tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BackgroundImpl.cpp (39784B)


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