OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/shell/application_manager.h" | 5 #include "mojo/shell/application_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/macros.h" | 10 #include "base/macros.h" |
11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
13 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
14 #include "mojo/application/public/interfaces/content_handler.mojom.h" | 14 #include "mojo/application/public/interfaces/content_handler.mojom.h" |
15 #include "mojo/public/cpp/bindings/binding.h" | 15 #include "mojo/public/cpp/bindings/binding.h" |
| 16 #include "mojo/shell/application_fetcher.h" |
16 #include "mojo/shell/application_instance.h" | 17 #include "mojo/shell/application_instance.h" |
17 #include "mojo/shell/content_handler_connection.h" | 18 #include "mojo/shell/content_handler_connection.h" |
18 #include "mojo/shell/fetcher.h" | 19 #include "mojo/shell/fetcher.h" |
19 #include "mojo/shell/package_manager.h" | |
20 #include "mojo/shell/query_util.h" | 20 #include "mojo/shell/query_util.h" |
21 #include "mojo/shell/switches.h" | 21 #include "mojo/shell/switches.h" |
22 | 22 |
23 namespace mojo { | 23 namespace mojo { |
24 namespace shell { | 24 namespace shell { |
25 | 25 |
26 namespace { | 26 namespace { |
27 | 27 |
28 // Used by TestAPI. | 28 // Used by TestAPI. |
29 bool has_created_instance = false; | 29 bool has_created_instance = false; |
(...skipping 13 matching lines...) Expand all Loading... |
43 bool ApplicationManager::TestAPI::HasCreatedInstance() { | 43 bool ApplicationManager::TestAPI::HasCreatedInstance() { |
44 return has_created_instance; | 44 return has_created_instance; |
45 } | 45 } |
46 | 46 |
47 bool ApplicationManager::TestAPI::HasRunningInstanceForURL( | 47 bool ApplicationManager::TestAPI::HasRunningInstanceForURL( |
48 const GURL& url) const { | 48 const GURL& url) const { |
49 return manager_->identity_to_instance_.find(Identity(url)) != | 49 return manager_->identity_to_instance_.find(Identity(url)) != |
50 manager_->identity_to_instance_.end(); | 50 manager_->identity_to_instance_.end(); |
51 } | 51 } |
52 | 52 |
53 ApplicationManager::ApplicationManager( | 53 ApplicationManager::ApplicationManager(scoped_ptr<ApplicationFetcher> fetcher) |
54 scoped_ptr<PackageManager> package_manager) | 54 : fetcher_(fetcher.Pass()), |
55 : package_manager_(package_manager.Pass()), | |
56 content_handler_id_counter_(0u), | 55 content_handler_id_counter_(0u), |
57 weak_ptr_factory_(this) { | 56 weak_ptr_factory_(this) { |
58 package_manager_->SetApplicationManager(this); | 57 fetcher_->SetApplicationManager(this); |
59 } | 58 } |
60 | 59 |
61 ApplicationManager::~ApplicationManager() { | 60 ApplicationManager::~ApplicationManager() { |
62 URLToContentHandlerMap url_to_content_handler(url_to_content_handler_); | 61 URLToContentHandlerMap url_to_content_handler(url_to_content_handler_); |
63 for (auto& pair : url_to_content_handler) | 62 for (auto& pair : url_to_content_handler) |
64 pair.second->CloseConnection(); | 63 pair.second->CloseConnection(); |
65 TerminateShellConnections(); | 64 TerminateShellConnections(); |
66 STLDeleteValues(&url_to_loader_); | 65 STLDeleteValues(&url_to_loader_); |
67 } | 66 } |
68 | 67 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 TRACE_EVENT_SCOPE_THREAD, "original_url", | 100 TRACE_EVENT_SCOPE_THREAD, "original_url", |
102 original_url.spec()); | 101 original_url.spec()); |
103 DCHECK(original_url.is_valid()); | 102 DCHECK(original_url.is_valid()); |
104 DCHECK(original_url_request); | 103 DCHECK(original_url_request); |
105 | 104 |
106 // We need to look for running instances based on both the unresolved and | 105 // We need to look for running instances based on both the unresolved and |
107 // resolved urls. | 106 // resolved urls. |
108 if (ConnectToRunningApplication(¶ms)) | 107 if (ConnectToRunningApplication(¶ms)) |
109 return; | 108 return; |
110 | 109 |
111 GURL resolved_url = package_manager_->ResolveURL(original_url); | 110 GURL resolved_url = fetcher_->ResolveURL(original_url); |
112 params->SetURLInfo(resolved_url); | 111 params->SetURLInfo(resolved_url); |
113 if (ConnectToRunningApplication(¶ms)) | 112 if (ConnectToRunningApplication(¶ms)) |
114 return; | 113 return; |
115 | 114 |
116 // The application is not running, let's compute the parameters. | 115 // The application is not running, let's compute the parameters. |
117 // NOTE: Set URL info using |original_url_request| instead of |original_url| | 116 // NOTE: Set URL info using |original_url_request| instead of |original_url| |
118 // because it may contain more information (e.g., it is a POST request). | 117 // because it may contain more information (e.g., it is a POST request). |
119 params->SetURLInfo(original_url_request.Pass()); | 118 params->SetURLInfo(original_url_request.Pass()); |
120 ApplicationLoader* loader = GetLoaderForURL(resolved_url); | 119 ApplicationLoader* loader = GetLoaderForURL(resolved_url); |
121 if (loader) { | 120 if (loader) { |
122 ConnectToApplicationWithLoader(¶ms, resolved_url, loader); | 121 ConnectToApplicationWithLoader(¶ms, resolved_url, loader); |
123 return; | 122 return; |
124 } | 123 } |
125 | 124 |
126 original_url_request = params->TakeAppURLRequest(); | 125 original_url_request = params->TakeAppURLRequest(); |
127 auto callback = | 126 auto callback = |
128 base::Bind(&ApplicationManager::HandleFetchCallback, | 127 base::Bind(&ApplicationManager::HandleFetchCallback, |
129 weak_ptr_factory_.GetWeakPtr(), base::Passed(¶ms)); | 128 weak_ptr_factory_.GetWeakPtr(), base::Passed(¶ms)); |
130 package_manager_->FetchRequest(original_url_request.Pass(), callback); | 129 fetcher_->FetchRequest(original_url_request.Pass(), callback); |
131 } | 130 } |
132 | 131 |
133 bool ApplicationManager::ConnectToRunningApplication( | 132 bool ApplicationManager::ConnectToRunningApplication( |
134 scoped_ptr<ConnectToApplicationParams>* params) { | 133 scoped_ptr<ConnectToApplicationParams>* params) { |
135 ApplicationInstance* instance = GetApplicationInstance( | 134 ApplicationInstance* instance = GetApplicationInstance( |
136 Identity((*params)->app_url(), (*params)->qualifier())); | 135 Identity((*params)->app_url(), (*params)->qualifier())); |
137 if (!instance) | 136 if (!instance) |
138 return false; | 137 return false; |
139 | 138 |
140 instance->ConnectToClient(params->Pass()); | 139 instance->ConnectToClient(params->Pass()); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 CapabilityFilter originator_filter = params->originator_filter(); | 219 CapabilityFilter originator_filter = params->originator_filter(); |
221 CapabilityFilter filter = params->filter(); | 220 CapabilityFilter filter = params->filter(); |
222 GURL app_url = params->app_url(); | 221 GURL app_url = params->app_url(); |
223 std::string qualifier = params->qualifier(); | 222 std::string qualifier = params->qualifier(); |
224 Shell::ConnectToApplicationCallback connect_callback = | 223 Shell::ConnectToApplicationCallback connect_callback = |
225 params->connect_callback(); | 224 params->connect_callback(); |
226 params->set_connect_callback(EmptyConnectCallback()); | 225 params->set_connect_callback(EmptyConnectCallback()); |
227 ApplicationInstance* app = nullptr; | 226 ApplicationInstance* app = nullptr; |
228 InterfaceRequest<Application> request(RegisterInstance(params.Pass(), &app)); | 227 InterfaceRequest<Application> request(RegisterInstance(params.Pass(), &app)); |
229 | 228 |
| 229 // For resources that are loaded with content handlers, we group app instances |
| 230 // by site. |
230 | 231 |
| 232 // If the response begins with a #!mojo <content-handler-url>, use it. |
231 GURL content_handler_url; | 233 GURL content_handler_url; |
232 URLResponsePtr new_response; | 234 std::string shebang; |
233 if (package_manager_->HandleWithContentHandler(fetcher.get(), | 235 // TODO(beng): it seems like some delegate should/would want to have a say in |
234 app_url, | 236 // configuring the qualifier also. |
235 blocking_pool_, | 237 bool enable_multi_process = base::CommandLine::ForCurrentProcess()->HasSwitch( |
236 &new_response, | 238 switches::kEnableMultiprocess); |
237 &content_handler_url, | 239 |
238 &qualifier)) { | 240 if (fetcher->PeekContentHandler(&shebang, &content_handler_url)) { |
| 241 URLResponsePtr response(fetcher->AsURLResponse( |
| 242 blocking_pool_, static_cast<int>(shebang.size()))); |
| 243 std::string site = |
| 244 enable_multi_process ? response->site.To<std::string>() : std::string(); |
239 LoadWithContentHandler(originator_identity, originator_filter, | 245 LoadWithContentHandler(originator_identity, originator_filter, |
240 content_handler_url, qualifier, filter, | 246 content_handler_url, site, filter, connect_callback, |
241 connect_callback, app, request.Pass(), | 247 app, request.Pass(), response.Pass()); |
242 new_response.Pass()); | 248 return; |
243 } else { | 249 } |
244 // TODO(erg): Have a better way of switching the sandbox on. For now, switch | 250 |
245 // it on hard coded when we're using some of the sandboxable core services. | 251 MimeTypeToURLMap::iterator iter = mime_type_to_url_.find(fetcher->MimeType()); |
246 bool start_sandboxed = false; | 252 if (iter != mime_type_to_url_.end()) { |
247 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | 253 URLResponsePtr response(fetcher->AsURLResponse(blocking_pool_, 0)); |
248 switches::kMojoNoSandbox)) { | 254 std::string site = |
249 if (app_url == GURL("mojo://core_services/") && qualifier == "Core") | 255 enable_multi_process ? response->site.To<std::string>() : std::string(); |
250 start_sandboxed = true; | 256 LoadWithContentHandler(originator_identity, originator_filter, iter->second, |
251 else if (app_url == GURL("mojo://html_viewer/")) | 257 site, filter, connect_callback, app, request.Pass(), |
252 start_sandboxed = true; | 258 response.Pass()); |
| 259 return; |
| 260 } |
| 261 |
| 262 auto alias_iter = application_package_alias_.find(app_url); |
| 263 if (alias_iter != application_package_alias_.end()) { |
| 264 // We replace the qualifier with the one our package alias requested. |
| 265 URLResponsePtr response(URLResponse::New()); |
| 266 response->url = app_url.spec(); |
| 267 |
| 268 std::string qualifier; |
| 269 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 270 switches::kEnableMultiprocess)) { |
| 271 // Why can't we use this in single process mode? Because of |
| 272 // base::AtExitManager. If you link in ApplicationRunner into |
| 273 // your code, and then we make initialize multiple copies of the |
| 274 // application, we end up with multiple AtExitManagers and will check on |
| 275 // the second one being created. |
| 276 // |
| 277 // Why doesn't that happen when running different apps? Because |
| 278 // your_thing.mojo!base::AtExitManager and |
| 279 // my_thing.mojo!base::AtExitManager are different symbols. |
| 280 qualifier = alias_iter->second.second; |
253 } | 281 } |
254 | 282 |
255 connect_callback.Run(Shell::kInvalidContentHandlerID); | 283 LoadWithContentHandler(originator_identity, originator_filter, |
| 284 alias_iter->second.first, qualifier, filter, |
| 285 connect_callback, app, request.Pass(), |
| 286 response.Pass()); |
| 287 return; |
| 288 } |
256 | 289 |
257 fetcher->AsPath(blocking_pool_, | 290 // TODO(erg): Have a better way of switching the sandbox on. For now, switch |
258 base::Bind(&ApplicationManager::RunNativeApplication, | 291 // it on hard coded when we're using some of the sandboxable core services. |
259 weak_ptr_factory_.GetWeakPtr(), | 292 bool start_sandboxed = false; |
260 base::Passed(request.Pass()), start_sandboxed, | 293 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
261 base::Passed(fetcher.Pass()))); | 294 switches::kMojoNoSandbox)) { |
| 295 if (app_url == GURL("mojo://core_services/") && qualifier == "Core") |
| 296 start_sandboxed = true; |
| 297 else if (app_url == GURL("mojo://html_viewer/")) |
| 298 start_sandboxed = true; |
262 } | 299 } |
| 300 |
| 301 connect_callback.Run(Shell::kInvalidContentHandlerID); |
| 302 |
| 303 fetcher->AsPath(blocking_pool_, |
| 304 base::Bind(&ApplicationManager::RunNativeApplication, |
| 305 weak_ptr_factory_.GetWeakPtr(), |
| 306 base::Passed(request.Pass()), start_sandboxed, |
| 307 base::Passed(fetcher.Pass()))); |
263 } | 308 } |
264 | 309 |
265 void ApplicationManager::RunNativeApplication( | 310 void ApplicationManager::RunNativeApplication( |
266 InterfaceRequest<Application> application_request, | 311 InterfaceRequest<Application> application_request, |
267 bool start_sandboxed, | 312 bool start_sandboxed, |
268 scoped_ptr<Fetcher> fetcher, | 313 scoped_ptr<Fetcher> fetcher, |
269 const base::FilePath& path, | 314 const base::FilePath& path, |
270 bool path_exists) { | 315 bool path_exists) { |
271 // We only passed fetcher to keep it alive. Done with it now. | 316 // We only passed fetcher to keep it alive. Done with it now. |
272 fetcher.reset(); | 317 fetcher.reset(); |
273 | 318 |
274 DCHECK(application_request.is_pending()); | 319 DCHECK(application_request.is_pending()); |
275 | 320 |
276 if (!path_exists) { | 321 if (!path_exists) { |
277 LOG(ERROR) << "Library not started because library path '" << path.value() | 322 LOG(ERROR) << "Library not started because library path '" << path.value() |
278 << "' does not exist."; | 323 << "' does not exist."; |
279 return; | 324 return; |
280 } | 325 } |
281 | 326 |
282 TRACE_EVENT1("mojo_shell", "ApplicationManager::RunNativeApplication", "path", | 327 TRACE_EVENT1("mojo_shell", "ApplicationManager::RunNativeApplication", "path", |
283 path.AsUTF8Unsafe()); | 328 path.AsUTF8Unsafe()); |
284 NativeRunner* runner = native_runner_factory_->Create().release(); | 329 NativeRunner* runner = native_runner_factory_->Create().release(); |
285 native_runners_.push_back(runner); | 330 native_runners_.push_back(runner); |
286 runner->Start(path, start_sandboxed, application_request.Pass(), | 331 runner->Start(path, start_sandboxed, application_request.Pass(), |
287 base::Bind(&ApplicationManager::CleanupRunner, | 332 base::Bind(&ApplicationManager::CleanupRunner, |
288 weak_ptr_factory_.GetWeakPtr(), runner)); | 333 weak_ptr_factory_.GetWeakPtr(), runner)); |
289 } | 334 } |
290 | 335 |
| 336 void ApplicationManager::RegisterContentHandler( |
| 337 const std::string& mime_type, |
| 338 const GURL& content_handler_url) { |
| 339 DCHECK(content_handler_url.is_valid()) |
| 340 << "Content handler URL is invalid for mime type " << mime_type; |
| 341 mime_type_to_url_[mime_type] = content_handler_url; |
| 342 } |
| 343 |
| 344 void ApplicationManager::RegisterApplicationPackageAlias( |
| 345 const GURL& alias, |
| 346 const GURL& content_handler_package, |
| 347 const std::string& qualifier) { |
| 348 application_package_alias_[alias] = |
| 349 std::make_pair(content_handler_package, qualifier); |
| 350 } |
| 351 |
291 void ApplicationManager::LoadWithContentHandler( | 352 void ApplicationManager::LoadWithContentHandler( |
292 const Identity& originator_identity, | 353 const Identity& originator_identity, |
293 const CapabilityFilter& originator_filter, | 354 const CapabilityFilter& originator_filter, |
294 const GURL& content_handler_url, | 355 const GURL& content_handler_url, |
295 const std::string& qualifier, | 356 const std::string& qualifier, |
296 const CapabilityFilter& filter, | 357 const CapabilityFilter& filter, |
297 const Shell::ConnectToApplicationCallback& connect_callback, | 358 const Shell::ConnectToApplicationCallback& connect_callback, |
298 ApplicationInstance* app, | 359 ApplicationInstance* app, |
299 InterfaceRequest<Application> application_request, | 360 InterfaceRequest<Application> application_request, |
300 URLResponsePtr url_response) { | 361 URLResponsePtr url_response) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 services->ConnectToService(interface_name, pipe.handle1.Pass()); | 436 services->ConnectToService(interface_name, pipe.handle1.Pass()); |
376 return pipe.handle0.Pass(); | 437 return pipe.handle0.Pass(); |
377 } | 438 } |
378 | 439 |
379 Shell::ConnectToApplicationCallback EmptyConnectCallback() { | 440 Shell::ConnectToApplicationCallback EmptyConnectCallback() { |
380 return base::Bind(&OnEmptyOnConnectCallback); | 441 return base::Bind(&OnEmptyOnConnectCallback); |
381 } | 442 } |
382 | 443 |
383 } // namespace shell | 444 } // namespace shell |
384 } // namespace mojo | 445 } // namespace mojo |
OLD | NEW |