blob: 89a74343f811b89c5f4bc243814912aaab8c29fb [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"
rockot02b8e182016-07-13 20:08:3022#include "mojo/public/cpp/bindings/associated_group.h"
23#include "mojo/public/cpp/bindings/associated_group_controller.h"
rockot02b8e182016-07-13 20:08:3024#include "mojo/public/cpp/bindings/connector.h"
25#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
26#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
27#include "mojo/public/cpp/bindings/interface_id.h"
rockot0e4de5f2016-07-22 21:18:0728#include "mojo/public/cpp/bindings/message.h"
rockot02b8e182016-07-13 20:08:3029#include "mojo/public/cpp/bindings/message_header_validator.h"
30#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
31#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
32#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
rockotb62e2e32017-03-24 18:36:4433#include "mojo/public/cpp/bindings/sync_event_watcher.h"
morrita54f6f80c2014-09-23 21:16:0034
35namespace IPC {
36
37namespace {
38
rockot02b8e182016-07-13 20:08:3039class ChannelAssociatedGroupController
40 : public mojo::AssociatedGroupController,
41 public mojo::MessageReceiver,
42 public mojo::PipeControlMessageHandlerDelegate {
43 public:
rockot0e4de5f2016-07-22 21:18:0744 ChannelAssociatedGroupController(
45 bool set_interface_id_namespace_bit,
46 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner)
rockotb01ef6a2016-07-27 03:24:3247 : task_runner_(ipc_task_runner),
rockot0e4de5f2016-07-22 21:18:0748 proxy_task_runner_(base::ThreadTaskRunnerHandle::Get()),
49 set_interface_id_namespace_bit_(set_interface_id_namespace_bit),
rockot222e7dd2016-08-24 23:37:1150 filters_(this),
rockot02b8e182016-07-13 20:08:3051 control_message_handler_(this),
rockot0e4de5f2016-07-22 21:18:0752 control_message_proxy_thunk_(this),
53 control_message_proxy_(&control_message_proxy_thunk_) {
54 thread_checker_.DetachFromThread();
rockot02b8e182016-07-13 20:08:3055 control_message_handler_.SetDescription(
56 "IPC::mojom::Bootstrap [master] PipeControlMessageHandler");
rockot222e7dd2016-08-24 23:37:1157 filters_.Append<mojo::MessageHeaderValidator>(
58 "IPC::mojom::Bootstrap [master] MessageHeaderValidator");
rockot02b8e182016-07-13 20:08:3059 }
60
rockot0e4de5f2016-07-22 21:18:0761 void Bind(mojo::ScopedMessagePipeHandle handle) {
62 DCHECK(thread_checker_.CalledOnValidThread());
63 DCHECK(task_runner_->BelongsToCurrentThread());
rockot90984352016-07-25 17:36:1964
rockot0e4de5f2016-07-22 21:18:0765 connector_.reset(new mojo::Connector(
66 std::move(handle), mojo::Connector::SINGLE_THREADED_SEND,
67 task_runner_));
rockot222e7dd2016-08-24 23:37:1168 connector_->set_incoming_receiver(&filters_);
rockot0e4de5f2016-07-22 21:18:0769 connector_->set_connection_error_handler(
70 base::Bind(&ChannelAssociatedGroupController::OnPipeError,
71 base::Unretained(this)));
jcivelli2207af12017-01-26 20:46:0072 connector_->SetWatcherHeapProfilerTag("IPC Channel");
rockot401fb2c2016-09-06 18:35:5773 }
rockot0e4de5f2016-07-22 21:18:0774
rockot10188752016-09-08 18:24:5675 void Pause() {
76 DCHECK(!paused_);
77 paused_ = true;
78 }
79
80 void Unpause() {
81 DCHECK(paused_);
82 paused_ = false;
rockot401fb2c2016-09-06 18:35:5783 }
84
85 void FlushOutgoingMessages() {
rockotc4cc691e2016-08-19 18:48:5786 std::vector<mojo::Message> outgoing_messages;
rockot0e4de5f2016-07-22 21:18:0787 std::swap(outgoing_messages, outgoing_messages_);
88 for (auto& message : outgoing_messages)
rockotc4cc691e2016-08-19 18:48:5789 SendMessage(&message);
rockot0e4de5f2016-07-22 21:18:0790 }
91
92 void CreateChannelEndpoints(mojom::ChannelAssociatedPtr* sender,
93 mojom::ChannelAssociatedRequest* receiver) {
94 mojo::InterfaceId sender_id, receiver_id;
95 if (set_interface_id_namespace_bit_) {
96 sender_id = 1 | mojo::kInterfaceIdNamespaceMask;
97 receiver_id = 1;
98 } else {
99 sender_id = 1;
100 receiver_id = 1 | mojo::kInterfaceIdNamespaceMask;
101 }
102
103 {
104 base::AutoLock locker(lock_);
105 Endpoint* sender_endpoint = new Endpoint(this, sender_id);
106 Endpoint* receiver_endpoint = new Endpoint(this, receiver_id);
107 endpoints_.insert({ sender_id, sender_endpoint });
108 endpoints_.insert({ receiver_id, receiver_endpoint });
yzshen0a5971312017-02-02 05:13:47109 sender_endpoint->set_handle_created();
110 receiver_endpoint->set_handle_created();
rockot0e4de5f2016-07-22 21:18:07111 }
112
113 mojo::ScopedInterfaceEndpointHandle sender_handle =
yzshen2859a2ac2017-02-14 22:24:25114 CreateScopedInterfaceEndpointHandle(sender_id);
rockot0e4de5f2016-07-22 21:18:07115 mojo::ScopedInterfaceEndpointHandle receiver_handle =
yzshen2859a2ac2017-02-14 22:24:25116 CreateScopedInterfaceEndpointHandle(receiver_id);
rockot0e4de5f2016-07-22 21:18:07117
118 sender->Bind(mojom::ChannelAssociatedPtrInfo(std::move(sender_handle), 0));
119 receiver->Bind(std::move(receiver_handle));
120 }
rockot02b8e182016-07-13 20:08:30121
122 void ShutDown() {
123 DCHECK(thread_checker_.CalledOnValidThread());
rockot0e4de5f2016-07-22 21:18:07124 connector_->CloseMessagePipe();
rockot02b8e182016-07-13 20:08:30125 OnPipeError();
rockot0e4de5f2016-07-22 21:18:07126 connector_.reset();
rockot02b8e182016-07-13 20:08:30127 }
128
129 // mojo::AssociatedGroupController:
yzshen2859a2ac2017-02-14 22:24:25130 mojo::InterfaceId AssociateInterface(
131 mojo::ScopedInterfaceEndpointHandle handle_to_send) override {
132 if (!handle_to_send.pending_association())
133 return mojo::kInvalidInterfaceId;
134
rockot02b8e182016-07-13 20:08:30135 uint32_t id = 0;
yzshen2859a2ac2017-02-14 22:24:25136 {
137 base::AutoLock locker(lock_);
138 do {
139 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask)
140 next_interface_id_ = 2;
141 id = next_interface_id_++;
142 if (set_interface_id_namespace_bit_)
143 id |= mojo::kInterfaceIdNamespaceMask;
144 } while (ContainsKey(endpoints_, id));
rockot02b8e182016-07-13 20:08:30145
yzshen2859a2ac2017-02-14 22:24:25146 Endpoint* endpoint = new Endpoint(this, id);
147 if (encountered_error_)
148 endpoint->set_peer_closed();
149 endpoint->set_handle_created();
150 endpoints_.insert({id, endpoint});
151 }
rockot02b8e182016-07-13 20:08:30152
yzshen2859a2ac2017-02-14 22:24:25153 if (!NotifyAssociation(&handle_to_send, id)) {
154 // The peer handle of |handle_to_send|, which is supposed to join this
155 // associated group, has been closed.
156 {
157 base::AutoLock locker(lock_);
158 Endpoint* endpoint = FindEndpoint(id);
159 if (endpoint)
160 MarkClosedAndMaybeRemove(endpoint);
161 }
162
163 control_message_proxy_.NotifyPeerEndpointClosed(
164 id, handle_to_send.disconnect_reason());
165 }
166 return id;
rockot02b8e182016-07-13 20:08:30167 }
168
169 mojo::ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
170 mojo::InterfaceId id) override {
171 if (!mojo::IsValidInterfaceId(id))
172 return mojo::ScopedInterfaceEndpointHandle();
173
174 base::AutoLock locker(lock_);
175 bool inserted = false;
176 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
yzshenea784ea2017-01-31 21:20:20177 if (inserted) {
178 DCHECK(!endpoint->handle_created());
179 if (encountered_error_)
180 endpoint->set_peer_closed();
181 } else {
182 if (endpoint->handle_created())
183 return mojo::ScopedInterfaceEndpointHandle();
184 }
rockot02b8e182016-07-13 20:08:30185
yzshenea784ea2017-01-31 21:20:20186 endpoint->set_handle_created();
yzshen2859a2ac2017-02-14 22:24:25187 return CreateScopedInterfaceEndpointHandle(id);
rockot02b8e182016-07-13 20:08:30188 }
189
yzshen8be41d3a2017-01-23 20:40:37190 void CloseEndpointHandle(
191 mojo::InterfaceId id,
yzshen8be41d3a2017-01-23 20:40:37192 const base::Optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30193 if (!mojo::IsValidInterfaceId(id))
194 return;
yzshen2859a2ac2017-02-14 22:24:25195 {
196 base::AutoLock locker(lock_);
rockot02b8e182016-07-13 20:08:30197 DCHECK(ContainsKey(endpoints_, id));
yzshen2859a2ac2017-02-14 22:24:25198 Endpoint* endpoint = endpoints_[id].get();
199 DCHECK(!endpoint->client());
200 DCHECK(!endpoint->closed());
201 MarkClosedAndMaybeRemove(endpoint);
rockot02b8e182016-07-13 20:08:30202 }
203
yzshen8be41d3a2017-01-23 20:40:37204 if (!mojo::IsMasterInterfaceId(id) || reason)
205 control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
rockot02b8e182016-07-13 20:08:30206 }
207
208 mojo::InterfaceEndpointController* AttachEndpointClient(
209 const mojo::ScopedInterfaceEndpointHandle& handle,
210 mojo::InterfaceEndpointClient* client,
211 scoped_refptr<base::SingleThreadTaskRunner> runner) override {
212 const mojo::InterfaceId id = handle.id();
213
214 DCHECK(mojo::IsValidInterfaceId(id));
215 DCHECK(client);
216
217 base::AutoLock locker(lock_);
218 DCHECK(ContainsKey(endpoints_, id));
219
220 Endpoint* endpoint = endpoints_[id].get();
221 endpoint->AttachClient(client, std::move(runner));
222
223 if (endpoint->peer_closed())
224 NotifyEndpointOfError(endpoint, true /* force_async */);
225
226 return endpoint;
227 }
228
229 void DetachEndpointClient(
230 const mojo::ScopedInterfaceEndpointHandle& handle) override {
231 const mojo::InterfaceId id = handle.id();
232
233 DCHECK(mojo::IsValidInterfaceId(id));
234
235 base::AutoLock locker(lock_);
236 DCHECK(ContainsKey(endpoints_, id));
237
238 Endpoint* endpoint = endpoints_[id].get();
239 endpoint->DetachClient();
240 }
241
242 void RaiseError() override {
rockot7604e7b72016-07-28 17:37:39243 if (task_runner_->BelongsToCurrentThread()) {
rockot0e4de5f2016-07-22 21:18:07244 connector_->RaiseError();
rockot02b8e182016-07-13 20:08:30245 } else {
246 task_runner_->PostTask(
247 FROM_HERE,
248 base::Bind(&ChannelAssociatedGroupController::RaiseError, this));
249 }
250 }
251
252 private:
253 class Endpoint;
rockot0e4de5f2016-07-22 21:18:07254 class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30255 friend class Endpoint;
rockot0e4de5f2016-07-22 21:18:07256 friend class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30257
yzshen0a5971312017-02-02 05:13:47258 // MessageWrapper objects are always destroyed under the controller's lock. On
259 // destruction, if the message it wrappers contains
260 // ScopedInterfaceEndpointHandles (which cannot be destructed under the
261 // controller's lock), the wrapper unlocks to clean them up.
262 class MessageWrapper {
yzshenea784ea2017-01-31 21:20:20263 public:
yzshen0a5971312017-02-02 05:13:47264 MessageWrapper() = default;
yzshenea784ea2017-01-31 21:20:20265
yzshen0a5971312017-02-02 05:13:47266 MessageWrapper(ChannelAssociatedGroupController* controller,
267 mojo::Message message)
268 : controller_(controller), value_(std::move(message)) {}
yzshenea784ea2017-01-31 21:20:20269
yzshen0a5971312017-02-02 05:13:47270 MessageWrapper(MessageWrapper&& other)
yzshenea784ea2017-01-31 21:20:20271 : controller_(other.controller_), value_(std::move(other.value_)) {}
272
yzshen0a5971312017-02-02 05:13:47273 ~MessageWrapper() {
274 if (value_.associated_endpoint_handles()->empty())
yzshenea784ea2017-01-31 21:20:20275 return;
276
277 controller_->lock_.AssertAcquired();
yzshen0a5971312017-02-02 05:13:47278 {
yzshenea784ea2017-01-31 21:20:20279 base::AutoUnlock unlocker(controller_->lock_);
yzshen0a5971312017-02-02 05:13:47280 value_.mutable_associated_endpoint_handles()->clear();
yzshenea784ea2017-01-31 21:20:20281 }
282 }
283
yzshen0a5971312017-02-02 05:13:47284 MessageWrapper& operator=(MessageWrapper&& other) {
yzshenea784ea2017-01-31 21:20:20285 controller_ = other.controller_;
286 value_ = std::move(other.value_);
287 return *this;
288 }
289
yzshen0a5971312017-02-02 05:13:47290 mojo::Message& value() { return value_; }
yzshenea784ea2017-01-31 21:20:20291
292 private:
293 ChannelAssociatedGroupController* controller_ = nullptr;
yzshenea784ea2017-01-31 21:20:20294 mojo::Message value_;
295
yzshen0a5971312017-02-02 05:13:47296 DISALLOW_COPY_AND_ASSIGN(MessageWrapper);
yzshenea784ea2017-01-31 21:20:20297 };
298
rockot02b8e182016-07-13 20:08:30299 class Endpoint : public base::RefCountedThreadSafe<Endpoint>,
300 public mojo::InterfaceEndpointController {
301 public:
302 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id)
303 : controller_(controller), id_(id) {}
304
305 mojo::InterfaceId id() const { return id_; }
306
307 bool closed() const {
308 controller_->lock_.AssertAcquired();
309 return closed_;
310 }
311
312 void set_closed() {
313 controller_->lock_.AssertAcquired();
314 closed_ = true;
315 }
316
317 bool peer_closed() const {
318 controller_->lock_.AssertAcquired();
319 return peer_closed_;
320 }
321
322 void set_peer_closed() {
323 controller_->lock_.AssertAcquired();
324 peer_closed_ = true;
325 }
326
yzshenea784ea2017-01-31 21:20:20327 bool handle_created() const {
328 controller_->lock_.AssertAcquired();
329 return handle_created_;
330 }
331
332 void set_handle_created() {
333 controller_->lock_.AssertAcquired();
334 handle_created_ = true;
335 }
336
yzshen8be41d3a2017-01-23 20:40:37337 const base::Optional<mojo::DisconnectReason>& disconnect_reason() const {
338 return disconnect_reason_;
339 }
340
341 void set_disconnect_reason(
342 const base::Optional<mojo::DisconnectReason>& disconnect_reason) {
343 disconnect_reason_ = disconnect_reason;
344 }
345
rockot02b8e182016-07-13 20:08:30346 base::SingleThreadTaskRunner* task_runner() const {
347 return task_runner_.get();
348 }
349
350 mojo::InterfaceEndpointClient* client() const {
351 controller_->lock_.AssertAcquired();
352 return client_;
353 }
354
355 void AttachClient(mojo::InterfaceEndpointClient* client,
356 scoped_refptr<base::SingleThreadTaskRunner> runner) {
357 controller_->lock_.AssertAcquired();
358 DCHECK(!client_);
359 DCHECK(!closed_);
360 DCHECK(runner->BelongsToCurrentThread());
361
362 task_runner_ = std::move(runner);
363 client_ = client;
364 }
365
366 void DetachClient() {
367 controller_->lock_.AssertAcquired();
368 DCHECK(client_);
369 DCHECK(task_runner_->BelongsToCurrentThread());
370 DCHECK(!closed_);
371
372 task_runner_ = nullptr;
373 client_ = nullptr;
rockot9abe09b2016-08-02 20:57:34374 sync_watcher_.reset();
375 }
376
yzshen0a5971312017-02-02 05:13:47377 uint32_t EnqueueSyncMessage(MessageWrapper message) {
rockot9abe09b2016-08-02 20:57:34378 controller_->lock_.AssertAcquired();
379 uint32_t id = GenerateSyncMessageId();
380 sync_messages_.emplace(id, std::move(message));
381 SignalSyncMessageEvent();
382 return id;
383 }
384
385 void SignalSyncMessageEvent() {
386 controller_->lock_.AssertAcquired();
yzshene25b5d52017-02-28 21:56:31387
388 if (sync_message_event_)
389 sync_message_event_->Signal();
rockot9abe09b2016-08-02 20:57:34390 }
391
yzshen0a5971312017-02-02 05:13:47392 MessageWrapper PopSyncMessage(uint32_t id) {
rockot9abe09b2016-08-02 20:57:34393 controller_->lock_.AssertAcquired();
394 if (sync_messages_.empty() || sync_messages_.front().first != id)
yzshen0a5971312017-02-02 05:13:47395 return MessageWrapper();
396 MessageWrapper message = std::move(sync_messages_.front().second);
rockot9abe09b2016-08-02 20:57:34397 sync_messages_.pop();
398 return message;
rockot02b8e182016-07-13 20:08:30399 }
400
401 // mojo::InterfaceEndpointController:
402 bool SendMessage(mojo::Message* message) override {
403 DCHECK(task_runner_->BelongsToCurrentThread());
404 message->set_interface_id(id_);
405 return controller_->SendMessage(message);
406 }
407
408 void AllowWokenUpBySyncWatchOnSameThread() override {
409 DCHECK(task_runner_->BelongsToCurrentThread());
410
rockot9abe09b2016-08-02 20:57:34411 EnsureSyncWatcherExists();
412 sync_watcher_->AllowWokenUpBySyncWatchOnSameThread();
rockot02b8e182016-07-13 20:08:30413 }
414
415 bool SyncWatch(const bool* should_stop) override {
416 DCHECK(task_runner_->BelongsToCurrentThread());
417
418 // It's not legal to make sync calls from the master endpoint's thread,
419 // and in fact they must only happen from the proxy task runner.
rockot7604e7b72016-07-28 17:37:39420 DCHECK(!controller_->task_runner_->BelongsToCurrentThread());
rockot02b8e182016-07-13 20:08:30421 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread());
422
rockot9abe09b2016-08-02 20:57:34423 EnsureSyncWatcherExists();
424 return sync_watcher_->SyncWatch(should_stop);
rockot02b8e182016-07-13 20:08:30425 }
426
427 private:
428 friend class base::RefCountedThreadSafe<Endpoint>;
429
rockot9abe09b2016-08-02 20:57:34430 ~Endpoint() override {
431 controller_->lock_.AssertAcquired();
432 DCHECK(!client_);
433 DCHECK(closed_);
434 DCHECK(peer_closed_);
435 DCHECK(!sync_watcher_);
436 }
437
rockotb62e2e32017-03-24 18:36:44438 void OnSyncMessageEventReady() {
rockot9abe09b2016-08-02 20:57:34439 DCHECK(task_runner_->BelongsToCurrentThread());
440
441 scoped_refptr<Endpoint> keepalive(this);
442 scoped_refptr<AssociatedGroupController> controller_keepalive(
443 controller_);
444
445 bool reset_sync_watcher = false;
446 {
447 base::AutoLock locker(controller_->lock_);
448 bool more_to_process = false;
449 if (!sync_messages_.empty()) {
yzshen0a5971312017-02-02 05:13:47450 MessageWrapper message_wrapper =
yzshenea784ea2017-01-31 21:20:20451 std::move(sync_messages_.front().second);
rockot9abe09b2016-08-02 20:57:34452 sync_messages_.pop();
453
454 bool dispatch_succeeded;
455 mojo::InterfaceEndpointClient* client = client_;
456 {
457 base::AutoUnlock unlocker(controller_->lock_);
yzshen0a5971312017-02-02 05:13:47458 dispatch_succeeded =
459 client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34460 }
461
462 if (!sync_messages_.empty())
463 more_to_process = true;
464
465 if (!dispatch_succeeded)
466 controller_->RaiseError();
467 }
468
469 if (!more_to_process)
470 sync_message_event_->Reset();
471
472 // If there are no queued sync messages and the peer has closed, there
473 // there won't be incoming sync messages in the future.
474 reset_sync_watcher = !more_to_process && peer_closed_;
475 }
476
477 if (reset_sync_watcher) {
478 // If a SyncWatch() call (or multiple ones) of this interface endpoint
479 // is on the call stack, resetting the sync watcher will allow it to
480 // exit when the call stack unwinds to that frame.
481 sync_watcher_.reset();
482 }
483 }
484
485 void EnsureSyncWatcherExists() {
486 DCHECK(task_runner_->BelongsToCurrentThread());
487 if (sync_watcher_)
488 return;
489
490 {
491 base::AutoLock locker(controller_->lock_);
yzshene25b5d52017-02-28 21:56:31492 if (!sync_message_event_) {
rockotb62e2e32017-03-24 18:36:44493 sync_message_event_ = base::MakeUnique<base::WaitableEvent>(
494 base::WaitableEvent::ResetPolicy::MANUAL,
495 base::WaitableEvent::InitialState::NOT_SIGNALED);
yzshene25b5d52017-02-28 21:56:31496 if (peer_closed_ || !sync_messages_.empty())
497 SignalSyncMessageEvent();
498 }
rockot9abe09b2016-08-02 20:57:34499 }
500
rockotb62e2e32017-03-24 18:36:44501 sync_watcher_ = base::MakeUnique<mojo::SyncEventWatcher>(
502 sync_message_event_.get(),
503 base::Bind(&Endpoint::OnSyncMessageEventReady,
504 base::Unretained(this)));
rockot9abe09b2016-08-02 20:57:34505 }
506
507 uint32_t GenerateSyncMessageId() {
508 // Overflow is fine.
509 uint32_t id = next_sync_message_id_++;
510 DCHECK(sync_messages_.empty() || sync_messages_.front().first != id);
511 return id;
512 }
rockot02b8e182016-07-13 20:08:30513
514 ChannelAssociatedGroupController* const controller_;
515 const mojo::InterfaceId id_;
516
517 bool closed_ = false;
518 bool peer_closed_ = false;
yzshenea784ea2017-01-31 21:20:20519 bool handle_created_ = false;
yzshen8be41d3a2017-01-23 20:40:37520 base::Optional<mojo::DisconnectReason> disconnect_reason_;
rockot02b8e182016-07-13 20:08:30521 mojo::InterfaceEndpointClient* client_ = nullptr;
522 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
rockotb62e2e32017-03-24 18:36:44523 std::unique_ptr<mojo::SyncEventWatcher> sync_watcher_;
524 std::unique_ptr<base::WaitableEvent> sync_message_event_;
yzshen0a5971312017-02-02 05:13:47525 std::queue<std::pair<uint32_t, MessageWrapper>> sync_messages_;
rockot9abe09b2016-08-02 20:57:34526 uint32_t next_sync_message_id_ = 0;
rockot02b8e182016-07-13 20:08:30527
528 DISALLOW_COPY_AND_ASSIGN(Endpoint);
529 };
530
rockot0e4de5f2016-07-22 21:18:07531 class ControlMessageProxyThunk : public MessageReceiver {
532 public:
533 explicit ControlMessageProxyThunk(
534 ChannelAssociatedGroupController* controller)
535 : controller_(controller) {}
536
537 private:
538 // MessageReceiver:
539 bool Accept(mojo::Message* message) override {
540 return controller_->SendMessage(message);
541 }
542
543 ChannelAssociatedGroupController* controller_;
544
545 DISALLOW_COPY_AND_ASSIGN(ControlMessageProxyThunk);
546 };
547
rockot02b8e182016-07-13 20:08:30548 ~ChannelAssociatedGroupController() override {
rockotb01ef6a2016-07-27 03:24:32549 DCHECK(!connector_);
550
rockot02b8e182016-07-13 20:08:30551 base::AutoLock locker(lock_);
rockot02b8e182016-07-13 20:08:30552 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
553 Endpoint* endpoint = iter->second.get();
554 ++iter;
555
yzshene003d592017-01-24 21:42:17556 if (!endpoint->closed()) {
557 // This happens when a NotifyPeerEndpointClosed message been received,
yzshen2859a2ac2017-02-14 22:24:25558 // but the interface ID hasn't been used to create local endpoint
559 // handle.
yzshene003d592017-01-24 21:42:17560 DCHECK(!endpoint->client());
561 DCHECK(endpoint->peer_closed());
562 MarkClosedAndMaybeRemove(endpoint);
563 } else {
564 MarkPeerClosedAndMaybeRemove(endpoint);
565 }
rockot02b8e182016-07-13 20:08:30566 }
567
568 DCHECK(endpoints_.empty());
569 }
570
571 bool SendMessage(mojo::Message* message) {
rockot7604e7b72016-07-28 17:37:39572 if (task_runner_->BelongsToCurrentThread()) {
rockot02b8e182016-07-13 20:08:30573 DCHECK(thread_checker_.CalledOnValidThread());
rockot10188752016-09-08 18:24:56574 if (!connector_ || paused_) {
rockotc4cc691e2016-08-19 18:48:57575 outgoing_messages_.emplace_back(std::move(*message));
rockot0e4de5f2016-07-22 21:18:07576 return true;
577 }
578 return connector_->Accept(message);
rockot02b8e182016-07-13 20:08:30579 } else {
rockotbecd3f742016-11-08 20:47:00580 // We always post tasks to the master endpoint thread when called from
581 // other threads in order to simulate IPC::ChannelProxy::Send behavior.
rockot02b8e182016-07-13 20:08:30582 task_runner_->PostTask(
583 FROM_HERE,
584 base::Bind(
585 &ChannelAssociatedGroupController::SendMessageOnMasterThread,
rockotc4cc691e2016-08-19 18:48:57586 this, base::Passed(message)));
rockot02b8e182016-07-13 20:08:30587 return true;
588 }
589 }
590
rockotc4cc691e2016-08-19 18:48:57591 void SendMessageOnMasterThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30592 DCHECK(thread_checker_.CalledOnValidThread());
rockotc4cc691e2016-08-19 18:48:57593 if (!SendMessage(&message))
rockot02b8e182016-07-13 20:08:30594 RaiseError();
595 }
596
597 void OnPipeError() {
598 DCHECK(thread_checker_.CalledOnValidThread());
599
600 // We keep |this| alive here because it's possible for the notifications
601 // below to release all other references.
602 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
603
604 base::AutoLock locker(lock_);
605 encountered_error_ = true;
606
607 std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
608 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
609 Endpoint* endpoint = iter->second.get();
610 ++iter;
611
612 if (endpoint->client())
613 endpoints_to_notify.push_back(endpoint);
614
615 MarkPeerClosedAndMaybeRemove(endpoint);
616 }
617
618 for (auto& endpoint : endpoints_to_notify) {
rockot0e4de5f2016-07-22 21:18:07619 // Because a notification may in turn detach any endpoint, we have to
rockot02b8e182016-07-13 20:08:30620 // check each client again here.
621 if (endpoint->client())
622 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
623 }
624 }
625
626 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
627 lock_.AssertAcquired();
628 DCHECK(endpoint->task_runner() && endpoint->client());
629 if (endpoint->task_runner()->BelongsToCurrentThread() && !force_async) {
630 mojo::InterfaceEndpointClient* client = endpoint->client();
yzshen8be41d3a2017-01-23 20:40:37631 base::Optional<mojo::DisconnectReason> reason(
632 endpoint->disconnect_reason());
rockot02b8e182016-07-13 20:08:30633
634 base::AutoUnlock unlocker(lock_);
yzshen8be41d3a2017-01-23 20:40:37635 client->NotifyError(reason);
rockot02b8e182016-07-13 20:08:30636 } else {
637 endpoint->task_runner()->PostTask(
638 FROM_HERE,
639 base::Bind(&ChannelAssociatedGroupController
rockot9abe09b2016-08-02 20:57:34640 ::NotifyEndpointOfErrorOnEndpointThread, this, endpoint->id(),
641 endpoint));
rockot02b8e182016-07-13 20:08:30642 }
643 }
644
rockot9abe09b2016-08-02 20:57:34645 void NotifyEndpointOfErrorOnEndpointThread(mojo::InterfaceId id,
646 Endpoint* endpoint) {
rockot02b8e182016-07-13 20:08:30647 base::AutoLock locker(lock_);
rockot9abe09b2016-08-02 20:57:34648 auto iter = endpoints_.find(id);
649 if (iter == endpoints_.end() || iter->second.get() != endpoint)
650 return;
rockot02b8e182016-07-13 20:08:30651 if (!endpoint->client())
652 return;
rockot9abe09b2016-08-02 20:57:34653
rockot02b8e182016-07-13 20:08:30654 DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
rockot9abe09b2016-08-02 20:57:34655 NotifyEndpointOfError(endpoint, false /* force_async */);
rockot02b8e182016-07-13 20:08:30656 }
657
658 void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
659 lock_.AssertAcquired();
660 endpoint->set_closed();
661 if (endpoint->closed() && endpoint->peer_closed())
662 endpoints_.erase(endpoint->id());
663 }
664
665 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
666 lock_.AssertAcquired();
667 endpoint->set_peer_closed();
rockot9abe09b2016-08-02 20:57:34668 endpoint->SignalSyncMessageEvent();
rockot02b8e182016-07-13 20:08:30669 if (endpoint->closed() && endpoint->peer_closed())
670 endpoints_.erase(endpoint->id());
671 }
672
673 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {
674 lock_.AssertAcquired();
675 DCHECK(!inserted || !*inserted);
676
yzshen0a5971312017-02-02 05:13:47677 Endpoint* endpoint = FindEndpoint(id);
678 if (!endpoint) {
679 endpoint = new Endpoint(this, id);
680 endpoints_.insert({id, endpoint});
681 if (inserted)
682 *inserted = true;
683 }
rockot02b8e182016-07-13 20:08:30684 return endpoint;
685 }
686
yzshen0a5971312017-02-02 05:13:47687 Endpoint* FindEndpoint(mojo::InterfaceId id) {
688 lock_.AssertAcquired();
689 auto iter = endpoints_.find(id);
690 return iter != endpoints_.end() ? iter->second.get() : nullptr;
691 }
692
rockot02b8e182016-07-13 20:08:30693 // mojo::MessageReceiver:
694 bool Accept(mojo::Message* message) override {
695 DCHECK(thread_checker_.CalledOnValidThread());
696
yzshen0a5971312017-02-02 05:13:47697 if (!message->DeserializeAssociatedEndpointHandles(this))
698 return false;
699
700 if (mojo::PipeControlMessageHandler::IsPipeControlMessage(message))
701 return control_message_handler_.Accept(message);
rockot02b8e182016-07-13 20:08:30702
703 mojo::InterfaceId id = message->interface_id();
704 DCHECK(mojo::IsValidInterfaceId(id));
705
706 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47707 Endpoint* endpoint = FindEndpoint(id);
708 if (!endpoint)
709 return true;
710
711 mojo::InterfaceEndpointClient* client = endpoint->client();
rockot02b8e182016-07-13 20:08:30712 if (!client || !endpoint->task_runner()->BelongsToCurrentThread()) {
713 // No client has been bound yet or the client runs tasks on another
714 // thread. We assume the other thread must always be the one on which
715 // |proxy_task_runner_| runs tasks, since that's the only valid scenario.
716 //
717 // If the client is not yet bound, it must be bound by the time this task
718 // runs or else it's programmer error.
719 DCHECK(proxy_task_runner_);
rockot9abe09b2016-08-02 20:57:34720
rockotc4cc691e2016-08-19 18:48:57721 if (message->has_flag(mojo::Message::kFlagIsSync)) {
yzshen0a5971312017-02-02 05:13:47722 MessageWrapper message_wrapper(this, std::move(*message));
rockot9abe09b2016-08-02 20:57:34723 // Sync messages may need to be handled by the endpoint if it's blocking
724 // on a sync reply. We pass ownership of the message to the endpoint's
725 // sync message queue. If the endpoint was blocking, it will dequeue the
726 // message and dispatch it. Otherwise the posted |AcceptSyncMessage()|
727 // call will dequeue the message and dispatch it.
yzshenea784ea2017-01-31 21:20:20728 uint32_t message_id =
729 endpoint->EnqueueSyncMessage(std::move(message_wrapper));
rockot9abe09b2016-08-02 20:57:34730 proxy_task_runner_->PostTask(
731 FROM_HERE,
732 base::Bind(&ChannelAssociatedGroupController::AcceptSyncMessage,
733 this, id, message_id));
734 return true;
735 }
736
rockot02b8e182016-07-13 20:08:30737 proxy_task_runner_->PostTask(
738 FROM_HERE,
739 base::Bind(&ChannelAssociatedGroupController::AcceptOnProxyThread,
rockotc4cc691e2016-08-19 18:48:57740 this, base::Passed(message)));
rockot02b8e182016-07-13 20:08:30741 return true;
742 }
743
744 // We do not expect to receive sync responses on the master endpoint thread.
745 // If it's happening, it's a bug.
rockot9abe09b2016-08-02 20:57:34746 DCHECK(!message->has_flag(mojo::Message::kFlagIsSync) ||
747 !message->has_flag(mojo::Message::kFlagIsResponse));
rockot02b8e182016-07-13 20:08:30748
rockot8d890f62016-07-14 16:37:14749 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47750 return client->HandleIncomingMessage(message);
rockot02b8e182016-07-13 20:08:30751 }
752
rockotc4cc691e2016-08-19 18:48:57753 void AcceptOnProxyThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30754 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
755
rockotc4cc691e2016-08-19 18:48:57756 mojo::InterfaceId id = message.interface_id();
rockot8d890f62016-07-14 16:37:14757 DCHECK(mojo::IsValidInterfaceId(id) && !mojo::IsMasterInterfaceId(id));
758
759 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47760 Endpoint* endpoint = FindEndpoint(id);
rockot8d890f62016-07-14 16:37:14761 if (!endpoint)
762 return;
763
764 mojo::InterfaceEndpointClient* client = endpoint->client();
765 if (!client)
766 return;
767
768 DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
769
rockot9abe09b2016-08-02 20:57:34770 // Sync messages should never make their way to this method.
yzshen0a5971312017-02-02 05:13:47771 DCHECK(!message.has_flag(mojo::Message::kFlagIsSync));
rockot8d890f62016-07-14 16:37:14772
773 bool result = false;
774 {
775 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47776 result = client->HandleIncomingMessage(&message);
rockot8d890f62016-07-14 16:37:14777 }
778
779 if (!result)
780 RaiseError();
781 }
782
rockot9abe09b2016-08-02 20:57:34783 void AcceptSyncMessage(mojo::InterfaceId interface_id, uint32_t message_id) {
784 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
785
786 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47787 Endpoint* endpoint = FindEndpoint(interface_id);
rockot9abe09b2016-08-02 20:57:34788 if (!endpoint)
789 return;
790
csharrison1af8d6ab2017-04-21 17:47:23791 // Careful, if the endpoint is detached its members are cleared. Check for
792 // that before dereferencing.
793 mojo::InterfaceEndpointClient* client = endpoint->client();
794 if (!client)
795 return;
796
rockot9abe09b2016-08-02 20:57:34797 DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
yzshen0a5971312017-02-02 05:13:47798 MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id);
rockot9abe09b2016-08-02 20:57:34799
800 // The message must have already been dequeued by the endpoint waking up
801 // from a sync wait. Nothing to do.
yzshenea784ea2017-01-31 21:20:20802 if (message_wrapper.value().IsNull())
rockot9abe09b2016-08-02 20:57:34803 return;
804
rockot9abe09b2016-08-02 20:57:34805 bool result = false;
806 {
807 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47808 result = client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34809 }
810
811 if (!result)
812 RaiseError();
813 }
814
rockot02b8e182016-07-13 20:08:30815 // mojo::PipeControlMessageHandlerDelegate:
yzshen8be41d3a2017-01-23 20:40:37816 bool OnPeerAssociatedEndpointClosed(
817 mojo::InterfaceId id,
818 const base::Optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30819 DCHECK(thread_checker_.CalledOnValidThread());
820
yzshen8be41d3a2017-01-23 20:40:37821 DCHECK(!mojo::IsMasterInterfaceId(id) || reason);
rockot02b8e182016-07-13 20:08:30822
rockot0e4de5f2016-07-22 21:18:07823 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
rockot02b8e182016-07-13 20:08:30824 base::AutoLock locker(lock_);
825 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr);
yzshen8be41d3a2017-01-23 20:40:37826 if (reason)
827 endpoint->set_disconnect_reason(reason);
rockot02b8e182016-07-13 20:08:30828 if (!endpoint->peer_closed()) {
829 if (endpoint->client())
830 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
831 MarkPeerClosedAndMaybeRemove(endpoint.get());
832 }
833
834 return true;
835 }
836
rockot02b8e182016-07-13 20:08:30837 // Checked in places which must be run on the master endpoint's thread.
838 base::ThreadChecker thread_checker_;
839
840 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
rockot0e4de5f2016-07-22 21:18:07841
rockot02b8e182016-07-13 20:08:30842 scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
rockot0e4de5f2016-07-22 21:18:07843 const bool set_interface_id_namespace_bit_;
rockot10188752016-09-08 18:24:56844 bool paused_ = false;
rockot0e4de5f2016-07-22 21:18:07845 std::unique_ptr<mojo::Connector> connector_;
rockot222e7dd2016-08-24 23:37:11846 mojo::FilterChain filters_;
rockot02b8e182016-07-13 20:08:30847 mojo::PipeControlMessageHandler control_message_handler_;
rockot0e4de5f2016-07-22 21:18:07848 ControlMessageProxyThunk control_message_proxy_thunk_;
rockot58909542016-11-10 20:05:45849
850 // NOTE: It is unsafe to call into this object while holding |lock_|.
rockot0e4de5f2016-07-22 21:18:07851 mojo::PipeControlMessageProxy control_message_proxy_;
852
853 // Outgoing messages that were sent before this controller was bound to a
854 // real message pipe.
rockotc4cc691e2016-08-19 18:48:57855 std::vector<mojo::Message> outgoing_messages_;
rockot02b8e182016-07-13 20:08:30856
857 // Guards the fields below for thread-safe access.
858 base::Lock lock_;
859
860 bool encountered_error_ = false;
rockot0e4de5f2016-07-22 21:18:07861
862 // ID #1 is reserved for the mojom::Channel interface.
863 uint32_t next_interface_id_ = 2;
864
rockot02b8e182016-07-13 20:08:30865 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_;
rockot02b8e182016-07-13 20:08:30866
867 DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController);
868};
869
rockot0e4de5f2016-07-22 21:18:07870class MojoBootstrapImpl : public MojoBootstrap {
rockot02b8e182016-07-13 20:08:30871 public:
rockot0e4de5f2016-07-22 21:18:07872 MojoBootstrapImpl(
873 mojo::ScopedMessagePipeHandle handle,
rockot0e4de5f2016-07-22 21:18:07874 const scoped_refptr<ChannelAssociatedGroupController> controller)
yzshen2859a2ac2017-02-14 22:24:25875 : controller_(controller),
876 associated_group_(controller),
877 handle_(std::move(handle)) {}
rockot02b8e182016-07-13 20:08:30878
rockot0e4de5f2016-07-22 21:18:07879 ~MojoBootstrapImpl() override {
880 controller_->ShutDown();
rockot02b8e182016-07-13 20:08:30881 }
882
883 private:
rockota628d0b2017-02-09 08:40:15884 void Connect(mojom::ChannelAssociatedPtr* sender,
885 mojom::ChannelAssociatedRequest* receiver) override {
rockot0e4de5f2016-07-22 21:18:07886 controller_->Bind(std::move(handle_));
rockota628d0b2017-02-09 08:40:15887 controller_->CreateChannelEndpoints(sender, receiver);
msramek5507fee2016-07-22 10:06:21888 }
889
rockot10188752016-09-08 18:24:56890 void Pause() override {
891 controller_->Pause();
892 }
893
894 void Unpause() override {
895 controller_->Unpause();
rockot401fb2c2016-09-06 18:35:57896 }
897
898 void Flush() override {
899 controller_->FlushOutgoingMessages();
900 }
901
msramek5507fee2016-07-22 10:06:21902 mojo::AssociatedGroup* GetAssociatedGroup() override {
yzshen2859a2ac2017-02-14 22:24:25903 return &associated_group_;
msramek5507fee2016-07-22 10:06:21904 }
905
rockot0e4de5f2016-07-22 21:18:07906 scoped_refptr<ChannelAssociatedGroupController> controller_;
yzshen2859a2ac2017-02-14 22:24:25907 mojo::AssociatedGroup associated_group_;
msramek5507fee2016-07-22 10:06:21908
rockot0e4de5f2016-07-22 21:18:07909 mojo::ScopedMessagePipeHandle handle_;
msramek5507fee2016-07-22 10:06:21910
rockot0e4de5f2016-07-22 21:18:07911 DISALLOW_COPY_AND_ASSIGN(MojoBootstrapImpl);
msramek5507fee2016-07-22 10:06:21912};
913
morrita54f6f80c2014-09-23 21:16:00914} // namespace
915
morrita54f6f80c2014-09-23 21:16:00916// static
danakj03de39b22016-04-23 04:21:09917std::unique_ptr<MojoBootstrap> MojoBootstrap::Create(
sammc57ed9f982016-03-10 06:28:35918 mojo::ScopedMessagePipeHandle handle,
919 Channel::Mode mode,
rockot0e4de5f2016-07-22 21:18:07920 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
921 return base::MakeUnique<MojoBootstrapImpl>(
rockota628d0b2017-02-09 08:40:15922 std::move(handle), new ChannelAssociatedGroupController(
923 mode == Channel::MODE_SERVER, ipc_task_runner));
sammc57ed9f982016-03-10 06:28:35924}
925
morrita54f6f80c2014-09-23 21:16:00926} // namespace IPC