Bug 1525720, part 11 - Use RemoteBrowser interface instead of IPDL actors in nsFrameLoader. r=nika
authorRyan Hunt <rhunt@eqrion.net>
Mon, 06 May 2019 21:29:48 -0500
changeset 475154 4cf9a1ce9e92dbcc022c1d8d7d6ac8ed185dc082
parent 475153 9d7151b26a9eb72d363b4a309f179c15452dc2bc
child 475155 50475885250c5a0411ae055f765bb7506dc41337
push id36055
push userdvarga@mozilla.com
push dateThu, 23 May 2019 15:55:11 +0000
treeherdermozilla-central@5a63f841eacb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1525720
milestone69.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 1525720, part 11 - Use RemoteBrowser interface instead of IPDL actors in nsFrameLoader. r=nika This commit replaces the direct use of the IPDL actors in nsFrameLoader with the RemoteBrowser interface. Some special use cases are adapted to still use the IPDL actors. In the future, we should burn these use cases down. Differential Revision: https://phabricator.services.mozilla.com/D31442
dom/base/nsFrameLoader.cpp
dom/base/nsFrameLoader.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -104,16 +104,18 @@
 #include "mozilla/WebBrowserPersistLocalDocument.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/ParentSHistory.h"
 #include "mozilla/dom/ChildSHistory.h"
 #include "mozilla/dom/CanonicalBrowsingContext.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/BrowserBridgeChild.h"
+#include "mozilla/dom/BrowserHost.h"
+#include "mozilla/dom/BrowserBridgeHost.h"
 
 #include "mozilla/dom/HTMLBodyElement.h"
 
 #include "mozilla/ContentPrincipal.h"
 
 #ifdef XP_WIN
 #  include "mozilla/plugins/PPluginWidgetParent.h"
 #  include "../plugins/ipc/PluginWidgetParent.h"
@@ -150,34 +152,33 @@ typedef ScrollableLayerGuid::ViewID View
 // keep number of shells to a reasonable number on accidental recursion with a
 // small (but not 1) branching factor.  With large branching factors the number
 // of shells can rapidly become huge and run us out of memory.  To solve that,
 // we'd need to re-institute a fixed version of bug 98158.
 #define MAX_DEPTH_CONTENT_FRAMES 10
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFrameLoader, mBrowsingContext,
                                       mMessageManager, mChildMessageManager,
-                                      mParentSHistory, mBrowserParent)
+                                      mParentSHistory)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_CONCRETE(nsFrameLoader)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext,
                              bool aNetworkCreated)
     : mBrowsingContext(aBrowsingContext),
       mOwnerContent(aOwner),
       mDetachedSubdocFrame(nullptr),
       mPendingSwitchID(0),
-      mBrowserParent(nullptr),
       mChildID(0),
       mDepthTooGreat(false),
       mIsTopLevelContent(false),
       mDestroyCalled(false),
       mNeedsAsyncDestroy(false),
       mInSwap(false),
       mInShow(false),
       mHideCalled(false),
@@ -192,17 +193,16 @@ nsFrameLoader::nsFrameLoader(Element* aO
 }
 
 nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext,
                              const mozilla::dom::RemotenessOptions& aOptions)
     : mBrowsingContext(aBrowsingContext),
       mOwnerContent(aOwner),
       mDetachedSubdocFrame(nullptr),
       mPendingSwitchID(0),
-      mBrowserParent(nullptr),
       mChildID(0),
       mDepthTooGreat(false),
       mIsTopLevelContent(false),
       mDestroyCalled(false),
       mNeedsAsyncDestroy(false),
       mInSwap(false),
       mInShow(false),
       mHideCalled(false),
@@ -538,38 +538,26 @@ nsresult nsFrameLoader::ReallyStartLoadi
 
 nsresult nsFrameLoader::ReallyStartLoadingInternal() {
   NS_ENSURE_STATE((mURIToLoad || mPendingSwitchID) && mOwnerContent &&
                   mOwnerContent->IsInComposedDoc());
 
   AUTO_PROFILER_LABEL("nsFrameLoader::ReallyStartLoadingInternal", OTHER);
 
   if (IsRemoteFrame()) {
-    if (!mBrowserParent && !mBrowserBridgeChild && !TryRemoteBrowser()) {
+    if (!EnsureRemoteBrowser()) {
       NS_WARNING("Couldn't create child process for iframe.");
       return NS_ERROR_FAILURE;
     }
 
     if (mPendingSwitchID) {
-      if (mBrowserBridgeChild) {
-        Unused << mBrowserBridgeChild->SendResumeLoad(mPendingSwitchID);
-      } else {
-        mBrowserParent->ResumeLoad(mPendingSwitchID);
-      }
-
+      mRemoteBrowser->ResumeLoad(mPendingSwitchID);
       mPendingSwitchID = 0;
     } else {
-      if (mBrowserBridgeChild) {
-        nsAutoCString spec;
-        mURIToLoad->GetSpec(spec);
-        Unused << mBrowserBridgeChild->SendLoadURL(spec);
-      } else {
-        // FIXME get error codes from child
-        mBrowserParent->LoadURL(mURIToLoad);
-      }
+      mRemoteBrowser->LoadURL(mURIToLoad);
     }
 
     if (!mRemoteBrowserShown) {
       // This can fail if it's too early to show the frame, we will retry later.
       Unused << ShowRemoteFrame(ScreenIntSize(0, 0));
     }
 
     return NS_OK;
@@ -1024,17 +1012,17 @@ void nsFrameLoader::MarginsChanged(uint3
 }
 
 bool nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
                                     nsSubDocumentFrame* aFrame) {
   AUTO_PROFILER_LABEL("nsFrameLoader::ShowRemoteFrame", OTHER);
   NS_ASSERTION(IsRemoteFrame(),
                "ShowRemote only makes sense on remote frames.");
 
-  if (!mBrowserParent && !mBrowserBridgeChild && !TryRemoteBrowser()) {
+  if (!EnsureRemoteBrowser()) {
     NS_ERROR("Couldn't create child process.");
     return false;
   }
 
   // FIXME/bug 589337: Show()/Hide() is pretty expensive for
   // cross-process layers; need to figure out what behavior we really
   // want here.  For now, hack.
   if (!mRemoteBrowserShown) {
@@ -1043,52 +1031,49 @@ bool nsFrameLoader::ShowRemoteFrame(cons
     }
 
     // We never want to host remote frameloaders in simple popups, like menus.
     nsIWidget* widget = nsContentUtils::WidgetForContent(mOwnerContent);
     if (!widget || static_cast<nsBaseWidget*>(widget)->IsSmallPopup()) {
       return false;
     }
 
-    if (mBrowserBridgeChild) {
+    if (RefPtr<BrowserBridgeChild> browserBridgeChild =
+            GetBrowserBridgeChild()) {
       nsCOMPtr<nsISupports> container =
           mOwnerContent->OwnerDoc()->GetContainer();
       nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
       nsCOMPtr<nsIWidget> mainWidget;
       baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
       nsSizeMode sizeMode =
           mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal;
 
-      Unused << mBrowserBridgeChild->SendShow(
+      Unused << browserBridgeChild->SendShow(
           size, ParentWindowIsActive(mOwnerContent->OwnerDoc()), sizeMode);
       mRemoteBrowserShown = true;
       return true;
     }
 
-    if (!mBrowserParent->Show(
+    if (!mRemoteBrowser->Show(
             size, ParentWindowIsActive(mOwnerContent->OwnerDoc()))) {
       return false;
     }
     mRemoteBrowserShown = true;
 
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     if (os) {
       os->NotifyObservers(ToSupports(this), "remote-browser-shown", nullptr);
     }
   } else {
     nsIntRect dimensions;
     NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
 
     // Don't show remote iframe if we are waiting for the completion of reflow.
     if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
-      if (mBrowserParent) {
-        mBrowserParent->UpdateDimensions(dimensions, size);
-      } else if (mBrowserBridgeChild) {
-        mBrowserBridgeChild->UpdateDimensions(dimensions, size);
-      }
+      mRemoteBrowser->UpdateDimensions(dimensions, size);
     }
   }
 
   return true;
 }
 
 void nsFrameLoader::Hide() {
   if (mHideCalled) {
@@ -1788,17 +1773,17 @@ void nsFrameLoader::StartDestroy() {
   // the message manager on the frame.
   if (mMessageManager) {
     mMessageManager->Close();
   }
 
   // Retain references to the <browser> element and the frameloader in case we
   // receive any messages from the message manager on the frame. These
   // references are dropped in DestroyComplete.
-  if (mChildMessageManager || mBrowserParent) {
+  if (mChildMessageManager || mRemoteBrowser) {
     mOwnerContentStrong = mOwnerContent;
     if (auto* browserParent = GetBrowserParent()) {
       browserParent->CacheFrameLoader(this);
     }
     if (mChildMessageManager) {
       mChildMessageManager->CacheFrameLoader(this);
     }
   }
@@ -1900,23 +1885,18 @@ nsresult nsFrameLoaderDestroyRunnable::R
 void nsFrameLoader::DestroyDocShell() {
   // This code runs after the frameloader has been detached from the <browser>
   // element. We postpone this work because we may not be allowed to run
   // script at that time.
 
   // Ask the BrowserChild to fire the frame script "unload" event, destroy its
   // docshell, and finally destroy the PBrowser actor. This eventually leads to
   // nsFrameLoader::DestroyComplete being called.
-  if (mBrowserParent) {
-    mBrowserParent->Destroy();
-  }
-
-  if (mBrowserBridgeChild) {
-    Unused << mBrowserBridgeChild->Send__delete__(mBrowserBridgeChild);
-    mBrowserBridgeChild = nullptr;
+  if (mRemoteBrowser) {
+    mRemoteBrowser->DestroyStart();
   }
 
   // Fire the "unload" event if we're in-process.
   if (mChildMessageManager) {
     mChildMessageManager->FireUnloadEvent();
   }
 
   if (mSessionStoreListener) {
@@ -1939,36 +1919,30 @@ void nsFrameLoader::DestroyDocShell() {
 
 void nsFrameLoader::DestroyComplete() {
   // We get here, as part of StartDestroy, after the docshell has been destroyed
   // and all message manager messages sent during docshell destruction have been
   // dispatched.  We also get here if the child process crashes. In the latter
   // case, StartDestroy might not have been called.
 
   // Drop the strong references created in StartDestroy.
-  if (mChildMessageManager || mBrowserParent) {
+  if (mChildMessageManager || mRemoteBrowser) {
     mOwnerContentStrong = nullptr;
     if (auto* browserParent = GetBrowserParent()) {
       browserParent->CacheFrameLoader(nullptr);
     }
     if (mChildMessageManager) {
       mChildMessageManager->CacheFrameLoader(nullptr);
     }
   }
 
   // Call BrowserParent::Destroy if we haven't already (in case of a crash).
-  if (mBrowserParent) {
-    mBrowserParent->SetOwnerElement(nullptr);
-    mBrowserParent->Destroy();
-    mBrowserParent = nullptr;
-  }
-
-  if (mBrowserBridgeChild) {
-    Unused << mBrowserBridgeChild->Send__delete__(mBrowserBridgeChild);
-    mBrowserBridgeChild = nullptr;
+  if (mRemoteBrowser) {
+    mRemoteBrowser->DestroyComplete();
+    mRemoteBrowser = nullptr;
   }
 
   if (mMessageManager) {
     mMessageManager->Disconnect();
   }
 
   if (mChildMessageManager) {
     mChildMessageManager->Disconnect();
@@ -2482,31 +2456,27 @@ nsresult nsFrameLoader::GetWindowDimensi
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_GetInterface(parentOwner));
   treeOwnerAsWin->GetPosition(&aRect.x, &aRect.y);
   treeOwnerAsWin->GetSize(&aRect.width, &aRect.height);
   return NS_OK;
 }
 
 nsresult nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame* aIFrame) {
   if (IsRemoteFrame()) {
-    if (mBrowserParent || mBrowserBridgeChild) {
+    if (mRemoteBrowser) {
       ScreenIntSize size = aIFrame->GetSubdocumentSize();
       // If we were not able to show remote frame before, we should probably
       // retry now to send correct showInfo.
       if (!mRemoteBrowserShown) {
         ShowRemoteFrame(size, aIFrame);
       }
       nsIntRect dimensions;
       NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
       mLazySize = size;
-      if (mBrowserParent) {
-        mBrowserParent->UpdateDimensions(dimensions, size);
-      } else if (mBrowserBridgeChild) {
-        mBrowserBridgeChild->UpdateDimensions(dimensions, size);
-      }
+      mRemoteBrowser->UpdateDimensions(dimensions, size);
     }
     return NS_OK;
   }
   UpdateBaseWindowPositionAndSize(aIFrame);
   return NS_OK;
 }
 
 void nsFrameLoader::SendIsUnderHiddenEmbedderElement(
@@ -2585,18 +2555,23 @@ static Tuple<ContentParent*, BrowserPare
   BrowserParent* browserParent = BrowserParent::GetFrom(otherLoader);
   if (browserParent && browserParent->Manager()) {
     return MakeTuple(browserParent->Manager(), browserParent);
   }
 
   return ReturnTuple(nullptr, nullptr);
 }
 
+bool nsFrameLoader::EnsureRemoteBrowser() {
+  MOZ_ASSERT(IsRemoteFrame());
+  return mRemoteBrowser || TryRemoteBrowser();
+}
+
 bool nsFrameLoader::TryRemoteBrowser() {
-  NS_ASSERTION(!mBrowserParent && !mBrowserBridgeChild,
+  NS_ASSERTION(!mRemoteBrowser,
                "TryRemoteBrowser called with a remote browser already?");
 
   if (!mOwnerContent) {
     return false;
   }
 
   // XXXsmaug Per spec (2014/08/21) frameloader should not work in case the
   //         element isn't in document, only in shadow dom, but that will change
@@ -2708,26 +2683,26 @@ bool nsFrameLoader::TryRemoteBrowser() {
   }
 
   nsCOMPtr<Element> ownerElement = mOwnerContent;
 
   // If we're in a content process, create a BrowserBridgeChild actor.
   if (XRE_IsContentProcess()) {
     mBrowsingContext->SetEmbedderElement(mOwnerContent);
 
-    mBrowserBridgeChild = ContentChild::CreateBrowser(
+    mRemoteBrowser = ContentChild::CreateBrowser(
         this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
         mBrowsingContext);
-    return !!mBrowserBridgeChild;
+    return !!mRemoteBrowser;
   }
 
-  mBrowserParent = ContentParent::CreateBrowser(
+  mRemoteBrowser = ContentParent::CreateBrowser(
       context, ownerElement, mBrowsingContext, openerContentParent,
       sameTabGroupAs, nextRemoteTabId);
-  if (!mBrowserParent) {
+  if (!mRemoteBrowser) {
     return false;
   }
 
   // Grab the reference to the actor
   RefPtr<BrowserParent> browserParent = GetBrowserParent();
 
   // We no longer need the remoteType attribute on the frame element.
   // The remoteType can be queried by asking the message manager instead.
@@ -2785,21 +2760,36 @@ bool nsFrameLoader::IsRemoteFrame() {
   if (mIsRemoteFrame) {
     MOZ_ASSERT(!GetDocShell(), "Found a remote frame with a DocShell");
     return true;
   }
   return false;
 }
 
 BrowserParent* nsFrameLoader::GetBrowserParent() const {
-  return mBrowserParent;
+  if (!mRemoteBrowser) {
+    return nullptr;
+  }
+  RefPtr<BrowserHost> browserHost = mRemoteBrowser->AsBrowserHost();
+  if (!browserHost) {
+    return nullptr;
+  }
+  return browserHost->GetActor();
 }
 
 BrowserBridgeChild* nsFrameLoader::GetBrowserBridgeChild() const {
-  return mBrowserBridgeChild;
+  if (!mRemoteBrowser) {
+    return nullptr;
+  }
+  RefPtr<BrowserBridgeHost> browserBridgeHost =
+      mRemoteBrowser->AsBrowserBridgeHost();
+  if (!browserBridgeHost) {
+    return nullptr;
+  }
+  return browserBridgeHost->GetActor();
 }
 
 mozilla::layers::LayersId nsFrameLoader::GetLayersId() const {
   MOZ_ASSERT(mIsRemoteFrame);
   if (auto* browserParent = GetBrowserParent()) {
     return browserParent->GetRenderFrame()->GetLayersId();
   }
   if (auto* browserBridgeChild = GetBrowserBridgeChild()) {
@@ -3043,24 +3033,24 @@ nsresult nsFrameLoader::ReallyLoadFrameS
   return NS_OK;
 }
 
 already_AddRefed<Element> nsFrameLoader::GetOwnerElement() {
   return do_AddRef(mOwnerContent);
 }
 
 void nsFrameLoader::InitializeFromBrowserParent(BrowserParent* aBrowserParent) {
-  MOZ_ASSERT(!mBrowserParent);
+  MOZ_ASSERT(!mRemoteBrowser);
   mIsRemoteFrame = true;
-  mBrowserParent = aBrowserParent;
-  mChildID = mBrowserParent ? mBrowserParent->Manager()->ChildID() : 0;
+  mRemoteBrowser = new BrowserHost(aBrowserParent);
+  mChildID = aBrowserParent ? aBrowserParent->Manager()->ChildID() : 0;
   MaybeUpdatePrimaryBrowserParent(eBrowserParentChanged);
   ReallyLoadFrameScripts();
   InitializeBrowserAPI();
-  mBrowserParent->InitRendering();
+  aBrowserParent->InitRendering();
   ShowRemoteFrame(ScreenIntSize(0, 0));
 }
 
 void nsFrameLoader::SetDetachedSubdocFrame(nsIFrame* aDetachedFrame,
                                            Document* aContainerDoc) {
   mDetachedSubdocFrame = aDetachedFrame;
   mContainerDocWhileDetached = aContainerDoc;
 }
@@ -3280,43 +3270,33 @@ already_AddRefed<mozilla::dom::Promise> 
     gfx::CrossProcessPaint::StartLocal(GetDocShell(), rect, aScale, color,
                                        promise);
   }
 
   return promise.forget();
 }
 
 already_AddRefed<nsIRemoteTab> nsFrameLoader::GetRemoteTab() {
-  return do_AddRef(mBrowserParent);
+  return do_AddRef(GetBrowserParent());
 }
 
 already_AddRefed<nsILoadContext> nsFrameLoader::LoadContext() {
   nsCOMPtr<nsILoadContext> loadContext;
-  if (IsRemoteFrame() &&
-      (mBrowserParent || mBrowserBridgeChild || TryRemoteBrowser())) {
-    if (mBrowserParent) {
-      loadContext = mBrowserParent->GetLoadContext();
-    } else {
-      loadContext = mBrowserBridgeChild->GetLoadContext();
-    }
+  if (IsRemoteFrame() && EnsureRemoteBrowser()) {
+    loadContext = mRemoteBrowser->GetLoadContext();
   } else {
     loadContext = do_GetInterface(ToSupports(GetDocShell(IgnoreErrors())));
   }
   return loadContext.forget();
 }
 
 already_AddRefed<BrowsingContext> nsFrameLoader::GetBrowsingContext() {
   RefPtr<BrowsingContext> browsingContext;
-  if (IsRemoteFrame() &&
-      (mBrowserParent || mBrowserBridgeChild || TryRemoteBrowser())) {
-    if (mBrowserParent) {
-      browsingContext = mBrowserParent->GetBrowsingContext();
-    } else {
-      browsingContext = mBrowserBridgeChild->GetBrowsingContext();
-    }
+  if (IsRemoteFrame() && EnsureRemoteBrowser()) {
+    browsingContext = mRemoteBrowser->GetBrowsingContext();
   } else if (GetDocShell(IgnoreErrors())) {
     browsingContext = GetDocShell()->GetBrowsingContext();
   }
   return browsingContext.forget();
 }
 
 void nsFrameLoader::InitializeBrowserAPI() {
   if (!OwnerIsMozBrowserFrame()) {
@@ -3376,44 +3356,51 @@ void nsFrameLoader::StartPersistence(
     nsCOMPtr<nsIWebBrowserPersistDocument> pdoc =
         new mozilla::WebBrowserPersistLocalDocument(foundDoc);
     aRecv->OnDocumentReady(pdoc);
   }
 }
 
 void nsFrameLoader::MaybeUpdatePrimaryBrowserParent(
     BrowserParentChange aChange) {
-  if (mBrowserParent && mOwnerContent) {
-    nsCOMPtr<nsIDocShell> docShell = mOwnerContent->OwnerDoc()->GetDocShell();
-    if (!docShell) {
-      return;
-    }
-
-    int32_t parentType = docShell->ItemType();
-    if (parentType != nsIDocShellTreeItem::typeChrome) {
-      return;
-    }
-
-    nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
-    docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
-    if (!parentTreeOwner) {
-      return;
-    }
-
-    if (!mObservingOwnerContent) {
-      mOwnerContent->AddMutationObserver(this);
-      mObservingOwnerContent = true;
-    }
-
-    parentTreeOwner->RemoteTabRemoved(mBrowserParent);
-    if (aChange == eBrowserParentChanged) {
-      bool isPrimary = mOwnerContent->AttrValueIs(
-          kNameSpaceID_None, nsGkAtoms::primary, nsGkAtoms::_true, eIgnoreCase);
-      parentTreeOwner->RemoteTabAdded(mBrowserParent, isPrimary);
-    }
+  if (!mOwnerContent) {
+    return;
+  }
+
+  RefPtr<BrowserParent> browserParent = GetBrowserParent();
+  if (!browserParent) {
+    return;
+  }
+
+  nsCOMPtr<nsIDocShell> docShell = mOwnerContent->OwnerDoc()->GetDocShell();
+  if (!docShell) {
+    return;
+  }
+
+  int32_t parentType = docShell->ItemType();
+  if (parentType != nsIDocShellTreeItem::typeChrome) {
+    return;
+  }
+
+  nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
+  docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
+  if (!parentTreeOwner) {
+    return;
+  }
+
+  if (!mObservingOwnerContent) {
+    mOwnerContent->AddMutationObserver(this);
+    mObservingOwnerContent = true;
+  }
+
+  parentTreeOwner->RemoteTabRemoved(browserParent);
+  if (aChange == eBrowserParentChanged) {
+    bool isPrimary = mOwnerContent->AttrValueIs(
+        kNameSpaceID_None, nsGkAtoms::primary, nsGkAtoms::_true, eIgnoreCase);
+    parentTreeOwner->RemoteTabAdded(browserParent, isPrimary);
   }
 }
 
 nsresult nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
                                          nsIURI* aURI) {
   OriginAttributes attrs;
   attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
   nsresult rv;
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -18,16 +18,17 @@
 #include "nsSize.h"
 #include "nsWrapperCache.h"
 #include "nsIURI.h"
 #include "nsFrameMessageManager.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BrowsingContext.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ParentSHistory.h"
+#include "mozilla/dom/RemoteBrowser.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "nsStubMutationObserver.h"
 #include "Units.h"
 #include "nsIFrame.h"
 #include "nsPluginTags.h"
 
 class nsIURI;
@@ -440,16 +441,20 @@ class nsFrameLoader final : public nsStu
    * @param aURI The URI to check.
    * @param aTriggeringPrincipal The triggering principal for the load. May be
    *        null, in which case the node principal of the owner content is used.
    */
   nsresult CheckURILoad(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal);
   void FireErrorEvent();
   nsresult ReallyStartLoadingInternal();
 
+  // Returns true if we have a remote browser or else attempts to create a
+  // remote browser and returns true if successful.
+  bool EnsureRemoteBrowser();
+
   // Return true if remote browser created; nothing else to do
   bool TryRemoteBrowser();
 
   // Tell the remote browser that it's now "virtually visible"
   bool ShowRemoteFrame(const mozilla::ScreenIntSize& size,
                        nsSubDocumentFrame* aFrame = nullptr);
 
   void AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
@@ -487,21 +492,18 @@ class nsFrameLoader final : public nsStu
   // a reframe, so that we know not to restore the presentation.
   RefPtr<Document> mContainerDocWhileDetached;
 
   // When performing a process switch, this value is used rather than mURIToLoad
   // to identify the process-switching load which should be resumed in the
   // target process.
   uint64_t mPendingSwitchID;
 
-  RefPtr<BrowserParent> mBrowserParent;
   uint64_t mChildID;
-
-  // This is used when this refers to a remote sub frame
-  RefPtr<mozilla::dom::BrowserBridgeChild> mBrowserBridgeChild;
+  RefPtr<mozilla::dom::RemoteBrowser> mRemoteBrowser;
 
   // Holds the last known size of the frame.
   mozilla::ScreenIntSize mLazySize;
 
   RefPtr<mozilla::dom::ParentSHistory> mParentSHistory;
 
   RefPtr<mozilla::dom::TabListener> mSessionStoreListener;
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/Unused.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/TelemetryIPC.h"
 #include "mozilla/VideoDecoderManagerChild.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/dom/BrowsingContext.h"
 #include "mozilla/dom/BrowsingContextGroup.h"
+#include "mozilla/dom/BrowserBridgeHost.h"
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientOpenWindowOpActors.h"
 #include "mozilla/dom/ChildProcessMessageManager.h"
 #include "mozilla/dom/ContentProcessMessageManager.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DocGroup.h"
@@ -2002,17 +2003,17 @@ mozilla::ipc::IPCResult ContentChild::Re
 
 void ContentChild::UpdateCookieStatus(nsIChannel* aChannel) {
   RefPtr<CookieServiceChild> csChild = CookieServiceChild::GetSingleton();
   NS_ASSERTION(csChild, "Couldn't get CookieServiceChild");
 
   csChild->TrackCookieLoad(aChannel);
 }
 
-already_AddRefed<BrowserBridgeChild> ContentChild::CreateBrowser(
+already_AddRefed<RemoteBrowser> ContentChild::CreateBrowser(
     nsFrameLoader* aFrameLoader, const TabContext& aContext,
     const nsString& aRemoteType, BrowsingContext* aBrowsingContext) {
   MOZ_ASSERT(XRE_IsContentProcess());
 
   // Determine our embedder's BrowserChild actor.
   RefPtr<Element> owner = aFrameLoader->GetOwnerContent();
   MOZ_DIAGNOSTIC_ASSERT(owner);
 
@@ -2049,17 +2050,19 @@ already_AddRefed<BrowserBridgeChild> Con
       new BrowserBridgeChild(aFrameLoader, aBrowsingContext);
   // Reference is freed in BrowserChild::DeallocPBrowserBridgeChild.
   browserChild->SendPBrowserBridgeConstructor(
       do_AddRef(browserBridge).take(),
       PromiseFlatString(aContext.PresentationURL()), aRemoteType,
       aBrowsingContext, chromeFlags);
   browserBridge->mIPCOpen = true;
 
-  return browserBridge.forget();
+  RefPtr<BrowserBridgeHost> browserBridgeHost =
+      new BrowserBridgeHost(browserBridge);
+  return browserBridgeHost.forget();
 }
 
 PScriptCacheChild* ContentChild::AllocPScriptCacheChild(
     const FileDescOrError& cacheFile, const bool& wantCacheData) {
   return new loader::ScriptCacheChild();
 }
 
 bool ContentChild::DeallocPScriptCacheChild(PScriptCacheChild* cache) {
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -8,16 +8,17 @@
 #define mozilla_dom_ContentChild_h
 
 #include "base/shared_memory.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BrowserBridgeChild.h"
 #include "mozilla/dom/PBrowserOrId.h"
 #include "mozilla/dom/PContentChild.h"
+#include "mozilla/dom/RemoteBrowser.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "nsAutoPtr.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsTHashtable.h"
@@ -157,17 +158,17 @@ class ContentChild final : public PConte
   bool IsShuttingDown() const;
 
   ipc::SharedMap* SharedData() { return mSharedData; };
 
   static void AppendProcessId(nsACString& aName);
 
   static void UpdateCookieStatus(nsIChannel* aChannel);
 
-  static already_AddRefed<BrowserBridgeChild> CreateBrowser(
+  static already_AddRefed<RemoteBrowser> CreateBrowser(
       nsFrameLoader* aFrameLoader, const TabContext& aContext,
       const nsString& aRemoteType, BrowsingContext* aBrowsingContext);
 
   mozilla::ipc::IPCResult RecvInitGMPService(
       Endpoint<PGMPServiceChild>&& aGMPService);
 
   mozilla::ipc::IPCResult RecvInitProfiler(
       Endpoint<PProfilerChild>&& aEndpoint);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1078,42 +1078,41 @@ mozilla::ipc::IPCResult ContentParent::R
       *aRv = NS_ERROR_NOT_AVAILABLE;
     }
   }
 
   return IPC_OK();
 }
 
 /*static*/
-BrowserParent* ContentParent::CreateBrowser(const TabContext& aContext,
-                                            Element* aFrameElement,
-                                            BrowsingContext* aBrowsingContext,
-                                            ContentParent* aOpenerContentParent,
-                                            BrowserParent* aSameTabGroupAs,
-                                            uint64_t aNextRemoteTabId) {
+already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
+    const TabContext& aContext, Element* aFrameElement,
+    BrowsingContext* aBrowsingContext, ContentParent* aOpenerContentParent,
+    BrowserParent* aSameTabGroupAs, uint64_t aNextRemoteTabId) {
   AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER);
 
   if (!sCanLaunchSubprocesses) {
     return nullptr;
   }
 
   nsAutoString remoteType;
   if (!aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
                               remoteType)) {
     remoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
   }
 
   if (aNextRemoteTabId) {
     if (BrowserParent* parent =
             sNextBrowserParents.GetAndRemove(aNextRemoteTabId)
                 .valueOr(nullptr)) {
+      RefPtr<BrowserHost> browserHost = new BrowserHost(parent);
       MOZ_ASSERT(!parent->GetOwnerElement(),
                  "Shouldn't have an owner elemnt before");
       parent->SetOwnerElement(aFrameElement);
-      return parent;
+      return browserHost.forget();
     }
   }
 
   ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
   TabId tabId(nsContentUtils::GenerateTabId());
 
   nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
   TabId openerTabId;
@@ -1211,18 +1210,19 @@ BrowserParent* ContentParent::CreateBrow
     }
 
     if (remoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
       // Tell the BrowserChild object that it was created due to a
       // Large-Allocation request.
       Unused << browserParent->SendAwaitLargeAlloc();
     }
 
+    RefPtr<BrowserHost> browserHost = new BrowserHost(browserParent);
     browserParent->SetOwnerElement(aFrameElement);
-    return browserParent;
+    return browserHost.forget();
   }
   return nullptr;
 }
 
 void ContentParent::GetAll(nsTArray<ContentParent*>& aArray) {
   aArray.Clear();
 
   for (auto* cp : AllProcesses(eLive)) {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ContentParent_h
 #define mozilla_dom_ContentParent_h
 
 #include "mozilla/dom/PContentParent.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 #include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/dom/RemoteBrowser.h"
 #include "mozilla/gfx/gfxVarReceiver.h"
 #include "mozilla/gfx/GPUProcessListener.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/PParentToChildStreamParent.h"
 #include "mozilla/ipc/PChildToParentStreamParent.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/FileUtils.h"
@@ -203,22 +204,20 @@ class ContentParent final : public PCont
   static already_AddRefed<ContentParent> GetNewOrUsedJSPluginProcess(
       uint32_t aPluginID, const hal::ProcessPriority& aPriority);
 
   /**
    * Get or create a content process for the given TabContext.  aFrameElement
    * should be the frame/iframe element with which this process will
    * associated.
    */
-  static BrowserParent* CreateBrowser(const TabContext& aContext,
-                                      Element* aFrameElement,
-                                      BrowsingContext* aBrowsingContext,
-                                      ContentParent* aOpenerContentParent,
-                                      BrowserParent* aSameTabGroupAs,
-                                      uint64_t aNextRemoteTabId);
+  static already_AddRefed<RemoteBrowser> CreateBrowser(
+      const TabContext& aContext, Element* aFrameElement,
+      BrowsingContext* aBrowsingContext, ContentParent* aOpenerContentParent,
+      BrowserParent* aSameTabGroupAs, uint64_t aNextRemoteTabId);
 
   static void GetAll(nsTArray<ContentParent*>& aArray);
 
   static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
 
   static void BroadcastStringBundle(const StringBundleDescriptor&);
 
   static void BroadcastFontListChanged();