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" | |
17 #include "mojo/shell/application_instance.h" | 16 #include "mojo/shell/application_instance.h" |
18 #include "mojo/shell/content_handler_connection.h" | 17 #include "mojo/shell/content_handler_connection.h" |
19 #include "mojo/shell/fetcher.h" | 18 #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(scoped_ptr<ApplicationFetcher> fetcher) | 53 ApplicationManager::ApplicationManager( |
54 : fetcher_(fetcher.Pass()), | 54 scoped_ptr<PackageManager> package_manager) |
| 55 : package_manager_(package_manager.Pass()), |
55 content_handler_id_counter_(0u), | 56 content_handler_id_counter_(0u), |
56 weak_ptr_factory_(this) { | 57 weak_ptr_factory_(this) { |
57 fetcher_->SetApplicationManager(this); | 58 package_manager_->SetApplicationManager(this); |
58 } | 59 } |
59 | 60 |
60 ApplicationManager::~ApplicationManager() { | 61 ApplicationManager::~ApplicationManager() { |
61 URLToContentHandlerMap url_to_content_handler(url_to_content_handler_); | 62 URLToContentHandlerMap url_to_content_handler(url_to_content_handler_); |
62 for (auto& pair : url_to_content_handler) | 63 for (auto& pair : url_to_content_handler) |
63 pair.second->CloseConnection(); | 64 pair.second->CloseConnection(); |
64 TerminateShellConnections(); | 65 TerminateShellConnections(); |
65 STLDeleteValues(&url_to_loader_); | 66 STLDeleteValues(&url_to_loader_); |
66 } | 67 } |
67 | 68 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 TRACE_EVENT_SCOPE_THREAD, "original_url", | 101 TRACE_EVENT_SCOPE_THREAD, "original_url", |
101 original_url.spec()); | 102 original_url.spec()); |
102 DCHECK(original_url.is_valid()); | 103 DCHECK(original_url.is_valid()); |
103 DCHECK(original_url_request); | 104 DCHECK(original_url_request); |
104 | 105 |
105 // We need to look for running instances based on both the unresolved and | 106 // We need to look for running instances based on both the unresolved and |
106 // resolved urls. | 107 // resolved urls. |
107 if (ConnectToRunningApplication(¶ms)) | 108 if (ConnectToRunningApplication(¶ms)) |
108 return; | 109 return; |
109 | 110 |
110 GURL resolved_url = fetcher_->ResolveURL(original_url); | 111 GURL resolved_url = package_manager_->ResolveURL(original_url); |
111 params->SetURLInfo(resolved_url); | 112 params->SetURLInfo(resolved_url); |
112 if (ConnectToRunningApplication(¶ms)) | 113 if (ConnectToRunningApplication(¶ms)) |
113 return; | 114 return; |
114 | 115 |
115 // The application is not running, let's compute the parameters. | 116 // The application is not running, let's compute the parameters. |
116 // NOTE: Set URL info using |original_url_request| instead of |original_url| | 117 // NOTE: Set URL info using |original_url_request| instead of |original_url| |
117 // because it may contain more information (e.g., it is a POST request). | 118 // because it may contain more information (e.g., it is a POST request). |
118 params->SetURLInfo(original_url_request.Pass()); | 119 params->SetURLInfo(original_url_request.Pass()); |
119 ApplicationLoader* loader = GetLoaderForURL(resolved_url); | 120 ApplicationLoader* loader = GetLoaderForURL(resolved_url); |
120 if (loader) { | 121 if (loader) { |
121 ConnectToApplicationWithLoader(¶ms, resolved_url, loader); | 122 ConnectToApplicationWithLoader(¶ms, resolved_url, loader); |
122 return; | 123 return; |
123 } | 124 } |
124 | 125 |
125 original_url_request = params->TakeAppURLRequest(); | 126 original_url_request = params->TakeAppURLRequest(); |
126 auto callback = | 127 auto callback = |
127 base::Bind(&ApplicationManager::HandleFetchCallback, | 128 base::Bind(&ApplicationManager::HandleFetchCallback, |
128 weak_ptr_factory_.GetWeakPtr(), base::Passed(¶ms)); | 129 weak_ptr_factory_.GetWeakPtr(), base::Passed(¶ms)); |
129 fetcher_->FetchRequest(original_url_request.Pass(), callback); | 130 package_manager_->FetchRequest(original_url_request.Pass(), callback); |
130 } | 131 } |
131 | 132 |
132 bool ApplicationManager::ConnectToRunningApplication( | 133 bool ApplicationManager::ConnectToRunningApplication( |
133 scoped_ptr<ConnectToApplicationParams>* params) { | 134 scoped_ptr<ConnectToApplicationParams>* params) { |
134 ApplicationInstance* instance = GetApplicationInstance( | 135 ApplicationInstance* instance = GetApplicationInstance( |
135 Identity((*params)->app_url(), (*params)->qualifier())); | 136 Identity((*params)->app_url(), (*params)->qualifier())); |
136 if (!instance) | 137 if (!instance) |
137 return false; | 138 return false; |
138 | 139 |
139 instance->ConnectToClient(params->Pass()); | 140 instance->ConnectToClient(params->Pass()); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 CapabilityFilter originator_filter = params->originator_filter(); | 220 CapabilityFilter originator_filter = params->originator_filter(); |
220 CapabilityFilter filter = params->filter(); | 221 CapabilityFilter filter = params->filter(); |
221 GURL app_url = params->app_url(); | 222 GURL app_url = params->app_url(); |
222 std::string qualifier = params->qualifier(); | 223 std::string qualifier = params->qualifier(); |
223 Shell::ConnectToApplicationCallback connect_callback = | 224 Shell::ConnectToApplicationCallback connect_callback = |
224 params->connect_callback(); | 225 params->connect_callback(); |
225 params->set_connect_callback(EmptyConnectCallback()); | 226 params->set_connect_callback(EmptyConnectCallback()); |
226 ApplicationInstance* app = nullptr; | 227 ApplicationInstance* app = nullptr; |
227 InterfaceRequest<Application> request(RegisterInstance(params.Pass(), &app)); | 228 InterfaceRequest<Application> request(RegisterInstance(params.Pass(), &app)); |
228 | 229 |
229 // For resources that are loaded with content handlers, we group app instances | |
230 // by site. | |
231 | 230 |
232 // If the response begins with a #!mojo <content-handler-url>, use it. | |
233 GURL content_handler_url; | 231 GURL content_handler_url; |
234 std::string shebang; | 232 URLResponsePtr new_response; |
235 // TODO(beng): it seems like some delegate should/would want to have a say in | 233 if (package_manager_->HandleWithContentHandler(fetcher.get(), |
236 // configuring the qualifier also. | 234 app_url, |
237 bool enable_multi_process = base::CommandLine::ForCurrentProcess()->HasSwitch( | 235 blocking_pool_, |
238 switches::kEnableMultiprocess); | 236 &new_response, |
239 | 237 &content_handler_url, |
240 if (fetcher->PeekContentHandler(&shebang, &content_handler_url)) { | 238 &qualifier)) { |
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(); | |
245 LoadWithContentHandler(originator_identity, originator_filter, | 239 LoadWithContentHandler(originator_identity, originator_filter, |
246 content_handler_url, site, filter, connect_callback, | 240 content_handler_url, qualifier, filter, |
247 app, request.Pass(), response.Pass()); | 241 connect_callback, app, request.Pass(), |
248 return; | 242 new_response.Pass()); |
249 } | 243 } else { |
250 | 244 // TODO(erg): Have a better way of switching the sandbox on. For now, switch |
251 MimeTypeToURLMap::iterator iter = mime_type_to_url_.find(fetcher->MimeType()); | 245 // it on hard coded when we're using some of the sandboxable core services. |
252 if (iter != mime_type_to_url_.end()) { | 246 bool start_sandboxed = false; |
253 URLResponsePtr response(fetcher->AsURLResponse(blocking_pool_, 0)); | 247 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
254 std::string site = | 248 switches::kMojoNoSandbox)) { |
255 enable_multi_process ? response->site.To<std::string>() : std::string(); | 249 if (app_url == GURL("mojo://core_services/") && qualifier == "Core") |
256 LoadWithContentHandler(originator_identity, originator_filter, iter->second, | 250 start_sandboxed = true; |
257 site, filter, connect_callback, app, request.Pass(), | 251 else if (app_url == GURL("mojo://html_viewer/")) |
258 response.Pass()); | 252 start_sandboxed = true; |
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; | |
281 } | 253 } |
282 | 254 |
283 LoadWithContentHandler(originator_identity, originator_filter, | 255 connect_callback.Run(Shell::kInvalidContentHandlerID); |
284 alias_iter->second.first, qualifier, filter, | 256 |
285 connect_callback, app, request.Pass(), | 257 fetcher->AsPath(blocking_pool_, |
286 response.Pass()); | 258 base::Bind(&ApplicationManager::RunNativeApplication, |
287 return; | 259 weak_ptr_factory_.GetWeakPtr(), |
| 260 base::Passed(request.Pass()), start_sandboxed, |
| 261 base::Passed(fetcher.Pass()))); |
288 } | 262 } |
289 | |
290 // TODO(erg): Have a better way of switching the sandbox on. For now, switch | |
291 // it on hard coded when we're using some of the sandboxable core services. | |
292 bool start_sandboxed = false; | |
293 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | |
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; | |
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()))); | |
308 } | 263 } |
309 | 264 |
310 void ApplicationManager::RunNativeApplication( | 265 void ApplicationManager::RunNativeApplication( |
311 InterfaceRequest<Application> application_request, | 266 InterfaceRequest<Application> application_request, |
312 bool start_sandboxed, | 267 bool start_sandboxed, |
313 scoped_ptr<Fetcher> fetcher, | 268 scoped_ptr<Fetcher> fetcher, |
314 const base::FilePath& path, | 269 const base::FilePath& path, |
315 bool path_exists) { | 270 bool path_exists) { |
316 // We only passed fetcher to keep it alive. Done with it now. | 271 // We only passed fetcher to keep it alive. Done with it now. |
317 fetcher.reset(); | 272 fetcher.reset(); |
318 | 273 |
319 DCHECK(application_request.is_pending()); | 274 DCHECK(application_request.is_pending()); |
320 | 275 |
321 if (!path_exists) { | 276 if (!path_exists) { |
322 LOG(ERROR) << "Library not started because library path '" << path.value() | 277 LOG(ERROR) << "Library not started because library path '" << path.value() |
323 << "' does not exist."; | 278 << "' does not exist."; |
324 return; | 279 return; |
325 } | 280 } |
326 | 281 |
327 TRACE_EVENT1("mojo_shell", "ApplicationManager::RunNativeApplication", "path", | 282 TRACE_EVENT1("mojo_shell", "ApplicationManager::RunNativeApplication", "path", |
328 path.AsUTF8Unsafe()); | 283 path.AsUTF8Unsafe()); |
329 NativeRunner* runner = native_runner_factory_->Create().release(); | 284 NativeRunner* runner = native_runner_factory_->Create().release(); |
330 native_runners_.push_back(runner); | 285 native_runners_.push_back(runner); |
331 runner->Start(path, start_sandboxed, application_request.Pass(), | 286 runner->Start(path, start_sandboxed, application_request.Pass(), |
332 base::Bind(&ApplicationManager::CleanupRunner, | 287 base::Bind(&ApplicationManager::CleanupRunner, |
333 weak_ptr_factory_.GetWeakPtr(), runner)); | 288 weak_ptr_factory_.GetWeakPtr(), runner)); |
334 } | 289 } |
335 | 290 |
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 | |
352 void ApplicationManager::LoadWithContentHandler( | 291 void ApplicationManager::LoadWithContentHandler( |
353 const Identity& originator_identity, | 292 const Identity& originator_identity, |
354 const CapabilityFilter& originator_filter, | 293 const CapabilityFilter& originator_filter, |
355 const GURL& content_handler_url, | 294 const GURL& content_handler_url, |
356 const std::string& qualifier, | 295 const std::string& qualifier, |
357 const CapabilityFilter& filter, | 296 const CapabilityFilter& filter, |
358 const Shell::ConnectToApplicationCallback& connect_callback, | 297 const Shell::ConnectToApplicationCallback& connect_callback, |
359 ApplicationInstance* app, | 298 ApplicationInstance* app, |
360 InterfaceRequest<Application> application_request, | 299 InterfaceRequest<Application> application_request, |
361 URLResponsePtr url_response) { | 300 URLResponsePtr url_response) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 services->ConnectToService(interface_name, pipe.handle1.Pass()); | 375 services->ConnectToService(interface_name, pipe.handle1.Pass()); |
437 return pipe.handle0.Pass(); | 376 return pipe.handle0.Pass(); |
438 } | 377 } |
439 | 378 |
440 Shell::ConnectToApplicationCallback EmptyConnectCallback() { | 379 Shell::ConnectToApplicationCallback EmptyConnectCallback() { |
441 return base::Bind(&OnEmptyOnConnectCallback); | 380 return base::Bind(&OnEmptyOnConnectCallback); |
442 } | 381 } |
443 | 382 |
444 } // namespace shell | 383 } // namespace shell |
445 } // namespace mojo | 384 } // namespace mojo |
OLD | NEW |