LCOV - code coverage report
Current view: top level - ipc/glue - ProtocolUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 143 375 38.1 %
Date: 2017-07-14 16:53:18 Functions: 31 70 44.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "base/process_util.h"
       8             : #include "base/task.h"
       9             : 
      10             : #ifdef OS_POSIX
      11             : #include <errno.h>
      12             : #endif
      13             : 
      14             : #include "mozilla/IntegerPrintfMacros.h"
      15             : 
      16             : #include "mozilla/ipc/ProtocolUtils.h"
      17             : 
      18             : #include "mozilla/dom/ContentParent.h"
      19             : #include "mozilla/ipc/MessageChannel.h"
      20             : #include "mozilla/ipc/Transport.h"
      21             : #include "mozilla/StaticMutex.h"
      22             : #include "mozilla/SystemGroup.h"
      23             : #include "mozilla/Unused.h"
      24             : #include "nsPrintfCString.h"
      25             : 
      26             : #if defined(MOZ_SANDBOX) && defined(XP_WIN)
      27             : #define TARGET_SANDBOX_EXPORTS
      28             : #include "mozilla/sandboxTarget.h"
      29             : #endif
      30             : 
      31             : #if defined(MOZ_CRASHREPORTER) && defined(XP_WIN)
      32             : #include "aclapi.h"
      33             : #include "sddl.h"
      34             : 
      35             : #include "mozilla/TypeTraits.h"
      36             : #endif
      37             : 
      38             : #include "nsAutoPtr.h"
      39             : 
      40             : using namespace IPC;
      41             : 
      42             : using base::GetCurrentProcId;
      43             : using base::ProcessHandle;
      44             : using base::ProcessId;
      45             : 
      46             : namespace mozilla {
      47             : 
      48             : #if defined(MOZ_CRASHREPORTER) && defined(XP_WIN)
      49             : // Generate RAII classes for LPTSTR and PSECURITY_DESCRIPTOR.
      50             : MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedLPTStr, \
      51             :                                           RemovePointer<LPTSTR>::Type, \
      52             :                                           ::LocalFree)
      53             : MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPSecurityDescriptor, \
      54             :                                           RemovePointer<PSECURITY_DESCRIPTOR>::Type, \
      55             :                                           ::LocalFree)
      56             : #endif
      57             : 
      58             : namespace ipc {
      59             : 
      60             : IPCResult
      61           0 : IPCResult::Fail(NotNull<IProtocol*> actor, const char* where, const char* why)
      62             : {
      63             :   // Calls top-level protocol to handle the error.
      64           0 :   nsPrintfCString errorMsg("%s::%s %s\n", actor->ProtocolName(), where, why);
      65           0 :   actor->GetIPCChannel()->Listener()->ProcessingError(
      66           0 :     HasResultCodes::MsgProcessingError, errorMsg.get());
      67           0 :   return IPCResult(false);
      68             : }
      69             : 
      70           0 : class ChannelOpened : public IPC::Message
      71             : {
      72             : public:
      73           0 :   ChannelOpened(TransportDescriptor aDescriptor,
      74             :                 ProcessId aOtherProcess,
      75             :                 ProtocolId aProtocol,
      76             :                 NestedLevel aNestedLevel = NOT_NESTED)
      77           0 :     : IPC::Message(MSG_ROUTING_CONTROL, // these only go to top-level actors
      78             :                    CHANNEL_OPENED_MESSAGE_TYPE,
      79             :                    0,
      80           0 :                    aNestedLevel)
      81             :   {
      82           0 :     IPC::WriteParam(this, aDescriptor);
      83           0 :     IPC::WriteParam(this, aOtherProcess);
      84           0 :     IPC::WriteParam(this, static_cast<uint32_t>(aProtocol));
      85           0 :   }
      86             : 
      87           0 :   static bool Read(const IPC::Message& aMsg,
      88             :                    TransportDescriptor* aDescriptor,
      89             :                    ProcessId* aOtherProcess,
      90             :                    ProtocolId* aProtocol)
      91             :   {
      92           0 :     PickleIterator iter(aMsg);
      93           0 :     if (!IPC::ReadParam(&aMsg, &iter, aDescriptor) ||
      94           0 :         !IPC::ReadParam(&aMsg, &iter, aOtherProcess) ||
      95           0 :         !IPC::ReadParam(&aMsg, &iter, reinterpret_cast<uint32_t*>(aProtocol))) {
      96           0 :       return false;
      97             :     }
      98           0 :     aMsg.EndRead(iter);
      99           0 :     return true;
     100             :   }
     101             : };
     102             : 
     103             : nsresult
     104           0 : Bridge(const PrivateIPDLInterface&,
     105             :        MessageChannel* aParentChannel, ProcessId aParentPid,
     106             :        MessageChannel* aChildChannel, ProcessId aChildPid,
     107             :        ProtocolId aProtocol, ProtocolId aChildProtocol)
     108             : {
     109           0 :   if (!aParentPid || !aChildPid) {
     110           0 :     return NS_ERROR_INVALID_ARG;
     111             :   }
     112             : 
     113           0 :   TransportDescriptor parentSide, childSide;
     114             :   nsresult rv;
     115           0 :   if (NS_FAILED(rv = CreateTransport(aParentPid, &parentSide, &childSide))) {
     116           0 :     return rv;
     117             :   }
     118             : 
     119           0 :   if (!aParentChannel->Send(new ChannelOpened(parentSide,
     120             :                                               aChildPid,
     121             :                                               aProtocol,
     122           0 :                                               IPC::Message::NESTED_INSIDE_CPOW))) {
     123           0 :     CloseDescriptor(parentSide);
     124           0 :     CloseDescriptor(childSide);
     125           0 :     return NS_ERROR_BRIDGE_OPEN_PARENT;
     126             :   }
     127             : 
     128           0 :   if (!aChildChannel->Send(new ChannelOpened(childSide,
     129             :                                             aParentPid,
     130             :                                             aChildProtocol,
     131           0 :                                             IPC::Message::NESTED_INSIDE_CPOW))) {
     132           0 :     CloseDescriptor(parentSide);
     133           0 :     CloseDescriptor(childSide);
     134           0 :     return NS_ERROR_BRIDGE_OPEN_CHILD;
     135             :   }
     136             : 
     137           0 :   return NS_OK;
     138             : }
     139             : 
     140             : bool
     141           0 : Open(const PrivateIPDLInterface&,
     142             :      MessageChannel* aOpenerChannel, ProcessId aOtherProcessId,
     143             :      Transport::Mode aOpenerMode,
     144             :      ProtocolId aProtocol, ProtocolId aChildProtocol)
     145             : {
     146           0 :   bool isParent = (Transport::MODE_SERVER == aOpenerMode);
     147           0 :   ProcessId thisPid = GetCurrentProcId();
     148           0 :   ProcessId parentId = isParent ? thisPid : aOtherProcessId;
     149           0 :   ProcessId childId = !isParent ? thisPid : aOtherProcessId;
     150           0 :   if (!parentId || !childId) {
     151           0 :     return false;
     152             :   }
     153             : 
     154           0 :   TransportDescriptor parentSide, childSide;
     155           0 :   if (NS_FAILED(CreateTransport(parentId, &parentSide, &childSide))) {
     156           0 :     return false;
     157             :   }
     158             : 
     159           0 :   Message* parentMsg = new ChannelOpened(parentSide, childId, aProtocol);
     160           0 :   Message* childMsg = new ChannelOpened(childSide, parentId, aChildProtocol);
     161           0 :   nsAutoPtr<Message> messageForUs(isParent ? parentMsg : childMsg);
     162           0 :   nsAutoPtr<Message> messageForOtherSide(!isParent ? parentMsg : childMsg);
     163           0 :   if (!aOpenerChannel->Echo(messageForUs.forget()) ||
     164           0 :       !aOpenerChannel->Send(messageForOtherSide.forget())) {
     165           0 :     CloseDescriptor(parentSide);
     166           0 :     CloseDescriptor(childSide);
     167           0 :     return false;
     168             :   }
     169           0 :   return true;
     170             : }
     171             : 
     172             : bool
     173           0 : UnpackChannelOpened(const PrivateIPDLInterface&,
     174             :                     const Message& aMsg,
     175             :                     TransportDescriptor* aTransport,
     176             :                     ProcessId* aOtherProcess,
     177             :                     ProtocolId* aProtocol)
     178             : {
     179           0 :   return ChannelOpened::Read(aMsg, aTransport, aOtherProcess, aProtocol);
     180             : }
     181             : 
     182             : #if defined(XP_WIN)
     183             : bool DuplicateHandle(HANDLE aSourceHandle,
     184             :                      DWORD aTargetProcessId,
     185             :                      HANDLE* aTargetHandle,
     186             :                      DWORD aDesiredAccess,
     187             :                      DWORD aOptions) {
     188             :   // If our process is the target just duplicate the handle.
     189             :   if (aTargetProcessId == base::GetCurrentProcId()) {
     190             :     return !!::DuplicateHandle(::GetCurrentProcess(), aSourceHandle,
     191             :                                ::GetCurrentProcess(), aTargetHandle,
     192             :                                aDesiredAccess, false, aOptions);
     193             : 
     194             :   }
     195             : 
     196             : #if defined(MOZ_SANDBOX)
     197             :   // Try the broker next (will fail if not sandboxed).
     198             :   if (SandboxTarget::Instance()->BrokerDuplicateHandle(aSourceHandle,
     199             :                                                        aTargetProcessId,
     200             :                                                        aTargetHandle,
     201             :                                                        aDesiredAccess,
     202             :                                                        aOptions)) {
     203             :     return true;
     204             :   }
     205             : #endif
     206             : 
     207             :   // Finally, see if we already have access to the process.
     208             :   ScopedProcessHandle targetProcess(OpenProcess(PROCESS_DUP_HANDLE,
     209             :                                                 FALSE,
     210             :                                                 aTargetProcessId));
     211             :   if (!targetProcess) {
     212             : #ifdef MOZ_CRASHREPORTER
     213             :     CrashReporter::AnnotateCrashReport(
     214             :       NS_LITERAL_CSTRING("IPCTransportFailureReason"),
     215             :       NS_LITERAL_CSTRING("Failed to open target process."));
     216             : #endif
     217             :     return false;
     218             :   }
     219             : 
     220             :   return !!::DuplicateHandle(::GetCurrentProcess(), aSourceHandle,
     221             :                               targetProcess, aTargetHandle,
     222             :                               aDesiredAccess, FALSE, aOptions);
     223             : }
     224             : #endif
     225             : 
     226             : #ifdef MOZ_CRASHREPORTER
     227             : void
     228           0 : AnnotateSystemError()
     229             : {
     230           0 :   int64_t error = 0;
     231             : #if defined(XP_WIN)
     232             :   error = ::GetLastError();
     233             : #elif defined(OS_POSIX)
     234           0 :   error = errno;
     235             : #endif
     236           0 :   if (error) {
     237           0 :     CrashReporter::AnnotateCrashReport(
     238           0 :       NS_LITERAL_CSTRING("IPCSystemError"),
     239           0 :       nsPrintfCString("%" PRId64, error));
     240             :   }
     241           0 : }
     242             : #endif
     243             : 
     244             : #if defined(MOZ_CRASHREPORTER) && defined(XP_MACOSX)
     245             : void
     246             : AnnotateCrashReportWithErrno(const char* tag, int error)
     247             : {
     248             :   CrashReporter::AnnotateCrashReport(
     249             :     nsCString(tag),
     250             :     nsPrintfCString("%d", error));
     251             : }
     252             : #endif
     253             : 
     254             : void
     255           0 : LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid,
     256             :                       const char* aContextDescription,
     257             :                       uint32_t aMessageId,
     258             :                       MessageDirection aDirection)
     259             : {
     260             :   nsPrintfCString logMessage("[time: %" PRId64 "][%d%s%d] [%s] %s %s\n",
     261             :                              PR_Now(), base::GetCurrentProcId(),
     262             :                              aDirection == MessageDirection::eReceiving ? "<-" : "->",
     263             :                              aOtherPid, aTopLevelProtocol,
     264             :                              aContextDescription,
     265           0 :                              StringFromIPCMessageType(aMessageId));
     266             : #ifdef ANDROID
     267             :   __android_log_write(ANDROID_LOG_INFO, "GeckoIPC", logMessage.get());
     268             : #endif
     269           0 :   fputs(logMessage.get(), stderr);
     270           0 : }
     271             : 
     272             : void
     273           0 : ProtocolErrorBreakpoint(const char* aMsg)
     274             : {
     275             :     // Bugs that generate these error messages can be tough to
     276             :     // reproduce.  Log always in the hope that someone finds the error
     277             :     // message.
     278           0 :     printf_stderr("IPDL protocol error: %s\n", aMsg);
     279           0 : }
     280             : 
     281             : void
     282           0 : FatalError(const char* aProtocolName, const char* aMsg, bool aIsParent)
     283             : {
     284           0 :   ProtocolErrorBreakpoint(aMsg);
     285             : 
     286           0 :   nsAutoCString formattedMessage("IPDL error [");
     287           0 :   formattedMessage.AppendASCII(aProtocolName);
     288           0 :   formattedMessage.AppendLiteral("]: \"");
     289           0 :   formattedMessage.AppendASCII(aMsg);
     290           0 :   if (aIsParent) {
     291             : #ifdef MOZ_CRASHREPORTER
     292             :     // We're going to crash the parent process because at this time
     293             :     // there's no other really nice way of getting a minidump out of
     294             :     // this process if we're off the main thread.
     295           0 :     formattedMessage.AppendLiteral("\". Intentionally crashing.");
     296           0 :     NS_ERROR(formattedMessage.get());
     297           0 :     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorProtocol"),
     298           0 :                                        nsDependentCString(aProtocolName));
     299           0 :     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorMsg"),
     300           0 :                                        nsDependentCString(aMsg));
     301           0 :     AnnotateSystemError();
     302             : #endif
     303           0 :     MOZ_CRASH("IPC FatalError in the parent process!");
     304             :   } else {
     305           0 :     formattedMessage.AppendLiteral("\". abort()ing as a result.");
     306           0 :     NS_RUNTIMEABORT(formattedMessage.get());
     307             :   }
     308           0 : }
     309             : 
     310             : void
     311           0 : LogicError(const char* aMsg)
     312             : {
     313           0 :   NS_RUNTIMEABORT(aMsg);
     314           0 : }
     315             : 
     316             : void
     317           0 : ActorIdReadError(const char* aActorDescription)
     318             : {
     319           0 :   nsPrintfCString message("Error deserializing id for %s", aActorDescription);
     320           0 :   NS_RUNTIMEABORT(message.get());
     321           0 : }
     322             : 
     323             : void
     324           0 : BadActorIdError(const char* aActorDescription)
     325             : {
     326           0 :   nsPrintfCString message("bad id for %s", aActorDescription);
     327           0 :   ProtocolErrorBreakpoint(message.get());
     328           0 : }
     329             : 
     330             : void
     331           0 : ActorLookupError(const char* aActorDescription)
     332             : {
     333           0 :   nsPrintfCString message("could not lookup id for %s", aActorDescription);
     334           0 :   ProtocolErrorBreakpoint(message.get());
     335           0 : }
     336             : 
     337             : void
     338           0 : MismatchedActorTypeError(const char* aActorDescription)
     339             : {
     340             :   nsPrintfCString message("actor that should be of type %s has different type",
     341           0 :                           aActorDescription);
     342           0 :   ProtocolErrorBreakpoint(message.get());
     343           0 : }
     344             : 
     345             : void
     346           0 : UnionTypeReadError(const char* aUnionName)
     347             : {
     348           0 :   nsPrintfCString message("error deserializing type of union %s", aUnionName);
     349           0 :   NS_RUNTIMEABORT(message.get());
     350           0 : }
     351             : 
     352             : void
     353           0 : ArrayLengthReadError(const char* aElementName)
     354             : {
     355           0 :   nsPrintfCString message("error deserializing length of %s[]", aElementName);
     356           0 :   NS_RUNTIMEABORT(message.get());
     357           0 : }
     358             : 
     359             : void
     360           0 : SentinelReadError(const char* aClassName)
     361             : {
     362           0 :   nsPrintfCString message("incorrect sentinel when reading %s", aClassName);
     363           0 :   NS_RUNTIMEABORT(message.get());
     364           0 : }
     365             : 
     366             : void
     367           0 : TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
     368             :              nsTArray<void*>& aArray)
     369             : {
     370           0 :   uint32_t i = 0;
     371           0 :   void** elements = aArray.AppendElements(aTable.Count());
     372           0 :   for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
     373           0 :     elements[i] = iter.Get()->GetKey();
     374           0 :     ++i;
     375             :   }
     376           0 : }
     377             : 
     378             : Maybe<IProtocol*>
     379          53 : IProtocol::ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
     380             :                      const char* aActorDescription, int32_t aProtocolTypeId)
     381             : {
     382             :     int32_t id;
     383          53 :     if (!IPC::ReadParam(aMessage, aIter, &id)) {
     384           0 :         ActorIdReadError(aActorDescription);
     385           0 :         return Nothing();
     386             :     }
     387             : 
     388          53 :     if (id == 1 || (id == 0 && !aNullable)) {
     389           0 :         BadActorIdError(aActorDescription);
     390           0 :         return Nothing();
     391             :     }
     392             : 
     393          53 :     if (id == 0) {
     394           0 :         return Some(static_cast<IProtocol*>(nullptr));
     395             :     }
     396             : 
     397          53 :     IProtocol* listener = this->Lookup(id);
     398          53 :     if (!listener) {
     399           0 :         ActorLookupError(aActorDescription);
     400           0 :         return Nothing();
     401             :     }
     402             : 
     403          53 :     if (listener->GetProtocolTypeId() != aProtocolTypeId) {
     404           0 :         MismatchedActorTypeError(aActorDescription);
     405           0 :         return Nothing();
     406             :     }
     407             : 
     408          53 :     return Some(listener);
     409             : }
     410             : 
     411             : int32_t
     412          17 : IProtocol::Register(IProtocol* aRouted)
     413             : {
     414          17 :   return Manager()->Register(aRouted);
     415             : }
     416             : 
     417             : int32_t
     418          17 : IProtocol::RegisterID(IProtocol* aRouted, int32_t aId)
     419             : {
     420          17 :   return Manager()->RegisterID(aRouted, aId);
     421             : }
     422             : 
     423             : IProtocol*
     424          94 : IProtocol::Lookup(int32_t aId)
     425             : {
     426          94 :   return Manager()->Lookup(aId);
     427             : }
     428             : 
     429             : void
     430          41 : IProtocol::Unregister(int32_t aId)
     431             : {
     432          41 :   if (mId == aId) {
     433          25 :     mId = kFreedActorId;
     434             :   }
     435          41 :   Manager()->Unregister(aId);
     436          41 : }
     437             : 
     438             : Shmem::SharedMemory*
     439           1 : IProtocol::CreateSharedMemory(size_t aSize,
     440             :                               SharedMemory::SharedMemoryType aType,
     441             :                               bool aUnsafe,
     442             :                               int32_t* aId)
     443             : {
     444           1 :   return Manager()->CreateSharedMemory(aSize, aType, aUnsafe, aId);
     445             : }
     446             : 
     447             : Shmem::SharedMemory*
     448           1 : IProtocol::LookupSharedMemory(int32_t aId)
     449             : {
     450           1 :   return Manager()->LookupSharedMemory(aId);
     451             : }
     452             : 
     453             : bool
     454           0 : IProtocol::IsTrackingSharedMemory(Shmem::SharedMemory* aSegment)
     455             : {
     456           0 :   return Manager()->IsTrackingSharedMemory(aSegment);
     457             : }
     458             : 
     459             : bool
     460           0 : IProtocol::DestroySharedMemory(Shmem& aShmem)
     461             : {
     462           0 :   return Manager()->DestroySharedMemory(aShmem);
     463             : }
     464             : 
     465             : ProcessId
     466         137 : IProtocol::OtherPid() const
     467             : {
     468         137 :   return Manager()->OtherPid();
     469             : }
     470             : 
     471             : void
     472           0 : IProtocol::FatalError(const char* const aErrorMsg) const
     473             : {
     474           0 :   HandleFatalError(ProtocolName(), aErrorMsg);
     475           0 : }
     476             : 
     477             : void
     478           0 : IProtocol::HandleFatalError(const char* aProtocolName, const char* aErrorMsg) const
     479             : {
     480           0 :   if (IProtocol* manager = Manager()) {
     481           0 :     manager->HandleFatalError(aProtocolName, aErrorMsg);
     482           0 :     return;
     483             :   }
     484             : 
     485           0 :   mozilla::ipc::FatalError(aProtocolName, aErrorMsg, mSide == ParentSide);
     486             : }
     487             : 
     488             : bool
     489           0 : IProtocol::AllocShmem(size_t aSize,
     490             :                       Shmem::SharedMemory::SharedMemoryType aType,
     491             :                       Shmem* aOutMem)
     492             : {
     493             :   Shmem::id_t id;
     494           0 :   Shmem::SharedMemory* rawmem(CreateSharedMemory(aSize, aType, false, &id));
     495           0 :   if (!rawmem) {
     496           0 :     return false;
     497             :   }
     498             : 
     499           0 :   *aOutMem = Shmem(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem, id);
     500           0 :   return true;
     501             : }
     502             : 
     503             : bool
     504           3 : IProtocol::AllocUnsafeShmem(size_t aSize,
     505             :                             Shmem::SharedMemory::SharedMemoryType aType,
     506             :                             Shmem* aOutMem)
     507             : {
     508             :   Shmem::id_t id;
     509           3 :   Shmem::SharedMemory* rawmem(CreateSharedMemory(aSize, aType, true, &id));
     510           3 :   if (!rawmem) {
     511           0 :     return false;
     512             :   }
     513             : 
     514           3 :   *aOutMem = Shmem(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem, id);
     515           3 :   return true;
     516             : }
     517             : 
     518             : bool
     519           0 : IProtocol::DeallocShmem(Shmem& aMem)
     520             : {
     521           0 :   bool ok = DestroySharedMemory(aMem);
     522             : #ifdef DEBUG
     523           0 :   if (!ok) {
     524           0 :     if (mSide == ChildSide) {
     525           0 :       FatalError("bad Shmem");
     526             :     } else {
     527           0 :       NS_WARNING("bad Shmem");
     528             :     }
     529           0 :     return false;
     530             :   }
     531             : #endif // DEBUG
     532           0 :   aMem.forget(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
     533           0 :   return ok;
     534             : }
     535             : 
     536             : void
     537          80 : IProtocol::SetManager(IProtocol* aManager)
     538             : {
     539          80 :   MOZ_RELEASE_ASSERT(!mManager || mManager == aManager);
     540          80 :   mManager = aManager;
     541          80 : }
     542             : 
     543             : void
     544           9 : IProtocol::SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget)
     545             : {
     546             :   // Make sure we have a manager for the internal method to access.
     547           9 :   aActor->SetManager(this);
     548           9 :   SetEventTargetForActorInternal(aActor, aEventTarget);
     549           9 : }
     550             : 
     551             : void
     552           0 : IProtocol::ReplaceEventTargetForActor(IProtocol* aActor,
     553             :                                       nsIEventTarget* aEventTarget)
     554             : {
     555             :   // Ensure the actor has been registered.
     556           0 :   MOZ_ASSERT(aActor->Manager());
     557           0 :   ReplaceEventTargetForActorInternal(aActor, aEventTarget);
     558           0 : }
     559             : 
     560             : void
     561           7 : IProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
     562             :                                           nsIEventTarget* aEventTarget)
     563             : {
     564           7 :   Manager()->SetEventTargetForActorInternal(aActor, aEventTarget);
     565           7 : }
     566             : 
     567             : void
     568           0 : IProtocol::ReplaceEventTargetForActorInternal(IProtocol* aActor,
     569             :                                               nsIEventTarget* aEventTarget)
     570             : {
     571           0 :   Manager()->ReplaceEventTargetForActorInternal(aActor, aEventTarget);
     572           0 : }
     573             : 
     574             : nsIEventTarget*
     575           5 : IProtocol::GetActorEventTarget()
     576             : {
     577             :   // We should only call this function when this actor has been registered and
     578             :   // is not unregistered yet.
     579           5 :   MOZ_RELEASE_ASSERT(mId != kNullActorId && mId != kFreedActorId);
     580          10 :   RefPtr<nsIEventTarget> target = Manager()->GetActorEventTargetInternal(this);
     581          10 :   return target;
     582             : }
     583             : 
     584             : already_AddRefed<nsIEventTarget>
     585           3 : IProtocol::GetActorEventTargetInternal(IProtocol* aActor)
     586             : {
     587           3 :   return Manager()->GetActorEventTargetInternal(aActor);
     588             : }
     589             : 
     590          40 : IToplevelProtocol::IToplevelProtocol(ProtocolId aProtoId, Side aSide)
     591             :  : IProtocol(aSide),
     592             :    mProtocolId(aProtoId),
     593             :    mOtherPid(mozilla::ipc::kInvalidProcessId),
     594          40 :    mLastRouteId(aSide == ParentSide ? kFreedActorId : kNullActorId),
     595          40 :    mLastShmemId(aSide == ParentSide ? kFreedActorId : kNullActorId),
     596         120 :    mEventTargetMutex("ProtocolEventTargetMutex")
     597             : {
     598          40 : }
     599             : 
     600           0 : IToplevelProtocol::~IToplevelProtocol()
     601             : {
     602           0 :   if (mTrans) {
     603           0 :     RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTrans.release());
     604           0 :     XRE_GetIOMessageLoop()->PostTask(task.forget());
     605             :   }
     606           0 : }
     607             : 
     608             : base::ProcessId
     609         127 : IToplevelProtocol::OtherPid() const
     610             : {
     611         127 :   return mOtherPid;
     612             : }
     613             : 
     614             : void
     615          42 : IToplevelProtocol::SetOtherProcessId(base::ProcessId aOtherPid)
     616             : {
     617          42 :   mOtherPid = aOtherPid;
     618          42 : }
     619             : 
     620             : bool
     621           0 : IToplevelProtocol::TakeMinidump(nsIFile** aDump, uint32_t* aSequence)
     622             : {
     623           0 :   MOZ_RELEASE_ASSERT(GetSide() == ParentSide);
     624             : #ifdef MOZ_CRASHREPORTER
     625           0 :   return XRE_TakeMinidumpForChild(OtherPid(), aDump, aSequence);
     626             : #else
     627             :   return false;
     628             : #endif
     629             : }
     630             : 
     631             : bool
     632          27 : IToplevelProtocol::Open(mozilla::ipc::Transport* aTransport,
     633             :                         base::ProcessId aOtherPid,
     634             :                         MessageLoop* aThread,
     635             :                         mozilla::ipc::Side aSide)
     636             : {
     637          27 :   SetOtherProcessId(aOtherPid);
     638          27 :   return GetIPCChannel()->Open(aTransport, aThread, aSide);
     639             : }
     640             : 
     641             : bool
     642           5 : IToplevelProtocol::Open(MessageChannel* aChannel,
     643             :                         MessageLoop* aMessageLoop,
     644             :                         mozilla::ipc::Side aSide)
     645             : {
     646           5 :   SetOtherProcessId(base::GetCurrentProcId());
     647           5 :   return GetIPCChannel()->Open(aChannel, aMessageLoop, aSide);
     648             : }
     649             : 
     650             : void
     651           0 : IToplevelProtocol::Close()
     652             : {
     653           0 :   GetIPCChannel()->Close();
     654           0 : }
     655             : 
     656             : void
     657           2 : IToplevelProtocol::SetReplyTimeoutMs(int32_t aTimeoutMs)
     658             : {
     659           2 :   GetIPCChannel()->SetReplyTimeoutMs(aTimeoutMs);
     660           2 : }
     661             : 
     662             : bool
     663           0 : IToplevelProtocol::IsOnCxxStack() const
     664             : {
     665           0 :   return GetIPCChannel()->IsOnCxxStack();
     666             : }
     667             : 
     668             : int32_t
     669          47 : IToplevelProtocol::Register(IProtocol* aRouted)
     670             : {
     671          47 :   if (aRouted->Id() != kNullActorId && aRouted->Id() != kFreedActorId) {
     672             :     // If there's already an ID, just return that.
     673           9 :     return aRouted->Id();
     674             :   }
     675          38 :   int32_t id = GetSide() == ParentSide ? ++mLastRouteId : --mLastRouteId;
     676          38 :   mActorMap.AddWithID(aRouted, id);
     677          38 :   aRouted->SetId(id);
     678             : 
     679             :   // Inherit our event target from our manager.
     680          38 :   if (IProtocol* manager = aRouted->Manager()) {
     681          76 :     MutexAutoLock lock(mEventTargetMutex);
     682          76 :     if (nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(manager->Id())) {
     683           0 :       mEventTargetMap.AddWithID(target, id);
     684             :     }
     685             :   }
     686             : 
     687          38 :   return id;
     688             : }
     689             : 
     690             : int32_t
     691          33 : IToplevelProtocol::RegisterID(IProtocol* aRouted,
     692             :                               int32_t aId)
     693             : {
     694          33 :   mActorMap.AddWithID(aRouted, aId);
     695          33 :   aRouted->SetId(aId);
     696          33 :   return aId;
     697             : }
     698             : 
     699             : IProtocol*
     700         391 : IToplevelProtocol::Lookup(int32_t aId)
     701             : {
     702         391 :   return mActorMap.Lookup(aId);
     703             : }
     704             : 
     705             : void
     706          25 : IToplevelProtocol::Unregister(int32_t aId)
     707             : {
     708          25 :   mActorMap.Remove(aId);
     709             : 
     710          50 :   MutexAutoLock lock(mEventTargetMutex);
     711          25 :   mEventTargetMap.RemoveIfPresent(aId);
     712          25 : }
     713             : 
     714             : Shmem::SharedMemory*
     715           3 : IToplevelProtocol::CreateSharedMemory(size_t aSize,
     716             :                                       Shmem::SharedMemory::SharedMemoryType aType,
     717             :                                       bool aUnsafe,
     718             :                                       Shmem::id_t* aId)
     719             : {
     720             :   RefPtr<Shmem::SharedMemory> segment(
     721           6 :     Shmem::Alloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), aSize, aType, aUnsafe));
     722           3 :   if (!segment) {
     723           0 :     return nullptr;
     724             :   }
     725           3 :   int32_t id = GetSide() == ParentSide ? ++mLastShmemId : --mLastShmemId;
     726             :   Shmem shmem(
     727           3 :     Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(),
     728             :     segment.get(),
     729           6 :     id);
     730           3 :   Message* descriptor = shmem.ShareTo(
     731           6 :     Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), OtherPid(), MSG_ROUTING_CONTROL);
     732           3 :   if (!descriptor) {
     733           0 :     return nullptr;
     734             :   }
     735           3 :   Unused << GetIPCChannel()->Send(descriptor);
     736             : 
     737           3 :   *aId = shmem.Id(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
     738           3 :   Shmem::SharedMemory* rawSegment = segment.get();
     739           3 :   mShmemMap.AddWithID(segment.forget().take(), *aId);
     740           3 :   return rawSegment;
     741             : }
     742             : 
     743             : Shmem::SharedMemory*
     744           2 : IToplevelProtocol::LookupSharedMemory(Shmem::id_t aId)
     745             : {
     746           2 :   return mShmemMap.Lookup(aId);
     747             : }
     748             : 
     749             : bool
     750           0 : IToplevelProtocol::IsTrackingSharedMemory(Shmem::SharedMemory* segment)
     751             : {
     752           0 :   return mShmemMap.HasData(segment);
     753             : }
     754             : 
     755             : bool
     756           0 : IToplevelProtocol::DestroySharedMemory(Shmem& shmem)
     757             : {
     758           0 :   Shmem::id_t aId = shmem.Id(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
     759           0 :   Shmem::SharedMemory* segment = LookupSharedMemory(aId);
     760           0 :   if (!segment) {
     761           0 :     return false;
     762             :   }
     763             : 
     764           0 :   Message* descriptor = shmem.UnshareFrom(
     765           0 :     Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), OtherPid(), MSG_ROUTING_CONTROL);
     766             : 
     767           0 :   mShmemMap.Remove(aId);
     768           0 :   Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), segment);
     769             : 
     770           0 :   if (!GetIPCChannel()->CanSend()) {
     771           0 :     delete descriptor;
     772           0 :     return true;
     773             :   }
     774             : 
     775           0 :   return descriptor && GetIPCChannel()->Send(descriptor);
     776             : }
     777             : 
     778             : void
     779           0 : IToplevelProtocol::DeallocShmems()
     780             : {
     781           0 :   for (IDMap<SharedMemory*>::const_iterator cit = mShmemMap.begin(); cit != mShmemMap.end(); ++cit) {
     782           0 :     Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), cit->second);
     783             :   }
     784           0 :   mShmemMap.Clear();
     785           0 : }
     786             : 
     787             : bool
     788           2 : IToplevelProtocol::ShmemCreated(const Message& aMsg)
     789             : {
     790             :   Shmem::id_t id;
     791           4 :   RefPtr<Shmem::SharedMemory> rawmem(Shmem::OpenExisting(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), aMsg, &id, true));
     792           2 :   if (!rawmem) {
     793           0 :     return false;
     794             :   }
     795           2 :   mShmemMap.AddWithID(rawmem.forget().take(), id);
     796           2 :   return true;
     797             : }
     798             : 
     799             : bool
     800           0 : IToplevelProtocol::ShmemDestroyed(const Message& aMsg)
     801             : {
     802             :   Shmem::id_t id;
     803           0 :   PickleIterator iter = PickleIterator(aMsg);
     804           0 :   if (!IPC::ReadParam(&aMsg, &iter, &id)) {
     805           0 :     return false;
     806             :   }
     807           0 :   aMsg.EndRead(iter);
     808             : 
     809           0 :   Shmem::SharedMemory* rawmem = LookupSharedMemory(id);
     810           0 :   if (rawmem) {
     811           0 :     mShmemMap.Remove(id);
     812           0 :     Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem);
     813             :   }
     814           0 :   return true;
     815             : }
     816             : 
     817             : already_AddRefed<nsIEventTarget>
     818         473 : IToplevelProtocol::GetMessageEventTarget(const Message& aMsg)
     819             : {
     820         473 :   if (IsMainThreadProtocol() && SystemGroup::Initialized()) {
     821         588 :     if (aMsg.type() == SHMEM_CREATED_MESSAGE_TYPE ||
     822         293 :         aMsg.type() == SHMEM_DESTROYED_MESSAGE_TYPE) {
     823           2 :       return do_AddRef(SystemGroup::EventTargetFor(TaskCategory::Other));
     824             :     }
     825             :   }
     826             : 
     827         471 :   int32_t route = aMsg.routing_id();
     828             : 
     829         942 :   Maybe<MutexAutoLock> lock;
     830         471 :   lock.emplace(mEventTargetMutex);
     831             : 
     832         942 :   nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(route);
     833             : 
     834         471 :   if (aMsg.is_constructor()) {
     835             :     ActorHandle handle;
     836          34 :     PickleIterator iter = PickleIterator(aMsg);
     837          34 :     if (!IPC::ReadParam(&aMsg, &iter, &handle)) {
     838           0 :       return nullptr;
     839             :     }
     840             : 
     841             :     // Normally a new actor inherits its event target from its manager. If the
     842             :     // manager has no event target, we give the subclass a chance to make a new
     843             :     // one.
     844          34 :     if (!target) {
     845          66 :       MutexAutoUnlock unlock(mEventTargetMutex);
     846          33 :       target = GetConstructedEventTarget(aMsg);
     847             :     }
     848             : 
     849          34 :     mEventTargetMap.AddWithID(target, handle.mId);
     850         437 :   } else if (!target) {
     851             :     // We don't need the lock after this point.
     852         392 :     lock.reset();
     853             : 
     854         392 :     target = GetSpecificMessageEventTarget(aMsg);
     855             :   }
     856             : 
     857         471 :   return target.forget();
     858             : }
     859             : 
     860             : already_AddRefed<nsIEventTarget>
     861           6 : IToplevelProtocol::GetActorEventTargetInternal(IProtocol* aActor)
     862             : {
     863           6 :   MOZ_RELEASE_ASSERT(aActor->Id() != kNullActorId && aActor->Id() != kFreedActorId);
     864             : 
     865          12 :   MutexAutoLock lock(mEventTargetMutex);
     866          12 :   nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(aActor->Id());
     867          12 :   return target.forget();
     868             : }
     869             : 
     870             : already_AddRefed<nsIEventTarget>
     871           1 : IToplevelProtocol::GetActorEventTarget(IProtocol* aActor)
     872             : {
     873           1 :   return GetActorEventTargetInternal(aActor);
     874             : }
     875             : 
     876             : nsIEventTarget*
     877           0 : IToplevelProtocol::GetActorEventTarget()
     878             : {
     879             :   // The EventTarget of a ToplevelProtocol shall never be set.
     880           0 :   return nullptr;
     881             : }
     882             : 
     883             : void
     884           9 : IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
     885             :                                                   nsIEventTarget* aEventTarget)
     886             : {
     887             :   // The EventTarget of a ToplevelProtocol shall never be set.
     888           9 :   MOZ_RELEASE_ASSERT(aActor != this);
     889             : 
     890             :   // We should only call this function on actors that haven't been used for IPC
     891             :   // code yet. Otherwise we'll be posting stuff to the wrong event target before
     892             :   // we're called.
     893           9 :   MOZ_RELEASE_ASSERT(aActor->Id() == kNullActorId || aActor->Id() == kFreedActorId);
     894             : 
     895             :   // Register the actor early. When it's registered again, it will keep the same
     896             :   // ID.
     897           9 :   int32_t id = Register(aActor);
     898           9 :   aActor->SetId(id);
     899             : 
     900          18 :   MutexAutoLock lock(mEventTargetMutex);
     901           9 :   mEventTargetMap.AddWithID(aEventTarget, id);
     902           9 : }
     903             : 
     904             : void
     905           0 : IToplevelProtocol::ReplaceEventTargetForActorInternal(
     906             :   IProtocol* aActor,
     907             :   nsIEventTarget* aEventTarget)
     908             : {
     909             :   // The EventTarget of a ToplevelProtocol shall never be set.
     910           0 :   MOZ_RELEASE_ASSERT(aActor != this);
     911             : 
     912           0 :   int32_t id = aActor->Id();
     913             :   // The ID of the actor should have existed.
     914           0 :   MOZ_RELEASE_ASSERT(id!= kNullActorId && id!= kFreedActorId);
     915             : 
     916           0 :   MutexAutoLock lock(mEventTargetMutex);
     917           0 :   mEventTargetMap.ReplaceWithID(aEventTarget, id);
     918           0 : }
     919             : 
     920             : } // namespace ipc
     921             : } // namespace mozilla

Generated by: LCOV version 1.13