OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "ipc/ipc_mojo_bootstrap.h" | 5 #include "ipc/ipc_mojo_bootstrap.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <map> | 9 #include <map> |
10 #include <memory> | 10 #include <memory> |
11 #include <utility> | 11 #include <utility> |
12 #include <vector> | |
13 | 12 |
14 #include "base/callback.h" | 13 #include "base/callback.h" |
15 #include "base/logging.h" | 14 #include "base/logging.h" |
16 #include "base/macros.h" | 15 #include "base/macros.h" |
17 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/process/process_handle.h" |
18 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
19 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
20 #include "base/synchronization/lock.h" | 20 #include "base/synchronization/lock.h" |
21 #include "base/threading/thread_task_runner_handle.h" | 21 #include "base/threading/thread_task_runner_handle.h" |
22 #include "build/build_config.h" | 22 #include "build/build_config.h" |
23 #include "ipc/ipc_message_utils.h" | 23 #include "ipc/ipc_message_utils.h" |
24 #include "ipc/ipc_platform_file.h" | 24 #include "ipc/ipc_platform_file.h" |
25 #include "mojo/public/cpp/bindings/associated_group.h" | 25 #include "mojo/public/cpp/bindings/associated_group.h" |
26 #include "mojo/public/cpp/bindings/associated_group_controller.h" | 26 #include "mojo/public/cpp/bindings/associated_group_controller.h" |
27 #include "mojo/public/cpp/bindings/binding.h" | 27 #include "mojo/public/cpp/bindings/binding.h" |
28 #include "mojo/public/cpp/bindings/connector.h" | 28 #include "mojo/public/cpp/bindings/connector.h" |
29 #include "mojo/public/cpp/bindings/interface_endpoint_client.h" | 29 #include "mojo/public/cpp/bindings/interface_endpoint_client.h" |
30 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h" | 30 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h" |
31 #include "mojo/public/cpp/bindings/interface_id.h" | 31 #include "mojo/public/cpp/bindings/interface_id.h" |
32 #include "mojo/public/cpp/bindings/message.h" | |
33 #include "mojo/public/cpp/bindings/message_header_validator.h" | 32 #include "mojo/public/cpp/bindings/message_header_validator.h" |
34 #include "mojo/public/cpp/bindings/pipe_control_message_handler.h" | 33 #include "mojo/public/cpp/bindings/pipe_control_message_handler.h" |
35 #include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h" | 34 #include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h" |
36 #include "mojo/public/cpp/bindings/pipe_control_message_proxy.h" | 35 #include "mojo/public/cpp/bindings/pipe_control_message_proxy.h" |
37 | 36 |
38 namespace IPC { | 37 namespace IPC { |
39 | 38 |
40 namespace { | 39 namespace { |
41 | 40 |
42 class ChannelAssociatedGroupController | 41 class ChannelAssociatedGroupController |
43 : public mojo::AssociatedGroupController, | 42 : public mojo::AssociatedGroupController, |
44 public mojo::MessageReceiver, | 43 public mojo::MessageReceiver, |
45 public mojo::PipeControlMessageHandlerDelegate { | 44 public mojo::PipeControlMessageHandlerDelegate { |
46 public: | 45 public: |
47 ChannelAssociatedGroupController( | 46 ChannelAssociatedGroupController(bool set_interface_id_namespace_bit, |
48 bool set_interface_id_namespace_bit, | 47 mojo::ScopedMessagePipeHandle handle) |
49 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) | |
50 : mojo::AssociatedGroupController(base::ThreadTaskRunnerHandle::Get()), | 48 : mojo::AssociatedGroupController(base::ThreadTaskRunnerHandle::Get()), |
51 task_runner_(ipc_task_runner), | 49 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
52 proxy_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 50 id_namespace_mask_(set_interface_id_namespace_bit ? |
53 set_interface_id_namespace_bit_(set_interface_id_namespace_bit), | 51 mojo::kInterfaceIdNamespaceMask : 0), |
| 52 associated_group_(CreateAssociatedGroup()), |
| 53 connector_(std::move(handle), mojo::Connector::SINGLE_THREADED_SEND, |
| 54 base::ThreadTaskRunnerHandle::Get()), |
54 header_validator_( | 55 header_validator_( |
55 "IPC::mojom::Bootstrap [master] MessageHeaderValidator", this), | 56 "IPC::mojom::Bootstrap [master] MessageHeaderValidator", this), |
56 control_message_handler_(this), | 57 control_message_handler_(this), |
57 control_message_proxy_thunk_(this), | 58 control_message_proxy_(&connector_) { |
58 control_message_proxy_(&control_message_proxy_thunk_) { | 59 connector_.set_incoming_receiver(&header_validator_); |
59 thread_checker_.DetachFromThread(); | 60 connector_.set_connection_error_handler( |
| 61 base::Bind(&ChannelAssociatedGroupController::OnPipeError, |
| 62 base::Unretained(this))); |
60 control_message_handler_.SetDescription( | 63 control_message_handler_.SetDescription( |
61 "IPC::mojom::Bootstrap [master] PipeControlMessageHandler"); | 64 "IPC::mojom::Bootstrap [master] PipeControlMessageHandler"); |
62 } | 65 } |
63 | 66 |
64 void Bind(mojo::ScopedMessagePipeHandle handle) { | 67 mojo::AssociatedGroup* associated_group() { return associated_group_.get(); } |
65 DCHECK(thread_checker_.CalledOnValidThread()); | |
66 DCHECK(task_runner_->BelongsToCurrentThread()); | |
67 thread_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
68 connector_.reset(new mojo::Connector( | |
69 std::move(handle), mojo::Connector::SINGLE_THREADED_SEND, | |
70 task_runner_)); | |
71 connector_->set_incoming_receiver(&header_validator_); | |
72 connector_->set_connection_error_handler( | |
73 base::Bind(&ChannelAssociatedGroupController::OnPipeError, | |
74 base::Unretained(this))); | |
75 | |
76 std::vector<std::unique_ptr<mojo::Message>> outgoing_messages; | |
77 std::swap(outgoing_messages, outgoing_messages_); | |
78 for (auto& message : outgoing_messages) | |
79 SendMessage(message.get()); | |
80 } | |
81 | |
82 void CreateChannelEndpoints(mojom::ChannelAssociatedPtr* sender, | |
83 mojom::ChannelAssociatedRequest* receiver) { | |
84 mojo::InterfaceId sender_id, receiver_id; | |
85 if (set_interface_id_namespace_bit_) { | |
86 sender_id = 1 | mojo::kInterfaceIdNamespaceMask; | |
87 receiver_id = 1; | |
88 } else { | |
89 sender_id = 1; | |
90 receiver_id = 1 | mojo::kInterfaceIdNamespaceMask; | |
91 } | |
92 | |
93 { | |
94 base::AutoLock locker(lock_); | |
95 Endpoint* sender_endpoint = new Endpoint(this, sender_id); | |
96 Endpoint* receiver_endpoint = new Endpoint(this, receiver_id); | |
97 endpoints_.insert({ sender_id, sender_endpoint }); | |
98 endpoints_.insert({ receiver_id, receiver_endpoint }); | |
99 } | |
100 | |
101 mojo::ScopedInterfaceEndpointHandle sender_handle = | |
102 CreateScopedInterfaceEndpointHandle(sender_id, true); | |
103 mojo::ScopedInterfaceEndpointHandle receiver_handle = | |
104 CreateScopedInterfaceEndpointHandle(receiver_id, true); | |
105 | |
106 sender->Bind(mojom::ChannelAssociatedPtrInfo(std::move(sender_handle), 0)); | |
107 receiver->Bind(std::move(receiver_handle)); | |
108 } | |
109 | 68 |
110 void ShutDown() { | 69 void ShutDown() { |
111 DCHECK(thread_checker_.CalledOnValidThread()); | 70 DCHECK(thread_checker_.CalledOnValidThread()); |
112 connector_->CloseMessagePipe(); | 71 connector_.CloseMessagePipe(); |
113 OnPipeError(); | 72 OnPipeError(); |
114 connector_.reset(); | 73 associated_group_.reset(); |
| 74 } |
| 75 |
| 76 void SetProxyTaskRunner( |
| 77 scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner) { |
| 78 proxy_task_runner_ = proxy_task_runner; |
115 } | 79 } |
116 | 80 |
117 // mojo::AssociatedGroupController: | 81 // mojo::AssociatedGroupController: |
118 void CreateEndpointHandlePair( | 82 void CreateEndpointHandlePair( |
119 mojo::ScopedInterfaceEndpointHandle* local_endpoint, | 83 mojo::ScopedInterfaceEndpointHandle* local_endpoint, |
120 mojo::ScopedInterfaceEndpointHandle* remote_endpoint) override { | 84 mojo::ScopedInterfaceEndpointHandle* remote_endpoint) override { |
121 base::AutoLock locker(lock_); | 85 base::AutoLock locker(lock_); |
122 uint32_t id = 0; | 86 uint32_t id = 0; |
123 do { | 87 do { |
124 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask) | 88 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask) |
125 next_interface_id_ = 2; | 89 next_interface_id_ = 1; |
126 id = next_interface_id_++; | 90 id = (next_interface_id_++) | id_namespace_mask_; |
127 if (set_interface_id_namespace_bit_) | |
128 id |= mojo::kInterfaceIdNamespaceMask; | |
129 } while (ContainsKey(endpoints_, id)); | 91 } while (ContainsKey(endpoints_, id)); |
130 | 92 |
131 Endpoint* endpoint = new Endpoint(this, id); | 93 Endpoint* endpoint = new Endpoint(this, id); |
132 if (encountered_error_) | 94 if (encountered_error_) |
133 endpoint->set_peer_closed(); | 95 endpoint->set_peer_closed(); |
134 endpoints_.insert({ id, endpoint }); | 96 endpoints_.insert({ id, endpoint }); |
135 | 97 |
136 *local_endpoint = CreateScopedInterfaceEndpointHandle(id, true); | 98 *local_endpoint = CreateScopedInterfaceEndpointHandle(id, true); |
137 *remote_endpoint = CreateScopedInterfaceEndpointHandle(id, false); | 99 *remote_endpoint = CreateScopedInterfaceEndpointHandle(id, false); |
138 } | 100 } |
(...skipping 13 matching lines...) Expand all Loading... |
152 } | 114 } |
153 | 115 |
154 void CloseEndpointHandle(mojo::InterfaceId id, bool is_local) override { | 116 void CloseEndpointHandle(mojo::InterfaceId id, bool is_local) override { |
155 if (!mojo::IsValidInterfaceId(id)) | 117 if (!mojo::IsValidInterfaceId(id)) |
156 return; | 118 return; |
157 | 119 |
158 base::AutoLock locker(lock_); | 120 base::AutoLock locker(lock_); |
159 if (!is_local) { | 121 if (!is_local) { |
160 DCHECK(ContainsKey(endpoints_, id)); | 122 DCHECK(ContainsKey(endpoints_, id)); |
161 DCHECK(!mojo::IsMasterInterfaceId(id)); | 123 DCHECK(!mojo::IsMasterInterfaceId(id)); |
162 control_message_proxy_.NotifyEndpointClosedBeforeSent(id); | 124 NotifyEndpointClosedBeforeSent(id); |
163 return; | 125 return; |
164 } | 126 } |
165 | 127 |
166 DCHECK(ContainsKey(endpoints_, id)); | 128 DCHECK(ContainsKey(endpoints_, id)); |
167 Endpoint* endpoint = endpoints_[id].get(); | 129 Endpoint* endpoint = endpoints_[id].get(); |
168 DCHECK(!endpoint->client()); | 130 DCHECK(!endpoint->client()); |
169 DCHECK(!endpoint->closed()); | 131 DCHECK(!endpoint->closed()); |
170 MarkClosedAndMaybeRemove(endpoint); | 132 MarkClosedAndMaybeRemove(endpoint); |
171 | 133 |
172 if (!mojo::IsMasterInterfaceId(id)) | 134 if (!mojo::IsMasterInterfaceId(id)) |
173 control_message_proxy_.NotifyPeerEndpointClosed(id); | 135 NotifyPeerEndpointClosed(id); |
174 } | 136 } |
175 | 137 |
176 mojo::InterfaceEndpointController* AttachEndpointClient( | 138 mojo::InterfaceEndpointController* AttachEndpointClient( |
177 const mojo::ScopedInterfaceEndpointHandle& handle, | 139 const mojo::ScopedInterfaceEndpointHandle& handle, |
178 mojo::InterfaceEndpointClient* client, | 140 mojo::InterfaceEndpointClient* client, |
179 scoped_refptr<base::SingleThreadTaskRunner> runner) override { | 141 scoped_refptr<base::SingleThreadTaskRunner> runner) override { |
180 const mojo::InterfaceId id = handle.id(); | 142 const mojo::InterfaceId id = handle.id(); |
181 | 143 |
182 DCHECK(mojo::IsValidInterfaceId(id)); | 144 DCHECK(mojo::IsValidInterfaceId(id)); |
183 DCHECK(client); | 145 DCHECK(client); |
(...skipping 17 matching lines...) Expand all Loading... |
201 DCHECK(mojo::IsValidInterfaceId(id)); | 163 DCHECK(mojo::IsValidInterfaceId(id)); |
202 | 164 |
203 base::AutoLock locker(lock_); | 165 base::AutoLock locker(lock_); |
204 DCHECK(ContainsKey(endpoints_, id)); | 166 DCHECK(ContainsKey(endpoints_, id)); |
205 | 167 |
206 Endpoint* endpoint = endpoints_[id].get(); | 168 Endpoint* endpoint = endpoints_[id].get(); |
207 endpoint->DetachClient(); | 169 endpoint->DetachClient(); |
208 } | 170 } |
209 | 171 |
210 void RaiseError() override { | 172 void RaiseError() override { |
211 if (IsRunningOnIPCThread()) { | 173 if (task_runner_->BelongsToCurrentThread()) { |
212 connector_->RaiseError(); | 174 connector_.RaiseError(); |
213 } else { | 175 } else { |
214 task_runner_->PostTask( | 176 task_runner_->PostTask( |
215 FROM_HERE, | 177 FROM_HERE, |
216 base::Bind(&ChannelAssociatedGroupController::RaiseError, this)); | 178 base::Bind(&ChannelAssociatedGroupController::RaiseError, this)); |
217 } | 179 } |
218 } | 180 } |
219 | 181 |
220 private: | 182 private: |
221 class Endpoint; | 183 class Endpoint; |
222 class ControlMessageProxyThunk; | |
223 friend class Endpoint; | 184 friend class Endpoint; |
224 friend class ControlMessageProxyThunk; | |
225 | 185 |
226 class Endpoint : public base::RefCountedThreadSafe<Endpoint>, | 186 class Endpoint : public base::RefCountedThreadSafe<Endpoint>, |
227 public mojo::InterfaceEndpointController { | 187 public mojo::InterfaceEndpointController { |
228 public: | 188 public: |
229 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id) | 189 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id) |
230 : controller_(controller), id_(id) {} | 190 : controller_(controller), id_(id) {} |
231 | 191 |
232 mojo::InterfaceId id() const { return id_; } | 192 mojo::InterfaceId id() const { return id_; } |
233 | 193 |
234 bool closed() const { | 194 bool closed() const { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 | 253 |
294 // TODO(rockot): Implement sync waiting. | 254 // TODO(rockot): Implement sync waiting. |
295 NOTREACHED(); | 255 NOTREACHED(); |
296 } | 256 } |
297 | 257 |
298 bool SyncWatch(const bool* should_stop) override { | 258 bool SyncWatch(const bool* should_stop) override { |
299 DCHECK(task_runner_->BelongsToCurrentThread()); | 259 DCHECK(task_runner_->BelongsToCurrentThread()); |
300 | 260 |
301 // It's not legal to make sync calls from the master endpoint's thread, | 261 // It's not legal to make sync calls from the master endpoint's thread, |
302 // and in fact they must only happen from the proxy task runner. | 262 // and in fact they must only happen from the proxy task runner. |
303 DCHECK(!controller_->IsRunningOnIPCThread()); | 263 DCHECK(!controller_->task_runner_->BelongsToCurrentThread()); |
304 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread()); | 264 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread()); |
305 | 265 |
306 // TODO(rockot): Implement sync waiting. | 266 // TODO(rockot): Implement sync waiting. |
307 NOTREACHED(); | 267 NOTREACHED(); |
308 return false; | 268 return false; |
309 } | 269 } |
310 | 270 |
311 private: | 271 private: |
312 friend class base::RefCountedThreadSafe<Endpoint>; | 272 friend class base::RefCountedThreadSafe<Endpoint>; |
313 | 273 |
314 ~Endpoint() override {} | 274 ~Endpoint() override {} |
315 | 275 |
316 ChannelAssociatedGroupController* const controller_; | 276 ChannelAssociatedGroupController* const controller_; |
317 const mojo::InterfaceId id_; | 277 const mojo::InterfaceId id_; |
318 | 278 |
319 bool closed_ = false; | 279 bool closed_ = false; |
320 bool peer_closed_ = false; | 280 bool peer_closed_ = false; |
321 mojo::InterfaceEndpointClient* client_ = nullptr; | 281 mojo::InterfaceEndpointClient* client_ = nullptr; |
322 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 282 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
323 | 283 |
324 DISALLOW_COPY_AND_ASSIGN(Endpoint); | 284 DISALLOW_COPY_AND_ASSIGN(Endpoint); |
325 }; | 285 }; |
326 | 286 |
327 class ControlMessageProxyThunk : public MessageReceiver { | |
328 public: | |
329 explicit ControlMessageProxyThunk( | |
330 ChannelAssociatedGroupController* controller) | |
331 : controller_(controller) {} | |
332 | |
333 private: | |
334 // MessageReceiver: | |
335 bool Accept(mojo::Message* message) override { | |
336 return controller_->SendMessage(message); | |
337 } | |
338 | |
339 ChannelAssociatedGroupController* controller_; | |
340 | |
341 DISALLOW_COPY_AND_ASSIGN(ControlMessageProxyThunk); | |
342 }; | |
343 | |
344 ~ChannelAssociatedGroupController() override { | 287 ~ChannelAssociatedGroupController() override { |
345 base::AutoLock locker(lock_); | 288 base::AutoLock locker(lock_); |
| 289 |
346 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) { | 290 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) { |
347 Endpoint* endpoint = iter->second.get(); | 291 Endpoint* endpoint = iter->second.get(); |
348 ++iter; | 292 ++iter; |
349 | 293 |
350 DCHECK(endpoint->closed()); | 294 DCHECK(endpoint->closed()); |
351 MarkPeerClosedAndMaybeRemove(endpoint); | 295 MarkPeerClosedAndMaybeRemove(endpoint); |
352 } | 296 } |
353 | 297 |
354 DCHECK(endpoints_.empty()); | 298 DCHECK(endpoints_.empty()); |
355 } | 299 } |
356 | 300 |
357 bool IsRunningOnIPCThread() { | |
358 // |task_runner_| is always non-null but may incorrectly report that | |
359 // BelongsToCurrentThread() == false during shutdown. By the time shutdown | |
360 // occurs, |thread_task_runner_| will be non-null and is guaranteed to run | |
361 // tasks on the same thread as |task_runner_|. | |
362 return task_runner_->BelongsToCurrentThread() || | |
363 (thread_task_runner_ && thread_task_runner_->BelongsToCurrentThread()); | |
364 } | |
365 | |
366 bool SendMessage(mojo::Message* message) { | 301 bool SendMessage(mojo::Message* message) { |
367 if (IsRunningOnIPCThread()) { | 302 if (task_runner_->BelongsToCurrentThread()) { |
368 DCHECK(thread_checker_.CalledOnValidThread()); | 303 DCHECK(thread_checker_.CalledOnValidThread()); |
369 if (!connector_) { | 304 return connector_.Accept(message); |
370 // Pipe may not be bound yet, so we queue the message. | |
371 std::unique_ptr<mojo::Message> queued_message(new mojo::Message); | |
372 message->MoveTo(queued_message.get()); | |
373 outgoing_messages_.emplace_back(std::move(queued_message)); | |
374 return true; | |
375 } | |
376 return connector_->Accept(message); | |
377 } else { | 305 } else { |
378 // We always post tasks to the master endpoint thread when called from the | 306 // We always post tasks to the master endpoint thread when called from the |
379 // proxy thread in order to simulate IPC::ChannelProxy::Send behavior. | 307 // proxy thread in order to simulate IPC::ChannelProxy::Send behavior. |
380 DCHECK(proxy_task_runner_->BelongsToCurrentThread()); | 308 DCHECK(proxy_task_runner_ && |
| 309 proxy_task_runner_->BelongsToCurrentThread()); |
381 std::unique_ptr<mojo::Message> passed_message(new mojo::Message); | 310 std::unique_ptr<mojo::Message> passed_message(new mojo::Message); |
382 message->MoveTo(passed_message.get()); | 311 message->MoveTo(passed_message.get()); |
383 task_runner_->PostTask( | 312 task_runner_->PostTask( |
384 FROM_HERE, | 313 FROM_HERE, |
385 base::Bind( | 314 base::Bind( |
386 &ChannelAssociatedGroupController::SendMessageOnMasterThread, | 315 &ChannelAssociatedGroupController::SendMessageOnMasterThread, |
387 this, base::Passed(&passed_message))); | 316 this, base::Passed(&passed_message))); |
388 return true; | 317 return true; |
389 } | 318 } |
390 } | 319 } |
(...skipping 19 matching lines...) Expand all Loading... |
410 Endpoint* endpoint = iter->second.get(); | 339 Endpoint* endpoint = iter->second.get(); |
411 ++iter; | 340 ++iter; |
412 | 341 |
413 if (endpoint->client()) | 342 if (endpoint->client()) |
414 endpoints_to_notify.push_back(endpoint); | 343 endpoints_to_notify.push_back(endpoint); |
415 | 344 |
416 MarkPeerClosedAndMaybeRemove(endpoint); | 345 MarkPeerClosedAndMaybeRemove(endpoint); |
417 } | 346 } |
418 | 347 |
419 for (auto& endpoint : endpoints_to_notify) { | 348 for (auto& endpoint : endpoints_to_notify) { |
420 // Because a notification may in turn detach any endpoint, we have to | 349 // Because an notification may in turn detach any endpoint, we have to |
421 // check each client again here. | 350 // check each client again here. |
422 if (endpoint->client()) | 351 if (endpoint->client()) |
423 NotifyEndpointOfError(endpoint.get(), false /* force_async */); | 352 NotifyEndpointOfError(endpoint.get(), false /* force_async */); |
424 } | 353 } |
425 } | 354 } |
426 | 355 |
427 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) { | 356 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) { |
428 lock_.AssertAcquired(); | 357 lock_.AssertAcquired(); |
429 DCHECK(endpoint->task_runner() && endpoint->client()); | 358 DCHECK(endpoint->task_runner() && endpoint->client()); |
430 if (endpoint->task_runner()->BelongsToCurrentThread() && !force_async) { | 359 if (endpoint->task_runner()->BelongsToCurrentThread() && !force_async) { |
(...skipping 25 matching lines...) Expand all Loading... |
456 endpoints_.erase(endpoint->id()); | 385 endpoints_.erase(endpoint->id()); |
457 } | 386 } |
458 | 387 |
459 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) { | 388 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) { |
460 lock_.AssertAcquired(); | 389 lock_.AssertAcquired(); |
461 endpoint->set_peer_closed(); | 390 endpoint->set_peer_closed(); |
462 if (endpoint->closed() && endpoint->peer_closed()) | 391 if (endpoint->closed() && endpoint->peer_closed()) |
463 endpoints_.erase(endpoint->id()); | 392 endpoints_.erase(endpoint->id()); |
464 } | 393 } |
465 | 394 |
| 395 void NotifyPeerEndpointClosed(mojo::InterfaceId id) { |
| 396 if (task_runner_->BelongsToCurrentThread()) { |
| 397 if (connector_.is_valid()) |
| 398 control_message_proxy_.NotifyPeerEndpointClosed(id); |
| 399 } else { |
| 400 task_runner_->PostTask( |
| 401 FROM_HERE, |
| 402 base::Bind(&ChannelAssociatedGroupController |
| 403 ::NotifyPeerEndpointClosed, this, id)); |
| 404 } |
| 405 } |
| 406 |
| 407 void NotifyEndpointClosedBeforeSent(mojo::InterfaceId id) { |
| 408 if (task_runner_->BelongsToCurrentThread()) { |
| 409 if (connector_.is_valid()) |
| 410 control_message_proxy_.NotifyEndpointClosedBeforeSent(id); |
| 411 } else { |
| 412 task_runner_->PostTask( |
| 413 FROM_HERE, |
| 414 base::Bind(&ChannelAssociatedGroupController |
| 415 ::NotifyEndpointClosedBeforeSent, this, id)); |
| 416 } |
| 417 } |
| 418 |
466 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) { | 419 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) { |
467 lock_.AssertAcquired(); | 420 lock_.AssertAcquired(); |
468 DCHECK(!inserted || !*inserted); | 421 DCHECK(!inserted || !*inserted); |
469 | 422 |
470 auto iter = endpoints_.find(id); | 423 auto iter = endpoints_.find(id); |
471 if (iter != endpoints_.end()) | 424 if (iter != endpoints_.end()) |
472 return iter->second.get(); | 425 return iter->second.get(); |
473 | 426 |
474 Endpoint* endpoint = new Endpoint(this, id); | 427 Endpoint* endpoint = new Endpoint(this, id); |
475 endpoints_.insert({ id, endpoint }); | 428 endpoints_.insert({ id, endpoint }); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 RaiseError(); | 503 RaiseError(); |
551 } | 504 } |
552 | 505 |
553 Endpoint* GetEndpointForDispatch(mojo::InterfaceId id) { | 506 Endpoint* GetEndpointForDispatch(mojo::InterfaceId id) { |
554 lock_.AssertAcquired(); | 507 lock_.AssertAcquired(); |
555 bool inserted = false; | 508 bool inserted = false; |
556 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted); | 509 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted); |
557 if (inserted) { | 510 if (inserted) { |
558 MarkClosedAndMaybeRemove(endpoint); | 511 MarkClosedAndMaybeRemove(endpoint); |
559 if (!mojo::IsMasterInterfaceId(id)) | 512 if (!mojo::IsMasterInterfaceId(id)) |
560 control_message_proxy_.NotifyPeerEndpointClosed(id); | 513 NotifyPeerEndpointClosed(id); |
561 return nullptr; | 514 return nullptr; |
562 } | 515 } |
563 | 516 |
564 if (endpoint->closed()) | 517 if (endpoint->closed()) |
565 return nullptr; | 518 return nullptr; |
566 | 519 |
567 return endpoint; | 520 return endpoint; |
568 } | 521 } |
569 | 522 |
570 // mojo::PipeControlMessageHandlerDelegate: | 523 // mojo::PipeControlMessageHandlerDelegate: |
571 bool OnPeerAssociatedEndpointClosed(mojo::InterfaceId id) override { | 524 bool OnPeerAssociatedEndpointClosed(mojo::InterfaceId id) override { |
572 DCHECK(thread_checker_.CalledOnValidThread()); | 525 DCHECK(thread_checker_.CalledOnValidThread()); |
573 | 526 |
574 if (mojo::IsMasterInterfaceId(id)) | 527 if (mojo::IsMasterInterfaceId(id)) |
575 return false; | 528 return false; |
576 | 529 |
577 scoped_refptr<ChannelAssociatedGroupController> keepalive(this); | |
578 base::AutoLock locker(lock_); | 530 base::AutoLock locker(lock_); |
579 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr); | 531 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr); |
580 if (!endpoint->peer_closed()) { | 532 if (!endpoint->peer_closed()) { |
581 if (endpoint->client()) | 533 if (endpoint->client()) |
582 NotifyEndpointOfError(endpoint.get(), false /* force_async */); | 534 NotifyEndpointOfError(endpoint.get(), false /* force_async */); |
583 MarkPeerClosedAndMaybeRemove(endpoint.get()); | 535 MarkPeerClosedAndMaybeRemove(endpoint.get()); |
584 } | 536 } |
585 | 537 |
586 return true; | 538 return true; |
587 } | 539 } |
588 | 540 |
589 bool OnAssociatedEndpointClosedBeforeSent(mojo::InterfaceId id) override { | 541 bool OnAssociatedEndpointClosedBeforeSent(mojo::InterfaceId id) override { |
590 DCHECK(thread_checker_.CalledOnValidThread()); | 542 DCHECK(thread_checker_.CalledOnValidThread()); |
591 | 543 |
592 if (mojo::IsMasterInterfaceId(id)) | 544 if (mojo::IsMasterInterfaceId(id)) |
593 return false; | 545 return false; |
594 | 546 |
595 base::AutoLock locker(lock_); | 547 base::AutoLock locker(lock_); |
596 Endpoint* endpoint = FindOrInsertEndpoint(id, nullptr); | 548 Endpoint* endpoint = FindOrInsertEndpoint(id, nullptr); |
597 DCHECK(!endpoint->closed()); | 549 DCHECK(!endpoint->closed()); |
598 MarkClosedAndMaybeRemove(endpoint); | 550 MarkClosedAndMaybeRemove(endpoint); |
599 control_message_proxy_.NotifyPeerEndpointClosed(id); | 551 control_message_proxy_.NotifyPeerEndpointClosed(id); |
600 return true; | 552 return true; |
601 } | 553 } |
602 | 554 |
603 // Checked in places which must be run on the master endpoint's thread. | 555 // Checked in places which must be run on the master endpoint's thread. |
604 base::ThreadChecker thread_checker_; | 556 base::ThreadChecker thread_checker_; |
605 | 557 |
606 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 558 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
607 | |
608 // A TaskRunner that runs tasks on the same thread as |task_runner_| but which | |
609 // is used exclusively to do thread safety checking. This is an unfortunate | |
610 // consequence of bad interaction between some TaskRunner implementations and | |
611 // MessageLoop destruction which may cause the user-provided |task_runner_| to | |
612 // incorrectly report that BelongsToCurrentThread() == false during shutdown. | |
613 scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_; | |
614 | |
615 scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_; | 559 scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_; |
616 const bool set_interface_id_namespace_bit_; | 560 const uint32_t id_namespace_mask_; |
617 std::unique_ptr<mojo::Connector> connector_; | 561 std::unique_ptr<mojo::AssociatedGroup> associated_group_; |
| 562 mojo::Connector connector_; |
618 mojo::MessageHeaderValidator header_validator_; | 563 mojo::MessageHeaderValidator header_validator_; |
619 mojo::PipeControlMessageHandler control_message_handler_; | 564 mojo::PipeControlMessageHandler control_message_handler_; |
620 ControlMessageProxyThunk control_message_proxy_thunk_; | |
621 mojo::PipeControlMessageProxy control_message_proxy_; | |
622 | |
623 // Outgoing messages that were sent before this controller was bound to a | |
624 // real message pipe. | |
625 std::vector<std::unique_ptr<mojo::Message>> outgoing_messages_; | |
626 | 565 |
627 // Guards the fields below for thread-safe access. | 566 // Guards the fields below for thread-safe access. |
628 base::Lock lock_; | 567 base::Lock lock_; |
629 | 568 |
630 bool encountered_error_ = false; | 569 bool encountered_error_ = false; |
631 | 570 uint32_t next_interface_id_ = 1; |
632 // ID #1 is reserved for the mojom::Channel interface. | |
633 uint32_t next_interface_id_ = 2; | |
634 | |
635 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_; | 571 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_; |
| 572 mojo::PipeControlMessageProxy control_message_proxy_; |
636 | 573 |
637 DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController); | 574 DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController); |
638 }; | 575 }; |
639 | 576 |
640 class MojoBootstrapImpl : public MojoBootstrap { | 577 class BootstrapMasterProxy { |
641 public: | 578 public: |
642 MojoBootstrapImpl( | 579 BootstrapMasterProxy() {} |
643 mojo::ScopedMessagePipeHandle handle, | 580 ~BootstrapMasterProxy() { |
644 Delegate* delegate, | 581 endpoint_client_.reset(); |
645 const scoped_refptr<ChannelAssociatedGroupController> controller) | 582 proxy_.reset(); |
646 : controller_(controller), | 583 if (controller_) |
647 handle_(std::move(handle)), | 584 controller_->ShutDown(); |
648 delegate_(delegate) { | 585 } |
649 associated_group_ = controller_->CreateAssociatedGroup(); | 586 |
650 } | 587 void Bind(mojo::ScopedMessagePipeHandle handle) { |
651 | 588 DCHECK(!controller_); |
652 ~MojoBootstrapImpl() override { | 589 controller_ = new ChannelAssociatedGroupController(true, std::move(handle)); |
653 controller_->ShutDown(); | 590 endpoint_client_.reset(new mojo::InterfaceEndpointClient( |
654 } | 591 controller_->CreateLocalEndpointHandle(mojo::kMasterInterfaceId), |
655 | 592 nullptr, |
656 private: | 593 base::MakeUnique<typename mojom::Bootstrap::ResponseValidator_>(), |
657 // MojoBootstrap: | 594 false, base::ThreadTaskRunnerHandle::Get())); |
658 void Connect() override { | 595 proxy_.reset(new mojom::BootstrapProxy(endpoint_client_.get())); |
659 controller_->Bind(std::move(handle_)); | 596 proxy_->serialization_context()->group_controller = controller_; |
660 | 597 } |
661 IPC::mojom::ChannelAssociatedPtr sender; | 598 |
662 IPC::mojom::ChannelAssociatedRequest receiver; | 599 void set_connection_error_handler(const base::Closure& handler) { |
663 controller_->CreateChannelEndpoints(&sender, &receiver); | 600 DCHECK(endpoint_client_); |
664 | 601 endpoint_client_->set_connection_error_handler(handler); |
665 delegate_->OnPipesAvailable(std::move(sender), std::move(receiver)); | 602 } |
666 } | 603 |
| 604 mojo::AssociatedGroup* associated_group() { |
| 605 DCHECK(controller_); |
| 606 return controller_->associated_group(); |
| 607 } |
| 608 |
| 609 ChannelAssociatedGroupController* controller() { |
| 610 DCHECK(controller_); |
| 611 return controller_.get(); |
| 612 } |
| 613 |
| 614 mojom::Bootstrap* operator->() { |
| 615 DCHECK(proxy_); |
| 616 return proxy_.get(); |
| 617 } |
| 618 |
| 619 private: |
| 620 std::unique_ptr<mojom::BootstrapProxy> proxy_; |
| 621 scoped_refptr<ChannelAssociatedGroupController> controller_; |
| 622 std::unique_ptr<mojo::InterfaceEndpointClient> endpoint_client_; |
| 623 |
| 624 DISALLOW_COPY_AND_ASSIGN(BootstrapMasterProxy); |
| 625 }; |
| 626 |
| 627 class BootstrapMasterBinding { |
| 628 public: |
| 629 explicit BootstrapMasterBinding(mojom::Bootstrap* impl) { |
| 630 stub_.set_sink(impl); |
| 631 } |
| 632 |
| 633 ~BootstrapMasterBinding() { |
| 634 endpoint_client_.reset(); |
| 635 if (controller_) |
| 636 controller_->ShutDown(); |
| 637 } |
| 638 |
| 639 void set_connection_error_handler(const base::Closure& handler) { |
| 640 DCHECK(endpoint_client_); |
| 641 endpoint_client_->set_connection_error_handler(handler); |
| 642 } |
| 643 |
| 644 mojo::AssociatedGroup* associated_group() { |
| 645 DCHECK(controller_); |
| 646 return controller_->associated_group(); |
| 647 } |
| 648 |
| 649 ChannelAssociatedGroupController* controller() { |
| 650 DCHECK(controller_); |
| 651 return controller_.get(); |
| 652 } |
| 653 |
| 654 void Bind(mojo::ScopedMessagePipeHandle handle) { |
| 655 DCHECK(!controller_); |
| 656 controller_ = |
| 657 new ChannelAssociatedGroupController(false, std::move(handle)); |
| 658 stub_.serialization_context()->group_controller = controller_; |
| 659 |
| 660 endpoint_client_.reset(new mojo::InterfaceEndpointClient( |
| 661 controller_->CreateLocalEndpointHandle(mojo::kMasterInterfaceId), |
| 662 &stub_, |
| 663 base::MakeUnique<typename mojom::Bootstrap::RequestValidator_>(), |
| 664 false, base::ThreadTaskRunnerHandle::Get())); |
| 665 } |
| 666 |
| 667 private: |
| 668 mojom::BootstrapStub stub_; |
| 669 scoped_refptr<ChannelAssociatedGroupController> controller_; |
| 670 std::unique_ptr<mojo::InterfaceEndpointClient> endpoint_client_; |
| 671 |
| 672 DISALLOW_COPY_AND_ASSIGN(BootstrapMasterBinding); |
| 673 }; |
| 674 |
| 675 // MojoBootstrap for the server process. You should create the instance |
| 676 // using MojoBootstrap::Create(). |
| 677 class MojoServerBootstrap : public MojoBootstrap { |
| 678 public: |
| 679 MojoServerBootstrap(); |
| 680 |
| 681 private: |
| 682 // MojoBootstrap implementation. |
| 683 void Connect() override; |
667 | 684 |
668 mojo::AssociatedGroup* GetAssociatedGroup() override { | 685 mojo::AssociatedGroup* GetAssociatedGroup() override { |
669 return associated_group_.get(); | 686 return bootstrap_.associated_group(); |
670 } | 687 } |
671 | 688 |
672 scoped_refptr<ChannelAssociatedGroupController> controller_; | 689 void SetProxyTaskRunner( |
673 | 690 scoped_refptr<base::SingleThreadTaskRunner> task_runner) override { |
674 mojo::ScopedMessagePipeHandle handle_; | 691 bootstrap_.controller()->SetProxyTaskRunner(task_runner); |
675 Delegate* delegate_; | 692 } |
676 std::unique_ptr<mojo::AssociatedGroup> associated_group_; | 693 |
677 | 694 void OnInitDone(int32_t peer_pid); |
678 DISALLOW_COPY_AND_ASSIGN(MojoBootstrapImpl); | 695 |
679 }; | 696 BootstrapMasterProxy bootstrap_; |
| 697 IPC::mojom::ChannelAssociatedPtrInfo send_channel_; |
| 698 IPC::mojom::ChannelAssociatedRequest receive_channel_request_; |
| 699 |
| 700 DISALLOW_COPY_AND_ASSIGN(MojoServerBootstrap); |
| 701 }; |
| 702 |
| 703 MojoServerBootstrap::MojoServerBootstrap() = default; |
| 704 |
| 705 void MojoServerBootstrap::Connect() { |
| 706 DCHECK_EQ(state(), STATE_INITIALIZED); |
| 707 |
| 708 bootstrap_.Bind(TakeHandle()); |
| 709 bootstrap_.set_connection_error_handler( |
| 710 base::Bind(&MojoServerBootstrap::Fail, base::Unretained(this))); |
| 711 |
| 712 IPC::mojom::ChannelAssociatedRequest send_channel_request; |
| 713 IPC::mojom::ChannelAssociatedPtrInfo receive_channel; |
| 714 |
| 715 bootstrap_.associated_group()->CreateAssociatedInterface( |
| 716 mojo::AssociatedGroup::WILL_PASS_REQUEST, &send_channel_, |
| 717 &send_channel_request); |
| 718 bootstrap_.associated_group()->CreateAssociatedInterface( |
| 719 mojo::AssociatedGroup::WILL_PASS_PTR, &receive_channel, |
| 720 &receive_channel_request_); |
| 721 |
| 722 bootstrap_->Init( |
| 723 std::move(send_channel_request), std::move(receive_channel), |
| 724 GetSelfPID(), |
| 725 base::Bind(&MojoServerBootstrap::OnInitDone, base::Unretained(this))); |
| 726 |
| 727 set_state(STATE_WAITING_ACK); |
| 728 } |
| 729 |
| 730 void MojoServerBootstrap::OnInitDone(int32_t peer_pid) { |
| 731 if (state() != STATE_WAITING_ACK) { |
| 732 set_state(STATE_ERROR); |
| 733 LOG(ERROR) << "Got inconsistent message from client."; |
| 734 return; |
| 735 } |
| 736 |
| 737 set_state(STATE_READY); |
| 738 bootstrap_.set_connection_error_handler(base::Closure()); |
| 739 delegate()->OnPipesAvailable(std::move(send_channel_), |
| 740 std::move(receive_channel_request_), peer_pid); |
| 741 } |
| 742 |
| 743 // MojoBootstrap for client processes. You should create the instance |
| 744 // using MojoBootstrap::Create(). |
| 745 class MojoClientBootstrap : public MojoBootstrap, public mojom::Bootstrap { |
| 746 public: |
| 747 MojoClientBootstrap(); |
| 748 |
| 749 private: |
| 750 // MojoBootstrap implementation. |
| 751 void Connect() override; |
| 752 |
| 753 mojo::AssociatedGroup* GetAssociatedGroup() override { |
| 754 return binding_.associated_group(); |
| 755 } |
| 756 |
| 757 void SetProxyTaskRunner( |
| 758 scoped_refptr<base::SingleThreadTaskRunner> task_runner) override { |
| 759 binding_.controller()->SetProxyTaskRunner(task_runner); |
| 760 } |
| 761 |
| 762 // mojom::Bootstrap implementation. |
| 763 void Init(mojom::ChannelAssociatedRequest receive_channel, |
| 764 mojom::ChannelAssociatedPtrInfo send_channel, |
| 765 int32_t peer_pid, |
| 766 const InitCallback& callback) override; |
| 767 |
| 768 BootstrapMasterBinding binding_; |
| 769 |
| 770 DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap); |
| 771 }; |
| 772 |
| 773 MojoClientBootstrap::MojoClientBootstrap() : binding_(this) {} |
| 774 |
| 775 void MojoClientBootstrap::Connect() { |
| 776 binding_.Bind(TakeHandle()); |
| 777 binding_.set_connection_error_handler( |
| 778 base::Bind(&MojoClientBootstrap::Fail, base::Unretained(this))); |
| 779 } |
| 780 |
| 781 void MojoClientBootstrap::Init(mojom::ChannelAssociatedRequest receive_channel, |
| 782 mojom::ChannelAssociatedPtrInfo send_channel, |
| 783 int32_t peer_pid, |
| 784 const InitCallback& callback) { |
| 785 callback.Run(GetSelfPID()); |
| 786 set_state(STATE_READY); |
| 787 binding_.set_connection_error_handler(base::Closure()); |
| 788 delegate()->OnPipesAvailable(std::move(send_channel), |
| 789 std::move(receive_channel), peer_pid); |
| 790 } |
680 | 791 |
681 } // namespace | 792 } // namespace |
682 | 793 |
| 794 // MojoBootstrap |
| 795 |
683 // static | 796 // static |
684 std::unique_ptr<MojoBootstrap> MojoBootstrap::Create( | 797 std::unique_ptr<MojoBootstrap> MojoBootstrap::Create( |
685 mojo::ScopedMessagePipeHandle handle, | 798 mojo::ScopedMessagePipeHandle handle, |
686 Channel::Mode mode, | 799 Channel::Mode mode, |
687 Delegate* delegate, | 800 Delegate* delegate) { |
688 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) { | 801 CHECK(mode == Channel::MODE_CLIENT || mode == Channel::MODE_SERVER); |
689 return base::MakeUnique<MojoBootstrapImpl>( | 802 std::unique_ptr<MojoBootstrap> self = |
690 std::move(handle), delegate, | 803 mode == Channel::MODE_CLIENT |
691 new ChannelAssociatedGroupController(mode == Channel::MODE_SERVER, | 804 ? std::unique_ptr<MojoBootstrap>(new MojoClientBootstrap) |
692 ipc_task_runner)); | 805 : std::unique_ptr<MojoBootstrap>(new MojoServerBootstrap); |
| 806 |
| 807 self->Init(std::move(handle), delegate); |
| 808 return self; |
| 809 } |
| 810 |
| 811 MojoBootstrap::MojoBootstrap() : delegate_(NULL), state_(STATE_INITIALIZED) { |
| 812 } |
| 813 |
| 814 MojoBootstrap::~MojoBootstrap() {} |
| 815 |
| 816 void MojoBootstrap::Init(mojo::ScopedMessagePipeHandle handle, |
| 817 Delegate* delegate) { |
| 818 handle_ = std::move(handle); |
| 819 delegate_ = delegate; |
| 820 } |
| 821 |
| 822 base::ProcessId MojoBootstrap::GetSelfPID() const { |
| 823 #if defined(OS_LINUX) |
| 824 if (int global_pid = Channel::GetGlobalPid()) |
| 825 return global_pid; |
| 826 #endif // OS_LINUX |
| 827 #if defined(OS_NACL) |
| 828 return -1; |
| 829 #else |
| 830 return base::GetCurrentProcId(); |
| 831 #endif // defined(OS_NACL) |
| 832 } |
| 833 |
| 834 void MojoBootstrap::Fail() { |
| 835 set_state(STATE_ERROR); |
| 836 delegate()->OnBootstrapError(); |
| 837 } |
| 838 |
| 839 bool MojoBootstrap::HasFailed() const { |
| 840 return state() == STATE_ERROR; |
| 841 } |
| 842 |
| 843 mojo::ScopedMessagePipeHandle MojoBootstrap::TakeHandle() { |
| 844 return std::move(handle_); |
693 } | 845 } |
694 | 846 |
695 } // namespace IPC | 847 } // namespace IPC |
OLD | NEW |