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 |
| 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 |