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 "base/process_util.h"
13 #include "base/task.h"
14 #include "FileDescriptor.h"
15 #include "GeckoProfiler.h"
16 #include "InputStreamUtils.h"
17 #include "mozilla/AbstractThread.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/StaticPtr.h"
25 #include "mozilla/Unused.h"
26 #include "mozilla/dom/ContentChild.h"
27 #include "mozilla/dom/ContentParent.h"
28 #include "mozilla/dom/File.h"
29 #include "mozilla/dom/WorkerPrivate.h"
30 #include "mozilla/dom/WorkerRef.h"
31 #include "mozilla/ipc/ProtocolTypes.h"
32 #include "mozilla/net/SocketProcessChild.h"
33 #include "mozilla/net/SocketProcessBridgeChild.h"
34 #include "nsCOMPtr.h"
35 #include "nsIEventTarget.h"
36 #include "nsIObserver.h"
37 #include "nsIObserverService.h"
38 #include "nsIRunnable.h"
39 #include "nsISupportsImpl.h"
40 #include "nsIThread.h"
41 #include "nsITimer.h"
42 #include "nsTArray.h"
43 #include "nsThreadUtils.h"
44 #include "nsTraceRefcnt.h"
45 #include "nsXULAppAPI.h"
46 #include "nsXPCOMPrivate.h"
47 #include "prthread.h"
48 
49 #include <functional>
50 
51 #ifdef RELEASE_OR_BETA
52 #  define THREADSAFETY_ASSERT MOZ_ASSERT
53 #else
54 #  define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
55 #endif
56 
57 #define CRASH_IN_CHILD_PROCESS(_msg) \
58   do {                               \
59     if (XRE_IsParentProcess()) {     \
60       MOZ_ASSERT(false, _msg);       \
61     } else {                         \
62       MOZ_CRASH(_msg);               \
63     }                                \
64   } while (0)
65 
66 using namespace mozilla;
67 using namespace mozilla::dom;
68 using namespace mozilla::ipc;
69 using namespace mozilla::net;
70 
71 namespace {
72 
73 class ChildImpl;
74 
75 // -----------------------------------------------------------------------------
76 // Utility Functions
77 // -----------------------------------------------------------------------------
78 
AssertIsInMainProcess()79 void AssertIsInMainProcess() { MOZ_ASSERT(XRE_IsParentProcess()); }
80 
AssertIsInMainOrSocketProcess()81 void AssertIsInMainOrSocketProcess() {
82   MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
83 }
84 
AssertIsOnMainThread()85 void AssertIsOnMainThread() { THREADSAFETY_ASSERT(NS_IsMainThread()); }
86 
AssertIsNotOnMainThread()87 void AssertIsNotOnMainThread() { THREADSAFETY_ASSERT(!NS_IsMainThread()); }
88 
89 // -----------------------------------------------------------------------------
90 // ParentImpl Declaration
91 // -----------------------------------------------------------------------------
92 
93 class ParentImpl final : public BackgroundParentImpl {
94   friend class mozilla::ipc::BackgroundParent;
95 
96  private:
97   class ShutdownObserver;
98   class CreateActorHelper;
99 
100   struct MOZ_STACK_CLASS TimerCallbackClosure {
101     nsIThread* mThread;
102     nsTArray<ParentImpl*>* mLiveActors;
103 
TimerCallbackClosure__anon2639c6600111::ParentImpl::TimerCallbackClosure104     TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors)
105         : mThread(aThread), mLiveActors(aLiveActors) {
106       AssertIsInMainOrSocketProcess();
107       AssertIsOnMainThread();
108       MOZ_ASSERT(aThread);
109       MOZ_ASSERT(aLiveActors);
110     }
111   };
112 
113   // The length of time we will wait at shutdown for all actors to clean
114   // themselves up before forcing them to be destroyed.
115   static const uint32_t kShutdownTimerDelayMS = 10000;
116 
117   // This is only modified on the main thread. It is null if the thread does not
118   // exist or is shutting down.
119   static StaticRefPtr<nsIThread> sBackgroundThread;
120   static StaticRefPtr<AbstractThread> sBackgroundAbstractThread;
121 
122   // This is created and destroyed on the main thread but only modified on the
123   // background thread. It is specific to each instance of sBackgroundThread.
124   static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread;
125 
126   // This is only modified on the main thread.
127   static StaticRefPtr<nsITimer> sShutdownTimer;
128 
129   // This exists so that that [Assert]IsOnBackgroundThread() can continue to
130   // work during shutdown.
131   static Atomic<PRThread*> sBackgroundPRThread;
132 
133   // This is only modified on the main thread. It maintains a count of live
134   // actors so that the background thread can be shut down when it is no longer
135   // needed.
136   static uint64_t sLiveActorCount;
137 
138   // This is only modified on the main thread. It is true after the shutdown
139   // observer is registered and is never unset thereafter.
140   static bool sShutdownObserverRegistered;
141 
142   // This is only modified on the main thread. It prevents us from trying to
143   // create the background thread after application shutdown has started.
144   static bool sShutdownHasStarted;
145 
146   // Only touched on the main thread, null if this is a same-process actor.
147   RefPtr<ContentParent> mContent;
148 
149   // Set when the actor is opened successfully and used to handle shutdown
150   // hangs. Only touched on the background thread.
151   nsTArray<ParentImpl*>* mLiveActorArray;
152 
153   // Set at construction to indicate whether this parent actor corresponds to a
154   // child actor in another process or to a child actor from a different thread
155   // in the same process.
156   const bool mIsOtherProcessActor;
157 
158   // Set after ActorDestroy has been called. Only touched on the background
159   // thread.
160   bool mActorDestroyed;
161 
162  public:
163   static already_AddRefed<ChildImpl> CreateActorForSameProcess(
164       nsIEventTarget* aMainEventTarget);
165 
IsOnBackgroundThread()166   static bool IsOnBackgroundThread() {
167     return PR_GetCurrentThread() == sBackgroundPRThread;
168   }
169 
AssertIsOnBackgroundThread()170   static void AssertIsOnBackgroundThread() {
171     THREADSAFETY_ASSERT(IsOnBackgroundThread());
172   }
173 
174   NS_INLINE_DECL_REFCOUNTING(ParentImpl)
175 
176   void Destroy();
177 
178  private:
179   // Forwarded from BackgroundParent.
180   static bool IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
181 
182   // Forwarded from BackgroundParent.
183   static already_AddRefed<ContentParent> GetContentParent(
184       PBackgroundParent* aBackgroundActor);
185 
186   // Forwarded from BackgroundParent.
187   static intptr_t GetRawContentParentForComparison(
188       PBackgroundParent* aBackgroundActor);
189 
190   // Forwarded from BackgroundParent.
191   static uint64_t GetChildID(PBackgroundParent* aBackgroundActor);
192 
193   // Forwarded from BackgroundParent.
194   static bool GetLiveActorArray(PBackgroundParent* aBackgroundActor,
195                                 nsTArray<PBackgroundParent*>& aLiveActorArray);
196 
197   // Forwarded from BackgroundParent.
198   static bool Alloc(ContentParent* aContent,
199                     Endpoint<PBackgroundParent>&& aEndpoint);
200 
201   static bool CreateBackgroundThread();
202 
203   static void ShutdownBackgroundThread();
204 
205   static void ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
206 
207   // For same-process actors.
ParentImpl()208   ParentImpl()
209       : mLiveActorArray(nullptr),
210         mIsOtherProcessActor(false),
211         mActorDestroyed(false) {
212     AssertIsInMainProcess();
213     AssertIsOnMainThread();
214   }
215 
216   // For other-process actors.
217   // NOTE: ParentImpl could be used in 3 cases below.
218   // 1. Between parent process and content process.
219   // 2. Between socket process and content process.
220   // 3. Between parent process and socket process.
221   // |mContent| should be not null for case 1. For case 2 and 3, it's null.
ParentImpl(ContentParent * aContent)222   explicit ParentImpl(ContentParent* aContent)
223       : mContent(aContent),
224         mLiveActorArray(nullptr),
225         mIsOtherProcessActor(true),
226         mActorDestroyed(false) {
227     MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
228     AssertIsOnMainThread();
229   }
230 
~ParentImpl()231   ~ParentImpl() {
232     AssertIsInMainOrSocketProcess();
233     AssertIsOnMainThread();
234     MOZ_ASSERT(!mContent);
235   }
236 
237   void MainThreadActorDestroy();
238 
SetLiveActorArray(nsTArray<ParentImpl * > * aLiveActorArray)239   void SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray) {
240     AssertIsInMainOrSocketProcess();
241     AssertIsOnBackgroundThread();
242     MOZ_ASSERT(aLiveActorArray);
243     MOZ_ASSERT(!aLiveActorArray->Contains(this));
244     MOZ_ASSERT(!mLiveActorArray);
245     MOZ_ASSERT(mIsOtherProcessActor);
246 
247     mLiveActorArray = aLiveActorArray;
248     mLiveActorArray->AppendElement(this);
249   }
250 
251   // These methods are only called by IPDL.
252   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
253 };
254 
255 // -----------------------------------------------------------------------------
256 // ChildImpl Declaration
257 // -----------------------------------------------------------------------------
258 
259 class ChildImpl final : public BackgroundChildImpl {
260   friend class mozilla::ipc::BackgroundChild;
261   friend class mozilla::ipc::BackgroundChildImpl;
262 
263   typedef base::ProcessId ProcessId;
264   typedef mozilla::ipc::Transport Transport;
265 
266   class ShutdownObserver;
267 
268  public:
269   class SendInitBackgroundRunnable;
270 
271   struct ThreadLocalInfo {
ThreadLocalInfo__anon2639c6600111::ChildImpl::ThreadLocalInfo272     ThreadLocalInfo()
273 #ifdef DEBUG
274         : mClosed(false)
275 #endif
276     {
277     }
278 
279     RefPtr<ChildImpl> mActor;
280     RefPtr<SendInitBackgroundRunnable> mSendInitBackgroundRunnable;
281     UniquePtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
282 #ifdef DEBUG
283     bool mClosed;
284 #endif
285   };
286 
287  private:
288   // A thread-local index that is not valid.
289   static constexpr unsigned int kBadThreadLocalIndex =
290       static_cast<unsigned int>(-1);
291 
292   // ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
293   // also provides some common functions for creating PBackground IPC actor.
294   class ThreadInfoWrapper final {
295     friend class ChildImpl;
296 
297    public:
298     using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int,
299                                      nsIEventTarget*, ChildImpl**);
300 
ThreadInfoWrapper(ActorCreateFunc aFunc)301     constexpr explicit ThreadInfoWrapper(ActorCreateFunc aFunc)
302         : mThreadLocalIndex(kBadThreadLocalIndex),
303           mMainThreadInfo(nullptr),
304           mCreateActorFunc(aFunc) {}
305 
Startup()306     void Startup() {
307       MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex,
308                  "ThreadInfoWrapper::Startup() called more than once!");
309 
310       PRStatus status =
311           PR_NewThreadPrivateIndex(&mThreadLocalIndex, ThreadLocalDestructor);
312       MOZ_RELEASE_ASSERT(status == PR_SUCCESS,
313                          "PR_NewThreadPrivateIndex failed!");
314 
315       MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex);
316     }
317 
Shutdown()318     void Shutdown() {
319       if (sShutdownHasStarted) {
320         MOZ_ASSERT_IF(mThreadLocalIndex != kBadThreadLocalIndex,
321                       !PR_GetThreadPrivate(mThreadLocalIndex));
322         return;
323       }
324 
325       if (mThreadLocalIndex == kBadThreadLocalIndex) {
326         return;
327       }
328 
329       ThreadLocalInfo* threadLocalInfo;
330 #ifdef DEBUG
331       threadLocalInfo =
332           static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
333       MOZ_ASSERT(!threadLocalInfo);
334 #endif
335 
336       threadLocalInfo = mMainThreadInfo;
337       if (threadLocalInfo) {
338 #ifdef DEBUG
339         MOZ_ASSERT(!threadLocalInfo->mClosed);
340         threadLocalInfo->mClosed = true;
341 #endif
342 
343         ThreadLocalDestructor(threadLocalInfo);
344         mMainThreadInfo = nullptr;
345       }
346     }
347 
CloseForCurrentThread()348     void CloseForCurrentThread() {
349       MOZ_ASSERT(!NS_IsMainThread());
350 
351       if (mThreadLocalIndex == kBadThreadLocalIndex) {
352         return;
353       }
354 
355       auto threadLocalInfo =
356           static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
357 
358       if (!threadLocalInfo) {
359         return;
360       }
361 
362 #ifdef DEBUG
363       MOZ_ASSERT(!threadLocalInfo->mClosed);
364       threadLocalInfo->mClosed = true;
365 #endif
366 
367       // Clearing the thread local will synchronously close the actor.
368       DebugOnly<PRStatus> status =
369           PR_SetThreadPrivate(mThreadLocalIndex, nullptr);
370       MOZ_ASSERT(status == PR_SUCCESS);
371     }
372 
GetOrCreateForCurrentThread(nsIEventTarget * aMainEventTarget)373     PBackgroundChild* GetOrCreateForCurrentThread(
374         nsIEventTarget* aMainEventTarget) {
375       MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget);
376 
377       MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex,
378                  "BackgroundChild::Startup() was never called!");
379 
380       if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted) {
381         return nullptr;
382       }
383 
384       auto threadLocalInfo = NS_IsMainThread()
385                                  ? mMainThreadInfo
386                                  : static_cast<ThreadLocalInfo*>(
387                                        PR_GetThreadPrivate(mThreadLocalIndex));
388 
389       if (!threadLocalInfo) {
390         auto newInfo = MakeUnique<ThreadLocalInfo>();
391 
392         if (NS_IsMainThread()) {
393           mMainThreadInfo = newInfo.get();
394         } else {
395           if (PR_SetThreadPrivate(mThreadLocalIndex, newInfo.get()) !=
396               PR_SUCCESS) {
397             CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
398             return nullptr;
399           }
400         }
401 
402         threadLocalInfo = newInfo.release();
403       }
404 
405       PBackgroundChild* bgChild =
406           GetFromThreadInfo(aMainEventTarget, threadLocalInfo);
407       if (bgChild) {
408         return bgChild;
409       }
410 
411       RefPtr<ChildImpl> actor;
412       mCreateActorFunc(threadLocalInfo, mThreadLocalIndex, aMainEventTarget,
413                        getter_AddRefs(actor));
414       return actor;
415     }
416 
417    private:
418     // This is only modified on the main thread. It is the thread-local index
419     // that we use to store the BackgroundChild for each thread.
420     unsigned int mThreadLocalIndex;
421 
422     // On the main thread, we store TLS in this global instead of in
423     // mThreadLocalIndex. That way, cooperative main threads all share the same
424     // thread info.
425     ThreadLocalInfo* mMainThreadInfo;
426     ActorCreateFunc mCreateActorFunc;
427   };
428 
429   // For PBackground between parent and content process.
430   static ThreadInfoWrapper sParentAndContentProcessThreadInfo;
431 
432   // For PBackground between socket and content process.
433   static ThreadInfoWrapper sSocketAndContentProcessThreadInfo;
434 
435   // For PBackground between socket and parent process.
436   static ThreadInfoWrapper sSocketAndParentProcessThreadInfo;
437 
438   // This is only modified on the main thread. It prevents us from trying to
439   // create the background thread after application shutdown has started.
440   static bool sShutdownHasStarted;
441 
442 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
443   nsISerialEventTarget* mOwningEventTarget;
444 #endif
445 
446 #ifdef DEBUG
447   bool mActorWasAlive;
448   bool mActorDestroyed;
449 #endif
450 
451  public:
452   static void Shutdown();
453 
AssertIsOnOwningThread()454   void AssertIsOnOwningThread() {
455     THREADSAFETY_ASSERT(mOwningEventTarget);
456 
457 #ifdef RELEASE_OR_BETA
458     DebugOnly<bool> current;
459 #else
460     bool current;
461 #endif
462     THREADSAFETY_ASSERT(
463         NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)));
464     THREADSAFETY_ASSERT(current);
465   }
466 
AssertActorDestroyed()467   void AssertActorDestroyed() {
468     MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
469   }
470 
ChildImpl()471   explicit ChildImpl()
472 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
473       : mOwningEventTarget(GetCurrentThreadSerialEventTarget())
474 #endif
475 #ifdef DEBUG
476         ,
477         mActorWasAlive(false),
478         mActorDestroyed(false)
479 #endif
480   {
481     AssertIsOnOwningThread();
482   }
483 
SetActorAlive()484   void SetActorAlive() {
485     AssertIsOnOwningThread();
486     MOZ_ASSERT(!mActorWasAlive);
487     MOZ_ASSERT(!mActorDestroyed);
488 
489 #ifdef DEBUG
490     mActorWasAlive = true;
491 #endif
492   }
493 
494   NS_INLINE_DECL_REFCOUNTING(ChildImpl)
495 
496  private:
497   // Forwarded from BackgroundChild.
498   static void Startup();
499 
500   // Forwarded from BackgroundChild.
501   static PBackgroundChild* GetForCurrentThread();
502 
503   // Helper function for getting PBackgroundChild from thread info.
504   static PBackgroundChild* GetFromThreadInfo(nsIEventTarget* aMainEventTarget,
505                                              ThreadLocalInfo* aThreadLocalInfo);
506 
507   // Forwarded from BackgroundChild.
508   static PBackgroundChild* GetOrCreateForCurrentThread(
509       nsIEventTarget* aMainEventTarget);
510 
511   // Forwarded from BackgroundChild.
512   static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(
513       nsIEventTarget* aMainEventTarget);
514 
515   // Forwarded from BackgroundChild.
516   static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(
517       nsIEventTarget* aMainEventTarget);
518 
519   static void CloseForCurrentThread();
520 
521   // Forwarded from BackgroundChildImpl.
522   static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread();
523 
524   static void ThreadLocalDestructor(void* aThreadLocal);
525 
526   // This class is reference counted.
~ChildImpl()527   ~ChildImpl() { MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed); }
528 
529   // Only called by IPDL.
530   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
531 };
532 
533 // -----------------------------------------------------------------------------
534 // ParentImpl Helper Declarations
535 // -----------------------------------------------------------------------------
536 
537 class ParentImpl::ShutdownObserver final : public nsIObserver {
538  public:
ShutdownObserver()539   ShutdownObserver() { AssertIsOnMainThread(); }
540 
541   NS_DECL_ISUPPORTS
542   NS_DECL_NSIOBSERVER
543 
544  private:
~ShutdownObserver()545   ~ShutdownObserver() { AssertIsOnMainThread(); }
546 };
547 
548 class ParentImpl::CreateActorHelper final : public Runnable {
549   mozilla::Monitor mMonitor;
550   RefPtr<ParentImpl> mParentActor;
551   nsCOMPtr<nsIThread> mThread;
552   nsresult mMainThreadResultCode;
553   bool mWaiting;
554 
555  public:
CreateActorHelper()556   explicit CreateActorHelper()
557       : Runnable("Background::ParentImpl::CreateActorHelper"),
558         mMonitor("CreateActorHelper::mMonitor"),
559         mMainThreadResultCode(NS_OK),
560         mWaiting(true) {
561     AssertIsInMainOrSocketProcess();
562     AssertIsNotOnMainThread();
563   }
564 
565   nsresult BlockAndGetResults(nsIEventTarget* aMainEventTarget,
566                               RefPtr<ParentImpl>& aParentActor,
567                               nsCOMPtr<nsIThread>& aThread);
568 
569  private:
~CreateActorHelper()570   ~CreateActorHelper() { AssertIsInMainOrSocketProcess(); }
571 
572   nsresult RunOnMainThread();
573 
574   NS_DECL_NSIRUNNABLE
575 };
576 
577 // -----------------------------------------------------------------------------
578 // ChildImpl Helper Declarations
579 // -----------------------------------------------------------------------------
580 
581 class ChildImpl::ShutdownObserver final : public nsIObserver {
582  public:
ShutdownObserver()583   ShutdownObserver() { AssertIsOnMainThread(); }
584 
585   NS_DECL_ISUPPORTS
586   NS_DECL_NSIOBSERVER
587 
588  private:
~ShutdownObserver()589   ~ShutdownObserver() { AssertIsOnMainThread(); }
590 };
591 
592 class ChildImpl::SendInitBackgroundRunnable final : public CancelableRunnable {
593   nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
594   RefPtr<StrongWorkerRef> mWorkerRef;
595   Endpoint<PBackgroundParent> mParent;
596   mozilla::Mutex mMutex;
597   bool mSentInitBackground;
598   std::function<void(Endpoint<PBackgroundParent>&& aParent)> mSendInitfunc;
599   unsigned int mThreadLocalIndex;
600 
601  public:
602   static already_AddRefed<SendInitBackgroundRunnable> Create(
603       Endpoint<PBackgroundParent>&& aParent,
604       std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
605       unsigned int aThreadLocalIndex);
606 
ClearEventTarget()607   void ClearEventTarget() {
608     mWorkerRef = nullptr;
609 
610     mozilla::MutexAutoLock lock(mMutex);
611     mOwningEventTarget = nullptr;
612   }
613 
614  private:
SendInitBackgroundRunnable(Endpoint<PBackgroundParent> && aParent,std::function<void (Endpoint<PBackgroundParent> && aParent)> && aFunc,unsigned int aThreadLocalIndex)615   explicit SendInitBackgroundRunnable(
616       Endpoint<PBackgroundParent>&& aParent,
617       std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
618       unsigned int aThreadLocalIndex)
619       : CancelableRunnable("Background::ChildImpl::SendInitBackgroundRunnable"),
620         mOwningEventTarget(GetCurrentThreadSerialEventTarget()),
621         mParent(std::move(aParent)),
622         mMutex("SendInitBackgroundRunnable::mMutex"),
623         mSentInitBackground(false),
624         mSendInitfunc(std::move(aFunc)),
625         mThreadLocalIndex(aThreadLocalIndex) {}
626 
627   ~SendInitBackgroundRunnable() = default;
628 
629   NS_DECL_NSIRUNNABLE
630 };
631 
632 }  // namespace
633 
634 namespace mozilla {
635 namespace ipc {
636 
IsOnBackgroundThread()637 bool IsOnBackgroundThread() { return ParentImpl::IsOnBackgroundThread(); }
638 
639 #ifdef DEBUG
640 
AssertIsOnBackgroundThread()641 void AssertIsOnBackgroundThread() { ParentImpl::AssertIsOnBackgroundThread(); }
642 
643 #endif  // DEBUG
644 
645 }  // namespace ipc
646 }  // namespace mozilla
647 
648 // -----------------------------------------------------------------------------
649 // BackgroundParent Public Methods
650 // -----------------------------------------------------------------------------
651 
652 // static
IsOtherProcessActor(PBackgroundParent * aBackgroundActor)653 bool BackgroundParent::IsOtherProcessActor(
654     PBackgroundParent* aBackgroundActor) {
655   return ParentImpl::IsOtherProcessActor(aBackgroundActor);
656 }
657 
658 // static
GetContentParent(PBackgroundParent * aBackgroundActor)659 already_AddRefed<ContentParent> BackgroundParent::GetContentParent(
660     PBackgroundParent* aBackgroundActor) {
661   return ParentImpl::GetContentParent(aBackgroundActor);
662 }
663 
664 // static
GetRawContentParentForComparison(PBackgroundParent * aBackgroundActor)665 intptr_t BackgroundParent::GetRawContentParentForComparison(
666     PBackgroundParent* aBackgroundActor) {
667   return ParentImpl::GetRawContentParentForComparison(aBackgroundActor);
668 }
669 
670 // static
GetChildID(PBackgroundParent * aBackgroundActor)671 uint64_t BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor) {
672   return ParentImpl::GetChildID(aBackgroundActor);
673 }
674 
675 // static
GetLiveActorArray(PBackgroundParent * aBackgroundActor,nsTArray<PBackgroundParent * > & aLiveActorArray)676 bool BackgroundParent::GetLiveActorArray(
677     PBackgroundParent* aBackgroundActor,
678     nsTArray<PBackgroundParent*>& aLiveActorArray) {
679   return ParentImpl::GetLiveActorArray(aBackgroundActor, aLiveActorArray);
680 }
681 
682 // static
Alloc(ContentParent * aContent,Endpoint<PBackgroundParent> && aEndpoint)683 bool BackgroundParent::Alloc(ContentParent* aContent,
684                              Endpoint<PBackgroundParent>&& aEndpoint) {
685   return ParentImpl::Alloc(aContent, std::move(aEndpoint));
686 }
687 
688 // -----------------------------------------------------------------------------
689 // BackgroundChild Public Methods
690 // -----------------------------------------------------------------------------
691 
692 // static
Startup()693 void BackgroundChild::Startup() { ChildImpl::Startup(); }
694 
695 // static
GetForCurrentThread()696 PBackgroundChild* BackgroundChild::GetForCurrentThread() {
697   return ChildImpl::GetForCurrentThread();
698 }
699 
700 // static
GetOrCreateForCurrentThread(nsIEventTarget * aMainEventTarget)701 PBackgroundChild* BackgroundChild::GetOrCreateForCurrentThread(
702     nsIEventTarget* aMainEventTarget) {
703   return ChildImpl::GetOrCreateForCurrentThread(aMainEventTarget);
704 }
705 
706 // static
GetOrCreateSocketActorForCurrentThread(nsIEventTarget * aMainEventTarget)707 PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread(
708     nsIEventTarget* aMainEventTarget) {
709   return ChildImpl::GetOrCreateSocketActorForCurrentThread(aMainEventTarget);
710 }
711 
712 // static
713 PBackgroundChild*
GetOrCreateForSocketParentBridgeForCurrentThread(nsIEventTarget * aMainEventTarget)714 BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread(
715     nsIEventTarget* aMainEventTarget) {
716   return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
717       aMainEventTarget);
718 }
719 
720 // static
CloseForCurrentThread()721 void BackgroundChild::CloseForCurrentThread() {
722   ChildImpl::CloseForCurrentThread();
723 }
724 
725 // -----------------------------------------------------------------------------
726 // BackgroundChildImpl Public Methods
727 // -----------------------------------------------------------------------------
728 
729 // static
730 BackgroundChildImpl::ThreadLocal*
GetThreadLocalForCurrentThread()731 BackgroundChildImpl::GetThreadLocalForCurrentThread() {
732   return ChildImpl::GetThreadLocalForCurrentThread();
733 }
734 
735 // -----------------------------------------------------------------------------
736 // ParentImpl Static Members
737 // -----------------------------------------------------------------------------
738 
739 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
740 StaticRefPtr<AbstractThread> ParentImpl::sBackgroundAbstractThread;
741 
742 nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread;
743 
744 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
745 
746 Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
747 
748 uint64_t ParentImpl::sLiveActorCount = 0;
749 
750 bool ParentImpl::sShutdownObserverRegistered = false;
751 
752 bool ParentImpl::sShutdownHasStarted = false;
753 
754 // -----------------------------------------------------------------------------
755 // ChildImpl Static Members
756 // -----------------------------------------------------------------------------
757 
ParentContentActorCreateFunc(ChildImpl::ThreadLocalInfo * aThreadLocalInfo,unsigned int aThreadLocalIndex,nsIEventTarget * aMainEventTarget,ChildImpl ** aOutput)758 static void ParentContentActorCreateFunc(
759     ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
760     unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
761     ChildImpl** aOutput) {
762   if (XRE_IsParentProcess()) {
763     RefPtr<ChildImpl> strongActor =
764         ParentImpl::CreateActorForSameProcess(aMainEventTarget);
765     if (NS_WARN_IF(!strongActor)) {
766       return;
767     }
768 
769     aThreadLocalInfo->mActor = strongActor;
770     strongActor.forget(aOutput);
771     return;
772   }
773 
774   RefPtr<ContentChild> content = ContentChild::GetSingleton();
775   MOZ_ASSERT(content);
776 
777   if (content->IsShuttingDown()) {
778     // The transport for ContentChild is shut down and can't be used to open
779     // PBackground.
780     return;
781   }
782 
783   Endpoint<PBackgroundParent> parent;
784   Endpoint<PBackgroundChild> child;
785   nsresult rv;
786   rv = PBackground::CreateEndpoints(content->OtherPid(),
787                                     base::GetCurrentProcId(), &parent, &child);
788   if (NS_FAILED(rv)) {
789     NS_WARNING("Failed to create top level actor!");
790     return;
791   }
792 
793   RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
794   if (!NS_IsMainThread()) {
795     runnable = ChildImpl::SendInitBackgroundRunnable::Create(
796         std::move(parent),
797         [](Endpoint<PBackgroundParent>&& aParent) {
798           RefPtr<ContentChild> content = ContentChild::GetSingleton();
799           MOZ_ASSERT(content);
800 
801           if (!content->SendInitBackground(std::move(aParent))) {
802             NS_WARNING("Failed to create top level actor!");
803           }
804         },
805         aThreadLocalIndex);
806     if (!runnable) {
807       return;
808     }
809   }
810 
811   RefPtr<ChildImpl> strongActor = new ChildImpl();
812 
813   if (!child.Bind(strongActor)) {
814     CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
815 
816     return;
817   }
818 
819   strongActor->SetActorAlive();
820 
821   if (NS_IsMainThread()) {
822     if (!content->SendInitBackground(std::move(parent))) {
823       NS_WARNING("Failed to create top level actor!");
824       return;
825     }
826   } else {
827     if (aMainEventTarget) {
828       MOZ_ALWAYS_SUCCEEDS(
829           aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
830     } else {
831       MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
832     }
833 
834     aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
835   }
836 
837   aThreadLocalInfo->mActor = strongActor;
838   strongActor.forget(aOutput);
839 }
840 
841 ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo(
842     ParentContentActorCreateFunc);
843 
SocketContentActorCreateFunc(ChildImpl::ThreadLocalInfo * aThreadLocalInfo,unsigned int aThreadLocalIndex,nsIEventTarget * aMainEventTarget,ChildImpl ** aOutput)844 static void SocketContentActorCreateFunc(
845     ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
846     unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
847     ChildImpl** aOutput) {
848   RefPtr<SocketProcessBridgeChild> bridgeChild =
849       SocketProcessBridgeChild::GetSingleton();
850 
851   if (!bridgeChild || bridgeChild->IsShuttingDown()) {
852     // The transport for SocketProcessBridgeChild is shut down
853     // and can't be used to open PBackground.
854     return;
855   }
856 
857   Endpoint<PBackgroundParent> parent;
858   Endpoint<PBackgroundChild> child;
859   nsresult rv;
860   rv = PBackground::CreateEndpoints(bridgeChild->SocketProcessPid(),
861                                     base::GetCurrentProcId(), &parent, &child);
862   if (NS_FAILED(rv)) {
863     NS_WARNING("Failed to create top level actor!");
864     return;
865   }
866 
867   RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
868   if (!NS_IsMainThread()) {
869     runnable = ChildImpl::SendInitBackgroundRunnable::Create(
870         std::move(parent),
871         [](Endpoint<PBackgroundParent>&& aParent) {
872           RefPtr<SocketProcessBridgeChild> bridgeChild =
873               SocketProcessBridgeChild::GetSingleton();
874 
875           if (!bridgeChild->SendInitBackground(std::move(aParent))) {
876             NS_WARNING("Failed to create top level actor!");
877           }
878         },
879         aThreadLocalIndex);
880     if (!runnable) {
881       return;
882     }
883   }
884 
885   RefPtr<ChildImpl> strongActor = new ChildImpl();
886 
887   if (!child.Bind(strongActor)) {
888     CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
889 
890     return;
891   }
892 
893   strongActor->SetActorAlive();
894 
895   if (NS_IsMainThread()) {
896     if (!bridgeChild->SendInitBackground(std::move(parent))) {
897       NS_WARNING("Failed to create top level actor!");
898       // Need to close the IPC channel before ChildImpl getting deleted.
899       strongActor->Close();
900       strongActor->AssertActorDestroyed();
901       return;
902     }
903   } else {
904     if (aMainEventTarget) {
905       MOZ_ALWAYS_SUCCEEDS(
906           aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
907     } else {
908       MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
909     }
910 
911     aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
912   }
913 
914   aThreadLocalInfo->mActor = strongActor;
915   strongActor.forget(aOutput);
916 }
917 
918 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo(
919     SocketContentActorCreateFunc);
920 
SocketParentActorCreateFunc(ChildImpl::ThreadLocalInfo * aThreadLocalInfo,unsigned int aThreadLocalIndex,nsIEventTarget * aMainEventTarget,ChildImpl ** aOutput)921 static void SocketParentActorCreateFunc(
922     ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
923     unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
924     ChildImpl** aOutput) {
925   SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
926 
927   if (!socketChild || socketChild->IsShuttingDown()) {
928     return;
929   }
930 
931   Endpoint<PBackgroundParent> parent;
932   Endpoint<PBackgroundChild> child;
933   nsresult rv;
934   rv = PBackground::CreateEndpoints(socketChild->OtherPid(),
935                                     base::GetCurrentProcId(), &parent, &child);
936   if (NS_FAILED(rv)) {
937     NS_WARNING("Failed to create top level actor!");
938     return;
939   }
940 
941   RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
942   if (!NS_IsMainThread()) {
943     runnable = ChildImpl::SendInitBackgroundRunnable::Create(
944         std::move(parent),
945         [](Endpoint<PBackgroundParent>&& aParent) {
946           SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
947           MOZ_ASSERT(socketChild);
948 
949           if (!socketChild->SendInitBackground(std::move(aParent))) {
950             MOZ_CRASH("Failed to create top level actor!");
951           }
952         },
953         aThreadLocalIndex);
954     if (!runnable) {
955       return;
956     }
957   }
958 
959   RefPtr<ChildImpl> strongActor = new ChildImpl();
960 
961   if (!child.Bind(strongActor)) {
962     CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
963     return;
964   }
965 
966   strongActor->SetActorAlive();
967 
968   if (NS_IsMainThread()) {
969     if (!socketChild->SendInitBackground(std::move(parent))) {
970       NS_WARNING("Failed to create top level actor!");
971       return;
972     }
973   } else {
974     if (aMainEventTarget) {
975       MOZ_ALWAYS_SUCCEEDS(
976           aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
977     } else {
978       MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
979     }
980 
981     aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
982   }
983 
984   aThreadLocalInfo->mActor = strongActor;
985   strongActor.forget(aOutput);
986 }
987 
988 ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo(
989     SocketParentActorCreateFunc);
990 
991 bool ChildImpl::sShutdownHasStarted = false;
992 
993 // -----------------------------------------------------------------------------
994 // ParentImpl Implementation
995 // -----------------------------------------------------------------------------
996 
997 // static
IsOtherProcessActor(PBackgroundParent * aBackgroundActor)998 bool ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) {
999   AssertIsOnBackgroundThread();
1000   MOZ_ASSERT(aBackgroundActor);
1001 
1002   return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
1003 }
1004 
1005 // static
GetContentParent(PBackgroundParent * aBackgroundActor)1006 already_AddRefed<ContentParent> ParentImpl::GetContentParent(
1007     PBackgroundParent* aBackgroundActor) {
1008   AssertIsOnBackgroundThread();
1009   MOZ_ASSERT(aBackgroundActor);
1010 
1011   auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1012   if (actor->mActorDestroyed) {
1013     MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
1014     return nullptr;
1015   }
1016 
1017   if (actor->mContent) {
1018     // We need to hand out a reference to our ContentParent but we also need to
1019     // keep the one we have. We can't call AddRef here because ContentParent is
1020     // not threadsafe so instead we dispatch a runnable to the main thread to do
1021     // it for us. This is safe since we are guaranteed that our AddRef runnable
1022     // will run before the reference we hand out can be released, and the
1023     // ContentParent can't die as long as the existing reference is maintained.
1024     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewNonOwningRunnableMethod(
1025         "ContentParent::AddRef", actor->mContent, &ContentParent::AddRef)));
1026   }
1027 
1028   return already_AddRefed<ContentParent>(actor->mContent.get());
1029 }
1030 
1031 // static
GetRawContentParentForComparison(PBackgroundParent * aBackgroundActor)1032 intptr_t ParentImpl::GetRawContentParentForComparison(
1033     PBackgroundParent* aBackgroundActor) {
1034   AssertIsOnBackgroundThread();
1035   MOZ_ASSERT(aBackgroundActor);
1036 
1037   auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1038   if (actor->mActorDestroyed) {
1039     MOZ_ASSERT(false,
1040                "GetRawContentParentForComparison called after ActorDestroy was "
1041                "called!");
1042     return intptr_t(-1);
1043   }
1044 
1045   return intptr_t(static_cast<ContentParent*>(actor->mContent.get()));
1046 }
1047 
1048 // static
GetChildID(PBackgroundParent * aBackgroundActor)1049 uint64_t ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor) {
1050   AssertIsOnBackgroundThread();
1051   MOZ_ASSERT(aBackgroundActor);
1052 
1053   auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1054   if (actor->mActorDestroyed) {
1055     MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
1056     return 0;
1057   }
1058 
1059   if (actor->mContent) {
1060     return actor->mContent->ChildID();
1061   }
1062 
1063   return 0;
1064 }
1065 
1066 // static
GetLiveActorArray(PBackgroundParent * aBackgroundActor,nsTArray<PBackgroundParent * > & aLiveActorArray)1067 bool ParentImpl::GetLiveActorArray(
1068     PBackgroundParent* aBackgroundActor,
1069     nsTArray<PBackgroundParent*>& aLiveActorArray) {
1070   AssertIsOnBackgroundThread();
1071   MOZ_ASSERT(aBackgroundActor);
1072   MOZ_ASSERT(aLiveActorArray.IsEmpty());
1073 
1074   auto actor = static_cast<ParentImpl*>(aBackgroundActor);
1075   if (actor->mActorDestroyed) {
1076     MOZ_ASSERT(false,
1077                "GetLiveActorArray called after ActorDestroy was called!");
1078     return false;
1079   }
1080 
1081   if (!actor->mLiveActorArray) {
1082     return true;
1083   }
1084 
1085   for (ParentImpl* liveActor : *actor->mLiveActorArray) {
1086     aLiveActorArray.AppendElement(liveActor);
1087   }
1088 
1089   return true;
1090 }
1091 
1092 // static
Alloc(ContentParent * aContent,Endpoint<PBackgroundParent> && aEndpoint)1093 bool ParentImpl::Alloc(ContentParent* aContent,
1094                        Endpoint<PBackgroundParent>&& aEndpoint) {
1095   AssertIsInMainOrSocketProcess();
1096   AssertIsOnMainThread();
1097   MOZ_ASSERT(aEndpoint.IsValid());
1098 
1099   if (!sBackgroundThread && !CreateBackgroundThread()) {
1100     NS_WARNING("Failed to create background thread!");
1101     return false;
1102   }
1103 
1104   MOZ_ASSERT(sLiveActorsForBackgroundThread);
1105 
1106   sLiveActorCount++;
1107 
1108   RefPtr<ParentImpl> actor = new ParentImpl(aContent);
1109 
1110   if (NS_FAILED(sBackgroundThread->Dispatch(NS_NewRunnableFunction(
1111           "Background::ParentImpl::ConnectActorRunnable",
1112           [actor = std::move(actor), endpoint = std::move(aEndpoint),
1113            liveActorArray = sLiveActorsForBackgroundThread]() mutable {
1114             MOZ_ASSERT(endpoint.IsValid());
1115             MOZ_ASSERT(liveActorArray);
1116             // Transfer ownership to this thread. If Open() fails then we will
1117             // release this reference in Destroy.
1118             ParentImpl* actorTmp;
1119             actor.forget(&actorTmp);
1120 
1121             if (!endpoint.Bind(actorTmp)) {
1122               actorTmp->Destroy();
1123               return;
1124             }
1125 
1126             actorTmp->SetLiveActorArray(liveActorArray);
1127           })))) {
1128     NS_WARNING("Failed to dispatch connect runnable!");
1129 
1130     MOZ_ASSERT(sLiveActorCount);
1131     sLiveActorCount--;
1132   }
1133 
1134   return true;
1135 }
1136 
1137 // static
CreateActorForSameProcess(nsIEventTarget * aMainEventTarget)1138 already_AddRefed<ChildImpl> ParentImpl::CreateActorForSameProcess(
1139     nsIEventTarget* aMainEventTarget) {
1140   AssertIsInMainProcess();
1141 
1142   RefPtr<ParentImpl> parentActor;
1143   nsCOMPtr<nsIThread> backgroundThread;
1144 
1145   if (NS_IsMainThread()) {
1146     if (!sBackgroundThread && !CreateBackgroundThread()) {
1147       NS_WARNING("Failed to create background thread!");
1148       return nullptr;
1149     }
1150 
1151     MOZ_ASSERT(!sShutdownHasStarted);
1152 
1153     sLiveActorCount++;
1154 
1155     parentActor = new ParentImpl();
1156     backgroundThread = sBackgroundThread.get();
1157   } else {
1158     RefPtr<CreateActorHelper> helper = new CreateActorHelper();
1159 
1160     nsresult rv = helper->BlockAndGetResults(aMainEventTarget, parentActor,
1161                                              backgroundThread);
1162     if (NS_WARN_IF(NS_FAILED(rv))) {
1163       return nullptr;
1164     }
1165   }
1166 
1167   RefPtr<ChildImpl> childActor = new ChildImpl();
1168 
1169   MessageChannel* parentChannel = parentActor->GetIPCChannel();
1170   MOZ_ASSERT(parentChannel);
1171 
1172   if (!childActor->Open(parentChannel, backgroundThread, ChildSide)) {
1173     NS_WARNING("Failed to open ChildImpl!");
1174 
1175     // Can't release it here, we will release this reference in Destroy.
1176     ParentImpl* actor;
1177     parentActor.forget(&actor);
1178 
1179     actor->Destroy();
1180 
1181     return nullptr;
1182   }
1183 
1184   childActor->SetActorAlive();
1185 
1186   // Make sure the parent knows it is same process.
1187   parentActor->SetOtherProcessId(base::GetCurrentProcId());
1188 
1189   // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
1190   Unused << parentActor.forget();
1191 
1192   return childActor.forget();
1193 }
1194 
1195 // static
CreateBackgroundThread()1196 bool ParentImpl::CreateBackgroundThread() {
1197   AssertIsInMainOrSocketProcess();
1198   AssertIsOnMainThread();
1199   MOZ_ASSERT(!sBackgroundThread);
1200   MOZ_ASSERT(!sLiveActorsForBackgroundThread);
1201 
1202   if (sShutdownHasStarted) {
1203     NS_WARNING(
1204         "Trying to create background thread after shutdown has "
1205         "already begun!");
1206     return false;
1207   }
1208 
1209   nsCOMPtr<nsITimer> newShutdownTimer;
1210 
1211   if (!sShutdownTimer) {
1212     newShutdownTimer = NS_NewTimer();
1213     if (!newShutdownTimer) {
1214       return false;
1215     }
1216   }
1217 
1218   if (!sShutdownObserverRegistered) {
1219     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1220     if (NS_WARN_IF(!obs)) {
1221       return false;
1222     }
1223 
1224     nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1225 
1226     nsresult rv = obs->AddObserver(
1227         observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1228     if (NS_WARN_IF(NS_FAILED(rv))) {
1229       return false;
1230     }
1231 
1232     sShutdownObserverRegistered = true;
1233   }
1234 
1235   nsCOMPtr<nsIThread> thread;
1236   if (NS_FAILED(NS_NewNamedThread(
1237           "IPDL Background", getter_AddRefs(thread),
1238           NS_NewRunnableFunction(
1239               "Background::ParentImpl::CreateBackgroundThreadRunnable", []() {
1240                 DebugOnly<PRThread*> oldBackgroundThread =
1241                     sBackgroundPRThread.exchange(PR_GetCurrentThread());
1242 
1243                 MOZ_ASSERT_IF(oldBackgroundThread,
1244                               PR_GetCurrentThread() != oldBackgroundThread);
1245               })))) {
1246     NS_WARNING("NS_NewNamedThread failed!");
1247     return false;
1248   }
1249 
1250   // We create an AbstractThread for this thread so that we can
1251   // use direct task
1252   // dispatching with MozPromise, which is similar (but not
1253   // identical to) the microtask semantics of JS promises.
1254   sBackgroundAbstractThread = AbstractThread::CreateXPCOMThreadWrapper(
1255       thread, false /* require tail dispatch */);
1256   sBackgroundThread = thread.forget();
1257 
1258   sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1);
1259 
1260   if (!sShutdownTimer) {
1261     MOZ_ASSERT(newShutdownTimer);
1262     sShutdownTimer = newShutdownTimer;
1263   }
1264 
1265   return true;
1266 }
1267 
1268 // static
ShutdownBackgroundThread()1269 void ParentImpl::ShutdownBackgroundThread() {
1270   AssertIsInMainOrSocketProcess();
1271   AssertIsOnMainThread();
1272   MOZ_ASSERT(sShutdownHasStarted);
1273   MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
1274   MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
1275 
1276   nsCOMPtr<nsITimer> shutdownTimer = sShutdownTimer.get();
1277   sShutdownTimer = nullptr;
1278 
1279   if (sBackgroundThread) {
1280     nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
1281     sBackgroundThread = nullptr;
1282     sBackgroundAbstractThread = nullptr;
1283 
1284     UniquePtr<nsTArray<ParentImpl*>> liveActors(sLiveActorsForBackgroundThread);
1285     sLiveActorsForBackgroundThread = nullptr;
1286 
1287     MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
1288 
1289     if (sLiveActorCount) {
1290       // We need to spin the event loop while we wait for all the actors to be
1291       // cleaned up. We also set a timeout to force-kill any hanging actors.
1292       TimerCallbackClosure closure(thread, liveActors.get());
1293 
1294       MOZ_ALWAYS_SUCCEEDS(shutdownTimer->InitWithNamedFuncCallback(
1295           &ShutdownTimerCallback, &closure, kShutdownTimerDelayMS,
1296           nsITimer::TYPE_ONE_SHOT, "ParentImpl::ShutdownTimerCallback"));
1297 
1298       SpinEventLoopUntil([&]() { return !sLiveActorCount; });
1299 
1300       MOZ_ASSERT(liveActors->IsEmpty());
1301 
1302       MOZ_ALWAYS_SUCCEEDS(shutdownTimer->Cancel());
1303     }
1304 
1305     // Dispatch this runnable to unregister the PR thread from the profiler.
1306     MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(NS_NewRunnableFunction(
1307         "Background::ParentImpl::ShutdownBackgroundThreadRunnable", []() {
1308           // It is possible that another background thread was created while
1309           // this thread was shutting down. In that case we can't assert
1310           // anything about sBackgroundPRThread and we should not modify it
1311           // here.
1312           sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
1313         })));
1314 
1315     MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
1316   }
1317 }
1318 
1319 // static
ShutdownTimerCallback(nsITimer * aTimer,void * aClosure)1320 void ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure) {
1321   AssertIsInMainOrSocketProcess();
1322   AssertIsOnMainThread();
1323   MOZ_ASSERT(sShutdownHasStarted);
1324   MOZ_ASSERT(sLiveActorCount);
1325 
1326   auto closure = static_cast<TimerCallbackClosure*>(aClosure);
1327   MOZ_ASSERT(closure);
1328 
1329   // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1330   // finished.
1331   sLiveActorCount++;
1332 
1333   InvokeAsync(closure->mThread, __func__,
1334               [liveActors = closure->mLiveActors]() {
1335                 MOZ_ASSERT(liveActors);
1336 
1337                 if (!liveActors->IsEmpty()) {
1338                   // Copy the array since calling Close() could mutate the
1339                   // actual array.
1340                   nsTArray<ParentImpl*> actorsToClose(liveActors->Clone());
1341                   for (ParentImpl* actor : actorsToClose) {
1342                     actor->Close();
1343                   }
1344                 }
1345                 return GenericPromise::CreateAndResolve(true, __func__);
1346               })
1347       ->Then(GetCurrentThreadSerialEventTarget(), __func__, []() {
1348         MOZ_ASSERT(sLiveActorCount);
1349         sLiveActorCount--;
1350       });
1351 }
1352 
Destroy()1353 void ParentImpl::Destroy() {
1354   // May be called on any thread!
1355 
1356   AssertIsInMainOrSocketProcess();
1357 
1358   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
1359       NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy", this,
1360                                  &ParentImpl::MainThreadActorDestroy)));
1361 }
1362 
MainThreadActorDestroy()1363 void ParentImpl::MainThreadActorDestroy() {
1364   AssertIsInMainOrSocketProcess();
1365   AssertIsOnMainThread();
1366   MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1367 
1368   mContent = nullptr;
1369 
1370   MOZ_ASSERT(sLiveActorCount);
1371   sLiveActorCount--;
1372 
1373   // This may be the last reference!
1374   Release();
1375 }
1376 
ActorDestroy(ActorDestroyReason aWhy)1377 void ParentImpl::ActorDestroy(ActorDestroyReason aWhy) {
1378   AssertIsInMainOrSocketProcess();
1379   AssertIsOnBackgroundThread();
1380   MOZ_ASSERT(!mActorDestroyed);
1381   MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1382 
1383   BackgroundParentImpl::ActorDestroy(aWhy);
1384 
1385   mActorDestroyed = true;
1386 
1387   if (mLiveActorArray) {
1388     MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1389     mLiveActorArray = nullptr;
1390   }
1391 
1392   // This is tricky. We should be able to call Destroy() here directly because
1393   // we're not going to touch 'this' or our MessageChannel any longer on this
1394   // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1395   // it runs it will destroy 'this' and our associated MessageChannel. However,
1396   // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1397   // racing with the main thread we must ensure that the MessageChannel lives
1398   // long enough to be cleared in this call stack.
1399 
1400   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
1401       "ParentImpl::Destroy", this, &ParentImpl::Destroy)));
1402 }
1403 
NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver,nsIObserver)1404 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1405 
1406 NS_IMETHODIMP
1407 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1408                                       const char16_t* aData) {
1409   AssertIsInMainOrSocketProcess();
1410   AssertIsOnMainThread();
1411   MOZ_ASSERT(!sShutdownHasStarted);
1412   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1413 
1414   sShutdownHasStarted = true;
1415 
1416   // Do this first before calling (and spinning the event loop in)
1417   // ShutdownBackgroundThread().
1418   ChildImpl::Shutdown();
1419 
1420   ShutdownBackgroundThread();
1421 
1422   return NS_OK;
1423 }
1424 
BlockAndGetResults(nsIEventTarget * aMainEventTarget,RefPtr<ParentImpl> & aParentActor,nsCOMPtr<nsIThread> & aThread)1425 nsresult ParentImpl::CreateActorHelper::BlockAndGetResults(
1426     nsIEventTarget* aMainEventTarget, RefPtr<ParentImpl>& aParentActor,
1427     nsCOMPtr<nsIThread>& aThread) {
1428   AssertIsNotOnMainThread();
1429 
1430   if (aMainEventTarget) {
1431     MOZ_ALWAYS_SUCCEEDS(aMainEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
1432   } else {
1433     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1434   }
1435 
1436   mozilla::MonitorAutoLock lock(mMonitor);
1437   while (mWaiting) {
1438     lock.Wait();
1439   }
1440 
1441   if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) {
1442     return mMainThreadResultCode;
1443   }
1444 
1445   aParentActor = std::move(mParentActor);
1446   aThread = std::move(mThread);
1447   return NS_OK;
1448 }
1449 
RunOnMainThread()1450 nsresult ParentImpl::CreateActorHelper::RunOnMainThread() {
1451   AssertIsOnMainThread();
1452 
1453   if (!sBackgroundThread && !CreateBackgroundThread()) {
1454     NS_WARNING("Failed to create background thread!");
1455     return NS_ERROR_FAILURE;
1456   }
1457 
1458   MOZ_ASSERT(!sShutdownHasStarted);
1459 
1460   sLiveActorCount++;
1461 
1462   mParentActor = new ParentImpl();
1463   mThread = sBackgroundThread;
1464 
1465   return NS_OK;
1466 }
1467 
1468 NS_IMETHODIMP
Run()1469 ParentImpl::CreateActorHelper::Run() {
1470   AssertIsOnMainThread();
1471 
1472   nsresult rv = RunOnMainThread();
1473   if (NS_WARN_IF(NS_FAILED(rv))) {
1474     mMainThreadResultCode = rv;
1475   }
1476 
1477   mozilla::MonitorAutoLock lock(mMonitor);
1478   MOZ_ASSERT(mWaiting);
1479 
1480   mWaiting = false;
1481   lock.Notify();
1482 
1483   return NS_OK;
1484 }
1485 
1486 // -----------------------------------------------------------------------------
1487 // ChildImpl Implementation
1488 // -----------------------------------------------------------------------------
1489 
1490 // static
Startup()1491 void ChildImpl::Startup() {
1492   // This happens on the main thread but before XPCOM has started so we can't
1493   // assert that we're being called on the main thread here.
1494 
1495   sParentAndContentProcessThreadInfo.Startup();
1496   sSocketAndContentProcessThreadInfo.Startup();
1497   sSocketAndParentProcessThreadInfo.Startup();
1498 
1499   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1500   MOZ_RELEASE_ASSERT(observerService);
1501 
1502   nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1503 
1504   nsresult rv = observerService->AddObserver(
1505       observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1506   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1507 }
1508 
1509 // static
Shutdown()1510 void ChildImpl::Shutdown() {
1511   AssertIsOnMainThread();
1512 
1513   sParentAndContentProcessThreadInfo.Shutdown();
1514   sSocketAndContentProcessThreadInfo.Shutdown();
1515   sSocketAndParentProcessThreadInfo.Shutdown();
1516 
1517   sShutdownHasStarted = true;
1518 }
1519 
1520 // static
GetForCurrentThread()1521 PBackgroundChild* ChildImpl::GetForCurrentThread() {
1522   MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1523              kBadThreadLocalIndex);
1524 
1525   auto threadLocalInfo =
1526       NS_IsMainThread()
1527           ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1528           : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1529                 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1530 
1531   if (!threadLocalInfo) {
1532     return nullptr;
1533   }
1534 
1535   return threadLocalInfo->mActor;
1536 }
1537 
1538 /* static */
GetFromThreadInfo(nsIEventTarget * aMainEventTarget,ThreadLocalInfo * aThreadLocalInfo)1539 PBackgroundChild* ChildImpl::GetFromThreadInfo(
1540     nsIEventTarget* aMainEventTarget, ThreadLocalInfo* aThreadLocalInfo) {
1541   MOZ_ASSERT(aThreadLocalInfo);
1542 
1543   if (aThreadLocalInfo->mActor) {
1544     RefPtr<SendInitBackgroundRunnable>& runnable =
1545         aThreadLocalInfo->mSendInitBackgroundRunnable;
1546 
1547     if (aMainEventTarget && runnable) {
1548       // The SendInitBackgroundRunnable was already dispatched to the main
1549       // thread to finish initialization of a new background child actor.
1550       // However, the caller passed a custom main event target which indicates
1551       // that synchronous blocking of the main thread is happening (done by
1552       // creating a nested event target and spinning the event loop).
1553       // It can happen that the SendInitBackgroundRunnable didn't have a chance
1554       // to run before the synchronous blocking has occured. Unblocking of the
1555       // main thread can depend on an IPC message received on this thread, so
1556       // we have to dispatch the SendInitBackgroundRunnable to the custom main
1557       // event target too, otherwise IPC will be only queueing messages on this
1558       // thread. The runnable will run twice in the end, but that's a harmless
1559       // race between the main and nested event queue of the main thread.
1560       // There's a guard in the runnable implementation for calling
1561       // SendInitBackground only once.
1562 
1563       MOZ_ALWAYS_SUCCEEDS(
1564           aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
1565     }
1566 
1567     return aThreadLocalInfo->mActor;
1568   }
1569 
1570   return nullptr;
1571 }
1572 
1573 /* static */
GetOrCreateForCurrentThread(nsIEventTarget * aMainEventTarget)1574 PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread(
1575     nsIEventTarget* aMainEventTarget) {
1576   return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread(
1577       aMainEventTarget);
1578 }
1579 
1580 /* static */
GetOrCreateSocketActorForCurrentThread(nsIEventTarget * aMainEventTarget)1581 PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread(
1582     nsIEventTarget* aMainEventTarget) {
1583   return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread(
1584       aMainEventTarget);
1585 }
1586 
1587 /* static */
GetOrCreateForSocketParentBridgeForCurrentThread(nsIEventTarget * aMainEventTarget)1588 PBackgroundChild* ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
1589     nsIEventTarget* aMainEventTarget) {
1590   return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread(
1591       aMainEventTarget);
1592 }
1593 
1594 // static
CloseForCurrentThread()1595 void ChildImpl::CloseForCurrentThread() {
1596   MOZ_ASSERT(!NS_IsMainThread(),
1597              "PBackground for the main thread should be shut down via "
1598              "ChildImpl::Shutdown().");
1599 
1600   sParentAndContentProcessThreadInfo.CloseForCurrentThread();
1601   sSocketAndContentProcessThreadInfo.CloseForCurrentThread();
1602   sSocketAndParentProcessThreadInfo.CloseForCurrentThread();
1603 }
1604 
1605 // static
GetThreadLocalForCurrentThread()1606 BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
1607   MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
1608                  kBadThreadLocalIndex,
1609              "BackgroundChild::Startup() was never called!");
1610 
1611   auto threadLocalInfo =
1612       NS_IsMainThread()
1613           ? sParentAndContentProcessThreadInfo.mMainThreadInfo
1614           : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
1615                 sParentAndContentProcessThreadInfo.mThreadLocalIndex));
1616 
1617   if (!threadLocalInfo) {
1618     return nullptr;
1619   }
1620 
1621   if (!threadLocalInfo->mConsumerThreadLocal) {
1622     threadLocalInfo->mConsumerThreadLocal =
1623         MakeUnique<BackgroundChildImpl::ThreadLocal>();
1624   }
1625 
1626   return threadLocalInfo->mConsumerThreadLocal.get();
1627 }
1628 
1629 // static
ThreadLocalDestructor(void * aThreadLocal)1630 void ChildImpl::ThreadLocalDestructor(void* aThreadLocal) {
1631   auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
1632 
1633   if (threadLocalInfo) {
1634     MOZ_ASSERT(threadLocalInfo->mClosed);
1635 
1636     if (threadLocalInfo->mActor) {
1637       threadLocalInfo->mActor->Close();
1638       threadLocalInfo->mActor->AssertActorDestroyed();
1639     }
1640 
1641     if (threadLocalInfo->mSendInitBackgroundRunnable) {
1642       threadLocalInfo->mSendInitBackgroundRunnable->ClearEventTarget();
1643     }
1644 
1645     delete threadLocalInfo;
1646   }
1647 }
1648 
ActorDestroy(ActorDestroyReason aWhy)1649 void ChildImpl::ActorDestroy(ActorDestroyReason aWhy) {
1650   AssertIsOnOwningThread();
1651 
1652 #ifdef DEBUG
1653   MOZ_ASSERT(!mActorDestroyed);
1654   mActorDestroyed = true;
1655 #endif
1656 
1657   BackgroundChildImpl::ActorDestroy(aWhy);
1658 }
1659 
NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver,nsIObserver)1660 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1661 
1662 NS_IMETHODIMP
1663 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
1664                                      const char16_t* aData) {
1665   AssertIsOnMainThread();
1666   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1667 
1668   ChildImpl::Shutdown();
1669 
1670   return NS_OK;
1671 }
1672 
1673 // static
1674 already_AddRefed<ChildImpl::SendInitBackgroundRunnable>
Create(Endpoint<PBackgroundParent> && aParent,std::function<void (Endpoint<PBackgroundParent> && aParent)> && aFunc,unsigned int aThreadLocalIndex)1675 ChildImpl::SendInitBackgroundRunnable::Create(
1676     Endpoint<PBackgroundParent>&& aParent,
1677     std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
1678     unsigned int aThreadLocalIndex) {
1679   MOZ_ASSERT(!NS_IsMainThread());
1680 
1681   RefPtr<SendInitBackgroundRunnable> runnable = new SendInitBackgroundRunnable(
1682       std::move(aParent), std::move(aFunc), aThreadLocalIndex);
1683 
1684   WorkerPrivate* workerPrivate = mozilla::dom::GetCurrentThreadWorkerPrivate();
1685   if (!workerPrivate) {
1686     return runnable.forget();
1687   }
1688 
1689   workerPrivate->AssertIsOnWorkerThread();
1690 
1691   runnable->mWorkerRef = StrongWorkerRef::Create(
1692       workerPrivate, "ChildImpl::SendInitBackgroundRunnable");
1693   if (NS_WARN_IF(!runnable->mWorkerRef)) {
1694     return nullptr;
1695   }
1696 
1697   return runnable.forget();
1698 }
1699 
1700 NS_IMETHODIMP
Run()1701 ChildImpl::SendInitBackgroundRunnable::Run() {
1702   if (NS_IsMainThread()) {
1703     if (mSentInitBackground) {
1704       return NS_OK;
1705     }
1706 
1707     mSentInitBackground = true;
1708 
1709     mSendInitfunc(std::move(mParent));
1710 
1711     nsCOMPtr<nsISerialEventTarget> owningEventTarget;
1712     {
1713       mozilla::MutexAutoLock lock(mMutex);
1714       owningEventTarget = mOwningEventTarget;
1715     }
1716 
1717     if (!owningEventTarget) {
1718       return NS_OK;
1719     }
1720 
1721     nsresult rv = owningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
1722     if (NS_WARN_IF(NS_FAILED(rv))) {
1723       return rv;
1724     }
1725 
1726     return NS_OK;
1727   }
1728 
1729   ClearEventTarget();
1730 
1731   auto threadLocalInfo =
1732       static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
1733 
1734   if (!threadLocalInfo) {
1735     return NS_OK;
1736   }
1737 
1738   threadLocalInfo->mSendInitBackgroundRunnable = nullptr;
1739 
1740   return NS_OK;
1741 }
1742