PBackground for the Parent-Socket process bridge. r=jld
authorDragana Damjanovic <dd.mozilla@gmail.com>
Thu, 11 Apr 2019 16:10:48 +0200
changeset 467143 6e6197fff86e4528ddf89e1e0c8eb07a7101fe44
parent 467142 1321d45bcd7ed09fd1ee5b6353ac5e1f3c1f0f50
child 467144 a8d91bca70d7f41525eb7951d8c2dbfb45dffaf7
push id47
push userdd.mozilla@gmail.com
push dateThu, 11 Apr 2019 14:11:25 +0000
reviewersjld
milestone68.0a1
PBackground for the Parent-Socket process bridge. r=jld
ipc/glue/BackgroundChild.h
ipc/glue/BackgroundImpl.cpp
ipc/glue/BackgroundParent.h
netwerk/ipc/PSocketProcess.ipdl
netwerk/ipc/SocketProcessChild.cpp
netwerk/ipc/SocketProcessChild.h
netwerk/ipc/SocketProcessParent.cpp
netwerk/ipc/SocketProcessParent.h
--- a/ipc/glue/BackgroundChild.h
+++ b/ipc/glue/BackgroundChild.h
@@ -19,17 +19,17 @@ class BlobImpl;
 class ContentChild;
 class ContentParent;
 
 }  // namespace dom
 
 namespace net {
 
 class SocketProcessImpl;
-
+class SocketProcessChild;
 }  // namespace net
 
 namespace ipc {
 
 class PBackgroundChild;
 
 // This class allows access to the PBackground protocol. PBackground allows
 // communication between any thread (in the parent or a child process) and a
@@ -52,16 +52,17 @@ class PBackgroundChild;
 // illegal to call this before the PBackground actor has been created.
 //
 // The PBackgroundChild actor and all its sub-protocol actors will be
 // automatically destroyed when its designated thread completes.
 class BackgroundChild final {
   friend class mozilla::dom::ContentChild;
   friend class mozilla::dom::ContentParent;
   friend class mozilla::net::SocketProcessImpl;
+  friend class mozilla::net::SocketProcessChild;
 
   typedef mozilla::ipc::Transport Transport;
 
  public:
   // See above.
   static PBackgroundChild* GetForCurrentThread();
 
   // See above.
@@ -70,16 +71,20 @@ class BackgroundChild final {
 
   // See above.
   static void CloseForCurrentThread();
 
   // See above.
   static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(
       nsIEventTarget* aMainEventTarget = nullptr);
 
+  // See above.
+  static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(
+      nsIEventTarget* aMainEventTarget = nullptr);
+
  private:
   // Only called by ContentChild or ContentParent.
   static void Startup();
 };
 
 }  // namespace ipc
 }  // namespace mozilla
 
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -22,16 +22,17 @@
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRef.h"
 #include "mozilla/ipc/ProtocolTypes.h"
+#include "mozilla/net/SocketProcessChild.h"
 #include "mozilla/net/SocketProcessBridgeChild.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIEventTarget.h"
 #include "nsIMutable.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsIRunnable.h"
@@ -273,16 +274,17 @@ class ChildImpl final : public Backgroun
   // A thread-local index that is not valid.
   static const unsigned int kBadThreadLocalIndex =
       static_cast<unsigned int>(-1);
 
   // This is only modified on the main thread. It is the thread-local index that
   // we use to store the BackgroundChild for each thread.
   static unsigned int sThreadLocalIndex;
   static unsigned int sThreadLocalIndexForSocketProcess;
+  static unsigned int sThreadLocalIndexForSocketParentBridge;
 
   struct ThreadLocalInfo {
     ThreadLocalInfo()
 #ifdef DEBUG
         : mClosed(false)
 #endif
     {
     }
@@ -297,16 +299,18 @@ class ChildImpl final : public Backgroun
 
   // On the main thread, we store TLS in this global instead of in
   // sThreadLocalIndex. That way, cooperative main threads all share the same
   // thread info.
   static ThreadLocalInfo* sMainThreadInfo;
 
   static ThreadLocalInfo* sMainThreadInfoForSocketProcess;
 
+  static ThreadLocalInfo* sMainThreadInfoForSocketParentBridge;
+
   // This is only modified on the main thread. It prevents us from trying to
   // create the background thread after application shutdown has started.
   static bool sShutdownHasStarted;
 
 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
   nsISerialEventTarget* mOwningEventTarget;
 #endif
 
@@ -377,16 +381,19 @@ class ChildImpl final : public Backgroun
   static PBackgroundChild* GetOrCreateForCurrentThread(
       nsIEventTarget* aMainEventTarget);
 
   // Forwarded from BackgroundChild.
   static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(
       nsIEventTarget* aMainEventTarget);
 
   // Forwarded from BackgroundChild.
+  static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(
+      nsIEventTarget* aMainEventTarget);
+
   static void CloseForCurrentThread();
 
   static void CloseThreadWithIndex(unsigned int aThreadLocalIndex);
 
   // Forwarded from BackgroundChildImpl.
   static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread();
 
   static void ThreadLocalDestructor(void* aThreadLocal);
@@ -660,16 +667,24 @@ PBackgroundChild* BackgroundChild::GetOr
 
 // static
 PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread(
     nsIEventTarget* aMainEventTarget) {
   return ChildImpl::GetOrCreateSocketActorForCurrentThread(aMainEventTarget);
 }
 
 // static
+PBackgroundChild*
+BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread(
+    nsIEventTarget* aMainEventTarget) {
+  return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
+      aMainEventTarget);
+}
+
+// static
 void BackgroundChild::CloseForCurrentThread() {
   ChildImpl::CloseForCurrentThread();
 }
 
 // -----------------------------------------------------------------------------
 // BackgroundChildImpl Public Methods
 // -----------------------------------------------------------------------------
 
@@ -701,16 +716,18 @@ bool ParentImpl::sShutdownHasStarted = f
 
 // -----------------------------------------------------------------------------
 // ChildImpl Static Members
 // -----------------------------------------------------------------------------
 
 unsigned int ChildImpl::sThreadLocalIndex = kBadThreadLocalIndex;
 unsigned int ChildImpl::sThreadLocalIndexForSocketProcess =
     kBadThreadLocalIndex;
+unsigned int ChildImpl::sThreadLocalIndexForSocketParentBridge =
+    kBadThreadLocalIndex;
 
 bool ChildImpl::sShutdownHasStarted = false;
 
 // -----------------------------------------------------------------------------
 // ParentImpl Implementation
 // -----------------------------------------------------------------------------
 
 // static
@@ -1090,21 +1107,17 @@ ParentImpl::ShutdownObserver::Observe(ns
   AssertIsOnMainThread();
   MOZ_ASSERT(!sShutdownHasStarted);
   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
 
   sShutdownHasStarted = true;
 
   // Do this first before calling (and spinning the event loop in)
   // ShutdownBackgroundThread().
-  // Since we didn't call BackgroundChild::Startup() in socket process,
-  // we can't call ChildImpl::Shutdown() here.
-  if (!XRE_IsSocketProcess()) {
-    ChildImpl::Shutdown();
-  }
+  ChildImpl::Shutdown();
 
   ShutdownBackgroundThread();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ParentImpl::RequestMessageLoopRunnable::Run() {
@@ -1282,27 +1295,34 @@ ParentImpl::CreateActorHelper::Run() {
 void ChildImpl::Startup() {
   // This happens on the main thread but before XPCOM has started so we can't
   // assert that we're being called on the main thread here.
 
   MOZ_ASSERT(sThreadLocalIndex == kBadThreadLocalIndex,
              "BackgroundChild::Startup() called more than once!");
   MOZ_ASSERT(sThreadLocalIndexForSocketProcess == kBadThreadLocalIndex,
              "BackgroundChild::Startup() called more than once!");
+  MOZ_ASSERT(sThreadLocalIndexForSocketParentBridge == kBadThreadLocalIndex,
+             "BackgroundChild::Startup() called more than once!");
 
   PRStatus status =
       PR_NewThreadPrivateIndex(&sThreadLocalIndex, ThreadLocalDestructor);
   MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
 
   status = PR_NewThreadPrivateIndex(&sThreadLocalIndexForSocketProcess,
                                     ThreadLocalDestructor);
   MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
 
+  status = PR_NewThreadPrivateIndex(&sThreadLocalIndexForSocketParentBridge,
+                                    ThreadLocalDestructor);
+  MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
+
   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
   MOZ_ASSERT(sThreadLocalIndexForSocketProcess != kBadThreadLocalIndex);
+  MOZ_ASSERT(sThreadLocalIndexForSocketParentBridge != kBadThreadLocalIndex);
 
   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
   MOZ_RELEASE_ASSERT(observerService);
 
   nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
 
   nsresult rv = observerService->AddObserver(
       observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
@@ -1313,31 +1333,36 @@ void ChildImpl::ShutdownWithThreadLocalI
   MOZ_ASSERT(aThreadLocalIndex != kBadThreadLocalIndex);
 
   ThreadLocalInfo* threadLocalInfo;
 #ifdef DEBUG
   threadLocalInfo =
       static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(aThreadLocalIndex));
   MOZ_ASSERT(!threadLocalInfo);
 #endif
-  threadLocalInfo = aThreadLocalIndex == sThreadLocalIndex
-                        ? sMainThreadInfo
-                        : sMainThreadInfoForSocketProcess;
+  threadLocalInfo =
+      aThreadLocalIndex == sThreadLocalIndex
+          ? sMainThreadInfo
+          : (aThreadLocalIndex == sThreadLocalIndexForSocketProcess
+                 ? sMainThreadInfoForSocketProcess
+                 : sMainThreadInfoForSocketParentBridge);
 
   if (threadLocalInfo) {
 #ifdef DEBUG
     MOZ_ASSERT(!threadLocalInfo->mClosed);
     threadLocalInfo->mClosed = true;
 #endif
 
     ThreadLocalDestructor(threadLocalInfo);
     if (aThreadLocalIndex == sThreadLocalIndex) {
       sMainThreadInfo = nullptr;
+    } else if (aThreadLocalIndex == sThreadLocalIndexForSocketProcess) {
+      sMainThreadInfoForSocketProcess = nullptr;
     } else {
-      sMainThreadInfoForSocketProcess = nullptr;
+      sMainThreadInfoForSocketParentBridge = nullptr;
     }
   }
 }
 
 // static
 void ChildImpl::Shutdown() {
   AssertIsOnMainThread();
 
@@ -1351,21 +1376,27 @@ void ChildImpl::Shutdown() {
 
   sShutdownHasStarted = true;
 
   ShutdownWithThreadLocalIndex(sThreadLocalIndex);
 
   if (sThreadLocalIndexForSocketProcess != kBadThreadLocalIndex) {
     ShutdownWithThreadLocalIndex(sThreadLocalIndexForSocketProcess);
   }
+
+  if (sThreadLocalIndexForSocketParentBridge != kBadThreadLocalIndex) {
+    ShutdownWithThreadLocalIndex(sThreadLocalIndexForSocketParentBridge);
+  }
 }
 
 ChildImpl::ThreadLocalInfo* ChildImpl::sMainThreadInfo = nullptr;
 ChildImpl::ThreadLocalInfo* ChildImpl::sMainThreadInfoForSocketProcess =
     nullptr;
+ChildImpl::ThreadLocalInfo* ChildImpl::sMainThreadInfoForSocketParentBridge =
+    nullptr;
 
 // static
 PBackgroundChild* ChildImpl::GetForCurrentThread() {
   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
 
   auto threadLocalInfo = NS_IsMainThread()
                              ? sMainThreadInfo
                              : static_cast<ThreadLocalInfo*>(
@@ -1632,16 +1663,118 @@ PBackgroundChild* ChildImpl::GetOrCreate
   }
 
   RefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
   strongActor.swap(actor);
 
   return actor;
 }
 
+/* static */
+PBackgroundChild* ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
+    nsIEventTarget* aMainEventTarget) {
+  MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget);
+
+  MOZ_ASSERT(sThreadLocalIndexForSocketParentBridge != kBadThreadLocalIndex,
+             "BackgroundChild::Startup() was never called!");
+
+  if (NS_IsMainThread() && sShutdownHasStarted) {
+    return nullptr;
+  }
+
+  auto threadLocalInfo =
+      NS_IsMainThread() ? sMainThreadInfoForSocketParentBridge
+                        : static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
+                              sThreadLocalIndexForSocketParentBridge));
+
+  if (!threadLocalInfo) {
+    nsAutoPtr<ThreadLocalInfo> newInfo(new ThreadLocalInfo());
+
+    if (NS_IsMainThread()) {
+      sMainThreadInfoForSocketParentBridge = newInfo;
+    } else {
+      if (PR_SetThreadPrivate(sThreadLocalIndexForSocketParentBridge,
+                              newInfo) != PR_SUCCESS) {
+        CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
+        return nullptr;
+      }
+    }
+
+    threadLocalInfo = newInfo.forget();
+  }
+
+  PBackgroundChild* bgChild =
+      GetFromThreadInfo(aMainEventTarget, threadLocalInfo);
+  if (bgChild) {
+    return bgChild;
+  }
+
+  SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
+
+  if (!socketChild || socketChild->IsShuttingDown()) {
+    return nullptr;
+  }
+
+  Endpoint<PBackgroundParent> parent;
+  Endpoint<PBackgroundChild> child;
+  nsresult rv;
+  rv = PBackground::CreateEndpoints(socketChild->OtherPid(),
+                                    base::GetCurrentProcId(), &parent, &child);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to create top level actor!");
+    return nullptr;
+  }
+
+  RefPtr<SendInitBackgroundRunnable> runnable;
+  if (!NS_IsMainThread()) {
+    runnable = SendInitBackgroundRunnable::Create(
+        std::move(parent), [](Endpoint<PBackgroundParent>&& aParent) {
+          SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
+          MOZ_ASSERT(socketChild);
+
+          if (!socketChild->SendInitBackground(std::move(aParent))) {
+            MOZ_CRASH("Failed to create top level actor!");
+          }
+        });
+    if (!runnable) {
+      return nullptr;
+    }
+  }
+
+  RefPtr<ChildImpl> strongActor = new ChildImpl();
+
+  if (!child.Bind(strongActor)) {
+    CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
+    return nullptr;
+  }
+
+  strongActor->SetActorAlive();
+
+  if (NS_IsMainThread()) {
+    if (!socketChild->SendInitBackground(std::move(parent))) {
+      NS_WARNING("Failed to create top level actor!");
+      return nullptr;
+    }
+  } else {
+    if (aMainEventTarget) {
+      MOZ_ALWAYS_SUCCEEDS(
+          aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
+    } else {
+      MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
+    }
+
+    threadLocalInfo->mSendInitBackgroundRunnable = runnable;
+  }
+
+  RefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
+  strongActor.swap(actor);
+
+  return actor;
+}
+
 // static
 void ChildImpl::CloseThreadWithIndex(unsigned int aThreadLocalIndex) {
   auto threadLocalInfo =
       static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(aThreadLocalIndex));
 
   if (!threadLocalInfo) {
     return;
   }
@@ -1663,16 +1796,19 @@ void ChildImpl::CloseForCurrentThread() 
              "ChildImpl::Shutdown().");
 
   if (sThreadLocalIndex != kBadThreadLocalIndex) {
     CloseThreadWithIndex(sThreadLocalIndex);
   }
   if (sThreadLocalIndexForSocketProcess != kBadThreadLocalIndex) {
     CloseThreadWithIndex(sThreadLocalIndexForSocketProcess);
   }
+  if (sThreadLocalIndexForSocketParentBridge != kBadThreadLocalIndex) {
+    CloseThreadWithIndex(sThreadLocalIndexForSocketParentBridge);
+  }
 }
 
 // static
 BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
              "BackgroundChild::Startup() was never called!");
 
   auto threadLocalInfo = NS_IsMainThread()
--- a/ipc/glue/BackgroundParent.h
+++ b/ipc/glue/BackgroundParent.h
@@ -14,16 +14,17 @@
 template <class>
 struct already_AddRefed;
 
 namespace mozilla {
 
 namespace net {
 
 class SocketProcessBridgeParent;
+class SocketProcessParent;
 
 }  // namespace net
 
 namespace dom {
 
 class BlobImpl;
 class ContentParent;
 
@@ -41,16 +42,17 @@ class Endpoint;
 class BackgroundParent final {
   friend class mozilla::dom::ContentParent;
 
   typedef base::ProcessId ProcessId;
   typedef mozilla::dom::BlobImpl BlobImpl;
   typedef mozilla::dom::ContentParent ContentParent;
   typedef mozilla::ipc::Transport Transport;
   friend class mozilla::net::SocketProcessBridgeParent;
+  friend class mozilla::net::SocketProcessParent;
 
  public:
   // This function allows the caller to determine if the given parent actor
   // corresponds to a child actor from another process or a child actor from a
   // different thread in the same process.
   // This function may only be called on the background thread.
   static bool IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
 
@@ -77,17 +79,18 @@ class BackgroundParent final {
   static bool GetLiveActorArray(PBackgroundParent* aBackgroundActor,
                                 nsTArray<PBackgroundParent*>& aLiveActorArray);
 
  private:
   // Only called by ContentParent for cross-process actors.
   static bool Alloc(ContentParent* aContent,
                     Endpoint<PBackgroundParent>&& aEndpoint);
 
-  // Only called by SocketProcessBridgeParent for cross-process actors.
+  // Called by SocketProcessBridgeParent and SocketProcessParent for
+  // cross-process actors.
   static bool Alloc(Endpoint<PBackgroundParent>&& aEndpoint);
 };
 
 // Implemented in BackgroundImpl.cpp.
 bool IsOnBackgroundThread();
 
 #ifdef DEBUG
 
--- a/netwerk/ipc/PSocketProcess.ipdl
+++ b/netwerk/ipc/PSocketProcess.ipdl
@@ -7,16 +7,17 @@ include MemoryReportTypes;
 include protocol PFileDescriptorSet;
 include protocol PHttpTransaction;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PSocketProcessBridge;
 include protocol PProfiler;
 include protocol PAltService;
 include protocol PDNSRequest;
+include protocol PBackground;
 
 include PrefsTypes;
 
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::Telemetry::HistogramAccumulation from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::KeyedHistogramAccumulation from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::ScalarAction from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::KeyedScalarAction from "mozilla/TelemetryComms.h";
@@ -47,16 +48,17 @@ parent:
   // Messages for sending telemetry to parent process.
   async AccumulateChildHistograms(HistogramAccumulation[] accumulations);
   async AccumulateChildKeyedHistograms(KeyedHistogramAccumulation[] accumulations);
   async UpdateChildScalars(ScalarAction[] actions);
   async UpdateChildKeyedScalars(KeyedScalarAction[] actions);
   async RecordChildEvents(ChildEventData[] events);
   async RecordDiscardedData(DiscardedData data);
   async PAltService();
+  async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
 
 child:
   async PreferenceUpdate(Pref pref);
   async RequestMemoryReport(uint32_t generation,
                             bool anonymize,
                             bool minimizeMemoryUsage,
                             FileDescriptor? DMDFile);
   async PHttpTransaction(uint64_t aChannelID);
--- a/netwerk/ipc/SocketProcessChild.cpp
+++ b/netwerk/ipc/SocketProcessChild.cpp
@@ -8,16 +8,17 @@
 
 #include "base/task.h"
 #include "AltServiceChild.h"
 #include "HttpInfo.h"
 #include "HttpTransactionChild.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/MemoryReportRequest.h"
 #include "mozilla/ipc/CrashReporterClient.h"
+#include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/IPCStreamAlloc.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/ipc/PChildToParentStreamChild.h"
 #include "mozilla/ipc/PParentToChildStreamChild.h"
 #include "mozilla/net/DNSRequestChild.h"
 #include "mozilla/Preferences.h"
 #include "nsDebugImpl.h"
@@ -31,19 +32,19 @@
 #  include "ChildProfilerController.h"
 #endif
 
 namespace mozilla {
 namespace net {
 
 using namespace ipc;
 
-static SocketProcessChild* sSocketProcessChild;
+SocketProcessChild* sSocketProcessChild;
 
-SocketProcessChild::SocketProcessChild() {
+SocketProcessChild::SocketProcessChild() : mShuttingDown(false) {
   LOG(("CONSTRUCT SocketProcessChild::SocketProcessChild\n"));
   nsDebugImpl::SetMultiprocessMode("Socket");
 
   MOZ_COUNT_CTOR(SocketProcessChild);
   sSocketProcessChild = this;
 }
 
 SocketProcessChild::~SocketProcessChild() {
@@ -78,23 +79,26 @@ bool SocketProcessChild::Init(base::Proc
 
   // Init crash reporter support.
   CrashReporterClient::InitSingleton(this);
 
   if (NS_FAILED(NS_InitMinimalXPCOM())) {
     return false;
   }
 
+  BackgroundChild::Startup();
   SetThisProcessName("Socket Process");
   return true;
 }
 
 void SocketProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
   LOG(("SocketProcessChild::ActorDestroy\n"));
 
+  mShuttingDown = true;
+
   if (AbnormalShutdown == aWhy) {
     NS_WARNING("Shutting down Socket process early due to a crash!");
     ProcessChild::QuickExit();
   }
 
 #ifdef MOZ_GECKO_PROFILER
   if (mProfilerController) {
     mProfilerController->Shutdown();
--- a/netwerk/ipc/SocketProcessChild.h
+++ b/netwerk/ipc/SocketProcessChild.h
@@ -19,18 +19,19 @@ namespace net {
 
 class SocketProcessBridgeParent;
 class BackgroundDataBridgeParent;
 
 // The IPC actor implements PSocketProcessChild in child process.
 // This is allocated and kept alive by SocketProcessImpl.
 class SocketProcessChild final : public PSocketProcessChild {
  public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketProcessChild)
+
   SocketProcessChild();
-  ~SocketProcessChild();
 
   static SocketProcessChild* GetSingleton();
 
   bool Init(base::ProcessId aParentPid, const char* aParentBuildID,
             MessageLoop* aIOLoop, IPC::Channel* aChannel);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
@@ -108,29 +109,37 @@ class SocketProcessChild final : public 
     return mBackgroundDataBridgeMap.Get(channelId);
   }
 
   void SaveBackgroundThread() {
     ipc::AssertIsOnBackgroundThread();
     mBackgroundThread = NS_GetCurrentThread();
   }
 
+  bool IsShuttingDown() { return mShuttingDown; }
+
   nsCOMPtr<nsIThread> mBackgroundThread;
 
+ protected:
+  friend class SocketProcessImpl;
+  ~SocketProcessChild();
+
  private:
   // Mapping of content process id and the SocketProcessBridgeParent.
   // This table keeps SocketProcessBridgeParent alive in socket process.
   nsRefPtrHashtable<nsUint32HashKey, SocketProcessBridgeParent>
       mSocketProcessBridgeParentMap;
 
   // Should only be accessed on the background thread.
   nsDataHashtable<nsUint64HashKey, BackgroundDataBridgeParent*>
       mBackgroundDataBridgeMap;
 
 #ifdef MOZ_GECKO_PROFILER
   RefPtr<ChildProfilerController> mProfilerController;
 #endif
+
+  bool mShuttingDown;
 };
 
 }  // namespace net
 }  // namespace mozilla
 
 #endif  // mozilla_net_SocketProcessChild_h
--- a/netwerk/ipc/SocketProcessParent.cpp
+++ b/netwerk/ipc/SocketProcessParent.cpp
@@ -198,16 +198,26 @@ PDNSRequestParent* SocketProcessParent::
 }
 
 bool SocketProcessParent::DeallocPDNSRequestParent(PDNSRequestParent* aActor) {
   DNSRequestParent* p = static_cast<DNSRequestParent*>(aActor);
   p->ReleaseIPDLReference();
   return true;
 }
 
+mozilla::ipc::IPCResult SocketProcessParent::RecvInitBackground(
+    Endpoint<PBackgroundParent>&& aEndpoint) {
+  LOG(("SocketProcessParent::RecvInitBackground\n"));
+  if (!ipc::BackgroundParent::Alloc(nullptr, std::move(aEndpoint))) {
+    return IPC_FAIL(this, "BackgroundParent::Alloc failed");
+  }
+
+  return IPC_OK();
+}
+
 // To ensure that IPDL is finished before SocketParent gets deleted.
 class DeferredDeleteSocketProcessParent : public Runnable {
  public:
   explicit DeferredDeleteSocketProcessParent(
       UniquePtr<SocketProcessParent>&& aParent)
       : Runnable("net::DeferredDeleteSocketProcessParent"),
         mParent(std::move(aParent)) {}
 
--- a/netwerk/ipc/SocketProcessParent.h
+++ b/netwerk/ipc/SocketProcessParent.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_net_SocketProcessParent_h
 #define mozilla_net_SocketProcessParent_h
 
 #include "mozilla/UniquePtr.h"
 #include "mozilla/net/PSocketProcessParent.h"
+#include "mozilla/ipc/BackgroundParent.h"
 
 namespace mozilla {
 
 namespace dom {
 class MemoryReport;
 class MemoryReportRequestHost;
 }  // namespace dom
 
@@ -73,16 +74,19 @@ class SocketProcessParent final : public
   PAltServiceParent* AllocPAltServiceParent();
   bool DeallocPAltServiceParent(PAltServiceParent* aActor);
 
   PDNSRequestParent* AllocPDNSRequestParent(
       const nsCString& aHost, const OriginAttributes& aOriginAttributes,
       const uint32_t& aFlags);
   bool DeallocPDNSRequestParent(PDNSRequestParent*);
 
+  mozilla::ipc::IPCResult RecvInitBackground(
+      Endpoint<PBackgroundParent>&& aEndpoint);
+
  private:
   SocketProcessHost* mHost;
   UniquePtr<ipc::CrashReporterHost> mCrashReporter;
   UniquePtr<dom::MemoryReportRequestHost> mMemoryReportRequest;
 
   static void Destroy(UniquePtr<SocketProcessParent>&& aParent);
 };