166 lines
5.8 KiB
C++
166 lines
5.8 KiB
C++
// Copyright 2016 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "components/metrics/data_use_tracker.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "base/strings/string_number_conversions.h"
|
|
#include "base/strings/stringprintf.h"
|
|
#include "base/values.h"
|
|
#include "build/build_config.h"
|
|
#include "components/metrics/metrics_pref_names.h"
|
|
#include "components/prefs/scoped_user_pref_update.h"
|
|
|
|
namespace metrics {
|
|
|
|
namespace {
|
|
|
|
// Default weekly quota and allowed UMA ratio for UMA log uploads for Android.
|
|
// These defaults will not be used for non-Android as |DataUseTracker| will not
|
|
// be initialized.
|
|
const int kDefaultUMAWeeklyQuotaBytes = 200 * 1024; // 200KB.
|
|
const double kDefaultUMARatio = 0.05;
|
|
|
|
} // namespace
|
|
|
|
DataUseTracker::DataUseTracker(PrefService* local_state)
|
|
: local_state_(local_state) {}
|
|
|
|
DataUseTracker::~DataUseTracker() {}
|
|
|
|
// static
|
|
std::unique_ptr<DataUseTracker> DataUseTracker::Create(
|
|
PrefService* local_state) {
|
|
std::unique_ptr<DataUseTracker> data_use_tracker;
|
|
// Instantiate DataUseTracker only on Android. UpdateMetricsUsagePrefs() honors
|
|
// this rule too.
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
data_use_tracker = std::make_unique<DataUseTracker>(local_state);
|
|
#endif
|
|
return data_use_tracker;
|
|
}
|
|
|
|
// static
|
|
void DataUseTracker::RegisterPrefs(PrefRegistrySimple* registry) {
|
|
registry->RegisterDictionaryPref(metrics::prefs::kUserCellDataUse);
|
|
registry->RegisterDictionaryPref(metrics::prefs::kUmaCellDataUse);
|
|
}
|
|
|
|
// static
|
|
void DataUseTracker::UpdateMetricsUsagePrefs(int message_size,
|
|
bool is_cellular,
|
|
bool is_metrics_service_usage,
|
|
PrefService* local_state) {
|
|
// Instantiate DataUseTracker only on Android. Create() honors this rule too.
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
metrics::DataUseTracker tracker(local_state);
|
|
tracker.UpdateMetricsUsagePrefsInternal(message_size, is_cellular,
|
|
is_metrics_service_usage);
|
|
#endif // BUILDFLAG(IS_ANDROID)
|
|
}
|
|
|
|
void DataUseTracker::UpdateMetricsUsagePrefsInternal(
|
|
int message_size,
|
|
bool is_cellular,
|
|
bool is_metrics_service_usage) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
|
if (!is_cellular)
|
|
return;
|
|
|
|
UpdateUsagePref(prefs::kUserCellDataUse, message_size);
|
|
// TODO(holte): Consider adding seperate tracking for UKM.
|
|
if (is_metrics_service_usage)
|
|
UpdateUsagePref(prefs::kUmaCellDataUse, message_size);
|
|
}
|
|
|
|
bool DataUseTracker::ShouldUploadLogOnCellular(int log_bytes) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
|
RemoveExpiredEntries();
|
|
|
|
int uma_total_data_use = ComputeTotalDataUse(prefs::kUmaCellDataUse);
|
|
int new_uma_total_data_use = log_bytes + uma_total_data_use;
|
|
// If the new log doesn't increase the total UMA traffic to be above the
|
|
// allowed quota then the log should be uploaded.
|
|
if (new_uma_total_data_use <= kDefaultUMAWeeklyQuotaBytes) {
|
|
return true;
|
|
}
|
|
|
|
int user_total_data_use = ComputeTotalDataUse(prefs::kUserCellDataUse);
|
|
// If after adding the new log the uma ratio is still under the allowed ratio
|
|
// then the log should be uploaded and vice versa.
|
|
return new_uma_total_data_use /
|
|
static_cast<double>(log_bytes + user_total_data_use) <=
|
|
kDefaultUMARatio;
|
|
}
|
|
|
|
void DataUseTracker::UpdateUsagePref(const std::string& pref_name,
|
|
int message_size) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
|
ScopedDictPrefUpdate pref_updater(local_state_, pref_name);
|
|
std::string todays_key = GetCurrentMeasurementDateAsString();
|
|
|
|
const base::Value::Dict& user_pref_dict = local_state_->GetDict(pref_name);
|
|
int todays_traffic = user_pref_dict.FindInt(todays_key).value_or(0);
|
|
pref_updater->Set(todays_key, todays_traffic + message_size);
|
|
}
|
|
|
|
void DataUseTracker::RemoveExpiredEntries() {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
RemoveExpiredEntriesForPref(prefs::kUmaCellDataUse);
|
|
RemoveExpiredEntriesForPref(prefs::kUserCellDataUse);
|
|
}
|
|
|
|
void DataUseTracker::RemoveExpiredEntriesForPref(const std::string& pref_name) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
|
const base::Value::Dict& user_pref_dict = local_state_->GetDict(pref_name);
|
|
const base::Time current_date = GetCurrentMeasurementDate();
|
|
const base::Time week_ago = current_date - base::Days(7);
|
|
|
|
base::Value::Dict user_pref_new_dict;
|
|
for (const auto it : user_pref_dict) {
|
|
base::Time key_date;
|
|
if (base::Time::FromUTCString(it.first.c_str(), &key_date) &&
|
|
key_date > week_ago) {
|
|
user_pref_new_dict.Set(it.first, it.second.Clone());
|
|
}
|
|
}
|
|
local_state_->SetDict(pref_name, std::move(user_pref_new_dict));
|
|
}
|
|
|
|
// Note: We compute total data use regardless of what is the current date. In
|
|
// scenario when user travels back in time zone and current date becomes earlier
|
|
// than latest registered date in perf, we still count that in total use as user
|
|
// actually used that data.
|
|
int DataUseTracker::ComputeTotalDataUse(const std::string& pref_name) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
|
int total_data_use = 0;
|
|
const base::Value::Dict& pref_dict = local_state_->GetDict(pref_name);
|
|
for (const auto it : pref_dict) {
|
|
total_data_use += it.second.GetIfInt().value_or(0);
|
|
}
|
|
return total_data_use;
|
|
}
|
|
|
|
base::Time DataUseTracker::GetCurrentMeasurementDate() const {
|
|
return base::Time::Now().LocalMidnight();
|
|
}
|
|
|
|
std::string DataUseTracker::GetCurrentMeasurementDateAsString() const {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
|
base::Time::Exploded today_exploded;
|
|
GetCurrentMeasurementDate().LocalExplode(&today_exploded);
|
|
return base::StringPrintf("%04d-%02d-%02d", today_exploded.year,
|
|
today_exploded.month, today_exploded.day_of_month);
|
|
}
|
|
|
|
} // namespace metrics
|