1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
// 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 "chrome/browser/page_load_metrics/observers/prefetch_page_load_metrics_observer.h"
#include <algorithm>
#include "base/metrics/histogram_macros_local.h"
#include "base/strings/string_util.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "components/history/core/browser/history_service.h"
#include "components/page_load_metrics/browser/page_load_tracker.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/prefetch_metrics.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 "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source.h"
#include "third_party/blink/public/common/mime_util/mime_util.h"
namespace {
// Yields 10 buckets between 1 and 180 (1,2,3,5,9,15,25,42,70,119), per privacy
// requirements. Computed using:
// CEIL(
// POW(kDaysSinceLastVisitBucketSpacing,
// FLOOR(LN(sample) / LN(kDaysSinceLastVisitBucketSpacing)))
// )
const double kDaysSinceLastVisitBucketSpacing = 1.7;
} // namespace
PrefetchPageLoadMetricsObserver::PrefetchPageLoadMetricsObserver() = default;
PrefetchPageLoadMetricsObserver::~PrefetchPageLoadMetricsObserver() = default;
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
PrefetchPageLoadMetricsObserver::OnStart(
content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url,
bool started_in_foreground) {
navigation_start_ = base::Time::Now();
return CONTINUE_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
PrefetchPageLoadMetricsObserver::OnFencedFramesStart(
content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url) {
// All observing events are preprocessed by PageLoadTracker so that the
// outermost page's observer instance sees gathered information. So, the
// instance for FencedFrames doesn't need to do anything.
return STOP_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
PrefetchPageLoadMetricsObserver::OnPrerenderStart(
content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url) {
// Prefetch proxy is used for privacy preserrving prefetch, and the feature
// and prerendering are exclusive in speculationrules. So, prerendering
// doesn't use the proxy, and this class just stops observing here. It's just
// interested in primary main page's performance with the prefetch proxy.
return STOP_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
PrefetchPageLoadMetricsObserver::OnRedirect(
content::NavigationHandle* navigation_handle) {
return CONTINUE_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
PrefetchPageLoadMetricsObserver::OnCommit(
content::NavigationHandle* navigation_handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!navigation_handle->GetURL().SchemeIsHTTPOrHTTPS()) {
return STOP_OBSERVING;
}
if (!navigation_handle->IsInPrimaryMainFrame()) {
return STOP_OBSERVING;
}
if (!page_load_metrics::IsNavigationUserInitiated(navigation_handle)) {
return STOP_OBSERVING;
}
if (!GetDelegate().StartedInForeground()) {
return STOP_OBSERVING;
}
Profile* profile = Profile::FromBrowserContext(
navigation_handle->GetWebContents()->GetBrowserContext());
if (profile->IsOffTheRecord()) {
return STOP_OBSERVING;
}
serving_page_metrics_ =
content::PrefetchServingPageMetrics::GetForNavigationHandle(
*navigation_handle);
history::HistoryService* history_service =
HistoryServiceFactory::GetForProfileIfExists(
profile, ServiceAccessType::IMPLICIT_ACCESS);
// For unit testing.
if (!history_service) {
return CONTINUE_OBSERVING;
}
for (const GURL& url : navigation_handle->GetRedirectChain()) {
history_service->GetLastVisitToOrigin(
url::Origin::Create(url), base::Time() /* before_time */,
navigation_start_ /* end_time */,
base::BindOnce(
&PrefetchPageLoadMetricsObserver::OnOriginLastVisitResult,
weak_factory_.GetWeakPtr(), base::Time::Now()),
&task_tracker_);
}
return CONTINUE_OBSERVING;
}
void PrefetchPageLoadMetricsObserver::OnDidInternalNavigationAbort(
content::NavigationHandle* navigation_handle) {
serving_page_metrics_ =
content::PrefetchServingPageMetrics::GetForNavigationHandle(
*navigation_handle);
RecordAfterPrefetchReferralEvent();
}
void PrefetchPageLoadMetricsObserver::OnPrefetchLikely() {
referring_page_metrics_ =
content::PrefetchReferringPageMetrics::GetForCurrentDocument(
GetDelegate().GetWebContents()->GetPrimaryMainFrame());
}
void PrefetchPageLoadMetricsObserver::OnOriginLastVisitResult(
base::Time query_start_time,
history::HistoryLastVisitResult result) {
if (!result.success) {
return;
}
if (!min_days_since_last_visit_to_origin_.has_value()) {
min_days_since_last_visit_to_origin_ = -1;
}
if (result.last_visit.is_null()) {
return;
}
base::TimeDelta last_visit_delta = base::Time::Now() - result.last_visit;
int last_visit_in_days = last_visit_delta.InDays();
if (min_days_since_last_visit_to_origin_.value() == -1 ||
min_days_since_last_visit_to_origin_.value() > last_visit_in_days) {
min_days_since_last_visit_to_origin_ = last_visit_in_days;
}
}
void PrefetchPageLoadMetricsObserver::RecordMetrics() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
task_tracker_.TryCancelAll();
if (min_days_since_last_visit_to_origin_.has_value()) {
int days_since_last_visit = min_days_since_last_visit_to_origin_.value();
LOCAL_HISTOGRAM_BOOLEAN(
"PageLoad.Clients.SubresourceLoading.HasPreviousVisitToOrigin",
days_since_last_visit != -1);
if (days_since_last_visit >= 0) {
LOCAL_HISTOGRAM_COUNTS_100(
"PageLoad.Clients.SubresourceLoading.DaysSinceLastVisitToOrigin",
days_since_last_visit);
}
}
RecordPrefetchProxyEvent();
RecordAfterPrefetchReferralEvent();
}
void PrefetchPageLoadMetricsObserver::RecordPrefetchProxyEvent() {
ukm::builders::PrefetchProxy builder(GetDelegate().GetPageUkmSourceId());
if (min_days_since_last_visit_to_origin_.has_value()) {
// The -1 value is a sentinel to signal there was no previous visit. Don't
// let the ukm call make it 0.
if (min_days_since_last_visit_to_origin_.value() == -1) {
builder.Setdays_since_last_visit_to_origin(-1);
} else {
int64_t maxxed_days_since_last_visit =
std::min(180, min_days_since_last_visit_to_origin_.value());
int64_t ukm_days_since_last_visit = ukm::GetExponentialBucketMin(
maxxed_days_since_last_visit, kDaysSinceLastVisitBucketSpacing);
builder.Setdays_since_last_visit_to_origin(ukm_days_since_last_visit);
}
}
if (referring_page_metrics_) {
builder.Setprefetch_eligible_count(
referring_page_metrics_->prefetch_eligible_count);
builder.Setprefetch_attempted_count(
referring_page_metrics_->prefetch_attempted_count);
builder.Setprefetch_successful_count(
referring_page_metrics_->prefetch_successful_count);
}
builder.Record(ukm::UkmRecorder::Get());
}
void PrefetchPageLoadMetricsObserver::RecordAfterPrefetchReferralEvent() {
if (!serving_page_metrics_) {
return;
}
ukm::builders::PrefetchProxy_AfterSRPClick builder(
GetDelegate().GetPageUkmSourceId());
if (serving_page_metrics_->prefetch_status) {
builder.SetSRPClickPrefetchStatus(
serving_page_metrics_->prefetch_status.value());
}
if (serving_page_metrics_->required_private_prefetch_proxy) {
builder.SetPrivatePrefetch(1);
}
if (serving_page_metrics_->same_tab_as_prefetching_tab) {
builder.SetSameTabAsPrefetchingTab(1);
}
if (serving_page_metrics_->prefetch_header_latency) {
builder.SetPrefetchHeaderLatencyMs(
serving_page_metrics_->prefetch_header_latency->InMilliseconds());
}
if (serving_page_metrics_->probe_latency) {
builder.SetProbeLatencyMs(
serving_page_metrics_->probe_latency.value().InMilliseconds());
}
builder.Record(ukm::UkmRecorder::Get());
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
PrefetchPageLoadMetricsObserver::OnHidden(
const page_load_metrics::mojom::PageLoadTiming& timing) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RecordMetrics();
return STOP_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
PrefetchPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
const page_load_metrics::mojom::PageLoadTiming& timing) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RecordMetrics();
return STOP_OBSERVING;
}
void PrefetchPageLoadMetricsObserver::OnComplete(
const page_load_metrics::mojom::PageLoadTiming& timing) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RecordMetrics();
}
|