context.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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/services/native_viewport/gpu_impl.h"
25#include "mojo/services/native_viewport/native_viewport_impl.h"
26#include "mojo/shell/dynamic_application_loader.h"
27#include "mojo/shell/in_process_dynamic_service_runner.h"
28#include "mojo/shell/out_of_process_dynamic_service_runner.h"
29#include "mojo/shell/switches.h"
30#include "mojo/shell/ui_application_loader_android.h"
31#include "mojo/spy/spy.h"
32#include "ui/gl/gl_share_group.h"
33
34#if defined(OS_LINUX)
35#include "mojo/shell/dbus_application_loader_linux.h"
36#endif  // defined(OS_LINUX)
37
38#if defined(OS_ANDROID)
39#include "mojo/shell/network_application_loader.h"
40#endif  // defined(OS_ANDROID)
41
42#if defined(USE_AURA)
43#include "mojo/shell/view_manager_loader.h"
44#endif
45
46namespace mojo {
47namespace shell {
48namespace {
49
50// These mojo: URLs are loaded directly from the local filesystem. They
51// correspond to shared libraries bundled alongside the mojo_shell.
52const char* kLocalMojoURLs[] = {
53  "mojo:mojo_network_service",
54};
55
56// Used to ensure we only init once.
57class Setup {
58 public:
59  Setup() {
60    embedder::Init(scoped_ptr<mojo::embedder::PlatformSupport>(
61        new mojo::embedder::SimplePlatformSupport()));
62  }
63
64  ~Setup() {
65  }
66
67 private:
68  DISALLOW_COPY_AND_ASSIGN(Setup);
69};
70
71static base::LazyInstance<Setup>::Leaky setup = LAZY_INSTANCE_INITIALIZER;
72
73void InitContentHandlers(DynamicApplicationLoader* loader,
74                         base::CommandLine* command_line) {
75  std::string handlers_spec = command_line->GetSwitchValueASCII(
76      switches::kContentHandlers);
77  if (handlers_spec.empty())
78    return;
79
80  std::vector<std::string> parts;
81  base::SplitString(handlers_spec, ',', &parts);
82  if (parts.size() % 2 != 0) {
83    LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers
84               << ": must be a comma-separated list of mimetype/url pairs.";
85    return;
86  }
87
88  for (size_t i = 0; i < parts.size(); i += 2) {
89    GURL url(parts[i + 1]);
90    if (!url.is_valid()) {
91      LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers
92                 << ": '" << parts[i + 1] << "' is not a valid URL.";
93      return;
94    }
95    loader->RegisterContentHandler(parts[i], url);
96  }
97}
98
99}  // namespace
100
101class Context::NativeViewportApplicationLoader
102    : public ApplicationLoader,
103      public ApplicationDelegate,
104      public InterfaceFactory<NativeViewport>,
105      public InterfaceFactory<Gpu> {
106 public:
107  NativeViewportApplicationLoader()
108      : share_group_(new gfx::GLShareGroup),
109        mailbox_manager_(new gpu::gles2::MailboxManager) {}
110  virtual ~NativeViewportApplicationLoader() {}
111
112 private:
113  // ApplicationLoader implementation.
114  virtual void Load(ApplicationManager* manager,
115                    const GURL& url,
116                    scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
117    ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
118    if (shell_handle.is_valid())
119      app_.reset(new ApplicationImpl(this, shell_handle.Pass()));
120  }
121
122  virtual void OnServiceError(ApplicationManager* manager,
123                              const GURL& url) OVERRIDE {}
124
125  // ApplicationDelegate implementation.
126  virtual bool ConfigureIncomingConnection(
127      mojo::ApplicationConnection* connection) OVERRIDE {
128    connection->AddService<NativeViewport>(this);
129    connection->AddService<Gpu>(this);
130    return true;
131  }
132
133  // InterfaceFactory<NativeViewport> implementation.
134  virtual void Create(ApplicationConnection* connection,
135                      InterfaceRequest<NativeViewport> request) OVERRIDE {
136    BindToRequest(new NativeViewportImpl, &request);
137  }
138
139  // InterfaceFactory<Gpu> implementation.
140  virtual void Create(ApplicationConnection* connection,
141                      InterfaceRequest<Gpu> request) OVERRIDE {
142    BindToRequest(new GpuImpl(share_group_.get(), mailbox_manager_.get()),
143                  &request);
144  }
145
146  scoped_refptr<gfx::GLShareGroup> share_group_;
147  scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_;
148  scoped_ptr<ApplicationImpl> app_;
149  DISALLOW_COPY_AND_ASSIGN(NativeViewportApplicationLoader);
150};
151
152Context::Context() {
153  DCHECK(!base::MessageLoop::current());
154}
155
156void Context::Init() {
157  setup.Get();
158  task_runners_.reset(
159      new TaskRunners(base::MessageLoop::current()->message_loop_proxy()));
160
161  for (size_t i = 0; i < arraysize(kLocalMojoURLs); ++i)
162    mojo_url_resolver_.AddLocalFileMapping(GURL(kLocalMojoURLs[i]));
163
164  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
165  scoped_ptr<DynamicServiceRunnerFactory> runner_factory;
166  if (command_line->HasSwitch(switches::kEnableMultiprocess))
167    runner_factory.reset(new OutOfProcessDynamicServiceRunnerFactory());
168  else
169    runner_factory.reset(new InProcessDynamicServiceRunnerFactory());
170
171  DynamicApplicationLoader* dynamic_application_loader =
172      new DynamicApplicationLoader(this, runner_factory.Pass());
173  InitContentHandlers(dynamic_application_loader, command_line);
174  application_manager_.set_default_loader(
175      scoped_ptr<ApplicationLoader>(dynamic_application_loader));
176
177  // The native viewport service synchronously waits for certain messages. If we
178  // don't run it on its own thread we can easily deadlock. Long term native
179  // viewport should run its own process so that this isn't an issue.
180#if defined(OS_ANDROID)
181  application_manager_.SetLoaderForURL(
182      scoped_ptr<ApplicationLoader>(new UIApplicationLoader(
183          scoped_ptr<ApplicationLoader>(new NativeViewportApplicationLoader()),
184          this)),
185      GURL("mojo:mojo_native_viewport_service"));
186#else
187  {
188    scoped_ptr<BackgroundShellApplicationLoader> loader(
189        new BackgroundShellApplicationLoader(
190            scoped_ptr<ApplicationLoader>(
191                new NativeViewportApplicationLoader()),
192            "native_viewport",
193            base::MessageLoop::TYPE_UI));
194    application_manager_.SetLoaderForURL(
195        loader.PassAs<ApplicationLoader>(),
196        GURL("mojo:mojo_native_viewport_service"));
197  }
198#endif
199#if defined(USE_AURA)
200  // TODO(sky): need a better way to find this. It shouldn't be linked in.
201  application_manager_.SetLoaderForURL(
202      scoped_ptr<ApplicationLoader>(new ViewManagerLoader()),
203      GURL("mojo:mojo_view_manager"));
204#endif
205
206#if defined(OS_LINUX)
207  application_manager_.SetLoaderForScheme(
208      scoped_ptr<ApplicationLoader>(new DBusApplicationLoader(this)), "dbus");
209#endif  // defined(OS_LINUX)
210
211  if (command_line->HasSwitch(switches::kSpy)) {
212    spy_.reset(
213        new mojo::Spy(&application_manager_,
214                      command_line->GetSwitchValueASCII(switches::kSpy)));
215  }
216
217#if defined(OS_ANDROID)
218  // On android, the network service is bundled with the shell because the
219  // network stack depends on the android runtime.
220  {
221    scoped_ptr<BackgroundShellApplicationLoader> loader(
222        new BackgroundShellApplicationLoader(
223            scoped_ptr<ApplicationLoader>(new NetworkApplicationLoader()),
224            "network_service",
225            base::MessageLoop::TYPE_IO));
226    application_manager_.SetLoaderForURL(loader.PassAs<ApplicationLoader>(),
227                                         GURL("mojo:mojo_network_service"));
228  }
229#endif
230}
231
232Context::~Context() {
233  DCHECK(!base::MessageLoop::current());
234}
235
236}  // namespace shell
237}  // namespace mojo
238