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

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