tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MessageChannel.cpp (82323B)


      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 "base/waitable_event.h"
     16 #include "mozilla/Assertions.h"
     17 #include "mozilla/CycleCollectedJSContext.h"
     18 #include "mozilla/FlowMarkers.h"
     19 #include "mozilla/IntentionalCrash.h"
     20 #include "mozilla/Logging.h"
     21 #include "mozilla/Monitor.h"
     22 #include "mozilla/Mutex.h"
     23 #include "mozilla/ProfilerMarkers.h"
     24 #include "mozilla/Sprintf.h"
     25 #include "mozilla/StaticMutex.h"
     26 #include "mozilla/glean/IpcMetrics.h"
     27 #include "mozilla/TimeStamp.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 "nsIDirectTaskDispatcher.h"
     35 #include "nsTHashMap.h"
     36 #include "nsDebug.h"
     37 #include "nsExceptionHandler.h"
     38 #include "nsIMemoryReporter.h"
     39 #include "nsISupportsImpl.h"
     40 #include "nsPrintfCString.h"
     41 #include "nsThreadUtils.h"
     42 
     43 #ifdef XP_WIN
     44 #  include "mozilla/gfx/Logging.h"
     45 #endif
     46 
     47 #ifdef FUZZING_SNAPSHOT
     48 #  include "mozilla/fuzzing/IPCFuzzController.h"
     49 #endif
     50 
     51 // Undo the damage done by mozzconf.h
     52 #undef compress
     53 
     54 static mozilla::LazyLogModule sLogModule("ipc");
     55 #define IPC_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__))
     56 
     57 /*
     58 * IPC design:
     59 *
     60 * There are two kinds of messages: async and sync. Sync messages are blocking.
     61 *
     62 * Terminology: To dispatch a message Foo is to run the RecvFoo code for
     63 * it. This is also called "handling" the message.
     64 *
     65 * Sync and async messages can sometimes "nest" inside other sync messages
     66 * (i.e., while waiting for the sync reply, we can dispatch the inner
     67 * message). The three possible nesting levels are NOT_NESTED,
     68 * NESTED_INSIDE_SYNC, and NESTED_INSIDE_CPOW.  The intended uses are:
     69 *   NOT_NESTED - most messages.
     70 *   NESTED_INSIDE_SYNC - CPOW-related messages, which are always sync
     71 *                        and can go in either direction.
     72 *   NESTED_INSIDE_CPOW - messages where we don't want to dispatch
     73 *                        incoming CPOWs while waiting for the response.
     74 * These nesting levels are ordered: NOT_NESTED, NESTED_INSIDE_SYNC,
     75 * NESTED_INSIDE_CPOW.  Async messages cannot be NESTED_INSIDE_SYNC but they can
     76 * be NESTED_INSIDE_CPOW.
     77 *
     78 * To avoid jank, the parent process is not allowed to send NOT_NESTED sync
     79 * messages. When a process is waiting for a response to a sync message M0, it
     80 * will dispatch an incoming message M if:
     81 *   1. M has a higher nesting level than M0, or
     82 *   2. if M has the same nesting level as M0 and we're in the child, or
     83 *   3. if M has the same nesting level as M0 and it was sent by the other side
     84 *      while dispatching M0.
     85 * The idea is that messages with higher nesting should take precendence. The
     86 * purpose of rule 2 is to handle a race where both processes send to each other
     87 * simultaneously. In this case, we resolve the race in favor of the parent (so
     88 * the child dispatches first).
     89 *
     90 * Messages satisfy the following properties:
     91 *   A. When waiting for a response to a sync message, we won't dispatch any
     92 *      messages of a lower nesting level.
     93 *   B. Messages of the same nesting level will be dispatched roughly in the
     94 *      order they were sent. The exception is when the parent and child send
     95 *      sync messages to each other simulataneously. In this case, the parent's
     96 *      message is dispatched first. While it is dispatched, the child may send
     97 *      further nested messages, and these messages may be dispatched before the
     98 *      child's original message. We can consider ordering to be preserved here
     99 *      because we pretend that the child's original message wasn't sent until
    100 *      after the parent's message is finished being dispatched.
    101 *
    102 * When waiting for a sync message reply, we dispatch an async message only if
    103 * it is NESTED_INSIDE_CPOW. Normally NESTED_INSIDE_CPOW async
    104 * messages are sent only from the child. However, the parent can send
    105 * NESTED_INSIDE_CPOW async messages when it is creating a bridged protocol.
    106 */
    107 
    108 using namespace mozilla;
    109 using namespace mozilla::ipc;
    110 
    111 using mozilla::MonitorAutoLock;
    112 using mozilla::MonitorAutoUnlock;
    113 using mozilla::dom::AutoNoJSAPI;
    114 
    115 #define IPC_ASSERT(_cond, ...)                                           \
    116  do {                                                                   \
    117    AssertWorkerThread();                                                \
    118    mMonitor->AssertCurrentThreadOwns();                                 \
    119    if (!(_cond)) DebugAbort(__FILE__, __LINE__, #_cond, ##__VA_ARGS__); \
    120  } while (0)
    121 
    122 static MessageChannel* gParentProcessBlocker = nullptr;
    123 
    124 namespace mozilla {
    125 namespace ipc {
    126 
    127 // static
    128 bool MessageChannel::sIsPumpingMessages = false;
    129 
    130 class AutoEnterTransaction {
    131 public:
    132  explicit AutoEnterTransaction(MessageChannel* aChan,
    133                                IPC::Message::seqno_t aMsgSeqno,
    134                                IPC::Message::seqno_t aTransactionID,
    135                                int aNestedLevel) MOZ_REQUIRES(*aChan->mMonitor)
    136      : mChan(aChan),
    137        mActive(true),
    138        mOutgoing(true),
    139        mNestedLevel(aNestedLevel),
    140        mSeqno(aMsgSeqno),
    141        mTransaction(aTransactionID),
    142        mNext(mChan->mTransactionStack) {
    143    mChan->mMonitor->AssertCurrentThreadOwns();
    144    mChan->mTransactionStack = this;
    145  }
    146 
    147  explicit AutoEnterTransaction(MessageChannel* aChan,
    148                                const IPC::Message& aMessage)
    149      MOZ_REQUIRES(*aChan->mMonitor)
    150      : mChan(aChan),
    151        mActive(true),
    152        mOutgoing(false),
    153        mNestedLevel(aMessage.nested_level()),
    154        mSeqno(aMessage.seqno()),
    155        mTransaction(aMessage.transaction_id()),
    156        mNext(mChan->mTransactionStack) {
    157    mChan->mMonitor->AssertCurrentThreadOwns();
    158 
    159    if (!aMessage.is_sync()) {
    160      mActive = false;
    161      return;
    162    }
    163 
    164    mChan->mTransactionStack = this;
    165  }
    166 
    167  ~AutoEnterTransaction() {
    168    mChan->mMonitor->AssertCurrentThreadOwns();
    169    if (mActive) {
    170      mChan->mTransactionStack = mNext;
    171    }
    172  }
    173 
    174  void Cancel() {
    175    mChan->mMonitor->AssertCurrentThreadOwns();
    176    AutoEnterTransaction* cur = mChan->mTransactionStack;
    177    MOZ_RELEASE_ASSERT(cur == this);
    178    while (cur && cur->mNestedLevel != IPC::Message::NOT_NESTED) {
    179      // Note that, in the following situation, we will cancel multiple
    180      // transactions:
    181      // 1. Parent sends NESTED_INSIDE_SYNC message P1 to child.
    182      // 2. Child sends NESTED_INSIDE_SYNC message C1 to child.
    183      // 3. Child dispatches P1, parent blocks.
    184      // 4. Child cancels.
    185      // In this case, both P1 and C1 are cancelled. The parent will
    186      // remove C1 from its queue when it gets the cancellation message.
    187      MOZ_RELEASE_ASSERT(cur->mActive);
    188      cur->mActive = false;
    189      cur = cur->mNext;
    190    }
    191 
    192    mChan->mTransactionStack = cur;
    193 
    194    MOZ_RELEASE_ASSERT(IsComplete());
    195  }
    196 
    197  bool AwaitingSyncReply() const {
    198    MOZ_RELEASE_ASSERT(mActive);
    199    if (mOutgoing) {
    200      return true;
    201    }
    202    return mNext ? mNext->AwaitingSyncReply() : false;
    203  }
    204 
    205  int AwaitingSyncReplyNestedLevel() const {
    206    MOZ_RELEASE_ASSERT(mActive);
    207    if (mOutgoing) {
    208      return mNestedLevel;
    209    }
    210    return mNext ? mNext->AwaitingSyncReplyNestedLevel() : 0;
    211  }
    212 
    213  bool DispatchingSyncMessage() const {
    214    MOZ_RELEASE_ASSERT(mActive);
    215    if (!mOutgoing) {
    216      return true;
    217    }
    218    return mNext ? mNext->DispatchingSyncMessage() : false;
    219  }
    220 
    221  int DispatchingSyncMessageNestedLevel() const {
    222    MOZ_RELEASE_ASSERT(mActive);
    223    if (!mOutgoing) {
    224      return mNestedLevel;
    225    }
    226    return mNext ? mNext->DispatchingSyncMessageNestedLevel() : 0;
    227  }
    228 
    229  int NestedLevel() const {
    230    MOZ_RELEASE_ASSERT(mActive);
    231    return mNestedLevel;
    232  }
    233 
    234  IPC::Message::seqno_t SequenceNumber() const {
    235    MOZ_RELEASE_ASSERT(mActive);
    236    return mSeqno;
    237  }
    238 
    239  IPC::Message::seqno_t TransactionID() const {
    240    MOZ_RELEASE_ASSERT(mActive);
    241    return mTransaction;
    242  }
    243 
    244  void ReceivedReply(UniquePtr<IPC::Message> aMessage) {
    245    MOZ_RELEASE_ASSERT(aMessage->seqno() == mSeqno);
    246    MOZ_RELEASE_ASSERT(aMessage->transaction_id() == mTransaction);
    247    MOZ_RELEASE_ASSERT(!mReply);
    248    IPC_LOG("Reply received on worker thread: seqno=%" PRId64, mSeqno);
    249    mReply = std::move(aMessage);
    250    MOZ_RELEASE_ASSERT(IsComplete());
    251  }
    252 
    253  void HandleReply(UniquePtr<IPC::Message> aMessage) {
    254    mChan->mMonitor->AssertCurrentThreadOwns();
    255    AutoEnterTransaction* cur = mChan->mTransactionStack;
    256    MOZ_RELEASE_ASSERT(cur == this);
    257    while (cur) {
    258      MOZ_RELEASE_ASSERT(cur->mActive);
    259      if (aMessage->seqno() == cur->mSeqno) {
    260        cur->ReceivedReply(std::move(aMessage));
    261        break;
    262      }
    263      cur = cur->mNext;
    264      MOZ_RELEASE_ASSERT(cur);
    265    }
    266  }
    267 
    268  bool IsComplete() { return !mActive || mReply; }
    269 
    270  bool IsOutgoing() { return mOutgoing; }
    271 
    272  bool IsCanceled() { return !mActive; }
    273 
    274  bool IsBottom() const { return !mNext; }
    275 
    276  bool IsError() {
    277    MOZ_RELEASE_ASSERT(mReply);
    278    return mReply->is_reply_error();
    279  }
    280 
    281  UniquePtr<IPC::Message> GetReply() { return std::move(mReply); }
    282 
    283 private:
    284  MessageChannel* mChan;
    285 
    286  // Active is true if this transaction is on the mChan->mTransactionStack
    287  // stack. Generally we're not on the stack if the transaction was canceled
    288  // or if it was for a message that doesn't require transactions (an async
    289  // message).
    290  bool mActive;
    291 
    292  // Is this stack frame for an outgoing message?
    293  bool mOutgoing;
    294 
    295  // Properties of the message being sent/received.
    296  int mNestedLevel;
    297  IPC::Message::seqno_t mSeqno;
    298  IPC::Message::seqno_t mTransaction;
    299 
    300  // Next item in mChan->mTransactionStack.
    301  AutoEnterTransaction* mNext;
    302 
    303  // Pointer the a reply received for this message, if one was received.
    304  UniquePtr<IPC::Message> mReply;
    305 };
    306 
    307 class ChannelCountReporter final : public nsIMemoryReporter {
    308  ~ChannelCountReporter() = default;
    309 
    310  struct ChannelCounts {
    311    size_t mNow;
    312    size_t mMax;
    313 
    314    ChannelCounts() : mNow(0), mMax(0) {}
    315 
    316    void Inc() {
    317      ++mNow;
    318      if (mMax < mNow) {
    319        mMax = mNow;
    320      }
    321    }
    322 
    323    void Dec() {
    324      MOZ_ASSERT(mNow > 0);
    325      --mNow;
    326    }
    327  };
    328 
    329  using CountTable = nsTHashMap<nsDepCharHashKey, ChannelCounts>;
    330 
    331  static StaticMutex sChannelCountMutex;
    332  static CountTable* sChannelCounts MOZ_GUARDED_BY(sChannelCountMutex);
    333 
    334 public:
    335  NS_DECL_THREADSAFE_ISUPPORTS
    336 
    337  NS_IMETHOD
    338  CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
    339                 bool aAnonymize) override {
    340    AutoTArray<std::pair<const char*, ChannelCounts>, 16> counts;
    341    {
    342      StaticMutexAutoLock countLock(sChannelCountMutex);
    343      if (!sChannelCounts) {
    344        return NS_OK;
    345      }
    346      counts.SetCapacity(sChannelCounts->Count());
    347      for (const auto& entry : *sChannelCounts) {
    348        counts.AppendElement(std::pair{entry.GetKey(), entry.GetData()});
    349      }
    350    }
    351 
    352    for (const auto& entry : counts) {
    353      nsPrintfCString pathNow("ipc-channels/%s", entry.first);
    354      nsPrintfCString pathMax("ipc-channels-peak/%s", entry.first);
    355      nsPrintfCString descNow(
    356          "Number of IPC channels for"
    357          " top-level actor type %s",
    358          entry.first);
    359      nsPrintfCString descMax(
    360          "Peak number of IPC channels for"
    361          " top-level actor type %s",
    362          entry.first);
    363 
    364      aHandleReport->Callback(""_ns, pathNow, KIND_OTHER, UNITS_COUNT,
    365                              entry.second.mNow, descNow, aData);
    366      aHandleReport->Callback(""_ns, pathMax, KIND_OTHER, UNITS_COUNT,
    367                              entry.second.mMax, descMax, aData);
    368    }
    369    return NS_OK;
    370  }
    371 
    372  static void Increment(const char* aName) {
    373    StaticMutexAutoLock countLock(sChannelCountMutex);
    374    if (!sChannelCounts) {
    375      sChannelCounts = new CountTable;
    376    }
    377    sChannelCounts->LookupOrInsert(aName).Inc();
    378  }
    379 
    380  static void Decrement(const char* aName) {
    381    StaticMutexAutoLock countLock(sChannelCountMutex);
    382    MOZ_ASSERT(sChannelCounts);
    383    sChannelCounts->LookupOrInsert(aName).Dec();
    384  }
    385 };
    386 
    387 StaticMutex ChannelCountReporter::sChannelCountMutex;
    388 ChannelCountReporter::CountTable* ChannelCountReporter::sChannelCounts;
    389 
    390 NS_IMPL_ISUPPORTS(ChannelCountReporter, nsIMemoryReporter)
    391 
    392 // In child processes, the first MessageChannel is created before
    393 // XPCOM is initialized enough to construct the memory reporter
    394 // manager.  This retries every time a MessageChannel is constructed,
    395 // which is good enough in practice.
    396 template <class Reporter>
    397 static void TryRegisterStrongMemoryReporter() {
    398  static Atomic<bool> registered;
    399  if (registered.compareExchange(false, true)) {
    400    RefPtr<Reporter> reporter = new Reporter();
    401    if (NS_FAILED(RegisterStrongMemoryReporter(reporter))) {
    402      registered = false;
    403    }
    404  }
    405 }
    406 
    407 MessageChannel::MessageChannel(const char* aName, IToplevelProtocol* aListener)
    408    : mName(aName), mListener(aListener), mMonitor(new RefCountedMonitor()) {
    409  MOZ_COUNT_CTOR(ipc::MessageChannel);
    410 
    411 #ifdef XP_WIN
    412  mEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
    413  MOZ_RELEASE_ASSERT(mEvent, "CreateEvent failed! Nothing is going to work!");
    414 #endif
    415 
    416  TryRegisterStrongMemoryReporter<ChannelCountReporter>();
    417 }
    418 
    419 MessageChannel::~MessageChannel() {
    420  MOZ_COUNT_DTOR(ipc::MessageChannel);
    421  MonitorAutoLock lock(*mMonitor);
    422  MOZ_RELEASE_ASSERT(!mOnCxxStack,
    423                     "MessageChannel destroyed while code on CxxStack");
    424 #ifdef XP_WIN
    425  if (mEvent) {
    426    BOOL ok = CloseHandle(mEvent);
    427    mEvent = nullptr;
    428 
    429    if (!ok) {
    430      gfxDevCrash(mozilla::gfx::LogReason::MessageChannelCloseFailure)
    431          << "MessageChannel failed to close. GetLastError: " << GetLastError();
    432    }
    433    MOZ_RELEASE_ASSERT(ok);
    434  } else {
    435    gfxDevCrash(mozilla::gfx::LogReason::MessageChannelCloseFailure)
    436        << "MessageChannel destructor ran without an mEvent Handle";
    437  }
    438 #endif
    439 
    440  // Make sure that the MessageChannel was closed (and therefore cleared) before
    441  // it was destroyed. We can't properly close the channel at this point, as it
    442  // would be unsafe to invoke our listener's callbacks, and we may be being
    443  // destroyed on a thread other than `mWorkerThread`.
    444  if (!IsClosedLocked()) {
    445    CrashReporter::RecordAnnotationCString(
    446        CrashReporter::Annotation::IPCFatalErrorProtocol, mName);
    447    switch (mChannelState) {
    448      case ChannelConnected:
    449        MOZ_CRASH(
    450            "MessageChannel destroyed without being closed "
    451            "(mChannelState == ChannelConnected).");
    452        break;
    453      case ChannelClosing:
    454        MOZ_CRASH(
    455            "MessageChannel destroyed without being closed "
    456            "(mChannelState == ChannelClosing).");
    457        break;
    458      case ChannelError:
    459        MOZ_CRASH(
    460            "MessageChannel destroyed without being closed "
    461            "(mChannelState == ChannelError).");
    462        break;
    463      default:
    464        MOZ_CRASH("MessageChannel destroyed without being closed.");
    465    }
    466  }
    467 
    468  // Double-check other properties for thoroughness.
    469  MOZ_RELEASE_ASSERT(!mLink);
    470  MOZ_RELEASE_ASSERT(!mChannelErrorTask);
    471  MOZ_RELEASE_ASSERT(mPending.isEmpty());
    472  MOZ_RELEASE_ASSERT(!mShutdownTask);
    473 }
    474 
    475 #ifdef DEBUG
    476 void MessageChannel::AssertMaybeDeferredCountCorrect() {
    477  mMonitor->AssertCurrentThreadOwns();
    478 
    479  size_t count = 0;
    480  for (MessageTask* task : mPending) {
    481    task->AssertMonitorHeld(*mMonitor);
    482    if (!IsAlwaysDeferred(*task->Msg())) {
    483      count++;
    484    }
    485  }
    486 
    487  MOZ_ASSERT(count == mMaybeDeferredPendingCount);
    488 }
    489 #endif
    490 
    491 // This function returns the current transaction ID. Since the notion of a
    492 // "current transaction" can be hard to define when messages race with each
    493 // other and one gets canceled and the other doesn't, we require that this
    494 // function is only called when the current transaction is known to be for a
    495 // NESTED_INSIDE_SYNC message. In that case, we know for sure what the caller is
    496 // looking for.
    497 auto MessageChannel::CurrentNestedInsideSyncTransaction() const -> seqno_t {
    498  mMonitor->AssertCurrentThreadOwns();
    499  if (!mTransactionStack) {
    500    return 0;
    501  }
    502  MOZ_RELEASE_ASSERT(mTransactionStack->NestedLevel() ==
    503                     IPC::Message::NESTED_INSIDE_SYNC);
    504  return mTransactionStack->TransactionID();
    505 }
    506 
    507 bool MessageChannel::TestOnlyIsTransactionComplete() const {
    508  AssertWorkerThread();
    509  MonitorAutoLock lock(*mMonitor);
    510  return !mTransactionStack || mTransactionStack->IsComplete();
    511 }
    512 
    513 bool MessageChannel::AwaitingSyncReply() const {
    514  mMonitor->AssertCurrentThreadOwns();
    515  return mTransactionStack ? mTransactionStack->AwaitingSyncReply() : false;
    516 }
    517 
    518 int MessageChannel::AwaitingSyncReplyNestedLevel() const {
    519  mMonitor->AssertCurrentThreadOwns();
    520  return mTransactionStack ? mTransactionStack->AwaitingSyncReplyNestedLevel()
    521                           : 0;
    522 }
    523 
    524 bool MessageChannel::DispatchingSyncMessage() const {
    525  mMonitor->AssertCurrentThreadOwns();
    526  return mTransactionStack ? mTransactionStack->DispatchingSyncMessage()
    527                           : false;
    528 }
    529 
    530 int MessageChannel::DispatchingSyncMessageNestedLevel() const {
    531  mMonitor->AssertCurrentThreadOwns();
    532  return mTransactionStack
    533             ? mTransactionStack->DispatchingSyncMessageNestedLevel()
    534             : 0;
    535 }
    536 
    537 static void PrintErrorMessage(Side side, const char* channelName,
    538                              const char* msg) {
    539  printf_stderr("\n###!!! [%s][%s] Error: %s\n\n", StringFromIPCSide(side),
    540                channelName, msg);
    541 }
    542 
    543 bool MessageChannel::Connected() const {
    544  mMonitor->AssertCurrentThreadOwns();
    545  return ChannelConnected == mChannelState;
    546 }
    547 
    548 bool MessageChannel::ConnectedOrClosing() const {
    549  mMonitor->AssertCurrentThreadOwns();
    550  return ChannelConnected == mChannelState || ChannelClosing == mChannelState;
    551 }
    552 
    553 bool MessageChannel::CanSend() const {
    554  if (!mMonitor) {
    555    return false;
    556  }
    557  MonitorAutoLock lock(*mMonitor);
    558  return Connected();
    559 }
    560 
    561 void MessageChannel::Clear() {
    562  AssertWorkerThread();
    563  mMonitor->AssertCurrentThreadOwns();
    564  MOZ_DIAGNOSTIC_ASSERT(IsClosedLocked(), "MessageChannel cleared too early?");
    565  MOZ_ASSERT(ChannelClosed == mChannelState || ChannelError == mChannelState);
    566 
    567  // Don't clear mWorkerThread; we use it in AssertWorkerThread().
    568  //
    569  // Also don't clear mListener.  If we clear it, then sending a message
    570  // through this channel after it's Clear()'ed can cause this process to
    571  // crash.
    572 
    573  if (mShutdownTask) {
    574    mShutdownTask->Clear();
    575    mWorkerThread->UnregisterShutdownTask(mShutdownTask);
    576  }
    577  mShutdownTask = nullptr;
    578 
    579  if (NS_IsMainThread() && gParentProcessBlocker == this) {
    580    gParentProcessBlocker = nullptr;
    581  }
    582 
    583  SetIsCrossProcess(false);
    584 
    585  mLink = nullptr;
    586 
    587  if (mChannelErrorTask) {
    588    mChannelErrorTask->Cancel();
    589    mChannelErrorTask = nullptr;
    590  }
    591 
    592  if (mFlushLazySendTask) {
    593    mFlushLazySendTask->Cancel();
    594    mFlushLazySendTask = nullptr;
    595  }
    596 
    597  // Free up any memory used by pending messages.
    598  mPending.clear();
    599 
    600  mMaybeDeferredPendingCount = 0;
    601 }
    602 
    603 bool MessageChannel::Open(ScopedPort aPort, Side aSide,
    604                          const nsID& aMessageChannelId,
    605                          nsISerialEventTarget* aEventTarget) {
    606  nsCOMPtr<nsISerialEventTarget> eventTarget =
    607      aEventTarget ? aEventTarget : GetCurrentSerialEventTarget();
    608  MOZ_RELEASE_ASSERT(eventTarget,
    609                     "Must open MessageChannel on a nsISerialEventTarget");
    610  MOZ_RELEASE_ASSERT(eventTarget->IsOnCurrentThread(),
    611                     "Must open MessageChannel from worker thread");
    612 
    613  auto shutdownTask = MakeRefPtr<WorkerTargetShutdownTask>(eventTarget, this);
    614  nsresult rv = eventTarget->RegisterShutdownTask(shutdownTask);
    615  MOZ_ASSERT(rv != NS_ERROR_NOT_IMPLEMENTED,
    616             "target for MessageChannel must support shutdown tasks");
    617  if (rv == NS_ERROR_UNEXPECTED) {
    618    // If shutdown tasks have already started running, dispatch our shutdown
    619    // task manually.
    620    NS_WARNING("Opening MessageChannel on EventTarget in shutdown");
    621    rv = eventTarget->Dispatch(shutdownTask->AsRunnable());
    622  }
    623  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
    624                     "error registering ShutdownTask for MessageChannel");
    625 
    626  {
    627    MonitorAutoLock lock(*mMonitor);
    628    MOZ_RELEASE_ASSERT(!mLink, "Open() called > once");
    629    MOZ_RELEASE_ASSERT(ChannelClosed == mChannelState, "Not currently closed");
    630    MOZ_ASSERT(mSide == UnknownSide);
    631 
    632    mMessageChannelId = aMessageChannelId;
    633    mWorkerThread = eventTarget;
    634    mShutdownTask = shutdownTask;
    635    mLink = MakeUnique<PortLink>(this, std::move(aPort));
    636    mChannelState = ChannelConnected;
    637    mSide = aSide;
    638  }
    639 
    640  // Notify our listener that the underlying IPC channel has been established.
    641  // IProtocol will use this callback to create the ActorLifecycleProxy, and
    642  // perform an `AddRef` call to keep the actor alive until the channel is
    643  // disconnected.
    644  //
    645  // We unlock our monitor before calling `OnIPCChannelOpened` to ensure that
    646  // any calls back into `MessageChannel` do not deadlock. At this point, we may
    647  // be receiving messages on the IO thread, however we cannot process them on
    648  // the worker thread or have notified our listener until after this function
    649  // returns.
    650  mListener->OnIPCChannelOpened();
    651  return true;
    652 }
    653 
    654 static Side GetOppSide(Side aSide) {
    655  switch (aSide) {
    656    case ChildSide:
    657      return ParentSide;
    658    case ParentSide:
    659      return ChildSide;
    660    default:
    661      return UnknownSide;
    662  }
    663 }
    664 
    665 bool MessageChannel::Open(MessageChannel* aTargetChan,
    666                          nsISerialEventTarget* aEventTarget, Side aSide) {
    667  // Opens a connection to another thread in the same process.
    668 
    669  MOZ_ASSERT(aTargetChan, "Need a target channel");
    670 
    671  nsID channelId = nsID::GenerateUUID();
    672 
    673  std::pair<ScopedPort, ScopedPort> ports =
    674      NodeController::GetSingleton()->CreatePortPair();
    675 
    676  // NOTE: This dispatch must be sync as it captures locals by non-owning
    677  // reference, however we can't use `NS_DispatchAndSpinEventLoopUntilComplete`
    678  // as that will spin a nested event loop, and doesn't work with certain types
    679  // of calling event targets.
    680  base::WaitableEvent event(/* manual_reset */ true,
    681                            /* initially_signaled */ false);
    682  MOZ_ALWAYS_SUCCEEDS(aEventTarget->Dispatch(NS_NewCancelableRunnableFunction(
    683      "ipc::MessageChannel::OpenAsOtherThread", [&]() {
    684        aTargetChan->Open(std::move(ports.second), GetOppSide(aSide), channelId,
    685                          aEventTarget);
    686        event.Signal();
    687      })));
    688  bool ok = event.Wait();
    689  MOZ_RELEASE_ASSERT(ok);
    690 
    691  // Now that the other side has connected, open the port on our side.
    692  return Open(std::move(ports.first), aSide, channelId);
    693 }
    694 
    695 bool MessageChannel::OpenOnSameThread(MessageChannel* aTargetChan,
    696                                      mozilla::ipc::Side aSide) {
    697  auto [porta, portb] = NodeController::GetSingleton()->CreatePortPair();
    698 
    699  nsID channelId = nsID::GenerateUUID();
    700 
    701  aTargetChan->mIsSameThreadChannel = true;
    702  mIsSameThreadChannel = true;
    703 
    704  auto* currentThread = GetCurrentSerialEventTarget();
    705  return aTargetChan->Open(std::move(portb), GetOppSide(aSide), channelId,
    706                           currentThread) &&
    707         Open(std::move(porta), aSide, channelId, currentThread);
    708 }
    709 
    710 bool MessageChannel::Send(UniquePtr<Message> aMsg, seqno_t* aSeqno) {
    711  MOZ_RELEASE_ASSERT(!aMsg->is_sync());
    712  MOZ_RELEASE_ASSERT(aMsg->nested_level() != IPC::Message::NESTED_INSIDE_SYNC);
    713  MOZ_RELEASE_ASSERT(aMsg->routing_id() != MSG_ROUTING_NONE);
    714  AssertWorkerThread();
    715  mMonitor->AssertNotCurrentThreadOwns();
    716 
    717  AutoSetValue<bool> setOnCxxStack(mOnCxxStack, true);
    718 
    719  if (aMsg->seqno() == 0) {
    720    aMsg->set_seqno(NextSeqno());
    721  }
    722  if (aSeqno) {
    723    *aSeqno = aMsg->seqno();
    724  }
    725 
    726  MonitorAutoLock lock(*mMonitor);
    727  if (!Connected()) {
    728    ReportConnectionError("Send", aMsg->type());
    729    return false;
    730  }
    731 
    732  AddProfilerMarker(*aMsg, MessageDirection::eSending);
    733  SendMessageToLink(std::move(aMsg));
    734  return true;
    735 }
    736 
    737 void MessageChannel::SendMessageToLink(UniquePtr<Message> aMsg) {
    738  AssertWorkerThread();
    739  mMonitor->AssertCurrentThreadOwns();
    740 
    741  // If the channel is not cross-process, there's no reason to be lazy, so we
    742  // ignore the flag in that case.
    743  if (aMsg->is_lazy_send() && mIsCrossProcess) {
    744    // If this is the first lazy message in the queue and our worker thread
    745    // supports direct task dispatch, dispatch a task to flush messages,
    746    // ensuring we don't leave them pending forever.
    747    if (!mFlushLazySendTask) {
    748      if (nsCOMPtr<nsIDirectTaskDispatcher> dispatcher =
    749              do_QueryInterface(mWorkerThread)) {
    750        mFlushLazySendTask = new FlushLazySendMessagesRunnable(this);
    751        MOZ_ALWAYS_SUCCEEDS(
    752            dispatcher->DispatchDirectTask(do_AddRef(mFlushLazySendTask)));
    753      }
    754    }
    755    if (mFlushLazySendTask) {
    756      mFlushLazySendTask->PushMessage(std::move(aMsg));
    757      return;
    758    }
    759  }
    760 
    761  if (mFlushLazySendTask) {
    762    FlushLazySendMessages();
    763  }
    764  mLink->SendMessage(std::move(aMsg));
    765 }
    766 
    767 void MessageChannel::FlushLazySendMessages() {
    768  AssertWorkerThread();
    769  mMonitor->AssertCurrentThreadOwns();
    770 
    771  // Clean up any SendLazyTask which might be pending.
    772  auto messages = mFlushLazySendTask->TakeMessages();
    773  mFlushLazySendTask = nullptr;
    774 
    775  // Send all lazy messages, then clear the queue.
    776  for (auto& msg : messages) {
    777    mLink->SendMessage(std::move(msg));
    778  }
    779 }
    780 
    781 class BuildIDsMatchMessage : public IPC::Message {
    782 public:
    783  BuildIDsMatchMessage()
    784      : IPC::Message(MSG_ROUTING_NONE, BUILD_IDS_MATCH_MESSAGE_TYPE) {}
    785  void Log(const std::string& aPrefix, FILE* aOutf) const {
    786    fputs("(special `Build IDs match' message)", aOutf);
    787  }
    788 };
    789 
    790 // Send the parent a special async message to confirm when the parent and child
    791 // are of the same buildID. Skips sending the message and returns false if the
    792 // buildIDs don't match. This is a minor variation on
    793 // MessageChannel::Send(Message* aMsg).
    794 bool MessageChannel::SendBuildIDsMatchMessage(const char* aParentBuildID) {
    795  MOZ_ASSERT(!XRE_IsParentProcess());
    796 
    797  nsCString parentBuildID(aParentBuildID);
    798  nsCString childBuildID(mozilla::PlatformBuildID());
    799 
    800  if (parentBuildID != childBuildID) {
    801    // The build IDs didn't match, usually because an update occurred in the
    802    // background.
    803    return false;
    804  }
    805 
    806  auto msg = MakeUnique<BuildIDsMatchMessage>();
    807 
    808  MOZ_RELEASE_ASSERT(!msg->is_sync());
    809  MOZ_RELEASE_ASSERT(msg->nested_level() != IPC::Message::NESTED_INSIDE_SYNC);
    810 
    811  AssertWorkerThread();
    812  mMonitor->AssertNotCurrentThreadOwns();
    813  // Don't check for MSG_ROUTING_NONE.
    814 
    815  MonitorAutoLock lock(*mMonitor);
    816  if (!Connected()) {
    817    ReportConnectionError("SendBuildIDsMatchMessage", msg->type());
    818    return false;
    819  }
    820 
    821 #if defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
    822  // Technically, the behavior is interesting for any kind of process
    823  // but when exercising tests, we want to crash only a content process and
    824  // avoid making noise with other kind of processes crashing
    825  if (const char* dontSend = PR_GetEnv("MOZ_BUILDID_MATCH_DONTSEND")) {
    826    if (dontSend[0] == '1') {
    827      // Bug 1732999: We are going to crash, so we need to advise leak check
    828      // tooling to avoid intermittent missing leakcheck
    829      NoteIntentionalCrash(XRE_GetProcessTypeString());
    830      if (XRE_IsContentProcess()) {
    831        return false;
    832      }
    833    }
    834  }
    835 #endif
    836 
    837  SendMessageToLink(std::move(msg));
    838  return true;
    839 }
    840 
    841 class CancelMessage : public IPC::Message {
    842 public:
    843  explicit CancelMessage(seqno_t transaction)
    844      : IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE) {
    845    set_transaction_id(transaction);
    846  }
    847  static bool Read(const Message* msg) { return true; }
    848  void Log(const std::string& aPrefix, FILE* aOutf) const {
    849    fputs("(special `Cancel' message)", aOutf);
    850  }
    851 };
    852 
    853 bool MessageChannel::MaybeInterceptSpecialIOMessage(const Message& aMsg) {
    854  mMonitor->AssertCurrentThreadOwns();
    855 
    856  if (MSG_ROUTING_NONE == aMsg.routing_id()) {
    857    if (GOODBYE_MESSAGE_TYPE == aMsg.type()) {
    858      // We've received a GOODBYE message, close the connection and mark
    859      // ourselves as "Closing".
    860      mLink->Close();
    861      mChannelState = ChannelClosing;
    862      if (LoggingEnabledFor(mListener->GetProtocolName(), mSide)) {
    863        printf(
    864            "[%s %u] NOTE: %s%s actor received `Goodbye' message.  Closing "
    865            "channel.\n",
    866            XRE_GeckoProcessTypeToString(XRE_GetProcessType()),
    867            static_cast<uint32_t>(base::GetCurrentProcId()),
    868            mListener->GetProtocolName(), StringFromIPCSide(mSide));
    869      }
    870 
    871      // Notify the worker thread that the connection has been closed, as we
    872      // will not receive an `OnChannelErrorFromLink` after calling
    873      // `mLink->Close()`.
    874      if (AwaitingSyncReply()) {
    875        NotifyWorkerThread();
    876      }
    877      PostErrorNotifyTask();
    878      return true;
    879    } else if (CANCEL_MESSAGE_TYPE == aMsg.type()) {
    880      IPC_LOG("Cancel from message");
    881      CancelTransaction(aMsg.transaction_id());
    882      NotifyWorkerThread();
    883      return true;
    884    } else if (BUILD_IDS_MATCH_MESSAGE_TYPE == aMsg.type()) {
    885      IPC_LOG("Build IDs match message");
    886      mBuildIDsConfirmedMatch = true;
    887      return true;
    888    } else if (IMPENDING_SHUTDOWN_MESSAGE_TYPE == aMsg.type()) {
    889      IPC_LOG("Impending Shutdown received");
    890      ProcessChild::NotifiedImpendingShutdown();
    891      return true;
    892    }
    893  }
    894  return false;
    895 }
    896 
    897 /* static */
    898 bool MessageChannel::IsAlwaysDeferred(const Message& aMsg) {
    899  // If a message is not NESTED_INSIDE_CPOW and not sync, then we always defer
    900  // it.
    901  return aMsg.nested_level() != IPC::Message::NESTED_INSIDE_CPOW &&
    902         !aMsg.is_sync();
    903 }
    904 
    905 bool MessageChannel::ShouldDeferMessage(const Message& aMsg) {
    906  // Never defer messages that have the highest nested level, even async
    907  // ones. This is safe because only the child can send these messages, so
    908  // they can never nest.
    909  if (aMsg.nested_level() == IPC::Message::NESTED_INSIDE_CPOW) {
    910    MOZ_ASSERT(!IsAlwaysDeferred(aMsg));
    911    return false;
    912  }
    913 
    914  // Unless they're NESTED_INSIDE_CPOW, we always defer async messages.
    915  // Note that we never send an async NESTED_INSIDE_SYNC message.
    916  if (!aMsg.is_sync()) {
    917    MOZ_RELEASE_ASSERT(aMsg.nested_level() == IPC::Message::NOT_NESTED);
    918    MOZ_ASSERT(IsAlwaysDeferred(aMsg));
    919    return true;
    920  }
    921 
    922  MOZ_ASSERT(!IsAlwaysDeferred(aMsg));
    923 
    924  int msgNestedLevel = aMsg.nested_level();
    925  int waitingNestedLevel = AwaitingSyncReplyNestedLevel();
    926 
    927  // Always defer if the nested level of the incoming message is less than the
    928  // nested level of the message we're awaiting.
    929  if (msgNestedLevel < waitingNestedLevel) return true;
    930 
    931  // Never defer if the message has strictly greater nested level.
    932  if (msgNestedLevel > waitingNestedLevel) return false;
    933 
    934  // When both sides send sync messages of the same nested level, we resolve the
    935  // race by dispatching in the child and deferring the incoming message in
    936  // the parent. However, the parent still needs to dispatch nested sync
    937  // messages.
    938  //
    939  // Deferring in the parent only sort of breaks message ordering. When the
    940  // child's message comes in, we can pretend the child hasn't quite
    941  // finished sending it yet. Since the message is sync, we know that the
    942  // child hasn't moved on yet.
    943  return mSide == ParentSide &&
    944         aMsg.transaction_id() != CurrentNestedInsideSyncTransaction();
    945 }
    946 
    947 class IPCFlowMarker : public BaseMarkerType<IPCFlowMarker> {
    948 public:
    949  static constexpr const char* Name = "IPCFlowMarker";
    950 
    951  using MS = MarkerSchema;
    952  static constexpr MS::PayloadField PayloadFields[] = {
    953      {"name", MS::InputType::CString, "Details", MS::Format::String,
    954       MS::PayloadFlags::Searchable},
    955      {"flow", MS::InputType::Uint64, "Flow", MS::Format::Flow,
    956       MS::PayloadFlags::Searchable}};
    957 
    958  static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
    959                                               MS::Location::MarkerTable};
    960  static constexpr const char* TableLabel =
    961      "{marker.data.name}(flow={marker.data.flow})";
    962  static constexpr const char* ChartLabel = "{marker.name}";
    963 
    964  static constexpr MS::ETWMarkerGroup Group = MS::ETWMarkerGroup::Generic;
    965 
    966  static constexpr bool IsStackBased = true;
    967 
    968  static void StreamJSONMarkerData(
    969      mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
    970      IPC::Message::msgid_t aMessageType, Flow aFlow) {
    971    aWriter.StringProperty(
    972        "name",
    973        mozilla::MakeStringSpan(IPC::StringFromIPCMessageType(aMessageType)));
    974    aWriter.FlowProperty("flow", aFlow);
    975  }
    976 };
    977 
    978 static uint64_t LossyNarrowChannelId(const nsID& aID) {
    979  // We xor both halves of the UUID together so that the parts of the id where
    980  // the variant (m2) and version (m3[0]) get xored with random bits from the
    981  // other halve.
    982  uint64_t bits[2];
    983  memcpy(&bits, &aID, sizeof(bits));
    984 
    985  return bits[0] ^ bits[1];
    986 }
    987 
    988 void MessageChannel::OnMessageReceivedFromLink(UniquePtr<Message> aMsg) {
    989  mMonitor->AssertCurrentThreadOwns();
    990  MOZ_ASSERT(mChannelState == ChannelConnected);
    991 
    992  if (MaybeInterceptSpecialIOMessage(*aMsg)) {
    993    return;
    994  }
    995 
    996  mListener->OnChannelReceivedMessage(*aMsg);
    997 
    998  // If we're awaiting a sync reply, we know that it needs to be immediately
    999  // handled to unblock us.
   1000  if (aMsg->is_sync() && aMsg->is_reply()) {
   1001    IPC_LOG("Received reply seqno=%" PRId64 " xid=%" PRId64, aMsg->seqno(),
   1002            aMsg->transaction_id());
   1003 
   1004    if (aMsg->seqno() == mTimedOutMessageSeqno) {
   1005      // Drop the message, but allow future sync messages to be sent.
   1006      IPC_LOG("Received reply to timedout message; igoring; xid=%" PRId64,
   1007              mTimedOutMessageSeqno);
   1008      EndTimeout();
   1009      return;
   1010    }
   1011 
   1012    MOZ_RELEASE_ASSERT(AwaitingSyncReply());
   1013    MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno);
   1014 
   1015    mTransactionStack->HandleReply(std::move(aMsg));
   1016    NotifyWorkerThread();
   1017    return;
   1018  }
   1019 
   1020  // Nested messages cannot be compressed.
   1021  MOZ_RELEASE_ASSERT(aMsg->compress_type() == IPC::Message::COMPRESSION_NONE ||
   1022                     aMsg->nested_level() == IPC::Message::NOT_NESTED);
   1023 
   1024  if (aMsg->compress_type() == IPC::Message::COMPRESSION_ENABLED &&
   1025      !mPending.isEmpty()) {
   1026    auto* last = mPending.getLast();
   1027    last->AssertMonitorHeld(*mMonitor);
   1028    bool compress = last->Msg()->type() == aMsg->type() &&
   1029                    last->Msg()->routing_id() == aMsg->routing_id();
   1030    if (compress) {
   1031      // This message type has compression enabled, and the back of the
   1032      // queue was the same message type and routed to the same destination.
   1033      // Replace it with the newer message.
   1034      MOZ_RELEASE_ASSERT(last->Msg()->compress_type() ==
   1035                         IPC::Message::COMPRESSION_ENABLED);
   1036      last->Msg() = std::move(aMsg);
   1037      return;
   1038    }
   1039  } else if (aMsg->compress_type() == IPC::Message::COMPRESSION_ALL &&
   1040             !mPending.isEmpty()) {
   1041    for (MessageTask* p = mPending.getLast(); p; p = p->getPrevious()) {
   1042      p->AssertMonitorHeld(*mMonitor);
   1043      if (p->Msg()->type() == aMsg->type() &&
   1044          p->Msg()->routing_id() == aMsg->routing_id()) {
   1045        // This message type has compression enabled, and the queue
   1046        // holds a message with the same message type and routed to the
   1047        // same destination. Erase it. Note that, since we always
   1048        // compress these redundancies, There Can Be Only One.
   1049        MOZ_RELEASE_ASSERT(p->Msg()->compress_type() ==
   1050                           IPC::Message::COMPRESSION_ALL);
   1051        MOZ_RELEASE_ASSERT(IsAlwaysDeferred(*p->Msg()));
   1052        p->remove();
   1053        break;
   1054      }
   1055    }
   1056  }
   1057 
   1058  bool alwaysDeferred = IsAlwaysDeferred(*aMsg);
   1059 
   1060  bool shouldWakeUp = AwaitingSyncReply() && !ShouldDeferMessage(*aMsg);
   1061 
   1062  IPC_LOG("Receive from link; seqno=%" PRId64 ", xid=%" PRId64
   1063          ", shouldWakeUp=%d",
   1064          aMsg->seqno(), aMsg->transaction_id(), shouldWakeUp);
   1065 
   1066  struct FlowMarkerDispatch {
   1067    FlowMarkerDispatch(msgid_t type, Flow flow) : type(type), flow(flow) {
   1068      if (profiler_feature_active(ProfilerFeature::Flows)) {
   1069        options.Set(MarkerTiming::InstantNow());
   1070      }
   1071    }
   1072    ~FlowMarkerDispatch() {
   1073      if (!options.IsTimingUnspecified()) {
   1074        options.TimingRef().SetIntervalEnd();
   1075        profiler_add_marker("IPCDispatch", baseprofiler::category::OTHER,
   1076                            std::move(options), IPCFlowMarker{}, type, flow);
   1077      }
   1078    }
   1079    msgid_t type;
   1080    Flow flow;
   1081    MarkerOptions options;
   1082  };
   1083 
   1084  // We want this marker to span the time when Post is called so that we
   1085  // can inherit the connection to the runnable.
   1086  FlowMarkerDispatch marker(
   1087      aMsg->type(), Flow::Global(static_cast<uint64_t>(aMsg->seqno()) ^
   1088                                 LossyNarrowChannelId(mMessageChannelId)));
   1089 
   1090  // There are two cases we're concerned about, relating to the state of the
   1091  // worker thread:
   1092  //
   1093  // (1) We are waiting on a sync reply - worker thread is blocked on the
   1094  //     IPC monitor.
   1095  //   - If the message is NESTED_INSIDE_SYNC, we wake up the worker thread to
   1096  //     deliver the message depending on ShouldDeferMessage. Otherwise, we
   1097  //     leave it in the mPending queue, posting a task to the worker event
   1098  //     loop, where it will be processed once the synchronous reply has been
   1099  //     received.
   1100  //
   1101  // (2) We are not waiting on a reply.
   1102  //   - We post a task to the worker event loop.
   1103  //
   1104  // Note that, we may notify the worker thread even though the monitor is not
   1105  // blocked. This is okay, since we always check for pending events before
   1106  // blocking again.
   1107 
   1108  RefPtr<MessageTask> task = new MessageTask(this, std::move(aMsg));
   1109  mPending.insertBack(task);
   1110 
   1111  if (!alwaysDeferred) {
   1112    mMaybeDeferredPendingCount++;
   1113  }
   1114 
   1115  if (shouldWakeUp) {
   1116    NotifyWorkerThread();
   1117  }
   1118 
   1119  // Although we usually don't need to post a message task if
   1120  // shouldWakeUp is true, it's easier to post anyway than to have to
   1121  // guarantee that every Send call processes everything it's supposed to
   1122  // before returning.
   1123  task->AssertMonitorHeld(*mMonitor);
   1124  task->Post();
   1125 }
   1126 
   1127 void MessageChannel::PeekMessages(
   1128    const std::function<bool(const Message& aMsg)>& aInvoke) {
   1129  // FIXME: We shouldn't be holding the lock for aInvoke!
   1130  MonitorAutoLock lock(*mMonitor);
   1131 
   1132  for (MessageTask* it : mPending) {
   1133    it->AssertMonitorHeld(*mMonitor);
   1134    const Message& msg = *it->Msg();
   1135    if (!aInvoke(msg)) {
   1136      break;
   1137    }
   1138  }
   1139 }
   1140 
   1141 void MessageChannel::ProcessPendingRequests(
   1142    ActorLifecycleProxy* aProxy, AutoEnterTransaction& aTransaction) {
   1143  mMonitor->AssertCurrentThreadOwns();
   1144 
   1145  AssertMaybeDeferredCountCorrect();
   1146  if (mMaybeDeferredPendingCount == 0) {
   1147    return;
   1148  }
   1149 
   1150  IPC_LOG("ProcessPendingRequests for seqno=%" PRId64 ", xid=%" PRId64,
   1151          aTransaction.SequenceNumber(), aTransaction.TransactionID());
   1152 
   1153  // Loop until there aren't any more nested messages to process.
   1154  for (;;) {
   1155    // If we canceled during ProcessPendingRequest, then we need to leave
   1156    // immediately because the results of ShouldDeferMessage will be
   1157    // operating with weird state (as if no Send is in progress). That could
   1158    // cause even NOT_NESTED sync messages to be processed (but not
   1159    // NOT_NESTED async messages), which would break message ordering.
   1160    if (aTransaction.IsCanceled()) {
   1161      return;
   1162    }
   1163 
   1164    Vector<UniquePtr<Message>> toProcess;
   1165 
   1166    for (MessageTask* p = mPending.getFirst(); p;) {
   1167      p->AssertMonitorHeld(*mMonitor);
   1168      UniquePtr<Message>& msg = p->Msg();
   1169 
   1170      MOZ_RELEASE_ASSERT(!aTransaction.IsCanceled(),
   1171                         "Calling ShouldDeferMessage when cancelled");
   1172      bool defer = ShouldDeferMessage(*msg);
   1173 
   1174      // Only log the interesting messages.
   1175      if (msg->is_sync() ||
   1176          msg->nested_level() == IPC::Message::NESTED_INSIDE_CPOW) {
   1177        IPC_LOG("ShouldDeferMessage(seqno=%" PRId64 ") = %d", msg->seqno(),
   1178                defer);
   1179      }
   1180 
   1181      if (!defer) {
   1182        MOZ_ASSERT(!IsAlwaysDeferred(*msg));
   1183 
   1184        if (!toProcess.append(std::move(msg))) MOZ_CRASH();
   1185 
   1186        mMaybeDeferredPendingCount--;
   1187 
   1188        p = p->removeAndGetNext();
   1189        continue;
   1190      }
   1191      p = p->getNext();
   1192    }
   1193 
   1194    if (toProcess.empty()) {
   1195      break;
   1196    }
   1197 
   1198    // Processing these messages could result in more messages, so we
   1199    // loop around to check for more afterwards.
   1200 
   1201    for (auto& msg : toProcess) {
   1202      ProcessPendingRequest(aProxy, std::move(msg));
   1203    }
   1204  }
   1205 
   1206  AssertMaybeDeferredCountCorrect();
   1207 }
   1208 
   1209 bool MessageChannel::Send(UniquePtr<Message> aMsg, UniquePtr<Message>* aReply) {
   1210  mozilla::TimeStamp start = TimeStamp::Now();
   1211 
   1212  // Sanity checks.
   1213  AssertWorkerThread();
   1214  mMonitor->AssertNotCurrentThreadOwns();
   1215  MOZ_RELEASE_ASSERT(!mIsSameThreadChannel,
   1216                     "sync send over same-thread channel will deadlock!");
   1217 
   1218  RefPtr<ActorLifecycleProxy> proxy = Listener()->GetLifecycleProxy();
   1219 
   1220 #ifdef XP_WIN
   1221  SyncStackFrame frame(this);
   1222  NeuteredWindowRegion neuteredRgn(mFlags &
   1223                                   REQUIRE_DEFERRED_MESSAGE_PROTECTION);
   1224 #endif
   1225 
   1226  AutoSetValue<bool> setOnCxxStack(mOnCxxStack, true);
   1227 
   1228  MonitorAutoLock lock(*mMonitor);
   1229 
   1230  if (mTimedOutMessageSeqno) {
   1231    // Don't bother sending another sync message if a previous one timed out
   1232    // and we haven't received a reply for it. Once the original timed-out
   1233    // message receives a reply, we'll be able to send more sync messages
   1234    // again.
   1235    IPC_LOG("Send() failed due to previous timeout");
   1236    mLastSendError = SyncSendError::PreviousTimeout;
   1237    return false;
   1238  }
   1239 
   1240  if (DispatchingSyncMessageNestedLevel() == IPC::Message::NOT_NESTED &&
   1241      aMsg->nested_level() > IPC::Message::NOT_NESTED) {
   1242    // Don't allow sending CPOWs while we're dispatching a sync message.
   1243    IPC_LOG("Nested level forbids send");
   1244    mLastSendError = SyncSendError::SendingCPOWWhileDispatchingSync;
   1245    return false;
   1246  }
   1247 
   1248  if (DispatchingSyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW ||
   1249      DispatchingAsyncMessageNestedLevel() ==
   1250          IPC::Message::NESTED_INSIDE_CPOW) {
   1251    // Generally only the parent dispatches urgent messages. And the only
   1252    // sync messages it can send are NESTED_INSIDE_SYNC. Mainly we want to
   1253    // ensure here that we don't return false for non-CPOW messages.
   1254    MOZ_RELEASE_ASSERT(aMsg->nested_level() ==
   1255                       IPC::Message::NESTED_INSIDE_SYNC);
   1256    IPC_LOG("Sending while dispatching urgent message");
   1257    mLastSendError = SyncSendError::SendingCPOWWhileDispatchingUrgent;
   1258    return false;
   1259  }
   1260 
   1261  if (aMsg->nested_level() < DispatchingSyncMessageNestedLevel() ||
   1262      aMsg->nested_level() < AwaitingSyncReplyNestedLevel()) {
   1263    MOZ_RELEASE_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage());
   1264    IPC_LOG("Cancel from Send");
   1265    auto cancel =
   1266        MakeUnique<CancelMessage>(CurrentNestedInsideSyncTransaction());
   1267    CancelTransaction(CurrentNestedInsideSyncTransaction());
   1268    SendMessageToLink(std::move(cancel));
   1269  }
   1270 
   1271  IPC_ASSERT(aMsg->is_sync(), "can only Send() sync messages here");
   1272 
   1273  IPC_ASSERT(aMsg->nested_level() >= DispatchingSyncMessageNestedLevel(),
   1274             "can't send sync message of a lesser nested level than what's "
   1275             "being dispatched");
   1276  IPC_ASSERT(AwaitingSyncReplyNestedLevel() <= aMsg->nested_level(),
   1277             "nested sync message sends must be of increasing nested level");
   1278  IPC_ASSERT(
   1279      DispatchingSyncMessageNestedLevel() != IPC::Message::NESTED_INSIDE_CPOW,
   1280      "not allowed to send messages while dispatching urgent messages");
   1281 
   1282  IPC_ASSERT(
   1283      DispatchingAsyncMessageNestedLevel() != IPC::Message::NESTED_INSIDE_CPOW,
   1284      "not allowed to send messages while dispatching urgent messages");
   1285 
   1286  if (!Connected()) {
   1287    ReportConnectionError("SendAndWait", aMsg->type());
   1288    mLastSendError = SyncSendError::NotConnectedBeforeSend;
   1289    return false;
   1290  }
   1291 
   1292  aMsg->set_seqno(NextSeqno());
   1293 
   1294  seqno_t seqno = aMsg->seqno();
   1295  int nestedLevel = aMsg->nested_level();
   1296  msgid_t replyType = aMsg->type() + 1;
   1297 
   1298  AutoEnterTransaction* stackTop = mTransactionStack;
   1299 
   1300  // If the most recent message on the stack is NESTED_INSIDE_SYNC, then our
   1301  // message should nest inside that and we use the same transaction
   1302  // ID. Otherwise we need a new transaction ID (so we use the seqno of the
   1303  // message we're sending).
   1304  bool nest =
   1305      stackTop && stackTop->NestedLevel() == IPC::Message::NESTED_INSIDE_SYNC;
   1306  seqno_t transaction = nest ? stackTop->TransactionID() : seqno;
   1307  aMsg->set_transaction_id(transaction);
   1308 
   1309  AutoEnterTransaction transact(this, seqno, transaction, nestedLevel);
   1310 
   1311  IPC_LOG("Send seqno=%" PRId64 ", xid=%" PRId64, seqno, transaction);
   1312 
   1313  // aMsg will be destroyed soon, let's keep its type.
   1314  const char* msgName = aMsg->name();
   1315  const msgid_t msgType = aMsg->type();
   1316 
   1317  AddProfilerMarker(*aMsg, MessageDirection::eSending);
   1318  SendMessageToLink(std::move(aMsg));
   1319 
   1320  while (true) {
   1321    MOZ_RELEASE_ASSERT(!transact.IsCanceled());
   1322    ProcessPendingRequests(proxy, transact);
   1323    if (transact.IsComplete()) {
   1324      break;
   1325    }
   1326    if (!Connected()) {
   1327      ReportConnectionError("Send", msgType);
   1328      mLastSendError = SyncSendError::DisconnectedDuringSend;
   1329      return false;
   1330    }
   1331 
   1332    MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno);
   1333    MOZ_RELEASE_ASSERT(!transact.IsComplete());
   1334    MOZ_RELEASE_ASSERT(mTransactionStack == &transact);
   1335 
   1336    bool maybeTimedOut = !WaitForSyncNotify();
   1337 
   1338    if (mListener->NeedArtificialSleep()) {
   1339      MonitorAutoUnlock unlock(*mMonitor);
   1340      mListener->ArtificialSleep();
   1341    }
   1342 
   1343    if (!Connected()) {
   1344      ReportConnectionError("SendAndWait", msgType);
   1345      mLastSendError = SyncSendError::DisconnectedDuringSend;
   1346      return false;
   1347    }
   1348 
   1349    if (transact.IsCanceled()) {
   1350      break;
   1351    }
   1352 
   1353    MOZ_RELEASE_ASSERT(mTransactionStack == &transact);
   1354 
   1355    // We only time out a message if it initiated a new transaction (i.e.,
   1356    // if neither side has any other message Sends on the stack).
   1357    bool canTimeOut = transact.IsBottom();
   1358    if (maybeTimedOut && canTimeOut && !ShouldContinueFromTimeout()) {
   1359      // Since ShouldContinueFromTimeout drops the lock, we need to
   1360      // re-check all our conditions here. We shouldn't time out if any of
   1361      // these things happen because there won't be a reply to the timed
   1362      // out message in these cases.
   1363      if (transact.IsComplete()) {
   1364        break;
   1365      }
   1366 
   1367      IPC_LOG("Timing out Send: xid=%" PRId64, transaction);
   1368 
   1369      mTimedOutMessageSeqno = seqno;
   1370      mTimedOutMessageNestedLevel = nestedLevel;
   1371      mLastSendError = SyncSendError::TimedOut;
   1372      return false;
   1373    }
   1374 
   1375    if (transact.IsCanceled()) {
   1376      break;
   1377    }
   1378  }
   1379 
   1380  if (transact.IsCanceled()) {
   1381    IPC_LOG("Other side canceled seqno=%" PRId64 ", xid=%" PRId64, seqno,
   1382            transaction);
   1383    mLastSendError = SyncSendError::CancelledAfterSend;
   1384    return false;
   1385  }
   1386 
   1387  if (transact.IsError()) {
   1388    IPC_LOG("Error: seqno=%" PRId64 ", xid=%" PRId64, seqno, transaction);
   1389    mLastSendError = SyncSendError::ReplyError;
   1390    return false;
   1391  }
   1392 
   1393  uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
   1394  IPC_LOG("Got reply: seqno=%" PRId64 ", xid=%" PRId64
   1395          ", msgName=%s, latency=%ums",
   1396          seqno, transaction, msgName, latencyMs);
   1397 
   1398  UniquePtr<Message> reply = transact.GetReply();
   1399 
   1400  MOZ_RELEASE_ASSERT(reply);
   1401  MOZ_RELEASE_ASSERT(reply->is_reply(), "expected reply");
   1402  MOZ_RELEASE_ASSERT(!reply->is_reply_error());
   1403  MOZ_RELEASE_ASSERT(reply->seqno() == seqno);
   1404  MOZ_RELEASE_ASSERT(reply->type() == replyType, "wrong reply type");
   1405  MOZ_RELEASE_ASSERT(reply->is_sync());
   1406 
   1407  AddProfilerMarker(*reply, MessageDirection::eReceiving);
   1408 
   1409  *aReply = std::move(reply);
   1410  return true;
   1411 }
   1412 
   1413 bool MessageChannel::HasPendingEvents() {
   1414  AssertWorkerThread();
   1415  mMonitor->AssertCurrentThreadOwns();
   1416  return ConnectedOrClosing() && !mPending.isEmpty();
   1417 }
   1418 
   1419 bool MessageChannel::ProcessPendingRequest(ActorLifecycleProxy* aProxy,
   1420                                           UniquePtr<Message> aUrgent) {
   1421  AssertWorkerThread();
   1422  mMonitor->AssertCurrentThreadOwns();
   1423 
   1424  IPC_LOG("Process pending: seqno=%" PRId64 ", xid=%" PRId64, aUrgent->seqno(),
   1425          aUrgent->transaction_id());
   1426 
   1427  // keep the error relevant information
   1428  msgid_t msgType = aUrgent->type();
   1429 
   1430  DispatchMessage(aProxy, std::move(aUrgent));
   1431  if (!ConnectedOrClosing()) {
   1432    ReportConnectionError("ProcessPendingRequest", msgType);
   1433    return false;
   1434  }
   1435 
   1436  return true;
   1437 }
   1438 
   1439 bool MessageChannel::ShouldRunMessage(const Message& aMsg) {
   1440  if (!mTimedOutMessageSeqno) {
   1441    return true;
   1442  }
   1443 
   1444  // If we've timed out a message and we're awaiting the reply to the timed
   1445  // out message, we have to be careful what messages we process. Here's what
   1446  // can go wrong:
   1447  // 1. child sends a NOT_NESTED sync message S
   1448  // 2. parent sends a NESTED_INSIDE_SYNC sync message H at the same time
   1449  // 3. parent times out H
   1450  // 4. child starts processing H and sends a NESTED_INSIDE_SYNC message H'
   1451  //    nested within the same transaction
   1452  // 5. parent dispatches S and sends reply
   1453  // 6. child asserts because it instead expected a reply to H'.
   1454  //
   1455  // To solve this, we refuse to process S in the parent until we get a reply
   1456  // to H. More generally, let the timed out message be M. We don't process a
   1457  // message unless the child would need the response to that message in order
   1458  // to process M. Those messages are the ones that have a higher nested level
   1459  // than M or that are part of the same transaction as M.
   1460  if (aMsg.nested_level() < mTimedOutMessageNestedLevel ||
   1461      (aMsg.nested_level() == mTimedOutMessageNestedLevel &&
   1462       aMsg.transaction_id() != mTimedOutMessageSeqno)) {
   1463    return false;
   1464  }
   1465 
   1466  return true;
   1467 }
   1468 
   1469 void MessageChannel::RunMessage(ActorLifecycleProxy* aProxy,
   1470                                MessageTask& aTask) {
   1471  AssertWorkerThread();
   1472  mMonitor->AssertCurrentThreadOwns();
   1473  aTask.AssertMonitorHeld(*mMonitor);
   1474 
   1475  UniquePtr<Message>& msg = aTask.Msg();
   1476 
   1477  if (!ConnectedOrClosing()) {
   1478    ReportConnectionError("RunMessage", msg->type());
   1479    return;
   1480  }
   1481 
   1482  // Check that we're going to run the first message that's valid to run.
   1483 #if 0
   1484 #  ifdef DEBUG
   1485    for (MessageTask* task : mPending) {
   1486        if (task == &aTask) {
   1487            break;
   1488        }
   1489 
   1490        MOZ_ASSERT(!ShouldRunMessage(*task->Msg()) ||
   1491                   aTask.Msg()->priority() != task->Msg()->priority());
   1492 
   1493    }
   1494 #  endif
   1495 #endif
   1496 
   1497  if (!ShouldRunMessage(*msg)) {
   1498    return;
   1499  }
   1500 
   1501  MOZ_RELEASE_ASSERT(aTask.isInList());
   1502  aTask.remove();
   1503 
   1504  if (!IsAlwaysDeferred(*msg)) {
   1505    mMaybeDeferredPendingCount--;
   1506  }
   1507 
   1508  DispatchMessage(aProxy, std::move(msg));
   1509 }
   1510 
   1511 NS_IMPL_ISUPPORTS_INHERITED(MessageChannel::MessageTask, CancelableRunnable,
   1512                            nsIRunnablePriority, nsIRunnableIPCMessageType)
   1513 
   1514 static uint32_t ToRunnablePriority(IPC::Message::PriorityValue aPriority) {
   1515  switch (aPriority) {
   1516    case IPC::Message::LOW_PRIORITY:
   1517      return nsIRunnablePriority::PRIORITY_LOW;
   1518    case IPC::Message::NORMAL_PRIORITY:
   1519      return nsIRunnablePriority::PRIORITY_NORMAL;
   1520    case IPC::Message::INPUT_PRIORITY:
   1521      return nsIRunnablePriority::PRIORITY_INPUT_HIGH;
   1522    case IPC::Message::VSYNC_PRIORITY:
   1523      return nsIRunnablePriority::PRIORITY_VSYNC;
   1524    case IPC::Message::MEDIUMHIGH_PRIORITY:
   1525      return nsIRunnablePriority::PRIORITY_MEDIUMHIGH;
   1526    case IPC::Message::CONTROL_PRIORITY:
   1527      return nsIRunnablePriority::PRIORITY_CONTROL;
   1528    default:
   1529      MOZ_ASSERT_UNREACHABLE();
   1530      return nsIRunnablePriority::PRIORITY_NORMAL;
   1531  }
   1532 }
   1533 
   1534 MessageChannel::MessageTask::MessageTask(MessageChannel* aChannel,
   1535                                         UniquePtr<Message> aMessage)
   1536    : CancelableRunnable(aMessage->name()),
   1537      mMonitor(aChannel->mMonitor),
   1538      mChannel(aChannel),
   1539      mMessage(std::move(aMessage)),
   1540      mPriority(ToRunnablePriority(mMessage->priority())),
   1541      mScheduled(false)
   1542 #ifdef FUZZING_SNAPSHOT
   1543      ,
   1544      mIsFuzzMsg(mMessage->IsFuzzMsg()),
   1545      mFuzzStopped(false)
   1546 #endif
   1547 {
   1548  MOZ_DIAGNOSTIC_ASSERT(mMessage, "message may not be null");
   1549 #ifdef FUZZING_SNAPSHOT
   1550  if (mIsFuzzMsg) {
   1551    MOZ_FUZZING_IPC_MT_CTOR();
   1552  }
   1553 #endif
   1554 }
   1555 
   1556 MessageChannel::MessageTask::~MessageTask() {
   1557 #ifdef FUZZING_SNAPSHOT
   1558  // We track fuzzing messages until their run is complete. To make sure
   1559  // that we don't miss messages that are for some reason destroyed without
   1560  // being run (e.g. canceled), we catch this condition in the destructor.
   1561  if (mIsFuzzMsg && !mFuzzStopped) {
   1562    MOZ_FUZZING_IPC_MT_STOP();
   1563  } else if (!mIsFuzzMsg && !fuzzing::Nyx::instance().started()) {
   1564    MOZ_FUZZING_IPC_PRE_FUZZ_MT_STOP();
   1565  }
   1566 #endif
   1567 }
   1568 
   1569 nsresult MessageChannel::MessageTask::Run() {
   1570  mMonitor->AssertNotCurrentThreadOwns();
   1571 
   1572  // Drop the toplevel actor's lifecycle proxy outside of our monitor if we take
   1573  // it, as destroying our ActorLifecycleProxy reference can acquire the
   1574  // monitor.
   1575  RefPtr<ActorLifecycleProxy> proxy;
   1576 
   1577  MonitorAutoLock lock(*mMonitor);
   1578 
   1579  // In case we choose not to run this message, we may need to be able to Post
   1580  // it again.
   1581  mScheduled = false;
   1582 
   1583  if (!isInList()) {
   1584    return NS_OK;
   1585  }
   1586 
   1587  Channel()->AssertWorkerThread();
   1588  mMonitor->AssertSameMonitor(*Channel()->mMonitor);
   1589 
   1590 #ifdef FUZZING_SNAPSHOT
   1591  if (!mIsFuzzMsg) {
   1592    if (fuzzing::Nyx::instance().started() && XRE_IsParentProcess() &&
   1593        Channel()->IsCrossProcess()) {
   1594      // Once we started fuzzing, prevent non-fuzzing tasks from being
   1595      // run and potentially blocking worker threads.
   1596      //
   1597      // TODO: This currently blocks all MessageTasks from running, not
   1598      // just those belonging to the target process pair. We currently
   1599      // do this for performance reasons, but it should be re-evaluated
   1600      // at a later stage when we found a better snapshot point.
   1601      return NS_OK;
   1602    }
   1603    // Record all running tasks prior to fuzzing, so we can wait for
   1604    // them to settle before snapshotting.
   1605    MOZ_FUZZING_IPC_PRE_FUZZ_MT_RUN();
   1606  }
   1607 #endif
   1608 
   1609  proxy = Channel()->Listener()->GetLifecycleProxy();
   1610  Channel()->RunMessage(proxy, *this);
   1611 
   1612 #ifdef FUZZING_SNAPSHOT
   1613  if (mIsFuzzMsg && !mFuzzStopped) {
   1614    MOZ_FUZZING_IPC_MT_STOP();
   1615    mFuzzStopped = true;
   1616  }
   1617 #endif
   1618  return NS_OK;
   1619 }
   1620 
   1621 // Warning: This method removes the receiver from whatever list it might be in.
   1622 nsresult MessageChannel::MessageTask::Cancel() {
   1623  mMonitor->AssertNotCurrentThreadOwns();
   1624 
   1625  MonitorAutoLock lock(*mMonitor);
   1626 
   1627  if (!isInList()) {
   1628    return NS_OK;
   1629  }
   1630 
   1631  Channel()->AssertWorkerThread();
   1632  mMonitor->AssertSameMonitor(*Channel()->mMonitor);
   1633  if (!IsAlwaysDeferred(*Msg())) {
   1634    Channel()->mMaybeDeferredPendingCount--;
   1635  }
   1636 
   1637  remove();
   1638 
   1639 #ifdef FUZZING_SNAPSHOT
   1640  if (mIsFuzzMsg && !mFuzzStopped) {
   1641    MOZ_FUZZING_IPC_MT_STOP();
   1642    mFuzzStopped = true;
   1643  }
   1644 #endif
   1645 
   1646  return NS_OK;
   1647 }
   1648 
   1649 void MessageChannel::MessageTask::Post() {
   1650  mMonitor->AssertCurrentThreadOwns();
   1651  mMonitor->AssertSameMonitor(*Channel()->mMonitor);
   1652  MOZ_RELEASE_ASSERT(!mScheduled);
   1653  MOZ_RELEASE_ASSERT(isInList());
   1654 
   1655  mScheduled = true;
   1656 
   1657  Channel()->mWorkerThread->Dispatch(do_AddRef(this));
   1658 }
   1659 
   1660 NS_IMETHODIMP
   1661 MessageChannel::MessageTask::GetPriority(uint32_t* aPriority) {
   1662  *aPriority = mPriority;
   1663  return NS_OK;
   1664 }
   1665 
   1666 NS_IMETHODIMP
   1667 MessageChannel::MessageTask::GetType(uint32_t* aType) {
   1668  mMonitor->AssertNotCurrentThreadOwns();
   1669 
   1670  MonitorAutoLock lock(*mMonitor);
   1671  if (!mMessage) {
   1672    // If mMessage has been moved already elsewhere, we can't know what the type
   1673    // has been.
   1674    return NS_ERROR_FAILURE;
   1675  }
   1676 
   1677  *aType = mMessage->type();
   1678  return NS_OK;
   1679 }
   1680 
   1681 void MessageChannel::DispatchMessage(ActorLifecycleProxy* aProxy,
   1682                                     UniquePtr<Message> aMsg) {
   1683  AssertWorkerThread();
   1684  mMonitor->AssertCurrentThreadOwns();
   1685 
   1686  Maybe<AutoNoJSAPI> nojsapi;
   1687  if (NS_IsMainThread() && CycleCollectedJSContext::Get()) {
   1688    nojsapi.emplace();
   1689  }
   1690 
   1691  UniquePtr<Message> reply;
   1692 
   1693 #ifdef FUZZING_SNAPSHOT
   1694  if (IsCrossProcess()) {
   1695    aMsg = mozilla::fuzzing::IPCFuzzController::instance().replaceIPCMessage(
   1696        std::move(aMsg));
   1697  }
   1698 #endif
   1699 
   1700  IPC_LOG("DispatchMessage: seqno=%" PRId64 ", xid=%" PRId64, aMsg->seqno(),
   1701          aMsg->transaction_id());
   1702  AddProfilerMarker(*aMsg, MessageDirection::eReceiving);
   1703 
   1704  {
   1705    AutoEnterTransaction transaction(this, *aMsg);
   1706 
   1707    seqno_t id = aMsg->transaction_id();
   1708    MOZ_RELEASE_ASSERT(!aMsg->is_sync() || id == transaction.TransactionID());
   1709 
   1710    {
   1711      MonitorAutoUnlock unlock(*mMonitor);
   1712      AutoSetValue<bool> setOnCxxStack(mOnCxxStack, true);
   1713 
   1714      mListener->ArtificialSleep();
   1715 
   1716      if (aMsg->is_sync()) {
   1717        DispatchSyncMessage(aProxy, *aMsg, reply);
   1718      } else {
   1719        DispatchAsyncMessage(aProxy, *aMsg);
   1720      }
   1721 
   1722      mListener->ArtificialSleep();
   1723    }
   1724 
   1725    if (reply && transaction.IsCanceled()) {
   1726      // The transaction has been canceled. Don't send a reply.
   1727      IPC_LOG("Nulling out reply due to cancellation, seqno=%" PRId64
   1728              ", xid=%" PRId64,
   1729              aMsg->seqno(), id);
   1730      reply = nullptr;
   1731    }
   1732  }
   1733 
   1734 #ifdef FUZZING_SNAPSHOT
   1735  if (aMsg->IsFuzzMsg()) {
   1736    mozilla::fuzzing::IPCFuzzController::instance().syncAfterReplace();
   1737  }
   1738 #endif
   1739 
   1740  if (reply && ChannelConnected == mChannelState) {
   1741    IPC_LOG("Sending reply seqno=%" PRId64 ", xid=%" PRId64, aMsg->seqno(),
   1742            aMsg->transaction_id());
   1743    AddProfilerMarker(*reply, MessageDirection::eSending);
   1744 
   1745    SendMessageToLink(std::move(reply));
   1746  }
   1747 }
   1748 
   1749 void MessageChannel::DispatchSyncMessage(ActorLifecycleProxy* aProxy,
   1750                                         const Message& aMsg,
   1751                                         UniquePtr<Message>& aReply) {
   1752  AssertWorkerThread();
   1753 
   1754  int nestedLevel = aMsg.nested_level();
   1755 
   1756  MOZ_RELEASE_ASSERT(nestedLevel == IPC::Message::NOT_NESTED ||
   1757                     NS_IsMainThread());
   1758 
   1759  MessageChannel* dummy;
   1760  MessageChannel*& blockingVar =
   1761      mSide == ChildSide && NS_IsMainThread() ? gParentProcessBlocker : dummy;
   1762 
   1763  Result rv;
   1764  {
   1765    AutoSetValue<MessageChannel*> blocked(blockingVar, this);
   1766    rv = aProxy->Get()->OnMessageReceived(aMsg, aReply);
   1767  }
   1768 
   1769  if (!MaybeHandleError(rv, aMsg, "DispatchSyncMessage")) {
   1770    aReply = Message::ForSyncDispatchError(aMsg.nested_level());
   1771  }
   1772  aReply->set_seqno(aMsg.seqno());
   1773  aReply->set_transaction_id(aMsg.transaction_id());
   1774 }
   1775 
   1776 void MessageChannel::DispatchAsyncMessage(ActorLifecycleProxy* aProxy,
   1777                                          const Message& aMsg) {
   1778  AssertWorkerThread();
   1779  MOZ_RELEASE_ASSERT(!aMsg.is_sync());
   1780 
   1781  if (aMsg.routing_id() == MSG_ROUTING_NONE) {
   1782    NS_WARNING("unhandled special message!");
   1783    MaybeHandleError(MsgNotKnown, aMsg, "DispatchAsyncMessage");
   1784    return;
   1785  }
   1786 
   1787  Result rv;
   1788  {
   1789    int nestedLevel = aMsg.nested_level();
   1790    AutoSetValue<bool> async(mDispatchingAsyncMessage, true);
   1791    AutoSetValue<int> nestedLevelSet(mDispatchingAsyncMessageNestedLevel,
   1792                                     nestedLevel);
   1793    rv = aProxy->Get()->OnMessageReceived(aMsg);
   1794  }
   1795  MaybeHandleError(rv, aMsg, "DispatchAsyncMessage");
   1796 }
   1797 
   1798 void MessageChannel::EnqueuePendingMessages() {
   1799  AssertWorkerThread();
   1800  mMonitor->AssertCurrentThreadOwns();
   1801 
   1802  // XXX performance tuning knob: could process all or k pending
   1803  // messages here, rather than enqueuing for later processing
   1804 
   1805  RepostAllMessages();
   1806 }
   1807 
   1808 bool MessageChannel::WaitResponse(bool aWaitTimedOut) {
   1809  AssertWorkerThread();
   1810  if (aWaitTimedOut) {
   1811    if (mInTimeoutSecondHalf) {
   1812      // We've really timed out this time.
   1813      return false;
   1814    }
   1815    // Try a second time.
   1816    mInTimeoutSecondHalf = true;
   1817  } else {
   1818    mInTimeoutSecondHalf = false;
   1819  }
   1820  return true;
   1821 }
   1822 
   1823 #ifndef XP_WIN
   1824 bool MessageChannel::WaitForSyncNotify() {
   1825  AssertWorkerThread();
   1826 #  ifdef DEBUG
   1827  // WARNING: We don't release the lock here. We can't because the link
   1828  // could signal at this time and we would miss it. Instead we require
   1829  // ArtificialTimeout() to be extremely simple.
   1830  if (mListener->ArtificialTimeout()) {
   1831    return false;
   1832  }
   1833 #  endif
   1834 
   1835  MOZ_RELEASE_ASSERT(!mIsSameThreadChannel,
   1836                     "Wait on same-thread channel will deadlock!");
   1837 
   1838  TimeDuration timeout = (kNoTimeout == mTimeoutMs)
   1839                             ? TimeDuration::Forever()
   1840                             : TimeDuration::FromMilliseconds(mTimeoutMs);
   1841  CVStatus status = mMonitor->Wait(timeout);
   1842 
   1843  // If the timeout didn't expire, we know we received an event. The
   1844  // converse is not true.
   1845  return WaitResponse(status == CVStatus::Timeout);
   1846 }
   1847 
   1848 void MessageChannel::NotifyWorkerThread() { mMonitor->Notify(); }
   1849 #endif
   1850 
   1851 bool MessageChannel::ShouldContinueFromTimeout() {
   1852  AssertWorkerThread();
   1853  mMonitor->AssertCurrentThreadOwns();
   1854 
   1855  bool cont;
   1856  {
   1857    MonitorAutoUnlock unlock(*mMonitor);
   1858    cont = mListener->ShouldContinueFromReplyTimeout();
   1859    mListener->ArtificialSleep();
   1860  }
   1861 
   1862  static enum {
   1863    UNKNOWN,
   1864    NOT_DEBUGGING,
   1865    DEBUGGING
   1866  } sDebuggingChildren = UNKNOWN;
   1867 
   1868  if (sDebuggingChildren == UNKNOWN) {
   1869    sDebuggingChildren =
   1870        getenv("MOZ_DEBUG_CHILD_PROCESS") || getenv("MOZ_DEBUG_CHILD_PAUSE")
   1871            ? DEBUGGING
   1872            : NOT_DEBUGGING;
   1873  }
   1874  if (sDebuggingChildren == DEBUGGING) {
   1875    return true;
   1876  }
   1877 
   1878  return cont;
   1879 }
   1880 
   1881 void MessageChannel::SetReplyTimeoutMs(int32_t aTimeoutMs) {
   1882  // Set channel timeout value. Since this is broken up into
   1883  // two period, the minimum timeout value is 2ms.
   1884  AssertWorkerThread();
   1885  mTimeoutMs =
   1886      (aTimeoutMs <= 0) ? kNoTimeout : (int32_t)ceil((double)aTimeoutMs / 2.0);
   1887 }
   1888 
   1889 void MessageChannel::ReportConnectionError(const char* aFunctionName,
   1890                                           const uint32_t aMsgType) const {
   1891  AssertWorkerThread();
   1892  mMonitor->AssertCurrentThreadOwns();
   1893 
   1894  const char* errorMsg = nullptr;
   1895  switch (mChannelState) {
   1896    case ChannelClosed:
   1897      errorMsg = "Closed channel: cannot send/recv";
   1898      break;
   1899    case ChannelClosing:
   1900      errorMsg = "Channel closing: too late to send, messages will be lost";
   1901      break;
   1902    case ChannelError:
   1903      errorMsg = "Channel error: cannot send/recv";
   1904      break;
   1905 
   1906    default:
   1907      MOZ_CRASH("unreached");
   1908  }
   1909 
   1910  // IPC connection errors are fairly common, especially "Channel closing: too
   1911  // late to send/recv, messages will be lost", so shouldn't be being reported
   1912  // on release builds, as that's misleading as to their severity.
   1913  NS_WARNING(nsPrintfCString("IPC Connection Error: [%s][%s] %s(msgname=%s) %s",
   1914                             StringFromIPCSide(mSide), mName, aFunctionName,
   1915                             IPC::StringFromIPCMessageType(aMsgType), errorMsg)
   1916                 .get());
   1917 
   1918  MonitorAutoUnlock unlock(*mMonitor);
   1919  mListener->ProcessingError(MsgDropped, errorMsg);
   1920 }
   1921 
   1922 bool MessageChannel::MaybeHandleError(Result code, const Message& aMsg,
   1923                                      const char* channelName) {
   1924  if (MsgProcessed == code) return true;
   1925 
   1926 #ifdef FUZZING_SNAPSHOT
   1927  mozilla::fuzzing::IPCFuzzController::instance().OnMessageError(code, aMsg);
   1928 #endif
   1929 
   1930  const char* errorMsg = nullptr;
   1931  switch (code) {
   1932    case MsgDropped:
   1933      errorMsg = "Message dropped: message could not be delivered";
   1934      break;
   1935    case MsgNotKnown:
   1936      errorMsg = "Unknown message: not processed";
   1937      break;
   1938    case MsgNotAllowed:
   1939      errorMsg = "Message not allowed: cannot be sent/recvd in this state";
   1940      break;
   1941    case MsgPayloadError:
   1942      errorMsg = "Payload error: message could not be deserialized";
   1943      break;
   1944    case MsgProcessingError:
   1945      errorMsg =
   1946          "Processing error: message was deserialized, but the handler "
   1947          "returned false (indicating failure)";
   1948      break;
   1949    case MsgValueError:
   1950      errorMsg =
   1951          "Value error: message was deserialized, but contained an illegal "
   1952          "value";
   1953      break;
   1954 
   1955    default:
   1956      MOZ_CRASH("unknown Result code");
   1957      return false;
   1958  }
   1959 
   1960  char reason[512];
   1961  const char* msgname = aMsg.name();
   1962  if (msgname[0] == '?') {
   1963    SprintfLiteral(reason, "(msgtype=0x%X) %s", aMsg.type(), errorMsg);
   1964  } else {
   1965    SprintfLiteral(reason, "%s %s", msgname, errorMsg);
   1966  }
   1967 
   1968  PrintErrorMessage(mSide, channelName, reason);
   1969 
   1970  // Error handled in mozilla::ipc::IPCResult.
   1971  if (code == MsgProcessingError) {
   1972    return false;
   1973  }
   1974 
   1975  mListener->ProcessingError(code, reason);
   1976 
   1977  return false;
   1978 }
   1979 
   1980 void MessageChannel::OnChannelErrorFromLink() {
   1981  mMonitor->AssertCurrentThreadOwns();
   1982  MOZ_ASSERT(mChannelState == ChannelConnected);
   1983 
   1984  IPC_LOG("OnChannelErrorFromLink");
   1985 
   1986  if (AwaitingSyncReply()) {
   1987    NotifyWorkerThread();
   1988  }
   1989 
   1990  if (mAbortOnError) {
   1991    // mAbortOnError is set by main actors (e.g., ContentChild) to ensure
   1992    // that the process terminates even if normal shutdown is prevented.
   1993    // A MOZ_CRASH() here is not helpful because crash reporting relies
   1994    // on the parent process which we know is dead or otherwise unusable.
   1995    //
   1996    // Additionally, the parent process can (and often is) killed on Android
   1997    // when apps are backgrounded. We don't need to report a crash for
   1998    // normal behavior in that case.
   1999    printf_stderr("Exiting due to channel error.\n");
   2000    ProcessChild::QuickExit();
   2001  }
   2002  mChannelState = ChannelError;
   2003  mMonitor->Notify();
   2004 
   2005  PostErrorNotifyTask();
   2006 }
   2007 
   2008 void MessageChannel::NotifyMaybeChannelError(ReleasableMonitorAutoLock& aLock) {
   2009  AssertWorkerThread();
   2010  mMonitor->AssertCurrentThreadOwns();
   2011  aLock.AssertCurrentThreadOwns();
   2012  MOZ_ASSERT(mChannelState != ChannelConnected);
   2013 
   2014  if (ChannelClosing == mChannelState || ChannelClosed == mChannelState) {
   2015    // the channel closed, but we received a "Goodbye" message warning us
   2016    // about it. no worries
   2017    mChannelState = ChannelClosed;
   2018    NotifyChannelClosed(aLock);
   2019    return;
   2020  }
   2021 
   2022  MOZ_ASSERT(ChannelError == mChannelState);
   2023 
   2024  Clear();
   2025 
   2026  // IPDL assumes these notifications do not fire twice, so we do not let
   2027  // that happen.
   2028  if (mNotifiedChannelDone) {
   2029    return;
   2030  }
   2031  mNotifiedChannelDone = true;
   2032 
   2033  // Let our listener know that the channel errored. This may cause the
   2034  // channel to be deleted. Release our caller's `MonitorAutoLock` before
   2035  // invoking the listener, as this may call back into MessageChannel, and/or
   2036  // cause the channel to be destroyed.
   2037  aLock.Unlock();
   2038  mListener->OnChannelError();
   2039 }
   2040 
   2041 void MessageChannel::OnNotifyMaybeChannelError() {
   2042  AssertWorkerThread();
   2043  mMonitor->AssertNotCurrentThreadOwns();
   2044 
   2045  // This lock guard may be reset by `NotifyMaybeChannelError` before invoking
   2046  // listener callbacks which may destroy this `MessageChannel`.
   2047  //
   2048  // Acquiring the lock here also allows us to ensure that
   2049  // `OnChannelErrorFromLink` has finished running before this task is allowed
   2050  // to continue.
   2051  ReleasableMonitorAutoLock lock(*mMonitor);
   2052 
   2053  mChannelErrorTask = nullptr;
   2054 
   2055  if (IsOnCxxStack()) {
   2056    // This used to post a 10ms delayed task; however not all
   2057    // nsISerialEventTarget implementations support delayed dispatch.
   2058    // The delay being completely arbitrary, we may not as well have any.
   2059    PostErrorNotifyTask();
   2060    return;
   2061  }
   2062 
   2063  // This call may destroy `this`.
   2064  NotifyMaybeChannelError(lock);
   2065 }
   2066 
   2067 void MessageChannel::PostErrorNotifyTask() {
   2068  mMonitor->AssertCurrentThreadOwns();
   2069 
   2070  if (mChannelErrorTask) {
   2071    return;
   2072  }
   2073 
   2074  // This must be the last code that runs on this thread!
   2075  mChannelErrorTask = NewNonOwningCancelableRunnableMethod(
   2076      "ipc::MessageChannel::OnNotifyMaybeChannelError", this,
   2077      &MessageChannel::OnNotifyMaybeChannelError);
   2078  mWorkerThread->Dispatch(do_AddRef(mChannelErrorTask));
   2079 }
   2080 
   2081 // Special async message.
   2082 class GoodbyeMessage : public IPC::Message {
   2083 public:
   2084  GoodbyeMessage() : IPC::Message(MSG_ROUTING_NONE, GOODBYE_MESSAGE_TYPE) {}
   2085  static bool Read(const Message* msg) { return true; }
   2086  void Log(const std::string& aPrefix, FILE* aOutf) const {
   2087    fputs("(special `Goodbye' message)", aOutf);
   2088  }
   2089 };
   2090 
   2091 void MessageChannel::InduceConnectionError() {
   2092  MonitorAutoLock lock(*mMonitor);
   2093 
   2094  // Either connected or closing, immediately convert to an error and notify.
   2095  switch (mChannelState) {
   2096    case ChannelConnected:
   2097      // The channel is still actively connected. Immediately shut down the
   2098      // connection with our peer and simulate it invoking
   2099      // OnChannelErrorFromLink on us.
   2100      //
   2101      // This will update the state to ChannelError, preventing new messages
   2102      // from being processed, leading to an error being reported asynchronously
   2103      // to our listener.
   2104      mLink->Close();
   2105      OnChannelErrorFromLink();
   2106      return;
   2107 
   2108    case ChannelClosing:
   2109      // An notify task has already been posted. Update mChannelState to stop
   2110      // processing new messages and treat the notification as an error.
   2111      mChannelState = ChannelError;
   2112      return;
   2113 
   2114    default:
   2115      // Either already closed or errored. Nothing to do.
   2116      MOZ_ASSERT(mChannelState == ChannelClosed ||
   2117                 mChannelState == ChannelError);
   2118      return;
   2119  }
   2120 }
   2121 
   2122 void MessageChannel::NotifyImpendingShutdown() {
   2123  UniquePtr<Message> msg =
   2124      MakeUnique<Message>(MSG_ROUTING_NONE, IMPENDING_SHUTDOWN_MESSAGE_TYPE);
   2125  MonitorAutoLock lock(*mMonitor);
   2126  if (Connected()) {
   2127    SendMessageToLink(std::move(msg));
   2128  }
   2129 }
   2130 
   2131 void MessageChannel::Close() {
   2132  AssertWorkerThread();
   2133  mMonitor->AssertNotCurrentThreadOwns();
   2134 
   2135  // This lock guard may be reset by `Notify{ChannelClosed,MaybeChannelError}`
   2136  // before invoking listener callbacks which may destroy this `MessageChannel`.
   2137  ReleasableMonitorAutoLock lock(*mMonitor);
   2138 
   2139  switch (mChannelState) {
   2140    case ChannelError:
   2141      // See bug 538586: if the listener gets deleted while the
   2142      // IO thread's NotifyChannelError event is still enqueued
   2143      // and subsequently deletes us, then the error event will
   2144      // also be deleted and the listener will never be notified
   2145      // of the channel error.
   2146      NotifyMaybeChannelError(lock);
   2147      return;
   2148    case ChannelClosed:
   2149      // Slightly unexpected but harmless; ignore.  See bug 1554244.
   2150      return;
   2151 
   2152    default:
   2153      // Notify the other side that we're about to close our socket. If we've
   2154      // already received a Goodbye from the other side (and our state is
   2155      // ChannelClosing), there's no reason to send one.
   2156      if (ChannelConnected == mChannelState) {
   2157        SendMessageToLink(MakeUnique<GoodbyeMessage>());
   2158      }
   2159      mLink->Close();
   2160      mChannelState = ChannelClosed;
   2161      NotifyChannelClosed(lock);
   2162      return;
   2163  }
   2164 }
   2165 
   2166 void MessageChannel::NotifyChannelClosed(ReleasableMonitorAutoLock& aLock) {
   2167  AssertWorkerThread();
   2168  mMonitor->AssertCurrentThreadOwns();
   2169  aLock.AssertCurrentThreadOwns();
   2170 
   2171  if (ChannelClosed != mChannelState) {
   2172    MOZ_CRASH("channel should have been closed!");
   2173  }
   2174 
   2175  Clear();
   2176 
   2177  // IPDL assumes these notifications do not fire twice, so we do not let
   2178  // that happen.
   2179  if (mNotifiedChannelDone) {
   2180    return;
   2181  }
   2182  mNotifiedChannelDone = true;
   2183 
   2184  // Let our listener know that the channel was closed. This may cause the
   2185  // channel to be deleted. Release our caller's `MonitorAutoLock` before
   2186  // invoking the listener, as this may call back into MessageChannel, and/or
   2187  // cause the channel to be destroyed.
   2188  aLock.Unlock();
   2189  mListener->OnChannelClose();
   2190 }
   2191 
   2192 void MessageChannel::DebugAbort(const char* file, int line, const char* cond,
   2193                                const char* why, bool reply) {
   2194  AssertWorkerThread();
   2195  mMonitor->AssertCurrentThreadOwns();
   2196 
   2197  printf_stderr(
   2198      "###!!! [MessageChannel][%s][%s:%d] "
   2199      "Assertion (%s) failed.  %s %s\n",
   2200      StringFromIPCSide(mSide), file, line, cond, why, reply ? "(reply)" : "");
   2201 
   2202  MessageQueue pending = std::move(mPending);
   2203  while (!pending.isEmpty()) {
   2204    pending.getFirst()->AssertMonitorHeld(*mMonitor);
   2205    printf_stderr("    [ %s%s ]\n",
   2206                  pending.getFirst()->Msg()->is_sync() ? "sync" : "async",
   2207                  pending.getFirst()->Msg()->is_reply() ? "reply" : "");
   2208    pending.popFirst();
   2209  }
   2210 
   2211  MOZ_CRASH_UNSAFE(why);
   2212 }
   2213 
   2214 void MessageChannel::AddProfilerMarker(const IPC::Message& aMessage,
   2215                                       MessageDirection aDirection) {
   2216  mMonitor->AssertCurrentThreadOwns();
   2217 
   2218  if (profiler_feature_active(ProfilerFeature::Flows) &&
   2219      // If one of the profiler mutexes is locked on this thread, don't
   2220      // record markers, because we don't want to expose profiler IPCs due to
   2221      // the profiler itself, and also to avoid possible re-entrancy issues.
   2222      !profiler_is_locked_on_current_thread()) {
   2223    if (aDirection == MessageDirection::eSending) {
   2224      auto flow = Flow::Global(aMessage.seqno() ^
   2225                               LossyNarrowChannelId(mMessageChannelId));
   2226      profiler_add_marker("IPC", baseprofiler::category::OTHER,
   2227                          MarkerTiming::InstantNow(), IPCFlowMarker{},
   2228                          aMessage.type(), flow);
   2229    }
   2230  }
   2231 
   2232  if (profiler_feature_active(ProfilerFeature::IPCMessages)) {
   2233    base::ProcessId pid = mListener->OtherPidMaybeInvalid();
   2234    // Only record markers for IPCs with a valid pid.
   2235    // And if one of the profiler mutexes is locked on this thread, don't record
   2236    // markers, because we don't want to expose profiler IPCs due to the
   2237    // profiler itself, and also to avoid possible re-entrancy issues.
   2238    if (pid != base::kInvalidProcessId &&
   2239        !profiler_is_locked_on_current_thread()) {
   2240      // The current timestamp must be given to the `IPCMarker` payload.
   2241      const TimeStamp now = TimeStamp::Now();
   2242      bool isThreadBeingProfiled =
   2243          profiler_thread_is_being_profiled_for_markers();
   2244      PROFILER_MARKER(
   2245          "IPC", IPC,
   2246          mozilla::MarkerOptions(
   2247              mozilla::MarkerTiming::InstantAt(now),
   2248              // If the thread is being profiled, add the marker to
   2249              // the current thread. If the thread is not being
   2250              // profiled, add the marker to the main thread. It
   2251              // will appear in the main thread's IPC track. Profiler analysis
   2252              // UI correlates all the IPC markers from different threads and
   2253              // generates processed markers.
   2254              isThreadBeingProfiled ? mozilla::MarkerThreadId::CurrentThread()
   2255                                    : mozilla::MarkerThreadId::MainThread()),
   2256          IPCMarker, now, now, pid, aMessage.seqno(), aMessage.type(), mSide,
   2257          aDirection, MessagePhase::Endpoint, aMessage.is_sync(),
   2258          // aOriginThreadId: If the thread is being profiled, do not include a
   2259          // thread ID, as it's the same as the markers. Only include this field
   2260          // when the marker is being sent from another thread.
   2261          isThreadBeingProfiled ? mozilla::MarkerThreadId{}
   2262                                : mozilla::MarkerThreadId::CurrentThread());
   2263    }
   2264  }
   2265 }
   2266 
   2267 void MessageChannel::EndTimeout() {
   2268  mMonitor->AssertCurrentThreadOwns();
   2269 
   2270  IPC_LOG("Ending timeout of seqno=%" PRId64, mTimedOutMessageSeqno);
   2271  mTimedOutMessageSeqno = 0;
   2272  mTimedOutMessageNestedLevel = 0;
   2273 
   2274  RepostAllMessages();
   2275 }
   2276 
   2277 void MessageChannel::RepostAllMessages() {
   2278  mMonitor->AssertCurrentThreadOwns();
   2279 
   2280  bool needRepost = false;
   2281  for (MessageTask* task : mPending) {
   2282    task->AssertMonitorHeld(*mMonitor);
   2283    if (!task->IsScheduled()) {
   2284      needRepost = true;
   2285      break;
   2286    }
   2287  }
   2288  if (!needRepost) {
   2289    // If everything is already scheduled to run, do nothing.
   2290    return;
   2291  }
   2292 
   2293  // In some cases we may have deferred dispatch of some messages in the
   2294  // queue. Now we want to run them again. However, we can't just re-post
   2295  // those messages since the messages after them in mPending would then be
   2296  // before them in the event queue. So instead we cancel everything and
   2297  // re-post all messages in the correct order.
   2298  MessageQueue queue = std::move(mPending);
   2299  while (RefPtr<MessageTask> task = queue.popFirst()) {
   2300    task->AssertMonitorHeld(*mMonitor);
   2301    RefPtr<MessageTask> newTask = new MessageTask(this, std::move(task->Msg()));
   2302    newTask->AssertMonitorHeld(*mMonitor);
   2303    mPending.insertBack(newTask);
   2304    newTask->Post();
   2305  }
   2306 
   2307  AssertMaybeDeferredCountCorrect();
   2308 }
   2309 
   2310 void MessageChannel::CancelTransaction(seqno_t transaction) {
   2311  mMonitor->AssertCurrentThreadOwns();
   2312 
   2313  // When we cancel a transaction, we need to behave as if there's no longer
   2314  // any IPC on the stack. Anything we were dispatching or sending will get
   2315  // canceled. Consequently, we have to update the state variables below.
   2316  //
   2317  // We also need to ensure that when any IPC functions on the stack return,
   2318  // they don't reset these values using an RAII class like AutoSetValue. To
   2319  // avoid that, these RAII classes check if the variable they set has been
   2320  // tampered with (by us). If so, they don't reset the variable to the old
   2321  // value.
   2322 
   2323  IPC_LOG("CancelTransaction: xid=%" PRId64, transaction);
   2324 
   2325  // An unusual case: We timed out a transaction which the other side then
   2326  // cancelled. In this case we just leave the timedout state and try to
   2327  // forget this ever happened.
   2328  if (transaction == mTimedOutMessageSeqno) {
   2329    IPC_LOG("Cancelled timed out message %" PRId64, mTimedOutMessageSeqno);
   2330    EndTimeout();
   2331 
   2332    // Normally mCurrentTransaction == 0 here. But it can be non-zero if:
   2333    // 1. Parent sends NESTED_INSIDE_SYNC message H.
   2334    // 2. Parent times out H.
   2335    // 3. Child dispatches H and sends nested message H' (same transaction).
   2336    // 4. Parent dispatches H' and cancels.
   2337    MOZ_RELEASE_ASSERT(!mTransactionStack ||
   2338                       mTransactionStack->TransactionID() == transaction);
   2339    if (mTransactionStack) {
   2340      mTransactionStack->Cancel();
   2341    }
   2342  } else {
   2343    MOZ_RELEASE_ASSERT(mTransactionStack->TransactionID() == transaction);
   2344    mTransactionStack->Cancel();
   2345  }
   2346 
   2347  bool foundSync = false;
   2348  for (MessageTask* p = mPending.getFirst(); p;) {
   2349    p->AssertMonitorHeld(*mMonitor);
   2350    UniquePtr<Message>& msg = p->Msg();
   2351 
   2352    // If there was a race between the parent and the child, then we may
   2353    // have a queued sync message. We want to drop this message from the
   2354    // queue since if will get cancelled along with the transaction being
   2355    // cancelled. This happens if the message in the queue is
   2356    // NESTED_INSIDE_SYNC.
   2357    if (msg->is_sync() && msg->nested_level() != IPC::Message::NOT_NESTED) {
   2358      MOZ_RELEASE_ASSERT(!foundSync);
   2359      MOZ_RELEASE_ASSERT(msg->transaction_id() != transaction);
   2360      IPC_LOG("Removing msg from queue seqno=%" PRId64 " xid=%" PRId64,
   2361              msg->seqno(), msg->transaction_id());
   2362      foundSync = true;
   2363      if (!IsAlwaysDeferred(*msg)) {
   2364        mMaybeDeferredPendingCount--;
   2365      }
   2366      p = p->removeAndGetNext();
   2367      continue;
   2368    }
   2369 
   2370    p = p->getNext();
   2371  }
   2372 
   2373  AssertMaybeDeferredCountCorrect();
   2374 }
   2375 
   2376 void MessageChannel::CancelCurrentTransaction() {
   2377  MonitorAutoLock lock(*mMonitor);
   2378  if (DispatchingSyncMessageNestedLevel() >= IPC::Message::NESTED_INSIDE_SYNC) {
   2379    if (DispatchingSyncMessageNestedLevel() ==
   2380            IPC::Message::NESTED_INSIDE_CPOW ||
   2381        DispatchingAsyncMessageNestedLevel() ==
   2382            IPC::Message::NESTED_INSIDE_CPOW) {
   2383      mListener->IntentionalCrash();
   2384    }
   2385 
   2386    IPC_LOG("Cancel requested: current xid=%" PRId64,
   2387            CurrentNestedInsideSyncTransaction());
   2388    MOZ_RELEASE_ASSERT(DispatchingSyncMessage());
   2389    auto cancel =
   2390        MakeUnique<CancelMessage>(CurrentNestedInsideSyncTransaction());
   2391    CancelTransaction(CurrentNestedInsideSyncTransaction());
   2392    SendMessageToLink(std::move(cancel));
   2393  }
   2394 }
   2395 
   2396 void CancelCPOWs() {
   2397  MOZ_ASSERT(NS_IsMainThread());
   2398 
   2399  if (gParentProcessBlocker) {
   2400    mozilla::glean::ipc::transaction_cancel
   2401        .EnumGet(mozilla::glean::ipc::TransactionCancelLabel::eTrue)
   2402        .Add();
   2403    gParentProcessBlocker->CancelCurrentTransaction();
   2404  }
   2405 }
   2406 
   2407 bool MessageChannel::IsCrossProcess() const {
   2408  mMonitor->AssertCurrentThreadOwns();
   2409  return mIsCrossProcess;
   2410 }
   2411 
   2412 void MessageChannel::SetIsCrossProcess(bool aIsCrossProcess) {
   2413  mMonitor->AssertCurrentThreadOwns();
   2414  if (aIsCrossProcess == mIsCrossProcess) {
   2415    return;
   2416  }
   2417  mIsCrossProcess = aIsCrossProcess;
   2418  if (mIsCrossProcess) {
   2419    ChannelCountReporter::Increment(mName);
   2420  } else {
   2421    ChannelCountReporter::Decrement(mName);
   2422  }
   2423 }
   2424 
   2425 NS_IMPL_ISUPPORTS(MessageChannel::WorkerTargetShutdownTask,
   2426                  nsITargetShutdownTask)
   2427 
   2428 MessageChannel::WorkerTargetShutdownTask::WorkerTargetShutdownTask(
   2429    nsISerialEventTarget* aTarget, MessageChannel* aChannel)
   2430    : mTarget(aTarget), mChannel(aChannel) {}
   2431 
   2432 void MessageChannel::WorkerTargetShutdownTask::TargetShutdown() {
   2433  MOZ_RELEASE_ASSERT(mTarget->IsOnCurrentThread());
   2434  IPC_LOG("Closing channel due to event target shutdown");
   2435  if (MessageChannel* channel = std::exchange(mChannel, nullptr)) {
   2436    channel->Close();
   2437  }
   2438 }
   2439 
   2440 void MessageChannel::WorkerTargetShutdownTask::Clear() {
   2441  MOZ_RELEASE_ASSERT(mTarget->IsOnCurrentThread());
   2442  mChannel = nullptr;
   2443 }
   2444 
   2445 NS_IMPL_ISUPPORTS_INHERITED0(MessageChannel::FlushLazySendMessagesRunnable,
   2446                             CancelableRunnable)
   2447 
   2448 MessageChannel::FlushLazySendMessagesRunnable::FlushLazySendMessagesRunnable(
   2449    MessageChannel* aChannel)
   2450    : CancelableRunnable("MessageChannel::FlushLazyMessagesRunnable"),
   2451      mChannel(aChannel) {}
   2452 
   2453 NS_IMETHODIMP MessageChannel::FlushLazySendMessagesRunnable::Run() {
   2454  if (mChannel) {
   2455    MonitorAutoLock lock(*mChannel->mMonitor);
   2456    MOZ_ASSERT(mChannel->mFlushLazySendTask == this);
   2457    mChannel->FlushLazySendMessages();
   2458  }
   2459  return NS_OK;
   2460 }
   2461 
   2462 nsresult MessageChannel::FlushLazySendMessagesRunnable::Cancel() {
   2463  mQueue.Clear();
   2464  mChannel = nullptr;
   2465  return NS_OK;
   2466 }
   2467 
   2468 void MessageChannel::FlushLazySendMessagesRunnable::PushMessage(
   2469    UniquePtr<Message> aMsg) {
   2470  MOZ_ASSERT(mChannel);
   2471  mQueue.AppendElement(std::move(aMsg));
   2472 }
   2473 
   2474 nsTArray<UniquePtr<IPC::Message>>
   2475 MessageChannel::FlushLazySendMessagesRunnable::TakeMessages() {
   2476  mChannel = nullptr;
   2477  return std::move(mQueue);
   2478 }
   2479 
   2480 }  // namespace ipc
   2481 }  // namespace mozilla