blob: 96f4e58de57d473c05df98ffabcbd15dae48f50b [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "build/build_config.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
#include "components/prefs/pref_member.h"
#include "components/prefs/pref_service.h"
#include "net/base/network_change_notifier.h"
namespace {
// Key of the UMA DataReductionProxy.StartupState histogram.
const char kUMAProxyStartupStateHistogram[] =
"DataReductionProxy.StartupState";
void RecordSettingsEnabledState(
data_reduction_proxy::DataReductionSettingsEnabledAction action) {
UMA_HISTOGRAM_ENUMERATION(
"DataReductionProxy.EnabledState", action,
data_reduction_proxy::DATA_REDUCTION_SETTINGS_ACTION_BOUNDARY);
}
// Record the number of days since data reduction proxy was enabled by the
// user.
void RecordDaysSinceEnabledMetric(int days_since_enabled) {
UMA_HISTOGRAM_CUSTOM_COUNTS("DataReductionProxy.DaysSinceEnabled",
days_since_enabled, 0, 365 * 10, 100);
}
} // namespace
namespace data_reduction_proxy {
DataReductionProxySettings::DataReductionProxySettings()
: unreachable_(false),
deferred_initialization_(false),
prefs_(nullptr),
config_(nullptr),
clock_(base::DefaultClock::GetInstance()) {}
DataReductionProxySettings::~DataReductionProxySettings() {
spdy_proxy_auth_enabled_.Destroy();
}
void DataReductionProxySettings::InitPrefMembers() {
DCHECK(thread_checker_.CalledOnValidThread());
spdy_proxy_auth_enabled_.Init(
data_reduction_proxy_enabled_pref_name_, GetOriginalProfilePrefs(),
base::Bind(&DataReductionProxySettings::OnProxyEnabledPrefChange,
base::Unretained(this)));
}
void DataReductionProxySettings::InitDataReductionProxySettings(
const std::string& data_reduction_proxy_enabled_pref_name,
PrefService* prefs,
DataReductionProxyIOData* io_data,
std::unique_ptr<DataReductionProxyService> data_reduction_proxy_service) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!data_reduction_proxy_enabled_pref_name.empty());
DCHECK(prefs);
DCHECK(io_data);
DCHECK(io_data->config());
DCHECK(data_reduction_proxy_service);
data_reduction_proxy_enabled_pref_name_ =
data_reduction_proxy_enabled_pref_name;
prefs_ = prefs;
config_ = io_data->config();
data_reduction_proxy_service_ = std::move(data_reduction_proxy_service);
data_reduction_proxy_service_->AddObserver(this);
InitPrefMembers();
RecordDataReductionInit();
#if defined(OS_ANDROID)
if (spdy_proxy_auth_enabled_.GetValue()) {
data_reduction_proxy_service_->compression_stats()
->SetDataUsageReportingEnabled(true);
}
#endif // defined(OS_ANDROID)
}
void DataReductionProxySettings::OnServiceInitialized() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!deferred_initialization_)
return;
deferred_initialization_ = false;
// Technically, this is not "at startup", but this is the first chance that
// IO data objects can be called.
UpdateIOData(true);
}
void DataReductionProxySettings::SetCallbackToRegisterSyntheticFieldTrial(
const SyntheticFieldTrialRegistrationCallback&
on_data_reduction_proxy_enabled) {
register_synthetic_field_trial_ = on_data_reduction_proxy_enabled;
RegisterDataReductionProxyFieldTrial();
}
bool DataReductionProxySettings::IsDataReductionProxyEnabled() const {
if (spdy_proxy_auth_enabled_.GetPrefName().empty())
return false;
return spdy_proxy_auth_enabled_.GetValue() ||
params::ShouldForceEnableDataReductionProxy();
}
bool DataReductionProxySettings::CanUseDataReductionProxy(
const GURL& url) const {
return url.is_valid() && url.scheme() == url::kHttpScheme &&
IsDataReductionProxyEnabled();
}
bool DataReductionProxySettings::IsDataReductionProxyManaged() {
return spdy_proxy_auth_enabled_.IsManaged();
}
void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(data_reduction_proxy_service_->compression_stats());
if (spdy_proxy_auth_enabled_.GetValue() != enabled) {
spdy_proxy_auth_enabled_.SetValue(enabled);
OnProxyEnabledPrefChange();
#if defined(OS_ANDROID)
data_reduction_proxy_service_->compression_stats()
->SetDataUsageReportingEnabled(enabled);
#endif // defined(OS_ANDROID)
}
}
int64_t DataReductionProxySettings::GetDataReductionLastUpdateTime() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(data_reduction_proxy_service_->compression_stats());
return
data_reduction_proxy_service_->compression_stats()->GetLastUpdateTime();
}
void DataReductionProxySettings::ClearDataSavingStatistics(
DataReductionProxySavingsClearedReason reason) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(data_reduction_proxy_service_->compression_stats());
data_reduction_proxy_service_->compression_stats()->ClearDataSavingStatistics(
reason);
}
int64_t DataReductionProxySettings::GetTotalHttpContentLengthSaved() {
DCHECK(thread_checker_.CalledOnValidThread());
return data_reduction_proxy_service_->compression_stats()
->GetHttpOriginalContentLength() -
data_reduction_proxy_service_->compression_stats()
->GetHttpReceivedContentLength();
}
void DataReductionProxySettings::SetUnreachable(bool unreachable) {
unreachable_ = unreachable;
}
bool DataReductionProxySettings::IsDataReductionProxyUnreachable() {
DCHECK(thread_checker_.CalledOnValidThread());
return unreachable_;
}
PrefService* DataReductionProxySettings::GetOriginalProfilePrefs() {
DCHECK(thread_checker_.CalledOnValidThread());
return prefs_;
}
void DataReductionProxySettings::RegisterDataReductionProxyFieldTrial() {
register_synthetic_field_trial_.Run(
"SyntheticDataReductionProxySetting",
IsDataReductionProxyEnabled() ? "Enabled" : "Disabled");
}
void DataReductionProxySettings::OnProxyEnabledPrefChange() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!register_synthetic_field_trial_.is_null()) {
RegisterDataReductionProxyFieldTrial();
}
MaybeActivateDataReductionProxy(false);
}
void DataReductionProxySettings::ResetDataReductionStatistics() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(data_reduction_proxy_service_->compression_stats());
data_reduction_proxy_service_->compression_stats()->ResetStatistics();
}
void DataReductionProxySettings::UpdateIOData(bool at_startup) {
data_reduction_proxy_service_->SetProxyPrefs(IsDataReductionProxyEnabled(),
at_startup);
}
void DataReductionProxySettings::MaybeActivateDataReductionProxy(
bool at_startup) {
DCHECK(thread_checker_.CalledOnValidThread());
PrefService* prefs = GetOriginalProfilePrefs();
// Do nothing if prefs have not been initialized. This allows unit testing
// of profile related code without having to initialize data reduction proxy
// related prefs.
if (!prefs)
return;
if (spdy_proxy_auth_enabled_.GetValue() && at_startup) {
// Record the number of days since data reduction proxy has been enabled.
int64_t last_enabled_time =
prefs->GetInt64(prefs::kDataReductionProxyLastEnabledTime);
if (last_enabled_time != 0) {
// Record the metric only if the time when data reduction proxy was
// enabled is available.
RecordDaysSinceEnabledMetric(
(clock_->Now() - base::Time::FromInternalValue(last_enabled_time))
.InDays());
}
int64_t last_savings_cleared_time = prefs->GetInt64(
prefs::kDataReductionProxySavingsClearedNegativeSystemClock);
if (last_savings_cleared_time != 0) {
int32_t days_since_savings_cleared =
(clock_->Now() -
base::Time::FromInternalValue(last_savings_cleared_time))
.InDays();
// Sample in the UMA histograms must be at least 1.
if (days_since_savings_cleared == 0)
days_since_savings_cleared = 1;
UMA_HISTOGRAM_CUSTOM_COUNTS(
"DataReductionProxy.DaysSinceSavingsCleared.NegativeSystemClock",
days_since_savings_cleared, 1, 365, 50);
}
}
if (spdy_proxy_auth_enabled_.GetValue() &&
!prefs->GetBoolean(prefs::kDataReductionProxyWasEnabledBefore)) {
prefs->SetBoolean(prefs::kDataReductionProxyWasEnabledBefore, true);
ResetDataReductionStatistics();
}
if (!at_startup) {
if (IsDataReductionProxyEnabled()) {
RecordSettingsEnabledState(DATA_REDUCTION_SETTINGS_ACTION_OFF_TO_ON);
// Data reduction proxy has been enabled by the user. Record the number of
// days since the data reduction proxy has been enabled as zero, and
// store the current time in the pref.
prefs->SetInt64(prefs::kDataReductionProxyLastEnabledTime,
clock_->Now().ToInternalValue());
RecordDaysSinceEnabledMetric(0);
} else {
RecordSettingsEnabledState(DATA_REDUCTION_SETTINGS_ACTION_ON_TO_OFF);
}
}
// Configure use of the data reduction proxy if it is enabled.
if (at_startup && !data_reduction_proxy_service_->Initialized())
deferred_initialization_ = true;
else
UpdateIOData(at_startup);
}
DataReductionProxyEventStore* DataReductionProxySettings::GetEventStore()
const {
if (data_reduction_proxy_service_)
return data_reduction_proxy_service_->event_store();
return nullptr;
}
// Metrics methods
void DataReductionProxySettings::RecordDataReductionInit() const {
DCHECK(thread_checker_.CalledOnValidThread());
RecordStartupState(IsDataReductionProxyEnabled() ? PROXY_ENABLED
: PROXY_DISABLED);
RecordStartupSavings();
}
void DataReductionProxySettings::RecordStartupState(
ProxyStartupState state) const {
UMA_HISTOGRAM_ENUMERATION(kUMAProxyStartupStateHistogram,
state,
PROXY_STARTUP_STATE_COUNT);
}
void DataReductionProxySettings::RecordStartupSavings() const {
// Minimum bytes the user should have browsed, for the data savings percent
// UMA to be recorded at startup.
const unsigned int kMinOriginalContentLengthBytes =
10 * 1024 * 1024; // 10 MB.
if (!IsDataReductionProxyEnabled())
return;
DCHECK(data_reduction_proxy_service_->compression_stats());
int64_t original_content_length =
data_reduction_proxy_service_->compression_stats()
->GetHttpOriginalContentLength();
int64_t received_content_length =
data_reduction_proxy_service_->compression_stats()
->GetHttpReceivedContentLength();
if (original_content_length < kMinOriginalContentLengthBytes)
return;
int savings_percent =
static_cast<int>(((original_content_length - received_content_length) /
(float)original_content_length) *
100.0);
if (savings_percent >= 0) {
UMA_HISTOGRAM_PERCENTAGE("DataReductionProxy.StartupSavingsPercent",
savings_percent > 0 ? savings_percent : 0);
}
if (savings_percent < 0) {
UMA_HISTOGRAM_PERCENTAGE("DataReductionProxy.StartupNegativeSavingsPercent",
-savings_percent);
}
}
ContentLengthList
DataReductionProxySettings::GetDailyContentLengths(const char* pref_name) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(data_reduction_proxy_service_->compression_stats());
return data_reduction_proxy_service_->compression_stats()->
GetDailyContentLengths(pref_name);
}
void DataReductionProxySettings::GetContentLengths(
unsigned int days,
int64_t* original_content_length,
int64_t* received_content_length,
int64_t* last_update_time) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(data_reduction_proxy_service_->compression_stats());
data_reduction_proxy_service_->compression_stats()->GetContentLengths(
days, original_content_length, received_content_length, last_update_time);
}
} // namespace data_reduction_proxy