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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "BackgroundChild.h"
8 #include "BackgroundParent.h"
10 #include "BackgroundChildImpl.h"
11 #include "BackgroundParentImpl.h"
12 #include "MainThreadUtils.h"
13 #include "base/process_util.h"
14 #include "base/task.h"
15 #include "FileDescriptor.h"
16 #include "GeckoProfiler.h"
17 #include "InputStreamUtils.h"
18 #include "mozilla/Assertions.h"
19 #include "mozilla/Atomics.h"
20 #include "mozilla/ClearOnShutdown.h"
21 #include "mozilla/DebugOnly.h"
22 #include "mozilla/MozPromise.h"
23 #include "mozilla/Services.h"
24 #include "mozilla/SpinEventLoopUntil.h"
25 #include "mozilla/StaticPtr.h"
26 #include "mozilla/Unused.h"
27 #include "mozilla/dom/ContentChild.h"
28 #include "mozilla/dom/ContentParent.h"
29 #include "mozilla/dom/File.h"
30 #include "mozilla/dom/WorkerPrivate.h"
31 #include "mozilla/dom/WorkerRef.h"
32 #include "mozilla/ipc/BackgroundStarterChild.h"
33 #include "mozilla/ipc/BackgroundStarterParent.h"
34 #include "mozilla/ipc/Endpoint.h"
35 #include "mozilla/ipc/PBackgroundStarter.h"
36 #include "mozilla/ipc/ProtocolTypes.h"
38 #include "nsIEventTarget.h"
39 #include "nsIObserver.h"
40 #include "nsIObserverService.h"
41 #include "nsIRunnable.h"
42 #include "nsISupportsImpl.h"
43 #include "nsIThread.h"
46 #include "nsThreadUtils.h"
47 #include "nsTraceRefcnt.h"
48 #include "nsXULAppAPI.h"
49 #include "nsXPCOMPrivate.h"
54 #ifdef RELEASE_OR_BETA
55 # define THREADSAFETY_ASSERT MOZ_ASSERT
57 # define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
60 #define CRASH_IN_CHILD_PROCESS(_msg) \
62 if (XRE_IsParentProcess()) { \
63 MOZ_ASSERT(false, _msg); \
69 using namespace mozilla
;
70 using namespace mozilla::dom
;
71 using namespace mozilla::ipc
;
72 using namespace mozilla::net
;
78 // -----------------------------------------------------------------------------
80 // -----------------------------------------------------------------------------
82 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
84 // -----------------------------------------------------------------------------
85 // ParentImpl Declaration
86 // -----------------------------------------------------------------------------
88 class ParentImpl final
: public BackgroundParentImpl
{
89 friend class ChildImpl
;
90 friend class mozilla::ipc::BackgroundParent
;
91 friend class mozilla::ipc::BackgroundStarterParent
;
94 class ShutdownObserver
;
96 struct MOZ_STACK_CLASS TimerCallbackClosure
{
98 nsTArray
<IToplevelProtocol
*>* mLiveActors
;
100 TimerCallbackClosure(nsIThread
* aThread
,
101 nsTArray
<IToplevelProtocol
*>* aLiveActors
)
102 : mThread(aThread
), mLiveActors(aLiveActors
) {
103 AssertIsInMainProcess();
104 AssertIsOnMainThread();
106 MOZ_ASSERT(aLiveActors
);
110 // The length of time we will wait at shutdown for all actors to clean
111 // themselves up before forcing them to be destroyed.
112 static const uint32_t kShutdownTimerDelayMS
= 10000;
114 // This is only modified on the main thread. It is null if the thread does not
115 // exist or is shutting down.
116 static StaticRefPtr
<nsIThread
> sBackgroundThread
;
118 // This is created and destroyed on the main thread but only modified on the
119 // background thread. It is specific to each instance of sBackgroundThread.
120 static nsTArray
<IToplevelProtocol
*>* sLiveActorsForBackgroundThread
;
122 // This is only modified on the main thread.
123 static StaticRefPtr
<nsITimer
> sShutdownTimer
;
125 // This exists so that that [Assert]IsOnBackgroundThread() can continue to
126 // work during shutdown.
127 static Atomic
<PRThread
*> sBackgroundPRThread
;
129 // Maintains a count of live actors so that the background thread can be shut
130 // down when it is no longer needed.
131 // May be incremented on either the background thread (by an existing actor)
132 // or on the main thread, but must be decremented on the main thread.
133 static Atomic
<uint64_t> sLiveActorCount
;
135 // This is only modified on the main thread. It is true after the shutdown
136 // observer is registered and is never unset thereafter.
137 static bool sShutdownObserverRegistered
;
139 // This is only modified on the main thread. It prevents us from trying to
140 // create the background thread after application shutdown has started.
141 static bool sShutdownHasStarted
;
143 // null if this is a same-process actor.
144 const RefPtr
<ThreadsafeContentParentHandle
> mContent
;
146 // Set when the actor is opened successfully and used to handle shutdown
147 // hangs. Only touched on the background thread.
148 nsTArray
<IToplevelProtocol
*>* mLiveActorArray
;
150 // Set at construction to indicate whether this parent actor corresponds to a
151 // child actor in another process or to a child actor from a different thread
152 // in the same process.
153 const bool mIsOtherProcessActor
;
155 // Set after ActorDestroy has been called. Only touched on the background
157 bool mActorDestroyed
;
160 static already_AddRefed
<nsISerialEventTarget
> GetBackgroundThread() {
161 AssertIsInMainProcess();
162 THREADSAFETY_ASSERT(NS_IsMainThread() || IsOnBackgroundThread());
163 return do_AddRef(sBackgroundThread
);
166 static bool IsOnBackgroundThread() {
167 return PR_GetCurrentThread() == sBackgroundPRThread
;
170 static void AssertIsOnBackgroundThread() {
171 THREADSAFETY_ASSERT(IsOnBackgroundThread());
174 // `ParentImpl` instances need to be deleted on the main thread, despite IPC
175 // controlling them on a background thread. Use `_WITH_DELETE_ON_MAIN_THREAD`
176 // to force destruction to occur on the desired thread.
177 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(ParentImpl
,
183 // Forwarded from BackgroundParent.
184 static bool IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
);
186 // Forwarded from BackgroundParent.
187 static ThreadsafeContentParentHandle
* GetContentParentHandle(
188 PBackgroundParent
* aBackgroundActor
);
190 // Forwarded from BackgroundParent.
191 static uint64_t GetChildID(PBackgroundParent
* aBackgroundActor
);
193 // Forwarded from BackgroundParent.
194 static void KillHardAsync(PBackgroundParent
* aBackgroundActor
,
195 const nsACString
& aReason
);
197 // Forwarded from BackgroundParent.
198 static bool AllocStarter(ContentParent
* aContent
,
199 Endpoint
<PBackgroundStarterParent
>&& aEndpoint
,
200 bool aCrossProcess
= true);
202 static bool CreateBackgroundThread();
204 static void ShutdownBackgroundThread();
206 static void ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
);
208 // NOTE: ParentImpl could be used in 2 cases below.
209 // 1. Within the parent process.
210 // 2. Between parent process and content process.
211 // |aContent| should be not null for case 2. For cases 1, it's null.
212 explicit ParentImpl(ThreadsafeContentParentHandle
* aContent
,
213 bool aIsOtherProcessActor
)
214 : mContent(aContent
),
215 mLiveActorArray(nullptr),
216 mIsOtherProcessActor(aIsOtherProcessActor
),
217 mActorDestroyed(false) {
218 AssertIsInMainProcess();
219 MOZ_ASSERT_IF(!aIsOtherProcessActor
, XRE_IsParentProcess());
223 AssertIsInMainProcess();
224 AssertIsOnMainThread();
227 void MainThreadActorDestroy();
229 void SetLiveActorArray(nsTArray
<IToplevelProtocol
*>* aLiveActorArray
) {
230 AssertIsInMainProcess();
231 AssertIsOnBackgroundThread();
232 MOZ_ASSERT(aLiveActorArray
);
233 MOZ_ASSERT(!aLiveActorArray
->Contains(this));
234 MOZ_ASSERT(!mLiveActorArray
);
235 MOZ_ASSERT(mIsOtherProcessActor
);
237 mLiveActorArray
= aLiveActorArray
;
238 mLiveActorArray
->AppendElement(this);
241 // These methods are only called by IPDL.
242 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
245 // -----------------------------------------------------------------------------
246 // ChildImpl Declaration
247 // -----------------------------------------------------------------------------
249 class ChildImpl final
: public BackgroundChildImpl
{
250 friend class mozilla::ipc::BackgroundChild
;
251 friend class mozilla::ipc::BackgroundChildImpl
;
252 friend class mozilla::ipc::BackgroundStarterChild
;
254 typedef base::ProcessId ProcessId
;
256 class ShutdownObserver
;
259 struct ThreadLocalInfo
{
267 RefPtr
<ChildImpl
> mActor
;
268 UniquePtr
<BackgroundChildImpl::ThreadLocal
> mConsumerThreadLocal
;
275 // A thread-local index that is not valid.
276 static constexpr unsigned int kBadThreadLocalIndex
=
277 static_cast<unsigned int>(-1);
279 // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
280 // also provides some common functions for creating PBackground IPC actor.
281 class ThreadInfoWrapper final
{
282 friend class ChildImpl
;
285 using ActorCreateFunc
= void (*)(ThreadLocalInfo
*, unsigned int,
286 nsIEventTarget
*, ChildImpl
**);
288 ThreadInfoWrapper() = default;
291 MOZ_ASSERT(mThreadLocalIndex
== kBadThreadLocalIndex
,
292 "ThreadInfoWrapper::Startup() called more than once!");
295 PR_NewThreadPrivateIndex(&mThreadLocalIndex
, ThreadLocalDestructor
);
296 MOZ_RELEASE_ASSERT(status
== PR_SUCCESS
,
297 "PR_NewThreadPrivateIndex failed!");
299 MOZ_ASSERT(mThreadLocalIndex
!= kBadThreadLocalIndex
);
303 if (sShutdownHasStarted
) {
304 MOZ_ASSERT_IF(mThreadLocalIndex
!= kBadThreadLocalIndex
,
305 !PR_GetThreadPrivate(mThreadLocalIndex
));
309 if (mThreadLocalIndex
== kBadThreadLocalIndex
) {
313 RefPtr
<BackgroundStarterChild
> starter
;
315 auto lock
= mStarter
.Lock();
316 starter
= lock
->forget();
319 CloseStarter(starter
);
322 ThreadLocalInfo
* threadLocalInfo
;
325 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(mThreadLocalIndex
));
326 MOZ_ASSERT(!threadLocalInfo
);
329 threadLocalInfo
= mMainThreadInfo
;
330 if (threadLocalInfo
) {
332 MOZ_ASSERT(!threadLocalInfo
->mClosed
);
333 threadLocalInfo
->mClosed
= true;
336 ThreadLocalDestructor(threadLocalInfo
);
337 mMainThreadInfo
= nullptr;
341 template <typename Actor
>
342 void InitStarter(Actor
* aActor
) {
343 AssertIsOnMainThread();
345 // Create a pair of endpoints and send them to the other process.
346 Endpoint
<PBackgroundStarterParent
> parent
;
347 Endpoint
<PBackgroundStarterChild
> child
;
348 MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
349 aActor
->OtherPid(), base::GetCurrentProcId(), &parent
, &child
));
350 MOZ_ALWAYS_TRUE(aActor
->SendInitBackground(std::move(parent
)));
352 InitStarter(std::move(child
));
355 void InitStarter(Endpoint
<PBackgroundStarterChild
>&& aEndpoint
) {
356 AssertIsOnMainThread();
358 base::ProcessId otherPid
= aEndpoint
.OtherPid();
360 nsCOMPtr
<nsISerialEventTarget
> taskQueue
;
361 MOZ_ALWAYS_SUCCEEDS(NS_CreateBackgroundTaskQueue(
362 "PBackgroundStarter Queue", getter_AddRefs(taskQueue
)));
364 RefPtr
<BackgroundStarterChild
> starter
=
365 new BackgroundStarterChild(otherPid
, taskQueue
);
367 taskQueue
->Dispatch(NS_NewRunnableFunction(
368 "PBackgroundStarterChild Init",
369 [starter
, endpoint
= std::move(aEndpoint
)]() mutable {
370 MOZ_ALWAYS_TRUE(endpoint
.Bind(starter
));
373 // Swap in the newly initialized `BackgroundStarterChild`, and close the
374 // previous one if we're replacing an existing PBackgroundStarterChild
376 RefPtr
<BackgroundStarterChild
> prevStarter
;
378 auto lock
= mStarter
.Lock();
379 prevStarter
= lock
->forget();
380 *lock
= starter
.forget();
383 CloseStarter(prevStarter
);
387 void CloseForCurrentThread() {
388 MOZ_ASSERT(!NS_IsMainThread());
390 if (mThreadLocalIndex
== kBadThreadLocalIndex
) {
394 auto* threadLocalInfo
=
395 static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(mThreadLocalIndex
));
397 if (!threadLocalInfo
) {
402 MOZ_ASSERT(!threadLocalInfo
->mClosed
);
403 threadLocalInfo
->mClosed
= true;
406 // Clearing the thread local will synchronously close the actor.
407 DebugOnly
<PRStatus
> status
=
408 PR_SetThreadPrivate(mThreadLocalIndex
, nullptr);
409 MOZ_ASSERT(status
== PR_SUCCESS
);
412 PBackgroundChild
* GetOrCreateForCurrentThread() {
413 // Processes can be told to do final CC's during shutdown even though
414 // they never finished starting (and thus call this), because they
415 // hadn't gotten far enough to call Startup() before shutdown began.
416 if (mThreadLocalIndex
== kBadThreadLocalIndex
) {
417 NS_ERROR("BackgroundChild::Startup() was never called");
420 if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted
) {
424 auto* threadLocalInfo
= NS_IsMainThread()
426 : static_cast<ThreadLocalInfo
*>(
427 PR_GetThreadPrivate(mThreadLocalIndex
));
429 if (!threadLocalInfo
) {
430 auto newInfo
= MakeUnique
<ThreadLocalInfo
>();
432 if (NS_IsMainThread()) {
433 mMainThreadInfo
= newInfo
.get();
435 if (PR_SetThreadPrivate(mThreadLocalIndex
, newInfo
.get()) !=
437 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
442 threadLocalInfo
= newInfo
.release();
445 if (threadLocalInfo
->mActor
) {
446 return threadLocalInfo
->mActor
;
449 RefPtr
<BackgroundStarterChild
> starter
;
451 auto lock
= mStarter
.Lock();
455 CRASH_IN_CHILD_PROCESS("No BackgroundStarterChild");
459 Endpoint
<PBackgroundParent
> parent
;
460 Endpoint
<PBackgroundChild
> child
;
462 rv
= PBackground::CreateEndpoints(
463 starter
->mOtherPid
, base::GetCurrentProcId(), &parent
, &child
);
465 NS_WARNING("Failed to create top level actor!");
469 RefPtr
<ChildImpl
> strongActor
= new ChildImpl();
470 if (!child
.Bind(strongActor
)) {
471 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
474 strongActor
->SetActorAlive();
475 threadLocalInfo
->mActor
= strongActor
;
477 // Dispatch to the background task queue to create the relevant actor in
478 // the remote process.
479 starter
->mTaskQueue
->Dispatch(NS_NewRunnableFunction(
480 "PBackground GetOrCreateForCurrentThread",
481 [starter
, endpoint
= std::move(parent
)]() mutable {
482 if (!starter
->SendInitBackground(std::move(endpoint
))) {
483 NS_WARNING("Failed to create toplevel actor");
490 static void CloseStarter(BackgroundStarterChild
* aStarter
) {
491 aStarter
->mTaskQueue
->Dispatch(NS_NewRunnableFunction(
492 "PBackgroundStarterChild Close",
493 [starter
= RefPtr
{aStarter
}] { starter
->Close(); }));
496 // This is only modified on the main thread. It is the thread-local index
497 // that we use to store the BackgroundChild for each thread.
498 unsigned int mThreadLocalIndex
= kBadThreadLocalIndex
;
500 // On the main thread, we store TLS in this global instead of in
501 // mThreadLocalIndex. That way, cooperative main threads all share the same
503 ThreadLocalInfo
* mMainThreadInfo
= nullptr;
505 // The starter which will be used to launch PBackground instances of this
506 // type. Only modified on the main thread, but may be read by any thread
507 // wanting to start background actors.
508 StaticDataMutex
<StaticRefPtr
<BackgroundStarterChild
>> mStarter
{"mStarter"};
511 // For PBackground between parent and content process.
512 static ThreadInfoWrapper sParentAndContentProcessThreadInfo
;
514 // This is only modified on the main thread. It prevents us from trying to
515 // create the background thread after application shutdown has started.
516 static bool sShutdownHasStarted
;
518 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
519 nsISerialEventTarget
* mOwningEventTarget
;
524 bool mActorDestroyed
;
528 static void Shutdown();
530 void AssertIsOnOwningThread() {
531 THREADSAFETY_ASSERT(mOwningEventTarget
);
533 #ifdef RELEASE_OR_BETA
534 DebugOnly
<bool> current
;
539 NS_SUCCEEDED(mOwningEventTarget
->IsOnCurrentThread(¤t
)));
540 THREADSAFETY_ASSERT(current
);
543 void AssertActorDestroyed() {
544 MOZ_ASSERT(mActorDestroyed
, "ChildImpl::ActorDestroy not called in time");
548 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
549 : mOwningEventTarget(GetCurrentSerialEventTarget())
553 mActorWasAlive(false),
554 mActorDestroyed(false)
557 AssertIsOnOwningThread();
560 void SetActorAlive() {
561 AssertIsOnOwningThread();
562 MOZ_ASSERT(!mActorWasAlive
);
563 MOZ_ASSERT(!mActorDestroyed
);
566 mActorWasAlive
= true;
570 // This type is threadsafe refcounted as actors managed by it may be destroyed
571 // after the thread it is bound to dies, and hold a reference to this object.
573 // It is _not_ safe to use this type or any methods on it from off of the
574 // thread it was created for.
575 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChildImpl
, override
)
578 // Forwarded from BackgroundChild.
579 static void Startup();
581 // Forwarded from BackgroundChild.
582 static PBackgroundChild
* GetForCurrentThread();
584 // Forwarded from BackgroundChild.
585 static PBackgroundChild
* GetOrCreateForCurrentThread();
587 static void CloseForCurrentThread();
589 // Forwarded from BackgroundChildImpl.
590 static BackgroundChildImpl::ThreadLocal
* GetThreadLocalForCurrentThread();
592 // Forwarded from BackgroundChild.
593 static void InitContentStarter(mozilla::dom::ContentChild
* aContent
);
595 static void ThreadLocalDestructor(void* aThreadLocal
);
597 // This class is reference counted.
598 ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive
, mActorDestroyed
); }
600 // Only called by IPDL.
601 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
604 // -----------------------------------------------------------------------------
605 // ParentImpl Helper Declarations
606 // -----------------------------------------------------------------------------
608 class ParentImpl::ShutdownObserver final
: public nsIObserver
{
610 ShutdownObserver() { AssertIsOnMainThread(); }
616 ~ShutdownObserver() { AssertIsOnMainThread(); }
619 // -----------------------------------------------------------------------------
620 // ChildImpl Helper Declarations
621 // -----------------------------------------------------------------------------
623 class ChildImpl::ShutdownObserver final
: public nsIObserver
{
625 ShutdownObserver() { AssertIsOnMainThread(); }
631 ~ShutdownObserver() { AssertIsOnMainThread(); }
639 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
643 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
648 } // namespace mozilla
650 // -----------------------------------------------------------------------------
651 // BackgroundParent Public Methods
652 // -----------------------------------------------------------------------------
655 already_AddRefed
<nsISerialEventTarget
> BackgroundParent::GetBackgroundThread() {
656 return ParentImpl::GetBackgroundThread();
660 bool BackgroundParent::IsOtherProcessActor(
661 PBackgroundParent
* aBackgroundActor
) {
662 return ParentImpl::IsOtherProcessActor(aBackgroundActor
);
666 ThreadsafeContentParentHandle
* BackgroundParent::GetContentParentHandle(
667 PBackgroundParent
* aBackgroundActor
) {
668 return ParentImpl::GetContentParentHandle(aBackgroundActor
);
672 uint64_t BackgroundParent::GetChildID(PBackgroundParent
* aBackgroundActor
) {
673 return ParentImpl::GetChildID(aBackgroundActor
);
677 void BackgroundParent::KillHardAsync(PBackgroundParent
* aBackgroundActor
,
678 const nsACString
& aReason
) {
679 ParentImpl::KillHardAsync(aBackgroundActor
, aReason
);
683 bool BackgroundParent::AllocStarter(
684 ContentParent
* aContent
, Endpoint
<PBackgroundStarterParent
>&& aEndpoint
) {
685 return ParentImpl::AllocStarter(aContent
, std::move(aEndpoint
));
688 // -----------------------------------------------------------------------------
689 // BackgroundChild Public Methods
690 // -----------------------------------------------------------------------------
693 void BackgroundChild::Startup() { ChildImpl::Startup(); }
696 PBackgroundChild
* BackgroundChild::GetForCurrentThread() {
697 return ChildImpl::GetForCurrentThread();
701 PBackgroundChild
* BackgroundChild::GetOrCreateForCurrentThread() {
702 return ChildImpl::GetOrCreateForCurrentThread();
706 void BackgroundChild::CloseForCurrentThread() {
707 ChildImpl::CloseForCurrentThread();
711 void BackgroundChild::InitContentStarter(ContentChild
* aContent
) {
712 ChildImpl::InitContentStarter(aContent
);
715 // -----------------------------------------------------------------------------
716 // BackgroundChildImpl Public Methods
717 // -----------------------------------------------------------------------------
720 BackgroundChildImpl::ThreadLocal
*
721 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
722 return ChildImpl::GetThreadLocalForCurrentThread();
725 // -----------------------------------------------------------------------------
726 // ParentImpl Static Members
727 // -----------------------------------------------------------------------------
729 StaticRefPtr
<nsIThread
> ParentImpl::sBackgroundThread
;
731 nsTArray
<IToplevelProtocol
*>* ParentImpl::sLiveActorsForBackgroundThread
;
733 StaticRefPtr
<nsITimer
> ParentImpl::sShutdownTimer
;
735 Atomic
<PRThread
*> ParentImpl::sBackgroundPRThread
;
737 Atomic
<uint64_t> ParentImpl::sLiveActorCount
;
739 bool ParentImpl::sShutdownObserverRegistered
= false;
741 bool ParentImpl::sShutdownHasStarted
= false;
743 // -----------------------------------------------------------------------------
744 // ChildImpl Static Members
745 // -----------------------------------------------------------------------------
747 ChildImpl::ThreadInfoWrapper
ChildImpl::sParentAndContentProcessThreadInfo
;
749 bool ChildImpl::sShutdownHasStarted
= false;
751 // -----------------------------------------------------------------------------
752 // ParentImpl Implementation
753 // -----------------------------------------------------------------------------
756 bool ParentImpl::IsOtherProcessActor(PBackgroundParent
* aBackgroundActor
) {
757 AssertIsOnBackgroundThread();
758 MOZ_ASSERT(aBackgroundActor
);
760 return static_cast<ParentImpl
*>(aBackgroundActor
)->mIsOtherProcessActor
;
764 ThreadsafeContentParentHandle
* ParentImpl::GetContentParentHandle(
765 PBackgroundParent
* aBackgroundActor
) {
766 AssertIsOnBackgroundThread();
767 MOZ_ASSERT(aBackgroundActor
);
769 return static_cast<ParentImpl
*>(aBackgroundActor
)->mContent
.get();
773 uint64_t ParentImpl::GetChildID(PBackgroundParent
* aBackgroundActor
) {
774 AssertIsOnBackgroundThread();
775 MOZ_ASSERT(aBackgroundActor
);
777 auto actor
= static_cast<ParentImpl
*>(aBackgroundActor
);
778 if (actor
->mContent
) {
779 return actor
->mContent
->ChildID();
786 void ParentImpl::KillHardAsync(PBackgroundParent
* aBackgroundActor
,
787 const nsACString
& aReason
) {
788 AssertIsInMainProcess();
789 AssertIsOnBackgroundThread();
790 MOZ_ASSERT(aBackgroundActor
);
791 MOZ_ASSERT(BackgroundParent::IsOtherProcessActor(aBackgroundActor
));
793 RefPtr
<ThreadsafeContentParentHandle
> handle
=
794 GetContentParentHandle(aBackgroundActor
);
797 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
798 NS_NewRunnableFunction(
799 "ParentImpl::KillHardAsync",
800 [handle
= std::move(handle
), reason
= nsCString
{aReason
}]() {
801 mozilla::AssertIsOnMainThread();
803 if (RefPtr
<ContentParent
> contentParent
=
804 handle
->GetContentParent()) {
805 contentParent
->KillHard(reason
.get());
808 NS_DISPATCH_NORMAL
));
810 // After we've scheduled killing of the remote process, also ensure we induce
811 // a connection error in the IPC channel to immediately stop all IPC
812 // communication on this channel.
813 if (aBackgroundActor
->CanSend()) {
814 aBackgroundActor
->GetIPCChannel()->InduceConnectionError();
819 bool ParentImpl::AllocStarter(ContentParent
* aContent
,
820 Endpoint
<PBackgroundStarterParent
>&& aEndpoint
,
821 bool aCrossProcess
) {
822 AssertIsInMainProcess();
823 AssertIsOnMainThread();
825 MOZ_ASSERT(aEndpoint
.IsValid());
827 if (!sBackgroundThread
&& !CreateBackgroundThread()) {
828 NS_WARNING("Failed to create background thread!");
834 RefPtr
<BackgroundStarterParent
> actor
= new BackgroundStarterParent(
835 aContent
? aContent
->ThreadsafeHandle() : nullptr, aCrossProcess
);
837 if (NS_FAILED(sBackgroundThread
->Dispatch(NS_NewRunnableFunction(
838 "BackgroundStarterParent::ConnectActorRunnable",
839 [actor
= std::move(actor
), endpoint
= std::move(aEndpoint
),
840 liveActorArray
= sLiveActorsForBackgroundThread
]() mutable {
841 MOZ_ASSERT(endpoint
.IsValid());
842 MOZ_ALWAYS_TRUE(endpoint
.Bind(actor
));
843 actor
->SetLiveActorArray(liveActorArray
);
845 NS_WARNING("Failed to dispatch connect runnable!");
847 MOZ_ASSERT(sLiveActorCount
);
855 bool ParentImpl::CreateBackgroundThread() {
856 AssertIsInMainProcess();
857 AssertIsOnMainThread();
858 MOZ_ASSERT(!sBackgroundThread
);
859 MOZ_ASSERT(!sLiveActorsForBackgroundThread
);
861 if (sShutdownHasStarted
) {
863 "Trying to create background thread after shutdown has "
868 nsCOMPtr
<nsITimer
> newShutdownTimer
;
870 if (!sShutdownTimer
) {
871 newShutdownTimer
= NS_NewTimer();
872 if (!newShutdownTimer
) {
877 if (!sShutdownObserverRegistered
) {
878 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
879 if (NS_WARN_IF(!obs
)) {
883 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
885 nsresult rv
= obs
->AddObserver(
886 observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
887 if (NS_WARN_IF(NS_FAILED(rv
))) {
891 sShutdownObserverRegistered
= true;
894 nsCOMPtr
<nsIThread
> thread
;
895 if (NS_FAILED(NS_NewNamedThread(
896 "IPDL Background", getter_AddRefs(thread
),
897 NS_NewRunnableFunction(
898 "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
899 DebugOnly
<PRThread
*> oldBackgroundThread
=
900 sBackgroundPRThread
.exchange(PR_GetCurrentThread());
902 MOZ_ASSERT_IF(oldBackgroundThread
,
903 PR_GetCurrentThread() != oldBackgroundThread
);
905 NS_WARNING("NS_NewNamedThread failed!");
909 sBackgroundThread
= thread
.forget();
911 sLiveActorsForBackgroundThread
= new nsTArray
<IToplevelProtocol
*>(1);
913 if (!sShutdownTimer
) {
914 MOZ_ASSERT(newShutdownTimer
);
915 sShutdownTimer
= newShutdownTimer
;
922 void ParentImpl::ShutdownBackgroundThread() {
923 AssertIsInMainProcess();
924 AssertIsOnMainThread();
925 MOZ_ASSERT(sShutdownHasStarted
);
926 MOZ_ASSERT_IF(!sBackgroundThread
, !sLiveActorCount
);
927 MOZ_ASSERT_IF(sBackgroundThread
, sShutdownTimer
);
929 nsCOMPtr
<nsITimer
> shutdownTimer
= sShutdownTimer
.get();
930 sShutdownTimer
= nullptr;
932 if (sBackgroundThread
) {
933 nsCOMPtr
<nsIThread
> thread
= sBackgroundThread
.get();
934 sBackgroundThread
= nullptr;
936 UniquePtr
<nsTArray
<IToplevelProtocol
*>> liveActors(
937 sLiveActorsForBackgroundThread
);
938 sLiveActorsForBackgroundThread
= nullptr;
940 MOZ_ASSERT_IF(!sShutdownHasStarted
, !sLiveActorCount
);
942 if (sLiveActorCount
) {
943 // We need to spin the event loop while we wait for all the actors to be
944 // cleaned up. We also set a timeout to force-kill any hanging actors.
945 TimerCallbackClosure
closure(thread
, liveActors
.get());
947 MOZ_ALWAYS_SUCCEEDS(shutdownTimer
->InitWithNamedFuncCallback(
948 &ShutdownTimerCallback
, &closure
, kShutdownTimerDelayMS
,
949 nsITimer::TYPE_ONE_SHOT
, "ParentImpl::ShutdownTimerCallback"));
951 SpinEventLoopUntil("ParentImpl::ShutdownBackgroundThread"_ns
,
952 [&]() { return !sLiveActorCount
; });
954 MOZ_ASSERT(liveActors
->IsEmpty());
956 MOZ_ALWAYS_SUCCEEDS(shutdownTimer
->Cancel());
959 // Dispatch this runnable to unregister the PR thread from the profiler.
960 MOZ_ALWAYS_SUCCEEDS(thread
->Dispatch(NS_NewRunnableFunction(
961 "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
962 // It is possible that another background thread was created while
963 // this thread was shutting down. In that case we can't assert
964 // anything about sBackgroundPRThread and we should not modify it
966 sBackgroundPRThread
.compareExchange(PR_GetCurrentThread(), nullptr);
969 MOZ_ALWAYS_SUCCEEDS(thread
->Shutdown());
974 void ParentImpl::ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
) {
975 AssertIsInMainProcess();
976 AssertIsOnMainThread();
977 MOZ_ASSERT(sShutdownHasStarted
);
978 MOZ_ASSERT(sLiveActorCount
);
980 auto closure
= static_cast<TimerCallbackClosure
*>(aClosure
);
983 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
988 closure
->mThread
, __func__
,
989 [liveActors
= closure
->mLiveActors
]() {
990 MOZ_ASSERT(liveActors
);
992 if (!liveActors
->IsEmpty()) {
993 // Copy the array since calling Close() could mutate the
995 nsTArray
<IToplevelProtocol
*> actorsToClose(liveActors
->Clone());
996 for (IToplevelProtocol
* actor
: actorsToClose
) {
1000 return GenericPromise::CreateAndResolve(true, __func__
);
1002 ->Then(GetCurrentSerialEventTarget(), __func__
, []() {
1003 MOZ_ASSERT(sLiveActorCount
);
1008 void ParentImpl::Destroy() {
1009 // May be called on any thread!
1011 AssertIsInMainProcess();
1013 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1014 NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1015 &ParentImpl::MainThreadActorDestroy
)));
1018 void ParentImpl::MainThreadActorDestroy() {
1019 AssertIsInMainProcess();
1020 AssertIsOnMainThread();
1021 MOZ_ASSERT_IF(!mIsOtherProcessActor
, !mContent
);
1023 MOZ_ASSERT(sLiveActorCount
);
1026 // This may be the last reference!
1030 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy
) {
1031 AssertIsInMainProcess();
1032 AssertIsOnBackgroundThread();
1033 MOZ_ASSERT(!mActorDestroyed
);
1034 MOZ_ASSERT_IF(mIsOtherProcessActor
, mLiveActorArray
);
1036 BackgroundParentImpl::ActorDestroy(aWhy
);
1038 mActorDestroyed
= true;
1040 if (mLiveActorArray
) {
1041 MOZ_ALWAYS_TRUE(mLiveActorArray
->RemoveElement(this));
1042 mLiveActorArray
= nullptr;
1045 // This is tricky. We should be able to call Destroy() here directly because
1046 // we're not going to touch 'this' or our MessageChannel any longer on this
1047 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1048 // it runs it will destroy 'this' and our associated MessageChannel. However,
1049 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1050 // racing with the main thread we must ensure that the MessageChannel lives
1051 // long enough to be cleared in this call stack.
1053 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1054 "ParentImpl::Destroy", this, &ParentImpl::Destroy
)));
1057 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver
, nsIObserver
)
1060 ParentImpl::ShutdownObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1061 const char16_t
* aData
) {
1062 AssertIsInMainProcess();
1063 AssertIsOnMainThread();
1064 MOZ_ASSERT(!sShutdownHasStarted
);
1065 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1067 sShutdownHasStarted
= true;
1069 // Do this first before calling (and spinning the event loop in)
1070 // ShutdownBackgroundThread().
1071 ChildImpl::Shutdown();
1073 ShutdownBackgroundThread();
1078 BackgroundStarterParent::BackgroundStarterParent(
1079 ThreadsafeContentParentHandle
* aContent
, bool aCrossProcess
)
1080 : mCrossProcess(aCrossProcess
), mContent(aContent
) {
1081 AssertIsOnMainThread();
1082 AssertIsInMainProcess();
1083 MOZ_ASSERT_IF(!mCrossProcess
, !mContent
);
1084 MOZ_ASSERT_IF(!mCrossProcess
, XRE_IsParentProcess());
1087 void BackgroundStarterParent::SetLiveActorArray(
1088 nsTArray
<IToplevelProtocol
*>* aLiveActorArray
) {
1089 AssertIsInMainProcess();
1090 AssertIsOnBackgroundThread();
1091 MOZ_ASSERT(aLiveActorArray
);
1092 MOZ_ASSERT(!aLiveActorArray
->Contains(this));
1093 MOZ_ASSERT(!mLiveActorArray
);
1094 MOZ_ASSERT_IF(!mCrossProcess
, OtherPid() == base::GetCurrentProcId());
1096 mLiveActorArray
= aLiveActorArray
;
1097 mLiveActorArray
->AppendElement(this);
1100 IPCResult
BackgroundStarterParent::RecvInitBackground(
1101 Endpoint
<PBackgroundParent
>&& aEndpoint
) {
1102 AssertIsOnBackgroundThread();
1104 if (!aEndpoint
.IsValid()) {
1105 return IPC_FAIL(this,
1106 "Cannot initialize PBackground with invalid endpoint");
1109 ParentImpl
* actor
= new ParentImpl(mContent
, mCrossProcess
);
1111 // Take a reference on this thread. If Open() fails then we will release this
1112 // reference in Destroy.
1115 ParentImpl::sLiveActorCount
++;
1117 if (!aEndpoint
.Bind(actor
)) {
1122 if (mCrossProcess
) {
1123 actor
->SetLiveActorArray(mLiveActorArray
);
1128 void BackgroundStarterParent::ActorDestroy(ActorDestroyReason aReason
) {
1129 AssertIsOnBackgroundThread();
1131 if (mLiveActorArray
) {
1132 MOZ_ALWAYS_TRUE(mLiveActorArray
->RemoveElement(this));
1133 mLiveActorArray
= nullptr;
1136 // Make sure to decrement `sLiveActorCount` on the main thread.
1137 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1138 NS_NewRunnableFunction("BackgroundStarterParent::MainThreadDestroy",
1139 [] { ParentImpl::sLiveActorCount
--; })));
1142 // -----------------------------------------------------------------------------
1143 // ChildImpl Implementation
1144 // -----------------------------------------------------------------------------
1147 void ChildImpl::Startup() {
1148 // This happens on the main thread but before XPCOM has started so we can't
1149 // assert that we're being called on the main thread here.
1151 sParentAndContentProcessThreadInfo
.Startup();
1153 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1154 MOZ_RELEASE_ASSERT(observerService
);
1156 nsCOMPtr
<nsIObserver
> observer
= new ShutdownObserver();
1158 nsresult rv
= observerService
->AddObserver(
1159 observer
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
, false);
1160 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
1162 // Initialize a starter actor to allow starting PBackground within the parent
1164 if (XRE_IsParentProcess()) {
1165 Endpoint
<PBackgroundStarterParent
> parent
;
1166 Endpoint
<PBackgroundStarterChild
> child
;
1167 MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
1168 base::GetCurrentProcId(), base::GetCurrentProcId(), &parent
, &child
));
1170 MOZ_ALWAYS_TRUE(ParentImpl::AllocStarter(nullptr, std::move(parent
),
1171 /* aCrossProcess */ false));
1172 sParentAndContentProcessThreadInfo
.InitStarter(std::move(child
));
1177 void ChildImpl::Shutdown() {
1178 AssertIsOnMainThread();
1180 sParentAndContentProcessThreadInfo
.Shutdown();
1182 sShutdownHasStarted
= true;
1186 PBackgroundChild
* ChildImpl::GetForCurrentThread() {
1187 MOZ_ASSERT(sParentAndContentProcessThreadInfo
.mThreadLocalIndex
!=
1188 kBadThreadLocalIndex
);
1190 auto threadLocalInfo
=
1192 ? sParentAndContentProcessThreadInfo
.mMainThreadInfo
1193 : static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(
1194 sParentAndContentProcessThreadInfo
.mThreadLocalIndex
));
1196 if (!threadLocalInfo
) {
1200 return threadLocalInfo
->mActor
;
1204 PBackgroundChild
* ChildImpl::GetOrCreateForCurrentThread() {
1205 return sParentAndContentProcessThreadInfo
.GetOrCreateForCurrentThread();
1209 void ChildImpl::CloseForCurrentThread() {
1210 MOZ_ASSERT(!NS_IsMainThread(),
1211 "PBackground for the main thread should be shut down via "
1212 "ChildImpl::Shutdown().");
1214 sParentAndContentProcessThreadInfo
.CloseForCurrentThread();
1218 BackgroundChildImpl::ThreadLocal
* ChildImpl::GetThreadLocalForCurrentThread() {
1219 MOZ_ASSERT(sParentAndContentProcessThreadInfo
.mThreadLocalIndex
!=
1220 kBadThreadLocalIndex
,
1221 "BackgroundChild::Startup() was never called!");
1223 auto threadLocalInfo
=
1225 ? sParentAndContentProcessThreadInfo
.mMainThreadInfo
1226 : static_cast<ThreadLocalInfo
*>(PR_GetThreadPrivate(
1227 sParentAndContentProcessThreadInfo
.mThreadLocalIndex
));
1229 if (!threadLocalInfo
) {
1233 if (!threadLocalInfo
->mConsumerThreadLocal
) {
1234 threadLocalInfo
->mConsumerThreadLocal
=
1235 MakeUnique
<BackgroundChildImpl::ThreadLocal
>();
1238 return threadLocalInfo
->mConsumerThreadLocal
.get();
1242 void ChildImpl::InitContentStarter(mozilla::dom::ContentChild
* aContent
) {
1243 sParentAndContentProcessThreadInfo
.InitStarter(aContent
);
1247 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal
) {
1248 auto threadLocalInfo
= static_cast<ThreadLocalInfo
*>(aThreadLocal
);
1250 if (threadLocalInfo
) {
1251 MOZ_ASSERT(threadLocalInfo
->mClosed
);
1253 if (threadLocalInfo
->mActor
) {
1254 threadLocalInfo
->mActor
->Close();
1255 threadLocalInfo
->mActor
->AssertActorDestroyed();
1258 delete threadLocalInfo
;
1262 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy
) {
1263 AssertIsOnOwningThread();
1266 MOZ_ASSERT(!mActorDestroyed
);
1267 mActorDestroyed
= true;
1270 BackgroundChildImpl::ActorDestroy(aWhy
);
1273 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver
, nsIObserver
)
1276 ChildImpl::ShutdownObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1277 const char16_t
* aData
) {
1278 AssertIsOnMainThread();
1279 MOZ_ASSERT(!strcmp(aTopic
, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
));
1281 ChildImpl::Shutdown();