tor-browser

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

MessageChannel.h (28851B)


      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 #ifndef ipc_glue_MessageChannel_h
      9 #define ipc_glue_MessageChannel_h
     10 
     11 #include "ipc/EnumSerializer.h"
     12 #include "mozilla/BaseProfilerMarkers.h"
     13 #include "mozilla/LinkedList.h"
     14 #include "mozilla/Monitor.h"
     15 #include "mozilla/MoveOnlyFunction.h"
     16 #if defined(XP_WIN)
     17 #  include "mozilla/ipc/Neutering.h"
     18 #endif  // defined(XP_WIN)
     19 
     20 #include <functional>
     21 #include <stack>
     22 
     23 #include "MessageLink.h"  // for HasResultCodes
     24 #include "mozilla/ipc/ScopedPort.h"
     25 #include "nsITargetShutdownTask.h"
     26 
     27 #ifdef FUZZING_SNAPSHOT
     28 #  include "mozilla/fuzzing/IPCFuzzController.h"
     29 #endif
     30 
     31 class MessageLoop;
     32 
     33 namespace IPC {
     34 template <typename T>
     35 struct ParamTraits;
     36 }
     37 
     38 namespace mozilla {
     39 namespace ipc {
     40 
     41 class IToplevelProtocol;
     42 class ActorLifecycleProxy;
     43 
     44 class RefCountedMonitor : public Monitor {
     45 public:
     46  RefCountedMonitor() : Monitor("mozilla.ipc.MessageChannel.mMonitor") {}
     47 
     48  void AssertSameMonitor(const RefCountedMonitor& aOther) const
     49      MOZ_REQUIRES(*this) MOZ_ASSERT_CAPABILITY(aOther) {
     50    MOZ_ASSERT(this == &aOther);
     51  }
     52 
     53  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMonitor)
     54 
     55 private:
     56  ~RefCountedMonitor() = default;
     57 };
     58 
     59 enum class MessageDirection {
     60  eSending,
     61  eReceiving,
     62 };
     63 
     64 enum class MessagePhase {
     65  Endpoint,
     66  TransferStart,
     67  TransferEnd,
     68 };
     69 
     70 enum class SyncSendError {
     71  SendSuccess,
     72  PreviousTimeout,
     73  SendingCPOWWhileDispatchingSync,
     74  SendingCPOWWhileDispatchingUrgent,
     75  NotConnectedBeforeSend,
     76  DisconnectedDuringSend,
     77  CancelledBeforeSend,
     78  CancelledAfterSend,
     79  TimedOut,
     80  ReplyError,
     81 };
     82 
     83 enum class ResponseRejectReason {
     84  SendError,
     85  ChannelClosed,
     86  HandlerRejected,
     87  ActorDestroyed,
     88  ResolverDestroyed,
     89  EndGuard_,
     90 };
     91 
     92 template <typename T>
     93 using ResolveCallback = MoveOnlyFunction<void(T&&)>;
     94 
     95 using RejectCallback = MoveOnlyFunction<void(ResponseRejectReason)>;
     96 
     97 enum ChannelState {
     98  ChannelClosed,
     99  ChannelConnected,
    100  ChannelClosing,
    101  ChannelError
    102 };
    103 
    104 class AutoEnterTransaction;
    105 
    106 class MessageChannel : HasResultCodes {
    107  friend class PortLink;
    108 
    109  typedef mozilla::Monitor Monitor;
    110 
    111 public:
    112  using Message = IPC::Message;
    113  using seqno_t = Message::seqno_t;
    114 
    115  static constexpr int32_t kNoTimeout = INT32_MIN;
    116 
    117  using ScopedPort = mozilla::ipc::ScopedPort;
    118 
    119  explicit MessageChannel(const char* aName, IToplevelProtocol* aListener);
    120  ~MessageChannel();
    121 
    122  IToplevelProtocol* Listener() const { return mListener; }
    123 
    124  // Returns the event target which the worker lives on and must be used for
    125  // operations on the current thread. Only safe to access after the
    126  // MessageChannel has been opened.
    127  nsISerialEventTarget* GetWorkerEventTarget() const { return mWorkerThread; }
    128 
    129  // "Open" a connection using an existing ScopedPort. The ScopedPort must be
    130  // valid and connected to a remote.
    131  //
    132  // The `aEventTarget` parameter must be on the current thread.
    133  bool Open(ScopedPort aPort, Side aSide, const nsID& aMessageChannelId,
    134            nsISerialEventTarget* aEventTarget = nullptr);
    135 
    136  // "Open" a connection to another thread in the same process.
    137  //
    138  // Returns true if the transport layer was successfully connected,
    139  // i.e., mChannelState == ChannelConnected.
    140  //
    141  // For more details on the process of opening a channel between
    142  // threads, see the extended comment on this function
    143  // in MessageChannel.cpp.
    144  bool Open(MessageChannel* aTargetChan, nsISerialEventTarget* aEventTarget,
    145            Side aSide);
    146 
    147  // "Open" a connection to an actor on the current thread.
    148  //
    149  // Returns true if the transport layer was successfully connected,
    150  // i.e., mChannelState == ChannelConnected.
    151  //
    152  // Same-thread channels may not perform synchronous or blocking message
    153  // sends, to avoid deadlocks.
    154  bool OpenOnSameThread(MessageChannel* aTargetChan, Side aSide);
    155 
    156  /**
    157   * This sends a special message that is processed on the IO thread, so that
    158   * other actors can know that the process will soon shutdown.
    159   */
    160  void NotifyImpendingShutdown() MOZ_EXCLUDES(*mMonitor);
    161 
    162  // Close the underlying transport channel.
    163  void Close() MOZ_EXCLUDES(*mMonitor);
    164 
    165  // Induce an error in this MessageChannel's connection.
    166  //
    167  // After this method is called, no more message notifications will be
    168  // delivered to the listener, and the channel will be unable to send or
    169  // receive future messages, as if the peer dropped the connection
    170  // unexpectedly.
    171  //
    172  // The OnChannelError notification will be delivered either asynchronously or
    173  // during an explicit call to Close(), whichever happens first.
    174  //
    175  // NOTE: If SetAbortOnError(true) has been called on this MessageChannel,
    176  // calling this function will immediately exit the current process.
    177  void InduceConnectionError() MOZ_EXCLUDES(*mMonitor);
    178 
    179  void SetAbortOnError(bool abort) MOZ_EXCLUDES(*mMonitor) {
    180    MonitorAutoLock lock(*mMonitor);
    181    mAbortOnError = abort;
    182  }
    183 
    184  // Call aInvoke for each pending message until it returns false.
    185  // XXX: You must get permission from an IPC peer to use this function
    186  //      since it requires custom deserialization and re-orders events.
    187  void PeekMessages(const std::function<bool(const Message& aMsg)>& aInvoke)
    188      MOZ_EXCLUDES(*mMonitor);
    189 
    190  // Misc. behavioral traits consumers can request for this channel
    191  enum ChannelFlags {
    192    REQUIRE_DEFAULT = 0,
    193    // Windows: if this channel operates on the UI thread, indicates
    194    // WindowsMessageLoop code should enable deferred native message
    195    // handling to prevent deadlocks. Should only be used for protocols
    196    // that manage child processes which might create native UI, like
    197    // plugins.
    198    REQUIRE_DEFERRED_MESSAGE_PROTECTION = 1 << 0,
    199  };
    200  void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; }
    201  ChannelFlags GetChannelFlags() { return mFlags; }
    202 
    203  // Asynchronously send a message to the other side of the channel.
    204  // If aSeqno is non-null, it will be set to the seqno of the sent message.
    205  bool Send(UniquePtr<Message> aMsg, seqno_t* aSeqno = nullptr)
    206      MOZ_EXCLUDES(*mMonitor);
    207 
    208  bool SendBuildIDsMatchMessage(const char* aParentBuildID)
    209      MOZ_EXCLUDES(*mMonitor);
    210  bool DoBuildIDsMatch() MOZ_EXCLUDES(*mMonitor) {
    211    MonitorAutoLock lock(*mMonitor);
    212    return mBuildIDsConfirmedMatch;
    213  }
    214 
    215  // Synchronously send |aMsg| (i.e., wait for |aReply|)
    216  bool Send(UniquePtr<Message> aMsg, UniquePtr<Message>* aReply)
    217      MOZ_EXCLUDES(*mMonitor);
    218 
    219  bool CanSend() const MOZ_EXCLUDES(*mMonitor);
    220 
    221  // If sending a sync message returns an error, this function gives a more
    222  // descriptive error message.
    223  SyncSendError LastSendError() const {
    224    AssertWorkerThread();
    225    return mLastSendError;
    226  }
    227 
    228  void SetReplyTimeoutMs(int32_t aTimeoutMs);
    229 
    230  bool IsOnCxxStack() const { return mOnCxxStack; }
    231 
    232  void CancelCurrentTransaction() MOZ_EXCLUDES(*mMonitor);
    233 
    234  // Return whether the current transaction is complete.
    235  //
    236  // This is intended only for tests.
    237  bool TestOnlyIsTransactionComplete() const MOZ_EXCLUDES(*mMonitor);
    238 
    239  // IsClosed and NumQueuedMessages are safe to call from any thread, but
    240  // may provide an out-of-date value.
    241  bool IsClosed() MOZ_EXCLUDES(*mMonitor) {
    242    MonitorAutoLock lock(*mMonitor);
    243    return IsClosedLocked();
    244  }
    245  bool IsClosedLocked() const MOZ_REQUIRES(*mMonitor) {
    246    mMonitor->AssertCurrentThreadOwns();
    247    return mLink ? mLink->IsClosed() : true;
    248  }
    249 
    250  static bool IsPumpingMessages() { return sIsPumpingMessages; }
    251  static void SetIsPumpingMessages(bool aIsPumping) {
    252    sIsPumpingMessages = aIsPumping;
    253  }
    254 
    255  /**
    256   * Does this MessageChannel currently cross process boundaries?
    257   */
    258  bool IsCrossProcess() const MOZ_REQUIRES(*mMonitor);
    259  void SetIsCrossProcess(bool aIsCrossProcess) MOZ_REQUIRES(*mMonitor);
    260 
    261  nsID GetMessageChannelId() const {
    262    MonitorAutoLock lock(*mMonitor);
    263    return mMessageChannelId;
    264  }
    265 
    266 #ifdef FUZZING_SNAPSHOT
    267  Maybe<mojo::core::ports::PortName> GetPortName() {
    268    MonitorAutoLock lock(*mMonitor);
    269    return mLink ? mLink->GetPortName() : Nothing();
    270  }
    271 #endif
    272 
    273 #ifdef XP_WIN
    274  struct MOZ_STACK_CLASS SyncStackFrame {
    275    explicit SyncStackFrame(MessageChannel* channel);
    276    ~SyncStackFrame();
    277 
    278    bool mSpinNestedEvents;
    279    bool mListenerNotified;
    280    MessageChannel* mChannel;
    281 
    282    // The previous stack frame for this channel.
    283    SyncStackFrame* mPrev;
    284 
    285    // The previous stack frame on any channel.
    286    SyncStackFrame* mStaticPrev;
    287  };
    288  friend struct MessageChannel::SyncStackFrame;
    289 
    290  static bool IsSpinLoopActive() {
    291    for (SyncStackFrame* frame = sStaticTopFrame; frame; frame = frame->mPrev) {
    292      if (frame->mSpinNestedEvents) return true;
    293    }
    294    return false;
    295  }
    296 
    297 protected:
    298  // The deepest sync stack frame for this channel.
    299  SyncStackFrame* mTopFrame = nullptr;
    300 
    301  bool mIsSyncWaitingOnNonMainThread = false;
    302 
    303  // The deepest sync stack frame on any channel.
    304  static SyncStackFrame* sStaticTopFrame;
    305 
    306 public:
    307  void ProcessNativeEventsInInterruptCall();
    308  static void NotifyGeckoEventDispatch();
    309 #endif  // defined(XP_WIN)
    310 
    311 private:
    312  void PostErrorNotifyTask() MOZ_REQUIRES(*mMonitor);
    313  void OnNotifyMaybeChannelError() MOZ_EXCLUDES(*mMonitor);
    314  void ReportConnectionError(const char* aFunctionName,
    315                             const uint32_t aMsgTyp) const
    316      MOZ_REQUIRES(*mMonitor);
    317  bool MaybeHandleError(Result code, const Message& aMsg,
    318                        const char* channelName) MOZ_EXCLUDES(*mMonitor);
    319 
    320  void Clear() MOZ_REQUIRES(*mMonitor);
    321 
    322  bool HasPendingEvents() MOZ_REQUIRES(*mMonitor);
    323 
    324  void ProcessPendingRequests(ActorLifecycleProxy* aProxy,
    325                              AutoEnterTransaction& aTransaction)
    326      MOZ_REQUIRES(*mMonitor);
    327  bool ProcessPendingRequest(ActorLifecycleProxy* aProxy,
    328                             UniquePtr<Message> aUrgent)
    329      MOZ_REQUIRES(*mMonitor);
    330 
    331  void EnqueuePendingMessages() MOZ_REQUIRES(*mMonitor);
    332 
    333  // Dispatches an incoming message to its appropriate handler.
    334  void DispatchMessage(ActorLifecycleProxy* aProxy, UniquePtr<Message> aMsg)
    335      MOZ_REQUIRES(*mMonitor);
    336 
    337  // DispatchMessage will route to one of these functions depending on the
    338  // protocol type of the message.
    339  void DispatchSyncMessage(ActorLifecycleProxy* aProxy, const Message& aMsg,
    340                           UniquePtr<Message>& aReply) MOZ_EXCLUDES(*mMonitor);
    341  void DispatchAsyncMessage(ActorLifecycleProxy* aProxy, const Message& aMsg)
    342      MOZ_EXCLUDES(*mMonitor);
    343 
    344  // Return true if the wait ended because a notification was received.
    345  //
    346  // Return false if the time elapsed from when we started the process of
    347  // waiting until afterwards exceeded the currently allotted timeout.
    348  // That *DOES NOT* mean false => "no event" (== timeout); there are many
    349  // circumstances that could cause the measured elapsed time to exceed the
    350  // timeout EVEN WHEN we were notified.
    351  //
    352  // So in sum: true is a meaningful return value; false isn't,
    353  // necessarily.
    354  bool WaitForSyncNotify() MOZ_REQUIRES(*mMonitor);
    355 
    356  bool WaitResponse(bool aWaitTimedOut);
    357 
    358  bool ShouldContinueFromTimeout() MOZ_REQUIRES(*mMonitor);
    359 
    360  void EndTimeout() MOZ_REQUIRES(*mMonitor);
    361  void CancelTransaction(seqno_t transaction) MOZ_REQUIRES(*mMonitor);
    362 
    363  void RepostAllMessages() MOZ_REQUIRES(*mMonitor);
    364 
    365  seqno_t NextSeqno() {
    366    AssertWorkerThread();
    367    MOZ_RELEASE_ASSERT(mozilla::Abs(mNextSeqno) < INT64_MAX, "seqno overflow");
    368    return (mSide == ChildSide) ? --mNextSeqno : ++mNextSeqno;
    369  }
    370 
    371  void DebugAbort(const char* file, int line, const char* cond, const char* why,
    372                  bool reply = false) MOZ_REQUIRES(*mMonitor);
    373 
    374  void AddProfilerMarker(const IPC::Message& aMessage,
    375                         MessageDirection aDirection) MOZ_REQUIRES(*mMonitor);
    376 
    377 private:
    378  // Returns true if we're dispatching an async message's callback.
    379  bool DispatchingAsyncMessage() const {
    380    AssertWorkerThread();
    381    return mDispatchingAsyncMessage;
    382  }
    383 
    384  int DispatchingAsyncMessageNestedLevel() const {
    385    AssertWorkerThread();
    386    return mDispatchingAsyncMessageNestedLevel;
    387  }
    388 
    389  // Check if there is still a live connection to our peer. This may change to
    390  // `false` at any time due to the connection to our peer being closed or
    391  // dropped (e.g. due to a crash).
    392  bool Connected() const MOZ_REQUIRES(*mMonitor);
    393 
    394  // Check if there is either still a live connection to our peer, or we have
    395  // received a `Goodbye` from our peer, and are actively shutting down our
    396  // connection with our peer.
    397  bool ConnectedOrClosing() const MOZ_REQUIRES(*mMonitor);
    398 
    399 private:
    400  // Executed on the IO thread.
    401  void NotifyWorkerThread() MOZ_REQUIRES(*mMonitor);
    402 
    403  // Return true if |aMsg| is a special message targeted at the IO
    404  // thread, in which case it shouldn't be delivered to the worker.
    405  bool MaybeInterceptSpecialIOMessage(const Message& aMsg)
    406      MOZ_REQUIRES(*mMonitor);
    407 
    408  // Returns true if ShouldDeferMessage(aMsg) is guaranteed to return true.
    409  // Otherwise, the result of ShouldDeferMessage(aMsg) may be true or false,
    410  // depending on context.
    411  static bool IsAlwaysDeferred(const Message& aMsg);
    412 
    413  // Helper for sending a message via the link. If the message is [LazySend], it
    414  // will be queued, and if the message is not-[LazySend], it will flush any
    415  // pending [LazySend] messages.
    416  void SendMessageToLink(UniquePtr<Message> aMsg) MOZ_REQUIRES(*mMonitor);
    417 
    418  // Called to flush [LazySend] messages to the link.
    419  void FlushLazySendMessages() MOZ_REQUIRES(*mMonitor);
    420 
    421  bool ShouldDeferMessage(const Message& aMsg) MOZ_REQUIRES(*mMonitor);
    422  void OnMessageReceivedFromLink(UniquePtr<Message> aMsg)
    423      MOZ_REQUIRES(*mMonitor);
    424  void OnChannelErrorFromLink() MOZ_REQUIRES(*mMonitor);
    425 
    426 private:
    427  // Clear this channel, and notify the listener that the channel has either
    428  // closed or errored.
    429  //
    430  // These methods must be called on the worker thread, passing in a
    431  // `ReleasableMonitorAutoLock`. This lock guard will be reset before the
    432  // listener is called, allowing for the monitor to be unlocked before the
    433  // MessageChannel is potentially destroyed.
    434  void NotifyChannelClosed(ReleasableMonitorAutoLock& aLock)
    435      MOZ_REQUIRES(*mMonitor);
    436  void NotifyMaybeChannelError(ReleasableMonitorAutoLock& aLock)
    437      MOZ_REQUIRES(*mMonitor);
    438 
    439 private:
    440  void AssertWorkerThread() const {
    441    MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet");
    442    MOZ_RELEASE_ASSERT(mWorkerThread && mWorkerThread->IsOnCurrentThread(),
    443                       "not on worker thread!");
    444  }
    445 
    446 private:
    447  class MessageTask : public CancelableRunnable,
    448                      public LinkedListElement<RefPtr<MessageTask>>,
    449                      public nsIRunnablePriority,
    450                      public nsIRunnableIPCMessageType {
    451   public:
    452    explicit MessageTask(MessageChannel* aChannel, UniquePtr<Message> aMessage);
    453    MessageTask() = delete;
    454    MessageTask(const MessageTask&) = delete;
    455 
    456    NS_DECL_ISUPPORTS_INHERITED
    457 
    458    NS_IMETHOD Run() override;
    459    nsresult Cancel() override;
    460    NS_IMETHOD GetPriority(uint32_t* aPriority) override;
    461    NS_DECL_NSIRUNNABLEIPCMESSAGETYPE
    462    void Post() MOZ_REQUIRES(*mMonitor);
    463 
    464    bool IsScheduled() const MOZ_REQUIRES(*mMonitor) {
    465      mMonitor->AssertCurrentThreadOwns();
    466      return mScheduled;
    467    }
    468 
    469    UniquePtr<Message>& Msg() MOZ_REQUIRES(*mMonitor) {
    470      MOZ_DIAGNOSTIC_ASSERT(mMessage, "message was moved");
    471      return mMessage;
    472    }
    473    const UniquePtr<Message>& Msg() const MOZ_REQUIRES(*mMonitor) {
    474      MOZ_DIAGNOSTIC_ASSERT(mMessage, "message was moved");
    475      return mMessage;
    476    }
    477 
    478    void AssertMonitorHeld(const RefCountedMonitor& aMonitor)
    479        MOZ_REQUIRES(aMonitor) MOZ_ASSERT_CAPABILITY(*mMonitor) {
    480      aMonitor.AssertSameMonitor(*mMonitor);
    481    }
    482 
    483   private:
    484    ~MessageTask();
    485 
    486    MessageChannel* Channel() MOZ_REQUIRES(*mMonitor) {
    487      mMonitor->AssertCurrentThreadOwns();
    488      MOZ_RELEASE_ASSERT(isInList());
    489      return mChannel;
    490    }
    491 
    492    // The connected MessageChannel's monitor. Guards `mChannel` and
    493    // `mScheduled`.
    494    RefPtr<RefCountedMonitor> const mMonitor;
    495    // The channel which this MessageTask is associated with. Only valid while
    496    // `mMonitor` is held, and this MessageTask `isInList()`.
    497    MessageChannel* const mChannel;
    498    UniquePtr<Message> mMessage MOZ_GUARDED_BY(*mMonitor);
    499    uint32_t const mPriority;
    500    bool mScheduled : 1 MOZ_GUARDED_BY(*mMonitor);
    501 #ifdef FUZZING_SNAPSHOT
    502    const bool mIsFuzzMsg;
    503    bool mFuzzStopped MOZ_GUARDED_BY(*mMonitor);
    504 #endif
    505  };
    506 
    507  bool ShouldRunMessage(const Message& aMsg) MOZ_REQUIRES(*mMonitor);
    508  void RunMessage(ActorLifecycleProxy* aProxy, MessageTask& aTask)
    509      MOZ_REQUIRES(*mMonitor);
    510 
    511  class WorkerTargetShutdownTask final : public nsITargetShutdownTask {
    512   public:
    513    NS_DECL_THREADSAFE_ISUPPORTS
    514 
    515    WorkerTargetShutdownTask(nsISerialEventTarget* aTarget,
    516                             MessageChannel* aChannel);
    517 
    518    void TargetShutdown() override;
    519    void Clear();
    520 
    521   private:
    522    ~WorkerTargetShutdownTask() = default;
    523 
    524    const nsCOMPtr<nsISerialEventTarget> mTarget;
    525    // Cleared by MessageChannel before it is destroyed.
    526    MessageChannel* MOZ_NON_OWNING_REF mChannel;
    527  };
    528 
    529  class FlushLazySendMessagesRunnable final : public CancelableRunnable {
    530   public:
    531    explicit FlushLazySendMessagesRunnable(MessageChannel* aChannel);
    532 
    533    NS_DECL_ISUPPORTS_INHERITED
    534 
    535    NS_IMETHOD Run() override;
    536    nsresult Cancel() override;
    537 
    538    void PushMessage(UniquePtr<Message> aMsg);
    539    nsTArray<UniquePtr<Message>> TakeMessages();
    540 
    541   private:
    542    ~FlushLazySendMessagesRunnable() = default;
    543 
    544    // Cleared by MessageChannel before it is destroyed.
    545    MessageChannel* MOZ_NON_OWNING_REF mChannel;
    546 
    547    // LazySend messages which haven't been sent yet, but will be sent as soon
    548    // as a non-LazySend message is sent, or this runnable is executed.
    549    nsTArray<UniquePtr<Message>> mQueue;
    550  };
    551 
    552  typedef LinkedList<RefPtr<MessageTask>> MessageQueue;
    553  typedef IPC::Message::msgid_t msgid_t;
    554 
    555 private:
    556  // This will be a string literal, so lifetime is not an issue.
    557  const char* const mName;
    558 
    559  // ID for each MessageChannel. Set when it is opened, and never cleared
    560  // afterwards.
    561  //
    562  // This ID is only intended for diagnostics, debugging, and reporting
    563  // purposes, and shouldn't be used for message routing or permissions checks.
    564  nsID mMessageChannelId MOZ_GUARDED_BY(*mMonitor) = {};
    565 
    566  // Based on presumption the listener owns and overlives the channel,
    567  // this is never nullified.
    568  IToplevelProtocol* const mListener;
    569 
    570  // This monitor guards all state in this MessageChannel, except where
    571  // otherwise noted. It is refcounted so a reference to it can be shared with
    572  // IPC listener objects which need to access weak references to this
    573  // `MessageChannel`.
    574  RefPtr<RefCountedMonitor> const mMonitor;
    575 
    576  ChannelState mChannelState MOZ_GUARDED_BY(*mMonitor) = ChannelClosed;
    577  Side mSide = UnknownSide;
    578  bool mIsCrossProcess MOZ_GUARDED_BY(*mMonitor) = false;
    579  UniquePtr<MessageLink> mLink MOZ_GUARDED_BY(*mMonitor);
    580 
    581  // NotifyMaybeChannelError runnable
    582  RefPtr<CancelableRunnable> mChannelErrorTask MOZ_GUARDED_BY(*mMonitor);
    583 
    584  // Thread we are allowed to send and receive on.  Set in Open(); never
    585  // changed, and we can only call Open() once.  We shouldn't be accessing
    586  // from multiple threads before Open().
    587  nsCOMPtr<nsISerialEventTarget> mWorkerThread;
    588 
    589  // Shutdown task to close the channel before mWorkerThread goes away.
    590  RefPtr<WorkerTargetShutdownTask> mShutdownTask MOZ_GUARDED_BY(*mMonitor);
    591 
    592  // Task to force sending lazy messages when mQueuedLazyMessages is non-empty.
    593  RefPtr<FlushLazySendMessagesRunnable> mFlushLazySendTask
    594      MOZ_GUARDED_BY(*mMonitor);
    595 
    596  // Timeout periods are broken up in two to prevent system suspension from
    597  // triggering an abort. This method (called by WaitForEvent with a 'did
    598  // timeout' flag) decides if we should wait again for half of mTimeoutMs
    599  // or give up.
    600  // only accessed on WorkerThread
    601  int32_t mTimeoutMs = kNoTimeout;
    602  bool mInTimeoutSecondHalf = false;
    603 
    604  // Worker-thread only; sequence numbers for messages that require
    605  // replies.
    606  seqno_t mNextSeqno = 0;
    607 
    608  static bool sIsPumpingMessages;
    609 
    610  // If ::Send returns false, this gives a more descriptive error.
    611  SyncSendError mLastSendError = SyncSendError::SendSuccess;
    612 
    613  template <class T>
    614  class AutoSetValue {
    615   public:
    616    explicit AutoSetValue(T& var, const T& newValue)
    617        : mVar(var), mPrev(var), mNew(newValue) {
    618      mVar = newValue;
    619    }
    620    ~AutoSetValue() {
    621      // The value may have been zeroed if the transaction was
    622      // canceled. In that case we shouldn't return it to its previous
    623      // value.
    624      if (mVar == mNew) {
    625        mVar = mPrev;
    626      }
    627    }
    628 
    629   private:
    630    T& mVar;
    631    T mPrev;
    632    T mNew;
    633  };
    634 
    635  bool mDispatchingAsyncMessage = false;
    636  int mDispatchingAsyncMessageNestedLevel = 0;
    637 
    638  // When we send an urgent request from the parent process, we could race
    639  // with an RPC message that was issued by the child beforehand. In this
    640  // case, if the parent were to wake up while waiting for the urgent reply,
    641  // and process the RPC, it could send an additional urgent message. The
    642  // child would wake up to process the urgent message (as it always will),
    643  // then send a reply, which could be received by the parent out-of-order
    644  // with respect to the first urgent reply.
    645  //
    646  // To address this problem, urgent or RPC requests are associated with a
    647  // "transaction". Whenever one side of the channel wishes to start a
    648  // chain of RPC/urgent messages, it allocates a new transaction ID. Any
    649  // messages the parent receives, not apart of this transaction, are
    650  // deferred. When issuing RPC/urgent requests on top of a started
    651  // transaction, the initiating transaction ID is used.
    652  //
    653  // To ensure IDs are unique, we use sequence numbers for transaction IDs,
    654  // which grow in opposite directions from child to parent.
    655 
    656  friend class AutoEnterTransaction;
    657  AutoEnterTransaction* mTransactionStack MOZ_GUARDED_BY(*mMonitor) = nullptr;
    658 
    659  seqno_t CurrentNestedInsideSyncTransaction() const MOZ_REQUIRES(*mMonitor);
    660 
    661  bool AwaitingSyncReply() const MOZ_REQUIRES(*mMonitor);
    662  int AwaitingSyncReplyNestedLevel() const MOZ_REQUIRES(*mMonitor);
    663 
    664  bool DispatchingSyncMessage() const MOZ_REQUIRES(*mMonitor);
    665  int DispatchingSyncMessageNestedLevel() const MOZ_REQUIRES(*mMonitor);
    666 
    667 #ifdef DEBUG
    668  void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor);
    669 #else
    670  void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor) {}
    671 #endif
    672 
    673  // If a sync message times out, we store its sequence number here. Any
    674  // future sync messages will fail immediately. Once the reply for original
    675  // sync message is received, we allow sync messages again.
    676  //
    677  // When a message times out, nothing is done to inform the other side. The
    678  // other side will eventually dispatch the message and send a reply. Our
    679  // side is responsible for replying to all sync messages sent by the other
    680  // side when it dispatches the timed out message. The response is always an
    681  // error.
    682  //
    683  // A message is only timed out if it initiated a transaction. This avoids
    684  // hitting a lot of corner cases with message nesting that we don't really
    685  // care about.
    686  seqno_t mTimedOutMessageSeqno MOZ_GUARDED_BY(*mMonitor) = 0;
    687  int mTimedOutMessageNestedLevel MOZ_GUARDED_BY(*mMonitor) = 0;
    688 
    689  // Queue of all incoming messages.
    690  //
    691  // If both this side and the other side are functioning correctly, the other
    692  // side can send as many async messages as it wants before sending us a
    693  // blocking message.  After sending a blocking message, the other side must be
    694  // blocked, and thus can't send us any more messages until we process the sync
    695  // in-msg.
    696  //
    697  MessageQueue mPending MOZ_GUARDED_BY(*mMonitor);
    698 
    699  // The number of messages in mPending for which IsAlwaysDeferred is false
    700  // (i.e., the number of messages that might not be deferred, depending on
    701  // context).
    702  size_t mMaybeDeferredPendingCount MOZ_GUARDED_BY(*mMonitor) = 0;
    703 
    704  // Is there currently MessageChannel logic for this channel on the C++ stack?
    705  // This member is only accessed on the worker thread, and so is not protected
    706  // by mMonitor.
    707  bool mOnCxxStack = false;
    708 
    709 #ifdef XP_WIN
    710  HANDLE mEvent;
    711 #endif
    712 
    713  // Should the channel abort the process from the I/O thread when
    714  // a channel error occurs?
    715  bool mAbortOnError MOZ_GUARDED_BY(*mMonitor) = false;
    716 
    717  // True if the listener has already been notified of a channel close or
    718  // error.
    719  bool mNotifiedChannelDone MOZ_GUARDED_BY(*mMonitor) = false;
    720 
    721  // See SetChannelFlags
    722  ChannelFlags mFlags = REQUIRE_DEFAULT;
    723 
    724  bool mBuildIDsConfirmedMatch MOZ_GUARDED_BY(*mMonitor) = false;
    725 
    726  // If this is true, both ends of this message channel have event targets
    727  // on the same thread.
    728  bool mIsSameThreadChannel = false;
    729 };
    730 
    731 void CancelCPOWs();
    732 
    733 }  // namespace ipc
    734 }  // namespace mozilla
    735 
    736 namespace IPC {
    737 template <>
    738 struct ParamTraits<mozilla::ipc::ResponseRejectReason>
    739    : public ContiguousEnumSerializer<
    740          mozilla::ipc::ResponseRejectReason,
    741          mozilla::ipc::ResponseRejectReason::SendError,
    742          mozilla::ipc::ResponseRejectReason::EndGuard_> {};
    743 }  // namespace IPC
    744 
    745 namespace geckoprofiler::markers {
    746 
    747 struct IPCMarker {
    748  static constexpr mozilla::Span<const char> MarkerTypeName() {
    749    return mozilla::MakeStringSpan("IPC");
    750  }
    751  static void StreamJSONMarkerData(
    752      mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
    753      mozilla::TimeStamp aStart, mozilla::TimeStamp aEnd, int32_t aOtherPid,
    754      IPC::Message::seqno_t aMessageSeqno, IPC::Message::msgid_t aMessageType,
    755      mozilla::ipc::Side aSide, mozilla::ipc::MessageDirection aDirection,
    756      mozilla::ipc::MessagePhase aPhase, bool aSync,
    757      mozilla::MarkerThreadId aOriginThreadId) {
    758    using namespace mozilla::ipc;
    759    // This payload still streams a startTime and endTime property because it
    760    // made the migration to MarkerTiming on the front-end easier.
    761    aWriter.TimeProperty("startTime", aStart);
    762    aWriter.TimeProperty("endTime", aEnd);
    763 
    764    aWriter.IntProperty("otherPid", aOtherPid);
    765    aWriter.IntProperty("messageSeqno", aMessageSeqno);
    766    aWriter.StringProperty(
    767        "messageType",
    768        mozilla::MakeStringSpan(IPC::StringFromIPCMessageType(aMessageType)));
    769    aWriter.StringProperty("side", IPCSideToString(aSide));
    770    aWriter.StringProperty("direction",
    771                           aDirection == MessageDirection::eSending
    772                               ? mozilla::MakeStringSpan("sending")
    773                               : mozilla::MakeStringSpan("receiving"));
    774    aWriter.StringProperty("phase", IPCPhaseToString(aPhase));
    775    aWriter.BoolProperty("sync", aSync);
    776    if (!aOriginThreadId.IsUnspecified()) {
    777      // Tech note: If `ToNumber()` returns a uint64_t, the conversion to
    778      // int64_t is "implementation-defined" before C++20. This is acceptable
    779      // here, because this is a one-way conversion to a unique identifier
    780      // that's used to visually separate data by thread on the front-end.
    781      aWriter.IntProperty(
    782          "threadId",
    783          static_cast<int64_t>(aOriginThreadId.ThreadId().ToNumber()));
    784    }
    785  }
    786  static mozilla::MarkerSchema MarkerTypeDisplay() {
    787    return mozilla::MarkerSchema::SpecialFrontendLocation{};
    788  }
    789 
    790 private:
    791  static mozilla::Span<const char> IPCSideToString(mozilla::ipc::Side aSide) {
    792    switch (aSide) {
    793      case mozilla::ipc::ParentSide:
    794        return mozilla::MakeStringSpan("parent");
    795      case mozilla::ipc::ChildSide:
    796        return mozilla::MakeStringSpan("child");
    797      case mozilla::ipc::UnknownSide:
    798        return mozilla::MakeStringSpan("unknown");
    799      default:
    800        MOZ_ASSERT_UNREACHABLE("Invalid IPC side");
    801        return mozilla::MakeStringSpan("<invalid IPC side>");
    802    }
    803  }
    804 
    805  static mozilla::Span<const char> IPCPhaseToString(
    806      mozilla::ipc::MessagePhase aPhase) {
    807    switch (aPhase) {
    808      case mozilla::ipc::MessagePhase::Endpoint:
    809        return mozilla::MakeStringSpan("endpoint");
    810      case mozilla::ipc::MessagePhase::TransferStart:
    811        return mozilla::MakeStringSpan("transferStart");
    812      case mozilla::ipc::MessagePhase::TransferEnd:
    813        return mozilla::MakeStringSpan("transferEnd");
    814      default:
    815        MOZ_ASSERT_UNREACHABLE("Invalid IPC phase");
    816        return mozilla::MakeStringSpan("<invalid IPC phase>");
    817    }
    818  }
    819 };
    820 
    821 }  // namespace geckoprofiler::markers
    822 
    823 #endif  // ifndef ipc_glue_MessageChannel_h