blob: 2d6cc4a4ada5d79ea4fb49cadb7715638d6639d0 [file] [log] [blame]
// Copyright 2017 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/experiments/delay_navigation_throttle.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/search.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
namespace {
const char kHistogramNavigationDelaySpecified[] =
"DelayNavigationThrottle.Delay.Specified";
const char kHistogramNavigationDelayActual[] =
"DelayNavigationThrottle.Delay.Actual";
const char kHistogramNavigationDelayDelta[] =
"DelayNavigationThrottle.Delay.Delta";
base::TimeDelta GetNavigationDelayFromParams() {
double delay_probability = base::GetFieldTrialParamByFeatureAsDouble(
kDelayNavigationFeature,
DelayNavigationThrottle::kParamDelayNavigationProbability,
0 /* default value */);
DCHECK_GE(delay_probability, 0.0);
DCHECK_LE(delay_probability, 1.0);
if (delay_probability == 0 || delay_probability < base::RandDouble())
return base::TimeDelta();
int navigation_delay_millis = base::GetFieldTrialParamByFeatureAsInt(
kDelayNavigationFeature,
DelayNavigationThrottle::kParamDelayNavigationDurationMillis,
-1 /* default value */);
if (navigation_delay_millis <= 0)
return base::TimeDelta();
bool randomize_delay = base::GetFieldTrialParamByFeatureAsBool(
kDelayNavigationFeature,
DelayNavigationThrottle::kParamDelayNavigationRandomize,
false /* default value */);
if (randomize_delay) {
// RandGenerator produces a value in [0, navigation_delay_millis). We want
// a value in [1, navigation_delay_millis].
navigation_delay_millis = base::RandGenerator(navigation_delay_millis) + 1;
}
return base::TimeDelta::FromMilliseconds(navigation_delay_millis);
}
} // namespace
const base::Feature kDelayNavigationFeature{"DelayNavigation",
base::FEATURE_DISABLED_BY_DEFAULT};
const char DelayNavigationThrottle::kParamDelayNavigationDurationMillis[] =
"delay_millis";
const char DelayNavigationThrottle::kParamDelayNavigationRandomize[] =
"randomize_delay";
const char DelayNavigationThrottle::kParamDelayNavigationProbability[] =
"delay_probability";
// static
std::unique_ptr<DelayNavigationThrottle>
DelayNavigationThrottle::MaybeCreateThrottleFor(
content::NavigationHandle* handle) {
if (!handle->IsInMainFrame() ||
!base::FeatureList::IsEnabled(kDelayNavigationFeature) ||
!handle->GetURL().SchemeIsHTTPOrHTTPS()) {
return nullptr;
}
// Do not delay the NTP, which in some cases has an HTTPS URL.
if (search::IsNTPURL(handle->GetURL(),
Profile::FromBrowserContext(
handle->GetWebContents()->GetBrowserContext()))) {
return nullptr;
}
base::TimeDelta navigation_delay = GetNavigationDelayFromParams();
if (navigation_delay.is_zero())
return nullptr;
return base::MakeUnique<DelayNavigationThrottle>(
handle, base::ThreadTaskRunnerHandle::Get(), navigation_delay);
}
DelayNavigationThrottle::DelayNavigationThrottle(
content::NavigationHandle* handle,
scoped_refptr<base::TaskRunner> task_runner,
base::TimeDelta navigation_delay)
: content::NavigationThrottle(handle),
task_runner_(task_runner),
navigation_delay_(navigation_delay),
weak_ptr_factory_(this) {}
DelayNavigationThrottle::~DelayNavigationThrottle() {}
content::NavigationThrottle::ThrottleCheckResult
DelayNavigationThrottle::WillStartRequest() {
UMA_HISTOGRAM_TIMES(kHistogramNavigationDelaySpecified, navigation_delay_);
delay_start_time_ = base::TimeTicks::Now();
task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DelayNavigationThrottle::OnDelayComplete,
weak_ptr_factory_.GetWeakPtr()),
navigation_delay_);
return content::NavigationThrottle::DEFER;
}
const char* DelayNavigationThrottle::GetNameForLogging() {
return "DelayNavigationThrottle";
}
void DelayNavigationThrottle::OnDelayComplete() {
base::TimeDelta actual_delay = base::TimeTicks::Now() - delay_start_time_;
base::TimeDelta delay_delta = actual_delay - navigation_delay_;
UMA_HISTOGRAM_TIMES(kHistogramNavigationDelayActual, actual_delay);
UMA_HISTOGRAM_TIMES(kHistogramNavigationDelayDelta, delay_delta.magnitude());
page_load_metrics::MetricsWebContentsObserver* observer =
page_load_metrics::MetricsWebContentsObserver::FromWebContents(
navigation_handle()->GetWebContents());
if (observer) {
observer->OnNavigationDelayComplete(navigation_handle(), navigation_delay_,
actual_delay);
}
Resume();
}