blob: 4c84885085552abf89c83d399fcb7f554482e61d [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"
avi246998d82015-12-22 02:39:0421#include "base/macros.h"
danakj03de39b22016-04-23 04:21:0922#include "base/memory/ptr_util.h"
Ken Rockot2b6de982018-03-20 22:28:1323#include "base/no_destructor.h"
Gabriel Charette14520232018-04-30 23:27:2224#include "base/sequenced_task_runner.h"
rockot02b8e182016-07-13 20:08:3025#include "base/single_thread_task_runner.h"
Ken Rockot2b6de982018-03-20 22:28:1326#include "base/strings/stringprintf.h"
rockot02b8e182016-07-13 20:08:3027#include "base/synchronization/lock.h"
Harkiran Bolaria8b1cf112020-09-15 22:58:3428#include "base/task/common/task_annotator.h"
Sam McNallyde5ae672017-06-19 23:34:4529#include "base/threading/thread_checker.h"
rockot02b8e182016-07-13 20:08:3030#include "base/threading/thread_task_runner_handle.h"
Ken Rockot2b6de982018-03-20 22:28:1331#include "base/trace_event/memory_allocator_dump.h"
32#include "base/trace_event/memory_dump_manager.h"
33#include "base/trace_event/memory_dump_provider.h"
Ken Rockotfb81dc02018-05-15 21:59:2634#include "ipc/ipc_channel.h"
rockot02b8e182016-07-13 20:08:3035#include "mojo/public/cpp/bindings/associated_group.h"
36#include "mojo/public/cpp/bindings/associated_group_controller.h"
rockot02b8e182016-07-13 20:08:3037#include "mojo/public/cpp/bindings/connector.h"
38#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
39#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
40#include "mojo/public/cpp/bindings/interface_id.h"
rockot0e4de5f2016-07-22 21:18:0741#include "mojo/public/cpp/bindings/message.h"
rockot02b8e182016-07-13 20:08:3042#include "mojo/public/cpp/bindings/message_header_validator.h"
43#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
44#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
45#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
Ken Rockotaa20dcc2018-03-28 03:06:5146#include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h"
morrita54f6f80c2014-09-23 21:16:0047
48namespace IPC {
49
50namespace {
51
Ken Rockot2b6de982018-03-20 22:28:1352class ChannelAssociatedGroupController;
53
54// Used to track some internal Channel state in pursuit of message leaks.
55//
56// TODO(https://crbug.com/813045): Remove this.
57class ControllerMemoryDumpProvider
58 : public base::trace_event::MemoryDumpProvider {
59 public:
60 ControllerMemoryDumpProvider() {
61 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
62 this, "IPCChannel", nullptr);
63 }
64
65 ~ControllerMemoryDumpProvider() override {
66 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
67 this);
68 }
69
70 void AddController(ChannelAssociatedGroupController* controller) {
71 base::AutoLock lock(lock_);
72 controllers_.insert(controller);
73 }
74
75 void RemoveController(ChannelAssociatedGroupController* controller) {
76 base::AutoLock lock(lock_);
77 controllers_.erase(controller);
78 }
79
80 // base::trace_event::MemoryDumpProvider:
81 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
82 base::trace_event::ProcessMemoryDump* pmd) override;
83
84 private:
85 base::Lock lock_;
86 std::set<ChannelAssociatedGroupController*> controllers_;
87
88 DISALLOW_COPY_AND_ASSIGN(ControllerMemoryDumpProvider);
89};
90
91ControllerMemoryDumpProvider& GetMemoryDumpProvider() {
92 static base::NoDestructor<ControllerMemoryDumpProvider> provider;
93 return *provider;
94}
95
Siddhartha S03484422019-04-23 20:30:0096// Messages are grouped by this info when recording memory metrics.
97struct MessageMemoryDumpInfo {
98 MessageMemoryDumpInfo(const mojo::Message& message)
99 : id(message.name()), profiler_tag(message.heap_profiler_tag()) {}
100 MessageMemoryDumpInfo() = default;
101
102 bool operator==(const MessageMemoryDumpInfo& other) const {
103 return other.id == id && other.profiler_tag == profiler_tag;
104 }
105
106 uint32_t id = 0;
107 const char* profiler_tag = nullptr;
108};
109
110struct MessageMemoryDumpInfoHash {
111 size_t operator()(const MessageMemoryDumpInfo& info) const {
Daniel Cheng5c5a6522019-11-19 18:03:36112 return base::HashInts(
113 info.id, info.profiler_tag ? base::FastHash(info.profiler_tag) : 0);
Siddhartha S03484422019-04-23 20:30:00114 }
115};
116
rockot02b8e182016-07-13 20:08:30117class ChannelAssociatedGroupController
118 : public mojo::AssociatedGroupController,
119 public mojo::MessageReceiver,
120 public mojo::PipeControlMessageHandlerDelegate {
121 public:
rockot0e4de5f2016-07-22 21:18:07122 ChannelAssociatedGroupController(
123 bool set_interface_id_namespace_bit,
Hajime Hoshia98f1102017-11-20 06:34:35124 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20125 const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner,
126 const scoped_refptr<mojo::internal::MessageQuotaChecker>& quota_checker)
rockotb01ef6a2016-07-27 03:24:32127 : task_runner_(ipc_task_runner),
Hajime Hoshia98f1102017-11-20 06:34:35128 proxy_task_runner_(proxy_task_runner),
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20129 quota_checker_(quota_checker),
rockot0e4de5f2016-07-22 21:18:07130 set_interface_id_namespace_bit_(set_interface_id_namespace_bit),
Dave Tapuskaf2df43e2019-10-10 22:10:10131 dispatcher_(this),
rockot02b8e182016-07-13 20:08:30132 control_message_handler_(this),
rockot0e4de5f2016-07-22 21:18:07133 control_message_proxy_thunk_(this),
134 control_message_proxy_(&control_message_proxy_thunk_) {
135 thread_checker_.DetachFromThread();
rockot02b8e182016-07-13 20:08:30136 control_message_handler_.SetDescription(
Ken Rockotcd23f752020-06-20 01:22:31137 "IPC::mojom::Bootstrap [primary] PipeControlMessageHandler");
Dave Tapuskaf2df43e2019-10-10 22:10:10138 dispatcher_.SetValidator(std::make_unique<mojo::MessageHeaderValidator>(
Ken Rockotcd23f752020-06-20 01:22:31139 "IPC::mojom::Bootstrap [primary] MessageHeaderValidator"));
Ken Rockot2b6de982018-03-20 22:28:13140
141 GetMemoryDumpProvider().AddController(this);
142 }
143
144 size_t GetQueuedMessageCount() {
145 base::AutoLock lock(outgoing_messages_lock_);
146 return outgoing_messages_.size();
rockot02b8e182016-07-13 20:08:30147 }
148
Siddhartha S03484422019-04-23 20:30:00149 void GetTopQueuedMessageMemoryDumpInfo(MessageMemoryDumpInfo* info,
150 size_t* count) {
151 std::unordered_map<MessageMemoryDumpInfo, size_t, MessageMemoryDumpInfoHash>
152 counts;
153 std::pair<MessageMemoryDumpInfo, size_t> top_message_info_and_count = {
154 MessageMemoryDumpInfo(), 0};
Siddharthad1cfec12018-09-17 21:42:15155 base::AutoLock lock(outgoing_messages_lock_);
156 for (const auto& message : outgoing_messages_) {
Siddhartha S03484422019-04-23 20:30:00157 auto it_and_inserted = counts.emplace(MessageMemoryDumpInfo(message), 0);
Siddharthad1cfec12018-09-17 21:42:15158 it_and_inserted.first->second++;
Siddhartha S03484422019-04-23 20:30:00159 if (it_and_inserted.first->second > top_message_info_and_count.second)
160 top_message_info_and_count = *it_and_inserted.first;
Siddharthad1cfec12018-09-17 21:42:15161 }
Siddhartha S03484422019-04-23 20:30:00162 *info = top_message_info_and_count.first;
163 *count = top_message_info_and_count.second;
Siddharthad1cfec12018-09-17 21:42:15164 }
165
rockot0e4de5f2016-07-22 21:18:07166 void Bind(mojo::ScopedMessagePipeHandle handle) {
167 DCHECK(thread_checker_.CalledOnValidThread());
168 DCHECK(task_runner_->BelongsToCurrentThread());
rockot90984352016-07-25 17:36:19169
Harkiran Bolaria875dd0d2020-09-15 18:10:46170 connector_ = std::make_unique<mojo::Connector>(
171 std::move(handle), mojo::Connector::SINGLE_THREADED_SEND, task_runner_,
172 "IPC Channel");
Dave Tapuskaf2df43e2019-10-10 22:10:10173 connector_->set_incoming_receiver(&dispatcher_);
rockot0e4de5f2016-07-22 21:18:07174 connector_->set_connection_error_handler(
Jan Wilken Dörrie0825fc3e2020-04-21 20:24:34175 base::BindOnce(&ChannelAssociatedGroupController::OnPipeError,
176 base::Unretained(this)));
Ken Rockot138153b2018-07-13 23:31:57177 connector_->set_enforce_errors_from_incoming_receiver(false);
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20178 if (quota_checker_)
179 connector_->SetMessageQuotaChecker(quota_checker_);
Ken Rockot471aa7942019-01-17 02:46:59180
181 // Don't let the Connector do any sort of queuing on our behalf. Individual
182 // messages bound for the IPC::ChannelProxy thread (i.e. that vast majority
183 // of messages received by this Connector) are already individually
184 // scheduled for dispatch by ChannelProxy, so Connector's normal mode of
185 // operation would only introduce a redundant scheduling step for most
186 // messages.
187 connector_->set_force_immediate_dispatch(true);
rockot401fb2c2016-09-06 18:35:57188 }
rockot0e4de5f2016-07-22 21:18:07189
rockot10188752016-09-08 18:24:56190 void Pause() {
191 DCHECK(!paused_);
192 paused_ = true;
193 }
194
195 void Unpause() {
196 DCHECK(paused_);
197 paused_ = false;
rockot401fb2c2016-09-06 18:35:57198 }
199
200 void FlushOutgoingMessages() {
rockotc4cc691e2016-08-19 18:48:57201 std::vector<mojo::Message> outgoing_messages;
Ken Rockot2b6de982018-03-20 22:28:13202 {
203 base::AutoLock lock(outgoing_messages_lock_);
204 std::swap(outgoing_messages, outgoing_messages_);
205 }
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20206 if (quota_checker_ && outgoing_messages.size())
207 quota_checker_->AfterMessagesDequeued(outgoing_messages.size());
208
rockot0e4de5f2016-07-22 21:18:07209 for (auto& message : outgoing_messages)
rockotc4cc691e2016-08-19 18:48:57210 SendMessage(&message);
rockot0e4de5f2016-07-22 21:18:07211 }
212
Julie Jeongeun Kim903b34b2019-09-25 11:11:54213 void CreateChannelEndpoints(
214 mojo::AssociatedRemote<mojom::Channel>* sender,
215 mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) {
rockot0e4de5f2016-07-22 21:18:07216 mojo::InterfaceId sender_id, receiver_id;
217 if (set_interface_id_namespace_bit_) {
218 sender_id = 1 | mojo::kInterfaceIdNamespaceMask;
219 receiver_id = 1;
220 } else {
221 sender_id = 1;
222 receiver_id = 1 | mojo::kInterfaceIdNamespaceMask;
223 }
224
225 {
226 base::AutoLock locker(lock_);
227 Endpoint* sender_endpoint = new Endpoint(this, sender_id);
228 Endpoint* receiver_endpoint = new Endpoint(this, receiver_id);
229 endpoints_.insert({ sender_id, sender_endpoint });
230 endpoints_.insert({ receiver_id, receiver_endpoint });
yzshen0a5971312017-02-02 05:13:47231 sender_endpoint->set_handle_created();
232 receiver_endpoint->set_handle_created();
rockot0e4de5f2016-07-22 21:18:07233 }
234
235 mojo::ScopedInterfaceEndpointHandle sender_handle =
yzshen2859a2ac2017-02-14 22:24:25236 CreateScopedInterfaceEndpointHandle(sender_id);
rockot0e4de5f2016-07-22 21:18:07237 mojo::ScopedInterfaceEndpointHandle receiver_handle =
yzshen2859a2ac2017-02-14 22:24:25238 CreateScopedInterfaceEndpointHandle(receiver_id);
rockot0e4de5f2016-07-22 21:18:07239
Julie Jeongeun Kim903b34b2019-09-25 11:11:54240 sender->Bind(mojo::PendingAssociatedRemote<mojom::Channel>(
241 std::move(sender_handle), 0));
242 *receiver = mojo::PendingAssociatedReceiver<mojom::Channel>(
243 std::move(receiver_handle));
rockot0e4de5f2016-07-22 21:18:07244 }
rockot02b8e182016-07-13 20:08:30245
246 void ShutDown() {
247 DCHECK(thread_checker_.CalledOnValidThread());
Ken Rockot3e7284bb2018-02-06 16:11:16248 shut_down_ = true;
Bruce Dawsona40d48472020-04-20 20:57:24249 if (connector_)
250 connector_->CloseMessagePipe();
rockot02b8e182016-07-13 20:08:30251 OnPipeError();
rockot0e4de5f2016-07-22 21:18:07252 connector_.reset();
Ken Rockot2b6de982018-03-20 22:28:13253
254 base::AutoLock lock(outgoing_messages_lock_);
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20255 if (quota_checker_ && outgoing_messages_.size())
256 quota_checker_->AfterMessagesDequeued(outgoing_messages_.size());
257
Ken Rockot3e7284bb2018-02-06 16:11:16258 outgoing_messages_.clear();
rockot02b8e182016-07-13 20:08:30259 }
260
261 // mojo::AssociatedGroupController:
yzshen2859a2ac2017-02-14 22:24:25262 mojo::InterfaceId AssociateInterface(
263 mojo::ScopedInterfaceEndpointHandle handle_to_send) override {
264 if (!handle_to_send.pending_association())
265 return mojo::kInvalidInterfaceId;
266
rockot02b8e182016-07-13 20:08:30267 uint32_t id = 0;
yzshen2859a2ac2017-02-14 22:24:25268 {
269 base::AutoLock locker(lock_);
270 do {
271 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask)
272 next_interface_id_ = 2;
273 id = next_interface_id_++;
274 if (set_interface_id_namespace_bit_)
275 id |= mojo::kInterfaceIdNamespaceMask;
Jan Wilken Dörrie73c901e2019-06-12 09:02:32276 } while (base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30277
yzshen2859a2ac2017-02-14 22:24:25278 Endpoint* endpoint = new Endpoint(this, id);
279 if (encountered_error_)
280 endpoint->set_peer_closed();
281 endpoint->set_handle_created();
282 endpoints_.insert({id, endpoint});
283 }
rockot02b8e182016-07-13 20:08:30284
yzshen2859a2ac2017-02-14 22:24:25285 if (!NotifyAssociation(&handle_to_send, id)) {
286 // The peer handle of |handle_to_send|, which is supposed to join this
287 // associated group, has been closed.
288 {
289 base::AutoLock locker(lock_);
290 Endpoint* endpoint = FindEndpoint(id);
291 if (endpoint)
292 MarkClosedAndMaybeRemove(endpoint);
293 }
294
295 control_message_proxy_.NotifyPeerEndpointClosed(
296 id, handle_to_send.disconnect_reason());
297 }
298 return id;
rockot02b8e182016-07-13 20:08:30299 }
300
301 mojo::ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
302 mojo::InterfaceId id) override {
303 if (!mojo::IsValidInterfaceId(id))
304 return mojo::ScopedInterfaceEndpointHandle();
305
Ken Rockotcd23f752020-06-20 01:22:31306 // Unless it is the primary ID, |id| is from the remote side and therefore
Yuzhu Shen9f87fb02017-08-11 17:07:06307 // its namespace bit is supposed to be different than the value that this
308 // router would use.
Ken Rockotcd23f752020-06-20 01:22:31309 if (!mojo::IsPrimaryInterfaceId(id) &&
Yuzhu Shen9f87fb02017-08-11 17:07:06310 set_interface_id_namespace_bit_ ==
311 mojo::HasInterfaceIdNamespaceBitSet(id)) {
312 return mojo::ScopedInterfaceEndpointHandle();
313 }
314
rockot02b8e182016-07-13 20:08:30315 base::AutoLock locker(lock_);
316 bool inserted = false;
317 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
yzshenea784ea2017-01-31 21:20:20318 if (inserted) {
319 DCHECK(!endpoint->handle_created());
320 if (encountered_error_)
321 endpoint->set_peer_closed();
322 } else {
323 if (endpoint->handle_created())
324 return mojo::ScopedInterfaceEndpointHandle();
325 }
rockot02b8e182016-07-13 20:08:30326
yzshenea784ea2017-01-31 21:20:20327 endpoint->set_handle_created();
yzshen2859a2ac2017-02-14 22:24:25328 return CreateScopedInterfaceEndpointHandle(id);
rockot02b8e182016-07-13 20:08:30329 }
330
yzshen8be41d3a2017-01-23 20:40:37331 void CloseEndpointHandle(
332 mojo::InterfaceId id,
Anton Bikineev1f42a452021-05-15 18:02:50333 const absl::optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30334 if (!mojo::IsValidInterfaceId(id))
335 return;
yzshen2859a2ac2017-02-14 22:24:25336 {
337 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32338 DCHECK(base::Contains(endpoints_, id));
yzshen2859a2ac2017-02-14 22:24:25339 Endpoint* endpoint = endpoints_[id].get();
340 DCHECK(!endpoint->client());
341 DCHECK(!endpoint->closed());
342 MarkClosedAndMaybeRemove(endpoint);
rockot02b8e182016-07-13 20:08:30343 }
344
Ken Rockotcd23f752020-06-20 01:22:31345 if (!mojo::IsPrimaryInterfaceId(id) || reason)
yzshen8be41d3a2017-01-23 20:40:37346 control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
rockot02b8e182016-07-13 20:08:30347 }
348
349 mojo::InterfaceEndpointController* AttachEndpointClient(
350 const mojo::ScopedInterfaceEndpointHandle& handle,
351 mojo::InterfaceEndpointClient* client,
Sam McNallyde5ae672017-06-19 23:34:45352 scoped_refptr<base::SequencedTaskRunner> runner) override {
rockot02b8e182016-07-13 20:08:30353 const mojo::InterfaceId id = handle.id();
354
355 DCHECK(mojo::IsValidInterfaceId(id));
356 DCHECK(client);
357
358 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32359 DCHECK(base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30360
361 Endpoint* endpoint = endpoints_[id].get();
362 endpoint->AttachClient(client, std::move(runner));
363
364 if (endpoint->peer_closed())
365 NotifyEndpointOfError(endpoint, true /* force_async */);
366
367 return endpoint;
368 }
369
370 void DetachEndpointClient(
371 const mojo::ScopedInterfaceEndpointHandle& handle) override {
372 const mojo::InterfaceId id = handle.id();
373
374 DCHECK(mojo::IsValidInterfaceId(id));
375
376 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32377 DCHECK(base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30378
379 Endpoint* endpoint = endpoints_[id].get();
380 endpoint->DetachClient();
381 }
382
383 void RaiseError() override {
Ken Rockot138153b2018-07-13 23:31:57384 // We ignore errors on channel endpoints, leaving the pipe open. There are
385 // good reasons for this:
386 //
387 // * We should never close a channel endpoint in either process as long as
388 // the child process is still alive. The child's endpoint should only be
389 // closed implicitly by process death, and the browser's endpoint should
390 // only be closed after the child process is confirmed to be dead. Crash
391 // reporting logic in Chrome relies on this behavior in order to do the
392 // right thing.
393 //
394 // * There are two interesting conditions under which RaiseError() can be
395 // implicitly reached: an incoming message fails validation, or the
396 // local endpoint drops a response callback without calling it.
397 //
398 // * In the validation case, we also report the message as bad, and this
399 // will imminently trigger the common bad-IPC path in the browser,
400 // causing the browser to kill the offending renderer.
401 //
402 // * In the dropped response callback case, the net result of ignoring the
403 // issue is generally innocuous. While indicative of programmer error,
404 // it's not a severe failure and is already covered by separate DCHECKs.
405 //
406 // See https://crbug.com/861607 for additional discussion.
rockot02b8e182016-07-13 20:08:30407 }
408
Ken Rockot474df0142017-07-12 13:28:56409 bool PrefersSerializedMessages() override { return true; }
410
rockot02b8e182016-07-13 20:08:30411 private:
412 class Endpoint;
rockot0e4de5f2016-07-22 21:18:07413 class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30414 friend class Endpoint;
rockot0e4de5f2016-07-22 21:18:07415 friend class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30416
yzshen0a5971312017-02-02 05:13:47417 // MessageWrapper objects are always destroyed under the controller's lock. On
418 // destruction, if the message it wrappers contains
419 // ScopedInterfaceEndpointHandles (which cannot be destructed under the
420 // controller's lock), the wrapper unlocks to clean them up.
421 class MessageWrapper {
yzshenea784ea2017-01-31 21:20:20422 public:
yzshen0a5971312017-02-02 05:13:47423 MessageWrapper() = default;
yzshenea784ea2017-01-31 21:20:20424
yzshen0a5971312017-02-02 05:13:47425 MessageWrapper(ChannelAssociatedGroupController* controller,
426 mojo::Message message)
427 : controller_(controller), value_(std::move(message)) {}
yzshenea784ea2017-01-31 21:20:20428
yzshen0a5971312017-02-02 05:13:47429 MessageWrapper(MessageWrapper&& other)
yzshenea784ea2017-01-31 21:20:20430 : controller_(other.controller_), value_(std::move(other.value_)) {}
431
yzshen0a5971312017-02-02 05:13:47432 ~MessageWrapper() {
433 if (value_.associated_endpoint_handles()->empty())
yzshenea784ea2017-01-31 21:20:20434 return;
435
436 controller_->lock_.AssertAcquired();
yzshen0a5971312017-02-02 05:13:47437 {
yzshenea784ea2017-01-31 21:20:20438 base::AutoUnlock unlocker(controller_->lock_);
yzshen0a5971312017-02-02 05:13:47439 value_.mutable_associated_endpoint_handles()->clear();
yzshenea784ea2017-01-31 21:20:20440 }
441 }
442
yzshen0a5971312017-02-02 05:13:47443 MessageWrapper& operator=(MessageWrapper&& other) {
yzshenea784ea2017-01-31 21:20:20444 controller_ = other.controller_;
445 value_ = std::move(other.value_);
446 return *this;
447 }
448
yzshen0a5971312017-02-02 05:13:47449 mojo::Message& value() { return value_; }
yzshenea784ea2017-01-31 21:20:20450
451 private:
452 ChannelAssociatedGroupController* controller_ = nullptr;
yzshenea784ea2017-01-31 21:20:20453 mojo::Message value_;
454
yzshen0a5971312017-02-02 05:13:47455 DISALLOW_COPY_AND_ASSIGN(MessageWrapper);
yzshenea784ea2017-01-31 21:20:20456 };
457
rockot02b8e182016-07-13 20:08:30458 class Endpoint : public base::RefCountedThreadSafe<Endpoint>,
459 public mojo::InterfaceEndpointController {
460 public:
461 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id)
462 : controller_(controller), id_(id) {}
463
464 mojo::InterfaceId id() const { return id_; }
465
466 bool closed() const {
467 controller_->lock_.AssertAcquired();
468 return closed_;
469 }
470
471 void set_closed() {
472 controller_->lock_.AssertAcquired();
473 closed_ = true;
474 }
475
476 bool peer_closed() const {
477 controller_->lock_.AssertAcquired();
478 return peer_closed_;
479 }
480
481 void set_peer_closed() {
482 controller_->lock_.AssertAcquired();
483 peer_closed_ = true;
484 }
485
yzshenea784ea2017-01-31 21:20:20486 bool handle_created() const {
487 controller_->lock_.AssertAcquired();
488 return handle_created_;
489 }
490
491 void set_handle_created() {
492 controller_->lock_.AssertAcquired();
493 handle_created_ = true;
494 }
495
Anton Bikineev1f42a452021-05-15 18:02:50496 const absl::optional<mojo::DisconnectReason>& disconnect_reason() const {
yzshen8be41d3a2017-01-23 20:40:37497 return disconnect_reason_;
498 }
499
500 void set_disconnect_reason(
Anton Bikineev1f42a452021-05-15 18:02:50501 const absl::optional<mojo::DisconnectReason>& disconnect_reason) {
yzshen8be41d3a2017-01-23 20:40:37502 disconnect_reason_ = disconnect_reason;
503 }
504
Sam McNallyde5ae672017-06-19 23:34:45505 base::SequencedTaskRunner* task_runner() const {
rockot02b8e182016-07-13 20:08:30506 return task_runner_.get();
507 }
508
509 mojo::InterfaceEndpointClient* client() const {
510 controller_->lock_.AssertAcquired();
511 return client_;
512 }
513
514 void AttachClient(mojo::InterfaceEndpointClient* client,
Sam McNallyde5ae672017-06-19 23:34:45515 scoped_refptr<base::SequencedTaskRunner> runner) {
rockot02b8e182016-07-13 20:08:30516 controller_->lock_.AssertAcquired();
517 DCHECK(!client_);
518 DCHECK(!closed_);
peary28cd3bd22017-06-29 02:15:28519 DCHECK(runner->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30520
521 task_runner_ = std::move(runner);
522 client_ = client;
523 }
524
525 void DetachClient() {
526 controller_->lock_.AssertAcquired();
527 DCHECK(client_);
peary28cd3bd22017-06-29 02:15:28528 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30529 DCHECK(!closed_);
530
531 task_runner_ = nullptr;
532 client_ = nullptr;
rockot9abe09b2016-08-02 20:57:34533 sync_watcher_.reset();
534 }
535
yzshen0a5971312017-02-02 05:13:47536 uint32_t EnqueueSyncMessage(MessageWrapper message) {
rockot9abe09b2016-08-02 20:57:34537 controller_->lock_.AssertAcquired();
538 uint32_t id = GenerateSyncMessageId();
539 sync_messages_.emplace(id, std::move(message));
540 SignalSyncMessageEvent();
541 return id;
542 }
543
544 void SignalSyncMessageEvent() {
545 controller_->lock_.AssertAcquired();
yzshene25b5d52017-02-28 21:56:31546
Ken Rockotaa20dcc2018-03-28 03:06:51547 if (sync_watcher_)
548 sync_watcher_->SignalEvent();
rockot9abe09b2016-08-02 20:57:34549 }
550
yzshen0a5971312017-02-02 05:13:47551 MessageWrapper PopSyncMessage(uint32_t id) {
rockot9abe09b2016-08-02 20:57:34552 controller_->lock_.AssertAcquired();
553 if (sync_messages_.empty() || sync_messages_.front().first != id)
yzshen0a5971312017-02-02 05:13:47554 return MessageWrapper();
555 MessageWrapper message = std::move(sync_messages_.front().second);
rockot9abe09b2016-08-02 20:57:34556 sync_messages_.pop();
557 return message;
rockot02b8e182016-07-13 20:08:30558 }
559
560 // mojo::InterfaceEndpointController:
561 bool SendMessage(mojo::Message* message) override {
peary28cd3bd22017-06-29 02:15:28562 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30563 message->set_interface_id(id_);
564 return controller_->SendMessage(message);
565 }
566
567 void AllowWokenUpBySyncWatchOnSameThread() override {
peary28cd3bd22017-06-29 02:15:28568 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30569
rockot9abe09b2016-08-02 20:57:34570 EnsureSyncWatcherExists();
Ken Rockotaa20dcc2018-03-28 03:06:51571 sync_watcher_->AllowWokenUpBySyncWatchOnSameSequence();
rockot02b8e182016-07-13 20:08:30572 }
573
Ken Rockot5b3136c2021-04-26 17:45:59574 bool SyncWatch(const bool& should_stop) override {
peary28cd3bd22017-06-29 02:15:28575 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30576
Ken Rockotcd23f752020-06-20 01:22:31577 // It's not legal to make sync calls from the primary endpoint's thread,
rockot02b8e182016-07-13 20:08:30578 // and in fact they must only happen from the proxy task runner.
rockot7604e7b72016-07-28 17:37:39579 DCHECK(!controller_->task_runner_->BelongsToCurrentThread());
rockot02b8e182016-07-13 20:08:30580 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread());
581
rockot9abe09b2016-08-02 20:57:34582 EnsureSyncWatcherExists();
Ken Rockot54272972021-04-20 22:08:04583 return sync_watcher_->SyncWatch(&should_stop);
rockot02b8e182016-07-13 20:08:30584 }
585
Ken Rockot5b3136c2021-04-26 17:45:59586 bool SyncWatchExclusive(uint64_t request_id) override {
587 // We don't support exclusive waits on Channel-associated interfaces.
588 NOTREACHED();
589 return false;
590 }
591
Ken Rockot9f69e162021-04-19 14:16:29592 void RegisterExternalSyncWaiter(uint64_t request_id) override {}
593
rockot02b8e182016-07-13 20:08:30594 private:
595 friend class base::RefCountedThreadSafe<Endpoint>;
596
rockot9abe09b2016-08-02 20:57:34597 ~Endpoint() override {
598 controller_->lock_.AssertAcquired();
599 DCHECK(!client_);
600 DCHECK(closed_);
601 DCHECK(peer_closed_);
602 DCHECK(!sync_watcher_);
603 }
604
rockotb62e2e32017-03-24 18:36:44605 void OnSyncMessageEventReady() {
peary28cd3bd22017-06-29 02:15:28606 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34607
608 scoped_refptr<Endpoint> keepalive(this);
609 scoped_refptr<AssociatedGroupController> controller_keepalive(
610 controller_);
Ken Rockotaa20dcc2018-03-28 03:06:51611 base::AutoLock locker(controller_->lock_);
612 bool more_to_process = false;
613 if (!sync_messages_.empty()) {
614 MessageWrapper message_wrapper =
615 std::move(sync_messages_.front().second);
616 sync_messages_.pop();
rockot9abe09b2016-08-02 20:57:34617
Ken Rockotaa20dcc2018-03-28 03:06:51618 bool dispatch_succeeded;
619 mojo::InterfaceEndpointClient* client = client_;
620 {
621 base::AutoUnlock unlocker(controller_->lock_);
622 dispatch_succeeded =
623 client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34624 }
625
Ken Rockotaa20dcc2018-03-28 03:06:51626 if (!sync_messages_.empty())
627 more_to_process = true;
rockot9abe09b2016-08-02 20:57:34628
Ken Rockotaa20dcc2018-03-28 03:06:51629 if (!dispatch_succeeded)
630 controller_->RaiseError();
rockot9abe09b2016-08-02 20:57:34631 }
632
Ken Rockotaa20dcc2018-03-28 03:06:51633 if (!more_to_process)
634 sync_watcher_->ResetEvent();
635
636 // If there are no queued sync messages and the peer has closed, there
637 // there won't be incoming sync messages in the future. If any
638 // SyncWatch() calls are on the stack for this endpoint, resetting the
639 // watcher will allow them to exit as the stack undwinds.
640 if (!more_to_process && peer_closed_)
rockot9abe09b2016-08-02 20:57:34641 sync_watcher_.reset();
rockot9abe09b2016-08-02 20:57:34642 }
643
644 void EnsureSyncWatcherExists() {
peary28cd3bd22017-06-29 02:15:28645 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34646 if (sync_watcher_)
647 return;
648
Ken Rockotaa20dcc2018-03-28 03:06:51649 base::AutoLock locker(controller_->lock_);
650 sync_watcher_ = std::make_unique<mojo::SequenceLocalSyncEventWatcher>(
651 base::BindRepeating(&Endpoint::OnSyncMessageEventReady,
652 base::Unretained(this)));
653 if (peer_closed_ || !sync_messages_.empty())
654 SignalSyncMessageEvent();
rockot9abe09b2016-08-02 20:57:34655 }
656
657 uint32_t GenerateSyncMessageId() {
658 // Overflow is fine.
659 uint32_t id = next_sync_message_id_++;
660 DCHECK(sync_messages_.empty() || sync_messages_.front().first != id);
661 return id;
662 }
rockot02b8e182016-07-13 20:08:30663
664 ChannelAssociatedGroupController* const controller_;
665 const mojo::InterfaceId id_;
666
667 bool closed_ = false;
668 bool peer_closed_ = false;
yzshenea784ea2017-01-31 21:20:20669 bool handle_created_ = false;
Anton Bikineev1f42a452021-05-15 18:02:50670 absl::optional<mojo::DisconnectReason> disconnect_reason_;
rockot02b8e182016-07-13 20:08:30671 mojo::InterfaceEndpointClient* client_ = nullptr;
Sam McNallyde5ae672017-06-19 23:34:45672 scoped_refptr<base::SequencedTaskRunner> task_runner_;
Ken Rockotaa20dcc2018-03-28 03:06:51673 std::unique_ptr<mojo::SequenceLocalSyncEventWatcher> sync_watcher_;
Brett Wilsona62d9c02017-09-20 20:53:20674 base::queue<std::pair<uint32_t, MessageWrapper>> sync_messages_;
rockot9abe09b2016-08-02 20:57:34675 uint32_t next_sync_message_id_ = 0;
rockot02b8e182016-07-13 20:08:30676
677 DISALLOW_COPY_AND_ASSIGN(Endpoint);
678 };
679
rockot0e4de5f2016-07-22 21:18:07680 class ControlMessageProxyThunk : public MessageReceiver {
681 public:
682 explicit ControlMessageProxyThunk(
683 ChannelAssociatedGroupController* controller)
684 : controller_(controller) {}
685
686 private:
687 // MessageReceiver:
688 bool Accept(mojo::Message* message) override {
689 return controller_->SendMessage(message);
690 }
691
692 ChannelAssociatedGroupController* controller_;
693
694 DISALLOW_COPY_AND_ASSIGN(ControlMessageProxyThunk);
695 };
696
rockot02b8e182016-07-13 20:08:30697 ~ChannelAssociatedGroupController() override {
rockotb01ef6a2016-07-27 03:24:32698 DCHECK(!connector_);
699
rockot02b8e182016-07-13 20:08:30700 base::AutoLock locker(lock_);
rockot02b8e182016-07-13 20:08:30701 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
702 Endpoint* endpoint = iter->second.get();
703 ++iter;
704
yzshene003d592017-01-24 21:42:17705 if (!endpoint->closed()) {
706 // This happens when a NotifyPeerEndpointClosed message been received,
yzshen2859a2ac2017-02-14 22:24:25707 // but the interface ID hasn't been used to create local endpoint
708 // handle.
yzshene003d592017-01-24 21:42:17709 DCHECK(!endpoint->client());
710 DCHECK(endpoint->peer_closed());
711 MarkClosedAndMaybeRemove(endpoint);
712 } else {
713 MarkPeerClosedAndMaybeRemove(endpoint);
714 }
rockot02b8e182016-07-13 20:08:30715 }
716
717 DCHECK(endpoints_.empty());
Ken Rockot2b6de982018-03-20 22:28:13718
719 GetMemoryDumpProvider().RemoveController(this);
rockot02b8e182016-07-13 20:08:30720 }
721
722 bool SendMessage(mojo::Message* message) {
Siddhartha S03484422019-04-23 20:30:00723 DCHECK(message->heap_profiler_tag());
rockot7604e7b72016-07-28 17:37:39724 if (task_runner_->BelongsToCurrentThread()) {
rockot02b8e182016-07-13 20:08:30725 DCHECK(thread_checker_.CalledOnValidThread());
rockot10188752016-09-08 18:24:56726 if (!connector_ || paused_) {
Ken Rockot37ddd8152018-02-22 18:18:46727 if (!shut_down_) {
Ken Rockot2b6de982018-03-20 22:28:13728 base::AutoLock lock(outgoing_messages_lock_);
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20729 if (quota_checker_)
730 quota_checker_->BeforeMessagesEnqueued(1);
Ken Rockot3e7284bb2018-02-06 16:11:16731 outgoing_messages_.emplace_back(std::move(*message));
Ken Rockot37ddd8152018-02-22 18:18:46732 }
rockot0e4de5f2016-07-22 21:18:07733 return true;
734 }
735 return connector_->Accept(message);
rockot02b8e182016-07-13 20:08:30736 } else {
Ken Rockotcd23f752020-06-20 01:22:31737 // We always post tasks to the primary endpoint thread when called from
rockotbecd3f742016-11-08 20:47:00738 // other threads in order to simulate IPC::ChannelProxy::Send behavior.
rockot02b8e182016-07-13 20:08:30739 task_runner_->PostTask(
740 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09741 base::BindOnce(
Ken Rockotcd23f752020-06-20 01:22:31742 &ChannelAssociatedGroupController::SendMessageOnPrimaryThread,
Jan Wilken Dörrie1494205b2020-03-26 09:32:53743 this, std::move(*message)));
rockot02b8e182016-07-13 20:08:30744 return true;
745 }
746 }
747
Ken Rockotcd23f752020-06-20 01:22:31748 void SendMessageOnPrimaryThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30749 DCHECK(thread_checker_.CalledOnValidThread());
rockotc4cc691e2016-08-19 18:48:57750 if (!SendMessage(&message))
rockot02b8e182016-07-13 20:08:30751 RaiseError();
752 }
753
754 void OnPipeError() {
755 DCHECK(thread_checker_.CalledOnValidThread());
756
757 // We keep |this| alive here because it's possible for the notifications
758 // below to release all other references.
759 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
760
761 base::AutoLock locker(lock_);
762 encountered_error_ = true;
763
764 std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
765 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
766 Endpoint* endpoint = iter->second.get();
767 ++iter;
768
769 if (endpoint->client())
770 endpoints_to_notify.push_back(endpoint);
771
772 MarkPeerClosedAndMaybeRemove(endpoint);
773 }
774
775 for (auto& endpoint : endpoints_to_notify) {
rockot0e4de5f2016-07-22 21:18:07776 // Because a notification may in turn detach any endpoint, we have to
rockot02b8e182016-07-13 20:08:30777 // check each client again here.
778 if (endpoint->client())
779 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
780 }
781 }
782
783 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
784 lock_.AssertAcquired();
785 DCHECK(endpoint->task_runner() && endpoint->client());
peary28cd3bd22017-06-29 02:15:28786 if (endpoint->task_runner()->RunsTasksInCurrentSequence() && !force_async) {
rockot02b8e182016-07-13 20:08:30787 mojo::InterfaceEndpointClient* client = endpoint->client();
Anton Bikineev1f42a452021-05-15 18:02:50788 absl::optional<mojo::DisconnectReason> reason(
yzshen8be41d3a2017-01-23 20:40:37789 endpoint->disconnect_reason());
rockot02b8e182016-07-13 20:08:30790
791 base::AutoUnlock unlocker(lock_);
yzshen8be41d3a2017-01-23 20:40:37792 client->NotifyError(reason);
rockot02b8e182016-07-13 20:08:30793 } else {
794 endpoint->task_runner()->PostTask(
795 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09796 base::BindOnce(&ChannelAssociatedGroupController::
797 NotifyEndpointOfErrorOnEndpointThread,
798 this, endpoint->id(), base::Unretained(endpoint)));
rockot02b8e182016-07-13 20:08:30799 }
800 }
801
rockot9abe09b2016-08-02 20:57:34802 void NotifyEndpointOfErrorOnEndpointThread(mojo::InterfaceId id,
803 Endpoint* endpoint) {
rockot02b8e182016-07-13 20:08:30804 base::AutoLock locker(lock_);
rockot9abe09b2016-08-02 20:57:34805 auto iter = endpoints_.find(id);
806 if (iter == endpoints_.end() || iter->second.get() != endpoint)
807 return;
rockot02b8e182016-07-13 20:08:30808 if (!endpoint->client())
809 return;
rockot9abe09b2016-08-02 20:57:34810
peary28cd3bd22017-06-29 02:15:28811 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34812 NotifyEndpointOfError(endpoint, false /* force_async */);
rockot02b8e182016-07-13 20:08:30813 }
814
815 void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
816 lock_.AssertAcquired();
817 endpoint->set_closed();
818 if (endpoint->closed() && endpoint->peer_closed())
819 endpoints_.erase(endpoint->id());
820 }
821
822 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
823 lock_.AssertAcquired();
824 endpoint->set_peer_closed();
rockot9abe09b2016-08-02 20:57:34825 endpoint->SignalSyncMessageEvent();
rockot02b8e182016-07-13 20:08:30826 if (endpoint->closed() && endpoint->peer_closed())
827 endpoints_.erase(endpoint->id());
828 }
829
830 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {
831 lock_.AssertAcquired();
832 DCHECK(!inserted || !*inserted);
833
yzshen0a5971312017-02-02 05:13:47834 Endpoint* endpoint = FindEndpoint(id);
835 if (!endpoint) {
836 endpoint = new Endpoint(this, id);
837 endpoints_.insert({id, endpoint});
838 if (inserted)
839 *inserted = true;
840 }
rockot02b8e182016-07-13 20:08:30841 return endpoint;
842 }
843
yzshen0a5971312017-02-02 05:13:47844 Endpoint* FindEndpoint(mojo::InterfaceId id) {
845 lock_.AssertAcquired();
846 auto iter = endpoints_.find(id);
847 return iter != endpoints_.end() ? iter->second.get() : nullptr;
848 }
849
rockot02b8e182016-07-13 20:08:30850 // mojo::MessageReceiver:
851 bool Accept(mojo::Message* message) override {
852 DCHECK(thread_checker_.CalledOnValidThread());
853
yzshen0a5971312017-02-02 05:13:47854 if (!message->DeserializeAssociatedEndpointHandles(this))
855 return false;
856
857 if (mojo::PipeControlMessageHandler::IsPipeControlMessage(message))
858 return control_message_handler_.Accept(message);
rockot02b8e182016-07-13 20:08:30859
860 mojo::InterfaceId id = message->interface_id();
Ken Rockot9f69e162021-04-19 14:16:29861 if (!mojo::IsValidInterfaceId(id))
862 return false;
rockot02b8e182016-07-13 20:08:30863
Ken Rockot4fede4552019-05-09 01:16:41864 base::ReleasableAutoLock locker(&lock_);
yzshen0a5971312017-02-02 05:13:47865 Endpoint* endpoint = FindEndpoint(id);
866 if (!endpoint)
867 return true;
868
869 mojo::InterfaceEndpointClient* client = endpoint->client();
peary28cd3bd22017-06-29 02:15:28870 if (!client || !endpoint->task_runner()->RunsTasksInCurrentSequence()) {
rockot02b8e182016-07-13 20:08:30871 // No client has been bound yet or the client runs tasks on another
872 // thread. We assume the other thread must always be the one on which
873 // |proxy_task_runner_| runs tasks, since that's the only valid scenario.
874 //
875 // If the client is not yet bound, it must be bound by the time this task
876 // runs or else it's programmer error.
877 DCHECK(proxy_task_runner_);
rockot9abe09b2016-08-02 20:57:34878
rockotc4cc691e2016-08-19 18:48:57879 if (message->has_flag(mojo::Message::kFlagIsSync)) {
yzshen0a5971312017-02-02 05:13:47880 MessageWrapper message_wrapper(this, std::move(*message));
rockot9abe09b2016-08-02 20:57:34881 // Sync messages may need to be handled by the endpoint if it's blocking
882 // on a sync reply. We pass ownership of the message to the endpoint's
883 // sync message queue. If the endpoint was blocking, it will dequeue the
884 // message and dispatch it. Otherwise the posted |AcceptSyncMessage()|
885 // call will dequeue the message and dispatch it.
yzshenea784ea2017-01-31 21:20:20886 uint32_t message_id =
887 endpoint->EnqueueSyncMessage(std::move(message_wrapper));
rockot9abe09b2016-08-02 20:57:34888 proxy_task_runner_->PostTask(
889 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09890 base::BindOnce(&ChannelAssociatedGroupController::AcceptSyncMessage,
891 this, id, message_id));
rockot9abe09b2016-08-02 20:57:34892 return true;
893 }
894
Ken Rockot4fede4552019-05-09 01:16:41895 // If |proxy_task_runner_| has been torn down already, this PostTask will
896 // fail and destroy |message|. That operation may need to in turn destroy
897 // in-transit associated endpoints and thus acquire |lock_|. We no longer
898 // need the lock to be held now since |proxy_task_runner_| is safe to
899 // access unguarded.
Harkiran Bolaria8b1cf112020-09-15 22:58:34900 {
901 // Grab interface name from |client| before releasing the lock to ensure
902 // that |client| is safe to access.
903 base::TaskAnnotator::ScopedSetIpcHash scoped_set_ipc_hash(
904 client ? client->interface_name() : "unknown interface");
905 locker.Release();
906 proxy_task_runner_->PostTask(
907 FROM_HERE,
908 base::BindOnce(
909 &ChannelAssociatedGroupController::AcceptOnProxyThread, this,
910 std::move(*message)));
911 }
rockot02b8e182016-07-13 20:08:30912 return true;
913 }
914
Ken Rockot4fede4552019-05-09 01:16:41915 locker.Release();
Harkiran Bolaria8b1cf112020-09-15 22:58:34916 // It's safe to access |client| here without holding a lock, because this
917 // code runs on a proxy thread and |client| can't be destroyed from any
918 // thread.
yzshen0a5971312017-02-02 05:13:47919 return client->HandleIncomingMessage(message);
rockot02b8e182016-07-13 20:08:30920 }
921
rockotc4cc691e2016-08-19 18:48:57922 void AcceptOnProxyThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30923 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
Stephen Nusko8e400642020-09-16 13:48:59924 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mojom"),
925 "ChannelAssociatedGroupController::AcceptOnProxyThread");
rockot02b8e182016-07-13 20:08:30926
rockotc4cc691e2016-08-19 18:48:57927 mojo::InterfaceId id = message.interface_id();
Ken Rockotcd23f752020-06-20 01:22:31928 DCHECK(mojo::IsValidInterfaceId(id) && !mojo::IsPrimaryInterfaceId(id));
rockot8d890f62016-07-14 16:37:14929
930 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47931 Endpoint* endpoint = FindEndpoint(id);
rockot8d890f62016-07-14 16:37:14932 if (!endpoint)
933 return;
934
935 mojo::InterfaceEndpointClient* client = endpoint->client();
936 if (!client)
937 return;
938
Stephen Nusko8e400642020-09-16 13:48:59939 // Using client->interface_name() is safe here because this is a static
940 // string defined for each mojo interface.
941 TRACE_EVENT0("mojom", client->interface_name());
peary28cd3bd22017-06-29 02:15:28942 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
rockot8d890f62016-07-14 16:37:14943
rockot9abe09b2016-08-02 20:57:34944 // Sync messages should never make their way to this method.
yzshen0a5971312017-02-02 05:13:47945 DCHECK(!message.has_flag(mojo::Message::kFlagIsSync));
rockot8d890f62016-07-14 16:37:14946
947 bool result = false;
948 {
949 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47950 result = client->HandleIncomingMessage(&message);
rockot8d890f62016-07-14 16:37:14951 }
952
953 if (!result)
954 RaiseError();
955 }
956
rockot9abe09b2016-08-02 20:57:34957 void AcceptSyncMessage(mojo::InterfaceId interface_id, uint32_t message_id) {
958 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
Stephen Nusko8e400642020-09-16 13:48:59959 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mojom"),
960 "ChannelAssociatedGroupController::AcceptSyncMessage");
rockot9abe09b2016-08-02 20:57:34961
962 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47963 Endpoint* endpoint = FindEndpoint(interface_id);
rockot9abe09b2016-08-02 20:57:34964 if (!endpoint)
965 return;
966
csharrison1af8d6ab2017-04-21 17:47:23967 // Careful, if the endpoint is detached its members are cleared. Check for
968 // that before dereferencing.
969 mojo::InterfaceEndpointClient* client = endpoint->client();
970 if (!client)
971 return;
972
Stephen Nusko8e400642020-09-16 13:48:59973 // Using client->interface_name() is safe here because this is a static
974 // string defined for each mojo interface.
975 TRACE_EVENT0("mojom", client->interface_name());
peary28cd3bd22017-06-29 02:15:28976 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
yzshen0a5971312017-02-02 05:13:47977 MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id);
rockot9abe09b2016-08-02 20:57:34978
979 // The message must have already been dequeued by the endpoint waking up
980 // from a sync wait. Nothing to do.
yzshenea784ea2017-01-31 21:20:20981 if (message_wrapper.value().IsNull())
rockot9abe09b2016-08-02 20:57:34982 return;
983
rockot9abe09b2016-08-02 20:57:34984 bool result = false;
985 {
986 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47987 result = client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34988 }
989
990 if (!result)
991 RaiseError();
992 }
993
rockot02b8e182016-07-13 20:08:30994 // mojo::PipeControlMessageHandlerDelegate:
yzshen8be41d3a2017-01-23 20:40:37995 bool OnPeerAssociatedEndpointClosed(
996 mojo::InterfaceId id,
Anton Bikineev1f42a452021-05-15 18:02:50997 const absl::optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30998 DCHECK(thread_checker_.CalledOnValidThread());
999
rockot0e4de5f2016-07-22 21:18:071000 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
rockot02b8e182016-07-13 20:08:301001 base::AutoLock locker(lock_);
1002 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr);
yzshen8be41d3a2017-01-23 20:40:371003 if (reason)
1004 endpoint->set_disconnect_reason(reason);
rockot02b8e182016-07-13 20:08:301005 if (!endpoint->peer_closed()) {
1006 if (endpoint->client())
1007 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
1008 MarkPeerClosedAndMaybeRemove(endpoint.get());
1009 }
1010
1011 return true;
1012 }
1013
Ken Rockoteb2366a2020-01-13 21:13:461014 bool WaitForFlushToComplete(
1015 mojo::ScopedMessagePipeHandle flush_pipe) override {
1016 // We don't support async flushing on the IPC Channel pipe.
1017 return false;
1018 }
1019
Ken Rockotcd23f752020-06-20 01:22:311020 // Checked in places which must be run on the primary endpoint's thread.
rockot02b8e182016-07-13 20:08:301021 base::ThreadChecker thread_checker_;
1022
1023 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
rockot0e4de5f2016-07-22 21:18:071024
Ken Rockot4fede4552019-05-09 01:16:411025 const scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201026 const scoped_refptr<mojo::internal::MessageQuotaChecker> quota_checker_;
rockot0e4de5f2016-07-22 21:18:071027 const bool set_interface_id_namespace_bit_;
rockot10188752016-09-08 18:24:561028 bool paused_ = false;
rockot0e4de5f2016-07-22 21:18:071029 std::unique_ptr<mojo::Connector> connector_;
Dave Tapuskaf2df43e2019-10-10 22:10:101030 mojo::MessageDispatcher dispatcher_;
rockot02b8e182016-07-13 20:08:301031 mojo::PipeControlMessageHandler control_message_handler_;
rockot0e4de5f2016-07-22 21:18:071032 ControlMessageProxyThunk control_message_proxy_thunk_;
rockot58909542016-11-10 20:05:451033
1034 // NOTE: It is unsafe to call into this object while holding |lock_|.
rockot0e4de5f2016-07-22 21:18:071035 mojo::PipeControlMessageProxy control_message_proxy_;
1036
Ken Rockot2b6de982018-03-20 22:28:131037 // Guards access to |outgoing_messages_| only. Used to support memory dumps
1038 // which may be triggered from any thread.
1039 base::Lock outgoing_messages_lock_;
1040
rockot0e4de5f2016-07-22 21:18:071041 // Outgoing messages that were sent before this controller was bound to a
1042 // real message pipe.
rockotc4cc691e2016-08-19 18:48:571043 std::vector<mojo::Message> outgoing_messages_;
rockot02b8e182016-07-13 20:08:301044
1045 // Guards the fields below for thread-safe access.
1046 base::Lock lock_;
1047
1048 bool encountered_error_ = false;
Ken Rockot3e7284bb2018-02-06 16:11:161049 bool shut_down_ = false;
rockot0e4de5f2016-07-22 21:18:071050
1051 // ID #1 is reserved for the mojom::Channel interface.
1052 uint32_t next_interface_id_ = 2;
1053
Yuzhu Shen7bcd8ebf2017-10-02 23:21:141054 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_;
rockot02b8e182016-07-13 20:08:301055
1056 DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController);
1057};
1058
Ken Rockot2b6de982018-03-20 22:28:131059bool ControllerMemoryDumpProvider::OnMemoryDump(
1060 const base::trace_event::MemoryDumpArgs& args,
1061 base::trace_event::ProcessMemoryDump* pmd) {
1062 base::AutoLock lock(lock_);
1063 for (auto* controller : controllers_) {
1064 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
1065 base::StringPrintf("mojo/queued_ipc_channel_message/0x%" PRIxPTR,
1066 reinterpret_cast<uintptr_t>(controller)));
1067 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
1068 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
1069 controller->GetQueuedMessageCount());
Siddhartha S03484422019-04-23 20:30:001070 MessageMemoryDumpInfo info;
1071 size_t count = 0;
1072 controller->GetTopQueuedMessageMemoryDumpInfo(&info, &count);
1073 dump->AddScalar("top_message_name", "id", info.id);
Siddharthad1cfec12018-09-17 21:42:151074 dump->AddScalar("top_message_count",
1075 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
Siddhartha S03484422019-04-23 20:30:001076 count);
1077
1078 if (info.profiler_tag) {
1079 // TODO(ssid): Memory dumps currently do not support adding string
1080 // arguments in background dumps. So, add this value as a trace event for
1081 // now.
ssidbc86cb72019-05-16 00:25:371082 TRACE_EVENT2(base::trace_event::MemoryDumpManager::kTraceCategory,
Siddhartha S03484422019-04-23 20:30:001083 "ControllerMemoryDumpProvider::OnMemoryDump",
ssidbc86cb72019-05-16 00:25:371084 "top_queued_message_tag", info.profiler_tag,
1085 "count", count);
Siddhartha S03484422019-04-23 20:30:001086 }
Ken Rockot2b6de982018-03-20 22:28:131087 }
1088
1089 return true;
1090}
1091
rockot0e4de5f2016-07-22 21:18:071092class MojoBootstrapImpl : public MojoBootstrap {
rockot02b8e182016-07-13 20:08:301093 public:
rockot0e4de5f2016-07-22 21:18:071094 MojoBootstrapImpl(
1095 mojo::ScopedMessagePipeHandle handle,
rockot0e4de5f2016-07-22 21:18:071096 const scoped_refptr<ChannelAssociatedGroupController> controller)
yzshen2859a2ac2017-02-14 22:24:251097 : controller_(controller),
1098 associated_group_(controller),
1099 handle_(std::move(handle)) {}
rockot02b8e182016-07-13 20:08:301100
rockot0e4de5f2016-07-22 21:18:071101 ~MojoBootstrapImpl() override {
1102 controller_->ShutDown();
rockot02b8e182016-07-13 20:08:301103 }
1104
1105 private:
Julie Jeongeun Kim903b34b2019-09-25 11:11:541106 void Connect(
1107 mojo::AssociatedRemote<mojom::Channel>* sender,
1108 mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) override {
rockot0e4de5f2016-07-22 21:18:071109 controller_->Bind(std::move(handle_));
rockota628d0b2017-02-09 08:40:151110 controller_->CreateChannelEndpoints(sender, receiver);
msramek5507fee2016-07-22 10:06:211111 }
1112
rockot10188752016-09-08 18:24:561113 void Pause() override {
1114 controller_->Pause();
1115 }
1116
1117 void Unpause() override {
1118 controller_->Unpause();
rockot401fb2c2016-09-06 18:35:571119 }
1120
1121 void Flush() override {
1122 controller_->FlushOutgoingMessages();
1123 }
1124
msramek5507fee2016-07-22 10:06:211125 mojo::AssociatedGroup* GetAssociatedGroup() override {
yzshen2859a2ac2017-02-14 22:24:251126 return &associated_group_;
msramek5507fee2016-07-22 10:06:211127 }
1128
rockot0e4de5f2016-07-22 21:18:071129 scoped_refptr<ChannelAssociatedGroupController> controller_;
yzshen2859a2ac2017-02-14 22:24:251130 mojo::AssociatedGroup associated_group_;
msramek5507fee2016-07-22 10:06:211131
rockot0e4de5f2016-07-22 21:18:071132 mojo::ScopedMessagePipeHandle handle_;
msramek5507fee2016-07-22 10:06:211133
rockot0e4de5f2016-07-22 21:18:071134 DISALLOW_COPY_AND_ASSIGN(MojoBootstrapImpl);
msramek5507fee2016-07-22 10:06:211135};
1136
morrita54f6f80c2014-09-23 21:16:001137} // namespace
1138
morrita54f6f80c2014-09-23 21:16:001139// static
danakj03de39b22016-04-23 04:21:091140std::unique_ptr<MojoBootstrap> MojoBootstrap::Create(
sammc57ed9f982016-03-10 06:28:351141 mojo::ScopedMessagePipeHandle handle,
1142 Channel::Mode mode,
Hajime Hoshia98f1102017-11-20 06:34:351143 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201144 const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner,
1145 const scoped_refptr<mojo::internal::MessageQuotaChecker>& quota_checker) {
Jeremy Roman160eb922017-08-29 17:43:431146 return std::make_unique<MojoBootstrapImpl>(
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201147 std::move(handle), new ChannelAssociatedGroupController(
1148 mode == Channel::MODE_SERVER, ipc_task_runner,
1149 proxy_task_runner, quota_checker));
sammc57ed9f982016-03-10 06:28:351150}
1151
morrita54f6f80c2014-09-23 21:16:001152} // namespace IPC