1 // Copyright 2014 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 5 #include "components/metrics/metrics_state_manager.h" 6 7 #include "base/command_line.h" 8 #include "base/guid.h" 9 #include "base/metrics/histogram.h" 10 #include "base/metrics/sparse_histogram.h" 11 #include "base/prefs/pref_registry_simple.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/rand_util.h" 14 #include "base/strings/string_number_conversions.h" 15 #include "base/time/time.h" 16 #include "components/metrics/cloned_install_detector.h" 17 #include "components/metrics/machine_id_provider.h" 18 #include "components/metrics/metrics_pref_names.h" 19 #include "components/metrics/metrics_switches.h" 20 #include "components/variations/caching_permuted_entropy_provider.h" 21 22 namespace metrics { 23 24 namespace { 25 26 // The argument used to generate a non-identifying entropy source. We want no 27 // more than 13 bits of entropy, so use this max to return a number in the range 28 // [0, 7999] as the entropy source (12.97 bits of entropy). 29 const int kMaxLowEntropySize = 8000; 30 31 // Default prefs value for prefs::kMetricsLowEntropySource to indicate that 32 // the value has not yet been set. 33 const int kLowEntropySourceNotSet = -1; 34 35 // Generates a new non-identifying entropy source used to seed persistent 36 // activities. 37 int GenerateLowEntropySource() { 38 return base::RandInt(0, kMaxLowEntropySize - 1); 39 } 40 41 } // namespace 42 43 // static 44 bool MetricsStateManager::instance_exists_ = false; 45 46 MetricsStateManager::MetricsStateManager( 47 PrefService* local_state, 48 const base::Callback<bool(void)>& is_reporting_enabled_callback) 49 : local_state_(local_state), 50 is_reporting_enabled_callback_(is_reporting_enabled_callback), 51 low_entropy_source_(kLowEntropySourceNotSet), 52 entropy_source_returned_(ENTROPY_SOURCE_NONE) { 53 ResetMetricsIDsIfNecessary(); 54 if (IsMetricsReportingEnabled()) 55 ForceClientIdCreation(); 56 57 DCHECK(!instance_exists_); 58 instance_exists_ = true; 59 } 60 61 MetricsStateManager::~MetricsStateManager() { 62 DCHECK(instance_exists_); 63 instance_exists_ = false; 64 } 65 66 bool MetricsStateManager::IsMetricsReportingEnabled() { 67 return is_reporting_enabled_callback_.Run(); 68 } 69 70 void MetricsStateManager::ForceClientIdCreation() { 71 if (!client_id_.empty()) 72 return; 73 74 client_id_ = local_state_->GetString(prefs::kMetricsClientID); 75 if (!client_id_.empty()) 76 return; 77 78 client_id_ = base::GenerateGUID(); 79 local_state_->SetString(prefs::kMetricsClientID, client_id_); 80 81 if (local_state_->GetString(prefs::kMetricsOldClientID).empty()) { 82 // Record the timestamp of when the user opted in to UMA. 83 local_state_->SetInt64(prefs::kMetricsReportingEnabledTimestamp, 84 base::Time::Now().ToTimeT()); 85 } else { 86 UMA_HISTOGRAM_BOOLEAN("UMA.ClientIdMigrated", true); 87 } 88 local_state_->ClearPref(prefs::kMetricsOldClientID); 89 } 90 91 void MetricsStateManager::CheckForClonedInstall( 92 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 93 DCHECK(!cloned_install_detector_); 94 95 MachineIdProvider* provider = MachineIdProvider::CreateInstance(); 96 if (!provider) 97 return; 98 99 cloned_install_detector_.reset(new ClonedInstallDetector(provider)); 100 cloned_install_detector_->CheckForClonedInstall(local_state_, task_runner); 101 } 102 103 scoped_ptr<const base::FieldTrial::EntropyProvider> 104 MetricsStateManager::CreateEntropyProvider() { 105 // For metrics reporting-enabled users, we combine the client ID and low 106 // entropy source to get the final entropy source. Otherwise, only use the low 107 // entropy source. 108 // This has two useful properties: 109 // 1) It makes the entropy source less identifiable for parties that do not 110 // know the low entropy source. 111 // 2) It makes the final entropy source resettable. 112 const int low_entropy_source_value = GetLowEntropySource(); 113 UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LowEntropySourceValue", 114 low_entropy_source_value); 115 if (IsMetricsReportingEnabled()) { 116 if (entropy_source_returned_ == ENTROPY_SOURCE_NONE) 117 entropy_source_returned_ = ENTROPY_SOURCE_HIGH; 118 DCHECK_EQ(ENTROPY_SOURCE_HIGH, entropy_source_returned_); 119 const std::string high_entropy_source = 120 client_id_ + base::IntToString(low_entropy_source_value); 121 return scoped_ptr<const base::FieldTrial::EntropyProvider>( 122 new SHA1EntropyProvider(high_entropy_source)); 123 } 124 125 if (entropy_source_returned_ == ENTROPY_SOURCE_NONE) 126 entropy_source_returned_ = ENTROPY_SOURCE_LOW; 127 DCHECK_EQ(ENTROPY_SOURCE_LOW, entropy_source_returned_); 128 129 #if defined(OS_ANDROID) || defined(OS_IOS) 130 return scoped_ptr<const base::FieldTrial::EntropyProvider>( 131 new CachingPermutedEntropyProvider(local_state_, 132 low_entropy_source_value, 133 kMaxLowEntropySize)); 134 #else 135 return scoped_ptr<const base::FieldTrial::EntropyProvider>( 136 new PermutedEntropyProvider(low_entropy_source_value, 137 kMaxLowEntropySize)); 138 #endif 139 } 140 141 // static 142 scoped_ptr<MetricsStateManager> MetricsStateManager::Create( 143 PrefService* local_state, 144 const base::Callback<bool(void)>& is_reporting_enabled_callback) { 145 scoped_ptr<MetricsStateManager> result; 146 // Note: |instance_exists_| is updated in the constructor and destructor. 147 if (!instance_exists_) { 148 result.reset( 149 new MetricsStateManager(local_state, is_reporting_enabled_callback)); 150 } 151 return result.Pass(); 152 } 153 154 // static 155 void MetricsStateManager::RegisterPrefs(PrefRegistrySimple* registry) { 156 registry->RegisterBooleanPref(prefs::kMetricsResetIds, false); 157 registry->RegisterStringPref(prefs::kMetricsClientID, std::string()); 158 registry->RegisterInt64Pref(prefs::kMetricsReportingEnabledTimestamp, 0); 159 registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource, 160 kLowEntropySourceNotSet); 161 162 ClonedInstallDetector::RegisterPrefs(registry); 163 CachingPermutedEntropyProvider::RegisterPrefs(registry); 164 165 // TODO(asvitkine): Remove these once a couple of releases have passed. 166 // http://crbug.com/357704 167 registry->RegisterStringPref(prefs::kMetricsOldClientID, std::string()); 168 registry->RegisterIntegerPref(prefs::kMetricsOldLowEntropySource, 0); 169 } 170 171 int MetricsStateManager::GetLowEntropySource() { 172 // Note that the default value for the low entropy source and the default pref 173 // value are both kLowEntropySourceNotSet, which is used to identify if the 174 // value has been set or not. 175 if (low_entropy_source_ != kLowEntropySourceNotSet) 176 return low_entropy_source_; 177 178 const CommandLine* command_line(CommandLine::ForCurrentProcess()); 179 // Only try to load the value from prefs if the user did not request a 180 // reset. 181 // Otherwise, skip to generating a new value. 182 if (!command_line->HasSwitch(switches::kResetVariationState)) { 183 int value = local_state_->GetInteger(prefs::kMetricsLowEntropySource); 184 // If the value is outside the [0, kMaxLowEntropySize) range, re-generate 185 // it below. 186 if (value >= 0 && value < kMaxLowEntropySize) { 187 low_entropy_source_ = value; 188 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", false); 189 return low_entropy_source_; 190 } 191 } 192 193 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", true); 194 low_entropy_source_ = GenerateLowEntropySource(); 195 local_state_->SetInteger(prefs::kMetricsLowEntropySource, 196 low_entropy_source_); 197 local_state_->ClearPref(prefs::kMetricsOldLowEntropySource); 198 CachingPermutedEntropyProvider::ClearCache(local_state_); 199 200 return low_entropy_source_; 201 } 202 203 void MetricsStateManager::ResetMetricsIDsIfNecessary() { 204 if (!local_state_->GetBoolean(prefs::kMetricsResetIds)) 205 return; 206 207 UMA_HISTOGRAM_BOOLEAN("UMA.MetricsIDsReset", true); 208 209 DCHECK(client_id_.empty()); 210 DCHECK_EQ(kLowEntropySourceNotSet, low_entropy_source_); 211 212 local_state_->ClearPref(prefs::kMetricsClientID); 213 local_state_->ClearPref(prefs::kMetricsLowEntropySource); 214 local_state_->ClearPref(prefs::kMetricsResetIds); 215 } 216 217 } // namespace metrics 218