Home | History | Annotate | Download | only in shell
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/shell/context.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/command_line.h"
     10 #include "base/lazy_instance.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/memory/scoped_vector.h"
     13 #include "base/strings/string_split.h"
     14 #include "build/build_config.h"
     15 #include "gpu/command_buffer/service/mailbox_manager.h"
     16 #include "mojo/application_manager/application_loader.h"
     17 #include "mojo/application_manager/application_manager.h"
     18 #include "mojo/application_manager/background_shell_application_loader.h"
     19 #include "mojo/embedder/embedder.h"
     20 #include "mojo/embedder/simple_platform_support.h"
     21 #include "mojo/public/cpp/application/application_connection.h"
     22 #include "mojo/public/cpp/application/application_delegate.h"
     23 #include "mojo/public/cpp/application/application_impl.h"
     24 #include "mojo/shell/dynamic_application_loader.h"
     25 #include "mojo/shell/in_process_dynamic_service_runner.h"
     26 #include "mojo/shell/out_of_process_dynamic_service_runner.h"
     27 #include "mojo/shell/switches.h"
     28 #include "mojo/shell/ui_application_loader_android.h"
     29 #include "mojo/spy/spy.h"
     30 
     31 #if defined(OS_LINUX)
     32 #include "mojo/shell/dbus_application_loader_linux.h"
     33 #endif  // defined(OS_LINUX)
     34 
     35 #if defined(OS_ANDROID)
     36 #include "mojo/services/native_viewport/gpu_impl.h"
     37 #include "mojo/services/native_viewport/native_viewport_impl.h"
     38 #include "mojo/shell/network_application_loader.h"
     39 #include "ui/gl/gl_share_group.h"
     40 #endif  // defined(OS_ANDROID)
     41 
     42 namespace mojo {
     43 namespace shell {
     44 namespace {
     45 
     46 // These mojo: URLs are loaded directly from the local filesystem. They
     47 // correspond to shared libraries bundled alongside the mojo_shell.
     48 const char* kLocalMojoURLs[] = {
     49   "mojo:mojo_network_service",
     50 };
     51 
     52 // Used to ensure we only init once.
     53 class Setup {
     54  public:
     55   Setup() {
     56     embedder::Init(scoped_ptr<mojo::embedder::PlatformSupport>(
     57         new mojo::embedder::SimplePlatformSupport()));
     58   }
     59 
     60   ~Setup() {
     61   }
     62 
     63  private:
     64   DISALLOW_COPY_AND_ASSIGN(Setup);
     65 };
     66 
     67 static base::LazyInstance<Setup>::Leaky setup = LAZY_INSTANCE_INITIALIZER;
     68 
     69 void InitContentHandlers(DynamicApplicationLoader* loader,
     70                          base::CommandLine* command_line) {
     71   // Default content handlers.
     72   loader->RegisterContentHandler("image/png", GURL("mojo://mojo_png_viewer/"));
     73   loader->RegisterContentHandler("text/html", GURL("mojo://mojo_html_viewer/"));
     74 
     75   // Command-line-specified content handlers.
     76   std::string handlers_spec = command_line->GetSwitchValueASCII(
     77       switches::kContentHandlers);
     78   if (handlers_spec.empty())
     79     return;
     80 
     81   std::vector<std::string> parts;
     82   base::SplitString(handlers_spec, ',', &parts);
     83   if (parts.size() % 2 != 0) {
     84     LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers
     85                << ": must be a comma-separated list of mimetype/url pairs.";
     86     return;
     87   }
     88 
     89   for (size_t i = 0; i < parts.size(); i += 2) {
     90     GURL url(parts[i + 1]);
     91     if (!url.is_valid()) {
     92       LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers
     93                  << ": '" << parts[i + 1] << "' is not a valid URL.";
     94       return;
     95     }
     96     loader->RegisterContentHandler(parts[i], url);
     97   }
     98 }
     99 
    100 class EmptyServiceProvider : public InterfaceImpl<ServiceProvider> {
    101  private:
    102   virtual void ConnectToService(const mojo::String& service_name,
    103                                 ScopedMessagePipeHandle client_handle)
    104       MOJO_OVERRIDE {
    105   }
    106 };
    107 
    108 }  // namespace
    109 
    110 #if defined(OS_ANDROID)
    111 class Context::NativeViewportApplicationLoader
    112     : public ApplicationLoader,
    113       public ApplicationDelegate,
    114       public InterfaceFactory<NativeViewport>,
    115       public InterfaceFactory<Gpu> {
    116  public:
    117   NativeViewportApplicationLoader()
    118       : share_group_(new gfx::GLShareGroup),
    119         mailbox_manager_(new gpu::gles2::MailboxManager) {}
    120   virtual ~NativeViewportApplicationLoader() {}
    121 
    122  private:
    123   // ApplicationLoader implementation.
    124   virtual void Load(ApplicationManager* manager,
    125                     const GURL& url,
    126                     scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
    127     ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
    128     if (shell_handle.is_valid())
    129       app_.reset(new ApplicationImpl(this, shell_handle.Pass()));
    130   }
    131 
    132   virtual void OnApplicationError(ApplicationManager* manager,
    133                                   const GURL& url) OVERRIDE {}
    134 
    135   // ApplicationDelegate implementation.
    136   virtual bool ConfigureIncomingConnection(
    137       mojo::ApplicationConnection* connection) OVERRIDE {
    138     connection->AddService<NativeViewport>(this);
    139     connection->AddService<Gpu>(this);
    140     return true;
    141   }
    142 
    143   // InterfaceFactory<NativeViewport> implementation.
    144   virtual void Create(ApplicationConnection* connection,
    145                       InterfaceRequest<NativeViewport> request) OVERRIDE {
    146     BindToRequest(new NativeViewportImpl(app_.get(), false), &request);
    147   }
    148 
    149   // InterfaceFactory<Gpu> implementation.
    150   virtual void Create(ApplicationConnection* connection,
    151                       InterfaceRequest<Gpu> request) OVERRIDE {
    152     BindToRequest(new GpuImpl(share_group_.get(), mailbox_manager_.get()),
    153                   &request);
    154   }
    155 
    156   scoped_refptr<gfx::GLShareGroup> share_group_;
    157   scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_;
    158   scoped_ptr<ApplicationImpl> app_;
    159   DISALLOW_COPY_AND_ASSIGN(NativeViewportApplicationLoader);
    160 };
    161 #endif
    162 
    163 Context::Context() {
    164   DCHECK(!base::MessageLoop::current());
    165 }
    166 
    167 Context::~Context() {
    168   DCHECK(!base::MessageLoop::current());
    169 }
    170 
    171 void Context::Init() {
    172   application_manager_.set_delegate(this);
    173   setup.Get();
    174   task_runners_.reset(
    175       new TaskRunners(base::MessageLoop::current()->message_loop_proxy()));
    176 
    177   for (size_t i = 0; i < arraysize(kLocalMojoURLs); ++i)
    178     mojo_url_resolver_.AddLocalFileMapping(GURL(kLocalMojoURLs[i]));
    179 
    180   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
    181   scoped_ptr<DynamicServiceRunnerFactory> runner_factory;
    182   if (command_line->HasSwitch(switches::kEnableMultiprocess))
    183     runner_factory.reset(new OutOfProcessDynamicServiceRunnerFactory());
    184   else
    185     runner_factory.reset(new InProcessDynamicServiceRunnerFactory());
    186 
    187   DynamicApplicationLoader* dynamic_application_loader =
    188       new DynamicApplicationLoader(this, runner_factory.Pass());
    189   InitContentHandlers(dynamic_application_loader, command_line);
    190   application_manager_.set_default_loader(
    191       scoped_ptr<ApplicationLoader>(dynamic_application_loader));
    192 
    193   // The native viewport service synchronously waits for certain messages. If we
    194   // don't run it on its own thread we can easily deadlock. Long term native
    195   // viewport should run its own process so that this isn't an issue.
    196 #if defined(OS_ANDROID)
    197   application_manager_.SetLoaderForURL(
    198       scoped_ptr<ApplicationLoader>(new UIApplicationLoader(
    199           scoped_ptr<ApplicationLoader>(new NativeViewportApplicationLoader()),
    200           this)),
    201       GURL("mojo:mojo_native_viewport_service"));
    202 #endif
    203 
    204 #if defined(OS_LINUX)
    205   application_manager_.SetLoaderForScheme(
    206       scoped_ptr<ApplicationLoader>(new DBusApplicationLoader(this)), "dbus");
    207 #endif  // defined(OS_LINUX)
    208 
    209   if (command_line->HasSwitch(switches::kSpy)) {
    210     spy_.reset(
    211         new mojo::Spy(&application_manager_,
    212                       command_line->GetSwitchValueASCII(switches::kSpy)));
    213   }
    214 
    215 #if defined(OS_ANDROID)
    216   // On android, the network service is bundled with the shell because the
    217   // network stack depends on the android runtime.
    218   {
    219     scoped_ptr<BackgroundShellApplicationLoader> loader(
    220         new BackgroundShellApplicationLoader(
    221             scoped_ptr<ApplicationLoader>(new NetworkApplicationLoader()),
    222             "network_service",
    223             base::MessageLoop::TYPE_IO));
    224     application_manager_.SetLoaderForURL(loader.PassAs<ApplicationLoader>(),
    225                                          GURL("mojo:mojo_network_service"));
    226   }
    227 #endif
    228 }
    229 
    230 void Context::OnApplicationError(const GURL& gurl) {
    231   if (app_urls_.find(gurl) != app_urls_.end()) {
    232     app_urls_.erase(gurl);
    233     if (app_urls_.empty() && base::MessageLoop::current()->is_running())
    234       base::MessageLoop::current()->Quit();
    235   }
    236 }
    237 
    238 void Context::Run(const GURL& url) {
    239   EmptyServiceProvider* sp = new EmptyServiceProvider;
    240   ServiceProviderPtr spp;
    241   BindToProxy(sp, &spp);
    242 
    243   app_urls_.insert(url);
    244   application_manager_.ConnectToApplication(url, GURL(), spp.Pass());
    245 }
    246 
    247 ScopedMessagePipeHandle Context::ConnectToServiceByName(
    248     const GURL& application_url,
    249     const std::string& service_name) {
    250   app_urls_.insert(application_url);
    251   return application_manager_.ConnectToServiceByName(
    252       application_url, service_name).Pass();
    253 }
    254 
    255 }  // namespace shell
    256 }  // namespace mojo
    257