blob: a2e24f4d94e9fbcd471645b75fd1ee8494615fec [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
Ken Rockot2b6de982018-03-20 22:28:137#include <inttypes.h>
tfarina10a5c062015-09-04 18:47:578#include <stdint.h>
rockot02b8e182016-07-13 20:08:309
10#include <map>
11#include <memory>
Ken Rockot2b6de982018-03-20 22:28:1312#include <set>
dchenge48600452015-12-28 02:24:5013#include <utility>
rockot0e4de5f2016-07-22 21:18:0714#include <vector>
tfarina10a5c062015-09-04 18:47:5715
Sebastien Marchand6d0558fd2019-01-25 16:49:3716#include "base/bind.h"
rockota21316a2016-06-19 17:08:3617#include "base/callback.h"
Brett Wilsona62d9c02017-09-20 20:53:2018#include "base/containers/queue.h"
morrita54f6f80c2014-09-23 21:16:0019#include "base/logging.h"
avi246998d82015-12-22 02:39:0420#include "base/macros.h"
danakj03de39b22016-04-23 04:21:0921#include "base/memory/ptr_util.h"
Ken Rockot2b6de982018-03-20 22:28:1322#include "base/no_destructor.h"
Gabriel Charette14520232018-04-30 23:27:2223#include "base/sequenced_task_runner.h"
rockot02b8e182016-07-13 20:08:3024#include "base/single_thread_task_runner.h"
Ken Rockot2b6de982018-03-20 22:28:1325#include "base/strings/stringprintf.h"
rockot02b8e182016-07-13 20:08:3026#include "base/synchronization/lock.h"
Sam McNallyde5ae672017-06-19 23:34:4527#include "base/threading/thread_checker.h"
rockot02b8e182016-07-13 20:08:3028#include "base/threading/thread_task_runner_handle.h"
Ken Rockot2b6de982018-03-20 22:28:1329#include "base/trace_event/memory_allocator_dump.h"
30#include "base/trace_event/memory_dump_manager.h"
31#include "base/trace_event/memory_dump_provider.h"
Ken Rockotfb81dc02018-05-15 21:59:2632#include "ipc/ipc_channel.h"
rockot02b8e182016-07-13 20:08:3033#include "mojo/public/cpp/bindings/associated_group.h"
34#include "mojo/public/cpp/bindings/associated_group_controller.h"
rockot02b8e182016-07-13 20:08:3035#include "mojo/public/cpp/bindings/connector.h"
36#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
37#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
38#include "mojo/public/cpp/bindings/interface_id.h"
rockot0e4de5f2016-07-22 21:18:0739#include "mojo/public/cpp/bindings/message.h"
rockot02b8e182016-07-13 20:08:3040#include "mojo/public/cpp/bindings/message_header_validator.h"
41#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
42#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
43#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
Ken Rockotaa20dcc2018-03-28 03:06:5144#include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h"
morrita54f6f80c2014-09-23 21:16:0045
46namespace IPC {
47
48namespace {
49
Ken Rockot2b6de982018-03-20 22:28:1350class ChannelAssociatedGroupController;
51
52// Used to track some internal Channel state in pursuit of message leaks.
53//
54// TODO(https://crbug.com/813045): Remove this.
55class ControllerMemoryDumpProvider
56 : public base::trace_event::MemoryDumpProvider {
57 public:
58 ControllerMemoryDumpProvider() {
59 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
60 this, "IPCChannel", nullptr);
61 }
62
63 ~ControllerMemoryDumpProvider() override {
64 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
65 this);
66 }
67
68 void AddController(ChannelAssociatedGroupController* controller) {
69 base::AutoLock lock(lock_);
70 controllers_.insert(controller);
71 }
72
73 void RemoveController(ChannelAssociatedGroupController* controller) {
74 base::AutoLock lock(lock_);
75 controllers_.erase(controller);
76 }
77
78 // base::trace_event::MemoryDumpProvider:
79 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
80 base::trace_event::ProcessMemoryDump* pmd) override;
81
82 private:
83 base::Lock lock_;
84 std::set<ChannelAssociatedGroupController*> controllers_;
85
86 DISALLOW_COPY_AND_ASSIGN(ControllerMemoryDumpProvider);
87};
88
89ControllerMemoryDumpProvider& GetMemoryDumpProvider() {
90 static base::NoDestructor<ControllerMemoryDumpProvider> provider;
91 return *provider;
92}
93
Siddhartha S03484422019-04-23 20:30:0094// Messages are grouped by this info when recording memory metrics.
95struct MessageMemoryDumpInfo {
96 MessageMemoryDumpInfo(const mojo::Message& message)
97 : id(message.name()), profiler_tag(message.heap_profiler_tag()) {}
98 MessageMemoryDumpInfo() = default;
99
100 bool operator==(const MessageMemoryDumpInfo& other) const {
101 return other.id == id && other.profiler_tag == profiler_tag;
102 }
103
104 uint32_t id = 0;
105 const char* profiler_tag = nullptr;
106};
107
108struct MessageMemoryDumpInfoHash {
109 size_t operator()(const MessageMemoryDumpInfo& info) const {
110 return base::HashInts32(
111 info.id, info.profiler_tag ? base::Hash(info.profiler_tag) : 0);
112 }
113};
114
rockot02b8e182016-07-13 20:08:30115class ChannelAssociatedGroupController
116 : public mojo::AssociatedGroupController,
117 public mojo::MessageReceiver,
118 public mojo::PipeControlMessageHandlerDelegate {
119 public:
rockot0e4de5f2016-07-22 21:18:07120 ChannelAssociatedGroupController(
121 bool set_interface_id_namespace_bit,
Hajime Hoshia98f1102017-11-20 06:34:35122 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
123 const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner)
rockotb01ef6a2016-07-27 03:24:32124 : task_runner_(ipc_task_runner),
Hajime Hoshia98f1102017-11-20 06:34:35125 proxy_task_runner_(proxy_task_runner),
rockot0e4de5f2016-07-22 21:18:07126 set_interface_id_namespace_bit_(set_interface_id_namespace_bit),
rockot222e7dd2016-08-24 23:37:11127 filters_(this),
rockot02b8e182016-07-13 20:08:30128 control_message_handler_(this),
rockot0e4de5f2016-07-22 21:18:07129 control_message_proxy_thunk_(this),
130 control_message_proxy_(&control_message_proxy_thunk_) {
131 thread_checker_.DetachFromThread();
rockot02b8e182016-07-13 20:08:30132 control_message_handler_.SetDescription(
133 "IPC::mojom::Bootstrap [master] PipeControlMessageHandler");
rockot222e7dd2016-08-24 23:37:11134 filters_.Append<mojo::MessageHeaderValidator>(
135 "IPC::mojom::Bootstrap [master] MessageHeaderValidator");
Ken Rockot2b6de982018-03-20 22:28:13136
137 GetMemoryDumpProvider().AddController(this);
138 }
139
140 size_t GetQueuedMessageCount() {
141 base::AutoLock lock(outgoing_messages_lock_);
142 return outgoing_messages_.size();
rockot02b8e182016-07-13 20:08:30143 }
144
Siddhartha S03484422019-04-23 20:30:00145 void GetTopQueuedMessageMemoryDumpInfo(MessageMemoryDumpInfo* info,
146 size_t* count) {
147 std::unordered_map<MessageMemoryDumpInfo, size_t, MessageMemoryDumpInfoHash>
148 counts;
149 std::pair<MessageMemoryDumpInfo, size_t> top_message_info_and_count = {
150 MessageMemoryDumpInfo(), 0};
Siddharthad1cfec12018-09-17 21:42:15151 base::AutoLock lock(outgoing_messages_lock_);
152 for (const auto& message : outgoing_messages_) {
Siddhartha S03484422019-04-23 20:30:00153 auto it_and_inserted = counts.emplace(MessageMemoryDumpInfo(message), 0);
Siddharthad1cfec12018-09-17 21:42:15154 it_and_inserted.first->second++;
Siddhartha S03484422019-04-23 20:30:00155 if (it_and_inserted.first->second > top_message_info_and_count.second)
156 top_message_info_and_count = *it_and_inserted.first;
Siddharthad1cfec12018-09-17 21:42:15157 }
Siddhartha S03484422019-04-23 20:30:00158 *info = top_message_info_and_count.first;
159 *count = top_message_info_and_count.second;
Siddharthad1cfec12018-09-17 21:42:15160 }
161
rockot0e4de5f2016-07-22 21:18:07162 void Bind(mojo::ScopedMessagePipeHandle handle) {
163 DCHECK(thread_checker_.CalledOnValidThread());
164 DCHECK(task_runner_->BelongsToCurrentThread());
rockot90984352016-07-25 17:36:19165
rockot0e4de5f2016-07-22 21:18:07166 connector_.reset(new mojo::Connector(
167 std::move(handle), mojo::Connector::SINGLE_THREADED_SEND,
168 task_runner_));
rockot222e7dd2016-08-24 23:37:11169 connector_->set_incoming_receiver(&filters_);
rockot0e4de5f2016-07-22 21:18:07170 connector_->set_connection_error_handler(
171 base::Bind(&ChannelAssociatedGroupController::OnPipeError,
172 base::Unretained(this)));
Ken Rockot138153b2018-07-13 23:31:57173 connector_->set_enforce_errors_from_incoming_receiver(false);
jcivelli2207af12017-01-26 20:46:00174 connector_->SetWatcherHeapProfilerTag("IPC Channel");
Ken Rockot471aa7942019-01-17 02:46:59175
176 // Don't let the Connector do any sort of queuing on our behalf. Individual
177 // messages bound for the IPC::ChannelProxy thread (i.e. that vast majority
178 // of messages received by this Connector) are already individually
179 // scheduled for dispatch by ChannelProxy, so Connector's normal mode of
180 // operation would only introduce a redundant scheduling step for most
181 // messages.
182 connector_->set_force_immediate_dispatch(true);
rockot401fb2c2016-09-06 18:35:57183 }
rockot0e4de5f2016-07-22 21:18:07184
rockot10188752016-09-08 18:24:56185 void Pause() {
186 DCHECK(!paused_);
187 paused_ = true;
188 }
189
190 void Unpause() {
191 DCHECK(paused_);
192 paused_ = false;
rockot401fb2c2016-09-06 18:35:57193 }
194
195 void FlushOutgoingMessages() {
rockotc4cc691e2016-08-19 18:48:57196 std::vector<mojo::Message> outgoing_messages;
Ken Rockot2b6de982018-03-20 22:28:13197 {
198 base::AutoLock lock(outgoing_messages_lock_);
199 std::swap(outgoing_messages, outgoing_messages_);
200 }
rockot0e4de5f2016-07-22 21:18:07201 for (auto& message : outgoing_messages)
rockotc4cc691e2016-08-19 18:48:57202 SendMessage(&message);
rockot0e4de5f2016-07-22 21:18:07203 }
204
205 void CreateChannelEndpoints(mojom::ChannelAssociatedPtr* sender,
206 mojom::ChannelAssociatedRequest* receiver) {
207 mojo::InterfaceId sender_id, receiver_id;
208 if (set_interface_id_namespace_bit_) {
209 sender_id = 1 | mojo::kInterfaceIdNamespaceMask;
210 receiver_id = 1;
211 } else {
212 sender_id = 1;
213 receiver_id = 1 | mojo::kInterfaceIdNamespaceMask;
214 }
215
216 {
217 base::AutoLock locker(lock_);
218 Endpoint* sender_endpoint = new Endpoint(this, sender_id);
219 Endpoint* receiver_endpoint = new Endpoint(this, receiver_id);
220 endpoints_.insert({ sender_id, sender_endpoint });
221 endpoints_.insert({ receiver_id, receiver_endpoint });
yzshen0a5971312017-02-02 05:13:47222 sender_endpoint->set_handle_created();
223 receiver_endpoint->set_handle_created();
rockot0e4de5f2016-07-22 21:18:07224 }
225
226 mojo::ScopedInterfaceEndpointHandle sender_handle =
yzshen2859a2ac2017-02-14 22:24:25227 CreateScopedInterfaceEndpointHandle(sender_id);
rockot0e4de5f2016-07-22 21:18:07228 mojo::ScopedInterfaceEndpointHandle receiver_handle =
yzshen2859a2ac2017-02-14 22:24:25229 CreateScopedInterfaceEndpointHandle(receiver_id);
rockot0e4de5f2016-07-22 21:18:07230
231 sender->Bind(mojom::ChannelAssociatedPtrInfo(std::move(sender_handle), 0));
Ken Rockot96d1b7b52017-05-13 00:29:21232 *receiver = mojom::ChannelAssociatedRequest(std::move(receiver_handle));
rockot0e4de5f2016-07-22 21:18:07233 }
rockot02b8e182016-07-13 20:08:30234
235 void ShutDown() {
236 DCHECK(thread_checker_.CalledOnValidThread());
Ken Rockot3e7284bb2018-02-06 16:11:16237 shut_down_ = true;
rockot0e4de5f2016-07-22 21:18:07238 connector_->CloseMessagePipe();
rockot02b8e182016-07-13 20:08:30239 OnPipeError();
rockot0e4de5f2016-07-22 21:18:07240 connector_.reset();
Ken Rockot2b6de982018-03-20 22:28:13241
242 base::AutoLock lock(outgoing_messages_lock_);
Ken Rockot3e7284bb2018-02-06 16:11:16243 outgoing_messages_.clear();
rockot02b8e182016-07-13 20:08:30244 }
245
246 // mojo::AssociatedGroupController:
yzshen2859a2ac2017-02-14 22:24:25247 mojo::InterfaceId AssociateInterface(
248 mojo::ScopedInterfaceEndpointHandle handle_to_send) override {
249 if (!handle_to_send.pending_association())
250 return mojo::kInvalidInterfaceId;
251
rockot02b8e182016-07-13 20:08:30252 uint32_t id = 0;
yzshen2859a2ac2017-02-14 22:24:25253 {
254 base::AutoLock locker(lock_);
255 do {
256 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask)
257 next_interface_id_ = 2;
258 id = next_interface_id_++;
259 if (set_interface_id_namespace_bit_)
260 id |= mojo::kInterfaceIdNamespaceMask;
261 } while (ContainsKey(endpoints_, id));
rockot02b8e182016-07-13 20:08:30262
yzshen2859a2ac2017-02-14 22:24:25263 Endpoint* endpoint = new Endpoint(this, id);
264 if (encountered_error_)
265 endpoint->set_peer_closed();
266 endpoint->set_handle_created();
267 endpoints_.insert({id, endpoint});
268 }
rockot02b8e182016-07-13 20:08:30269
yzshen2859a2ac2017-02-14 22:24:25270 if (!NotifyAssociation(&handle_to_send, id)) {
271 // The peer handle of |handle_to_send|, which is supposed to join this
272 // associated group, has been closed.
273 {
274 base::AutoLock locker(lock_);
275 Endpoint* endpoint = FindEndpoint(id);
276 if (endpoint)
277 MarkClosedAndMaybeRemove(endpoint);
278 }
279
280 control_message_proxy_.NotifyPeerEndpointClosed(
281 id, handle_to_send.disconnect_reason());
282 }
283 return id;
rockot02b8e182016-07-13 20:08:30284 }
285
286 mojo::ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
287 mojo::InterfaceId id) override {
288 if (!mojo::IsValidInterfaceId(id))
289 return mojo::ScopedInterfaceEndpointHandle();
290
Yuzhu Shen9f87fb02017-08-11 17:07:06291 // Unless it is the master ID, |id| is from the remote side and therefore
292 // its namespace bit is supposed to be different than the value that this
293 // router would use.
294 if (!mojo::IsMasterInterfaceId(id) &&
295 set_interface_id_namespace_bit_ ==
296 mojo::HasInterfaceIdNamespaceBitSet(id)) {
297 return mojo::ScopedInterfaceEndpointHandle();
298 }
299
rockot02b8e182016-07-13 20:08:30300 base::AutoLock locker(lock_);
301 bool inserted = false;
302 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
yzshenea784ea2017-01-31 21:20:20303 if (inserted) {
304 DCHECK(!endpoint->handle_created());
305 if (encountered_error_)
306 endpoint->set_peer_closed();
307 } else {
308 if (endpoint->handle_created())
309 return mojo::ScopedInterfaceEndpointHandle();
310 }
rockot02b8e182016-07-13 20:08:30311
yzshenea784ea2017-01-31 21:20:20312 endpoint->set_handle_created();
yzshen2859a2ac2017-02-14 22:24:25313 return CreateScopedInterfaceEndpointHandle(id);
rockot02b8e182016-07-13 20:08:30314 }
315
yzshen8be41d3a2017-01-23 20:40:37316 void CloseEndpointHandle(
317 mojo::InterfaceId id,
yzshen8be41d3a2017-01-23 20:40:37318 const base::Optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30319 if (!mojo::IsValidInterfaceId(id))
320 return;
yzshen2859a2ac2017-02-14 22:24:25321 {
322 base::AutoLock locker(lock_);
Yuzhu Shen7bcd8ebf2017-10-02 23:21:14323 DCHECK(ContainsKey(endpoints_, id));
yzshen2859a2ac2017-02-14 22:24:25324 Endpoint* endpoint = endpoints_[id].get();
325 DCHECK(!endpoint->client());
326 DCHECK(!endpoint->closed());
327 MarkClosedAndMaybeRemove(endpoint);
rockot02b8e182016-07-13 20:08:30328 }
329
yzshen8be41d3a2017-01-23 20:40:37330 if (!mojo::IsMasterInterfaceId(id) || reason)
331 control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
rockot02b8e182016-07-13 20:08:30332 }
333
334 mojo::InterfaceEndpointController* AttachEndpointClient(
335 const mojo::ScopedInterfaceEndpointHandle& handle,
336 mojo::InterfaceEndpointClient* client,
Sam McNallyde5ae672017-06-19 23:34:45337 scoped_refptr<base::SequencedTaskRunner> runner) override {
rockot02b8e182016-07-13 20:08:30338 const mojo::InterfaceId id = handle.id();
339
340 DCHECK(mojo::IsValidInterfaceId(id));
341 DCHECK(client);
342
343 base::AutoLock locker(lock_);
Yuzhu Shen7bcd8ebf2017-10-02 23:21:14344 DCHECK(ContainsKey(endpoints_, id));
rockot02b8e182016-07-13 20:08:30345
346 Endpoint* endpoint = endpoints_[id].get();
347 endpoint->AttachClient(client, std::move(runner));
348
349 if (endpoint->peer_closed())
350 NotifyEndpointOfError(endpoint, true /* force_async */);
351
352 return endpoint;
353 }
354
355 void DetachEndpointClient(
356 const mojo::ScopedInterfaceEndpointHandle& handle) override {
357 const mojo::InterfaceId id = handle.id();
358
359 DCHECK(mojo::IsValidInterfaceId(id));
360
361 base::AutoLock locker(lock_);
Yuzhu Shen7bcd8ebf2017-10-02 23:21:14362 DCHECK(ContainsKey(endpoints_, id));
rockot02b8e182016-07-13 20:08:30363
364 Endpoint* endpoint = endpoints_[id].get();
365 endpoint->DetachClient();
366 }
367
368 void RaiseError() override {
Ken Rockot138153b2018-07-13 23:31:57369 // We ignore errors on channel endpoints, leaving the pipe open. There are
370 // good reasons for this:
371 //
372 // * We should never close a channel endpoint in either process as long as
373 // the child process is still alive. The child's endpoint should only be
374 // closed implicitly by process death, and the browser's endpoint should
375 // only be closed after the child process is confirmed to be dead. Crash
376 // reporting logic in Chrome relies on this behavior in order to do the
377 // right thing.
378 //
379 // * There are two interesting conditions under which RaiseError() can be
380 // implicitly reached: an incoming message fails validation, or the
381 // local endpoint drops a response callback without calling it.
382 //
383 // * In the validation case, we also report the message as bad, and this
384 // will imminently trigger the common bad-IPC path in the browser,
385 // causing the browser to kill the offending renderer.
386 //
387 // * In the dropped response callback case, the net result of ignoring the
388 // issue is generally innocuous. While indicative of programmer error,
389 // it's not a severe failure and is already covered by separate DCHECKs.
390 //
391 // See https://crbug.com/861607 for additional discussion.
rockot02b8e182016-07-13 20:08:30392 }
393
Ken Rockot474df0142017-07-12 13:28:56394 bool PrefersSerializedMessages() override { return true; }
395
rockot02b8e182016-07-13 20:08:30396 private:
397 class Endpoint;
rockot0e4de5f2016-07-22 21:18:07398 class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30399 friend class Endpoint;
rockot0e4de5f2016-07-22 21:18:07400 friend class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30401
yzshen0a5971312017-02-02 05:13:47402 // MessageWrapper objects are always destroyed under the controller's lock. On
403 // destruction, if the message it wrappers contains
404 // ScopedInterfaceEndpointHandles (which cannot be destructed under the
405 // controller's lock), the wrapper unlocks to clean them up.
406 class MessageWrapper {
yzshenea784ea2017-01-31 21:20:20407 public:
yzshen0a5971312017-02-02 05:13:47408 MessageWrapper() = default;
yzshenea784ea2017-01-31 21:20:20409
yzshen0a5971312017-02-02 05:13:47410 MessageWrapper(ChannelAssociatedGroupController* controller,
411 mojo::Message message)
412 : controller_(controller), value_(std::move(message)) {}
yzshenea784ea2017-01-31 21:20:20413
yzshen0a5971312017-02-02 05:13:47414 MessageWrapper(MessageWrapper&& other)
yzshenea784ea2017-01-31 21:20:20415 : controller_(other.controller_), value_(std::move(other.value_)) {}
416
yzshen0a5971312017-02-02 05:13:47417 ~MessageWrapper() {
418 if (value_.associated_endpoint_handles()->empty())
yzshenea784ea2017-01-31 21:20:20419 return;
420
421 controller_->lock_.AssertAcquired();
yzshen0a5971312017-02-02 05:13:47422 {
yzshenea784ea2017-01-31 21:20:20423 base::AutoUnlock unlocker(controller_->lock_);
yzshen0a5971312017-02-02 05:13:47424 value_.mutable_associated_endpoint_handles()->clear();
yzshenea784ea2017-01-31 21:20:20425 }
426 }
427
yzshen0a5971312017-02-02 05:13:47428 MessageWrapper& operator=(MessageWrapper&& other) {
yzshenea784ea2017-01-31 21:20:20429 controller_ = other.controller_;
430 value_ = std::move(other.value_);
431 return *this;
432 }
433
yzshen0a5971312017-02-02 05:13:47434 mojo::Message& value() { return value_; }
yzshenea784ea2017-01-31 21:20:20435
436 private:
437 ChannelAssociatedGroupController* controller_ = nullptr;
yzshenea784ea2017-01-31 21:20:20438 mojo::Message value_;
439
yzshen0a5971312017-02-02 05:13:47440 DISALLOW_COPY_AND_ASSIGN(MessageWrapper);
yzshenea784ea2017-01-31 21:20:20441 };
442
rockot02b8e182016-07-13 20:08:30443 class Endpoint : public base::RefCountedThreadSafe<Endpoint>,
444 public mojo::InterfaceEndpointController {
445 public:
446 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id)
447 : controller_(controller), id_(id) {}
448
449 mojo::InterfaceId id() const { return id_; }
450
451 bool closed() const {
452 controller_->lock_.AssertAcquired();
453 return closed_;
454 }
455
456 void set_closed() {
457 controller_->lock_.AssertAcquired();
458 closed_ = true;
459 }
460
461 bool peer_closed() const {
462 controller_->lock_.AssertAcquired();
463 return peer_closed_;
464 }
465
466 void set_peer_closed() {
467 controller_->lock_.AssertAcquired();
468 peer_closed_ = true;
469 }
470
yzshenea784ea2017-01-31 21:20:20471 bool handle_created() const {
472 controller_->lock_.AssertAcquired();
473 return handle_created_;
474 }
475
476 void set_handle_created() {
477 controller_->lock_.AssertAcquired();
478 handle_created_ = true;
479 }
480
yzshen8be41d3a2017-01-23 20:40:37481 const base::Optional<mojo::DisconnectReason>& disconnect_reason() const {
482 return disconnect_reason_;
483 }
484
485 void set_disconnect_reason(
486 const base::Optional<mojo::DisconnectReason>& disconnect_reason) {
487 disconnect_reason_ = disconnect_reason;
488 }
489
Sam McNallyde5ae672017-06-19 23:34:45490 base::SequencedTaskRunner* task_runner() const {
rockot02b8e182016-07-13 20:08:30491 return task_runner_.get();
492 }
493
494 mojo::InterfaceEndpointClient* client() const {
495 controller_->lock_.AssertAcquired();
496 return client_;
497 }
498
499 void AttachClient(mojo::InterfaceEndpointClient* client,
Sam McNallyde5ae672017-06-19 23:34:45500 scoped_refptr<base::SequencedTaskRunner> runner) {
rockot02b8e182016-07-13 20:08:30501 controller_->lock_.AssertAcquired();
502 DCHECK(!client_);
503 DCHECK(!closed_);
peary28cd3bd22017-06-29 02:15:28504 DCHECK(runner->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30505
506 task_runner_ = std::move(runner);
507 client_ = client;
508 }
509
510 void DetachClient() {
511 controller_->lock_.AssertAcquired();
512 DCHECK(client_);
peary28cd3bd22017-06-29 02:15:28513 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30514 DCHECK(!closed_);
515
516 task_runner_ = nullptr;
517 client_ = nullptr;
rockot9abe09b2016-08-02 20:57:34518 sync_watcher_.reset();
519 }
520
yzshen0a5971312017-02-02 05:13:47521 uint32_t EnqueueSyncMessage(MessageWrapper message) {
rockot9abe09b2016-08-02 20:57:34522 controller_->lock_.AssertAcquired();
523 uint32_t id = GenerateSyncMessageId();
524 sync_messages_.emplace(id, std::move(message));
525 SignalSyncMessageEvent();
526 return id;
527 }
528
529 void SignalSyncMessageEvent() {
530 controller_->lock_.AssertAcquired();
yzshene25b5d52017-02-28 21:56:31531
Ken Rockotaa20dcc2018-03-28 03:06:51532 if (sync_watcher_)
533 sync_watcher_->SignalEvent();
rockot9abe09b2016-08-02 20:57:34534 }
535
yzshen0a5971312017-02-02 05:13:47536 MessageWrapper PopSyncMessage(uint32_t id) {
rockot9abe09b2016-08-02 20:57:34537 controller_->lock_.AssertAcquired();
538 if (sync_messages_.empty() || sync_messages_.front().first != id)
yzshen0a5971312017-02-02 05:13:47539 return MessageWrapper();
540 MessageWrapper message = std::move(sync_messages_.front().second);
rockot9abe09b2016-08-02 20:57:34541 sync_messages_.pop();
542 return message;
rockot02b8e182016-07-13 20:08:30543 }
544
545 // mojo::InterfaceEndpointController:
546 bool SendMessage(mojo::Message* message) override {
peary28cd3bd22017-06-29 02:15:28547 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30548 message->set_interface_id(id_);
549 return controller_->SendMessage(message);
550 }
551
552 void AllowWokenUpBySyncWatchOnSameThread() override {
peary28cd3bd22017-06-29 02:15:28553 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30554
rockot9abe09b2016-08-02 20:57:34555 EnsureSyncWatcherExists();
Ken Rockotaa20dcc2018-03-28 03:06:51556 sync_watcher_->AllowWokenUpBySyncWatchOnSameSequence();
rockot02b8e182016-07-13 20:08:30557 }
558
559 bool SyncWatch(const bool* should_stop) override {
peary28cd3bd22017-06-29 02:15:28560 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30561
562 // It's not legal to make sync calls from the master endpoint's thread,
563 // and in fact they must only happen from the proxy task runner.
rockot7604e7b72016-07-28 17:37:39564 DCHECK(!controller_->task_runner_->BelongsToCurrentThread());
rockot02b8e182016-07-13 20:08:30565 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread());
566
rockot9abe09b2016-08-02 20:57:34567 EnsureSyncWatcherExists();
568 return sync_watcher_->SyncWatch(should_stop);
rockot02b8e182016-07-13 20:08:30569 }
570
571 private:
572 friend class base::RefCountedThreadSafe<Endpoint>;
573
rockot9abe09b2016-08-02 20:57:34574 ~Endpoint() override {
575 controller_->lock_.AssertAcquired();
576 DCHECK(!client_);
577 DCHECK(closed_);
578 DCHECK(peer_closed_);
579 DCHECK(!sync_watcher_);
580 }
581
rockotb62e2e32017-03-24 18:36:44582 void OnSyncMessageEventReady() {
peary28cd3bd22017-06-29 02:15:28583 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34584
585 scoped_refptr<Endpoint> keepalive(this);
586 scoped_refptr<AssociatedGroupController> controller_keepalive(
587 controller_);
Ken Rockotaa20dcc2018-03-28 03:06:51588 base::AutoLock locker(controller_->lock_);
589 bool more_to_process = false;
590 if (!sync_messages_.empty()) {
591 MessageWrapper message_wrapper =
592 std::move(sync_messages_.front().second);
593 sync_messages_.pop();
rockot9abe09b2016-08-02 20:57:34594
Ken Rockotaa20dcc2018-03-28 03:06:51595 bool dispatch_succeeded;
596 mojo::InterfaceEndpointClient* client = client_;
597 {
598 base::AutoUnlock unlocker(controller_->lock_);
599 dispatch_succeeded =
600 client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34601 }
602
Ken Rockotaa20dcc2018-03-28 03:06:51603 if (!sync_messages_.empty())
604 more_to_process = true;
rockot9abe09b2016-08-02 20:57:34605
Ken Rockotaa20dcc2018-03-28 03:06:51606 if (!dispatch_succeeded)
607 controller_->RaiseError();
rockot9abe09b2016-08-02 20:57:34608 }
609
Ken Rockotaa20dcc2018-03-28 03:06:51610 if (!more_to_process)
611 sync_watcher_->ResetEvent();
612
613 // If there are no queued sync messages and the peer has closed, there
614 // there won't be incoming sync messages in the future. If any
615 // SyncWatch() calls are on the stack for this endpoint, resetting the
616 // watcher will allow them to exit as the stack undwinds.
617 if (!more_to_process && peer_closed_)
rockot9abe09b2016-08-02 20:57:34618 sync_watcher_.reset();
rockot9abe09b2016-08-02 20:57:34619 }
620
621 void EnsureSyncWatcherExists() {
peary28cd3bd22017-06-29 02:15:28622 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34623 if (sync_watcher_)
624 return;
625
Ken Rockotaa20dcc2018-03-28 03:06:51626 base::AutoLock locker(controller_->lock_);
627 sync_watcher_ = std::make_unique<mojo::SequenceLocalSyncEventWatcher>(
628 base::BindRepeating(&Endpoint::OnSyncMessageEventReady,
629 base::Unretained(this)));
630 if (peer_closed_ || !sync_messages_.empty())
631 SignalSyncMessageEvent();
rockot9abe09b2016-08-02 20:57:34632 }
633
634 uint32_t GenerateSyncMessageId() {
635 // Overflow is fine.
636 uint32_t id = next_sync_message_id_++;
637 DCHECK(sync_messages_.empty() || sync_messages_.front().first != id);
638 return id;
639 }
rockot02b8e182016-07-13 20:08:30640
641 ChannelAssociatedGroupController* const controller_;
642 const mojo::InterfaceId id_;
643
644 bool closed_ = false;
645 bool peer_closed_ = false;
yzshenea784ea2017-01-31 21:20:20646 bool handle_created_ = false;
yzshen8be41d3a2017-01-23 20:40:37647 base::Optional<mojo::DisconnectReason> disconnect_reason_;
rockot02b8e182016-07-13 20:08:30648 mojo::InterfaceEndpointClient* client_ = nullptr;
Sam McNallyde5ae672017-06-19 23:34:45649 scoped_refptr<base::SequencedTaskRunner> task_runner_;
Ken Rockotaa20dcc2018-03-28 03:06:51650 std::unique_ptr<mojo::SequenceLocalSyncEventWatcher> sync_watcher_;
Brett Wilsona62d9c02017-09-20 20:53:20651 base::queue<std::pair<uint32_t, MessageWrapper>> sync_messages_;
rockot9abe09b2016-08-02 20:57:34652 uint32_t next_sync_message_id_ = 0;
rockot02b8e182016-07-13 20:08:30653
654 DISALLOW_COPY_AND_ASSIGN(Endpoint);
655 };
656
rockot0e4de5f2016-07-22 21:18:07657 class ControlMessageProxyThunk : public MessageReceiver {
658 public:
659 explicit ControlMessageProxyThunk(
660 ChannelAssociatedGroupController* controller)
661 : controller_(controller) {}
662
663 private:
664 // MessageReceiver:
665 bool Accept(mojo::Message* message) override {
666 return controller_->SendMessage(message);
667 }
668
669 ChannelAssociatedGroupController* controller_;
670
671 DISALLOW_COPY_AND_ASSIGN(ControlMessageProxyThunk);
672 };
673
rockot02b8e182016-07-13 20:08:30674 ~ChannelAssociatedGroupController() override {
rockotb01ef6a2016-07-27 03:24:32675 DCHECK(!connector_);
676
rockot02b8e182016-07-13 20:08:30677 base::AutoLock locker(lock_);
rockot02b8e182016-07-13 20:08:30678 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
679 Endpoint* endpoint = iter->second.get();
680 ++iter;
681
yzshene003d592017-01-24 21:42:17682 if (!endpoint->closed()) {
683 // This happens when a NotifyPeerEndpointClosed message been received,
yzshen2859a2ac2017-02-14 22:24:25684 // but the interface ID hasn't been used to create local endpoint
685 // handle.
yzshene003d592017-01-24 21:42:17686 DCHECK(!endpoint->client());
687 DCHECK(endpoint->peer_closed());
688 MarkClosedAndMaybeRemove(endpoint);
689 } else {
690 MarkPeerClosedAndMaybeRemove(endpoint);
691 }
rockot02b8e182016-07-13 20:08:30692 }
693
694 DCHECK(endpoints_.empty());
Ken Rockot2b6de982018-03-20 22:28:13695
696 GetMemoryDumpProvider().RemoveController(this);
rockot02b8e182016-07-13 20:08:30697 }
698
699 bool SendMessage(mojo::Message* message) {
Siddhartha S03484422019-04-23 20:30:00700 DCHECK(message->heap_profiler_tag());
rockot7604e7b72016-07-28 17:37:39701 if (task_runner_->BelongsToCurrentThread()) {
rockot02b8e182016-07-13 20:08:30702 DCHECK(thread_checker_.CalledOnValidThread());
rockot10188752016-09-08 18:24:56703 if (!connector_ || paused_) {
Ken Rockot37ddd8152018-02-22 18:18:46704 if (!shut_down_) {
Ken Rockot2b6de982018-03-20 22:28:13705 base::AutoLock lock(outgoing_messages_lock_);
Ken Rockot3e7284bb2018-02-06 16:11:16706 outgoing_messages_.emplace_back(std::move(*message));
Ken Rockot37ddd8152018-02-22 18:18:46707 }
rockot0e4de5f2016-07-22 21:18:07708 return true;
709 }
710 return connector_->Accept(message);
rockot02b8e182016-07-13 20:08:30711 } else {
Ken Rockotfb81dc02018-05-15 21:59:26712 // Do a message size check here so we don't lose valuable stack
713 // information to the task scheduler.
714 CHECK_LE(message->data_num_bytes(), Channel::kMaximumMessageSize);
715
rockotbecd3f742016-11-08 20:47:00716 // We always post tasks to the master endpoint thread when called from
717 // other threads in order to simulate IPC::ChannelProxy::Send behavior.
rockot02b8e182016-07-13 20:08:30718 task_runner_->PostTask(
719 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09720 base::BindOnce(
rockot02b8e182016-07-13 20:08:30721 &ChannelAssociatedGroupController::SendMessageOnMasterThread,
rockotc4cc691e2016-08-19 18:48:57722 this, base::Passed(message)));
rockot02b8e182016-07-13 20:08:30723 return true;
724 }
725 }
726
rockotc4cc691e2016-08-19 18:48:57727 void SendMessageOnMasterThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30728 DCHECK(thread_checker_.CalledOnValidThread());
rockotc4cc691e2016-08-19 18:48:57729 if (!SendMessage(&message))
rockot02b8e182016-07-13 20:08:30730 RaiseError();
731 }
732
733 void OnPipeError() {
734 DCHECK(thread_checker_.CalledOnValidThread());
735
736 // We keep |this| alive here because it's possible for the notifications
737 // below to release all other references.
738 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
739
740 base::AutoLock locker(lock_);
741 encountered_error_ = true;
742
743 std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
744 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
745 Endpoint* endpoint = iter->second.get();
746 ++iter;
747
748 if (endpoint->client())
749 endpoints_to_notify.push_back(endpoint);
750
751 MarkPeerClosedAndMaybeRemove(endpoint);
752 }
753
754 for (auto& endpoint : endpoints_to_notify) {
rockot0e4de5f2016-07-22 21:18:07755 // Because a notification may in turn detach any endpoint, we have to
rockot02b8e182016-07-13 20:08:30756 // check each client again here.
757 if (endpoint->client())
758 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
759 }
760 }
761
762 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
763 lock_.AssertAcquired();
764 DCHECK(endpoint->task_runner() && endpoint->client());
peary28cd3bd22017-06-29 02:15:28765 if (endpoint->task_runner()->RunsTasksInCurrentSequence() && !force_async) {
rockot02b8e182016-07-13 20:08:30766 mojo::InterfaceEndpointClient* client = endpoint->client();
yzshen8be41d3a2017-01-23 20:40:37767 base::Optional<mojo::DisconnectReason> reason(
768 endpoint->disconnect_reason());
rockot02b8e182016-07-13 20:08:30769
770 base::AutoUnlock unlocker(lock_);
yzshen8be41d3a2017-01-23 20:40:37771 client->NotifyError(reason);
rockot02b8e182016-07-13 20:08:30772 } else {
773 endpoint->task_runner()->PostTask(
774 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09775 base::BindOnce(&ChannelAssociatedGroupController::
776 NotifyEndpointOfErrorOnEndpointThread,
777 this, endpoint->id(), base::Unretained(endpoint)));
rockot02b8e182016-07-13 20:08:30778 }
779 }
780
rockot9abe09b2016-08-02 20:57:34781 void NotifyEndpointOfErrorOnEndpointThread(mojo::InterfaceId id,
782 Endpoint* endpoint) {
rockot02b8e182016-07-13 20:08:30783 base::AutoLock locker(lock_);
rockot9abe09b2016-08-02 20:57:34784 auto iter = endpoints_.find(id);
785 if (iter == endpoints_.end() || iter->second.get() != endpoint)
786 return;
rockot02b8e182016-07-13 20:08:30787 if (!endpoint->client())
788 return;
rockot9abe09b2016-08-02 20:57:34789
peary28cd3bd22017-06-29 02:15:28790 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34791 NotifyEndpointOfError(endpoint, false /* force_async */);
rockot02b8e182016-07-13 20:08:30792 }
793
794 void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
795 lock_.AssertAcquired();
796 endpoint->set_closed();
797 if (endpoint->closed() && endpoint->peer_closed())
798 endpoints_.erase(endpoint->id());
799 }
800
801 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
802 lock_.AssertAcquired();
803 endpoint->set_peer_closed();
rockot9abe09b2016-08-02 20:57:34804 endpoint->SignalSyncMessageEvent();
rockot02b8e182016-07-13 20:08:30805 if (endpoint->closed() && endpoint->peer_closed())
806 endpoints_.erase(endpoint->id());
807 }
808
809 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {
810 lock_.AssertAcquired();
811 DCHECK(!inserted || !*inserted);
812
yzshen0a5971312017-02-02 05:13:47813 Endpoint* endpoint = FindEndpoint(id);
814 if (!endpoint) {
815 endpoint = new Endpoint(this, id);
816 endpoints_.insert({id, endpoint});
817 if (inserted)
818 *inserted = true;
819 }
rockot02b8e182016-07-13 20:08:30820 return endpoint;
821 }
822
yzshen0a5971312017-02-02 05:13:47823 Endpoint* FindEndpoint(mojo::InterfaceId id) {
824 lock_.AssertAcquired();
825 auto iter = endpoints_.find(id);
826 return iter != endpoints_.end() ? iter->second.get() : nullptr;
827 }
828
rockot02b8e182016-07-13 20:08:30829 // mojo::MessageReceiver:
830 bool Accept(mojo::Message* message) override {
831 DCHECK(thread_checker_.CalledOnValidThread());
832
yzshen0a5971312017-02-02 05:13:47833 if (!message->DeserializeAssociatedEndpointHandles(this))
834 return false;
835
836 if (mojo::PipeControlMessageHandler::IsPipeControlMessage(message))
837 return control_message_handler_.Accept(message);
rockot02b8e182016-07-13 20:08:30838
839 mojo::InterfaceId id = message->interface_id();
840 DCHECK(mojo::IsValidInterfaceId(id));
841
Ken Rockot4fede4552019-05-09 01:16:41842 base::ReleasableAutoLock locker(&lock_);
yzshen0a5971312017-02-02 05:13:47843 Endpoint* endpoint = FindEndpoint(id);
844 if (!endpoint)
845 return true;
846
847 mojo::InterfaceEndpointClient* client = endpoint->client();
peary28cd3bd22017-06-29 02:15:28848 if (!client || !endpoint->task_runner()->RunsTasksInCurrentSequence()) {
rockot02b8e182016-07-13 20:08:30849 // No client has been bound yet or the client runs tasks on another
850 // thread. We assume the other thread must always be the one on which
851 // |proxy_task_runner_| runs tasks, since that's the only valid scenario.
852 //
853 // If the client is not yet bound, it must be bound by the time this task
854 // runs or else it's programmer error.
855 DCHECK(proxy_task_runner_);
rockot9abe09b2016-08-02 20:57:34856
rockotc4cc691e2016-08-19 18:48:57857 if (message->has_flag(mojo::Message::kFlagIsSync)) {
yzshen0a5971312017-02-02 05:13:47858 MessageWrapper message_wrapper(this, std::move(*message));
rockot9abe09b2016-08-02 20:57:34859 // Sync messages may need to be handled by the endpoint if it's blocking
860 // on a sync reply. We pass ownership of the message to the endpoint's
861 // sync message queue. If the endpoint was blocking, it will dequeue the
862 // message and dispatch it. Otherwise the posted |AcceptSyncMessage()|
863 // call will dequeue the message and dispatch it.
yzshenea784ea2017-01-31 21:20:20864 uint32_t message_id =
865 endpoint->EnqueueSyncMessage(std::move(message_wrapper));
rockot9abe09b2016-08-02 20:57:34866 proxy_task_runner_->PostTask(
867 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09868 base::BindOnce(&ChannelAssociatedGroupController::AcceptSyncMessage,
869 this, id, message_id));
rockot9abe09b2016-08-02 20:57:34870 return true;
871 }
872
Ken Rockot4fede4552019-05-09 01:16:41873 // If |proxy_task_runner_| has been torn down already, this PostTask will
874 // fail and destroy |message|. That operation may need to in turn destroy
875 // in-transit associated endpoints and thus acquire |lock_|. We no longer
876 // need the lock to be held now since |proxy_task_runner_| is safe to
877 // access unguarded.
878 locker.Release();
rockot02b8e182016-07-13 20:08:30879 proxy_task_runner_->PostTask(
880 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09881 base::BindOnce(&ChannelAssociatedGroupController::AcceptOnProxyThread,
Ken Rockot4fede4552019-05-09 01:16:41882 this, std::move(*message)));
rockot02b8e182016-07-13 20:08:30883 return true;
884 }
885
886 // We do not expect to receive sync responses on the master endpoint thread.
887 // If it's happening, it's a bug.
rockot9abe09b2016-08-02 20:57:34888 DCHECK(!message->has_flag(mojo::Message::kFlagIsSync) ||
889 !message->has_flag(mojo::Message::kFlagIsResponse));
rockot02b8e182016-07-13 20:08:30890
Ken Rockot4fede4552019-05-09 01:16:41891 locker.Release();
yzshen0a5971312017-02-02 05:13:47892 return client->HandleIncomingMessage(message);
rockot02b8e182016-07-13 20:08:30893 }
894
rockotc4cc691e2016-08-19 18:48:57895 void AcceptOnProxyThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30896 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
897
rockotc4cc691e2016-08-19 18:48:57898 mojo::InterfaceId id = message.interface_id();
rockot8d890f62016-07-14 16:37:14899 DCHECK(mojo::IsValidInterfaceId(id) && !mojo::IsMasterInterfaceId(id));
900
901 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47902 Endpoint* endpoint = FindEndpoint(id);
rockot8d890f62016-07-14 16:37:14903 if (!endpoint)
904 return;
905
906 mojo::InterfaceEndpointClient* client = endpoint->client();
907 if (!client)
908 return;
909
peary28cd3bd22017-06-29 02:15:28910 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
rockot8d890f62016-07-14 16:37:14911
rockot9abe09b2016-08-02 20:57:34912 // Sync messages should never make their way to this method.
yzshen0a5971312017-02-02 05:13:47913 DCHECK(!message.has_flag(mojo::Message::kFlagIsSync));
rockot8d890f62016-07-14 16:37:14914
915 bool result = false;
916 {
917 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47918 result = client->HandleIncomingMessage(&message);
rockot8d890f62016-07-14 16:37:14919 }
920
921 if (!result)
922 RaiseError();
923 }
924
rockot9abe09b2016-08-02 20:57:34925 void AcceptSyncMessage(mojo::InterfaceId interface_id, uint32_t message_id) {
926 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
927
928 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47929 Endpoint* endpoint = FindEndpoint(interface_id);
rockot9abe09b2016-08-02 20:57:34930 if (!endpoint)
931 return;
932
csharrison1af8d6ab2017-04-21 17:47:23933 // Careful, if the endpoint is detached its members are cleared. Check for
934 // that before dereferencing.
935 mojo::InterfaceEndpointClient* client = endpoint->client();
936 if (!client)
937 return;
938
peary28cd3bd22017-06-29 02:15:28939 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
yzshen0a5971312017-02-02 05:13:47940 MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id);
rockot9abe09b2016-08-02 20:57:34941
942 // The message must have already been dequeued by the endpoint waking up
943 // from a sync wait. Nothing to do.
yzshenea784ea2017-01-31 21:20:20944 if (message_wrapper.value().IsNull())
rockot9abe09b2016-08-02 20:57:34945 return;
946
rockot9abe09b2016-08-02 20:57:34947 bool result = false;
948 {
949 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47950 result = client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34951 }
952
953 if (!result)
954 RaiseError();
955 }
956
rockot02b8e182016-07-13 20:08:30957 // mojo::PipeControlMessageHandlerDelegate:
yzshen8be41d3a2017-01-23 20:40:37958 bool OnPeerAssociatedEndpointClosed(
959 mojo::InterfaceId id,
960 const base::Optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30961 DCHECK(thread_checker_.CalledOnValidThread());
962
rockot0e4de5f2016-07-22 21:18:07963 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
rockot02b8e182016-07-13 20:08:30964 base::AutoLock locker(lock_);
965 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr);
yzshen8be41d3a2017-01-23 20:40:37966 if (reason)
967 endpoint->set_disconnect_reason(reason);
rockot02b8e182016-07-13 20:08:30968 if (!endpoint->peer_closed()) {
969 if (endpoint->client())
970 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
971 MarkPeerClosedAndMaybeRemove(endpoint.get());
972 }
973
974 return true;
975 }
976
rockot02b8e182016-07-13 20:08:30977 // Checked in places which must be run on the master endpoint's thread.
978 base::ThreadChecker thread_checker_;
979
980 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
rockot0e4de5f2016-07-22 21:18:07981
Ken Rockot4fede4552019-05-09 01:16:41982 const scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
rockot0e4de5f2016-07-22 21:18:07983 const bool set_interface_id_namespace_bit_;
rockot10188752016-09-08 18:24:56984 bool paused_ = false;
rockot0e4de5f2016-07-22 21:18:07985 std::unique_ptr<mojo::Connector> connector_;
rockot222e7dd2016-08-24 23:37:11986 mojo::FilterChain filters_;
rockot02b8e182016-07-13 20:08:30987 mojo::PipeControlMessageHandler control_message_handler_;
rockot0e4de5f2016-07-22 21:18:07988 ControlMessageProxyThunk control_message_proxy_thunk_;
rockot58909542016-11-10 20:05:45989
990 // NOTE: It is unsafe to call into this object while holding |lock_|.
rockot0e4de5f2016-07-22 21:18:07991 mojo::PipeControlMessageProxy control_message_proxy_;
992
Ken Rockot2b6de982018-03-20 22:28:13993 // Guards access to |outgoing_messages_| only. Used to support memory dumps
994 // which may be triggered from any thread.
995 base::Lock outgoing_messages_lock_;
996
rockot0e4de5f2016-07-22 21:18:07997 // Outgoing messages that were sent before this controller was bound to a
998 // real message pipe.
rockotc4cc691e2016-08-19 18:48:57999 std::vector<mojo::Message> outgoing_messages_;
rockot02b8e182016-07-13 20:08:301000
1001 // Guards the fields below for thread-safe access.
1002 base::Lock lock_;
1003
1004 bool encountered_error_ = false;
Ken Rockot3e7284bb2018-02-06 16:11:161005 bool shut_down_ = false;
rockot0e4de5f2016-07-22 21:18:071006
1007 // ID #1 is reserved for the mojom::Channel interface.
1008 uint32_t next_interface_id_ = 2;
1009
Yuzhu Shen7bcd8ebf2017-10-02 23:21:141010 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_;
rockot02b8e182016-07-13 20:08:301011
1012 DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController);
1013};
1014
Ken Rockot2b6de982018-03-20 22:28:131015bool ControllerMemoryDumpProvider::OnMemoryDump(
1016 const base::trace_event::MemoryDumpArgs& args,
1017 base::trace_event::ProcessMemoryDump* pmd) {
1018 base::AutoLock lock(lock_);
1019 for (auto* controller : controllers_) {
1020 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
1021 base::StringPrintf("mojo/queued_ipc_channel_message/0x%" PRIxPTR,
1022 reinterpret_cast<uintptr_t>(controller)));
1023 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
1024 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
1025 controller->GetQueuedMessageCount());
Siddhartha S03484422019-04-23 20:30:001026 MessageMemoryDumpInfo info;
1027 size_t count = 0;
1028 controller->GetTopQueuedMessageMemoryDumpInfo(&info, &count);
1029 dump->AddScalar("top_message_name", "id", info.id);
Siddharthad1cfec12018-09-17 21:42:151030 dump->AddScalar("top_message_count",
1031 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
Siddhartha S03484422019-04-23 20:30:001032 count);
1033
1034 if (info.profiler_tag) {
1035 // TODO(ssid): Memory dumps currently do not support adding string
1036 // arguments in background dumps. So, add this value as a trace event for
1037 // now.
1038 TRACE_EVENT1(base::trace_event::MemoryDumpManager::kTraceCategory,
1039 "ControllerMemoryDumpProvider::OnMemoryDump",
1040 "top_queued_message_tag", info.profiler_tag);
1041 }
Ken Rockot2b6de982018-03-20 22:28:131042 }
1043
1044 return true;
1045}
1046
rockot0e4de5f2016-07-22 21:18:071047class MojoBootstrapImpl : public MojoBootstrap {
rockot02b8e182016-07-13 20:08:301048 public:
rockot0e4de5f2016-07-22 21:18:071049 MojoBootstrapImpl(
1050 mojo::ScopedMessagePipeHandle handle,
rockot0e4de5f2016-07-22 21:18:071051 const scoped_refptr<ChannelAssociatedGroupController> controller)
yzshen2859a2ac2017-02-14 22:24:251052 : controller_(controller),
1053 associated_group_(controller),
1054 handle_(std::move(handle)) {}
rockot02b8e182016-07-13 20:08:301055
rockot0e4de5f2016-07-22 21:18:071056 ~MojoBootstrapImpl() override {
1057 controller_->ShutDown();
rockot02b8e182016-07-13 20:08:301058 }
1059
1060 private:
rockota628d0b2017-02-09 08:40:151061 void Connect(mojom::ChannelAssociatedPtr* sender,
1062 mojom::ChannelAssociatedRequest* receiver) override {
rockot0e4de5f2016-07-22 21:18:071063 controller_->Bind(std::move(handle_));
rockota628d0b2017-02-09 08:40:151064 controller_->CreateChannelEndpoints(sender, receiver);
msramek5507fee2016-07-22 10:06:211065 }
1066
rockot10188752016-09-08 18:24:561067 void Pause() override {
1068 controller_->Pause();
1069 }
1070
1071 void Unpause() override {
1072 controller_->Unpause();
rockot401fb2c2016-09-06 18:35:571073 }
1074
1075 void Flush() override {
1076 controller_->FlushOutgoingMessages();
1077 }
1078
msramek5507fee2016-07-22 10:06:211079 mojo::AssociatedGroup* GetAssociatedGroup() override {
yzshen2859a2ac2017-02-14 22:24:251080 return &associated_group_;
msramek5507fee2016-07-22 10:06:211081 }
1082
rockot0e4de5f2016-07-22 21:18:071083 scoped_refptr<ChannelAssociatedGroupController> controller_;
yzshen2859a2ac2017-02-14 22:24:251084 mojo::AssociatedGroup associated_group_;
msramek5507fee2016-07-22 10:06:211085
rockot0e4de5f2016-07-22 21:18:071086 mojo::ScopedMessagePipeHandle handle_;
msramek5507fee2016-07-22 10:06:211087
rockot0e4de5f2016-07-22 21:18:071088 DISALLOW_COPY_AND_ASSIGN(MojoBootstrapImpl);
msramek5507fee2016-07-22 10:06:211089};
1090
morrita54f6f80c2014-09-23 21:16:001091} // namespace
1092
morrita54f6f80c2014-09-23 21:16:001093// static
danakj03de39b22016-04-23 04:21:091094std::unique_ptr<MojoBootstrap> MojoBootstrap::Create(
sammc57ed9f982016-03-10 06:28:351095 mojo::ScopedMessagePipeHandle handle,
1096 Channel::Mode mode,
Hajime Hoshia98f1102017-11-20 06:34:351097 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
1098 const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner) {
Jeremy Roman160eb922017-08-29 17:43:431099 return std::make_unique<MojoBootstrapImpl>(
Hajime Hoshia98f1102017-11-20 06:34:351100 std::move(handle),
1101 new ChannelAssociatedGroupController(mode == Channel::MODE_SERVER,
1102 ipc_task_runner, proxy_task_runner));
sammc57ed9f982016-03-10 06:28:351103}
1104
morrita54f6f80c2014-09-23 21:16:001105} // namespace IPC