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