1 // Copyright 2014 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 "mojo/application_manager/application_manager.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/stl_util.h"
14 #include "mojo/application_manager/application_loader.h"
15 #include "mojo/common/common_type_converters.h"
16 #include "mojo/public/cpp/application/connect.h"
17 #include "mojo/public/interfaces/application/application.mojom.h"
18 #include "mojo/public/interfaces/application/shell.mojom.h"
19 #include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h"
25 bool has_created_instance
= false;
27 class StubServiceProvider
: public InterfaceImpl
<ServiceProvider
> {
29 ServiceProvider
* GetRemoteServiceProvider() { return client(); }
32 virtual void ConnectToService(const String
& service_name
,
33 ScopedMessagePipeHandle client_handle
)
39 ApplicationManager::Delegate::~Delegate() {}
41 class ApplicationManager::LoadCallbacksImpl
42 : public ApplicationLoader::LoadCallbacks
{
44 LoadCallbacksImpl(base::WeakPtr
<ApplicationManager
> manager
,
45 const GURL
& requested_url
,
46 const GURL
& requestor_url
,
47 ServiceProviderPtr service_provider
)
49 requested_url_(requested_url
),
50 requestor_url_(requestor_url
),
51 service_provider_(service_provider
.Pass()) {}
54 virtual ~LoadCallbacksImpl() {}
56 // LoadCallbacks implementation
57 virtual ScopedMessagePipeHandle
RegisterApplication() OVERRIDE
{
58 ScopedMessagePipeHandle shell_handle
;
60 manager_
->RegisterLoadedApplication(requested_url_
,
62 service_provider_
.Pass(),
65 return shell_handle
.Pass();
68 virtual void LoadWithContentHandler(const GURL
& content_handler_url
,
69 URLResponsePtr url_response
) OVERRIDE
{
71 manager_
->LoadWithContentHandler(requested_url_
,
75 service_provider_
.Pass());
79 base::WeakPtr
<ApplicationManager
> manager_
;
82 ServiceProviderPtr service_provider_
;
85 class ApplicationManager::ShellImpl
: public InterfaceImpl
<Shell
> {
87 ShellImpl(ApplicationManager
* manager
, const GURL
& url
)
88 : manager_(manager
), url_(url
) {}
90 virtual ~ShellImpl() {}
92 void ConnectToClient(const GURL
& requestor_url
,
93 ServiceProviderPtr service_provider
) {
94 client()->AcceptConnection(String::From(requestor_url
),
95 service_provider
.Pass());
98 // ServiceProvider implementation:
99 virtual void ConnectToApplication(
100 const String
& app_url
,
101 InterfaceRequest
<ServiceProvider
> in_service_provider
) OVERRIDE
{
102 ServiceProviderPtr out_service_provider
;
103 out_service_provider
.Bind(in_service_provider
.PassMessagePipe());
104 manager_
->ConnectToApplication(
105 app_url
.To
<GURL
>(), url_
, out_service_provider
.Pass());
108 const GURL
& url() const { return url_
; }
111 virtual void OnConnectionError() OVERRIDE
{
112 manager_
->OnShellImplError(this);
115 ApplicationManager
* const manager_
;
118 DISALLOW_COPY_AND_ASSIGN(ShellImpl
);
121 struct ApplicationManager::ContentHandlerConnection
{
122 ContentHandlerConnection(ApplicationManager
* manager
,
123 const GURL
& content_handler_url
) {
124 ServiceProviderPtr service_provider
;
125 BindToProxy(&service_provider_impl
, &service_provider
);
126 manager
->ConnectToApplication(
127 content_handler_url
, GURL(), service_provider
.Pass());
128 mojo::ConnectToService(service_provider_impl
.client(), &content_handler
);
131 StubServiceProvider service_provider_impl
;
132 ContentHandlerPtr content_handler
;
136 ApplicationManager::TestAPI::TestAPI(ApplicationManager
* manager
)
137 : manager_(manager
) {
140 ApplicationManager::TestAPI::~TestAPI() {
143 bool ApplicationManager::TestAPI::HasCreatedInstance() {
144 return has_created_instance
;
147 bool ApplicationManager::TestAPI::HasFactoryForURL(const GURL
& url
) const {
148 return manager_
->url_to_shell_impl_
.find(url
) !=
149 manager_
->url_to_shell_impl_
.end();
152 ApplicationManager::ApplicationManager()
155 weak_ptr_factory_(this) {
158 ApplicationManager::~ApplicationManager() {
159 STLDeleteValues(&url_to_content_handler_
);
160 TerminateShellConnections();
161 STLDeleteValues(&url_to_loader_
);
162 STLDeleteValues(&scheme_to_loader_
);
165 void ApplicationManager::TerminateShellConnections() {
166 STLDeleteValues(&url_to_shell_impl_
);
170 ApplicationManager
* ApplicationManager::GetInstance() {
171 static base::LazyInstance
<ApplicationManager
> instance
=
172 LAZY_INSTANCE_INITIALIZER
;
173 has_created_instance
= true;
174 return &instance
.Get();
177 void ApplicationManager::ConnectToApplication(
179 const GURL
& requestor_url
,
180 ServiceProviderPtr service_provider
) {
181 URLToShellImplMap::const_iterator shell_it
= url_to_shell_impl_
.find(url
);
182 if (shell_it
!= url_to_shell_impl_
.end()) {
184 shell_it
->second
, url
, requestor_url
, service_provider
.Pass());
188 scoped_refptr
<LoadCallbacksImpl
> callbacks(
189 new LoadCallbacksImpl(weak_ptr_factory_
.GetWeakPtr(),
192 service_provider
.Pass()));
193 GetLoaderForURL(url
)->Load(this, url
, callbacks
);
196 void ApplicationManager::ConnectToClient(ShellImpl
* shell_impl
,
198 const GURL
& requestor_url
,
199 ServiceProviderPtr service_provider
) {
201 shell_impl
->ConnectToClient(
203 interceptor_
->OnConnectToClient(url
, service_provider
.Pass()));
205 shell_impl
->ConnectToClient(requestor_url
, service_provider
.Pass());
209 void ApplicationManager::RegisterLoadedApplication(
211 const GURL
& requestor_url
,
212 ServiceProviderPtr service_provider
,
213 ScopedMessagePipeHandle
* shell_handle
) {
214 ShellImpl
* shell_impl
= NULL
;
215 URLToShellImplMap::iterator iter
= url_to_shell_impl_
.find(url
);
216 if (iter
!= url_to_shell_impl_
.end()) {
217 // This can happen because services are loaded asynchronously. So if we get
218 // two requests for the same service close to each other, we might get here
219 // and find that we already have it.
220 shell_impl
= iter
->second
;
223 shell_impl
= WeakBindToPipe(new ShellImpl(this, url
), pipe
.handle1
.Pass());
224 url_to_shell_impl_
[url
] = shell_impl
;
225 *shell_handle
= pipe
.handle0
.Pass();
228 ConnectToClient(shell_impl
, url
, requestor_url
, service_provider
.Pass());
231 void ApplicationManager::LoadWithContentHandler(
232 const GURL
& content_url
,
233 const GURL
& requestor_url
,
234 const GURL
& content_handler_url
,
235 URLResponsePtr url_response
,
236 ServiceProviderPtr service_provider
) {
237 ContentHandlerConnection
* connection
= NULL
;
238 URLToContentHandlerMap::iterator iter
=
239 url_to_content_handler_
.find(content_handler_url
);
240 if (iter
!= url_to_content_handler_
.end()) {
241 connection
= iter
->second
;
243 connection
= new ContentHandlerConnection(this, content_handler_url
);
244 url_to_content_handler_
[content_handler_url
] = connection
;
247 InterfaceRequest
<ServiceProvider
> spir
;
248 spir
.Bind(service_provider
.PassMessagePipe());
249 connection
->content_handler
->OnConnect(
250 content_url
.spec(), url_response
.Pass(), spir
.Pass());
253 void ApplicationManager::SetLoaderForURL(scoped_ptr
<ApplicationLoader
> loader
,
255 URLToLoaderMap::iterator it
= url_to_loader_
.find(url
);
256 if (it
!= url_to_loader_
.end())
258 url_to_loader_
[url
] = loader
.release();
261 void ApplicationManager::SetLoaderForScheme(
262 scoped_ptr
<ApplicationLoader
> loader
,
263 const std::string
& scheme
) {
264 SchemeToLoaderMap::iterator it
= scheme_to_loader_
.find(scheme
);
265 if (it
!= scheme_to_loader_
.end())
267 scheme_to_loader_
[scheme
] = loader
.release();
270 void ApplicationManager::SetInterceptor(Interceptor
* interceptor
) {
271 interceptor_
= interceptor
;
274 ApplicationLoader
* ApplicationManager::GetLoaderForURL(const GURL
& url
) {
275 URLToLoaderMap::const_iterator url_it
= url_to_loader_
.find(url
);
276 if (url_it
!= url_to_loader_
.end())
277 return url_it
->second
;
278 SchemeToLoaderMap::const_iterator scheme_it
=
279 scheme_to_loader_
.find(url
.scheme());
280 if (scheme_it
!= scheme_to_loader_
.end())
281 return scheme_it
->second
;
282 return default_loader_
.get();
285 void ApplicationManager::OnShellImplError(ShellImpl
* shell_impl
) {
286 // Called from ~ShellImpl, so we do not need to call Destroy here.
287 const GURL url
= shell_impl
->url();
288 URLToShellImplMap::iterator it
= url_to_shell_impl_
.find(url
);
289 DCHECK(it
!= url_to_shell_impl_
.end());
291 url_to_shell_impl_
.erase(it
);
292 ApplicationLoader
* loader
= GetLoaderForURL(url
);
294 loader
->OnApplicationError(this, url
);
296 delegate_
->OnApplicationError(url
);
299 ScopedMessagePipeHandle
ApplicationManager::ConnectToServiceByName(
300 const GURL
& application_url
,
301 const std::string
& interface_name
) {
302 StubServiceProvider
* stub_sp
= new StubServiceProvider
;
303 ServiceProviderPtr spp
;
304 BindToProxy(stub_sp
, &spp
);
305 ConnectToApplication(application_url
, GURL(), spp
.Pass());
307 stub_sp
->GetRemoteServiceProvider()->ConnectToService(interface_name
,
308 pipe
.handle1
.Pass());
309 return pipe
.handle0
.Pass();