[go: nahoru, domu]

blob: 26a19a1bbafaad9210c5cebabe993af5d70574b9 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/page_load_metrics_util.h"
#include "components/page_load_metrics/browser/responsiveness_metrics_normalization.h"
#include "components/page_load_metrics/common/page_visit_final_status.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "services/metrics/public/cpp/metrics_utils.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/common/features.h"
using page_load_metrics::PageVisitFinalStatus;
namespace internal {
const char kHistogramFirstPaintAfterBackForwardCacheRestore[] =
"PageLoad.PaintTiming.NavigationToFirstPaint.AfterBackForwardCacheRestore";
const char kHistogramFirstRequestAnimationFrameAfterBackForwardCacheRestore[] =
"PageLoad.PaintTiming.NavigationToFirstPaint.BFCachePolyfillFirst";
const char kHistogramSecondRequestAnimationFrameAfterBackForwardCacheRestore[] =
"PageLoad.PaintTiming.NavigationToFirstPaint.BFCachePolyfillSecond";
const char kHistogramThirdRequestAnimationFrameAfterBackForwardCacheRestore[] =
"PageLoad.PaintTiming.NavigationToFirstPaint.BFCachePolyfillThird";
const char kHistogramFirstInputDelayAfterBackForwardCacheRestore[] =
"PageLoad.InteractiveTiming.FirstInputDelay.AfterBackForwardCacheRestore";
extern const char
kHistogramCumulativeShiftScoreMainFrameAfterBackForwardCacheRestore[] =
"PageLoad.LayoutInstability.CumulativeShiftScore.MainFrame."
"AfterBackForwardCacheRestore";
extern const char kHistogramCumulativeShiftScoreAfterBackForwardCacheRestore[] =
"PageLoad.LayoutInstability.CumulativeShiftScore."
"AfterBackForwardCacheRestore";
const char
kAverageUserInteractionLatencyOverBudget_MaxEventDuration_AfterBackForwardCacheRestore
[] = "PageLoad.InteractiveTiming."
"AverageUserInteractionLatencyOverBudget."
"MaxEventDuration.AfterBackForwardCacheRestore";
const char kNumInteractions_AfterBackForwardCacheRestore[] =
"PageLoad.InteractiveTiming.NumInteractions.AfterBackForwardCacheRestore";
const char
kSlowUserInteractionLatencyOverBudgetHighPercentile2_MaxEventDuration_AfterBackForwardCacheRestore
[] = "PageLoad.InteractiveTiming."
"SlowUserInteractionLatencyOverBudget."
"HighPercentile2.MaxEventDuration.AfterBackForwardCacheRestore";
const char
kSumOfUserInteractionLatencyOverBudget_MaxEventDuration_AfterBackForwardCacheRestore
[] = "PageLoad.InteractiveTiming."
"SumOfUserInteractionLatencyOverBudget."
"MaxEventDuration.AfterBackForwardCacheRestore";
const char
kUserInteractionLatencyHighPercentile2_MaxEventDuration_AfterBackForwardCacheRestore
[] = "PageLoad.InteractiveTiming."
"UserInteractionLatency."
"HighPercentile2.MaxEventDuration.AfterBackForwardCacheRestore";
const char
kWorstUserInteractionLatency_MaxEventDuration_AfterBackForwardCacheRestore
[] = "PageLoad.InteractiveTiming."
"WorstUserInteractionLatency."
"MaxEventDuration.AfterBackForwardCacheRestore";
// Enables to emit zero values for some key metrics when back-forward cache is
// used.
//
// With this flag disabled, no samples are emitted for regular VOLT metrics
// after the page is restored from the back-forward cache. This means that we
// will miss a lot of metrics for history navigations after we launch back-
// forward cache. As metrics for history navigations tend to be better figures
// than other navigations (e.g., due to network cache), the average of such
// metrics values will become worse and might seem regression if we don't take
// any actions.
//
// To mitigate this issue, we plan to emit 0 samples for such key metrics for
// back-forward navigations. This is implemented behind this flag so far, and we
// will enable this by default when we reach the conclusion how to adjust them.
//
// For cumulative layout shift scores, we use actual score values for back-
// forward cache navigations instead of 0s.
const base::Feature kBackForwardCacheEmitZeroSamplesForKeyMetrics{
"BackForwardCacheEmitZeroSamplesForKeyMetrics",
base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace internal
BackForwardCachePageLoadMetricsObserver::
BackForwardCachePageLoadMetricsObserver() = default;
BackForwardCachePageLoadMetricsObserver::
~BackForwardCachePageLoadMetricsObserver() {
// TODO(crbug.com/1265307): Revert to the default destructor when we've
// figured out why sometimes page end metrics are not logged.
if (back_forward_cache_navigation_ids_.size() > 0) {
DCHECK(logged_page_end_metrics_);
}
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
BackForwardCachePageLoadMetricsObserver::OnStart(
content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url,
bool started_in_foreground) {
was_hidden_ = !started_in_foreground;
return CONTINUE_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
BackForwardCachePageLoadMetricsObserver::OnHidden(
const page_load_metrics::mojom::PageLoadTiming& timing) {
if (!in_back_forward_cache_) {
MaybeRecordForegroundDurationAfterBackForwardCacheRestore(
base::DefaultTickClock::GetInstance(),
/*app_entering_background=*/false);
}
was_hidden_ = true;
return CONTINUE_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
BackForwardCachePageLoadMetricsObserver::OnEnterBackForwardCache(
const page_load_metrics::mojom::PageLoadTiming& timing) {
in_back_forward_cache_ = true;
RecordMetricsOnPageVisitEnd(timing, /*app_entering_background=*/false);
has_ever_entered_back_forward_cache_ = true;
return CONTINUE_OBSERVING;
}
void BackForwardCachePageLoadMetricsObserver::OnRestoreFromBackForwardCache(
const page_load_metrics::mojom::PageLoadTiming& timing,
content::NavigationHandle* navigation_handle) {
page_metrics_logged_due_to_backgrounding_ = false;
in_back_forward_cache_ = false;
back_forward_cache_navigation_ids_.push_back(
navigation_handle->GetNavigationId());
content::WebContents* web_contents = GetDelegate().GetWebContents();
was_hidden_ = web_contents &&
web_contents->GetVisibility() == content::Visibility::HIDDEN;
logged_page_end_metrics_ = false;
restored_main_frame_layout_shift_score_ =
GetDelegate().GetMainFrameRenderData().layout_shift_score;
restored_layout_shift_score_ =
GetDelegate().GetPageRenderData().layout_shift_score;
// HistoryNavigation is a singular event, and we share the same instance as
// long as we use the same source ID.
ukm::builders::HistoryNavigation builder(
GetUkmSourceIdForBackForwardCacheRestore(
back_forward_cache_navigation_ids_.size() - 1));
bool amp_flag = GetDelegate().GetMainFrameMetadata().behavior_flags &
blink::kLoadingBehaviorAmpDocumentLoaded;
builder.SetBackForwardCache_IsAmpPage(amp_flag);
builder.Record(ukm::UkmRecorder::Get());
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
BackForwardCachePageLoadMetricsObserver::ShouldObserveMimeType(
const std::string& mime_type) const {
PageLoadMetricsObserver::ObservePolicy policy =
PageLoadMetricsObserver::ShouldObserveMimeType(mime_type);
if (policy == STOP_OBSERVING && has_ever_entered_back_forward_cache_) {
ukm::builders::UserPerceivedPageVisit(
GetLastUkmSourceIdForBackForwardCacheRestore())
.SetNotCountedForCoreWebVitals(true)
.Record(ukm::UkmRecorder::Get());
}
return policy;
}
void BackForwardCachePageLoadMetricsObserver::
OnFirstPaintAfterBackForwardCacheRestoreInPage(
const page_load_metrics::mojom::BackForwardCacheTiming& timing,
size_t index) {
if (index >= back_forward_cache_navigation_ids_.size())
return;
auto first_paint = timing.first_paint_after_back_forward_cache_restore;
DCHECK(!first_paint.is_zero());
if (page_load_metrics::
WasStartedInForegroundOptionalEventInForegroundAfterBackForwardCacheRestore(
first_paint, GetDelegate(), index)) {
PAGE_LOAD_HISTOGRAM(
internal::kHistogramFirstPaintAfterBackForwardCacheRestore,
first_paint);
// HistoryNavigation is a singular event, and we share the same instance as
// long as we use the same source ID.
ukm::builders::HistoryNavigation builder(
GetUkmSourceIdForBackForwardCacheRestore(index));
builder.SetNavigationToFirstPaintAfterBackForwardCacheRestore(
first_paint.InMilliseconds());
builder.Record(ukm::UkmRecorder::Get());
if (base::FeatureList::IsEnabled(
internal::kBackForwardCacheEmitZeroSamplesForKeyMetrics)) {
PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstPaint, base::TimeDelta{});
PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaint,
base::TimeDelta{});
PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaint,
base::TimeDelta{});
}
}
}
void BackForwardCachePageLoadMetricsObserver::
OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage(
const page_load_metrics::mojom::BackForwardCacheTiming& timing,
size_t index) {
if (index >= back_forward_cache_navigation_ids_.size())
return;
auto request_animation_frames =
timing.request_animation_frames_after_back_forward_cache_restore;
DCHECK_EQ(request_animation_frames.size(), 3u);
PAGE_LOAD_HISTOGRAM(
internal::
kHistogramFirstRequestAnimationFrameAfterBackForwardCacheRestore,
request_animation_frames[0]);
PAGE_LOAD_HISTOGRAM(
internal::
kHistogramSecondRequestAnimationFrameAfterBackForwardCacheRestore,
request_animation_frames[1]);
PAGE_LOAD_HISTOGRAM(
internal::
kHistogramThirdRequestAnimationFrameAfterBackForwardCacheRestore,
request_animation_frames[2]);
// HistoryNavigation is a singular event, and we share the same instance as
// long as we use the same source ID.
ukm::builders::HistoryNavigation builder(
GetUkmSourceIdForBackForwardCacheRestore(index));
builder.SetFirstRequestAnimationFrameAfterBackForwardCacheRestore(
request_animation_frames[0].InMilliseconds());
builder.SetSecondRequestAnimationFrameAfterBackForwardCacheRestore(
request_animation_frames[1].InMilliseconds());
builder.SetThirdRequestAnimationFrameAfterBackForwardCacheRestore(
request_animation_frames[2].InMilliseconds());
builder.Record(ukm::UkmRecorder::Get());
}
void BackForwardCachePageLoadMetricsObserver::
OnFirstInputAfterBackForwardCacheRestoreInPage(
const page_load_metrics::mojom::BackForwardCacheTiming& timing,
size_t index) {
if (index >= back_forward_cache_navigation_ids_.size())
return;
auto first_input_delay =
timing.first_input_delay_after_back_forward_cache_restore;
DCHECK(first_input_delay.has_value());
if (page_load_metrics::
WasStartedInForegroundOptionalEventInForegroundAfterBackForwardCacheRestore(
first_input_delay, GetDelegate(), index)) {
UMA_HISTOGRAM_CUSTOM_TIMES(
internal::kHistogramFirstInputDelayAfterBackForwardCacheRestore,
*first_input_delay, base::Milliseconds(1), base::Seconds(60), 50);
// HistoryNavigation is a singular event, and we share the same instance as
// long as we use the same source ID.
ukm::builders::HistoryNavigation builder(
GetUkmSourceIdForBackForwardCacheRestore(index));
builder.SetFirstInputDelayAfterBackForwardCacheRestore(
first_input_delay.value().InMilliseconds());
builder.Record(ukm::UkmRecorder::Get());
if (base::FeatureList::IsEnabled(
internal::kBackForwardCacheEmitZeroSamplesForKeyMetrics)) {
PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstInputDelay,
base::TimeDelta{});
}
}
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
BackForwardCachePageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
const page_load_metrics::mojom::PageLoadTiming& timing) {
if (!in_back_forward_cache_)
RecordMetricsOnPageVisitEnd(timing, /*app_entering_background=*/true);
page_metrics_logged_due_to_backgrounding_ = true;
return CONTINUE_OBSERVING;
}
void BackForwardCachePageLoadMetricsObserver::OnComplete(
const page_load_metrics::mojom::PageLoadTiming& timing) {
// If the page is in the back-forward cache and OnComplete is called, the page
// is being evicted from the cache. Do not record metrics here as we have
// already recorded them in OnEnterBackForwardCache.
if (in_back_forward_cache_)
return;
RecordMetricsOnPageVisitEnd(timing, /*app_entering_background=*/false);
}
void BackForwardCachePageLoadMetricsObserver::RecordMetricsOnPageVisitEnd(
const page_load_metrics::mojom::PageLoadTiming& timing,
bool app_entering_background) {
if (page_metrics_logged_due_to_backgrounding_)
return;
MaybeRecordLayoutShiftScoreAfterBackForwardCacheRestore(timing);
MaybeRecordPageEndAfterBackForwardCacheRestore(app_entering_background);
MaybeRecordForegroundDurationAfterBackForwardCacheRestore(
base::DefaultTickClock::GetInstance(), app_entering_background);
MaybeRecordNormalizedResponsivenessMetrics();
if (has_ever_entered_back_forward_cache_) {
page_load_metrics::RecordPageVisitFinalStatusForTiming(
timing, GetDelegate(), GetLastUkmSourceIdForBackForwardCacheRestore());
bool is_user_initiated_navigation =
// All browser initiated page loads are user-initiated.
GetDelegate().GetUserInitiatedInfo().browser_initiated ||
// Renderer-initiated navigations are user-initiated if there is an
// associated input event.
GetDelegate().GetUserInitiatedInfo().user_input_event;
ukm::builders::UserPerceivedPageVisit(
GetLastUkmSourceIdForBackForwardCacheRestore())
.SetUserInitiated(is_user_initiated_navigation)
.Record(ukm::UkmRecorder::Get());
}
}
void BackForwardCachePageLoadMetricsObserver::
MaybeRecordNormalizedResponsivenessMetrics() {
if (!has_ever_entered_back_forward_cache_)
return;
// Normalized Responsiveness Metrics.
const page_load_metrics::NormalizedResponsivenessMetrics&
normalized_responsiveness_metrics =
GetDelegate().GetNormalizedResponsivenessMetrics();
if (!normalized_responsiveness_metrics.num_user_interactions)
return;
auto& max_event_durations =
normalized_responsiveness_metrics.normalized_max_event_durations;
// HistoryNavigation is a singular event, and we share the same instance as
// long as we use the same source ID.
ukm::builders::HistoryNavigation builder(
GetLastUkmSourceIdForBackForwardCacheRestore());
builder
.SetWorstUserInteractionLatencyAfterBackForwardCacheRestore_MaxEventduration(
max_event_durations.worst_latency.InMilliseconds());
UmaHistogramCustomTimes(
internal::
kWorstUserInteractionLatency_MaxEventDuration_AfterBackForwardCacheRestore,
max_event_durations.worst_latency, base::Milliseconds(1),
base::Seconds(60), 50);
builder
.SetSumOfUserInteractionLatencyOverBudgetAfterBackForwardCacheRestore_MaxEventduration(
max_event_durations.sum_of_latency_over_budget.InMilliseconds());
builder
.SetAverageUserInteractionLatencyOverBudgetAfterBackForwardCacheRestore_MaxEventduration(
max_event_durations.sum_of_latency_over_budget.InMilliseconds() /
normalized_responsiveness_metrics.num_user_interactions);
base::TimeDelta high_percentile2_max_event_duration = page_load_metrics::
ResponsivenessMetricsNormalization::ApproximateHighPercentile(
normalized_responsiveness_metrics.num_user_interactions,
max_event_durations.worst_ten_latencies);
base::TimeDelta high_percentile2_max_event_duration_over_budget =
page_load_metrics::ResponsivenessMetricsNormalization::
ApproximateHighPercentile(
normalized_responsiveness_metrics.num_user_interactions,
max_event_durations.worst_ten_latencies_over_budget);
builder
.SetSlowUserInteractionLatencyOverBudgetAfterBackForwardCacheRestore_HighPercentile2_MaxEventduration(
high_percentile2_max_event_duration_over_budget.InMilliseconds());
builder
.SetUserInteractionLatencyAfterBackForwardCacheRestore_HighPercentile2_MaxEventDuration(
high_percentile2_max_event_duration.InMilliseconds());
builder.SetNumInteractionsAfterBackForwardCacheRestore(
ukm::GetExponentialBucketMinForCounts1000(
normalized_responsiveness_metrics.num_user_interactions));
UmaHistogramCustomTimes(
internal::
kSumOfUserInteractionLatencyOverBudget_MaxEventDuration_AfterBackForwardCacheRestore,
max_event_durations.sum_of_latency_over_budget, base::Milliseconds(1),
base::Seconds(60), 50);
UmaHistogramCustomTimes(
internal::
kAverageUserInteractionLatencyOverBudget_MaxEventDuration_AfterBackForwardCacheRestore,
max_event_durations.sum_of_latency_over_budget /
normalized_responsiveness_metrics.num_user_interactions,
base::Milliseconds(1), base::Seconds(60), 50);
UmaHistogramCustomTimes(
internal::
kSlowUserInteractionLatencyOverBudgetHighPercentile2_MaxEventDuration_AfterBackForwardCacheRestore,
high_percentile2_max_event_duration_over_budget, base::Milliseconds(1),
base::Seconds(60), 50);
UmaHistogramCustomTimes(
internal::
kUserInteractionLatencyHighPercentile2_MaxEventDuration_AfterBackForwardCacheRestore,
high_percentile2_max_event_duration, base::Milliseconds(1),
base::Seconds(60), 50);
base::UmaHistogramCounts1000(
internal::kNumInteractions_AfterBackForwardCacheRestore,
normalized_responsiveness_metrics.num_user_interactions);
builder.Record(ukm::UkmRecorder::Get());
}
void BackForwardCachePageLoadMetricsObserver::
MaybeRecordLayoutShiftScoreAfterBackForwardCacheRestore(
const page_load_metrics::mojom::PageLoadTiming& timing) {
if (!has_ever_entered_back_forward_cache_ ||
!restored_main_frame_layout_shift_score_.has_value()) {
return;
}
DCHECK(restored_layout_shift_score_.has_value());
double layout_main_frame_shift_score =
GetDelegate().GetMainFrameRenderData().layout_shift_score -
restored_main_frame_layout_shift_score_.value();
DCHECK_GE(layout_main_frame_shift_score, 0);
double layout_shift_score =
GetDelegate().GetPageRenderData().layout_shift_score -
restored_layout_shift_score_.value();
DCHECK_GE(layout_shift_score, 0);
UMA_HISTOGRAM_COUNTS_100(
internal::
kHistogramCumulativeShiftScoreMainFrameAfterBackForwardCacheRestore,
page_load_metrics::LayoutShiftUmaValue(layout_main_frame_shift_score));
UMA_HISTOGRAM_COUNTS_100(
internal::kHistogramCumulativeShiftScoreAfterBackForwardCacheRestore,
page_load_metrics::LayoutShiftUmaValue(layout_shift_score));
// HistoryNavigation is a singular event, and we share the same instance as
// long as we use the same source ID.
ukm::builders::HistoryNavigation builder(
GetLastUkmSourceIdForBackForwardCacheRestore());
builder.SetCumulativeShiftScoreAfterBackForwardCacheRestore(
page_load_metrics::LayoutShiftUkmValue(layout_shift_score));
page_load_metrics::NormalizedCLSData normalized_cls_data =
GetDelegate().GetNormalizedCLSData(
page_load_metrics::PageLoadMetricsObserverDelegate::BfcacheStrategy::
RESET);
if (!normalized_cls_data.data_tainted) {
builder
.SetMaxCumulativeShiftScoreAfterBackForwardCacheRestore_SessionWindow_Gap1000ms_Max5000ms(
page_load_metrics::LayoutShiftUkmValue(
normalized_cls_data
.session_windows_gap1000ms_max5000ms_max_cls));
base::UmaHistogramCounts100(
"PageLoad.LayoutInstability.MaxCumulativeShiftScore."
"AfterBackForwardCacheRestore.SessionWindow.Gap1000ms.Max5000ms",
page_load_metrics::LayoutShiftUmaValue(
normalized_cls_data.session_windows_gap1000ms_max5000ms_max_cls));
base::UmaHistogramCustomCounts(
"PageLoad.LayoutInstability.MaxCumulativeShiftScore."
"AfterBackForwardCacheRestore.SessionWindow.Gap1000ms.Max5000ms2",
page_load_metrics::LayoutShiftUmaValue10000(
normalized_cls_data.session_windows_gap1000ms_max5000ms_max_cls),
1, 24000, 50);
}
builder.Record(ukm::UkmRecorder::Get());
if (base::FeatureList::IsEnabled(
internal::kBackForwardCacheEmitZeroSamplesForKeyMetrics)) {
UMA_HISTOGRAM_COUNTS_100(
"PageLoad.LayoutInstability.CumulativeShiftScore.MainFrame",
page_load_metrics::LayoutShiftUmaValue(layout_main_frame_shift_score));
UMA_HISTOGRAM_COUNTS_100(
"PageLoad.LayoutInstability.CumulativeShiftScore",
page_load_metrics::LayoutShiftUmaValue(layout_shift_score));
}
}
void BackForwardCachePageLoadMetricsObserver::
MaybeRecordPageEndAfterBackForwardCacheRestore(
bool app_entering_background) {
if (!has_ever_entered_back_forward_cache_)
return;
auto page_end_reason = GetDelegate().GetPageEndReason();
if (page_end_reason == page_load_metrics::PageEndReason::END_NONE &&
app_entering_background) {
page_end_reason =
page_load_metrics::PageEndReason::END_APP_ENTER_BACKGROUND;
}
// HistoryNavigation is a singular event, and we share the same instance as
// long as we use the same source ID.
ukm::builders::HistoryNavigation builder(
GetLastUkmSourceIdForBackForwardCacheRestore());
builder.SetPageEndReasonAfterBackForwardCacheRestore(page_end_reason);
builder.Record(ukm::UkmRecorder::Get());
logged_page_end_metrics_ = true;
}
void BackForwardCachePageLoadMetricsObserver::
MaybeRecordForegroundDurationAfterBackForwardCacheRestore(
const base::TickClock* clock,
bool app_entering_background) const {
if (!was_hidden_ && has_ever_entered_back_forward_cache_) {
// This logic for finding the foreground duration is intended to mimic
// page_load_metrics::GetInitialForegroundDuration, but adjusted to
// take into account the back forward cache.
absl::optional<base::TimeDelta> foreground_duration;
DCHECK(back_forward_cache_navigation_ids_.size() >= 1);
auto back_forward_state = GetDelegate().GetBackForwardCacheRestore(
back_forward_cache_navigation_ids_.size() - 1);
// If the BFCache restoration happened while not in the foreground, don't
// record a foreground duration.
if (!back_forward_state.was_in_foreground)
return;
absl::optional<base::TimeDelta> time_to_page_end =
GetDelegate().GetPageEndReason() == page_load_metrics::END_NONE
? absl::optional<base::TimeDelta>()
: GetDelegate().GetPageEndTime() -
back_forward_state.navigation_start_time;
// |first_background_time| is actually time-to-first-background here, i.e.
// it's a delta, not an absolute time, so does not need to be adjusted by
// navigation start time.
foreground_duration = page_load_metrics::OptionalMin(
back_forward_state.first_background_time, time_to_page_end);
if (!foreground_duration && app_entering_background) {
foreground_duration =
clock->NowTicks() - back_forward_state.navigation_start_time;
}
if (foreground_duration.has_value()) {
ukm::builders::HistoryNavigation builder(
GetLastUkmSourceIdForBackForwardCacheRestore());
builder.SetForegroundDurationAfterBackForwardCacheRestore(
ukm::GetSemanticBucketMinForDurationTiming(
foreground_duration.value().InMilliseconds()));
builder.Record(ukm::UkmRecorder::Get());
}
}
}
int64_t BackForwardCachePageLoadMetricsObserver::
GetUkmSourceIdForBackForwardCacheRestore(size_t index) const {
DCHECK_GT(back_forward_cache_navigation_ids_.size(), index);
int64_t navigation_id = back_forward_cache_navigation_ids_[index];
DCHECK_NE(ukm::kInvalidSourceId, navigation_id);
return ukm::ConvertToSourceId(navigation_id,
ukm::SourceIdType::NAVIGATION_ID);
}
int64_t BackForwardCachePageLoadMetricsObserver::
GetLastUkmSourceIdForBackForwardCacheRestore() const {
int64_t navigation_id = back_forward_cache_navigation_ids_.back();
DCHECK_NE(ukm::kInvalidSourceId, navigation_id);
return ukm::ConvertToSourceId(navigation_id,
ukm::SourceIdType::NAVIGATION_ID);
}