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

Generated by: LCOV version 1.13-14-ga5dd952