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.
5 #include "content/browser/mojo/mojo_shell_context.h"
7 #include "base/lazy_instance.h"
8 #include "base/macros.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "content/common/process_control.mojom.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/content_browser_client.h"
14 #include "content/public/browser/utility_process_host.h"
15 #include "content/public/browser/utility_process_host_client.h"
16 #include "content/public/common/content_client.h"
17 #include "content/public/common/service_registry.h"
18 #include "mojo/application/public/cpp/application_delegate.h"
19 #include "mojo/common/url_type_converters.h"
20 #include "mojo/shell/application_loader.h"
21 #include "mojo/shell/connect_to_application_params.h"
22 #include "mojo/shell/identity.h"
23 #include "mojo/shell/static_application_loader.h"
24 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
25 #include "third_party/mojo/src/mojo/public/cpp/bindings/string.h"
27 #if defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
28 #include "media/mojo/services/mojo_media_application.h"
35 // An extra set of apps to register on initialization, if set by a test.
36 const MojoShellContext::StaticApplicationMap
* g_applications_for_test
;
38 void StartProcessOnIOThread(mojo::InterfaceRequest
<ProcessControl
> request
,
39 const base::string16
& process_name
,
41 UtilityProcessHost
* process_host
=
42 UtilityProcessHost::Create(nullptr, nullptr);
43 process_host
->SetName(process_name
);
45 process_host
->DisableSandbox();
46 process_host
->StartMojoMode();
48 ServiceRegistry
* services
= process_host
->GetServiceRegistry();
49 services
->ConnectToRemoteService(request
.Pass());
52 void OnApplicationLoaded(const GURL
& url
, bool success
) {
54 LOG(ERROR
) << "Failed to launch Mojo application for " << url
.spec();
57 // The default loader to use for all applications. This does nothing but drop
58 // the Application request.
59 class DefaultApplicationLoader
: public mojo::shell::ApplicationLoader
{
61 DefaultApplicationLoader() {}
62 ~DefaultApplicationLoader() override
{}
65 // mojo::shell::ApplicationLoader:
68 mojo::InterfaceRequest
<mojo::Application
> application_request
) override
{}
70 DISALLOW_COPY_AND_ASSIGN(DefaultApplicationLoader
);
73 // This launches a utility process and forwards the Load request the
74 // ProcessControl service there. The utility process is sandboxed iff
75 // |use_sandbox| is true.
76 class UtilityProcessLoader
: public mojo::shell::ApplicationLoader
{
78 UtilityProcessLoader(const base::string16
& process_name
, bool use_sandbox
)
79 : process_name_(process_name
), use_sandbox_(use_sandbox
) {}
80 ~UtilityProcessLoader() override
{}
83 // mojo::shell::ApplicationLoader:
86 mojo::InterfaceRequest
<mojo::Application
> application_request
) override
{
87 ProcessControlPtr process_control
;
88 auto process_request
= mojo::GetProxy(&process_control
);
89 BrowserThread::PostTask(
90 BrowserThread::IO
, FROM_HERE
,
91 base::Bind(&StartProcessOnIOThread
, base::Passed(&process_request
),
92 process_name_
, use_sandbox_
));
93 process_control
->LoadApplication(url
.spec(), application_request
.Pass(),
94 base::Bind(&OnApplicationLoaded
, url
));
97 const base::string16 process_name_
;
98 const bool use_sandbox_
;
100 DISALLOW_COPY_AND_ASSIGN(UtilityProcessLoader
);
105 // Thread-safe proxy providing access to the shell context from any thread.
106 class MojoShellContext::Proxy
{
108 Proxy(MojoShellContext
* shell_context
)
109 : shell_context_(shell_context
),
110 task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
114 void ConnectToApplication(
116 const GURL
& requestor_url
,
117 mojo::InterfaceRequest
<mojo::ServiceProvider
> request
,
118 mojo::ServiceProviderPtr exposed_services
,
119 const mojo::shell::CapabilityFilter
& filter
,
120 const mojo::Shell::ConnectToApplicationCallback
& callback
) {
121 if (task_runner_
== base::ThreadTaskRunnerHandle::Get()) {
122 if (shell_context_
) {
123 shell_context_
->ConnectToApplicationOnOwnThread(
124 url
, requestor_url
, request
.Pass(), exposed_services
.Pass(), filter
,
128 // |shell_context_| outlives the main MessageLoop, so it's safe for it to
129 // be unretained here.
130 task_runner_
->PostTask(
132 base::Bind(&MojoShellContext::ConnectToApplicationOnOwnThread
,
133 base::Unretained(shell_context_
), url
, requestor_url
,
134 base::Passed(&request
), base::Passed(&exposed_services
),
140 MojoShellContext
* shell_context_
;
141 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
143 DISALLOW_COPY_AND_ASSIGN(Proxy
);
147 base::LazyInstance
<scoped_ptr
<MojoShellContext::Proxy
>>
148 MojoShellContext::proxy_
= LAZY_INSTANCE_INITIALIZER
;
150 void MojoShellContext::SetApplicationsForTest(
151 const StaticApplicationMap
* apps
) {
152 g_applications_for_test
= apps
;
155 MojoShellContext::MojoShellContext()
156 : application_manager_(new mojo::shell::ApplicationManager(this)) {
157 proxy_
.Get().reset(new Proxy(this));
159 application_manager_
->set_default_loader(
160 scoped_ptr
<mojo::shell::ApplicationLoader
>(new DefaultApplicationLoader
));
162 StaticApplicationMap apps
;
163 GetContentClient()->browser()->RegisterInProcessMojoApplications(&apps
);
164 if (g_applications_for_test
) {
165 // Add testing apps to the map, potentially overwriting whatever the
166 // browser client registered.
167 for (const auto& entry
: *g_applications_for_test
)
168 apps
[entry
.first
] = entry
.second
;
170 for (const auto& entry
: apps
) {
171 application_manager_
->SetLoaderForURL(
172 scoped_ptr
<mojo::shell::ApplicationLoader
>(
173 new mojo::shell::StaticApplicationLoader(entry
.second
)),
177 ContentBrowserClient::OutOfProcessMojoApplicationMap sandboxed_apps
;
180 ->RegisterOutOfProcessMojoApplications(&sandboxed_apps
);
181 for (const auto& app
: sandboxed_apps
) {
182 application_manager_
->SetLoaderForURL(
183 scoped_ptr
<mojo::shell::ApplicationLoader
>(
184 new UtilityProcessLoader(app
.second
, true /* use_sandbox */)),
188 ContentBrowserClient::OutOfProcessMojoApplicationMap unsandboxed_apps
;
191 ->RegisterUnsandboxedOutOfProcessMojoApplications(&unsandboxed_apps
);
192 for (const auto& app
: unsandboxed_apps
) {
193 application_manager_
->SetLoaderForURL(
194 scoped_ptr
<mojo::shell::ApplicationLoader
>(
195 new UtilityProcessLoader(app
.second
, false /* use_sandbox */)),
199 #if (ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
200 application_manager_
->SetLoaderForURL(
201 scoped_ptr
<mojo::shell::ApplicationLoader
>(
202 new mojo::shell::StaticApplicationLoader(
203 base::Bind(&media::MojoMediaApplication::CreateApp
))),
204 media::MojoMediaApplication::AppUrl());
208 MojoShellContext::~MojoShellContext() {
212 void MojoShellContext::ConnectToApplication(
214 const GURL
& requestor_url
,
215 mojo::InterfaceRequest
<mojo::ServiceProvider
> request
,
216 mojo::ServiceProviderPtr exposed_services
,
217 const mojo::shell::CapabilityFilter
& filter
,
218 const mojo::Shell::ConnectToApplicationCallback
& callback
) {
219 proxy_
.Get()->ConnectToApplication(url
, requestor_url
, request
.Pass(),
220 exposed_services
.Pass(), filter
, callback
);
223 void MojoShellContext::ConnectToApplicationOnOwnThread(
225 const GURL
& requestor_url
,
226 mojo::InterfaceRequest
<mojo::ServiceProvider
> request
,
227 mojo::ServiceProviderPtr exposed_services
,
228 const mojo::shell::CapabilityFilter
& filter
,
229 const mojo::Shell::ConnectToApplicationCallback
& callback
) {
230 scoped_ptr
<mojo::shell::ConnectToApplicationParams
> params(
231 new mojo::shell::ConnectToApplicationParams
);
232 params
->set_originator_identity(mojo::shell::Identity(requestor_url
));
233 params
->set_originator_filter(mojo::shell::GetPermissiveCapabilityFilter());
234 params
->SetURLInfo(url
);
235 params
->set_services(request
.Pass());
236 params
->set_exposed_services(exposed_services
.Pass());
237 params
->set_filter(filter
);
238 params
->set_on_application_end(base::Bind(&base::DoNothing
));
239 params
->set_connect_callback(callback
);
240 application_manager_
->ConnectToApplication(params
.Pass());
243 GURL
MojoShellContext::ResolveMappings(const GURL
& url
) {
247 GURL
MojoShellContext::ResolveMojoURL(const GURL
& url
) {
251 bool MojoShellContext::CreateFetcher(
253 const mojo::shell::Fetcher::FetchCallback
& loader_callback
) {
257 } // namespace content