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/. */
7 #include "base/process_util.h"
13 #include <type_traits>
15 #include "mozilla/IntegerPrintfMacros.h"
17 #include "mozilla/ipc/ProtocolMessageUtils.h"
18 #include "mozilla/ipc/ProtocolUtils.h"
20 #include "mozilla/ipc/MessageChannel.h"
21 #include "mozilla/ipc/IPDLParamTraits.h"
22 #include "mozilla/StaticMutex.h"
23 #if defined(DEBUG) || defined(FUZZING)
24 # include "mozilla/Tokenizer.h"
26 #include "mozilla/Unused.h"
27 #include "nsPrintfCString.h"
29 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
30 # include "mozilla/sandboxTarget.h"
38 #ifdef FUZZING_SNAPSHOT
39 # include "mozilla/fuzzing/IPCFuzzController.h"
44 using base::GetCurrentProcId
;
45 using base::ProcessHandle
;
46 using base::ProcessId
;
51 // Generate RAII classes for LPTSTR and PSECURITY_DESCRIPTOR.
52 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedLPTStr
,
53 std::remove_pointer_t
<LPTSTR
>,
55 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(
56 ScopedPSecurityDescriptor
, std::remove_pointer_t
<PSECURITY_DESCRIPTOR
>,
62 IPCResult
IPCResult::Fail(NotNull
<IProtocol
*> actor
, const char* where
,
64 // Calls top-level protocol to handle the error.
65 nsPrintfCString
errorMsg("%s %s\n", where
, why
);
66 actor
->GetIPCChannel()->Listener()->ProcessingError(
67 HasResultCodes::MsgProcessingError
, errorMsg
.get());
69 MOZ_ASSERT_UNLESS_FUZZING(false,
70 "Please ensure to IPC_FAIL only when in an "
71 "unrecoverable, unexpected state.");
73 return IPCResult(false);
76 void AnnotateSystemError() {
79 error
= ::GetLastError();
80 #elif defined(OS_POSIX)
84 CrashReporter::AnnotateCrashReport(
85 CrashReporter::Annotation::IPCSystemError
,
86 nsPrintfCString("%" PRId64
, error
));
90 #if defined(XP_MACOSX)
91 void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag
, int error
) {
92 CrashReporter::AnnotateCrashReport(tag
, error
);
94 #endif // defined(XP_MACOSX)
96 #if defined(DEBUG) || defined(FUZZING)
97 // This overload is for testability; application code should use the single-
98 // argument version (defined in the ProtocolUtils.h) which takes the filter from
100 bool LoggingEnabledFor(const char* aTopLevelProtocol
, const char* aFilter
) {
104 if (strcmp(aFilter
, "1") == 0) {
108 const char kDelimiters
[] = ", ";
109 Tokenizer
tokens(aFilter
, kDelimiters
);
111 while (tokens
.Next(t
)) {
112 if (t
.Type() == Tokenizer::TOKEN_WORD
&&
113 t
.AsString() == aTopLevelProtocol
) {
120 #endif // defined(DEBUG) || defined(FUZZING)
122 void LogMessageForProtocol(const char* aTopLevelProtocol
,
123 base::ProcessId aOtherPid
,
124 const char* aContextDescription
, uint32_t aMessageId
,
125 MessageDirection aDirection
) {
126 nsPrintfCString
logMessage(
127 "[time: %" PRId64
"][%" PRIPID
"%s%" PRIPID
"] [%s] %s %s\n", PR_Now(),
128 base::GetCurrentProcId(),
129 aDirection
== MessageDirection::eReceiving
? "<-" : "->", aOtherPid
,
130 aTopLevelProtocol
, aContextDescription
,
131 StringFromIPCMessageType(aMessageId
));
133 __android_log_write(ANDROID_LOG_INFO
, "GeckoIPC", logMessage
.get());
135 fputs(logMessage
.get(), stderr
);
138 void ProtocolErrorBreakpoint(const char* aMsg
) {
139 // Bugs that generate these error messages can be tough to
140 // reproduce. Log always in the hope that someone finds the error
142 printf_stderr("IPDL protocol error: %s\n", aMsg
);
145 void PickleFatalError(const char* aMsg
, IProtocol
* aActor
) {
147 aActor
->FatalError(aMsg
);
149 FatalError(aMsg
, false);
153 void FatalError(const char* aMsg
, bool aIsParent
) {
155 ProtocolErrorBreakpoint(aMsg
);
158 nsAutoCString
formattedMessage("IPDL error: \"");
159 formattedMessage
.AppendASCII(aMsg
);
161 // We're going to crash the parent process because at this time
162 // there's no other really nice way of getting a minidump out of
163 // this process if we're off the main thread.
164 formattedMessage
.AppendLiteral("\". Intentionally crashing.");
165 NS_ERROR(formattedMessage
.get());
166 CrashReporter::AnnotateCrashReport(
167 CrashReporter::Annotation::IPCFatalErrorMsg
, nsDependentCString(aMsg
));
168 AnnotateSystemError();
170 MOZ_CRASH("IPC FatalError in the parent process!");
173 formattedMessage
.AppendLiteral("\". abort()ing as a result.");
175 MOZ_CRASH_UNSAFE(formattedMessage
.get());
180 void LogicError(const char* aMsg
) { MOZ_CRASH_UNSAFE(aMsg
); }
182 void ActorIdReadError(const char* aActorDescription
) {
184 MOZ_CRASH_UNSAFE_PRINTF("Error deserializing id for %s", aActorDescription
);
188 void BadActorIdError(const char* aActorDescription
) {
189 nsPrintfCString
message("bad id for %s", aActorDescription
);
190 ProtocolErrorBreakpoint(message
.get());
193 void ActorLookupError(const char* aActorDescription
) {
194 nsPrintfCString
message("could not lookup id for %s", aActorDescription
);
195 ProtocolErrorBreakpoint(message
.get());
198 void MismatchedActorTypeError(const char* aActorDescription
) {
199 nsPrintfCString
message("actor that should be of type %s has different type",
201 ProtocolErrorBreakpoint(message
.get());
204 void UnionTypeReadError(const char* aUnionName
) {
205 MOZ_CRASH_UNSAFE_PRINTF("error deserializing type of union %s", aUnionName
);
208 void ArrayLengthReadError(const char* aElementName
) {
209 MOZ_CRASH_UNSAFE_PRINTF("error deserializing length of %s[]", aElementName
);
212 void SentinelReadError(const char* aClassName
) {
213 MOZ_CRASH_UNSAFE_PRINTF("incorrect sentinel when reading %s", aClassName
);
216 ActorLifecycleProxy::ActorLifecycleProxy(IProtocol
* aActor
) : mActor(aActor
) {
218 MOZ_ASSERT(mActor
->CanSend(),
219 "Cannot create LifecycleProxy for non-connected actor!");
221 // Take a reference to our manager's lifecycle proxy to try to hold it &
222 // ensure it doesn't die before us.
223 if (mActor
->mManager
) {
224 mManager
= mActor
->mManager
->mLifecycleProxy
;
227 // Record that we've taken our first reference to our actor.
228 mActor
->ActorAlloc();
231 WeakActorLifecycleProxy
* ActorLifecycleProxy::GetWeakProxy() {
233 mWeakProxy
= new WeakActorLifecycleProxy(this);
238 ActorLifecycleProxy::~ActorLifecycleProxy() {
240 mWeakProxy
->mProxy
= nullptr;
241 mWeakProxy
= nullptr;
244 // When the LifecycleProxy's lifetime has come to an end, it means that the
245 // actor should have its `Dealloc` method called on it. In a well-behaved
246 // actor, this will release the IPC-held reference to the actor.
248 // If the actor has already died before the `LifecycleProxy`, the `IProtocol`
249 // destructor below will clear our reference to it, preventing us from
250 // performing a use-after-free here.
255 // Clear our actor's state back to inactive, and then invoke ActorDealloc.
256 MOZ_ASSERT(mActor
->mLinkStatus
== LinkStatus::Destroyed
,
257 "Deallocating non-destroyed actor!");
258 mActor
->mLifecycleProxy
= nullptr;
259 mActor
->mLinkStatus
= LinkStatus::Inactive
;
260 mActor
->ActorDealloc();
264 WeakActorLifecycleProxy::WeakActorLifecycleProxy(ActorLifecycleProxy
* aProxy
)
265 : mProxy(aProxy
), mActorEventTarget(GetCurrentSerialEventTarget()) {}
267 WeakActorLifecycleProxy::~WeakActorLifecycleProxy() {
268 MOZ_DIAGNOSTIC_ASSERT(!mProxy
, "Destroyed before mProxy was cleared?");
271 IProtocol
* WeakActorLifecycleProxy::Get() const {
272 MOZ_DIAGNOSTIC_ASSERT(mActorEventTarget
->IsOnCurrentThread());
273 return mProxy
? mProxy
->Get() : nullptr;
276 WeakActorLifecycleProxy
* IProtocol::GetWeakLifecycleProxy() {
277 return mLifecycleProxy
? mLifecycleProxy
->GetWeakProxy() : nullptr;
280 IProtocol::~IProtocol() {
281 // If the actor still has a lifecycle proxy when it is being torn down, it
282 // means that IPC was not given control over the lifecycle of the actor
283 // correctly. Usually this means that the actor was destroyed while IPC is
284 // calling a message handler for it, and the actor incorrectly frees itself
285 // during that operation.
287 // As this happens unfortunately frequently, due to many odd protocols in
288 // Gecko, simply emit a warning and clear the weak backreference from our
289 // LifecycleProxy back to us.
290 if (mLifecycleProxy
) {
292 nsPrintfCString("Actor destructor for '%s%s' called before IPC "
293 "lifecycle complete!\n"
294 "References to this actor may unexpectedly dangle!",
296 GetSide() == ChildSide
? "Child" : "Parent")
299 mLifecycleProxy
->mActor
= nullptr;
301 // If we are somehow being destroyed while active, make sure that the
302 // existing IPC reference has been freed. If the status of the actor is
303 // `Destroyed`, the reference has already been freed, and we shouldn't free
305 MOZ_ASSERT(mLinkStatus
!= LinkStatus::Inactive
);
306 if (mLinkStatus
!= LinkStatus::Destroyed
) {
307 NS_IF_RELEASE(mLifecycleProxy
);
309 mLifecycleProxy
= nullptr;
313 // The following methods either directly forward to the toplevel protocol, or
314 // almost directly do.
315 int32_t IProtocol::Register(IProtocol
* aRouted
) {
316 return mToplevel
->Register(aRouted
);
318 int32_t IProtocol::RegisterID(IProtocol
* aRouted
, int32_t aId
) {
319 return mToplevel
->RegisterID(aRouted
, aId
);
321 IProtocol
* IProtocol::Lookup(int32_t aId
) { return mToplevel
->Lookup(aId
); }
322 void IProtocol::Unregister(int32_t aId
) {
326 return mToplevel
->Unregister(aId
);
329 Shmem::SharedMemory
* IProtocol::CreateSharedMemory(size_t aSize
, bool aUnsafe
,
331 return mToplevel
->CreateSharedMemory(aSize
, aUnsafe
, aId
);
333 Shmem::SharedMemory
* IProtocol::LookupSharedMemory(int32_t aId
) {
334 return mToplevel
->LookupSharedMemory(aId
);
336 bool IProtocol::IsTrackingSharedMemory(Shmem::SharedMemory
* aSegment
) {
337 return mToplevel
->IsTrackingSharedMemory(aSegment
);
339 bool IProtocol::DestroySharedMemory(Shmem
& aShmem
) {
340 return mToplevel
->DestroySharedMemory(aShmem
);
343 MessageChannel
* IProtocol::GetIPCChannel() {
344 return mToplevel
->GetIPCChannel();
346 const MessageChannel
* IProtocol::GetIPCChannel() const {
347 return mToplevel
->GetIPCChannel();
350 nsISerialEventTarget
* IProtocol::GetActorEventTarget() {
351 return GetIPCChannel()->GetWorkerEventTarget();
354 void IProtocol::SetId(int32_t aId
) {
355 MOZ_ASSERT(mId
== aId
|| mLinkStatus
== LinkStatus::Inactive
);
359 Maybe
<IProtocol
*> IProtocol::ReadActor(IPC::MessageReader
* aReader
,
361 const char* aActorDescription
,
362 int32_t aProtocolTypeId
) {
364 if (!IPC::ReadParam(aReader
, &id
)) {
365 ActorIdReadError(aActorDescription
);
369 if (id
== 1 || (id
== 0 && !aNullable
)) {
370 BadActorIdError(aActorDescription
);
375 return Some(static_cast<IProtocol
*>(nullptr));
378 IProtocol
* listener
= this->Lookup(id
);
380 ActorLookupError(aActorDescription
);
384 if (listener
->GetProtocolId() != aProtocolTypeId
) {
385 MismatchedActorTypeError(aActorDescription
);
389 return Some(listener
);
392 void IProtocol::FatalError(const char* const aErrorMsg
) const {
393 HandleFatalError(aErrorMsg
);
396 void IProtocol::HandleFatalError(const char* aErrorMsg
) const {
397 if (IProtocol
* manager
= Manager()) {
398 manager
->HandleFatalError(aErrorMsg
);
402 mozilla::ipc::FatalError(aErrorMsg
, mSide
== ParentSide
);
405 bool IProtocol::AllocShmem(size_t aSize
, Shmem
* aOutMem
) {
408 "Shmem not allocated. Cannot communicate with the other actor.");
413 Shmem::SharedMemory
* rawmem(CreateSharedMemory(aSize
, false, &id
));
418 *aOutMem
= Shmem(rawmem
, id
);
422 bool IProtocol::AllocUnsafeShmem(size_t aSize
, Shmem
* aOutMem
) {
425 "Shmem not allocated. Cannot communicate with the other actor.");
430 Shmem::SharedMemory
* rawmem(CreateSharedMemory(aSize
, true, &id
));
435 *aOutMem
= Shmem(rawmem
, id
);
439 bool IProtocol::DeallocShmem(Shmem
& aMem
) {
440 bool ok
= DestroySharedMemory(aMem
);
443 if (mSide
== ChildSide
) {
444 FatalError("bad Shmem");
446 NS_WARNING("bad Shmem");
455 void IProtocol::SetManager(IProtocol
* aManager
) {
456 MOZ_RELEASE_ASSERT(!mManager
|| mManager
== aManager
);
458 mToplevel
= aManager
->mToplevel
;
461 void IProtocol::SetManagerAndRegister(IProtocol
* aManager
) {
462 // Set the manager prior to registering so registering properly inherits
463 // the manager's event target.
464 SetManager(aManager
);
466 aManager
->Register(this);
469 void IProtocol::SetManagerAndRegister(IProtocol
* aManager
, int32_t aId
) {
470 // Set the manager prior to registering so registering properly inherits
471 // the manager's event target.
472 SetManager(aManager
);
474 aManager
->RegisterID(this, aId
);
477 bool IProtocol::ChannelSend(UniquePtr
<IPC::Message
> aMsg
) {
479 // NOTE: This send call failing can only occur during toplevel channel
480 // teardown. As this is an async call, this isn't reasonable to predict or
481 // respond to, so just drop the message on the floor silently.
482 GetIPCChannel()->Send(std::move(aMsg
));
486 WarnMessageDiscarded(aMsg
.get());
490 bool IProtocol::ChannelSend(UniquePtr
<IPC::Message
> aMsg
,
491 UniquePtr
<IPC::Message
>* aReply
) {
493 return GetIPCChannel()->Send(std::move(aMsg
), aReply
);
496 WarnMessageDiscarded(aMsg
.get());
501 void IProtocol::WarnMessageDiscarded(IPC::Message
* aMsg
) {
502 NS_WARNING(nsPrintfCString("IPC message '%s' discarded: actor cannot send",
508 void IProtocol::ActorConnected() {
509 if (mLinkStatus
!= LinkStatus::Inactive
) {
513 #ifdef FUZZING_SNAPSHOT
514 fuzzing::IPCFuzzController::instance().OnActorConnected(this);
517 mLinkStatus
= LinkStatus::Connected
;
519 MOZ_ASSERT(!mLifecycleProxy
, "double-connecting live actor");
520 mLifecycleProxy
= new ActorLifecycleProxy(this);
521 NS_ADDREF(mLifecycleProxy
); // Reference freed in DestroySubtree();
524 void IProtocol::DoomSubtree() {
525 MOZ_ASSERT(CanSend(), "dooming non-connected actor");
526 MOZ_ASSERT(mLifecycleProxy
, "dooming zombie actor");
528 nsTArray
<RefPtr
<ActorLifecycleProxy
>> managed
;
529 AllManagedActors(managed
);
530 for (ActorLifecycleProxy
* proxy
: managed
) {
531 // Guard against actor being disconnected or destroyed during previous Doom
532 IProtocol
* actor
= proxy
->Get();
533 if (actor
&& actor
->CanSend()) {
534 actor
->DoomSubtree();
538 // ActorDoom is called immediately before changing state, this allows messages
539 // to be sent during ActorDoom immediately before the channel is closed and
540 // sending messages is disabled.
542 mLinkStatus
= LinkStatus::Doomed
;
545 void IProtocol::DestroySubtree(ActorDestroyReason aWhy
) {
546 MOZ_ASSERT(CanRecv(), "destroying non-connected actor");
547 MOZ_ASSERT(mLifecycleProxy
, "destroying zombie actor");
549 #ifdef FUZZING_SNAPSHOT
550 fuzzing::IPCFuzzController::instance().OnActorDestroyed(this);
555 // If we're a managed actor, unregister from our manager
561 ActorDestroyReason subtreeWhy
= aWhy
;
562 if (aWhy
== Deletion
|| aWhy
== FailedConstructor
) {
563 subtreeWhy
= AncestorDeletion
;
566 nsTArray
<RefPtr
<ActorLifecycleProxy
>> managed
;
567 AllManagedActors(managed
);
568 for (ActorLifecycleProxy
* proxy
: managed
) {
569 // Guard against actor being disconnected or destroyed during previous
571 IProtocol
* actor
= proxy
->Get();
572 if (actor
&& actor
->CanRecv()) {
573 actor
->DestroySubtree(subtreeWhy
);
577 // Ensure that we don't send any messages while we're calling `ActorDestroy`
578 // by setting our state to `Doomed`.
579 mLinkStatus
= LinkStatus::Doomed
;
581 // The actor is being destroyed, reject any pending responses, invoke
582 // `ActorDestroy` to destroy it, and then clear our status to
583 // `LinkStatus::Destroyed`.
584 GetIPCChannel()->RejectPendingResponsesForActor(id
);
586 mLinkStatus
= LinkStatus::Destroyed
;
589 IToplevelProtocol::IToplevelProtocol(const char* aName
, ProtocolId aProtoId
,
591 : IProtocol(aProtoId
, aSide
),
592 mOtherPid(base::kInvalidProcessId
),
594 mChannel(aName
, this) {
598 void IToplevelProtocol::SetOtherProcessId(base::ProcessId aOtherPid
) {
599 mOtherPid
= aOtherPid
;
602 bool IToplevelProtocol::Open(ScopedPort aPort
, const nsID
& aMessageChannelId
,
603 base::ProcessId aOtherPid
,
604 nsISerialEventTarget
* aEventTarget
) {
605 SetOtherProcessId(aOtherPid
);
606 return GetIPCChannel()->Open(std::move(aPort
), mSide
, aMessageChannelId
,
610 bool IToplevelProtocol::Open(IToplevelProtocol
* aTarget
,
611 nsISerialEventTarget
* aEventTarget
,
612 mozilla::ipc::Side aSide
) {
613 SetOtherProcessId(base::GetCurrentProcId());
614 aTarget
->SetOtherProcessId(base::GetCurrentProcId());
615 return GetIPCChannel()->Open(aTarget
->GetIPCChannel(), aEventTarget
, aSide
);
618 bool IToplevelProtocol::OpenOnSameThread(IToplevelProtocol
* aTarget
,
620 SetOtherProcessId(base::GetCurrentProcId());
621 aTarget
->SetOtherProcessId(base::GetCurrentProcId());
622 return GetIPCChannel()->OpenOnSameThread(aTarget
->GetIPCChannel(), aSide
);
625 void IToplevelProtocol::NotifyImpendingShutdown() {
627 GetIPCChannel()->NotifyImpendingShutdown();
631 void IToplevelProtocol::Close() { GetIPCChannel()->Close(); }
633 void IToplevelProtocol::SetReplyTimeoutMs(int32_t aTimeoutMs
) {
634 GetIPCChannel()->SetReplyTimeoutMs(aTimeoutMs
);
637 bool IToplevelProtocol::IsOnCxxStack() const {
638 return GetIPCChannel()->IsOnCxxStack();
641 int32_t IToplevelProtocol::NextId() {
642 // Generate the next ID to use for a shared memory or protocol. Parent and
643 // Child sides of the protocol use different pools.
645 if (GetSide() == ParentSide
) {
649 // Check any overflow
650 MOZ_RELEASE_ASSERT(mLastLocalId
< (1 << 29));
652 // Compute the ID to use with the low two bits as our tag, and the remaining
653 // bits as a monotonic.
654 return (++mLastLocalId
<< 2) | tag
;
657 int32_t IToplevelProtocol::Register(IProtocol
* aRouted
) {
658 if (aRouted
->Id() != kNullActorId
&& aRouted
->Id() != kFreedActorId
) {
659 // If there's already an ID, just return that.
660 return aRouted
->Id();
662 return RegisterID(aRouted
, NextId());
665 int32_t IToplevelProtocol::RegisterID(IProtocol
* aRouted
, int32_t aId
) {
667 aRouted
->ActorConnected();
668 MOZ_ASSERT(!mActorMap
.Contains(aId
), "Don't insert with an existing ID");
669 mActorMap
.InsertOrUpdate(aId
, aRouted
);
673 IProtocol
* IToplevelProtocol::Lookup(int32_t aId
) { return mActorMap
.Get(aId
); }
675 void IToplevelProtocol::Unregister(int32_t aId
) {
676 MOZ_ASSERT(mActorMap
.Contains(aId
),
677 "Attempting to remove an ID not in the actor map");
678 mActorMap
.Remove(aId
);
681 Shmem::SharedMemory
* IToplevelProtocol::CreateSharedMemory(size_t aSize
,
684 RefPtr
<Shmem::SharedMemory
> segment(Shmem::Alloc(aSize
, aUnsafe
));
688 int32_t id
= NextId();
689 Shmem
shmem(segment
.get(), id
);
691 UniquePtr
<Message
> descriptor
= shmem
.MkCreatedMessage(MSG_ROUTING_CONTROL
);
695 Unused
<< GetIPCChannel()->Send(std::move(descriptor
));
698 Shmem::SharedMemory
* rawSegment
= segment
.get();
699 MOZ_ASSERT(!mShmemMap
.Contains(*aId
), "Don't insert with an existing ID");
700 mShmemMap
.InsertOrUpdate(*aId
, segment
.forget().take());
704 Shmem::SharedMemory
* IToplevelProtocol::LookupSharedMemory(Shmem::id_t aId
) {
705 return mShmemMap
.Get(aId
);
708 bool IToplevelProtocol::IsTrackingSharedMemory(Shmem::SharedMemory
* segment
) {
709 for (const auto& shmem
: mShmemMap
.Values()) {
710 if (segment
== shmem
) {
717 bool IToplevelProtocol::DestroySharedMemory(Shmem
& shmem
) {
718 Shmem::id_t aId
= shmem
.Id();
719 Shmem::SharedMemory
* segment
= LookupSharedMemory(aId
);
724 UniquePtr
<Message
> descriptor
= shmem
.MkDestroyedMessage(MSG_ROUTING_CONTROL
);
726 MOZ_ASSERT(mShmemMap
.Contains(aId
),
727 "Attempting to remove an ID not in the shmem map");
728 mShmemMap
.Remove(aId
);
729 Shmem::Dealloc(segment
);
731 MessageChannel
* channel
= GetIPCChannel();
732 if (!channel
->CanSend()) {
736 return descriptor
&& channel
->Send(std::move(descriptor
));
739 void IToplevelProtocol::DeallocShmems() {
740 for (const auto& shmem
: mShmemMap
.Values()) {
741 Shmem::Dealloc(shmem
);
746 bool IToplevelProtocol::ShmemCreated(const Message
& aMsg
) {
748 RefPtr
<Shmem::SharedMemory
> rawmem(Shmem::OpenExisting(aMsg
, &id
, true));
752 MOZ_ASSERT(!mShmemMap
.Contains(id
), "Don't insert with an existing ID");
753 mShmemMap
.InsertOrUpdate(id
, rawmem
.forget().take());
757 bool IToplevelProtocol::ShmemDestroyed(const Message
& aMsg
) {
759 MessageReader
reader(aMsg
);
760 if (!IPC::ReadParam(&reader
, &id
)) {
765 Shmem::SharedMemory
* rawmem
= LookupSharedMemory(id
);
767 MOZ_ASSERT(mShmemMap
.Contains(id
),
768 "Attempting to remove an ID not in the shmem map");
769 mShmemMap
.Remove(id
);
770 Shmem::Dealloc(rawmem
);
775 IPDLResolverInner::IPDLResolverInner(UniquePtr
<IPC::Message
> aReply
,
777 : mReply(std::move(aReply
)),
778 mWeakProxy(aActor
->GetLifecycleProxy()->GetWeakProxy()) {}
780 void IPDLResolverInner::ResolveOrReject(
781 bool aResolve
, FunctionRef
<void(IPC::Message
*, IProtocol
*)> aWrite
) {
782 MOZ_ASSERT(mWeakProxy
);
783 MOZ_ASSERT(mWeakProxy
->ActorEventTarget()->IsOnCurrentThread());
786 UniquePtr
<IPC::Message
> reply
= std::move(mReply
);
788 IProtocol
* actor
= mWeakProxy
->Get();
790 NS_WARNING(nsPrintfCString("Not resolving response '%s': actor is dead",
796 IPC::MessageWriter
writer(*reply
, actor
);
797 WriteIPDLParam(&writer
, actor
, aResolve
);
798 aWrite(reply
.get(), actor
);
800 actor
->ChannelSend(std::move(reply
));
803 void IPDLResolverInner::Destroy() {
805 NS_PROXY_DELETE_TO_EVENT_TARGET(IPDLResolverInner
,
806 mWeakProxy
->ActorEventTarget());
808 // If we've already been consumed, just delete without proxying. This avoids
809 // leaking the resolver if the actor's thread is already dead.
814 IPDLResolverInner::~IPDLResolverInner() {
818 "Rejecting reply '%s': resolver dropped without being called",
821 ResolveOrReject(false, [](IPC::Message
* aMessage
, IProtocol
* aActor
) {
822 IPC::MessageWriter
writer(*aMessage
, aActor
);
823 ResponseRejectReason reason
= ResponseRejectReason::ResolverDestroyed
;
824 WriteIPDLParam(&writer
, aActor
, reason
);
830 } // namespace mozilla