blob: cb2bf86716438b1a9760d536c8cc08a7014c86f7 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/back_forward_cache_metrics.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/metrics_hashes.h"
#include "base/metrics/sparse_histogram.h"
#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/browser/renderer_host/back_forward_cache_impl.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/navigation_request.h"
#include "content/browser/renderer_host/should_swap_browsing_instance.h"
#include "content/browser/site_instance_impl.h"
#include "content/common/debug_utils.h"
#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/reload_type.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
#include "ui/accessibility/ax_event.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace {
// Overridden time for unit tests. Should be accessed only from the main thread.
base::TickClock* g_mock_time_clock_for_testing = nullptr;
// Reduce the resolution of the longer intervals due to privacy considerations.
base::TimeDelta ClampTime(base::TimeDelta time) {
if (time < base::Seconds(5))
return base::Milliseconds(time.InMilliseconds());
if (time < base::Minutes(3))
return base::Seconds(time.InSeconds());
if (time < base::Hours(3))
return base::Minutes(time.InMinutes());
return base::Hours(time.InHours());
}
base::TimeTicks Now() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (g_mock_time_clock_for_testing)
return g_mock_time_clock_for_testing->NowTicks();
return base::TimeTicks::Now();
}
} // namespace
// static
void BackForwardCacheMetrics::OverrideTimeForTesting(base::TickClock* clock) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
g_mock_time_clock_for_testing = clock;
}
// static
bool BackForwardCacheMetrics::IsCrossDocumentMainFrameHistoryNavigation(
NavigationRequest* navigation) {
return navigation->IsInPrimaryMainFrame() && !navigation->IsSameDocument() &&
navigation->GetPageTransition() & ui::PAGE_TRANSITION_FORWARD_BACK;
}
// static
scoped_refptr<BackForwardCacheMetrics>
BackForwardCacheMetrics::CreateOrReuseBackForwardCacheMetricsForNavigation(
NavigationEntryImpl* previous_entry,
bool is_main_frame_navigation,
int64_t committing_document_sequence_number) {
if (!previous_entry) {
// There is no previous NavigationEntry, so we must create a new metrics
// object.
return base::WrapRefCounted(new BackForwardCacheMetrics(
is_main_frame_navigation ? committing_document_sequence_number : -1));
}
BackForwardCacheMetrics* previous_entry_metrics =
previous_entry->back_forward_cache_metrics();
if (!previous_entry_metrics) {
// It's possible to encounter a `previous_entry` without metrics, e.g. on
// session restore. We will have to create a new metrics object for the main
// document.
return base::WrapRefCounted(new BackForwardCacheMetrics(
is_main_frame_navigation
? committing_document_sequence_number
: previous_entry->root_node()
->frame_entry->document_sequence_number()));
}
// Reuse `previous_entry_metrics` on subframe navigations and same-document
// navigations.
if (!is_main_frame_navigation ||
committing_document_sequence_number ==
previous_entry_metrics->document_sequence_number_) {
return previous_entry_metrics;
}
return base::WrapRefCounted(
new BackForwardCacheMetrics(committing_document_sequence_number));
}
BackForwardCacheMetrics::BackForwardCacheMetrics(
int64_t document_sequence_number)
: document_sequence_number_(document_sequence_number),
page_store_result_(
std::make_unique<BackForwardCacheCanStoreDocumentResult>()) {}
BackForwardCacheMetrics::~BackForwardCacheMetrics() = default;
void BackForwardCacheMetrics::MainFrameDidStartNavigationToDocument() {
if (!started_navigation_timestamp_)
started_navigation_timestamp_ = Now();
}
void BackForwardCacheMetrics::DidCommitNavigation(
NavigationRequest* navigation,
bool back_forward_cache_allowed) {
// Back-forward cache in enabled only for primary frame trees, so we need to
// record metrics only for primary main frame navigations.
if (!navigation->IsInPrimaryMainFrame() || navigation->IsSameDocument())
return;
// Record metrics for reloads after history navigation, if applicable.
RecordHistogramForReloadsAfterHistoryNavigations(
navigation->GetReloadType() != ReloadType::NONE,
back_forward_cache_allowed);
// Record metrics for history navigation, if applicable.
if (IsCrossDocumentMainFrameHistoryNavigation(navigation)) {
// We have to update not restored reasons even though we already did in
// |SendCommitNavigation()|, because the NavigationEntry and
// the BackForwardCacheMetrics object might not exist anymore, e.g. when the
// NavigationEntry got pruned by another navigation committing before the
// history navigation committed.
UpdateNotRestoredReasonsForNavigation(navigation);
bool can_restore = page_store_result_->CanRestore();
bool did_store = navigation->IsServedFromBackForwardCache();
DCHECK_EQ(can_restore, did_store) << page_store_result_->ToString();
// If a navigation serves the result from back/forward cache, then it must
// not have logged any NotRestoredReasons. Also if it is not restored from
// back/forward cache, the logged reasons must match the actual condition of
// the navigation and other logged data.
bool served_from_bfcache_not_match =
did_store && !page_store_result_->not_restored_reasons().Empty();
bool browsing_instance_not_swapped_not_match =
page_store_result_->HasNotRestoredReason(
NotRestoredReason::kBrowsingInstanceNotSwapped) &&
DidSwapBrowsingInstance();
bool disable_for_rfh_not_match =
page_store_result_->HasNotRestoredReason(
NotRestoredReason::kDisableForRenderFrameHostCalled) &&
page_store_result_->disabled_reasons().size() == 0;
bool blocklisted_features_not_match =
page_store_result_->HasNotRestoredReason(
NotRestoredReason::kBlocklistedFeatures) &&
page_store_result_->blocklisted_features().Empty();
if (served_from_bfcache_not_match ||
browsing_instance_not_swapped_not_match || disable_for_rfh_not_match ||
blocklisted_features_not_match) {
CaptureTraceForNavigationDebugScenario(
DebugScenario::kDebugBackForwardCacheMetricsMismatch);
}
// TODO(https://crbug.com/1338089): Remove this.
if (served_from_bfcache_not_match) {
SCOPED_CRASH_KEY_BOOL("BFCacheMismatch", "did_store", did_store);
SCOPED_CRASH_KEY_BOOL("BFCacheMismatch", "can_restore", can_restore);
SCOPED_CRASH_KEY_NUMBER(
"BFCacheMismatch", "not_restored",
page_store_result_->not_restored_reasons().ToEnumBitmask());
SCOPED_CRASH_KEY_NUMBER(
"BFCacheMismatch", "bi_swap",
page_store_result_->browsing_instance_swap_result().has_value()
? static_cast<int>(
page_store_result_->browsing_instance_swap_result().value())
: -1);
SCOPED_CRASH_KEY_NUMBER(
"BFCacheMismatch", "blocklisted",
page_store_result_->blocklisted_features().ToEnumBitmask());
SCOPED_CRASH_KEY_NUMBER("BFCacheMismatch", "disabled",
page_store_result_->disabled_reasons().size());
SCOPED_CRASH_KEY_NUMBER(
"BFCacheMismatch", "disallow_activation",
page_store_result_->disallow_activation_reasons().size());
SCOPED_CRASH_KEY_NUMBER("BFCacheMismatch", "restore_type",
static_cast<int>(navigation->GetRestoreType()));
SCOPED_CRASH_KEY_NUMBER("BFCacheMismatch", "reload_type",
static_cast<int>(navigation->GetReloadType()));
SCOPED_CRASH_KEY_STRING256("BFCacheMismatch", "url",
navigation->GetURL().spec());
SCOPED_CRASH_KEY_STRING256(
"BFCacheMismatch", "previous_url",
navigation->GetPreviousPrimaryMainFrameURL().spec());
// base::debug::DumpWithoutCrashing();
}
TRACE_EVENT1("navigation", "HistoryNavigationOutcome", "outcome",
page_store_result_->ToString());
RecordHistoryNavigationUMA(navigation, back_forward_cache_allowed);
RecordHistoryNavigationUKM(navigation);
if (!navigation->IsServedFromBackForwardCache()) {
devtools_instrumentation::BackForwardCacheNotUsed(
navigation, page_store_result_.get(), page_store_tree_result_.get());
}
if (test_observer_) {
// This is for reporting |page_store_tree_result_| for testing.
test_observer_->NotifyNotRestoredReasons(
std::move(page_store_tree_result_));
}
}
// Save the information about the last cross-document main frame navigation
// that uses this metrics object.
previous_navigation_is_served_from_bfcache_ =
navigation->IsServedFromBackForwardCache();
previous_navigation_is_history_ =
IsCrossDocumentMainFrameHistoryNavigation(navigation);
last_committed_cross_document_main_frame_navigation_id_ =
navigation->GetNavigationId();
// BackForwardCacheMetrics can be reused in some cases. Reset fields for UKM
// for the next navigation.
page_store_result_ =
std::make_unique<BackForwardCacheCanStoreDocumentResult>();
page_store_tree_result_ = nullptr;
navigated_away_from_main_document_timestamp_ = absl::nullopt;
started_navigation_timestamp_ = absl::nullopt;
renderer_killed_timestamp_ = absl::nullopt;
browsing_instance_swap_result_ = absl::nullopt;
}
namespace {
void RecordDisabledForRenderFrameHostReasonUKM(ukm::SourceId source_id,
uint64_t reason) {
ukm::builders::BackForwardCacheDisabledForRenderFrameHostReason(source_id)
.SetReason2(reason)
.Record(ukm::UkmRecorder::Get());
}
} // namespace
void BackForwardCacheMetrics::RecordHistoryNavigationUKM(
NavigationRequest* navigation) {
DCHECK(IsCrossDocumentMainFrameHistoryNavigation(navigation));
// We've visited an entry associated with this main frame document before,
// so record metrics to determine whether it might be a back-forward cache
// hit.
ukm::SourceId source_id = ukm::ConvertToSourceId(
navigation->GetNavigationId(), ukm::SourceIdType::NAVIGATION_ID);
ukm::builders::HistoryNavigation builder(source_id);
if (last_committed_cross_document_main_frame_navigation_id_ != -1) {
// Only record `last_committed_cross_document_main_frame_navigation_id_`
// when it's set. It won't be set if the NavigationEntry this history
// navigation is targeting hasn't been navigated to in this session (e.g.
// due to session restore or cloning a tab).
builder.SetLastCommittedCrossDocumentNavigationSourceIdForTheSameDocument(
ukm::ConvertToSourceId(
last_committed_cross_document_main_frame_navigation_id_,
ukm::SourceIdType::NAVIGATION_ID));
}
builder.SetMainFrameFeatures(main_frame_features_.ToEnumBitmask());
builder.SetSameOriginSubframesFeatures(
same_origin_frames_features_.ToEnumBitmask());
builder.SetCrossOriginSubframesFeatures(
cross_origin_frames_features_.ToEnumBitmask());
// DidStart notification might be missing for some same-document
// navigations. It's good that we don't care about the time in the cache
// in that case.
if (started_navigation_timestamp_ &&
navigated_away_from_main_document_timestamp_) {
builder.SetTimeSinceNavigatedAwayFromDocument(
ClampTime(started_navigation_timestamp_.value() -
navigated_away_from_main_document_timestamp_.value())
.InMilliseconds());
}
builder.SetBackForwardCache_IsServedFromBackForwardCache(
navigation->IsServedFromBackForwardCache());
builder.SetBackForwardCache_NotRestoredReasons(
page_store_result_->not_restored_reasons().ToEnumBitmask());
builder.SetBackForwardCache_BlocklistedFeatures(
page_store_result_->blocklisted_features().ToEnumBitmask());
if (browsing_instance_swap_result_) {
builder.SetBackForwardCache_BrowsingInstanceNotSwappedReason(
static_cast<int64_t>(browsing_instance_swap_result_.value()));
}
builder.SetBackForwardCache_DisabledForRenderFrameHostReasonCount(
page_store_result_->disabled_reasons().size());
builder.Record(ukm::UkmRecorder::Get());
for (const auto& [reason, associated_source_ids] :
page_store_result_->disabled_reasons()) {
uint64_t reason_value = MetricValue(reason);
// We always record the event under the source id that was obtained from
// the navigation.
RecordDisabledForRenderFrameHostReasonUKM(source_id, reason_value);
for (const auto& associated_source_id : associated_source_ids) {
if (associated_source_id.has_value()) {
RecordDisabledForRenderFrameHostReasonUKM(associated_source_id.value(),
reason_value);
}
}
}
for (const uint64_t reason :
page_store_result_->disallow_activation_reasons()) {
ukm::builders::BackForwardCacheDisallowActivationReason reason_builder(
source_id);
reason_builder.SetReason(reason);
reason_builder.Record(ukm::UkmRecorder::Get());
}
}
void BackForwardCacheMetrics::MainFrameDidNavigateAwayFromDocument() {
// MainFrameDidNavigateAwayFromDocument is called when we commit a navigation
// to another main frame document and the current document loses its "last
// committed" status.
navigated_away_from_main_document_timestamp_ = Now();
}
void BackForwardCacheMetrics::RecordFeatureUsage(
RenderFrameHostImpl* main_frame) {
DCHECK(!main_frame->GetParent());
main_frame_features_.Clear();
same_origin_frames_features_.Clear();
cross_origin_frames_features_.Clear();
CollectFeatureUsageFromSubtree(main_frame,
main_frame->GetLastCommittedOrigin());
}
void BackForwardCacheMetrics::CollectFeatureUsageFromSubtree(
RenderFrameHostImpl* rfh,
const url::Origin& main_frame_origin) {
blink::scheduler::WebSchedulerTrackedFeatures features =
rfh->GetBackForwardCacheDisablingFeatures();
if (!rfh->GetParent()) {
main_frame_features_.PutAll(features);
} else if (rfh->GetLastCommittedOrigin().IsSameOriginWith(
main_frame_origin)) {
same_origin_frames_features_.PutAll(features);
} else {
cross_origin_frames_features_.PutAll(features);
}
for (size_t i = 0; i < rfh->child_count(); ++i) {
CollectFeatureUsageFromSubtree(rfh->child_at(i)->current_frame_host(),
main_frame_origin);
}
}
void BackForwardCacheMetrics::AddNotRestoredFlattenedReasonsToExistingResult(
BackForwardCacheCanStoreDocumentResult& flattened) {
page_store_result_->AddReasonsFrom(flattened);
const BackForwardCacheCanStoreDocumentResult::NotRestoredReasons&
not_restored_reasons = flattened.not_restored_reasons();
if (not_restored_reasons.Has(NotRestoredReason::kRendererProcessKilled)) {
renderer_killed_timestamp_ = Now();
}
if (!not_restored_reasons.Has(NotRestoredReason::kHTTPStatusNotOK) &&
!not_restored_reasons.Has(NotRestoredReason::kSchemeNotHTTPOrHTTPS) &&
not_restored_reasons.Has(NotRestoredReason::kNoResponseHead)) {
CaptureTraceForNavigationDebugScenario(
DebugScenario::kDebugNoResponseHeadForHttpOrHttps);
base::debug::DumpWithoutCrashing();
}
}
void BackForwardCacheMetrics::SetNotRestoredReasons(
BackForwardCacheCanStoreDocumentResultWithTree& can_store) {
DCHECK(can_store.tree_reasons->FlattenTree() == can_store.flattened_reasons);
page_store_tree_result_ = std::move(can_store.tree_reasons);
AddNotRestoredFlattenedReasonsToExistingResult(can_store.flattened_reasons);
}
blink::mojom::BackForwardCacheNotRestoredReasonsPtr
BackForwardCacheMetrics::GetWebExposedNotRestoredReasons() {
return page_store_tree_result_->GetWebExposedNotRestoredReasons();
}
void BackForwardCacheMetrics::UpdateNotRestoredReasonsForNavigation(
NavigationRequest* navigation) {
DCHECK(IsCrossDocumentMainFrameHistoryNavigation(navigation));
BackForwardCacheCanStoreDocumentResult new_blocking_reasons;
// |last_committed_cross_document_main_frame_navigation_id_| is -1 even though
// this is a history navigation. This can happen only when the session history
// has been restored, as the NavigationEntry will exist and can be navigated
// to, but the BackForwardCacheMetrics object is brand new (as it's not
// persisted and restored).
if (last_committed_cross_document_main_frame_navigation_id_ == -1) {
new_blocking_reasons.No(NotRestoredReason::kSessionRestored);
}
// TODO(rakina): Remove this call from here and move it to
// |SetNotRestoredReasons()| that is called from |UnloadOldFrame()|.
if (!DidSwapBrowsingInstance()) {
new_blocking_reasons.No(NotRestoredReason::kBrowsingInstanceNotSwapped);
}
// This should not happen, but record this as an 'unknown' reason just in
// case.
if (page_store_result_->not_restored_reasons().Empty() &&
new_blocking_reasons.not_restored_reasons().Empty() &&
!navigation->IsServedFromBackForwardCache()) {
// TODO(altimin): Add a (D)CHECK here, but this code is reached in
// unittests.
new_blocking_reasons.No(NotRestoredReason::kUnknown);
}
page_store_result_->AddReasonsFrom(new_blocking_reasons);
// Initialize the empty tree result if nothing is set.
if (!page_store_tree_result_) {
page_store_tree_result_ =
BackForwardCacheCanStoreTreeResult::CreateEmptyTreeForNavigation(
navigation);
}
// Add the same reason to the root node of the tree once we update the
// flattened list of reasons.
page_store_tree_result_->AddReasonsToSubtreeRootFrom(new_blocking_reasons);
TRACE_EVENT("navigation",
"BackForwardCacheMetrics::UpdateNotRestoredReasonsForNavigation",
ChromeTrackEvent::kBackForwardCacheCanStoreDocumentResult,
*(page_store_result_.get()));
}
void BackForwardCacheMetrics::RecordHistoryNavigationUMA(
NavigationRequest* navigation,
bool back_forward_cache_allowed) const {
HistoryNavigationOutcome outcome = HistoryNavigationOutcome::kNotRestored;
if (navigation->IsServedFromBackForwardCache()) {
outcome = HistoryNavigationOutcome::kRestored;
if (back_forward_cache_allowed) {
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.EvictedAfterDocumentRestoredReason",
EvictedAfterDocumentRestoredReason::kRestored);
}
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.AllSites.EvictedAfterDocumentRestoredReason",
EvictedAfterDocumentRestoredReason::kRestored);
}
if (back_forward_cache_allowed) {
UMA_HISTOGRAM_ENUMERATION("BackForwardCache.HistoryNavigationOutcome",
outcome);
// Record total number of history navigations for all websites allowed by
// back-forward cache.
UMA_HISTOGRAM_ENUMERATION("BackForwardCache.ReloadsAndHistoryNavigations",
ReloadsAndHistoryNavigations::kHistoryNavigation);
}
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.AllSites.HistoryNavigationOutcome", outcome);
for (NotRestoredReason reason : page_store_result_->not_restored_reasons()) {
DCHECK(!navigation->IsServedFromBackForwardCache());
if (back_forward_cache_allowed) {
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.HistoryNavigationOutcome.NotRestoredReason",
reason);
}
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.AllSites.HistoryNavigationOutcome.NotRestoredReason",
reason);
if (reason == NotRestoredReason::kRendererProcessKilled) {
DCHECK(renderer_killed_timestamp_);
DCHECK(navigated_away_from_main_document_timestamp_);
base::TimeDelta time =
renderer_killed_timestamp_.value() -
navigated_away_from_main_document_timestamp_.value();
UMA_HISTOGRAM_LONG_TIMES(
"BackForwardCache.Eviction.TimeUntilProcessKilled", time);
}
}
for (blink::scheduler::WebSchedulerTrackedFeature feature :
page_store_result_->blocklisted_features()) {
if (back_forward_cache_allowed) {
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.HistoryNavigationOutcome.BlocklistedFeature",
feature);
}
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.AllSites.HistoryNavigationOutcome."
"BlocklistedFeature",
feature);
}
for (const auto& [reason, _] : page_store_result_->disabled_reasons()) {
// Use SparseHistogram instead of other simple macros for metrics. The
// reasons cannot be represented as a unified enum because they come from
// multiple sources. At first they were represented as strings but that
// makes it hard to track new additions. Now they are represented by
// a combination of source and source-specific enum.
base::UmaHistogramSparse(
"BackForwardCache.HistoryNavigationOutcome."
"DisabledForRenderFrameHostReason2",
MetricValue(reason));
}
for (const uint64_t reason :
page_store_result_->disallow_activation_reasons()) {
base::UmaHistogramSparse(
"BackForwardCache.HistoryNavigationOutcome."
"DisallowActivationReason",
reason);
}
if (!DidSwapBrowsingInstance()) {
DCHECK(!navigation->IsServedFromBackForwardCache());
if (back_forward_cache_allowed) {
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.HistoryNavigationOutcome."
"BrowsingInstanceNotSwappedReason",
browsing_instance_swap_result_.value());
}
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.AllSites.HistoryNavigationOutcome."
"BrowsingInstanceNotSwappedReason",
browsing_instance_swap_result_.value());
}
}
void BackForwardCacheMetrics::RecordEvictedAfterDocumentRestored(
EvictedAfterDocumentRestoredReason reason) {
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.EvictedAfterDocumentRestoredReason", reason);
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.AllSites.EvictedAfterDocumentRestoredReason", reason);
}
void BackForwardCacheMetrics::RecordHistogramForReloadsAfterHistoryNavigations(
bool is_reload,
bool back_forward_cache_allowed) const {
if (!is_reload || !previous_navigation_is_history_ ||
!back_forward_cache_allowed) {
return;
}
// Record the total number of reloads after a history navigation.
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.ReloadsAndHistoryNavigations",
ReloadsAndHistoryNavigations::kReloadAfterHistoryNavigation);
// Record separate buckets for cases served and not served from
// back-forward cache.
UMA_HISTOGRAM_ENUMERATION(
"BackForwardCache.ReloadsAfterHistoryNavigation",
previous_navigation_is_served_from_bfcache_
? ReloadsAfterHistoryNavigation::kServedFromBackForwardCache
: ReloadsAfterHistoryNavigation::kNotServedFromBackForwardCache);
}
// static
uint64_t BackForwardCacheMetrics::MetricValue(
BackForwardCache::DisabledReason reason) {
return static_cast<BackForwardCache::DisabledReasonType>(reason.source)
<< BackForwardCache::kDisabledReasonTypeBits |
reason.id;
}
void BackForwardCacheMetrics::SetBrowsingInstanceSwapResult(
absl::optional<ShouldSwapBrowsingInstance> reason) {
browsing_instance_swap_result_ = reason;
}
bool BackForwardCacheMetrics::DidSwapBrowsingInstance() const {
if (!browsing_instance_swap_result_)
return true;
switch (browsing_instance_swap_result_.value()) {
case ShouldSwapBrowsingInstance::kNo_ProactiveSwapDisabled:
case ShouldSwapBrowsingInstance::kNo_NotMainFrame:
case ShouldSwapBrowsingInstance::kNo_HasRelatedActiveContents:
case ShouldSwapBrowsingInstance::kNo_DoesNotHaveSite:
case ShouldSwapBrowsingInstance::kNo_SourceURLSchemeIsNotHTTPOrHTTPS:
case ShouldSwapBrowsingInstance::kNo_SameSiteNavigation:
case ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance:
case ShouldSwapBrowsingInstance::kNo_RendererDebugURL:
case ShouldSwapBrowsingInstance::kNo_NotNeededForBackForwardCache:
case ShouldSwapBrowsingInstance::kNo_SameDocumentNavigation:
case ShouldSwapBrowsingInstance::kNo_SameUrlNavigation:
case ShouldSwapBrowsingInstance::kNo_WillReplaceEntry:
case ShouldSwapBrowsingInstance::kNo_Reload:
case ShouldSwapBrowsingInstance::kNo_Guest:
case ShouldSwapBrowsingInstance::kNo_HasNotComittedAnyNavigation:
case ShouldSwapBrowsingInstance::kNo_NotPrimaryMainFrame:
return false;
case ShouldSwapBrowsingInstance::kYes_ForceSwap:
case ShouldSwapBrowsingInstance::kYes_CrossSiteProactiveSwap:
case ShouldSwapBrowsingInstance::kYes_SameSiteProactiveSwap:
return true;
}
}
} // namespace content