зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1640019 - Part 1: Support toplevel process switches outside of tabbrowser, r=mattwoodrow
This new process switching behavior is only enabled for some browser elements, which have specified a specific attribute. Turning this on for all browsers with a `remote` attribute causes breakage in reftests. The initial version does not handle switching from remote to parent or vice-versa, that is covered in a later part. Differential Revision: https://phabricator.services.mozilla.com/D78969
This commit is contained in:
Родитель
74ca6cc819
Коммит
212943c862
|
@ -27,6 +27,7 @@
|
|||
#include "nsNetUtil.h"
|
||||
#include "nsSHistory.h"
|
||||
#include "nsSecureBrowserUI.h"
|
||||
#include "nsQueryObject.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
|
@ -383,7 +384,7 @@ void CanonicalBrowsingContext::LoadURI(const nsAString& aURI,
|
|||
LoadURI(loadState, true);
|
||||
}
|
||||
|
||||
void CanonicalBrowsingContext::PendingRemotenessChange::Complete(
|
||||
void CanonicalBrowsingContext::PendingRemotenessChange::ProcessReady(
|
||||
ContentParent* aContentParent) {
|
||||
if (!mPromise) {
|
||||
return;
|
||||
|
@ -395,6 +396,42 @@ void CanonicalBrowsingContext::PendingRemotenessChange::Complete(
|
|||
return;
|
||||
}
|
||||
|
||||
// If this BrowsingContext is embedded within the parent process, perform the
|
||||
// process switch directly.
|
||||
if (Element* browserElement = target->GetEmbedderElement()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(target->IsTop(),
|
||||
"We shouldn't be trying to change the remoteness of "
|
||||
"non-remote iframes");
|
||||
|
||||
RefPtr<nsFrameLoaderOwner> frameLoaderOwner =
|
||||
do_QueryObject(browserElement);
|
||||
MOZ_RELEASE_ASSERT(frameLoaderOwner,
|
||||
"embedder browser must be nsFrameLoaderOwner");
|
||||
|
||||
// The process has been created, hand off to nsFrameLoaderOwner to finish
|
||||
// the process switch.
|
||||
ErrorResult error;
|
||||
frameLoaderOwner->ChangeRemotenessToProcess(
|
||||
aContentParent, mPendingSwitchId, mReplaceBrowsingContext, error);
|
||||
if (error.Failed()) {
|
||||
Cancel(error.StealNSResult());
|
||||
return;
|
||||
}
|
||||
|
||||
// We did it! The process switch is complete.
|
||||
RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
|
||||
if (RefPtr<BrowserParent> newBrowser = frameLoader->GetBrowserParent()) {
|
||||
mPromise->Resolve(newBrowser, __func__);
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Failed to create the BrowserParent somehow! Abort the process switch
|
||||
// attempt.
|
||||
Cancel(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<WindowGlobalParent> embedderWindow = target->GetEmbedderWindowGlobal();
|
||||
if (NS_WARN_IF(!embedderWindow) || NS_WARN_IF(!embedderWindow->CanSend())) {
|
||||
Cancel(NS_ERROR_FAILURE);
|
||||
|
@ -450,6 +487,7 @@ void CanonicalBrowsingContext::PendingRemotenessChange::Complete(
|
|||
oldBrowser->Destroy();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mReplaceBrowsingContext, "Cannot replace BC for subframe");
|
||||
nsCOMPtr<nsIPrincipal> initialPrincipal =
|
||||
NullPrincipal::CreateWithInheritedAttributes(
|
||||
target->OriginAttributesRef(),
|
||||
|
@ -517,14 +555,27 @@ void CanonicalBrowsingContext::PendingRemotenessChange::Clear() {
|
|||
mTarget = nullptr;
|
||||
}
|
||||
|
||||
CanonicalBrowsingContext::PendingRemotenessChange::PendingRemotenessChange(
|
||||
CanonicalBrowsingContext* aTarget, RemotenessPromise::Private* aPromise,
|
||||
uint64_t aPendingSwitchId, bool aReplaceBrowsingContext)
|
||||
: mTarget(aTarget),
|
||||
mPromise(aPromise),
|
||||
mPendingSwitchId(aPendingSwitchId),
|
||||
mReplaceBrowsingContext(aReplaceBrowsingContext) {}
|
||||
|
||||
CanonicalBrowsingContext::PendingRemotenessChange::~PendingRemotenessChange() {
|
||||
MOZ_ASSERT(!mPromise && !mTarget,
|
||||
"should've already been Cancel() or Complete()-ed");
|
||||
}
|
||||
|
||||
RefPtr<CanonicalBrowsingContext::RemotenessPromise>
|
||||
CanonicalBrowsingContext::ChangeFrameRemoteness(const nsAString& aRemoteType,
|
||||
uint64_t aPendingSwitchId) {
|
||||
CanonicalBrowsingContext::ChangeRemoteness(const nsAString& aRemoteType,
|
||||
uint64_t aPendingSwitchId,
|
||||
bool aReplaceBrowsingContext) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
!aReplaceBrowsingContext || (IsEmbeddedInProcess(0) && IsTopContent()),
|
||||
"Cannot replace BrowsingContext for subframes");
|
||||
|
||||
// Ensure our embedder hasn't been destroyed already.
|
||||
RefPtr<WindowGlobalParent> embedderWindowGlobal = GetEmbedderWindowGlobal();
|
||||
if (!embedderWindowGlobal) {
|
||||
|
@ -544,7 +595,8 @@ CanonicalBrowsingContext::ChangeFrameRemoteness(const nsAString& aRemoteType,
|
|||
__func__);
|
||||
}
|
||||
|
||||
if (aRemoteType.Equals(oldContent->GetRemoteType())) {
|
||||
if (!aReplaceBrowsingContext &&
|
||||
aRemoteType.Equals(oldContent->GetRemoteType())) {
|
||||
NS_WARNING("Already in the correct process");
|
||||
return RemotenessPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
@ -557,10 +609,9 @@ CanonicalBrowsingContext::ChangeFrameRemoteness(const nsAString& aRemoteType,
|
|||
|
||||
RefPtr<BrowserParent> embedderBrowser =
|
||||
embedderWindowGlobal->GetBrowserParent();
|
||||
MOZ_ASSERT(embedderBrowser);
|
||||
|
||||
// Switching to local. No new process, so perform switch sync.
|
||||
if (aRemoteType.Equals(embedderBrowser->Manager()->GetRemoteType())) {
|
||||
if (embedderBrowser &&
|
||||
aRemoteType.Equals(embedderBrowser->Manager()->GetRemoteType())) {
|
||||
if (GetCurrentWindowGlobal()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(GetCurrentWindowGlobal()->IsProcessRoot());
|
||||
RefPtr<BrowserParent> oldBrowser =
|
||||
|
@ -576,6 +627,7 @@ CanonicalBrowsingContext::ChangeFrameRemoteness(const nsAString& aRemoteType,
|
|||
oldBrowser->Destroy();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!aReplaceBrowsingContext);
|
||||
SetOwnerProcessId(embedderBrowser->Manager()->ChildID());
|
||||
Unused << embedderWindowGlobal->SendMakeFrameLocal(this, aPendingSwitchId);
|
||||
return RemotenessPromise::CreateAndResolve(embedderBrowser, __func__);
|
||||
|
@ -583,8 +635,8 @@ CanonicalBrowsingContext::ChangeFrameRemoteness(const nsAString& aRemoteType,
|
|||
|
||||
// Switching to remote. Wait for new process to launch before switch.
|
||||
auto promise = MakeRefPtr<RemotenessPromise::Private>(__func__);
|
||||
RefPtr<PendingRemotenessChange> change =
|
||||
new PendingRemotenessChange(this, promise, aPendingSwitchId);
|
||||
RefPtr<PendingRemotenessChange> change = new PendingRemotenessChange(
|
||||
this, promise, aPendingSwitchId, aReplaceBrowsingContext);
|
||||
mPendingRemotenessChange = change;
|
||||
|
||||
ContentParent::GetNewOrUsedBrowserProcessAsync(
|
||||
|
@ -596,7 +648,7 @@ CanonicalBrowsingContext::ChangeFrameRemoteness(const nsAString& aRemoteType,
|
|||
->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[change](ContentParent* aContentParent) {
|
||||
change->Complete(aContentParent);
|
||||
change->ProcessReady(aContentParent);
|
||||
},
|
||||
[change](LaunchError aError) { change->Cancel(NS_ERROR_FAILURE); });
|
||||
return promise.forget();
|
||||
|
|
|
@ -131,9 +131,15 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
|||
void LoadURI(const nsAString& aURI, const LoadURIOptions& aOptions,
|
||||
ErrorResult& aError);
|
||||
|
||||
// Internal method to change which process a BrowsingContext is being loaded
|
||||
// in. The returned promise will resolve when the process switch is completed.
|
||||
//
|
||||
// A VoidString() aRemoteType argument will perform a process switch into the
|
||||
// parent process, and the method will resolve with a null BrowserParent.
|
||||
using RemotenessPromise = MozPromise<RefPtr<BrowserParent>, nsresult, false>;
|
||||
RefPtr<RemotenessPromise> ChangeFrameRemoteness(const nsAString& aRemoteType,
|
||||
uint64_t aPendingSwitchId);
|
||||
RefPtr<RemotenessPromise> ChangeRemoteness(const nsAString& aRemoteType,
|
||||
uint64_t aPendingSwitchId,
|
||||
bool aReplaceBrowsingContext);
|
||||
|
||||
// Return a media controller from the top-level browsing context that can
|
||||
// control all media belonging to this browsing context tree. Return nullptr
|
||||
|
@ -175,13 +181,11 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
|||
|
||||
PendingRemotenessChange(CanonicalBrowsingContext* aTarget,
|
||||
RemotenessPromise::Private* aPromise,
|
||||
uint64_t aPendingSwitchId)
|
||||
: mTarget(aTarget),
|
||||
mPromise(aPromise),
|
||||
mPendingSwitchId(aPendingSwitchId) {}
|
||||
uint64_t aPendingSwitchId,
|
||||
bool aReplaceBrowsingContext);
|
||||
|
||||
void Cancel(nsresult aRv);
|
||||
void Complete(ContentParent* aContentParent);
|
||||
void ProcessReady(ContentParent* aContentParent);
|
||||
|
||||
private:
|
||||
~PendingRemotenessChange();
|
||||
|
@ -191,6 +195,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
|||
RefPtr<RemotenessPromise::Private> mPromise;
|
||||
|
||||
uint64_t mPendingSwitchId;
|
||||
bool mReplaceBrowsingContext;
|
||||
};
|
||||
|
||||
friend class net::DocumentLoadListener;
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
#include "mozilla/dom/ChildSHistory.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentProcessManager.h"
|
||||
#include "mozilla/dom/BrowserBridgeChild.h"
|
||||
#include "mozilla/dom/BrowserHost.h"
|
||||
#include "mozilla/dom/BrowserBridgeHost.h"
|
||||
|
@ -161,13 +162,13 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
|
|||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext,
|
||||
const nsAString& aRemoteType, bool aNetworkCreated)
|
||||
bool aIsRemoteFrame, bool aNetworkCreated)
|
||||
: mPendingBrowsingContext(aBrowsingContext),
|
||||
mOwnerContent(aOwner),
|
||||
mDetachedSubdocFrame(nullptr),
|
||||
mPendingSwitchID(0),
|
||||
mChildID(0),
|
||||
mRemoteType(aRemoteType),
|
||||
mRemoteType(VoidString()),
|
||||
mDepthTooGreat(false),
|
||||
mIsTopLevelContent(false),
|
||||
mDestroyCalled(false),
|
||||
|
@ -178,7 +179,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext,
|
|||
mNetworkCreated(aNetworkCreated),
|
||||
mLoadingOriginalSrc(false),
|
||||
mRemoteBrowserShown(false),
|
||||
mIsRemoteFrame(!aRemoteType.IsEmpty()),
|
||||
mIsRemoteFrame(aIsRemoteFrame),
|
||||
mWillChangeProcess(false),
|
||||
mObservingOwnerContent(false),
|
||||
mTabProcessCrashFired(false) {}
|
||||
|
@ -341,6 +342,42 @@ static bool InitialLoadIsRemote(Element* aOwner) {
|
|||
nsGkAtoms::_true, eCaseMatters);
|
||||
}
|
||||
|
||||
static void GetInitialRemoteTypeAndProcess(Element* aOwner,
|
||||
nsAString& aRemoteType,
|
||||
uint64_t* aChildID) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
*aChildID = 0;
|
||||
|
||||
// Check if there is an explicit `remoteType` attribute which we should use.
|
||||
bool hasRemoteType =
|
||||
aOwner->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, aRemoteType);
|
||||
if (!hasRemoteType || aRemoteType.IsEmpty()) {
|
||||
hasRemoteType = false;
|
||||
aRemoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
|
||||
}
|
||||
|
||||
// Check if `sameProcessAsFrameLoader` was used to override the process.
|
||||
nsCOMPtr<nsIBrowser> browser = aOwner->AsBrowser();
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
RefPtr<nsFrameLoader> otherLoader;
|
||||
browser->GetSameProcessAsFrameLoader(getter_AddRefs(otherLoader));
|
||||
if (!otherLoader) {
|
||||
return;
|
||||
}
|
||||
BrowserParent* browserParent = BrowserParent::GetFrom(otherLoader);
|
||||
if (!browserParent) {
|
||||
return;
|
||||
}
|
||||
RefPtr<ContentParent> contentParent = browserParent->Manager();
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
!hasRemoteType || contentParent->GetRemoteType() == aRemoteType,
|
||||
"If specified, remoteType attribute must match sameProcessAsFrameLoader");
|
||||
aRemoteType = contentParent->GetRemoteType();
|
||||
*aChildID = contentParent->ChildID();
|
||||
}
|
||||
|
||||
already_AddRefed<nsFrameLoader> nsFrameLoader::Create(
|
||||
Element* aOwner, bool aNetworkCreated, nsIOpenWindowInfo* aOpenWindowInfo) {
|
||||
NS_ENSURE_TRUE(aOwner, nullptr);
|
||||
|
@ -375,30 +412,20 @@ already_AddRefed<nsFrameLoader> nsFrameLoader::Create(
|
|||
CreateBrowsingContext(aOwner, aOpenWindowInfo);
|
||||
NS_ENSURE_TRUE(context, nullptr);
|
||||
|
||||
// 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)) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
bool isRemoteFrame = InitialLoadIsRemote(aOwner);
|
||||
RefPtr<nsFrameLoader> fl =
|
||||
new nsFrameLoader(aOwner, context, remoteType, aNetworkCreated);
|
||||
new nsFrameLoader(aOwner, context, isRemoteFrame, aNetworkCreated);
|
||||
fl->mOpenWindowInfo = aOpenWindowInfo;
|
||||
if (isRemoteFrame) {
|
||||
GetInitialRemoteTypeAndProcess(aOwner, fl->mRemoteType, &fl->mChildID);
|
||||
}
|
||||
return fl.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<nsFrameLoader> nsFrameLoader::Recreate(
|
||||
mozilla::dom::Element* aOwner, BrowsingContext* aContext,
|
||||
const nsAString& aRemoteType, bool aNetworkCreated, bool aPreserveContext) {
|
||||
mozilla::dom::Element* aOwner, BrowsingContext* aContext, bool aIsRemote,
|
||||
bool aNetworkCreated, bool aPreserveContext) {
|
||||
NS_ENSURE_TRUE(aOwner, nullptr);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -417,7 +444,7 @@ already_AddRefed<nsFrameLoader> nsFrameLoader::Recreate(
|
|||
NS_ENSURE_TRUE(context, nullptr);
|
||||
|
||||
RefPtr<nsFrameLoader> fl =
|
||||
new nsFrameLoader(aOwner, context, aRemoteType, aNetworkCreated);
|
||||
new nsFrameLoader(aOwner, context, aIsRemote, aNetworkCreated);
|
||||
return fl.forget();
|
||||
}
|
||||
|
||||
|
@ -482,6 +509,17 @@ void nsFrameLoader::LoadFrame(bool aOriginalSrc) {
|
|||
}
|
||||
}
|
||||
|
||||
void nsFrameLoader::ConfigRemoteProcess(const nsAString& aRemoteType,
|
||||
ContentParent* aContentParent) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(IsRemoteFrame(), "Must be a remote frame");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mRemoteBrowser, "Must not have a browser yet");
|
||||
MOZ_DIAGNOSTIC_ASSERT_IF(aContentParent,
|
||||
aContentParent->GetRemoteType() == aRemoteType);
|
||||
|
||||
mRemoteType = aRemoteType;
|
||||
mChildID = aContentParent ? aContentParent->ChildID() : 0;
|
||||
}
|
||||
|
||||
void nsFrameLoader::FireErrorEvent() {
|
||||
if (!mOwnerContent) {
|
||||
return;
|
||||
|
@ -2386,26 +2424,6 @@ uint32_t nsFrameLoader::LazyHeight() const {
|
|||
return lazyHeight;
|
||||
}
|
||||
|
||||
static ContentParent* GetContentParent(Element* aBrowser) {
|
||||
nsCOMPtr<nsIBrowser> browser = aBrowser ? aBrowser->AsBrowser() : nullptr;
|
||||
if (!browser) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<nsFrameLoader> otherLoader;
|
||||
browser->GetSameProcessAsFrameLoader(getter_AddRefs(otherLoader));
|
||||
if (!otherLoader) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BrowserParent* browserParent = BrowserParent::GetFrom(otherLoader);
|
||||
if (browserParent) {
|
||||
return browserParent->Manager();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool nsFrameLoader::EnsureRemoteBrowser() {
|
||||
MOZ_ASSERT(IsRemoteFrame());
|
||||
return mRemoteBrowser || TryRemoteBrowser();
|
||||
|
@ -2414,10 +2432,9 @@ bool nsFrameLoader::EnsureRemoteBrowser() {
|
|||
bool nsFrameLoader::TryRemoteBrowserInternal() {
|
||||
NS_ASSERTION(!mRemoteBrowser,
|
||||
"TryRemoteBrowser called with a remote browser already?");
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
XRE_IsParentProcess(),
|
||||
"Remote subframes should only be created using the "
|
||||
"`CanonicalBrowsingContext::ChangeFrameRemoteness` API");
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(),
|
||||
"Remote subframes should only be created using the "
|
||||
"`CanonicalBrowsingContext::ChangeRemoteness` API");
|
||||
|
||||
AssertSafeToInit();
|
||||
|
||||
|
@ -2477,9 +2494,6 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
|
|||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ContentParent> openerContentParent;
|
||||
RefPtr<BrowserParent> sameTabGroupAs;
|
||||
|
||||
// <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
|
||||
|
@ -2522,9 +2536,6 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
|
|||
nsGkAtoms::content, eIgnoreCase)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to get the related content parent from our browser element.
|
||||
openerContentParent = GetContentParent(mOwnerContent);
|
||||
}
|
||||
|
||||
uint32_t chromeFlags = 0;
|
||||
|
@ -2556,9 +2567,14 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
|
|||
}
|
||||
nextRemoteBrowser->SetOwnerElement(ownerElement);
|
||||
} else {
|
||||
mRemoteBrowser = ContentParent::CreateBrowser(
|
||||
context, ownerElement, mRemoteType, mPendingBrowsingContext,
|
||||
openerContentParent);
|
||||
RefPtr<ContentParent> contentParent;
|
||||
if (mChildID != 0) {
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
contentParent = cpm->GetContentProcessById(ContentParentId(mChildID));
|
||||
}
|
||||
mRemoteBrowser =
|
||||
ContentParent::CreateBrowser(context, ownerElement, mRemoteType,
|
||||
mPendingBrowsingContext, contentParent);
|
||||
}
|
||||
if (!mRemoteBrowser) {
|
||||
return false;
|
||||
|
|
|
@ -110,7 +110,7 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
// FrameLoaders.
|
||||
static already_AddRefed<nsFrameLoader> Recreate(Element* aOwner,
|
||||
BrowsingContext* aContext,
|
||||
const nsAString& aRemoteType,
|
||||
bool aIsRemote,
|
||||
bool aNetworkCreated,
|
||||
bool aPreserveContext);
|
||||
|
||||
|
@ -391,6 +391,14 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
|
||||
void SetWillChangeProcess();
|
||||
|
||||
// Configure which remote process should be used to host the remote browser
|
||||
// created in `TryRemoteBrowser`. This method _must_ be called before
|
||||
// `TryRemoteBrowser`, and a script blocker must be on the stack.
|
||||
//
|
||||
// |aContentParent|, if set, must have the remote type |aRemoteType|.
|
||||
void ConfigRemoteProcess(const nsAString& aRemoteType,
|
||||
mozilla::dom::ContentParent* aContentParent);
|
||||
|
||||
void MaybeNotifyCrashed(mozilla::dom::BrowsingContext* aBrowsingContext,
|
||||
mozilla::ipc::MessageChannel* aChannel);
|
||||
|
||||
|
@ -398,8 +406,8 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
|
||||
private:
|
||||
nsFrameLoader(mozilla::dom::Element* aOwner,
|
||||
mozilla::dom::BrowsingContext* aBrowsingContext,
|
||||
const nsAString& aRemoteType, bool aNetworkCreated);
|
||||
mozilla::dom::BrowsingContext* aBrowsingContext, bool aIsRemote,
|
||||
bool aNetworkCreated);
|
||||
~nsFrameLoader();
|
||||
|
||||
void SetOwnerContent(mozilla::dom::Element* aContent);
|
||||
|
|
|
@ -56,33 +56,37 @@ bool nsFrameLoaderOwner::UseRemoteSubframes() {
|
|||
return loadContext->UseRemoteSubframes();
|
||||
}
|
||||
|
||||
bool nsFrameLoaderOwner::ShouldPreserveBrowsingContext(
|
||||
const mozilla::dom::RemotenessOptions& aOptions) {
|
||||
if (aOptions.mReplaceBrowsingContext) {
|
||||
return false;
|
||||
nsFrameLoaderOwner::ChangeRemotenessContextType
|
||||
nsFrameLoaderOwner::ShouldPreserveBrowsingContext(
|
||||
bool aIsRemote, bool aReplaceBrowsingContext) {
|
||||
if (aReplaceBrowsingContext) {
|
||||
return ChangeRemotenessContextType::DONT_PRESERVE_BUT_PROPAGATE;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
// Don't preserve for remote => parent loads.
|
||||
if (aOptions.mRemoteType.IsVoid()) {
|
||||
return false;
|
||||
if (!aIsRemote) {
|
||||
return ChangeRemotenessContextType::DONT_PRESERVE;
|
||||
}
|
||||
|
||||
// Don't preserve for parent => remote loads.
|
||||
if (mFrameLoader && !mFrameLoader->IsRemoteFrame()) {
|
||||
return false;
|
||||
return ChangeRemotenessContextType::DONT_PRESERVE;
|
||||
}
|
||||
}
|
||||
|
||||
// We will preserve our browsing context if either fission is enabled, or the
|
||||
// `preserve_browsing_contexts` pref is active.
|
||||
return UseRemoteSubframes() ||
|
||||
StaticPrefs::fission_preserve_browsing_contexts();
|
||||
if (UseRemoteSubframes() ||
|
||||
StaticPrefs::fission_preserve_browsing_contexts()) {
|
||||
return ChangeRemotenessContextType::PRESERVE;
|
||||
}
|
||||
return ChangeRemotenessContextType::DONT_PRESERVE;
|
||||
}
|
||||
|
||||
void nsFrameLoaderOwner::ChangeRemotenessCommon(
|
||||
const ChangeRemotenessContextType& aContextType,
|
||||
bool aSwitchingInProgressLoad, const nsAString& aRemoteType,
|
||||
bool aSwitchingInProgressLoad, bool aIsRemote,
|
||||
std::function<void()>& aFrameLoaderInit, mozilla::ErrorResult& aRv) {
|
||||
RefPtr<mozilla::dom::BrowsingContext> bc;
|
||||
bool networkCreated = false;
|
||||
|
@ -127,7 +131,7 @@ void nsFrameLoaderOwner::ChangeRemotenessCommon(
|
|||
}
|
||||
|
||||
mFrameLoader = nsFrameLoader::Recreate(
|
||||
owner, bc, aRemoteType, networkCreated,
|
||||
owner, bc, aIsRemote, networkCreated,
|
||||
aContextType == ChangeRemotenessContextType::PRESERVE);
|
||||
if (NS_WARN_IF(!mFrameLoader)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
|
@ -186,7 +190,13 @@ void nsFrameLoaderOwner::ChangeRemotenessCommon(
|
|||
|
||||
void nsFrameLoaderOwner::ChangeRemoteness(
|
||||
const mozilla::dom::RemotenessOptions& aOptions, mozilla::ErrorResult& rv) {
|
||||
bool isRemote = !aOptions.mRemoteType.IsEmpty();
|
||||
|
||||
std::function<void()> frameLoaderInit = [&] {
|
||||
if (isRemote) {
|
||||
mFrameLoader->ConfigRemoteProcess(aOptions.mRemoteType, nullptr);
|
||||
}
|
||||
|
||||
if (aOptions.mPendingSwitchID.WasPassed()) {
|
||||
mFrameLoader->ResumeLoad(aOptions.mPendingSwitchID.Value());
|
||||
} else {
|
||||
|
@ -194,16 +204,10 @@ void nsFrameLoaderOwner::ChangeRemoteness(
|
|||
}
|
||||
};
|
||||
|
||||
ChangeRemotenessContextType preserveType =
|
||||
ChangeRemotenessContextType::DONT_PRESERVE;
|
||||
if (ShouldPreserveBrowsingContext(aOptions)) {
|
||||
preserveType = ChangeRemotenessContextType::PRESERVE;
|
||||
} else if (aOptions.mReplaceBrowsingContext) {
|
||||
preserveType = ChangeRemotenessContextType::DONT_PRESERVE_BUT_PROPAGATE;
|
||||
}
|
||||
|
||||
ChangeRemotenessCommon(preserveType, aOptions.mSwitchingInProgressLoad,
|
||||
aOptions.mRemoteType, frameLoaderInit, rv);
|
||||
auto shouldPreserve =
|
||||
ShouldPreserveBrowsingContext(isRemote, aOptions.mReplaceBrowsingContext);
|
||||
ChangeRemotenessCommon(shouldPreserve, aOptions.mSwitchingInProgressLoad,
|
||||
isRemote, frameLoaderInit, rv);
|
||||
}
|
||||
|
||||
void nsFrameLoaderOwner::ChangeRemotenessWithBridge(BrowserBridgeChild* aBridge,
|
||||
|
@ -221,12 +225,26 @@ void nsFrameLoaderOwner::ChangeRemotenessWithBridge(BrowserBridgeChild* aBridge,
|
|||
mFrameLoader->mRemoteBrowser = host;
|
||||
};
|
||||
|
||||
// NOTE: We always use the DEFAULT_REMOTE_TYPE here, because we don't actually
|
||||
// know the real remote type, and don't need to, as we're a content process.
|
||||
ChangeRemotenessCommon(
|
||||
/* preserve */ ChangeRemotenessContextType::PRESERVE,
|
||||
/* switching in progress load */ true,
|
||||
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE), frameLoaderInit, rv);
|
||||
ChangeRemotenessCommon(ChangeRemotenessContextType::PRESERVE,
|
||||
/* inProgress */ true,
|
||||
/* isRemote */ true, frameLoaderInit, rv);
|
||||
}
|
||||
|
||||
void nsFrameLoaderOwner::ChangeRemotenessToProcess(
|
||||
ContentParent* aContentParent, uint64_t aPendingSwitchId,
|
||||
bool aReplaceBrowsingContext, mozilla::ErrorResult& rv) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
std::function<void()> frameLoaderInit = [&] {
|
||||
mFrameLoader->ConfigRemoteProcess(aContentParent->GetRemoteType(),
|
||||
aContentParent);
|
||||
mFrameLoader->ResumeLoad(aPendingSwitchId);
|
||||
};
|
||||
|
||||
auto shouldPreserve = ShouldPreserveBrowsingContext(
|
||||
/* isRemote */ true, aReplaceBrowsingContext);
|
||||
ChangeRemotenessCommon(shouldPreserve, /* inProgress */ true,
|
||||
/* isRemote */ true, frameLoaderInit, rv);
|
||||
}
|
||||
|
||||
void nsFrameLoaderOwner::SubframeCrashed() {
|
||||
|
@ -253,6 +271,7 @@ void nsFrameLoaderOwner::SubframeCrashed() {
|
|||
}));
|
||||
};
|
||||
|
||||
ChangeRemotenessCommon(ChangeRemotenessContextType::PRESERVE, false,
|
||||
VoidString(), frameLoaderInit, IgnoreErrors());
|
||||
ChangeRemotenessCommon(ChangeRemotenessContextType::PRESERVE,
|
||||
/* inProgress */ false,
|
||||
/* isRemote */ false, frameLoaderInit, IgnoreErrors());
|
||||
}
|
||||
|
|
|
@ -46,23 +46,37 @@ class nsFrameLoaderOwner : public nsISupports {
|
|||
mozilla::dom::BrowsingContext* GetExtantBrowsingContext();
|
||||
|
||||
// Destroy (if it exists) and recreate our frameloader, based on new
|
||||
// remoteness requirements. This should follow the same path as
|
||||
// tabbrowser.js's updateBrowserRemoteness, including running the same logic
|
||||
// and firing the same events as unbinding a XULBrowserElement from the tree.
|
||||
// However, this method is available from backend and does not manipulate the
|
||||
// DOM.
|
||||
// remoteness requirements.
|
||||
//
|
||||
// This method is called by frontend code when it wants to perform a
|
||||
// remoteness update, and allows for behaviour such as preserving
|
||||
// BrowsingContexts across process switches during navigation.
|
||||
//
|
||||
// See the WebIDL definition for more details.
|
||||
void ChangeRemoteness(const mozilla::dom::RemotenessOptions& aOptions,
|
||||
mozilla::ErrorResult& rv);
|
||||
|
||||
// Like `ChangeRemoteness` but switches to an already-created
|
||||
// `BrowserBridgeChild`. This method is used when performing remote subframe
|
||||
// process switches.
|
||||
void ChangeRemotenessWithBridge(mozilla::dom::BrowserBridgeChild* aBridge,
|
||||
mozilla::ErrorResult& rv);
|
||||
|
||||
// Like `ChangeRemoteness`, but switches into an already-created
|
||||
// `ContentParent`. This method is used when performing toplevel process
|
||||
// switches. If `aContentParent` is nullptr, switches into the parent process.
|
||||
//
|
||||
// If `aReplaceBrowsingContext` is set, BrowsingContext preservation will be
|
||||
// disabled for this process switch.
|
||||
void ChangeRemotenessToProcess(mozilla::dom::ContentParent* aContentParent,
|
||||
uint64_t aPendingSwitchId,
|
||||
bool aReplaceBrowsingContext,
|
||||
mozilla::ErrorResult& rv);
|
||||
|
||||
void SubframeCrashed();
|
||||
|
||||
private:
|
||||
bool UseRemoteSubframes();
|
||||
bool ShouldPreserveBrowsingContext(
|
||||
const mozilla::dom::RemotenessOptions& aOptions);
|
||||
|
||||
// The enum class for determine how to handle previous BrowsingContext during
|
||||
// the change remoteness. It could be followings
|
||||
|
@ -78,9 +92,11 @@ class nsFrameLoaderOwner : public nsISupports {
|
|||
DONT_PRESERVE_BUT_PROPAGATE = 1,
|
||||
PRESERVE = 2,
|
||||
};
|
||||
ChangeRemotenessContextType ShouldPreserveBrowsingContext(
|
||||
bool aIsRemote, bool aReplaceBrowsingContext);
|
||||
|
||||
void ChangeRemotenessCommon(const ChangeRemotenessContextType& aContextType,
|
||||
bool aSwitchingInProgressLoad,
|
||||
const nsAString& aRemoteType,
|
||||
bool aSwitchingInProgressLoad, bool aIsRemote,
|
||||
std::function<void()>& aFrameLoaderInit,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
|
|
|
@ -160,6 +160,33 @@ interface nsIBrowser : nsISupports
|
|||
in uint64_t aRequestContextID,
|
||||
in AString aContentType);
|
||||
|
||||
/**
|
||||
* Determine what process switching behavior this browser element should have.
|
||||
*/
|
||||
cenum ProcessBehavior : 8 {
|
||||
// Gecko won't automatically change which process this frame, or it's
|
||||
// subframes, are loaded in.
|
||||
PROCESS_BEHAVIOR_DISABLED,
|
||||
|
||||
// If `useRemoteTabs` is enabled, Gecko will change which process this frame
|
||||
// is loaded in automatically, without calling `performProcessSwitch`.
|
||||
// When `useRemoteSubframes` is enabled, subframes will change processes.
|
||||
PROCESS_BEHAVIOR_STANDARD,
|
||||
|
||||
// When `useRemoteTabs` is enabled, Gecko will call `performProcessSwitch`
|
||||
// in order to change which process this frame is loaded in.
|
||||
// When `useRemoteSubframes` is enabled, subframes will change processes.
|
||||
PROCESS_BEHAVIOR_CUSTOM,
|
||||
|
||||
// Gecko won't automatically change which process this frame is loaded, but
|
||||
// when `useRemoteSubframes` is enabled, subframes will change processes.
|
||||
//
|
||||
// NOTE: This configuration is included only for backwards compatibility,
|
||||
// and will be removed, as it can easily lead to invalid behavior.
|
||||
PROCESS_BEHAVIOR_SUBFRAME_ONLY,
|
||||
};
|
||||
readonly attribute nsIBrowser_ProcessBehavior processSwitchBehavior;
|
||||
|
||||
/**
|
||||
* Called by Gecko when it wants to change the process which is currently
|
||||
* being used to render content in this tab.
|
||||
|
@ -167,6 +194,9 @@ interface nsIBrowser : nsISupports
|
|||
* Returns a promise which will be resolved with the ChildID of the new
|
||||
* process.
|
||||
*
|
||||
* NOTE: This method is only called if `processSwitchBehavior` is
|
||||
* `PROCESS_BEHAVIOR_CUSTOM`.
|
||||
*
|
||||
* @param aRemoteType the new remote type to switch this browser into
|
||||
* @param aPendingSwitchId unique identifier for the ongoing
|
||||
* process-switching load
|
||||
|
@ -177,7 +207,4 @@ interface nsIBrowser : nsISupports
|
|||
Promise performProcessSwitch(in AString aRemoteType,
|
||||
in uint64_t aPendingSwitchId,
|
||||
in boolean aReplaceBrowsingContext);
|
||||
|
||||
/** If `true`, this browser supports the `performProcessSwitch` method */
|
||||
readonly attribute bool canPerformProcessSwitch;
|
||||
};
|
||||
|
|
|
@ -1317,7 +1317,7 @@ already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
|
|||
RefPtr<ContentParent> constructorSender;
|
||||
MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
|
||||
"Cannot allocate BrowserParent in content process");
|
||||
if (aOpenerContentParent) {
|
||||
if (aOpenerContentParent && aOpenerContentParent->IsAlive()) {
|
||||
constructorSender = aOpenerContentParent;
|
||||
} else {
|
||||
if (aContext.IsJSPlugin()) {
|
||||
|
|
|
@ -1118,46 +1118,53 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
|
|||
return false;
|
||||
}
|
||||
|
||||
// We currently can't switch processes for toplevel loads unless they're
|
||||
// loaded within a browser tab.
|
||||
// FIXME: Ideally we won't do this in the future.
|
||||
nsCOMPtr<nsIBrowser> browser;
|
||||
bool isPreloadSwitch = false;
|
||||
if (!browsingContext->GetParent()) {
|
||||
Element* browserElement = browsingContext->GetEmbedderElement();
|
||||
if (!browserElement) {
|
||||
LOG(("Process Switch Abort: cannot get browser element"));
|
||||
return false;
|
||||
}
|
||||
browser = browserElement->AsBrowser();
|
||||
if (!browser) {
|
||||
LOG(("Process Switch Abort: not loaded within nsIBrowser"));
|
||||
return false;
|
||||
}
|
||||
bool loadedInTab = false;
|
||||
if (NS_FAILED(browser->GetCanPerformProcessSwitch(&loadedInTab)) ||
|
||||
!loadedInTab) {
|
||||
LOG(("Process Switch Abort: browser is not loaded in a tab"));
|
||||
return false;
|
||||
}
|
||||
// Determine what process switching behaviour is being requested by the root
|
||||
// <browser> element.
|
||||
Element* browserElement = browsingContext->Top()->GetEmbedderElement();
|
||||
if (!browserElement) {
|
||||
LOG(("Process Switch Abort: cannot get embedder element"));
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIBrowser> browser = browserElement->AsBrowser();
|
||||
if (!browser) {
|
||||
LOG(("Process Switch Abort: not loaded within nsIBrowser"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Leaving about:newtab from a used to be preloaded browser should run the
|
||||
// process selecting algorithm again.
|
||||
nsAutoString isPreloadBrowserStr;
|
||||
if (browserElement->GetAttr(kNameSpaceID_None, nsGkAtoms::preloadedState,
|
||||
isPreloadBrowserStr)) {
|
||||
if (isPreloadBrowserStr.EqualsLiteral("consumed")) {
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
if (NS_SUCCEEDED(
|
||||
mChannel->GetOriginalURI(getter_AddRefs(originalURI)))) {
|
||||
if (!originalURI->GetSpecOrDefault().EqualsLiteral("about:newtab")) {
|
||||
LOG(("Process Switch: leaving preloaded browser"));
|
||||
isPreloadSwitch = true;
|
||||
browserElement->UnsetAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::preloadedState, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
nsIBrowser::ProcessBehavior processBehavior =
|
||||
nsIBrowser::PROCESS_BEHAVIOR_DISABLED;
|
||||
nsresult rv = browser->GetProcessSwitchBehavior(&processBehavior);
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"nsIBrowser::GetProcessSwitchBehavior shouldn't fail");
|
||||
LOG(("Process Switch Abort: failed to get process switch behavior"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the process switch we're considering is disabled by the
|
||||
// <browser>'s process behavior.
|
||||
if (processBehavior == nsIBrowser::PROCESS_BEHAVIOR_DISABLED) {
|
||||
LOG(("Process Switch Abort: switch disabled by <browser>"));
|
||||
return false;
|
||||
}
|
||||
if (browsingContext->IsTop() &&
|
||||
processBehavior == nsIBrowser::PROCESS_BEHAVIOR_SUBFRAME_ONLY) {
|
||||
LOG(("Process Switch Abort: toplevel switch disabled by <browser>"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isPreloadSwitch = false;
|
||||
nsAutoString isPreloadBrowserStr;
|
||||
if (browserElement->GetAttr(kNameSpaceID_None, nsGkAtoms::preloadedState,
|
||||
isPreloadBrowserStr) &&
|
||||
isPreloadBrowserStr.EqualsLiteral("consumed")) {
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
if (NS_SUCCEEDED(mChannel->GetOriginalURI(getter_AddRefs(originalURI))) &&
|
||||
!originalURI->GetSpecOrDefault().EqualsLiteral("about:newtab")) {
|
||||
LOG(("Process Switch: leaving preloaded browser"));
|
||||
isPreloadSwitch = true;
|
||||
browserElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::preloadedState,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1173,7 +1180,7 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
|
|||
|
||||
// Get the final principal, used to select which process to load into.
|
||||
nsCOMPtr<nsIPrincipal> resultPrincipal;
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
|
||||
rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
|
||||
mChannel, getter_AddRefs(resultPrincipal));
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Process Switch Abort: failed to get channel result principal"));
|
||||
|
@ -1267,21 +1274,26 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
|
|||
mDoingProcessSwitch = true;
|
||||
|
||||
RefPtr<DocumentLoadListener> self = this;
|
||||
// At this point, we're actually going to perform a process switch, which
|
||||
// involves calling into other logic.
|
||||
if (browsingContext->GetParent()) {
|
||||
LOG(("Process Switch: Calling ChangeFrameRemoteness"));
|
||||
// If we're switching a subframe, ask BrowsingContext to do it for us.
|
||||
MOZ_ASSERT(!isCOOPSwitch);
|
||||
browsingContext
|
||||
->ChangeFrameRemoteness(remoteType, mCrossProcessRedirectIdentifier)
|
||||
|
||||
// If <browser> has custom process switching behaviour, use that.
|
||||
if (processBehavior == nsIBrowser::PROCESS_BEHAVIOR_CUSTOM &&
|
||||
browsingContext->IsTop()) {
|
||||
LOG(("Process Switch: Calling nsIBrowser::PerformProcessSwitch"));
|
||||
// We're switching a toplevel BrowsingContext's process. This has to be done
|
||||
// using nsIBrowser.
|
||||
RefPtr<dom::Promise> domPromise;
|
||||
browser->PerformProcessSwitch(remoteType, mCrossProcessRedirectIdentifier,
|
||||
isCOOPSwitch, getter_AddRefs(domPromise));
|
||||
MOZ_DIAGNOSTIC_ASSERT(domPromise,
|
||||
"PerformProcessSwitch didn't return a promise");
|
||||
|
||||
MozPromise<uint64_t, nsresult, true>::FromDomPromise(domPromise)
|
||||
->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self](BrowserParent* aBrowserParent) {
|
||||
[self](uint64_t aCpId) {
|
||||
MOZ_ASSERT(self->mChannel,
|
||||
"Something went wrong, channel got cancelled");
|
||||
self->TriggerRedirectToRealChannel(
|
||||
Some(aBrowserParent->Manager()->ChildID()));
|
||||
self->TriggerRedirectToRealChannel(Some(aCpId));
|
||||
},
|
||||
[self](nsresult aStatusCode) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error");
|
||||
|
@ -1290,22 +1302,17 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
|
|||
return true;
|
||||
}
|
||||
|
||||
LOG(("Process Switch: Calling nsIBrowser::PerformProcessSwitch"));
|
||||
// We're switching a toplevel BrowsingContext's process. This has to be done
|
||||
// using nsIBrowser.
|
||||
RefPtr<dom::Promise> domPromise;
|
||||
browser->PerformProcessSwitch(remoteType, mCrossProcessRedirectIdentifier,
|
||||
isCOOPSwitch, getter_AddRefs(domPromise));
|
||||
MOZ_DIAGNOSTIC_ASSERT(domPromise,
|
||||
"PerformProcessSwitch didn't return a promise");
|
||||
|
||||
MozPromise<uint64_t, nsresult, true>::FromDomPromise(domPromise)
|
||||
LOG(("Process Switch: Calling ChangeRemoteness"));
|
||||
browsingContext
|
||||
->ChangeRemoteness(remoteType, mCrossProcessRedirectIdentifier,
|
||||
isCOOPSwitch)
|
||||
->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self](uint64_t aCpId) {
|
||||
[self](BrowserParent* aBrowserParent) {
|
||||
MOZ_ASSERT(self->mChannel,
|
||||
"Something went wrong, channel got cancelled");
|
||||
self->TriggerRedirectToRealChannel(Some(aCpId));
|
||||
self->TriggerRedirectToRealChannel(
|
||||
Some(aBrowserParent->Manager()->ChildID()));
|
||||
},
|
||||
[self](nsresult aStatusCode) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error");
|
||||
|
|
|
@ -1946,8 +1946,29 @@
|
|||
return origins;
|
||||
}
|
||||
|
||||
get canPerformProcessSwitch() {
|
||||
return this.getTabBrowser() != null;
|
||||
get processSwitchBehavior() {
|
||||
// If a `remotenessChangeHandler` is attached to this browser, it supports
|
||||
// having its toplevel process switched dynamically in response to
|
||||
// navigations.
|
||||
if (this.hasAttribute("maychangeremoteness")) {
|
||||
return Ci.nsIBrowser.PROCESS_BEHAVIOR_STANDARD;
|
||||
}
|
||||
|
||||
// When loaded in a TabBrowser, use the custom behavior from
|
||||
// `performProcessSwitch`.
|
||||
if (this.getTabBrowser() != null) {
|
||||
return Ci.nsIBrowser.PROCESS_BEHAVIOR_CUSTOM;
|
||||
}
|
||||
|
||||
// For backwards compatibility, we need to mark remote, but
|
||||
// non-`allowremote`, frames as `PROCESS_BEHAVIOR_SUBFRAME_ONLY`, as some
|
||||
// tests rely on it.
|
||||
// FIXME: Remove this?
|
||||
if (this.isRemoteBrowser) {
|
||||
return Ci.nsIBrowser.PROCESS_BEHAVIOR_SUBFRAME_ONLY;
|
||||
}
|
||||
// Otherwise, don't allow gecko-initiated toplevel process switches.
|
||||
return Ci.nsIBrowser.PROCESS_BEHAVIOR_DISABLED;
|
||||
}
|
||||
|
||||
performProcessSwitch(
|
||||
|
|
Загрузка…
Ссылка в новой задаче