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/path_service.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "content/common/process_control.mojom.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/content_browser_client.h"
15 #include "content/public/browser/utility_process_host.h"
16 #include "content/public/browser/utility_process_host_client.h"
17 #include "content/public/common/content_client.h"
18 #include "content/public/common/service_registry.h"
19 #include "mojo/application/public/cpp/application_delegate.h"
20 #include "mojo/common/url_type_converters.h"
21 #include "mojo/package_manager/package_manager_impl.h"
22 #include "mojo/shell/application_loader.h"
23 #include "mojo/shell/connect_to_application_params.h"
24 #include "mojo/shell/identity.h"
25 #include "mojo/shell/static_application_loader.h"
26 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
27 #include "third_party/mojo/src/mojo/public/cpp/bindings/string.h"
29 #if defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
30 #include "media/mojo/services/mojo_media_application.h"
37 // An extra set of apps to register on initialization, if set by a test.
38 const MojoShellContext::StaticApplicationMap
* g_applications_for_test
;
40 void StartProcessOnIOThread(mojo::InterfaceRequest
<ProcessControl
> request
,
41 const base::string16
& process_name
,
43 UtilityProcessHost
* process_host
=
44 UtilityProcessHost::Create(nullptr, nullptr);
45 process_host
->SetName(process_name
);
47 process_host
->DisableSandbox();
48 process_host
->StartMojoMode();
50 ServiceRegistry
* services
= process_host
->GetServiceRegistry();
51 services
->ConnectToRemoteService(request
.Pass());
54 void OnApplicationLoaded(const GURL
& url
, bool success
) {
56 LOG(ERROR
) << "Failed to launch Mojo application for " << url
.spec();
59 // The default loader to use for all applications. This does nothing but drop
60 // the Application request.
61 class DefaultApplicationLoader
: public mojo::shell::ApplicationLoader
{
63 DefaultApplicationLoader() {}
64 ~DefaultApplicationLoader() override
{}
67 // mojo::shell::ApplicationLoader:
70 mojo::InterfaceRequest
<mojo::Application
> application_request
) override
{}
72 DISALLOW_COPY_AND_ASSIGN(DefaultApplicationLoader
);
75 // This launches a utility process and forwards the Load request the
76 // ProcessControl service there. The utility process is sandboxed iff
77 // |use_sandbox| is true.
78 class UtilityProcessLoader
: public mojo::shell::ApplicationLoader
{
80 UtilityProcessLoader(const base::string16
& process_name
, bool use_sandbox
)
81 : process_name_(process_name
), use_sandbox_(use_sandbox
) {}
82 ~UtilityProcessLoader() override
{}
85 // mojo::shell::ApplicationLoader:
88 mojo::InterfaceRequest
<mojo::Application
> application_request
) override
{
89 ProcessControlPtr process_control
;
90 auto process_request
= mojo::GetProxy(&process_control
);
91 BrowserThread::PostTask(
92 BrowserThread::IO
, FROM_HERE
,
93 base::Bind(&StartProcessOnIOThread
, base::Passed(&process_request
),
94 process_name_
, use_sandbox_
));
95 process_control
->LoadApplication(url
.spec(), application_request
.Pass(),
96 base::Bind(&OnApplicationLoaded
, url
));
99 const base::string16 process_name_
;
100 const bool use_sandbox_
;
102 DISALLOW_COPY_AND_ASSIGN(UtilityProcessLoader
);
107 // Thread-safe proxy providing access to the shell context from any thread.
108 class MojoShellContext::Proxy
{
110 Proxy(MojoShellContext
* shell_context
)
111 : shell_context_(shell_context
),
112 task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
116 void ConnectToApplication(
118 const GURL
& requestor_url
,
119 mojo::InterfaceRequest
<mojo::ServiceProvider
> request
,
120 mojo::ServiceProviderPtr exposed_services
,
121 const mojo::shell::CapabilityFilter
& filter
,
122 const mojo::Shell::ConnectToApplicationCallback
& callback
) {
123 if (task_runner_
== base::ThreadTaskRunnerHandle::Get()) {
124 if (shell_context_
) {
125 shell_context_
->ConnectToApplicationOnOwnThread(
126 url
, requestor_url
, request
.Pass(), exposed_services
.Pass(), filter
,
130 // |shell_context_| outlives the main MessageLoop, so it's safe for it to
131 // be unretained here.
132 task_runner_
->PostTask(
134 base::Bind(&MojoShellContext::ConnectToApplicationOnOwnThread
,
135 base::Unretained(shell_context_
), url
, requestor_url
,
136 base::Passed(&request
), base::Passed(&exposed_services
),
142 MojoShellContext
* shell_context_
;
143 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
145 DISALLOW_COPY_AND_ASSIGN(Proxy
);
149 base::LazyInstance
<scoped_ptr
<MojoShellContext::Proxy
>>
150 MojoShellContext::proxy_
= LAZY_INSTANCE_INITIALIZER
;
152 void MojoShellContext::SetApplicationsForTest(
153 const StaticApplicationMap
* apps
) {
154 g_applications_for_test
= apps
;
157 MojoShellContext::MojoShellContext() {
158 proxy_
.Get().reset(new Proxy(this));
160 // Construct with an empty filepath since mojo: urls can't be registered now
161 // the url scheme registry is locked.
162 scoped_ptr
<mojo::package_manager::PackageManagerImpl
> package_manager(
163 new mojo::package_manager::PackageManagerImpl(base::FilePath()));
164 application_manager_
.reset(
165 new mojo::shell::ApplicationManager(package_manager
.Pass()));
167 application_manager_
->set_default_loader(
168 scoped_ptr
<mojo::shell::ApplicationLoader
>(new DefaultApplicationLoader
));
170 StaticApplicationMap apps
;
171 GetContentClient()->browser()->RegisterInProcessMojoApplications(&apps
);
172 if (g_applications_for_test
) {
173 // Add testing apps to the map, potentially overwriting whatever the
174 // browser client registered.
175 for (const auto& entry
: *g_applications_for_test
)
176 apps
[entry
.first
] = entry
.second
;
178 for (const auto& entry
: apps
) {
179 application_manager_
->SetLoaderForURL(
180 scoped_ptr
<mojo::shell::ApplicationLoader
>(
181 new mojo::shell::StaticApplicationLoader(entry
.second
)),
185 ContentBrowserClient::OutOfProcessMojoApplicationMap sandboxed_apps
;
188 ->RegisterOutOfProcessMojoApplications(&sandboxed_apps
);
189 for (const auto& app
: sandboxed_apps
) {
190 application_manager_
->SetLoaderForURL(
191 scoped_ptr
<mojo::shell::ApplicationLoader
>(
192 new UtilityProcessLoader(app
.second
, true /* use_sandbox */)),
196 ContentBrowserClient::OutOfProcessMojoApplicationMap unsandboxed_apps
;
199 ->RegisterUnsandboxedOutOfProcessMojoApplications(&unsandboxed_apps
);
200 for (const auto& app
: unsandboxed_apps
) {
201 application_manager_
->SetLoaderForURL(
202 scoped_ptr
<mojo::shell::ApplicationLoader
>(
203 new UtilityProcessLoader(app
.second
, false /* use_sandbox */)),
207 #if (ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
208 application_manager_
->SetLoaderForURL(
209 scoped_ptr
<mojo::shell::ApplicationLoader
>(
210 new mojo::shell::StaticApplicationLoader(
211 base::Bind(&media::MojoMediaApplication::CreateApp
))),
212 media::MojoMediaApplication::AppUrl());
216 MojoShellContext::~MojoShellContext() {
220 void MojoShellContext::ConnectToApplication(
222 const GURL
& requestor_url
,
223 mojo::InterfaceRequest
<mojo::ServiceProvider
> request
,
224 mojo::ServiceProviderPtr exposed_services
,
225 const mojo::shell::CapabilityFilter
& filter
,
226 const mojo::Shell::ConnectToApplicationCallback
& callback
) {
227 proxy_
.Get()->ConnectToApplication(url
, requestor_url
, request
.Pass(),
228 exposed_services
.Pass(), filter
, callback
);
231 void MojoShellContext::ConnectToApplicationOnOwnThread(
233 const GURL
& requestor_url
,
234 mojo::InterfaceRequest
<mojo::ServiceProvider
> request
,
235 mojo::ServiceProviderPtr exposed_services
,
236 const mojo::shell::CapabilityFilter
& filter
,
237 const mojo::Shell::ConnectToApplicationCallback
& callback
) {
238 scoped_ptr
<mojo::shell::ConnectToApplicationParams
> params(
239 new mojo::shell::ConnectToApplicationParams
);
240 params
->set_originator_identity(mojo::shell::Identity(requestor_url
));
241 params
->set_originator_filter(mojo::shell::GetPermissiveCapabilityFilter());
242 params
->SetURLInfo(url
);
243 params
->set_services(request
.Pass());
244 params
->set_exposed_services(exposed_services
.Pass());
245 params
->set_filter(filter
);
246 params
->set_on_application_end(base::Bind(&base::DoNothing
));
247 params
->set_connect_callback(callback
);
248 application_manager_
->ConnectToApplication(params
.Pass());
251 } // namespace content