Index: mojo/shell/dynamic_application_loader.cc |
diff --git a/mojo/shell/dynamic_application_loader.cc b/mojo/shell/dynamic_application_loader.cc |
index 718ece4263714b9f81fd388f3b683eb554efaf84..a5fa0e7d94be870c29bfe6f06463e7070ead4f5b 100644 |
--- a/mojo/shell/dynamic_application_loader.cc |
+++ b/mojo/shell/dynamic_application_loader.cc |
@@ -9,6 +9,7 @@ |
#include "base/file_util.h" |
#include "base/files/file_path.h" |
#include "base/memory/scoped_ptr.h" |
+#include "base/memory/weak_ptr.h" |
#include "base/message_loop/message_loop.h" |
#include "mojo/common/common_type_converters.h" |
#include "mojo/common/data_pipe_utils.h" |
@@ -20,12 +21,175 @@ |
namespace mojo { |
namespace shell { |
+// Encapsulates loading and running one individual application. |
+// |
+// Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must |
+// ensure that all the parameters passed to Loader subclasses stay valid through |
+// Loader's lifetime. |
+// |
+// Async operations are done with WeakPtr to protect against |
+// DynamicApplicationLoader going away (and taking all the Loaders with it) |
+// while the async operation is outstanding. |
+class DynamicApplicationLoader::Loader { |
+ public: |
+ Loader(Context* context, |
+ DynamicServiceRunnerFactory* runner_factory, |
+ scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, |
+ const LoaderCompleteCallback& loader_complete_callback) |
+ : load_callbacks_(load_callbacks), |
+ loader_complete_callback_(loader_complete_callback), |
+ context_(context), |
+ runner_factory_(runner_factory), |
+ weak_ptr_factory_(this) {} |
+ |
+ virtual ~Loader() {} |
+ |
+ protected: |
+ void RunLibrary(const base::FilePath& path, bool path_exists) { |
+ ScopedMessagePipeHandle shell_handle = |
+ load_callbacks_->RegisterApplication(); |
+ if (!shell_handle.is_valid()) { |
+ LoaderComplete(); |
+ return; |
+ } |
+ |
+ if (!path_exists) { |
+ DVLOG(1) << "Library not started because library path '" << path.value() |
+ << "' does not exist."; |
+ LoaderComplete(); |
+ return; |
+ } |
+ |
+ runner_ = runner_factory_->Create(context_); |
+ runner_->Start( |
+ path, |
+ shell_handle.Pass(), |
+ base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr())); |
+ } |
+ |
+ void LoaderComplete() { loader_complete_callback_.Run(this); } |
+ |
+ scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_; |
+ LoaderCompleteCallback loader_complete_callback_; |
+ Context* context_; |
+ |
+ private: |
+ DynamicServiceRunnerFactory* runner_factory_; |
+ scoped_ptr<DynamicServiceRunner> runner_; |
+ base::WeakPtrFactory<Loader> weak_ptr_factory_; |
+}; |
+ |
+// A loader for local files. |
+class DynamicApplicationLoader::LocalLoader : public Loader { |
+ public: |
+ LocalLoader(const GURL& url, |
+ Context* context, |
+ DynamicServiceRunnerFactory* runner_factory, |
+ scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, |
+ const LoaderCompleteCallback& loader_complete_callback) |
+ : Loader(context, |
+ runner_factory, |
+ load_callbacks, |
+ loader_complete_callback), |
+ weak_ptr_factory_(this) { |
+ base::FilePath path; |
+ net::FileURLToFilePath(url, &path); |
+ |
+ // Async for consistency with network case. |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&LocalLoader::RunLibrary, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ path, |
+ base::PathExists(path))); |
+ } |
+ |
+ virtual ~LocalLoader() {} |
+ |
+ private: |
+ base::WeakPtrFactory<LocalLoader> weak_ptr_factory_; |
+}; |
+ |
+// A loader for network files. |
+class DynamicApplicationLoader::NetworkLoader : public Loader { |
+ public: |
+ NetworkLoader(const GURL& url, |
+ MimeTypeToURLMap* mime_type_to_url, |
+ Context* context, |
+ DynamicServiceRunnerFactory* runner_factory, |
+ NetworkService* network_service, |
+ scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks, |
+ const LoaderCompleteCallback& loader_complete_callback) |
+ : Loader(context, |
+ runner_factory, |
+ load_callbacks, |
+ loader_complete_callback), |
+ mime_type_to_url_(mime_type_to_url), |
+ weak_ptr_factory_(this) { |
+ URLRequestPtr request(URLRequest::New()); |
+ request->url = String::From(url); |
+ request->auto_follow_redirects = true; |
+ |
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kDisableCache)) { |
+ request->bypass_cache = true; |
+ } |
+ |
+ network_service->CreateURLLoader(Get(&url_loader_)); |
+ url_loader_->Start(request.Pass(), |
+ base::Bind(&NetworkLoader::OnLoadComplete, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ } |
+ |
+ virtual ~NetworkLoader() { |
+ if (!file_.empty()) |
+ base::DeleteFile(file_, false); |
+ } |
+ |
+ private: |
+ void OnLoadComplete(URLResponsePtr response) { |
+ if (response->error) { |
+ LOG(ERROR) << "Error (" << response->error->code << ": " |
+ << response->error->description << ") while fetching " |
+ << response->url; |
+ LoaderComplete(); |
+ return; |
+ } |
+ |
+ MimeTypeToURLMap::iterator iter = |
+ mime_type_to_url_->find(response->mime_type); |
+ if (iter != mime_type_to_url_->end()) { |
+ load_callbacks_->LoadWithContentHandler(iter->second, response.Pass()); |
+ LoaderComplete(); |
+ return; |
+ } |
+ |
+ base::CreateTemporaryFile(&file_); |
+ common::CopyToFile( |
+ response->body.Pass(), |
+ file_, |
+ context_->task_runners()->blocking_pool(), |
+ base::Bind( |
+ &NetworkLoader::RunLibrary, weak_ptr_factory_.GetWeakPtr(), file_)); |
+ } |
+ |
+ MimeTypeToURLMap* mime_type_to_url_; |
+ URLLoaderPtr url_loader_; |
+ base::FilePath file_; |
+ base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_; |
+}; |
+ |
DynamicApplicationLoader::DynamicApplicationLoader( |
Context* context, |
scoped_ptr<DynamicServiceRunnerFactory> runner_factory) |
: context_(context), |
runner_factory_(runner_factory.Pass()), |
- weak_ptr_factory_(this) { |
+ |
+ // Unretained() is correct here because DynamicApplicationLoader owns the |
+ // loaders that we pass this callback to. |
+ loader_complete_callback_( |
+ base::Bind(&DynamicApplicationLoader::LoaderComplete, |
+ base::Unretained(this))) { |
} |
DynamicApplicationLoader::~DynamicApplicationLoader() { |
@@ -37,9 +201,10 @@ void DynamicApplicationLoader::RegisterContentHandler( |
mime_type_to_url_[mime_type] = content_handler_url; |
} |
-void DynamicApplicationLoader::Load(ApplicationManager* manager, |
- const GURL& url, |
- scoped_refptr<LoadCallbacks> callbacks) { |
+void DynamicApplicationLoader::Load( |
+ ApplicationManager* manager, |
+ const GURL& url, |
+ scoped_refptr<LoadCallbacks> load_callbacks) { |
GURL resolved_url; |
if (url.SchemeIs("mojo")) { |
resolved_url = context_->mojo_url_resolver()->Resolve(url); |
@@ -47,124 +212,27 @@ void DynamicApplicationLoader::Load(ApplicationManager* manager, |
resolved_url = url; |
} |
- if (resolved_url.SchemeIsFile()) |
- LoadLocalService(resolved_url, callbacks); |
- else |
- LoadNetworkService(resolved_url, callbacks); |
-} |
- |
-void DynamicApplicationLoader::LoadLocalService( |
- const GURL& resolved_url, |
- scoped_refptr<LoadCallbacks> callbacks) { |
- base::FilePath path; |
- net::FileURLToFilePath(resolved_url, &path); |
- const bool kDeleteFileAfter = false; |
- |
- // Async for consistency with network case. |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&DynamicApplicationLoader::RunLibrary, |
- weak_ptr_factory_.GetWeakPtr(), |
- path, |
- callbacks, |
- kDeleteFileAfter, |
- base::PathExists(path))); |
-} |
+ if (resolved_url.SchemeIsFile()) { |
+ loaders_.push_back(new LocalLoader(resolved_url, |
+ context_, |
+ runner_factory_.get(), |
+ load_callbacks, |
+ loader_complete_callback_)); |
+ return; |
+ } |
-void DynamicApplicationLoader::LoadNetworkService( |
- const GURL& resolved_url, |
- scoped_refptr<LoadCallbacks> callbacks) { |
if (!network_service_) { |
context_->application_manager()->ConnectToService( |
GURL("mojo:mojo_network_service"), &network_service_); |
} |
- if (!url_loader_) |
- network_service_->CreateURLLoader(Get(&url_loader_)); |
- |
- URLRequestPtr request(URLRequest::New()); |
- request->url = String::From(resolved_url); |
- request->auto_follow_redirects = true; |
- |
- if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kDisableCache)) { |
- request->bypass_cache = true; |
- } |
- |
- url_loader_->Start( |
- request.Pass(), |
- base::Bind(&DynamicApplicationLoader::OnLoadNetworkServiceComplete, |
- weak_ptr_factory_.GetWeakPtr(), |
- callbacks)); |
-} |
- |
-void DynamicApplicationLoader::OnLoadNetworkServiceComplete( |
- scoped_refptr<LoadCallbacks> callbacks, |
- URLResponsePtr response) { |
- if (response->error) { |
- LOG(ERROR) << "Error (" << response->error->code << ": " |
- << response->error->description << ") while fetching " |
- << response->url; |
- } |
- |
- MimeTypeToURLMap::iterator iter = mime_type_to_url_.find(response->mime_type); |
- if (iter != mime_type_to_url_.end()) { |
- callbacks->LoadWithContentHandler(iter->second, response.Pass()); |
- return; |
- } |
- |
- base::FilePath file; |
- base::CreateTemporaryFile(&file); |
- |
- const bool kDeleteFileAfter = true; |
- common::CopyToFile(response->body.Pass(), |
- file, |
- context_->task_runners()->blocking_pool(), |
- base::Bind(&DynamicApplicationLoader::RunLibrary, |
- weak_ptr_factory_.GetWeakPtr(), |
- file, |
- callbacks, |
- kDeleteFileAfter)); |
-} |
- |
-void DynamicApplicationLoader::RunLibrary( |
- const base::FilePath& path, |
- scoped_refptr<LoadCallbacks> callbacks, |
- bool delete_file_after, |
- bool path_exists) { |
- |
- ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); |
- if (!shell_handle.is_valid()) |
- return; |
- |
- if (!path_exists) { |
- DVLOG(1) << "Library not started because library path '" |
- << path.value() << "' does not exist."; |
- return; |
- } |
- scoped_ptr<DynamicServiceRunner> runner = |
- runner_factory_->Create(context_).Pass(); |
- runner->Start(path, |
- shell_handle.Pass(), |
- base::Bind(&DynamicApplicationLoader::OnRunLibraryComplete, |
- weak_ptr_factory_.GetWeakPtr(), |
- base::Unretained(runner.get()), |
- delete_file_after ? path : base::FilePath())); |
- runners_.push_back(runner.release()); |
-} |
- |
-void DynamicApplicationLoader::OnRunLibraryComplete( |
- DynamicServiceRunner* runner, |
- const base::FilePath& temp_file) { |
- for (ScopedVector<DynamicServiceRunner>::iterator it = runners_.begin(); |
- it != runners_.end(); ++it) { |
- if (*it == runner) { |
- runners_.erase(it); |
- if (!temp_file.empty()) |
- base::DeleteFile(temp_file, false); |
- return; |
- } |
- } |
+ loaders_.push_back(new NetworkLoader(resolved_url, |
+ &mime_type_to_url_, |
+ context_, |
+ runner_factory_.get(), |
+ network_service_.get(), |
+ load_callbacks, |
+ loader_complete_callback_)); |
} |
void DynamicApplicationLoader::OnApplicationError(ApplicationManager* manager, |
@@ -173,5 +241,9 @@ void DynamicApplicationLoader::OnApplicationError(ApplicationManager* manager, |
// the app closed its handle to the service manager. Maybe we don't care? |
} |
+void DynamicApplicationLoader::LoaderComplete(Loader* loader) { |
+ loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader)); |
+} |
+ |
} // namespace shell |
} // namespace mojo |