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