LCOV - code coverage report
Current view: top level - ipc/glue - ProtocolUtils.h (source / functions) Hit Total Coverage
Test: output.info Lines: 116 156 74.4 %
Date: 2017-07-14 16:53:18 Functions: 302 1831 16.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: sw=4 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 mozilla_ipc_ProtocolUtils_h
       9             : #define mozilla_ipc_ProtocolUtils_h 1
      10             : 
      11             : #include "base/id_map.h"
      12             : #include "base/process.h"
      13             : #include "base/process_util.h"
      14             : #include "chrome/common/ipc_message_utils.h"
      15             : 
      16             : #include "prenv.h"
      17             : 
      18             : #include "IPCMessageStart.h"
      19             : #include "mozilla/AlreadyAddRefed.h"
      20             : #include "mozilla/Attributes.h"
      21             : #include "mozilla/ipc/FileDescriptor.h"
      22             : #include "mozilla/ipc/Shmem.h"
      23             : #include "mozilla/ipc/Transport.h"
      24             : #include "mozilla/ipc/MessageLink.h"
      25             : #include "mozilla/LinkedList.h"
      26             : #include "mozilla/Maybe.h"
      27             : #include "mozilla/MozPromise.h"
      28             : #include "mozilla/Mutex.h"
      29             : #include "mozilla/NotNull.h"
      30             : #include "mozilla/UniquePtr.h"
      31             : #include "MainThreadUtils.h"
      32             : 
      33             : #if defined(ANDROID) && defined(DEBUG)
      34             : #include <android/log.h>
      35             : #endif
      36             : 
      37             : template<typename T> class nsTHashtable;
      38             : template<typename T> class nsPtrHashKey;
      39             : 
      40             : // WARNING: this takes into account the private, special-message-type
      41             : // enum in ipc_channel.h.  They need to be kept in sync.
      42             : namespace {
      43             : // XXX the max message ID is actually kuint32max now ... when this
      44             : // changed, the assumptions of the special message IDs changed in that
      45             : // they're not carving out messages from likely-unallocated space, but
      46             : // rather carving out messages from the end of space allocated to
      47             : // protocol 0.  Oops!  We can get away with this until protocol 0
      48             : // starts approaching its 65,536th message.
      49             : enum {
      50             :     BUILD_ID_MESSAGE_TYPE = kuint16max - 7,
      51             :     CHANNEL_OPENED_MESSAGE_TYPE = kuint16max - 6,
      52             :     SHMEM_DESTROYED_MESSAGE_TYPE = kuint16max - 5,
      53             :     SHMEM_CREATED_MESSAGE_TYPE = kuint16max - 4,
      54             :     GOODBYE_MESSAGE_TYPE       = kuint16max - 3,
      55             :     CANCEL_MESSAGE_TYPE        = kuint16max - 2,
      56             : 
      57             :     // kuint16max - 1 is used by ipc_channel.h.
      58             : };
      59             : 
      60             : } // namespace
      61             : 
      62             : class nsIEventTarget;
      63             : 
      64             : namespace mozilla {
      65             : namespace dom {
      66             : class ContentParent;
      67             : } // namespace dom
      68             : 
      69             : namespace net {
      70             : class NeckoParent;
      71             : } // namespace net
      72             : 
      73             : namespace ipc {
      74             : 
      75             : class MessageChannel;
      76             : 
      77             : #ifdef XP_WIN
      78             : const base::ProcessHandle kInvalidProcessHandle = INVALID_HANDLE_VALUE;
      79             : 
      80             : // In theory, on Windows, this is a valid process ID, but in practice they are
      81             : // currently divisible by four. Process IDs share the kernel handle allocation
      82             : // code and they are guaranteed to be divisible by four.
      83             : // As this could change for process IDs we shouldn't generally rely on this
      84             : // property, however even if that were to change, it seems safe to rely on this
      85             : // particular value never being used.
      86             : const base::ProcessId kInvalidProcessId = kuint32max;
      87             : #else
      88             : const base::ProcessHandle kInvalidProcessHandle = -1;
      89             : const base::ProcessId kInvalidProcessId = -1;
      90             : #endif
      91             : 
      92             : // Scoped base::ProcessHandle to ensure base::CloseProcessHandle is called.
      93             : struct ScopedProcessHandleTraits
      94             : {
      95             :   typedef base::ProcessHandle type;
      96             : 
      97           0 :   static type empty()
      98             :   {
      99           0 :     return kInvalidProcessHandle;
     100             :   }
     101             : 
     102           0 :   static void release(type aProcessHandle)
     103             :   {
     104           0 :     if (aProcessHandle && aProcessHandle != kInvalidProcessHandle) {
     105           0 :       base::CloseProcessHandle(aProcessHandle);
     106             :     }
     107           0 :   }
     108             : };
     109             : typedef mozilla::Scoped<ScopedProcessHandleTraits> ScopedProcessHandle;
     110             : 
     111             : class ProtocolFdMapping;
     112             : class ProtocolCloneContext;
     113             : 
     114             : // Used to pass references to protocol actors across the wire.
     115             : // Actors created on the parent-side have a positive ID, and actors
     116             : // allocated on the child side have a negative ID.
     117             : struct ActorHandle
     118             : {
     119             :     int mId;
     120             : };
     121             : 
     122             : // What happens if Interrupt calls race?
     123             : enum RacyInterruptPolicy {
     124             :     RIPError,
     125             :     RIPChildWins,
     126             :     RIPParentWins
     127             : };
     128             : 
     129             : class IToplevelProtocol;
     130             : 
     131             : class IProtocol : public HasResultCodes
     132             : {
     133             : public:
     134             :     enum ActorDestroyReason {
     135             :         FailedConstructor,
     136             :         Deletion,
     137             :         AncestorDeletion,
     138             :         NormalShutdown,
     139             :         AbnormalShutdown
     140             :     };
     141             : 
     142             :     typedef base::ProcessId ProcessId;
     143             :     typedef IPC::Message Message;
     144             :     typedef IPC::MessageInfo MessageInfo;
     145             : 
     146         394 :     IProtocol(Side aSide) : mId(0), mSide(aSide), mManager(nullptr), mChannel(nullptr) {}
     147             : 
     148             :     virtual int32_t Register(IProtocol*);
     149             :     virtual int32_t RegisterID(IProtocol*, int32_t);
     150             :     virtual IProtocol* Lookup(int32_t);
     151             :     virtual void Unregister(int32_t);
     152             :     virtual void RemoveManagee(int32_t, IProtocol*) = 0;
     153             : 
     154             :     virtual Shmem::SharedMemory* CreateSharedMemory(
     155             :         size_t, SharedMemory::SharedMemoryType, bool, int32_t*);
     156             :     virtual Shmem::SharedMemory* LookupSharedMemory(int32_t);
     157             :     virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*);
     158             :     virtual bool DestroySharedMemory(Shmem&);
     159             : 
     160             :     // XXX odd ducks, acknowledged
     161             :     virtual ProcessId OtherPid() const;
     162          41 :     Side GetSide() const { return mSide; }
     163             : 
     164             :     virtual const char* ProtocolName() const = 0;
     165             :     void FatalError(const char* const aErrorMsg) const;
     166             :     virtual void HandleFatalError(const char* aProtocolName, const char* aErrorMsg) const;
     167             : 
     168             :     Maybe<IProtocol*> ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
     169             :                                 const char* aActorDescription, int32_t aProtocolTypeId);
     170             : 
     171             :     virtual Result OnMessageReceived(const Message& aMessage) = 0;
     172             :     virtual Result OnMessageReceived(const Message& aMessage, Message *& aReply) = 0;
     173             :     virtual Result OnCallReceived(const Message& aMessage, Message *& aReply) = 0;
     174             : 
     175             :     virtual int32_t GetProtocolTypeId() = 0;
     176             : 
     177         643 :     int32_t Id() const { return mId; }
     178         401 :     IProtocol* Manager() const { return mManager; }
     179           0 :     virtual const MessageChannel* GetIPCChannel() const { return mChannel; }
     180         521 :     virtual MessageChannel* GetIPCChannel() { return mChannel; }
     181             : 
     182             :     bool AllocShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
     183             :     bool AllocUnsafeShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
     184             :     bool DeallocShmem(Shmem& aMem);
     185             : 
     186             :     // Sets an event target to which all messages for aActor will be
     187             :     // dispatched. This method must be called before right before the SendPFoo
     188             :     // message for aActor is sent. And SendPFoo *must* be called if
     189             :     // SetEventTargetForActor is called. The receiver when calling
     190             :     // SetEventTargetForActor must be the actor that will be the manager for
     191             :     // aActor.
     192             :     void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget);
     193             : 
     194             :     // Replace the event target for the messages of aActor. There must not be
     195             :     // any messages of aActor in the task queue, or we might run into some
     196             :     // unexpected behavior.
     197             :     void ReplaceEventTargetForActor(IProtocol* aActor,
     198             :                                     nsIEventTarget* aEventTarget);
     199             : 
     200             :     // Returns the event target set by SetEventTargetForActor() if available.
     201             :     virtual nsIEventTarget* GetActorEventTarget();
     202             : 
     203             : protected:
     204             :     friend class IToplevelProtocol;
     205             : 
     206          80 :     void SetId(int32_t aId) { mId = aId; }
     207           0 :     void ResetManager() { mManager = nullptr; }
     208             :     void SetManager(IProtocol* aManager);
     209          71 :     void SetIPCChannel(MessageChannel* aChannel) { mChannel = aChannel; }
     210             : 
     211             :     virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);
     212             :     virtual void ReplaceEventTargetForActorInternal(
     213             :       IProtocol* aActor,
     214             :       nsIEventTarget* aEventTarget);
     215             : 
     216             :     virtual already_AddRefed<nsIEventTarget>
     217             :     GetActorEventTargetInternal(IProtocol* aActor);
     218             : 
     219             :     static const int32_t kNullActorId = 0;
     220             :     static const int32_t kFreedActorId = 1;
     221             : 
     222             : private:
     223             :     int32_t mId;
     224             :     Side mSide;
     225             :     IProtocol* mManager;
     226             :     MessageChannel* mChannel;
     227             : };
     228             : 
     229             : typedef IPCMessageStart ProtocolId;
     230             : 
     231             : #define IPC_OK() mozilla::ipc::IPCResult::Ok()
     232             : #define IPC_FAIL(actor, why) mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__, (why))
     233             : #define IPC_FAIL_NO_REASON(actor) mozilla::ipc::IPCResult::Fail(WrapNotNull(actor), __func__)
     234             : 
     235             : /**
     236             :  * All message deserializer and message handler should return this
     237             :  * type via above macros. We use a less generic name here to avoid
     238             :  * conflict with mozilla::Result because we have quite a few using
     239             :  * namespace mozilla::ipc; in the code base.
     240             :  */
     241             : class IPCResult {
     242             : public:
     243         471 :     static IPCResult Ok() { return IPCResult(true); }
     244             :     static IPCResult Fail(NotNull<IProtocol*> aActor, const char* aWhere, const char* aWhy = "");
     245         454 :     MOZ_IMPLICIT operator bool() const { return mSuccess; }
     246             : private:
     247         471 :     explicit IPCResult(bool aResult) : mSuccess(aResult) {}
     248             :     bool mSuccess;
     249             : };
     250             : 
     251             : template<class PFooSide>
     252             : class Endpoint;
     253             : 
     254             : /**
     255             :  * All top-level protocols should inherit this class.
     256             :  *
     257             :  * IToplevelProtocol tracks all top-level protocol actors created from
     258             :  * this protocol actor.
     259             :  */
     260             : class IToplevelProtocol : public IProtocol
     261             : {
     262             :     template<class PFooSide> friend class Endpoint;
     263             : 
     264             : protected:
     265             :     explicit IToplevelProtocol(ProtocolId aProtoId, Side aSide);
     266             :     ~IToplevelProtocol();
     267             : 
     268             : public:
     269          24 :     void SetTransport(UniquePtr<Transport> aTrans)
     270             :     {
     271          24 :         mTrans = Move(aTrans);
     272          24 :     }
     273             : 
     274             :     Transport* GetTransport() const { return mTrans.get(); }
     275             : 
     276             :     ProtocolId GetProtocolId() const { return mProtocolId; }
     277             : 
     278             :     base::ProcessId OtherPid() const;
     279             :     void SetOtherProcessId(base::ProcessId aOtherPid);
     280             : 
     281             :     bool TakeMinidump(nsIFile** aDump, uint32_t* aSequence);
     282             : 
     283             :     virtual void OnChannelClose() = 0;
     284             :     virtual void OnChannelError() = 0;
     285           0 :     virtual void ProcessingError(Result aError, const char* aMsgName) {}
     286          17 :     virtual void OnChannelConnected(int32_t peer_pid) {}
     287             : 
     288             :     bool Open(mozilla::ipc::Transport* aTransport,
     289             :               base::ProcessId aOtherPid,
     290             :               MessageLoop* aThread = nullptr,
     291             :               mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
     292             : 
     293             :     bool Open(MessageChannel* aChannel,
     294             :               MessageLoop* aMessageLoop,
     295             :               mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
     296             : 
     297             :     void Close();
     298             : 
     299             :     void SetReplyTimeoutMs(int32_t aTimeoutMs);
     300             : 
     301             :     virtual int32_t Register(IProtocol*);
     302             :     virtual int32_t RegisterID(IProtocol*, int32_t);
     303             :     virtual IProtocol* Lookup(int32_t);
     304             :     virtual void Unregister(int32_t);
     305             : 
     306             :     virtual Shmem::SharedMemory* CreateSharedMemory(
     307             :         size_t, SharedMemory::SharedMemoryType, bool, int32_t*);
     308             :     virtual Shmem::SharedMemory* LookupSharedMemory(int32_t);
     309             :     virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*);
     310             :     virtual bool DestroySharedMemory(Shmem&);
     311             : 
     312             :     void DeallocShmems();
     313             : 
     314             :     bool ShmemCreated(const Message& aMsg);
     315             :     bool ShmemDestroyed(const Message& aMsg);
     316             : 
     317           0 :     virtual bool ShouldContinueFromReplyTimeout() {
     318           0 :         return false;
     319             :     }
     320             : 
     321             :     // WARNING: This function is called with the MessageChannel monitor held.
     322           0 :     virtual void IntentionalCrash() {
     323           0 :         MOZ_CRASH("Intentional IPDL crash");
     324             :     }
     325             : 
     326             :     // The code here is only useful for fuzzing. It should not be used for any
     327             :     // other purpose.
     328             : #ifdef DEBUG
     329             :     // Returns true if we should simulate a timeout.
     330             :     // WARNING: This is a testing-only function that is called with the
     331             :     // MessageChannel monitor held. Don't do anything fancy here or we could
     332             :     // deadlock.
     333           3 :     virtual bool ArtificialTimeout() {
     334           3 :         return false;
     335             :     }
     336             : 
     337             :     // Returns true if we want to cause the worker thread to sleep with the
     338             :     // monitor unlocked.
     339           3 :     virtual bool NeedArtificialSleep() {
     340           3 :         return false;
     341             :     }
     342             : 
     343             :     // This function should be implemented to sleep for some amount of time on
     344             :     // the worker thread. Will only be called if NeedArtificialSleep() returns
     345             :     // true.
     346         907 :     virtual void ArtificialSleep() {}
     347             : #else
     348             :     bool ArtificialTimeout() { return false; }
     349             :     bool NeedArtificialSleep() { return false; }
     350             :     void ArtificialSleep() {}
     351             : #endif
     352             : 
     353           0 :     virtual void EnteredCxxStack() {}
     354           0 :     virtual void ExitedCxxStack() {}
     355           0 :     virtual void EnteredCall() {}
     356           0 :     virtual void ExitedCall() {}
     357             : 
     358             :     bool IsOnCxxStack() const;
     359             : 
     360           0 :     virtual RacyInterruptPolicy MediateInterruptRace(const MessageInfo& parent,
     361             :                                                      const MessageInfo& child)
     362             :     {
     363           0 :         return RIPChildWins;
     364             :     }
     365             : 
     366             :     /**
     367             :      * Return true if windows messages can be handled while waiting for a reply
     368             :      * to a sync IPDL message.
     369             :      */
     370           3 :     virtual bool HandleWindowsMessages(const Message& aMsg) const { return true; }
     371             : 
     372           3 :     virtual void OnEnteredSyncSend() {
     373           3 :     }
     374           3 :     virtual void OnExitedSyncSend() {
     375           3 :     }
     376             : 
     377           0 :     virtual void ProcessRemoteNativeEventsInInterruptCall() {
     378           0 :     }
     379             : 
     380             :     virtual already_AddRefed<nsIEventTarget>
     381             :     GetMessageEventTarget(const Message& aMsg);
     382             : 
     383             :     already_AddRefed<nsIEventTarget>
     384             :     GetActorEventTarget(IProtocol* aActor);
     385             : 
     386             :     virtual nsIEventTarget*
     387             :     GetActorEventTarget();
     388             : 
     389         454 :     virtual void OnChannelReceivedMessage(const Message& aMsg) {}
     390             : 
     391         473 :     bool IsMainThreadProtocol() const { return mIsMainThreadProtocol; }
     392          38 :     void SetIsMainThreadProtocol() { mIsMainThreadProtocol = NS_IsMainThread(); }
     393             : 
     394             : protected:
     395             :     // Override this method in top-level protocols to change the event target
     396             :     // for a new actor (and its sub-actors).
     397             :     virtual already_AddRefed<nsIEventTarget>
     398          30 :     GetConstructedEventTarget(const Message& aMsg) { return nullptr; }
     399             : 
     400             :     // Override this method in top-level protocols to change the event target
     401             :     // for specific messages.
     402             :     virtual already_AddRefed<nsIEventTarget>
     403         236 :     GetSpecificMessageEventTarget(const Message& aMsg) { return nullptr; }
     404             : 
     405             :     virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);
     406             :     virtual void ReplaceEventTargetForActorInternal(
     407             :       IProtocol* aActor,
     408             :       nsIEventTarget* aEventTarget);
     409             : 
     410             :     virtual already_AddRefed<nsIEventTarget>
     411             :     GetActorEventTargetInternal(IProtocol* aActor);
     412             : 
     413             :   private:
     414             :     ProtocolId mProtocolId;
     415             :     UniquePtr<Transport> mTrans;
     416             :     base::ProcessId mOtherPid;
     417             :     IDMap<IProtocol*> mActorMap;
     418             :     int32_t mLastRouteId;
     419             :     IDMap<Shmem::SharedMemory*> mShmemMap;
     420             :     Shmem::id_t mLastShmemId;
     421             :     bool mIsMainThreadProtocol;
     422             : 
     423             :     Mutex mEventTargetMutex;
     424             :     IDMap<nsCOMPtr<nsIEventTarget>> mEventTargetMap;
     425             : };
     426             : 
     427          14 : class IShmemAllocator
     428             : {
     429             : public:
     430             :   virtual bool AllocShmem(size_t aSize,
     431             :                           mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
     432             :                           mozilla::ipc::Shmem* aShmem) = 0;
     433             :   virtual bool AllocUnsafeShmem(size_t aSize,
     434             :                                 mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
     435             :                                 mozilla::ipc::Shmem* aShmem) = 0;
     436             :   virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) = 0;
     437             : };
     438             : 
     439             : #define FORWARD_SHMEM_ALLOCATOR_TO(aImplClass) \
     440             :   virtual bool AllocShmem(size_t aSize, \
     441             :                           mozilla::ipc::SharedMemory::SharedMemoryType aShmType, \
     442             :                           mozilla::ipc::Shmem* aShmem) override \
     443             :   { return aImplClass::AllocShmem(aSize, aShmType, aShmem); } \
     444             :   virtual bool AllocUnsafeShmem(size_t aSize, \
     445             :                                 mozilla::ipc::SharedMemory::SharedMemoryType aShmType, \
     446             :                                 mozilla::ipc::Shmem* aShmem) override \
     447             :   { return aImplClass::AllocUnsafeShmem(aSize, aShmType, aShmem); } \
     448             :   virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override \
     449             :   { return aImplClass::DeallocShmem(aShmem); }
     450             : 
     451             : inline bool
     452           0 : LoggingEnabled()
     453             : {
     454             : #if defined(DEBUG) || defined(FUZZING)
     455           0 :     return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
     456             : #else
     457             :     return false;
     458             : #endif
     459             : }
     460             : 
     461             : inline bool
     462         976 : LoggingEnabledFor(const char *aTopLevelProtocol)
     463             : {
     464             : #if defined(DEBUG) || defined(FUZZING)
     465         976 :     const char *filter = PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
     466         976 :     if (!filter) {
     467         976 :         return false;
     468             :     }
     469           0 :     return strcmp(filter, "1") == 0 || strcmp(filter, aTopLevelProtocol) == 0;
     470             : #else
     471             :     return false;
     472             : #endif
     473             : }
     474             : 
     475             : enum class MessageDirection {
     476             :     eSending,
     477             :     eReceiving,
     478             : };
     479             : 
     480             : MOZ_NEVER_INLINE void
     481             : LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid,
     482             :                       const char* aContextDescription,
     483             :                       uint32_t aMessageId,
     484             :                       MessageDirection aDirection);
     485             : 
     486             : MOZ_NEVER_INLINE void
     487             : ProtocolErrorBreakpoint(const char* aMsg);
     488             : 
     489             : // The code generator calls this function for errors which come from the
     490             : // methods of protocols.  Doing this saves codesize by making the error
     491             : // cases significantly smaller.
     492             : MOZ_NEVER_INLINE void
     493             : FatalError(const char* aProtocolName, const char* aMsg, bool aIsParent);
     494             : 
     495             : // The code generator calls this function for errors which are not
     496             : // protocol-specific: errors in generated struct methods or errors in
     497             : // transition functions, for instance.  Doing this saves codesize by
     498             : // by making the error cases significantly smaller.
     499             : MOZ_NEVER_INLINE void
     500             : LogicError(const char* aMsg);
     501             : 
     502             : MOZ_NEVER_INLINE void
     503             : ActorIdReadError(const char* aActorDescription);
     504             : 
     505             : MOZ_NEVER_INLINE void
     506             : BadActorIdError(const char* aActorDescription);
     507             : 
     508             : MOZ_NEVER_INLINE void
     509             : ActorLookupError(const char* aActorDescription);
     510             : 
     511             : MOZ_NEVER_INLINE void
     512             : MismatchedActorTypeError(const char* aActorDescription);
     513             : 
     514             : MOZ_NEVER_INLINE void
     515             : UnionTypeReadError(const char* aUnionName);
     516             : 
     517             : MOZ_NEVER_INLINE void
     518             : ArrayLengthReadError(const char* aElementName);
     519             : 
     520             : MOZ_NEVER_INLINE void
     521             : SentinelReadError(const char* aElementName);
     522             : 
     523             : struct PrivateIPDLInterface {};
     524             : 
     525             : nsresult
     526             : Bridge(const PrivateIPDLInterface&,
     527             :        MessageChannel*, base::ProcessId, MessageChannel*, base::ProcessId,
     528             :        ProtocolId, ProtocolId);
     529             : 
     530             : bool
     531             : Open(const PrivateIPDLInterface&,
     532             :      MessageChannel*, base::ProcessId, Transport::Mode,
     533             :      ProtocolId, ProtocolId);
     534             : 
     535             : bool
     536             : UnpackChannelOpened(const PrivateIPDLInterface&,
     537             :                     const IPC::Message&,
     538             :                     TransportDescriptor*, base::ProcessId*, ProtocolId*);
     539             : 
     540             : #if defined(XP_WIN)
     541             : // This is a restricted version of Windows' DuplicateHandle() function
     542             : // that works inside the sandbox and can send handles but not retrieve
     543             : // them.  Unlike DuplicateHandle(), it takes a process ID rather than
     544             : // a process handle.  It returns true on success, false otherwise.
     545             : bool
     546             : DuplicateHandle(HANDLE aSourceHandle,
     547             :                 DWORD aTargetProcessId,
     548             :                 HANDLE* aTargetHandle,
     549             :                 DWORD aDesiredAccess,
     550             :                 DWORD aOptions);
     551             : #endif
     552             : 
     553             : /**
     554             :  * Annotate the crash reporter with the error code from the most recent system
     555             :  * call. Returns the system error.
     556             :  */
     557             : #ifdef MOZ_CRASHREPORTER
     558             : void AnnotateSystemError();
     559             : #else
     560             : #define AnnotateSystemError() do { } while (0)
     561             : #endif
     562             : 
     563             : /**
     564             :  * An endpoint represents one end of a partially initialized IPDL channel. To
     565             :  * set up a new top-level protocol:
     566             :  *
     567             :  * Endpoint<PFooParent> parentEp;
     568             :  * Endpoint<PFooChild> childEp;
     569             :  * nsresult rv;
     570             :  * rv = PFoo::CreateEndpoints(parentPid, childPid, &parentEp, &childEp);
     571             :  *
     572             :  * You're required to pass in parentPid and childPid, which are the pids of the
     573             :  * processes in which the parent and child endpoints will be used.
     574             :  *
     575             :  * Endpoints can be passed in IPDL messages or sent to other threads using
     576             :  * PostTask. Once an Endpoint has arrived at its destination process and thread,
     577             :  * you need to create the top-level actor and bind it to the endpoint:
     578             :  *
     579             :  * FooParent* parent = new FooParent();
     580             :  * bool rv1 = parentEp.Bind(parent, processActor);
     581             :  * bool rv2 = parent->SendBar(...);
     582             :  *
     583             :  * (See Bind below for an explanation of processActor.) Once the actor is bound
     584             :  * to the endpoint, it can send and receive messages.
     585             :  */
     586             : template<class PFooSide>
     587             : class Endpoint
     588             : {
     589             : public:
     590             :     typedef base::ProcessId ProcessId;
     591             : 
     592          48 :     Endpoint()
     593          48 :       : mValid(false)
     594          48 :     {}
     595             : 
     596          26 :     Endpoint(const PrivateIPDLInterface&,
     597             :              mozilla::ipc::Transport::Mode aMode,
     598             :              TransportDescriptor aTransport,
     599             :              ProcessId aMyPid,
     600             :              ProcessId aOtherPid,
     601             :              ProtocolId aProtocolId)
     602             :       : mValid(true)
     603             :       , mMode(aMode)
     604             :       , mTransport(aTransport)
     605             :       , mMyPid(aMyPid)
     606             :       , mOtherPid(aOtherPid)
     607          26 :       , mProtocolId(aProtocolId)
     608          26 :     {}
     609             : 
     610          29 :     Endpoint(Endpoint&& aOther)
     611          29 :       : mValid(aOther.mValid)
     612          29 :       , mMode(aOther.mMode)
     613             :       , mTransport(aOther.mTransport)
     614          29 :       , mMyPid(aOther.mMyPid)
     615          29 :       , mOtherPid(aOther.mOtherPid)
     616         116 :       , mProtocolId(aOther.mProtocolId)
     617             :     {
     618          29 :         aOther.mValid = false;
     619          29 :     }
     620             : 
     621          32 :     Endpoint& operator=(Endpoint&& aOther)
     622             :     {
     623          32 :         mValid = aOther.mValid;
     624          32 :         mMode = aOther.mMode;
     625          32 :         mTransport = aOther.mTransport;
     626          32 :         mMyPid = aOther.mMyPid;
     627          32 :         mOtherPid = aOther.mOtherPid;
     628          32 :         mProtocolId = aOther.mProtocolId;
     629             : 
     630          32 :         aOther.mValid = false;
     631          32 :         return *this;
     632             :     }
     633             : 
     634         102 :     ~Endpoint() {
     635         102 :         if (mValid) {
     636          13 :             CloseDescriptor(mTransport);
     637             :         }
     638         102 :     }
     639             : 
     640           6 :     ProcessId OtherPid() const {
     641           6 :         return mOtherPid;
     642             :     }
     643             : 
     644             :     // This method binds aActor to this endpoint. After this call, the actor can
     645             :     // be used to send and receive messages. The endpoint becomes invalid.
     646          24 :     bool Bind(PFooSide* aActor)
     647             :     {
     648          24 :         MOZ_RELEASE_ASSERT(mValid);
     649          24 :         MOZ_RELEASE_ASSERT(mMyPid == base::GetCurrentProcId());
     650             : 
     651          48 :         UniquePtr<Transport> t = mozilla::ipc::OpenDescriptor(mTransport, mMode);
     652          24 :         if (!t) {
     653           0 :             return false;
     654             :         }
     655          24 :         if (!aActor->Open(t.get(), mOtherPid, XRE_GetIOMessageLoop(),
     656          24 :                           mMode == Transport::MODE_SERVER ? ParentSide : ChildSide)) {
     657           0 :             return false;
     658             :         }
     659          24 :         mValid = false;
     660          24 :         aActor->SetTransport(Move(t));
     661          24 :         return true;
     662             :     }
     663             : 
     664          18 :     bool IsValid() const {
     665          18 :         return mValid;
     666             :     }
     667             : 
     668             : private:
     669             :     friend struct IPC::ParamTraits<Endpoint<PFooSide>>;
     670             : 
     671             :     Endpoint(const Endpoint&) = delete;
     672             :     Endpoint& operator=(const Endpoint&) = delete;
     673             : 
     674             :     bool mValid;
     675             :     mozilla::ipc::Transport::Mode mMode;
     676             :     TransportDescriptor mTransport;
     677             :     ProcessId mMyPid, mOtherPid;
     678             :     ProtocolId mProtocolId;
     679             : };
     680             : 
     681             : #if defined(MOZ_CRASHREPORTER) && defined(XP_MACOSX)
     682             : void AnnotateCrashReportWithErrno(const char* tag, int error);
     683             : #else
     684           0 : static inline void AnnotateCrashReportWithErrno(const char* tag, int error)
     685           0 : {}
     686             : #endif
     687             : 
     688             : // This function is used internally to create a pair of Endpoints. See the
     689             : // comment above Endpoint for a description of how it might be used.
     690             : template<class PFooParent, class PFooChild>
     691             : nsresult
     692          13 : CreateEndpoints(const PrivateIPDLInterface& aPrivate,
     693             :                 base::ProcessId aParentDestPid,
     694             :                 base::ProcessId aChildDestPid,
     695             :                 ProtocolId aProtocol,
     696             :                 ProtocolId aChildProtocol,
     697             :                 Endpoint<PFooParent>* aParentEndpoint,
     698             :                 Endpoint<PFooChild>* aChildEndpoint)
     699             : {
     700          13 :   MOZ_RELEASE_ASSERT(aParentDestPid);
     701          13 :   MOZ_RELEASE_ASSERT(aChildDestPid);
     702             : 
     703          13 :   TransportDescriptor parentTransport, childTransport;
     704             :   nsresult rv;
     705          13 :   if (NS_FAILED(rv = CreateTransport(aParentDestPid, &parentTransport, &childTransport))) {
     706           0 :     AnnotateCrashReportWithErrno("IpcCreateEndpointsNsresult", int(rv));
     707           0 :     return rv;
     708             :   }
     709             : 
     710          13 :   *aParentEndpoint = Endpoint<PFooParent>(aPrivate, mozilla::ipc::Transport::MODE_SERVER,
     711             :                                           parentTransport, aParentDestPid, aChildDestPid, aProtocol);
     712             : 
     713          13 :   *aChildEndpoint = Endpoint<PFooChild>(aPrivate, mozilla::ipc::Transport::MODE_CLIENT,
     714             :                                         childTransport, aChildDestPid, aParentDestPid, aChildProtocol);
     715             : 
     716          13 :   return NS_OK;
     717             : }
     718             : 
     719             : void
     720             : TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
     721             :              nsTArray<void*>& aArray);
     722             : 
     723             : const char* StringFromIPCMessageType(uint32_t aMessageType);
     724             : 
     725             : } // namespace ipc
     726             : 
     727             : template<typename Protocol>
     728         473 : class ManagedContainer : public nsTHashtable<nsPtrHashKey<Protocol>>
     729             : {
     730             :   typedef nsTHashtable<nsPtrHashKey<Protocol>> BaseClass;
     731             : 
     732             : public:
     733             :   // Having the core logic work on void pointers, rather than typed pointers,
     734             :   // means that we can have one instance of this code out-of-line, rather
     735             :   // than several hundred instances of this code out-of-lined.  (Those
     736             :   // repeated instances don't necessarily get folded together by the linker
     737             :   // because they contain member offsets and such that differ between the
     738             :   // functions.)  We do have to pay for it with some eye-bleedingly bad casts,
     739             :   // though.
     740           0 :   void ToArray(nsTArray<Protocol*>& aArray) const {
     741           0 :     ::mozilla::ipc::TableToArray(*reinterpret_cast<const nsTHashtable<nsPtrHashKey<void>>*>
     742             :                                  (static_cast<const BaseClass*>(this)),
     743             :                                  reinterpret_cast<nsTArray<void*>&>(aArray));
     744           0 :   }
     745             : };
     746             : 
     747             : template<typename Protocol>
     748             : Protocol*
     749         927 : LoneManagedOrNullAsserts(const ManagedContainer<Protocol>& aManagees)
     750             : {
     751         927 :     if (aManagees.IsEmpty()) {
     752         281 :         return nullptr;
     753             :     }
     754         646 :     MOZ_ASSERT(aManagees.Count() == 1);
     755         646 :     return aManagees.ConstIter().Get()->GetKey();
     756             : }
     757             : 
     758             : // appId's are for B2G only currently, where managees.Count() == 1. This is
     759             : // not guaranteed currently in Desktop, so for paths used for desktop,
     760             : // don't assert there's one managee.
     761             : template<typename Protocol>
     762             : Protocol*
     763           0 : SingleManagedOrNull(const ManagedContainer<Protocol>& aManagees)
     764             : {
     765           0 :     if (aManagees.Count() != 1) {
     766           0 :         return nullptr;
     767             :     }
     768           0 :     return aManagees.ConstIter().Get()->GetKey();
     769             : }
     770             : 
     771             : } // namespace mozilla
     772             : 
     773             : 
     774             : namespace IPC {
     775             : 
     776             : template <>
     777             : struct ParamTraits<mozilla::ipc::ActorHandle>
     778             : {
     779             :     typedef mozilla::ipc::ActorHandle paramType;
     780             : 
     781             :     static void Write(Message* aMsg, const paramType& aParam)
     782             :     {
     783             :         IPC::WriteParam(aMsg, aParam.mId);
     784             :     }
     785             : 
     786          68 :     static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
     787             :     {
     788             :         int id;
     789          68 :         if (IPC::ReadParam(aMsg, aIter, &id)) {
     790          68 :             aResult->mId = id;
     791          68 :             return true;
     792             :         }
     793           0 :         return false;
     794             :     }
     795             : 
     796             :     static void Log(const paramType& aParam, std::wstring* aLog)
     797             :     {
     798             :         aLog->append(StringPrintf(L"(%d)", aParam.mId));
     799             :     }
     800             : };
     801             : 
     802             : template<class PFooSide>
     803             : struct ParamTraits<mozilla::ipc::Endpoint<PFooSide>>
     804             : {
     805             :     typedef mozilla::ipc::Endpoint<PFooSide> paramType;
     806             : 
     807          15 :     static void Write(Message* aMsg, const paramType& aParam)
     808             :     {
     809          15 :         IPC::WriteParam(aMsg, aParam.mValid);
     810          15 :         if (!aParam.mValid) {
     811           2 :             return;
     812             :         }
     813             : 
     814          13 :         IPC::WriteParam(aMsg, static_cast<uint32_t>(aParam.mMode));
     815             : 
     816             :         // We duplicate the descriptor so that our own file descriptor remains
     817             :         // valid after the write. An alternative would be to set
     818             :         // aParam.mTransport.mValid to false, but that won't work because aParam
     819             :         // is const.
     820          13 :         mozilla::ipc::TransportDescriptor desc = mozilla::ipc::DuplicateDescriptor(aParam.mTransport);
     821          13 :         IPC::WriteParam(aMsg, desc);
     822             : 
     823          13 :         IPC::WriteParam(aMsg, aParam.mMyPid);
     824          13 :         IPC::WriteParam(aMsg, aParam.mOtherPid);
     825          13 :         IPC::WriteParam(aMsg, static_cast<uint32_t>(aParam.mProtocolId));
     826             :     }
     827             : 
     828          14 :     static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
     829             :     {
     830          14 :         MOZ_RELEASE_ASSERT(!aResult->mValid);
     831             : 
     832          14 :         if (!IPC::ReadParam(aMsg, aIter, &aResult->mValid)) {
     833           0 :             return false;
     834             :         }
     835          14 :         if (!aResult->mValid) {
     836             :             // Object is empty, but read succeeded.
     837           2 :             return true;
     838             :         }
     839             : 
     840             :         uint32_t mode, protocolId;
     841          36 :         if (!IPC::ReadParam(aMsg, aIter, &mode) ||
     842          24 :             !IPC::ReadParam(aMsg, aIter, &aResult->mTransport) ||
     843          24 :             !IPC::ReadParam(aMsg, aIter, &aResult->mMyPid) ||
     844          36 :             !IPC::ReadParam(aMsg, aIter, &aResult->mOtherPid) ||
     845          12 :             !IPC::ReadParam(aMsg, aIter, &protocolId)) {
     846           0 :             return false;
     847             :         }
     848          12 :         aResult->mMode = Channel::Mode(mode);
     849          12 :         aResult->mProtocolId = mozilla::ipc::ProtocolId(protocolId);
     850          12 :         return true;
     851             :     }
     852             : 
     853             :     static void Log(const paramType& aParam, std::wstring* aLog)
     854             :     {
     855             :         aLog->append(StringPrintf(L"Endpoint"));
     856             :     }
     857             : };
     858             : 
     859             : } // namespace IPC
     860             : 
     861             : 
     862             : #endif  // mozilla_ipc_ProtocolUtils_h

Generated by: LCOV version 1.13