Commit d728829e authored by Matt Falkenhagen's avatar Matt Falkenhagen Committed by Commit Bot

prerender: Add metrics for when Local Storage is used.

This adds UseCounter for local storage being first used before fcp and
after fcp. For prerendering, we expect to cancel the prerender on a
local storage access, because it uses a synchronous IPC. Note that while
getAll() is the only sync method in blink::mojom::StorageArea, any
initial use of local storage uses that to populate Blink's in memory
cache.

This adds a page load metrics observer which logs to Blink UseCounter on
Local Storage access. This is somewhat an abuse of the UseCounter, as
it's a targeted use case, but the UseCounter has good properties like
defining what a page load is. This will eventually be replaced with
Prerendering cancellation metrics when Prerendering is actually
implemented.

Bug: 1126305
Change-Id: If719c21115481d93930101e95d6fe86701f30523
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2497965
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarTakashi Toyoshima <toyoshim@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarHiroki Nakagawa <nhiroki@chromium.org>
Reviewed-by: default avatarCharlie Harrison <csharrison@chromium.org>
Cr-Commit-Position: refs/heads/master@{#822078}
parent e6ed840d
......@@ -20,6 +20,8 @@ source_set("browser") {
"observers/core/uma_page_load_metrics_observer.h",
"observers/layout_page_load_metrics_observer.cc",
"observers/layout_page_load_metrics_observer.h",
"observers/prerender_page_load_metrics_observer.cc",
"observers/prerender_page_load_metrics_observer.h",
"observers/use_counter/ukm_features.cc",
"observers/use_counter_page_load_metrics_observer.cc",
"observers/use_counter_page_load_metrics_observer.h",
......@@ -88,6 +90,7 @@ source_set("unit_tests") {
"observers/core/uma_page_load_metrics_observer_unittest.cc",
"observers/page_load_metrics_observer_content_test_harness.cc",
"observers/page_load_metrics_observer_content_test_harness.h",
"observers/prerender_page_load_metrics_observer_unittest.cc",
"observers/use_counter_page_load_metrics_observer_unittest.cc",
"page_load_metrics_util_unittest.cc",
"resource_tracker_unittest.cc",
......
// 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/prerender_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom.h"
void PrerenderPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
const page_load_metrics::mojom::PageLoadTiming& timing) {
did_fcp_ = true;
}
void PrerenderPageLoadMetricsObserver::OnStorageAccessed(
const GURL& url,
const GURL& first_party_url,
bool blocked_by_policy,
page_load_metrics::StorageType access_type) {
if (access_type != page_load_metrics::StorageType::kLocalStorage ||
did_local_storage_)
return;
// The purpose of this observer is to estimate how many prerendering pages
// will use certain features. The plan for prerendering is to delay loading
// of cross-origin iframes, so we want to ignore feature uses inside
// cross-origin iframes. To do this, just check if the |url| is cross-origin
// to |first_party_url|. This may not be an accurate count if a third-party
// subframe embeds a first-party subframe, or if there is a way for a frame
// to access cross-origin storage, but it's probably not significant.
if (!url::IsSameOriginWith(url, first_party_url))
return;
did_local_storage_ = true;
RecordFeatureUse(
did_fcp_ ? blink::mojom::WebFeature::kLocalStorageFirstUsedAfterFcp
: blink::mojom::WebFeature::kLocalStorageFirstUsedBeforeFcp);
}
void PrerenderPageLoadMetricsObserver::RecordFeatureUse(
blink::mojom::WebFeature feature) {
page_load_metrics::mojom::PageLoadFeatures page_load_features;
page_load_features.features.push_back(feature);
page_load_metrics::MetricsWebContentsObserver::RecordFeatureUsage(
GetDelegate().GetWebContents()->GetMainFrame(), page_load_features);
}
// 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.
#ifndef COMPONENTS_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_PRERENDER_PAGE_LOAD_METRICS_OBSERVER_H_
#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_PRERENDER_PAGE_LOAD_METRICS_OBSERVER_H_
#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
namespace blink {
namespace mojom {
enum class WebFeature : int32_t;
} // namespace mojom
} // namespace blink
// Records metrics relevant to prerendering. Currently it logs feature usage in
// normal page loads which, when if used during prerendering, may result in
// cancelling or freezing the prerender, to help estimate the effect on
// coverage.
class PrerenderPageLoadMetricsObserver
: public page_load_metrics::PageLoadMetricsObserver {
public:
PrerenderPageLoadMetricsObserver() = default;
// page_load_metrics::PageLoadMetricsObserver implementation:
void OnFirstContentfulPaintInPage(
const page_load_metrics::mojom::PageLoadTiming& timing) override;
void OnStorageAccessed(const GURL& url,
const GURL& first_party_url,
bool blocked_by_policy,
page_load_metrics::StorageType access_type) override;
private:
void RecordFeatureUse(blink::mojom::WebFeature feature);
bool did_fcp_ = false;
bool did_local_storage_ = false;
};
#endif // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_PRERENDER_PAGE_LOAD_METRICS_OBSERVER_H_
// 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/prerender_page_load_metrics_observer.h"
#include <memory>
#include "components/page_load_metrics/browser/observers/page_load_metrics_observer_content_test_harness.h"
#include "components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/page_load_tracker.h"
#include "components/page_load_metrics/common/test/page_load_metrics_test_util.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/navigation_simulator.h"
namespace {
const char kDefaultTestUrl[] = "https://a.test";
const char kOtherOriginUrl[] = "https://b.test";
const char kFeaturesHistogramName[] = "Blink.UseCounter.Features";
class PrerenderPageLoadMetricsObserverTest
: public page_load_metrics::PageLoadMetricsObserverContentTestHarness {
protected:
void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
// PrerenderPageLoadMetricsObserver requires
// UseCounterPageLoadMetricsObserver to log UseCounter to UMA.
tracker->AddObserver(std::make_unique<UseCounterPageLoadMetricsObserver>());
tracker->AddObserver(std::make_unique<PrerenderPageLoadMetricsObserver>());
}
void SimulateFirstContentfulPaint() {
page_load_metrics::mojom::PageLoadTiming timing;
page_load_metrics::InitPageLoadTimingForTest(&timing);
timing.navigation_start = base::Time::Now();
timing.parse_timing->parse_stop = base::TimeDelta::FromMilliseconds(50);
timing.paint_timing->first_contentful_paint =
base::TimeDelta::FromMilliseconds(100);
PopulateRequiredTimingFields(&timing);
tester()->SimulateTimingUpdate(timing);
}
int GetPageVisits() {
return tester()->histogram_tester().GetBucketCount(
kFeaturesHistogramName, static_cast<base::Histogram::Sample>(
blink::mojom::WebFeature::kPageVisits));
}
int GetLocalStorageBeforeFcpCount() {
return tester()->histogram_tester().GetBucketCount(
kFeaturesHistogramName,
static_cast<base::Histogram::Sample>(
blink::mojom::WebFeature::kLocalStorageFirstUsedBeforeFcp));
}
int GetLocalStorageAfterFcpCount() {
return tester()->histogram_tester().GetBucketCount(
kFeaturesHistogramName,
static_cast<base::Histogram::Sample>(
blink::mojom::WebFeature::kLocalStorageFirstUsedAfterFcp));
}
};
TEST_F(PrerenderPageLoadMetricsObserverTest, NoLocalStorage) {
NavigateAndCommit(GURL(kDefaultTestUrl));
EXPECT_EQ(GetPageVisits(), 1);
EXPECT_EQ(GetLocalStorageBeforeFcpCount(), 0);
EXPECT_EQ(GetLocalStorageAfterFcpCount(), 0);
}
TEST_F(PrerenderPageLoadMetricsObserverTest, LocalStorageBeforeFcp) {
NavigateAndCommit(GURL(kDefaultTestUrl));
// Access local storage.
tester()->SimulateStorageAccess(
GURL(kDefaultTestUrl), GURL(kDefaultTestUrl), false,
page_load_metrics::StorageType::kLocalStorage);
// Reach FCP.
SimulateFirstContentfulPaint();
// Access local storage again.
tester()->SimulateStorageAccess(
GURL(kDefaultTestUrl), GURL(kDefaultTestUrl), false,
page_load_metrics::StorageType::kLocalStorage);
EXPECT_EQ(GetPageVisits(), 1);
EXPECT_EQ(GetLocalStorageBeforeFcpCount(), 1);
// The UMA counts the first use, so AfterFcp is 0.
EXPECT_EQ(GetLocalStorageAfterFcpCount(), 0);
}
TEST_F(PrerenderPageLoadMetricsObserverTest, LocalStorageAfterFcp) {
NavigateAndCommit(GURL(kDefaultTestUrl));
// Reach FCP.
SimulateFirstContentfulPaint();
// Access local storage.
tester()->SimulateStorageAccess(
GURL(kDefaultTestUrl), GURL(kDefaultTestUrl), false,
page_load_metrics::StorageType::kLocalStorage);
EXPECT_EQ(GetPageVisits(), 1);
EXPECT_EQ(GetLocalStorageBeforeFcpCount(), 0);
EXPECT_EQ(GetLocalStorageAfterFcpCount(), 1);
}
TEST_F(PrerenderPageLoadMetricsObserverTest, ThirdPartyLocalStorage) {
NavigateAndCommit(GURL(kDefaultTestUrl));
tester()->SimulateStorageAccess(
GURL(kOtherOriginUrl), GURL(kDefaultTestUrl), false,
page_load_metrics::StorageType::kLocalStorage);
// Cross-origin local storage is not logged.
EXPECT_EQ(GetPageVisits(), 1);
EXPECT_EQ(GetLocalStorageBeforeFcpCount(), 0);
EXPECT_EQ(GetLocalStorageAfterFcpCount(), 0);
}
} // namespace
......@@ -9,6 +9,7 @@
#include "components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/page_load_tracker.h"
......@@ -28,6 +29,11 @@ void PageLoadMetricsEmbedderBase::RegisterObservers(PageLoadTracker* tracker) {
tracker->AddObserver(std::make_unique<UmaPageLoadMetricsObserver>());
tracker->AddObserver(std::make_unique<LayoutPageLoadMetricsObserver>());
tracker->AddObserver(std::make_unique<UseCounterPageLoadMetricsObserver>());
// So far, PrerenderPageLoadMetricsObserver is used to gather metrics from
// normal (non-prerendering) page loads, to estimate future coverage of
// prerendering, so it's in the !IsPrerendering() block.
tracker->AddObserver(std::make_unique<PrerenderPageLoadMetricsObserver>());
}
// Allow the embedder to register any embedder-specific observers
RegisterEmbedderObservers(tracker);
......
......@@ -3040,6 +3040,8 @@ enum WebFeature {
kBarcodeDetectorDetect = 3711,
kFaceDetectorDetect = 3712,
kTextDetectorDetect = 3713,
kLocalStorageFirstUsedBeforeFcp = 3714,
kLocalStorageFirstUsedAfterFcp = 3715,
// Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots.
......
......@@ -30066,6 +30066,8 @@ Called by update_use_counter_feature_enum.py.-->
<int value="3711" label="BarcodeDetectorDetect"/>
<int value="3712" label="FaceDetectorDetect"/>
<int value="3713" label="TextDetectorDetect"/>
<int value="3714" label="LocalStorageFirstUsedBeforeFcp"/>
<int value="3715" label="LocalStorageFirstUsedAfterFcp"/>
</enum>
<enum name="FeaturePolicyAllowlistType">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment