1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: sw=2 ts=4 et :
3  */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 #include "mozilla/ipc/MessageChannel.h"
9 
10 #include <math.h>
11 
12 #include <utility>
13 
14 #include "CrashAnnotations.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/CycleCollectedJSContext.h"
17 #include "mozilla/DebugOnly.h"
18 #include "mozilla/IntentionalCrash.h"
19 #include "mozilla/Logging.h"
20 #include "mozilla/Mutex.h"
21 #include "mozilla/ProfilerMarkers.h"
22 #include "mozilla/ScopeExit.h"
23 #include "mozilla/Sprintf.h"
24 #include "mozilla/StaticMutex.h"
25 #include "mozilla/Telemetry.h"
26 #include "mozilla/TimeStamp.h"
27 #include "mozilla/UniquePtrExtensions.h"
28 #include "mozilla/dom/ScriptSettings.h"
29 #include "mozilla/ipc/NodeController.h"
30 #include "mozilla/ipc/ProcessChild.h"
31 #include "mozilla/ipc/ProtocolUtils.h"
32 #include "nsAppRunner.h"
33 #include "nsContentUtils.h"
34 #include "nsTHashMap.h"
35 #include "nsDebug.h"
36 #include "nsExceptionHandler.h"
37 #include "nsIMemoryReporter.h"
38 #include "nsISupportsImpl.h"
39 #include "nsPrintfCString.h"
40 #include "nsThreadUtils.h"
41 
42 #ifdef OS_WIN
43 #  include "mozilla/gfx/Logging.h"
44 #endif
45 
46 // Undo the damage done by mozzconf.h
47 #undef compress
48 
49 static mozilla::LazyLogModule sLogModule("ipc");
50 #define IPC_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__))
51 
52 /*
53  * IPC design:
54  *
55  * There are three kinds of messages: async, sync, and intr. Sync and intr
56  * messages are blocking.
57  *
58  * Terminology: To dispatch a message Foo is to run the RecvFoo code for
59  * it. This is also called "handling" the message.
60  *
61  * Sync and async messages can sometimes "nest" inside other sync messages
62  * (i.e., while waiting for the sync reply, we can dispatch the inner
63  * message). Intr messages cannot nest.  The three possible nesting levels are
64  * NOT_NESTED, NESTED_INSIDE_SYNC, and NESTED_INSIDE_CPOW.  The intended uses
65  * are:
66  *   NOT_NESTED - most messages.
67  *   NESTED_INSIDE_SYNC - CPOW-related messages, which are always sync
68  *                        and can go in either direction.
69  *   NESTED_INSIDE_CPOW - messages where we don't want to dispatch
70  *                        incoming CPOWs while waiting for the response.
71  * These nesting levels are ordered: NOT_NESTED, NESTED_INSIDE_SYNC,
72  * NESTED_INSIDE_CPOW.  Async messages cannot be NESTED_INSIDE_SYNC but they can
73  * be NESTED_INSIDE_CPOW.
74  *
75  * To avoid jank, the parent process is not allowed to send NOT_NESTED sync
76  * messages. When a process is waiting for a response to a sync message M0, it
77  * will dispatch an incoming message M if:
78  *   1. M has a higher nesting level than M0, or
79  *   2. if M has the same nesting level as M0 and we're in the child, or
80  *   3. if M has the same nesting level as M0 and it was sent by the other side
81  *      while dispatching M0.
82  * The idea is that messages with higher nesting should take precendence. The
83  * purpose of rule 2 is to handle a race where both processes send to each other
84  * simultaneously. In this case, we resolve the race in favor of the parent (so
85  * the child dispatches first).
86  *
87  * Messages satisfy the following properties:
88  *   A. When waiting for a response to a sync message, we won't dispatch any
89  *      messages of nesting level.
90  *   B. Messages of the same nesting level will be dispatched roughly in the
91  *      order they were sent. The exception is when the parent and child send
92  *      sync messages to each other simulataneously. In this case, the parent's
93  *      message is dispatched first. While it is dispatched, the child may send
94  *      further nested messages, and these messages may be dispatched before the
95  *      child's original message. We can consider ordering to be preserved here
96  *      because we pretend that the child's original message wasn't sent until
97  *      after the parent's message is finished being dispatched.
98  *
99  * When waiting for a sync message reply, we dispatch an async message only if
100  * it is NESTED_INSIDE_CPOW. Normally NESTED_INSIDE_CPOW async
101  * messages are sent only from the child. However, the parent can send
102  * NESTED_INSIDE_CPOW async messages when it is creating a bridged protocol.
103  *
104  * Intr messages are blocking and can nest, but they don't participate in the
105  * nesting levels. While waiting for an intr response, all incoming messages are
106  * dispatched until a response is received. When two intr messages race with
107  * each other, a similar scheme is used to ensure that one side wins. The
108  * winning side is chosen based on the message type.
109  *
110  * Intr messages differ from sync messages in that, while sending an intr
111  * message, we may dispatch an async message. This causes some additional
112  * complexity. One issue is that replies can be received out of order. It's also
113  * more difficult to determine whether one message is nested inside
114  * another. Consequently, intr handling uses mOutOfTurnReplies and
115  * mRemoteStackDepthGuess, which are not needed for sync messages.
116  */
117 
118 using namespace mozilla;
119 using namespace mozilla::ipc;
120 
121 using mozilla::MonitorAutoLock;
122 using mozilla::MonitorAutoUnlock;
123 using mozilla::dom::AutoNoJSAPI;
124 
125 #define IPC_ASSERT(_cond, ...)                                           \
126   do {                                                                   \
127     if (!(_cond)) DebugAbort(__FILE__, __LINE__, #_cond, ##__VA_ARGS__); \
128   } while (0)
129 
130 static MessageChannel* gParentProcessBlocker;
131 
132 namespace mozilla {
133 namespace ipc {
134 
135 static const uint32_t kMinTelemetryMessageSize = 4096;
136 
137 // Note: we round the time we spend to the nearest millisecond. So a min value
138 // of 1 ms actually captures from 500us and above.
139 static const uint32_t kMinTelemetryIPCWriteLatencyMs = 1;
140 
141 // Note: we round the time we spend waiting for a response to the nearest
142 // millisecond. So a min value of 1 ms actually captures from 500us and above.
143 // This is used for both the sending and receiving side telemetry for sync IPC,
144 // (IPC_SYNC_MAIN_LATENCY_MS and IPC_SYNC_RECEIVE_MS).
145 static const uint32_t kMinTelemetrySyncIPCLatencyMs = 1;
146 
147 const int32_t MessageChannel::kNoTimeout = INT32_MIN;
148 
149 // static
150 bool MessageChannel::sIsPumpingMessages = false;
151 
152 enum Direction { IN_MESSAGE, OUT_MESSAGE };
153 
154 class MessageChannel::InterruptFrame {
155  private:
156   enum Semantics { INTR_SEMS, SYNC_SEMS, ASYNC_SEMS };
157 
158  public:
InterruptFrame(Direction direction,const Message * msg)159   InterruptFrame(Direction direction, const Message* msg)
160       : mMessageName(msg->name()),
161         mMessageRoutingId(msg->routing_id()),
162         mMesageSemantics(msg->is_interrupt() ? INTR_SEMS
163                          : msg->is_sync()    ? SYNC_SEMS
164                                              : ASYNC_SEMS),
165         mDirection(direction),
166         mMoved(false) {
167     MOZ_RELEASE_ASSERT(mMessageName);
168   }
169 
InterruptFrame(InterruptFrame && aOther)170   InterruptFrame(InterruptFrame&& aOther) {
171     MOZ_RELEASE_ASSERT(aOther.mMessageName);
172     mMessageName = aOther.mMessageName;
173     aOther.mMessageName = nullptr;
174     mMoved = aOther.mMoved;
175     aOther.mMoved = true;
176 
177     mMessageRoutingId = aOther.mMessageRoutingId;
178     mMesageSemantics = aOther.mMesageSemantics;
179     mDirection = aOther.mDirection;
180   }
181 
~InterruptFrame()182   ~InterruptFrame() { MOZ_RELEASE_ASSERT(mMessageName || mMoved); }
183 
operator =(InterruptFrame && aOther)184   InterruptFrame& operator=(InterruptFrame&& aOther) {
185     MOZ_RELEASE_ASSERT(&aOther != this);
186     this->~InterruptFrame();
187     new (this) InterruptFrame(std::move(aOther));
188     return *this;
189   }
190 
IsInterruptIncall() const191   bool IsInterruptIncall() const {
192     return INTR_SEMS == mMesageSemantics && IN_MESSAGE == mDirection;
193   }
194 
IsInterruptOutcall() const195   bool IsInterruptOutcall() const {
196     return INTR_SEMS == mMesageSemantics && OUT_MESSAGE == mDirection;
197   }
198 
IsOutgoingSync() const199   bool IsOutgoingSync() const {
200     return (mMesageSemantics == INTR_SEMS || mMesageSemantics == SYNC_SEMS) &&
201            mDirection == OUT_MESSAGE;
202   }
203 
Describe(int32_t * id,const char ** dir,const char ** sems,const char ** name) const204   void Describe(int32_t* id, const char** dir, const char** sems,
205                 const char** name) const {
206     *id = mMessageRoutingId;
207     *dir = (IN_MESSAGE == mDirection) ? "in" : "out";
208     *sems = (INTR_SEMS == mMesageSemantics)   ? "intr"
209             : (SYNC_SEMS == mMesageSemantics) ? "sync"
210                                               : "async";
211     *name = mMessageName;
212   }
213 
GetRoutingId() const214   int32_t GetRoutingId() const { return mMessageRoutingId; }
215 
216  private:
217   const char* mMessageName;
218   int32_t mMessageRoutingId;
219   Semantics mMesageSemantics;
220   Direction mDirection;
221   bool mMoved;
222 
223   // Disable harmful methods.
224   InterruptFrame(const InterruptFrame& aOther) = delete;
225   InterruptFrame& operator=(const InterruptFrame&) = delete;
226 };
227 
228 class MOZ_STACK_CLASS MessageChannel::CxxStackFrame {
229  public:
CxxStackFrame(MessageChannel & that,Direction direction,const Message * msg)230   CxxStackFrame(MessageChannel& that, Direction direction, const Message* msg)
231       : mThat(that) {
232     mThat.AssertWorkerThread();
233 
234     if (mThat.mCxxStackFrames.empty()) mThat.EnteredCxxStack();
235 
236     if (!mThat.mCxxStackFrames.append(InterruptFrame(direction, msg)))
237       MOZ_CRASH();
238 
239     const InterruptFrame& frame = mThat.mCxxStackFrames.back();
240 
241     if (frame.IsInterruptIncall()) mThat.EnteredCall();
242 
243     if (frame.IsOutgoingSync()) mThat.EnteredSyncSend();
244 
245     mThat.mSawInterruptOutMsg |= frame.IsInterruptOutcall();
246   }
247 
~CxxStackFrame()248   ~CxxStackFrame() {
249     mThat.AssertWorkerThread();
250 
251     MOZ_RELEASE_ASSERT(!mThat.mCxxStackFrames.empty());
252 
253     const InterruptFrame& frame = mThat.mCxxStackFrames.back();
254     bool exitingSync = frame.IsOutgoingSync();
255     bool exitingCall = frame.IsInterruptIncall();
256     mThat.mCxxStackFrames.shrinkBy(1);
257 
258     bool exitingStack = mThat.mCxxStackFrames.empty();
259 
260     // According how lifetime is declared, mListener on MessageChannel
261     // lives longer than MessageChannel itself.  Hence is expected to
262     // be alive.  There is nothing to even assert here, there is no place
263     // we would be nullifying mListener on MessageChannel.
264 
265     if (exitingCall) mThat.ExitedCall();
266 
267     if (exitingSync) mThat.ExitedSyncSend();
268 
269     if (exitingStack) mThat.ExitedCxxStack();
270   }
271 
272  private:
273   MessageChannel& mThat;
274 
275   // Disable harmful methods.
276   CxxStackFrame() = delete;
277   CxxStackFrame(const CxxStackFrame&) = delete;
278   CxxStackFrame& operator=(const CxxStackFrame&) = delete;
279 };
280 
281 class AutoEnterTransaction {
282  public:
AutoEnterTransaction(MessageChannel * aChan,int32_t aMsgSeqno,int32_t aTransactionID,int aNestedLevel)283   explicit AutoEnterTransaction(MessageChannel* aChan, int32_t aMsgSeqno,
284                                 int32_t aTransactionID, int aNestedLevel)
285       : mChan(aChan),
286         mActive(true),
287         mOutgoing(true),
288         mNestedLevel(aNestedLevel),
289         mSeqno(aMsgSeqno),
290         mTransaction(aTransactionID),
291         mNext(mChan->mTransactionStack) {
292     mChan->mMonitor->AssertCurrentThreadOwns();
293     mChan->mTransactionStack = this;
294   }
295 
AutoEnterTransaction(MessageChannel * aChan,const IPC::Message & aMessage)296   explicit AutoEnterTransaction(MessageChannel* aChan,
297                                 const IPC::Message& aMessage)
298       : mChan(aChan),
299         mActive(true),
300         mOutgoing(false),
301         mNestedLevel(aMessage.nested_level()),
302         mSeqno(aMessage.seqno()),
303         mTransaction(aMessage.transaction_id()),
304         mNext(mChan->mTransactionStack) {
305     mChan->mMonitor->AssertCurrentThreadOwns();
306 
307     if (!aMessage.is_sync()) {
308       mActive = false;
309       return;
310     }
311 
312     mChan->mTransactionStack = this;
313   }
314 
~AutoEnterTransaction()315   ~AutoEnterTransaction() {
316     mChan->mMonitor->AssertCurrentThreadOwns();
317     if (mActive) {
318       mChan->mTransactionStack = mNext;
319     }
320   }
321 
Cancel()322   void Cancel() {
323     AutoEnterTransaction* cur = mChan->mTransactionStack;
324     MOZ_RELEASE_ASSERT(cur == this);
325     while (cur && cur->mNestedLevel != IPC::Message::NOT_NESTED) {
326       // Note that, in the following situation, we will cancel multiple
327       // transactions:
328       // 1. Parent sends NESTED_INSIDE_SYNC message P1 to child.
329       // 2. Child sends NESTED_INSIDE_SYNC message C1 to child.
330       // 3. Child dispatches P1, parent blocks.
331       // 4. Child cancels.
332       // In this case, both P1 and C1 are cancelled. The parent will
333       // remove C1 from its queue when it gets the cancellation message.
334       MOZ_RELEASE_ASSERT(cur->mActive);
335       cur->mActive = false;
336       cur = cur->mNext;
337     }
338 
339     mChan->mTransactionStack = cur;
340 
341     MOZ_RELEASE_ASSERT(IsComplete());
342   }
343 
AwaitingSyncReply() const344   bool AwaitingSyncReply() const {
345     MOZ_RELEASE_ASSERT(mActive);
346     if (mOutgoing) {
347       return true;
348     }
349     return mNext ? mNext->AwaitingSyncReply() : false;
350   }
351 
AwaitingSyncReplyNestedLevel() const352   int AwaitingSyncReplyNestedLevel() const {
353     MOZ_RELEASE_ASSERT(mActive);
354     if (mOutgoing) {
355       return mNestedLevel;
356     }
357     return mNext ? mNext->AwaitingSyncReplyNestedLevel() : 0;
358   }
359 
DispatchingSyncMessage() const360   bool DispatchingSyncMessage() const {
361     MOZ_RELEASE_ASSERT(mActive);
362     if (!mOutgoing) {
363       return true;
364     }
365     return mNext ? mNext->DispatchingSyncMessage() : false;
366   }
367 
DispatchingSyncMessageNestedLevel() const368   int DispatchingSyncMessageNestedLevel() const {
369     MOZ_RELEASE_ASSERT(mActive);
370     if (!mOutgoing) {
371       return mNestedLevel;
372     }
373     return mNext ? mNext->DispatchingSyncMessageNestedLevel() : 0;
374   }
375 
NestedLevel() const376   int NestedLevel() const {
377     MOZ_RELEASE_ASSERT(mActive);
378     return mNestedLevel;
379   }
380 
SequenceNumber() const381   int32_t SequenceNumber() const {
382     MOZ_RELEASE_ASSERT(mActive);
383     return mSeqno;
384   }
385 
TransactionID() const386   int32_t TransactionID() const {
387     MOZ_RELEASE_ASSERT(mActive);
388     return mTransaction;
389   }
390 
ReceivedReply(IPC::Message && aMessage)391   void ReceivedReply(IPC::Message&& aMessage) {
392     MOZ_RELEASE_ASSERT(aMessage.seqno() == mSeqno);
393     MOZ_RELEASE_ASSERT(aMessage.transaction_id() == mTransaction);
394     MOZ_RELEASE_ASSERT(!mReply);
395     IPC_LOG("Reply received on worker thread: seqno=%d", mSeqno);
396     mReply = MakeUnique<IPC::Message>(std::move(aMessage));
397     MOZ_RELEASE_ASSERT(IsComplete());
398   }
399 
HandleReply(IPC::Message && aMessage)400   void HandleReply(IPC::Message&& aMessage) {
401     AutoEnterTransaction* cur = mChan->mTransactionStack;
402     MOZ_RELEASE_ASSERT(cur == this);
403     while (cur) {
404       MOZ_RELEASE_ASSERT(cur->mActive);
405       if (aMessage.seqno() == cur->mSeqno) {
406         cur->ReceivedReply(std::move(aMessage));
407         break;
408       }
409       cur = cur->mNext;
410       MOZ_RELEASE_ASSERT(cur);
411     }
412   }
413 
IsComplete()414   bool IsComplete() { return !mActive || mReply; }
415 
IsOutgoing()416   bool IsOutgoing() { return mOutgoing; }
417 
IsCanceled()418   bool IsCanceled() { return !mActive; }
419 
IsBottom() const420   bool IsBottom() const { return !mNext; }
421 
IsError()422   bool IsError() {
423     MOZ_RELEASE_ASSERT(mReply);
424     return mReply->is_reply_error();
425   }
426 
GetReply()427   UniquePtr<IPC::Message> GetReply() { return std::move(mReply); }
428 
429  private:
430   MessageChannel* mChan;
431 
432   // Active is true if this transaction is on the mChan->mTransactionStack
433   // stack. Generally we're not on the stack if the transaction was canceled
434   // or if it was for a message that doesn't require transactions (an async
435   // message).
436   bool mActive;
437 
438   // Is this stack frame for an outgoing message?
439   bool mOutgoing;
440 
441   // Properties of the message being sent/received.
442   int mNestedLevel;
443   int32_t mSeqno;
444   int32_t mTransaction;
445 
446   // Next item in mChan->mTransactionStack.
447   AutoEnterTransaction* mNext;
448 
449   // Pointer the a reply received for this message, if one was received.
450   UniquePtr<IPC::Message> mReply;
451 };
452 
453 class PendingResponseReporter final : public nsIMemoryReporter {
454   ~PendingResponseReporter() = default;
455 
456  public:
457   NS_DECL_THREADSAFE_ISUPPORTS
458 
459   NS_IMETHOD
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)460   CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
461                  bool aAnonymize) override {
462     MOZ_COLLECT_REPORT(
463         "unresolved-ipc-responses", KIND_OTHER, UNITS_COUNT,
464         MessageChannel::gUnresolvedResponses,
465         "Outstanding IPC async message responses that are still not resolved.");
466     return NS_OK;
467   }
468 };
469 
470 NS_IMPL_ISUPPORTS(PendingResponseReporter, nsIMemoryReporter)
471 
472 class ChannelCountReporter final : public nsIMemoryReporter {
473   ~ChannelCountReporter() = default;
474 
475   struct ChannelCounts {
476     size_t mNow;
477     size_t mMax;
478 
ChannelCountsmozilla::ipc::ChannelCountReporter::ChannelCounts479     ChannelCounts() : mNow(0), mMax(0) {}
480 
Incmozilla::ipc::ChannelCountReporter::ChannelCounts481     void Inc() {
482       ++mNow;
483       if (mMax < mNow) {
484         mMax = mNow;
485       }
486     }
487 
Decmozilla::ipc::ChannelCountReporter::ChannelCounts488     void Dec() {
489       MOZ_ASSERT(mNow > 0);
490       --mNow;
491     }
492   };
493 
494   using CountTable = nsTHashMap<nsDepCharHashKey, ChannelCounts>;
495 
496   static StaticMutex sChannelCountMutex;
497   static CountTable* sChannelCounts;
498 
499  public:
500   NS_DECL_THREADSAFE_ISUPPORTS
501 
502   NS_IMETHOD
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)503   CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
504                  bool aAnonymize) override {
505     AutoTArray<std::pair<const char*, ChannelCounts>, 16> counts;
506     {
507       StaticMutexAutoLock countLock(sChannelCountMutex);
508       if (!sChannelCounts) {
509         return NS_OK;
510       }
511       counts.SetCapacity(sChannelCounts->Count());
512       for (const auto& entry : *sChannelCounts) {
513         counts.AppendElement(std::pair{entry.GetKey(), entry.GetData()});
514       }
515     }
516 
517     for (const auto& entry : counts) {
518       nsPrintfCString pathNow("ipc-channels/%s", entry.first);
519       nsPrintfCString pathMax("ipc-channels-peak/%s", entry.first);
520       nsPrintfCString descNow(
521           "Number of IPC channels for"
522           " top-level actor type %s",
523           entry.first);
524       nsPrintfCString descMax(
525           "Peak number of IPC channels for"
526           " top-level actor type %s",
527           entry.first);
528 
529       aHandleReport->Callback(""_ns, pathNow, KIND_OTHER, UNITS_COUNT,
530                               entry.second.mNow, descNow, aData);
531       aHandleReport->Callback(""_ns, pathMax, KIND_OTHER, UNITS_COUNT,
532                               entry.second.mMax, descMax, aData);
533     }
534     return NS_OK;
535   }
536 
Increment(const char * aName)537   static void Increment(const char* aName) {
538     StaticMutexAutoLock countLock(sChannelCountMutex);
539     if (!sChannelCounts) {
540       sChannelCounts = new CountTable;
541     }
542     sChannelCounts->LookupOrInsert(aName).Inc();
543   }
544 
Decrement(const char * aName)545   static void Decrement(const char* aName) {
546     StaticMutexAutoLock countLock(sChannelCountMutex);
547     MOZ_ASSERT(sChannelCounts);
548     sChannelCounts->LookupOrInsert(aName).Dec();
549   }
550 };
551 
552 StaticMutex ChannelCountReporter::sChannelCountMutex;
553 ChannelCountReporter::CountTable* ChannelCountReporter::sChannelCounts;
554 
NS_IMPL_ISUPPORTS(ChannelCountReporter,nsIMemoryReporter)555 NS_IMPL_ISUPPORTS(ChannelCountReporter, nsIMemoryReporter)
556 
557 // In child processes, the first MessageChannel is created before
558 // XPCOM is initialized enough to construct the memory reporter
559 // manager.  This retries every time a MessageChannel is constructed,
560 // which is good enough in practice.
561 template <class Reporter>
562 static void TryRegisterStrongMemoryReporter() {
563   static Atomic<bool> registered;
564   if (registered.compareExchange(false, true)) {
565     RefPtr<Reporter> reporter = new Reporter();
566     if (NS_FAILED(RegisterStrongMemoryReporter(reporter))) {
567       registered = false;
568     }
569   }
570 }
571 
572 Atomic<size_t> MessageChannel::gUnresolvedResponses;
573 
MessageChannel(const char * aName,IToplevelProtocol * aListener)574 MessageChannel::MessageChannel(const char* aName, IToplevelProtocol* aListener)
575     : mName(aName),
576       mListener(aListener),
577       mChannelState(ChannelClosed),
578       mSide(UnknownSide),
579       mIsCrossProcess(false),
580       mChannelErrorTask(nullptr),
581       mTimeoutMs(kNoTimeout),
582       mInTimeoutSecondHalf(false),
583       mNextSeqno(0),
584       mLastSendError(SyncSendError::SendSuccess),
585       mDispatchingAsyncMessage(false),
586       mDispatchingAsyncMessageNestedLevel(0),
587       mTransactionStack(nullptr),
588       mTimedOutMessageSeqno(0),
589       mTimedOutMessageNestedLevel(0),
590       mMaybeDeferredPendingCount(0),
591       mRemoteStackDepthGuess(0),
592       mSawInterruptOutMsg(false),
593       mIsWaitingForIncoming(false),
594       mAbortOnError(false),
595       mNotifiedChannelDone(false),
596       mFlags(REQUIRE_DEFAULT),
597       mIsPostponingSends(false),
598       mBuildIDsConfirmedMatch(false),
599       mIsSameThreadChannel(false) {
600   MOZ_COUNT_CTOR(ipc::MessageChannel);
601 
602 #ifdef OS_WIN
603   mTopFrame = nullptr;
604   mIsSyncWaitingOnNonMainThread = false;
605 
606   mEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
607   MOZ_RELEASE_ASSERT(mEvent, "CreateEvent failed! Nothing is going to work!");
608 #endif
609 
610   TryRegisterStrongMemoryReporter<PendingResponseReporter>();
611   TryRegisterStrongMemoryReporter<ChannelCountReporter>();
612 }
613 
~MessageChannel()614 MessageChannel::~MessageChannel() {
615   MOZ_COUNT_DTOR(ipc::MessageChannel);
616   IPC_ASSERT(mCxxStackFrames.empty(), "mismatched CxxStackFrame ctor/dtors");
617 #ifdef OS_WIN
618   if (mEvent) {
619     BOOL ok = CloseHandle(mEvent);
620     mEvent = nullptr;
621 
622     if (!ok) {
623       gfxDevCrash(mozilla::gfx::LogReason::MessageChannelCloseFailure)
624           << "MessageChannel failed to close. GetLastError: " << GetLastError();
625     }
626     MOZ_RELEASE_ASSERT(ok);
627   } else {
628     gfxDevCrash(mozilla::gfx::LogReason::MessageChannelCloseFailure)
629         << "MessageChannel destructor ran without an mEvent Handle";
630   }
631 #endif
632   Clear();
633 }
634 
635 #ifdef DEBUG
AssertMaybeDeferredCountCorrect()636 void MessageChannel::AssertMaybeDeferredCountCorrect() {
637   size_t count = 0;
638   for (MessageTask* task : mPending) {
639     if (!IsAlwaysDeferred(task->Msg())) {
640       count++;
641     }
642   }
643 
644   MOZ_ASSERT(count == mMaybeDeferredPendingCount);
645 }
646 #endif
647 
648 // This function returns the current transaction ID. Since the notion of a
649 // "current transaction" can be hard to define when messages race with each
650 // other and one gets canceled and the other doesn't, we require that this
651 // function is only called when the current transaction is known to be for a
652 // NESTED_INSIDE_SYNC message. In that case, we know for sure what the caller is
653 // looking for.
CurrentNestedInsideSyncTransaction() const654 int32_t MessageChannel::CurrentNestedInsideSyncTransaction() const {
655   mMonitor->AssertCurrentThreadOwns();
656   if (!mTransactionStack) {
657     return 0;
658   }
659   MOZ_RELEASE_ASSERT(mTransactionStack->NestedLevel() ==
660                      IPC::Message::NESTED_INSIDE_SYNC);
661   return mTransactionStack->TransactionID();
662 }
663 
AwaitingSyncReply() const664 bool MessageChannel::AwaitingSyncReply() const {
665   mMonitor->AssertCurrentThreadOwns();
666   return mTransactionStack ? mTransactionStack->AwaitingSyncReply() : false;
667 }
668 
AwaitingSyncReplyNestedLevel() const669 int MessageChannel::AwaitingSyncReplyNestedLevel() const {
670   mMonitor->AssertCurrentThreadOwns();
671   return mTransactionStack ? mTransactionStack->AwaitingSyncReplyNestedLevel()
672                            : 0;
673 }
674 
DispatchingSyncMessage() const675 bool MessageChannel::DispatchingSyncMessage() const {
676   mMonitor->AssertCurrentThreadOwns();
677   return mTransactionStack ? mTransactionStack->DispatchingSyncMessage()
678                            : false;
679 }
680 
DispatchingSyncMessageNestedLevel() const681 int MessageChannel::DispatchingSyncMessageNestedLevel() const {
682   mMonitor->AssertCurrentThreadOwns();
683   return mTransactionStack
684              ? mTransactionStack->DispatchingSyncMessageNestedLevel()
685              : 0;
686 }
687 
PrintErrorMessage(Side side,const char * channelName,const char * msg)688 static void PrintErrorMessage(Side side, const char* channelName,
689                               const char* msg) {
690   const char* from = (side == ChildSide)
691                          ? "Child"
692                          : ((side == ParentSide) ? "Parent" : "Unknown");
693   printf_stderr("\n###!!! [%s][%s] Error: %s\n\n", from, channelName, msg);
694 }
695 
Connected() const696 bool MessageChannel::Connected() const {
697   mMonitor->AssertCurrentThreadOwns();
698 
699   // The transport layer allows us to send messages before
700   // receiving the "connected" ack from the remote side.
701   return (ChannelOpening == mChannelState || ChannelConnected == mChannelState);
702 }
703 
CanSend() const704 bool MessageChannel::CanSend() const {
705   if (!mMonitor) {
706     return false;
707   }
708   MonitorAutoLock lock(*mMonitor);
709   return Connected();
710 }
711 
Clear()712 void MessageChannel::Clear() {
713   // Don't clear mWorkerThread; we use it in AssertWorkerThread().
714   //
715   // Also don't clear mListener.  If we clear it, then sending a message
716   // through this channel after it's Clear()'ed can cause this process to
717   // crash.
718   //
719   // In practice, mListener owns the channel, so the channel gets deleted
720   // before mListener.  But just to be safe, mListener is a weak pointer.
721 
722 #if !defined(ANDROID)
723   if (!Unsound_IsClosed()) {
724     CrashReporter::AnnotateCrashReport(
725         CrashReporter::Annotation::IPCFatalErrorProtocol,
726         nsDependentCString(mName));
727     switch (mChannelState) {
728       case ChannelOpening:
729         MOZ_CRASH(
730             "MessageChannel destroyed without being closed "
731             "(mChannelState == ChannelOpening).");
732         break;
733       case ChannelConnected:
734         MOZ_CRASH(
735             "MessageChannel destroyed without being closed "
736             "(mChannelState == ChannelConnected).");
737         break;
738       case ChannelTimeout:
739         MOZ_CRASH(
740             "MessageChannel destroyed without being closed "
741             "(mChannelState == ChannelTimeout).");
742         break;
743       case ChannelClosing:
744         MOZ_CRASH(
745             "MessageChannel destroyed without being closed "
746             "(mChannelState == ChannelClosing).");
747         break;
748       case ChannelError:
749         MOZ_CRASH(
750             "MessageChannel destroyed without being closed "
751             "(mChannelState == ChannelError).");
752         break;
753       default:
754         MOZ_CRASH("MessageChannel destroyed without being closed.");
755     }
756   }
757 #endif
758 
759   if (gParentProcessBlocker == this) {
760     gParentProcessBlocker = nullptr;
761   }
762 
763   gUnresolvedResponses -= mPendingResponses.size();
764   for (auto& pair : mPendingResponses) {
765     pair.second.get()->Reject(ResponseRejectReason::ChannelClosed);
766   }
767   mPendingResponses.clear();
768 
769   if (mLink != nullptr && mIsCrossProcess) {
770     ChannelCountReporter::Decrement(mName);
771   }
772 
773   if (mLink) {
774     mLink->PrepareToDestroy();
775     mLink = nullptr;
776   }
777 
778   if (mChannelErrorTask) {
779     mChannelErrorTask->Cancel();
780     mChannelErrorTask = nullptr;
781   }
782 
783   // Free up any memory used by pending messages.
784   mPending.clear();
785 
786   mMaybeDeferredPendingCount = 0;
787 
788   mOutOfTurnReplies.clear();
789   while (!mDeferred.empty()) {
790     mDeferred.pop();
791   }
792 }
793 
Open(ScopedPort aPort,Side aSide,nsISerialEventTarget * aEventTarget)794 bool MessageChannel::Open(ScopedPort aPort, Side aSide,
795                           nsISerialEventTarget* aEventTarget) {
796   MOZ_ASSERT(!mLink, "Open() called > once");
797 
798   mMonitor = new RefCountedMonitor();
799   mWorkerThread = aEventTarget ? aEventTarget : GetCurrentSerialEventTarget();
800   MOZ_ASSERT(mWorkerThread, "We should always be on a nsISerialEventTarget");
801   mListener->OnIPCChannelOpened();
802 
803   mLink = MakeUnique<PortLink>(this, std::move(aPort));
804   mSide = aSide;
805   return true;
806 }
807 
GetOppSide(Side aSide)808 static Side GetOppSide(Side aSide) {
809   switch (aSide) {
810     case ChildSide:
811       return ParentSide;
812     case ParentSide:
813       return ChildSide;
814     default:
815       return UnknownSide;
816   }
817 }
818 
Open(MessageChannel * aTargetChan,nsISerialEventTarget * aEventTarget,Side aSide)819 bool MessageChannel::Open(MessageChannel* aTargetChan,
820                           nsISerialEventTarget* aEventTarget, Side aSide) {
821   // Opens a connection to another thread in the same process.
822 
823   MOZ_ASSERT(aTargetChan, "Need a target channel");
824   MOZ_ASSERT(ChannelClosed == mChannelState, "Not currently closed");
825 
826   std::pair<ScopedPort, ScopedPort> ports =
827       NodeController::GetSingleton()->CreatePortPair();
828 
829   // NOTE: This dispatch must be sync as it captures locals by non-owning
830   // reference, however we can't use `NS_DISPATCH_SYNC` as that will spin a
831   // nested event loop, and doesn't work with certain types of calling event
832   // targets.
833   base::WaitableEvent event(/* manual_reset */ true,
834                             /* initially_signaled */ false);
835   MOZ_ALWAYS_SUCCEEDS(aEventTarget->Dispatch(NS_NewCancelableRunnableFunction(
836       "ipc::MessageChannel::OpenAsOtherThread", [&]() {
837         aTargetChan->Open(std::move(ports.second), GetOppSide(aSide),
838                           aEventTarget);
839         event.Signal();
840       })));
841   bool ok = event.Wait();
842   MOZ_RELEASE_ASSERT(ok);
843 
844   // Now that the other side has connected, open the port on our side.
845   return Open(std::move(ports.first), aSide);
846 }
847 
OpenOnSameThread(MessageChannel * aTargetChan,mozilla::ipc::Side aSide)848 bool MessageChannel::OpenOnSameThread(MessageChannel* aTargetChan,
849                                       mozilla::ipc::Side aSide) {
850   auto [porta, portb] = NodeController::GetSingleton()->CreatePortPair();
851 
852   aTargetChan->mIsSameThreadChannel = true;
853   mIsSameThreadChannel = true;
854 
855   auto* currentThread = GetCurrentSerialEventTarget();
856   return aTargetChan->Open(std::move(portb), GetOppSide(aSide),
857                            currentThread) &&
858          Open(std::move(porta), aSide, currentThread);
859 }
860 
Send(UniquePtr<Message> aMsg)861 bool MessageChannel::Send(UniquePtr<Message> aMsg) {
862   if (aMsg->size() >= kMinTelemetryMessageSize) {
863     Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE2, aMsg->size());
864   }
865 
866   // If the message was created by the IPC bindings, the create time will be
867   // recorded. Use this information to report the
868   // IPC_WRITE_MAIN_THREAD_LATENCY_MS (time from message creation to it being
869   // sent).
870   if (NS_IsMainThread() && aMsg->create_time()) {
871     uint32_t latencyMs = round(
872         (mozilla::TimeStamp::Now() - aMsg->create_time()).ToMilliseconds());
873     if (latencyMs >= kMinTelemetryIPCWriteLatencyMs) {
874       mozilla::Telemetry::Accumulate(
875           mozilla::Telemetry::IPC_WRITE_MAIN_THREAD_LATENCY_MS,
876           nsDependentCString(aMsg->name()), latencyMs);
877     }
878   }
879 
880   MOZ_RELEASE_ASSERT(!aMsg->is_sync());
881   MOZ_RELEASE_ASSERT(aMsg->nested_level() != IPC::Message::NESTED_INSIDE_SYNC);
882 
883   CxxStackFrame frame(*this, OUT_MESSAGE, aMsg.get());
884 
885   AssertWorkerThread();
886   mMonitor->AssertNotCurrentThreadOwns();
887   if (MSG_ROUTING_NONE == aMsg->routing_id()) {
888     ReportMessageRouteError("MessageChannel::Send");
889     return false;
890   }
891 
892   if (aMsg->seqno() == 0) {
893     aMsg->set_seqno(NextSeqno());
894   }
895 
896   MonitorAutoLock lock(*mMonitor);
897   if (!Connected()) {
898     ReportConnectionError("MessageChannel", aMsg.get());
899     return false;
900   }
901 
902   AddProfilerMarker(*aMsg, MessageDirection::eSending);
903   SendMessageToLink(std::move(aMsg));
904   return true;
905 }
906 
SendMessageToLink(UniquePtr<Message> aMsg)907 void MessageChannel::SendMessageToLink(UniquePtr<Message> aMsg) {
908   if (mIsPostponingSends) {
909     mPostponedSends.push_back(std::move(aMsg));
910     return;
911   }
912   mLink->SendMessage(std::move(aMsg));
913 }
914 
BeginPostponingSends()915 void MessageChannel::BeginPostponingSends() {
916   AssertWorkerThread();
917   mMonitor->AssertNotCurrentThreadOwns();
918 
919   MonitorAutoLock lock(*mMonitor);
920   {
921     MOZ_ASSERT(!mIsPostponingSends);
922     mIsPostponingSends = true;
923   }
924 }
925 
StopPostponingSends()926 void MessageChannel::StopPostponingSends() {
927   // Note: this can be called from any thread.
928   MonitorAutoLock lock(*mMonitor);
929 
930   MOZ_ASSERT(mIsPostponingSends);
931 
932   for (UniquePtr<Message>& iter : mPostponedSends) {
933     mLink->SendMessage(std::move(iter));
934   }
935 
936   // We unset this after SendMessage so we can make correct thread
937   // assertions in MessageLink.
938   mIsPostponingSends = false;
939   mPostponedSends.clear();
940 }
941 
PopCallback(const Message & aMsg)942 UniquePtr<MessageChannel::UntypedCallbackHolder> MessageChannel::PopCallback(
943     const Message& aMsg) {
944   auto iter = mPendingResponses.find(aMsg.seqno());
945   if (iter != mPendingResponses.end()) {
946     UniquePtr<MessageChannel::UntypedCallbackHolder> ret =
947         std::move(iter->second);
948     mPendingResponses.erase(iter);
949     gUnresolvedResponses--;
950     return ret;
951   }
952   return nullptr;
953 }
954 
RejectPendingResponsesForActor(ActorIdType aActorId)955 void MessageChannel::RejectPendingResponsesForActor(ActorIdType aActorId) {
956   auto itr = mPendingResponses.begin();
957   while (itr != mPendingResponses.end()) {
958     if (itr->second.get()->mActorId != aActorId) {
959       ++itr;
960       continue;
961     }
962     itr->second.get()->Reject(ResponseRejectReason::ActorDestroyed);
963     // Take special care of advancing the iterator since we are
964     // removing it while iterating.
965     itr = mPendingResponses.erase(itr);
966     gUnresolvedResponses--;
967   }
968 }
969 
970 class BuildIDsMatchMessage : public IPC::Message {
971  public:
BuildIDsMatchMessage()972   BuildIDsMatchMessage()
973       : IPC::Message(MSG_ROUTING_NONE, BUILD_IDS_MATCH_MESSAGE_TYPE) {}
Log(const std::string & aPrefix,FILE * aOutf) const974   void Log(const std::string& aPrefix, FILE* aOutf) const {
975     fputs("(special `Build IDs match' message)", aOutf);
976   }
977 };
978 
979 // Send the parent a special async message to confirm when the parent and child
980 // are of the same buildID. Skips sending the message and returns false if the
981 // buildIDs don't match. This is a minor variation on
982 // MessageChannel::Send(Message* aMsg).
SendBuildIDsMatchMessage(const char * aParentBuildID)983 bool MessageChannel::SendBuildIDsMatchMessage(const char* aParentBuildID) {
984   MOZ_ASSERT(!XRE_IsParentProcess());
985 
986   nsCString parentBuildID(aParentBuildID);
987   nsCString childBuildID(mozilla::PlatformBuildID());
988 
989   if (parentBuildID != childBuildID) {
990     // The build IDs didn't match, usually because an update occurred in the
991     // background.
992     return false;
993   }
994 
995   auto msg = MakeUnique<BuildIDsMatchMessage>();
996 
997   MOZ_RELEASE_ASSERT(!msg->is_sync());
998   MOZ_RELEASE_ASSERT(msg->nested_level() != IPC::Message::NESTED_INSIDE_SYNC);
999 
1000   AssertWorkerThread();
1001   mMonitor->AssertNotCurrentThreadOwns();
1002   // Don't check for MSG_ROUTING_NONE.
1003 
1004   MonitorAutoLock lock(*mMonitor);
1005   if (!Connected()) {
1006     ReportConnectionError("MessageChannel", msg.get());
1007     return false;
1008   }
1009 
1010 #if defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
1011   // Technically, the behavior is interesting for any kind of process
1012   // but when exercising tests, we want to crash only a content process and
1013   // avoid making noise with other kind of processes crashing
1014   if (const char* dontSend = PR_GetEnv("MOZ_BUILDID_MATCH_DONTSEND")) {
1015     if (dontSend[0] == '1') {
1016       // Bug 1732999: We are going to crash, so we need to advise leak check
1017       // tooling to avoid intermittent missing leakcheck
1018       NoteIntentionalCrash(XRE_GetProcessTypeString());
1019       if (XRE_IsContentProcess()) {
1020         // Make sure we do not die too early, as this causes weird behavior
1021         PR_Sleep(PR_MillisecondsToInterval(1000));
1022         return false;
1023       }
1024     }
1025   }
1026 #endif
1027 
1028   mLink->SendMessage(std::move(msg));
1029   return true;
1030 }
1031 
1032 class CancelMessage : public IPC::Message {
1033  public:
CancelMessage(int transaction)1034   explicit CancelMessage(int transaction)
1035       : IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE) {
1036     set_transaction_id(transaction);
1037   }
Read(const Message * msg)1038   static bool Read(const Message* msg) { return true; }
Log(const std::string & aPrefix,FILE * aOutf) const1039   void Log(const std::string& aPrefix, FILE* aOutf) const {
1040     fputs("(special `Cancel' message)", aOutf);
1041   }
1042 };
1043 
MaybeInterceptSpecialIOMessage(const Message & aMsg)1044 bool MessageChannel::MaybeInterceptSpecialIOMessage(const Message& aMsg) {
1045   mMonitor->AssertCurrentThreadOwns();
1046 
1047   if (MSG_ROUTING_NONE == aMsg.routing_id()) {
1048     if (GOODBYE_MESSAGE_TYPE == aMsg.type()) {
1049       // :TODO: Sort out Close() on this side racing with Close() on the
1050       // other side
1051       mChannelState = ChannelClosing;
1052       if (LoggingEnabled()) {
1053         printf("NOTE: %s process received `Goodbye', closing down\n",
1054                (mSide == ChildSide) ? "child" : "parent");
1055       }
1056       return true;
1057     } else if (CANCEL_MESSAGE_TYPE == aMsg.type()) {
1058       IPC_LOG("Cancel from message");
1059       CancelTransaction(aMsg.transaction_id());
1060       NotifyWorkerThread();
1061       return true;
1062     } else if (BUILD_IDS_MATCH_MESSAGE_TYPE == aMsg.type()) {
1063       IPC_LOG("Build IDs match message");
1064       mBuildIDsConfirmedMatch = true;
1065       return true;
1066     } else if (IMPENDING_SHUTDOWN_MESSAGE_TYPE == aMsg.type()) {
1067       IPC_LOG("Impending Shutdown received");
1068       ProcessChild::NotifyImpendingShutdown();
1069       return true;
1070     }
1071   }
1072   return false;
1073 }
1074 
1075 /* static */
IsAlwaysDeferred(const Message & aMsg)1076 bool MessageChannel::IsAlwaysDeferred(const Message& aMsg) {
1077   // If a message is not NESTED_INSIDE_CPOW and not sync, then we always defer
1078   // it.
1079   return aMsg.nested_level() != IPC::Message::NESTED_INSIDE_CPOW &&
1080          !aMsg.is_sync();
1081 }
1082 
ShouldDeferMessage(const Message & aMsg)1083 bool MessageChannel::ShouldDeferMessage(const Message& aMsg) {
1084   // Never defer messages that have the highest nested level, even async
1085   // ones. This is safe because only the child can send these messages, so
1086   // they can never nest.
1087   if (aMsg.nested_level() == IPC::Message::NESTED_INSIDE_CPOW) {
1088     MOZ_ASSERT(!IsAlwaysDeferred(aMsg));
1089     return false;
1090   }
1091 
1092   // Unless they're NESTED_INSIDE_CPOW, we always defer async messages.
1093   // Note that we never send an async NESTED_INSIDE_SYNC message.
1094   if (!aMsg.is_sync()) {
1095     MOZ_RELEASE_ASSERT(aMsg.nested_level() == IPC::Message::NOT_NESTED);
1096     MOZ_ASSERT(IsAlwaysDeferred(aMsg));
1097     return true;
1098   }
1099 
1100   MOZ_ASSERT(!IsAlwaysDeferred(aMsg));
1101 
1102   int msgNestedLevel = aMsg.nested_level();
1103   int waitingNestedLevel = AwaitingSyncReplyNestedLevel();
1104 
1105   // Always defer if the nested level of the incoming message is less than the
1106   // nested level of the message we're awaiting.
1107   if (msgNestedLevel < waitingNestedLevel) return true;
1108 
1109   // Never defer if the message has strictly greater nested level.
1110   if (msgNestedLevel > waitingNestedLevel) return false;
1111 
1112   // When both sides send sync messages of the same nested level, we resolve the
1113   // race by dispatching in the child and deferring the incoming message in
1114   // the parent. However, the parent still needs to dispatch nested sync
1115   // messages.
1116   //
1117   // Deferring in the parent only sort of breaks message ordering. When the
1118   // child's message comes in, we can pretend the child hasn't quite
1119   // finished sending it yet. Since the message is sync, we know that the
1120   // child hasn't moved on yet.
1121   return mSide == ParentSide &&
1122          aMsg.transaction_id() != CurrentNestedInsideSyncTransaction();
1123 }
1124 
OnMessageReceivedFromLink(Message && aMsg)1125 void MessageChannel::OnMessageReceivedFromLink(Message&& aMsg) {
1126   mMonitor->AssertCurrentThreadOwns();
1127 
1128   if (MaybeInterceptSpecialIOMessage(aMsg)) {
1129     return;
1130   }
1131 
1132   mListener->OnChannelReceivedMessage(aMsg);
1133 
1134   // Regardless of the Interrupt stack, if we're awaiting a sync reply,
1135   // we know that it needs to be immediately handled to unblock us.
1136   if (aMsg.is_sync() && aMsg.is_reply()) {
1137     IPC_LOG("Received reply seqno=%d xid=%d", aMsg.seqno(),
1138             aMsg.transaction_id());
1139 
1140     if (aMsg.seqno() == mTimedOutMessageSeqno) {
1141       // Drop the message, but allow future sync messages to be sent.
1142       IPC_LOG("Received reply to timedout message; igoring; xid=%d",
1143               mTimedOutMessageSeqno);
1144       EndTimeout();
1145       return;
1146     }
1147 
1148     MOZ_RELEASE_ASSERT(AwaitingSyncReply());
1149     MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno);
1150 
1151     mTransactionStack->HandleReply(std::move(aMsg));
1152     NotifyWorkerThread();
1153     return;
1154   }
1155 
1156   // Nested messages cannot be compressed.
1157   MOZ_RELEASE_ASSERT(aMsg.compress_type() == IPC::Message::COMPRESSION_NONE ||
1158                      aMsg.nested_level() == IPC::Message::NOT_NESTED);
1159 
1160   bool reuseTask = false;
1161   if (aMsg.compress_type() == IPC::Message::COMPRESSION_ENABLED) {
1162     bool compress =
1163         (!mPending.isEmpty() &&
1164          mPending.getLast()->Msg().type() == aMsg.type() &&
1165          mPending.getLast()->Msg().routing_id() == aMsg.routing_id());
1166     if (compress) {
1167       // This message type has compression enabled, and the back of the
1168       // queue was the same message type and routed to the same destination.
1169       // Replace it with the newer message.
1170       MOZ_RELEASE_ASSERT(mPending.getLast()->Msg().compress_type() ==
1171                          IPC::Message::COMPRESSION_ENABLED);
1172       mPending.getLast()->Msg() = std::move(aMsg);
1173 
1174       reuseTask = true;
1175     }
1176   } else if (aMsg.compress_type() == IPC::Message::COMPRESSION_ALL &&
1177              !mPending.isEmpty()) {
1178     for (MessageTask* p = mPending.getLast(); p; p = p->getPrevious()) {
1179       if (p->Msg().type() == aMsg.type() &&
1180           p->Msg().routing_id() == aMsg.routing_id()) {
1181         // This message type has compression enabled, and the queue
1182         // holds a message with the same message type and routed to the
1183         // same destination. Erase it. Note that, since we always
1184         // compress these redundancies, There Can Be Only One.
1185         MOZ_RELEASE_ASSERT(p->Msg().compress_type() ==
1186                            IPC::Message::COMPRESSION_ALL);
1187         MOZ_RELEASE_ASSERT(IsAlwaysDeferred(p->Msg()));
1188         p->remove();
1189         break;
1190       }
1191     }
1192   }
1193 
1194   bool alwaysDeferred = IsAlwaysDeferred(aMsg);
1195 
1196   bool wakeUpSyncSend = AwaitingSyncReply() && !ShouldDeferMessage(aMsg);
1197 
1198   bool shouldWakeUp =
1199       AwaitingInterruptReply() || wakeUpSyncSend || AwaitingIncomingMessage();
1200 
1201   // Although we usually don't need to post a message task if
1202   // shouldWakeUp is true, it's easier to post anyway than to have to
1203   // guarantee that every Send call processes everything it's supposed to
1204   // before returning.
1205   bool shouldPostTask = !shouldWakeUp || wakeUpSyncSend;
1206 
1207   IPC_LOG("Receive from link; seqno=%d, xid=%d, shouldWakeUp=%d", aMsg.seqno(),
1208           aMsg.transaction_id(), shouldWakeUp);
1209 
1210   if (reuseTask) {
1211     return;
1212   }
1213 
1214   // There are three cases we're concerned about, relating to the state of the
1215   // main thread:
1216   //
1217   // (1) We are waiting on a sync reply - main thread is blocked on the
1218   //     IPC monitor.
1219   //   - If the message is NESTED_INSIDE_SYNC, we wake up the main thread to
1220   //     deliver the message depending on ShouldDeferMessage. Otherwise, we
1221   //     leave it in the mPending queue, posting a task to the main event
1222   //     loop, where it will be processed once the synchronous reply has been
1223   //     received.
1224   //
1225   // (2) We are waiting on an Interrupt reply - main thread is blocked on the
1226   //     IPC monitor.
1227   //   - Always notify and wake up the main thread.
1228   //
1229   // (3) We are not waiting on a reply.
1230   //   - We post a task to the main event loop.
1231   //
1232   // Note that, we may notify the main thread even though the monitor is not
1233   // blocked. This is okay, since we always check for pending events before
1234   // blocking again.
1235 
1236   RefPtr<MessageTask> task = new MessageTask(this, std::move(aMsg));
1237   mPending.insertBack(task);
1238 
1239   if (!alwaysDeferred) {
1240     mMaybeDeferredPendingCount++;
1241   }
1242 
1243   if (shouldWakeUp) {
1244     NotifyWorkerThread();
1245   }
1246 
1247   if (shouldPostTask) {
1248     task->Post();
1249   }
1250 }
1251 
PeekMessages(const std::function<bool (const Message & aMsg)> & aInvoke)1252 void MessageChannel::PeekMessages(
1253     const std::function<bool(const Message& aMsg)>& aInvoke) {
1254   // FIXME: We shouldn't be holding the lock for aInvoke!
1255   MonitorAutoLock lock(*mMonitor);
1256 
1257   for (MessageTask* it : mPending) {
1258     const Message& msg = it->Msg();
1259     if (!aInvoke(msg)) {
1260       break;
1261     }
1262   }
1263 }
1264 
ProcessPendingRequests(AutoEnterTransaction & aTransaction)1265 void MessageChannel::ProcessPendingRequests(
1266     AutoEnterTransaction& aTransaction) {
1267   mMonitor->AssertCurrentThreadOwns();
1268 
1269   AssertMaybeDeferredCountCorrect();
1270   if (mMaybeDeferredPendingCount == 0) {
1271     return;
1272   }
1273 
1274   IPC_LOG("ProcessPendingRequests for seqno=%d, xid=%d",
1275           aTransaction.SequenceNumber(), aTransaction.TransactionID());
1276 
1277   // Loop until there aren't any more nested messages to process.
1278   for (;;) {
1279     // If we canceled during ProcessPendingRequest, then we need to leave
1280     // immediately because the results of ShouldDeferMessage will be
1281     // operating with weird state (as if no Send is in progress). That could
1282     // cause even NOT_NESTED sync messages to be processed (but not
1283     // NOT_NESTED async messages), which would break message ordering.
1284     if (aTransaction.IsCanceled()) {
1285       return;
1286     }
1287 
1288     mozilla::Vector<Message> toProcess;
1289 
1290     for (MessageTask* p = mPending.getFirst(); p;) {
1291       Message& msg = p->Msg();
1292 
1293       MOZ_RELEASE_ASSERT(!aTransaction.IsCanceled(),
1294                          "Calling ShouldDeferMessage when cancelled");
1295       bool defer = ShouldDeferMessage(msg);
1296 
1297       // Only log the interesting messages.
1298       if (msg.is_sync() ||
1299           msg.nested_level() == IPC::Message::NESTED_INSIDE_CPOW) {
1300         IPC_LOG("ShouldDeferMessage(seqno=%d) = %d", msg.seqno(), defer);
1301       }
1302 
1303       if (!defer) {
1304         MOZ_ASSERT(!IsAlwaysDeferred(msg));
1305 
1306         if (!toProcess.append(std::move(msg))) MOZ_CRASH();
1307 
1308         mMaybeDeferredPendingCount--;
1309 
1310         p = p->removeAndGetNext();
1311         continue;
1312       }
1313       p = p->getNext();
1314     }
1315 
1316     if (toProcess.empty()) {
1317       break;
1318     }
1319 
1320     // Processing these messages could result in more messages, so we
1321     // loop around to check for more afterwards.
1322 
1323     for (auto it = toProcess.begin(); it != toProcess.end(); it++) {
1324       ProcessPendingRequest(std::move(*it));
1325     }
1326   }
1327 
1328   AssertMaybeDeferredCountCorrect();
1329 }
1330 
Send(UniquePtr<Message> aMsg,Message * aReply)1331 bool MessageChannel::Send(UniquePtr<Message> aMsg, Message* aReply) {
1332   mozilla::TimeStamp start = TimeStamp::Now();
1333   if (aMsg->size() >= kMinTelemetryMessageSize) {
1334     Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE2, aMsg->size());
1335   }
1336 
1337   // Sanity checks.
1338   AssertWorkerThread();
1339   mMonitor->AssertNotCurrentThreadOwns();
1340   MOZ_RELEASE_ASSERT(!mIsSameThreadChannel,
1341                      "sync send over same-thread channel will deadlock!");
1342 
1343 #ifdef OS_WIN
1344   SyncStackFrame frame(this, false);
1345   NeuteredWindowRegion neuteredRgn(mFlags &
1346                                    REQUIRE_DEFERRED_MESSAGE_PROTECTION);
1347 #endif
1348 
1349   CxxStackFrame f(*this, OUT_MESSAGE, aMsg.get());
1350 
1351   MonitorAutoLock lock(*mMonitor);
1352 
1353   if (mTimedOutMessageSeqno) {
1354     // Don't bother sending another sync message if a previous one timed out
1355     // and we haven't received a reply for it. Once the original timed-out
1356     // message receives a reply, we'll be able to send more sync messages
1357     // again.
1358     IPC_LOG("Send() failed due to previous timeout");
1359     mLastSendError = SyncSendError::PreviousTimeout;
1360     return false;
1361   }
1362 
1363   if (DispatchingSyncMessageNestedLevel() == IPC::Message::NOT_NESTED &&
1364       aMsg->nested_level() > IPC::Message::NOT_NESTED) {
1365     // Don't allow sending CPOWs while we're dispatching a sync message.
1366     IPC_LOG("Nested level forbids send");
1367     mLastSendError = SyncSendError::SendingCPOWWhileDispatchingSync;
1368     return false;
1369   }
1370 
1371   if (DispatchingSyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW ||
1372       DispatchingAsyncMessageNestedLevel() ==
1373           IPC::Message::NESTED_INSIDE_CPOW) {
1374     // Generally only the parent dispatches urgent messages. And the only
1375     // sync messages it can send are NESTED_INSIDE_SYNC. Mainly we want to
1376     // ensure here that we don't return false for non-CPOW messages.
1377     MOZ_RELEASE_ASSERT(aMsg->nested_level() ==
1378                        IPC::Message::NESTED_INSIDE_SYNC);
1379     IPC_LOG("Sending while dispatching urgent message");
1380     mLastSendError = SyncSendError::SendingCPOWWhileDispatchingUrgent;
1381     return false;
1382   }
1383 
1384   if (aMsg->nested_level() < DispatchingSyncMessageNestedLevel() ||
1385       aMsg->nested_level() < AwaitingSyncReplyNestedLevel()) {
1386     MOZ_RELEASE_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage());
1387     MOZ_RELEASE_ASSERT(!mIsPostponingSends);
1388     IPC_LOG("Cancel from Send");
1389     auto cancel =
1390         MakeUnique<CancelMessage>(CurrentNestedInsideSyncTransaction());
1391     CancelTransaction(CurrentNestedInsideSyncTransaction());
1392     mLink->SendMessage(std::move(cancel));
1393   }
1394 
1395   IPC_ASSERT(aMsg->is_sync(), "can only Send() sync messages here");
1396 
1397   IPC_ASSERT(aMsg->nested_level() >= DispatchingSyncMessageNestedLevel(),
1398              "can't send sync message of a lesser nested level than what's "
1399              "being dispatched");
1400   IPC_ASSERT(AwaitingSyncReplyNestedLevel() <= aMsg->nested_level(),
1401              "nested sync message sends must be of increasing nested level");
1402   IPC_ASSERT(
1403       DispatchingSyncMessageNestedLevel() != IPC::Message::NESTED_INSIDE_CPOW,
1404       "not allowed to send messages while dispatching urgent messages");
1405 
1406   IPC_ASSERT(
1407       DispatchingAsyncMessageNestedLevel() != IPC::Message::NESTED_INSIDE_CPOW,
1408       "not allowed to send messages while dispatching urgent messages");
1409 
1410   if (!Connected()) {
1411     ReportConnectionError("MessageChannel::SendAndWait", aMsg.get());
1412     mLastSendError = SyncSendError::NotConnectedBeforeSend;
1413     return false;
1414   }
1415 
1416   aMsg->set_seqno(NextSeqno());
1417 
1418   int32_t seqno = aMsg->seqno();
1419   int nestedLevel = aMsg->nested_level();
1420   msgid_t replyType = aMsg->type() + 1;
1421 
1422   AutoEnterTransaction* stackTop = mTransactionStack;
1423 
1424   // If the most recent message on the stack is NESTED_INSIDE_SYNC, then our
1425   // message should nest inside that and we use the same transaction
1426   // ID. Otherwise we need a new transaction ID (so we use the seqno of the
1427   // message we're sending).
1428   bool nest =
1429       stackTop && stackTop->NestedLevel() == IPC::Message::NESTED_INSIDE_SYNC;
1430   int32_t transaction = nest ? stackTop->TransactionID() : seqno;
1431   aMsg->set_transaction_id(transaction);
1432 
1433   bool handleWindowsMessages = mListener->HandleWindowsMessages(*aMsg.get());
1434   AutoEnterTransaction transact(this, seqno, transaction, nestedLevel);
1435 
1436   IPC_LOG("Send seqno=%d, xid=%d", seqno, transaction);
1437 
1438   // aMsg will be destroyed soon, but name() is not owned by aMsg.
1439   const char* msgName = aMsg->name();
1440 
1441   AddProfilerMarker(*aMsg, MessageDirection::eSending);
1442   SendMessageToLink(std::move(aMsg));
1443 
1444   while (true) {
1445     MOZ_RELEASE_ASSERT(!transact.IsCanceled());
1446     ProcessPendingRequests(transact);
1447     if (transact.IsComplete()) {
1448       break;
1449     }
1450     if (!Connected()) {
1451       ReportConnectionError("MessageChannel::Send");
1452       mLastSendError = SyncSendError::DisconnectedDuringSend;
1453       return false;
1454     }
1455 
1456     MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno);
1457     MOZ_RELEASE_ASSERT(!transact.IsComplete());
1458     MOZ_RELEASE_ASSERT(mTransactionStack == &transact);
1459 
1460     bool maybeTimedOut = !WaitForSyncNotify(handleWindowsMessages);
1461 
1462     if (mListener->NeedArtificialSleep()) {
1463       MonitorAutoUnlock unlock(*mMonitor);
1464       mListener->ArtificialSleep();
1465     }
1466 
1467     if (!Connected()) {
1468       ReportConnectionError("MessageChannel::SendAndWait");
1469       mLastSendError = SyncSendError::DisconnectedDuringSend;
1470       return false;
1471     }
1472 
1473     if (transact.IsCanceled()) {
1474       break;
1475     }
1476 
1477     MOZ_RELEASE_ASSERT(mTransactionStack == &transact);
1478 
1479     // We only time out a message if it initiated a new transaction (i.e.,
1480     // if neither side has any other message Sends on the stack).
1481     bool canTimeOut = transact.IsBottom();
1482     if (maybeTimedOut && canTimeOut && !ShouldContinueFromTimeout()) {
1483       // Since ShouldContinueFromTimeout drops the lock, we need to
1484       // re-check all our conditions here. We shouldn't time out if any of
1485       // these things happen because there won't be a reply to the timed
1486       // out message in these cases.
1487       if (transact.IsComplete()) {
1488         break;
1489       }
1490 
1491       IPC_LOG("Timing out Send: xid=%d", transaction);
1492 
1493       mTimedOutMessageSeqno = seqno;
1494       mTimedOutMessageNestedLevel = nestedLevel;
1495       mLastSendError = SyncSendError::TimedOut;
1496       return false;
1497     }
1498 
1499     if (transact.IsCanceled()) {
1500       break;
1501     }
1502   }
1503 
1504   if (transact.IsCanceled()) {
1505     IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction);
1506     mLastSendError = SyncSendError::CancelledAfterSend;
1507     return false;
1508   }
1509 
1510   if (transact.IsError()) {
1511     IPC_LOG("Error: seqno=%d, xid=%d", seqno, transaction);
1512     mLastSendError = SyncSendError::ReplyError;
1513     return false;
1514   }
1515 
1516   uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
1517   IPC_LOG("Got reply: seqno=%d, xid=%d, msgName=%s, latency=%ums", seqno,
1518           transaction, msgName, latencyMs);
1519 
1520   UniquePtr<Message> reply = transact.GetReply();
1521 
1522   MOZ_RELEASE_ASSERT(reply);
1523   MOZ_RELEASE_ASSERT(reply->is_reply(), "expected reply");
1524   MOZ_RELEASE_ASSERT(!reply->is_reply_error());
1525   MOZ_RELEASE_ASSERT(reply->seqno() == seqno);
1526   MOZ_RELEASE_ASSERT(reply->type() == replyType, "wrong reply type");
1527   MOZ_RELEASE_ASSERT(reply->is_sync());
1528 
1529   AddProfilerMarker(*reply, MessageDirection::eReceiving);
1530 
1531   *aReply = std::move(*reply);
1532   if (aReply->size() >= kMinTelemetryMessageSize) {
1533     Telemetry::Accumulate(Telemetry::IPC_REPLY_SIZE,
1534                           nsDependentCString(msgName), aReply->size());
1535   }
1536 
1537   // NOTE: Only collect IPC_SYNC_MAIN_LATENCY_MS on the main thread (bug
1538   // 1343729)
1539   if (NS_IsMainThread() && latencyMs >= kMinTelemetrySyncIPCLatencyMs) {
1540     Telemetry::Accumulate(Telemetry::IPC_SYNC_MAIN_LATENCY_MS,
1541                           nsDependentCString(msgName), latencyMs);
1542   }
1543   return true;
1544 }
1545 
Call(UniquePtr<Message> aMsg,Message * aReply)1546 bool MessageChannel::Call(UniquePtr<Message> aMsg, Message* aReply) {
1547   AssertWorkerThread();
1548   mMonitor->AssertNotCurrentThreadOwns();
1549   MOZ_RELEASE_ASSERT(!mIsSameThreadChannel,
1550                      "intr call send over same-thread channel will deadlock!");
1551 
1552 #ifdef OS_WIN
1553   SyncStackFrame frame(this, true);
1554 #endif
1555 
1556   // This must come before MonitorAutoLock, as its destructor acquires the
1557   // monitor lock.
1558   CxxStackFrame cxxframe(*this, OUT_MESSAGE, aMsg.get());
1559 
1560   MonitorAutoLock lock(*mMonitor);
1561   if (!Connected()) {
1562     ReportConnectionError("MessageChannel::Call", aMsg.get());
1563     return false;
1564   }
1565 
1566   // Sanity checks.
1567   IPC_ASSERT(!AwaitingSyncReply(),
1568              "cannot issue Interrupt call while blocked on sync request");
1569   IPC_ASSERT(!DispatchingSyncMessage(), "violation of sync handler invariant");
1570   IPC_ASSERT(aMsg->is_interrupt(), "can only Call() Interrupt messages here");
1571   IPC_ASSERT(!mIsPostponingSends, "not postponing sends");
1572 
1573   aMsg->set_seqno(NextSeqno());
1574   aMsg->set_interrupt_remote_stack_depth_guess(mRemoteStackDepthGuess);
1575   aMsg->set_interrupt_local_stack_depth(1 + InterruptStackDepth());
1576   mInterruptStack.push(MessageInfo(*aMsg));
1577 
1578   AddProfilerMarker(*aMsg, MessageDirection::eSending);
1579 
1580   mLink->SendMessage(std::move(aMsg));
1581 
1582   while (true) {
1583     // if a handler invoked by *Dispatch*() spun a nested event
1584     // loop, and the connection was broken during that loop, we
1585     // might have already processed the OnError event. if so,
1586     // trying another loop iteration will be futile because
1587     // channel state will have been cleared
1588     if (!Connected()) {
1589       ReportConnectionError("MessageChannel::Call");
1590       return false;
1591     }
1592 
1593 #ifdef OS_WIN
1594     // We need to limit the scoped of neuteredRgn to this spot in the code.
1595     // Window neutering can't be enabled during some plugin calls because
1596     // we then risk the neutered window procedure being subclassed by a
1597     // plugin.
1598     {
1599       NeuteredWindowRegion neuteredRgn(mFlags &
1600                                        REQUIRE_DEFERRED_MESSAGE_PROTECTION);
1601       /* We should pump messages at this point to ensure that the IPC
1602          peer does not become deadlocked on a pending inter-thread
1603          SendMessage() */
1604       neuteredRgn.PumpOnce();
1605     }
1606 #endif
1607 
1608     // Now might be the time to process a message deferred because of race
1609     // resolution.
1610     MaybeUndeferIncall();
1611 
1612     // Wait for an event to occur.
1613     while (!InterruptEventOccurred()) {
1614       bool maybeTimedOut = !WaitForInterruptNotify();
1615 
1616       // We might have received a "subtly deferred" message in a nested
1617       // loop that it's now time to process.
1618       if (InterruptEventOccurred() ||
1619           (!maybeTimedOut &&
1620            (!mDeferred.empty() || !mOutOfTurnReplies.empty()))) {
1621         break;
1622       }
1623 
1624       if (maybeTimedOut && !ShouldContinueFromTimeout()) return false;
1625     }
1626 
1627     Message recvd;
1628     MessageMap::iterator it;
1629 
1630     if ((it = mOutOfTurnReplies.find(mInterruptStack.top().seqno())) !=
1631         mOutOfTurnReplies.end()) {
1632       recvd = std::move(it->second);
1633       mOutOfTurnReplies.erase(it);
1634     } else if (!mPending.isEmpty()) {
1635       RefPtr<MessageTask> task = mPending.popFirst();
1636       recvd = std::move(task->Msg());
1637       if (!IsAlwaysDeferred(recvd)) {
1638         mMaybeDeferredPendingCount--;
1639       }
1640     } else {
1641       // because of subtleties with nested event loops, it's possible
1642       // that we got here and nothing happened.  or, we might have a
1643       // deferred in-call that needs to be processed.  either way, we
1644       // won't break the inner while loop again until something new
1645       // happens.
1646       continue;
1647     }
1648 
1649     // If the message is not Interrupt, we can dispatch it as normal.
1650     if (!recvd.is_interrupt()) {
1651       DispatchMessage(std::move(recvd));
1652       if (!Connected()) {
1653         ReportConnectionError("MessageChannel::DispatchMessage");
1654         return false;
1655       }
1656       continue;
1657     }
1658 
1659     // If the message is an Interrupt reply, either process it as a reply to our
1660     // call, or add it to the list of out-of-turn replies we've received.
1661     if (recvd.is_reply()) {
1662       IPC_ASSERT(!mInterruptStack.empty(), "invalid Interrupt stack");
1663 
1664       // If this is not a reply the call we've initiated, add it to our
1665       // out-of-turn replies and keep polling for events.
1666       {
1667         const MessageInfo& outcall = mInterruptStack.top();
1668 
1669         // Note, In the parent, sequence numbers increase from 0, and
1670         // in the child, they decrease from 0.
1671         if ((mSide == ChildSide && recvd.seqno() > outcall.seqno()) ||
1672             (mSide != ChildSide && recvd.seqno() < outcall.seqno())) {
1673           mOutOfTurnReplies[recvd.seqno()] = std::move(recvd);
1674           continue;
1675         }
1676 
1677         IPC_ASSERT(
1678             recvd.is_reply_error() || (recvd.type() == (outcall.type() + 1) &&
1679                                        recvd.seqno() == outcall.seqno()),
1680             "somebody's misbehavin'", true);
1681       }
1682 
1683       // We received a reply to our most recent outstanding call. Pop
1684       // this frame and return the reply.
1685       mInterruptStack.pop();
1686 
1687       AddProfilerMarker(recvd, MessageDirection::eReceiving);
1688 
1689       bool is_reply_error = recvd.is_reply_error();
1690       if (!is_reply_error) {
1691         *aReply = std::move(recvd);
1692       }
1693 
1694       // If we have no more pending out calls waiting on replies, then
1695       // the reply queue should be empty.
1696       IPC_ASSERT(!mInterruptStack.empty() || mOutOfTurnReplies.empty(),
1697                  "still have pending replies with no pending out-calls", true);
1698 
1699       return !is_reply_error;
1700     }
1701 
1702     // Dispatch an Interrupt in-call. Snapshot the current stack depth while we
1703     // own the monitor.
1704     size_t stackDepth = InterruptStackDepth();
1705     {
1706       MonitorAutoUnlock unlock(*mMonitor);
1707 
1708       CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
1709       RefPtr<ActorLifecycleProxy> listenerProxy =
1710           mListener->GetLifecycleProxy();
1711       DispatchInterruptMessage(listenerProxy, std::move(recvd), stackDepth);
1712     }
1713     if (!Connected()) {
1714       ReportConnectionError("MessageChannel::DispatchInterruptMessage");
1715       return false;
1716     }
1717   }
1718 }
1719 
WaitForIncomingMessage()1720 bool MessageChannel::WaitForIncomingMessage() {
1721 #ifdef OS_WIN
1722   SyncStackFrame frame(this, true);
1723   NeuteredWindowRegion neuteredRgn(mFlags &
1724                                    REQUIRE_DEFERRED_MESSAGE_PROTECTION);
1725 #endif
1726 
1727   MonitorAutoLock lock(*mMonitor);
1728   AutoEnterWaitForIncoming waitingForIncoming(*this);
1729   if (mChannelState != ChannelConnected) {
1730     return false;
1731   }
1732   if (!HasPendingEvents()) {
1733     return WaitForInterruptNotify();
1734   }
1735 
1736   MOZ_RELEASE_ASSERT(!mPending.isEmpty());
1737   RefPtr<MessageTask> task = mPending.getFirst();
1738   RunMessage(*task);
1739   return true;
1740 }
1741 
HasPendingEvents()1742 bool MessageChannel::HasPendingEvents() {
1743   AssertWorkerThread();
1744   mMonitor->AssertCurrentThreadOwns();
1745   return Connected() && !mPending.isEmpty();
1746 }
1747 
InterruptEventOccurred()1748 bool MessageChannel::InterruptEventOccurred() {
1749   AssertWorkerThread();
1750   mMonitor->AssertCurrentThreadOwns();
1751   IPC_ASSERT(InterruptStackDepth() > 0, "not in wait loop");
1752 
1753   return (!Connected() || !mPending.isEmpty() ||
1754           (!mOutOfTurnReplies.empty() &&
1755            mOutOfTurnReplies.find(mInterruptStack.top().seqno()) !=
1756                mOutOfTurnReplies.end()));
1757 }
1758 
ProcessPendingRequest(Message && aUrgent)1759 bool MessageChannel::ProcessPendingRequest(Message&& aUrgent) {
1760   AssertWorkerThread();
1761   mMonitor->AssertCurrentThreadOwns();
1762 
1763   IPC_LOG("Process pending: seqno=%d, xid=%d", aUrgent.seqno(),
1764           aUrgent.transaction_id());
1765 
1766   DispatchMessage(std::move(aUrgent));
1767   if (!Connected()) {
1768     ReportConnectionError("MessageChannel::ProcessPendingRequest");
1769     return false;
1770   }
1771 
1772   return true;
1773 }
1774 
ShouldRunMessage(const Message & aMsg)1775 bool MessageChannel::ShouldRunMessage(const Message& aMsg) {
1776   if (!mTimedOutMessageSeqno) {
1777     return true;
1778   }
1779 
1780   // If we've timed out a message and we're awaiting the reply to the timed
1781   // out message, we have to be careful what messages we process. Here's what
1782   // can go wrong:
1783   // 1. child sends a NOT_NESTED sync message S
1784   // 2. parent sends a NESTED_INSIDE_SYNC sync message H at the same time
1785   // 3. parent times out H
1786   // 4. child starts processing H and sends a NESTED_INSIDE_SYNC message H'
1787   //    nested within the same transaction
1788   // 5. parent dispatches S and sends reply
1789   // 6. child asserts because it instead expected a reply to H'.
1790   //
1791   // To solve this, we refuse to process S in the parent until we get a reply
1792   // to H. More generally, let the timed out message be M. We don't process a
1793   // message unless the child would need the response to that message in order
1794   // to process M. Those messages are the ones that have a higher nested level
1795   // than M or that are part of the same transaction as M.
1796   if (aMsg.nested_level() < mTimedOutMessageNestedLevel ||
1797       (aMsg.nested_level() == mTimedOutMessageNestedLevel &&
1798        aMsg.transaction_id() != mTimedOutMessageSeqno)) {
1799     return false;
1800   }
1801 
1802   return true;
1803 }
1804 
RunMessage(MessageTask & aTask)1805 void MessageChannel::RunMessage(MessageTask& aTask) {
1806   AssertWorkerThread();
1807   mMonitor->AssertCurrentThreadOwns();
1808 
1809   Message& msg = aTask.Msg();
1810 
1811   if (!Connected()) {
1812     ReportConnectionError("RunMessage");
1813     return;
1814   }
1815 
1816   // Check that we're going to run the first message that's valid to run.
1817 #if 0
1818 #  ifdef DEBUG
1819     nsCOMPtr<nsIEventTarget> messageTarget =
1820         mListener->GetMessageEventTarget(msg);
1821 
1822     for (MessageTask* task : mPending) {
1823         if (task == &aTask) {
1824             break;
1825         }
1826 
1827         nsCOMPtr<nsIEventTarget> taskTarget =
1828             mListener->GetMessageEventTarget(task->Msg());
1829 
1830         MOZ_ASSERT(!ShouldRunMessage(task->Msg()) ||
1831                    taskTarget != messageTarget ||
1832                    aTask.Msg().priority() != task->Msg().priority());
1833 
1834     }
1835 #  endif
1836 #endif
1837 
1838   if (!mDeferred.empty()) {
1839     MaybeUndeferIncall();
1840   }
1841 
1842   if (!ShouldRunMessage(msg)) {
1843     return;
1844   }
1845 
1846   MOZ_RELEASE_ASSERT(aTask.isInList());
1847   aTask.remove();
1848 
1849   if (!IsAlwaysDeferred(msg)) {
1850     mMaybeDeferredPendingCount--;
1851   }
1852 
1853   if (IsOnCxxStack() && msg.is_interrupt() && msg.is_reply()) {
1854     // We probably just received a reply in a nested loop for an
1855     // Interrupt call sent before entering that loop.
1856     mOutOfTurnReplies[msg.seqno()] = std::move(msg);
1857     return;
1858   }
1859 
1860   DispatchMessage(std::move(msg));
1861 }
1862 
NS_IMPL_ISUPPORTS_INHERITED(MessageChannel::MessageTask,CancelableRunnable,nsIRunnablePriority,nsIRunnableIPCMessageType)1863 NS_IMPL_ISUPPORTS_INHERITED(MessageChannel::MessageTask, CancelableRunnable,
1864                             nsIRunnablePriority, nsIRunnableIPCMessageType)
1865 
1866 MessageChannel::MessageTask::MessageTask(MessageChannel* aChannel,
1867                                          Message&& aMessage)
1868     : CancelableRunnable(aMessage.name()),
1869       mMonitor(aChannel->mMonitor),
1870       mChannel(aChannel),
1871       mMessage(std::move(aMessage)),
1872       mScheduled(false) {}
1873 
Run()1874 nsresult MessageChannel::MessageTask::Run() {
1875   mMonitor->AssertNotCurrentThreadOwns();
1876 
1877   MonitorAutoLock lock(*mMonitor);
1878 
1879   // In case we choose not to run this message, we may need to be able to Post
1880   // it again.
1881   mScheduled = false;
1882 
1883   if (!isInList()) {
1884     return NS_OK;
1885   }
1886 
1887   Channel()->AssertWorkerThread();
1888   Channel()->RunMessage(*this);
1889   return NS_OK;
1890 }
1891 
1892 // Warning: This method removes the receiver from whatever list it might be in.
Cancel()1893 nsresult MessageChannel::MessageTask::Cancel() {
1894   mMonitor->AssertNotCurrentThreadOwns();
1895 
1896   MonitorAutoLock lock(*mMonitor);
1897 
1898   if (!isInList()) {
1899     return NS_OK;
1900   }
1901 
1902   Channel()->AssertWorkerThread();
1903   if (!IsAlwaysDeferred(Msg())) {
1904     Channel()->mMaybeDeferredPendingCount--;
1905   }
1906 
1907   remove();
1908 
1909   return NS_OK;
1910 }
1911 
Post()1912 void MessageChannel::MessageTask::Post() {
1913   mMonitor->AssertCurrentThreadOwns();
1914   MOZ_RELEASE_ASSERT(!mScheduled);
1915   MOZ_RELEASE_ASSERT(isInList());
1916 
1917   mScheduled = true;
1918 
1919   RefPtr<MessageTask> self = this;
1920   nsCOMPtr<nsISerialEventTarget> eventTarget =
1921       Channel()->mListener->GetMessageEventTarget(mMessage);
1922 
1923   if (eventTarget) {
1924     eventTarget->Dispatch(self.forget(), NS_DISPATCH_NORMAL);
1925   } else {
1926     Channel()->mWorkerThread->Dispatch(self.forget());
1927   }
1928 }
1929 
1930 NS_IMETHODIMP
GetPriority(uint32_t * aPriority)1931 MessageChannel::MessageTask::GetPriority(uint32_t* aPriority) {
1932   switch (mMessage.priority()) {
1933     case Message::NORMAL_PRIORITY:
1934       *aPriority = PRIORITY_NORMAL;
1935       break;
1936     case Message::INPUT_PRIORITY:
1937       *aPriority = PRIORITY_INPUT_HIGH;
1938       break;
1939     case Message::VSYNC_PRIORITY:
1940       *aPriority = PRIORITY_VSYNC;
1941       break;
1942     case Message::MEDIUMHIGH_PRIORITY:
1943       *aPriority = PRIORITY_MEDIUMHIGH;
1944       break;
1945     case Message::CONTROL_PRIORITY:
1946       *aPriority = PRIORITY_CONTROL;
1947       break;
1948     default:
1949       MOZ_ASSERT(false);
1950       break;
1951   }
1952   return NS_OK;
1953 }
1954 
1955 NS_IMETHODIMP
GetType(uint32_t * aType)1956 MessageChannel::MessageTask::GetType(uint32_t* aType) {
1957   if (!Msg().is_valid()) {
1958     // If mMessage has been moved already elsewhere, we can't know what the type
1959     // has been.
1960     return NS_ERROR_FAILURE;
1961   }
1962 
1963   *aType = Msg().type();
1964   return NS_OK;
1965 }
1966 
DispatchMessage(Message && aMsg)1967 void MessageChannel::DispatchMessage(Message&& aMsg) {
1968   AssertWorkerThread();
1969   mMonitor->AssertCurrentThreadOwns();
1970 
1971   RefPtr<ActorLifecycleProxy> listenerProxy = mListener->GetLifecycleProxy();
1972 
1973   Maybe<AutoNoJSAPI> nojsapi;
1974   if (NS_IsMainThread() && CycleCollectedJSContext::Get()) {
1975     nojsapi.emplace();
1976   }
1977 
1978   UniquePtr<Message> reply;
1979 
1980   IPC_LOG("DispatchMessage: seqno=%d, xid=%d", aMsg.seqno(),
1981           aMsg.transaction_id());
1982   AddProfilerMarker(aMsg, MessageDirection::eReceiving);
1983 
1984   {
1985     AutoEnterTransaction transaction(this, aMsg);
1986 
1987     int id = aMsg.transaction_id();
1988     MOZ_RELEASE_ASSERT(!aMsg.is_sync() || id == transaction.TransactionID());
1989 
1990     {
1991       MonitorAutoUnlock unlock(*mMonitor);
1992       CxxStackFrame frame(*this, IN_MESSAGE, &aMsg);
1993 
1994       mListener->ArtificialSleep();
1995 
1996       if (aMsg.is_sync()) {
1997         DispatchSyncMessage(listenerProxy, aMsg, *getter_Transfers(reply));
1998       } else if (aMsg.is_interrupt()) {
1999         DispatchInterruptMessage(listenerProxy, std::move(aMsg), 0);
2000       } else {
2001         DispatchAsyncMessage(listenerProxy, aMsg);
2002       }
2003 
2004       mListener->ArtificialSleep();
2005     }
2006 
2007     if (reply && transaction.IsCanceled()) {
2008       // The transaction has been canceled. Don't send a reply.
2009       IPC_LOG("Nulling out reply due to cancellation, seqno=%d, xid=%d",
2010               aMsg.seqno(), id);
2011       reply = nullptr;
2012     }
2013   }
2014 
2015   if (reply && ChannelConnected == mChannelState) {
2016     IPC_LOG("Sending reply seqno=%d, xid=%d", aMsg.seqno(),
2017             aMsg.transaction_id());
2018     AddProfilerMarker(*reply, MessageDirection::eSending);
2019 
2020     mLink->SendMessage(std::move(reply));
2021   }
2022 }
2023 
DispatchSyncMessage(ActorLifecycleProxy * aProxy,const Message & aMsg,Message * & aReply)2024 void MessageChannel::DispatchSyncMessage(ActorLifecycleProxy* aProxy,
2025                                          const Message& aMsg,
2026                                          Message*& aReply) {
2027   AssertWorkerThread();
2028 
2029   mozilla::TimeStamp start = TimeStamp::Now();
2030 
2031   int nestedLevel = aMsg.nested_level();
2032 
2033   MOZ_RELEASE_ASSERT(nestedLevel == IPC::Message::NOT_NESTED ||
2034                      NS_IsMainThread());
2035 
2036   MessageChannel* dummy;
2037   MessageChannel*& blockingVar =
2038       mSide == ChildSide && NS_IsMainThread() ? gParentProcessBlocker : dummy;
2039 
2040   Result rv;
2041   {
2042     AutoSetValue<MessageChannel*> blocked(blockingVar, this);
2043     rv = aProxy->Get()->OnMessageReceived(aMsg, aReply);
2044   }
2045 
2046   uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
2047   if (latencyMs >= kMinTelemetrySyncIPCLatencyMs) {
2048     Telemetry::Accumulate(Telemetry::IPC_SYNC_RECEIVE_MS,
2049                           nsDependentCString(aMsg.name()), latencyMs);
2050   }
2051 
2052   if (!MaybeHandleError(rv, aMsg, "DispatchSyncMessage")) {
2053     aReply = Message::ForSyncDispatchError(aMsg.nested_level());
2054   }
2055   aReply->set_seqno(aMsg.seqno());
2056   aReply->set_transaction_id(aMsg.transaction_id());
2057 }
2058 
DispatchAsyncMessage(ActorLifecycleProxy * aProxy,const Message & aMsg)2059 void MessageChannel::DispatchAsyncMessage(ActorLifecycleProxy* aProxy,
2060                                           const Message& aMsg) {
2061   AssertWorkerThread();
2062   MOZ_RELEASE_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync());
2063 
2064   if (aMsg.routing_id() == MSG_ROUTING_NONE) {
2065     NS_WARNING("unhandled special message!");
2066     MaybeHandleError(MsgNotKnown, aMsg, "DispatchAsyncMessage");
2067     return;
2068   }
2069 
2070   Result rv;
2071   {
2072     int nestedLevel = aMsg.nested_level();
2073     AutoSetValue<bool> async(mDispatchingAsyncMessage, true);
2074     AutoSetValue<int> nestedLevelSet(mDispatchingAsyncMessageNestedLevel,
2075                                      nestedLevel);
2076     rv = aProxy->Get()->OnMessageReceived(aMsg);
2077   }
2078   MaybeHandleError(rv, aMsg, "DispatchAsyncMessage");
2079 }
2080 
DispatchInterruptMessage(ActorLifecycleProxy * aProxy,Message && aMsg,size_t stackDepth)2081 void MessageChannel::DispatchInterruptMessage(ActorLifecycleProxy* aProxy,
2082                                               Message&& aMsg,
2083                                               size_t stackDepth) {
2084   AssertWorkerThread();
2085   mMonitor->AssertNotCurrentThreadOwns();
2086 
2087   IPC_ASSERT(aMsg.is_interrupt() && !aMsg.is_reply(), "wrong message type");
2088 
2089   if (ShouldDeferInterruptMessage(aMsg, stackDepth)) {
2090     // We now know the other side's stack has one more frame
2091     // than we thought.
2092     ++mRemoteStackDepthGuess;  // decremented in MaybeProcessDeferred()
2093     mDeferred.push(std::move(aMsg));
2094     return;
2095   }
2096 
2097   // If we "lost" a race and need to process the other side's in-call, we
2098   // don't need to fix up the mRemoteStackDepthGuess here, because we're just
2099   // about to increment it, which will make it correct again.
2100 
2101 #ifdef OS_WIN
2102   SyncStackFrame frame(this, true);
2103 #endif
2104 
2105   UniquePtr<Message> reply;
2106 
2107   ++mRemoteStackDepthGuess;
2108   Result rv = aProxy->Get()->OnCallReceived(aMsg, *getter_Transfers(reply));
2109   --mRemoteStackDepthGuess;
2110 
2111   if (!MaybeHandleError(rv, aMsg, "DispatchInterruptMessage")) {
2112     reply = WrapUnique(Message::ForInterruptDispatchError());
2113   }
2114   reply->set_seqno(aMsg.seqno());
2115 
2116   MonitorAutoLock lock(*mMonitor);
2117   if (ChannelConnected == mChannelState) {
2118     AddProfilerMarker(*reply, MessageDirection::eSending);
2119     mLink->SendMessage(std::move(reply));
2120   }
2121 }
2122 
ShouldDeferInterruptMessage(const Message & aMsg,size_t aStackDepth)2123 bool MessageChannel::ShouldDeferInterruptMessage(const Message& aMsg,
2124                                                  size_t aStackDepth) {
2125   AssertWorkerThread();
2126 
2127   // We may or may not own the lock in this function, so don't access any
2128   // channel state.
2129 
2130   IPC_ASSERT(aMsg.is_interrupt() && !aMsg.is_reply(), "wrong message type");
2131 
2132   // Race detection: see the long comment near mRemoteStackDepthGuess in
2133   // MessageChannel.h. "Remote" stack depth means our side, and "local" means
2134   // the other side.
2135   if (aMsg.interrupt_remote_stack_depth_guess() ==
2136           RemoteViewOfStackDepth(aStackDepth) ||
2137       mInterruptStack.empty()) {
2138     return false;
2139   }
2140 
2141   // Interrupt in-calls have raced. The winner, if there is one, gets to defer
2142   // processing of the other side's in-call.
2143   bool defer;
2144   const char* winner;
2145   const MessageInfo parentMsgInfo =
2146       (mSide == ChildSide) ? MessageInfo(aMsg) : mInterruptStack.top();
2147   const MessageInfo childMsgInfo =
2148       (mSide == ChildSide) ? mInterruptStack.top() : MessageInfo(aMsg);
2149   switch (mListener->MediateInterruptRace(parentMsgInfo, childMsgInfo)) {
2150     case RIPChildWins:
2151       winner = "child";
2152       defer = (mSide == ChildSide);
2153       break;
2154     case RIPParentWins:
2155       winner = "parent";
2156       defer = (mSide != ChildSide);
2157       break;
2158     case RIPError:
2159       MOZ_CRASH("NYI: 'Error' Interrupt race policy");
2160     default:
2161       MOZ_CRASH("not reached");
2162   }
2163 
2164   IPC_LOG("race in %s: %s won", (mSide == ChildSide) ? "child" : "parent",
2165           winner);
2166 
2167   return defer;
2168 }
2169 
MaybeUndeferIncall()2170 void MessageChannel::MaybeUndeferIncall() {
2171   AssertWorkerThread();
2172   mMonitor->AssertCurrentThreadOwns();
2173 
2174   if (mDeferred.empty()) return;
2175 
2176   size_t stackDepth = InterruptStackDepth();
2177 
2178   Message& deferred = mDeferred.top();
2179 
2180   // the other side can only *under*-estimate our actual stack depth
2181   IPC_ASSERT(deferred.interrupt_remote_stack_depth_guess() <= stackDepth,
2182              "fatal logic error");
2183 
2184   if (ShouldDeferInterruptMessage(deferred, stackDepth)) {
2185     return;
2186   }
2187 
2188   // maybe time to process this message
2189   Message call(std::move(deferred));
2190   mDeferred.pop();
2191 
2192   // fix up fudge factor we added to account for race
2193   IPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
2194   --mRemoteStackDepthGuess;
2195 
2196   MOZ_RELEASE_ASSERT(call.nested_level() == IPC::Message::NOT_NESTED);
2197   RefPtr<MessageTask> task = new MessageTask(this, std::move(call));
2198   mPending.insertBack(task);
2199   MOZ_ASSERT(IsAlwaysDeferred(task->Msg()));
2200   task->Post();
2201 }
2202 
EnteredCxxStack()2203 void MessageChannel::EnteredCxxStack() { mListener->EnteredCxxStack(); }
2204 
ExitedCxxStack()2205 void MessageChannel::ExitedCxxStack() {
2206   mListener->ExitedCxxStack();
2207   if (mSawInterruptOutMsg) {
2208     MonitorAutoLock lock(*mMonitor);
2209     // see long comment in OnMaybeDequeueOne()
2210     EnqueuePendingMessages();
2211     mSawInterruptOutMsg = false;
2212   }
2213 }
2214 
EnteredCall()2215 void MessageChannel::EnteredCall() { mListener->EnteredCall(); }
2216 
ExitedCall()2217 void MessageChannel::ExitedCall() { mListener->ExitedCall(); }
2218 
EnteredSyncSend()2219 void MessageChannel::EnteredSyncSend() { mListener->OnEnteredSyncSend(); }
2220 
ExitedSyncSend()2221 void MessageChannel::ExitedSyncSend() { mListener->OnExitedSyncSend(); }
2222 
EnqueuePendingMessages()2223 void MessageChannel::EnqueuePendingMessages() {
2224   AssertWorkerThread();
2225   mMonitor->AssertCurrentThreadOwns();
2226 
2227   MaybeUndeferIncall();
2228 
2229   // XXX performance tuning knob: could process all or k pending
2230   // messages here, rather than enqueuing for later processing
2231 
2232   RepostAllMessages();
2233 }
2234 
WaitResponse(bool aWaitTimedOut)2235 bool MessageChannel::WaitResponse(bool aWaitTimedOut) {
2236   if (aWaitTimedOut) {
2237     if (mInTimeoutSecondHalf) {
2238       // We've really timed out this time.
2239       return false;
2240     }
2241     // Try a second time.
2242     mInTimeoutSecondHalf = true;
2243   } else {
2244     mInTimeoutSecondHalf = false;
2245   }
2246   return true;
2247 }
2248 
2249 #ifndef OS_WIN
WaitForSyncNotify(bool)2250 bool MessageChannel::WaitForSyncNotify(bool /* aHandleWindowsMessages */) {
2251 #  ifdef DEBUG
2252   // WARNING: We don't release the lock here. We can't because the link
2253   // could signal at this time and we would miss it. Instead we require
2254   // ArtificialTimeout() to be extremely simple.
2255   if (mListener->ArtificialTimeout()) {
2256     return false;
2257   }
2258 #  endif
2259 
2260   MOZ_RELEASE_ASSERT(!mIsSameThreadChannel,
2261                      "Wait on same-thread channel will deadlock!");
2262 
2263   TimeDuration timeout = (kNoTimeout == mTimeoutMs)
2264                              ? TimeDuration::Forever()
2265                              : TimeDuration::FromMilliseconds(mTimeoutMs);
2266   CVStatus status = mMonitor->Wait(timeout);
2267 
2268   // If the timeout didn't expire, we know we received an event. The
2269   // converse is not true.
2270   return WaitResponse(status == CVStatus::Timeout);
2271 }
2272 
WaitForInterruptNotify()2273 bool MessageChannel::WaitForInterruptNotify() {
2274   return WaitForSyncNotify(true);
2275 }
2276 
NotifyWorkerThread()2277 void MessageChannel::NotifyWorkerThread() { mMonitor->Notify(); }
2278 #endif
2279 
ShouldContinueFromTimeout()2280 bool MessageChannel::ShouldContinueFromTimeout() {
2281   AssertWorkerThread();
2282   mMonitor->AssertCurrentThreadOwns();
2283 
2284   bool cont;
2285   {
2286     MonitorAutoUnlock unlock(*mMonitor);
2287     cont = mListener->ShouldContinueFromReplyTimeout();
2288     mListener->ArtificialSleep();
2289   }
2290 
2291   static enum {
2292     UNKNOWN,
2293     NOT_DEBUGGING,
2294     DEBUGGING
2295   } sDebuggingChildren = UNKNOWN;
2296 
2297   if (sDebuggingChildren == UNKNOWN) {
2298     sDebuggingChildren =
2299         getenv("MOZ_DEBUG_CHILD_PROCESS") || getenv("MOZ_DEBUG_CHILD_PAUSE")
2300             ? DEBUGGING
2301             : NOT_DEBUGGING;
2302   }
2303   if (sDebuggingChildren == DEBUGGING) {
2304     return true;
2305   }
2306 
2307   return cont;
2308 }
2309 
SetReplyTimeoutMs(int32_t aTimeoutMs)2310 void MessageChannel::SetReplyTimeoutMs(int32_t aTimeoutMs) {
2311   // Set channel timeout value. Since this is broken up into
2312   // two period, the minimum timeout value is 2ms.
2313   AssertWorkerThread();
2314   mTimeoutMs =
2315       (aTimeoutMs <= 0) ? kNoTimeout : (int32_t)ceil((double)aTimeoutMs / 2.0);
2316 }
2317 
ReportMessageRouteError(const char * channelName) const2318 void MessageChannel::ReportMessageRouteError(const char* channelName) const {
2319   PrintErrorMessage(mSide, channelName, "Need a route");
2320   mListener->ProcessingError(MsgRouteError, "MsgRouteError");
2321 }
2322 
ReportConnectionError(const char * aChannelName,Message * aMsg) const2323 void MessageChannel::ReportConnectionError(const char* aChannelName,
2324                                            Message* aMsg) const {
2325   AssertWorkerThread();
2326   mMonitor->AssertCurrentThreadOwns();
2327 
2328   const char* errorMsg = nullptr;
2329   switch (mChannelState) {
2330     case ChannelClosed:
2331       errorMsg = "Closed channel: cannot send/recv";
2332       break;
2333     case ChannelOpening:
2334       errorMsg = "Opening channel: not yet ready for send/recv";
2335       break;
2336     case ChannelTimeout:
2337       errorMsg = "Channel timeout: cannot send/recv";
2338       break;
2339     case ChannelClosing:
2340       errorMsg =
2341           "Channel closing: too late to send/recv, messages will be lost";
2342       break;
2343     case ChannelError:
2344       errorMsg = "Channel error: cannot send/recv";
2345       break;
2346 
2347     default:
2348       MOZ_CRASH("unreached");
2349   }
2350 
2351   if (aMsg) {
2352     char reason[512];
2353     SprintfLiteral(reason, "(msgtype=0x%X,name=%s) %s", aMsg->type(),
2354                    aMsg->name(), errorMsg);
2355 
2356     PrintErrorMessage(mSide, aChannelName, reason);
2357   } else {
2358     PrintErrorMessage(mSide, aChannelName, errorMsg);
2359   }
2360 
2361   MonitorAutoUnlock unlock(*mMonitor);
2362   mListener->ProcessingError(MsgDropped, errorMsg);
2363 }
2364 
MaybeHandleError(Result code,const Message & aMsg,const char * channelName)2365 bool MessageChannel::MaybeHandleError(Result code, const Message& aMsg,
2366                                       const char* channelName) {
2367   if (MsgProcessed == code) return true;
2368 
2369   const char* errorMsg = nullptr;
2370   switch (code) {
2371     case MsgNotKnown:
2372       errorMsg = "Unknown message: not processed";
2373       break;
2374     case MsgNotAllowed:
2375       errorMsg = "Message not allowed: cannot be sent/recvd in this state";
2376       break;
2377     case MsgPayloadError:
2378       errorMsg = "Payload error: message could not be deserialized";
2379       break;
2380     case MsgProcessingError:
2381       errorMsg =
2382           "Processing error: message was deserialized, but the handler "
2383           "returned false (indicating failure)";
2384       break;
2385     case MsgRouteError:
2386       errorMsg = "Route error: message sent to unknown actor ID";
2387       break;
2388     case MsgValueError:
2389       errorMsg =
2390           "Value error: message was deserialized, but contained an illegal "
2391           "value";
2392       break;
2393 
2394     default:
2395       MOZ_CRASH("unknown Result code");
2396       return false;
2397   }
2398 
2399   char reason[512];
2400   const char* msgname = aMsg.name();
2401   if (msgname[0] == '?') {
2402     SprintfLiteral(reason, "(msgtype=0x%X) %s", aMsg.type(), errorMsg);
2403   } else {
2404     SprintfLiteral(reason, "%s %s", msgname, errorMsg);
2405   }
2406 
2407   PrintErrorMessage(mSide, channelName, reason);
2408 
2409   // Error handled in mozilla::ipc::IPCResult.
2410   if (code == MsgProcessingError) {
2411     return false;
2412   }
2413 
2414   mListener->ProcessingError(code, reason);
2415 
2416   return false;
2417 }
2418 
OnChannelErrorFromLink()2419 void MessageChannel::OnChannelErrorFromLink() {
2420   mMonitor->AssertCurrentThreadOwns();
2421 
2422   IPC_LOG("OnChannelErrorFromLink");
2423 
2424   if (InterruptStackDepth() > 0) NotifyWorkerThread();
2425 
2426   if (AwaitingSyncReply() || AwaitingIncomingMessage()) NotifyWorkerThread();
2427 
2428   if (ChannelClosing != mChannelState) {
2429     if (mAbortOnError) {
2430       // mAbortOnError is set by main actors (e.g., ContentChild) to ensure
2431       // that the process terminates even if normal shutdown is prevented.
2432       // A MOZ_CRASH() here is not helpful because crash reporting relies
2433       // on the parent process which we know is dead or otherwise unusable.
2434       //
2435       // Additionally, the parent process can (and often is) killed on Android
2436       // when apps are backgrounded. We don't need to report a crash for
2437       // normal behavior in that case.
2438       printf_stderr("Exiting due to channel error.\n");
2439       ProcessChild::QuickExit();
2440     }
2441     mChannelState = ChannelError;
2442     mMonitor->Notify();
2443   }
2444 
2445   PostErrorNotifyTask();
2446 }
2447 
NotifyMaybeChannelError()2448 void MessageChannel::NotifyMaybeChannelError() {
2449   mMonitor->AssertNotCurrentThreadOwns();
2450 
2451   // TODO sort out Close() on this side racing with Close() on the other side
2452   if (ChannelClosing == mChannelState) {
2453     // the channel closed, but we received a "Goodbye" message warning us
2454     // about it. no worries
2455     mChannelState = ChannelClosed;
2456     NotifyChannelClosed();
2457     return;
2458   }
2459 
2460   Clear();
2461 
2462   // Oops, error!  Let the listener know about it.
2463   mChannelState = ChannelError;
2464 
2465   // IPDL assumes these notifications do not fire twice, so we do not let
2466   // that happen.
2467   if (mNotifiedChannelDone) {
2468     return;
2469   }
2470   mNotifiedChannelDone = true;
2471 
2472   // After this, the channel may be deleted.  Based on the premise that
2473   // mListener owns this channel, any calls back to this class that may
2474   // work with mListener should still work on living objects.
2475   mListener->OnChannelError();
2476 }
2477 
OnNotifyMaybeChannelError()2478 void MessageChannel::OnNotifyMaybeChannelError() {
2479   AssertWorkerThread();
2480   mMonitor->AssertNotCurrentThreadOwns();
2481 
2482   mChannelErrorTask = nullptr;
2483 
2484   // OnChannelError holds mMonitor when it posts this task and this
2485   // task cannot be allowed to run until OnChannelError has
2486   // exited. We enforce that order by grabbing the mutex here which
2487   // should only continue once OnChannelError has completed.
2488   {
2489     MonitorAutoLock lock(*mMonitor);
2490     // nothing to do here
2491   }
2492 
2493   if (IsOnCxxStack()) {
2494     mChannelErrorTask = NewNonOwningCancelableRunnableMethod(
2495         "ipc::MessageChannel::OnNotifyMaybeChannelError", this,
2496         &MessageChannel::OnNotifyMaybeChannelError);
2497     RefPtr<Runnable> task = mChannelErrorTask;
2498     // This used to post a 10ms delayed patch; however not all
2499     // nsISerialEventTarget implementations support delayed dispatch.
2500     // The delay being completely arbitrary, we may not as well have any.
2501     mWorkerThread->Dispatch(task.forget());
2502     return;
2503   }
2504 
2505   NotifyMaybeChannelError();
2506 }
2507 
PostErrorNotifyTask()2508 void MessageChannel::PostErrorNotifyTask() {
2509   mMonitor->AssertCurrentThreadOwns();
2510 
2511   if (mChannelErrorTask) return;
2512 
2513   // This must be the last code that runs on this thread!
2514   mChannelErrorTask = NewNonOwningCancelableRunnableMethod(
2515       "ipc::MessageChannel::OnNotifyMaybeChannelError", this,
2516       &MessageChannel::OnNotifyMaybeChannelError);
2517   RefPtr<Runnable> task = mChannelErrorTask;
2518   mWorkerThread->Dispatch(task.forget());
2519 }
2520 
2521 // Special async message.
2522 class GoodbyeMessage : public IPC::Message {
2523  public:
GoodbyeMessage()2524   GoodbyeMessage() : IPC::Message(MSG_ROUTING_NONE, GOODBYE_MESSAGE_TYPE) {}
Read(const Message * msg)2525   static bool Read(const Message* msg) { return true; }
Log(const std::string & aPrefix,FILE * aOutf) const2526   void Log(const std::string& aPrefix, FILE* aOutf) const {
2527     fputs("(special `Goodbye' message)", aOutf);
2528   }
2529 };
2530 
SynchronouslyClose()2531 void MessageChannel::SynchronouslyClose() {
2532   AssertWorkerThread();
2533   mMonitor->AssertCurrentThreadOwns();
2534   mLink->SendClose();
2535 
2536   MOZ_RELEASE_ASSERT(!mIsSameThreadChannel || ChannelClosed == mChannelState,
2537                      "same-thread channel failed to synchronously close?");
2538 
2539   while (ChannelClosed != mChannelState) mMonitor->Wait();
2540 }
2541 
CloseWithError()2542 void MessageChannel::CloseWithError() {
2543   AssertWorkerThread();
2544 
2545   MonitorAutoLock lock(*mMonitor);
2546   if (ChannelConnected != mChannelState) {
2547     return;
2548   }
2549   SynchronouslyClose();
2550   mChannelState = ChannelError;
2551   PostErrorNotifyTask();
2552 }
2553 
CloseWithTimeout()2554 void MessageChannel::CloseWithTimeout() {
2555   AssertWorkerThread();
2556 
2557   MonitorAutoLock lock(*mMonitor);
2558   if (ChannelConnected != mChannelState) {
2559     return;
2560   }
2561   SynchronouslyClose();
2562   mChannelState = ChannelTimeout;
2563 }
2564 
NotifyImpendingShutdown()2565 void MessageChannel::NotifyImpendingShutdown() {
2566   UniquePtr<Message> msg =
2567       MakeUnique<Message>(MSG_ROUTING_NONE, IMPENDING_SHUTDOWN_MESSAGE_TYPE);
2568   MonitorAutoLock lock(*mMonitor);
2569   if (Connected()) {
2570     mLink->SendMessage(std::move(msg));
2571   }
2572 }
2573 
Close()2574 void MessageChannel::Close() {
2575   AssertWorkerThread();
2576 
2577   {
2578     // We don't use MonitorAutoLock here as that causes some sort of
2579     // deadlock in the error/timeout-with-a-listener state below when
2580     // compiling an optimized msvc build.
2581     mMonitor->Lock();
2582 
2583     // Instead just use a ScopeExit to manage the unlock.
2584     RefPtr<RefCountedMonitor> monitor(mMonitor);
2585     auto exit = MakeScopeExit([m = std::move(monitor)]() { m->Unlock(); });
2586 
2587     if (ChannelError == mChannelState || ChannelTimeout == mChannelState) {
2588       // See bug 538586: if the listener gets deleted while the
2589       // IO thread's NotifyChannelError event is still enqueued
2590       // and subsequently deletes us, then the error event will
2591       // also be deleted and the listener will never be notified
2592       // of the channel error.
2593       if (mListener) {
2594         exit.release();  // Explicitly unlocking, clear scope exit.
2595         mMonitor->Unlock();
2596         NotifyMaybeChannelError();
2597       }
2598       return;
2599     }
2600 
2601     if (ChannelOpening == mChannelState) {
2602       // SynchronouslyClose() waits for an ack from the other side, so
2603       // the opening sequence should complete before this returns.
2604       SynchronouslyClose();
2605       mChannelState = ChannelError;
2606       NotifyMaybeChannelError();
2607       return;
2608     }
2609 
2610     if (ChannelClosed == mChannelState) {
2611       // Slightly unexpected but harmless; ignore.  See bug 1554244.
2612       return;
2613     }
2614 
2615     // Notify the other side that we're about to close our socket. If we've
2616     // already received a Goodbye from the other side (and our state is
2617     // ChannelClosing), there's no reason to send one.
2618     if (ChannelConnected == mChannelState) {
2619       mLink->SendMessage(MakeUnique<GoodbyeMessage>());
2620     }
2621     SynchronouslyClose();
2622   }
2623 
2624   NotifyChannelClosed();
2625 }
2626 
NotifyChannelClosed()2627 void MessageChannel::NotifyChannelClosed() {
2628   mMonitor->AssertNotCurrentThreadOwns();
2629 
2630   if (ChannelClosed != mChannelState)
2631     MOZ_CRASH("channel should have been closed!");
2632 
2633   Clear();
2634 
2635   // IPDL assumes these notifications do not fire twice, so we do not let
2636   // that happen.
2637   if (mNotifiedChannelDone) {
2638     return;
2639   }
2640   mNotifiedChannelDone = true;
2641 
2642   // OK, the IO thread just closed the channel normally.  Let the
2643   // listener know about it. After this point the channel may be
2644   // deleted.
2645   mListener->OnChannelClose();
2646 }
2647 
DebugAbort(const char * file,int line,const char * cond,const char * why,bool reply)2648 void MessageChannel::DebugAbort(const char* file, int line, const char* cond,
2649                                 const char* why, bool reply) {
2650   printf_stderr(
2651       "###!!! [MessageChannel][%s][%s:%d] "
2652       "Assertion (%s) failed.  %s %s\n",
2653       mSide == ChildSide ? "Child" : "Parent", file, line, cond, why,
2654       reply ? "(reply)" : "");
2655   // technically we need the mutex for this, but we're dying anyway
2656   DumpInterruptStack("  ");
2657   printf_stderr("  remote Interrupt stack guess: %zu\n",
2658                 mRemoteStackDepthGuess);
2659   printf_stderr("  deferred stack size: %zu\n", mDeferred.size());
2660   printf_stderr("  out-of-turn Interrupt replies stack size: %zu\n",
2661                 mOutOfTurnReplies.size());
2662 
2663   MessageQueue pending = std::move(mPending);
2664   while (!pending.isEmpty()) {
2665     printf_stderr(
2666         "    [ %s%s ]\n",
2667         pending.getFirst()->Msg().is_interrupt()
2668             ? "intr"
2669             : (pending.getFirst()->Msg().is_sync() ? "sync" : "async"),
2670         pending.getFirst()->Msg().is_reply() ? "reply" : "");
2671     pending.popFirst();
2672   }
2673 
2674   MOZ_CRASH_UNSAFE(why);
2675 }
2676 
DumpInterruptStack(const char * const pfx) const2677 void MessageChannel::DumpInterruptStack(const char* const pfx) const {
2678   NS_WARNING_ASSERTION(!mWorkerThread->IsOnCurrentThread(),
2679                        "The worker thread had better be paused in a debugger!");
2680 
2681   printf_stderr("%sMessageChannel 'backtrace':\n", pfx);
2682 
2683   // print a python-style backtrace, first frame to last
2684   for (uint32_t i = 0; i < mCxxStackFrames.length(); ++i) {
2685     int32_t id;
2686     const char* dir;
2687     const char* sems;
2688     const char* name;
2689     mCxxStackFrames[i].Describe(&id, &dir, &sems, &name);
2690 
2691     printf_stderr("%s[(%u) %s %s %s(actor=%d) ]\n", pfx, i, dir, sems, name,
2692                   id);
2693   }
2694 }
2695 
AddProfilerMarker(const IPC::Message & aMessage,MessageDirection aDirection)2696 void MessageChannel::AddProfilerMarker(const IPC::Message& aMessage,
2697                                        MessageDirection aDirection) {
2698   mMonitor->AssertCurrentThreadOwns();
2699 
2700   if (profiler_feature_active(ProfilerFeature::IPCMessages)) {
2701     int32_t pid = mListener->OtherPidMaybeInvalid();
2702     // Only record markers for IPCs with a valid pid.
2703     // And if one of the profiler mutexes is locked on this thread, don't record
2704     // markers, because we don't want to expose profiler IPCs due to the
2705     // profiler itself, and also to avoid possible re-entrancy issues.
2706     if (pid != kInvalidProcessId && !profiler_is_locked_on_current_thread()) {
2707       // The current timestamp must be given to the `IPCMarker` payload.
2708       [[maybe_unused]] const TimeStamp now = TimeStamp::NowUnfuzzed();
2709       PROFILER_MARKER("IPC", IPC, MarkerTiming::InstantAt(now), IPCMarker, now,
2710                       now, pid, aMessage.seqno(), aMessage.type(), mSide,
2711                       aDirection, MessagePhase::Endpoint, aMessage.is_sync());
2712     }
2713   }
2714 }
2715 
GetTopmostMessageRoutingId() const2716 int32_t MessageChannel::GetTopmostMessageRoutingId() const {
2717   AssertWorkerThread();
2718 
2719   if (mCxxStackFrames.empty()) {
2720     return MSG_ROUTING_NONE;
2721   }
2722   const InterruptFrame& frame = mCxxStackFrames.back();
2723   return frame.GetRoutingId();
2724 }
2725 
EndTimeout()2726 void MessageChannel::EndTimeout() {
2727   mMonitor->AssertCurrentThreadOwns();
2728 
2729   IPC_LOG("Ending timeout of seqno=%d", mTimedOutMessageSeqno);
2730   mTimedOutMessageSeqno = 0;
2731   mTimedOutMessageNestedLevel = 0;
2732 
2733   RepostAllMessages();
2734 }
2735 
RepostAllMessages()2736 void MessageChannel::RepostAllMessages() {
2737   bool needRepost = false;
2738   for (MessageTask* task : mPending) {
2739     if (!task->IsScheduled()) {
2740       needRepost = true;
2741       break;
2742     }
2743   }
2744   if (!needRepost) {
2745     // If everything is already scheduled to run, do nothing.
2746     return;
2747   }
2748 
2749   // In some cases we may have deferred dispatch of some messages in the
2750   // queue. Now we want to run them again. However, we can't just re-post
2751   // those messages since the messages after them in mPending would then be
2752   // before them in the event queue. So instead we cancel everything and
2753   // re-post all messages in the correct order.
2754   MessageQueue queue = std::move(mPending);
2755   while (RefPtr<MessageTask> task = queue.popFirst()) {
2756     RefPtr<MessageTask> newTask = new MessageTask(this, std::move(task->Msg()));
2757     mPending.insertBack(newTask);
2758     newTask->Post();
2759   }
2760 
2761   AssertMaybeDeferredCountCorrect();
2762 }
2763 
CancelTransaction(int transaction)2764 void MessageChannel::CancelTransaction(int transaction) {
2765   mMonitor->AssertCurrentThreadOwns();
2766 
2767   // When we cancel a transaction, we need to behave as if there's no longer
2768   // any IPC on the stack. Anything we were dispatching or sending will get
2769   // canceled. Consequently, we have to update the state variables below.
2770   //
2771   // We also need to ensure that when any IPC functions on the stack return,
2772   // they don't reset these values using an RAII class like AutoSetValue. To
2773   // avoid that, these RAII classes check if the variable they set has been
2774   // tampered with (by us). If so, they don't reset the variable to the old
2775   // value.
2776 
2777   IPC_LOG("CancelTransaction: xid=%d", transaction);
2778 
2779   // An unusual case: We timed out a transaction which the other side then
2780   // cancelled. In this case we just leave the timedout state and try to
2781   // forget this ever happened.
2782   if (transaction == mTimedOutMessageSeqno) {
2783     IPC_LOG("Cancelled timed out message %d", mTimedOutMessageSeqno);
2784     EndTimeout();
2785 
2786     // Normally mCurrentTransaction == 0 here. But it can be non-zero if:
2787     // 1. Parent sends NESTED_INSIDE_SYNC message H.
2788     // 2. Parent times out H.
2789     // 3. Child dispatches H and sends nested message H' (same transaction).
2790     // 4. Parent dispatches H' and cancels.
2791     MOZ_RELEASE_ASSERT(!mTransactionStack ||
2792                        mTransactionStack->TransactionID() == transaction);
2793     if (mTransactionStack) {
2794       mTransactionStack->Cancel();
2795     }
2796   } else {
2797     MOZ_RELEASE_ASSERT(mTransactionStack->TransactionID() == transaction);
2798     mTransactionStack->Cancel();
2799   }
2800 
2801   bool foundSync = false;
2802   for (MessageTask* p = mPending.getFirst(); p;) {
2803     Message& msg = p->Msg();
2804 
2805     // If there was a race between the parent and the child, then we may
2806     // have a queued sync message. We want to drop this message from the
2807     // queue since if will get cancelled along with the transaction being
2808     // cancelled. This happens if the message in the queue is
2809     // NESTED_INSIDE_SYNC.
2810     if (msg.is_sync() && msg.nested_level() != IPC::Message::NOT_NESTED) {
2811       MOZ_RELEASE_ASSERT(!foundSync);
2812       MOZ_RELEASE_ASSERT(msg.transaction_id() != transaction);
2813       IPC_LOG("Removing msg from queue seqno=%d xid=%d", msg.seqno(),
2814               msg.transaction_id());
2815       foundSync = true;
2816       if (!IsAlwaysDeferred(msg)) {
2817         mMaybeDeferredPendingCount--;
2818       }
2819       p = p->removeAndGetNext();
2820       continue;
2821     }
2822 
2823     p = p->getNext();
2824   }
2825 
2826   AssertMaybeDeferredCountCorrect();
2827 }
2828 
CancelCurrentTransaction()2829 void MessageChannel::CancelCurrentTransaction() {
2830   MonitorAutoLock lock(*mMonitor);
2831   if (DispatchingSyncMessageNestedLevel() >= IPC::Message::NESTED_INSIDE_SYNC) {
2832     if (DispatchingSyncMessageNestedLevel() ==
2833             IPC::Message::NESTED_INSIDE_CPOW ||
2834         DispatchingAsyncMessageNestedLevel() ==
2835             IPC::Message::NESTED_INSIDE_CPOW) {
2836       mListener->IntentionalCrash();
2837     }
2838 
2839     IPC_LOG("Cancel requested: current xid=%d",
2840             CurrentNestedInsideSyncTransaction());
2841     MOZ_RELEASE_ASSERT(DispatchingSyncMessage());
2842     auto cancel =
2843         MakeUnique<CancelMessage>(CurrentNestedInsideSyncTransaction());
2844     CancelTransaction(CurrentNestedInsideSyncTransaction());
2845     mLink->SendMessage(std::move(cancel));
2846   }
2847 }
2848 
CancelCPOWs()2849 void CancelCPOWs() {
2850   if (gParentProcessBlocker) {
2851     mozilla::Telemetry::Accumulate(mozilla::Telemetry::IPC_TRANSACTION_CANCEL,
2852                                    true);
2853     gParentProcessBlocker->CancelCurrentTransaction();
2854   }
2855 }
2856 
IsCrossProcess() const2857 bool MessageChannel::IsCrossProcess() const {
2858   mMonitor->AssertCurrentThreadOwns();
2859   return mIsCrossProcess;
2860 }
2861 
SetIsCrossProcess(bool aIsCrossProcess)2862 void MessageChannel::SetIsCrossProcess(bool aIsCrossProcess) {
2863   mMonitor->AssertCurrentThreadOwns();
2864   if (aIsCrossProcess == mIsCrossProcess) {
2865     return;
2866   }
2867   mIsCrossProcess = aIsCrossProcess;
2868   if (mIsCrossProcess) {
2869     ChannelCountReporter::Increment(mName);
2870   } else {
2871     ChannelCountReporter::Decrement(mName);
2872   }
2873 }
2874 
2875 }  // namespace ipc
2876 }  // namespace mozilla
2877