Commit 1401b43e authored by bmcquade's avatar bmcquade Committed by Commit bot

Persist EffectiveConnectionType in UKM on navigation start.

This change emits a UKM PageLoad metric for the EffectiveConnectionType
observed at navigation start.

This change also corrects an issue where we logged some information in
OnStart. When OnStart is invoked, we don't yet know if we're observing
a page load, so we move all logging to later in the flow, when we know
we're observing a page load.

BUG=700537

Review-Url: https://codereview.chromium.org/2740403002
Cr-Commit-Position: refs/heads/master@{#456219}
parent 20e72f4b
...@@ -4,9 +4,13 @@ ...@@ -4,9 +4,13 @@
#include "chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/net/nqe/ui_network_quality_estimator_service.h"
#include "chrome/browser/net/nqe/ui_network_quality_estimator_service_factory.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_util.h" #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
#include "chrome/browser/profiles/profile.h"
#include "components/ukm/ukm_entry_builder.h" #include "components/ukm/ukm_entry_builder.h"
#include "components/ukm/ukm_service.h" #include "components/ukm/ukm_service.h"
#include "content/public/browser/web_contents.h"
namespace internal { namespace internal {
...@@ -20,21 +24,39 @@ const char kUkmFirstContentfulPaintName[] = ...@@ -20,21 +24,39 @@ const char kUkmFirstContentfulPaintName[] =
const char kUkmFirstMeaningfulPaintName[] = const char kUkmFirstMeaningfulPaintName[] =
"Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"; "Experimental.PaintTiming.NavigationToFirstMeaningfulPaint";
const char kUkmForegroundDurationName[] = "PageTiming.ForegroundDuration"; const char kUkmForegroundDurationName[] = "PageTiming.ForegroundDuration";
const char kUkmEffectiveConnectionType[] =
"Net.EffectiveConnectionType.OnNavigationStart";
} // namespace internal } // namespace internal
namespace {
UINetworkQualityEstimatorService* GetNQEService(
content::WebContents* web_contents) {
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
if (!profile)
return nullptr;
return UINetworkQualityEstimatorServiceFactory::GetForProfile(profile);
}
} // namespace
// static // static
std::unique_ptr<page_load_metrics::PageLoadMetricsObserver> std::unique_ptr<page_load_metrics::PageLoadMetricsObserver>
UkmPageLoadMetricsObserver::CreateIfNeeded() { UkmPageLoadMetricsObserver::CreateIfNeeded(content::WebContents* web_contents) {
if (!g_browser_process->ukm_service()) { if (!g_browser_process->ukm_service()) {
return nullptr; return nullptr;
} }
return base::MakeUnique<UkmPageLoadMetricsObserver>(
return base::MakeUnique<UkmPageLoadMetricsObserver>(); GetNQEService(web_contents));
} }
UkmPageLoadMetricsObserver::UkmPageLoadMetricsObserver() UkmPageLoadMetricsObserver::UkmPageLoadMetricsObserver(
: source_id_(ukm::UkmService::GetNewSourceID()) {} net::NetworkQualityEstimator::NetworkQualityProvider*
network_quality_provider)
: network_quality_provider_(network_quality_provider),
source_id_(ukm::UkmService::GetNewSourceID()) {}
UkmPageLoadMetricsObserver::~UkmPageLoadMetricsObserver() = default; UkmPageLoadMetricsObserver::~UkmPageLoadMetricsObserver() = default;
...@@ -45,8 +67,17 @@ UkmPageLoadMetricsObserver::ObservePolicy UkmPageLoadMetricsObserver::OnStart( ...@@ -45,8 +67,17 @@ UkmPageLoadMetricsObserver::ObservePolicy UkmPageLoadMetricsObserver::OnStart(
if (!started_in_foreground) if (!started_in_foreground)
return STOP_OBSERVING; return STOP_OBSERVING;
ukm::UkmService* ukm_service = g_browser_process->ukm_service(); // When OnStart is invoked, we don't yet know whether we're observing a web
ukm_service->UpdateSourceURL(source_id_, navigation_handle->GetURL()); // page load, vs another kind of load (e.g. a download or a PDF). Thus,
// metrics and source information should not be recorded here. Instead, we
// store data we might want to persist in member variables below, and later
// record UKM metrics for that data once we've confirmed that we're observing
// a web page load.
if (network_quality_provider_) {
effective_connection_type_ =
network_quality_provider_->GetEffectiveConnectionType();
}
return CONTINUE_OBSERVING; return CONTINUE_OBSERVING;
} }
...@@ -54,17 +85,17 @@ UkmPageLoadMetricsObserver::ObservePolicy ...@@ -54,17 +85,17 @@ UkmPageLoadMetricsObserver::ObservePolicy
UkmPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground( UkmPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
const page_load_metrics::PageLoadTiming& timing, const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) { const page_load_metrics::PageLoadExtraInfo& info) {
RecordTimingMetrics(timing);
RecordPageLoadExtraInfoMetrics(info, base::TimeTicks::Now()); RecordPageLoadExtraInfoMetrics(info, base::TimeTicks::Now());
RecordTimingMetrics(timing);
return STOP_OBSERVING; return STOP_OBSERVING;
} }
UkmPageLoadMetricsObserver::ObservePolicy UkmPageLoadMetricsObserver::OnHidden( UkmPageLoadMetricsObserver::ObservePolicy UkmPageLoadMetricsObserver::OnHidden(
const page_load_metrics::PageLoadTiming& timing, const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) { const page_load_metrics::PageLoadExtraInfo& info) {
RecordTimingMetrics(timing);
RecordPageLoadExtraInfoMetrics( RecordPageLoadExtraInfoMetrics(
info, base::TimeTicks() /* no app_background_time */); info, base::TimeTicks() /* no app_background_time */);
RecordTimingMetrics(timing);
return STOP_OBSERVING; return STOP_OBSERVING;
} }
...@@ -78,9 +109,9 @@ void UkmPageLoadMetricsObserver::OnFailedProvisionalLoad( ...@@ -78,9 +109,9 @@ void UkmPageLoadMetricsObserver::OnFailedProvisionalLoad(
void UkmPageLoadMetricsObserver::OnComplete( void UkmPageLoadMetricsObserver::OnComplete(
const page_load_metrics::PageLoadTiming& timing, const page_load_metrics::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) { const page_load_metrics::PageLoadExtraInfo& info) {
RecordTimingMetrics(timing);
RecordPageLoadExtraInfoMetrics( RecordPageLoadExtraInfoMetrics(
info, base::TimeTicks() /* no app_background_time */); info, base::TimeTicks() /* no app_background_time */);
RecordTimingMetrics(timing);
} }
void UkmPageLoadMetricsObserver::RecordTimingMetrics( void UkmPageLoadMetricsObserver::RecordTimingMetrics(
...@@ -115,16 +146,20 @@ void UkmPageLoadMetricsObserver::RecordPageLoadExtraInfoMetrics( ...@@ -115,16 +146,20 @@ void UkmPageLoadMetricsObserver::RecordPageLoadExtraInfoMetrics(
const page_load_metrics::PageLoadExtraInfo& info, const page_load_metrics::PageLoadExtraInfo& info,
base::TimeTicks app_background_time) { base::TimeTicks app_background_time) {
ukm::UkmService* ukm_service = g_browser_process->ukm_service(); ukm::UkmService* ukm_service = g_browser_process->ukm_service();
ukm_service->UpdateSourceURL(source_id_, info.start_url);
ukm_service->UpdateSourceURL(source_id_, info.url); ukm_service->UpdateSourceURL(source_id_, info.url);
std::unique_ptr<ukm::UkmEntryBuilder> builder =
ukm_service->GetEntryBuilder(source_id_, internal::kUkmPageLoadEventName);
base::Optional<base::TimeDelta> foreground_duration = base::Optional<base::TimeDelta> foreground_duration =
page_load_metrics::GetInitialForegroundDuration(info, page_load_metrics::GetInitialForegroundDuration(info,
app_background_time); app_background_time);
if (foreground_duration) { if (foreground_duration) {
std::unique_ptr<ukm::UkmEntryBuilder> builder =
ukm_service->GetEntryBuilder(source_id_,
internal::kUkmPageLoadEventName);
builder->AddMetric(internal::kUkmForegroundDurationName, builder->AddMetric(internal::kUkmForegroundDurationName,
foreground_duration.value().InMilliseconds()); foreground_duration.value().InMilliseconds());
} }
if (effective_connection_type_ != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
builder->AddMetric(internal::kUkmEffectiveConnectionType,
static_cast<int64_t>(effective_connection_type_));
}
} }
...@@ -7,6 +7,11 @@ ...@@ -7,6 +7,11 @@
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "net/nqe/network_quality_estimator.h"
namespace content {
class WebContents;
}
namespace internal { namespace internal {
...@@ -18,6 +23,7 @@ extern const char kUkmLoadEventName[]; ...@@ -18,6 +23,7 @@ extern const char kUkmLoadEventName[];
extern const char kUkmFirstContentfulPaintName[]; extern const char kUkmFirstContentfulPaintName[];
extern const char kUkmFirstMeaningfulPaintName[]; extern const char kUkmFirstMeaningfulPaintName[];
extern const char kUkmForegroundDurationName[]; extern const char kUkmForegroundDurationName[];
extern const char kUkmEffectiveConnectionType[];
} // namespace internal } // namespace internal
...@@ -28,9 +34,11 @@ class UkmPageLoadMetricsObserver ...@@ -28,9 +34,11 @@ class UkmPageLoadMetricsObserver
public: public:
// Returns a UkmPageLoadMetricsObserver, or nullptr if it is not needed. // Returns a UkmPageLoadMetricsObserver, or nullptr if it is not needed.
static std::unique_ptr<page_load_metrics::PageLoadMetricsObserver> static std::unique_ptr<page_load_metrics::PageLoadMetricsObserver>
CreateIfNeeded(); CreateIfNeeded(content::WebContents* web_contents);
UkmPageLoadMetricsObserver(); explicit UkmPageLoadMetricsObserver(
net::NetworkQualityEstimator::NetworkQualityProvider*
network_quality_provider);
~UkmPageLoadMetricsObserver() override; ~UkmPageLoadMetricsObserver() override;
// page_load_metrics::PageLoadMetricsObserver implementation: // page_load_metrics::PageLoadMetricsObserver implementation:
...@@ -65,9 +73,15 @@ class UkmPageLoadMetricsObserver ...@@ -65,9 +73,15 @@ class UkmPageLoadMetricsObserver
const page_load_metrics::PageLoadExtraInfo& info, const page_load_metrics::PageLoadExtraInfo& info,
base::TimeTicks app_background_time); base::TimeTicks app_background_time);
net::NetworkQualityEstimator::NetworkQualityProvider* const
network_quality_provider_;
// Unique UKM identifier for the page load we are recording metrics for. // Unique UKM identifier for the page load we are recording metrics for.
const int32_t source_id_; const int32_t source_id_;
net::EffectiveConnectionType effective_connection_type_ =
net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
DISALLOW_COPY_AND_ASSIGN(UkmPageLoadMetricsObserver); DISALLOW_COPY_AND_ASSIGN(UkmPageLoadMetricsObserver);
}; };
......
...@@ -12,24 +12,47 @@ ...@@ -12,24 +12,47 @@
#include "components/ukm/test_ukm_service.h" #include "components/ukm/test_ukm_service.h"
#include "components/ukm/ukm_entry.h" #include "components/ukm/ukm_entry.h"
#include "components/ukm/ukm_source.h" #include "components/ukm/ukm_source.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::AnyNumber;
using testing::Mock;
using testing::Return;
namespace { namespace {
const char kTestUrl1[] = "https://www.google.com/"; const char kTestUrl1[] = "https://www.google.com/";
const char kTestUrl2[] = "https://www.example.com/"; const char kTestUrl2[] = "https://www.example.com/";
class MockNetworkQualityProvider
: public net::NetworkQualityEstimator::NetworkQualityProvider {
public:
MOCK_CONST_METHOD0(GetEffectiveConnectionType,
net::EffectiveConnectionType());
MOCK_METHOD1(
AddEffectiveConnectionTypeObserver,
void(net::NetworkQualityEstimator::EffectiveConnectionTypeObserver*));
MOCK_METHOD1(
RemoveEffectiveConnectionTypeObserver,
void(net::NetworkQualityEstimator::EffectiveConnectionTypeObserver*));
};
} // namespace } // namespace
class UkmPageLoadMetricsObserverTest class UkmPageLoadMetricsObserverTest
: public page_load_metrics::PageLoadMetricsObserverTestHarness { : public page_load_metrics::PageLoadMetricsObserverTestHarness {
protected: protected:
void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override { void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
tracker->AddObserver(base::MakeUnique<UkmPageLoadMetricsObserver>()); tracker->AddObserver(base::MakeUnique<UkmPageLoadMetricsObserver>(
&mock_network_quality_provider_));
} }
void SetUp() override { void SetUp() override {
page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp(); page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp();
EXPECT_CALL(mock_network_quality_provider_, GetEffectiveConnectionType())
.Times(AnyNumber())
.WillRepeatedly(Return(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN));
TestingBrowserProcess::GetGlobal()->SetUkmService( TestingBrowserProcess::GetGlobal()->SetUkmService(
ukm_service_test_harness_.test_ukm_service()); ukm_service_test_harness_.test_ukm_service());
} }
...@@ -42,6 +65,10 @@ class UkmPageLoadMetricsObserverTest ...@@ -42,6 +65,10 @@ class UkmPageLoadMetricsObserverTest
return ukm_service_test_harness_.test_ukm_service()->entries_count(); return ukm_service_test_harness_.test_ukm_service()->entries_count();
} }
MockNetworkQualityProvider& mock_network_quality_provider() {
return mock_network_quality_provider_;
}
const ukm::UkmSource* GetUkmSource(size_t source_index) { const ukm::UkmSource* GetUkmSource(size_t source_index) {
return ukm_service_test_harness_.test_ukm_service()->GetSource( return ukm_service_test_harness_.test_ukm_service()->GetSource(
source_index); source_index);
...@@ -118,6 +145,7 @@ class UkmPageLoadMetricsObserverTest ...@@ -118,6 +145,7 @@ class UkmPageLoadMetricsObserverTest
} }
private: private:
MockNetworkQualityProvider mock_network_quality_provider_;
ukm::UkmServiceTestingHarness ukm_service_test_harness_; ukm::UkmServiceTestingHarness ukm_service_test_harness_;
}; };
...@@ -250,3 +278,26 @@ TEST_F(UkmPageLoadMetricsObserverTest, MultiplePageLoads) { ...@@ -250,3 +278,26 @@ TEST_F(UkmPageLoadMetricsObserverTest, MultiplePageLoads) {
EXPECT_TRUE( EXPECT_TRUE(
HasMetric(internal::kUkmForegroundDurationName, entry2_proto.metrics())); HasMetric(internal::kUkmForegroundDurationName, entry2_proto.metrics()));
} }
TEST_F(UkmPageLoadMetricsObserverTest, EffectiveConnectionType) {
EXPECT_CALL(mock_network_quality_provider(), GetEffectiveConnectionType())
.WillRepeatedly(Return(net::EFFECTIVE_CONNECTION_TYPE_3G));
NavigateAndCommit(GURL(kTestUrl1));
// Simulate closing the tab.
DeleteContents();
EXPECT_EQ(1ul, ukm_source_count());
const ukm::UkmSource* source = GetUkmSource(0);
EXPECT_EQ(GURL(kTestUrl1), source->url());
EXPECT_GE(ukm_entry_count(), 1ul);
ukm::Entry entry_proto = GetMergedEntryProtoForSourceID(source->id());
EXPECT_EQ(entry_proto.source_id(), source->id());
EXPECT_EQ(entry_proto.event_hash(),
base::HashMetricName(internal::kUkmPageLoadEventName));
EXPECT_FALSE(entry_proto.metrics().empty());
ExpectMetric(internal::kUkmEffectiveConnectionType,
net::EFFECTIVE_CONNECTION_TYPE_3G, entry_proto.metrics());
}
...@@ -92,7 +92,7 @@ void PageLoadMetricsEmbedder::RegisterObservers( ...@@ -92,7 +92,7 @@ void PageLoadMetricsEmbedder::RegisterObservers(
tracker->AddObserver(base::MakeUnique<TabRestorePageLoadMetricsObserver>()); tracker->AddObserver(base::MakeUnique<TabRestorePageLoadMetricsObserver>());
std::unique_ptr<page_load_metrics::PageLoadMetricsObserver> ukm_observer = std::unique_ptr<page_load_metrics::PageLoadMetricsObserver> ukm_observer =
UkmPageLoadMetricsObserver::CreateIfNeeded(); UkmPageLoadMetricsObserver::CreateIfNeeded(web_contents_);
if (ukm_observer) if (ukm_observer)
tracker->AddObserver(std::move(ukm_observer)); tracker->AddObserver(std::move(ukm_observer));
......
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