| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/service_manager.h" | 5 #include "mojo/shell/service_manager.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/logging.h" |
| 8 #include "base/callback_helpers.h" | |
| 9 #include "base/command_line.h" | |
| 10 #include "base/file_util.h" | |
| 11 #include "base/scoped_native_library.h" | |
| 12 #include "base/threading/simple_thread.h" | |
| 13 #include "mojo/public/bindings/lib/remote_ptr.h" | 8 #include "mojo/public/bindings/lib/remote_ptr.h" |
| 14 #include "mojo/shell/context.h" | |
| 15 #include "mojo/shell/switches.h" | |
| 16 #include "mojom/shell.h" | 9 #include "mojom/shell.h" |
| 17 | 10 |
| 18 typedef MojoResult (*MojoMainFunction)(MojoHandle pipe); | |
| 19 | |
| 20 namespace mojo { | 11 namespace mojo { |
| 21 namespace shell { | 12 namespace shell { |
| 22 | 13 |
| 23 class ServiceManager::Service : public ShellStub { | 14 class ServiceManager::Service : public ShellStub { |
| 24 public: | 15 public: |
| 25 Service(ServiceManager* manager, const GURL& url) | 16 Service(ServiceManager* manager, const GURL& url) |
| 26 : manager_(manager), | 17 : manager_(manager), |
| 27 url_(url) { | 18 url_(url) { |
| 28 MessagePipe pipe; | 19 MessagePipe pipe; |
| 29 shell_client_.reset(pipe.handle0.Pass()); | 20 shell_client_.reset(pipe.handle0.Pass()); |
| 30 shell_client_.SetPeer(this); | 21 shell_client_.SetPeer(this); |
| 31 manager_->GetLoaderForURL(url)->Load(url, manager_, pipe.handle1.Pass()); | 22 manager_->GetLoaderForURL(url)->Load(url, pipe.handle1.Pass()); |
| 32 } | 23 } |
| 33 | |
| 34 virtual ~Service() {} | 24 virtual ~Service() {} |
| 35 | 25 |
| 36 void ConnectToClient(ScopedMessagePipeHandle handle) { | 26 void ConnectToClient(ScopedMessagePipeHandle handle) { |
| 37 if (handle.is_valid()) | 27 if (handle.is_valid()) |
| 38 shell_client_->AcceptConnection(handle.Pass()); | 28 shell_client_->AcceptConnection(handle.Pass()); |
| 39 } | 29 } |
| 40 | 30 |
| 41 virtual void Connect(const String& url, | 31 virtual void Connect(const String& url, |
| 42 ScopedMessagePipeHandle client_pipe) MOJO_OVERRIDE { | 32 ScopedMessagePipeHandle client_pipe) MOJO_OVERRIDE { |
| 43 manager_->Connect(GURL(url.To<std::string>()), client_pipe.Pass()); | 33 manager_->Connect(GURL(url.To<std::string>()), client_pipe.Pass()); |
| 44 } | 34 } |
| 45 | 35 |
| 46 private: | 36 private: |
| 47 ServiceManager* manager_; | 37 ServiceManager* manager_; |
| 48 GURL url_; | 38 GURL url_; |
| 49 RemotePtr<ShellClient> shell_client_; | 39 RemotePtr<ShellClient> shell_client_; |
| 50 DISALLOW_COPY_AND_ASSIGN(Service); | 40 DISALLOW_COPY_AND_ASSIGN(Service); |
| 51 }; | 41 }; |
| 52 | 42 |
| 53 class ServiceManager::DynamicLoader : public ServiceManager::Loader { | |
| 54 public: | |
| 55 explicit DynamicLoader(ServiceManager* manager) : manager_(manager) {} | |
| 56 virtual ~DynamicLoader() {} | |
| 57 | |
| 58 private: | |
| 59 class Context : public mojo::shell::Loader::Delegate, | |
| 60 public base::DelegateSimpleThread::Delegate { | |
| 61 public: | |
| 62 Context(DynamicLoader* loader, | |
| 63 const GURL& url, | |
| 64 ScopedMessagePipeHandle service_handle) | |
| 65 : loader_(loader), | |
| 66 url_(url), | |
| 67 service_handle_(service_handle.Pass()), | |
| 68 weak_factory_(this) { | |
| 69 url_ = url; | |
| 70 if (url.scheme() == "mojo") { | |
| 71 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
| 72 std::string origin = | |
| 73 command_line.GetSwitchValueASCII(switches::kOrigin); | |
| 74 #if defined(OS_WIN) | |
| 75 std::string lib(url.ExtractFileName() + ".dll"); | |
| 76 #elif defined(OS_LINUX) | |
| 77 std::string lib("lib" + url.ExtractFileName() + ".so"); | |
| 78 #elif defined(OS_MACOSX) | |
| 79 std::string lib("lib" + url.ExtractFileName() + ".dylib"); | |
| 80 #else | |
| 81 std::string lib; | |
| 82 NOTREACHED() << "dynamic loading of services not supported"; | |
| 83 return; | |
| 84 #endif | |
| 85 url_ = GURL(origin + std::string("/") + lib); | |
| 86 } | |
| 87 request_ = loader_->manager_->context_->loader()->Load(url_, this); | |
| 88 } | |
| 89 | |
| 90 private: | |
| 91 friend class base::WeakPtrFactory<Context>; | |
| 92 | |
| 93 // From Loader::Delegate. | |
| 94 virtual void DidCompleteLoad(const GURL& app_url, | |
| 95 const base::FilePath& app_path) OVERRIDE { | |
| 96 app_path_ = app_path; | |
| 97 ack_closure_ = | |
| 98 base::Bind(&ServiceManager::DynamicLoader::Context::AppCompleted, | |
| 99 weak_factory_.GetWeakPtr()); | |
| 100 thread_.reset(new base::DelegateSimpleThread(this, "app_thread")); | |
| 101 thread_->Start(); | |
| 102 } | |
| 103 | |
| 104 // From base::DelegateSimpleThread::Delegate. | |
| 105 virtual void Run() OVERRIDE { | |
| 106 base::ScopedClosureRunner app_deleter( | |
| 107 base::Bind(base::IgnoreResult(&base::DeleteFile), app_path_, false)); | |
| 108 std::string load_error; | |
| 109 base::ScopedNativeLibrary app_library( | |
| 110 base::LoadNativeLibrary(app_path_, &load_error)); | |
| 111 if (!app_library.is_valid()) { | |
| 112 LOG(ERROR) << "Failed to load library: " << app_path_.value().c_str(); | |
| 113 LOG(ERROR) << "error: " << load_error; | |
| 114 return; | |
| 115 } | |
| 116 | |
| 117 MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>( | |
| 118 app_library.GetFunctionPointer("MojoMain")); | |
| 119 if (!main_function) { | |
| 120 LOG(ERROR) << "Entrypoint MojoMain not found."; | |
| 121 return; | |
| 122 } | |
| 123 | |
| 124 MojoHandle handle = service_handle_.release().value(); | |
| 125 // |MojoMain()| takes ownership of the app handle. | |
| 126 MojoResult result = main_function(handle); | |
| 127 if (result < MOJO_RESULT_OK) { | |
| 128 LOG(ERROR) << "MojoMain returned an error: " << result; | |
| 129 return; | |
| 130 } | |
| 131 loader_->manager_->context_->task_runners()->ui_runner()->PostTask( | |
| 132 FROM_HERE, | |
| 133 ack_closure_); | |
| 134 } | |
| 135 | |
| 136 void AppCompleted() { | |
| 137 thread_->Join(); | |
| 138 thread_.reset(); | |
| 139 loader_->url_to_context_.erase(url_); | |
| 140 delete this; | |
| 141 } | |
| 142 | |
| 143 DynamicLoader* loader_; | |
| 144 GURL url_; | |
| 145 base::FilePath app_path_; | |
| 146 base::Closure ack_closure_; | |
| 147 scoped_ptr<mojo::shell::Loader::Job> request_; | |
| 148 scoped_ptr<base::DelegateSimpleThread> thread_; | |
| 149 ScopedMessagePipeHandle service_handle_; | |
| 150 base::WeakPtrFactory<Context> weak_factory_; | |
| 151 }; | |
| 152 | |
| 153 virtual void Load(const GURL& url, | |
| 154 ServiceManager* manager, | |
| 155 ScopedMessagePipeHandle service_handle) | |
| 156 MOJO_OVERRIDE { | |
| 157 DCHECK(url_to_context_.find(url) == url_to_context_.end()); | |
| 158 url_to_context_[url] = new Context(this, url, service_handle.Pass()); | |
| 159 } | |
| 160 | |
| 161 typedef std::map<GURL, Context*> ContextMap; | |
| 162 ContextMap url_to_context_; | |
| 163 ServiceManager* manager_; | |
| 164 }; | |
| 165 | |
| 166 ServiceManager::Loader::Loader() {} | 43 ServiceManager::Loader::Loader() {} |
| 167 ServiceManager::Loader::~Loader() {} | 44 ServiceManager::Loader::~Loader() {} |
| 168 | 45 |
| 169 ServiceManager::ServiceManager(Context* context) | 46 ServiceManager::ServiceManager() : default_loader_(NULL) { |
| 170 : context_(context), | |
| 171 default_loader_(new DynamicLoader(this)) { | |
| 172 } | 47 } |
| 173 | 48 |
| 174 ServiceManager::~ServiceManager() { | 49 ServiceManager::~ServiceManager() { |
| 50 for (ServiceMap::iterator it = url_to_service_.begin(); |
| 51 it != url_to_service_.end(); ++it) { |
| 52 delete it->second; |
| 53 } |
| 54 url_to_service_.clear(); |
| 175 } | 55 } |
| 176 | 56 |
| 177 void ServiceManager::SetLoaderForURL(Loader* loader, const GURL& gurl) { | 57 void ServiceManager::SetLoaderForURL(Loader* loader, const GURL& gurl) { |
| 178 DCHECK(url_to_loader_.find(gurl) == url_to_loader_.end()); | 58 DCHECK(url_to_loader_.find(gurl) == url_to_loader_.end()); |
| 179 url_to_loader_[gurl] = loader; | 59 url_to_loader_[gurl] = loader; |
| 180 } | 60 } |
| 181 | 61 |
| 182 ServiceManager::Loader* ServiceManager::GetLoaderForURL(const GURL& gurl) { | 62 ServiceManager::Loader* ServiceManager::GetLoaderForURL(const GURL& gurl) { |
| 183 LoaderMap::const_iterator it = url_to_loader_.find(gurl); | 63 LoaderMap::const_iterator it = url_to_loader_.find(gurl); |
| 184 if (it != url_to_loader_.end()) | 64 if (it != url_to_loader_.end()) |
| 185 return it->second; | 65 return it->second; |
| 186 return default_loader_.get(); | 66 DCHECK(default_loader_); |
| 67 return default_loader_; |
| 187 } | 68 } |
| 188 | 69 |
| 189 void ServiceManager::Connect(const GURL& url, | 70 void ServiceManager::Connect(const GURL& url, |
| 190 ScopedMessagePipeHandle client_handle) { | 71 ScopedMessagePipeHandle client_handle) { |
| 191 ServiceMap::const_iterator service_it = url_to_service_.find(url); | 72 ServiceMap::const_iterator service_it = url_to_service_.find(url); |
| 192 Service* service; | 73 Service* service; |
| 193 if (service_it != url_to_service_.end()) { | 74 if (service_it != url_to_service_.end()) { |
| 194 service = service_it->second; | 75 service = service_it->second; |
| 195 } else { | 76 } else { |
| 196 service = new Service(this, url); | 77 service = new Service(this, url); |
| 197 url_to_service_[url] = service; | 78 url_to_service_[url] = service; |
| 198 } | 79 } |
| 199 service->ConnectToClient(client_handle.Pass()); | 80 service->ConnectToClient(client_handle.Pass()); |
| 200 } | 81 } |
| 201 | 82 |
| 202 } // namespace shell | 83 } // namespace shell |
| 203 } // namespace mojo | 84 } // namespace mojo |
| OLD | NEW |