Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: chrome/browser/metrics/metrics_state_manager.cc

Issue 256143006: Refactor MetricsStateManager class out of MetricsService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "chrome/browser/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 "chrome/browser/metrics/cloned_install_detector.h"
17 #include "chrome/browser/metrics/machine_id_provider.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/metrics/caching_permuted_entropy_provider.h"
20 #include "chrome/common/pref_names.h"
21
22 #if defined(OS_CHROMEOS)
23 #include "chrome/browser/chromeos/settings/cros_settings.h"
24 #endif
25
26
Ilya Sherman 2014/05/02 23:12:03 nit: Spurious newline.
Alexei Svitkine (slow) 2014/05/05 14:10:43 Done.
27 namespace metrics {
28
29 namespace {
30
31 // The argument used to generate a non-identifying entropy source. We want no
32 // more than 13 bits of entropy, so use this max to return a number in the range
33 // [0, 7999] as the entropy source (12.97 bits of entropy).
34 const int kMaxLowEntropySize = 8000;
35
36 // Default prefs value for prefs::kMetricsLowEntropySource to indicate that the
37 // value has not yet been set.
38 const int kLowEntropySourceNotSet = -1;
39
40 // Generates a new non-identifying entropy source used to seed persistent
41 // activities.
42 int GenerateLowEntropySource() {
43 return base::RandInt(0, kMaxLowEntropySize - 1);
44 }
45
46 } // namespace
47
48 // static
49 bool MetricsStateManager::instance_exists_ = false;
50
51 MetricsStateManager::MetricsStateManager(PrefService* local_state)
52 : local_state_(local_state),
53 low_entropy_source_(kLowEntropySourceNotSet),
54 entropy_source_returned_(ENTROPY_SOURCE_NONE) {
55 ResetMetricsIDsIfNecessary();
56 if (IsMetricsReportingEnabled())
57 ForceClientIdCreation();
58
59 DCHECK(!instance_exists_);
60 instance_exists_ = true;
61 }
62
63 MetricsStateManager::~MetricsStateManager() {
64 DCHECK(instance_exists_);
65 instance_exists_ = false;
66 }
67
68 bool MetricsStateManager::IsMetricsReportingEnabled() {
69 // If the user permits metrics reporting with the checkbox in the
70 // prefs, we turn on recording. We disable metrics completely for
71 // non-official builds. This can be forced with a flag.
72 const CommandLine* command_line = CommandLine::ForCurrentProcess();
73 if (command_line->HasSwitch(switches::kEnableMetricsReportingForTesting))
74 return true;
75
76 // Disable metrics reporting when field trials are forced.
77 if (command_line->HasSwitch(switches::kForceFieldTrials))
78 return false;
79
80 bool enabled = false;
81 #if defined(GOOGLE_CHROME_BUILD)
82 #if defined(OS_CHROMEOS)
83 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
84 &enabled);
85 #else
86 enabled = local_state->GetBoolean(prefs::kMetricsReportingEnabled);
87 #endif // #if defined(OS_CHROMEOS)
88 #endif // defined(GOOGLE_CHROME_BUILD)
89 return enabled;
90 }
91
92 void MetricsStateManager::ForceClientIdCreation() {
93 if (!client_id_.empty())
94 return;
95
96 client_id_ = local_state_->GetString(prefs::kMetricsClientID);
97 if (!client_id_.empty())
98 return;
99
100 client_id_ = base::GenerateGUID();
101 local_state_->SetString(prefs::kMetricsClientID, client_id_);
102
103 if (local_state_->GetString(prefs::kMetricsOldClientID).empty()) {
104 // Record the timestamp of when the user opted in to UMA.
105 local_state_->SetInt64(prefs::kMetricsReportingEnabledTimestamp,
106 base::Time::Now().ToTimeT());
107 } else {
108 UMA_HISTOGRAM_BOOLEAN("UMA.ClientIdMigrated", true);
109 }
110 local_state_->ClearPref(prefs::kMetricsOldClientID);
111 }
112
113 void MetricsStateManager::CheckForClonedInstall() {
114 DCHECK(!cloned_install_detector_);
115
116 MachineIdProvider* provider = MachineIdProvider::CreateInstance();
117 if (!provider)
118 return;
119
120 cloned_install_detector_.reset(new ClonedInstallDetector(provider));
121 cloned_install_detector_->CheckForClonedInstall(local_state_);
122 }
123
124 scoped_ptr<const base::FieldTrial::EntropyProvider>
125 MetricsStateManager::CreateEntropyProvider() {
126 // For metrics reporting-enabled users, we combine the client ID and low
127 // entropy source to get the final entropy source. Otherwise, only use the low
128 // entropy source.
129 // This has two useful properties:
130 // 1) It makes the entropy source less identifiable for parties that do not
131 // know the low entropy source.
132 // 2) It makes the final entropy source resettable.
133 const int low_entropy_source_value = GetLowEntropySource();
134 UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LowEntropySourceValue",
135 low_entropy_source_value);
136 if (IsMetricsReportingEnabled()) {
137 if (entropy_source_returned_ == ENTROPY_SOURCE_NONE)
138 entropy_source_returned_ = ENTROPY_SOURCE_HIGH;
139 DCHECK_EQ(ENTROPY_SOURCE_HIGH, entropy_source_returned_);
140 const std::string high_entropy_source =
141 client_id_ + base::IntToString(low_entropy_source_value);
142 return scoped_ptr<const base::FieldTrial::EntropyProvider>(
143 new SHA1EntropyProvider(high_entropy_source));
144 }
145
146 if (entropy_source_returned_ == ENTROPY_SOURCE_NONE)
147 entropy_source_returned_ = ENTROPY_SOURCE_LOW;
148 DCHECK_EQ(ENTROPY_SOURCE_LOW, entropy_source_returned_);
149
150 #if defined(OS_ANDROID) || defined(OS_IOS)
151 return scoped_ptr<const base::FieldTrial::EntropyProvider>(
152 new CachingPermutedEntropyProvider(local_state_,
153 low_entropy_source_value,
154 kMaxLowEntropySize));
155 #else
156 return scoped_ptr<const base::FieldTrial::EntropyProvider>(
157 new PermutedEntropyProvider(low_entropy_source_value,
158 kMaxLowEntropySize));
159 #endif
160 }
161
162 // static
163 scoped_ptr<MetricsStateManager> MetricsStateManager::Create(
164 PrefService* local_state) {
165 scoped_ptr<MetricsStateManager> result;
166 // Note: |instance_exists_| is updated in the constructor and destructor.
167 if (!instance_exists_)
168 result.reset(new MetricsStateManager(local_state));
169 return result.Pass();
170 }
171
172 // static
173 void MetricsStateManager::RegisterPrefs(PrefRegistrySimple* registry) {
174 registry->RegisterBooleanPref(prefs::kMetricsResetIds, false);
175 registry->RegisterStringPref(prefs::kMetricsClientID, std::string());
176 registry->RegisterInt64Pref(prefs::kMetricsReportingEnabledTimestamp, 0);
177 registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource,
178 kLowEntropySourceNotSet);
179
180 ClonedInstallDetector::RegisterPrefs(registry);
181 CachingPermutedEntropyProvider::RegisterPrefs(registry);
182
183 // TODO(asvitkine): Remove these once a couple of releases have passed.
184 // http://crbug.com/357704
185 registry->RegisterStringPref(prefs::kMetricsOldClientID, std::string());
186 registry->RegisterIntegerPref(prefs::kMetricsOldLowEntropySource, 0);
187 }
188
189 int MetricsStateManager::GetLowEntropySource() {
190 // Note that the default value for the low entropy source and the default pref
191 // value are both kLowEntropySourceNotSet, which is used to identify if the
192 // value has been set or not.
193 if (low_entropy_source_ != kLowEntropySourceNotSet)
194 return low_entropy_source_;
195
196 const CommandLine* command_line(CommandLine::ForCurrentProcess());
197 // Only try to load the value from prefs if the user did not request a reset.
198 // Otherwise, skip to generating a new value.
199 if (!command_line->HasSwitch(switches::kResetVariationState)) {
200 int value = local_state_->GetInteger(prefs::kMetricsLowEntropySource);
201 // If the value is outside the [0, kMaxLowEntropySize) range, re-generate
202 // it below.
203 if (value >= 0 && value < kMaxLowEntropySize) {
204 low_entropy_source_ = value;
205 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", false);
206 return low_entropy_source_;
207 }
208 }
209
210 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", true);
211 low_entropy_source_ = GenerateLowEntropySource();
212 local_state_->SetInteger(prefs::kMetricsLowEntropySource,
213 low_entropy_source_);
214 local_state_->ClearPref(prefs::kMetricsOldLowEntropySource);
215 metrics::CachingPermutedEntropyProvider::ClearCache(local_state_);
216
217 return low_entropy_source_;
218 }
219
220 void MetricsStateManager::ResetMetricsIDsIfNecessary() {
221 if (!local_state_->GetBoolean(prefs::kMetricsResetIds))
222 return;
223
224 UMA_HISTOGRAM_BOOLEAN("UMA.MetricsIDsReset", true);
225
226 DCHECK(client_id_.empty());
227 DCHECK_EQ(kLowEntropySourceNotSet, low_entropy_source_);
228
229 local_state_->ClearPref(prefs::kMetricsClientID);
230 local_state_->ClearPref(prefs::kMetricsLowEntropySource);
231 local_state_->ClearPref(prefs::kMetricsResetIds);
232 }
233
234 } // namespace metrics
OLDNEW
« no previous file with comments | « chrome/browser/metrics/metrics_state_manager.h ('k') | chrome/browser/metrics/metrics_state_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698