OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "content/common/mojo/mojo_shell_connection_impl.h" | 5 #include "content/common/mojo/mojo_shell_connection_impl.h" |
6 | 6 |
7 #include <utility> | |
8 #include <vector> | |
9 | |
7 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/callback_helpers.h" | |
8 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
13 #include "base/macros.h" | |
9 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
10 #include "base/threading/thread_local.h" | 15 #include "base/threading/thread_checker.h" |
11 #include "content/common/mojo/embedded_application_runner.h" | 16 #include "content/common/mojo/embedded_application_runner.h" |
17 #include "mojo/public/cpp/bindings/binding_set.h" | |
18 #include "mojo/public/cpp/system/message_pipe.h" | |
12 #include "services/shell/public/cpp/shell_client.h" | 19 #include "services/shell/public/cpp/shell_client.h" |
13 #include "services/shell/public/cpp/shell_connection.h" | 20 #include "services/shell/public/cpp/shell_connection.h" |
21 #include "services/shell/public/interfaces/shell_client_factory.mojom.h" | |
14 #include "services/shell/runner/common/client_util.h" | 22 #include "services/shell/runner/common/client_util.h" |
15 | 23 |
16 namespace content { | 24 namespace content { |
17 namespace { | 25 namespace { |
18 | 26 |
19 using MojoShellConnectionPtr = | 27 base::LazyInstance<std::unique_ptr<MojoShellConnection>>::Leaky |
20 base::ThreadLocalPointer<MojoShellConnection>; | 28 g_connection_for_process = LAZY_INSTANCE_INITIALIZER; |
21 | |
22 // Env is thread local so that aura may be used on multiple threads. | |
23 base::LazyInstance<MojoShellConnectionPtr>::Leaky lazy_tls_ptr = | |
24 LAZY_INSTANCE_INITIALIZER; | |
25 | 29 |
26 MojoShellConnection::Factory* mojo_shell_connection_factory = nullptr; | 30 MojoShellConnection::Factory* mojo_shell_connection_factory = nullptr; |
27 | 31 |
28 } // namespace | 32 } // namespace |
29 | 33 |
34 // A ref-counted object which owns the IO thread state of a | |
35 // MojoShellConnectionImpl. This includes ShellClient and ShellClientFactory | |
36 // bindings. | |
37 class MojoShellConnectionImpl::IOThreadContext | |
38 : public base::RefCountedThreadSafe<IOThreadContext>, | |
39 public shell::ShellClient, | |
40 public shell::InterfaceFactory<shell::mojom::ShellClientFactory>, | |
41 public shell::mojom::ShellClientFactory { | |
42 public: | |
43 using ShellClientFactoryCallback = | |
44 base::Callback<void(shell::mojom::ShellClientRequest, | |
45 const mojo::String&)>; | |
46 | |
47 IOThreadContext() {} | |
48 | |
49 // The following methods are safe to call from any thread. | |
50 | |
51 void Initialize(shell::mojom::ShellClientRequest request, | |
52 scoped_refptr<base::SequencedTaskRunner> io_task_runner, | |
53 std::unique_ptr<shell::Connector> io_thread_connector, | |
54 shell::mojom::ConnectorRequest connector_request, | |
55 const base::Closure& initialize_callback, | |
56 const ShellClientFactoryCallback& create_shell_client) { | |
57 DCHECK(!io_task_runner_); | |
58 io_thread_checker_.DetachFromThread(); | |
59 | |
60 io_task_runner_ = io_task_runner; | |
61 initialize_handler_ = base::Bind( | |
62 &IOThreadContext::CallInitializeOnTaskRunner, | |
63 base::ThreadTaskRunnerHandle::Get(), initialize_callback); | |
64 | |
65 create_shell_client_ = base::Bind( | |
66 &IOThreadContext::CallShellClientFactoryOnTaskRunner, | |
67 base::ThreadTaskRunnerHandle::Get(), create_shell_client); | |
68 | |
69 io_task_runner_->PostTask( | |
70 FROM_HERE, | |
71 base::Bind(&IOThreadContext::InitializeOnIOThread, this, | |
72 base::Passed(&request), base::Passed(&io_thread_connector), | |
73 base::Passed(&connector_request))); | |
74 } | |
75 | |
76 void ShutDown() { | |
77 bool posted = io_task_runner_->PostTask( | |
78 FROM_HERE, base::Bind(&IOThreadContext::ShutdownOnIOThread, this)); | |
79 | |
80 // This must be called before IO thread shutdown. | |
81 DCHECK(posted); | |
82 } | |
83 | |
84 void AddConnectionFilter( | |
85 const MojoShellConnection::ConnectionFilter& filter) { | |
86 base::AutoLock lock(lock_); | |
87 connection_filters_.push_back(filter); | |
88 } | |
89 | |
90 shell::Identity GetIdentity() { | |
91 base::AutoLock lock(lock_); | |
92 if (!shell_connection_) | |
93 return shell::Identity(); | |
94 | |
95 return shell_connection_->identity(); | |
96 } | |
97 | |
98 private: | |
99 friend class base::RefCountedThreadSafe<IOThreadContext>; | |
100 | |
101 ~IOThreadContext() override {} | |
102 | |
103 void InitializeOnIOThread(shell::mojom::ShellClientRequest request, | |
104 std::unique_ptr<shell::Connector> connector, | |
105 shell::mojom::ConnectorRequest connector_request) { | |
106 // Should bind |io_thread_checker_| to the context's thread. | |
107 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
108 shell_connection_.reset(new shell::ShellConnection( | |
109 this, std::move(request), std::move(connector), | |
110 std::move(connector_request))); | |
111 } | |
112 | |
113 void ShutdownOnIOThread() { | |
114 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
115 shell_connection_.reset(); | |
116 factory_bindings_.CloseAllBindings(); | |
117 } | |
118 | |
119 ///////////////////////////////////////////////////////////////////////////// | |
120 // shell::ShellClient implementation | |
121 | |
122 void Initialize(shell::Connector* connector, | |
123 const shell::Identity& identity, | |
124 uint32_t id) override { | |
125 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
126 DCHECK(!initialize_handler_.is_null()); | |
127 base::ResetAndReturn(&initialize_handler_).Run(); | |
128 } | |
129 | |
130 bool AcceptConnection(shell::Connection* connection) override { | |
131 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
132 std::string remote_app = connection->GetRemoteIdentity().name(); | |
133 if (remote_app == "mojo:shell") { | |
134 // Only expose the SCF interface to the shell. | |
135 connection->AddInterface<shell::mojom::ShellClientFactory>(this); | |
136 return true; | |
137 } | |
138 | |
139 bool accept = false; | |
140 base::AutoLock lock(lock_); | |
141 for (auto& filter : connection_filters_) | |
142 accept = accept || filter.Run(connection, shell_connection_->connector()); | |
143 | |
144 // Reject all other connections to this application. | |
145 return accept; | |
146 } | |
147 | |
148 ///////////////////////////////////////////////////////////////////////////// | |
149 // shell::InterfaceFactory<shell::mojom::ShellClientFactory> implementation | |
150 | |
151 void Create(shell::Connection* connection, | |
152 shell::mojom::ShellClientFactoryRequest request) override { | |
153 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
154 factory_bindings_.AddBinding(this, std::move(request)); | |
155 } | |
156 | |
157 ///////////////////////////////////////////////////////////////////////////// | |
158 // shell::mojom::ShellClientFactory implementation | |
159 | |
160 void CreateShellClient(shell::mojom::ShellClientRequest request, | |
161 const mojo::String& name) override { | |
162 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
163 create_shell_client_.Run(std::move(request), name); | |
164 } | |
165 | |
166 static void CallInitializeOnTaskRunner( | |
167 scoped_refptr<base::SequencedTaskRunner> task_runner, | |
168 const base::Closure& callback) { | |
169 task_runner->PostTask(FROM_HERE, callback); | |
170 } | |
171 | |
172 static void CallShellClientFactoryOnTaskRunner( | |
173 scoped_refptr<base::SequencedTaskRunner> task_runner, | |
174 const ShellClientFactoryCallback& callback, | |
175 shell::mojom::ShellClientRequest request, | |
176 const mojo::String& name) { | |
177 task_runner->PostTask( | |
178 FROM_HERE, base::Bind(callback, base::Passed(&request), name)); | |
179 } | |
180 | |
181 base::ThreadChecker io_thread_checker_; | |
182 | |
183 scoped_refptr<base::SequencedTaskRunner> io_task_runner_; | |
184 | |
185 base::Closure initialize_handler_; | |
186 ShellClientFactoryCallback create_shell_client_; | |
187 | |
188 // Guards fields below for thread-safe access. | |
189 base::Lock lock_; | |
190 | |
191 std::unique_ptr<shell::ShellConnection> shell_connection_; | |
192 mojo::BindingSet<shell::mojom::ShellClientFactory> factory_bindings_; | |
193 std::vector<MojoShellConnection::ConnectionFilter> connection_filters_; | |
194 | |
195 DISALLOW_COPY_AND_ASSIGN(IOThreadContext); | |
196 }; | |
197 | |
30 //////////////////////////////////////////////////////////////////////////////// | 198 //////////////////////////////////////////////////////////////////////////////// |
31 // MojoShellConnection, public: | 199 // MojoShellConnection, public: |
32 | 200 |
33 // static | 201 // static |
34 void MojoShellConnection::SetForProcess( | 202 void MojoShellConnection::SetForProcess( |
35 std::unique_ptr<MojoShellConnection> connection) { | 203 std::unique_ptr<MojoShellConnection> connection) { |
36 DCHECK(!lazy_tls_ptr.Pointer()->Get()); | 204 DCHECK(!g_connection_for_process.Get()); |
37 lazy_tls_ptr.Pointer()->Set(connection.release()); | 205 g_connection_for_process.Get() = std::move(connection); |
38 } | 206 } |
39 | 207 |
40 // static | 208 // static |
41 MojoShellConnection* MojoShellConnection::GetForProcess() { | 209 MojoShellConnection* MojoShellConnection::GetForProcess() { |
42 return lazy_tls_ptr.Pointer()->Get(); | 210 return g_connection_for_process.Get().get(); |
43 } | 211 } |
44 | 212 |
45 // static | 213 // static |
46 void MojoShellConnection::DestroyForProcess() { | 214 void MojoShellConnection::DestroyForProcess() { |
47 // This joins the shell controller thread. | 215 // This joins the shell controller thread. |
48 delete GetForProcess(); | 216 g_connection_for_process.Get().reset(); |
49 lazy_tls_ptr.Pointer()->Set(nullptr); | |
50 } | 217 } |
51 | 218 |
52 // static | 219 // static |
53 void MojoShellConnection::SetFactoryForTest(Factory* factory) { | 220 void MojoShellConnection::SetFactoryForTest(Factory* factory) { |
54 DCHECK(!lazy_tls_ptr.Pointer()->Get()); | 221 DCHECK(!g_connection_for_process.Get()); |
55 mojo_shell_connection_factory = factory; | 222 mojo_shell_connection_factory = factory; |
56 } | 223 } |
57 | 224 |
58 // static | 225 // static |
59 std::unique_ptr<MojoShellConnection> MojoShellConnection::Create( | 226 std::unique_ptr<MojoShellConnection> MojoShellConnection::Create( |
60 shell::mojom::ShellClientRequest request) { | 227 shell::mojom::ShellClientRequest request, |
228 scoped_refptr<base::SequencedTaskRunner> io_task_runner) { | |
61 if (mojo_shell_connection_factory) | 229 if (mojo_shell_connection_factory) |
62 return mojo_shell_connection_factory->Run(); | 230 return mojo_shell_connection_factory->Run(); |
63 return base::WrapUnique(new MojoShellConnectionImpl(std::move(request))); | 231 return base::MakeUnique<MojoShellConnectionImpl>( |
232 std::move(request), io_task_runner); | |
64 } | 233 } |
65 | 234 |
66 MojoShellConnection::~MojoShellConnection() {} | 235 MojoShellConnection::~MojoShellConnection() {} |
67 | 236 |
68 //////////////////////////////////////////////////////////////////////////////// | 237 //////////////////////////////////////////////////////////////////////////////// |
69 // MojoShellConnectionImpl, public: | 238 // MojoShellConnectionImpl, public: |
70 | 239 |
71 MojoShellConnectionImpl::MojoShellConnectionImpl( | 240 MojoShellConnectionImpl::MojoShellConnectionImpl( |
72 shell::mojom::ShellClientRequest request) | 241 shell::mojom::ShellClientRequest request, |
73 : shell_connection_(new shell::ShellConnection(this, std::move(request))) {} | 242 scoped_refptr<base::SequencedTaskRunner> io_task_runner) |
243 : context_(new IOThreadContext), weak_factory_(this) { | |
244 shell::mojom::ConnectorRequest connector_request; | |
245 connector_ = shell::Connector::Create(&connector_request); | |
74 | 246 |
75 MojoShellConnectionImpl::~MojoShellConnectionImpl() {} | 247 std::unique_ptr<shell::Connector> io_thread_connector = connector_->Clone(); |
76 | 248 context_->Initialize( |
77 //////////////////////////////////////////////////////////////////////////////// | 249 std::move(request), io_task_runner, std::move(io_thread_connector), |
78 // MojoShellConnectionImpl, shell::ShellClient implementation: | 250 std::move(connector_request), |
79 | 251 base::Bind(&MojoShellConnectionImpl::OnContextInitialized, |
80 void MojoShellConnectionImpl::Initialize(shell::Connector* connector, | 252 weak_factory_.GetWeakPtr()), |
81 const shell::Identity& identity, | 253 base::Bind(&MojoShellConnectionImpl::CreateShellClient, |
82 uint32_t id) { | 254 weak_factory_.GetWeakPtr())); |
83 for (auto& client : embedded_shell_clients_) | |
84 client->Initialize(connector, identity, id); | |
85 } | 255 } |
86 | 256 |
87 bool MojoShellConnectionImpl::AcceptConnection(shell::Connection* connection) { | 257 MojoShellConnectionImpl::~MojoShellConnectionImpl() { |
88 std::string remote_app = connection->GetRemoteIdentity().name(); | 258 context_->ShutDown(); |
89 if (remote_app == "mojo:shell") { | |
90 // Only expose the SCF interface to the shell. | |
91 connection->AddInterface<shell::mojom::ShellClientFactory>(this); | |
92 return true; | |
93 } | |
94 | |
95 bool accept = false; | |
96 for (auto& client : embedded_shell_clients_) | |
97 accept |= client->AcceptConnection(connection); | |
98 | |
99 // Reject all other connections to this application. | |
100 return accept; | |
101 } | |
102 | |
103 shell::InterfaceRegistry* | |
104 MojoShellConnectionImpl::GetInterfaceRegistryForConnection() { | |
105 // TODO(beng): This is really horrible since obviously subject to issues | |
106 // of ordering, but is no more horrible than this API is in general. | |
107 shell::InterfaceRegistry* registry = nullptr; | |
108 for (auto& client : embedded_shell_clients_) { | |
109 registry = client->GetInterfaceRegistryForConnection(); | |
110 if (registry) | |
111 return registry; | |
112 } | |
113 return nullptr; | |
114 } | |
115 | |
116 shell::InterfaceProvider* | |
117 MojoShellConnectionImpl::GetInterfaceProviderForConnection() { | |
118 // TODO(beng): This is really horrible since obviously subject to issues | |
119 // of ordering, but is no more horrible than this API is in general. | |
120 shell::InterfaceProvider* provider = nullptr; | |
121 for (auto& client : embedded_shell_clients_) { | |
122 provider = client->GetInterfaceProviderForConnection(); | |
123 if (provider) | |
124 return provider; | |
125 } | |
126 return nullptr; | |
127 } | |
128 | |
129 //////////////////////////////////////////////////////////////////////////////// | |
130 // MojoShellConnectionImpl, | |
131 // shell::InterfaceFactory<shell::mojom::ShellClientFactory> implementation: | |
132 | |
133 void MojoShellConnectionImpl::Create( | |
134 shell::Connection* connection, | |
135 shell::mojom::ShellClientFactoryRequest request) { | |
136 factory_bindings_.AddBinding(this, std::move(request)); | |
137 } | |
138 | |
139 //////////////////////////////////////////////////////////////////////////////// | |
140 // MojoShellConnectionImpl, shell::mojom::ShellClientFactory implementation: | |
141 | |
142 void MojoShellConnectionImpl::CreateShellClient( | |
143 shell::mojom::ShellClientRequest request, | |
144 const mojo::String& name) { | |
145 auto it = request_handlers_.find(name); | |
146 if (it != request_handlers_.end()) | |
147 it->second.Run(std::move(request)); | |
148 } | 259 } |
149 | 260 |
150 //////////////////////////////////////////////////////////////////////////////// | 261 //////////////////////////////////////////////////////////////////////////////// |
151 // MojoShellConnectionImpl, MojoShellConnection implementation: | 262 // MojoShellConnectionImpl, MojoShellConnection implementation: |
152 | 263 |
153 shell::ShellConnection* MojoShellConnectionImpl::GetShellConnection() { | 264 void MojoShellConnectionImpl::SetInitializeHandler( |
154 return shell_connection_.get(); | 265 const base::Closure& handler) { |
266 DCHECK(initialize_handler_.is_null()); | |
267 initialize_handler_ = handler; | |
155 } | 268 } |
156 | 269 |
157 shell::Connector* MojoShellConnectionImpl::GetConnector() { | 270 shell::Connector* MojoShellConnectionImpl::GetConnector() { |
158 DCHECK(shell_connection_); | 271 return connector_.get(); |
159 return shell_connection_->connector(); | |
160 } | 272 } |
161 | 273 |
162 const shell::Identity& MojoShellConnectionImpl::GetIdentity() const { | 274 const shell::Identity& MojoShellConnectionImpl::GetIdentity() const { |
163 DCHECK(shell_connection_); | 275 return identity_; |
164 return shell_connection_->identity(); | |
165 } | 276 } |
166 | 277 |
167 void MojoShellConnectionImpl::SetConnectionLostClosure( | 278 void MojoShellConnectionImpl::SetConnectionLostClosure( |
168 const base::Closure& closure) { | 279 const base::Closure& closure) { |
169 shell_connection_->SetConnectionLostClosure(closure); | 280 connection_lost_handler_ = closure; |
170 } | 281 } |
171 | 282 |
172 void MojoShellConnectionImpl::AddEmbeddedShellClient( | 283 void MojoShellConnectionImpl::AddConnectionFilter( |
173 std::unique_ptr<shell::ShellClient> shell_client) { | 284 const ConnectionFilter& filter) { |
Ben Goodger (Google)
2016/07/03 03:29:27
did you mean to leave this implementation empty?
| |
174 embedded_shell_clients_.push_back(shell_client.get()); | |
175 owned_shell_clients_.push_back(std::move(shell_client)); | |
176 } | |
177 | |
178 void MojoShellConnectionImpl::AddEmbeddedShellClient( | |
179 shell::ShellClient* shell_client) { | |
180 embedded_shell_clients_.push_back(shell_client); | |
181 } | 285 } |
182 | 286 |
183 void MojoShellConnectionImpl::AddEmbeddedService( | 287 void MojoShellConnectionImpl::AddEmbeddedService( |
184 const std::string& name, | 288 const std::string& name, |
185 const MojoApplicationInfo& info) { | 289 const MojoApplicationInfo& info) { |
186 std::unique_ptr<EmbeddedApplicationRunner> app( | 290 std::unique_ptr<EmbeddedApplicationRunner> app( |
187 new EmbeddedApplicationRunner(name, info)); | 291 new EmbeddedApplicationRunner(name, info)); |
188 AddShellClientRequestHandler( | 292 AddShellClientRequestHandler( |
189 name, base::Bind(&EmbeddedApplicationRunner::BindShellClientRequest, | 293 name, base::Bind(&EmbeddedApplicationRunner::BindShellClientRequest, |
190 base::Unretained(app.get()))); | 294 base::Unretained(app.get()))); |
191 auto result = embedded_apps_.insert(std::make_pair(name, std::move(app))); | 295 auto result = embedded_apps_.insert(std::make_pair(name, std::move(app))); |
192 DCHECK(result.second); | 296 DCHECK(result.second); |
193 } | 297 } |
194 | 298 |
195 void MojoShellConnectionImpl::AddShellClientRequestHandler( | 299 void MojoShellConnectionImpl::AddShellClientRequestHandler( |
196 const std::string& name, | 300 const std::string& name, |
197 const ShellClientRequestHandler& handler) { | 301 const ShellClientRequestHandler& handler) { |
198 auto result = request_handlers_.insert(std::make_pair(name, handler)); | 302 auto result = request_handlers_.insert(std::make_pair(name, handler)); |
199 DCHECK(result.second); | 303 DCHECK(result.second); |
200 } | 304 } |
201 | 305 |
306 void MojoShellConnectionImpl::CreateShellClient( | |
307 shell::mojom::ShellClientRequest request, | |
308 const mojo::String& name) { | |
309 auto it = request_handlers_.find(name); | |
310 if (it != request_handlers_.end()) | |
311 it->second.Run(std::move(request)); | |
312 } | |
313 | |
314 void MojoShellConnectionImpl::OnContextInitialized() { | |
315 identity_ = context_->GetIdentity(); | |
316 if (!initialize_handler_.is_null()) | |
317 base::ResetAndReturn(&initialize_handler_).Run(); | |
318 } | |
319 | |
320 void MojoShellConnectionImpl::OnConnectionLost() { | |
321 if (!connection_lost_handler_.is_null()) | |
322 connection_lost_handler_.Run(); | |
323 } | |
324 | |
202 } // namespace content | 325 } // namespace content |
OLD | NEW |