Bug 879475 - Part 002. Add an nsIContentChild api r=jlebar
☠☠ backed out by 403e528b14dd ☠ ☠
author"Kan-Ru Chen (陳侃如)" <kanru@kanru.info>
Mon, 09 Jun 2014 16:49:11 +0800
changeset 187529 f1406960c26a5f18a74a5046fba0304c1541eb9a
parent 187528 f7e0ffc1debdbac432fa5a96bd0d5ae7765c1fc9
child 187530 3f1a5417af05693178de465e70ce581ee853df15
push id44615
push userkchen@mozilla.com
push dateMon, 09 Jun 2014 08:52:19 +0000
treeherdermozilla-inbound@00c2ba04f8d4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar
bugs879475
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 879475 - Part 002. Add an nsIContentChild api r=jlebar Based on original patch by David Zbarsky <dzbarsky@gmail.com>
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsFrameMessageManager.h
dom/ipc/Blob.cpp
dom/ipc/Blob.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/moz.build
dom/ipc/nsIContentChild.cpp
dom/ipc/nsIContentChild.h
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -149,17 +149,17 @@ struct BlobTraits<Parent>
   typedef mozilla::dom::nsIContentParent ConcreteContentManagerType;
 };
 
 template <>
 struct BlobTraits<Child>
 {
   typedef mozilla::dom::BlobChild BlobType;
   typedef mozilla::dom::PBlobChild ProtocolType;
-  typedef mozilla::dom::ContentChild ConcreteContentManagerType;
+  typedef mozilla::dom::nsIContentChild ConcreteContentManagerType;
 };
 
 template<ActorFlavorEnum>
 struct DataBlobs
 { };
 
 template<>
 struct DataBlobs<Parent>
@@ -224,17 +224,17 @@ bool
 MessageManagerCallback::BuildClonedMessageDataForParent(nsIContentParent* aParent,
                                                         const StructuredCloneData& aData,
                                                         ClonedMessageData& aClonedData)
 {
   return BuildClonedMessageData<Parent>(aParent, aData, aClonedData);
 }
 
 bool
-MessageManagerCallback::BuildClonedMessageDataForChild(ContentChild* aChild,
+MessageManagerCallback::BuildClonedMessageDataForChild(nsIContentChild* aChild,
                                                        const StructuredCloneData& aData,
                                                        ClonedMessageData& aClonedData)
 {
   return BuildClonedMessageData<Child>(aChild, aData, aClonedData);
 }
 
 template<ActorFlavorEnum Flavor>
 static StructuredCloneData
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -28,17 +28,17 @@
 #include "js/RootingAPI.h"
 #include "nsTObserverArray.h"
 #include "mozilla/dom/StructuredCloneUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 class nsIContentParent;
-class ContentChild;
+class nsIContentChild;
 class ClonedMessageData;
 class MessageManagerReporter;
 
 namespace ipc {
 
 enum MessageManagerFlags {
   MM_CHILD = 0,
   MM_CHROME = 1,
@@ -97,17 +97,17 @@ public:
   {
     return false;
   }
 
 protected:
   bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
                                        const StructuredCloneData& aData,
                                        ClonedMessageData& aClonedData);
-  bool BuildClonedMessageDataForChild(ContentChild* aChild,
+  bool BuildClonedMessageDataForChild(nsIContentChild* aChild,
                                       const StructuredCloneData& aData,
                                       ClonedMessageData& aClonedData);
 };
 
 StructuredCloneData UnpackClonedMessageDataForParent(const ClonedMessageData& aData);
 StructuredCloneData UnpackClonedMessageDataForChild(const ClonedMessageData& aData);
 
 } // namespace ipc
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -8,16 +8,17 @@
 #include "ContentParent.h"
 #include "FileDescriptorSetChild.h"
 #include "jsapi.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/nsIContentParent.h"
+#include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/dom/PBlobStreamChild.h"
 #include "mozilla/dom/PBlobStreamParent.h"
 #include "mozilla/dom/PFileDescriptorSetParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDOMFile.h"
 #include "nsIDOMFile.h"
 #include "nsIInputStream.h"
@@ -1051,34 +1052,34 @@ RemoteBlob::GetPBlob()
 {
   return static_cast<PBlobChild*>(mActor);
 }
 
 /*******************************************************************************
  * BlobChild
  ******************************************************************************/
 
-BlobChild::BlobChild(ContentChild* aManager, nsIDOMBlob* aBlob)
+BlobChild::BlobChild(nsIContentChild* aManager, nsIDOMBlob* aBlob)
   : mBlob(aBlob)
   , mRemoteBlob(nullptr)
   , mStrongManager(aManager)
   , mOwnsBlob(true)
   , mBlobIsFile(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aBlob);
 
   aBlob->AddRef();
 
   nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
   mBlobIsFile = !!file;
 }
 
-BlobChild::BlobChild(ContentChild* aManager,
+BlobChild::BlobChild(nsIContentChild* aManager,
                      const ChildBlobConstructorParams& aParams)
   : mBlob(nullptr)
   , mRemoteBlob(nullptr)
   , mStrongManager(aManager)
   , mOwnsBlob(false)
   , mBlobIsFile(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -1100,17 +1101,17 @@ BlobChild::BlobChild(ContentChild* aMana
   mOwnsBlob = true;
 }
 
 BlobChild::~BlobChild()
 {
 }
 
 BlobChild*
-BlobChild::Create(ContentChild* aManager,
+BlobChild::Create(nsIContentChild* aManager,
                   const ChildBlobConstructorParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
 
   switch (aParams.type()) {
     case ChildBlobConstructorParams::TNormalBlobConstructorParams:
     case ChildBlobConstructorParams::TFileBlobConstructorParams:
@@ -1200,16 +1201,22 @@ BlobChild::SetMysteryBlobInfo(const nsSt
 
   ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength,
                                      UINT64_MAX);
 
   NormalBlobConstructorParams params(aContentType, aLength);
   return SendResolveMystery(params);
 }
 
+nsIContentChild*
+BlobChild::Manager()
+{
+  return mStrongManager;
+}
+
 already_AddRefed<BlobChild::RemoteBlob>
 BlobChild::CreateRemoteBlob(const ChildBlobConstructorParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsRefPtr<RemoteBlob> remoteBlob;
 
   switch (aParams.type()) {
--- a/dom/ipc/Blob.h
+++ b/dom/ipc/Blob.h
@@ -13,40 +13,40 @@
 
 class nsIDOMBlob;
 class nsString;
 template <class> class nsRevocableEventPtr;
 
 namespace mozilla {
 namespace dom {
 
-class ContentChild;
+class nsIContentChild;
 class nsIContentParent;
 class PBlobStreamChild;
 class PBlobStreamParent;
 
 class BlobChild MOZ_FINAL
   : public PBlobChild
 {
-  friend class ContentChild;
+  friend class nsIContentChild;
 
   class RemoteBlob;
   friend class RemoteBlob;
 
   nsIDOMBlob* mBlob;
   RemoteBlob* mRemoteBlob;
-  nsRefPtr<ContentChild> mStrongManager;
+  nsRefPtr<nsIContentChild> mStrongManager;
 
   bool mOwnsBlob;
   bool mBlobIsFile;
 
 public:
   // This create function is called on the sending side.
   static BlobChild*
-  Create(ContentChild* aManager, nsIDOMBlob* aBlob)
+  Create(nsIContentChild* aManager, nsIDOMBlob* aBlob)
   {
     return new BlobChild(aManager, aBlob);
   }
 
   // Get the blob associated with this actor. This may always be called on the
   // sending side. It may also be called on the receiving side unless this is a
   // "mystery" blob that has not yet received a SetMysteryBlobInfo() call.
   already_AddRefed<nsIDOMBlob>
@@ -58,29 +58,31 @@ public:
                      const nsString& aContentType,
                      uint64_t aLength,
                      uint64_t aLastModifiedDate);
 
   // Use this for non-file blobs.
   bool
   SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength);
 
+  nsIContentChild* Manager();
+
 private:
   // This constructor is called on the sending side.
-  BlobChild(ContentChild* aManager, nsIDOMBlob* aBlob);
+  BlobChild(nsIContentChild* aManager, nsIDOMBlob* aBlob);
 
   // This constructor is called on the receiving side.
-  BlobChild(ContentChild* aManager, const ChildBlobConstructorParams& aParams);
+  BlobChild(nsIContentChild* aManager, const ChildBlobConstructorParams& aParams);
 
   // Only destroyed by ContentChild.
   ~BlobChild();
 
   // This create function is called on the receiving side by ContentChild.
   static BlobChild*
-  Create(ContentChild* aManager, const ChildBlobConstructorParams& aParams);
+  Create(nsIContentChild* aManager, const ChildBlobConstructorParams& aParams);
 
   static already_AddRefed<RemoteBlob>
   CreateRemoteBlob(const ChildBlobConstructorParams& aParams);
 
   void
   NoteDyingRemoteBlob();
 
   // These methods are only called by the IPDL message machinery.
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -13,33 +13,34 @@
 #endif
 
 #include "ContentChild.h"
 #include "CrashReporterChild.h"
 #include "FileDescriptorSetChild.h"
 #include "TabChild.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/dom/DOMStorageIPC.h"
+#include "mozilla/dom/ExternalHelperAppChild.h"
+#include "mozilla/dom/PCrashReporterChild.h"
+#include "mozilla/dom/Promise.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/asmjscache/PAsmJSCacheEntryChild.h"
-#include "mozilla/dom/ExternalHelperAppChild.h"
-#include "mozilla/dom/PCrashReporterChild.h"
-#include "mozilla/dom/DOMStorageIPC.h"
-#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
-#include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/net/NeckoChild.h"
-#include "mozilla/Preferences.h"
 
 #if defined(MOZ_CONTENT_SANDBOX)
 #if defined(XP_WIN)
 #define TARGET_SANDBOX_EXPORTS
 #include "mozilla/sandboxTarget.h"
 #elif defined(XP_LINUX)
 #include "mozilla/Sandbox.h"
 #endif
@@ -492,16 +493,21 @@ ContentChild::ContentChild()
     // multiprocess mode!
     nsDebugImpl::SetMultiprocessMode("Child");
 }
 
 ContentChild::~ContentChild()
 {
 }
 
+NS_INTERFACE_MAP_BEGIN(ContentChild)
+  NS_INTERFACE_MAP_ENTRY(nsIContentChild)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
 bool
 ContentChild::Init(MessageLoop* aIOLoop,
                    base::ProcessHandle aParentHandle,
                    IPC::Channel* aChannel)
 {
 #ifdef MOZ_WIDGET_GTK
     // sigh
     gtk_init(nullptr, nullptr);
@@ -895,61 +901,53 @@ static void FirstIdle(void)
     ContentChild::GetSingleton()->SendFirstIdle();
 }
 
 mozilla::jsipc::PJavaScriptChild *
 ContentChild::AllocPJavaScriptChild()
 {
     MOZ_ASSERT(!ManagedPJavaScriptChild().Length());
 
-    nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
-    NS_ENSURE_TRUE(svc, nullptr);
-
-    JSRuntime *rt;
-    svc->GetRuntime(&rt);
-    NS_ENSURE_TRUE(svc, nullptr);
-
-    mozilla::jsipc::JavaScriptChild *child = new mozilla::jsipc::JavaScriptChild(rt);
-    if (!child->init()) {
-        delete child;
-        return nullptr;
-    }
-    return child;
+    return nsIContentChild::AllocPJavaScriptChild();
 }
 
 bool
-ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
+ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *aChild)
 {
-    static_cast<mozilla::jsipc::JavaScriptChild *>(child)->decref();
-    return true;
+    return nsIContentChild::DeallocPJavaScriptChild(aChild);
 }
 
 PBrowserChild*
 ContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
                                  const uint32_t& aChromeFlags,
-                                 const uint64_t& aId,
+                                 const uint64_t& aID,
                                  const bool& aIsForApp,
                                  const bool& aIsForBrowser)
 {
-    // We'll happily accept any kind of IPCTabContext here; we don't need to
-    // check that it's of a certain type for security purposes, because we
-    // believe whatever the parent process tells us.
+    return nsIContentChild::AllocPBrowserChild(aContext,
+                                               aChromeFlags,
+                                               aID,
+                                               aIsForApp,
+                                               aIsForBrowser);
+}
 
-    MaybeInvalidTabContext tc(aContext);
-    if (!tc.IsValid()) {
-        NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
-                                 "the parent process. (%s)  Crashing...",
-                                 tc.GetInvalidReason()).get());
-        MOZ_CRASH("Invalid TabContext received from the parent process.");
-    }
-
-    nsRefPtr<TabChild> child = TabChild::Create(this, tc.GetTabContext(), aChromeFlags);
-
-    // The ref here is released in DeallocPBrowserChild.
-    return child.forget().take();
+bool
+ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
+                                      const IPCTabContext& aContext,
+                                      const uint32_t& aChromeFlags,
+                                      const uint64_t& aID,
+                                      const bool& aIsForApp,
+                                      const bool& aIsForBrowser)
+{
+    return PContentChild::SendPBrowserConstructor(aActor,
+                                                  aContext,
+                                                  aChromeFlags,
+                                                  aID,
+                                                  aIsForApp,
+                                                  aIsForBrowser);
 }
 
 bool
 ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
                                       const uint64_t& aID,
                                       const bool& aIsForApp,
@@ -993,118 +991,38 @@ ContentChild::AllocPFileDescriptorSetChi
 bool
 ContentChild::DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor)
 {
     delete static_cast<FileDescriptorSetChild*>(aActor);
     return true;
 }
 
 bool
-ContentChild::DeallocPBrowserChild(PBrowserChild* iframe)
+ContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
 {
-    TabChild* child = static_cast<TabChild*>(iframe);
-    NS_RELEASE(child);
-    return true;
+    return nsIContentChild::DeallocPBrowserChild(aIframe);
 }
 
 PBlobChild*
 ContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
 {
-    return BlobChild::Create(this, aParams);
+    return nsIContentChild::AllocPBlobChild(aParams);
 }
 
 bool
 ContentChild::DeallocPBlobChild(PBlobChild* aActor)
 {
-    delete aActor;
-    return true;
+    return nsIContentChild::DeallocPBlobChild(aActor);
 }
 
-BlobChild*
-ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
+PBlobChild*
+ContentChild::SendPBlobConstructor(PBlobChild* aActor,
+                                   const BlobConstructorParams& aParams)
 {
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(aBlob);
-
-    // If the blob represents a remote blob then we can simply pass its actor back
-    // here.
-    if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
-        BlobChild* actor =
-            static_cast<BlobChild*>(
-            static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
-        MOZ_ASSERT(actor);
-        return actor;
-    }
-
-    // All blobs shared between processes must be immutable.
-    nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
-    if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
-        NS_WARNING("Failed to make blob immutable!");
-        return nullptr;
-    }
-
-#ifdef DEBUG
-    {
-        // XXX This is only safe so long as all blob implementations in our tree
-        //     inherit nsDOMFileBase. If that ever changes then this will need to
-        //     grow a real interface or something.
-        const auto* blob = static_cast<nsDOMFileBase*>(aBlob);
-
-        MOZ_ASSERT(!blob->IsSizeUnknown());
-        MOZ_ASSERT(!blob->IsDateUnknown());
-    }
-#endif
-
-    ParentBlobConstructorParams params;
-
-    nsString contentType;
-    nsresult rv = aBlob->GetType(contentType);
-    NS_ENSURE_SUCCESS(rv, nullptr);
-
-    uint64_t length;
-    rv = aBlob->GetSize(&length);
-    NS_ENSURE_SUCCESS(rv, nullptr);
-
-    nsCOMPtr<nsIInputStream> stream;
-    rv = aBlob->GetInternalStream(getter_AddRefs(stream));
-    NS_ENSURE_SUCCESS(rv, nullptr);
-
-    InputStreamParams inputStreamParams;
-    nsTArray<mozilla::ipc::FileDescriptor> fds;
-    SerializeInputStream(stream, inputStreamParams, fds);
-
-    MOZ_ASSERT(fds.IsEmpty());
-
-    params.optionalInputStreamParams() = inputStreamParams;
-
-    nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
-    if (file) {
-        FileBlobConstructorParams fileParams;
-
-        rv = file->GetName(fileParams.name());
-        NS_ENSURE_SUCCESS(rv, nullptr);
-
-        rv = file->GetMozLastModifiedDate(&fileParams.modDate());
-        NS_ENSURE_SUCCESS(rv, nullptr);
-
-        fileParams.contentType() = contentType;
-        fileParams.length() = length;
-
-        params.blobParams() = fileParams;
-    } else {
-        NormalBlobConstructorParams blobParams;
-        blobParams.contentType() = contentType;
-        blobParams.length() = length;
-        params.blobParams() = blobParams;
-    }
-
-    BlobChild* actor = BlobChild::Create(this, aBlob);
-    NS_ENSURE_TRUE(actor, nullptr);
-
-    return SendPBlobConstructor(actor, params) ? actor : nullptr;
+    return PContentChild::SendPBlobConstructor(aActor, aParams);
 }
 
 PCrashReporterChild*
 ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
                                        const uint32_t& processType)
 {
 #ifdef MOZ_CRASHREPORTER
     return new CrashReporterChild();
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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_dom_ContentChild_h
 #define mozilla_dom_ContentChild_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/dom/PContentChild.h"
 #include "mozilla/dom/ipc/Blob.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsTHashtable.h"
 
 #include "nsWeakPtr.h"
 
@@ -43,26 +44,28 @@ namespace dom {
 class AlertObserver;
 class PrefObserver;
 class ConsoleListener;
 class PStorageChild;
 class ClonedMessageData;
 class PFileDescriptorSetChild;
 
 class ContentChild : public PContentChild
+                   , public nsIContentChild
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
     typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
     typedef mozilla::ipc::URIParams URIParams;
 
 public:
     ContentChild();
     virtual ~ContentChild();
-    nsrefcnt AddRef() { return 1; }
-    nsrefcnt Release() { return 1; }
+    NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
+    NS_IMETHOD_(MozExternalRefCountType) AddRef(void) { return 1; }
+    NS_IMETHOD_(MozExternalRefCountType) Release(void) { return 1; }
 
     struct AppInfo
     {
         nsCString version;
         nsCString buildID;
         nsCString name;
         nsCString UAName;
     };
@@ -294,24 +297,32 @@ public:
     // cache the value
     nsString &GetIndexedDBPath();
 
     uint64_t GetID() { return mID; }
 
     bool IsForApp() { return mIsForApp; }
     bool IsForBrowser() { return mIsForBrowser; }
 
-    BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
+    virtual PBlobChild*
+    SendPBlobConstructor(PBlobChild* actor,
+                         const BlobConstructorParams& params) MOZ_OVERRIDE;
 
     virtual PFileDescriptorSetChild*
     AllocPFileDescriptorSetChild(const FileDescriptor&) MOZ_OVERRIDE;
 
     virtual bool
     DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*) MOZ_OVERRIDE;
 
+    virtual bool SendPBrowserConstructor(PBrowserChild* actor,
+                                         const IPCTabContext& context,
+                                         const uint32_t& chromeFlags,
+                                         const uint64_t& aID,
+                                         const bool& aIsForApp,
+                                         const bool& aIsForBrowser) MOZ_OVERRIDE;
 protected:
     virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
                                          const IPCTabContext& aContext,
                                          const uint32_t& aChromeFlags,
                                          const uint64_t& aID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -647,17 +647,17 @@ TabChild::PreloadSlowThings()
         presShell->MakeZombie();
     }
 
     sPreallocatedTab = tab;
     ClearOnShutdown(&sPreallocatedTab);
 }
 
 /*static*/ already_AddRefed<TabChild>
-TabChild::Create(ContentChild* aManager, const TabContext &aContext, uint32_t aChromeFlags)
+TabChild::Create(nsIContentChild* aManager, const TabContext &aContext, uint32_t aChromeFlags)
 {
     if (sPreallocatedTab &&
         sPreallocatedTab->mChromeFlags == aChromeFlags &&
         aContext.IsBrowserOrApp()) {
 
         nsRefPtr<TabChild> child = sPreallocatedTab.get();
         sPreallocatedTab = nullptr;
 
@@ -669,17 +669,17 @@ TabChild::Create(ContentChild* aManager,
     }
 
     nsRefPtr<TabChild> iframe = new TabChild(aManager,
                                              aContext, aChromeFlags);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
 }
 
 
-TabChild::TabChild(ContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags)
+TabChild::TabChild(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags)
   : TabContext(aContext)
   , mRemoteFrame(nullptr)
   , mManager(aManager)
   , mChromeFlags(aChromeFlags)
   , mLayersId(0)
   , mOuterRect(0, 0, 0, 0)
   , mActivePointerId(-1)
   , mTapHoldTimer(nullptr)
@@ -2317,17 +2317,17 @@ TabChild::RecvAsyncMessage(const nsStrin
                            const InfallibleTArray<CpowEntry>& aCpows,
                            const IPC::Principal& aPrincipal)
 {
   if (mTabChildGlobal) {
     nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
     StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData);
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
-    CpowIdHolder cpows(static_cast<ContentChild*>(Manager())->GetCPOWManager(), aCpows);
+    CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
     mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
                        aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
   }
   return true;
 }
 
 class UnloadScriptEvent : public nsRunnable
 {
@@ -2663,24 +2663,23 @@ bool
 TabChild::DoSendBlockingMessage(JSContext* aCx,
                                 const nsAString& aMessage,
                                 const StructuredCloneData& aData,
                                 JS::Handle<JSObject *> aCpows,
                                 nsIPrincipal* aPrincipal,
                                 InfallibleTArray<nsString>* aJSONRetVal,
                                 bool aIsSync)
 {
-  ContentChild* cc = Manager();
   ClonedMessageData data;
-  if (!BuildClonedMessageDataForChild(cc, aData, data)) {
+  if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
     return false;
   }
   InfallibleTArray<CpowEntry> cpows;
   if (sCpowsEnabled) {
-    if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
+    if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
   }
   if (aIsSync) {
     return SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
                            aPrincipal, aJSONRetVal);
   }
 
@@ -2690,24 +2689,23 @@ TabChild::DoSendBlockingMessage(JSContex
 
 bool
 TabChild::DoSendAsyncMessage(JSContext* aCx,
                              const nsAString& aMessage,
                              const StructuredCloneData& aData,
                              JS::Handle<JSObject *> aCpows,
                              nsIPrincipal* aPrincipal)
 {
-  ContentChild* cc = Manager();
   ClonedMessageData data;
-  if (!BuildClonedMessageDataForChild(cc, aData, data)) {
+  if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
     return false;
   }
   InfallibleTArray<CpowEntry> cpows;
   if (sCpowsEnabled) {
-    if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
+    if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
   }
   return SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
                           aPrincipal);
 }
 
 TabChild*
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -245,17 +245,17 @@ public:
      * This is expected to be called off the critical path to content
      * startup.  This is an opportunity to load things that are slow
      * on the critical path.
      */
     static void PreloadSlowThings();
 
     /** Return a TabChild with the given attributes. */
     static already_AddRefed<TabChild>
-    Create(ContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    Create(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
 
     virtual ~TabChild();
 
     bool IsRootContentDocument();
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
@@ -425,17 +425,17 @@ public:
     // otherwise.
     bool GetCachedFileDescriptor(const nsAString& aPath,
                                  nsICachedFileDescriptorListener* aCallback);
 
     void CancelCachedFileDescriptorCallback(
                                     const nsAString& aPath,
                                     nsICachedFileDescriptorListener* aCallback);
 
-    ContentChild* Manager() { return mManager; }
+    nsIContentChild* Manager() { return mManager; }
 
     bool GetUpdateHitRegion() { return mUpdateHitRegion; }
 
     void UpdateHitRegion(const nsRegion& aRegion);
 
     static inline TabChild*
     GetFrom(nsIDocShell* aDocShell)
     {
@@ -478,17 +478,17 @@ private:
     /**
      * Create a new TabChild object.
      *
      * |aOwnOrContainingAppId| is the app-id of our frame or of the closest app
      * frame in the hierarchy which contains us.
      *
      * |aIsBrowserElement| indicates whether we're a browser (but not an app).
      */
-    TabChild(ContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    TabChild(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
 
     nsresult Init();
 
 
     // Notify others that our TabContext has been updated.  (At the moment, this
     // sets the appropriate app-id and is-browser flags on our docshell.)
     //
     // You should call this after calling TabContext::SetTabContext().  We also
@@ -531,17 +531,17 @@ private:
     class CachedFileDescriptorInfo;
     class CachedFileDescriptorCallbackRunnable;
 
     TextureFactoryIdentifier mTextureFactoryIdentifier;
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
     nsCOMPtr<nsIURI> mLastURI;
     RenderFrameChild* mRemoteFrame;
-    nsRefPtr<ContentChild> mManager;
+    nsRefPtr<nsIContentChild> mManager;
     uint32_t mChromeFlags;
     uint64_t mLayersId;
     nsIntRect mOuterRect;
     // When we're tracking a possible tap gesture, this is the "down"
     // point of the touchstart.
     LayoutDevicePoint mGestureDownPoint;
     // The touch identifier of the active gesture.
     int32_t mActivePointerId;
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -20,16 +20,17 @@ EXPORTS.mozilla.dom += [
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
     'CrashReporterChild.h',
     'CrashReporterParent.h',
     'FileDescriptorSetChild.h',
     'FileDescriptorSetParent.h',
     'FilePickerParent.h',
+    'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'StructuredCloneUtils.h',
     'TabChild.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
 ]
@@ -44,16 +45,17 @@ UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ColorPickerParent.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
     'CrashReporterParent.cpp',
     'FileDescriptorSetChild.cpp',
     'FileDescriptorSetParent.cpp',
     'FilePickerParent.cpp',
+    'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'StructuredCloneUtils.cpp',
     'TabChild.cpp',
     'TabContext.cpp',
     'TabMessageUtils.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/ipc/nsIContentChild.cpp
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#include "nsIContentChild.h"
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/dom/StructuredCloneUtils.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/ipc/nsIRemoteBlob.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+
+#include "JavaScriptChild.h"
+#include "nsDOMFile.h"
+#include "nsIJSRuntimeService.h"
+#include "nsPrintfCString.h"
+
+using namespace mozilla::ipc;
+using namespace mozilla::jsipc;
+
+namespace mozilla {
+namespace dom {
+
+PJavaScriptChild*
+nsIContentChild::AllocPJavaScriptChild()
+{
+  nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
+  NS_ENSURE_TRUE(svc, nullptr);
+
+  JSRuntime *rt;
+  svc->GetRuntime(&rt);
+  NS_ENSURE_TRUE(svc, nullptr);
+
+  nsAutoPtr<JavaScriptChild> child(new JavaScriptChild(rt));
+  if (!child->init()) {
+    return nullptr;
+  }
+  return child.forget();
+}
+
+bool
+nsIContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild)
+{
+  static_cast<JavaScriptChild*>(aChild)->decref();
+  return true;
+}
+
+PBrowserChild*
+nsIContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
+                                    const uint32_t& aChromeFlags,
+                                    const uint64_t& aID,
+                                    const bool& aIsForApp,
+                                    const bool& aIsForBrowser)
+{
+  // We'll happily accept any kind of IPCTabContext here; we don't need to
+  // check that it's of a certain type for security purposes, because we
+  // believe whatever the parent process tells us.
+
+  MaybeInvalidTabContext tc(aContext);
+  if (!tc.IsValid()) {
+    NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
+                             "the parent process. (%s)  Crashing...",
+                             tc.GetInvalidReason()).get());
+    MOZ_CRASH("Invalid TabContext received from the parent process.");
+  }
+
+  nsRefPtr<TabChild> child = TabChild::Create(this, tc.GetTabContext(), aChromeFlags);
+
+  // The ref here is released in DeallocPBrowserChild.
+  return child.forget().take();
+}
+
+bool
+nsIContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
+{
+  TabChild* child = static_cast<TabChild*>(aIframe);
+  NS_RELEASE(child);
+  return true;
+}
+
+PBlobChild*
+nsIContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
+{
+  return BlobChild::Create(this, aParams);
+}
+
+bool
+nsIContentChild::DeallocPBlobChild(PBlobChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+BlobChild*
+nsIContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aBlob);
+
+  // If the blob represents a remote blob then we can simply pass its actor back
+  // here.
+  if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
+    BlobChild* actor =
+      static_cast<BlobChild*>(
+        static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
+    MOZ_ASSERT(actor);
+    if (actor->Manager() == this) {
+      return actor;
+    }
+  }
+
+  // All blobs shared between processes must be immutable.
+  nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
+  if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
+    NS_WARNING("Failed to make blob immutable!");
+    return nullptr;
+  }
+
+#ifdef DEBUG
+  {
+    // XXX This is only safe so long as all blob implementations in our tree
+    //     inherit nsDOMFileBase. If that ever changes then this will need to
+    //     grow a real interface or something.
+    const auto* blob = static_cast<nsDOMFileBase*>(aBlob);
+
+    MOZ_ASSERT(!blob->IsSizeUnknown());
+    MOZ_ASSERT(!blob->IsDateUnknown());
+  }
+#endif
+
+  ParentBlobConstructorParams params;
+
+  nsString contentType;
+  nsresult rv = aBlob->GetType(contentType);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  uint64_t length;
+  rv = aBlob->GetSize(&length);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  nsCOMPtr<nsIInputStream> stream;
+  rv = aBlob->GetInternalStream(getter_AddRefs(stream));
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  InputStreamParams inputStreamParams;
+  nsTArray<mozilla::ipc::FileDescriptor> fds;
+  SerializeInputStream(stream, inputStreamParams, fds);
+
+  MOZ_ASSERT(fds.IsEmpty());
+
+  params.optionalInputStreamParams() = inputStreamParams;
+
+  nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
+  if (file) {
+    FileBlobConstructorParams fileParams;
+
+    rv = file->GetName(fileParams.name());
+    NS_ENSURE_SUCCESS(rv, nullptr);
+
+    rv = file->GetMozLastModifiedDate(&fileParams.modDate());
+    NS_ENSURE_SUCCESS(rv, nullptr);
+
+    fileParams.contentType() = contentType;
+    fileParams.length() = length;
+
+    params.blobParams() = fileParams;
+  } else {
+    NormalBlobConstructorParams blobParams;
+    blobParams.contentType() = contentType;
+    blobParams.length() = length;
+    params.blobParams() = blobParams;
+  }
+
+  BlobChild* actor = BlobChild::Create(this, aBlob);
+  NS_ENSURE_TRUE(actor, nullptr);
+
+  return SendPBlobConstructor(actor, params) ? actor : nullptr;
+}
+
+bool
+nsIContentChild::RecvAsyncMessage(const nsString& aMsg,
+                                  const ClonedMessageData& aData,
+                                  const InfallibleTArray<CpowEntry>& aCpows,
+                                  const IPC::Principal& aPrincipal)
+{
+  nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
+  if (cpm) {
+    StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
+    CpowIdHolder cpows(GetCPOWManager(), aCpows);
+    cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
+                        aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
+  }
+  return true;
+}
+
+} // dom
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/nsIContentChild.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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_dom_nsIContentChild_h
+#define mozilla_dom_nsIContentChild_h
+
+#include "mozilla/dom/ipc/Blob.h"
+
+#include "nsISupports.h"
+
+#define NS_ICONTENTCHILD_IID                                    \
+  { 0x4eed2e73, 0x94ba, 0x48a8,                                 \
+    { 0xa2, 0xd1, 0xa5, 0xed, 0x86, 0xd7, 0xbb, 0xe4 } }
+
+class PBrowserChild;
+
+namespace IPC {
+class Principal;
+} // IPC
+
+namespace mozilla {
+
+namespace jsipc {
+class PJavaScriptChild;
+class JavaScriptChild;
+class CpowEntry;
+} // jsipc
+
+namespace dom {
+struct IPCTabContext;
+
+class nsIContentChild : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTCHILD_IID)
+
+  BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
+
+  virtual PBlobChild*
+  SendPBlobConstructor(PBlobChild* aActor,
+                       const BlobConstructorParams& params) = 0;
+  virtual bool
+  SendPBrowserConstructor(PBrowserChild* aActor,
+                          const IPCTabContext& aContext,
+                          const uint32_t& aChromeFlags,
+                          const uint64_t& aID,
+                          const bool& aIsForApp,
+                          const bool& aIsForBrowser) = 0;
+  virtual jsipc::JavaScriptChild* GetCPOWManager() = 0;
+protected:
+  virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
+  virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);
+
+  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+                                            const uint32_t& aChromeFlags,
+                                            const uint64_t& aID,
+                                            const bool& aIsForApp,
+                                            const bool& aIsForBrowser);
+  virtual bool DeallocPBrowserChild(PBrowserChild*);
+
+  virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
+  virtual bool DeallocPBlobChild(PBlobChild*);
+
+  virtual bool RecvAsyncMessage(const nsString& aMsg,
+                                const ClonedMessageData& aData,
+                                const InfallibleTArray<jsipc::CpowEntry>& aCpows,
+                                const IPC::Principal& aPrincipal);
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentChild, NS_ICONTENTCHILD_IID)
+
+} // dom
+} // mozilla
+#endif /* mozilla_dom_nsIContentChild_h */