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