data_use_tracker.cc 6.9 KB

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