Skip to content

Commit

Permalink
prerender: Add metrics for when Local Storage is used.
Browse files Browse the repository at this point in the history
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: Takashi Toyoshima <toyoshim@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Reviewed-by: Charlie Harrison <csharrison@chromium.org>
Cr-Commit-Position: refs/heads/master@{#822078}
  • Loading branch information
mfalken authored and Commit Bot committed Oct 29, 2020
1 parent e6ed840 commit d728829
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 0 deletions.
3 changes: 3 additions & 0 deletions components/page_load_metrics/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// 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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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_
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// 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
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions third_party/blink/public/mojom/web_feature/web_feature.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions tools/metrics/histograms/enums.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down

0 comments on commit d728829

Please sign in to comment.