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