context.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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_vector.h"
12#include "base/strings/string_split.h"
13#include "build/build_config.h"
14#include "mojo/application_manager/application_loader.h"
15#include "mojo/application_manager/application_manager.h"
16#include "mojo/application_manager/background_shell_application_loader.h"
17#include "mojo/embedder/embedder.h"
18#include "mojo/public/cpp/application/application_connection.h"
19#include "mojo/public/cpp/application/application_delegate.h"
20#include "mojo/public/cpp/application/application_impl.h"
21#include "mojo/services/native_viewport/native_viewport_impl.h"
22#include "mojo/shell/dynamic_application_loader.h"
23#include "mojo/shell/in_process_dynamic_service_runner.h"
24#include "mojo/shell/out_of_process_dynamic_service_runner.h"
25#include "mojo/shell/switches.h"
26#include "mojo/shell/ui_application_loader_android.h"
27#include "mojo/spy/spy.h"
28
29#if defined(OS_LINUX)
30#include "mojo/shell/dbus_application_loader_linux.h"
31#endif  // defined(OS_LINUX)
32
33#if defined(OS_ANDROID)
34#include "mojo/shell/network_application_loader.h"
35#endif  // defined(OS_ANDROID)
36
37#if defined(USE_AURA)
38#include "mojo/shell/view_manager_loader.h"
39#endif
40
41namespace mojo {
42namespace shell {
43namespace {
44
45// These mojo: URLs are loaded directly from the local filesystem. They
46// correspond to shared libraries bundled alongside the mojo_shell.
47const char* kLocalMojoURLs[] = {
48  "mojo:mojo_network_service",
49};
50
51// Used to ensure we only init once.
52class Setup {
53 public:
54  Setup() {
55    embedder::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(DynamicApplicationLoader* 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::NativeViewportApplicationLoader
96    : public ApplicationLoader,
97      public ApplicationDelegate,
98      public InterfaceFactory<NativeViewport> {
99 public:
100  NativeViewportApplicationLoader() {}
101  virtual ~NativeViewportApplicationLoader() {}
102
103 private:
104  // ApplicationLoader implementation.
105  virtual void Load(ApplicationManager* manager,
106                    const GURL& url,
107                    scoped_refptr<LoadCallbacks> callbacks) OVERRIDE {
108    ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
109    if (shell_handle.is_valid())
110      app_.reset(new ApplicationImpl(this, shell_handle.Pass()));
111  }
112
113  virtual void OnServiceError(ApplicationManager* manager,
114                              const GURL& url) OVERRIDE {}
115
116  // ApplicationDelegate implementation.
117  virtual bool ConfigureIncomingConnection(
118      mojo::ApplicationConnection* connection) OVERRIDE {
119    connection->AddService(this);
120    return true;
121  }
122
123  // InterfaceFactory<NativeViewport> implementation.
124  virtual void Create(ApplicationConnection* connection,
125                      InterfaceRequest<NativeViewport> request) OVERRIDE {
126    BindToRequest(new NativeViewportImpl, &request);
127  }
128
129  scoped_ptr<ApplicationImpl> app_;
130  DISALLOW_COPY_AND_ASSIGN(NativeViewportApplicationLoader);
131};
132
133Context::Context() {
134  DCHECK(!base::MessageLoop::current());
135}
136
137void Context::Init() {
138  setup.Get();
139  task_runners_.reset(
140      new TaskRunners(base::MessageLoop::current()->message_loop_proxy()));
141
142  for (size_t i = 0; i < arraysize(kLocalMojoURLs); ++i)
143    mojo_url_resolver_.AddLocalFileMapping(GURL(kLocalMojoURLs[i]));
144
145  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
146  scoped_ptr<DynamicServiceRunnerFactory> runner_factory;
147  if (command_line->HasSwitch(switches::kEnableMultiprocess))
148    runner_factory.reset(new OutOfProcessDynamicServiceRunnerFactory());
149  else
150    runner_factory.reset(new InProcessDynamicServiceRunnerFactory());
151
152  DynamicApplicationLoader* dynamic_application_loader =
153      new DynamicApplicationLoader(this, runner_factory.Pass());
154  InitContentHandlers(dynamic_application_loader, command_line);
155  application_manager_.set_default_loader(
156      scoped_ptr<ApplicationLoader>(dynamic_application_loader));
157
158  // The native viewport service synchronously waits for certain messages. If we
159  // don't run it on its own thread we can easily deadlock. Long term native
160  // viewport should run its own process so that this isn't an issue.
161#if defined(OS_ANDROID)
162  application_manager_.SetLoaderForURL(
163      scoped_ptr<ApplicationLoader>(new UIApplicationLoader(
164          scoped_ptr<ApplicationLoader>(new NativeViewportApplicationLoader()),
165          this)),
166      GURL("mojo:mojo_native_viewport_service"));
167#else
168  {
169    scoped_ptr<BackgroundShellApplicationLoader> loader(
170        new BackgroundShellApplicationLoader(
171            scoped_ptr<ApplicationLoader>(
172                new NativeViewportApplicationLoader()),
173            "native_viewport",
174            base::MessageLoop::TYPE_UI));
175    application_manager_.SetLoaderForURL(
176        loader.PassAs<ApplicationLoader>(),
177        GURL("mojo:mojo_native_viewport_service"));
178  }
179#endif
180#if defined(USE_AURA)
181  // TODO(sky): need a better way to find this. It shouldn't be linked in.
182  application_manager_.SetLoaderForURL(
183      scoped_ptr<ApplicationLoader>(new ViewManagerLoader()),
184      GURL("mojo:mojo_view_manager"));
185#endif
186
187#if defined(OS_LINUX)
188  application_manager_.SetLoaderForScheme(
189      scoped_ptr<ApplicationLoader>(new DBusApplicationLoader(this)), "dbus");
190#endif  // defined(OS_LINUX)
191
192  if (command_line->HasSwitch(switches::kSpy)) {
193    spy_.reset(
194        new mojo::Spy(&application_manager_,
195                      command_line->GetSwitchValueASCII(switches::kSpy)));
196  }
197
198#if defined(OS_ANDROID)
199  // On android, the network service is bundled with the shell because the
200  // network stack depends on the android runtime.
201  {
202    scoped_ptr<BackgroundShellApplicationLoader> loader(
203        new BackgroundShellApplicationLoader(
204            scoped_ptr<ApplicationLoader>(new NetworkApplicationLoader()),
205            "network_service",
206            base::MessageLoop::TYPE_IO));
207    application_manager_.SetLoaderForURL(loader.PassAs<ApplicationLoader>(),
208                                         GURL("mojo:mojo_network_service"));
209  }
210#endif
211}
212
213Context::~Context() {
214  DCHECK(!base::MessageLoop::current());
215}
216
217}  // namespace shell
218}  // namespace mojo
219