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/. */
6 
7 #include "BackgroundChild.h"
8 #include "BackgroundParent.h"
9 
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 "mozilla/net/SocketProcessChild.h"
38 #include "mozilla/net/SocketProcessBridgeChild.h"
39 #include "nsCOMPtr.h"
40 #include "nsIEventTarget.h"
41 #include "nsIObserver.h"
42 #include "nsIObserverService.h"
43 #include "nsIRunnable.h"
44 #include "nsISupportsImpl.h"
45 #include "nsIThread.h"
46 #include "nsITimer.h"
47 #include "nsTArray.h"
48 #include "nsThreadUtils.h"
49 #include "nsTraceRefcnt.h"
50 #include "nsXULAppAPI.h"
51 #include "nsXPCOMPrivate.h"
52 #include "prthread.h"
53 
54 #include <functional>
55 
56 #ifdef RELEASE_OR_BETA
57 #  define THREADSAFETY_ASSERT MOZ_ASSERT
58 #else
59 #  define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
60 #endif
61 
62 #define CRASH_IN_CHILD_PROCESS(_msg) \
63   do {                               \
64     if (XRE_IsParentProcess()) {     \
65       MOZ_ASSERT(false, _msg);       \
66     } else {                         \
67       MOZ_CRASH(_msg);               \
68     }                                \
69   } while (0)
70 
71 using namespace mozilla;
72 using namespace mozilla::dom;
73 using namespace mozilla::ipc;
74 using namespace mozilla::net;
75 
76 namespace {
77 
78 class ChildImpl;
79 
80 // -----------------------------------------------------------------------------
81 // Utility Functions
82 // -----------------------------------------------------------------------------
83 
AssertIsInMainOrSocketProcess()84 void AssertIsInMainOrSocketProcess() {
85   MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
86 }
87 
AssertIsOnMainThread()88 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
89 
90 // -----------------------------------------------------------------------------
91 // ParentImpl Declaration
92 // -----------------------------------------------------------------------------
93 
94 class ParentImpl final : public BackgroundParentImpl {
95   friend class ChildImpl;
96   friend class mozilla::ipc::BackgroundParent;
97   friend class mozilla::ipc::BackgroundStarterParent;
98 
99  private:
100   class ShutdownObserver;
101 
102   struct MOZ_STACK_CLASS TimerCallbackClosure {
103     nsIThread* mThread;
104     nsTArray<IToplevelProtocol*>* mLiveActors;
105 
TimerCallbackClosure__anonc429a1a90111::ParentImpl::TimerCallbackClosure106     TimerCallbackClosure(nsIThread* aThread,
107                          nsTArray<IToplevelProtocol*>* aLiveActors)
108         : mThread(aThread), mLiveActors(aLiveActors) {
109       AssertIsInMainOrSocketProcess();
110       AssertIsOnMainThread();
111       MOZ_ASSERT(aThread);
112       MOZ_ASSERT(aLiveActors);
113     }
114   };
115 
116   // The length of time we will wait at shutdown for all actors to clean
117   // themselves up before forcing them to be destroyed.
118   static const uint32_t kShutdownTimerDelayMS = 10000;
119 
120   // This is only modified on the main thread. It is null if the thread does not
121   // exist or is shutting down.
122   static StaticRefPtr<nsIThread> sBackgroundThread;
123 
124   // This is created and destroyed on the main thread but only modified on the
125   // background thread. It is specific to each instance of sBackgroundThread.
126   static nsTArray<IToplevelProtocol*>* sLiveActorsForBackgroundThread;
127 
128   // This is only modified on the main thread.
129   static StaticRefPtr<nsITimer> sShutdownTimer;
130 
131   // This exists so that that [Assert]IsOnBackgroundThread() can continue to
132   // work during shutdown.
133   static Atomic<PRThread*> sBackgroundPRThread;
134 
135   // Maintains a count of live actors so that the background thread can be shut
136   // down when it is no longer needed.
137   // May be incremented on either the background thread (by an existing actor)
138   // or on the main thread, but must be decremented on the main thread.
139   static Atomic<uint64_t> sLiveActorCount;
140 
141   // This is only modified on the main thread. It is true after the shutdown
142   // observer is registered and is never unset thereafter.
143   static bool sShutdownObserverRegistered;
144 
145   // This is only modified on the main thread. It prevents us from trying to
146   // create the background thread after application shutdown has started.
147   static bool sShutdownHasStarted;
148 
149   // Only touched on the main thread, null if this is a same-process actor.
150   RefPtr<ContentParent> mContent;
151 
152   // Set when the actor is opened successfully and used to handle shutdown
153   // hangs. Only touched on the background thread.
154   nsTArray<IToplevelProtocol*>* mLiveActorArray;
155 
156   // Set at construction to indicate whether this parent actor corresponds to a
157   // child actor in another process or to a child actor from a different thread
158   // in the same process.
159   const bool mIsOtherProcessActor;
160 
161   // Set after ActorDestroy has been called. Only touched on the background
162   // thread.
163   bool mActorDestroyed;
164 
165  public:
IsOnBackgroundThread()166   static bool IsOnBackgroundThread() {
167     return PR_GetCurrentThread() == sBackgroundPRThread;
168   }
169 
AssertIsOnBackgroundThread()170   static void AssertIsOnBackgroundThread() {
171     THREADSAFETY_ASSERT(IsOnBackgroundThread());
172   }
173 
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)
179 
180   void Destroy();
181 
182  private:
183   // Forwarded from BackgroundParent.
184   static bool IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
185 
186   // Forwarded from BackgroundParent.
187   static already_AddRefed<ContentParent> GetContentParent(
188       PBackgroundParent* aBackgroundActor);
189 
190   // Forwarded from BackgroundParent.
191   static intptr_t GetRawContentParentForComparison(
192       PBackgroundParent* aBackgroundActor);
193 
194   // Forwarded from BackgroundParent.
195   static uint64_t GetChildID(PBackgroundParent* aBackgroundActor);
196 
197   // Forwarded from BackgroundParent.
198   static bool AllocStarter(ContentParent* aContent,
199                            Endpoint<PBackgroundStarterParent>&& aEndpoint,
200                            bool aCrossProcess = true);
201 
202   static bool CreateBackgroundThread();
203 
204   static void ShutdownBackgroundThread();
205 
206   static void ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
207 
208   // NOTE: ParentImpl could be used in 4 cases below.
209   // 1. Within the parent process.
210   // 2. Between parent process and content process.
211   // 3. Between socket process and content process.
212   // 4. Between parent process and socket process.
213   // |aContent| should be not null for case 2. For cases 1, 3 and 4, it's null.
ParentImpl(already_AddRefed<ContentParent> && aContent,bool aIsOtherProcessActor)214   explicit ParentImpl(already_AddRefed<ContentParent>&& aContent,
215                       bool aIsOtherProcessActor)
216       : mContent(std::move(aContent)),
217         mLiveActorArray(nullptr),
218         mIsOtherProcessActor(aIsOtherProcessActor),
219         mActorDestroyed(false) {
220     MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
221     MOZ_ASSERT_IF(!aIsOtherProcessActor, XRE_IsParentProcess());
222   }
223 
~ParentImpl()224   ~ParentImpl() {
225     AssertIsInMainOrSocketProcess();
226     AssertIsOnMainThread();
227     MOZ_ASSERT(!mContent);
228   }
229 
230   void MainThreadActorDestroy();
231 
SetLiveActorArray(nsTArray<IToplevelProtocol * > * aLiveActorArray)232   void SetLiveActorArray(nsTArray<IToplevelProtocol*>* aLiveActorArray) {
233     AssertIsInMainOrSocketProcess();
234     AssertIsOnBackgroundThread();
235     MOZ_ASSERT(aLiveActorArray);
236     MOZ_ASSERT(!aLiveActorArray->Contains(this));
237     MOZ_ASSERT(!mLiveActorArray);
238     MOZ_ASSERT(mIsOtherProcessActor);
239 
240     mLiveActorArray = aLiveActorArray;
241     mLiveActorArray->AppendElement(this);
242   }
243 
244   // These methods are only called by IPDL.
245   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
246 };
247 
248 // -----------------------------------------------------------------------------
249 // ChildImpl Declaration
250 // -----------------------------------------------------------------------------
251 
252 class ChildImpl final : public BackgroundChildImpl {
253   friend class mozilla::ipc::BackgroundChild;
254   friend class mozilla::ipc::BackgroundChildImpl;
255   friend class mozilla::ipc::BackgroundStarterChild;
256 
257   typedef base::ProcessId ProcessId;
258 
259   class ShutdownObserver;
260 
261  public:
262   struct ThreadLocalInfo {
ThreadLocalInfo__anonc429a1a90111::ChildImpl::ThreadLocalInfo263     ThreadLocalInfo()
264 #ifdef DEBUG
265         : mClosed(false)
266 #endif
267     {
268     }
269 
270     RefPtr<ChildImpl> mActor;
271     UniquePtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
272 #ifdef DEBUG
273     bool mClosed;
274 #endif
275   };
276 
277  private:
278   // A thread-local index that is not valid.
279   static constexpr unsigned int kBadThreadLocalIndex =
280       static_cast<unsigned int>(-1);
281 
282   // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
283   // also provides some common functions for creating PBackground IPC actor.
284   class ThreadInfoWrapper final {
285     friend class ChildImpl;
286 
287    public:
288     using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int,
289                                      nsIEventTarget*, ChildImpl**);
290 
291     ThreadInfoWrapper() = default;
292 
Startup()293     void Startup() {
294       MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex,
295                  "ThreadInfoWrapper::Startup() called more than once!");
296 
297       PRStatus status =
298           PR_NewThreadPrivateIndex(&mThreadLocalIndex, ThreadLocalDestructor);
299       MOZ_RELEASE_ASSERT(status == PR_SUCCESS,
300                          "PR_NewThreadPrivateIndex failed!");
301 
302       MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex);
303     }
304 
Shutdown()305     void Shutdown() {
306       if (sShutdownHasStarted) {
307         MOZ_ASSERT_IF(mThreadLocalIndex != kBadThreadLocalIndex,
308                       !PR_GetThreadPrivate(mThreadLocalIndex));
309         return;
310       }
311 
312       if (mThreadLocalIndex == kBadThreadLocalIndex) {
313         return;
314       }
315 
316       RefPtr<BackgroundStarterChild> starter;
317       {
318         auto lock = mStarter.Lock();
319         starter = lock->forget();
320       }
321       if (starter) {
322         CloseStarter(starter);
323       }
324 
325       ThreadLocalInfo* threadLocalInfo;
326 #ifdef DEBUG
327       threadLocalInfo =
328           static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
329       MOZ_ASSERT(!threadLocalInfo);
330 #endif
331 
332       threadLocalInfo = mMainThreadInfo;
333       if (threadLocalInfo) {
334 #ifdef DEBUG
335         MOZ_ASSERT(!threadLocalInfo->mClosed);
336         threadLocalInfo->mClosed = true;
337 #endif
338 
339         ThreadLocalDestructor(threadLocalInfo);
340         mMainThreadInfo = nullptr;
341       }
342     }
343 
344     template <typename Actor>
InitStarter(Actor * aActor)345     void InitStarter(Actor* aActor) {
346       AssertIsOnMainThread();
347 
348       // Create a pair of endpoints and send them to the other process.
349       Endpoint<PBackgroundStarterParent> parent;
350       Endpoint<PBackgroundStarterChild> child;
351       MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
352           aActor->OtherPid(), base::GetCurrentProcId(), &parent, &child));
353       MOZ_ALWAYS_TRUE(aActor->SendInitBackground(std::move(parent)));
354 
355       InitStarter(std::move(child));
356     }
357 
InitStarter(Endpoint<PBackgroundStarterChild> && aEndpoint)358     void InitStarter(Endpoint<PBackgroundStarterChild>&& aEndpoint) {
359       AssertIsOnMainThread();
360 
361       base::ProcessId otherPid = aEndpoint.OtherPid();
362 
363       nsCOMPtr<nsISerialEventTarget> taskQueue;
364       MOZ_ALWAYS_SUCCEEDS(NS_CreateBackgroundTaskQueue(
365           "PBackgroundStarter Queue", getter_AddRefs(taskQueue)));
366 
367       RefPtr<BackgroundStarterChild> starter =
368           new BackgroundStarterChild(otherPid, taskQueue);
369 
370       taskQueue->Dispatch(NS_NewRunnableFunction(
371           "PBackgroundStarterChild Init",
372           [starter, endpoint = std::move(aEndpoint)]() mutable {
373             MOZ_ALWAYS_TRUE(endpoint.Bind(starter));
374           }));
375 
376       // Swap in the newly initialized `BackgroundStarterChild`, and close the
377       // previous one if we're replacing an existing PBackgroundStarterChild
378       // instance.
379       RefPtr<BackgroundStarterChild> prevStarter;
380       {
381         auto lock = mStarter.Lock();
382         prevStarter = lock->forget();
383         *lock = starter.forget();
384       }
385       if (prevStarter) {
386         CloseStarter(prevStarter);
387       }
388     }
389 
CloseForCurrentThread()390     void CloseForCurrentThread() {
391       MOZ_ASSERT(!NS_IsMainThread());
392 
393       if (mThreadLocalIndex == kBadThreadLocalIndex) {
394         return;
395       }
396 
397       auto* threadLocalInfo =
398           static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
399 
400       if (!threadLocalInfo) {
401         return;
402       }
403 
404 #ifdef DEBUG
405       MOZ_ASSERT(!threadLocalInfo->mClosed);
406       threadLocalInfo->mClosed = true;
407 #endif
408 
409       // Clearing the thread local will synchronously close the actor.
410       DebugOnly<PRStatus> status =
411           PR_SetThreadPrivate(mThreadLocalIndex, nullptr);
412       MOZ_ASSERT(status == PR_SUCCESS);
413     }
414 
GetOrCreateForCurrentThread()415     PBackgroundChild* GetOrCreateForCurrentThread() {
416       // Processes can be told to do final CC's during shutdown even though
417       // they never finished starting (and thus call this), because they
418       // hadn't gotten far enough to call Startup() before shutdown began.
419       if (mThreadLocalIndex == kBadThreadLocalIndex) {
420         NS_ERROR("BackgroundChild::Startup() was never called");
421         return nullptr;
422       }
423       if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted) {
424         return nullptr;
425       }
426 
427       auto* threadLocalInfo = NS_IsMainThread()
428                                   ? mMainThreadInfo
429                                   : static_cast<ThreadLocalInfo*>(
430                                         PR_GetThreadPrivate(mThreadLocalIndex));
431 
432       if (!threadLocalInfo) {
433         auto newInfo = MakeUnique<ThreadLocalInfo>();
434 
435         if (NS_IsMainThread()) {
436           mMainThreadInfo = newInfo.get();
437         } else {
438           if (PR_SetThreadPrivate(mThreadLocalIndex, newInfo.get()) !=
439               PR_SUCCESS) {
440             CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
441             return nullptr;
442           }
443         }
444 
445         threadLocalInfo = newInfo.release();
446       }
447 
448       if (threadLocalInfo->mActor) {
449         return threadLocalInfo->mActor;
450       }
451 
452       RefPtr<BackgroundStarterChild> starter;
453       {
454         auto lock = mStarter.Lock();
455         starter = *lock;
456       }
457       if (!starter) {
458         CRASH_IN_CHILD_PROCESS("No BackgroundStarterChild");
459         return nullptr;
460       }
461 
462       Endpoint<PBackgroundParent> parent;
463       Endpoint<PBackgroundChild> child;
464       nsresult rv;
465       rv = PBackground::CreateEndpoints(
466           starter->mOtherPid, base::GetCurrentProcId(), &parent, &child);
467       if (NS_FAILED(rv)) {
468         NS_WARNING("Failed to create top level actor!");
469         return nullptr;
470       }
471 
472       RefPtr<ChildImpl> strongActor = new ChildImpl();
473       if (!child.Bind(strongActor)) {
474         CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
475         return nullptr;
476       }
477       strongActor->SetActorAlive();
478       threadLocalInfo->mActor = strongActor;
479 
480       // Dispatch to the background task queue to create the relevant actor in
481       // the remote process.
482       starter->mTaskQueue->Dispatch(NS_NewRunnableFunction(
483           "PBackground GetOrCreateForCurrentThread",
484           [starter, endpoint = std::move(parent)]() mutable {
485             if (!starter->SendInitBackground(std::move(endpoint))) {
486               NS_WARNING("Failed to create toplevel actor");
487             }
488           }));
489       return strongActor;
490     }
491 
492    private:
CloseStarter(BackgroundStarterChild * aStarter)493     static void CloseStarter(BackgroundStarterChild* aStarter) {
494       aStarter->mTaskQueue->Dispatch(NS_NewRunnableFunction(
495           "PBackgroundStarterChild Close",
496           [starter = RefPtr{aStarter}] { starter->Close(); }));
497     }
498 
499     // This is only modified on the main thread. It is the thread-local index
500     // that we use to store the BackgroundChild for each thread.
501     unsigned int mThreadLocalIndex = kBadThreadLocalIndex;
502 
503     // On the main thread, we store TLS in this global instead of in
504     // mThreadLocalIndex. That way, cooperative main threads all share the same
505     // thread info.
506     ThreadLocalInfo* mMainThreadInfo = nullptr;
507 
508     // The starter which will be used to launch PBackground instances of this
509     // type. Only modified on the main thread, but may be read by any thread
510     // wanting to start background actors.
511     StaticDataMutex<StaticRefPtr<BackgroundStarterChild>> mStarter{"mStarter"};
512   };
513 
514   // For PBackground between parent and content process.
515   static ThreadInfoWrapper sParentAndContentProcessThreadInfo;
516 
517   // For PBackground between socket and content process.
518   static ThreadInfoWrapper sSocketAndContentProcessThreadInfo;
519 
520   // For PBackground between socket and parent process.
521   static ThreadInfoWrapper sSocketAndParentProcessThreadInfo;
522 
523   // This is only modified on the main thread. It prevents us from trying to
524   // create the background thread after application shutdown has started.
525   static bool sShutdownHasStarted;
526 
527 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
528   nsISerialEventTarget* mOwningEventTarget;
529 #endif
530 
531 #ifdef DEBUG
532   bool mActorWasAlive;
533   bool mActorDestroyed;
534 #endif
535 
536  public:
537   static void Shutdown();
538 
AssertIsOnOwningThread()539   void AssertIsOnOwningThread() {
540     THREADSAFETY_ASSERT(mOwningEventTarget);
541 
542 #ifdef RELEASE_OR_BETA
543     DebugOnly<bool> current;
544 #else
545     bool current;
546 #endif
547     THREADSAFETY_ASSERT(
548         NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)));
549     THREADSAFETY_ASSERT(current);
550   }
551 
AssertActorDestroyed()552   void AssertActorDestroyed() {
553     MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
554   }
555 
ChildImpl()556   explicit ChildImpl()
557 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
558       : mOwningEventTarget(GetCurrentSerialEventTarget())
559 #endif
560 #ifdef DEBUG
561         ,
562         mActorWasAlive(false),
563         mActorDestroyed(false)
564 #endif
565   {
566     AssertIsOnOwningThread();
567   }
568 
SetActorAlive()569   void SetActorAlive() {
570     AssertIsOnOwningThread();
571     MOZ_ASSERT(!mActorWasAlive);
572     MOZ_ASSERT(!mActorDestroyed);
573 
574 #ifdef DEBUG
575     mActorWasAlive = true;
576 #endif
577   }
578 
579   NS_INLINE_DECL_REFCOUNTING(ChildImpl, override)
580 
581  private:
582   // Forwarded from BackgroundChild.
583   static void Startup();
584 
585   // Forwarded from BackgroundChild.
586   static PBackgroundChild* GetForCurrentThread();
587 
588   // Forwarded from BackgroundChild.
589   static PBackgroundChild* GetOrCreateForCurrentThread();
590 
591   // Forwarded from BackgroundChild.
592   static PBackgroundChild* GetOrCreateSocketActorForCurrentThread();
593 
594   // Forwarded from BackgroundChild.
595   static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread();
596 
597   static void CloseForCurrentThread();
598 
599   // Forwarded from BackgroundChildImpl.
600   static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread();
601 
602   // Forwarded from BackgroundChild.
603   static void InitContentStarter(mozilla::dom::ContentChild* aContent);
604 
605   // Forwarded from BackgroundChild.
606   static void InitSocketStarter(mozilla::net::SocketProcessChild* aSocket);
607 
608   // Forwarded from BackgroundChild.
609   static void InitSocketBridgeStarter(
610       mozilla::net::SocketProcessBridgeChild* aSocketBridge);
611 
612   static void ThreadLocalDestructor(void* aThreadLocal);
613 
614   // This class is reference counted.
~ChildImpl()615   ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed); }
616 
617   // Only called by IPDL.
618   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
619 };
620 
621 // -----------------------------------------------------------------------------
622 // ParentImpl Helper Declarations
623 // -----------------------------------------------------------------------------
624 
625 class ParentImpl::ShutdownObserver final : public nsIObserver {
626  public:
ShutdownObserver()627   ShutdownObserver() { AssertIsOnMainThread(); }
628 
629   NS_DECL_ISUPPORTS
630   NS_DECL_NSIOBSERVER
631 
632  private:
~ShutdownObserver()633   ~ShutdownObserver() { AssertIsOnMainThread(); }
634 };
635 
636 // -----------------------------------------------------------------------------
637 // ChildImpl Helper Declarations
638 // -----------------------------------------------------------------------------
639 
640 class ChildImpl::ShutdownObserver final : public nsIObserver {
641  public:
ShutdownObserver()642   ShutdownObserver() { AssertIsOnMainThread(); }
643 
644   NS_DECL_ISUPPORTS
645   NS_DECL_NSIOBSERVER
646 
647  private:
~ShutdownObserver()648   ~ShutdownObserver() { AssertIsOnMainThread(); }
649 };
650 
651 }  // namespace
652 
653 namespace mozilla {
654 namespace ipc {
655 
IsOnBackgroundThread()656 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
657 
658 #ifdef DEBUG
659 
AssertIsOnBackgroundThread()660 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
661 
662 #endif  // DEBUG
663 
664 }  // namespace ipc
665 }  // namespace mozilla
666 
667 // -----------------------------------------------------------------------------
668 // BackgroundParent Public Methods
669 // -----------------------------------------------------------------------------
670 
671 // static
IsOtherProcessActor(PBackgroundParent * aBackgroundActor)672 bool BackgroundParent::IsOtherProcessActor(
673     PBackgroundParent* aBackgroundActor) {
674   return ParentImpl::IsOtherProcessActor(aBackgroundActor);
675 }
676 
677 // static
GetContentParent(PBackgroundParent * aBackgroundActor)678 already_AddRefed<ContentParent> BackgroundParent::GetContentParent(
679     PBackgroundParent* aBackgroundActor) {
680   return ParentImpl::GetContentParent(aBackgroundActor);
681 }
682 
683 // static
GetRawContentParentForComparison(PBackgroundParent * aBackgroundActor)684 intptr_t BackgroundParent::GetRawContentParentForComparison(
685     PBackgroundParent* aBackgroundActor) {
686   return ParentImpl::GetRawContentParentForComparison(aBackgroundActor);
687 }
688 
689 // static
GetChildID(PBackgroundParent * aBackgroundActor)690 uint64_t BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor) {
691   return ParentImpl::GetChildID(aBackgroundActor);
692 }
693 
694 // static
AllocStarter(ContentParent * aContent,Endpoint<PBackgroundStarterParent> && aEndpoint)695 bool BackgroundParent::AllocStarter(
696     ContentParent* aContent, Endpoint<PBackgroundStarterParent>&& aEndpoint) {
697   return ParentImpl::AllocStarter(aContent, std::move(aEndpoint));
698 }
699 
700 // -----------------------------------------------------------------------------
701 // BackgroundChild Public Methods
702 // -----------------------------------------------------------------------------
703 
704 // static
Startup()705 void BackgroundChild::Startup() { ChildImpl::Startup(); }
706 
707 // static
GetForCurrentThread()708 PBackgroundChild* BackgroundChild::GetForCurrentThread() {
709   return ChildImpl::GetForCurrentThread();
710 }
711 
712 // static
GetOrCreateForCurrentThread()713 PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread() {
714   return ChildImpl::GetOrCreateForCurrentThread();
715 }
716 
717 // static
GetOrCreateSocketActorForCurrentThread()718 PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread() {
719   return ChildImpl::GetOrCreateSocketActorForCurrentThread();
720 }
721 
722 // static
723 PBackgroundChild*
GetOrCreateForSocketParentBridgeForCurrentThread()724 BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread() {
725   return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread();
726 }
727 
728 // static
CloseForCurrentThread()729 void BackgroundChild::CloseForCurrentThread() {
730   ChildImpl::CloseForCurrentThread();
731 }
732 
733 // static
InitContentStarter(ContentChild * aContent)734 void BackgroundChild::InitContentStarter(ContentChild* aContent) {
735   ChildImpl::InitContentStarter(aContent);
736 }
737 
738 // static
InitSocketStarter(net::SocketProcessChild * aSocket)739 void BackgroundChild::InitSocketStarter(net::SocketProcessChild* aSocket) {
740   ChildImpl::InitSocketStarter(aSocket);
741 }
742 
743 // static
InitSocketBridgeStarter(net::SocketProcessBridgeChild * aSocketBridge)744 void BackgroundChild::InitSocketBridgeStarter(
745     net::SocketProcessBridgeChild* aSocketBridge) {
746   ChildImpl::InitSocketBridgeStarter(aSocketBridge);
747 }
748 
749 // -----------------------------------------------------------------------------
750 // BackgroundChildImpl Public Methods
751 // -----------------------------------------------------------------------------
752 
753 // static
754 BackgroundChildImpl::ThreadLocal*
GetThreadLocalForCurrentThread()755 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
756   return ChildImpl::GetThreadLocalForCurrentThread();
757 }
758 
759 // -----------------------------------------------------------------------------
760 // ParentImpl Static Members
761 // -----------------------------------------------------------------------------
762 
763 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
764 
765 nsTArray<IToplevelProtocol*>* ParentImpl::sLiveActorsForBackgroundThread;
766 
767 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
768 
769 Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
770 
771 Atomic<uint64_t> ParentImpl::sLiveActorCount;
772 
773 bool ParentImpl::sShutdownObserverRegistered = false;
774 
775 bool ParentImpl::sShutdownHasStarted = false;
776 
777 // -----------------------------------------------------------------------------
778 // ChildImpl Static Members
779 // -----------------------------------------------------------------------------
780 
781 ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo;
782 
783 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo;
784 
785 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo;
786 
787 bool ChildImpl::sShutdownHasStarted = false;
788 
789 // -----------------------------------------------------------------------------
790 // ParentImpl Implementation
791 // -----------------------------------------------------------------------------
792 
793 // static
IsOtherProcessActor(PBackgroundParent * aBackgroundActor)794 bool ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) {
795   AssertIsOnBackgroundThread();
796   MOZ_ASSERT(aBackgroundActor);
797 
798   return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
799 }
800 
801 // static
GetContentParent(PBackgroundParent * aBackgroundActor)802 already_AddRefed<ContentParent> ParentImpl::GetContentParent(
803     PBackgroundParent* aBackgroundActor) {
804   AssertIsOnBackgroundThread();
805   MOZ_ASSERT(aBackgroundActor);
806 
807   auto actor = static_cast<ParentImpl*>(aBackgroundActor);
808   if (actor->mActorDestroyed) {
809     MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
810     return nullptr;
811   }
812 
813   if (actor->mContent) {
814     // We need to hand out a reference to our ContentParent but we also need to
815     // keep the one we have. We can't call AddRef here because ContentParent is
816     // not threadsafe so instead we dispatch a runnable to the main thread to do
817     // it for us. This is safe since we are guaranteed that our AddRef runnable
818     // will run before the reference we hand out can be released, and the
819     // ContentParent can't die as long as the existing reference is maintained.
820     //
821     // XXX: Why can't we use `nsMainThreadPtrHandle` here instead?
822     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
823         "ContentParent::AddRef", actor->mContent, &ContentParent::AddRef)));
824   }
825 
826   return already_AddRefed<ContentParent>(actor->mContent.get());
827 }
828 
829 // static
GetRawContentParentForComparison(PBackgroundParent * aBackgroundActor)830 intptr_t ParentImpl::GetRawContentParentForComparison(
831     PBackgroundParent* aBackgroundActor) {
832   AssertIsOnBackgroundThread();
833   MOZ_ASSERT(aBackgroundActor);
834 
835   auto actor = static_cast<ParentImpl*>(aBackgroundActor);
836   if (actor->mActorDestroyed) {
837     MOZ_ASSERT(false,
838                "GetRawContentParentForComparison called after ActorDestroy was "
839                "called!");
840     return intptr_t(-1);
841   }
842 
843   return intptr_t(static_cast<ContentParent*>(actor->mContent.get()));
844 }
845 
846 // static
GetChildID(PBackgroundParent * aBackgroundActor)847 uint64_t ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor) {
848   AssertIsOnBackgroundThread();
849   MOZ_ASSERT(aBackgroundActor);
850 
851   auto actor = static_cast<ParentImpl*>(aBackgroundActor);
852   if (actor->mActorDestroyed) {
853     MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
854     return 0;
855   }
856 
857   if (actor->mContent) {
858     return actor->mContent->ChildID();
859   }
860 
861   return 0;
862 }
863 
864 // static
AllocStarter(ContentParent * aContent,Endpoint<PBackgroundStarterParent> && aEndpoint,bool aCrossProcess)865 bool ParentImpl::AllocStarter(ContentParent* aContent,
866                               Endpoint<PBackgroundStarterParent>&& aEndpoint,
867                               bool aCrossProcess) {
868   AssertIsInMainOrSocketProcess();
869   AssertIsOnMainThread();
870 
871   MOZ_ASSERT(aEndpoint.IsValid());
872 
873   if (!sBackgroundThread && !CreateBackgroundThread()) {
874     NS_WARNING("Failed to create background thread!");
875     return false;
876   }
877 
878   sLiveActorCount++;
879 
880   RefPtr<BackgroundStarterParent> actor =
881       new BackgroundStarterParent(aContent, aCrossProcess);
882 
883   if (NS_FAILED(sBackgroundThread->Dispatch(NS_NewRunnableFunction(
884           "BackgroundStarterParent::ConnectActorRunnable",
885           [actor = std::move(actor), endpoint = std::move(aEndpoint),
886            liveActorArray = sLiveActorsForBackgroundThread]() mutable {
887             MOZ_ASSERT(endpoint.IsValid());
888             MOZ_ALWAYS_TRUE(endpoint.Bind(actor));
889             actor->SetLiveActorArray(liveActorArray);
890           })))) {
891     NS_WARNING("Failed to dispatch connect runnable!");
892 
893     MOZ_ASSERT(sLiveActorCount);
894     sLiveActorCount--;
895   }
896 
897   return true;
898 }
899 
900 // static
CreateBackgroundThread()901 bool ParentImpl::CreateBackgroundThread() {
902   AssertIsInMainOrSocketProcess();
903   AssertIsOnMainThread();
904   MOZ_ASSERT(!sBackgroundThread);
905   MOZ_ASSERT(!sLiveActorsForBackgroundThread);
906 
907   if (sShutdownHasStarted) {
908     NS_WARNING(
909         "Trying to create background thread after shutdown has "
910         "already begun!");
911     return false;
912   }
913 
914   nsCOMPtr<nsITimer> newShutdownTimer;
915 
916   if (!sShutdownTimer) {
917     newShutdownTimer = NS_NewTimer();
918     if (!newShutdownTimer) {
919       return false;
920     }
921   }
922 
923   if (!sShutdownObserverRegistered) {
924     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
925     if (NS_WARN_IF(!obs)) {
926       return false;
927     }
928 
929     nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
930 
931     nsresult rv = obs->AddObserver(
932         observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
933     if (NS_WARN_IF(NS_FAILED(rv))) {
934       return false;
935     }
936 
937     sShutdownObserverRegistered = true;
938   }
939 
940   nsCOMPtr<nsIThread> thread;
941   if (NS_FAILED(NS_NewNamedThread(
942           "IPDL Background", getter_AddRefs(thread),
943           NS_NewRunnableFunction(
944               "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
945                 DebugOnly<PRThread*> oldBackgroundThread =
946                     sBackgroundPRThread.exchange(PR_GetCurrentThread());
947 
948                 MOZ_ASSERT_IF(oldBackgroundThread,
949                               PR_GetCurrentThread() != oldBackgroundThread);
950               })))) {
951     NS_WARNING("NS_NewNamedThread failed!");
952     return false;
953   }
954 
955   sBackgroundThread = thread.forget();
956 
957   sLiveActorsForBackgroundThread = new nsTArray<IToplevelProtocol*>(1);
958 
959   if (!sShutdownTimer) {
960     MOZ_ASSERT(newShutdownTimer);
961     sShutdownTimer = newShutdownTimer;
962   }
963 
964   return true;
965 }
966 
967 // static
ShutdownBackgroundThread()968 void ParentImpl::ShutdownBackgroundThread() {
969   AssertIsInMainOrSocketProcess();
970   AssertIsOnMainThread();
971   MOZ_ASSERT(sShutdownHasStarted);
972   MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
973   MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
974 
975   nsCOMPtr<nsITimer> shutdownTimer = sShutdownTimer.get();
976   sShutdownTimer = nullptr;
977 
978   if (sBackgroundThread) {
979     nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
980     sBackgroundThread = nullptr;
981 
982     UniquePtr<nsTArray<IToplevelProtocol*>> liveActors(
983         sLiveActorsForBackgroundThread);
984     sLiveActorsForBackgroundThread = nullptr;
985 
986     MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
987 
988     if (sLiveActorCount) {
989       // We need to spin the event loop while we wait for all the actors to be
990       // cleaned up. We also set a timeout to force-kill any hanging actors.
991       TimerCallbackClosure closure(thread, liveActors.get());
992 
993       MOZ_ALWAYS_SUCCEEDS(shutdownTimer->InitWithNamedFuncCallback(
994           &ShutdownTimerCallback, &closure, kShutdownTimerDelayMS,
995           nsITimer::TYPE_ONE_SHOT, "ParentImpl::ShutdownTimerCallback"));
996 
997       SpinEventLoopUntil("ParentImpl::ShutdownBackgroundThread"_ns,
998                          [&]() { return !sLiveActorCount; });
999 
1000       MOZ_ASSERT(liveActors->IsEmpty());
1001 
1002       MOZ_ALWAYS_SUCCEEDS(shutdownTimer->Cancel());
1003     }
1004 
1005     // Dispatch this runnable to unregister the PR thread from the profiler.
1006     MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(NS_NewRunnableFunction(
1007         "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
1008           // It is possible that another background thread was created while
1009           // this thread was shutting down. In that case we can't assert
1010           // anything about sBackgroundPRThread and we should not modify it
1011           // here.
1012           sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
1013         })));
1014 
1015     MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
1016   }
1017 }
1018 
1019 // static
ShutdownTimerCallback(nsITimer * aTimer,void * aClosure)1020 void ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure) {
1021   AssertIsInMainOrSocketProcess();
1022   AssertIsOnMainThread();
1023   MOZ_ASSERT(sShutdownHasStarted);
1024   MOZ_ASSERT(sLiveActorCount);
1025 
1026   auto closure = static_cast<TimerCallbackClosure*>(aClosure);
1027   MOZ_ASSERT(closure);
1028 
1029   // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1030   // finished.
1031   sLiveActorCount++;
1032 
1033   InvokeAsync(
1034       closure->mThread, __func__,
1035       [liveActors = closure->mLiveActors]() {
1036         MOZ_ASSERT(liveActors);
1037 
1038         if (!liveActors->IsEmpty()) {
1039           // Copy the array since calling Close() could mutate the
1040           // actual array.
1041           nsTArray<IToplevelProtocol*> actorsToClose(liveActors->Clone());
1042           for (IToplevelProtocol* actor : actorsToClose) {
1043             actor->Close();
1044           }
1045         }
1046         return GenericPromise::CreateAndResolve(true, __func__);
1047       })
1048       ->Then(GetCurrentSerialEventTarget(), __func__, []() {
1049         MOZ_ASSERT(sLiveActorCount);
1050         sLiveActorCount--;
1051       });
1052 }
1053 
Destroy()1054 void ParentImpl::Destroy() {
1055   // May be called on any thread!
1056 
1057   AssertIsInMainOrSocketProcess();
1058 
1059   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1060       NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1061                                  &ParentImpl::MainThreadActorDestroy)));
1062 }
1063 
MainThreadActorDestroy()1064 void ParentImpl::MainThreadActorDestroy() {
1065   AssertIsInMainOrSocketProcess();
1066   AssertIsOnMainThread();
1067   MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1068 
1069   mContent = nullptr;
1070 
1071   MOZ_ASSERT(sLiveActorCount);
1072   sLiveActorCount--;
1073 
1074   // This may be the last reference!
1075   Release();
1076 }
1077 
ActorDestroy(ActorDestroyReason aWhy)1078 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy) {
1079   AssertIsInMainOrSocketProcess();
1080   AssertIsOnBackgroundThread();
1081   MOZ_ASSERT(!mActorDestroyed);
1082   MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1083 
1084   BackgroundParentImpl::ActorDestroy(aWhy);
1085 
1086   mActorDestroyed = true;
1087 
1088   if (mLiveActorArray) {
1089     MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1090     mLiveActorArray = nullptr;
1091   }
1092 
1093   // This is tricky. We should be able to call Destroy() here directly because
1094   // we're not going to touch 'this' or our MessageChannel any longer on this
1095   // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1096   // it runs it will destroy 'this' and our associated MessageChannel. However,
1097   // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1098   // racing with the main thread we must ensure that the MessageChannel lives
1099   // long enough to be cleared in this call stack.
1100 
1101   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1102       "ParentImpl::Destroy", this, &ParentImpl::Destroy)));
1103 }
1104 
NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver,nsIObserver)1105 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1106 
1107 NS_IMETHODIMP
1108 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1109                                       const char16_t* aData) {
1110   AssertIsInMainOrSocketProcess();
1111   AssertIsOnMainThread();
1112   MOZ_ASSERT(!sShutdownHasStarted);
1113   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1114 
1115   sShutdownHasStarted = true;
1116 
1117   // Do this first before calling (and spinning the event loop in)
1118   // ShutdownBackgroundThread().
1119   ChildImpl::Shutdown();
1120 
1121   ShutdownBackgroundThread();
1122 
1123   return NS_OK;
1124 }
1125 
BackgroundStarterParent(ContentParent * aContent,bool aCrossProcess)1126 BackgroundStarterParent::BackgroundStarterParent(ContentParent* aContent,
1127                                                  bool aCrossProcess)
1128     : mCrossProcess(aCrossProcess), mContent(aContent) {
1129   AssertIsOnMainThread();
1130   AssertIsInMainOrSocketProcess();
1131   MOZ_ASSERT_IF(!mCrossProcess, !mContent);
1132   MOZ_ASSERT_IF(!mCrossProcess, XRE_IsParentProcess());
1133 }
1134 
SetLiveActorArray(nsTArray<IToplevelProtocol * > * aLiveActorArray)1135 void BackgroundStarterParent::SetLiveActorArray(
1136     nsTArray<IToplevelProtocol*>* aLiveActorArray) {
1137   AssertIsInMainOrSocketProcess();
1138   AssertIsOnBackgroundThread();
1139   MOZ_ASSERT(aLiveActorArray);
1140   MOZ_ASSERT(!aLiveActorArray->Contains(this));
1141   MOZ_ASSERT(!mLiveActorArray);
1142   MOZ_ASSERT_IF(!mCrossProcess, OtherPid() == base::GetCurrentProcId());
1143 
1144   mLiveActorArray = aLiveActorArray;
1145   mLiveActorArray->AppendElement(this);
1146 }
1147 
RecvInitBackground(Endpoint<PBackgroundParent> && aEndpoint)1148 IPCResult BackgroundStarterParent::RecvInitBackground(
1149     Endpoint<PBackgroundParent>&& aEndpoint) {
1150   AssertIsOnBackgroundThread();
1151 
1152   if (!aEndpoint.IsValid()) {
1153     return IPC_FAIL(this,
1154                     "Cannot initialize PBackground with invalid endpoint");
1155   }
1156 
1157   if (mContent) {
1158     // We need to hand out a reference to our ContentParent for the new
1159     // ParentImpl actor, but we also need to keep the one we have. We can't call
1160     // AddRef here because ContentParent is not threadsafe so instead we
1161     // dispatch a runnable to the main thread to do it for us. This is safe
1162     // since we are guaranteed that our AddRef runnable will run before the
1163     // reference we hand out can be released, and the ContentParent can't die as
1164     // long as the existing reference is maintained.
1165     //
1166     // XXX: Why can't we use `nsMainThreadPtrHandle` here?
1167     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
1168         "ContentParent::AddRef", mContent, &ContentParent::AddRef)));
1169   }
1170 
1171   ParentImpl* actor = new ParentImpl(
1172       already_AddRefed<ContentParent>(mContent.get()), mCrossProcess);
1173 
1174   // Take a reference on this thread. If Open() fails then we will release this
1175   // reference in Destroy.
1176   NS_ADDREF(actor);
1177 
1178   ParentImpl::sLiveActorCount++;
1179 
1180   if (!aEndpoint.Bind(actor)) {
1181     actor->Destroy();
1182     return IPC_OK();
1183   }
1184 
1185   if (mCrossProcess) {
1186     actor->SetLiveActorArray(mLiveActorArray);
1187   }
1188   return IPC_OK();
1189 }
1190 
ActorDestroy(ActorDestroyReason aReason)1191 void BackgroundStarterParent::ActorDestroy(ActorDestroyReason aReason) {
1192   AssertIsOnBackgroundThread();
1193 
1194   if (mLiveActorArray) {
1195     MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1196     mLiveActorArray = nullptr;
1197   }
1198 
1199   // Make sure to decrement `sLiveActorCount` on the main thread.
1200   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NS_NewRunnableFunction(
1201       "BackgroundStarterParent::MainThreadDestroy", [self = RefPtr{this}] {
1202         self->mContent = nullptr;
1203         ParentImpl::sLiveActorCount--;
1204       })));
1205 }
1206 
1207 // -----------------------------------------------------------------------------
1208 // ChildImpl Implementation
1209 // -----------------------------------------------------------------------------
1210 
1211 // static
Startup()1212 void ChildImpl::Startup() {
1213   // This happens on the main thread but before XPCOM has started so we can't
1214   // assert that we're being called on the main thread here.
1215 
1216   sParentAndContentProcessThreadInfo.Startup();
1217   sSocketAndContentProcessThreadInfo.Startup();
1218   sSocketAndParentProcessThreadInfo.Startup();
1219 
1220   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1221   MOZ_RELEASE_ASSERT(observerService);
1222 
1223   nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1224 
1225   nsresult rv = observerService->AddObserver(
1226       observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1227   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1228 
1229   // Initialize a starter actor to allow starting PBackground within the parent
1230   // process.
1231   if (XRE_IsParentProcess()) {
1232     Endpoint<PBackgroundStarterParent> parent;
1233     Endpoint<PBackgroundStarterChild> child;
1234     MOZ_ALWAYS_SUCCEEDS(PBackgroundStarter::CreateEndpoints(
1235         base::GetCurrentProcId(), base::GetCurrentProcId(), &parent, &child));
1236 
1237     MOZ_ALWAYS_TRUE(ParentImpl::AllocStarter(nullptr, std::move(parent),
1238                                              /* aCrossProcess */ false));
1239     sParentAndContentProcessThreadInfo.InitStarter(std::move(child));
1240   }
1241 }
1242 
1243 // static
Shutdown()1244 void ChildImpl::Shutdown() {
1245   AssertIsOnMainThread();
1246 
1247   sParentAndContentProcessThreadInfo.Shutdown();
1248   sSocketAndContentProcessThreadInfo.Shutdown();
1249   sSocketAndParentProcessThreadInfo.Shutdown();
1250 
1251   sShutdownHasStarted = true;
1252 }
1253 
1254 // static
GetForCurrentThread()1255 PBackgroundChild* ChildImpl::GetForCurrentThread() {
1256   MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1257              kBadThreadLocalIndex);
1258 
1259   auto threadLocalInfo =
1260       NS_IsMainThread()
1261           ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1262           : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1263                 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1264 
1265   if (!threadLocalInfo) {
1266     return nullptr;
1267   }
1268 
1269   return threadLocalInfo->mActor;
1270 }
1271 
1272 /* static */
GetOrCreateForCurrentThread()1273 PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread() {
1274   return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread();
1275 }
1276 
1277 /* static */
GetOrCreateSocketActorForCurrentThread()1278 PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread() {
1279   return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread();
1280 }
1281 
1282 /* static */
1283 PBackgroundChild*
GetOrCreateForSocketParentBridgeForCurrentThread()1284 ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread() {
1285   return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread();
1286 }
1287 
1288 // static
CloseForCurrentThread()1289 void ChildImpl::CloseForCurrentThread() {
1290   MOZ_ASSERT(!NS_IsMainThread(),
1291              "PBackground for the main thread should be shut down via "
1292              "ChildImpl::Shutdown().");
1293 
1294   sParentAndContentProcessThreadInfo.CloseForCurrentThread();
1295   sSocketAndContentProcessThreadInfo.CloseForCurrentThread();
1296   sSocketAndParentProcessThreadInfo.CloseForCurrentThread();
1297 }
1298 
1299 // static
GetThreadLocalForCurrentThread()1300 BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
1301   MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1302                  kBadThreadLocalIndex,
1303              "BackgroundChild::Startup() was never called!");
1304 
1305   auto threadLocalInfo =
1306       NS_IsMainThread()
1307           ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1308           : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1309                 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1310 
1311   if (!threadLocalInfo) {
1312     return nullptr;
1313   }
1314 
1315   if (!threadLocalInfo->mConsumerThreadLocal) {
1316     threadLocalInfo->mConsumerThreadLocal =
1317         MakeUnique<BackgroundChildImpl::ThreadLocal>();
1318   }
1319 
1320   return threadLocalInfo->mConsumerThreadLocal.get();
1321 }
1322 
1323 // static
InitContentStarter(mozilla::dom::ContentChild * aContent)1324 void ChildImpl::InitContentStarter(mozilla::dom::ContentChild* aContent) {
1325   sParentAndContentProcessThreadInfo.InitStarter(aContent);
1326 }
1327 
1328 // static
InitSocketStarter(mozilla::net::SocketProcessChild * aSocket)1329 void ChildImpl::InitSocketStarter(mozilla::net::SocketProcessChild* aSocket) {
1330   sSocketAndParentProcessThreadInfo.InitStarter(aSocket);
1331 }
1332 
1333 // static
InitSocketBridgeStarter(mozilla::net::SocketProcessBridgeChild * aSocketBridge)1334 void ChildImpl::InitSocketBridgeStarter(
1335     mozilla::net::SocketProcessBridgeChild* aSocketBridge) {
1336   sSocketAndContentProcessThreadInfo.InitStarter(aSocketBridge);
1337 }
1338 
1339 // static
ThreadLocalDestructor(void * aThreadLocal)1340 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal) {
1341   auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
1342 
1343   if (threadLocalInfo) {
1344     MOZ_ASSERT(threadLocalInfo->mClosed);
1345 
1346     if (threadLocalInfo->mActor) {
1347       threadLocalInfo->mActor->Close();
1348       threadLocalInfo->mActor->AssertActorDestroyed();
1349     }
1350 
1351     delete threadLocalInfo;
1352   }
1353 }
1354 
ActorDestroy(ActorDestroyReason aWhy)1355 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy) {
1356   AssertIsOnOwningThread();
1357 
1358 #ifdef DEBUG
1359   MOZ_ASSERT(!mActorDestroyed);
1360   mActorDestroyed = true;
1361 #endif
1362 
1363   BackgroundChildImpl::ActorDestroy(aWhy);
1364 }
1365 
NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver,nsIObserver)1366 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1367 
1368 NS_IMETHODIMP
1369 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1370                                      const char16_t* aData) {
1371   AssertIsOnMainThread();
1372   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1373 
1374   ChildImpl::Shutdown();
1375 
1376   return NS_OK;
1377 }
1378