xref: /aosp_15_r20/external/libchrome/ipc/ipc_sync_channel.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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