Bug 1579213 - Remove unused fields from ChangeRemoteness API, r=farre

This patch changes a few things about how nsFrameLoader is created, specifically
around the ChangeRemoteness API.

1. The private 'nsFrameLoader::nsFrameLoader' constructor has been simplified to
   only have one overload, shared by the different `::Create` static methods.

2. The creation static method used by `ChangeRemoteness` has changed name to
   `::Recreate`, as the signature is becoming more like the old method.

3. The `mNetworkCreated` bit is preserved when doing a `ChangeRemoteness`, as a
   remoteness change shouldn't be affecting that property.

4. Unused fields are removed from the ChangeRemoteness API.

5. The `remoteType` attribute is now mandatory in the ChangeRemoteness API,
   which simplifies the logic and makes it harder to accidentally misuse.

Differential Revision: https://phabricator.services.mozilla.com/D44893

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nika Layzell 2019-09-11 08:09:58 +00:00
parent d7eecef1e9
commit f103e26834
7 changed files with 100 additions and 122 deletions

View File

@ -169,13 +169,13 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
NS_INTERFACE_MAP_END
nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext,
bool aNetworkCreated)
const nsAString& aRemoteType, bool aNetworkCreated)
: mBrowsingContext(aBrowsingContext),
mOwnerContent(aOwner),
mDetachedSubdocFrame(nullptr),
mPendingSwitchID(0),
mChildID(0),
mRemoteType(VoidString()),
mRemoteType(aRemoteType),
mDepthTooGreat(false),
mIsTopLevelContent(false),
mDestroyCalled(false),
@ -186,46 +186,9 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext,
mNetworkCreated(aNetworkCreated),
mLoadingOriginalSrc(false),
mRemoteBrowserShown(false),
mIsRemoteFrame(false),
mIsRemoteFrame(!aRemoteType.IsEmpty()),
mObservingOwnerContent(false),
mTabProcessCrashFired(false) {
mIsRemoteFrame = ShouldUseRemoteProcess();
MOZ_ASSERT(!mIsRemoteFrame || !mBrowsingContext->HasOpener(),
"Cannot pass aOpener for a remote frame!");
if (mIsRemoteFrame &&
!aOwner->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, mRemoteType)) {
mRemoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
}
}
nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext,
const mozilla::dom::RemotenessOptions& aOptions)
: mBrowsingContext(aBrowsingContext),
mOwnerContent(aOwner),
mDetachedSubdocFrame(nullptr),
mPendingSwitchID(0),
mChildID(0),
mRemoteType(VoidString()),
mDepthTooGreat(false),
mIsTopLevelContent(false),
mDestroyCalled(false),
mNeedsAsyncDestroy(false),
mInSwap(false),
mInShow(false),
mHideCalled(false),
mNetworkCreated(false),
mLoadingOriginalSrc(false),
mRemoteBrowserShown(false),
mIsRemoteFrame(false),
mObservingOwnerContent(false),
mTabProcessCrashFired(false) {
if (aOptions.mRemoteType.WasPassed() &&
(!aOptions.mRemoteType.Value().IsVoid())) {
mIsRemoteFrame = true;
mRemoteType = aOptions.mRemoteType.Value();
}
}
mTabProcessCrashFired(false) {}
nsFrameLoader::~nsFrameLoader() {
if (mMessageManager) {
@ -338,8 +301,37 @@ static already_AddRefed<BrowsingContext> CreateBrowsingContext(
return BrowsingContext::Create(parentContext, aOpener, frameName, type);
}
nsFrameLoader* nsFrameLoader::Create(Element* aOwner, BrowsingContext* aOpener,
bool aNetworkCreated) {
static bool InitialLoadIsRemote(Element* aOwner) {
if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
return false;
}
// The initial load in an content process iframe should never be made remote.
// Content process iframes always become remote due to navigation.
if (XRE_IsContentProcess()) {
return false;
}
// If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
// fall back to the default.
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(aOwner);
bool isMozBrowserFrame = browserFrame && browserFrame->GetReallyIsBrowser();
if (isMozBrowserFrame &&
!aOwner->HasAttr(kNameSpaceID_None, nsGkAtoms::remote)) {
return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
}
// Otherwise, we're remote if we have "remote=true" and we're either a
// browser frame or a XUL element.
return (isMozBrowserFrame || aOwner->GetNameSpaceID() == kNameSpaceID_XUL) &&
aOwner->AttrValueIs(kNameSpaceID_None, nsGkAtoms::remote,
nsGkAtoms::_true, eCaseMatters);
}
already_AddRefed<nsFrameLoader> nsFrameLoader::Create(Element* aOwner,
BrowsingContext* aOpener,
bool aNetworkCreated) {
NS_ENSURE_TRUE(aOwner, nullptr);
Document* doc = aOwner->OwnerDoc();
@ -370,36 +362,52 @@ nsFrameLoader* nsFrameLoader::Create(Element* aOwner, BrowsingContext* aOpener,
RefPtr<BrowsingContext> context = CreateBrowsingContext(aOwner, aOpener);
NS_ENSURE_TRUE(context, nullptr);
return new nsFrameLoader(aOwner, context, aNetworkCreated);
// Determine the initial RemoteType from the load environment. An empty or
// void remote type denotes a non-remote frame, while a named remote type
// denotes a remote frame.
nsAutoString remoteType(VoidString());
if (InitialLoadIsRemote(aOwner)) {
MOZ_ASSERT(!aOpener, "Cannot pass `aOpener` for a remote frame!");
// If the `remoteType` attribute is specified and valid, use it. Otherwise,
// use a default remote type.
bool hasRemoteType =
aOwner->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, remoteType);
if (!hasRemoteType || remoteType.IsEmpty()) {
remoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
}
}
RefPtr<nsFrameLoader> fl =
new nsFrameLoader(aOwner, context, remoteType, aNetworkCreated);
return fl.forget();
}
/* static */
nsFrameLoader* nsFrameLoader::Create(
mozilla::dom::Element* aOwner, BrowsingContext* aPreservedBrowsingContext,
const mozilla::dom::RemotenessOptions& aOptions) {
already_AddRefed<nsFrameLoader> nsFrameLoader::Recreate(
mozilla::dom::Element* aOwner, BrowsingContext* aContext,
const nsAString& aRemoteType, bool aNetworkCreated) {
NS_ENSURE_TRUE(aOwner, nullptr);
#ifdef DEBUG
// This version of Create is only called for Remoteness updates, so we can
// assume we need a FrameLoader here and skip the check in the other Create.
Document* doc = aOwner->OwnerDoc();
MOZ_ASSERT(!doc->IsResourceDoc());
MOZ_ASSERT((!doc->IsLoadedAsData() && aOwner->IsInComposedDoc()) ||
doc->IsStaticDocument());
#endif
bool hasOpener =
aOptions.mOpener.WasPassed() && !aOptions.mOpener.Value().IsNull();
MOZ_ASSERT(!aOptions.mRemoteType.WasPassed() ||
aOptions.mRemoteType.Value().IsVoid() || !hasOpener,
"Cannot pass aOpener for a remote frame!");
// This seems slightly unwieldy.
RefPtr<BrowsingContext> opener;
if (hasOpener) {
opener = aOptions.mOpener.Value().Value().get();
}
RefPtr<BrowsingContext> context;
if (aPreservedBrowsingContext) {
context = aPreservedBrowsingContext;
} else {
context = CreateBrowsingContext(aOwner, opener);
RefPtr<BrowsingContext> context = aContext;
if (!context) {
context = CreateBrowsingContext(aOwner, /* opener */ nullptr);
}
NS_ENSURE_TRUE(context, nullptr);
return new nsFrameLoader(aOwner, context, aOptions);
RefPtr<nsFrameLoader> fl =
new nsFrameLoader(aOwner, context, aRemoteType, aNetworkCreated);
return fl.forget();
}
void nsFrameLoader::LoadFrame(bool aOriginalSrc) {
@ -1951,40 +1959,6 @@ bool nsFrameLoader::OwnerIsMozBrowserFrame() {
return browserFrame ? browserFrame->GetReallyIsBrowser() : false;
}
bool nsFrameLoader::ShouldUseRemoteProcess() {
if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
return false;
}
// Don't try to launch nested children if we don't have OMTC.
// They won't render!
if (XRE_IsContentProcess() &&
!CompositorBridgeChild::ChildProcessHasCompositorBridge()) {
return false;
}
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.
if (OwnerIsMozBrowserFrame() &&
!mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::remote)) {
return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
}
// 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);
}
nsresult nsFrameLoader::MaybeCreateDocShell() {
if (GetDocShell()) {
return NS_OK;

View File

@ -94,21 +94,23 @@ class nsFrameLoader final : public nsStubMutationObserver,
friend class AutoResetInShow;
friend class AutoResetInFrameSwap;
typedef mozilla::dom::Document Document;
typedef mozilla::dom::Element Element;
typedef mozilla::dom::BrowserParent BrowserParent;
typedef mozilla::dom::BrowserBridgeChild BrowserBridgeChild;
typedef mozilla::dom::BrowsingContext BrowsingContext;
public:
// Called by Frame Elements to create a new FrameLoader.
static nsFrameLoader* Create(mozilla::dom::Element* aOwner,
mozilla::dom::BrowsingContext* aOpener,
bool aNetworkCreated);
static already_AddRefed<nsFrameLoader> Create(Element* aOwner,
BrowsingContext* aOpener,
bool aNetworkCreated);
// Called by nsFrameLoaderOwner::ChangeRemoteness when switching out
// FrameLoaders.
static nsFrameLoader* Create(mozilla::dom::Element* aOwner,
BrowsingContext* aPreservedBrowsingContext,
const mozilla::dom::RemotenessOptions& aOptions);
static already_AddRefed<nsFrameLoader> Recreate(Element* aOwner,
BrowsingContext* aContext,
const nsAString& aRemoteType,
bool aNetworkCreated);
NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID)
@ -234,6 +236,8 @@ class nsFrameLoader final : public nsStubMutationObserver,
bool IsDead() const { return mDestroyCalled; }
bool IsNetworkCreated() const { return mNetworkCreated; }
/**
* Is this a frame loader for a bona fide <iframe mozbrowser>?
* <xul:browser> is not a mozbrowser, so this is false for that case.
@ -406,16 +410,11 @@ class nsFrameLoader final : public nsStubMutationObserver,
private:
nsFrameLoader(mozilla::dom::Element* aOwner,
mozilla::dom::BrowsingContext* aBrowsingContext,
bool aNetworkCreated);
nsFrameLoader(mozilla::dom::Element* aOwner,
mozilla::dom::BrowsingContext* aBrowsingContext,
const mozilla::dom::RemotenessOptions& aOptions);
const nsAString& aRemoteType, bool aNetworkCreated);
~nsFrameLoader();
void SetOwnerContent(mozilla::dom::Element* aContent);
bool ShouldUseRemoteProcess();
/**
* Get our owning element's app manifest URL, or return the empty string if
* our owning element doesn't have an app manifest URL.

View File

@ -53,8 +53,7 @@ bool nsFrameLoaderOwner::ShouldPreserveBrowsingContext(
// Don't preserve contexts if this is a chrome (parent process) window
// that is changing from remote to local.
if (XRE_IsParentProcess() && (!aOptions.mRemoteType.WasPassed() ||
aOptions.mRemoteType.Value().IsVoid())) {
if (XRE_IsParentProcess() && aOptions.mRemoteType.IsVoid()) {
return false;
}
@ -67,6 +66,7 @@ bool nsFrameLoaderOwner::ShouldPreserveBrowsingContext(
void nsFrameLoaderOwner::ChangeRemoteness(
const mozilla::dom::RemotenessOptions& aOptions, mozilla::ErrorResult& rv) {
RefPtr<mozilla::dom::BrowsingContext> bc;
bool networkCreated = false;
// If we already have a Frameloader, destroy it, possibly preserving its
// browsing context.
@ -76,6 +76,9 @@ void nsFrameLoaderOwner::ChangeRemoteness(
mFrameLoader->SkipBrowsingContextDetach();
}
// Preserve the networkCreated status, as nsDocShells created after a
// process swap may shouldn't change their dynamically-created status.
networkCreated = mFrameLoader->IsNetworkCreated();
mFrameLoader->Destroy();
mFrameLoader = nullptr;
}
@ -85,7 +88,8 @@ void nsFrameLoaderOwner::ChangeRemoteness(
// owner.
RefPtr<Element> owner = do_QueryObject(this);
MOZ_ASSERT(owner);
mFrameLoader = nsFrameLoader::Create(owner, bc, aOptions);
mFrameLoader =
nsFrameLoader::Recreate(owner, bc, aOptions.mRemoteType, networkCreated);
if (NS_WARN_IF(!mFrameLoader)) {
return;

View File

@ -2540,7 +2540,7 @@ void nsObjectLoadingContent::CreateStaticClone(
if (mFrameLoader) {
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
nsFrameLoader* fl =
RefPtr<nsFrameLoader> fl =
nsFrameLoader::Create(content->AsElement(), nullptr, false);
if (fl) {
aDest->mFrameLoader = fl;

View File

@ -384,7 +384,7 @@ nsresult nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest) {
if (doc->IsStaticDocument() && mFrameLoader) {
nsGenericHTMLFrameElement* dest =
static_cast<nsGenericHTMLFrameElement*>(aDest);
nsFrameLoader* fl = nsFrameLoader::Create(dest, nullptr, false);
RefPtr<nsFrameLoader> fl = nsFrameLoader::Create(dest, nullptr, false);
NS_ENSURE_STATE(fl);
dest->mFrameLoader = fl;
mFrameLoader->CreateStaticClone(fl);

View File

@ -25,6 +25,7 @@
#include "nsFrameLoaderOwner.h"
#include "nsQueryObject.h"
#include "nsSerializationHelper.h"
#include "nsFrameLoader.h"
#include "mozilla/dom/JSWindowActorBinding.h"
#include "mozilla/dom/JSWindowActorChild.h"
@ -260,10 +261,12 @@ static nsresult ChangeFrameRemoteness(WindowGlobalChild* aWgc,
// Actually perform the remoteness swap.
RemotenessOptions options;
options.mPendingSwitchID.Construct(aPendingSwitchId);
options.mRemoteType.Assign(aRemoteType);
// Only set mRemoteType if it doesn't match the current process' remote type.
if (!ContentChild::GetSingleton()->GetRemoteType().Equals(aRemoteType)) {
options.mRemoteType.Construct(aRemoteType);
// Clear mRemoteType to VoidString() (for non-remote) if it matches the
// current process' remote type.
if (ContentChild::GetSingleton()->GetRemoteType().Equals(aRemoteType)) {
options.mRemoteType.Assign(VoidString());
}
ErrorResult error;

View File

@ -5,9 +5,7 @@
*/
dictionary RemotenessOptions {
DOMString? remoteType;
FrameLoader? sameProcessAsFrameLoader;
WindowProxy? opener;
required DOMString? remoteType;
// Used to indicate that there is an error condition that needs to
// be handled.
@ -48,5 +46,5 @@ interface MozFrameLoaderOwner {
void swapFrameLoaders(HTMLIFrameElement aOtherLoaderOwner);
[ChromeOnly, Throws]
void changeRemoteness(optional RemotenessOptions aOptions = {});
void changeRemoteness(RemotenessOptions aOptions);
};