blob: 0bd4ee7d4d4454ae25514cd75b24a2f49cbb9e95 [file] [log] [blame]
morrita54f6f80c2014-09-23 21:16:001// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
amistryd4aa70d2016-06-23 07:52:375#include "ipc/ipc_mojo_bootstrap.h"
morrita54f6f80c2014-09-23 21:16:006
Ken Rockot2b6de982018-03-20 22:28:137#include <inttypes.h>
tfarina10a5c062015-09-04 18:47:578#include <stdint.h>
rockot02b8e182016-07-13 20:08:309
10#include <map>
11#include <memory>
Ken Rockot2b6de982018-03-20 22:28:1312#include <set>
dchenge48600452015-12-28 02:24:5013#include <utility>
rockot0e4de5f2016-07-22 21:18:0714#include <vector>
tfarina10a5c062015-09-04 18:47:5715
Sebastien Marchand6d0558fd2019-01-25 16:49:3716#include "base/bind.h"
rockota21316a2016-06-19 17:08:3617#include "base/callback.h"
Brett Wilsona62d9c02017-09-20 20:53:2018#include "base/containers/queue.h"
morrita54f6f80c2014-09-23 21:16:0019#include "base/logging.h"
avi246998d82015-12-22 02:39:0420#include "base/macros.h"
danakj03de39b22016-04-23 04:21:0921#include "base/memory/ptr_util.h"
Ken Rockot2b6de982018-03-20 22:28:1322#include "base/no_destructor.h"
Gabriel Charette14520232018-04-30 23:27:2223#include "base/sequenced_task_runner.h"
rockot02b8e182016-07-13 20:08:3024#include "base/single_thread_task_runner.h"
Ken Rockot2b6de982018-03-20 22:28:1325#include "base/strings/stringprintf.h"
rockot02b8e182016-07-13 20:08:3026#include "base/synchronization/lock.h"
Sam McNallyde5ae672017-06-19 23:34:4527#include "base/threading/thread_checker.h"
rockot02b8e182016-07-13 20:08:3028#include "base/threading/thread_task_runner_handle.h"
Ken Rockot2b6de982018-03-20 22:28:1329#include "base/trace_event/memory_allocator_dump.h"
30#include "base/trace_event/memory_dump_manager.h"
31#include "base/trace_event/memory_dump_provider.h"
Ken Rockotfb81dc02018-05-15 21:59:2632#include "ipc/ipc_channel.h"
rockot02b8e182016-07-13 20:08:3033#include "mojo/public/cpp/bindings/associated_group.h"
34#include "mojo/public/cpp/bindings/associated_group_controller.h"
rockot02b8e182016-07-13 20:08:3035#include "mojo/public/cpp/bindings/connector.h"
36#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
37#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
38#include "mojo/public/cpp/bindings/interface_id.h"
rockot0e4de5f2016-07-22 21:18:0739#include "mojo/public/cpp/bindings/message.h"
rockot02b8e182016-07-13 20:08:3040#include "mojo/public/cpp/bindings/message_header_validator.h"
41#include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
42#include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h"
43#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
Ken Rockotaa20dcc2018-03-28 03:06:5144#include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h"
morrita54f6f80c2014-09-23 21:16:0045
46namespace IPC {
47
48namespace {
49
Ken Rockot2b6de982018-03-20 22:28:1350class ChannelAssociatedGroupController;
51
52// Used to track some internal Channel state in pursuit of message leaks.
53//
54// TODO(https://crbug.com/813045): Remove this.
55class ControllerMemoryDumpProvider
56 : public base::trace_event::MemoryDumpProvider {
57 public:
58 ControllerMemoryDumpProvider() {
59 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
60 this, "IPCChannel", nullptr);
61 }
62
63 ~ControllerMemoryDumpProvider() override {
64 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
65 this);
66 }
67
68 void AddController(ChannelAssociatedGroupController* controller) {
69 base::AutoLock lock(lock_);
70 controllers_.insert(controller);
71 }
72
73 void RemoveController(ChannelAssociatedGroupController* controller) {
74 base::AutoLock lock(lock_);
75 controllers_.erase(controller);
76 }
77
78 // base::trace_event::MemoryDumpProvider:
79 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
80 base::trace_event::ProcessMemoryDump* pmd) override;
81
82 private:
83 base::Lock lock_;
84 std::set<ChannelAssociatedGroupController*> controllers_;
85
86 DISALLOW_COPY_AND_ASSIGN(ControllerMemoryDumpProvider);
87};
88
89ControllerMemoryDumpProvider& GetMemoryDumpProvider() {
90 static base::NoDestructor<ControllerMemoryDumpProvider> provider;
91 return *provider;
92}
93
Siddhartha S03484422019-04-23 20:30:0094// Messages are grouped by this info when recording memory metrics.
95struct MessageMemoryDumpInfo {
96 MessageMemoryDumpInfo(const mojo::Message& message)
97 : id(message.name()), profiler_tag(message.heap_profiler_tag()) {}
98 MessageMemoryDumpInfo() = default;
99
100 bool operator==(const MessageMemoryDumpInfo& other) const {
101 return other.id == id && other.profiler_tag == profiler_tag;
102 }
103
104 uint32_t id = 0;
105 const char* profiler_tag = nullptr;
106};
107
108struct MessageMemoryDumpInfoHash {
109 size_t operator()(const MessageMemoryDumpInfo& info) const {
Daniel Cheng5c5a6522019-11-19 18:03:36110 return base::HashInts(
111 info.id, info.profiler_tag ? base::FastHash(info.profiler_tag) : 0);
Siddhartha S03484422019-04-23 20:30:00112 }
113};
114
rockot02b8e182016-07-13 20:08:30115class ChannelAssociatedGroupController
116 : public mojo::AssociatedGroupController,
117 public mojo::MessageReceiver,
118 public mojo::PipeControlMessageHandlerDelegate {
119 public:
rockot0e4de5f2016-07-22 21:18:07120 ChannelAssociatedGroupController(
121 bool set_interface_id_namespace_bit,
Hajime Hoshia98f1102017-11-20 06:34:35122 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20123 const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner,
124 const scoped_refptr<mojo::internal::MessageQuotaChecker>& quota_checker)
rockotb01ef6a2016-07-27 03:24:32125 : task_runner_(ipc_task_runner),
Hajime Hoshia98f1102017-11-20 06:34:35126 proxy_task_runner_(proxy_task_runner),
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20127 quota_checker_(quota_checker),
rockot0e4de5f2016-07-22 21:18:07128 set_interface_id_namespace_bit_(set_interface_id_namespace_bit),
Dave Tapuskaf2df43e2019-10-10 22:10:10129 dispatcher_(this),
rockot02b8e182016-07-13 20:08:30130 control_message_handler_(this),
rockot0e4de5f2016-07-22 21:18:07131 control_message_proxy_thunk_(this),
132 control_message_proxy_(&control_message_proxy_thunk_) {
133 thread_checker_.DetachFromThread();
rockot02b8e182016-07-13 20:08:30134 control_message_handler_.SetDescription(
135 "IPC::mojom::Bootstrap [master] PipeControlMessageHandler");
Dave Tapuskaf2df43e2019-10-10 22:10:10136 dispatcher_.SetValidator(std::make_unique<mojo::MessageHeaderValidator>(
137 "IPC::mojom::Bootstrap [master] MessageHeaderValidator"));
Ken Rockot2b6de982018-03-20 22:28:13138
139 GetMemoryDumpProvider().AddController(this);
140 }
141
142 size_t GetQueuedMessageCount() {
143 base::AutoLock lock(outgoing_messages_lock_);
144 return outgoing_messages_.size();
rockot02b8e182016-07-13 20:08:30145 }
146
Siddhartha S03484422019-04-23 20:30:00147 void GetTopQueuedMessageMemoryDumpInfo(MessageMemoryDumpInfo* info,
148 size_t* count) {
149 std::unordered_map<MessageMemoryDumpInfo, size_t, MessageMemoryDumpInfoHash>
150 counts;
151 std::pair<MessageMemoryDumpInfo, size_t> top_message_info_and_count = {
152 MessageMemoryDumpInfo(), 0};
Siddharthad1cfec12018-09-17 21:42:15153 base::AutoLock lock(outgoing_messages_lock_);
154 for (const auto& message : outgoing_messages_) {
Siddhartha S03484422019-04-23 20:30:00155 auto it_and_inserted = counts.emplace(MessageMemoryDumpInfo(message), 0);
Siddharthad1cfec12018-09-17 21:42:15156 it_and_inserted.first->second++;
Siddhartha S03484422019-04-23 20:30:00157 if (it_and_inserted.first->second > top_message_info_and_count.second)
158 top_message_info_and_count = *it_and_inserted.first;
Siddharthad1cfec12018-09-17 21:42:15159 }
Siddhartha S03484422019-04-23 20:30:00160 *info = top_message_info_and_count.first;
161 *count = top_message_info_and_count.second;
Siddharthad1cfec12018-09-17 21:42:15162 }
163
rockot0e4de5f2016-07-22 21:18:07164 void Bind(mojo::ScopedMessagePipeHandle handle) {
165 DCHECK(thread_checker_.CalledOnValidThread());
166 DCHECK(task_runner_->BelongsToCurrentThread());
rockot90984352016-07-25 17:36:19167
rockot0e4de5f2016-07-22 21:18:07168 connector_.reset(new mojo::Connector(
169 std::move(handle), mojo::Connector::SINGLE_THREADED_SEND,
170 task_runner_));
Dave Tapuskaf2df43e2019-10-10 22:10:10171 connector_->set_incoming_receiver(&dispatcher_);
rockot0e4de5f2016-07-22 21:18:07172 connector_->set_connection_error_handler(
Matt Falkenhagenfb888f02019-11-21 00:30:02173 base::BindRepeating(&ChannelAssociatedGroupController::OnPipeError,
174 base::Unretained(this)));
Ken Rockot138153b2018-07-13 23:31:57175 connector_->set_enforce_errors_from_incoming_receiver(false);
jcivelli2207af12017-01-26 20:46:00176 connector_->SetWatcherHeapProfilerTag("IPC Channel");
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20177 if (quota_checker_)
178 connector_->SetMessageQuotaChecker(quota_checker_);
Ken Rockot471aa7942019-01-17 02:46:59179
180 // Don't let the Connector do any sort of queuing on our behalf. Individual
181 // messages bound for the IPC::ChannelProxy thread (i.e. that vast majority
182 // of messages received by this Connector) are already individually
183 // scheduled for dispatch by ChannelProxy, so Connector's normal mode of
184 // operation would only introduce a redundant scheduling step for most
185 // messages.
186 connector_->set_force_immediate_dispatch(true);
rockot401fb2c2016-09-06 18:35:57187 }
rockot0e4de5f2016-07-22 21:18:07188
rockot10188752016-09-08 18:24:56189 void Pause() {
190 DCHECK(!paused_);
191 paused_ = true;
192 }
193
194 void Unpause() {
195 DCHECK(paused_);
196 paused_ = false;
rockot401fb2c2016-09-06 18:35:57197 }
198
199 void FlushOutgoingMessages() {
rockotc4cc691e2016-08-19 18:48:57200 std::vector<mojo::Message> outgoing_messages;
Ken Rockot2b6de982018-03-20 22:28:13201 {
202 base::AutoLock lock(outgoing_messages_lock_);
203 std::swap(outgoing_messages, outgoing_messages_);
204 }
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20205 if (quota_checker_ && outgoing_messages.size())
206 quota_checker_->AfterMessagesDequeued(outgoing_messages.size());
207
rockot0e4de5f2016-07-22 21:18:07208 for (auto& message : outgoing_messages)
rockotc4cc691e2016-08-19 18:48:57209 SendMessage(&message);
rockot0e4de5f2016-07-22 21:18:07210 }
211
Julie Jeongeun Kim903b34b2019-09-25 11:11:54212 void CreateChannelEndpoints(
213 mojo::AssociatedRemote<mojom::Channel>* sender,
214 mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) {
rockot0e4de5f2016-07-22 21:18:07215 mojo::InterfaceId sender_id, receiver_id;
216 if (set_interface_id_namespace_bit_) {
217 sender_id = 1 | mojo::kInterfaceIdNamespaceMask;
218 receiver_id = 1;
219 } else {
220 sender_id = 1;
221 receiver_id = 1 | mojo::kInterfaceIdNamespaceMask;
222 }
223
224 {
225 base::AutoLock locker(lock_);
226 Endpoint* sender_endpoint = new Endpoint(this, sender_id);
227 Endpoint* receiver_endpoint = new Endpoint(this, receiver_id);
228 endpoints_.insert({ sender_id, sender_endpoint });
229 endpoints_.insert({ receiver_id, receiver_endpoint });
yzshen0a5971312017-02-02 05:13:47230 sender_endpoint->set_handle_created();
231 receiver_endpoint->set_handle_created();
rockot0e4de5f2016-07-22 21:18:07232 }
233
234 mojo::ScopedInterfaceEndpointHandle sender_handle =
yzshen2859a2ac2017-02-14 22:24:25235 CreateScopedInterfaceEndpointHandle(sender_id);
rockot0e4de5f2016-07-22 21:18:07236 mojo::ScopedInterfaceEndpointHandle receiver_handle =
yzshen2859a2ac2017-02-14 22:24:25237 CreateScopedInterfaceEndpointHandle(receiver_id);
rockot0e4de5f2016-07-22 21:18:07238
Julie Jeongeun Kim903b34b2019-09-25 11:11:54239 sender->Bind(mojo::PendingAssociatedRemote<mojom::Channel>(
240 std::move(sender_handle), 0));
241 *receiver = mojo::PendingAssociatedReceiver<mojom::Channel>(
242 std::move(receiver_handle));
rockot0e4de5f2016-07-22 21:18:07243 }
rockot02b8e182016-07-13 20:08:30244
245 void ShutDown() {
246 DCHECK(thread_checker_.CalledOnValidThread());
Ken Rockot3e7284bb2018-02-06 16:11:16247 shut_down_ = true;
rockot0e4de5f2016-07-22 21:18:07248 connector_->CloseMessagePipe();
rockot02b8e182016-07-13 20:08:30249 OnPipeError();
rockot0e4de5f2016-07-22 21:18:07250 connector_.reset();
Ken Rockot2b6de982018-03-20 22:28:13251
252 base::AutoLock lock(outgoing_messages_lock_);
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20253 if (quota_checker_ && outgoing_messages_.size())
254 quota_checker_->AfterMessagesDequeued(outgoing_messages_.size());
255
Ken Rockot3e7284bb2018-02-06 16:11:16256 outgoing_messages_.clear();
rockot02b8e182016-07-13 20:08:30257 }
258
259 // mojo::AssociatedGroupController:
yzshen2859a2ac2017-02-14 22:24:25260 mojo::InterfaceId AssociateInterface(
261 mojo::ScopedInterfaceEndpointHandle handle_to_send) override {
262 if (!handle_to_send.pending_association())
263 return mojo::kInvalidInterfaceId;
264
rockot02b8e182016-07-13 20:08:30265 uint32_t id = 0;
yzshen2859a2ac2017-02-14 22:24:25266 {
267 base::AutoLock locker(lock_);
268 do {
269 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask)
270 next_interface_id_ = 2;
271 id = next_interface_id_++;
272 if (set_interface_id_namespace_bit_)
273 id |= mojo::kInterfaceIdNamespaceMask;
Jan Wilken Dörrie73c901e2019-06-12 09:02:32274 } while (base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30275
yzshen2859a2ac2017-02-14 22:24:25276 Endpoint* endpoint = new Endpoint(this, id);
277 if (encountered_error_)
278 endpoint->set_peer_closed();
279 endpoint->set_handle_created();
280 endpoints_.insert({id, endpoint});
281 }
rockot02b8e182016-07-13 20:08:30282
yzshen2859a2ac2017-02-14 22:24:25283 if (!NotifyAssociation(&handle_to_send, id)) {
284 // The peer handle of |handle_to_send|, which is supposed to join this
285 // associated group, has been closed.
286 {
287 base::AutoLock locker(lock_);
288 Endpoint* endpoint = FindEndpoint(id);
289 if (endpoint)
290 MarkClosedAndMaybeRemove(endpoint);
291 }
292
293 control_message_proxy_.NotifyPeerEndpointClosed(
294 id, handle_to_send.disconnect_reason());
295 }
296 return id;
rockot02b8e182016-07-13 20:08:30297 }
298
299 mojo::ScopedInterfaceEndpointHandle CreateLocalEndpointHandle(
300 mojo::InterfaceId id) override {
301 if (!mojo::IsValidInterfaceId(id))
302 return mojo::ScopedInterfaceEndpointHandle();
303
Yuzhu Shen9f87fb02017-08-11 17:07:06304 // Unless it is the master ID, |id| is from the remote side and therefore
305 // its namespace bit is supposed to be different than the value that this
306 // router would use.
307 if (!mojo::IsMasterInterfaceId(id) &&
308 set_interface_id_namespace_bit_ ==
309 mojo::HasInterfaceIdNamespaceBitSet(id)) {
310 return mojo::ScopedInterfaceEndpointHandle();
311 }
312
rockot02b8e182016-07-13 20:08:30313 base::AutoLock locker(lock_);
314 bool inserted = false;
315 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
yzshenea784ea2017-01-31 21:20:20316 if (inserted) {
317 DCHECK(!endpoint->handle_created());
318 if (encountered_error_)
319 endpoint->set_peer_closed();
320 } else {
321 if (endpoint->handle_created())
322 return mojo::ScopedInterfaceEndpointHandle();
323 }
rockot02b8e182016-07-13 20:08:30324
yzshenea784ea2017-01-31 21:20:20325 endpoint->set_handle_created();
yzshen2859a2ac2017-02-14 22:24:25326 return CreateScopedInterfaceEndpointHandle(id);
rockot02b8e182016-07-13 20:08:30327 }
328
yzshen8be41d3a2017-01-23 20:40:37329 void CloseEndpointHandle(
330 mojo::InterfaceId id,
yzshen8be41d3a2017-01-23 20:40:37331 const base::Optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30332 if (!mojo::IsValidInterfaceId(id))
333 return;
yzshen2859a2ac2017-02-14 22:24:25334 {
335 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32336 DCHECK(base::Contains(endpoints_, id));
yzshen2859a2ac2017-02-14 22:24:25337 Endpoint* endpoint = endpoints_[id].get();
338 DCHECK(!endpoint->client());
339 DCHECK(!endpoint->closed());
340 MarkClosedAndMaybeRemove(endpoint);
rockot02b8e182016-07-13 20:08:30341 }
342
yzshen8be41d3a2017-01-23 20:40:37343 if (!mojo::IsMasterInterfaceId(id) || reason)
344 control_message_proxy_.NotifyPeerEndpointClosed(id, reason);
rockot02b8e182016-07-13 20:08:30345 }
346
347 mojo::InterfaceEndpointController* AttachEndpointClient(
348 const mojo::ScopedInterfaceEndpointHandle& handle,
349 mojo::InterfaceEndpointClient* client,
Sam McNallyde5ae672017-06-19 23:34:45350 scoped_refptr<base::SequencedTaskRunner> runner) override {
rockot02b8e182016-07-13 20:08:30351 const mojo::InterfaceId id = handle.id();
352
353 DCHECK(mojo::IsValidInterfaceId(id));
354 DCHECK(client);
355
356 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32357 DCHECK(base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30358
359 Endpoint* endpoint = endpoints_[id].get();
360 endpoint->AttachClient(client, std::move(runner));
361
362 if (endpoint->peer_closed())
363 NotifyEndpointOfError(endpoint, true /* force_async */);
364
365 return endpoint;
366 }
367
368 void DetachEndpointClient(
369 const mojo::ScopedInterfaceEndpointHandle& handle) override {
370 const mojo::InterfaceId id = handle.id();
371
372 DCHECK(mojo::IsValidInterfaceId(id));
373
374 base::AutoLock locker(lock_);
Jan Wilken Dörrie73c901e2019-06-12 09:02:32375 DCHECK(base::Contains(endpoints_, id));
rockot02b8e182016-07-13 20:08:30376
377 Endpoint* endpoint = endpoints_[id].get();
378 endpoint->DetachClient();
379 }
380
381 void RaiseError() override {
Ken Rockot138153b2018-07-13 23:31:57382 // We ignore errors on channel endpoints, leaving the pipe open. There are
383 // good reasons for this:
384 //
385 // * We should never close a channel endpoint in either process as long as
386 // the child process is still alive. The child's endpoint should only be
387 // closed implicitly by process death, and the browser's endpoint should
388 // only be closed after the child process is confirmed to be dead. Crash
389 // reporting logic in Chrome relies on this behavior in order to do the
390 // right thing.
391 //
392 // * There are two interesting conditions under which RaiseError() can be
393 // implicitly reached: an incoming message fails validation, or the
394 // local endpoint drops a response callback without calling it.
395 //
396 // * In the validation case, we also report the message as bad, and this
397 // will imminently trigger the common bad-IPC path in the browser,
398 // causing the browser to kill the offending renderer.
399 //
400 // * In the dropped response callback case, the net result of ignoring the
401 // issue is generally innocuous. While indicative of programmer error,
402 // it's not a severe failure and is already covered by separate DCHECKs.
403 //
404 // See https://crbug.com/861607 for additional discussion.
rockot02b8e182016-07-13 20:08:30405 }
406
Ken Rockot474df0142017-07-12 13:28:56407 bool PrefersSerializedMessages() override { return true; }
408
rockot02b8e182016-07-13 20:08:30409 private:
410 class Endpoint;
rockot0e4de5f2016-07-22 21:18:07411 class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30412 friend class Endpoint;
rockot0e4de5f2016-07-22 21:18:07413 friend class ControlMessageProxyThunk;
rockot02b8e182016-07-13 20:08:30414
yzshen0a5971312017-02-02 05:13:47415 // MessageWrapper objects are always destroyed under the controller's lock. On
416 // destruction, if the message it wrappers contains
417 // ScopedInterfaceEndpointHandles (which cannot be destructed under the
418 // controller's lock), the wrapper unlocks to clean them up.
419 class MessageWrapper {
yzshenea784ea2017-01-31 21:20:20420 public:
yzshen0a5971312017-02-02 05:13:47421 MessageWrapper() = default;
yzshenea784ea2017-01-31 21:20:20422
yzshen0a5971312017-02-02 05:13:47423 MessageWrapper(ChannelAssociatedGroupController* controller,
424 mojo::Message message)
425 : controller_(controller), value_(std::move(message)) {}
yzshenea784ea2017-01-31 21:20:20426
yzshen0a5971312017-02-02 05:13:47427 MessageWrapper(MessageWrapper&& other)
yzshenea784ea2017-01-31 21:20:20428 : controller_(other.controller_), value_(std::move(other.value_)) {}
429
yzshen0a5971312017-02-02 05:13:47430 ~MessageWrapper() {
431 if (value_.associated_endpoint_handles()->empty())
yzshenea784ea2017-01-31 21:20:20432 return;
433
434 controller_->lock_.AssertAcquired();
yzshen0a5971312017-02-02 05:13:47435 {
yzshenea784ea2017-01-31 21:20:20436 base::AutoUnlock unlocker(controller_->lock_);
yzshen0a5971312017-02-02 05:13:47437 value_.mutable_associated_endpoint_handles()->clear();
yzshenea784ea2017-01-31 21:20:20438 }
439 }
440
yzshen0a5971312017-02-02 05:13:47441 MessageWrapper& operator=(MessageWrapper&& other) {
yzshenea784ea2017-01-31 21:20:20442 controller_ = other.controller_;
443 value_ = std::move(other.value_);
444 return *this;
445 }
446
yzshen0a5971312017-02-02 05:13:47447 mojo::Message& value() { return value_; }
yzshenea784ea2017-01-31 21:20:20448
449 private:
450 ChannelAssociatedGroupController* controller_ = nullptr;
yzshenea784ea2017-01-31 21:20:20451 mojo::Message value_;
452
yzshen0a5971312017-02-02 05:13:47453 DISALLOW_COPY_AND_ASSIGN(MessageWrapper);
yzshenea784ea2017-01-31 21:20:20454 };
455
rockot02b8e182016-07-13 20:08:30456 class Endpoint : public base::RefCountedThreadSafe<Endpoint>,
457 public mojo::InterfaceEndpointController {
458 public:
459 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id)
460 : controller_(controller), id_(id) {}
461
462 mojo::InterfaceId id() const { return id_; }
463
464 bool closed() const {
465 controller_->lock_.AssertAcquired();
466 return closed_;
467 }
468
469 void set_closed() {
470 controller_->lock_.AssertAcquired();
471 closed_ = true;
472 }
473
474 bool peer_closed() const {
475 controller_->lock_.AssertAcquired();
476 return peer_closed_;
477 }
478
479 void set_peer_closed() {
480 controller_->lock_.AssertAcquired();
481 peer_closed_ = true;
482 }
483
yzshenea784ea2017-01-31 21:20:20484 bool handle_created() const {
485 controller_->lock_.AssertAcquired();
486 return handle_created_;
487 }
488
489 void set_handle_created() {
490 controller_->lock_.AssertAcquired();
491 handle_created_ = true;
492 }
493
yzshen8be41d3a2017-01-23 20:40:37494 const base::Optional<mojo::DisconnectReason>& disconnect_reason() const {
495 return disconnect_reason_;
496 }
497
498 void set_disconnect_reason(
499 const base::Optional<mojo::DisconnectReason>& disconnect_reason) {
500 disconnect_reason_ = disconnect_reason;
501 }
502
Sam McNallyde5ae672017-06-19 23:34:45503 base::SequencedTaskRunner* task_runner() const {
rockot02b8e182016-07-13 20:08:30504 return task_runner_.get();
505 }
506
507 mojo::InterfaceEndpointClient* client() const {
508 controller_->lock_.AssertAcquired();
509 return client_;
510 }
511
512 void AttachClient(mojo::InterfaceEndpointClient* client,
Sam McNallyde5ae672017-06-19 23:34:45513 scoped_refptr<base::SequencedTaskRunner> runner) {
rockot02b8e182016-07-13 20:08:30514 controller_->lock_.AssertAcquired();
515 DCHECK(!client_);
516 DCHECK(!closed_);
peary28cd3bd22017-06-29 02:15:28517 DCHECK(runner->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30518
519 task_runner_ = std::move(runner);
520 client_ = client;
521 }
522
523 void DetachClient() {
524 controller_->lock_.AssertAcquired();
525 DCHECK(client_);
peary28cd3bd22017-06-29 02:15:28526 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30527 DCHECK(!closed_);
528
529 task_runner_ = nullptr;
530 client_ = nullptr;
rockot9abe09b2016-08-02 20:57:34531 sync_watcher_.reset();
532 }
533
yzshen0a5971312017-02-02 05:13:47534 uint32_t EnqueueSyncMessage(MessageWrapper message) {
rockot9abe09b2016-08-02 20:57:34535 controller_->lock_.AssertAcquired();
536 uint32_t id = GenerateSyncMessageId();
537 sync_messages_.emplace(id, std::move(message));
538 SignalSyncMessageEvent();
539 return id;
540 }
541
542 void SignalSyncMessageEvent() {
543 controller_->lock_.AssertAcquired();
yzshene25b5d52017-02-28 21:56:31544
Ken Rockotaa20dcc2018-03-28 03:06:51545 if (sync_watcher_)
546 sync_watcher_->SignalEvent();
rockot9abe09b2016-08-02 20:57:34547 }
548
yzshen0a5971312017-02-02 05:13:47549 MessageWrapper PopSyncMessage(uint32_t id) {
rockot9abe09b2016-08-02 20:57:34550 controller_->lock_.AssertAcquired();
551 if (sync_messages_.empty() || sync_messages_.front().first != id)
yzshen0a5971312017-02-02 05:13:47552 return MessageWrapper();
553 MessageWrapper message = std::move(sync_messages_.front().second);
rockot9abe09b2016-08-02 20:57:34554 sync_messages_.pop();
555 return message;
rockot02b8e182016-07-13 20:08:30556 }
557
558 // mojo::InterfaceEndpointController:
559 bool SendMessage(mojo::Message* message) override {
peary28cd3bd22017-06-29 02:15:28560 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30561 message->set_interface_id(id_);
562 return controller_->SendMessage(message);
563 }
564
565 void AllowWokenUpBySyncWatchOnSameThread() override {
peary28cd3bd22017-06-29 02:15:28566 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30567
rockot9abe09b2016-08-02 20:57:34568 EnsureSyncWatcherExists();
Ken Rockotaa20dcc2018-03-28 03:06:51569 sync_watcher_->AllowWokenUpBySyncWatchOnSameSequence();
rockot02b8e182016-07-13 20:08:30570 }
571
572 bool SyncWatch(const bool* should_stop) override {
peary28cd3bd22017-06-29 02:15:28573 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot02b8e182016-07-13 20:08:30574
575 // It's not legal to make sync calls from the master endpoint's thread,
576 // and in fact they must only happen from the proxy task runner.
rockot7604e7b72016-07-28 17:37:39577 DCHECK(!controller_->task_runner_->BelongsToCurrentThread());
rockot02b8e182016-07-13 20:08:30578 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread());
579
rockot9abe09b2016-08-02 20:57:34580 EnsureSyncWatcherExists();
581 return sync_watcher_->SyncWatch(should_stop);
rockot02b8e182016-07-13 20:08:30582 }
583
584 private:
585 friend class base::RefCountedThreadSafe<Endpoint>;
586
rockot9abe09b2016-08-02 20:57:34587 ~Endpoint() override {
588 controller_->lock_.AssertAcquired();
589 DCHECK(!client_);
590 DCHECK(closed_);
591 DCHECK(peer_closed_);
592 DCHECK(!sync_watcher_);
593 }
594
rockotb62e2e32017-03-24 18:36:44595 void OnSyncMessageEventReady() {
peary28cd3bd22017-06-29 02:15:28596 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34597
598 scoped_refptr<Endpoint> keepalive(this);
599 scoped_refptr<AssociatedGroupController> controller_keepalive(
600 controller_);
Ken Rockotaa20dcc2018-03-28 03:06:51601 base::AutoLock locker(controller_->lock_);
602 bool more_to_process = false;
603 if (!sync_messages_.empty()) {
604 MessageWrapper message_wrapper =
605 std::move(sync_messages_.front().second);
606 sync_messages_.pop();
rockot9abe09b2016-08-02 20:57:34607
Ken Rockotaa20dcc2018-03-28 03:06:51608 bool dispatch_succeeded;
609 mojo::InterfaceEndpointClient* client = client_;
610 {
611 base::AutoUnlock unlocker(controller_->lock_);
612 dispatch_succeeded =
613 client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34614 }
615
Ken Rockotaa20dcc2018-03-28 03:06:51616 if (!sync_messages_.empty())
617 more_to_process = true;
rockot9abe09b2016-08-02 20:57:34618
Ken Rockotaa20dcc2018-03-28 03:06:51619 if (!dispatch_succeeded)
620 controller_->RaiseError();
rockot9abe09b2016-08-02 20:57:34621 }
622
Ken Rockotaa20dcc2018-03-28 03:06:51623 if (!more_to_process)
624 sync_watcher_->ResetEvent();
625
626 // If there are no queued sync messages and the peer has closed, there
627 // there won't be incoming sync messages in the future. If any
628 // SyncWatch() calls are on the stack for this endpoint, resetting the
629 // watcher will allow them to exit as the stack undwinds.
630 if (!more_to_process && peer_closed_)
rockot9abe09b2016-08-02 20:57:34631 sync_watcher_.reset();
rockot9abe09b2016-08-02 20:57:34632 }
633
634 void EnsureSyncWatcherExists() {
peary28cd3bd22017-06-29 02:15:28635 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34636 if (sync_watcher_)
637 return;
638
Ken Rockotaa20dcc2018-03-28 03:06:51639 base::AutoLock locker(controller_->lock_);
640 sync_watcher_ = std::make_unique<mojo::SequenceLocalSyncEventWatcher>(
641 base::BindRepeating(&Endpoint::OnSyncMessageEventReady,
642 base::Unretained(this)));
643 if (peer_closed_ || !sync_messages_.empty())
644 SignalSyncMessageEvent();
rockot9abe09b2016-08-02 20:57:34645 }
646
647 uint32_t GenerateSyncMessageId() {
648 // Overflow is fine.
649 uint32_t id = next_sync_message_id_++;
650 DCHECK(sync_messages_.empty() || sync_messages_.front().first != id);
651 return id;
652 }
rockot02b8e182016-07-13 20:08:30653
654 ChannelAssociatedGroupController* const controller_;
655 const mojo::InterfaceId id_;
656
657 bool closed_ = false;
658 bool peer_closed_ = false;
yzshenea784ea2017-01-31 21:20:20659 bool handle_created_ = false;
yzshen8be41d3a2017-01-23 20:40:37660 base::Optional<mojo::DisconnectReason> disconnect_reason_;
rockot02b8e182016-07-13 20:08:30661 mojo::InterfaceEndpointClient* client_ = nullptr;
Sam McNallyde5ae672017-06-19 23:34:45662 scoped_refptr<base::SequencedTaskRunner> task_runner_;
Ken Rockotaa20dcc2018-03-28 03:06:51663 std::unique_ptr<mojo::SequenceLocalSyncEventWatcher> sync_watcher_;
Brett Wilsona62d9c02017-09-20 20:53:20664 base::queue<std::pair<uint32_t, MessageWrapper>> sync_messages_;
rockot9abe09b2016-08-02 20:57:34665 uint32_t next_sync_message_id_ = 0;
rockot02b8e182016-07-13 20:08:30666
667 DISALLOW_COPY_AND_ASSIGN(Endpoint);
668 };
669
rockot0e4de5f2016-07-22 21:18:07670 class ControlMessageProxyThunk : public MessageReceiver {
671 public:
672 explicit ControlMessageProxyThunk(
673 ChannelAssociatedGroupController* controller)
674 : controller_(controller) {}
675
676 private:
677 // MessageReceiver:
678 bool Accept(mojo::Message* message) override {
679 return controller_->SendMessage(message);
680 }
681
682 ChannelAssociatedGroupController* controller_;
683
684 DISALLOW_COPY_AND_ASSIGN(ControlMessageProxyThunk);
685 };
686
rockot02b8e182016-07-13 20:08:30687 ~ChannelAssociatedGroupController() override {
rockotb01ef6a2016-07-27 03:24:32688 DCHECK(!connector_);
689
rockot02b8e182016-07-13 20:08:30690 base::AutoLock locker(lock_);
rockot02b8e182016-07-13 20:08:30691 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
692 Endpoint* endpoint = iter->second.get();
693 ++iter;
694
yzshene003d592017-01-24 21:42:17695 if (!endpoint->closed()) {
696 // This happens when a NotifyPeerEndpointClosed message been received,
yzshen2859a2ac2017-02-14 22:24:25697 // but the interface ID hasn't been used to create local endpoint
698 // handle.
yzshene003d592017-01-24 21:42:17699 DCHECK(!endpoint->client());
700 DCHECK(endpoint->peer_closed());
701 MarkClosedAndMaybeRemove(endpoint);
702 } else {
703 MarkPeerClosedAndMaybeRemove(endpoint);
704 }
rockot02b8e182016-07-13 20:08:30705 }
706
707 DCHECK(endpoints_.empty());
Ken Rockot2b6de982018-03-20 22:28:13708
709 GetMemoryDumpProvider().RemoveController(this);
rockot02b8e182016-07-13 20:08:30710 }
711
712 bool SendMessage(mojo::Message* message) {
Siddhartha S03484422019-04-23 20:30:00713 DCHECK(message->heap_profiler_tag());
rockot7604e7b72016-07-28 17:37:39714 if (task_runner_->BelongsToCurrentThread()) {
rockot02b8e182016-07-13 20:08:30715 DCHECK(thread_checker_.CalledOnValidThread());
rockot10188752016-09-08 18:24:56716 if (!connector_ || paused_) {
Ken Rockot37ddd8152018-02-22 18:18:46717 if (!shut_down_) {
Ken Rockot2b6de982018-03-20 22:28:13718 base::AutoLock lock(outgoing_messages_lock_);
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:20719 if (quota_checker_)
720 quota_checker_->BeforeMessagesEnqueued(1);
Ken Rockot3e7284bb2018-02-06 16:11:16721 outgoing_messages_.emplace_back(std::move(*message));
Ken Rockot37ddd8152018-02-22 18:18:46722 }
rockot0e4de5f2016-07-22 21:18:07723 return true;
724 }
725 return connector_->Accept(message);
rockot02b8e182016-07-13 20:08:30726 } else {
Ken Rockotfb81dc02018-05-15 21:59:26727 // Do a message size check here so we don't lose valuable stack
728 // information to the task scheduler.
729 CHECK_LE(message->data_num_bytes(), Channel::kMaximumMessageSize);
730
rockotbecd3f742016-11-08 20:47:00731 // We always post tasks to the master endpoint thread when called from
732 // other threads in order to simulate IPC::ChannelProxy::Send behavior.
rockot02b8e182016-07-13 20:08:30733 task_runner_->PostTask(
734 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09735 base::BindOnce(
rockot02b8e182016-07-13 20:08:30736 &ChannelAssociatedGroupController::SendMessageOnMasterThread,
Jan Wilken Dörrie1494205b2020-03-26 09:32:53737 this, std::move(*message)));
rockot02b8e182016-07-13 20:08:30738 return true;
739 }
740 }
741
rockotc4cc691e2016-08-19 18:48:57742 void SendMessageOnMasterThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30743 DCHECK(thread_checker_.CalledOnValidThread());
rockotc4cc691e2016-08-19 18:48:57744 if (!SendMessage(&message))
rockot02b8e182016-07-13 20:08:30745 RaiseError();
746 }
747
748 void OnPipeError() {
749 DCHECK(thread_checker_.CalledOnValidThread());
750
751 // We keep |this| alive here because it's possible for the notifications
752 // below to release all other references.
753 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
754
755 base::AutoLock locker(lock_);
756 encountered_error_ = true;
757
758 std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
759 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
760 Endpoint* endpoint = iter->second.get();
761 ++iter;
762
763 if (endpoint->client())
764 endpoints_to_notify.push_back(endpoint);
765
766 MarkPeerClosedAndMaybeRemove(endpoint);
767 }
768
769 for (auto& endpoint : endpoints_to_notify) {
rockot0e4de5f2016-07-22 21:18:07770 // Because a notification may in turn detach any endpoint, we have to
rockot02b8e182016-07-13 20:08:30771 // check each client again here.
772 if (endpoint->client())
773 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
774 }
775 }
776
777 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
778 lock_.AssertAcquired();
779 DCHECK(endpoint->task_runner() && endpoint->client());
peary28cd3bd22017-06-29 02:15:28780 if (endpoint->task_runner()->RunsTasksInCurrentSequence() && !force_async) {
rockot02b8e182016-07-13 20:08:30781 mojo::InterfaceEndpointClient* client = endpoint->client();
yzshen8be41d3a2017-01-23 20:40:37782 base::Optional<mojo::DisconnectReason> reason(
783 endpoint->disconnect_reason());
rockot02b8e182016-07-13 20:08:30784
785 base::AutoUnlock unlocker(lock_);
yzshen8be41d3a2017-01-23 20:40:37786 client->NotifyError(reason);
rockot02b8e182016-07-13 20:08:30787 } else {
788 endpoint->task_runner()->PostTask(
789 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09790 base::BindOnce(&ChannelAssociatedGroupController::
791 NotifyEndpointOfErrorOnEndpointThread,
792 this, endpoint->id(), base::Unretained(endpoint)));
rockot02b8e182016-07-13 20:08:30793 }
794 }
795
rockot9abe09b2016-08-02 20:57:34796 void NotifyEndpointOfErrorOnEndpointThread(mojo::InterfaceId id,
797 Endpoint* endpoint) {
rockot02b8e182016-07-13 20:08:30798 base::AutoLock locker(lock_);
rockot9abe09b2016-08-02 20:57:34799 auto iter = endpoints_.find(id);
800 if (iter == endpoints_.end() || iter->second.get() != endpoint)
801 return;
rockot02b8e182016-07-13 20:08:30802 if (!endpoint->client())
803 return;
rockot9abe09b2016-08-02 20:57:34804
peary28cd3bd22017-06-29 02:15:28805 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
rockot9abe09b2016-08-02 20:57:34806 NotifyEndpointOfError(endpoint, false /* force_async */);
rockot02b8e182016-07-13 20:08:30807 }
808
809 void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
810 lock_.AssertAcquired();
811 endpoint->set_closed();
812 if (endpoint->closed() && endpoint->peer_closed())
813 endpoints_.erase(endpoint->id());
814 }
815
816 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
817 lock_.AssertAcquired();
818 endpoint->set_peer_closed();
rockot9abe09b2016-08-02 20:57:34819 endpoint->SignalSyncMessageEvent();
rockot02b8e182016-07-13 20:08:30820 if (endpoint->closed() && endpoint->peer_closed())
821 endpoints_.erase(endpoint->id());
822 }
823
824 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {
825 lock_.AssertAcquired();
826 DCHECK(!inserted || !*inserted);
827
yzshen0a5971312017-02-02 05:13:47828 Endpoint* endpoint = FindEndpoint(id);
829 if (!endpoint) {
830 endpoint = new Endpoint(this, id);
831 endpoints_.insert({id, endpoint});
832 if (inserted)
833 *inserted = true;
834 }
rockot02b8e182016-07-13 20:08:30835 return endpoint;
836 }
837
yzshen0a5971312017-02-02 05:13:47838 Endpoint* FindEndpoint(mojo::InterfaceId id) {
839 lock_.AssertAcquired();
840 auto iter = endpoints_.find(id);
841 return iter != endpoints_.end() ? iter->second.get() : nullptr;
842 }
843
rockot02b8e182016-07-13 20:08:30844 // mojo::MessageReceiver:
845 bool Accept(mojo::Message* message) override {
846 DCHECK(thread_checker_.CalledOnValidThread());
847
yzshen0a5971312017-02-02 05:13:47848 if (!message->DeserializeAssociatedEndpointHandles(this))
849 return false;
850
851 if (mojo::PipeControlMessageHandler::IsPipeControlMessage(message))
852 return control_message_handler_.Accept(message);
rockot02b8e182016-07-13 20:08:30853
854 mojo::InterfaceId id = message->interface_id();
855 DCHECK(mojo::IsValidInterfaceId(id));
856
Ken Rockot4fede4552019-05-09 01:16:41857 base::ReleasableAutoLock locker(&lock_);
yzshen0a5971312017-02-02 05:13:47858 Endpoint* endpoint = FindEndpoint(id);
859 if (!endpoint)
860 return true;
861
862 mojo::InterfaceEndpointClient* client = endpoint->client();
peary28cd3bd22017-06-29 02:15:28863 if (!client || !endpoint->task_runner()->RunsTasksInCurrentSequence()) {
rockot02b8e182016-07-13 20:08:30864 // No client has been bound yet or the client runs tasks on another
865 // thread. We assume the other thread must always be the one on which
866 // |proxy_task_runner_| runs tasks, since that's the only valid scenario.
867 //
868 // If the client is not yet bound, it must be bound by the time this task
869 // runs or else it's programmer error.
870 DCHECK(proxy_task_runner_);
rockot9abe09b2016-08-02 20:57:34871
rockotc4cc691e2016-08-19 18:48:57872 if (message->has_flag(mojo::Message::kFlagIsSync)) {
yzshen0a5971312017-02-02 05:13:47873 MessageWrapper message_wrapper(this, std::move(*message));
rockot9abe09b2016-08-02 20:57:34874 // Sync messages may need to be handled by the endpoint if it's blocking
875 // on a sync reply. We pass ownership of the message to the endpoint's
876 // sync message queue. If the endpoint was blocking, it will dequeue the
877 // message and dispatch it. Otherwise the posted |AcceptSyncMessage()|
878 // call will dequeue the message and dispatch it.
yzshenea784ea2017-01-31 21:20:20879 uint32_t message_id =
880 endpoint->EnqueueSyncMessage(std::move(message_wrapper));
rockot9abe09b2016-08-02 20:57:34881 proxy_task_runner_->PostTask(
882 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09883 base::BindOnce(&ChannelAssociatedGroupController::AcceptSyncMessage,
884 this, id, message_id));
rockot9abe09b2016-08-02 20:57:34885 return true;
886 }
887
Ken Rockot4fede4552019-05-09 01:16:41888 // If |proxy_task_runner_| has been torn down already, this PostTask will
889 // fail and destroy |message|. That operation may need to in turn destroy
890 // in-transit associated endpoints and thus acquire |lock_|. We no longer
891 // need the lock to be held now since |proxy_task_runner_| is safe to
892 // access unguarded.
893 locker.Release();
rockot02b8e182016-07-13 20:08:30894 proxy_task_runner_->PostTask(
895 FROM_HERE,
kylecharf448cc92019-02-19 20:28:09896 base::BindOnce(&ChannelAssociatedGroupController::AcceptOnProxyThread,
Ken Rockot4fede4552019-05-09 01:16:41897 this, std::move(*message)));
rockot02b8e182016-07-13 20:08:30898 return true;
899 }
900
901 // We do not expect to receive sync responses on the master endpoint thread.
902 // If it's happening, it's a bug.
rockot9abe09b2016-08-02 20:57:34903 DCHECK(!message->has_flag(mojo::Message::kFlagIsSync) ||
904 !message->has_flag(mojo::Message::kFlagIsResponse));
rockot02b8e182016-07-13 20:08:30905
Ken Rockot4fede4552019-05-09 01:16:41906 locker.Release();
yzshen0a5971312017-02-02 05:13:47907 return client->HandleIncomingMessage(message);
rockot02b8e182016-07-13 20:08:30908 }
909
rockotc4cc691e2016-08-19 18:48:57910 void AcceptOnProxyThread(mojo::Message message) {
rockot02b8e182016-07-13 20:08:30911 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
912
rockotc4cc691e2016-08-19 18:48:57913 mojo::InterfaceId id = message.interface_id();
rockot8d890f62016-07-14 16:37:14914 DCHECK(mojo::IsValidInterfaceId(id) && !mojo::IsMasterInterfaceId(id));
915
916 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47917 Endpoint* endpoint = FindEndpoint(id);
rockot8d890f62016-07-14 16:37:14918 if (!endpoint)
919 return;
920
921 mojo::InterfaceEndpointClient* client = endpoint->client();
922 if (!client)
923 return;
924
peary28cd3bd22017-06-29 02:15:28925 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
rockot8d890f62016-07-14 16:37:14926
rockot9abe09b2016-08-02 20:57:34927 // Sync messages should never make their way to this method.
yzshen0a5971312017-02-02 05:13:47928 DCHECK(!message.has_flag(mojo::Message::kFlagIsSync));
rockot8d890f62016-07-14 16:37:14929
930 bool result = false;
931 {
932 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47933 result = client->HandleIncomingMessage(&message);
rockot8d890f62016-07-14 16:37:14934 }
935
936 if (!result)
937 RaiseError();
938 }
939
rockot9abe09b2016-08-02 20:57:34940 void AcceptSyncMessage(mojo::InterfaceId interface_id, uint32_t message_id) {
941 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
942
943 base::AutoLock locker(lock_);
yzshen0a5971312017-02-02 05:13:47944 Endpoint* endpoint = FindEndpoint(interface_id);
rockot9abe09b2016-08-02 20:57:34945 if (!endpoint)
946 return;
947
csharrison1af8d6ab2017-04-21 17:47:23948 // Careful, if the endpoint is detached its members are cleared. Check for
949 // that before dereferencing.
950 mojo::InterfaceEndpointClient* client = endpoint->client();
951 if (!client)
952 return;
953
peary28cd3bd22017-06-29 02:15:28954 DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence());
yzshen0a5971312017-02-02 05:13:47955 MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id);
rockot9abe09b2016-08-02 20:57:34956
957 // The message must have already been dequeued by the endpoint waking up
958 // from a sync wait. Nothing to do.
yzshenea784ea2017-01-31 21:20:20959 if (message_wrapper.value().IsNull())
rockot9abe09b2016-08-02 20:57:34960 return;
961
rockot9abe09b2016-08-02 20:57:34962 bool result = false;
963 {
964 base::AutoUnlock unlocker(lock_);
yzshen0a5971312017-02-02 05:13:47965 result = client->HandleIncomingMessage(&message_wrapper.value());
rockot9abe09b2016-08-02 20:57:34966 }
967
968 if (!result)
969 RaiseError();
970 }
971
rockot02b8e182016-07-13 20:08:30972 // mojo::PipeControlMessageHandlerDelegate:
yzshen8be41d3a2017-01-23 20:40:37973 bool OnPeerAssociatedEndpointClosed(
974 mojo::InterfaceId id,
975 const base::Optional<mojo::DisconnectReason>& reason) override {
rockot02b8e182016-07-13 20:08:30976 DCHECK(thread_checker_.CalledOnValidThread());
977
rockot0e4de5f2016-07-22 21:18:07978 scoped_refptr<ChannelAssociatedGroupController> keepalive(this);
rockot02b8e182016-07-13 20:08:30979 base::AutoLock locker(lock_);
980 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr);
yzshen8be41d3a2017-01-23 20:40:37981 if (reason)
982 endpoint->set_disconnect_reason(reason);
rockot02b8e182016-07-13 20:08:30983 if (!endpoint->peer_closed()) {
984 if (endpoint->client())
985 NotifyEndpointOfError(endpoint.get(), false /* force_async */);
986 MarkPeerClosedAndMaybeRemove(endpoint.get());
987 }
988
989 return true;
990 }
991
Ken Rockoteb2366a2020-01-13 21:13:46992 bool WaitForFlushToComplete(
993 mojo::ScopedMessagePipeHandle flush_pipe) override {
994 // We don't support async flushing on the IPC Channel pipe.
995 return false;
996 }
997
rockot02b8e182016-07-13 20:08:30998 // Checked in places which must be run on the master endpoint's thread.
999 base::ThreadChecker thread_checker_;
1000
1001 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
rockot0e4de5f2016-07-22 21:18:071002
Ken Rockot4fede4552019-05-09 01:16:411003 const scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201004 const scoped_refptr<mojo::internal::MessageQuotaChecker> quota_checker_;
rockot0e4de5f2016-07-22 21:18:071005 const bool set_interface_id_namespace_bit_;
rockot10188752016-09-08 18:24:561006 bool paused_ = false;
rockot0e4de5f2016-07-22 21:18:071007 std::unique_ptr<mojo::Connector> connector_;
Dave Tapuskaf2df43e2019-10-10 22:10:101008 mojo::MessageDispatcher dispatcher_;
rockot02b8e182016-07-13 20:08:301009 mojo::PipeControlMessageHandler control_message_handler_;
rockot0e4de5f2016-07-22 21:18:071010 ControlMessageProxyThunk control_message_proxy_thunk_;
rockot58909542016-11-10 20:05:451011
1012 // NOTE: It is unsafe to call into this object while holding |lock_|.
rockot0e4de5f2016-07-22 21:18:071013 mojo::PipeControlMessageProxy control_message_proxy_;
1014
Ken Rockot2b6de982018-03-20 22:28:131015 // Guards access to |outgoing_messages_| only. Used to support memory dumps
1016 // which may be triggered from any thread.
1017 base::Lock outgoing_messages_lock_;
1018
rockot0e4de5f2016-07-22 21:18:071019 // Outgoing messages that were sent before this controller was bound to a
1020 // real message pipe.
rockotc4cc691e2016-08-19 18:48:571021 std::vector<mojo::Message> outgoing_messages_;
rockot02b8e182016-07-13 20:08:301022
1023 // Guards the fields below for thread-safe access.
1024 base::Lock lock_;
1025
1026 bool encountered_error_ = false;
Ken Rockot3e7284bb2018-02-06 16:11:161027 bool shut_down_ = false;
rockot0e4de5f2016-07-22 21:18:071028
1029 // ID #1 is reserved for the mojom::Channel interface.
1030 uint32_t next_interface_id_ = 2;
1031
Yuzhu Shen7bcd8ebf2017-10-02 23:21:141032 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_;
rockot02b8e182016-07-13 20:08:301033
1034 DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController);
1035};
1036
Ken Rockot2b6de982018-03-20 22:28:131037bool ControllerMemoryDumpProvider::OnMemoryDump(
1038 const base::trace_event::MemoryDumpArgs& args,
1039 base::trace_event::ProcessMemoryDump* pmd) {
1040 base::AutoLock lock(lock_);
1041 for (auto* controller : controllers_) {
1042 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
1043 base::StringPrintf("mojo/queued_ipc_channel_message/0x%" PRIxPTR,
1044 reinterpret_cast<uintptr_t>(controller)));
1045 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
1046 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
1047 controller->GetQueuedMessageCount());
Siddhartha S03484422019-04-23 20:30:001048 MessageMemoryDumpInfo info;
1049 size_t count = 0;
1050 controller->GetTopQueuedMessageMemoryDumpInfo(&info, &count);
1051 dump->AddScalar("top_message_name", "id", info.id);
Siddharthad1cfec12018-09-17 21:42:151052 dump->AddScalar("top_message_count",
1053 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
Siddhartha S03484422019-04-23 20:30:001054 count);
1055
1056 if (info.profiler_tag) {
1057 // TODO(ssid): Memory dumps currently do not support adding string
1058 // arguments in background dumps. So, add this value as a trace event for
1059 // now.
ssidbc86cb72019-05-16 00:25:371060 TRACE_EVENT2(base::trace_event::MemoryDumpManager::kTraceCategory,
Siddhartha S03484422019-04-23 20:30:001061 "ControllerMemoryDumpProvider::OnMemoryDump",
ssidbc86cb72019-05-16 00:25:371062 "top_queued_message_tag", info.profiler_tag,
1063 "count", count);
Siddhartha S03484422019-04-23 20:30:001064 }
Ken Rockot2b6de982018-03-20 22:28:131065 }
1066
1067 return true;
1068}
1069
rockot0e4de5f2016-07-22 21:18:071070class MojoBootstrapImpl : public MojoBootstrap {
rockot02b8e182016-07-13 20:08:301071 public:
rockot0e4de5f2016-07-22 21:18:071072 MojoBootstrapImpl(
1073 mojo::ScopedMessagePipeHandle handle,
rockot0e4de5f2016-07-22 21:18:071074 const scoped_refptr<ChannelAssociatedGroupController> controller)
yzshen2859a2ac2017-02-14 22:24:251075 : controller_(controller),
1076 associated_group_(controller),
1077 handle_(std::move(handle)) {}
rockot02b8e182016-07-13 20:08:301078
rockot0e4de5f2016-07-22 21:18:071079 ~MojoBootstrapImpl() override {
1080 controller_->ShutDown();
rockot02b8e182016-07-13 20:08:301081 }
1082
1083 private:
Julie Jeongeun Kim903b34b2019-09-25 11:11:541084 void Connect(
1085 mojo::AssociatedRemote<mojom::Channel>* sender,
1086 mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) override {
rockot0e4de5f2016-07-22 21:18:071087 controller_->Bind(std::move(handle_));
rockota628d0b2017-02-09 08:40:151088 controller_->CreateChannelEndpoints(sender, receiver);
msramek5507fee2016-07-22 10:06:211089 }
1090
rockot10188752016-09-08 18:24:561091 void Pause() override {
1092 controller_->Pause();
1093 }
1094
1095 void Unpause() override {
1096 controller_->Unpause();
rockot401fb2c2016-09-06 18:35:571097 }
1098
1099 void Flush() override {
1100 controller_->FlushOutgoingMessages();
1101 }
1102
msramek5507fee2016-07-22 10:06:211103 mojo::AssociatedGroup* GetAssociatedGroup() override {
yzshen2859a2ac2017-02-14 22:24:251104 return &associated_group_;
msramek5507fee2016-07-22 10:06:211105 }
1106
rockot0e4de5f2016-07-22 21:18:071107 scoped_refptr<ChannelAssociatedGroupController> controller_;
yzshen2859a2ac2017-02-14 22:24:251108 mojo::AssociatedGroup associated_group_;
msramek5507fee2016-07-22 10:06:211109
rockot0e4de5f2016-07-22 21:18:071110 mojo::ScopedMessagePipeHandle handle_;
msramek5507fee2016-07-22 10:06:211111
rockot0e4de5f2016-07-22 21:18:071112 DISALLOW_COPY_AND_ASSIGN(MojoBootstrapImpl);
msramek5507fee2016-07-22 10:06:211113};
1114
morrita54f6f80c2014-09-23 21:16:001115} // namespace
1116
morrita54f6f80c2014-09-23 21:16:001117// static
danakj03de39b22016-04-23 04:21:091118std::unique_ptr<MojoBootstrap> MojoBootstrap::Create(
sammc57ed9f982016-03-10 06:28:351119 mojo::ScopedMessagePipeHandle handle,
1120 Channel::Mode mode,
Hajime Hoshia98f1102017-11-20 06:34:351121 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201122 const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner,
1123 const scoped_refptr<mojo::internal::MessageQuotaChecker>& quota_checker) {
Jeremy Roman160eb922017-08-29 17:43:431124 return std::make_unique<MojoBootstrapImpl>(
Sigurdur Asgeirssond655dd65f2019-11-12 19:32:201125 std::move(handle), new ChannelAssociatedGroupController(
1126 mode == Channel::MODE_SERVER, ipc_task_runner,
1127 proxy_task_runner, quota_checker));
sammc57ed9f982016-03-10 06:28:351128}
1129
morrita54f6f80c2014-09-23 21:16:001130} // namespace IPC