Bug 1696158 - Move CanSavePresentation to the parent process. Do CanSavePresentation check completely in parent. r=smaug,nika

Differential Revision: https://phabricator.services.mozilla.com/D110234
This commit is contained in:
Peter Van der Beken 2021-04-19 14:50:56 +00:00
Родитель 1c8872c7e2
Коммит 302c37978b
7 изменённых файлов: 204 добавлений и 150 удалений

Просмотреть файл

@ -25,6 +25,7 @@
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/net/DocumentLoadListener.h"
#include "mozilla/NullPrincipal.h"
#include "mozilla/StaticPrefs_docshell.h"
#include "mozilla/StaticPrefs_fission.h"
#include "nsIWebNavigation.h"
#include "mozilla/MozPromiseInlines.h"
@ -51,6 +52,7 @@ using namespace mozilla::ipc;
extern mozilla::LazyLogModule gAutoplayPermissionLog;
extern mozilla::LazyLogModule gSHLog;
extern mozilla::LazyLogModule gSHIPBFCacheLog;
#define AUTOPLAY_LOG(msg, ...) \
MOZ_LOG(gAutoplayPermissionLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
@ -2050,6 +2052,117 @@ void CanonicalBrowsingContext::ShowSubframeCrashedUI(
Unused << aBridge->SendSubFrameCrashed();
}
static void LogBFCacheBlockingForDoc(BrowsingContext* aBrowsingContext,
uint16_t aBFCacheCombo, bool aIsSubDoc) {
if (aIsSubDoc) {
nsAutoCString uri("[no uri]");
nsCOMPtr<nsIURI> currentURI =
aBrowsingContext->Canonical()->GetCurrentURI();
if (currentURI) {
uri = currentURI->GetSpecOrDefault();
}
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
(" ** Blocked for document %s", uri.get()));
}
if (aBFCacheCombo & BFCacheStatus::EVENT_HANDLING_SUPPRESSED) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
(" * event handling suppression"));
}
if (aBFCacheCombo & BFCacheStatus::SUSPENDED) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, (" * suspended Window"));
}
if (aBFCacheCombo & BFCacheStatus::UNLOAD_LISTENER) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
(" * beforeunload or unload listener"));
}
if (aBFCacheCombo & BFCacheStatus::REQUEST) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, (" * requests in the loadgroup"));
}
if (aBFCacheCombo & BFCacheStatus::ACTIVE_GET_USER_MEDIA) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, (" * GetUserMedia"));
}
if (aBFCacheCombo & BFCacheStatus::ACTIVE_PEER_CONNECTION) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, (" * PeerConnection"));
}
if (aBFCacheCombo & BFCacheStatus::CONTAINS_EME_CONTENT) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, (" * EME content"));
}
if (aBFCacheCombo & BFCacheStatus::CONTAINS_MSE_CONTENT) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, (" * MSE use"));
}
if (aBFCacheCombo & BFCacheStatus::HAS_ACTIVE_SPEECH_SYNTHESIS) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, (" * Speech use"));
}
if (aBFCacheCombo & BFCacheStatus::HAS_USED_VR) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, (" * used VR"));
}
}
bool CanonicalBrowsingContext::AllowedInBFCache(
const Maybe<uint64_t>& aChannelId) {
if (MOZ_UNLIKELY(MOZ_LOG_TEST(gSHIPBFCacheLog, LogLevel::Debug))) {
nsAutoCString uri("[no uri]");
nsCOMPtr<nsIURI> currentURI = GetCurrentURI();
if (currentURI) {
uri = currentURI->GetSpecOrDefault();
}
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug, ("Checking %s", uri.get()));
}
if (IsInProcess()) {
return false;
}
uint16_t bfcacheCombo = 0;
if (Group()->Toplevels().Length() > 1) {
bfcacheCombo |= BFCacheStatus::NOT_ONLY_TOPLEVEL_IN_BCG;
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
(" * auxiliary BrowsingContexts"));
}
// For telemetry we're collecting all the flags for all the BCs hanging
// from this top-level BC.
PreOrderWalk([&](BrowsingContext* aBrowsingContext) {
WindowGlobalParent* wgp =
aBrowsingContext->Canonical()->GetCurrentWindowGlobal();
uint16_t subDocBFCacheCombo = wgp ? wgp->GetBFCacheStatus() : 0;
if (wgp) {
const Maybe<uint64_t>& singleChannelId = wgp->GetSingleChannelId();
if (singleChannelId.isSome()) {
if (singleChannelId.value() == 0 || aChannelId.isNothing() ||
singleChannelId.value() != aChannelId.value()) {
subDocBFCacheCombo |= BFCacheStatus::REQUEST;
}
}
}
if (MOZ_UNLIKELY(MOZ_LOG_TEST(gSHIPBFCacheLog, LogLevel::Debug))) {
LogBFCacheBlockingForDoc(aBrowsingContext, subDocBFCacheCombo,
aBrowsingContext != this);
}
bfcacheCombo |= subDocBFCacheCombo;
});
nsDocShell::ReportBFCacheComboTelemetry(bfcacheCombo);
if (MOZ_UNLIKELY(MOZ_LOG_TEST(gSHIPBFCacheLog, LogLevel::Debug))) {
nsAutoCString uri("[no uri]");
nsCOMPtr<nsIURI> currentURI = GetCurrentURI();
if (currentURI) {
uri = currentURI->GetSpecOrDefault();
}
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
(" +> %s %s be blocked from going into the BFCache", uri.get(),
bfcacheCombo == 0 ? "shouldn't" : "should"));
}
if (StaticPrefs::docshell_shistory_bfcache_allow_unload_listeners()) {
bfcacheCombo &= ~BFCacheStatus::UNLOAD_LISTENER;
}
return bfcacheCombo == 0;
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(CanonicalBrowsingContext, BrowsingContext,
mSessionHistory, mContainerFeaturePolicy,
mCurrentBrowserParent)

Просмотреть файл

@ -297,6 +297,8 @@ class CanonicalBrowsingContext final : public BrowsingContext {
void StartUnloadingHost(uint64_t aChildID);
void ClearUnloadingHost(uint64_t aChildID);
bool AllowedInBFCache(const Maybe<uint64_t>& aChannelId);
protected:
// Called when the browsing context is being discarded.
void CanonicalDiscard();

Просмотреть файл

@ -6992,6 +6992,7 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType,
return doc && canSavePresentation;
}
/* static */
void nsDocShell::ReportBFCacheComboTelemetry(uint16_t aCombo) {
// There are 11 possible reasons to make a request fails to use BFCache
// (see BFCacheStatus in dom/base/Document.h), and we'd like to record

Просмотреть файл

@ -717,8 +717,6 @@ class nsDocShell final : public nsDocLoader,
nsIContentSecurityPolicy* aCsp, bool aFireOnLocationChange,
bool aAddToGlobalHistory, bool aCloneSHChildren);
void RecordSingleChannelId();
public:
// Helper method that is called when a new document (including any
// sub-documents - ie. frames) has been completely loaded.
@ -865,7 +863,7 @@ class nsDocShell final : public nsDocLoader,
bool CanSavePresentation(uint32_t aLoadType, nsIRequest* aNewRequest,
mozilla::dom::Document* aNewDocument);
void ReportBFCacheComboTelemetry(uint16_t aCombo);
static void ReportBFCacheComboTelemetry(uint16_t aCombo);
// Captures the state of the supporting elements of the presentation
// (the "window" object, docshell tree, meta-refresh loads, and security
@ -1085,6 +1083,8 @@ class nsDocShell final : public nsDocLoader,
bool ShouldOpenInBlankTarget(const nsAString& aOriginalTarget,
nsIURI* aLinkURI, nsIContent* aContent);
void RecordSingleChannelId();
private: // data members
nsString mTitle;
nsCString mOriginalUriString;

Просмотреть файл

@ -1189,49 +1189,50 @@ static void FinishRestore(CanonicalBrowsingContext* aBrowsingContext,
MOZ_ASSERT(aEntry);
MOZ_ASSERT(aFrameLoader);
aEntry->SetFrameLoader(nullptr);
nsCOMPtr<nsFrameLoaderOwner> frameLoaderOwner =
do_QueryInterface(aBrowsingContext->GetEmbedderElement());
if (frameLoaderOwner) {
aEntry->SetFrameLoader(nullptr);
if (aFrameLoader->GetMaybePendingBrowsingContext()) {
RefPtr<CanonicalBrowsingContext> loadingBC =
aFrameLoader->GetMaybePendingBrowsingContext()->Canonical();
RefPtr<nsFrameLoader> currentFrameLoader =
frameLoaderOwner->GetFrameLoader();
// The current page can be bfcached, store the
// nsFrameLoader in the current SessionHistoryEntry.
if (aCanSave && aBrowsingContext->GetActiveSessionHistoryEntry()) {
aBrowsingContext->GetActiveSessionHistoryEntry()->SetFrameLoader(
currentFrameLoader);
Unused << aBrowsingContext->SetIsInBFCache(true);
}
// ReplacedBy will swap the entry back.
aBrowsingContext->SetActiveSessionHistoryEntry(aEntry);
loadingBC->SetActiveSessionHistoryEntry(nullptr);
RemotenessChangeOptions options;
aBrowsingContext->ReplacedBy(loadingBC, options);
frameLoaderOwner->ReplaceFrameLoader(aFrameLoader);
// The old page can't be stored in the bfcache,
// destroy the nsFrameLoader.
if (!aCanSave && currentFrameLoader) {
currentFrameLoader->Destroy();
}
// Assuming we still have the session history, update the index.
if (loadingBC->GetSessionHistory()) {
loadingBC->GetSessionHistory()->UpdateIndex();
}
loadingBC->HistoryCommitIndexAndLength();
Unused << loadingBC->SetIsInBFCache(false);
// ResetSHEntryHasUserInteractionCache(); ?
// browser.navigation.requireUserInteraction is still
// disabled everywhere.
return;
if (frameLoaderOwner && aFrameLoader->GetMaybePendingBrowsingContext()) {
RefPtr<CanonicalBrowsingContext> loadingBC =
aFrameLoader->GetMaybePendingBrowsingContext()->Canonical();
RefPtr<nsFrameLoader> currentFrameLoader =
frameLoaderOwner->GetFrameLoader();
// The current page can be bfcached, store the
// nsFrameLoader in the current SessionHistoryEntry.
if (aCanSave && aBrowsingContext->GetActiveSessionHistoryEntry()) {
aBrowsingContext->GetActiveSessionHistoryEntry()->SetFrameLoader(
currentFrameLoader);
Unused << aBrowsingContext->SetIsInBFCache(true);
}
// ReplacedBy will swap the entry back.
aBrowsingContext->SetActiveSessionHistoryEntry(aEntry);
loadingBC->SetActiveSessionHistoryEntry(nullptr);
RemotenessChangeOptions options;
aBrowsingContext->ReplacedBy(loadingBC, options);
frameLoaderOwner->ReplaceFrameLoader(aFrameLoader);
// The old page can't be stored in the bfcache,
// destroy the nsFrameLoader.
if (!aCanSave && currentFrameLoader) {
currentFrameLoader->Destroy();
}
// Assuming we still have the session history, update the index.
if (loadingBC->GetSessionHistory()) {
loadingBC->GetSessionHistory()->UpdateIndex();
}
loadingBC->HistoryCommitIndexAndLength();
Unused << loadingBC->SetIsInBFCache(false);
// ResetSHEntryHasUserInteractionCache(); ?
// browser.navigation.requireUserInteraction is still
// disabled everywhere.
return;
}
aFrameLoader->Destroy();
// Fall back to do a normal load.
aBrowsingContext->LoadURI(aLoadState, false);
}
@ -1248,82 +1249,52 @@ void nsSHistory::LoadURIOrBFCache(LoadEntryResult& aLoadEntry) {
canonicalBC->GetActiveSessionHistoryEntry();
MOZ_ASSERT(she);
RefPtr<nsFrameLoader> frameLoader = she->GetFrameLoader();
if (canonicalBC->Group()->Toplevels().Length() == 1 && frameLoader &&
if (frameLoader &&
(!currentShe || she->SharedInfo() != currentShe->SharedInfo())) {
auto restoreInitialStep = [canonicalBC, loadState, she,
frameLoader](const nsTArray<bool> aCanSaves) {
bool canSave = !aCanSaves.Contains(false);
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
("nsSHistory::LoadURIOrBFCache "
"saving presentation=%i",
canSave));
bool canSave = (!currentShe || currentShe->GetSaveLayoutStateFlag()) &&
canonicalBC->AllowedInBFCache(Nothing());
if (!canSave) {
nsCOMPtr<nsFrameLoaderOwner> frameLoaderOwner =
do_QueryInterface(canonicalBC->GetEmbedderElement());
if (frameLoaderOwner) {
RefPtr<nsFrameLoader> currentFrameLoader =
frameLoaderOwner->GetFrameLoader();
if (currentFrameLoader &&
currentFrameLoader->GetMaybePendingBrowsingContext()) {
WindowGlobalParent* wgp =
currentFrameLoader->GetMaybePendingBrowsingContext()
->Canonical()
->GetCurrentWindowGlobal();
if (wgp) {
wgp->PermitUnload([canonicalBC, loadState, she, frameLoader,
currentFrameLoader](bool aAllow) {
if (aAllow) {
FinishRestore(canonicalBC, loadState, she, frameLoader,
false);
} else if (currentFrameLoader
->GetMaybePendingBrowsingContext()) {
nsISHistory* shistory =
currentFrameLoader->GetMaybePendingBrowsingContext()
->Canonical()
->GetSessionHistory();
if (shistory) {
shistory->InternalSetRequestedIndex(-1);
}
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
("nsSHistory::LoadURIOrBFCache "
"saving presentation=%i",
canSave));
if (!canSave) {
nsCOMPtr<nsFrameLoaderOwner> frameLoaderOwner =
do_QueryInterface(canonicalBC->GetEmbedderElement());
if (frameLoaderOwner) {
RefPtr<nsFrameLoader> currentFrameLoader =
frameLoaderOwner->GetFrameLoader();
if (currentFrameLoader &&
currentFrameLoader->GetMaybePendingBrowsingContext()) {
WindowGlobalParent* wgp =
currentFrameLoader->GetMaybePendingBrowsingContext()
->Canonical()
->GetCurrentWindowGlobal();
if (wgp) {
wgp->PermitUnload([canonicalBC, loadState, she, frameLoader,
currentFrameLoader](bool aAllow) {
if (aAllow) {
FinishRestore(canonicalBC, loadState, she, frameLoader,
false);
} else if (currentFrameLoader
->GetMaybePendingBrowsingContext()) {
nsISHistory* shistory =
currentFrameLoader->GetMaybePendingBrowsingContext()
->Canonical()
->GetSessionHistory();
if (shistory) {
shistory->InternalSetRequestedIndex(-1);
}
});
return;
}
}
});
return;
}
}
}
FinishRestore(canonicalBC, loadState, she, frameLoader, canSave);
};
if (currentShe && !currentShe->GetSaveLayoutStateFlag()) {
// Current page can't enter bfcache because of
// SaveLayoutStateFlag, just run the restore immediately.
nsTArray<bool> canSaves;
canSaves.AppendElement(false);
restoreInitialStep(std::move(canSaves));
return;
}
nsTArray<RefPtr<PContentParent::CanSavePresentationPromise>>
canSavePromises;
canonicalBC->Group()->EachParent([&](ContentParent* aParent) {
RefPtr<PContentParent::CanSavePresentationPromise> canSave =
aParent->SendCanSavePresentation(canonicalBC, Nothing());
canSavePromises.AppendElement(canSave);
});
// Check if the current page can enter bfcache.
PContentParent::CanSavePresentationPromise::All(
GetCurrentSerialEventTarget(), canSavePromises)
->Then(GetMainThreadSerialEventTarget(), __func__,
std::move(restoreInitialStep),
[canonicalBC, loadState](mozilla::ipc::ResponseRejectReason) {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
("nsSHistory::LoadURIOrBFCache "
"error in trying to save presentation"));
canonicalBC->LoadURI(loadState, false);
});
FinishRestore(canonicalBC, loadState, she, frameLoader, canSave);
return;
}
if (frameLoader) {

Просмотреть файл

@ -215,6 +215,8 @@ class WindowGlobalParent final : public WindowContext,
Maybe<uint64_t> GetSingleChannelId() { return mSingleChannelId; }
uint16_t GetBFCacheStatus() { return mBFCacheStatus; }
protected:
already_AddRefed<JSActor> InitJSActor(JS::HandleObject aMaybeActor,
const nsACString& aName,

Просмотреть файл

@ -1709,7 +1709,6 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
if (mozilla::BFCacheInParent() && nsSHistory::GetMaxTotalViewers() > 0 &&
!parentWindow && !browsingContext->HadOriginalOpener() &&
browsingContext->Group()->Toplevels().Length() == 1 &&
!options.mRemoteType.IsEmpty() &&
browsingContext->GetHasLoadedNonInitialDocument() &&
(mLoadStateLoadType == LOAD_NORMAL ||
@ -1719,8 +1718,12 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
(!browsingContext->GetActiveSessionHistoryEntry() ||
browsingContext->GetActiveSessionHistoryEntry()
->GetSaveLayoutStateFlag())) {
options.mReplaceBrowsingContext = true;
options.mTryUseBFCache = true;
MOZ_ASSERT(mIsDocumentLoad);
options.mTryUseBFCache =
browsingContext->AllowedInBFCache(mDocumentChannelId);
if (options.mTryUseBFCache) {
options.mReplaceBrowsingContext = true;
}
}
LOG(("GetRemoteTypeForPrincipal -> current:%s remoteType:%s",
@ -1744,44 +1747,6 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
// If we're doing a document load, we can immediately perform a process
// switch.
if (mIsDocumentLoad) {
if (options.mTryUseBFCache && wgp) {
if (RefPtr<BrowserParent> browserParent = wgp->GetBrowserParent()) {
nsTArray<RefPtr<PContentParent::CanSavePresentationPromise>>
canSavePromises;
browsingContext->Group()->EachParent([&](ContentParent* aParent) {
RefPtr<PContentParent::CanSavePresentationPromise> canSave =
aParent->SendCanSavePresentation(browsingContext,
mDocumentChannelId);
canSavePromises.AppendElement(canSave);
});
PContentParent::CanSavePresentationPromise::All(
GetCurrentSerialEventTarget(), canSavePromises)
->Then(
GetMainThreadSerialEventTarget(), __func__,
[self = RefPtr{this}, browsingContext,
options](const nsTArray<bool> aCanSaves) mutable {
bool canSave = !aCanSaves.Contains(false);
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
("DocumentLoadListener::MaybeTriggerProcessSwitch "
"saving presentation=%i",
canSave));
options.mTryUseBFCache = canSave;
self->TriggerProcessSwitch(browsingContext, options);
},
[self = RefPtr{this}, browsingContext,
options](ipc::ResponseRejectReason) mutable {
MOZ_LOG(gSHIPBFCacheLog, LogLevel::Debug,
("DocumentLoadListener::MaybeTriggerProcessSwitch "
"error in trying to save presentation"));
options.mTryUseBFCache = false;
self->TriggerProcessSwitch(browsingContext, options);
});
return true;
}
}
options.mTryUseBFCache = false;
TriggerProcessSwitch(browsingContext, options);
return true;
}