xref: /aosp_15_r20/external/cronet/components/metrics/data_use_tracker.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2016 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "components/metrics/data_use_tracker.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <memory>
8*6777b538SAndroid Build Coastguard Worker #include <string>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/i18n/time_formatting.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
12*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
13*6777b538SAndroid Build Coastguard Worker #include "components/metrics/metrics_pref_names.h"
14*6777b538SAndroid Build Coastguard Worker #include "components/prefs/scoped_user_pref_update.h"
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker namespace metrics {
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker namespace {
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker // Default weekly quota and allowed UMA ratio for UMA log uploads for Android.
21*6777b538SAndroid Build Coastguard Worker // These defaults will not be used for non-Android as |DataUseTracker| will not
22*6777b538SAndroid Build Coastguard Worker // be initialized.
23*6777b538SAndroid Build Coastguard Worker const int kDefaultUMAWeeklyQuotaBytes = 200 * 1024;  // 200KB.
24*6777b538SAndroid Build Coastguard Worker const double kDefaultUMARatio = 0.05;
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker }  // namespace
27*6777b538SAndroid Build Coastguard Worker 
DataUseTracker(PrefService * local_state)28*6777b538SAndroid Build Coastguard Worker DataUseTracker::DataUseTracker(PrefService* local_state)
29*6777b538SAndroid Build Coastguard Worker     : local_state_(local_state) {}
30*6777b538SAndroid Build Coastguard Worker 
~DataUseTracker()31*6777b538SAndroid Build Coastguard Worker DataUseTracker::~DataUseTracker() {}
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker // static
Create(PrefService * local_state)34*6777b538SAndroid Build Coastguard Worker std::unique_ptr<DataUseTracker> DataUseTracker::Create(
35*6777b538SAndroid Build Coastguard Worker     PrefService* local_state) {
36*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DataUseTracker> data_use_tracker;
37*6777b538SAndroid Build Coastguard Worker // Instantiate DataUseTracker only on Android. UpdateMetricsUsagePrefs() honors
38*6777b538SAndroid Build Coastguard Worker // this rule too.
39*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
40*6777b538SAndroid Build Coastguard Worker   data_use_tracker = std::make_unique<DataUseTracker>(local_state);
41*6777b538SAndroid Build Coastguard Worker #endif
42*6777b538SAndroid Build Coastguard Worker   return data_use_tracker;
43*6777b538SAndroid Build Coastguard Worker }
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker // static
RegisterPrefs(PrefRegistrySimple * registry)46*6777b538SAndroid Build Coastguard Worker void DataUseTracker::RegisterPrefs(PrefRegistrySimple* registry) {
47*6777b538SAndroid Build Coastguard Worker   registry->RegisterDictionaryPref(metrics::prefs::kUserCellDataUse);
48*6777b538SAndroid Build Coastguard Worker   registry->RegisterDictionaryPref(metrics::prefs::kUmaCellDataUse);
49*6777b538SAndroid Build Coastguard Worker }
50*6777b538SAndroid Build Coastguard Worker 
51*6777b538SAndroid Build Coastguard Worker // static
UpdateMetricsUsagePrefs(int message_size,bool is_cellular,bool is_metrics_service_usage,PrefService * local_state)52*6777b538SAndroid Build Coastguard Worker void DataUseTracker::UpdateMetricsUsagePrefs(int message_size,
53*6777b538SAndroid Build Coastguard Worker                                              bool is_cellular,
54*6777b538SAndroid Build Coastguard Worker                                              bool is_metrics_service_usage,
55*6777b538SAndroid Build Coastguard Worker                                              PrefService* local_state) {
56*6777b538SAndroid Build Coastguard Worker // Instantiate DataUseTracker only on Android. Create() honors this rule too.
57*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
58*6777b538SAndroid Build Coastguard Worker   metrics::DataUseTracker tracker(local_state);
59*6777b538SAndroid Build Coastguard Worker   tracker.UpdateMetricsUsagePrefsInternal(message_size, is_cellular,
60*6777b538SAndroid Build Coastguard Worker                                           is_metrics_service_usage);
61*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_ANDROID)
62*6777b538SAndroid Build Coastguard Worker }
63*6777b538SAndroid Build Coastguard Worker 
UpdateMetricsUsagePrefsInternal(int message_size,bool is_cellular,bool is_metrics_service_usage)64*6777b538SAndroid Build Coastguard Worker void DataUseTracker::UpdateMetricsUsagePrefsInternal(
65*6777b538SAndroid Build Coastguard Worker     int message_size,
66*6777b538SAndroid Build Coastguard Worker     bool is_cellular,
67*6777b538SAndroid Build Coastguard Worker     bool is_metrics_service_usage) {
68*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
69*6777b538SAndroid Build Coastguard Worker 
70*6777b538SAndroid Build Coastguard Worker   if (!is_cellular)
71*6777b538SAndroid Build Coastguard Worker     return;
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker   UpdateUsagePref(prefs::kUserCellDataUse, message_size);
74*6777b538SAndroid Build Coastguard Worker   // TODO(holte): Consider adding seperate tracking for UKM.
75*6777b538SAndroid Build Coastguard Worker   if (is_metrics_service_usage)
76*6777b538SAndroid Build Coastguard Worker     UpdateUsagePref(prefs::kUmaCellDataUse, message_size);
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker 
ShouldUploadLogOnCellular(int log_bytes)79*6777b538SAndroid Build Coastguard Worker bool DataUseTracker::ShouldUploadLogOnCellular(int log_bytes) {
80*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker   RemoveExpiredEntries();
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   int uma_total_data_use = ComputeTotalDataUse(prefs::kUmaCellDataUse);
85*6777b538SAndroid Build Coastguard Worker   int new_uma_total_data_use = log_bytes + uma_total_data_use;
86*6777b538SAndroid Build Coastguard Worker   // If the new log doesn't increase the total UMA traffic to be above the
87*6777b538SAndroid Build Coastguard Worker   // allowed quota then the log should be uploaded.
88*6777b538SAndroid Build Coastguard Worker   if (new_uma_total_data_use <= kDefaultUMAWeeklyQuotaBytes) {
89*6777b538SAndroid Build Coastguard Worker     return true;
90*6777b538SAndroid Build Coastguard Worker   }
91*6777b538SAndroid Build Coastguard Worker 
92*6777b538SAndroid Build Coastguard Worker   int user_total_data_use = ComputeTotalDataUse(prefs::kUserCellDataUse);
93*6777b538SAndroid Build Coastguard Worker   // If after adding the new log the uma ratio is still under the allowed ratio
94*6777b538SAndroid Build Coastguard Worker   // then the log should be uploaded and vice versa.
95*6777b538SAndroid Build Coastguard Worker   return new_uma_total_data_use /
96*6777b538SAndroid Build Coastguard Worker              static_cast<double>(log_bytes + user_total_data_use) <=
97*6777b538SAndroid Build Coastguard Worker          kDefaultUMARatio;
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker 
UpdateUsagePref(const std::string & pref_name,int message_size)100*6777b538SAndroid Build Coastguard Worker void DataUseTracker::UpdateUsagePref(const std::string& pref_name,
101*6777b538SAndroid Build Coastguard Worker                                      int message_size) {
102*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker   ScopedDictPrefUpdate pref_updater(local_state_, pref_name);
105*6777b538SAndroid Build Coastguard Worker   std::string todays_key = GetCurrentMeasurementDateAsString();
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker   const base::Value::Dict& user_pref_dict = local_state_->GetDict(pref_name);
108*6777b538SAndroid Build Coastguard Worker   int todays_traffic = user_pref_dict.FindInt(todays_key).value_or(0);
109*6777b538SAndroid Build Coastguard Worker   pref_updater->Set(todays_key, todays_traffic + message_size);
110*6777b538SAndroid Build Coastguard Worker }
111*6777b538SAndroid Build Coastguard Worker 
RemoveExpiredEntries()112*6777b538SAndroid Build Coastguard Worker void DataUseTracker::RemoveExpiredEntries() {
113*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
114*6777b538SAndroid Build Coastguard Worker   RemoveExpiredEntriesForPref(prefs::kUmaCellDataUse);
115*6777b538SAndroid Build Coastguard Worker   RemoveExpiredEntriesForPref(prefs::kUserCellDataUse);
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker 
RemoveExpiredEntriesForPref(const std::string & pref_name)118*6777b538SAndroid Build Coastguard Worker void DataUseTracker::RemoveExpiredEntriesForPref(const std::string& pref_name) {
119*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   const base::Value::Dict& user_pref_dict = local_state_->GetDict(pref_name);
122*6777b538SAndroid Build Coastguard Worker   const base::Time current_date = GetCurrentMeasurementDate();
123*6777b538SAndroid Build Coastguard Worker   const base::Time week_ago = current_date - base::Days(7);
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker   base::Value::Dict user_pref_new_dict;
126*6777b538SAndroid Build Coastguard Worker   for (const auto it : user_pref_dict) {
127*6777b538SAndroid Build Coastguard Worker     base::Time key_date;
128*6777b538SAndroid Build Coastguard Worker     if (base::Time::FromUTCString(it.first.c_str(), &key_date) &&
129*6777b538SAndroid Build Coastguard Worker         key_date > week_ago) {
130*6777b538SAndroid Build Coastguard Worker       user_pref_new_dict.Set(it.first, it.second.Clone());
131*6777b538SAndroid Build Coastguard Worker     }
132*6777b538SAndroid Build Coastguard Worker   }
133*6777b538SAndroid Build Coastguard Worker   local_state_->SetDict(pref_name, std::move(user_pref_new_dict));
134*6777b538SAndroid Build Coastguard Worker }
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker // Note: We compute total data use regardless of what is the current date. In
137*6777b538SAndroid Build Coastguard Worker // scenario when user travels back in time zone and current date becomes earlier
138*6777b538SAndroid Build Coastguard Worker // than latest registered date in perf, we still count that in total use as user
139*6777b538SAndroid Build Coastguard Worker // actually used that data.
ComputeTotalDataUse(const std::string & pref_name)140*6777b538SAndroid Build Coastguard Worker int DataUseTracker::ComputeTotalDataUse(const std::string& pref_name) {
141*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker   int total_data_use = 0;
144*6777b538SAndroid Build Coastguard Worker   const base::Value::Dict& pref_dict = local_state_->GetDict(pref_name);
145*6777b538SAndroid Build Coastguard Worker   for (const auto it : pref_dict) {
146*6777b538SAndroid Build Coastguard Worker     total_data_use += it.second.GetIfInt().value_or(0);
147*6777b538SAndroid Build Coastguard Worker   }
148*6777b538SAndroid Build Coastguard Worker   return total_data_use;
149*6777b538SAndroid Build Coastguard Worker }
150*6777b538SAndroid Build Coastguard Worker 
GetCurrentMeasurementDate() const151*6777b538SAndroid Build Coastguard Worker base::Time DataUseTracker::GetCurrentMeasurementDate() const {
152*6777b538SAndroid Build Coastguard Worker   return base::Time::Now().LocalMidnight();
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker 
GetCurrentMeasurementDateAsString() const155*6777b538SAndroid Build Coastguard Worker std::string DataUseTracker::GetCurrentMeasurementDateAsString() const {
156*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
157*6777b538SAndroid Build Coastguard Worker   return base::UnlocalizedTimeFormatWithPattern(GetCurrentMeasurementDate(),
158*6777b538SAndroid Build Coastguard Worker                                                 "yyyy-MM-dd");
159*6777b538SAndroid Build Coastguard Worker }
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker }  // namespace metrics
162