Skip to content

Commit

Permalink
Bug 1696158 - Move CanSavePresentation to the parent process. Do CanS…
Browse files Browse the repository at this point in the history
…avePresentation check completely in parent. r=smaug,nika

Differential Revision: https://phabricator.services.mozilla.com/D110234
  • Loading branch information
petervanderbeken committed Apr 19, 2021
1 parent c64d406 commit e747b7a
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 149 deletions.
113 changes: 113 additions & 0 deletions docshell/base/CanonicalBrowsingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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__))
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions docshell/base/CanonicalBrowsingContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions docshell/base/nsDocShell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions docshell/base/nsDocShell.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
181 changes: 76 additions & 105 deletions docshell/shistory/nsSHistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
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();
}
// 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;
// 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);
}
Expand All @@ -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));

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);
}
bool canSave = (!currentShe || currentShe->GetSaveLayoutStateFlag()) &&
canonicalBC->AllowedInBFCache(Nothing());

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) {
Expand Down
2 changes: 2 additions & 0 deletions dom/ipc/WindowGlobalParent.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit e747b7a

Please sign in to comment.