no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / ipc / glue / BackgroundImpl.cpp
blobed854b01d70f74294b59058269457253f0329e31
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"
37 #include "nsCOMPtr.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"
44 #include "nsITimer.h"
45 #include "nsTArray.h"
46 #include "nsThreadUtils.h"
47 #include "nsTraceRefcnt.h"
48 #include "nsXULAppAPI.h"
49 #include "nsXPCOMPrivate.h"
50 #include "prthread.h"
52 #include <functional>
54 #ifdef RELEASE_OR_BETA
55 # define THREADSAFETY_ASSERT MOZ_ASSERT
56 #else
57 # define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
58 #endif
60 #define CRASH_IN_CHILD_PROCESS(_msg) \
61 do { \
62 if (XRE_IsParentProcess()) { \
63 MOZ_ASSERT(false, _msg); \
64 } else { \
65 MOZ_CRASH(_msg); \
66 } \
67 } while (0)
69 using namespace mozilla;
70 using namespace mozilla::dom;
71 using namespace mozilla::ipc;
72 using namespace mozilla::net;
74 namespace {
76 class ChildImpl;
78 // -----------------------------------------------------------------------------
79 // Utility Functions
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;
93 private:
94 class ShutdownObserver;
96 struct MOZ_STACK_CLASS TimerCallbackClosure {
97 nsIThread* mThread;
98 nsTArray<IToplevelProtocol*>* mLiveActors;
100 TimerCallbackClosure(nsIThread* aThread,
101 nsTArray<IToplevelProtocol*>* aLiveActors)
102 : mThread(aThread), mLiveActors(aLiveActors) {
103 AssertIsInMainProcess();
104 AssertIsOnMainThread();
105 MOZ_ASSERT(aThread);
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
156 // thread.
157 bool mActorDestroyed;
159 public:
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,
178 override)
180 void Destroy();
182 private:
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());
222 ~ParentImpl() {
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;
258 public:
259 struct ThreadLocalInfo {
260 ThreadLocalInfo()
261 #ifdef DEBUG
262 : mClosed(false)
263 #endif
267 RefPtr<ChildImpl> mActor;
268 UniquePtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
269 #ifdef DEBUG
270 bool mClosed;
271 #endif
274 private:
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;
284 public:
285 using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int,
286 nsIEventTarget*, ChildImpl**);
288 ThreadInfoWrapper() = default;
290 void Startup() {
291 MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex,
292 "ThreadInfoWrapper::Startup() called more than once!");
294 PRStatus status =
295 PR_NewThreadPrivateIndex(&mThreadLocalIndex, ThreadLocalDestructor);
296 MOZ_RELEASE_ASSERT(status == PR_SUCCESS,
297 "PR_NewThreadPrivateIndex failed!");
299 MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex);
302 void Shutdown() {
303 if (sShutdownHasStarted) {
304 MOZ_ASSERT_IF(mThreadLocalIndex != kBadThreadLocalIndex,
305 !PR_GetThreadPrivate(mThreadLocalIndex));
306 return;
309 if (mThreadLocalIndex == kBadThreadLocalIndex) {
310 return;
313 RefPtr<BackgroundStarterChild> starter;
315 auto lock = mStarter.Lock();
316 starter = lock->forget();
318 if (starter) {
319 CloseStarter(starter);
322 ThreadLocalInfo* threadLocalInfo;
323 #ifdef DEBUG
324 threadLocalInfo =
325 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
326 MOZ_ASSERT(!threadLocalInfo);
327 #endif
329 threadLocalInfo = mMainThreadInfo;
330 if (threadLocalInfo) {
331 #ifdef DEBUG
332 MOZ_ASSERT(!threadLocalInfo->mClosed);
333 threadLocalInfo->mClosed = true;
334 #endif
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));
371 }));
373 // Swap in the newly initialized `BackgroundStarterChild`, and close the
374 // previous one if we're replacing an existing PBackgroundStarterChild
375 // instance.
376 RefPtr<BackgroundStarterChild> prevStarter;
378 auto lock = mStarter.Lock();
379 prevStarter = lock->forget();
380 *lock = starter.forget();
382 if (prevStarter) {
383 CloseStarter(prevStarter);
387 void CloseForCurrentThread() {
388 MOZ_ASSERT(!NS_IsMainThread());
390 if (mThreadLocalIndex == kBadThreadLocalIndex) {
391 return;
394 auto* threadLocalInfo =
395 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
397 if (!threadLocalInfo) {
398 return;
401 #ifdef DEBUG
402 MOZ_ASSERT(!threadLocalInfo->mClosed);
403 threadLocalInfo->mClosed = true;
404 #endif
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");
418 return nullptr;
420 if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted) {
421 return nullptr;
424 auto* threadLocalInfo = NS_IsMainThread()
425 ? mMainThreadInfo
426 : static_cast<ThreadLocalInfo*>(
427 PR_GetThreadPrivate(mThreadLocalIndex));
429 if (!threadLocalInfo) {
430 auto newInfo = MakeUnique<ThreadLocalInfo>();
432 if (NS_IsMainThread()) {
433 mMainThreadInfo = newInfo.get();
434 } else {
435 if (PR_SetThreadPrivate(mThreadLocalIndex, newInfo.get()) !=
436 PR_SUCCESS) {
437 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
438 return nullptr;
442 threadLocalInfo = newInfo.release();
445 if (threadLocalInfo->mActor) {
446 return threadLocalInfo->mActor;
449 RefPtr<BackgroundStarterChild> starter;
451 auto lock = mStarter.Lock();
452 starter = *lock;
454 if (!starter) {
455 CRASH_IN_CHILD_PROCESS("No BackgroundStarterChild");
456 return nullptr;
459 Endpoint<PBackgroundParent> parent;
460 Endpoint<PBackgroundChild> child;
461 nsresult rv;
462 rv = PBackground::CreateEndpoints(
463 starter->mOtherPid, base::GetCurrentProcId(), &parent, &child);
464 if (NS_FAILED(rv)) {
465 NS_WARNING("Failed to create top level actor!");
466 return nullptr;
469 RefPtr<ChildImpl> strongActor = new ChildImpl();
470 if (!child.Bind(strongActor)) {
471 CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
472 return nullptr;
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");
485 }));
486 return strongActor;
489 private:
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
502 // thread info.
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;
520 #endif
522 #ifdef DEBUG
523 bool mActorWasAlive;
524 bool mActorDestroyed;
525 #endif
527 public:
528 static void Shutdown();
530 void AssertIsOnOwningThread() {
531 THREADSAFETY_ASSERT(mOwningEventTarget);
533 #ifdef RELEASE_OR_BETA
534 DebugOnly<bool> current;
535 #else
536 bool current;
537 #endif
538 THREADSAFETY_ASSERT(
539 NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)));
540 THREADSAFETY_ASSERT(current);
543 void AssertActorDestroyed() {
544 MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
547 explicit ChildImpl()
548 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
549 : mOwningEventTarget(GetCurrentSerialEventTarget())
550 #endif
551 #ifdef DEBUG
553 mActorWasAlive(false),
554 mActorDestroyed(false)
555 #endif
557 AssertIsOnOwningThread();
560 void SetActorAlive() {
561 AssertIsOnOwningThread();
562 MOZ_ASSERT(!mActorWasAlive);
563 MOZ_ASSERT(!mActorDestroyed);
565 #ifdef DEBUG
566 mActorWasAlive = true;
567 #endif
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)
577 private:
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 {
609 public:
610 ShutdownObserver() { AssertIsOnMainThread(); }
612 NS_DECL_ISUPPORTS
613 NS_DECL_NSIOBSERVER
615 private:
616 ~ShutdownObserver() { AssertIsOnMainThread(); }
619 // -----------------------------------------------------------------------------
620 // ChildImpl Helper Declarations
621 // -----------------------------------------------------------------------------
623 class ChildImpl::ShutdownObserver final : public nsIObserver {
624 public:
625 ShutdownObserver() { AssertIsOnMainThread(); }
627 NS_DECL_ISUPPORTS
628 NS_DECL_NSIOBSERVER
630 private:
631 ~ShutdownObserver() { AssertIsOnMainThread(); }
634 } // namespace
636 namespace mozilla {
637 namespace ipc {
639 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
641 #ifdef DEBUG
643 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
645 #endif // DEBUG
647 } // namespace ipc
648 } // namespace mozilla
650 // -----------------------------------------------------------------------------
651 // BackgroundParent Public Methods
652 // -----------------------------------------------------------------------------
654 // static
655 already_AddRefed<nsISerialEventTarget> BackgroundParent::GetBackgroundThread() {
656 return ParentImpl::GetBackgroundThread();
659 // static
660 bool BackgroundParent::IsOtherProcessActor(
661 PBackgroundParent* aBackgroundActor) {
662 return ParentImpl::IsOtherProcessActor(aBackgroundActor);
665 // static
666 ThreadsafeContentParentHandle* BackgroundParent::GetContentParentHandle(
667 PBackgroundParent* aBackgroundActor) {
668 return ParentImpl::GetContentParentHandle(aBackgroundActor);
671 // static
672 uint64_t BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor) {
673 return ParentImpl::GetChildID(aBackgroundActor);
676 // static
677 void BackgroundParent::KillHardAsync(PBackgroundParent* aBackgroundActor,
678 const nsACString& aReason) {
679 ParentImpl::KillHardAsync(aBackgroundActor, aReason);
682 // static
683 bool BackgroundParent::AllocStarter(
684 ContentParent* aContent, Endpoint<PBackgroundStarterParent>&& aEndpoint) {
685 return ParentImpl::AllocStarter(aContent, std::move(aEndpoint));
688 // -----------------------------------------------------------------------------
689 // BackgroundChild Public Methods
690 // -----------------------------------------------------------------------------
692 // static
693 void BackgroundChild::Startup() { ChildImpl::Startup(); }
695 // static
696 PBackgroundChild* BackgroundChild::GetForCurrentThread() {
697 return ChildImpl::GetForCurrentThread();
700 // static
701 PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread() {
702 return ChildImpl::GetOrCreateForCurrentThread();
705 // static
706 void BackgroundChild::CloseForCurrentThread() {
707 ChildImpl::CloseForCurrentThread();
710 // static
711 void BackgroundChild::InitContentStarter(ContentChild* aContent) {
712 ChildImpl::InitContentStarter(aContent);
715 // -----------------------------------------------------------------------------
716 // BackgroundChildImpl Public Methods
717 // -----------------------------------------------------------------------------
719 // static
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 // -----------------------------------------------------------------------------
755 // static
756 bool ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) {
757 AssertIsOnBackgroundThread();
758 MOZ_ASSERT(aBackgroundActor);
760 return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
763 // static
764 ThreadsafeContentParentHandle* ParentImpl::GetContentParentHandle(
765 PBackgroundParent* aBackgroundActor) {
766 AssertIsOnBackgroundThread();
767 MOZ_ASSERT(aBackgroundActor);
769 return static_cast<ParentImpl*>(aBackgroundActor)->mContent.get();
772 // static
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();
782 return 0;
785 // static
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);
795 MOZ_ASSERT(handle);
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();
818 // static
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!");
829 return false;
832 sLiveActorCount++;
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);
844 })))) {
845 NS_WARNING("Failed to dispatch connect runnable!");
847 MOZ_ASSERT(sLiveActorCount);
848 sLiveActorCount--;
851 return true;
854 // static
855 bool ParentImpl::CreateBackgroundThread() {
856 AssertIsInMainProcess();
857 AssertIsOnMainThread();
858 MOZ_ASSERT(!sBackgroundThread);
859 MOZ_ASSERT(!sLiveActorsForBackgroundThread);
861 if (sShutdownHasStarted) {
862 NS_WARNING(
863 "Trying to create background thread after shutdown has "
864 "already begun!");
865 return false;
868 nsCOMPtr<nsITimer> newShutdownTimer;
870 if (!sShutdownTimer) {
871 newShutdownTimer = NS_NewTimer();
872 if (!newShutdownTimer) {
873 return false;
877 if (!sShutdownObserverRegistered) {
878 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
879 if (NS_WARN_IF(!obs)) {
880 return false;
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))) {
888 return false;
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);
904 })))) {
905 NS_WARNING("NS_NewNamedThread failed!");
906 return false;
909 sBackgroundThread = thread.forget();
911 sLiveActorsForBackgroundThread = new nsTArray<IToplevelProtocol*>(1);
913 if (!sShutdownTimer) {
914 MOZ_ASSERT(newShutdownTimer);
915 sShutdownTimer = newShutdownTimer;
918 return true;
921 // static
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
965 // here.
966 sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
967 })));
969 MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
973 // static
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);
981 MOZ_ASSERT(closure);
983 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
984 // finished.
985 sLiveActorCount++;
987 InvokeAsync(
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
994 // actual array.
995 nsTArray<IToplevelProtocol*> actorsToClose(liveActors->Clone());
996 for (IToplevelProtocol* actor : actorsToClose) {
997 actor->Close();
1000 return GenericPromise::CreateAndResolve(true, __func__);
1002 ->Then(GetCurrentSerialEventTarget(), __func__, []() {
1003 MOZ_ASSERT(sLiveActorCount);
1004 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);
1024 sLiveActorCount--;
1026 // This may be the last reference!
1027 Release();
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)
1059 NS_IMETHODIMP
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();
1075 return NS_OK;
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.
1113 NS_ADDREF(actor);
1115 ParentImpl::sLiveActorCount++;
1117 if (!aEndpoint.Bind(actor)) {
1118 actor->Destroy();
1119 return IPC_OK();
1122 if (mCrossProcess) {
1123 actor->SetLiveActorArray(mLiveActorArray);
1125 return IPC_OK();
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 // -----------------------------------------------------------------------------
1146 // static
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
1163 // process.
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));
1176 // static
1177 void ChildImpl::Shutdown() {
1178 AssertIsOnMainThread();
1180 sParentAndContentProcessThreadInfo.Shutdown();
1182 sShutdownHasStarted = true;
1185 // static
1186 PBackgroundChild* ChildImpl::GetForCurrentThread() {
1187 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1188 kBadThreadLocalIndex);
1190 auto threadLocalInfo =
1191 NS_IsMainThread()
1192 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1193 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1194 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1196 if (!threadLocalInfo) {
1197 return nullptr;
1200 return threadLocalInfo->mActor;
1203 /* static */
1204 PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread() {
1205 return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread();
1208 // static
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();
1217 // static
1218 BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
1219 MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1220 kBadThreadLocalIndex,
1221 "BackgroundChild::Startup() was never called!");
1223 auto threadLocalInfo =
1224 NS_IsMainThread()
1225 ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1226 : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1227 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1229 if (!threadLocalInfo) {
1230 return nullptr;
1233 if (!threadLocalInfo->mConsumerThreadLocal) {
1234 threadLocalInfo->mConsumerThreadLocal =
1235 MakeUnique<BackgroundChildImpl::ThreadLocal>();
1238 return threadLocalInfo->mConsumerThreadLocal.get();
1241 // static
1242 void ChildImpl::InitContentStarter(mozilla::dom::ContentChild* aContent) {
1243 sParentAndContentProcessThreadInfo.InitStarter(aContent);
1246 // static
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();
1265 #ifdef DEBUG
1266 MOZ_ASSERT(!mActorDestroyed);
1267 mActorDestroyed = true;
1268 #endif
1270 BackgroundChildImpl::ActorDestroy(aWhy);
1273 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1275 NS_IMETHODIMP
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();
1283 return NS_OK;