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 |