blob: 568f2c0c01274b5b3f4357f71e2801149ac45347 [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"
Hans Wennborg4ed044f2020-04-27 09:43:3818#include "base/check_op.h"
Lei Zhang812c5392021-05-18 04:44:3219#include "base/containers/contains.h"
Brett Wilsona62d9c02017-09-20 20:53:2020#include "base/containers/queue.h"
danakj03de39b22016-04-23 04:21:0921#include "base/memory/ptr_util.h"
Keishi Hattori0e45c022021-11-27 09:25:5222#include "base/memory/raw_ptr.h"
Ken Rockot2b6de982018-03-20 22:28:1323#include "base/no_destructor.h"
Ken Rockot2b6de982018-03-20 22:28:1324#include "base/strings/stringprintf.h"
rockot02b8e182016-07-13 20:08:3025#include "base/synchronization/lock.h"
Harkiran Bolaria8b1cf112020-09-15 22:58:3426#include "base/task/common/task_annotator.h"
Patrick Monette643cdf62021-10-15 19:13:4227#include "base/task/sequenced_task_runner.h"
28#include "base/task/single_thread_task_runner.h"
Sam McNallyde5ae672017-06-19 23:34:4529#include "base/threading/thread_checker.h"
Ken Rockotc5cc02732021-06-04 08:02:4130#include "base/threading/thread_local.h"
rockot02b8e182016-07-13 20:08:3031#include "base/threading/thread_task_runner_handle.h"
Ken Rockot2b6de982018-03-20 22:28:1332#include "base/trace_event/memory_allocator_dump.h"
33#include "base/trace_event/memory_dump_manager.h"
34#include "base/trace_event/memory_dump_provider.h"
Alexander Timinda1f2c52021-11-03 02:23:0535#include "base/trace_event/typed_macros.h"
Ken Rockotfb81dc02018-05-15 21:59:2636#include "ipc/ipc_channel.h"
rockot02b8e182016-07-13 20:08:3037#include "mojo/public/cpp/bindings/associated_group.h"
38#include "mojo/public/cpp/bindings/associated_group_controller.h"
rockot02b8e182016-07-13 20:08:3039#include "mojo/public/cpp/bindings/connector.h"
40#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
41#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
42#include "mojo/public/cpp/bindings/interface_id.h"
rockot0e4de5f2016-07-22 21:18:0743#include "mojo/public/cpp/bindings/message.h"
rockot02b8e182016-07-13 20:08:3044#include "mojo/public/cpp/bindings/message_header_validator.h"
Alexander Timinda1f2c52021-11-03 02:23:0545#include "mojo/public/cpp/bindings/mojo_buildflags.h"
rockot02b8e182016-07-13 20:08:3046#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
47#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
48#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
Ken Rockotaa20dcc2018-03-28 03:06:5149#include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h"
Alexander Timinda1f2c52021-11-03 02:23:0550#include "mojo/public/cpp/bindings/tracing_helpers.h"
morrita54f6f80c2014-09-23 21:16:0051
52namespace IPC {
53
54namespace {
55
Ken Rockot2b6de982018-03-20 22:28:1356class ChannelAssociatedGroupController;
57
Ken Rockotc5cc02732021-06-04 08:02:4158base::ThreadLocalBoolean& GetOffSequenceBindingAllowedFlag() {
59 static base::NoDestructor<base::ThreadLocalBoolean> flag;
60 return *flag;
61}
62
63bool CanBindOffSequence() {
64 return GetOffSequenceBindingAllowedFlag().Get();
65}
66
Ken Rockot2b6de982018-03-20 22:28:1367// Used to track some internal Channel state in pursuit of message leaks.
68//
69// TODO(https://crbug.com/813045): Remove this.
70class ControllerMemoryDumpProvider
71 : public base::trace_event::MemoryDumpProvider {
72 public:
73 ControllerMemoryDumpProvider() {
74 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
75 this, "IPCChannel", nullptr);
76 }
77
Peter Boströmc68c5aa2021-09-28 00:28:0078 ControllerMemoryDumpProvider(const ControllerMemoryDumpProvider&) = delete;
79 ControllerMemoryDumpProvider& operator=(const ControllerMemoryDumpProvider&) =
80 delete;
81
Ken Rockot2b6de982018-03-20 22:28:1382 ~ControllerMemoryDumpProvider() override {
83 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
84 this);
85 }
86
87 void AddController(ChannelAssociatedGroupController* controller) {
88 base::AutoLock lock(lock_);
89 controllers_.insert(controller);
90 }
91
92 void RemoveController(ChannelAssociatedGroupController* controller) {
93 base::AutoLock lock(lock_);
94 controllers_.erase(controller);
95 }
96
97 // base::trace_event::MemoryDumpProvider:
98 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
99 base::trace_event::ProcessMemoryDump* pmd) override;
100
101 private:
102 base::Lock lock_;
103 std::set<ChannelAssociatedGroupController*> controllers_;
Ken Rockot2b6de982018-03-20 22:28:13104};
105
106ControllerMemoryDumpProvider& GetMemoryDumpProvider() {
107 static base::NoDestructor<ControllerMemoryDumpProvider> provider;
108 return *provider;
109}
110
Siddhartha S03484422019-04-23 20:30:00111// Messages are grouped by this info when recording memory metrics.
112struct MessageMemoryDumpInfo {
113 MessageMemoryDumpInfo(const mojo::Message& message)
114 : id(message.name()), profiler_tag(message.heap_profiler_tag()) {}
115 MessageMemoryDumpInfo() = default;
116
117 bool operator==(const MessageMemoryDumpInfo& other) const {
118 return other.id == id && other.profiler_tag == profiler_tag;
119 }
120
121 uint32_t id = 0;
122 const char* profiler_tag = nullptr;
123};
124
125struct MessageMemoryDumpInfoHash {
126 size_t operator()(const MessageMemoryDumpInfo& info) const {
Daniel Cheng5c5a6522019-11-19 18:03:36127 return base::HashInts(
128 info.id, info.profiler_tag ? base::FastHash(info.profiler_tag) : 0);
Siddhartha S03484422019-04-23 20:30:00129 }
130};
131
rockot02b8e182016-07-13 20:08:30132class ChannelAssociatedGroupController
133 : public mojo::AssociatedGroupController,
134 public mojo::MessageReceiver,
135 public mojo::PipeControlMessageHandlerDelegate {
136 public:
rockot0e4de5f2016-07-22 21:18:07137 ChannelAssociatedGroupController(
138 bool set_interface_id_namespace_bit,
Hajime Hoshia98f1102017-11-20 06:34:35139 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20140 const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner,
141 const scoped_refptr<mojo::internal::MessageQuotaChecker>& quota_checker)
rockotb01ef6a2016-07-27 03:24:32142 : task_runner_(ipc_task_runner),
Hajime Hoshia98f1102017-11-20 06:34:35143 proxy_task_runner_(proxy_task_runner),
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20144 quota_checker_(quota_checker),
rockot0e4de5f2016-07-22 21:18:07145 set_interface_id_namespace_bit_(set_interface_id_namespace_bit),
Dave Tapuskaf2df43e2019-10-10 22:10:10146 dispatcher_(this),
rockot02b8e182016-07-13 20:08:30147 control_message_handler_(this),
rockot0e4de5f2016-07-22 21:18:07148 control_message_proxy_thunk_(this),
149 control_message_proxy_(&control_message_proxy_thunk_) {
150 thread_checker_.DetachFromThread();
rockot02b8e182016-07-13 20:08:30151 control_message_handler_.SetDescription(
Ken Rockotcd23f752020-06-20 01:22:31152 "IPC::mojom::Bootstrap [primary] PipeControlMessageHandler");
Dave Tapuskaf2df43e2019-10-10 22:10:10153 dispatcher_.SetValidator(std::make_unique<mojo::MessageHeaderValidator>(
Ken Rockotcd23f752020-06-20 01:22:31154 "IPC::mojom::Bootstrap [primary] MessageHeaderValidator"));
Ken Rockot2b6de982018-03-20 22:28:13155
156 GetMemoryDumpProvider().AddController(this);
157 }
158
Peter Boström896f1372021-11-05 01:12:30159 ChannelAssociatedGroupController(const ChannelAssociatedGroupController&) =
160 delete;
161 ChannelAssociatedGroupController& operator=(
162 const ChannelAssociatedGroupController&) = delete;
163
Ken Rockot2b6de982018-03-20 22:28:13164 size_t GetQueuedMessageCount() {
165 base::AutoLock lock(outgoing_messages_lock_);
166 return outgoing_messages_.size();
rockot02b8e182016-07-13 20:08:30167 }
168
Siddhartha S03484422019-04-23 20:30:00169 void GetTopQueuedMessageMemoryDumpInfo(MessageMemoryDumpInfo* info,
170 size_t* count) {
171 std::unordered_map<MessageMemoryDumpInfo, size_t, MessageMemoryDumpInfoHash>
172 counts;
173 std::pair<MessageMemoryDumpInfo, size_t> top_message_info_and_count = {
174 MessageMemoryDumpInfo(), 0};
Siddharthad1cfec12018-09-17 21:42:15175 base::AutoLock lock(outgoing_messages_lock_);
176 for (const auto& message : outgoing_messages_) {
Siddhartha S03484422019-04-23 20:30:00177 auto it_and_inserted = counts.emplace(MessageMemoryDumpInfo(message), 0);
Siddharthad1cfec12018-09-17 21:42:15178 it_and_inserted.first->second++;
Siddhartha S03484422019-04-23 20:30:00179 if (it_and_inserted.first->second > top_message_info_and_count.second)
180 top_message_info_and_count = *it_and_inserted.first;
Siddharthad1cfec12018-09-17 21:42:15181 }
Siddhartha S03484422019-04-23 20:30:00182 *info = top_message_info_and_count.first;
183 *count = top_message_info_and_count.second;
Siddharthad1cfec12018-09-17 21:42:15184 }
185
rockot10188752016-09-08 18:24:56186 void Pause() {
187 DCHECK(!paused_);
188 paused_ = true;
189 }
190
191 void Unpause() {
192 DCHECK(paused_);
193 paused_ = false;
rockot401fb2c2016-09-06 18:35:57194 }
195
196 void FlushOutgoingMessages() {
rockotc4cc691e2016-08-19 18:48:57197 std::vector<mojo::Message> outgoing_messages;
Ken Rockot2b6de982018-03-20 22:28:13198 {
199 base::AutoLock lock(outgoing_messages_lock_);
200 std::swap(outgoing_messages, outgoing_messages_);
201 }
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20202 if (quota_checker_ && outgoing_messages.size())
203 quota_checker_->AfterMessagesDequeued(outgoing_messages.size());
204
rockot0e4de5f2016-07-22 21:18:07205 for (auto& message : outgoing_messages)
rockotc4cc691e2016-08-19 18:48:57206 SendMessage(&message);
rockot0e4de5f2016-07-22 21:18:07207 }
208
Ken Rockot9fae8bcd2021-06-04 22:09:49209 void Bind(mojo::ScopedMessagePipeHandle handle,
210 mojo::PendingAssociatedRemote<mojom::Channel>* sender,
211 mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) {
212 connector_ = std::make_unique<mojo::Connector>(
213 std::move(handle), mojo::Connector::SINGLE_THREADED_SEND,
214 "IPC Channel");
215 connector_->set_incoming_receiver(&dispatcher_);
216 connector_->set_connection_error_handler(
217 base::BindOnce(&ChannelAssociatedGroupController::OnPipeError,
218 base::Unretained(this)));
219 connector_->set_enforce_errors_from_incoming_receiver(false);
220 if (quota_checker_)
221 connector_->SetMessageQuotaChecker(quota_checker_);
222
223 // Don't let the Connector do any sort of queuing on our behalf. Individual
224 // messages bound for the IPC::ChannelProxy thread (i.e. that vast majority
225 // of messages received by this Connector) are already individually
226 // scheduled for dispatch by ChannelProxy, so Connector's normal mode of
227 // operation would only introduce a redundant scheduling step for most
228 // messages.
229 connector_->set_force_immediate_dispatch(true);
230
rockot0e4de5f2016-07-22 21:18:07231 mojo::InterfaceId sender_id, receiver_id;
232 if (set_interface_id_namespace_bit_) {
233 sender_id = 1 | mojo::kInterfaceIdNamespaceMask;
234 receiver_id = 1;
235 } else {
236 sender_id = 1;
237 receiver_id = 1 | mojo::kInterfaceIdNamespaceMask;
238 }
239
240 {
241 base::AutoLock locker(lock_);
242 Endpoint* sender_endpoint = new Endpoint(this, sender_id);
243 Endpoint* receiver_endpoint = new Endpoint(this, receiver_id);
244 endpoints_.insert({ sender_id, sender_endpoint });
245 endpoints_.insert({ receiver_id, receiver_endpoint });
yzshen0a5971312017-02-02 05:13:47246 sender_endpoint->set_handle_created();
247 receiver_endpoint->set_handle_created();
rockot0e4de5f2016-07-22 21:18:07248 }
249
250 mojo::ScopedInterfaceEndpointHandle sender_handle =
yzshen2859a2ac2017-02-14 22:24:25251 CreateScopedInterfaceEndpointHandle(sender_id);
rockot0e4de5f2016-07-22 21:18:07252 mojo::ScopedInterfaceEndpointHandle receiver_handle =
yzshen2859a2ac2017-02-14 22:24:25253 CreateScopedInterfaceEndpointHandle(receiver_id);
rockot0e4de5f2016-07-22 21:18:07254
Ken Rockotfbbd4442021-06-04 01:19:14255 *sender = mojo::PendingAssociatedRemote<mojom::Channel>(
256 std::move(sender_handle), 0);
Julie Jeongeun Kim903b34b2019-09-25 11:11:54257 *receiver = mojo::PendingAssociatedReceiver<mojom::Channel>(
258 std::move(receiver_handle));
rockot0e4de5f2016-07-22 21:18:07259 }
rockot02b8e182016-07-13 20:08:30260
Ken Rockot9fae8bcd2021-06-04 22:09:49261 void StartReceiving() { connector_->StartReceiving(task_runner_); }
262
rockot02b8e182016-07-13 20:08:30263 void ShutDown() {
264 DCHECK(thread_checker_.CalledOnValidThread());
Ken Rockot3e7284bb2018-02-06 16:11:16265 shut_down_ = true;
Bruce Dawsona40d48472020-04-20 20:57:24266 if (connector_)
267 connector_->CloseMessagePipe();
rockot02b8e182016-07-13 20:08:30268 OnPipeError();
rockot0e4de5f2016-07-22 21:18:07269 connector_.reset();
Ken Rockot2b6de982018-03-20 22:28:13270
271 base::AutoLock lock(outgoing_messages_lock_);
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20272 if (quota_checker_ && outgoing_messages_.size())
273 quota_checker_->AfterMessagesDequeued(outgoing_messages_.size());
274
Ken Rockot3e7284bb2018-02-06 16:11:16275 outgoing_messages_.clear();
rockot02b8e182016-07-13 20:08:30276 }
277
278 // mojo::AssociatedGroupController:
yzshen2859a2ac2017-02-14 22:24:25279 mojo::InterfaceId AssociateInterface(
280 mojo::ScopedInterfaceEndpointHandle handle_to_send) override {
281 if (!handle_to_send.pending_association())
282 return mojo::kInvalidInterfaceId;
283
rockot02b8e182016-07-13 20:08:30284 uint32_t id = 0;
yzshen2859a2ac2017-02-14 22:24:25285 {
286 base::AutoLock locker(lock_);
287 do {
288 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask)
289 next_interface_id_ = 2;
290 id = next_interface_id_++;
291 if (set_interface_id_namespace_bit_)
292 id |= mojo::kInterfaceIdNamespaceMask;
Jan Wilken Dörrie73c901e2019-06-12 09:02:32293 } while (base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30294
yzshen2859a2ac2017-02-14 22:24:25295 Endpoint* endpoint = new Endpoint(this, id);
296 if (encountered_error_)
297 endpoint->set_peer_closed();
298 endpoint->set_handle_created();
299 endpoints_.insert({id, endpoint});
300 }
rockot02b8e182016-07-13 20:08:30301
yzshen2859a2ac2017-02-14 22:24:25302 if (!NotifyAssociation(&handle_to_send, id)) {
303 // The peer handle of |handle_to_send|, which is supposed to join this
304 // associated group, has been closed.
305 {
306 base::AutoLock locker(lock_);
307 Endpoint* endpoint = FindEndpoint(id);
308 if (endpoint)
309 MarkClosedAndMaybeRemove(endpoint);
310 }
311
312 control_message_proxy_.NotifyPeerEndpointClosed(
313 id, handle_to_send.disconnect_reason());
314 }
315 return id;
rockot02b8e182016-07-13 20:08:30316 }
317
318 mojo::ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
319 mojo::InterfaceId id) override {
320 if (!mojo::IsValidInterfaceId(id))
321 return mojo::ScopedInterfaceEndpointHandle();
322
Ken Rockotcd23f752020-06-20 01:22:31323 // Unless it is the primary ID, |id| is from the remote side and therefore
Yuzhu Shen9f87fb02017-08-11 17:07:06324 // its namespace bit is supposed to be different than the value that this
325 // router would use.
Ken Rockotcd23f752020-06-20 01:22:31326 if (!mojo::IsPrimaryInterfaceId(id) &&
Yuzhu Shen9f87fb02017-08-11 17:07:06327 set_interface_id_namespace_bit_ ==
328 mojo::HasInterfaceIdNamespaceBitSet(id)) {
329 return mojo::ScopedInterfaceEndpointHandle();
330 }
331
rockot02b8e182016-07-13 20:08:30332 base::AutoLock locker(lock_);
333 bool inserted = false;
334 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
yzshenea784ea2017-01-31 21:20:20335 if (inserted) {
336 DCHECK(!endpoint->handle_created());
337 if (encountered_error_)
338 endpoint->set_peer_closed();
339 } else {
340 if (endpoint->handle_created())
341 return mojo::ScopedInterfaceEndpointHandle();
342 }
rockot02b8e182016-07-13 20:08:30343
yzshenea784ea2017-01-31 21:20:20344 endpoint->set_handle_created();
yzshen2859a2ac2017-02-14 22:24:25345 return CreateScopedInterfaceEndpointHandle(id);
rockot02b8e182016-07-13 20:08:30346 }
347
yzshen8be41d3a2017-01-23 20:40:37348 void CloseEndpointHandle(
349 mojo::InterfaceId id,
Anton Bikineev1f42a452021-05-15 18:02:50350 const absl::optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30351 if (!mojo::IsValidInterfaceId(id))
352 return;
yzshen2859a2ac2017-02-14 22:24:25353 {
354 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32355 DCHECK(base::Contains(endpoints_, id));
yzshen2859a2ac2017-02-14 22:24:25356 Endpoint* endpoint = endpoints_[id].get();
357 DCHECK(!endpoint->client());
358 DCHECK(!endpoint->closed());
359 MarkClosedAndMaybeRemove(endpoint);
rockot02b8e182016-07-13 20:08:30360 }
361
Ken Rockotcd23f752020-06-20 01:22:31362 if (!mojo::IsPrimaryInterfaceId(id) || reason)
yzshen8be41d3a2017-01-23 20:40:37363 control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
rockot02b8e182016-07-13 20:08:30364 }
365
366 mojo::InterfaceEndpointController* AttachEndpointClient(
367 const mojo::ScopedInterfaceEndpointHandle& handle,
368 mojo::InterfaceEndpointClient* client,
Sam McNallyde5ae672017-06-19 23:34:45369 scoped_refptr<base::SequencedTaskRunner> runner) override {
rockot02b8e182016-07-13 20:08:30370 const mojo::InterfaceId id = handle.id();
371
372 DCHECK(mojo::IsValidInterfaceId(id));
373 DCHECK(client);
374
375 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32376 DCHECK(base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30377
378 Endpoint* endpoint = endpoints_[id].get();
379 endpoint->AttachClient(client, std::move(runner));
380
381 if (endpoint->peer_closed())
382 NotifyEndpointOfError(endpoint, true /* force_async */);
383
384 return endpoint;
385 }
386
387 void DetachEndpointClient(
388 const mojo::ScopedInterfaceEndpointHandle& handle) override {
389 const mojo::InterfaceId id = handle.id();
390
391 DCHECK(mojo::IsValidInterfaceId(id));
392
393 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32394 DCHECK(base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30395
396 Endpoint* endpoint = endpoints_[id].get();
397 endpoint->DetachClient();
398 }
399
400 void RaiseError() override {
Ken Rockot138153b2018-07-13 23:31:57401 // We ignore errors on channel endpoints, leaving the pipe open. There are
402 // good reasons for this:
403 //
404 // * We should never close a channel endpoint in either process as long as
405 // the child process is still alive. The child's endpoint should only be
406 // closed implicitly by process death, and the browser's endpoint should
407 // only be closed after the child process is confirmed to be dead. Crash
408 // reporting logic in Chrome relies on this behavior in order to do the
409 // right thing.
410 //
411 // * There are two interesting conditions under which RaiseError() can be
412 // implicitly reached: an incoming message fails validation, or the
413 // local endpoint drops a response callback without calling it.
414 //
415 // * In the validation case, we also report the message as bad, and this
416 // will imminently trigger the common bad-IPC path in the browser,
417 // causing the browser to kill the offending renderer.
418 //
419 // * In the dropped response callback case, the net result of ignoring the
420 // issue is generally innocuous. While indicative of programmer error,
421 // it's not a severe failure and is already covered by separate DCHECKs.
422 //
423 // See https://crbug.com/861607 for additional discussion.
rockot02b8e182016-07-13 20:08:30424 }
425
Ken Rockot474df0142017-07-12 13:28:56426 bool PrefersSerializedMessages() override { return true; }
427
rockot02b8e182016-07-13 20:08:30428 private:
429 class Endpoint;
rockot0e4de5f2016-07-22 21:18:07430 class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30431 friend class Endpoint;
rockot0e4de5f2016-07-22 21:18:07432 friend class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30433
yzshen0a5971312017-02-02 05:13:47434 // MessageWrapper objects are always destroyed under the controller's lock. On
435 // destruction, if the message it wrappers contains
436 // ScopedInterfaceEndpointHandles (which cannot be destructed under the
437 // controller's lock), the wrapper unlocks to clean them up.
438 class MessageWrapper {
yzshenea784ea2017-01-31 21:20:20439 public:
yzshen0a5971312017-02-02 05:13:47440 MessageWrapper() = default;
yzshenea784ea2017-01-31 21:20:20441
yzshen0a5971312017-02-02 05:13:47442 MessageWrapper(ChannelAssociatedGroupController* controller,
443 mojo::Message message)
444 : controller_(controller), value_(std::move(message)) {}
yzshenea784ea2017-01-31 21:20:20445
yzshen0a5971312017-02-02 05:13:47446 MessageWrapper(MessageWrapper&& other)
yzshenea784ea2017-01-31 21:20:20447 : controller_(other.controller_), value_(std::move(other.value_)) {}
448
Peter Boströmc68c5aa2021-09-28 00:28:00449 MessageWrapper(const MessageWrapper&) = delete;
450 MessageWrapper& operator=(const MessageWrapper&) = delete;
451
yzshen0a5971312017-02-02 05:13:47452 ~MessageWrapper() {
453 if (value_.associated_endpoint_handles()->empty())
yzshenea784ea2017-01-31 21:20:20454 return;
455
456 controller_->lock_.AssertAcquired();
yzshen0a5971312017-02-02 05:13:47457 {
yzshenea784ea2017-01-31 21:20:20458 base::AutoUnlock unlocker(controller_->lock_);
yzshen0a5971312017-02-02 05:13:47459 value_.mutable_associated_endpoint_handles()->clear();
yzshenea784ea2017-01-31 21:20:20460 }
461 }
462
yzshen0a5971312017-02-02 05:13:47463 MessageWrapper& operator=(MessageWrapper&& other) {
yzshenea784ea2017-01-31 21:20:20464 controller_ = other.controller_;
465 value_ = std::move(other.value_);
466 return *this;
467 }
468
yzshen0a5971312017-02-02 05:13:47469 mojo::Message& value() { return value_; }
yzshenea784ea2017-01-31 21:20:20470
471 private:
Keishi Hattori0e45c022021-11-27 09:25:52472 raw_ptr<ChannelAssociatedGroupController> controller_ = nullptr;
yzshenea784ea2017-01-31 21:20:20473 mojo::Message value_;
yzshenea784ea2017-01-31 21:20:20474 };
475
rockot02b8e182016-07-13 20:08:30476 class Endpoint : public base::RefCountedThreadSafe<Endpoint>,
477 public mojo::InterfaceEndpointController {
478 public:
479 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id)
480 : controller_(controller), id_(id) {}
481
Peter Boström896f1372021-11-05 01:12:30482 Endpoint(const Endpoint&) = delete;
483 Endpoint& operator=(const Endpoint&) = delete;
484
rockot02b8e182016-07-13 20:08:30485 mojo::InterfaceId id() const { return id_; }
486
487 bool closed() const {
488 controller_->lock_.AssertAcquired();
489 return closed_;
490 }
491
492 void set_closed() {
493 controller_->lock_.AssertAcquired();
494 closed_ = true;
495 }
496
497 bool peer_closed() const {
498 controller_->lock_.AssertAcquired();
499 return peer_closed_;
500 }
501
502 void set_peer_closed() {
503 controller_->lock_.AssertAcquired();
504 peer_closed_ = true;
505 }
506
yzshenea784ea2017-01-31 21:20:20507 bool handle_created() const {
508 controller_->lock_.AssertAcquired();
509 return handle_created_;
510 }
511
512 void set_handle_created() {
513 controller_->lock_.AssertAcquired();
514 handle_created_ = true;
515 }
516
Anton Bikineev1f42a452021-05-15 18:02:50517 const absl::optional<mojo::DisconnectReason>& disconnect_reason() const {
yzshen8be41d3a2017-01-23 20:40:37518 return disconnect_reason_;
519 }
520
521 void set_disconnect_reason(
Anton Bikineev1f42a452021-05-15 18:02:50522 const absl::optional<mojo::DisconnectReason>& disconnect_reason) {
yzshen8be41d3a2017-01-23 20:40:37523 disconnect_reason_ = disconnect_reason;
524 }
525
Sam McNallyde5ae672017-06-19 23:34:45526 base::SequencedTaskRunner* task_runner() const {
rockot02b8e182016-07-13 20:08:30527 return task_runner_.get();
528 }
529
Ken Rockotc5cc02732021-06-04 08:02:41530 bool was_bound_off_sequence() const { return was_bound_off_sequence_; }
531
rockot02b8e182016-07-13 20:08:30532 mojo::InterfaceEndpointClient* client() const {
533 controller_->lock_.AssertAcquired();
534 return client_;
535 }
536
537 void AttachClient(mojo::InterfaceEndpointClient* client,
Sam McNallyde5ae672017-06-19 23:34:45538 scoped_refptr<base::SequencedTaskRunner> runner) {
rockot02b8e182016-07-13 20:08:30539 controller_->lock_.AssertAcquired();
540 DCHECK(!client_);
541 DCHECK(!closed_);
rockot02b8e182016-07-13 20:08:30542
543 task_runner_ = std::move(runner);
544 client_ = client;
Ken Rockotc5cc02732021-06-04 08:02:41545
Ken Rockota55ea6712021-06-16 19:36:06546 if (CanBindOffSequence())
Ken Rockotc5cc02732021-06-04 08:02:41547 was_bound_off_sequence_ = true;
rockot02b8e182016-07-13 20:08:30548 }
549
550 void DetachClient() {
551 controller_->lock_.AssertAcquired();
552 DCHECK(client_);
rockot02b8e182016-07-13 20:08:30553 DCHECK(!closed_);
554
555 task_runner_ = nullptr;
556 client_ = nullptr;
rockot9abe09b2016-08-02 20:57:34557 sync_watcher_.reset();
558 }
559
yzshen0a5971312017-02-02 05:13:47560 uint32_t EnqueueSyncMessage(MessageWrapper message) {
rockot9abe09b2016-08-02 20:57:34561 controller_->lock_.AssertAcquired();
562 uint32_t id = GenerateSyncMessageId();
563 sync_messages_.emplace(id, std::move(message));
564 SignalSyncMessageEvent();
565 return id;
566 }
567
568 void SignalSyncMessageEvent() {
569 controller_->lock_.AssertAcquired();
yzshene25b5d52017-02-28 21:56:31570
Ken Rockotaa20dcc2018-03-28 03:06:51571 if (sync_watcher_)
572 sync_watcher_->SignalEvent();
rockot9abe09b2016-08-02 20:57:34573 }
574
yzshen0a5971312017-02-02 05:13:47575 MessageWrapper PopSyncMessage(uint32_t id) {
rockot9abe09b2016-08-02 20:57:34576 controller_->lock_.AssertAcquired();
577 if (sync_messages_.empty() || sync_messages_.front().first != id)
yzshen0a5971312017-02-02 05:13:47578 return MessageWrapper();
579 MessageWrapper message = std::move(sync_messages_.front().second);
rockot9abe09b2016-08-02 20:57:34580 sync_messages_.pop();
581 return message;
rockot02b8e182016-07-13 20:08:30582 }
583
584 // mojo::InterfaceEndpointController:
585 bool SendMessage(mojo::Message* message) override {
peary28cd3bd22017-06-29 02:15:28586 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30587 message->set_interface_id(id_);
588 return controller_->SendMessage(message);
589 }
590
591 void AllowWokenUpBySyncWatchOnSameThread() override {
peary28cd3bd22017-06-29 02:15:28592 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30593
rockot9abe09b2016-08-02 20:57:34594 EnsureSyncWatcherExists();
Ken Rockotaa20dcc2018-03-28 03:06:51595 sync_watcher_->AllowWokenUpBySyncWatchOnSameSequence();
rockot02b8e182016-07-13 20:08:30596 }
597
Ken Rockot5b3136c2021-04-26 17:45:59598 bool SyncWatch(const bool& should_stop) override {
peary28cd3bd22017-06-29 02:15:28599 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30600
Ken Rockotcd23f752020-06-20 01:22:31601 // It's not legal to make sync calls from the primary endpoint's thread,
rockot02b8e182016-07-13 20:08:30602 // and in fact they must only happen from the proxy task runner.
rockot7604e7b72016-07-28 17:37:39603 DCHECK(!controller_->task_runner_->BelongsToCurrentThread());
rockot02b8e182016-07-13 20:08:30604 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread());
605
rockot9abe09b2016-08-02 20:57:34606 EnsureSyncWatcherExists();
Ken Rockot54272972021-04-20 22:08:04607 return sync_watcher_->SyncWatch(&should_stop);
rockot02b8e182016-07-13 20:08:30608 }
609
Ken Rockot5b3136c2021-04-26 17:45:59610 bool SyncWatchExclusive(uint64_t request_id) override {
611 // We don't support exclusive waits on Channel-associated interfaces.
612 NOTREACHED();
613 return false;
614 }
615
Ken Rockot9f69e162021-04-19 14:16:29616 void RegisterExternalSyncWaiter(uint64_t request_id) override {}
617
rockot02b8e182016-07-13 20:08:30618 private:
619 friend class base::RefCountedThreadSafe<Endpoint>;
620
rockot9abe09b2016-08-02 20:57:34621 ~Endpoint() override {
622 controller_->lock_.AssertAcquired();
623 DCHECK(!client_);
624 DCHECK(closed_);
625 DCHECK(peer_closed_);
626 DCHECK(!sync_watcher_);
627 }
628
rockotb62e2e32017-03-24 18:36:44629 void OnSyncMessageEventReady() {
peary28cd3bd22017-06-29 02:15:28630 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34631
632 scoped_refptr<Endpoint> keepalive(this);
633 scoped_refptr<AssociatedGroupController> controller_keepalive(
Keishi Hattori0e45c022021-11-27 09:25:52634 controller_.get());
Ken Rockotaa20dcc2018-03-28 03:06:51635 base::AutoLock locker(controller_->lock_);
636 bool more_to_process = false;
637 if (!sync_messages_.empty()) {
638 MessageWrapper message_wrapper =
639 std::move(sync_messages_.front().second);
640 sync_messages_.pop();
rockot9abe09b2016-08-02 20:57:34641
Ken Rockotaa20dcc2018-03-28 03:06:51642 bool dispatch_succeeded;
643 mojo::InterfaceEndpointClient* client = client_;
644 {
645 base::AutoUnlock unlocker(controller_->lock_);
646 dispatch_succeeded =
647 client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34648 }
649
Ken Rockotaa20dcc2018-03-28 03:06:51650 if (!sync_messages_.empty())
651 more_to_process = true;
rockot9abe09b2016-08-02 20:57:34652
Ken Rockotaa20dcc2018-03-28 03:06:51653 if (!dispatch_succeeded)
654 controller_->RaiseError();
rockot9abe09b2016-08-02 20:57:34655 }
656
Ken Rockotaa20dcc2018-03-28 03:06:51657 if (!more_to_process)
658 sync_watcher_->ResetEvent();
659
660 // If there are no queued sync messages and the peer has closed, there
661 // there won't be incoming sync messages in the future. If any
662 // SyncWatch() calls are on the stack for this endpoint, resetting the
663 // watcher will allow them to exit as the stack undwinds.
664 if (!more_to_process && peer_closed_)
rockot9abe09b2016-08-02 20:57:34665 sync_watcher_.reset();
rockot9abe09b2016-08-02 20:57:34666 }
667
668 void EnsureSyncWatcherExists() {
peary28cd3bd22017-06-29 02:15:28669 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34670 if (sync_watcher_)
671 return;
672
Ken Rockotaa20dcc2018-03-28 03:06:51673 base::AutoLock locker(controller_->lock_);
674 sync_watcher_ = std::make_unique<mojo::SequenceLocalSyncEventWatcher>(
675 base::BindRepeating(&Endpoint::OnSyncMessageEventReady,
676 base::Unretained(this)));
677 if (peer_closed_ || !sync_messages_.empty())
678 SignalSyncMessageEvent();
rockot9abe09b2016-08-02 20:57:34679 }
680
681 uint32_t GenerateSyncMessageId() {
682 // Overflow is fine.
683 uint32_t id = next_sync_message_id_++;
684 DCHECK(sync_messages_.empty() || sync_messages_.front().first != id);
685 return id;
686 }
rockot02b8e182016-07-13 20:08:30687
Keishi Hattori0e45c022021-11-27 09:25:52688 const raw_ptr<ChannelAssociatedGroupController> controller_;
rockot02b8e182016-07-13 20:08:30689 const mojo::InterfaceId id_;
690
691 bool closed_ = false;
692 bool peer_closed_ = false;
yzshenea784ea2017-01-31 21:20:20693 bool handle_created_ = false;
Ken Rockotc5cc02732021-06-04 08:02:41694 bool was_bound_off_sequence_ = false;
Anton Bikineev1f42a452021-05-15 18:02:50695 absl::optional<mojo::DisconnectReason> disconnect_reason_;
Keishi Hattori0e45c022021-11-27 09:25:52696 raw_ptr<mojo::InterfaceEndpointClient> client_ = nullptr;
Sam McNallyde5ae672017-06-19 23:34:45697 scoped_refptr<base::SequencedTaskRunner> task_runner_;
Ken Rockotaa20dcc2018-03-28 03:06:51698 std::unique_ptr<mojo::SequenceLocalSyncEventWatcher> sync_watcher_;
Brett Wilsona62d9c02017-09-20 20:53:20699 base::queue<std::pair<uint32_t, MessageWrapper>> sync_messages_;
rockot9abe09b2016-08-02 20:57:34700 uint32_t next_sync_message_id_ = 0;
rockot02b8e182016-07-13 20:08:30701 };
702
rockot0e4de5f2016-07-22 21:18:07703 class ControlMessageProxyThunk : public MessageReceiver {
704 public:
705 explicit ControlMessageProxyThunk(
706 ChannelAssociatedGroupController* controller)
707 : controller_(controller) {}
708
Peter Boström896f1372021-11-05 01:12:30709 ControlMessageProxyThunk(const ControlMessageProxyThunk&) = delete;
710 ControlMessageProxyThunk& operator=(const ControlMessageProxyThunk&) =
711 delete;
712
rockot0e4de5f2016-07-22 21:18:07713 private:
714 // MessageReceiver:
715 bool Accept(mojo::Message* message) override {
716 return controller_->SendMessage(message);
717 }
718
Keishi Hattori0e45c022021-11-27 09:25:52719 raw_ptr<ChannelAssociatedGroupController> controller_;
rockot0e4de5f2016-07-22 21:18:07720 };
721
rockot02b8e182016-07-13 20:08:30722 ~ChannelAssociatedGroupController() override {
rockotb01ef6a2016-07-27 03:24:32723 DCHECK(!connector_);
724
rockot02b8e182016-07-13 20:08:30725 base::AutoLock locker(lock_);
rockot02b8e182016-07-13 20:08:30726 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
727 Endpoint* endpoint = iter->second.get();
728 ++iter;
729
yzshene003d592017-01-24 21:42:17730 if (!endpoint->closed()) {
731 // This happens when a NotifyPeerEndpointClosed message been received,
yzshen2859a2ac2017-02-14 22:24:25732 // but the interface ID hasn't been used to create local endpoint
733 // handle.
yzshene003d592017-01-24 21:42:17734 DCHECK(!endpoint->client());
735 DCHECK(endpoint->peer_closed());
736 MarkClosedAndMaybeRemove(endpoint);
737 } else {
738 MarkPeerClosedAndMaybeRemove(endpoint);
739 }
rockot02b8e182016-07-13 20:08:30740 }
741
742 DCHECK(endpoints_.empty());
Ken Rockot2b6de982018-03-20 22:28:13743
744 GetMemoryDumpProvider().RemoveController(this);
rockot02b8e182016-07-13 20:08:30745 }
746
747 bool SendMessage(mojo::Message* message) {
Siddhartha S03484422019-04-23 20:30:00748 DCHECK(message->heap_profiler_tag());
rockot7604e7b72016-07-28 17:37:39749 if (task_runner_->BelongsToCurrentThread()) {
rockot02b8e182016-07-13 20:08:30750 DCHECK(thread_checker_.CalledOnValidThread());
rockot10188752016-09-08 18:24:56751 if (!connector_ || paused_) {
Ken Rockot37ddd8152018-02-22 18:18:46752 if (!shut_down_) {
Ken Rockot2b6de982018-03-20 22:28:13753 base::AutoLock lock(outgoing_messages_lock_);
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20754 if (quota_checker_)
755 quota_checker_->BeforeMessagesEnqueued(1);
Ken Rockot3e7284bb2018-02-06 16:11:16756 outgoing_messages_.emplace_back(std::move(*message));
Ken Rockot37ddd8152018-02-22 18:18:46757 }
rockot0e4de5f2016-07-22 21:18:07758 return true;
759 }
760 return connector_->Accept(message);
rockot02b8e182016-07-13 20:08:30761 } else {
Ken Rockotcd23f752020-06-20 01:22:31762 // We always post tasks to the primary endpoint thread when called from
rockotbecd3f742016-11-08 20:47:00763 // other threads in order to simulate IPC::ChannelProxy::Send behavior.
rockot02b8e182016-07-13 20:08:30764 task_runner_->PostTask(
765 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09766 base::BindOnce(
Ken Rockotcd23f752020-06-20 01:22:31767 &ChannelAssociatedGroupController::SendMessageOnPrimaryThread,
Jan Wilken Dörrie1494205b2020-03-26 09:32:53768 this, std::move(*message)));
rockot02b8e182016-07-13 20:08:30769 return true;
770 }
771 }
772
Ken Rockotcd23f752020-06-20 01:22:31773 void SendMessageOnPrimaryThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30774 DCHECK(thread_checker_.CalledOnValidThread());
rockotc4cc691e2016-08-19 18:48:57775 if (!SendMessage(&message))
rockot02b8e182016-07-13 20:08:30776 RaiseError();
777 }
778
779 void OnPipeError() {
780 DCHECK(thread_checker_.CalledOnValidThread());
781
782 // We keep |this| alive here because it's possible for the notifications
783 // below to release all other references.
784 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
785
786 base::AutoLock locker(lock_);
787 encountered_error_ = true;
788
789 std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
790 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
791 Endpoint* endpoint = iter->second.get();
792 ++iter;
793
794 if (endpoint->client())
795 endpoints_to_notify.push_back(endpoint);
796
797 MarkPeerClosedAndMaybeRemove(endpoint);
798 }
799
800 for (auto& endpoint : endpoints_to_notify) {
rockot0e4de5f2016-07-22 21:18:07801 // Because a notification may in turn detach any endpoint, we have to
rockot02b8e182016-07-13 20:08:30802 // check each client again here.
803 if (endpoint->client())
804 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
805 }
806 }
807
808 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
809 lock_.AssertAcquired();
810 DCHECK(endpoint->task_runner() && endpoint->client());
peary28cd3bd22017-06-29 02:15:28811 if (endpoint->task_runner()->RunsTasksInCurrentSequence() && !force_async) {
rockot02b8e182016-07-13 20:08:30812 mojo::InterfaceEndpointClient* client = endpoint->client();
Anton Bikineev1f42a452021-05-15 18:02:50813 absl::optional<mojo::DisconnectReason> reason(
yzshen8be41d3a2017-01-23 20:40:37814 endpoint->disconnect_reason());
rockot02b8e182016-07-13 20:08:30815
816 base::AutoUnlock unlocker(lock_);
yzshen8be41d3a2017-01-23 20:40:37817 client->NotifyError(reason);
rockot02b8e182016-07-13 20:08:30818 } else {
819 endpoint->task_runner()->PostTask(
820 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09821 base::BindOnce(&ChannelAssociatedGroupController::
822 NotifyEndpointOfErrorOnEndpointThread,
823 this, endpoint->id(), base::Unretained(endpoint)));
rockot02b8e182016-07-13 20:08:30824 }
825 }
826
rockot9abe09b2016-08-02 20:57:34827 void NotifyEndpointOfErrorOnEndpointThread(mojo::InterfaceId id,
828 Endpoint* endpoint) {
rockot02b8e182016-07-13 20:08:30829 base::AutoLock locker(lock_);
rockot9abe09b2016-08-02 20:57:34830 auto iter = endpoints_.find(id);
831 if (iter == endpoints_.end() || iter->second.get() != endpoint)
832 return;
rockot02b8e182016-07-13 20:08:30833 if (!endpoint->client())
834 return;
rockot9abe09b2016-08-02 20:57:34835
peary28cd3bd22017-06-29 02:15:28836 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34837 NotifyEndpointOfError(endpoint, false /* force_async */);
rockot02b8e182016-07-13 20:08:30838 }
839
840 void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
841 lock_.AssertAcquired();
842 endpoint->set_closed();
843 if (endpoint->closed() && endpoint->peer_closed())
844 endpoints_.erase(endpoint->id());
845 }
846
847 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
848 lock_.AssertAcquired();
849 endpoint->set_peer_closed();
rockot9abe09b2016-08-02 20:57:34850 endpoint->SignalSyncMessageEvent();
rockot02b8e182016-07-13 20:08:30851 if (endpoint->closed() && endpoint->peer_closed())
852 endpoints_.erase(endpoint->id());
853 }
854
855 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {
856 lock_.AssertAcquired();
857 DCHECK(!inserted || !*inserted);
858
yzshen0a5971312017-02-02 05:13:47859 Endpoint* endpoint = FindEndpoint(id);
860 if (!endpoint) {
861 endpoint = new Endpoint(this, id);
862 endpoints_.insert({id, endpoint});
863 if (inserted)
864 *inserted = true;
865 }
rockot02b8e182016-07-13 20:08:30866 return endpoint;
867 }
868
yzshen0a5971312017-02-02 05:13:47869 Endpoint* FindEndpoint(mojo::InterfaceId id) {
870 lock_.AssertAcquired();
871 auto iter = endpoints_.find(id);
872 return iter != endpoints_.end() ? iter->second.get() : nullptr;
873 }
874
rockot02b8e182016-07-13 20:08:30875 // mojo::MessageReceiver:
876 bool Accept(mojo::Message* message) override {
877 DCHECK(thread_checker_.CalledOnValidThread());
878
yzshen0a5971312017-02-02 05:13:47879 if (!message->DeserializeAssociatedEndpointHandles(this))
880 return false;
881
882 if (mojo::PipeControlMessageHandler::IsPipeControlMessage(message))
883 return control_message_handler_.Accept(message);
rockot02b8e182016-07-13 20:08:30884
885 mojo::InterfaceId id = message->interface_id();
Ken Rockot9f69e162021-04-19 14:16:29886 if (!mojo::IsValidInterfaceId(id))
887 return false;
rockot02b8e182016-07-13 20:08:30888
Ken Rockot4fede4552019-05-09 01:16:41889 base::ReleasableAutoLock locker(&lock_);
yzshen0a5971312017-02-02 05:13:47890 Endpoint* endpoint = FindEndpoint(id);
891 if (!endpoint)
892 return true;
893
894 mojo::InterfaceEndpointClient* client = endpoint->client();
peary28cd3bd22017-06-29 02:15:28895 if (!client || !endpoint->task_runner()->RunsTasksInCurrentSequence()) {
Ken Rockotc5cc02732021-06-04 08:02:41896 // The ChannelProxy for this channel is bound to `proxy_task_runner_` and
897 // by default legacy IPCs must dispatch to either the IO thread or the
898 // proxy task runner. We generally impose the same constraint on
899 // associated interface endpoints so that FIFO can be guaranteed across
900 // all interfaces without stalling any of them to wait for a pending
901 // endpoint to be bound.
rockot02b8e182016-07-13 20:08:30902 //
Ken Rockotc5cc02732021-06-04 08:02:41903 // This allows us to assume that if an endpoint is not yet bound when we
904 // receive a message targeting it, it *will* be bound on the proxy task
905 // runner by the time a newly posted task runs there. Hence we simply post
906 // a hopeful dispatch task to that task runner.
907 //
908 // As it turns out, there are even some instances of endpoints binding to
909 // alternative (non-IO-thread, non-proxy) task runners, but still
910 // ultimately relying on the fact that we schedule their messages on the
911 // proxy task runner. So even if the endpoint is already bound, we
912 // default to scheduling it on the proxy task runner as long as it's not
913 // bound specifically to the IO task runner.
914 // TODO(rockot): Try to sort out these cases and maybe eliminate them.
915 //
916 // Finally, it's also possible that an endpoint was bound to an
917 // alternative task runner and it really does want its messages to
918 // dispatch there. In that case `was_bound_off_sequence()` will be true to
919 // signal that we should really use that task runner.
920 const scoped_refptr<base::SequencedTaskRunner> task_runner =
921 client && endpoint->was_bound_off_sequence()
922 ? endpoint->task_runner()
923 : proxy_task_runner_.get();
rockot9abe09b2016-08-02 20:57:34924
rockotc4cc691e2016-08-19 18:48:57925 if (message->has_flag(mojo::Message::kFlagIsSync)) {
yzshen0a5971312017-02-02 05:13:47926 MessageWrapper message_wrapper(this, std::move(*message));
rockot9abe09b2016-08-02 20:57:34927 // Sync messages may need to be handled by the endpoint if it's blocking
928 // on a sync reply. We pass ownership of the message to the endpoint's
929 // sync message queue. If the endpoint was blocking, it will dequeue the
930 // message and dispatch it. Otherwise the posted |AcceptSyncMessage()|
931 // call will dequeue the message and dispatch it.
yzshenea784ea2017-01-31 21:20:20932 uint32_t message_id =
933 endpoint->EnqueueSyncMessage(std::move(message_wrapper));
Ken Rockotc5cc02732021-06-04 08:02:41934 task_runner->PostTask(
rockot9abe09b2016-08-02 20:57:34935 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09936 base::BindOnce(&ChannelAssociatedGroupController::AcceptSyncMessage,
937 this, id, message_id));
rockot9abe09b2016-08-02 20:57:34938 return true;
939 }
940
Ken Rockotc5cc02732021-06-04 08:02:41941 // If |task_runner| has been torn down already, this PostTask will fail
942 // and destroy |message|. That operation may need to in turn destroy
Ken Rockot4fede4552019-05-09 01:16:41943 // in-transit associated endpoints and thus acquire |lock_|. We no longer
Ken Rockotc5cc02732021-06-04 08:02:41944 // need the lock to be held now, so we can release it before the PostTask.
Harkiran Bolaria8b1cf112020-09-15 22:58:34945 {
946 // Grab interface name from |client| before releasing the lock to ensure
947 // that |client| is safe to access.
948 base::TaskAnnotator::ScopedSetIpcHash scoped_set_ipc_hash(
949 client ? client->interface_name() : "unknown interface");
950 locker.Release();
Ken Rockotc5cc02732021-06-04 08:02:41951 task_runner->PostTask(
Harkiran Bolaria8b1cf112020-09-15 22:58:34952 FROM_HERE,
953 base::BindOnce(
Ken Rockotc5cc02732021-06-04 08:02:41954 &ChannelAssociatedGroupController::AcceptOnEndpointThread, this,
Harkiran Bolaria8b1cf112020-09-15 22:58:34955 std::move(*message)));
956 }
rockot02b8e182016-07-13 20:08:30957 return true;
958 }
959
Ken Rockot4fede4552019-05-09 01:16:41960 locker.Release();
Harkiran Bolaria8b1cf112020-09-15 22:58:34961 // It's safe to access |client| here without holding a lock, because this
962 // code runs on a proxy thread and |client| can't be destroyed from any
963 // thread.
yzshen0a5971312017-02-02 05:13:47964 return client->HandleIncomingMessage(message);
rockot02b8e182016-07-13 20:08:30965 }
966
Ken Rockotc5cc02732021-06-04 08:02:41967 void AcceptOnEndpointThread(mojo::Message message) {
Stephen Nusko8e400642020-09-16 13:48:59968 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mojom"),
Ken Rockotc5cc02732021-06-04 08:02:41969 "ChannelAssociatedGroupController::AcceptOnEndpointThread");
rockot02b8e182016-07-13 20:08:30970
rockotc4cc691e2016-08-19 18:48:57971 mojo::InterfaceId id = message.interface_id();
Ken Rockotcd23f752020-06-20 01:22:31972 DCHECK(mojo::IsValidInterfaceId(id) && !mojo::IsPrimaryInterfaceId(id));
rockot8d890f62016-07-14 16:37:14973
974 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47975 Endpoint* endpoint = FindEndpoint(id);
rockot8d890f62016-07-14 16:37:14976 if (!endpoint)
977 return;
978
979 mojo::InterfaceEndpointClient* client = endpoint->client();
Greg Thompsonfe432e762021-06-04 06:47:14980 if (!client)
rockot8d890f62016-07-14 16:37:14981 return;
982
Alexander Timinda1f2c52021-11-03 02:23:05983 TRACE_EVENT(
984 TRACE_CATEGORY_OR_DISABLED_BY_DEFAULT_MOJOM("mojom"),
985 // Using client->interface_name() is safe here because this is a static
986 // string defined for each mojo interface.
987 perfetto::StaticString(client->interface_name()),
988 [&](perfetto::EventContext& ctx) {
989 static const uint8_t* toplevel_flow_enabled =
990 TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("toplevel.flow");
991 if (!*toplevel_flow_enabled)
992 return;
993
994 perfetto::Flow::Global(message.GetTraceId())(ctx);
995 });
Ken Rockotc5cc02732021-06-04 08:02:41996 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence() ||
997 proxy_task_runner_->RunsTasksInCurrentSequence());
rockot8d890f62016-07-14 16:37:14998
rockot9abe09b2016-08-02 20:57:34999 // Sync messages should never make their way to this method.
yzshen0a5971312017-02-02 05:13:471000 DCHECK(!message.has_flag(mojo::Message::kFlagIsSync));
rockot8d890f62016-07-14 16:37:141001
1002 bool result = false;
1003 {
1004 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:471005 result = client->HandleIncomingMessage(&message);
rockot8d890f62016-07-14 16:37:141006 }
1007
1008 if (!result)
1009 RaiseError();
1010 }
1011
rockot9abe09b2016-08-02 20:57:341012 void AcceptSyncMessage(mojo::InterfaceId interface_id, uint32_t message_id) {
Stephen Nusko8e400642020-09-16 13:48:591013 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mojom"),
1014 "ChannelAssociatedGroupController::AcceptSyncMessage");
rockot9abe09b2016-08-02 20:57:341015
1016 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:471017 Endpoint* endpoint = FindEndpoint(interface_id);
rockot9abe09b2016-08-02 20:57:341018 if (!endpoint)
1019 return;
1020
csharrison1af8d6ab2017-04-21 17:47:231021 // Careful, if the endpoint is detached its members are cleared. Check for
1022 // that before dereferencing.
1023 mojo::InterfaceEndpointClient* client = endpoint->client();
1024 if (!client)
1025 return;
1026
Stephen Nusko8e400642020-09-16 13:48:591027 // Using client->interface_name() is safe here because this is a static
1028 // string defined for each mojo interface.
1029 TRACE_EVENT0("mojom", client->interface_name());
Ken Rockota55ea6712021-06-16 19:36:061030 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence() ||
1031 proxy_task_runner_->RunsTasksInCurrentSequence());
yzshen0a5971312017-02-02 05:13:471032 MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id);
rockot9abe09b2016-08-02 20:57:341033
1034 // The message must have already been dequeued by the endpoint waking up
1035 // from a sync wait. Nothing to do.
yzshenea784ea2017-01-31 21:20:201036 if (message_wrapper.value().IsNull())
rockot9abe09b2016-08-02 20:57:341037 return;
1038
rockot9abe09b2016-08-02 20:57:341039 bool result = false;
1040 {
1041 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:471042 result = client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:341043 }
1044
1045 if (!result)
1046 RaiseError();
1047 }
1048
rockot02b8e182016-07-13 20:08:301049 // mojo::PipeControlMessageHandlerDelegate:
yzshen8be41d3a2017-01-23 20:40:371050 bool OnPeerAssociatedEndpointClosed(
1051 mojo::InterfaceId id,
Anton Bikineev1f42a452021-05-15 18:02:501052 const absl::optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:301053 DCHECK(thread_checker_.CalledOnValidThread());
1054
rockot0e4de5f2016-07-22 21:18:071055 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
rockot02b8e182016-07-13 20:08:301056 base::AutoLock locker(lock_);
1057 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr);
yzshen8be41d3a2017-01-23 20:40:371058 if (reason)
1059 endpoint->set_disconnect_reason(reason);
rockot02b8e182016-07-13 20:08:301060 if (!endpoint->peer_closed()) {
1061 if (endpoint->client())
1062 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
1063 MarkPeerClosedAndMaybeRemove(endpoint.get());
1064 }
1065
1066 return true;
1067 }
1068
Ken Rockoteb2366a2020-01-13 21:13:461069 bool WaitForFlushToComplete(
1070 mojo::ScopedMessagePipeHandle flush_pipe) override {
1071 // We don't support async flushing on the IPC Channel pipe.
1072 return false;
1073 }
1074
Ken Rockotcd23f752020-06-20 01:22:311075 // Checked in places which must be run on the primary endpoint's thread.
rockot02b8e182016-07-13 20:08:301076 base::ThreadChecker thread_checker_;
1077
1078 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
rockot0e4de5f2016-07-22 21:18:071079
Ken Rockot4fede4552019-05-09 01:16:411080 const scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201081 const scoped_refptr<mojo::internal::MessageQuotaChecker> quota_checker_;
rockot0e4de5f2016-07-22 21:18:071082 const bool set_interface_id_namespace_bit_;
rockot10188752016-09-08 18:24:561083 bool paused_ = false;
rockot0e4de5f2016-07-22 21:18:071084 std::unique_ptr<mojo::Connector> connector_;
Dave Tapuskaf2df43e2019-10-10 22:10:101085 mojo::MessageDispatcher dispatcher_;
rockot02b8e182016-07-13 20:08:301086 mojo::PipeControlMessageHandler control_message_handler_;
rockot0e4de5f2016-07-22 21:18:071087 ControlMessageProxyThunk control_message_proxy_thunk_;
rockot58909542016-11-10 20:05:451088
1089 // NOTE: It is unsafe to call into this object while holding |lock_|.
rockot0e4de5f2016-07-22 21:18:071090 mojo::PipeControlMessageProxy control_message_proxy_;
1091
Ken Rockot2b6de982018-03-20 22:28:131092 // Guards access to |outgoing_messages_| only. Used to support memory dumps
1093 // which may be triggered from any thread.
1094 base::Lock outgoing_messages_lock_;
1095
rockot0e4de5f2016-07-22 21:18:071096 // Outgoing messages that were sent before this controller was bound to a
1097 // real message pipe.
rockotc4cc691e2016-08-19 18:48:571098 std::vector<mojo::Message> outgoing_messages_;
rockot02b8e182016-07-13 20:08:301099
1100 // Guards the fields below for thread-safe access.
1101 base::Lock lock_;
1102
1103 bool encountered_error_ = false;
Ken Rockot3e7284bb2018-02-06 16:11:161104 bool shut_down_ = false;
rockot0e4de5f2016-07-22 21:18:071105
1106 // ID #1 is reserved for the mojom::Channel interface.
1107 uint32_t next_interface_id_ = 2;
1108
Yuzhu Shen7bcd8ebf2017-10-02 23:21:141109 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_;
rockot02b8e182016-07-13 20:08:301110};
1111
Ken Rockot2b6de982018-03-20 22:28:131112bool ControllerMemoryDumpProvider::OnMemoryDump(
1113 const base::trace_event::MemoryDumpArgs& args,
1114 base::trace_event::ProcessMemoryDump* pmd) {
1115 base::AutoLock lock(lock_);
1116 for (auto* controller : controllers_) {
1117 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
1118 base::StringPrintf("mojo/queued_ipc_channel_message/0x%" PRIxPTR,
1119 reinterpret_cast<uintptr_t>(controller)));
1120 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
1121 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
1122 controller->GetQueuedMessageCount());
Siddhartha S03484422019-04-23 20:30:001123 MessageMemoryDumpInfo info;
1124 size_t count = 0;
1125 controller->GetTopQueuedMessageMemoryDumpInfo(&info, &count);
1126 dump->AddScalar("top_message_name", "id", info.id);
Siddharthad1cfec12018-09-17 21:42:151127 dump->AddScalar("top_message_count",
1128 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
Siddhartha S03484422019-04-23 20:30:001129 count);
1130
1131 if (info.profiler_tag) {
1132 // TODO(ssid): Memory dumps currently do not support adding string
1133 // arguments in background dumps. So, add this value as a trace event for
1134 // now.
ssidbc86cb72019-05-16 00:25:371135 TRACE_EVENT2(base::trace_event::MemoryDumpManager::kTraceCategory,
Siddhartha S03484422019-04-23 20:30:001136 "ControllerMemoryDumpProvider::OnMemoryDump",
ssidbc86cb72019-05-16 00:25:371137 "top_queued_message_tag", info.profiler_tag,
1138 "count", count);
Siddhartha S03484422019-04-23 20:30:001139 }
Ken Rockot2b6de982018-03-20 22:28:131140 }
1141
1142 return true;
1143}
1144
rockot0e4de5f2016-07-22 21:18:071145class MojoBootstrapImpl : public MojoBootstrap {
rockot02b8e182016-07-13 20:08:301146 public:
rockot0e4de5f2016-07-22 21:18:071147 MojoBootstrapImpl(
1148 mojo::ScopedMessagePipeHandle handle,
rockot0e4de5f2016-07-22 21:18:071149 const scoped_refptr<ChannelAssociatedGroupController> controller)
yzshen2859a2ac2017-02-14 22:24:251150 : controller_(controller),
1151 associated_group_(controller),
1152 handle_(std::move(handle)) {}
rockot02b8e182016-07-13 20:08:301153
Peter Boströmc68c5aa2021-09-28 00:28:001154 MojoBootstrapImpl(const MojoBootstrapImpl&) = delete;
1155 MojoBootstrapImpl& operator=(const MojoBootstrapImpl&) = delete;
1156
rockot0e4de5f2016-07-22 21:18:071157 ~MojoBootstrapImpl() override {
1158 controller_->ShutDown();
rockot02b8e182016-07-13 20:08:301159 }
1160
1161 private:
Julie Jeongeun Kim903b34b2019-09-25 11:11:541162 void Connect(
Ken Rockotfbbd4442021-06-04 01:19:141163 mojo::PendingAssociatedRemote<mojom::Channel>* sender,
Julie Jeongeun Kim903b34b2019-09-25 11:11:541164 mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) override {
Ken Rockot9fae8bcd2021-06-04 22:09:491165 controller_->Bind(std::move(handle_), sender, receiver);
msramek5507fee2016-07-22 10:06:211166 }
1167
Ken Rockot9fae8bcd2021-06-04 22:09:491168 void StartReceiving() override { controller_->StartReceiving(); }
1169
rockot10188752016-09-08 18:24:561170 void Pause() override {
1171 controller_->Pause();
1172 }
1173
1174 void Unpause() override {
1175 controller_->Unpause();
rockot401fb2c2016-09-06 18:35:571176 }
1177
1178 void Flush() override {
1179 controller_->FlushOutgoingMessages();
1180 }
1181
msramek5507fee2016-07-22 10:06:211182 mojo::AssociatedGroup* GetAssociatedGroup() override {
yzshen2859a2ac2017-02-14 22:24:251183 return &associated_group_;
msramek5507fee2016-07-22 10:06:211184 }
1185
rockot0e4de5f2016-07-22 21:18:071186 scoped_refptr<ChannelAssociatedGroupController> controller_;
yzshen2859a2ac2017-02-14 22:24:251187 mojo::AssociatedGroup associated_group_;
msramek5507fee2016-07-22 10:06:211188
rockot0e4de5f2016-07-22 21:18:071189 mojo::ScopedMessagePipeHandle handle_;
msramek5507fee2016-07-22 10:06:211190};
1191
morrita54f6f80c2014-09-23 21:16:001192} // namespace
1193
Ken Rockotc5cc02732021-06-04 08:02:411194ScopedAllowOffSequenceChannelAssociatedBindings::
1195 ScopedAllowOffSequenceChannelAssociatedBindings()
1196 : outer_flag_(GetOffSequenceBindingAllowedFlag().Get()) {
1197 GetOffSequenceBindingAllowedFlag().Set(true);
1198}
1199
1200ScopedAllowOffSequenceChannelAssociatedBindings::
1201 ~ScopedAllowOffSequenceChannelAssociatedBindings() {
1202 GetOffSequenceBindingAllowedFlag().Set(outer_flag_);
1203}
1204
morrita54f6f80c2014-09-23 21:16:001205// static
danakj03de39b22016-04-23 04:21:091206std::unique_ptr<MojoBootstrap> MojoBootstrap::Create(
sammc57ed9f982016-03-10 06:28:351207 mojo::ScopedMessagePipeHandle handle,
1208 Channel::Mode mode,
Hajime Hoshia98f1102017-11-20 06:34:351209 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201210 const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner,
1211 const scoped_refptr<mojo::internal::MessageQuotaChecker>& quota_checker) {
Jeremy Roman160eb922017-08-29 17:43:431212 return std::make_unique<MojoBootstrapImpl>(
Ken Rockotfe45c2462021-06-04 00:18:181213 std::move(handle), base::MakeRefCounted<ChannelAssociatedGroupController>(
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201214 mode == Channel::MODE_SERVER, ipc_task_runner,
1215 proxy_task_runner, quota_checker));
sammc57ed9f982016-03-10 06:28:351216}
1217
morrita54f6f80c2014-09-23 21:16:001218} // namespace IPC