Commit e21cc524 authored by Robert Ogden's avatar Robert Ogden Committed by Commit Bot

DRP Pingbacks: Factor out the pingback logic to a base class

Since HTTPS Server Previews will also send pingbacks, and we don't want
a lot of copied code, this factors all DRP pingback logic out into a
shareable base class. The histogram recording stays in the DRP Observer.

Also factors out a test_utils class for testing pingbacks.

This CL has no behavorial changes to pingbacks themselves. However, in
the next CL, the OnCommit logic will move from the base class to the
derived classes.

Bug: 864665
Change-Id: I569bc58331b45b71ae702149e43a2630d523e6dc
Reviewed-on: https://chromium-review.googlesource.com/c/1351497
Commit-Queue: Robert Ogden <robertogden@chromium.org>
Reviewed-by: default avatarRyan Sturm <ryansturm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611364}
parent 98f045a4
......@@ -939,6 +939,8 @@ jumbo_split_static_library("browser") {
"page_load_metrics/observers/core_page_load_metrics_observer.h",
"page_load_metrics/observers/data_reduction_proxy_metrics_observer.cc",
"page_load_metrics/observers/data_reduction_proxy_metrics_observer.h",
"page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.cc",
"page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.h",
"page_load_metrics/observers/data_saver_site_breakdown_metrics_observer.cc",
"page_load_metrics/observers/data_saver_site_breakdown_metrics_observer.h",
"page_load_metrics/observers/document_write_page_load_metrics_observer.cc",
......
......@@ -7,32 +7,11 @@
#include <string>
#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "chrome/browser/loader/chrome_navigation_data.h"
#include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
#include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
#include "chrome/browser/page_load_metrics/observers/histogram_suffixes.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
#include "chrome/browser/previews/previews_ui_tab_helper.h"
#include "chrome/common/page_load_metrics/page_load_timing.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/proto/pageload_metrics.pb.h"
#include "components/previews/content/previews_user_data.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_data.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h"
#include "services/metrics/public/cpp/metrics_utils.h"
#include "url/gurl.h"
namespace data_reduction_proxy {
......@@ -46,32 +25,6 @@ std::string GetConstHistogramWithSuffix(const char* suffix) {
.append(suffix);
}
PageloadMetrics_PageEndReason ConvertPLMPageEndReasonToProto(
page_load_metrics::PageEndReason reason) {
switch (reason) {
case page_load_metrics::END_NONE:
return PageloadMetrics_PageEndReason_END_NONE;
case page_load_metrics::END_RELOAD:
return PageloadMetrics_PageEndReason_END_RELOAD;
case page_load_metrics::END_FORWARD_BACK:
return PageloadMetrics_PageEndReason_END_FORWARD_BACK;
case page_load_metrics::END_CLIENT_REDIRECT:
return PageloadMetrics_PageEndReason_END_CLIENT_REDIRECT;
case page_load_metrics::END_NEW_NAVIGATION:
return PageloadMetrics_PageEndReason_END_NEW_NAVIGATION;
case page_load_metrics::END_STOP:
return PageloadMetrics_PageEndReason_END_STOP;
case page_load_metrics::END_CLOSE:
return PageloadMetrics_PageEndReason_END_CLOSE;
case page_load_metrics::END_PROVISIONAL_LOAD_FAILED:
return PageloadMetrics_PageEndReason_END_PROVISIONAL_LOAD_FAILED;
case page_load_metrics::END_RENDER_PROCESS_GONE:
return PageloadMetrics_PageEndReason_END_RENDER_PROCESS_GONE;
default:
return PageloadMetrics_PageEndReason_END_OTHER;
}
}
// A macro is needed because PAGE_LOAD_HISTOGRAM creates a static instance of
// the histogram. A distinct histogram is needed for each place that calls
// RECORD_HISTOGRAMS_FOR_SUFFIX. |event| is the timing event representing when
......@@ -129,107 +82,10 @@ const char kBytesInflation[] = "Experimental.Bytes.Network.Inflation2";
} // namespace internal
DataReductionProxyMetricsObserver::DataReductionProxyMetricsObserver()
: browser_context_(nullptr),
opted_out_(false),
num_data_reduction_proxy_resources_(0),
num_network_resources_(0),
insecure_original_network_bytes_(0),
secure_original_network_bytes_(0),
network_bytes_proxied_(0),
insecure_network_bytes_(0),
secure_network_bytes_(0),
insecure_cached_bytes_(0),
secure_cached_bytes_(0),
process_id_(base::kNullProcessId),
renderer_memory_usage_kb_(0),
render_process_host_id_(content::ChildProcessHost::kInvalidUniqueID),
touch_count_(0),
scroll_count_(0),
redirect_count_(0),
weak_ptr_factory_(this) {}
: DataReductionProxyMetricsObserverBase() {}
DataReductionProxyMetricsObserver::~DataReductionProxyMetricsObserver() {}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
DataReductionProxyMetricsObserver::OnRedirect(
content::NavigationHandle* navigation_handle) {
redirect_count_++;
return CONTINUE_OBSERVING;
}
// Check if the NavigationData indicates anything about the DataReductionProxy.
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
DataReductionProxyMetricsObserver::OnCommit(
content::NavigationHandle* navigation_handle,
ukm::SourceId source_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This BrowserContext is valid for the lifetime of
// DataReductionProxyMetricsObserver. BrowserContext is always valid and
// non-nullptr in NavigationControllerImpl, which is a member of WebContents.
// A raw pointer to BrowserContext taken at this point will be valid until
// after WebContent's destructor. The latest that PageLoadTracker's destructor
// will be called is in MetricsWebContentsObserver's destrcutor, which is
// called in WebContents destructor.
browser_context_ = navigation_handle->GetWebContents()->GetBrowserContext();
// As documented in content/public/browser/navigation_handle.h, this
// NavigationData is a clone of the NavigationData instance returned from
// ResourceDispatcherHostDelegate::GetNavigationData during commit.
// Because ChromeResourceDispatcherHostDelegate always returns a
// ChromeNavigationData, it is safe to static_cast here.
std::unique_ptr<DataReductionProxyData> data;
auto* settings =
DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
browser_context_);
if (settings) {
data = settings->CreateDataFromNavigationHandle(
navigation_handle, navigation_handle->GetResponseHeaders());
}
if (!data || !(data->used_data_reduction_proxy() ||
data->was_cached_data_reduction_proxy_response())) {
return STOP_OBSERVING;
}
data_ = std::move(data);
PreviewsUITabHelper* ui_tab_helper =
PreviewsUITabHelper::FromWebContents(navigation_handle->GetWebContents());
previews::PreviewsUserData* previews_data = nullptr;
if (ui_tab_helper)
previews_data = ui_tab_helper->GetPreviewsUserData(navigation_handle);
if (previews_data) {
data_->set_black_listed(previews_data->black_listed_for_lite_page());
}
process_id_ = navigation_handle->GetWebContents()
->GetMainFrame()
->GetProcess()
->GetProcess()
.Pid();
render_process_host_id_ = navigation_handle->GetWebContents()
->GetMainFrame()
->GetProcess()
->GetID();
navigation_start_ = navigation_handle->NavigationStart();
// DataReductionProxy page loads should only occur on HTTP navigations.
DCHECK(!navigation_handle->GetURL().SchemeIsCryptographic());
DCHECK_EQ(data_->request_url(), navigation_handle->GetURL());
return CONTINUE_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
DataReductionProxyMetricsObserver::OnStart(
content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url,
bool started_in_foreground) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!started_in_foreground)
return STOP_OBSERVING;
return CONTINUE_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
DataReductionProxyMetricsObserver::FlushMetricsOnAppEnterBackground(
const page_load_metrics::mojom::PageLoadTiming& timing,
......@@ -241,30 +97,31 @@ DataReductionProxyMetricsObserver::FlushMetricsOnAppEnterBackground(
// notification, so we send a pingback with data collected up to this point.
if (info.did_commit) {
RecordPageSizeUMA();
SendPingback(timing, info, true /* app_background_occurred */);
}
return STOP_OBSERVING;
return DataReductionProxyMetricsObserverBase::
FlushMetricsOnAppEnterBackground(timing, info);
}
void DataReductionProxyMetricsObserver::OnComplete(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
DataReductionProxyMetricsObserverBase::OnComplete(timing, info);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RecordPageSizeUMA();
SendPingback(timing, info, false /* app_background_occurred */);
}
void DataReductionProxyMetricsObserver::RecordPageSizeUMA() const {
if (!data_)
if (!data())
return;
// If the first request didn't complete, don't record UMA.
if (num_network_resources_ == 0)
if (num_network_resources() == 0)
return;
const int64_t network_bytes = insecure_network_bytes_ + secure_network_bytes_;
const int64_t network_bytes =
insecure_network_bytes() + secure_network_bytes();
const int64_t original_network_bytes =
insecure_original_network_bytes_ + secure_original_network_bytes_;
insecure_original_network_bytes() + secure_original_network_bytes();
// TODO(ryansturm): Evaluate if any of the below histograms are unncessary
// once data is available. crbug.com/682782
......@@ -272,13 +129,13 @@ void DataReductionProxyMetricsObserver::RecordPageSizeUMA() const {
// The percent of resources that went through the data reduction proxy.
UMA_HISTOGRAM_PERCENTAGE(
GetConstHistogramWithSuffix(internal::kResourcesPercentProxied),
(100 * num_data_reduction_proxy_resources_) / num_network_resources_);
(100 * num_data_reduction_proxy_resources()) / num_network_resources());
// The percent of bytes that went through the data reduction proxy.
if (network_bytes > 0) {
UMA_HISTOGRAM_PERCENTAGE(
GetConstHistogramWithSuffix(internal::kBytesPercentProxied),
static_cast<int>((100 * network_bytes_proxied_) / network_bytes));
static_cast<int>((100 * network_bytes_proxied()) / network_bytes));
}
// If the data reduction proxy caused savings, record the compression ratio;
......@@ -297,17 +154,17 @@ void DataReductionProxyMetricsObserver::RecordPageSizeUMA() const {
// Record the number of network resources seen.
PAGE_RESOURCE_COUNT_HISTOGRAM(
GetConstHistogramWithSuffix(internal::kNetworkResources),
num_network_resources_);
num_network_resources());
// Record the number of resources that used data reduction proxy.
PAGE_RESOURCE_COUNT_HISTOGRAM(
GetConstHistogramWithSuffix(internal::kResourcesProxied),
num_data_reduction_proxy_resources_);
num_data_reduction_proxy_resources());
// Record the number of resources that did not use data reduction proxy.
PAGE_RESOURCE_COUNT_HISTOGRAM(
GetConstHistogramWithSuffix(internal::kResourcesNotProxied),
num_network_resources_ - num_data_reduction_proxy_resources_);
num_network_resources() - num_data_reduction_proxy_resources());
// Record the total KB of network bytes.
PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kNetworkBytes),
......@@ -316,12 +173,12 @@ void DataReductionProxyMetricsObserver::RecordPageSizeUMA() const {
// Record the total amount of bytes that went through the data reduction
// proxy.
PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kBytesProxied),
network_bytes_proxied_);
network_bytes_proxied());
// Record the total amount of bytes that did not go through the data reduction
// proxy.
PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kBytesNotProxied),
network_bytes - network_bytes_proxied_);
network_bytes - network_bytes_proxied());
// Record the total KB of network bytes that the user would have seen without
// using data reduction proxy.
......@@ -335,127 +192,8 @@ void DataReductionProxyMetricsObserver::RecordPageSizeUMA() const {
original_network_bytes - network_bytes);
} else {
PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kBytesInflation),
network_bytes_proxied_ - original_network_bytes);
}
}
// static
int64_t DataReductionProxyMetricsObserver::ExponentiallyBucketBytes(
int64_t bytes) {
const int64_t start_buckets = 10000;
if (bytes < start_buckets) {
return 0;
}
return ukm::GetExponentialBucketMin(bytes, 1.16);
}
void DataReductionProxyMetricsObserver::SendPingback(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info,
bool app_background_occurred) {
// TODO(ryansturm): Move to OnFirstBackgroundEvent to handle some fast
// shutdown cases. crbug.com/618072
if (!browser_context_ || !data_)
return;
// Only consider timing events that happened before the first background
// event.
base::Optional<base::TimeDelta> response_start;
base::Optional<base::TimeDelta> load_event_start;
base::Optional<base::TimeDelta> first_image_paint;
base::Optional<base::TimeDelta> first_contentful_paint;
base::Optional<base::TimeDelta> experimental_first_meaningful_paint;
base::Optional<base::TimeDelta> first_input_delay;
base::Optional<base::TimeDelta> parse_blocked_on_script_load_duration;
base::Optional<base::TimeDelta> parse_stop;
base::Optional<base::TimeDelta> page_end_time;
if (WasStartedInForegroundOptionalEventInForeground(timing.response_start,
info)) {
response_start = timing.response_start;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.document_timing->load_event_start, info)) {
load_event_start = timing.document_timing->load_event_start;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.paint_timing->first_image_paint, info)) {
first_image_paint = timing.paint_timing->first_image_paint;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.paint_timing->first_contentful_paint, info)) {
first_contentful_paint = timing.paint_timing->first_contentful_paint;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.paint_timing->first_meaningful_paint, info)) {
experimental_first_meaningful_paint =
timing.paint_timing->first_meaningful_paint;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.interactive_timing->first_input_delay, info)) {
first_input_delay = timing.interactive_timing->first_input_delay;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.parse_timing->parse_blocked_on_script_load_duration, info)) {
parse_blocked_on_script_load_duration =
timing.parse_timing->parse_blocked_on_script_load_duration;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.parse_timing->parse_stop, info)) {
parse_stop = timing.parse_timing->parse_stop;
}
if (info.started_in_foreground && info.page_end_time.has_value()) {
// This should be reported even when the app goes into the background which
// is excluded in |WasStartedInForegroundOptionalEventInForeground|.
page_end_time = info.page_end_time;
} else if (info.started_in_foreground) {
page_end_time = base::TimeTicks::Now() - info.navigation_start;
}
// If a crash happens, report the host |render_process_host_id_| to the
// pingback client. Otherwise report kInvalidUniqueID.
int host_id = content::ChildProcessHost::kInvalidUniqueID;
if (info.page_end_reason ==
page_load_metrics::PageEndReason::END_RENDER_PROCESS_GONE) {
host_id = render_process_host_id_;
}
const int64_t original_network_bytes =
insecure_original_network_bytes_ +
ExponentiallyBucketBytes(secure_original_network_bytes_);
const int64_t network_bytes =
insecure_network_bytes_ + ExponentiallyBucketBytes(secure_network_bytes_);
const int64_t total_page_size_bytes =
insecure_network_bytes_ + insecure_cached_bytes_ +
ExponentiallyBucketBytes(secure_network_bytes_ + secure_cached_bytes_);
// Recording cached bytes can be done with raw data, but the end result must
// be bucketed in 50 linear buckets between 0% - 100%.
const int64_t cached_bytes = insecure_cached_bytes_ + secure_cached_bytes_;
const int64_t total_bytes =
cached_bytes + insecure_network_bytes_ + secure_network_bytes_;
int cached_percentage;
if (total_bytes <= 0) {
cached_percentage = 0;
} else {
cached_percentage =
static_cast<int>(std::lround(static_cast<float>(cached_bytes) /
static_cast<float>(total_bytes) * 100.0));
network_bytes_proxied() - original_network_bytes);
}
DCHECK_GE(cached_percentage, 0);
DCHECK_LE(cached_percentage, 100);
cached_percentage = cached_percentage - (cached_percentage % 2);
const float cached_fraction = static_cast<float>(cached_percentage) / 100.0;
DataReductionProxyPageLoadTiming data_reduction_proxy_timing(
timing.navigation_start, response_start, load_event_start,
first_image_paint, first_contentful_paint,
experimental_first_meaningful_paint, first_input_delay,
parse_blocked_on_script_load_duration, parse_stop, page_end_time,
navigation_start_to_main_frame_fetch_start_, network_bytes,
original_network_bytes, total_page_size_bytes, cached_fraction,
app_background_occurred, opted_out_, renderer_memory_usage_kb_, host_id,
ConvertPLMPageEndReasonToProto(info.page_end_reason), touch_count_,
scroll_count_, redirect_count_);
GetPingbackClient()->SendPingback(*data_, data_reduction_proxy_timing);
}
void DataReductionProxyMetricsObserver::OnDomContentLoadedEventStart(
......@@ -463,7 +201,7 @@ void DataReductionProxyMetricsObserver::OnDomContentLoadedEventStart(
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.document_timing->dom_content_loaded_event_start,
info, data(), timing.document_timing->dom_content_loaded_event_start,
::internal::kHistogramDOMContentLoadedEventFiredSuffix);
}
......@@ -471,15 +209,10 @@ void DataReductionProxyMetricsObserver::OnLoadEventStart(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DataReductionProxyMetricsObserverBase::OnLoadEventStart(timing, info);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.document_timing->load_event_start,
info, data(), timing.document_timing->load_event_start,
::internal::kHistogramLoadEventFiredSuffix);
if (process_id_ != base::kNullProcessId) {
auto callback = base::BindRepeating(
&DataReductionProxyMetricsObserver::ProcessMemoryDump,
weak_ptr_factory_.GetWeakPtr());
RequestProcessDump(process_id_, callback);
}
}
void DataReductionProxyMetricsObserver::OnFirstLayout(
......@@ -487,7 +220,7 @@ void DataReductionProxyMetricsObserver::OnFirstLayout(
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.document_timing->first_layout,
info, data(), timing.document_timing->first_layout,
::internal::kHistogramFirstLayoutSuffix);
}
......@@ -496,7 +229,7 @@ void DataReductionProxyMetricsObserver::OnFirstPaintInPage(
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.paint_timing->first_paint,
info, data(), timing.paint_timing->first_paint,
::internal::kHistogramFirstPaintSuffix);
}
......@@ -505,7 +238,7 @@ void DataReductionProxyMetricsObserver::OnFirstTextPaintInPage(
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.paint_timing->first_text_paint,
info, data(), timing.paint_timing->first_text_paint,
::internal::kHistogramFirstTextPaintSuffix);
}
......@@ -514,7 +247,7 @@ void DataReductionProxyMetricsObserver::OnFirstImagePaintInPage(
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.paint_timing->first_image_paint,
info, data(), timing.paint_timing->first_image_paint,
::internal::kHistogramFirstImagePaintSuffix);
}
......@@ -523,7 +256,7 @@ void DataReductionProxyMetricsObserver::OnFirstContentfulPaintInPage(
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.paint_timing->first_contentful_paint,
info, data(), timing.paint_timing->first_contentful_paint,
::internal::kHistogramFirstContentfulPaintSuffix);
}
......@@ -533,7 +266,7 @@ void DataReductionProxyMetricsObserver::
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.paint_timing->first_meaningful_paint,
info, data(), timing.paint_timing->first_meaningful_paint,
::internal::kHistogramFirstMeaningfulPaintSuffix);
}
......@@ -542,7 +275,7 @@ void DataReductionProxyMetricsObserver::OnParseStart(
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
info, data_, timing.parse_timing->parse_start,
info, data(), timing.parse_timing->parse_start,
::internal::kHistogramParseStartSuffix);
}
......@@ -556,125 +289,12 @@ void DataReductionProxyMetricsObserver::OnParseStop(
base::TimeDelta parse_duration = timing.parse_timing->parse_stop.value() -
timing.parse_timing->parse_start.value();
RECORD_HISTOGRAMS_FOR_SUFFIX(data_, parse_duration,
RECORD_HISTOGRAMS_FOR_SUFFIX(data(), parse_duration,
::internal::kHistogramParseDurationSuffix);
RECORD_HISTOGRAMS_FOR_SUFFIX(
data_, timing.parse_timing->parse_blocked_on_script_load_duration.value(),
data(),
timing.parse_timing->parse_blocked_on_script_load_duration.value(),
::internal::kHistogramParseBlockedOnScriptLoadSuffix);
}
void DataReductionProxyMetricsObserver::OnLoadedResource(
const page_load_metrics::ExtraRequestCompleteInfo&
extra_request_complete_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (extra_request_complete_info.data_reduction_proxy_data &&
extra_request_complete_info.data_reduction_proxy_data->lofi_received()) {
data_->set_lofi_received(true);
}
if (extra_request_complete_info.resource_type ==
content::RESOURCE_TYPE_MAIN_FRAME) {
navigation_start_to_main_frame_fetch_start_ =
extra_request_complete_info.load_timing_info->request_start -
navigation_start_;
}
}
void DataReductionProxyMetricsObserver::OnResourceDataUseObserved(
const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
resources) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto const& resource : resources) {
if (resource->was_fetched_via_cache) {
if (resource->is_complete) {
if (resource->is_secure_scheme) {
secure_cached_bytes_ += resource->encoded_body_length;
} else {
insecure_cached_bytes_ += resource->encoded_body_length;
}
}
continue;
}
int64_t original_network_bytes =
resource->delta_bytes *
resource->data_reduction_proxy_compression_ratio_estimate;
if (resource->is_secure_scheme) {
secure_original_network_bytes_ += original_network_bytes;
secure_network_bytes_ += resource->delta_bytes;
} else {
insecure_original_network_bytes_ += original_network_bytes;
insecure_network_bytes_ += resource->delta_bytes;
}
if (resource->is_complete)
num_network_resources_++;
// If the request is proxied on a page with data saver proxy for the main
// frame request, then it is very likely a data saver proxy for this
// request.
if (resource->proxy_used) {
if (resource->is_complete)
num_data_reduction_proxy_resources_++;
// Proxied bytes are always non-secure.
network_bytes_proxied_ += resource->delta_bytes;
}
}
}
DataReductionProxyPingbackClient*
DataReductionProxyMetricsObserver::GetPingbackClient() const {
return DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
browser_context_)
->data_reduction_proxy_service()
->pingback_client();
}
void DataReductionProxyMetricsObserver::OnEventOccurred(
const void* const event_key) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (event_key == PreviewsUITabHelper::OptOutEventKey())
opted_out_ = true;
}
void DataReductionProxyMetricsObserver::OnUserInput(
const blink::WebInputEvent& event) {
if (event.GetType() == blink::WebInputEvent::kMouseDown ||
event.GetType() == blink::WebInputEvent::kGestureTap) {
touch_count_++;
}
if (event.GetType() == blink::WebInputEvent::kMouseWheel ||
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
scroll_count_++;
}
}
void DataReductionProxyMetricsObserver::ProcessMemoryDump(
bool success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> memory_dump) {
if (!success || !memory_dump)
return;
// There should only be one process in the dump.
DCHECK_EQ(1, std::distance(memory_dump->process_dumps().begin(),
memory_dump->process_dumps().end()));
auto process_dump_it = memory_dump->process_dumps().begin();
if (process_dump_it == memory_dump->process_dumps().end())
return;
// We want to catch this in debug but not crash in release.
DCHECK_EQ(process_id_, process_dump_it->pid());
if (process_dump_it->pid() != process_id_)
return;
renderer_memory_usage_kb_ =
static_cast<int64_t>(process_dump_it->os_dump().private_footprint_kb);
}
void DataReductionProxyMetricsObserver::RequestProcessDump(
base::ProcessId pid,
memory_instrumentation::MemoryInstrumentation::RequestGlobalDumpCallback
callback) {
memory_instrumentation::MemoryInstrumentation::GetInstance()
->RequestPrivateMemoryFootprint(pid, std::move(callback));
}
} // namespace data_reduction_proxy
......@@ -5,27 +5,11 @@
#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_DATA_REDUCTION_PROXY_METRICS_OBSERVER_H_
#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_DATA_REDUCTION_PROXY_METRICS_OBSERVER_H_
#include <stdint.h>
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process_handle.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "services/metrics/public/cpp/ukm_source.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
namespace content {
class BrowserContext;
class NavigationHandle;
}
#include "chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.h"
namespace data_reduction_proxy {
class DataReductionProxyData;
class DataReductionProxyPingbackClient;
namespace internal {
......@@ -50,22 +34,15 @@ extern const char kBytesInflation[];
} // namespace internal
// Observer responsible for recording core page load metrics releveant to
// DataReductionProxy.
// Observer responsible for recording core page load metrics histograms relevant
// to DataReductionProxy.
class DataReductionProxyMetricsObserver
: public page_load_metrics::PageLoadMetricsObserver {
: public DataReductionProxyMetricsObserverBase {
public:
DataReductionProxyMetricsObserver();
~DataReductionProxyMetricsObserver() override;
// page_load_metrics::PageLoadMetricsObserver:
ObservePolicy OnStart(content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url,
bool started_in_foreground) override;
ObservePolicy OnRedirect(
content::NavigationHandle* navigation_handle) override;
ObservePolicy OnCommit(content::NavigationHandle* navigation_handle,
ukm::SourceId source_id) override;
ObservePolicy FlushMetricsOnAppEnterBackground(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) override;
......@@ -98,114 +75,11 @@ class DataReductionProxyMetricsObserver
const page_load_metrics::PageLoadExtraInfo& info) override;
void OnParseStop(const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) override;
void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo&
extra_request_compelte_info) override;
void OnResourceDataUseObserved(
const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
resources) override;
void OnEventOccurred(const void* const event_key) override;
void OnUserInput(const blink::WebInputEvent& event) override;
// Exponentially bucket the number of bytes for privacy-implicated resources.
// Input below 10KB returns 0.
static int64_t ExponentiallyBucketBytes(int64_t bytes);
private:
// Sends the page load information to the pingback client.
void SendPingback(const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info,
bool app_background_occurred);
// Records UMA of page size when the observer is about to be deleted.
void RecordPageSizeUMA() const;
// Gets the default DataReductionProxyPingbackClient. Overridden in testing.
virtual DataReductionProxyPingbackClient* GetPingbackClient() const;
// Used as a callback to getting a memory dump of the related renderer
// process.
void ProcessMemoryDump(
bool success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> memory_dump);
// Gets the memory coordinator for Chrome. Virtual for testing.
virtual void RequestProcessDump(
base::ProcessId pid,
memory_instrumentation::MemoryInstrumentation::RequestGlobalDumpCallback
callback);
// Data related to this navigation.
std::unique_ptr<DataReductionProxyData> data_;
// The browser context this navigation is operating in.
content::BrowserContext* browser_context_;
// True if a Preview opt out occurred during this page load.
bool opted_out_;
// The number of resources that used data reduction proxy.
int num_data_reduction_proxy_resources_;
// The number of resources that did not come from cache.
int num_network_resources_;
// The total content network bytes that the user would have downloaded if they
// were not using data reduction proxy for HTTP resources.
int64_t insecure_original_network_bytes_;
// The total content network bytes that the user would have downloaded if they
// were not using data reduction proxy for HTTPS resources.
int64_t secure_original_network_bytes_;
// The total network bytes loaded through data reduction proxy. This value
// only concerns HTTP traffic.
int64_t network_bytes_proxied_;
// The total network bytes used for HTTP resources.
int64_t insecure_network_bytes_;
// The total network bytes used for HTTPS resources.
int64_t secure_network_bytes_;
// The total cached bytes used for HTTP resources.
int64_t insecure_cached_bytes_;
// The total cached bytes used for HTTPS resources.
int64_t secure_cached_bytes_;
// The process ID of the main frame renderer during OnCommit.
base::ProcessId process_id_;
// The memory usage of the main frame renderer shortly after OnLoadEventStart.
// Available after ProcessMemoryDump is called. 0 before that point.
int64_t renderer_memory_usage_kb_;
// A unique identifier to the child process of the render frame, stored in
// case of a renderer crash.
// Set at navigation commit time.
int render_process_host_id_;
// The number of touch events on the page.
uint32_t touch_count_;
// The number of scroll events on the page.
uint32_t scroll_count_;
// The number of main frame redirects that occurred before commit.
uint32_t redirect_count_;
// The time when the navigation started. Used to estimate
// |navigation_start_to_main_frame_fetch_start_|.
base::TimeTicks navigation_start_;
// The duration between the navigation start as reported by the navigation
// handle, and when the fetchStart of the main page HTML.
base::TimeDelta navigation_start_to_main_frame_fetch_start_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<DataReductionProxyMetricsObserver> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyMetricsObserver);
};
......
// Copyright 2018 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 "chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.h"
#include <string>
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "chrome/browser/loader/chrome_navigation_data.h"
#include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
#include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
#include "chrome/browser/previews/previews_ui_tab_helper.h"
#include "chrome/common/page_load_metrics/page_load_timing.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/proto/pageload_metrics.pb.h"
#include "components/previews/content/previews_user_data.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_data.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h"
#include "services/metrics/public/cpp/metrics_utils.h"
#include "url/gurl.h"
namespace data_reduction_proxy {
namespace {
PageloadMetrics_PageEndReason ConvertPLMPageEndReasonToProto(
page_load_metrics::PageEndReason reason) {
switch (reason) {
case page_load_metrics::END_NONE:
return PageloadMetrics_PageEndReason_END_NONE;
case page_load_metrics::END_RELOAD:
return PageloadMetrics_PageEndReason_END_RELOAD;
case page_load_metrics::END_FORWARD_BACK:
return PageloadMetrics_PageEndReason_END_FORWARD_BACK;
case page_load_metrics::END_CLIENT_REDIRECT:
return PageloadMetrics_PageEndReason_END_CLIENT_REDIRECT;
case page_load_metrics::END_NEW_NAVIGATION:
return PageloadMetrics_PageEndReason_END_NEW_NAVIGATION;
case page_load_metrics::END_STOP:
return PageloadMetrics_PageEndReason_END_STOP;
case page_load_metrics::END_CLOSE:
return PageloadMetrics_PageEndReason_END_CLOSE;
case page_load_metrics::END_PROVISIONAL_LOAD_FAILED:
return PageloadMetrics_PageEndReason_END_PROVISIONAL_LOAD_FAILED;
case page_load_metrics::END_RENDER_PROCESS_GONE:
return PageloadMetrics_PageEndReason_END_RENDER_PROCESS_GONE;
default:
return PageloadMetrics_PageEndReason_END_OTHER;
}
}
} // namespace
DataReductionProxyMetricsObserverBase::DataReductionProxyMetricsObserverBase()
: browser_context_(nullptr),
opted_out_(false),
num_data_reduction_proxy_resources_(0),
num_network_resources_(0),
insecure_original_network_bytes_(0),
secure_original_network_bytes_(0),
network_bytes_proxied_(0),
insecure_network_bytes_(0),
secure_network_bytes_(0),
insecure_cached_bytes_(0),
secure_cached_bytes_(0),
process_id_(base::kNullProcessId),
renderer_memory_usage_kb_(0),
render_process_host_id_(content::ChildProcessHost::kInvalidUniqueID),
touch_count_(0),
scroll_count_(0),
redirect_count_(0),
weak_ptr_factory_(this) {}
DataReductionProxyMetricsObserverBase::
~DataReductionProxyMetricsObserverBase() {}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
DataReductionProxyMetricsObserverBase::OnRedirect(
content::NavigationHandle* navigation_handle) {
redirect_count_++;
return CONTINUE_OBSERVING;
}
// Check if the NavigationData indicates anything about the DataReductionProxy.
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
DataReductionProxyMetricsObserverBase::OnCommit(
content::NavigationHandle* navigation_handle,
ukm::SourceId source_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This BrowserContext is valid for the lifetime of
// DataReductionProxyMetricsObserverBase. BrowserContext is always valid and
// non-nullptr in NavigationControllerImpl, which is a member of WebContents.
// A raw pointer to BrowserContext taken at this point will be valid until
// after WebContent's destructor. The latest that PageLoadTracker's destructor
// will be called is in MetricsWebContentsObserver's destrcutor, which is
// called in WebContents destructor.
browser_context_ = navigation_handle->GetWebContents()->GetBrowserContext();
// As documented in content/public/browser/navigation_handle.h, this
// NavigationData is a clone of the NavigationData instance returned from
// ResourceDispatcherHostDelegate::GetNavigationData during commit.
// Because ChromeResourceDispatcherHostDelegate always returns a
// ChromeNavigationData, it is safe to static_cast here.
std::unique_ptr<DataReductionProxyData> data;
auto* settings =
DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
browser_context_);
if (settings) {
data = settings->CreateDataFromNavigationHandle(
navigation_handle, navigation_handle->GetResponseHeaders());
}
if (!data || !(data->used_data_reduction_proxy() ||
data->was_cached_data_reduction_proxy_response())) {
return STOP_OBSERVING;
}
data_ = std::move(data);
PreviewsUITabHelper* ui_tab_helper =
PreviewsUITabHelper::FromWebContents(navigation_handle->GetWebContents());
previews::PreviewsUserData* previews_data = nullptr;
if (ui_tab_helper)
previews_data = ui_tab_helper->GetPreviewsUserData(navigation_handle);
if (previews_data) {
data_->set_black_listed(previews_data->black_listed_for_lite_page());
}
process_id_ = navigation_handle->GetWebContents()
->GetMainFrame()
->GetProcess()
->GetProcess()
.Pid();
render_process_host_id_ = navigation_handle->GetWebContents()
->GetMainFrame()
->GetProcess()
->GetID();
navigation_start_ = navigation_handle->NavigationStart();
// DataReductionProxy page loads should only occur on HTTP navigations.
DCHECK(!navigation_handle->GetURL().SchemeIsCryptographic());
DCHECK_EQ(data_->request_url(), navigation_handle->GetURL());
return CONTINUE_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
DataReductionProxyMetricsObserverBase::OnStart(
content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url,
bool started_in_foreground) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!started_in_foreground)
return STOP_OBSERVING;
return CONTINUE_OBSERVING;
}
page_load_metrics::PageLoadMetricsObserver::ObservePolicy
DataReductionProxyMetricsObserverBase::FlushMetricsOnAppEnterBackground(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// FlushMetricsOnAppEnterBackground is invoked on Android in cases where the
// app is about to be backgrounded, as part of the Activity.onPause()
// flow. After this method is invoked, Chrome may be killed without further
// notification, so we send a pingback with data collected up to this point.
if (info.did_commit) {
SendPingback(timing, info, true /* app_background_occurred */);
}
return STOP_OBSERVING;
}
void DataReductionProxyMetricsObserverBase::OnComplete(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
SendPingback(timing, info, false /* app_background_occurred */);
}
// static
int64_t DataReductionProxyMetricsObserverBase::ExponentiallyBucketBytes(
int64_t bytes) {
const int64_t start_buckets = 10000;
if (bytes < start_buckets) {
return 0;
}
return ukm::GetExponentialBucketMin(bytes, 1.16);
}
void DataReductionProxyMetricsObserverBase::SendPingback(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info,
bool app_background_occurred) {
// TODO(ryansturm): Move to OnFirstBackgroundEvent to handle some fast
// shutdown cases. crbug.com/618072
if (!browser_context_ || !data_)
return;
// Only consider timing events that happened before the first background
// event.
base::Optional<base::TimeDelta> response_start;
base::Optional<base::TimeDelta> load_event_start;
base::Optional<base::TimeDelta> first_image_paint;
base::Optional<base::TimeDelta> first_contentful_paint;
base::Optional<base::TimeDelta> experimental_first_meaningful_paint;
base::Optional<base::TimeDelta> first_input_delay;
base::Optional<base::TimeDelta> parse_blocked_on_script_load_duration;
base::Optional<base::TimeDelta> parse_stop;
base::Optional<base::TimeDelta> page_end_time;
if (WasStartedInForegroundOptionalEventInForeground(timing.response_start,
info)) {
response_start = timing.response_start;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.document_timing->load_event_start, info)) {
load_event_start = timing.document_timing->load_event_start;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.paint_timing->first_image_paint, info)) {
first_image_paint = timing.paint_timing->first_image_paint;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.paint_timing->first_contentful_paint, info)) {
first_contentful_paint = timing.paint_timing->first_contentful_paint;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.paint_timing->first_meaningful_paint, info)) {
experimental_first_meaningful_paint =
timing.paint_timing->first_meaningful_paint;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.interactive_timing->first_input_delay, info)) {
first_input_delay = timing.interactive_timing->first_input_delay;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.parse_timing->parse_blocked_on_script_load_duration, info)) {
parse_blocked_on_script_load_duration =
timing.parse_timing->parse_blocked_on_script_load_duration;
}
if (WasStartedInForegroundOptionalEventInForeground(
timing.parse_timing->parse_stop, info)) {
parse_stop = timing.parse_timing->parse_stop;
}
if (info.started_in_foreground && info.page_end_time.has_value()) {
// This should be reported even when the app goes into the background which
// is excluded in |WasStartedInForegroundOptionalEventInForeground|.
page_end_time = info.page_end_time;
} else if (info.started_in_foreground) {
page_end_time = base::TimeTicks::Now() - info.navigation_start;
}
// If a crash happens, report the host |render_process_host_id_| to the
// pingback client. Otherwise report kInvalidUniqueID.
int host_id = content::ChildProcessHost::kInvalidUniqueID;
if (info.page_end_reason ==
page_load_metrics::PageEndReason::END_RENDER_PROCESS_GONE) {
host_id = render_process_host_id_;
}
const int64_t original_network_bytes =
insecure_original_network_bytes_ +
ExponentiallyBucketBytes(secure_original_network_bytes_);
const int64_t network_bytes =
insecure_network_bytes_ + ExponentiallyBucketBytes(secure_network_bytes_);
const int64_t total_page_size_bytes =
insecure_network_bytes_ + insecure_cached_bytes_ +
ExponentiallyBucketBytes(secure_network_bytes_ + secure_cached_bytes_);
// Recording cached bytes can be done with raw data, but the end result must
// be bucketed in 50 linear buckets between 0% - 100%.
const int64_t cached_bytes = insecure_cached_bytes_ + secure_cached_bytes_;
const int64_t total_bytes =
cached_bytes + insecure_network_bytes_ + secure_network_bytes_;
int cached_percentage;
if (total_bytes <= 0) {
cached_percentage = 0;
} else {
cached_percentage =
static_cast<int>(std::lround(static_cast<float>(cached_bytes) /
static_cast<float>(total_bytes) * 100.0));
}
DCHECK_GE(cached_percentage, 0);
DCHECK_LE(cached_percentage, 100);
cached_percentage = cached_percentage - (cached_percentage % 2);
const float cached_fraction = static_cast<float>(cached_percentage) / 100.0;
DataReductionProxyPageLoadTiming data_reduction_proxy_timing(
timing.navigation_start, response_start, load_event_start,
first_image_paint, first_contentful_paint,
experimental_first_meaningful_paint, first_input_delay,
parse_blocked_on_script_load_duration, parse_stop, page_end_time,
navigation_start_to_main_frame_fetch_start_, network_bytes,
original_network_bytes, total_page_size_bytes, cached_fraction,
app_background_occurred, opted_out_, renderer_memory_usage_kb_, host_id,
ConvertPLMPageEndReasonToProto(info.page_end_reason), touch_count_,
scroll_count_, redirect_count_);
GetPingbackClient()->SendPingback(*data_, data_reduction_proxy_timing);
}
void DataReductionProxyMetricsObserverBase::OnLoadEventStart(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (process_id_ != base::kNullProcessId) {
auto callback = base::BindRepeating(
&DataReductionProxyMetricsObserverBase::ProcessMemoryDump,
weak_ptr_factory_.GetWeakPtr());
RequestProcessDump(process_id_, callback);
}
}
void DataReductionProxyMetricsObserverBase::OnLoadedResource(
const page_load_metrics::ExtraRequestCompleteInfo&
extra_request_complete_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (extra_request_complete_info.data_reduction_proxy_data &&
extra_request_complete_info.data_reduction_proxy_data->lofi_received()) {
data_->set_lofi_received(true);
}
if (extra_request_complete_info.resource_type ==
content::RESOURCE_TYPE_MAIN_FRAME) {
navigation_start_to_main_frame_fetch_start_ =
extra_request_complete_info.load_timing_info->request_start -
navigation_start_;
}
}
void DataReductionProxyMetricsObserverBase::OnResourceDataUseObserved(
const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
resources) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto const& resource : resources) {
if (resource->was_fetched_via_cache) {
if (resource->is_complete) {
if (resource->is_secure_scheme) {
secure_cached_bytes_ += resource->encoded_body_length;
} else {
insecure_cached_bytes_ += resource->encoded_body_length;
}
}
continue;
}
int64_t original_network_bytes =
resource->delta_bytes *
resource->data_reduction_proxy_compression_ratio_estimate;
if (resource->is_secure_scheme) {
secure_original_network_bytes_ += original_network_bytes;
secure_network_bytes_ += resource->delta_bytes;
} else {
insecure_original_network_bytes_ += original_network_bytes;
insecure_network_bytes_ += resource->delta_bytes;
}
if (resource->is_complete)
num_network_resources_++;
// If the request is proxied on a page with data saver proxy for the main
// frame request, then it is very likely a data saver proxy for this
// request.
if (resource->proxy_used) {
if (resource->is_complete)
num_data_reduction_proxy_resources_++;
// Proxied bytes are always non-secure.
network_bytes_proxied_ += resource->delta_bytes;
}
}
}
DataReductionProxyPingbackClient*
DataReductionProxyMetricsObserverBase::GetPingbackClient() const {
return DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
browser_context_)
->data_reduction_proxy_service()
->pingback_client();
}
void DataReductionProxyMetricsObserverBase::OnEventOccurred(
const void* const event_key) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (event_key == PreviewsUITabHelper::OptOutEventKey())
opted_out_ = true;
}
void DataReductionProxyMetricsObserverBase::OnUserInput(
const blink::WebInputEvent& event) {
if (event.GetType() == blink::WebInputEvent::kMouseDown ||
event.GetType() == blink::WebInputEvent::kGestureTap) {
touch_count_++;
}
if (event.GetType() == blink::WebInputEvent::kMouseWheel ||
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
scroll_count_++;
}
}
void DataReductionProxyMetricsObserverBase::ProcessMemoryDump(
bool success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> memory_dump) {
if (!success || !memory_dump)
return;
// There should only be one process in the dump.
DCHECK_EQ(1, std::distance(memory_dump->process_dumps().begin(),
memory_dump->process_dumps().end()));
auto process_dump_it = memory_dump->process_dumps().begin();
if (process_dump_it == memory_dump->process_dumps().end())
return;
// We want to catch this in debug but not crash in release.
DCHECK_EQ(process_id_, process_dump_it->pid());
if (process_dump_it->pid() != process_id_)
return;
renderer_memory_usage_kb_ =
static_cast<int64_t>(process_dump_it->os_dump().private_footprint_kb);
}
void DataReductionProxyMetricsObserverBase::RequestProcessDump(
base::ProcessId pid,
memory_instrumentation::MemoryInstrumentation::RequestGlobalDumpCallback
callback) {
memory_instrumentation::MemoryInstrumentation::GetInstance()
->RequestPrivateMemoryFootprint(pid, std::move(callback));
}
} // namespace data_reduction_proxy
// Copyright 2018 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 CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_DATA_REDUCTION_PROXY_METRICS_OBSERVER_BASE_H_
#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_DATA_REDUCTION_PROXY_METRICS_OBSERVER_BASE_H_
#include <stdint.h>
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process_handle.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
namespace content {
class BrowserContext;
class NavigationHandle;
} // namespace content
namespace data_reduction_proxy {
class DataReductionProxyData;
class DataReductionProxyPingbackClient;
// Observer responsible for recording core page load metrics relevant to
// DataReductionProxy's pingback.
class DataReductionProxyMetricsObserverBase
: public page_load_metrics::PageLoadMetricsObserver {
public:
DataReductionProxyMetricsObserverBase();
~DataReductionProxyMetricsObserverBase() override;
// page_load_metrics::PageLoadMetricsObserver:
ObservePolicy OnStart(content::NavigationHandle* navigation_handle,
const GURL& currently_committed_url,
bool started_in_foreground) override;
ObservePolicy OnRedirect(
content::NavigationHandle* navigation_handle) override;
ObservePolicy OnCommit(content::NavigationHandle* navigation_handle,
ukm::SourceId source_id) override;
ObservePolicy FlushMetricsOnAppEnterBackground(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) override;
void OnComplete(const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) override;
void OnLoadEventStart(
const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info) override;
void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo&
extra_request_compelte_info) override;
void OnResourceDataUseObserved(
const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
resources) override;
void OnEventOccurred(const void* const event_key) override;
void OnUserInput(const blink::WebInputEvent& event) override;
// Exponentially bucket the number of bytes for privacy-implicated resources.
// Input below 10KB returns 0.
static int64_t ExponentiallyBucketBytes(int64_t bytes);
protected:
DataReductionProxyData* data() const { return data_.get(); }
int num_network_resources() const { return num_network_resources_; }
int num_data_reduction_proxy_resources() const {
return num_data_reduction_proxy_resources_;
}
int64_t network_bytes_proxied() const { return network_bytes_proxied_; }
int64_t insecure_network_bytes() const { return insecure_network_bytes_; }
int64_t secure_network_bytes() const { return secure_network_bytes_; }
int64_t insecure_original_network_bytes() const {
return insecure_original_network_bytes_;
}
int64_t secure_original_network_bytes() const {
return secure_original_network_bytes_;
}
SEQUENCE_CHECKER(sequence_checker_);
private:
// Sends the page load information to the pingback client.
void SendPingback(const page_load_metrics::mojom::PageLoadTiming& timing,
const page_load_metrics::PageLoadExtraInfo& info,
bool app_background_occurred);
// Gets the default DataReductionProxyPingbackClient. Overridden in testing.
virtual DataReductionProxyPingbackClient* GetPingbackClient() const;
// Used as a callback to getting a memory dump of the related renderer
// process.
void ProcessMemoryDump(
bool success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> memory_dump);
// Gets the memory coordinator for Chrome. Virtual for testing.
virtual void RequestProcessDump(
base::ProcessId pid,
memory_instrumentation::MemoryInstrumentation::RequestGlobalDumpCallback
callback);
// Data related to this navigation.
std::unique_ptr<DataReductionProxyData> data_;
// The browser context this navigation is operating in.
content::BrowserContext* browser_context_;
// True if a Preview opt out occurred during this page load.
bool opted_out_;
// The number of resources that used data reduction proxy.
int num_data_reduction_proxy_resources_;
// The number of resources that did not come from cache.
int num_network_resources_;
// The total content network bytes that the user would have downloaded if they
// were not using data reduction proxy for HTTP resources.
int64_t insecure_original_network_bytes_;
// The total content network bytes that the user would have downloaded if they
// were not using data reduction proxy for HTTPS resources.
int64_t secure_original_network_bytes_;
// The total network bytes loaded through data reduction proxy. This value
// only concerns HTTP traffic.
int64_t network_bytes_proxied_;
// The total network bytes used for HTTP resources.
int64_t insecure_network_bytes_;
// The total network bytes used for HTTPS resources.
int64_t secure_network_bytes_;
// The total cached bytes used for HTTP resources.
int64_t insecure_cached_bytes_;
// The total cached bytes used for HTTPS resources.
int64_t secure_cached_bytes_;
// The process ID of the main frame renderer during OnCommit.
base::ProcessId process_id_;
// The memory usage of the main frame renderer shortly after OnLoadEventStart.
// Available after ProcessMemoryDump is called. 0 before that point.
int64_t renderer_memory_usage_kb_;
// A unique identifier to the child process of the render frame, stored in
// case of a renderer crash.
// Set at navigation commit time.
int render_process_host_id_;
// The number of touch events on the page.
uint32_t touch_count_;
// The number of scroll events on the page.
uint32_t scroll_count_;
// The number of main frame redirects that occurred before commit.
uint32_t redirect_count_;
// The time when the navigation started. Used to estimate
// |navigation_start_to_main_frame_fetch_start_|.
base::TimeTicks navigation_start_;
// The duration between the navigation start as reported by the navigation
// handle, and when the fetchStart of the main page HTML.
base::TimeDelta navigation_start_to_main_frame_fetch_start_;
base::WeakPtrFactory<DataReductionProxyMetricsObserverBase> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyMetricsObserverBase);
};
} // namespace data_reduction_proxy
#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_DATA_REDUCTION_PROXY_METRICS_OBSERVER_BASE_H_
// Copyright 2018 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 "chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_base.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/optional.h"
#include "base/process/kill.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chrome/browser/loader/chrome_navigation_data.h"
#include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
#include "chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.h"
#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "chrome/browser/page_load_metrics/page_load_tracker.h"
#include "chrome/browser/previews/previews_ui_tab_helper.h"
#include "chrome/common/page_load_metrics/page_load_timing.h"
#include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/previews/content/previews_user_data.h"
#include "content/public/test/web_contents_tester.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "third_party/blink/public/platform/web_input_event.h"
namespace data_reduction_proxy {
namespace {
// DataReductionProxyMetricsObserver responsible for modifying data about the
// navigation in OnCommit. It is also responsible for using a passed in
// DataReductionProxyPingbackClient instead of the default.
class TestDataReductionProxyMetricsObserverBase
: public DataReductionProxyMetricsObserverBase {
public:
TestDataReductionProxyMetricsObserverBase(
content::WebContents* web_contents,
TestPingbackClient* pingback_client,
bool data_reduction_proxy_used,
bool cached_data_reduction_proxy_used,
bool lite_page_used,
bool black_listed)
: web_contents_(web_contents),
pingback_client_(pingback_client),
data_reduction_proxy_used_(data_reduction_proxy_used),
cached_data_reduction_proxy_used_(cached_data_reduction_proxy_used),
lite_page_used_(lite_page_used),
black_listed_(black_listed) {}
~TestDataReductionProxyMetricsObserverBase() override {}
// page_load_metrics::PageLoadMetricsObserver:
ObservePolicy OnCommit(content::NavigationHandle* navigation_handle,
ukm::SourceId source_id) override {
DataReductionProxyData* data =
DataForNavigationHandle(web_contents_, navigation_handle);
data->set_used_data_reduction_proxy(data_reduction_proxy_used_);
data->set_was_cached_data_reduction_proxy_response(
cached_data_reduction_proxy_used_);
data->set_request_url(GURL(kDefaultTestUrl));
data->set_lite_page_received(lite_page_used_);
auto* previews_data = PreviewsDataForNavigationHandle(navigation_handle);
previews_data->set_black_listed_for_lite_page(black_listed_);
return DataReductionProxyMetricsObserverBase::OnCommit(navigation_handle,
source_id);
}
DataReductionProxyPingbackClient* GetPingbackClient() const override {
return pingback_client_;
}
void RequestProcessDump(
base::ProcessId pid,
memory_instrumentation::MemoryInstrumentation::RequestGlobalDumpCallback
callback) override {
memory_instrumentation::mojom::GlobalMemoryDumpPtr global_dump(
memory_instrumentation::mojom::GlobalMemoryDump::New());
memory_instrumentation::mojom::ProcessMemoryDumpPtr pmd(
memory_instrumentation::mojom::ProcessMemoryDump::New());
pmd->pid = pid;
pmd->process_type = memory_instrumentation::mojom::ProcessType::RENDERER;
pmd->os_dump = memory_instrumentation::mojom::OSMemDump::New();
pmd->os_dump->private_footprint_kb = kMemoryKb;
global_dump->process_dumps.push_back(std::move(pmd));
std::move(callback).Run(true,
memory_instrumentation::GlobalMemoryDump::MoveFrom(
std::move(global_dump)));
}
private:
content::WebContents* web_contents_;
TestPingbackClient* pingback_client_;
bool data_reduction_proxy_used_;
bool cached_data_reduction_proxy_used_;
bool lite_page_used_;
bool black_listed_;
DISALLOW_COPY_AND_ASSIGN(TestDataReductionProxyMetricsObserverBase);
};
class DataReductionProxyMetricsObserverBaseTest
: public DataReductionProxyMetricsObserverTestBase {
protected:
void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
tracker->AddObserver(
std::make_unique<TestDataReductionProxyMetricsObserverBase>(
web_contents(), pingback_client(), data_reduction_proxy_used(),
cached_data_reduction_proxy_used(), is_using_lite_page(),
black_listed()));
}
};
} // namespace
TEST_F(DataReductionProxyMetricsObserverBaseTest, OnCompletePingback) {
ResetTest();
// Verify that when data reduction proxy was used the correct timing
// information is sent to SendPingback.
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ResetTest();
// Verify that when data reduction proxy was used but first image paint is
// unset, the correct timing information is sent to SendPingback.
timing()->paint_timing->first_image_paint = base::nullopt;
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ResetTest();
// Verify that when data reduction proxy was used but first contentful paint
// is unset, SendPingback is not called.
timing()->paint_timing->first_contentful_paint = base::nullopt;
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ResetTest();
// Verify that when data reduction proxy was used but first meaningful paint
// is unset, SendPingback is not called.
timing()->paint_timing->first_meaningful_paint = base::nullopt;
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ResetTest();
// Verify that when data reduction proxy was used but load event start is
// unset, SendPingback is not called.
timing()->document_timing->load_event_start = base::nullopt;
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ValidateLoFiInPingback(false);
ResetTest();
// Verify that when an opt out occurs, that it is reported in the pingback.
timing()->document_timing->load_event_start = base::nullopt;
RunTest(true, true, true, false);
observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
NavigateToUntrackedUrl();
ValidateTimes();
ValidateLoFiInPingback(false);
ResetTest();
std::unique_ptr<DataReductionProxyData> data =
std::make_unique<DataReductionProxyData>();
data->set_used_data_reduction_proxy(true);
data->set_request_url(GURL(kDefaultTestUrl));
data->set_lofi_received(true);
// Verify LoFi is tracked when a LoFi response is received.
page_load_metrics::ExtraRequestCompleteInfo resource = {
GURL(kResourceUrl),
net::HostPortPair(),
-1 /* frame_tree_node_id */,
true /*was_cached*/,
1024 * 40 /* raw_body_bytes */,
0 /* original_network_content_length */,
std::move(data),
content::ResourceType::RESOURCE_TYPE_SCRIPT,
0,
{} /* load_timing()info */};
RunTest(true, false, false, false);
SimulateLoadedResource(resource);
NavigateToUntrackedUrl();
ValidateTimes();
ValidateLoFiInPingback(true);
ValidateBlackListInPingback(false);
ResetTest();
RunTest(true, false, false, true);
NavigateToUntrackedUrl();
ValidateBlackListInPingback(true);
ResetTest();
// Verify that when data reduction proxy was not used, SendPingback is not
// called.
RunTestAndNavigateToUntrackedUrl(false, false, false);
EXPECT_FALSE(pingback_client_->send_pingback_called());
ResetTest();
cached_data_reduction_proxy_used_ = true;
RunTestAndNavigateToUntrackedUrl(false, false, false);
EXPECT_TRUE(pingback_client_->send_pingback_called());
cached_data_reduction_proxy_used_ = false;
ResetTest();
// Verify that when the holdback experiment is enabled, a pingback is sent.
base::FieldTrialList field_trial_list(nullptr);
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"DataCompressionProxyHoldback", "Enabled"));
RunTestAndNavigateToUntrackedUrl(true, false, false);
EXPECT_TRUE(pingback_client_->send_pingback_called());
}
TEST_F(DataReductionProxyMetricsObserverBaseTest, TouchScrollEventCount) {
struct TestCase {
std::vector<FakeInputEvent> events;
uint32_t want_touch;
uint32_t want_scroll;
};
const TestCase test_cases[] = {
{
// Test zero value.
{},
0 /* want_touch */,
0 /* want_scroll */,
},
{
// Test all inputs, should only count the ones we care about.
{
FakeInputEvent(blink::WebInputEvent::kMouseDown),
FakeInputEvent(blink::WebInputEvent::kMouseUp),
FakeInputEvent(blink::WebInputEvent::kMouseMove),
FakeInputEvent(blink::WebInputEvent::kMouseEnter),
FakeInputEvent(blink::WebInputEvent::kMouseLeave),
FakeInputEvent(blink::WebInputEvent::kContextMenu),
FakeInputEvent(blink::WebInputEvent::kMouseWheel),
FakeInputEvent(blink::WebInputEvent::kRawKeyDown),
FakeInputEvent(blink::WebInputEvent::kKeyDown),
FakeInputEvent(blink::WebInputEvent::kKeyUp),
FakeInputEvent(blink::WebInputEvent::kChar),
FakeInputEvent(blink::WebInputEvent::kGestureScrollBegin),
FakeInputEvent(blink::WebInputEvent::kGestureScrollEnd),
FakeInputEvent(blink::WebInputEvent::kGestureScrollUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureFlingStart),
FakeInputEvent(blink::WebInputEvent::kGestureFlingCancel),
FakeInputEvent(blink::WebInputEvent::kGesturePinchBegin),
FakeInputEvent(blink::WebInputEvent::kGesturePinchEnd),
FakeInputEvent(blink::WebInputEvent::kGesturePinchUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureTapDown),
FakeInputEvent(blink::WebInputEvent::kGestureShowPress),
FakeInputEvent(blink::WebInputEvent::kGestureTap),
FakeInputEvent(blink::WebInputEvent::kGestureTapCancel),
FakeInputEvent(blink::WebInputEvent::kGestureLongPress),
FakeInputEvent(blink::WebInputEvent::kGestureLongTap),
FakeInputEvent(blink::WebInputEvent::kGestureTwoFingerTap),
FakeInputEvent(blink::WebInputEvent::kGestureTapUnconfirmed),
FakeInputEvent(blink::WebInputEvent::kGestureDoubleTap),
FakeInputEvent(blink::WebInputEvent::kTouchStart),
FakeInputEvent(blink::WebInputEvent::kTouchMove),
FakeInputEvent(blink::WebInputEvent::kTouchEnd),
FakeInputEvent(blink::WebInputEvent::kTouchCancel),
FakeInputEvent(blink::WebInputEvent::kTouchScrollStarted),
FakeInputEvent(blink::WebInputEvent::kPointerDown),
FakeInputEvent(blink::WebInputEvent::kPointerUp),
FakeInputEvent(blink::WebInputEvent::kPointerMove),
FakeInputEvent(blink::WebInputEvent::kPointerCancel),
FakeInputEvent(blink::WebInputEvent::kPointerCausedUaAction),
},
2 /* want_touch */,
3 /* want_scroll */,
},
{
// Test all inputs, with the ones we care about repeated.
{
FakeInputEvent(blink::WebInputEvent::kMouseDown),
FakeInputEvent(blink::WebInputEvent::kMouseUp),
FakeInputEvent(blink::WebInputEvent::kMouseMove),
FakeInputEvent(blink::WebInputEvent::kMouseEnter),
FakeInputEvent(blink::WebInputEvent::kMouseLeave),
FakeInputEvent(blink::WebInputEvent::kContextMenu),
FakeInputEvent(blink::WebInputEvent::kMouseWheel),
FakeInputEvent(blink::WebInputEvent::kRawKeyDown),
FakeInputEvent(blink::WebInputEvent::kKeyDown),
FakeInputEvent(blink::WebInputEvent::kKeyUp),
FakeInputEvent(blink::WebInputEvent::kChar),
FakeInputEvent(blink::WebInputEvent::kGestureScrollBegin),
FakeInputEvent(blink::WebInputEvent::kGestureScrollEnd),
FakeInputEvent(blink::WebInputEvent::kGestureScrollUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureFlingStart),
FakeInputEvent(blink::WebInputEvent::kGestureFlingCancel),
FakeInputEvent(blink::WebInputEvent::kGesturePinchBegin),
FakeInputEvent(blink::WebInputEvent::kGesturePinchEnd),
FakeInputEvent(blink::WebInputEvent::kGesturePinchUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureTapDown),
FakeInputEvent(blink::WebInputEvent::kGestureShowPress),
FakeInputEvent(blink::WebInputEvent::kGestureTap),
FakeInputEvent(blink::WebInputEvent::kGestureTapCancel),
FakeInputEvent(blink::WebInputEvent::kGestureLongPress),
FakeInputEvent(blink::WebInputEvent::kGestureLongTap),
FakeInputEvent(blink::WebInputEvent::kGestureTwoFingerTap),
FakeInputEvent(blink::WebInputEvent::kGestureTapUnconfirmed),
FakeInputEvent(blink::WebInputEvent::kGestureDoubleTap),
FakeInputEvent(blink::WebInputEvent::kTouchStart),
FakeInputEvent(blink::WebInputEvent::kTouchMove),
FakeInputEvent(blink::WebInputEvent::kTouchEnd),
FakeInputEvent(blink::WebInputEvent::kTouchCancel),
FakeInputEvent(blink::WebInputEvent::kTouchScrollStarted),
FakeInputEvent(blink::WebInputEvent::kPointerDown),
FakeInputEvent(blink::WebInputEvent::kPointerUp),
FakeInputEvent(blink::WebInputEvent::kPointerMove),
FakeInputEvent(blink::WebInputEvent::kPointerCancel),
FakeInputEvent(blink::WebInputEvent::kPointerCausedUaAction),
// Repeat.
FakeInputEvent(blink::WebInputEvent::kMouseDown),
FakeInputEvent(blink::WebInputEvent::kGestureTap),
FakeInputEvent(blink::WebInputEvent::kMouseWheel),
FakeInputEvent(blink::WebInputEvent::kGestureScrollUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureFlingStart),
},
4 /* want_touch */,
6 /* want_scroll */,
},
};
for (const TestCase& test_case : test_cases) {
ResetTest();
RunTest(true, false, false, false);
for (const blink::WebInputEvent& event : test_case.events)
SimulateInputEvent(event);
NavigateToUntrackedUrl();
EXPECT_EQ(pingback_client_->timing()->touch_count, test_case.want_touch);
EXPECT_EQ(pingback_client_->timing()->scroll_count, test_case.want_scroll);
}
}
TEST_F(DataReductionProxyMetricsObserverBaseTest,
ProcessIdSentOnRendererCrash) {
ResetTest();
RunTest(true, false, false, false);
std::unique_ptr<DataReductionProxyData> data =
std::make_unique<DataReductionProxyData>();
data->set_used_data_reduction_proxy(true);
data->set_request_url(GURL(kDefaultTestUrl));
SimulateRendererCrash();
// When the renderer crashes, the pingback should report that.
ValidateRendererCrash(true);
ResetTest();
RunTest(true, false, false, false);
data = std::make_unique<DataReductionProxyData>();
data->set_used_data_reduction_proxy(true);
data->set_request_url(GURL(kDefaultTestUrl));
NavigateToUntrackedUrl();
// When the renderer does not crash, the pingback should report that.
ValidateRendererCrash(false);
}
} // namespace data_reduction_proxy
// Copyright 2018 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 "chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.h"
#include "chrome/browser/loader/chrome_navigation_data.h"
#include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "chrome/browser/page_load_metrics/page_load_tracker.h"
#include "chrome/browser/previews/previews_ui_tab_helper.h"
#include "components/previews/content/previews_user_data.h"
#include "content/public/test/web_contents_tester.h"
namespace data_reduction_proxy {
DataReductionProxyData* DataForNavigationHandle(
content::WebContents* web_contents,
content::NavigationHandle* navigation_handle) {
auto chrome_navigation_data = std::make_unique<ChromeNavigationData>();
auto drp_data = std::make_unique<DataReductionProxyData>();
DataReductionProxyData* data = drp_data.get();
chrome_navigation_data->SetDataReductionProxyData(std::move(drp_data));
content::WebContentsTester::For(web_contents)
->SetNavigationData(navigation_handle, std::move(chrome_navigation_data));
return data;
}
previews::PreviewsUserData* PreviewsDataForNavigationHandle(
content::NavigationHandle* navigation_handle) {
PreviewsUITabHelper* ui_tab_helper =
PreviewsUITabHelper::FromWebContents(navigation_handle->GetWebContents());
previews::PreviewsUserData* previews_user_data =
ui_tab_helper->GetPreviewsUserData(navigation_handle);
if (previews_user_data)
return previews_user_data;
return ui_tab_helper->CreatePreviewsUserDataForNavigationHandle(
navigation_handle, 1u);
}
page_load_metrics::mojom::ResourceDataUpdatePtr
CreateDataReductionProxyResource(bool was_cached,
int64_t delta_bytes,
bool is_complete,
bool proxy_used,
double compression_ratio) {
auto resource_data_update =
page_load_metrics::mojom::ResourceDataUpdate::New();
resource_data_update->was_fetched_via_cache = was_cached;
resource_data_update->delta_bytes = was_cached ? 0 : delta_bytes;
resource_data_update->encoded_body_length = delta_bytes;
resource_data_update->is_complete = is_complete;
resource_data_update->proxy_used = true;
resource_data_update->data_reduction_proxy_compression_ratio_estimate =
compression_ratio;
return resource_data_update;
}
TestPingbackClient::TestPingbackClient()
: DataReductionProxyPingbackClientImpl(nullptr,
base::ThreadTaskRunnerHandle::Get(),
"unknown"),
send_pingback_called_(false) {}
TestPingbackClient::~TestPingbackClient() {}
void TestPingbackClient::SendPingback(
const DataReductionProxyData& data,
const DataReductionProxyPageLoadTiming& timing) {
timing_.reset(new DataReductionProxyPageLoadTiming(timing));
send_pingback_called_ = true;
data_ = data.DeepCopy();
}
void TestPingbackClient::Reset() {
send_pingback_called_ = false;
timing_.reset();
}
FakeInputEvent::FakeInputEvent(blink::WebInputEvent::Type type)
: WebInputEvent(sizeof(FakeInputEvent),
type,
blink::WebInputEvent::kNoModifiers,
base::TimeTicks::Now()) {}
DataReductionProxyMetricsObserverTestBase::
DataReductionProxyMetricsObserverTestBase()
: pingback_client_(new TestPingbackClient()),
data_reduction_proxy_used_(false),
is_using_lite_page_(false),
opt_out_expected_(false),
black_listed_(false) {}
DataReductionProxyMetricsObserverTestBase::
~DataReductionProxyMetricsObserverTestBase() {}
void DataReductionProxyMetricsObserverTestBase::ResetTest() {
page_load_metrics::InitPageLoadTimingForTest(&timing_);
// Reset to the default testing state. Does not reset histogram state.
timing_.navigation_start = base::Time::FromDoubleT(1);
timing_.response_start = base::TimeDelta::FromSeconds(2);
timing_.parse_timing->parse_start = base::TimeDelta::FromSeconds(3);
timing_.paint_timing->first_contentful_paint =
base::TimeDelta::FromSeconds(4);
timing_.paint_timing->first_paint = base::TimeDelta::FromSeconds(4);
timing_.paint_timing->first_meaningful_paint =
base::TimeDelta::FromSeconds(8);
timing_.paint_timing->first_image_paint = base::TimeDelta::FromSeconds(5);
timing_.paint_timing->first_text_paint = base::TimeDelta::FromSeconds(6);
timing_.document_timing->load_event_start = base::TimeDelta::FromSeconds(7);
timing_.parse_timing->parse_stop = base::TimeDelta::FromSeconds(4);
timing_.parse_timing->parse_blocked_on_script_load_duration =
base::TimeDelta::FromSeconds(1);
PopulateRequiredTimingFields(&timing_);
}
void DataReductionProxyMetricsObserverTestBase::RunTest(
bool data_reduction_proxy_used,
bool is_using_lite_page,
bool opt_out_expected,
bool black_listed) {
data_reduction_proxy_used_ = data_reduction_proxy_used;
is_using_lite_page_ = is_using_lite_page;
opt_out_expected_ = opt_out_expected;
black_listed_ = black_listed;
NavigateAndCommit(GURL(kDefaultTestUrl));
SimulateTimingUpdate(timing_);
pingback_client_->Reset();
}
void DataReductionProxyMetricsObserverTestBase::
RunTestAndNavigateToUntrackedUrl(bool data_reduction_proxy_used,
bool is_using_lite_page,
bool opt_out_expected) {
RunTest(data_reduction_proxy_used, is_using_lite_page, opt_out_expected,
false);
NavigateToUntrackedUrl();
}
void DataReductionProxyMetricsObserverTestBase::SimulateRendererCrash() {
observer()->RenderProcessGone(
base::TerminationStatus::TERMINATION_STATUS_ABNORMAL_TERMINATION);
}
// Verify that, if expected and actual are set, their values are equal.
// Otherwise, verify that both are unset.
void DataReductionProxyMetricsObserverTestBase::ExpectEqualOrUnset(
const base::Optional<base::TimeDelta>& expected,
const base::Optional<base::TimeDelta>& actual) {
if (expected && actual) {
EXPECT_EQ(expected.value(), actual.value());
} else {
EXPECT_TRUE(!expected);
EXPECT_TRUE(!actual);
}
}
void DataReductionProxyMetricsObserverTestBase::ValidateTimes() {
EXPECT_TRUE(pingback_client_->send_pingback_called());
EXPECT_EQ(timing_.navigation_start,
pingback_client_->timing()->navigation_start);
EXPECT_GT(pingback_client_->timing()->page_end_time, base::TimeDelta());
ExpectEqualOrUnset(timing_.paint_timing->first_contentful_paint,
pingback_client_->timing()->first_contentful_paint);
ExpectEqualOrUnset(
timing_.paint_timing->first_meaningful_paint,
pingback_client_->timing()->experimental_first_meaningful_paint);
ExpectEqualOrUnset(timing_.response_start,
pingback_client_->timing()->response_start);
ExpectEqualOrUnset(timing_.document_timing->load_event_start,
pingback_client_->timing()->load_event_start);
ExpectEqualOrUnset(timing_.paint_timing->first_image_paint,
pingback_client_->timing()->first_image_paint);
EXPECT_EQ(opt_out_expected_, pingback_client_->timing()->opt_out_occurred);
EXPECT_EQ(timing_.document_timing->load_event_start
? static_cast<int64_t>(kMemoryKb)
: 0,
pingback_client_->timing()->renderer_memory_usage_kb);
}
void DataReductionProxyMetricsObserverTestBase::ValidateLoFiInPingback(
bool lofi_expected) {
EXPECT_TRUE(pingback_client_->send_pingback_called());
EXPECT_EQ(lofi_expected, pingback_client_->data().lofi_received());
}
void DataReductionProxyMetricsObserverTestBase::ValidateBlackListInPingback(
bool black_listed) {
EXPECT_TRUE(pingback_client_->send_pingback_called());
EXPECT_EQ(black_listed, pingback_client_->data().black_listed());
}
void DataReductionProxyMetricsObserverTestBase::ValidateRendererCrash(
bool renderer_crashed) {
EXPECT_TRUE(pingback_client_->send_pingback_called());
EXPECT_EQ(renderer_crashed, pingback_client_->timing()->host_id !=
content::ChildProcessHost::kInvalidUniqueID);
}
void DataReductionProxyMetricsObserverTestBase::SetUp() {
page_load_metrics::PageLoadMetricsObserverTestHarness ::SetUp();
PreviewsUITabHelper::CreateForWebContents(web_contents());
}
} // namespace data_reduction_proxy
// Copyright 2018 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 CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_DATA_REDUCTION_PROXY_METRICS_OBSERVER_TEST_UTILS_H_
#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_DATA_REDUCTION_PROXY_METRICS_OBSERVER_TEST_UTILS_H_
#include <stdint.h>
#include <functional>
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
#include "chrome/common/page_load_metrics/page_load_timing.h"
#include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h"
#include "components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
#include "third_party/blink/public/platform/web_input_event.h"
namespace previews {
class PreviewsUserData;
}
namespace data_reduction_proxy {
const char kDefaultTestUrl[] = "http://google.com";
const int kMemoryKb = 1024;
// Attaches a new |DataReductionProxyData| to |navigation_handle|'s navigation
// data.
DataReductionProxyData* DataForNavigationHandle(
content::WebContents* web_contents,
content::NavigationHandle* navigation_handle);
// Attaches a new |PreviewsUserData| to the given |navigation_handle|.
previews::PreviewsUserData* PreviewsDataForNavigationHandle(
content::NavigationHandle* navigation_handle);
page_load_metrics::mojom::ResourceDataUpdatePtr
CreateDataReductionProxyResource(bool was_cached,
int64_t delta_bytes,
bool is_complete,
bool proxy_used,
double compression_ratio = 1.0);
// Pingback client responsible for recording the timing information it receives
// from a SendPingback call.
class TestPingbackClient : public DataReductionProxyPingbackClientImpl {
public:
TestPingbackClient();
~TestPingbackClient() override;
// Mocks sending a pingback. |data_| and |timing_| are set to |data| and
// |timing|.
void SendPingback(const DataReductionProxyData& data,
const DataReductionProxyPageLoadTiming& timing) override;
// Resets the internal state of |this|.
void Reset();
DataReductionProxyPageLoadTiming* timing() const { return timing_.get(); }
const DataReductionProxyData& data() const { return *data_; }
bool send_pingback_called() const { return send_pingback_called_; }
private:
std::unique_ptr<DataReductionProxyPageLoadTiming> timing_;
std::unique_ptr<DataReductionProxyData> data_;
bool send_pingback_called_;
DISALLOW_COPY_AND_ASSIGN(TestPingbackClient);
};
class FakeInputEvent : public blink::WebInputEvent {
public:
explicit FakeInputEvent(blink::WebInputEvent::Type type);
};
// This base test class does all the test support and validation associated with
// the DRP pingbacks.
class DataReductionProxyMetricsObserverTestBase
: public page_load_metrics::PageLoadMetricsObserverTestHarness {
public:
DataReductionProxyMetricsObserverTestBase();
~DataReductionProxyMetricsObserverTestBase() override;
// Resets all testing state. Should be called before every test case.
void ResetTest();
// Navigates and commits to |kDefaultTestUrl| and mocks a single timing
// update.
void RunTest(bool data_reduction_proxy_used,
bool is_using_lite_page,
bool opt_out_expected,
bool black_listed);
// The same as |RunTest| but also navigates to an untracked URL afterwards.
void RunTestAndNavigateToUntrackedUrl(bool data_reduction_proxy_used,
bool is_using_lite_page,
bool opt_out_expected);
// Mocks a renderer crash.
void SimulateRendererCrash();
// Verify that, if expected and actual are set, their values are equal.
// Otherwise, verify that both are unset.
void ExpectEqualOrUnset(const base::Optional<base::TimeDelta>& expected,
const base::Optional<base::TimeDelta>& actual);
// Validates the times in the pingback.
void ValidateTimes();
// Validates the LoFi state in the pingback.
void ValidateLoFiInPingback(bool lofi_expected);
// Validates the blacklist state in the pingback.
void ValidateBlackListInPingback(bool black_listed);
// Validates the renderer crash state in the pingback.
void ValidateRendererCrash(bool renderer_crashed);
// Set ups test state.
void SetUp() override;
TestPingbackClient* pingback_client() const { return pingback_client_.get(); }
page_load_metrics::mojom::PageLoadTimingPtr timing() {
return timing_.Clone();
}
bool cached_data_reduction_proxy_used() const {
return cached_data_reduction_proxy_used_;
}
bool data_reduction_proxy_used() const { return data_reduction_proxy_used_; }
bool is_using_lite_page() const { return is_using_lite_page_; }
bool opt_out_expected() const { return opt_out_expected_; }
bool black_listed() const { return black_listed_; }
protected:
std::unique_ptr<TestPingbackClient> pingback_client_;
page_load_metrics::mojom::PageLoadTiming timing_;
bool cached_data_reduction_proxy_used_ = false;
private:
bool data_reduction_proxy_used_;
bool is_using_lite_page_;
bool opt_out_expected_;
bool black_listed_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyMetricsObserverTestBase);
};
} // namespace data_reduction_proxy
#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_DATA_REDUCTION_PROXY_METRICS_OBSERVER_TEST_UTILS_H_
......@@ -5,152 +5,20 @@
#include "chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.h"
#include <stdint.h>
#include <functional>
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/optional.h"
#include "base/process/kill.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chrome/browser/loader/chrome_navigation_data.h"
#include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
#include "chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.h"
#include "chrome/browser/page_load_metrics/observers/histogram_suffixes.h"
#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
#include "chrome/browser/page_load_metrics/page_load_tracker.h"
#include "chrome/browser/previews/previews_ui_tab_helper.h"
#include "chrome/common/page_load_metrics/page_load_timing.h"
#include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/previews/content/previews_user_data.h"
#include "content/public/test/web_contents_tester.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "third_party/blink/public/platform/web_input_event.h"
namespace data_reduction_proxy {
namespace {
const char kDefaultTestUrl[] = "http://google.com";
const int kMemoryKb = 1024;
data_reduction_proxy::DataReductionProxyData* DataForNavigationHandle(
content::WebContents* web_contents,
content::NavigationHandle* navigation_handle) {
auto chrome_navigation_data = std::make_unique<ChromeNavigationData>();
auto drp_data =
std::make_unique<data_reduction_proxy::DataReductionProxyData>();
data_reduction_proxy::DataReductionProxyData* data = drp_data.get();
chrome_navigation_data->SetDataReductionProxyData(std::move(drp_data));
content::WebContentsTester::For(web_contents)
->SetNavigationData(navigation_handle, std::move(chrome_navigation_data));
return data;
}
previews::PreviewsUserData* PreviewsDataForNavigationHandle(
content::NavigationHandle* navigation_handle) {
PreviewsUITabHelper* ui_tab_helper =
PreviewsUITabHelper::FromWebContents(navigation_handle->GetWebContents());
previews::PreviewsUserData* previews_user_data =
ui_tab_helper->GetPreviewsUserData(navigation_handle);
if (previews_user_data)
return previews_user_data;
return ui_tab_helper->CreatePreviewsUserDataForNavigationHandle(
navigation_handle, 1u);
}
page_load_metrics::mojom::ResourceDataUpdatePtr
CreateDataReductionProxyResource(bool was_cached,
int64_t delta_bytes,
bool is_complete,
bool proxy_used,
double compression_ratio = 1.0) {
auto resource_data_update =
page_load_metrics::mojom::ResourceDataUpdate::New();
resource_data_update->was_fetched_via_cache = was_cached;
resource_data_update->delta_bytes = was_cached ? 0 : delta_bytes;
resource_data_update->encoded_body_length = delta_bytes;
resource_data_update->is_complete = is_complete;
resource_data_update->proxy_used = true;
resource_data_update->data_reduction_proxy_compression_ratio_estimate =
compression_ratio;
return resource_data_update;
}
// Pingback client responsible for recording the timing information it receives
// from a SendPingback call.
class TestPingbackClient
: public data_reduction_proxy::DataReductionProxyPingbackClientImpl {
public:
TestPingbackClient()
: data_reduction_proxy::DataReductionProxyPingbackClientImpl(
nullptr,
base::ThreadTaskRunnerHandle::Get(),
"unknown"),
send_pingback_called_(false) {}
~TestPingbackClient() override {}
void SendPingback(
const data_reduction_proxy::DataReductionProxyData& data,
const data_reduction_proxy::DataReductionProxyPageLoadTiming& timing)
override {
timing_.reset(
new data_reduction_proxy::DataReductionProxyPageLoadTiming(timing));
send_pingback_called_ = true;
data_ = data.DeepCopy();
}
data_reduction_proxy::DataReductionProxyPageLoadTiming* timing() const {
return timing_.get();
}
const data_reduction_proxy::DataReductionProxyData& data() const {
return *data_;
}
bool send_pingback_called() const { return send_pingback_called_; }
void Reset() {
send_pingback_called_ = false;
timing_.reset();
}
private:
std::unique_ptr<data_reduction_proxy::DataReductionProxyPageLoadTiming>
timing_;
std::unique_ptr<data_reduction_proxy::DataReductionProxyData> data_;
bool send_pingback_called_;
DISALLOW_COPY_AND_ASSIGN(TestPingbackClient);
};
namespace {
class FakeInputEvent : public blink::WebInputEvent {
public:
explicit FakeInputEvent(blink::WebInputEvent::Type type)
: WebInputEvent(sizeof(FakeInputEvent),
type,
blink::WebInputEvent::kNoModifiers,
base::TimeTicks::Now()) {}
};
} // namespace
} // namespace
// DataReductionProxyMetricsObserver responsible for modifying data about the
// navigation in OnCommit. It is also responsible for using a passed in
// DataReductionProxyPingbackClient instead of the default.
......@@ -172,7 +40,7 @@ class TestDataReductionProxyMetricsObserver
~TestDataReductionProxyMetricsObserver() override {}
// page_load_metrics::PageLoadMetricsObserver implementation:
// page_load_metrics::PageLoadMetricsObserver:
ObservePolicy OnCommit(content::NavigationHandle* navigation_handle,
ukm::SourceId source_id) override {
DataReductionProxyData* data =
......@@ -226,112 +94,10 @@ class TestDataReductionProxyMetricsObserver
};
class DataReductionProxyMetricsObserverTest
: public page_load_metrics::PageLoadMetricsObserverTestHarness {
: public DataReductionProxyMetricsObserverTestBase {
public:
DataReductionProxyMetricsObserverTest()
: pingback_client_(new TestPingbackClient()),
data_reduction_proxy_used_(false),
is_using_lite_page_(false),
opt_out_expected_(false),
black_listed_(false) {}
void ResetTest() {
page_load_metrics::InitPageLoadTimingForTest(&timing_);
// Reset to the default testing state. Does not reset histogram state.
timing_.navigation_start = base::Time::FromDoubleT(1);
timing_.response_start = base::TimeDelta::FromSeconds(2);
timing_.parse_timing->parse_start = base::TimeDelta::FromSeconds(3);
timing_.paint_timing->first_contentful_paint =
base::TimeDelta::FromSeconds(4);
timing_.paint_timing->first_paint = base::TimeDelta::FromSeconds(4);
timing_.paint_timing->first_meaningful_paint =
base::TimeDelta::FromSeconds(8);
timing_.paint_timing->first_image_paint = base::TimeDelta::FromSeconds(5);
timing_.paint_timing->first_text_paint = base::TimeDelta::FromSeconds(6);
timing_.document_timing->load_event_start = base::TimeDelta::FromSeconds(7);
timing_.parse_timing->parse_stop = base::TimeDelta::FromSeconds(4);
timing_.parse_timing->parse_blocked_on_script_load_duration =
base::TimeDelta::FromSeconds(1);
PopulateRequiredTimingFields(&timing_);
}
void RunTest(bool data_reduction_proxy_used,
bool is_using_lite_page,
bool opt_out_expected,
bool black_listed) {
data_reduction_proxy_used_ = data_reduction_proxy_used;
is_using_lite_page_ = is_using_lite_page;
opt_out_expected_ = opt_out_expected;
black_listed_ = black_listed;
NavigateAndCommit(GURL(kDefaultTestUrl));
SimulateTimingUpdate(timing_);
pingback_client_->Reset();
}
void RunTestAndNavigateToUntrackedUrl(bool data_reduction_proxy_used,
bool is_using_lite_page,
bool opt_out_expected) {
RunTest(data_reduction_proxy_used, is_using_lite_page, opt_out_expected,
false);
NavigateToUntrackedUrl();
}
void SimulateRendererCrash() {
observer()->RenderProcessGone(
base::TerminationStatus::TERMINATION_STATUS_ABNORMAL_TERMINATION);
}
// Verify that, if expected and actual are set, their values are equal.
// Otherwise, verify that both are unset.
void ExpectEqualOrUnset(const base::Optional<base::TimeDelta>& expected,
const base::Optional<base::TimeDelta>& actual) {
if (expected && actual) {
EXPECT_EQ(expected.value(), actual.value());
} else {
EXPECT_TRUE(!expected);
EXPECT_TRUE(!actual);
}
}
void ValidateTimes() {
EXPECT_TRUE(pingback_client_->send_pingback_called());
EXPECT_EQ(timing_.navigation_start,
pingback_client_->timing()->navigation_start);
EXPECT_GT(pingback_client_->timing()->page_end_time, base::TimeDelta());
ExpectEqualOrUnset(timing_.paint_timing->first_contentful_paint,
pingback_client_->timing()->first_contentful_paint);
ExpectEqualOrUnset(
timing_.paint_timing->first_meaningful_paint,
pingback_client_->timing()->experimental_first_meaningful_paint);
ExpectEqualOrUnset(timing_.response_start,
pingback_client_->timing()->response_start);
ExpectEqualOrUnset(timing_.document_timing->load_event_start,
pingback_client_->timing()->load_event_start);
ExpectEqualOrUnset(timing_.paint_timing->first_image_paint,
pingback_client_->timing()->first_image_paint);
EXPECT_EQ(opt_out_expected_, pingback_client_->timing()->opt_out_occurred);
EXPECT_EQ(timing_.document_timing->load_event_start
? static_cast<int64_t>(kMemoryKb)
: 0,
pingback_client_->timing()->renderer_memory_usage_kb);
}
void ValidateLoFiInPingback(bool lofi_expected) {
EXPECT_TRUE(pingback_client_->send_pingback_called());
EXPECT_EQ(lofi_expected, pingback_client_->data().lofi_received());
}
void ValidateBlackListInPingback(bool black_listed) {
EXPECT_TRUE(pingback_client_->send_pingback_called());
EXPECT_EQ(black_listed, pingback_client_->data().black_listed());
}
void ValidateRendererCrash(bool renderer_crashed) {
EXPECT_TRUE(pingback_client_->send_pingback_called());
EXPECT_EQ(renderer_crashed,
pingback_client_->timing()->host_id !=
content::ChildProcessHost::kInvalidUniqueID);
}
DataReductionProxyMetricsObserverTest() {}
~DataReductionProxyMetricsObserverTest() override {}
void ValidateHistograms() {
ValidateHistogramsForSuffix(
......@@ -369,13 +135,13 @@ class DataReductionProxyMetricsObserverTest
histogram_tester().ExpectTotalCount(
std::string(internal::kHistogramDataReductionProxyPrefix)
.append(histogram_suffix),
data_reduction_proxy_used_ || cached_data_reduction_proxy_used_ ? 1
data_reduction_proxy_used() || cached_data_reduction_proxy_used() ? 1
: 0);
histogram_tester().ExpectTotalCount(
std::string(internal::kHistogramDataReductionProxyLitePagePrefix)
.append(histogram_suffix),
is_using_lite_page_ ? 1 : 0);
if (!(data_reduction_proxy_used_ || cached_data_reduction_proxy_used_))
is_using_lite_page() ? 1 : 0);
if (!(data_reduction_proxy_used() || cached_data_reduction_proxy_used()))
return;
histogram_tester().ExpectUniqueSample(
std::string(internal::kHistogramDataReductionProxyPrefix)
......@@ -383,12 +149,12 @@ class DataReductionProxyMetricsObserverTest
static_cast<base::HistogramBase::Sample>(
event.value().InMilliseconds()),
1);
if (!is_using_lite_page_)
if (!is_using_lite_page())
return;
histogram_tester().ExpectUniqueSample(
std::string(internal::kHistogramDataReductionProxyLitePagePrefix)
.append(histogram_suffix),
event.value().InMilliseconds(), is_using_lite_page_ ? 1 : 0);
event.value().InMilliseconds(), is_using_lite_page() ? 1 : 0);
}
void ValidateDataHistograms(int network_resources,
......@@ -463,31 +229,16 @@ class DataReductionProxyMetricsObserverTest
}
}
void SetUp() override {
page_load_metrics::PageLoadMetricsObserverTestHarness ::SetUp();
PreviewsUITabHelper::CreateForWebContents(web_contents());
}
protected:
void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
tracker->AddObserver(
std::make_unique<TestDataReductionProxyMetricsObserver>(
web_contents(), pingback_client_.get(), data_reduction_proxy_used_,
cached_data_reduction_proxy_used_, is_using_lite_page_,
black_listed_));
web_contents(), pingback_client(), data_reduction_proxy_used(),
cached_data_reduction_proxy_used(), is_using_lite_page(),
black_listed()));
}
std::unique_ptr<TestPingbackClient> pingback_client_;
page_load_metrics::mojom::PageLoadTiming timing_;
bool cached_data_reduction_proxy_used_ = false;
private:
bool data_reduction_proxy_used_;
bool is_using_lite_page_;
bool opt_out_expected_;
bool black_listed_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyMetricsObserverTest);
};
......@@ -514,104 +265,6 @@ TEST_F(DataReductionProxyMetricsObserverTest, LitePageEnabled) {
ValidateHistograms();
}
TEST_F(DataReductionProxyMetricsObserverTest, OnCompletePingback) {
ResetTest();
// Verify that when data reduction proxy was used the correct timing
// information is sent to SendPingback.
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ResetTest();
// Verify that when data reduction proxy was used but first image paint is
// unset, the correct timing information is sent to SendPingback.
timing_.paint_timing->first_image_paint = base::nullopt;
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ResetTest();
// Verify that when data reduction proxy was used but first contentful paint
// is unset, SendPingback is not called.
timing_.paint_timing->first_contentful_paint = base::nullopt;
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ResetTest();
// Verify that when data reduction proxy was used but first meaningful paint
// is unset, SendPingback is not called.
timing_.paint_timing->first_meaningful_paint = base::nullopt;
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ResetTest();
// Verify that when data reduction proxy was used but load event start is
// unset, SendPingback is not called.
timing_.document_timing->load_event_start = base::nullopt;
RunTestAndNavigateToUntrackedUrl(true, false, false);
ValidateTimes();
ValidateLoFiInPingback(false);
ResetTest();
// Verify that when an opt out occurs, that it is reported in the pingback.
timing_.document_timing->load_event_start = base::nullopt;
RunTest(true, true, true, false);
observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
NavigateToUntrackedUrl();
ValidateTimes();
ValidateLoFiInPingback(false);
ResetTest();
std::unique_ptr<DataReductionProxyData> data =
std::make_unique<DataReductionProxyData>();
data->set_used_data_reduction_proxy(true);
data->set_request_url(GURL(kDefaultTestUrl));
data->set_lofi_received(true);
// Verify LoFi is tracked when a LoFi response is received.
page_load_metrics::ExtraRequestCompleteInfo resource = {
GURL(kResourceUrl),
net::HostPortPair(),
-1 /* frame_tree_node_id */,
true /*was_cached*/,
1024 * 40 /* raw_body_bytes */,
0 /* original_network_content_length */,
std::move(data),
content::ResourceType::RESOURCE_TYPE_SCRIPT,
0,
{} /* load_timing_info */};
RunTest(true, false, false, false);
SimulateLoadedResource(resource);
NavigateToUntrackedUrl();
ValidateTimes();
ValidateLoFiInPingback(true);
ValidateBlackListInPingback(false);
ResetTest();
RunTest(true, false, false, true);
NavigateToUntrackedUrl();
ValidateBlackListInPingback(true);
ResetTest();
// Verify that when data reduction proxy was not used, SendPingback is not
// called.
RunTestAndNavigateToUntrackedUrl(false, false, false);
EXPECT_FALSE(pingback_client_->send_pingback_called());
ResetTest();
cached_data_reduction_proxy_used_ = true;
RunTestAndNavigateToUntrackedUrl(false, false, false);
EXPECT_TRUE(pingback_client_->send_pingback_called());
cached_data_reduction_proxy_used_ = false;
ResetTest();
// Verify that when the holdback experiment is enabled, a pingback is sent.
base::FieldTrialList field_trial_list(nullptr);
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
"DataCompressionProxyHoldback", "Enabled"));
RunTestAndNavigateToUntrackedUrl(true, false, false);
EXPECT_TRUE(pingback_client_->send_pingback_called());
}
TEST_F(DataReductionProxyMetricsObserverTest, ByteInformationCompression) {
ResetTest();
......@@ -752,152 +405,4 @@ TEST_F(DataReductionProxyMetricsObserverTest, ByteInformationInflation) {
insecure_ocl_bytes + secure_ocl_bytes);
}
TEST_F(DataReductionProxyMetricsObserverTest, TouchScrollEventCount) {
struct TestCase {
std::vector<FakeInputEvent> events;
uint32_t want_touch;
uint32_t want_scroll;
};
const TestCase test_cases[] = {
{
// Test zero value.
{},
0 /* want_touch */,
0 /* want_scroll */,
},
{
// Test all inputs, should only count the ones we care about.
{
FakeInputEvent(blink::WebInputEvent::kMouseDown),
FakeInputEvent(blink::WebInputEvent::kMouseUp),
FakeInputEvent(blink::WebInputEvent::kMouseMove),
FakeInputEvent(blink::WebInputEvent::kMouseEnter),
FakeInputEvent(blink::WebInputEvent::kMouseLeave),
FakeInputEvent(blink::WebInputEvent::kContextMenu),
FakeInputEvent(blink::WebInputEvent::kMouseWheel),
FakeInputEvent(blink::WebInputEvent::kRawKeyDown),
FakeInputEvent(blink::WebInputEvent::kKeyDown),
FakeInputEvent(blink::WebInputEvent::kKeyUp),
FakeInputEvent(blink::WebInputEvent::kChar),
FakeInputEvent(blink::WebInputEvent::kGestureScrollBegin),
FakeInputEvent(blink::WebInputEvent::kGestureScrollEnd),
FakeInputEvent(blink::WebInputEvent::kGestureScrollUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureFlingStart),
FakeInputEvent(blink::WebInputEvent::kGestureFlingCancel),
FakeInputEvent(blink::WebInputEvent::kGesturePinchBegin),
FakeInputEvent(blink::WebInputEvent::kGesturePinchEnd),
FakeInputEvent(blink::WebInputEvent::kGesturePinchUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureTapDown),
FakeInputEvent(blink::WebInputEvent::kGestureShowPress),
FakeInputEvent(blink::WebInputEvent::kGestureTap),
FakeInputEvent(blink::WebInputEvent::kGestureTapCancel),
FakeInputEvent(blink::WebInputEvent::kGestureLongPress),
FakeInputEvent(blink::WebInputEvent::kGestureLongTap),
FakeInputEvent(blink::WebInputEvent::kGestureTwoFingerTap),
FakeInputEvent(blink::WebInputEvent::kGestureTapUnconfirmed),
FakeInputEvent(blink::WebInputEvent::kGestureDoubleTap),
FakeInputEvent(blink::WebInputEvent::kTouchStart),
FakeInputEvent(blink::WebInputEvent::kTouchMove),
FakeInputEvent(blink::WebInputEvent::kTouchEnd),
FakeInputEvent(blink::WebInputEvent::kTouchCancel),
FakeInputEvent(blink::WebInputEvent::kTouchScrollStarted),
FakeInputEvent(blink::WebInputEvent::kPointerDown),
FakeInputEvent(blink::WebInputEvent::kPointerUp),
FakeInputEvent(blink::WebInputEvent::kPointerMove),
FakeInputEvent(blink::WebInputEvent::kPointerCancel),
FakeInputEvent(blink::WebInputEvent::kPointerCausedUaAction),
},
2 /* want_touch */,
3 /* want_scroll */,
},
{
// Test all inputs, with the ones we care about repeated.
{
FakeInputEvent(blink::WebInputEvent::kMouseDown),
FakeInputEvent(blink::WebInputEvent::kMouseUp),
FakeInputEvent(blink::WebInputEvent::kMouseMove),
FakeInputEvent(blink::WebInputEvent::kMouseEnter),
FakeInputEvent(blink::WebInputEvent::kMouseLeave),
FakeInputEvent(blink::WebInputEvent::kContextMenu),
FakeInputEvent(blink::WebInputEvent::kMouseWheel),
FakeInputEvent(blink::WebInputEvent::kRawKeyDown),
FakeInputEvent(blink::WebInputEvent::kKeyDown),
FakeInputEvent(blink::WebInputEvent::kKeyUp),
FakeInputEvent(blink::WebInputEvent::kChar),
FakeInputEvent(blink::WebInputEvent::kGestureScrollBegin),
FakeInputEvent(blink::WebInputEvent::kGestureScrollEnd),
FakeInputEvent(blink::WebInputEvent::kGestureScrollUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureFlingStart),
FakeInputEvent(blink::WebInputEvent::kGestureFlingCancel),
FakeInputEvent(blink::WebInputEvent::kGesturePinchBegin),
FakeInputEvent(blink::WebInputEvent::kGesturePinchEnd),
FakeInputEvent(blink::WebInputEvent::kGesturePinchUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureTapDown),
FakeInputEvent(blink::WebInputEvent::kGestureShowPress),
FakeInputEvent(blink::WebInputEvent::kGestureTap),
FakeInputEvent(blink::WebInputEvent::kGestureTapCancel),
FakeInputEvent(blink::WebInputEvent::kGestureLongPress),
FakeInputEvent(blink::WebInputEvent::kGestureLongTap),
FakeInputEvent(blink::WebInputEvent::kGestureTwoFingerTap),
FakeInputEvent(blink::WebInputEvent::kGestureTapUnconfirmed),
FakeInputEvent(blink::WebInputEvent::kGestureDoubleTap),
FakeInputEvent(blink::WebInputEvent::kTouchStart),
FakeInputEvent(blink::WebInputEvent::kTouchMove),
FakeInputEvent(blink::WebInputEvent::kTouchEnd),
FakeInputEvent(blink::WebInputEvent::kTouchCancel),
FakeInputEvent(blink::WebInputEvent::kTouchScrollStarted),
FakeInputEvent(blink::WebInputEvent::kPointerDown),
FakeInputEvent(blink::WebInputEvent::kPointerUp),
FakeInputEvent(blink::WebInputEvent::kPointerMove),
FakeInputEvent(blink::WebInputEvent::kPointerCancel),
FakeInputEvent(blink::WebInputEvent::kPointerCausedUaAction),
// Repeat.
FakeInputEvent(blink::WebInputEvent::kMouseDown),
FakeInputEvent(blink::WebInputEvent::kGestureTap),
FakeInputEvent(blink::WebInputEvent::kMouseWheel),
FakeInputEvent(blink::WebInputEvent::kGestureScrollUpdate),
FakeInputEvent(blink::WebInputEvent::kGestureFlingStart),
},
4 /* want_touch */,
6 /* want_scroll */,
},
};
for (const TestCase& test_case : test_cases) {
ResetTest();
RunTest(true, false, false, false);
for (const blink::WebInputEvent& event : test_case.events)
SimulateInputEvent(event);
NavigateToUntrackedUrl();
EXPECT_EQ(pingback_client_->timing()->touch_count, test_case.want_touch);
EXPECT_EQ(pingback_client_->timing()->scroll_count, test_case.want_scroll);
}
}
TEST_F(DataReductionProxyMetricsObserverTest, ProcessIdSentOnRendererCrash) {
ResetTest();
RunTest(true, false, false, false);
std::unique_ptr<DataReductionProxyData> data =
std::make_unique<DataReductionProxyData>();
data->set_used_data_reduction_proxy(true);
data->set_request_url(GURL(kDefaultTestUrl));
SimulateRendererCrash();
// When the renderer crashes, the pingback should report that.
ValidateRendererCrash(true);
ResetTest();
RunTest(true, false, false, false);
data = std::make_unique<DataReductionProxyData>();
data->set_used_data_reduction_proxy(true);
data->set_request_url(GURL(kDefaultTestUrl));
NavigateToUntrackedUrl();
// When the renderer does not crash, the pingback should report that.
ValidateRendererCrash(false);
}
} // namespace data_reduction_proxy
......@@ -2555,6 +2555,9 @@ test("unit_tests") {
"../browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc",
"../browser/page_load_metrics/observers/amp_page_load_metrics_observer_unittest.cc",
"../browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc",
"../browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_base_unittest.cc",
"../browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.cc",
"../browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_test_utils.h",
"../browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc",
"../browser/page_load_metrics/observers/document_write_page_load_metrics_observer_unittest.cc",
"../browser/page_load_metrics/observers/from_gws_page_load_metrics_observer_unittest.cc",
......
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