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 |