| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 "content/browser/mojo/mojo_shell_context.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <string> | |
| 9 #include <utility> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/json/json_reader.h" | |
| 13 #include "base/lazy_instance.h" | |
| 14 #include "base/macros.h" | |
| 15 #include "base/memory/ptr_util.h" | |
| 16 #include "base/single_thread_task_runner.h" | |
| 17 #include "content/browser/gpu/gpu_process_host.h" | |
| 18 #include "content/browser/mojo/merge_dictionary.h" | |
| 19 #include "content/common/mojo/mojo_shell_connection_impl.h" | |
| 20 #include "content/grit/content_resources.h" | |
| 21 #include "content/public/browser/browser_thread.h" | |
| 22 #include "content/public/browser/content_browser_client.h" | |
| 23 #include "content/public/browser/utility_process_host.h" | |
| 24 #include "content/public/browser/utility_process_host_client.h" | |
| 25 #include "content/public/common/content_client.h" | |
| 26 #include "content/public/common/mojo_shell_connection.h" | |
| 27 #include "content/public/common/service_names.h" | |
| 28 #include "mojo/edk/embedder/embedder.h" | |
| 29 #include "services/catalog/catalog.h" | |
| 30 #include "services/catalog/manifest_provider.h" | |
| 31 #include "services/catalog/store.h" | |
| 32 #include "services/file/public/cpp/constants.h" | |
| 33 #include "services/shell/connect_params.h" | |
| 34 #include "services/shell/native_runner.h" | |
| 35 #include "services/shell/public/cpp/connector.h" | |
| 36 #include "services/shell/public/cpp/service.h" | |
| 37 #include "services/shell/public/interfaces/service.mojom.h" | |
| 38 #include "services/shell/runner/common/client_util.h" | |
| 39 #include "services/shell/runner/host/in_process_native_runner.h" | |
| 40 #include "services/shell/service_manager.h" | |
| 41 | |
| 42 namespace content { | |
| 43 | |
| 44 namespace { | |
| 45 | |
| 46 base::LazyInstance<std::unique_ptr<shell::Connector>>::Leaky | |
| 47 g_io_thread_connector = LAZY_INSTANCE_INITIALIZER; | |
| 48 | |
| 49 void DestroyConnectorOnIOThread() { g_io_thread_connector.Get().reset(); } | |
| 50 | |
| 51 void StartUtilityProcessOnIOThread(shell::mojom::ServiceFactoryRequest request, | |
| 52 const base::string16& process_name, | |
| 53 bool use_sandbox) { | |
| 54 UtilityProcessHost* process_host = | |
| 55 UtilityProcessHost::Create(nullptr, nullptr); | |
| 56 process_host->SetName(process_name); | |
| 57 if (!use_sandbox) | |
| 58 process_host->DisableSandbox(); | |
| 59 process_host->Start(); | |
| 60 process_host->GetRemoteInterfaces()->GetInterface(std::move(request)); | |
| 61 } | |
| 62 | |
| 63 void StartServiceInUtilityProcess(const std::string& service_name, | |
| 64 const base::string16& process_name, | |
| 65 bool use_sandbox, | |
| 66 shell::mojom::ServiceRequest request) { | |
| 67 shell::mojom::ServiceFactoryPtr service_factory; | |
| 68 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 69 base::Bind(&StartUtilityProcessOnIOThread, | |
| 70 base::Passed(GetProxy(&service_factory)), | |
| 71 process_name, use_sandbox)); | |
| 72 service_factory->CreateService(std::move(request), service_name); | |
| 73 } | |
| 74 | |
| 75 #if (ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | |
| 76 | |
| 77 // Request shell::mojom::ServiceFactory from GPU process host. Must be called on | |
| 78 // IO thread. | |
| 79 void RequestGpuServiceFactory(shell::mojom::ServiceFactoryRequest request) { | |
| 80 GpuProcessHost* process_host = | |
| 81 GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED); | |
| 82 if (!process_host) { | |
| 83 DLOG(ERROR) << "GPU process host not available."; | |
| 84 return; | |
| 85 } | |
| 86 | |
| 87 // TODO(xhwang): It's possible that |process_host| is non-null, but the actual | |
| 88 // process is dead. In that case, |request| will be dropped and application | |
| 89 // load requests through ServiceFactory will also fail. Make sure we handle | |
| 90 // these cases correctly. | |
| 91 process_host->GetRemoteInterfaces()->GetInterface(std::move(request)); | |
| 92 } | |
| 93 | |
| 94 void StartServiceInGpuProcess(const std::string& service_name, | |
| 95 shell::mojom::ServiceRequest request) { | |
| 96 shell::mojom::ServiceFactoryPtr service_factory; | |
| 97 BrowserThread::PostTask( | |
| 98 BrowserThread::IO, FROM_HERE, | |
| 99 base::Bind(&RequestGpuServiceFactory, | |
| 100 base::Passed(GetProxy(&service_factory)))); | |
| 101 service_factory->CreateService(std::move(request), service_name); | |
| 102 } | |
| 103 | |
| 104 #endif // ENABLE_MOJO_MEDIA_IN_GPU_PROCESS | |
| 105 | |
| 106 // A ManifestProvider which resolves application names to builtin manifest | |
| 107 // resources for the catalog service to consume. | |
| 108 class BuiltinManifestProvider : public catalog::ManifestProvider { | |
| 109 public: | |
| 110 BuiltinManifestProvider() {} | |
| 111 ~BuiltinManifestProvider() override {} | |
| 112 | |
| 113 void AddManifestValue(const std::string& name, | |
| 114 std::unique_ptr<base::Value> manifest_contents) { | |
| 115 auto result = manifests_.insert( | |
| 116 std::make_pair(name, std::move(manifest_contents))); | |
| 117 DCHECK(result.second) << "Duplicate manifest entry: " << name; | |
| 118 } | |
| 119 | |
| 120 private: | |
| 121 // catalog::ManifestProvider: | |
| 122 std::unique_ptr<base::Value> GetManifest(const std::string& name) override { | |
| 123 auto it = manifests_.find(name); | |
| 124 return it != manifests_.end() ? it->second->CreateDeepCopy() : nullptr; | |
| 125 } | |
| 126 | |
| 127 std::map<std::string, std::unique_ptr<base::Value>> manifests_; | |
| 128 | |
| 129 DISALLOW_COPY_AND_ASSIGN(BuiltinManifestProvider); | |
| 130 }; | |
| 131 | |
| 132 } // namespace | |
| 133 | |
| 134 // State which lives on the IO thread and drives the ServiceManager. | |
| 135 class MojoShellContext::InProcessServiceManagerContext | |
| 136 : public base::RefCountedThreadSafe<InProcessServiceManagerContext> { | |
| 137 public: | |
| 138 InProcessServiceManagerContext() {} | |
| 139 | |
| 140 shell::mojom::ServiceRequest Start( | |
| 141 std::unique_ptr<BuiltinManifestProvider> manifest_provider) { | |
| 142 shell::mojom::ServicePtr embedder_service_proxy; | |
| 143 shell::mojom::ServiceRequest embedder_service_request = | |
| 144 mojo::GetProxy(&embedder_service_proxy); | |
| 145 shell::mojom::ServicePtrInfo embedder_service_proxy_info = | |
| 146 embedder_service_proxy.PassInterface(); | |
| 147 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)->PostTask( | |
| 148 FROM_HERE, | |
| 149 base::Bind(&InProcessServiceManagerContext::StartOnIOThread, this, | |
| 150 base::Passed(&manifest_provider), | |
| 151 base::Passed(&embedder_service_proxy_info))); | |
| 152 return embedder_service_request; | |
| 153 } | |
| 154 | |
| 155 void ShutDown() { | |
| 156 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)->PostTask( | |
| 157 FROM_HERE, | |
| 158 base::Bind(&InProcessServiceManagerContext::ShutDownOnIOThread, this)); | |
| 159 } | |
| 160 | |
| 161 private: | |
| 162 friend class base::RefCountedThreadSafe<InProcessServiceManagerContext>; | |
| 163 | |
| 164 ~InProcessServiceManagerContext() {} | |
| 165 | |
| 166 void StartOnIOThread( | |
| 167 std::unique_ptr<BuiltinManifestProvider> manifest_provider, | |
| 168 shell::mojom::ServicePtrInfo embedder_service_proxy_info) { | |
| 169 manifest_provider_ = std::move(manifest_provider); | |
| 170 | |
| 171 base::SequencedWorkerPool* blocking_pool = BrowserThread::GetBlockingPool(); | |
| 172 std::unique_ptr<shell::NativeRunnerFactory> native_runner_factory( | |
| 173 new shell::InProcessNativeRunnerFactory(blocking_pool)); | |
| 174 catalog_.reset( | |
| 175 new catalog::Catalog(blocking_pool, nullptr, manifest_provider_.get())); | |
| 176 service_manager_.reset(new shell::ServiceManager( | |
| 177 std::move(native_runner_factory), catalog_->TakeService())); | |
| 178 | |
| 179 shell::mojom::ServiceRequest request = | |
| 180 service_manager_->StartEmbedderService(kBrowserMojoApplicationName); | |
| 181 mojo::FuseInterface( | |
| 182 std::move(request), std::move(embedder_service_proxy_info)); | |
| 183 } | |
| 184 | |
| 185 void ShutDownOnIOThread() { | |
| 186 service_manager_.reset(); | |
| 187 catalog_.reset(); | |
| 188 manifest_provider_.reset(); | |
| 189 } | |
| 190 | |
| 191 std::unique_ptr<BuiltinManifestProvider> manifest_provider_; | |
| 192 std::unique_ptr<catalog::Catalog> catalog_; | |
| 193 std::unique_ptr<shell::ServiceManager> service_manager_; | |
| 194 | |
| 195 DISALLOW_COPY_AND_ASSIGN(InProcessServiceManagerContext); | |
| 196 }; | |
| 197 | |
| 198 MojoShellContext::MojoShellContext() { | |
| 199 shell::mojom::ServiceRequest request; | |
| 200 if (shell::ShellIsRemote()) { | |
| 201 mojo::edk::SetParentPipeHandleFromCommandLine(); | |
| 202 request = shell::GetServiceRequestFromCommandLine(); | |
| 203 } else { | |
| 204 std::unique_ptr<BuiltinManifestProvider> manifest_provider = | |
| 205 base::MakeUnique<BuiltinManifestProvider>(); | |
| 206 | |
| 207 static const struct ManifestInfo { | |
| 208 const char* name; | |
| 209 int resource_id; | |
| 210 } kManifests[] = { | |
| 211 { kBrowserMojoApplicationName, IDR_MOJO_CONTENT_BROWSER_MANIFEST }, | |
| 212 { kGpuMojoApplicationName, IDR_MOJO_CONTENT_GPU_MANIFEST }, | |
| 213 { kPluginMojoApplicationName, IDR_MOJO_CONTENT_PLUGIN_MANIFEST }, | |
| 214 { kRendererMojoApplicationName, IDR_MOJO_CONTENT_RENDERER_MANIFEST }, | |
| 215 { kUtilityMojoApplicationName, IDR_MOJO_CONTENT_UTILITY_MANIFEST }, | |
| 216 { "service:catalog", IDR_MOJO_CATALOG_MANIFEST }, | |
| 217 { file::kFileServiceName, IDR_MOJO_FILE_MANIFEST } | |
| 218 }; | |
| 219 | |
| 220 for (size_t i = 0; i < arraysize(kManifests); ++i) { | |
| 221 std::string contents = GetContentClient()->GetDataResource( | |
| 222 kManifests[i].resource_id, | |
| 223 ui::ScaleFactor::SCALE_FACTOR_NONE).as_string(); | |
| 224 DCHECK(!contents.empty()); | |
| 225 std::unique_ptr<base::Value> manifest_value = | |
| 226 base::JSONReader::Read(contents); | |
| 227 std::unique_ptr<base::Value> overlay_value = | |
| 228 GetContentClient()->browser()->GetServiceManifestOverlay( | |
| 229 kManifests[i].name); | |
| 230 if (overlay_value) { | |
| 231 base::DictionaryValue* manifest_dictionary = nullptr; | |
| 232 CHECK(manifest_value->GetAsDictionary(&manifest_dictionary)); | |
| 233 base::DictionaryValue* overlay_dictionary = nullptr; | |
| 234 CHECK(overlay_value->GetAsDictionary(&overlay_dictionary)); | |
| 235 MergeDictionary(manifest_dictionary, overlay_dictionary); | |
| 236 } | |
| 237 manifest_provider->AddManifestValue(kManifests[i].name, | |
| 238 std::move(manifest_value)); | |
| 239 } | |
| 240 in_process_context_ = new InProcessServiceManagerContext; | |
| 241 request = in_process_context_->Start(std::move(manifest_provider)); | |
| 242 } | |
| 243 MojoShellConnection::SetForProcess(MojoShellConnection::Create( | |
| 244 std::move(request), | |
| 245 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO))); | |
| 246 | |
| 247 ContentBrowserClient::StaticMojoApplicationMap apps; | |
| 248 GetContentClient()->browser()->RegisterInProcessMojoApplications(&apps); | |
| 249 for (const auto& entry : apps) { | |
| 250 MojoShellConnection::GetForProcess()->AddEmbeddedService(entry.first, | |
| 251 entry.second); | |
| 252 } | |
| 253 | |
| 254 // This is safe to assign directly from any thread, because MojoShellContext | |
| 255 // must be constructed before anyone can call GetConnectorForIOThread(). | |
| 256 g_io_thread_connector.Get() = | |
| 257 MojoShellConnection::GetForProcess()->GetConnector()->Clone(); | |
| 258 | |
| 259 MojoShellConnection::GetForProcess()->Start(); | |
| 260 | |
| 261 ContentBrowserClient::OutOfProcessMojoApplicationMap sandboxed_apps; | |
| 262 GetContentClient() | |
| 263 ->browser() | |
| 264 ->RegisterOutOfProcessMojoApplications(&sandboxed_apps); | |
| 265 for (const auto& app : sandboxed_apps) { | |
| 266 MojoShellConnection::GetForProcess()->AddServiceRequestHandler( | |
| 267 app.first, | |
| 268 base::Bind(&StartServiceInUtilityProcess, app.first, app.second, | |
| 269 true /* use_sandbox */)); | |
| 270 } | |
| 271 | |
| 272 ContentBrowserClient::OutOfProcessMojoApplicationMap unsandboxed_apps; | |
| 273 GetContentClient() | |
| 274 ->browser() | |
| 275 ->RegisterUnsandboxedOutOfProcessMojoApplications(&unsandboxed_apps); | |
| 276 for (const auto& app : unsandboxed_apps) { | |
| 277 MojoShellConnection::GetForProcess()->AddServiceRequestHandler( | |
| 278 app.first, | |
| 279 base::Bind(&StartServiceInUtilityProcess, app.first, app.second, | |
| 280 false /* use_sandbox */)); | |
| 281 } | |
| 282 | |
| 283 #if (ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | |
| 284 MojoShellConnection::GetForProcess()->AddServiceRequestHandler( | |
| 285 "service:media", base::Bind(&StartServiceInGpuProcess, "service:media")); | |
| 286 #endif | |
| 287 } | |
| 288 | |
| 289 MojoShellContext::~MojoShellContext() { | |
| 290 // NOTE: The in-process ServiceManager MUST be destroyed before the browser | |
| 291 // process-wide MojoShellConnection. Otherwise it's possible for the | |
| 292 // ServiceManager to receive connection requests for service:content_browser | |
| 293 // which it may attempt to service by launching a new instance of the browser. | |
| 294 if (in_process_context_) | |
| 295 in_process_context_->ShutDown(); | |
| 296 if (MojoShellConnection::GetForProcess()) | |
| 297 MojoShellConnection::DestroyForProcess(); | |
| 298 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 299 base::Bind(&DestroyConnectorOnIOThread)); | |
| 300 } | |
| 301 | |
| 302 // static | |
| 303 shell::Connector* MojoShellContext::GetConnectorForIOThread() { | |
| 304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 305 return g_io_thread_connector.Get().get(); | |
| 306 } | |
| 307 | |
| 308 } // namespace content | |
| OLD | NEW |