1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "ipc/ipc_sync_channel.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <stddef.h>
8*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
9*635a8641SAndroid Build Coastguard Worker
10*635a8641SAndroid Build Coastguard Worker #include <utility>
11*635a8641SAndroid Build Coastguard Worker
12*635a8641SAndroid Build Coastguard Worker #include "base/bind.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/lazy_instance.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/location.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/macros.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/run_loop.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/sequenced_task_runner.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_local.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_task_runner_handle.h"
23*635a8641SAndroid Build Coastguard Worker #include "base/trace_event/trace_event.h"
24*635a8641SAndroid Build Coastguard Worker #include "ipc/ipc_channel_factory.h"
25*635a8641SAndroid Build Coastguard Worker #include "ipc/ipc_logging.h"
26*635a8641SAndroid Build Coastguard Worker #include "ipc/ipc_message_macros.h"
27*635a8641SAndroid Build Coastguard Worker #include "ipc/ipc_sync_message.h"
28*635a8641SAndroid Build Coastguard Worker #include "mojo/public/cpp/bindings/sync_event_watcher.h"
29*635a8641SAndroid Build Coastguard Worker
30*635a8641SAndroid Build Coastguard Worker using base::WaitableEvent;
31*635a8641SAndroid Build Coastguard Worker
32*635a8641SAndroid Build Coastguard Worker namespace IPC {
33*635a8641SAndroid Build Coastguard Worker
34*635a8641SAndroid Build Coastguard Worker namespace {
35*635a8641SAndroid Build Coastguard Worker
36*635a8641SAndroid Build Coastguard Worker // A generic callback used when watching handles synchronously. Sets |*signal|
37*635a8641SAndroid Build Coastguard Worker // to true.
OnEventReady(bool * signal)38*635a8641SAndroid Build Coastguard Worker void OnEventReady(bool* signal) {
39*635a8641SAndroid Build Coastguard Worker *signal = true;
40*635a8641SAndroid Build Coastguard Worker }
41*635a8641SAndroid Build Coastguard Worker
42*635a8641SAndroid Build Coastguard Worker base::LazyInstance<std::unique_ptr<base::WaitableEvent>>::Leaky
43*635a8641SAndroid Build Coastguard Worker g_pump_messages_event = LAZY_INSTANCE_INITIALIZER;
44*635a8641SAndroid Build Coastguard Worker
45*635a8641SAndroid Build Coastguard Worker } // namespace
46*635a8641SAndroid Build Coastguard Worker
47*635a8641SAndroid Build Coastguard Worker // When we're blocked in a Send(), we need to process incoming synchronous
48*635a8641SAndroid Build Coastguard Worker // messages right away because it could be blocking our reply (either
49*635a8641SAndroid Build Coastguard Worker // directly from the same object we're calling, or indirectly through one or
50*635a8641SAndroid Build Coastguard Worker // more other channels). That means that in SyncContext's OnMessageReceived,
51*635a8641SAndroid Build Coastguard Worker // we need to process sync message right away if we're blocked. However a
52*635a8641SAndroid Build Coastguard Worker // simple check isn't sufficient, because the listener thread can be in the
53*635a8641SAndroid Build Coastguard Worker // process of calling Send.
54*635a8641SAndroid Build Coastguard Worker // To work around this, when SyncChannel filters a sync message, it sets
55*635a8641SAndroid Build Coastguard Worker // an event that the listener thread waits on during its Send() call. This
56*635a8641SAndroid Build Coastguard Worker // allows us to dispatch incoming sync messages when blocked. The race
57*635a8641SAndroid Build Coastguard Worker // condition is handled because if Send is in the process of being called, it
58*635a8641SAndroid Build Coastguard Worker // will check the event. In case the listener thread isn't sending a message,
59*635a8641SAndroid Build Coastguard Worker // we queue a task on the listener thread to dispatch the received messages.
60*635a8641SAndroid Build Coastguard Worker // The messages are stored in this queue object that's shared among all
61*635a8641SAndroid Build Coastguard Worker // SyncChannel objects on the same thread (since one object can receive a
62*635a8641SAndroid Build Coastguard Worker // sync message while another one is blocked).
63*635a8641SAndroid Build Coastguard Worker
64*635a8641SAndroid Build Coastguard Worker class SyncChannel::ReceivedSyncMsgQueue :
65*635a8641SAndroid Build Coastguard Worker public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> {
66*635a8641SAndroid Build Coastguard Worker public:
67*635a8641SAndroid Build Coastguard Worker // SyncChannel::WaitForReplyWithNestedMessageLoop may be re-entered, i.e. we
68*635a8641SAndroid Build Coastguard Worker // may nest waiting message loops arbitrarily deep on the SyncChannel's
69*635a8641SAndroid Build Coastguard Worker // thread. Every such operation has a corresponding WaitableEvent to be
70*635a8641SAndroid Build Coastguard Worker // watched which, when signalled for IPC completion, breaks out of the loop.
71*635a8641SAndroid Build Coastguard Worker // A reference to the innermost (i.e. topmost) watcher is held in
72*635a8641SAndroid Build Coastguard Worker // |ReceivedSyncMsgQueue::top_send_done_event_watcher_|.
73*635a8641SAndroid Build Coastguard Worker //
74*635a8641SAndroid Build Coastguard Worker // NestedSendDoneWatcher provides a simple scoper which is used by
75*635a8641SAndroid Build Coastguard Worker // WaitForReplyWithNestedMessageLoop to begin watching a new local "send done"
76*635a8641SAndroid Build Coastguard Worker // event, preserving the previous topmost state on the local stack until the
77*635a8641SAndroid Build Coastguard Worker // new inner loop is broken. If yet another subsequent nested loop is started
78*635a8641SAndroid Build Coastguard Worker // therein the process is repeated again in the new inner stack frame, and so
79*635a8641SAndroid Build Coastguard Worker // on.
80*635a8641SAndroid Build Coastguard Worker //
81*635a8641SAndroid Build Coastguard Worker // When this object is destroyed on stack unwind, the previous topmost state
82*635a8641SAndroid Build Coastguard Worker // is swapped back into |ReceivedSyncMsgQueue::top_send_done_event_watcher_|,
83*635a8641SAndroid Build Coastguard Worker // and its watch is resumed immediately.
84*635a8641SAndroid Build Coastguard Worker class NestedSendDoneWatcher {
85*635a8641SAndroid Build Coastguard Worker public:
NestedSendDoneWatcher(SyncChannel::SyncContext * context,base::RunLoop * run_loop,scoped_refptr<base::SequencedTaskRunner> task_runner)86*635a8641SAndroid Build Coastguard Worker NestedSendDoneWatcher(SyncChannel::SyncContext* context,
87*635a8641SAndroid Build Coastguard Worker base::RunLoop* run_loop,
88*635a8641SAndroid Build Coastguard Worker scoped_refptr<base::SequencedTaskRunner> task_runner)
89*635a8641SAndroid Build Coastguard Worker : sync_msg_queue_(context->received_sync_msgs()),
90*635a8641SAndroid Build Coastguard Worker outer_state_(sync_msg_queue_->top_send_done_event_watcher_),
91*635a8641SAndroid Build Coastguard Worker event_(context->GetSendDoneEvent()),
92*635a8641SAndroid Build Coastguard Worker callback_(
93*635a8641SAndroid Build Coastguard Worker base::BindOnce(&SyncChannel::SyncContext::OnSendDoneEventSignaled,
94*635a8641SAndroid Build Coastguard Worker context,
95*635a8641SAndroid Build Coastguard Worker run_loop)),
96*635a8641SAndroid Build Coastguard Worker task_runner_(std::move(task_runner)) {
97*635a8641SAndroid Build Coastguard Worker sync_msg_queue_->top_send_done_event_watcher_ = this;
98*635a8641SAndroid Build Coastguard Worker if (outer_state_)
99*635a8641SAndroid Build Coastguard Worker outer_state_->StopWatching();
100*635a8641SAndroid Build Coastguard Worker StartWatching();
101*635a8641SAndroid Build Coastguard Worker }
102*635a8641SAndroid Build Coastguard Worker
~NestedSendDoneWatcher()103*635a8641SAndroid Build Coastguard Worker ~NestedSendDoneWatcher() {
104*635a8641SAndroid Build Coastguard Worker sync_msg_queue_->top_send_done_event_watcher_ = outer_state_;
105*635a8641SAndroid Build Coastguard Worker if (outer_state_)
106*635a8641SAndroid Build Coastguard Worker outer_state_->StartWatching();
107*635a8641SAndroid Build Coastguard Worker }
108*635a8641SAndroid Build Coastguard Worker
109*635a8641SAndroid Build Coastguard Worker private:
Run(WaitableEvent * event)110*635a8641SAndroid Build Coastguard Worker void Run(WaitableEvent* event) {
111*635a8641SAndroid Build Coastguard Worker DCHECK(callback_);
112*635a8641SAndroid Build Coastguard Worker std::move(callback_).Run(event);
113*635a8641SAndroid Build Coastguard Worker }
114*635a8641SAndroid Build Coastguard Worker
StartWatching()115*635a8641SAndroid Build Coastguard Worker void StartWatching() {
116*635a8641SAndroid Build Coastguard Worker watcher_.StartWatching(
117*635a8641SAndroid Build Coastguard Worker event_,
118*635a8641SAndroid Build Coastguard Worker base::BindOnce(&NestedSendDoneWatcher::Run, base::Unretained(this)),
119*635a8641SAndroid Build Coastguard Worker task_runner_);
120*635a8641SAndroid Build Coastguard Worker }
121*635a8641SAndroid Build Coastguard Worker
StopWatching()122*635a8641SAndroid Build Coastguard Worker void StopWatching() { watcher_.StopWatching(); }
123*635a8641SAndroid Build Coastguard Worker
124*635a8641SAndroid Build Coastguard Worker ReceivedSyncMsgQueue* const sync_msg_queue_;
125*635a8641SAndroid Build Coastguard Worker NestedSendDoneWatcher* const outer_state_;
126*635a8641SAndroid Build Coastguard Worker
127*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* const event_;
128*635a8641SAndroid Build Coastguard Worker base::WaitableEventWatcher::EventCallback callback_;
129*635a8641SAndroid Build Coastguard Worker base::WaitableEventWatcher watcher_;
130*635a8641SAndroid Build Coastguard Worker scoped_refptr<base::SequencedTaskRunner> task_runner_;
131*635a8641SAndroid Build Coastguard Worker
132*635a8641SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(NestedSendDoneWatcher);
133*635a8641SAndroid Build Coastguard Worker };
134*635a8641SAndroid Build Coastguard Worker
135*635a8641SAndroid Build Coastguard Worker // Returns the ReceivedSyncMsgQueue instance for this thread, creating one
136*635a8641SAndroid Build Coastguard Worker // if necessary. Call RemoveContext on the same thread when done.
AddContext()137*635a8641SAndroid Build Coastguard Worker static ReceivedSyncMsgQueue* AddContext() {
138*635a8641SAndroid Build Coastguard Worker // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple
139*635a8641SAndroid Build Coastguard Worker // SyncChannel objects can block the same thread).
140*635a8641SAndroid Build Coastguard Worker ReceivedSyncMsgQueue* rv = lazy_tls_ptr_.Pointer()->Get();
141*635a8641SAndroid Build Coastguard Worker if (!rv) {
142*635a8641SAndroid Build Coastguard Worker rv = new ReceivedSyncMsgQueue();
143*635a8641SAndroid Build Coastguard Worker ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Set(rv);
144*635a8641SAndroid Build Coastguard Worker }
145*635a8641SAndroid Build Coastguard Worker rv->listener_count_++;
146*635a8641SAndroid Build Coastguard Worker return rv;
147*635a8641SAndroid Build Coastguard Worker }
148*635a8641SAndroid Build Coastguard Worker
149*635a8641SAndroid Build Coastguard Worker // Prevents messages from being dispatched immediately when the dispatch event
150*635a8641SAndroid Build Coastguard Worker // is signaled. Instead, |*dispatch_flag| will be set.
BlockDispatch(bool * dispatch_flag)151*635a8641SAndroid Build Coastguard Worker void BlockDispatch(bool* dispatch_flag) { dispatch_flag_ = dispatch_flag; }
152*635a8641SAndroid Build Coastguard Worker
153*635a8641SAndroid Build Coastguard Worker // Allows messages to be dispatched immediately when the dispatch event is
154*635a8641SAndroid Build Coastguard Worker // signaled.
UnblockDispatch()155*635a8641SAndroid Build Coastguard Worker void UnblockDispatch() { dispatch_flag_ = nullptr; }
156*635a8641SAndroid Build Coastguard Worker
157*635a8641SAndroid Build Coastguard Worker // Called on IPC thread when a synchronous message or reply arrives.
QueueMessage(const Message & msg,SyncChannel::SyncContext * context)158*635a8641SAndroid Build Coastguard Worker void QueueMessage(const Message& msg, SyncChannel::SyncContext* context) {
159*635a8641SAndroid Build Coastguard Worker bool was_task_pending;
160*635a8641SAndroid Build Coastguard Worker {
161*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(message_lock_);
162*635a8641SAndroid Build Coastguard Worker
163*635a8641SAndroid Build Coastguard Worker was_task_pending = task_pending_;
164*635a8641SAndroid Build Coastguard Worker task_pending_ = true;
165*635a8641SAndroid Build Coastguard Worker
166*635a8641SAndroid Build Coastguard Worker // We set the event in case the listener thread is blocked (or is about
167*635a8641SAndroid Build Coastguard Worker // to). In case it's not, the PostTask dispatches the messages.
168*635a8641SAndroid Build Coastguard Worker message_queue_.push_back(QueuedMessage(new Message(msg), context));
169*635a8641SAndroid Build Coastguard Worker message_queue_version_++;
170*635a8641SAndroid Build Coastguard Worker }
171*635a8641SAndroid Build Coastguard Worker
172*635a8641SAndroid Build Coastguard Worker dispatch_event_.Signal();
173*635a8641SAndroid Build Coastguard Worker if (!was_task_pending) {
174*635a8641SAndroid Build Coastguard Worker listener_task_runner_->PostTask(
175*635a8641SAndroid Build Coastguard Worker FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchMessagesTask,
176*635a8641SAndroid Build Coastguard Worker this, base::RetainedRef(context)));
177*635a8641SAndroid Build Coastguard Worker }
178*635a8641SAndroid Build Coastguard Worker }
179*635a8641SAndroid Build Coastguard Worker
QueueReply(const Message & msg,SyncChannel::SyncContext * context)180*635a8641SAndroid Build Coastguard Worker void QueueReply(const Message &msg, SyncChannel::SyncContext* context) {
181*635a8641SAndroid Build Coastguard Worker received_replies_.push_back(QueuedMessage(new Message(msg), context));
182*635a8641SAndroid Build Coastguard Worker }
183*635a8641SAndroid Build Coastguard Worker
184*635a8641SAndroid Build Coastguard Worker // Called on the listener's thread to process any queues synchronous
185*635a8641SAndroid Build Coastguard Worker // messages.
DispatchMessagesTask(SyncContext * context)186*635a8641SAndroid Build Coastguard Worker void DispatchMessagesTask(SyncContext* context) {
187*635a8641SAndroid Build Coastguard Worker {
188*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(message_lock_);
189*635a8641SAndroid Build Coastguard Worker task_pending_ = false;
190*635a8641SAndroid Build Coastguard Worker }
191*635a8641SAndroid Build Coastguard Worker context->DispatchMessages();
192*635a8641SAndroid Build Coastguard Worker }
193*635a8641SAndroid Build Coastguard Worker
194*635a8641SAndroid Build Coastguard Worker // Dispatches any queued incoming sync messages. If |dispatching_context| is
195*635a8641SAndroid Build Coastguard Worker // not null, messages which target a restricted dispatch channel will only be
196*635a8641SAndroid Build Coastguard Worker // dispatched if |dispatching_context| belongs to the same restricted dispatch
197*635a8641SAndroid Build Coastguard Worker // group as that channel. If |dispatching_context| is null, all queued
198*635a8641SAndroid Build Coastguard Worker // messages are dispatched.
DispatchMessages(SyncContext * dispatching_context)199*635a8641SAndroid Build Coastguard Worker void DispatchMessages(SyncContext* dispatching_context) {
200*635a8641SAndroid Build Coastguard Worker bool first_time = true;
201*635a8641SAndroid Build Coastguard Worker uint32_t expected_version = 0;
202*635a8641SAndroid Build Coastguard Worker SyncMessageQueue::iterator it;
203*635a8641SAndroid Build Coastguard Worker while (true) {
204*635a8641SAndroid Build Coastguard Worker Message* message = nullptr;
205*635a8641SAndroid Build Coastguard Worker scoped_refptr<SyncChannel::SyncContext> context;
206*635a8641SAndroid Build Coastguard Worker {
207*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(message_lock_);
208*635a8641SAndroid Build Coastguard Worker if (first_time || message_queue_version_ != expected_version) {
209*635a8641SAndroid Build Coastguard Worker it = message_queue_.begin();
210*635a8641SAndroid Build Coastguard Worker first_time = false;
211*635a8641SAndroid Build Coastguard Worker }
212*635a8641SAndroid Build Coastguard Worker for (; it != message_queue_.end(); it++) {
213*635a8641SAndroid Build Coastguard Worker int message_group = it->context->restrict_dispatch_group();
214*635a8641SAndroid Build Coastguard Worker if (message_group == kRestrictDispatchGroup_None ||
215*635a8641SAndroid Build Coastguard Worker (dispatching_context &&
216*635a8641SAndroid Build Coastguard Worker message_group ==
217*635a8641SAndroid Build Coastguard Worker dispatching_context->restrict_dispatch_group())) {
218*635a8641SAndroid Build Coastguard Worker message = it->message;
219*635a8641SAndroid Build Coastguard Worker context = it->context;
220*635a8641SAndroid Build Coastguard Worker it = message_queue_.erase(it);
221*635a8641SAndroid Build Coastguard Worker message_queue_version_++;
222*635a8641SAndroid Build Coastguard Worker expected_version = message_queue_version_;
223*635a8641SAndroid Build Coastguard Worker break;
224*635a8641SAndroid Build Coastguard Worker }
225*635a8641SAndroid Build Coastguard Worker }
226*635a8641SAndroid Build Coastguard Worker }
227*635a8641SAndroid Build Coastguard Worker
228*635a8641SAndroid Build Coastguard Worker if (message == nullptr)
229*635a8641SAndroid Build Coastguard Worker break;
230*635a8641SAndroid Build Coastguard Worker context->OnDispatchMessage(*message);
231*635a8641SAndroid Build Coastguard Worker delete message;
232*635a8641SAndroid Build Coastguard Worker }
233*635a8641SAndroid Build Coastguard Worker }
234*635a8641SAndroid Build Coastguard Worker
235*635a8641SAndroid Build Coastguard Worker // SyncChannel calls this in its destructor.
RemoveContext(SyncContext * context)236*635a8641SAndroid Build Coastguard Worker void RemoveContext(SyncContext* context) {
237*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(message_lock_);
238*635a8641SAndroid Build Coastguard Worker
239*635a8641SAndroid Build Coastguard Worker SyncMessageQueue::iterator iter = message_queue_.begin();
240*635a8641SAndroid Build Coastguard Worker while (iter != message_queue_.end()) {
241*635a8641SAndroid Build Coastguard Worker if (iter->context.get() == context) {
242*635a8641SAndroid Build Coastguard Worker delete iter->message;
243*635a8641SAndroid Build Coastguard Worker iter = message_queue_.erase(iter);
244*635a8641SAndroid Build Coastguard Worker message_queue_version_++;
245*635a8641SAndroid Build Coastguard Worker } else {
246*635a8641SAndroid Build Coastguard Worker iter++;
247*635a8641SAndroid Build Coastguard Worker }
248*635a8641SAndroid Build Coastguard Worker }
249*635a8641SAndroid Build Coastguard Worker
250*635a8641SAndroid Build Coastguard Worker if (--listener_count_ == 0) {
251*635a8641SAndroid Build Coastguard Worker DCHECK(lazy_tls_ptr_.Pointer()->Get());
252*635a8641SAndroid Build Coastguard Worker lazy_tls_ptr_.Pointer()->Set(nullptr);
253*635a8641SAndroid Build Coastguard Worker sync_dispatch_watcher_.reset();
254*635a8641SAndroid Build Coastguard Worker }
255*635a8641SAndroid Build Coastguard Worker }
256*635a8641SAndroid Build Coastguard Worker
dispatch_event()257*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* dispatch_event() { return &dispatch_event_; }
listener_task_runner()258*635a8641SAndroid Build Coastguard Worker base::SingleThreadTaskRunner* listener_task_runner() {
259*635a8641SAndroid Build Coastguard Worker return listener_task_runner_.get();
260*635a8641SAndroid Build Coastguard Worker }
261*635a8641SAndroid Build Coastguard Worker
262*635a8641SAndroid Build Coastguard Worker // Holds a pointer to the per-thread ReceivedSyncMsgQueue object.
263*635a8641SAndroid Build Coastguard Worker static base::LazyInstance<base::ThreadLocalPointer<ReceivedSyncMsgQueue>>::
264*635a8641SAndroid Build Coastguard Worker DestructorAtExit lazy_tls_ptr_;
265*635a8641SAndroid Build Coastguard Worker
266*635a8641SAndroid Build Coastguard Worker // Called on the ipc thread to check if we can unblock any current Send()
267*635a8641SAndroid Build Coastguard Worker // calls based on a queued reply.
DispatchReplies()268*635a8641SAndroid Build Coastguard Worker void DispatchReplies() {
269*635a8641SAndroid Build Coastguard Worker for (size_t i = 0; i < received_replies_.size(); ++i) {
270*635a8641SAndroid Build Coastguard Worker Message* message = received_replies_[i].message;
271*635a8641SAndroid Build Coastguard Worker if (received_replies_[i].context->TryToUnblockListener(message)) {
272*635a8641SAndroid Build Coastguard Worker delete message;
273*635a8641SAndroid Build Coastguard Worker received_replies_.erase(received_replies_.begin() + i);
274*635a8641SAndroid Build Coastguard Worker return;
275*635a8641SAndroid Build Coastguard Worker }
276*635a8641SAndroid Build Coastguard Worker }
277*635a8641SAndroid Build Coastguard Worker }
278*635a8641SAndroid Build Coastguard Worker
279*635a8641SAndroid Build Coastguard Worker private:
280*635a8641SAndroid Build Coastguard Worker friend class base::RefCountedThreadSafe<ReceivedSyncMsgQueue>;
281*635a8641SAndroid Build Coastguard Worker
282*635a8641SAndroid Build Coastguard Worker // See the comment in SyncChannel::SyncChannel for why this event is created
283*635a8641SAndroid Build Coastguard Worker // as manual reset.
ReceivedSyncMsgQueue()284*635a8641SAndroid Build Coastguard Worker ReceivedSyncMsgQueue()
285*635a8641SAndroid Build Coastguard Worker : message_queue_version_(0),
286*635a8641SAndroid Build Coastguard Worker dispatch_event_(base::WaitableEvent::ResetPolicy::MANUAL,
287*635a8641SAndroid Build Coastguard Worker base::WaitableEvent::InitialState::NOT_SIGNALED),
288*635a8641SAndroid Build Coastguard Worker listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
289*635a8641SAndroid Build Coastguard Worker sync_dispatch_watcher_(std::make_unique<mojo::SyncEventWatcher>(
290*635a8641SAndroid Build Coastguard Worker &dispatch_event_,
291*635a8641SAndroid Build Coastguard Worker base::Bind(&ReceivedSyncMsgQueue::OnDispatchEventReady,
292*635a8641SAndroid Build Coastguard Worker base::Unretained(this)))) {
293*635a8641SAndroid Build Coastguard Worker sync_dispatch_watcher_->AllowWokenUpBySyncWatchOnSameThread();
294*635a8641SAndroid Build Coastguard Worker }
295*635a8641SAndroid Build Coastguard Worker
296*635a8641SAndroid Build Coastguard Worker ~ReceivedSyncMsgQueue() = default;
297*635a8641SAndroid Build Coastguard Worker
OnDispatchEventReady()298*635a8641SAndroid Build Coastguard Worker void OnDispatchEventReady() {
299*635a8641SAndroid Build Coastguard Worker if (dispatch_flag_) {
300*635a8641SAndroid Build Coastguard Worker *dispatch_flag_ = true;
301*635a8641SAndroid Build Coastguard Worker return;
302*635a8641SAndroid Build Coastguard Worker }
303*635a8641SAndroid Build Coastguard Worker
304*635a8641SAndroid Build Coastguard Worker // We were woken up during a sync wait, but no specific SyncChannel is
305*635a8641SAndroid Build Coastguard Worker // currently waiting. i.e., some other Mojo interface on this thread is
306*635a8641SAndroid Build Coastguard Worker // waiting for a response. Since we don't support anything analogous to
307*635a8641SAndroid Build Coastguard Worker // restricted dispatch on Mojo interfaces, in this case it's safe to
308*635a8641SAndroid Build Coastguard Worker // dispatch sync messages for any context.
309*635a8641SAndroid Build Coastguard Worker DispatchMessages(nullptr);
310*635a8641SAndroid Build Coastguard Worker }
311*635a8641SAndroid Build Coastguard Worker
312*635a8641SAndroid Build Coastguard Worker // Holds information about a queued synchronous message or reply.
313*635a8641SAndroid Build Coastguard Worker struct QueuedMessage {
QueuedMessageIPC::SyncChannel::ReceivedSyncMsgQueue::QueuedMessage314*635a8641SAndroid Build Coastguard Worker QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { }
315*635a8641SAndroid Build Coastguard Worker Message* message;
316*635a8641SAndroid Build Coastguard Worker scoped_refptr<SyncChannel::SyncContext> context;
317*635a8641SAndroid Build Coastguard Worker };
318*635a8641SAndroid Build Coastguard Worker
319*635a8641SAndroid Build Coastguard Worker typedef std::list<QueuedMessage> SyncMessageQueue;
320*635a8641SAndroid Build Coastguard Worker SyncMessageQueue message_queue_;
321*635a8641SAndroid Build Coastguard Worker
322*635a8641SAndroid Build Coastguard Worker // Used to signal DispatchMessages to rescan
323*635a8641SAndroid Build Coastguard Worker uint32_t message_queue_version_ = 0;
324*635a8641SAndroid Build Coastguard Worker
325*635a8641SAndroid Build Coastguard Worker std::vector<QueuedMessage> received_replies_;
326*635a8641SAndroid Build Coastguard Worker
327*635a8641SAndroid Build Coastguard Worker // Signaled when we get a synchronous message that we must respond to, as the
328*635a8641SAndroid Build Coastguard Worker // sender needs its reply before it can reply to our original synchronous
329*635a8641SAndroid Build Coastguard Worker // message.
330*635a8641SAndroid Build Coastguard Worker base::WaitableEvent dispatch_event_;
331*635a8641SAndroid Build Coastguard Worker scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
332*635a8641SAndroid Build Coastguard Worker base::Lock message_lock_;
333*635a8641SAndroid Build Coastguard Worker bool task_pending_ = false;
334*635a8641SAndroid Build Coastguard Worker int listener_count_ = 0;
335*635a8641SAndroid Build Coastguard Worker
336*635a8641SAndroid Build Coastguard Worker // The current NestedSendDoneWatcher for this thread, if we're currently
337*635a8641SAndroid Build Coastguard Worker // in a SyncChannel::WaitForReplyWithNestedMessageLoop. See
338*635a8641SAndroid Build Coastguard Worker // NestedSendDoneWatcher comments for more details.
339*635a8641SAndroid Build Coastguard Worker NestedSendDoneWatcher* top_send_done_event_watcher_ = nullptr;
340*635a8641SAndroid Build Coastguard Worker
341*635a8641SAndroid Build Coastguard Worker // If not null, the address of a flag to set when the dispatch event signals,
342*635a8641SAndroid Build Coastguard Worker // in lieu of actually dispatching messages. This is used by
343*635a8641SAndroid Build Coastguard Worker // SyncChannel::WaitForReply to restrict the scope of queued messages we're
344*635a8641SAndroid Build Coastguard Worker // allowed to process while it's waiting.
345*635a8641SAndroid Build Coastguard Worker bool* dispatch_flag_ = nullptr;
346*635a8641SAndroid Build Coastguard Worker
347*635a8641SAndroid Build Coastguard Worker // Watches |dispatch_event_| during all sync handle watches on this thread.
348*635a8641SAndroid Build Coastguard Worker std::unique_ptr<mojo::SyncEventWatcher> sync_dispatch_watcher_;
349*635a8641SAndroid Build Coastguard Worker };
350*635a8641SAndroid Build Coastguard Worker
351*635a8641SAndroid Build Coastguard Worker base::LazyInstance<base::ThreadLocalPointer<
352*635a8641SAndroid Build Coastguard Worker SyncChannel::ReceivedSyncMsgQueue>>::DestructorAtExit
353*635a8641SAndroid Build Coastguard Worker SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_ =
354*635a8641SAndroid Build Coastguard Worker LAZY_INSTANCE_INITIALIZER;
355*635a8641SAndroid Build Coastguard Worker
SyncContext(Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner,WaitableEvent * shutdown_event)356*635a8641SAndroid Build Coastguard Worker SyncChannel::SyncContext::SyncContext(
357*635a8641SAndroid Build Coastguard Worker Listener* listener,
358*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
359*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
360*635a8641SAndroid Build Coastguard Worker WaitableEvent* shutdown_event)
361*635a8641SAndroid Build Coastguard Worker : ChannelProxy::Context(listener, ipc_task_runner, listener_task_runner),
362*635a8641SAndroid Build Coastguard Worker received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()),
363*635a8641SAndroid Build Coastguard Worker shutdown_event_(shutdown_event),
364*635a8641SAndroid Build Coastguard Worker restrict_dispatch_group_(kRestrictDispatchGroup_None) {}
365*635a8641SAndroid Build Coastguard Worker
OnSendDoneEventSignaled(base::RunLoop * nested_loop,base::WaitableEvent * event)366*635a8641SAndroid Build Coastguard Worker void SyncChannel::SyncContext::OnSendDoneEventSignaled(
367*635a8641SAndroid Build Coastguard Worker base::RunLoop* nested_loop,
368*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* event) {
369*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetSendDoneEvent(), event);
370*635a8641SAndroid Build Coastguard Worker nested_loop->Quit();
371*635a8641SAndroid Build Coastguard Worker }
372*635a8641SAndroid Build Coastguard Worker
~SyncContext()373*635a8641SAndroid Build Coastguard Worker SyncChannel::SyncContext::~SyncContext() {
374*635a8641SAndroid Build Coastguard Worker while (!deserializers_.empty())
375*635a8641SAndroid Build Coastguard Worker Pop();
376*635a8641SAndroid Build Coastguard Worker }
377*635a8641SAndroid Build Coastguard Worker
378*635a8641SAndroid Build Coastguard Worker // Adds information about an outgoing sync message to the context so that
379*635a8641SAndroid Build Coastguard Worker // we know how to deserialize the reply. Returns |true| if the message was added
380*635a8641SAndroid Build Coastguard Worker // to the context or |false| if it was rejected (e.g. due to shutdown.)
Push(SyncMessage * sync_msg)381*635a8641SAndroid Build Coastguard Worker bool SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
382*635a8641SAndroid Build Coastguard Worker // Create the tracking information for this message. This object is stored
383*635a8641SAndroid Build Coastguard Worker // by value since all members are pointers that are cheap to copy. These
384*635a8641SAndroid Build Coastguard Worker // pointers are cleaned up in the Pop() function.
385*635a8641SAndroid Build Coastguard Worker //
386*635a8641SAndroid Build Coastguard Worker // The event is created as manual reset because in between Signal and
387*635a8641SAndroid Build Coastguard Worker // OnObjectSignalled, another Send can happen which would stop the watcher
388*635a8641SAndroid Build Coastguard Worker // from being called. The event would get watched later, when the nested
389*635a8641SAndroid Build Coastguard Worker // Send completes, so the event will need to remain set.
390*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(deserializers_lock_);
391*635a8641SAndroid Build Coastguard Worker if (reject_new_deserializers_)
392*635a8641SAndroid Build Coastguard Worker return false;
393*635a8641SAndroid Build Coastguard Worker PendingSyncMsg pending(
394*635a8641SAndroid Build Coastguard Worker SyncMessage::GetMessageId(*sync_msg), sync_msg->GetReplyDeserializer(),
395*635a8641SAndroid Build Coastguard Worker new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
396*635a8641SAndroid Build Coastguard Worker base::WaitableEvent::InitialState::NOT_SIGNALED));
397*635a8641SAndroid Build Coastguard Worker deserializers_.push_back(pending);
398*635a8641SAndroid Build Coastguard Worker return true;
399*635a8641SAndroid Build Coastguard Worker }
400*635a8641SAndroid Build Coastguard Worker
Pop()401*635a8641SAndroid Build Coastguard Worker bool SyncChannel::SyncContext::Pop() {
402*635a8641SAndroid Build Coastguard Worker bool result;
403*635a8641SAndroid Build Coastguard Worker {
404*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(deserializers_lock_);
405*635a8641SAndroid Build Coastguard Worker PendingSyncMsg msg = deserializers_.back();
406*635a8641SAndroid Build Coastguard Worker delete msg.deserializer;
407*635a8641SAndroid Build Coastguard Worker delete msg.done_event;
408*635a8641SAndroid Build Coastguard Worker msg.done_event = nullptr;
409*635a8641SAndroid Build Coastguard Worker deserializers_.pop_back();
410*635a8641SAndroid Build Coastguard Worker result = msg.send_result;
411*635a8641SAndroid Build Coastguard Worker }
412*635a8641SAndroid Build Coastguard Worker
413*635a8641SAndroid Build Coastguard Worker // We got a reply to a synchronous Send() call that's blocking the listener
414*635a8641SAndroid Build Coastguard Worker // thread. However, further down the call stack there could be another
415*635a8641SAndroid Build Coastguard Worker // blocking Send() call, whose reply we received after we made this last
416*635a8641SAndroid Build Coastguard Worker // Send() call. So check if we have any queued replies available that
417*635a8641SAndroid Build Coastguard Worker // can now unblock the listener thread.
418*635a8641SAndroid Build Coastguard Worker ipc_task_runner()->PostTask(
419*635a8641SAndroid Build Coastguard Worker FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchReplies,
420*635a8641SAndroid Build Coastguard Worker received_sync_msgs_));
421*635a8641SAndroid Build Coastguard Worker
422*635a8641SAndroid Build Coastguard Worker return result;
423*635a8641SAndroid Build Coastguard Worker }
424*635a8641SAndroid Build Coastguard Worker
GetSendDoneEvent()425*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
426*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(deserializers_lock_);
427*635a8641SAndroid Build Coastguard Worker return deserializers_.back().done_event;
428*635a8641SAndroid Build Coastguard Worker }
429*635a8641SAndroid Build Coastguard Worker
GetDispatchEvent()430*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* SyncChannel::SyncContext::GetDispatchEvent() {
431*635a8641SAndroid Build Coastguard Worker return received_sync_msgs_->dispatch_event();
432*635a8641SAndroid Build Coastguard Worker }
433*635a8641SAndroid Build Coastguard Worker
DispatchMessages()434*635a8641SAndroid Build Coastguard Worker void SyncChannel::SyncContext::DispatchMessages() {
435*635a8641SAndroid Build Coastguard Worker received_sync_msgs_->DispatchMessages(this);
436*635a8641SAndroid Build Coastguard Worker }
437*635a8641SAndroid Build Coastguard Worker
TryToUnblockListener(const Message * msg)438*635a8641SAndroid Build Coastguard Worker bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) {
439*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(deserializers_lock_);
440*635a8641SAndroid Build Coastguard Worker if (deserializers_.empty() ||
441*635a8641SAndroid Build Coastguard Worker !SyncMessage::IsMessageReplyTo(*msg, deserializers_.back().id)) {
442*635a8641SAndroid Build Coastguard Worker return false;
443*635a8641SAndroid Build Coastguard Worker }
444*635a8641SAndroid Build Coastguard Worker
445*635a8641SAndroid Build Coastguard Worker if (!msg->is_reply_error()) {
446*635a8641SAndroid Build Coastguard Worker bool send_result = deserializers_.back().deserializer->
447*635a8641SAndroid Build Coastguard Worker SerializeOutputParameters(*msg);
448*635a8641SAndroid Build Coastguard Worker deserializers_.back().send_result = send_result;
449*635a8641SAndroid Build Coastguard Worker DVLOG_IF(1, !send_result) << "Couldn't deserialize reply message";
450*635a8641SAndroid Build Coastguard Worker } else {
451*635a8641SAndroid Build Coastguard Worker DVLOG(1) << "Received error reply";
452*635a8641SAndroid Build Coastguard Worker }
453*635a8641SAndroid Build Coastguard Worker
454*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* done_event = deserializers_.back().done_event;
455*635a8641SAndroid Build Coastguard Worker TRACE_EVENT_FLOW_BEGIN0(
456*635a8641SAndroid Build Coastguard Worker TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
457*635a8641SAndroid Build Coastguard Worker "SyncChannel::SyncContext::TryToUnblockListener", done_event);
458*635a8641SAndroid Build Coastguard Worker
459*635a8641SAndroid Build Coastguard Worker done_event->Signal();
460*635a8641SAndroid Build Coastguard Worker
461*635a8641SAndroid Build Coastguard Worker return true;
462*635a8641SAndroid Build Coastguard Worker }
463*635a8641SAndroid Build Coastguard Worker
Clear()464*635a8641SAndroid Build Coastguard Worker void SyncChannel::SyncContext::Clear() {
465*635a8641SAndroid Build Coastguard Worker CancelPendingSends();
466*635a8641SAndroid Build Coastguard Worker received_sync_msgs_->RemoveContext(this);
467*635a8641SAndroid Build Coastguard Worker Context::Clear();
468*635a8641SAndroid Build Coastguard Worker }
469*635a8641SAndroid Build Coastguard Worker
OnMessageReceived(const Message & msg)470*635a8641SAndroid Build Coastguard Worker bool SyncChannel::SyncContext::OnMessageReceived(const Message& msg) {
471*635a8641SAndroid Build Coastguard Worker // Give the filters a chance at processing this message.
472*635a8641SAndroid Build Coastguard Worker if (TryFilters(msg))
473*635a8641SAndroid Build Coastguard Worker return true;
474*635a8641SAndroid Build Coastguard Worker
475*635a8641SAndroid Build Coastguard Worker if (TryToUnblockListener(&msg))
476*635a8641SAndroid Build Coastguard Worker return true;
477*635a8641SAndroid Build Coastguard Worker
478*635a8641SAndroid Build Coastguard Worker if (msg.is_reply()) {
479*635a8641SAndroid Build Coastguard Worker received_sync_msgs_->QueueReply(msg, this);
480*635a8641SAndroid Build Coastguard Worker return true;
481*635a8641SAndroid Build Coastguard Worker }
482*635a8641SAndroid Build Coastguard Worker
483*635a8641SAndroid Build Coastguard Worker if (msg.should_unblock()) {
484*635a8641SAndroid Build Coastguard Worker received_sync_msgs_->QueueMessage(msg, this);
485*635a8641SAndroid Build Coastguard Worker return true;
486*635a8641SAndroid Build Coastguard Worker }
487*635a8641SAndroid Build Coastguard Worker
488*635a8641SAndroid Build Coastguard Worker return Context::OnMessageReceivedNoFilter(msg);
489*635a8641SAndroid Build Coastguard Worker }
490*635a8641SAndroid Build Coastguard Worker
OnChannelError()491*635a8641SAndroid Build Coastguard Worker void SyncChannel::SyncContext::OnChannelError() {
492*635a8641SAndroid Build Coastguard Worker CancelPendingSends();
493*635a8641SAndroid Build Coastguard Worker shutdown_watcher_.StopWatching();
494*635a8641SAndroid Build Coastguard Worker Context::OnChannelError();
495*635a8641SAndroid Build Coastguard Worker }
496*635a8641SAndroid Build Coastguard Worker
OnChannelOpened()497*635a8641SAndroid Build Coastguard Worker void SyncChannel::SyncContext::OnChannelOpened() {
498*635a8641SAndroid Build Coastguard Worker shutdown_watcher_.StartWatching(
499*635a8641SAndroid Build Coastguard Worker shutdown_event_,
500*635a8641SAndroid Build Coastguard Worker base::Bind(&SyncChannel::SyncContext::OnShutdownEventSignaled,
501*635a8641SAndroid Build Coastguard Worker base::Unretained(this)),
502*635a8641SAndroid Build Coastguard Worker base::SequencedTaskRunnerHandle::Get());
503*635a8641SAndroid Build Coastguard Worker Context::OnChannelOpened();
504*635a8641SAndroid Build Coastguard Worker }
505*635a8641SAndroid Build Coastguard Worker
OnChannelClosed()506*635a8641SAndroid Build Coastguard Worker void SyncChannel::SyncContext::OnChannelClosed() {
507*635a8641SAndroid Build Coastguard Worker CancelPendingSends();
508*635a8641SAndroid Build Coastguard Worker shutdown_watcher_.StopWatching();
509*635a8641SAndroid Build Coastguard Worker Context::OnChannelClosed();
510*635a8641SAndroid Build Coastguard Worker }
511*635a8641SAndroid Build Coastguard Worker
CancelPendingSends()512*635a8641SAndroid Build Coastguard Worker void SyncChannel::SyncContext::CancelPendingSends() {
513*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(deserializers_lock_);
514*635a8641SAndroid Build Coastguard Worker reject_new_deserializers_ = true;
515*635a8641SAndroid Build Coastguard Worker PendingSyncMessageQueue::iterator iter;
516*635a8641SAndroid Build Coastguard Worker DVLOG(1) << "Canceling pending sends";
517*635a8641SAndroid Build Coastguard Worker for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
518*635a8641SAndroid Build Coastguard Worker TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
519*635a8641SAndroid Build Coastguard Worker "SyncChannel::SyncContext::CancelPendingSends",
520*635a8641SAndroid Build Coastguard Worker iter->done_event);
521*635a8641SAndroid Build Coastguard Worker iter->done_event->Signal();
522*635a8641SAndroid Build Coastguard Worker }
523*635a8641SAndroid Build Coastguard Worker }
524*635a8641SAndroid Build Coastguard Worker
OnShutdownEventSignaled(WaitableEvent * event)525*635a8641SAndroid Build Coastguard Worker void SyncChannel::SyncContext::OnShutdownEventSignaled(WaitableEvent* event) {
526*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(event, shutdown_event_);
527*635a8641SAndroid Build Coastguard Worker
528*635a8641SAndroid Build Coastguard Worker // Process shut down before we can get a reply to a synchronous message.
529*635a8641SAndroid Build Coastguard Worker // Cancel pending Send calls, which will end up setting the send done event.
530*635a8641SAndroid Build Coastguard Worker CancelPendingSends();
531*635a8641SAndroid Build Coastguard Worker }
532*635a8641SAndroid Build Coastguard Worker
533*635a8641SAndroid Build Coastguard Worker // static
Create(const IPC::ChannelHandle & channel_handle,Channel::Mode mode,Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner,bool create_pipe_now,base::WaitableEvent * shutdown_event)534*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SyncChannel> SyncChannel::Create(
535*635a8641SAndroid Build Coastguard Worker const IPC::ChannelHandle& channel_handle,
536*635a8641SAndroid Build Coastguard Worker Channel::Mode mode,
537*635a8641SAndroid Build Coastguard Worker Listener* listener,
538*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
539*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
540*635a8641SAndroid Build Coastguard Worker bool create_pipe_now,
541*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* shutdown_event) {
542*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SyncChannel> channel =
543*635a8641SAndroid Build Coastguard Worker Create(listener, ipc_task_runner, listener_task_runner, shutdown_event);
544*635a8641SAndroid Build Coastguard Worker channel->Init(channel_handle, mode, create_pipe_now);
545*635a8641SAndroid Build Coastguard Worker return channel;
546*635a8641SAndroid Build Coastguard Worker }
547*635a8641SAndroid Build Coastguard Worker
548*635a8641SAndroid Build Coastguard Worker // static
Create(std::unique_ptr<ChannelFactory> factory,Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner,bool create_pipe_now,base::WaitableEvent * shutdown_event)549*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SyncChannel> SyncChannel::Create(
550*635a8641SAndroid Build Coastguard Worker std::unique_ptr<ChannelFactory> factory,
551*635a8641SAndroid Build Coastguard Worker Listener* listener,
552*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
553*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
554*635a8641SAndroid Build Coastguard Worker bool create_pipe_now,
555*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* shutdown_event) {
556*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SyncChannel> channel =
557*635a8641SAndroid Build Coastguard Worker Create(listener, ipc_task_runner, listener_task_runner, shutdown_event);
558*635a8641SAndroid Build Coastguard Worker channel->Init(std::move(factory), create_pipe_now);
559*635a8641SAndroid Build Coastguard Worker return channel;
560*635a8641SAndroid Build Coastguard Worker }
561*635a8641SAndroid Build Coastguard Worker
562*635a8641SAndroid Build Coastguard Worker // static
Create(Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner,WaitableEvent * shutdown_event)563*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SyncChannel> SyncChannel::Create(
564*635a8641SAndroid Build Coastguard Worker Listener* listener,
565*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
566*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
567*635a8641SAndroid Build Coastguard Worker WaitableEvent* shutdown_event) {
568*635a8641SAndroid Build Coastguard Worker return base::WrapUnique(new SyncChannel(
569*635a8641SAndroid Build Coastguard Worker listener, ipc_task_runner, listener_task_runner, shutdown_event));
570*635a8641SAndroid Build Coastguard Worker }
571*635a8641SAndroid Build Coastguard Worker
SyncChannel(Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner,WaitableEvent * shutdown_event)572*635a8641SAndroid Build Coastguard Worker SyncChannel::SyncChannel(
573*635a8641SAndroid Build Coastguard Worker Listener* listener,
574*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
575*635a8641SAndroid Build Coastguard Worker const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
576*635a8641SAndroid Build Coastguard Worker WaitableEvent* shutdown_event)
577*635a8641SAndroid Build Coastguard Worker : ChannelProxy(new SyncContext(listener,
578*635a8641SAndroid Build Coastguard Worker ipc_task_runner,
579*635a8641SAndroid Build Coastguard Worker listener_task_runner,
580*635a8641SAndroid Build Coastguard Worker shutdown_event)),
581*635a8641SAndroid Build Coastguard Worker sync_handle_registry_(mojo::SyncHandleRegistry::current()) {
582*635a8641SAndroid Build Coastguard Worker // The current (listener) thread must be distinct from the IPC thread, or else
583*635a8641SAndroid Build Coastguard Worker // sending synchronous messages will deadlock.
584*635a8641SAndroid Build Coastguard Worker DCHECK_NE(ipc_task_runner.get(), base::ThreadTaskRunnerHandle::Get().get());
585*635a8641SAndroid Build Coastguard Worker StartWatching();
586*635a8641SAndroid Build Coastguard Worker }
587*635a8641SAndroid Build Coastguard Worker
588*635a8641SAndroid Build Coastguard Worker SyncChannel::~SyncChannel() = default;
589*635a8641SAndroid Build Coastguard Worker
SetRestrictDispatchChannelGroup(int group)590*635a8641SAndroid Build Coastguard Worker void SyncChannel::SetRestrictDispatchChannelGroup(int group) {
591*635a8641SAndroid Build Coastguard Worker sync_context()->set_restrict_dispatch_group(group);
592*635a8641SAndroid Build Coastguard Worker }
593*635a8641SAndroid Build Coastguard Worker
CreateSyncMessageFilter()594*635a8641SAndroid Build Coastguard Worker scoped_refptr<SyncMessageFilter> SyncChannel::CreateSyncMessageFilter() {
595*635a8641SAndroid Build Coastguard Worker scoped_refptr<SyncMessageFilter> filter = new SyncMessageFilter(
596*635a8641SAndroid Build Coastguard Worker sync_context()->shutdown_event());
597*635a8641SAndroid Build Coastguard Worker AddFilter(filter.get());
598*635a8641SAndroid Build Coastguard Worker if (!did_init())
599*635a8641SAndroid Build Coastguard Worker pre_init_sync_message_filters_.push_back(filter);
600*635a8641SAndroid Build Coastguard Worker return filter;
601*635a8641SAndroid Build Coastguard Worker }
602*635a8641SAndroid Build Coastguard Worker
Send(Message * message)603*635a8641SAndroid Build Coastguard Worker bool SyncChannel::Send(Message* message) {
604*635a8641SAndroid Build Coastguard Worker #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
605*635a8641SAndroid Build Coastguard Worker std::string name;
606*635a8641SAndroid Build Coastguard Worker Logging::GetInstance()->GetMessageText(
607*635a8641SAndroid Build Coastguard Worker message->type(), &name, message, nullptr);
608*635a8641SAndroid Build Coastguard Worker TRACE_EVENT1("ipc", "SyncChannel::Send", "name", name);
609*635a8641SAndroid Build Coastguard Worker #else
610*635a8641SAndroid Build Coastguard Worker TRACE_EVENT2("ipc", "SyncChannel::Send",
611*635a8641SAndroid Build Coastguard Worker "class", IPC_MESSAGE_ID_CLASS(message->type()),
612*635a8641SAndroid Build Coastguard Worker "line", IPC_MESSAGE_ID_LINE(message->type()));
613*635a8641SAndroid Build Coastguard Worker #endif
614*635a8641SAndroid Build Coastguard Worker if (!message->is_sync()) {
615*635a8641SAndroid Build Coastguard Worker ChannelProxy::SendInternal(message);
616*635a8641SAndroid Build Coastguard Worker return true;
617*635a8641SAndroid Build Coastguard Worker }
618*635a8641SAndroid Build Coastguard Worker
619*635a8641SAndroid Build Coastguard Worker SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
620*635a8641SAndroid Build Coastguard Worker bool pump_messages = sync_msg->ShouldPumpMessages();
621*635a8641SAndroid Build Coastguard Worker
622*635a8641SAndroid Build Coastguard Worker // *this* might get deleted in WaitForReply.
623*635a8641SAndroid Build Coastguard Worker scoped_refptr<SyncContext> context(sync_context());
624*635a8641SAndroid Build Coastguard Worker if (!context->Push(sync_msg)) {
625*635a8641SAndroid Build Coastguard Worker DVLOG(1) << "Channel is shutting down. Dropping sync message.";
626*635a8641SAndroid Build Coastguard Worker delete message;
627*635a8641SAndroid Build Coastguard Worker return false;
628*635a8641SAndroid Build Coastguard Worker }
629*635a8641SAndroid Build Coastguard Worker
630*635a8641SAndroid Build Coastguard Worker ChannelProxy::SendInternal(message);
631*635a8641SAndroid Build Coastguard Worker
632*635a8641SAndroid Build Coastguard Worker // Wait for reply, or for any other incoming synchronous messages.
633*635a8641SAndroid Build Coastguard Worker // |this| might get deleted, so only call static functions at this point.
634*635a8641SAndroid Build Coastguard Worker scoped_refptr<mojo::SyncHandleRegistry> registry = sync_handle_registry_;
635*635a8641SAndroid Build Coastguard Worker WaitForReply(registry.get(), context.get(), pump_messages);
636*635a8641SAndroid Build Coastguard Worker
637*635a8641SAndroid Build Coastguard Worker TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
638*635a8641SAndroid Build Coastguard Worker "SyncChannel::Send", context->GetSendDoneEvent());
639*635a8641SAndroid Build Coastguard Worker
640*635a8641SAndroid Build Coastguard Worker return context->Pop();
641*635a8641SAndroid Build Coastguard Worker }
642*635a8641SAndroid Build Coastguard Worker
WaitForReply(mojo::SyncHandleRegistry * registry,SyncContext * context,bool pump_messages)643*635a8641SAndroid Build Coastguard Worker void SyncChannel::WaitForReply(mojo::SyncHandleRegistry* registry,
644*635a8641SAndroid Build Coastguard Worker SyncContext* context,
645*635a8641SAndroid Build Coastguard Worker bool pump_messages) {
646*635a8641SAndroid Build Coastguard Worker context->DispatchMessages();
647*635a8641SAndroid Build Coastguard Worker
648*635a8641SAndroid Build Coastguard Worker base::WaitableEvent* pump_messages_event = nullptr;
649*635a8641SAndroid Build Coastguard Worker if (pump_messages) {
650*635a8641SAndroid Build Coastguard Worker if (!g_pump_messages_event.Get()) {
651*635a8641SAndroid Build Coastguard Worker g_pump_messages_event.Get() = std::make_unique<base::WaitableEvent>(
652*635a8641SAndroid Build Coastguard Worker base::WaitableEvent::ResetPolicy::MANUAL,
653*635a8641SAndroid Build Coastguard Worker base::WaitableEvent::InitialState::SIGNALED);
654*635a8641SAndroid Build Coastguard Worker }
655*635a8641SAndroid Build Coastguard Worker pump_messages_event = g_pump_messages_event.Get().get();
656*635a8641SAndroid Build Coastguard Worker }
657*635a8641SAndroid Build Coastguard Worker
658*635a8641SAndroid Build Coastguard Worker while (true) {
659*635a8641SAndroid Build Coastguard Worker bool dispatch = false;
660*635a8641SAndroid Build Coastguard Worker bool send_done = false;
661*635a8641SAndroid Build Coastguard Worker bool should_pump_messages = false;
662*635a8641SAndroid Build Coastguard Worker base::Closure on_send_done_callback = base::Bind(&OnEventReady, &send_done);
663*635a8641SAndroid Build Coastguard Worker registry->RegisterEvent(context->GetSendDoneEvent(), on_send_done_callback);
664*635a8641SAndroid Build Coastguard Worker
665*635a8641SAndroid Build Coastguard Worker base::Closure on_pump_messages_callback;
666*635a8641SAndroid Build Coastguard Worker if (pump_messages_event) {
667*635a8641SAndroid Build Coastguard Worker on_pump_messages_callback =
668*635a8641SAndroid Build Coastguard Worker base::Bind(&OnEventReady, &should_pump_messages);
669*635a8641SAndroid Build Coastguard Worker registry->RegisterEvent(pump_messages_event, on_pump_messages_callback);
670*635a8641SAndroid Build Coastguard Worker }
671*635a8641SAndroid Build Coastguard Worker
672*635a8641SAndroid Build Coastguard Worker const bool* stop_flags[] = { &dispatch, &send_done, &should_pump_messages };
673*635a8641SAndroid Build Coastguard Worker context->received_sync_msgs()->BlockDispatch(&dispatch);
674*635a8641SAndroid Build Coastguard Worker registry->Wait(stop_flags, 3);
675*635a8641SAndroid Build Coastguard Worker context->received_sync_msgs()->UnblockDispatch();
676*635a8641SAndroid Build Coastguard Worker
677*635a8641SAndroid Build Coastguard Worker registry->UnregisterEvent(context->GetSendDoneEvent(),
678*635a8641SAndroid Build Coastguard Worker on_send_done_callback);
679*635a8641SAndroid Build Coastguard Worker if (pump_messages_event)
680*635a8641SAndroid Build Coastguard Worker registry->UnregisterEvent(pump_messages_event, on_pump_messages_callback);
681*635a8641SAndroid Build Coastguard Worker
682*635a8641SAndroid Build Coastguard Worker if (dispatch) {
683*635a8641SAndroid Build Coastguard Worker // We're waiting for a reply, but we received a blocking synchronous call.
684*635a8641SAndroid Build Coastguard Worker // We must process it to avoid potential deadlocks.
685*635a8641SAndroid Build Coastguard Worker context->GetDispatchEvent()->Reset();
686*635a8641SAndroid Build Coastguard Worker context->DispatchMessages();
687*635a8641SAndroid Build Coastguard Worker continue;
688*635a8641SAndroid Build Coastguard Worker }
689*635a8641SAndroid Build Coastguard Worker
690*635a8641SAndroid Build Coastguard Worker if (should_pump_messages)
691*635a8641SAndroid Build Coastguard Worker WaitForReplyWithNestedMessageLoop(context); // Run a nested run loop.
692*635a8641SAndroid Build Coastguard Worker
693*635a8641SAndroid Build Coastguard Worker break;
694*635a8641SAndroid Build Coastguard Worker }
695*635a8641SAndroid Build Coastguard Worker }
696*635a8641SAndroid Build Coastguard Worker
WaitForReplyWithNestedMessageLoop(SyncContext * context)697*635a8641SAndroid Build Coastguard Worker void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) {
698*635a8641SAndroid Build Coastguard Worker base::RunLoop nested_loop(base::RunLoop::Type::kNestableTasksAllowed);
699*635a8641SAndroid Build Coastguard Worker ReceivedSyncMsgQueue::NestedSendDoneWatcher watcher(
700*635a8641SAndroid Build Coastguard Worker context, &nested_loop, context->listener_task_runner());
701*635a8641SAndroid Build Coastguard Worker nested_loop.Run();
702*635a8641SAndroid Build Coastguard Worker }
703*635a8641SAndroid Build Coastguard Worker
OnDispatchEventSignaled(base::WaitableEvent * event)704*635a8641SAndroid Build Coastguard Worker void SyncChannel::OnDispatchEventSignaled(base::WaitableEvent* event) {
705*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(sync_context()->GetDispatchEvent(), event);
706*635a8641SAndroid Build Coastguard Worker sync_context()->GetDispatchEvent()->Reset();
707*635a8641SAndroid Build Coastguard Worker
708*635a8641SAndroid Build Coastguard Worker StartWatching();
709*635a8641SAndroid Build Coastguard Worker
710*635a8641SAndroid Build Coastguard Worker // NOTE: May delete |this|.
711*635a8641SAndroid Build Coastguard Worker sync_context()->DispatchMessages();
712*635a8641SAndroid Build Coastguard Worker }
713*635a8641SAndroid Build Coastguard Worker
StartWatching()714*635a8641SAndroid Build Coastguard Worker void SyncChannel::StartWatching() {
715*635a8641SAndroid Build Coastguard Worker // |dispatch_watcher_| watches the event asynchronously, only dispatching
716*635a8641SAndroid Build Coastguard Worker // messages once the listener thread is unblocked and pumping its task queue.
717*635a8641SAndroid Build Coastguard Worker // The ReceivedSyncMsgQueue also watches this event and may dispatch
718*635a8641SAndroid Build Coastguard Worker // immediately if woken up by a message which it's allowed to dispatch.
719*635a8641SAndroid Build Coastguard Worker dispatch_watcher_.StartWatching(
720*635a8641SAndroid Build Coastguard Worker sync_context()->GetDispatchEvent(),
721*635a8641SAndroid Build Coastguard Worker base::BindOnce(&SyncChannel::OnDispatchEventSignaled,
722*635a8641SAndroid Build Coastguard Worker base::Unretained(this)),
723*635a8641SAndroid Build Coastguard Worker sync_context()->listener_task_runner());
724*635a8641SAndroid Build Coastguard Worker }
725*635a8641SAndroid Build Coastguard Worker
OnChannelInit()726*635a8641SAndroid Build Coastguard Worker void SyncChannel::OnChannelInit() {
727*635a8641SAndroid Build Coastguard Worker pre_init_sync_message_filters_.clear();
728*635a8641SAndroid Build Coastguard Worker }
729*635a8641SAndroid Build Coastguard Worker
730*635a8641SAndroid Build Coastguard Worker } // namespace IPC
731