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 ::shell::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< ::shell::ShellClient> shell_client_; | |
51 DISALLOW_COPY_AND_ASSIGN(Service); | |
52 }; | |
53 | |
54 class ServiceManager::DynamicLoader : public ServiceManager::Loader { | |
55 public: | |
56 DynamicLoader(ServiceManager* manager) : manager_(manager) {} | |
abarth-chromium
2013/12/15 22:54:10
Please mark one-argument constructors explicit.
DaveMoore
2013/12/16 17:40:22
Done.
| |
57 virtual ~DynamicLoader() {} | |
58 | |
59 private: | |
60 class Context : public mojo::shell::Loader::Delegate, | |
61 public base::DelegateSimpleThread::Delegate { | |
abarth-chromium
2013/12/15 22:54:10
I think we're going a bit crazy here with nested c
DaveMoore
2013/12/16 17:40:22
It may be going too far, but it keeps the publicly
| |
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 base::AutoLock lock(lock_); | |
abarth-chromium
2013/12/15 22:54:10
Why is this lock needed? This is the only line of
DaveMoore
2013/12/16 17:40:22
Removed.
On 2013/12/15 22:54:10, abarth wrote:
| |
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")); | |
abarth-chromium
2013/12/15 22:54:10
You don't create the other thread until here....
DaveMoore
2013/12/16 17:40:22
Done.
| |
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 base::ScopedNativeLibrary app_library( | |
109 base::LoadNativeLibrary(app_path_, NULL)); | |
110 if (!app_library.is_valid()) { | |
111 LOG(ERROR) << "Failed to load library: " << app_path_.value().c_str(); | |
112 return; | |
113 } | |
114 | |
115 MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>( | |
116 app_library.GetFunctionPointer("MojoMain")); | |
117 if (!main_function) { | |
118 LOG(ERROR) << "Entrypoint MojoMain not found."; | |
119 return; | |
120 } | |
121 | |
122 MojoHandle handle = service_handle_.release().value(); | |
123 // |MojoMain()| takes ownership of the app handle. | |
124 MojoResult result = main_function(handle); | |
125 if (result < MOJO_RESULT_OK) { | |
126 LOG(ERROR) << "MojoMain returned an error: " << result; | |
127 return; | |
128 } | |
129 loader_->manager_->context_->task_runners()->ui_runner()->PostTask( | |
130 FROM_HERE, | |
131 ack_closure_); | |
132 } | |
133 | |
134 void AppCompleted() { | |
135 thread_->Join(); | |
136 thread_.reset(); | |
137 loader_->url_to_context_.erase(url_); | |
138 delete this; | |
139 } | |
140 | |
141 DynamicLoader* loader_; | |
142 GURL url_; | |
143 base::Lock lock_; | |
144 base::FilePath app_path_; | |
145 base::Closure ack_closure_; | |
146 scoped_ptr<mojo::shell::Loader::Job> request_; | |
147 scoped_ptr<base::DelegateSimpleThread> thread_; | |
148 ScopedMessagePipeHandle service_handle_; | |
149 base::WeakPtrFactory<Context> weak_factory_; | |
150 }; | |
151 | |
152 virtual void Load(const GURL& url, | |
153 ServiceManager* manager, | |
154 ScopedMessagePipeHandle service_handle) | |
155 MOJO_OVERRIDE { | |
156 DCHECK(url_to_context_.find(url) == url_to_context_.end()); | |
157 url_to_context_[url] = new Context(this, url, service_handle.Pass()); | |
158 } | |
159 | |
160 typedef std::map<GURL, Context*> ContextMap; | |
161 ContextMap url_to_context_; | |
162 ServiceManager* manager_; | |
163 }; | |
164 | |
165 ServiceManager::Loader::Loader() {} | |
166 ServiceManager::Loader::~Loader() {} | |
167 | |
168 ServiceManager::ServiceManager(Context* context) | |
169 : context_(context), | |
170 default_loader_(new DynamicLoader(this)) { | |
171 } | |
172 | |
173 ServiceManager::~ServiceManager() { | |
174 } | |
175 | |
176 void ServiceManager::SetLoaderForURL(Loader* loader, const GURL& gurl) { | |
177 DCHECK(url_to_loader_.find(gurl) == url_to_loader_.end()); | |
178 url_to_loader_[gurl] = loader; | |
179 } | |
180 | |
181 ServiceManager::Loader* ServiceManager::GetLoaderForURL(const GURL& gurl) { | |
182 LoaderMap::const_iterator it = url_to_loader_.find(gurl); | |
183 if (it != url_to_loader_.end()) | |
184 return it->second; | |
185 return default_loader_.get(); | |
186 } | |
187 | |
188 void ServiceManager::Connect(const GURL& url, | |
189 ScopedMessagePipeHandle client_handle) { | |
190 ServiceMap::const_iterator service_it = url_to_service_.find(url); | |
191 Service* service; | |
192 if (service_it != url_to_service_.end()) { | |
193 service = service_it->second; | |
194 } else { | |
195 service = new Service(this, url); | |
196 url_to_service_[url] = service; | |
197 } | |
198 service->ConnectToClient(client_handle.Pass()); | |
199 } | |
200 | |
201 } // namespace shell | |
202 } // namespace mojo | |
OLD | NEW |