context.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 "build/build_config.h"
10#include "base/command_line.h"
11#include "base/lazy_instance.h"
12#include "base/memory/scoped_vector.h"
13#include "base/strings/string_split.h"
14#include "mojo/embedder/embedder.h"
15#include "mojo/gles2/gles2_support_impl.h"
16#include "mojo/public/cpp/application/application_impl.h"
17#include "mojo/service_manager/background_shell_service_loader.h"
18#include "mojo/service_manager/service_loader.h"
19#include "mojo/service_manager/service_manager.h"
20#include "mojo/services/native_viewport/native_viewport_service.h"
21#include "mojo/shell/dynamic_service_loader.h"
22#include "mojo/shell/in_process_dynamic_service_runner.h"
23#include "mojo/shell/out_of_process_dynamic_service_runner.h"
24#include "mojo/shell/switches.h"
25#include "mojo/shell/ui_service_loader_android.h"
26#include "mojo/spy/spy.h"
27
28#if defined(OS_LINUX)
29#include "mojo/shell/dbus_service_loader_linux.h"
30#endif  // defined(OS_LINUX)
31
32#if defined(OS_ANDROID)
33#include "mojo/shell/network_service_loader.h"
34#endif  // defined(OS_ANDROID)
35
36#if defined(USE_AURA)
37#include "mojo/shell/view_manager_loader.h"
38#endif
39
40namespace mojo {
41namespace shell {
42namespace {
43
44// These mojo: URLs are loaded directly from the local filesystem. They
45// correspond to shared libraries bundled alongside the mojo_shell.
46const char* kLocalMojoURLs[] = {
47  "mojo:mojo_network_service",
48};
49
50// Used to ensure we only init once.
51class Setup {
52 public:
53  Setup() {
54    embedder::Init();
55    gles2::GLES2SupportImpl::Init();
56  }
57
58  ~Setup() {
59  }
60
61 private:
62  DISALLOW_COPY_AND_ASSIGN(Setup);
63};
64
65static base::LazyInstance<Setup>::Leaky setup = LAZY_INSTANCE_INITIALIZER;
66
67void InitContentHandlers(DynamicServiceLoader* loader,
68                         base::CommandLine* command_line) {
69  std::string handlers_spec = command_line->GetSwitchValueASCII(
70      switches::kContentHandlers);
71  if (handlers_spec.empty())
72    return;
73
74  std::vector<std::string> parts;
75  base::SplitString(handlers_spec, ',', &parts);
76  if (parts.size() % 2 != 0) {
77    LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers
78               << ": must be a comma-separated list of mimetype/url pairs.";
79    return;
80  }
81
82  for (size_t i = 0; i < parts.size(); i += 2) {
83    GURL url(parts[i + 1]);
84    if (!url.is_valid()) {
85      LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers
86                 << ": '" << parts[i + 1] << "' is not a valid URL.";
87      return;
88    }
89    loader->RegisterContentHandler(parts[i], url);
90  }
91}
92
93}  // namespace
94
95class Context::NativeViewportServiceLoader : public ServiceLoader {
96 public:
97  NativeViewportServiceLoader() {}
98  virtual ~NativeViewportServiceLoader() {}
99
100 private:
101  virtual void Load(ServiceManager* manager,
102                    const GURL& url,
103                    scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
104    ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
105    if (shell_handle.is_valid())
106      app_.reset(services::CreateNativeViewportService(shell_handle.Pass()));
107  }
108
109  virtual void OnServiceError(ServiceManager* manager,
110                              const GURL& url) OVERRIDE {
111  }
112
113  scoped_ptr<ApplicationImpl> app_;
114  DISALLOW_COPY_AND_ASSIGN(NativeViewportServiceLoader);
115};
116
117Context::Context() {
118  DCHECK(!base::MessageLoop::current());
119}
120
121void Context::Init() {
122  setup.Get();
123  task_runners_.reset(
124      new TaskRunners(base::MessageLoop::current()->message_loop_proxy()));
125
126  for (size_t i = 0; i < arraysize(kLocalMojoURLs); ++i)
127    mojo_url_resolver_.AddLocalFileMapping(GURL(kLocalMojoURLs[i]));
128
129  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
130  scoped_ptr<DynamicServiceRunnerFactory> runner_factory;
131  if (command_line->HasSwitch(switches::kEnableMultiprocess))
132    runner_factory.reset(new OutOfProcessDynamicServiceRunnerFactory());
133  else
134    runner_factory.reset(new InProcessDynamicServiceRunnerFactory());
135
136  DynamicServiceLoader* dynamic_service_loader =
137      new DynamicServiceLoader(this, runner_factory.Pass());
138  InitContentHandlers(dynamic_service_loader, command_line);
139  service_manager_.set_default_loader(
140      scoped_ptr<ServiceLoader>(dynamic_service_loader));
141
142  // The native viewport service synchronously waits for certain messages. If we
143  // don't run it on its own thread we can easily deadlock. Long term native
144  // viewport should run its own process so that this isn't an issue.
145#if defined(OS_ANDROID)
146  service_manager_.SetLoaderForURL(
147      scoped_ptr<ServiceLoader>(
148          new UIServiceLoader(
149              scoped_ptr<ServiceLoader>(new NativeViewportServiceLoader()),
150              this)),
151      GURL("mojo:mojo_native_viewport_service"));
152#else
153  {
154    scoped_ptr<BackgroundShellServiceLoader> loader(
155        new BackgroundShellServiceLoader(
156            scoped_ptr<ServiceLoader>(new NativeViewportServiceLoader()),
157            "native_viewport",
158             base::MessageLoop::TYPE_UI));
159    service_manager_.SetLoaderForURL(
160        loader.PassAs<ServiceLoader>(),
161        GURL("mojo:mojo_native_viewport_service"));
162  }
163#endif
164#if defined(USE_AURA)
165  // TODO(sky): need a better way to find this. It shouldn't be linked in.
166  service_manager_.SetLoaderForURL(
167      scoped_ptr<ServiceLoader>(new ViewManagerLoader()),
168      GURL("mojo:mojo_view_manager"));
169#endif
170
171#if defined(OS_LINUX)
172  service_manager_.SetLoaderForScheme(
173      scoped_ptr<ServiceLoader>(new DBusServiceLoader(this)),
174      "dbus");
175#endif  // defined(OS_LINUX)
176
177  if (command_line->HasSwitch(switches::kSpy)) {
178    spy_.reset(new mojo::Spy(
179        &service_manager_, command_line->GetSwitchValueASCII(switches::kSpy)));
180  }
181
182#if defined(OS_ANDROID)
183  // On android, the network service is bundled with the shell because the
184  // network stack depends on the android runtime.
185  {
186    scoped_ptr<BackgroundShellServiceLoader> loader(
187        new BackgroundShellServiceLoader(
188            scoped_ptr<ServiceLoader>(new NetworkServiceLoader()),
189            "network_service",
190             base::MessageLoop::TYPE_IO));
191    service_manager_.SetLoaderForURL(loader.PassAs<ServiceLoader>(),
192                                     GURL("mojo:mojo_network_service"));
193  }
194#endif
195}
196
197Context::~Context() {
198  DCHECK(!base::MessageLoop::current());
199}
200
201}  // namespace shell
202}  // namespace mojo
203