Bug 1500257 part 4 - Modify nsFrameLoader to create PRemoteFrame when enabled via pref and attribute. r=qdot
☠☠ backed out by 2b27038adbe4 ☠ ☠
authorRyan Hunt <rhunt@eqrion.net>
Wed, 23 Jan 2019 10:56:27 -0600
changeset 458339 e33b9de7283e5fb6441e118b25af8d4ac3411bf2
parent 458338 002762a021c49287c1aad0db877a3a242ea3eba8
child 458340 b68b732411e2e1e6851799262246bff70e6649da
push id111812
push userrhunt@eqrion.net
push dateSat, 09 Feb 2019 06:41:25 +0000
treeherdermozilla-inbound@335ddf6a213a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs1500257
milestone67.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 1500257 part 4 - Modify nsFrameLoader to create PRemoteFrame when enabled via pref and attribute. r=qdot This commit hooks up nsFrameLoader in the child process to use the PRemoteFrame protocol to support remote iframes. This is only activated when a special pref is set, and the iframe has a marker attribute on it. For example: <iframe fission/> In the future, we should unify nsFrameLoader to operate on a common interface between the parent process top-level browser, and child process subframe case. This commit just adds a new member that can be used instead of mRemoteBrowser, when appropriate. IsRemoteFrame() will return true for both cases. Differential Revision: https://phabricator.services.mozilla.com/D17444
dom/base/nsFrameLoader.cpp
dom/base/nsFrameLoader.h
xpcom/ds/StaticAtoms.py
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -96,16 +96,18 @@
 
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #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/RemoteFrameChild.h"
 
 #include "mozilla/dom/HTMLBodyElement.h"
 
 #include "mozilla/ContentPrincipal.h"
 
 #ifdef XP_WIN
 #  include "mozilla/plugins/PPluginWidgetParent.h"
 #  include "../plugins/ipc/PluginWidgetParent.h"
@@ -344,17 +346,17 @@ nsresult nsFrameLoader::ReallyStartLoadi
 
 nsresult nsFrameLoader::ReallyStartLoadingInternal() {
   NS_ENSURE_STATE(mURIToLoad && mOwnerContent &&
                   mOwnerContent->IsInComposedDoc());
 
   AUTO_PROFILER_LABEL("nsFrameLoader::ReallyStartLoadingInternal", OTHER);
 
   if (IsRemoteFrame()) {
-    if (!mRemoteBrowser && !TryRemoteBrowser()) {
+    if (!mRemoteBrowser && !mRemoteFrameChild && !TryRemoteBrowser()) {
       NS_WARNING("Couldn't create child process for iframe.");
       return NS_ERROR_FAILURE;
     }
 
     // FIXME get error codes from child
     mRemoteBrowser->LoadURL(mURIToLoad);
 
     if (!mRemoteBrowserShown) {
@@ -785,17 +787,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 (!mRemoteBrowser && !TryRemoteBrowser()) {
+  if (!mRemoteBrowser && !mRemoteFrameChild && !TryRemoteBrowser()) {
     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) {
@@ -1659,16 +1661,21 @@ void nsFrameLoader::DestroyDocShell() {
 
   // Ask the TabChild 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 (mRemoteBrowser) {
     mRemoteBrowser->Destroy();
   }
 
+  if (mRemoteFrameChild) {
+    Unused << mRemoteFrameChild->Send__delete__(mRemoteFrameChild);
+    mRemoteFrameChild = nullptr;
+  }
+
   // Fire the "unload" event if we're in-process.
   if (mChildMessageManager) {
     mChildMessageManager->FireUnloadEvent();
   }
 
   // Destroy the docshell.
   if (mDocShell) {
     mDocShell->Destroy();
@@ -1700,16 +1707,21 @@ void nsFrameLoader::DestroyComplete() {
 
   // Call TabParent::Destroy if we haven't already (in case of a crash).
   if (mRemoteBrowser) {
     mRemoteBrowser->SetOwnerElement(nullptr);
     mRemoteBrowser->Destroy();
     mRemoteBrowser = nullptr;
   }
 
+  if (mRemoteFrameChild) {
+    Unused << mRemoteFrameChild->Send__delete__(mRemoteFrameChild);
+    mRemoteFrameChild = nullptr;
+  }
+
   if (mMessageManager) {
     mMessageManager->Disconnect();
   }
 
   if (mChildMessageManager) {
     mChildMessageManager->Disconnect();
   }
 
@@ -1775,16 +1787,23 @@ bool nsFrameLoader::ShouldUseRemoteProce
 
   // Don't try to launch nested children if we don't have OMTC.
   // They won't render!
   if (XRE_IsContentProcess() &&
       !CompositorBridgeChild::ChildProcessHasCompositorBridge()) {
     return false;
   }
 
+  // Check if the force fission test attribute is enabled.
+  if (XRE_IsContentProcess() &&
+      Preferences::GetBool("browser.fission.oopif.attribute", false) &&
+      mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::fission)) {
+    return true;
+  }
+
   if (XRE_IsContentProcess() &&
       !(PR_GetEnv("MOZ_NESTED_OOP_TABS") ||
         Preferences::GetBool("dom.ipc.tabs.nested.enabled", false))) {
     return false;
   }
 
   // If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
   // fall back to the default.
@@ -1796,24 +1815,16 @@ bool nsFrameLoader::ShouldUseRemoteProce
   // Otherwise, we're remote if we have "remote=true" and we're either a
   // browser frame or a XUL element.
   return (OwnerIsMozBrowserFrame() ||
           mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
          mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::remote,
                                     nsGkAtoms::_true, eCaseMatters);
 }
 
-bool nsFrameLoader::IsRemoteFrame() {
-  if (mRemoteFrame) {
-    MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell");
-    return true;
-  }
-  return false;
-}
-
 static already_AddRefed<BrowsingContext> CreateBrowsingContext(
     BrowsingContext* aParentContext, BrowsingContext* aOpenerContext,
     const nsAString& aName, bool aIsContent) {
   // If we're content but our parent isn't, we're going to want to start a new
   // browsing context tree.
   if (aIsContent && !aParentContext->IsContent()) {
     aParentContext = nullptr;
   }
@@ -2382,17 +2393,17 @@ static Tuple<ContentParent*, TabParent*>
       tabParent->Manager()->IsContentParent()) {
     return MakeTuple(tabParent->Manager()->AsContentParent(), tabParent);
   }
 
   return ReturnTuple(nullptr, nullptr);
 }
 
 bool nsFrameLoader::TryRemoteBrowser() {
-  NS_ASSERTION(!mRemoteBrowser,
+  NS_ASSERTION(!mRemoteBrowser && !mRemoteFrameChild,
                "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
@@ -2428,17 +2439,19 @@ bool nsFrameLoader::TryRemoteBrowser() {
       openingTab->Manager()->IsContentParent()) {
     openerContentParent = openingTab->Manager()->AsContentParent();
   }
 
   // <iframe mozbrowser> gets to skip these checks.
   // iframes for JS plugins also get to skip these checks. We control the URL
   // that gets loaded, but the load is triggered from the document containing
   // the plugin.
-  if (!OwnerIsMozBrowserFrame() && !IsForJSPlugin()) {
+  // out of process iframes also get to skip this check.
+  if (!OwnerIsMozBrowserFrame() && !IsForJSPlugin() &&
+      !XRE_IsContentProcess()) {
     if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
       // Allow about:addon an exception to this rule so it can load remote
       // extension options pages.
       //
       // Note that the new frame's message manager will not be a child of the
       // chrome window message manager, and, the values of window.top and
       // window.parent will be different than they would be for a non-remote
       // frame.
@@ -2498,16 +2511,24 @@ bool nsFrameLoader::TryRemoteBrowser() {
     // We may be in a window that was just opened, so try the
     // nsIBrowserDOMWindow API as a backup.
     if (!nextTabParentId && window) {
       Unused << window->GetNextTabParentId(&nextTabParentId);
     }
   }
 
   nsCOMPtr<Element> ownerElement = mOwnerContent;
+
+  // If we're in a content process, create a RemoteFrameChild actor.
+  if (XRE_IsContentProcess()) {
+    mRemoteFrameChild = RemoteFrameChild::Create(
+        this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
+    return !!mRemoteFrameChild;
+  }
+
   mRemoteBrowser =
       ContentParent::CreateBrowser(context, ownerElement, openerContentParent,
                                    sameTabGroupAs, nextTabParentId);
   if (!mRemoteBrowser) {
     return false;
   }
 
   // We no longer need the remoteType attribute on the frame element.
@@ -2557,16 +2578,24 @@ bool nsFrameLoader::TryRemoteBrowser() {
   }
 
   ReallyLoadFrameScripts();
   InitializeBrowserAPI();
 
   return true;
 }
 
+bool nsFrameLoader::IsRemoteFrame() {
+  if (mRemoteFrame) {
+    MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell");
+    return true;
+  }
+  return false;
+}
+
 mozilla::dom::PBrowserParent* nsFrameLoader::GetRemoteBrowser() const {
   return mRemoteBrowser;
 }
 
 RenderFrame* nsFrameLoader::GetCurrentRenderFrame() const {
   if (mRemoteBrowser) {
     return mRemoteBrowser->GetRenderFrame();
   }
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -53,16 +53,17 @@ class ChromeMessageSender;
 class ContentParent;
 class InProcessTabChildMessageManager;
 class MessageSender;
 class PBrowserParent;
 class ProcessMessageManager;
 class Promise;
 class TabParent;
 class MutableTabContext;
+class RemoteFrameChild;
 
 namespace ipc {
 class StructuredCloneData;
 }  // namespace ipc
 
 }  // namespace dom
 
 namespace layout {
@@ -265,16 +266,28 @@ class nsFrameLoader final : public nsStu
   /**
    * Return the document that owns this, or null if we don't have
    * an owner.
    */
   Document* GetOwnerDoc() const {
     return mOwnerContent ? mOwnerContent->OwnerDoc() : nullptr;
   }
 
+  /**
+   * Returns whether this frame is a remote frame.
+   *
+   * This is true for either a top-level remote browser in the parent process,
+   * or a remote subframe in the child process.
+   */
+  bool IsRemoteFrame();
+
+  /**
+   * Returns the IPDL actor used if this is a top-level remote browser, or null
+   * otherwise.
+   */
   PBrowserParent* GetRemoteBrowser() const;
 
   /**
    * The "current" render frame is the one on which the most recent
    * remote layer-tree transaction was executed.  If no content has
    * been drawn yet, or the remote browser doesn't have any drawn
    * content for whatever reason, return nullptr.  The returned render
    * frame has an associated shadow layer tree.
@@ -353,21 +366,16 @@ class nsFrameLoader final : public nsStu
   nsFrameLoader(mozilla::dom::Element* aOwner, nsPIDOMWindowOuter* aOpener,
                 bool aNetworkCreated, int32_t aJSPluginID);
   ~nsFrameLoader();
 
   void SetOwnerContent(mozilla::dom::Element* aContent);
 
   bool ShouldUseRemoteProcess();
 
-  /**
-   * Return true if the frame is a remote frame. Return false otherwise
-   */
-  bool IsRemoteFrame();
-
   bool IsForJSPlugin() { return mJSPluginID != nsFakePluginTag::NOT_JSPLUGIN; }
 
   /**
    * Is this a frame loader for an isolated <iframe mozbrowser>?
    *
    * By default, mozbrowser frames are isolated.  Isolation can be disabled by
    * setting the frame's noisolation attribute.  Disabling isolation is
    * only allowed if the containing document is chrome.
@@ -451,16 +459,19 @@ class nsFrameLoader final : public nsStu
   RefPtr<Document> mContainerDocWhileDetached;
 
   // An opener window which should be used when the docshell is created.
   nsCOMPtr<nsPIDOMWindowOuter> mOpener;
 
   TabParent* mRemoteBrowser;
   uint64_t mChildID;
 
+  // This is used when this refers to a remote sub frame
+  RefPtr<mozilla::dom::RemoteFrameChild> mRemoteFrameChild;
+
   int32_t mJSPluginID;
 
   // Holds the last known size of the frame.
   mozilla::ScreenIntSize mLazySize;
 
   RefPtr<mozilla::dom::ParentSHistory> mParentSHistory;
 
   bool mDepthTooGreat : 1;
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py
@@ -419,16 +419,17 @@ STATIC_ATOMS = [
     Atom("featurePolicyViolation", "feature-policy-violation"),
     Atom("field", "field"),
     Atom("fieldset", "fieldset"),
     Atom("file", "file"),
     Atom("figcaption", "figcaption"),
     Atom("figure", "figure"),
     Atom("findbar", "findbar"),
     Atom("fixed", "fixed"),
+    Atom("fission", "fission"),
     Atom("flags", "flags"),
     Atom("flex", "flex"),
     Atom("flip", "flip"),
     Atom("floating", "floating"),
     Atom("floor", "floor"),
     Atom("flowlength", "flowlength"),
     Atom("focus", "focus"),
     Atom("focused", "focused"),