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"
28 #include "nsReadableUtils.h"
30 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
31 # include "mozilla/sandboxTarget.h"
39 #ifdef FUZZING_SNAPSHOT
40 # include "mozilla/fuzzing/IPCFuzzController.h"
45 using base::GetCurrentProcId
;
46 using base::ProcessHandle
;
47 using base::ProcessId
;
53 IPCResult
IPCResult::FailImpl(NotNull
<IProtocol
*> actor
, const char* where
,
55 // Calls top-level protocol to handle the error.
56 nsPrintfCString
errorMsg("%s %s\n", where
, why
);
57 actor
->GetIPCChannel()->Listener()->ProcessingError(
58 HasResultCodes::MsgProcessingError
, errorMsg
.get());
60 #if defined(DEBUG) && !defined(FUZZING)
61 // We do not expect IPC_FAIL to ever happen in normal operations. If this
62 // happens in DEBUG, we most likely see some behavior during a test we should
63 // really investigate.
64 nsPrintfCString
crashMsg(
65 "Use IPC_FAIL only in an "
66 "unrecoverable, unexpected state: %s",
68 // We already leak the same information potentially on child process failures
69 // even in release, and here we are only in DEBUG.
70 MOZ_CRASH_UNSAFE(crashMsg
.get());
72 return IPCResult(false);
77 IPCResult
IPCResult::FailForTesting(NotNull
<IProtocol
*> actor
,
78 const char* where
, const char* why
) {
79 return IPCResult(false);
82 void AnnotateSystemError() {
85 error
= ::GetLastError();
90 CrashReporter::RecordAnnotationU32(
91 CrashReporter::Annotation::IPCSystemError
, error
);
95 #if defined(XP_MACOSX)
96 void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag
, int error
) {
97 CrashReporter::RecordAnnotationU32(tag
, static_cast<uint32_t>(error
));
99 #endif // defined(XP_MACOSX)
101 #if defined(DEBUG) || defined(FUZZING)
102 // If aTopLevelProtocol matches any token in aFilter, return true.
104 // aTopLevelProtocol is a protocol name, without the "Parent" / "Child" suffix.
105 // aSide indicates whether we're logging parent-side or child-side activity.
107 // aFilter is a list of protocol names separated by commas and/or
108 // spaces. These may include the "Child" / "Parent" suffix, or omit
109 // the suffix to log activity on both sides.
111 // This overload is for testability; application code should use the single-
112 // argument version (defined in the ProtocolUtils.h) which takes the filter from
114 bool LoggingEnabledFor(const char* aTopLevelProtocol
, Side aSide
,
115 const char* aFilter
) {
119 if (strcmp(aFilter
, "1") == 0) {
123 const char kDelimiters
[] = ", ";
124 Tokenizer
tokens(aFilter
, kDelimiters
);
126 while (tokens
.Next(t
)) {
127 if (t
.Type() == Tokenizer::TOKEN_WORD
) {
128 auto filter
= t
.AsString();
130 // Since aTopLevelProtocol never includes the "Parent" / "Child" suffix,
131 // this will only occur when filter doesn't include it either, meaning
132 // that we should log activity on both sides.
133 if (filter
== aTopLevelProtocol
) {
137 if (aSide
== ParentSide
&&
138 StringEndsWith(filter
, nsDependentCString("Parent")) &&
139 Substring(filter
, 0, filter
.Length() - 6) == aTopLevelProtocol
) {
143 if (aSide
== ChildSide
&&
144 StringEndsWith(filter
, nsDependentCString("Child")) &&
145 Substring(filter
, 0, filter
.Length() - 5) == aTopLevelProtocol
) {
153 #endif // defined(DEBUG) || defined(FUZZING)
155 void LogMessageForProtocol(const char* aTopLevelProtocol
,
156 base::ProcessId aOtherPid
,
157 const char* aContextDescription
, uint32_t aMessageId
,
158 MessageDirection aDirection
) {
159 nsPrintfCString
logMessage(
160 "[time: %" PRId64
"][%" PRIPID
"%s%" PRIPID
"] [%s] %s %s\n", PR_Now(),
161 base::GetCurrentProcId(),
162 aDirection
== MessageDirection::eReceiving
? "<-" : "->", aOtherPid
,
163 aTopLevelProtocol
, aContextDescription
,
164 StringFromIPCMessageType(aMessageId
));
166 __android_log_write(ANDROID_LOG_INFO
, "GeckoIPC", logMessage
.get());
168 fputs(logMessage
.get(), stderr
);
171 void ProtocolErrorBreakpoint(const char* aMsg
) {
172 // Bugs that generate these error messages can be tough to
173 // reproduce. Log always in the hope that someone finds the error
175 printf_stderr("IPDL protocol error: %s\n", aMsg
);
178 void PickleFatalError(const char* aMsg
, IProtocol
* aActor
) {
180 aActor
->FatalError(aMsg
);
182 FatalError(aMsg
, false);
186 void FatalError(const char* aMsg
, bool aIsParent
) {
188 ProtocolErrorBreakpoint(aMsg
);
191 nsAutoCString
formattedMessage("IPDL error: \"");
192 formattedMessage
.AppendASCII(aMsg
);
194 // We're going to crash the parent process because at this time
195 // there's no other really nice way of getting a minidump out of
196 // this process if we're off the main thread.
197 formattedMessage
.AppendLiteral("\". Intentionally crashing.");
198 NS_ERROR(formattedMessage
.get());
199 CrashReporter::RecordAnnotationCString(
200 CrashReporter::Annotation::IPCFatalErrorMsg
, aMsg
);
201 AnnotateSystemError();
203 MOZ_CRASH("IPC FatalError in the parent process!");
206 formattedMessage
.AppendLiteral("\". abort()ing as a result.");
208 MOZ_CRASH_UNSAFE(formattedMessage
.get());
213 void LogicError(const char* aMsg
) { MOZ_CRASH_UNSAFE(aMsg
); }
215 void ActorIdReadError(const char* aActorDescription
) {
217 MOZ_CRASH_UNSAFE_PRINTF("Error deserializing id for %s", aActorDescription
);
221 void BadActorIdError(const char* aActorDescription
) {
222 nsPrintfCString
message("bad id for %s", aActorDescription
);
223 ProtocolErrorBreakpoint(message
.get());
226 void ActorLookupError(const char* aActorDescription
) {
227 nsPrintfCString
message("could not lookup id for %s", aActorDescription
);
228 ProtocolErrorBreakpoint(message
.get());
231 void MismatchedActorTypeError(const char* aActorDescription
) {
232 nsPrintfCString
message("actor that should be of type %s has different type",
234 ProtocolErrorBreakpoint(message
.get());
237 void UnionTypeReadError(const char* aUnionName
) {
238 MOZ_CRASH_UNSAFE_PRINTF("error deserializing type of union %s", aUnionName
);
241 void ArrayLengthReadError(const char* aElementName
) {
242 MOZ_CRASH_UNSAFE_PRINTF("error deserializing length of %s[]", aElementName
);
245 void SentinelReadError(const char* aClassName
) {
246 MOZ_CRASH_UNSAFE_PRINTF("incorrect sentinel when reading %s", aClassName
);
249 ActorLifecycleProxy::ActorLifecycleProxy(IProtocol
* aActor
) : mActor(aActor
) {
251 MOZ_ASSERT(mActor
->CanSend(),
252 "Cannot create LifecycleProxy for non-connected actor!");
254 // Take a reference to our manager's lifecycle proxy to try to hold it &
255 // ensure it doesn't die before us.
256 if (mActor
->mManager
) {
257 mManager
= mActor
->mManager
->mLifecycleProxy
;
260 // Record that we've taken our first reference to our actor.
261 mActor
->ActorAlloc();
264 WeakActorLifecycleProxy
* ActorLifecycleProxy::GetWeakProxy() {
266 mWeakProxy
= new WeakActorLifecycleProxy(this);
271 ActorLifecycleProxy::~ActorLifecycleProxy() {
273 mWeakProxy
->mProxy
= nullptr;
274 mWeakProxy
= nullptr;
277 // When the LifecycleProxy's lifetime has come to an end, it means that the
278 // actor should have its `Dealloc` method called on it. In a well-behaved
279 // actor, this will release the IPC-held reference to the actor.
281 // If the actor has already died before the `LifecycleProxy`, the `IProtocol`
282 // destructor below will clear our reference to it, preventing us from
283 // performing a use-after-free here.
288 // Clear our actor's state back to inactive, and then invoke ActorDealloc.
289 MOZ_ASSERT(mActor
->mLinkStatus
== LinkStatus::Destroyed
,
290 "Deallocating non-destroyed actor!");
291 mActor
->mLifecycleProxy
= nullptr;
292 mActor
->mLinkStatus
= LinkStatus::Inactive
;
293 mActor
->ActorDealloc();
297 WeakActorLifecycleProxy::WeakActorLifecycleProxy(ActorLifecycleProxy
* aProxy
)
298 : mProxy(aProxy
), mActorEventTarget(GetCurrentSerialEventTarget()) {}
300 WeakActorLifecycleProxy::~WeakActorLifecycleProxy() {
301 MOZ_DIAGNOSTIC_ASSERT(!mProxy
, "Destroyed before mProxy was cleared?");
304 IProtocol
* WeakActorLifecycleProxy::Get() const {
305 MOZ_DIAGNOSTIC_ASSERT(mActorEventTarget
->IsOnCurrentThread());
306 return mProxy
? mProxy
->Get() : nullptr;
309 WeakActorLifecycleProxy
* IProtocol::GetWeakLifecycleProxy() {
310 return mLifecycleProxy
? mLifecycleProxy
->GetWeakProxy() : nullptr;
313 IProtocol::~IProtocol() {
314 // If the actor still has a lifecycle proxy when it is being torn down, it
315 // means that IPC was not given control over the lifecycle of the actor
316 // correctly. Usually this means that the actor was destroyed while IPC is
317 // calling a message handler for it, and the actor incorrectly frees itself
318 // during that operation.
320 // As this happens unfortunately frequently, due to many odd protocols in
321 // Gecko, simply emit a warning and clear the weak backreference from our
322 // LifecycleProxy back to us.
323 if (mLifecycleProxy
) {
325 nsPrintfCString("Actor destructor for '%s%s' called before IPC "
326 "lifecycle complete!\n"
327 "References to this actor may unexpectedly dangle!",
328 GetProtocolName(), StringFromIPCSide(GetSide()))
331 mLifecycleProxy
->mActor
= nullptr;
333 // If we are somehow being destroyed while active, make sure that the
334 // existing IPC reference has been freed. If the status of the actor is
335 // `Destroyed`, the reference has already been freed, and we shouldn't free
337 MOZ_ASSERT(mLinkStatus
!= LinkStatus::Inactive
);
338 if (mLinkStatus
!= LinkStatus::Destroyed
) {
339 NS_IF_RELEASE(mLifecycleProxy
);
341 mLifecycleProxy
= nullptr;
345 // The following methods either directly forward to the toplevel protocol, or
346 // almost directly do.
347 int32_t IProtocol::Register(IProtocol
* aRouted
) {
348 return mToplevel
->Register(aRouted
);
350 int32_t IProtocol::RegisterID(IProtocol
* aRouted
, int32_t aId
) {
351 return mToplevel
->RegisterID(aRouted
, aId
);
353 IProtocol
* IProtocol::Lookup(int32_t aId
) { return mToplevel
->Lookup(aId
); }
354 void IProtocol::Unregister(int32_t aId
) {
358 return mToplevel
->Unregister(aId
);
361 Shmem::SharedMemory
* IProtocol::CreateSharedMemory(size_t aSize
, bool aUnsafe
,
363 return mToplevel
->CreateSharedMemory(aSize
, aUnsafe
, aId
);
365 Shmem::SharedMemory
* IProtocol::LookupSharedMemory(int32_t aId
) {
366 return mToplevel
->LookupSharedMemory(aId
);
368 bool IProtocol::IsTrackingSharedMemory(Shmem::SharedMemory
* aSegment
) {
369 return mToplevel
->IsTrackingSharedMemory(aSegment
);
371 bool IProtocol::DestroySharedMemory(Shmem
& aShmem
) {
372 return mToplevel
->DestroySharedMemory(aShmem
);
375 MessageChannel
* IProtocol::GetIPCChannel() {
376 return mToplevel
->GetIPCChannel();
378 const MessageChannel
* IProtocol::GetIPCChannel() const {
379 return mToplevel
->GetIPCChannel();
382 nsISerialEventTarget
* IProtocol::GetActorEventTarget() {
383 return GetIPCChannel()->GetWorkerEventTarget();
386 void IProtocol::SetId(int32_t aId
) {
387 MOZ_ASSERT(mId
== aId
|| mLinkStatus
== LinkStatus::Inactive
);
391 Maybe
<IProtocol
*> IProtocol::ReadActor(IPC::MessageReader
* aReader
,
393 const char* aActorDescription
,
394 int32_t aProtocolTypeId
) {
396 if (!IPC::ReadParam(aReader
, &id
)) {
397 ActorIdReadError(aActorDescription
);
401 if (id
== 1 || (id
== 0 && !aNullable
)) {
402 BadActorIdError(aActorDescription
);
407 return Some(static_cast<IProtocol
*>(nullptr));
410 IProtocol
* listener
= this->Lookup(id
);
412 ActorLookupError(aActorDescription
);
416 if (listener
->GetProtocolId() != aProtocolTypeId
) {
417 MismatchedActorTypeError(aActorDescription
);
421 return Some(listener
);
424 void IProtocol::FatalError(const char* const aErrorMsg
) {
425 HandleFatalError(aErrorMsg
);
428 void IProtocol::HandleFatalError(const char* aErrorMsg
) {
429 if (IProtocol
* manager
= Manager()) {
430 manager
->HandleFatalError(aErrorMsg
);
434 mozilla::ipc::FatalError(aErrorMsg
, mSide
== ParentSide
);
436 GetIPCChannel()->InduceConnectionError();
440 bool IProtocol::AllocShmem(size_t aSize
, Shmem
* aOutMem
) {
443 "Shmem not allocated. Cannot communicate with the other actor.");
448 Shmem::SharedMemory
* rawmem(CreateSharedMemory(aSize
, false, &id
));
453 *aOutMem
= Shmem(rawmem
, id
, aSize
, false);
457 bool IProtocol::AllocUnsafeShmem(size_t aSize
, Shmem
* aOutMem
) {
460 "Shmem not allocated. Cannot communicate with the other actor.");
465 Shmem::SharedMemory
* rawmem(CreateSharedMemory(aSize
, true, &id
));
470 *aOutMem
= Shmem(rawmem
, id
, aSize
, true);
474 bool IProtocol::DeallocShmem(Shmem
& aMem
) {
475 bool ok
= DestroySharedMemory(aMem
);
478 if (mSide
== ChildSide
) {
479 FatalError("bad Shmem");
481 NS_WARNING("bad Shmem");
490 void IProtocol::SetManager(IProtocol
* aManager
) {
491 MOZ_RELEASE_ASSERT(!mManager
|| mManager
== aManager
);
493 mToplevel
= aManager
->mToplevel
;
496 void IProtocol::SetManagerAndRegister(IProtocol
* aManager
) {
497 // Set the manager prior to registering so registering properly inherits
498 // the manager's event target.
499 SetManager(aManager
);
501 aManager
->Register(this);
504 void IProtocol::SetManagerAndRegister(IProtocol
* aManager
, int32_t aId
) {
505 // Set the manager prior to registering so registering properly inherits
506 // the manager's event target.
507 SetManager(aManager
);
509 aManager
->RegisterID(this, aId
);
512 bool IProtocol::ChannelSend(UniquePtr
<IPC::Message
> aMsg
) {
514 // NOTE: This send call failing can only occur during toplevel channel
515 // teardown. As this is an async call, this isn't reasonable to predict or
516 // respond to, so just drop the message on the floor silently.
517 GetIPCChannel()->Send(std::move(aMsg
));
521 WarnMessageDiscarded(aMsg
.get());
525 bool IProtocol::ChannelSend(UniquePtr
<IPC::Message
> aMsg
,
526 UniquePtr
<IPC::Message
>* aReply
) {
528 return GetIPCChannel()->Send(std::move(aMsg
), aReply
);
531 WarnMessageDiscarded(aMsg
.get());
536 void IProtocol::WarnMessageDiscarded(IPC::Message
* aMsg
) {
537 NS_WARNING(nsPrintfCString("IPC message '%s' discarded: actor cannot send",
543 void IProtocol::ActorConnected() {
544 if (mLinkStatus
!= LinkStatus::Inactive
) {
548 #ifdef FUZZING_SNAPSHOT
549 fuzzing::IPCFuzzController::instance().OnActorConnected(this);
552 mLinkStatus
= LinkStatus::Connected
;
554 MOZ_ASSERT(!mLifecycleProxy
, "double-connecting live actor");
555 mLifecycleProxy
= new ActorLifecycleProxy(this);
556 NS_ADDREF(mLifecycleProxy
); // Reference freed in DestroySubtree();
559 void IProtocol::DoomSubtree() {
560 MOZ_ASSERT(CanSend(), "dooming non-connected actor");
561 MOZ_ASSERT(mLifecycleProxy
, "dooming zombie actor");
563 nsTArray
<RefPtr
<ActorLifecycleProxy
>> managed
;
564 AllManagedActors(managed
);
565 for (ActorLifecycleProxy
* proxy
: managed
) {
566 // Guard against actor being disconnected or destroyed during previous Doom
567 IProtocol
* actor
= proxy
->Get();
568 if (actor
&& actor
->CanSend()) {
569 actor
->DoomSubtree();
573 // ActorDoom is called immediately before changing state, this allows messages
574 // to be sent during ActorDoom immediately before the channel is closed and
575 // sending messages is disabled.
577 mLinkStatus
= LinkStatus::Doomed
;
580 void IProtocol::DestroySubtree(ActorDestroyReason aWhy
) {
581 MOZ_ASSERT(CanRecv(), "destroying non-connected actor");
582 MOZ_ASSERT(mLifecycleProxy
, "destroying zombie actor");
584 #ifdef FUZZING_SNAPSHOT
585 fuzzing::IPCFuzzController::instance().OnActorDestroyed(this);
590 // If we're a managed actor, unregister from our manager
596 ActorDestroyReason subtreeWhy
= aWhy
;
597 if (aWhy
== Deletion
|| aWhy
== FailedConstructor
) {
598 subtreeWhy
= AncestorDeletion
;
601 nsTArray
<RefPtr
<ActorLifecycleProxy
>> managed
;
602 AllManagedActors(managed
);
603 for (ActorLifecycleProxy
* proxy
: managed
) {
604 // Guard against actor being disconnected or destroyed during previous
606 IProtocol
* actor
= proxy
->Get();
607 if (actor
&& actor
->CanRecv()) {
608 actor
->DestroySubtree(subtreeWhy
);
612 // Ensure that we don't send any messages while we're calling `ActorDestroy`
613 // by setting our state to `Doomed`.
614 mLinkStatus
= LinkStatus::Doomed
;
616 // The actor is being destroyed, reject any pending responses, invoke
617 // `ActorDestroy` to destroy it, and then clear our status to
618 // `LinkStatus::Destroyed`.
619 GetIPCChannel()->RejectPendingResponsesForActor(id
);
621 mLinkStatus
= LinkStatus::Destroyed
;
624 IToplevelProtocol::IToplevelProtocol(const char* aName
, ProtocolId aProtoId
,
626 : IRefCountedProtocol(aProtoId
, aSide
),
627 mOtherPid(base::kInvalidProcessId
),
629 mChannel(aName
, this) {
633 void IToplevelProtocol::SetOtherProcessId(base::ProcessId aOtherPid
) {
634 mOtherPid
= aOtherPid
;
637 bool IToplevelProtocol::Open(ScopedPort aPort
, const nsID
& aMessageChannelId
,
638 base::ProcessId aOtherPid
,
639 nsISerialEventTarget
* aEventTarget
) {
640 SetOtherProcessId(aOtherPid
);
641 return GetIPCChannel()->Open(std::move(aPort
), mSide
, aMessageChannelId
,
645 bool IToplevelProtocol::Open(IToplevelProtocol
* aTarget
,
646 nsISerialEventTarget
* aEventTarget
,
647 mozilla::ipc::Side aSide
) {
648 SetOtherProcessId(base::GetCurrentProcId());
649 aTarget
->SetOtherProcessId(base::GetCurrentProcId());
650 return GetIPCChannel()->Open(aTarget
->GetIPCChannel(), aEventTarget
, aSide
);
653 bool IToplevelProtocol::OpenOnSameThread(IToplevelProtocol
* aTarget
,
655 SetOtherProcessId(base::GetCurrentProcId());
656 aTarget
->SetOtherProcessId(base::GetCurrentProcId());
657 return GetIPCChannel()->OpenOnSameThread(aTarget
->GetIPCChannel(), aSide
);
660 void IToplevelProtocol::NotifyImpendingShutdown() {
662 GetIPCChannel()->NotifyImpendingShutdown();
666 void IToplevelProtocol::Close() { GetIPCChannel()->Close(); }
668 void IToplevelProtocol::SetReplyTimeoutMs(int32_t aTimeoutMs
) {
669 GetIPCChannel()->SetReplyTimeoutMs(aTimeoutMs
);
672 bool IToplevelProtocol::IsOnCxxStack() const {
673 return GetIPCChannel()->IsOnCxxStack();
676 int32_t IToplevelProtocol::NextId() {
677 // Generate the next ID to use for a shared memory or protocol. Parent and
678 // Child sides of the protocol use different pools.
680 if (GetSide() == ParentSide
) {
684 // Check any overflow
685 MOZ_RELEASE_ASSERT(mLastLocalId
< (1 << 29));
687 // Compute the ID to use with the low two bits as our tag, and the remaining
688 // bits as a monotonic.
689 return (++mLastLocalId
<< 2) | tag
;
692 int32_t IToplevelProtocol::Register(IProtocol
* aRouted
) {
693 if (aRouted
->Id() != kNullActorId
&& aRouted
->Id() != kFreedActorId
) {
694 // If there's already an ID, just return that.
695 return aRouted
->Id();
697 return RegisterID(aRouted
, NextId());
700 int32_t IToplevelProtocol::RegisterID(IProtocol
* aRouted
, int32_t aId
) {
702 aRouted
->ActorConnected();
703 MOZ_ASSERT(!mActorMap
.Contains(aId
), "Don't insert with an existing ID");
704 mActorMap
.InsertOrUpdate(aId
, aRouted
);
708 IProtocol
* IToplevelProtocol::Lookup(int32_t aId
) { return mActorMap
.Get(aId
); }
710 void IToplevelProtocol::Unregister(int32_t aId
) {
711 MOZ_ASSERT(mActorMap
.Contains(aId
),
712 "Attempting to remove an ID not in the actor map");
713 mActorMap
.Remove(aId
);
716 Shmem::SharedMemory
* IToplevelProtocol::CreateSharedMemory(size_t aSize
,
719 RefPtr
<Shmem::SharedMemory
> segment(Shmem::Alloc(aSize
));
723 int32_t id
= NextId();
724 Shmem
shmem(segment
.get(), id
, aSize
, aUnsafe
);
726 UniquePtr
<Message
> descriptor
= shmem
.MkCreatedMessage(MSG_ROUTING_CONTROL
);
730 Unused
<< GetIPCChannel()->Send(std::move(descriptor
));
733 Shmem::SharedMemory
* rawSegment
= segment
.get();
734 MOZ_ASSERT(!mShmemMap
.Contains(*aId
), "Don't insert with an existing ID");
735 mShmemMap
.InsertOrUpdate(*aId
, std::move(segment
));
739 Shmem::SharedMemory
* IToplevelProtocol::LookupSharedMemory(Shmem::id_t aId
) {
740 auto entry
= mShmemMap
.Lookup(aId
);
741 return entry
? entry
.Data().get() : nullptr;
744 bool IToplevelProtocol::IsTrackingSharedMemory(Shmem::SharedMemory
* segment
) {
745 for (const auto& shmem
: mShmemMap
.Values()) {
746 if (segment
== shmem
) {
753 bool IToplevelProtocol::DestroySharedMemory(Shmem
& shmem
) {
754 Shmem::id_t aId
= shmem
.Id();
755 Shmem::SharedMemory
* segment
= LookupSharedMemory(aId
);
760 UniquePtr
<Message
> descriptor
= shmem
.MkDestroyedMessage(MSG_ROUTING_CONTROL
);
762 MOZ_ASSERT(mShmemMap
.Contains(aId
),
763 "Attempting to remove an ID not in the shmem map");
764 mShmemMap
.Remove(aId
);
766 MessageChannel
* channel
= GetIPCChannel();
767 if (!channel
->CanSend()) {
771 return descriptor
&& channel
->Send(std::move(descriptor
));
774 void IToplevelProtocol::DeallocShmems() { mShmemMap
.Clear(); }
776 bool IToplevelProtocol::ShmemCreated(const Message
& aMsg
) {
778 RefPtr
<Shmem::SharedMemory
> rawmem(Shmem::OpenExisting(aMsg
, &id
, true));
782 MOZ_ASSERT(!mShmemMap
.Contains(id
), "Don't insert with an existing ID");
783 mShmemMap
.InsertOrUpdate(id
, std::move(rawmem
));
787 bool IToplevelProtocol::ShmemDestroyed(const Message
& aMsg
) {
789 MessageReader
reader(aMsg
);
790 if (!IPC::ReadParam(&reader
, &id
)) {
795 mShmemMap
.Remove(id
);
799 IPDLResolverInner::IPDLResolverInner(UniquePtr
<IPC::Message
> aReply
,
801 : mReply(std::move(aReply
)),
802 mWeakProxy(aActor
->GetLifecycleProxy()->GetWeakProxy()) {}
804 void IPDLResolverInner::ResolveOrReject(
805 bool aResolve
, FunctionRef
<void(IPC::Message
*, IProtocol
*)> aWrite
) {
806 MOZ_ASSERT(mWeakProxy
);
807 MOZ_ASSERT(mWeakProxy
->ActorEventTarget()->IsOnCurrentThread());
810 UniquePtr
<IPC::Message
> reply
= std::move(mReply
);
812 IProtocol
* actor
= mWeakProxy
->Get();
814 NS_WARNING(nsPrintfCString("Not resolving response '%s': actor is dead",
820 IPC::MessageWriter
writer(*reply
, actor
);
821 WriteIPDLParam(&writer
, actor
, aResolve
);
822 aWrite(reply
.get(), actor
);
824 actor
->ChannelSend(std::move(reply
));
827 void IPDLResolverInner::Destroy() {
829 NS_PROXY_DELETE_TO_EVENT_TARGET(IPDLResolverInner
,
830 mWeakProxy
->ActorEventTarget());
832 // If we've already been consumed, just delete without proxying. This avoids
833 // leaking the resolver if the actor's thread is already dead.
838 IPDLResolverInner::~IPDLResolverInner() {
842 "Rejecting reply '%s': resolver dropped without being called",
845 ResolveOrReject(false, [](IPC::Message
* aMessage
, IProtocol
* aActor
) {
846 IPC::MessageWriter
writer(*aMessage
, aActor
);
847 ResponseRejectReason reason
= ResponseRejectReason::ResolverDestroyed
;
848 WriteIPDLParam(&writer
, aActor
, reason
);
854 } // namespace mozilla