blob: 5fa88ea5cc25bc003bf0e4b53ec8cd4f5a547aba [file] [log] [blame]
morrita54f6f80c2014-09-23 21:16:001// Copyright 2014 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
amistryd4aa70d2016-06-23 07:52:375#include "ipc/ipc_mojo_bootstrap.h"
morrita54f6f80c2014-09-23 21:16:006
tfarina10a5c062015-09-04 18:47:577#include <stdint.h>
rockot02b8e182016-07-13 20:08:308
9#include <map>
10#include <memory>
rockot9abe09b2016-08-02 20:57:3411#include <queue>
dchenge48600452015-12-28 02:24:5012#include <utility>
rockot0e4de5f2016-07-22 21:18:0713#include <vector>
tfarina10a5c062015-09-04 18:47:5714
rockota21316a2016-06-19 17:08:3615#include "base/callback.h"
morrita54f6f80c2014-09-23 21:16:0016#include "base/logging.h"
avi246998d82015-12-22 02:39:0417#include "base/macros.h"
danakj03de39b22016-04-23 04:21:0918#include "base/memory/ptr_util.h"
rockot02b8e182016-07-13 20:08:3019#include "base/single_thread_task_runner.h"
rockot02b8e182016-07-13 20:08:3020#include "base/synchronization/lock.h"
21#include "base/threading/thread_task_runner_handle.h"
rockot9abe09b2016-08-02 20:57:3422#include "ipc/mojo_event.h"
rockot02b8e182016-07-13 20:08:3023#include "mojo/public/cpp/bindings/associated_group.h"
24#include "mojo/public/cpp/bindings/associated_group_controller.h"
rockot02b8e182016-07-13 20:08:3025#include "mojo/public/cpp/bindings/connector.h"
26#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
27#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
28#include "mojo/public/cpp/bindings/interface_id.h"
rockot0e4de5f2016-07-22 21:18:0729#include "mojo/public/cpp/bindings/message.h"
rockot02b8e182016-07-13 20:08:3030#include "mojo/public/cpp/bindings/message_header_validator.h"
31#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
32#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
33#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
rockot9abe09b2016-08-02 20:57:3434#include "mojo/public/cpp/bindings/sync_handle_watcher.h"
morrita54f6f80c2014-09-23 21:16:0035
36namespace IPC {
37
38namespace {
39
rockot02b8e182016-07-13 20:08:3040class ChannelAssociatedGroupController
41 : public mojo::AssociatedGroupController,
42 public mojo::MessageReceiver,
43 public mojo::PipeControlMessageHandlerDelegate {
44 public:
rockot0e4de5f2016-07-22 21:18:0745 ChannelAssociatedGroupController(
46 bool set_interface_id_namespace_bit,
47 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner)
rockotb01ef6a2016-07-27 03:24:3248 : task_runner_(ipc_task_runner),
rockot0e4de5f2016-07-22 21:18:0749 proxy_task_runner_(base::ThreadTaskRunnerHandle::Get()),
50 set_interface_id_namespace_bit_(set_interface_id_namespace_bit),
rockot222e7dd2016-08-24 23:37:1151 filters_(this),
rockot02b8e182016-07-13 20:08:3052 control_message_handler_(this),
rockot0e4de5f2016-07-22 21:18:0753 control_message_proxy_thunk_(this),
54 control_message_proxy_(&control_message_proxy_thunk_) {
55 thread_checker_.DetachFromThread();
rockot02b8e182016-07-13 20:08:3056 control_message_handler_.SetDescription(
57 "IPC::mojom::Bootstrap [master] PipeControlMessageHandler");
rockot222e7dd2016-08-24 23:37:1158 filters_.Append<mojo::MessageHeaderValidator>(
59 "IPC::mojom::Bootstrap [master] MessageHeaderValidator");
rockot02b8e182016-07-13 20:08:3060 }
61
rockot0e4de5f2016-07-22 21:18:0762 void Bind(mojo::ScopedMessagePipeHandle handle) {
63 DCHECK(thread_checker_.CalledOnValidThread());
64 DCHECK(task_runner_->BelongsToCurrentThread());
rockot90984352016-07-25 17:36:1965
rockot0e4de5f2016-07-22 21:18:0766 connector_.reset(new mojo::Connector(
67 std::move(handle), mojo::Connector::SINGLE_THREADED_SEND,
68 task_runner_));
rockot222e7dd2016-08-24 23:37:1169 connector_->set_incoming_receiver(&filters_);
rockot0e4de5f2016-07-22 21:18:0770 connector_->set_connection_error_handler(
71 base::Bind(&ChannelAssociatedGroupController::OnPipeError,
72 base::Unretained(this)));
jcivelli2207af12017-01-26 20:46:0073 connector_->SetWatcherHeapProfilerTag("IPC Channel");
rockot401fb2c2016-09-06 18:35:5774 }
rockot0e4de5f2016-07-22 21:18:0775
rockot10188752016-09-08 18:24:5676 void Pause() {
77 DCHECK(!paused_);
78 paused_ = true;
79 }
80
81 void Unpause() {
82 DCHECK(paused_);
83 paused_ = false;
rockot401fb2c2016-09-06 18:35:5784 }
85
86 void FlushOutgoingMessages() {
rockotc4cc691e2016-08-19 18:48:5787 std::vector<mojo::Message> outgoing_messages;
rockot0e4de5f2016-07-22 21:18:0788 std::swap(outgoing_messages, outgoing_messages_);
89 for (auto& message : outgoing_messages)
rockotc4cc691e2016-08-19 18:48:5790 SendMessage(&message);
rockot0e4de5f2016-07-22 21:18:0791 }
92
93 void CreateChannelEndpoints(mojom::ChannelAssociatedPtr* sender,
94 mojom::ChannelAssociatedRequest* receiver) {
95 mojo::InterfaceId sender_id, receiver_id;
96 if (set_interface_id_namespace_bit_) {
97 sender_id = 1 | mojo::kInterfaceIdNamespaceMask;
98 receiver_id = 1;
99 } else {
100 sender_id = 1;
101 receiver_id = 1 | mojo::kInterfaceIdNamespaceMask;
102 }
103
104 {
105 base::AutoLock locker(lock_);
106 Endpoint* sender_endpoint = new Endpoint(this, sender_id);
107 Endpoint* receiver_endpoint = new Endpoint(this, receiver_id);
108 endpoints_.insert({ sender_id, sender_endpoint });
109 endpoints_.insert({ receiver_id, receiver_endpoint });
110 }
111
112 mojo::ScopedInterfaceEndpointHandle sender_handle =
113 CreateScopedInterfaceEndpointHandle(sender_id, true);
114 mojo::ScopedInterfaceEndpointHandle receiver_handle =
115 CreateScopedInterfaceEndpointHandle(receiver_id, true);
116
117 sender->Bind(mojom::ChannelAssociatedPtrInfo(std::move(sender_handle), 0));
118 receiver->Bind(std::move(receiver_handle));
119 }
rockot02b8e182016-07-13 20:08:30120
121 void ShutDown() {
122 DCHECK(thread_checker_.CalledOnValidThread());
rockot0e4de5f2016-07-22 21:18:07123 connector_->CloseMessagePipe();
rockot02b8e182016-07-13 20:08:30124 OnPipeError();
rockot0e4de5f2016-07-22 21:18:07125 connector_.reset();
rockot02b8e182016-07-13 20:08:30126 }
127
128 // mojo::AssociatedGroupController:
129 void CreateEndpointHandlePair(
130 mojo::ScopedInterfaceEndpointHandle* local_endpoint,
131 mojo::ScopedInterfaceEndpointHandle* remote_endpoint) override {
132 base::AutoLock locker(lock_);
133 uint32_t id = 0;
134 do {
135 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask)
rockot0e4de5f2016-07-22 21:18:07136 next_interface_id_ = 2;
137 id = next_interface_id_++;
138 if (set_interface_id_namespace_bit_)
139 id |= mojo::kInterfaceIdNamespaceMask;
rockot02b8e182016-07-13 20:08:30140 } while (ContainsKey(endpoints_, id));
141
142 Endpoint* endpoint = new Endpoint(this, id);
143 if (encountered_error_)
144 endpoint->set_peer_closed();
145 endpoints_.insert({ id, endpoint });
146
147 *local_endpoint = CreateScopedInterfaceEndpointHandle(id, true);
148 *remote_endpoint = CreateScopedInterfaceEndpointHandle(id, false);
149 }
150
151 mojo::ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
152 mojo::InterfaceId id) override {
153 if (!mojo::IsValidInterfaceId(id))
154 return mojo::ScopedInterfaceEndpointHandle();
155
156 base::AutoLock locker(lock_);
157 bool inserted = false;
158 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
yzshenea784ea2017-01-31 21:20:20159 if (inserted) {
160 DCHECK(!endpoint->handle_created());
161 if (encountered_error_)
162 endpoint->set_peer_closed();
163 } else {
164 if (endpoint->handle_created())
165 return mojo::ScopedInterfaceEndpointHandle();
166 }
rockot02b8e182016-07-13 20:08:30167
yzshenea784ea2017-01-31 21:20:20168 endpoint->set_handle_created();
rockot02b8e182016-07-13 20:08:30169 return CreateScopedInterfaceEndpointHandle(id, true);
170 }
171
yzshen8be41d3a2017-01-23 20:40:37172 void CloseEndpointHandle(
173 mojo::InterfaceId id,
174 bool is_local,
175 const base::Optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30176 if (!mojo::IsValidInterfaceId(id))
177 return;
178
179 base::AutoLock locker(lock_);
180 if (!is_local) {
181 DCHECK(ContainsKey(endpoints_, id));
182 DCHECK(!mojo::IsMasterInterfaceId(id));
rockot58909542016-11-10 20:05:45183
184 base::AutoUnlock unlocker(lock_);
rockot0e4de5f2016-07-22 21:18:07185 control_message_proxy_.NotifyEndpointClosedBeforeSent(id);
rockot02b8e182016-07-13 20:08:30186 return;
187 }
188
189 DCHECK(ContainsKey(endpoints_, id));
190 Endpoint* endpoint = endpoints_[id].get();
191 DCHECK(!endpoint->client());
192 DCHECK(!endpoint->closed());
193 MarkClosedAndMaybeRemove(endpoint);
194
rockot58909542016-11-10 20:05:45195 base::AutoUnlock unlocker(lock_);
yzshen8be41d3a2017-01-23 20:40:37196 if (!mojo::IsMasterInterfaceId(id) || reason)
197 control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
rockot02b8e182016-07-13 20:08:30198 }
199
200 mojo::InterfaceEndpointController* AttachEndpointClient(
201 const mojo::ScopedInterfaceEndpointHandle& handle,
202 mojo::InterfaceEndpointClient* client,
203 scoped_refptr<base::SingleThreadTaskRunner> runner) override {
204 const mojo::InterfaceId id = handle.id();
205
206 DCHECK(mojo::IsValidInterfaceId(id));
207 DCHECK(client);
208
209 base::AutoLock locker(lock_);
210 DCHECK(ContainsKey(endpoints_, id));
211
212 Endpoint* endpoint = endpoints_[id].get();
213 endpoint->AttachClient(client, std::move(runner));
214
215 if (endpoint->peer_closed())
216 NotifyEndpointOfError(endpoint, true /* force_async */);
217
218 return endpoint;
219 }
220
221 void DetachEndpointClient(
222 const mojo::ScopedInterfaceEndpointHandle& handle) override {
223 const mojo::InterfaceId id = handle.id();
224
225 DCHECK(mojo::IsValidInterfaceId(id));
226
227 base::AutoLock locker(lock_);
228 DCHECK(ContainsKey(endpoints_, id));
229
230 Endpoint* endpoint = endpoints_[id].get();
231 endpoint->DetachClient();
232 }
233
234 void RaiseError() override {
rockot7604e7b72016-07-28 17:37:39235 if (task_runner_->BelongsToCurrentThread()) {
rockot0e4de5f2016-07-22 21:18:07236 connector_->RaiseError();
rockot02b8e182016-07-13 20:08:30237 } else {
238 task_runner_->PostTask(
239 FROM_HERE,
240 base::Bind(&ChannelAssociatedGroupController::RaiseError, this));
241 }
242 }
243
244 private:
245 class Endpoint;
rockot0e4de5f2016-07-22 21:18:07246 class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30247 friend class Endpoint;
rockot0e4de5f2016-07-22 21:18:07248 friend class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30249
yzshenea784ea2017-01-31 21:20:20250 // Message objects cannot be destroyed under the controller's lock, if they
251 // contain ScopedInterfaceEndpointHandle objects.
252 // IncomingMessageWrapper is used to wrap messages which haven't got the
253 // payload interface IDs deserialized into ScopedInterfaceEndpointHandles.
254 // Wrapper objects are always destroyed under the controller's lock. When a
255 // wrapper is destroyed and the message hasn't been consumed, the wrapper is
256 // responsible to send endpoint closed notifications.
257 class IncomingMessageWrapper {
258 public:
259 IncomingMessageWrapper() = default;
260
261 IncomingMessageWrapper(ChannelAssociatedGroupController* controller,
262 mojo::Message* message)
263 : controller_(controller), value_(std::move(*message)) {
264 DCHECK(value_.associated_endpoint_handles()->empty());
265 }
266
267 IncomingMessageWrapper(IncomingMessageWrapper&& other)
268 : controller_(other.controller_), value_(std::move(other.value_)) {}
269
270 ~IncomingMessageWrapper() {
271 if (value_.IsNull())
272 return;
273
274 controller_->lock_.AssertAcquired();
275
276 uint32_t num_ids = value_.payload_num_interface_ids();
277 const uint32_t* ids = value_.payload_interface_ids();
278 for (uint32_t i = 0; i < num_ids; ++i) {
279 base::AutoUnlock unlocker(controller_->lock_);
280 controller_->control_message_proxy_.NotifyPeerEndpointClosed(
281 ids[i], base::nullopt);
282 }
283 }
284
285 IncomingMessageWrapper& operator=(IncomingMessageWrapper&& other) {
286 controller_ = other.controller_;
287 value_ = std::move(other.value_);
288 return *this;
289 }
290
291 // Must be called outside of the controller's lock.
292 bool TakeMessage(mojo::Message* output) {
293 DCHECK(!value_.IsNull());
294
295 *output = std::move(value_);
296 return output->DeserializeAssociatedEndpointHandles(controller_);
297 }
298
299 const mojo::Message& value() const { return value_; }
300
301 private:
302 ChannelAssociatedGroupController* controller_ = nullptr;
303 // It must not hold any ScopedInterfaceEndpointHandle objects.
304 mojo::Message value_;
305
306 DISALLOW_COPY_AND_ASSIGN(IncomingMessageWrapper);
307 };
308
rockot02b8e182016-07-13 20:08:30309 class Endpoint : public base::RefCountedThreadSafe<Endpoint>,
310 public mojo::InterfaceEndpointController {
311 public:
312 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id)
313 : controller_(controller), id_(id) {}
314
315 mojo::InterfaceId id() const { return id_; }
316
317 bool closed() const {
318 controller_->lock_.AssertAcquired();
319 return closed_;
320 }
321
322 void set_closed() {
323 controller_->lock_.AssertAcquired();
324 closed_ = true;
325 }
326
327 bool peer_closed() const {
328 controller_->lock_.AssertAcquired();
329 return peer_closed_;
330 }
331
332 void set_peer_closed() {
333 controller_->lock_.AssertAcquired();
334 peer_closed_ = true;
335 }
336
yzshenea784ea2017-01-31 21:20:20337 bool handle_created() const {
338 controller_->lock_.AssertAcquired();
339 return handle_created_;
340 }
341
342 void set_handle_created() {
343 controller_->lock_.AssertAcquired();
344 handle_created_ = true;
345 }
346
yzshen8be41d3a2017-01-23 20:40:37347 const base::Optional<mojo::DisconnectReason>& disconnect_reason() const {
348 return disconnect_reason_;
349 }
350
351 void set_disconnect_reason(
352 const base::Optional<mojo::DisconnectReason>& disconnect_reason) {
353 disconnect_reason_ = disconnect_reason;
354 }
355
rockot02b8e182016-07-13 20:08:30356 base::SingleThreadTaskRunner* task_runner() const {
357 return task_runner_.get();
358 }
359
360 mojo::InterfaceEndpointClient* client() const {
361 controller_->lock_.AssertAcquired();
362 return client_;
363 }
364
365 void AttachClient(mojo::InterfaceEndpointClient* client,
366 scoped_refptr<base::SingleThreadTaskRunner> runner) {
367 controller_->lock_.AssertAcquired();
368 DCHECK(!client_);
369 DCHECK(!closed_);
370 DCHECK(runner->BelongsToCurrentThread());
371
372 task_runner_ = std::move(runner);
373 client_ = client;
374 }
375
376 void DetachClient() {
377 controller_->lock_.AssertAcquired();
378 DCHECK(client_);
379 DCHECK(task_runner_->BelongsToCurrentThread());
380 DCHECK(!closed_);
381
382 task_runner_ = nullptr;
383 client_ = nullptr;
rockot9abe09b2016-08-02 20:57:34384 sync_watcher_.reset();
385 }
386
yzshenea784ea2017-01-31 21:20:20387 uint32_t EnqueueSyncMessage(IncomingMessageWrapper message) {
rockot9abe09b2016-08-02 20:57:34388 controller_->lock_.AssertAcquired();
389 uint32_t id = GenerateSyncMessageId();
390 sync_messages_.emplace(id, std::move(message));
391 SignalSyncMessageEvent();
392 return id;
393 }
394
395 void SignalSyncMessageEvent() {
396 controller_->lock_.AssertAcquired();
397 EnsureSyncMessageEventExists();
398 sync_message_event_->Signal();
399 }
400
yzshenea784ea2017-01-31 21:20:20401 IncomingMessageWrapper PopSyncMessage(uint32_t id) {
rockot9abe09b2016-08-02 20:57:34402 controller_->lock_.AssertAcquired();
403 if (sync_messages_.empty() || sync_messages_.front().first != id)
yzshenea784ea2017-01-31 21:20:20404 return IncomingMessageWrapper();
405 IncomingMessageWrapper message = std::move(sync_messages_.front().second);
rockot9abe09b2016-08-02 20:57:34406 sync_messages_.pop();
407 return message;
rockot02b8e182016-07-13 20:08:30408 }
409
410 // mojo::InterfaceEndpointController:
411 bool SendMessage(mojo::Message* message) override {
412 DCHECK(task_runner_->BelongsToCurrentThread());
413 message->set_interface_id(id_);
yzshenea784ea2017-01-31 21:20:20414 message->SerializeAssociatedEndpointHandles(controller_);
rockot02b8e182016-07-13 20:08:30415 return controller_->SendMessage(message);
416 }
417
418 void AllowWokenUpBySyncWatchOnSameThread() override {
419 DCHECK(task_runner_->BelongsToCurrentThread());
420
rockot9abe09b2016-08-02 20:57:34421 EnsureSyncWatcherExists();
422 sync_watcher_->AllowWokenUpBySyncWatchOnSameThread();
rockot02b8e182016-07-13 20:08:30423 }
424
425 bool SyncWatch(const bool* should_stop) override {
426 DCHECK(task_runner_->BelongsToCurrentThread());
427
428 // It's not legal to make sync calls from the master endpoint's thread,
429 // and in fact they must only happen from the proxy task runner.
rockot7604e7b72016-07-28 17:37:39430 DCHECK(!controller_->task_runner_->BelongsToCurrentThread());
rockot02b8e182016-07-13 20:08:30431 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread());
432
rockot9abe09b2016-08-02 20:57:34433 EnsureSyncWatcherExists();
434 return sync_watcher_->SyncWatch(should_stop);
rockot02b8e182016-07-13 20:08:30435 }
436
437 private:
438 friend class base::RefCountedThreadSafe<Endpoint>;
439
rockot9abe09b2016-08-02 20:57:34440 ~Endpoint() override {
441 controller_->lock_.AssertAcquired();
442 DCHECK(!client_);
443 DCHECK(closed_);
444 DCHECK(peer_closed_);
445 DCHECK(!sync_watcher_);
446 }
447
448 void OnSyncMessageEventHandleReady(MojoResult result) {
449 DCHECK(task_runner_->BelongsToCurrentThread());
450
451 scoped_refptr<Endpoint> keepalive(this);
452 scoped_refptr<AssociatedGroupController> controller_keepalive(
453 controller_);
454
455 bool reset_sync_watcher = false;
456 {
457 base::AutoLock locker(controller_->lock_);
458 bool more_to_process = false;
459 if (!sync_messages_.empty()) {
yzshenea784ea2017-01-31 21:20:20460 IncomingMessageWrapper message_wrapper =
461 std::move(sync_messages_.front().second);
rockot9abe09b2016-08-02 20:57:34462 sync_messages_.pop();
463
464 bool dispatch_succeeded;
465 mojo::InterfaceEndpointClient* client = client_;
466 {
467 base::AutoUnlock unlocker(controller_->lock_);
yzshenea784ea2017-01-31 21:20:20468 mojo::Message message;
469 dispatch_succeeded = message_wrapper.TakeMessage(&message) &&
470 client->HandleIncomingMessage(&message);
rockot9abe09b2016-08-02 20:57:34471 }
472
473 if (!sync_messages_.empty())
474 more_to_process = true;
475
476 if (!dispatch_succeeded)
477 controller_->RaiseError();
478 }
479
480 if (!more_to_process)
481 sync_message_event_->Reset();
482
483 // If there are no queued sync messages and the peer has closed, there
484 // there won't be incoming sync messages in the future.
485 reset_sync_watcher = !more_to_process && peer_closed_;
486 }
487
488 if (reset_sync_watcher) {
489 // If a SyncWatch() call (or multiple ones) of this interface endpoint
490 // is on the call stack, resetting the sync watcher will allow it to
491 // exit when the call stack unwinds to that frame.
492 sync_watcher_.reset();
493 }
494 }
495
496 void EnsureSyncWatcherExists() {
497 DCHECK(task_runner_->BelongsToCurrentThread());
498 if (sync_watcher_)
499 return;
500
501 {
502 base::AutoLock locker(controller_->lock_);
503 EnsureSyncMessageEventExists();
504 if (!sync_messages_.empty())
505 SignalSyncMessageEvent();
506 }
507
508 sync_watcher_.reset(new mojo::SyncHandleWatcher(
509 sync_message_event_->GetHandle(), MOJO_HANDLE_SIGNAL_READABLE,
510 base::Bind(&Endpoint::OnSyncMessageEventHandleReady,
511 base::Unretained(this))));
512 }
513
514 void EnsureSyncMessageEventExists() {
515 controller_->lock_.AssertAcquired();
516 if (!sync_message_event_)
517 sync_message_event_.reset(new MojoEvent);
518 }
519
520 uint32_t GenerateSyncMessageId() {
521 // Overflow is fine.
522 uint32_t id = next_sync_message_id_++;
523 DCHECK(sync_messages_.empty() || sync_messages_.front().first != id);
524 return id;
525 }
rockot02b8e182016-07-13 20:08:30526
527 ChannelAssociatedGroupController* const controller_;
528 const mojo::InterfaceId id_;
529
530 bool closed_ = false;
531 bool peer_closed_ = false;
yzshenea784ea2017-01-31 21:20:20532 bool handle_created_ = false;
yzshen8be41d3a2017-01-23 20:40:37533 base::Optional<mojo::DisconnectReason> disconnect_reason_;
rockot02b8e182016-07-13 20:08:30534 mojo::InterfaceEndpointClient* client_ = nullptr;
535 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
rockot9abe09b2016-08-02 20:57:34536 std::unique_ptr<mojo::SyncHandleWatcher> sync_watcher_;
537 std::unique_ptr<MojoEvent> sync_message_event_;
yzshenea784ea2017-01-31 21:20:20538 std::queue<std::pair<uint32_t, IncomingMessageWrapper>> sync_messages_;
rockot9abe09b2016-08-02 20:57:34539 uint32_t next_sync_message_id_ = 0;
rockot02b8e182016-07-13 20:08:30540
541 DISALLOW_COPY_AND_ASSIGN(Endpoint);
542 };
543
rockot0e4de5f2016-07-22 21:18:07544 class ControlMessageProxyThunk : public MessageReceiver {
545 public:
546 explicit ControlMessageProxyThunk(
547 ChannelAssociatedGroupController* controller)
548 : controller_(controller) {}
549
550 private:
551 // MessageReceiver:
552 bool Accept(mojo::Message* message) override {
yzshenea784ea2017-01-31 21:20:20553 message->SerializeAssociatedEndpointHandles(controller_);
rockot0e4de5f2016-07-22 21:18:07554 return controller_->SendMessage(message);
555 }
556
557 ChannelAssociatedGroupController* controller_;
558
559 DISALLOW_COPY_AND_ASSIGN(ControlMessageProxyThunk);
560 };
561
rockot02b8e182016-07-13 20:08:30562 ~ChannelAssociatedGroupController() override {
rockotb01ef6a2016-07-27 03:24:32563 DCHECK(!connector_);
564
rockot02b8e182016-07-13 20:08:30565 base::AutoLock locker(lock_);
rockot02b8e182016-07-13 20:08:30566 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
567 Endpoint* endpoint = iter->second.get();
568 ++iter;
569
yzshene003d592017-01-24 21:42:17570 if (!endpoint->closed()) {
571 // This happens when a NotifyPeerEndpointClosed message been received,
572 // but (1) the interface ID hasn't been used to create local endpoint
573 // handle; and (2) a NotifyEndpointClosedBeforeSent hasn't been
574 // received.
575 DCHECK(!endpoint->client());
576 DCHECK(endpoint->peer_closed());
577 MarkClosedAndMaybeRemove(endpoint);
578 } else {
579 MarkPeerClosedAndMaybeRemove(endpoint);
580 }
rockot02b8e182016-07-13 20:08:30581 }
582
583 DCHECK(endpoints_.empty());
584 }
585
586 bool SendMessage(mojo::Message* message) {
rockot7604e7b72016-07-28 17:37:39587 if (task_runner_->BelongsToCurrentThread()) {
rockot02b8e182016-07-13 20:08:30588 DCHECK(thread_checker_.CalledOnValidThread());
rockot10188752016-09-08 18:24:56589 if (!connector_ || paused_) {
rockotc4cc691e2016-08-19 18:48:57590 outgoing_messages_.emplace_back(std::move(*message));
rockot0e4de5f2016-07-22 21:18:07591 return true;
592 }
593 return connector_->Accept(message);
rockot02b8e182016-07-13 20:08:30594 } else {
rockotbecd3f742016-11-08 20:47:00595 // We always post tasks to the master endpoint thread when called from
596 // other threads in order to simulate IPC::ChannelProxy::Send behavior.
rockot02b8e182016-07-13 20:08:30597 task_runner_->PostTask(
598 FROM_HERE,
599 base::Bind(
600 &ChannelAssociatedGroupController::SendMessageOnMasterThread,
rockotc4cc691e2016-08-19 18:48:57601 this, base::Passed(message)));
rockot02b8e182016-07-13 20:08:30602 return true;
603 }
604 }
605
rockotc4cc691e2016-08-19 18:48:57606 void SendMessageOnMasterThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30607 DCHECK(thread_checker_.CalledOnValidThread());
rockotc4cc691e2016-08-19 18:48:57608 if (!SendMessage(&message))
rockot02b8e182016-07-13 20:08:30609 RaiseError();
610 }
611
612 void OnPipeError() {
613 DCHECK(thread_checker_.CalledOnValidThread());
614
615 // We keep |this| alive here because it's possible for the notifications
616 // below to release all other references.
617 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
618
619 base::AutoLock locker(lock_);
620 encountered_error_ = true;
621
622 std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
623 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
624 Endpoint* endpoint = iter->second.get();
625 ++iter;
626
627 if (endpoint->client())
628 endpoints_to_notify.push_back(endpoint);
629
630 MarkPeerClosedAndMaybeRemove(endpoint);
631 }
632
633 for (auto& endpoint : endpoints_to_notify) {
rockot0e4de5f2016-07-22 21:18:07634 // Because a notification may in turn detach any endpoint, we have to
rockot02b8e182016-07-13 20:08:30635 // check each client again here.
636 if (endpoint->client())
637 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
638 }
639 }
640
641 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
642 lock_.AssertAcquired();
643 DCHECK(endpoint->task_runner() && endpoint->client());
644 if (endpoint->task_runner()->BelongsToCurrentThread() && !force_async) {
645 mojo::InterfaceEndpointClient* client = endpoint->client();
yzshen8be41d3a2017-01-23 20:40:37646 base::Optional<mojo::DisconnectReason> reason(
647 endpoint->disconnect_reason());
rockot02b8e182016-07-13 20:08:30648
649 base::AutoUnlock unlocker(lock_);
yzshen8be41d3a2017-01-23 20:40:37650 client->NotifyError(reason);
rockot02b8e182016-07-13 20:08:30651 } else {
652 endpoint->task_runner()->PostTask(
653 FROM_HERE,
654 base::Bind(&ChannelAssociatedGroupController
rockot9abe09b2016-08-02 20:57:34655 ::NotifyEndpointOfErrorOnEndpointThread, this, endpoint->id(),
656 endpoint));
rockot02b8e182016-07-13 20:08:30657 }
658 }
659
rockot9abe09b2016-08-02 20:57:34660 void NotifyEndpointOfErrorOnEndpointThread(mojo::InterfaceId id,
661 Endpoint* endpoint) {
rockot02b8e182016-07-13 20:08:30662 base::AutoLock locker(lock_);
rockot9abe09b2016-08-02 20:57:34663 auto iter = endpoints_.find(id);
664 if (iter == endpoints_.end() || iter->second.get() != endpoint)
665 return;
rockot02b8e182016-07-13 20:08:30666 if (!endpoint->client())
667 return;
rockot9abe09b2016-08-02 20:57:34668
rockot02b8e182016-07-13 20:08:30669 DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
rockot9abe09b2016-08-02 20:57:34670 NotifyEndpointOfError(endpoint, false /* force_async */);
rockot02b8e182016-07-13 20:08:30671 }
672
673 void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
674 lock_.AssertAcquired();
675 endpoint->set_closed();
676 if (endpoint->closed() && endpoint->peer_closed())
677 endpoints_.erase(endpoint->id());
678 }
679
680 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
681 lock_.AssertAcquired();
682 endpoint->set_peer_closed();
rockot9abe09b2016-08-02 20:57:34683 endpoint->SignalSyncMessageEvent();
rockot02b8e182016-07-13 20:08:30684 if (endpoint->closed() && endpoint->peer_closed())
685 endpoints_.erase(endpoint->id());
686 }
687
688 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {
689 lock_.AssertAcquired();
690 DCHECK(!inserted || !*inserted);
691
692 auto iter = endpoints_.find(id);
693 if (iter != endpoints_.end())
694 return iter->second.get();
695
696 Endpoint* endpoint = new Endpoint(this, id);
697 endpoints_.insert({ id, endpoint });
698 if (inserted)
699 *inserted = true;
700 return endpoint;
701 }
702
703 // mojo::MessageReceiver:
704 bool Accept(mojo::Message* message) override {
705 DCHECK(thread_checker_.CalledOnValidThread());
706
yzshenea784ea2017-01-31 21:20:20707 if (mojo::PipeControlMessageHandler::IsPipeControlMessage(message)) {
708 return message->DeserializeAssociatedEndpointHandles(this) &&
709 control_message_handler_.Accept(message);
710 }
rockot02b8e182016-07-13 20:08:30711
712 mojo::InterfaceId id = message->interface_id();
713 DCHECK(mojo::IsValidInterfaceId(id));
714
715 base::AutoLock locker(lock_);
rockotf62002a2016-09-15 00:08:59716 Endpoint* endpoint = GetEndpointForDispatch(id, true /* create */);
rockot401fb2c2016-09-06 18:35:57717 mojo::InterfaceEndpointClient* client =
718 endpoint ? endpoint->client() : nullptr;
rockot02b8e182016-07-13 20:08:30719 if (!client || !endpoint->task_runner()->BelongsToCurrentThread()) {
720 // No client has been bound yet or the client runs tasks on another
721 // thread. We assume the other thread must always be the one on which
722 // |proxy_task_runner_| runs tasks, since that's the only valid scenario.
723 //
724 // If the client is not yet bound, it must be bound by the time this task
725 // runs or else it's programmer error.
726 DCHECK(proxy_task_runner_);
rockot9abe09b2016-08-02 20:57:34727
rockotc4cc691e2016-08-19 18:48:57728 if (message->has_flag(mojo::Message::kFlagIsSync)) {
yzshenea784ea2017-01-31 21:20:20729 IncomingMessageWrapper message_wrapper(this, message);
rockot9abe09b2016-08-02 20:57:34730 // Sync messages may need to be handled by the endpoint if it's blocking
731 // on a sync reply. We pass ownership of the message to the endpoint's
732 // sync message queue. If the endpoint was blocking, it will dequeue the
733 // message and dispatch it. Otherwise the posted |AcceptSyncMessage()|
734 // call will dequeue the message and dispatch it.
yzshenea784ea2017-01-31 21:20:20735 uint32_t message_id =
736 endpoint->EnqueueSyncMessage(std::move(message_wrapper));
rockot9abe09b2016-08-02 20:57:34737 proxy_task_runner_->PostTask(
738 FROM_HERE,
739 base::Bind(&ChannelAssociatedGroupController::AcceptSyncMessage,
740 this, id, message_id));
741 return true;
742 }
743
rockot02b8e182016-07-13 20:08:30744 proxy_task_runner_->PostTask(
745 FROM_HERE,
746 base::Bind(&ChannelAssociatedGroupController::AcceptOnProxyThread,
rockotc4cc691e2016-08-19 18:48:57747 this, base::Passed(message)));
rockot02b8e182016-07-13 20:08:30748 return true;
749 }
750
751 // We do not expect to receive sync responses on the master endpoint thread.
752 // If it's happening, it's a bug.
rockot9abe09b2016-08-02 20:57:34753 DCHECK(!message->has_flag(mojo::Message::kFlagIsSync) ||
754 !message->has_flag(mojo::Message::kFlagIsResponse));
rockot02b8e182016-07-13 20:08:30755
rockot8d890f62016-07-14 16:37:14756 base::AutoUnlock unlocker(lock_);
yzshenea784ea2017-01-31 21:20:20757 return message->DeserializeAssociatedEndpointHandles(this) &&
758 client->HandleIncomingMessage(message);
rockot02b8e182016-07-13 20:08:30759 }
760
rockotc4cc691e2016-08-19 18:48:57761 void AcceptOnProxyThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30762 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
763
rockotc4cc691e2016-08-19 18:48:57764 mojo::InterfaceId id = message.interface_id();
rockot8d890f62016-07-14 16:37:14765 DCHECK(mojo::IsValidInterfaceId(id) && !mojo::IsMasterInterfaceId(id));
766
767 base::AutoLock locker(lock_);
yzshenea784ea2017-01-31 21:20:20768 IncomingMessageWrapper message_wrapper(this, &message);
769
rockotf62002a2016-09-15 00:08:59770 Endpoint* endpoint = GetEndpointForDispatch(id, false /* create */);
rockot8d890f62016-07-14 16:37:14771 if (!endpoint)
772 return;
773
774 mojo::InterfaceEndpointClient* client = endpoint->client();
775 if (!client)
776 return;
777
778 DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
779
rockot9abe09b2016-08-02 20:57:34780 // Sync messages should never make their way to this method.
yzshenea784ea2017-01-31 21:20:20781 DCHECK(!message_wrapper.value().has_flag(mojo::Message::kFlagIsSync));
rockot8d890f62016-07-14 16:37:14782
783 bool result = false;
784 {
785 base::AutoUnlock unlocker(lock_);
yzshenea784ea2017-01-31 21:20:20786 mojo::Message message;
787 result = message_wrapper.TakeMessage(&message) &&
788 client->HandleIncomingMessage(&message);
rockot8d890f62016-07-14 16:37:14789 }
790
791 if (!result)
792 RaiseError();
793 }
794
rockot9abe09b2016-08-02 20:57:34795 void AcceptSyncMessage(mojo::InterfaceId interface_id, uint32_t message_id) {
796 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
797
798 base::AutoLock locker(lock_);
rockot401fb2c2016-09-06 18:35:57799 Endpoint* endpoint =
rockotf62002a2016-09-15 00:08:59800 GetEndpointForDispatch(interface_id, false /* create */);
rockot9abe09b2016-08-02 20:57:34801 if (!endpoint)
802 return;
803
804 DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
yzshenea784ea2017-01-31 21:20:20805 IncomingMessageWrapper message_wrapper =
806 endpoint->PopSyncMessage(message_id);
rockot9abe09b2016-08-02 20:57:34807
808 // The message must have already been dequeued by the endpoint waking up
809 // from a sync wait. Nothing to do.
yzshenea784ea2017-01-31 21:20:20810 if (message_wrapper.value().IsNull())
rockot9abe09b2016-08-02 20:57:34811 return;
812
813 mojo::InterfaceEndpointClient* client = endpoint->client();
814 if (!client)
815 return;
816
817 bool result = false;
818 {
819 base::AutoUnlock unlocker(lock_);
yzshenea784ea2017-01-31 21:20:20820 mojo::Message message;
821 result = message_wrapper.TakeMessage(&message) &&
822 client->HandleIncomingMessage(&message);
rockot9abe09b2016-08-02 20:57:34823 }
824
825 if (!result)
826 RaiseError();
827 }
828
rockotf62002a2016-09-15 00:08:59829 Endpoint* GetEndpointForDispatch(mojo::InterfaceId id, bool create) {
rockot8d890f62016-07-14 16:37:14830 lock_.AssertAcquired();
rockotf62002a2016-09-15 00:08:59831 auto iter = endpoints_.find(id);
832 if (iter != endpoints_.end())
833 return iter->second.get();
834 if (!create)
835 return nullptr;
rockot8d890f62016-07-14 16:37:14836 bool inserted = false;
837 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
rockotf62002a2016-09-15 00:08:59838 DCHECK(inserted);
rockot8d890f62016-07-14 16:37:14839 return endpoint;
rockot02b8e182016-07-13 20:08:30840 }
841
842 // mojo::PipeControlMessageHandlerDelegate:
yzshen8be41d3a2017-01-23 20:40:37843 bool OnPeerAssociatedEndpointClosed(
844 mojo::InterfaceId id,
845 const base::Optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30846 DCHECK(thread_checker_.CalledOnValidThread());
847
yzshen8be41d3a2017-01-23 20:40:37848 DCHECK(!mojo::IsMasterInterfaceId(id) || reason);
rockot02b8e182016-07-13 20:08:30849
rockot0e4de5f2016-07-22 21:18:07850 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
rockot02b8e182016-07-13 20:08:30851 base::AutoLock locker(lock_);
852 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr);
yzshen8be41d3a2017-01-23 20:40:37853 if (reason)
854 endpoint->set_disconnect_reason(reason);
rockot02b8e182016-07-13 20:08:30855 if (!endpoint->peer_closed()) {
856 if (endpoint->client())
857 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
858 MarkPeerClosedAndMaybeRemove(endpoint.get());
859 }
860
861 return true;
862 }
863
864 bool OnAssociatedEndpointClosedBeforeSent(mojo::InterfaceId id) override {
865 DCHECK(thread_checker_.CalledOnValidThread());
866
867 if (mojo::IsMasterInterfaceId(id))
868 return false;
869
rockot58909542016-11-10 20:05:45870 {
871 base::AutoLock locker(lock_);
872 Endpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
873 DCHECK(!endpoint->closed());
874 MarkClosedAndMaybeRemove(endpoint);
875 }
876
yzshen8be41d3a2017-01-23 20:40:37877 control_message_proxy_.NotifyPeerEndpointClosed(id, base::nullopt);
rockot02b8e182016-07-13 20:08:30878 return true;
879 }
880
881 // Checked in places which must be run on the master endpoint's thread.
882 base::ThreadChecker thread_checker_;
883
884 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
rockot0e4de5f2016-07-22 21:18:07885
rockot02b8e182016-07-13 20:08:30886 scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
rockot0e4de5f2016-07-22 21:18:07887 const bool set_interface_id_namespace_bit_;
rockot10188752016-09-08 18:24:56888 bool paused_ = false;
rockot0e4de5f2016-07-22 21:18:07889 std::unique_ptr<mojo::Connector> connector_;
rockot222e7dd2016-08-24 23:37:11890 mojo::FilterChain filters_;
rockot02b8e182016-07-13 20:08:30891 mojo::PipeControlMessageHandler control_message_handler_;
rockot0e4de5f2016-07-22 21:18:07892 ControlMessageProxyThunk control_message_proxy_thunk_;
rockot58909542016-11-10 20:05:45893
894 // NOTE: It is unsafe to call into this object while holding |lock_|.
rockot0e4de5f2016-07-22 21:18:07895 mojo::PipeControlMessageProxy control_message_proxy_;
896
897 // Outgoing messages that were sent before this controller was bound to a
898 // real message pipe.
rockotc4cc691e2016-08-19 18:48:57899 std::vector<mojo::Message> outgoing_messages_;
rockot02b8e182016-07-13 20:08:30900
901 // Guards the fields below for thread-safe access.
902 base::Lock lock_;
903
904 bool encountered_error_ = false;
rockot0e4de5f2016-07-22 21:18:07905
906 // ID #1 is reserved for the mojom::Channel interface.
907 uint32_t next_interface_id_ = 2;
908
rockot02b8e182016-07-13 20:08:30909 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_;
rockot02b8e182016-07-13 20:08:30910
911 DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController);
912};
913
rockot0e4de5f2016-07-22 21:18:07914class MojoBootstrapImpl : public MojoBootstrap {
rockot02b8e182016-07-13 20:08:30915 public:
rockot0e4de5f2016-07-22 21:18:07916 MojoBootstrapImpl(
917 mojo::ScopedMessagePipeHandle handle,
918 Delegate* delegate,
919 const scoped_refptr<ChannelAssociatedGroupController> controller)
920 : controller_(controller),
921 handle_(std::move(handle)),
922 delegate_(delegate) {
923 associated_group_ = controller_->CreateAssociatedGroup();
rockot02b8e182016-07-13 20:08:30924 }
925
rockot0e4de5f2016-07-22 21:18:07926 ~MojoBootstrapImpl() override {
927 controller_->ShutDown();
rockot02b8e182016-07-13 20:08:30928 }
929
930 private:
rockot0e4de5f2016-07-22 21:18:07931 // MojoBootstrap:
932 void Connect() override {
933 controller_->Bind(std::move(handle_));
rockotf192a0752016-07-21 01:33:51934
rockot0e4de5f2016-07-22 21:18:07935 IPC::mojom::ChannelAssociatedPtr sender;
936 IPC::mojom::ChannelAssociatedRequest receiver;
937 controller_->CreateChannelEndpoints(&sender, &receiver);
rockotf192a0752016-07-21 01:33:51938
rockot0e4de5f2016-07-22 21:18:07939 delegate_->OnPipesAvailable(std::move(sender), std::move(receiver));
msramek5507fee2016-07-22 10:06:21940 }
941
rockot10188752016-09-08 18:24:56942 void Pause() override {
943 controller_->Pause();
944 }
945
946 void Unpause() override {
947 controller_->Unpause();
rockot401fb2c2016-09-06 18:35:57948 }
949
950 void Flush() override {
951 controller_->FlushOutgoingMessages();
952 }
953
msramek5507fee2016-07-22 10:06:21954 mojo::AssociatedGroup* GetAssociatedGroup() override {
rockot0e4de5f2016-07-22 21:18:07955 return associated_group_.get();
msramek5507fee2016-07-22 10:06:21956 }
957
rockot0e4de5f2016-07-22 21:18:07958 scoped_refptr<ChannelAssociatedGroupController> controller_;
msramek5507fee2016-07-22 10:06:21959
rockot0e4de5f2016-07-22 21:18:07960 mojo::ScopedMessagePipeHandle handle_;
961 Delegate* delegate_;
962 std::unique_ptr<mojo::AssociatedGroup> associated_group_;
msramek5507fee2016-07-22 10:06:21963
rockot0e4de5f2016-07-22 21:18:07964 DISALLOW_COPY_AND_ASSIGN(MojoBootstrapImpl);
msramek5507fee2016-07-22 10:06:21965};
966
morrita54f6f80c2014-09-23 21:16:00967} // namespace
968
morrita54f6f80c2014-09-23 21:16:00969// static
danakj03de39b22016-04-23 04:21:09970std::unique_ptr<MojoBootstrap> MojoBootstrap::Create(
sammc57ed9f982016-03-10 06:28:35971 mojo::ScopedMessagePipeHandle handle,
972 Channel::Mode mode,
rockot0e4de5f2016-07-22 21:18:07973 Delegate* delegate,
974 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
975 return base::MakeUnique<MojoBootstrapImpl>(
976 std::move(handle), delegate,
977 new ChannelAssociatedGroupController(mode == Channel::MODE_SERVER,
978 ipc_task_runner));
sammc57ed9f982016-03-10 06:28:35979}
980
morrita54f6f80c2014-09-23 21:16:00981} // namespace IPC