xref: /aosp_15_r20/external/cronet/components/metrics/entropy_state.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2020 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "components/metrics/entropy_state.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include "base/command_line.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/token.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/unguessable_token.h"
14*6777b538SAndroid Build Coastguard Worker #include "components/metrics/metrics_pref_names.h"
15*6777b538SAndroid Build Coastguard Worker #include "components/metrics/metrics_switches.h"
16*6777b538SAndroid Build Coastguard Worker #include "components/prefs/pref_service.h"
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
19*6777b538SAndroid Build Coastguard Worker #include "base/android/jni_android.h"
20*6777b538SAndroid Build Coastguard Worker #include "components/metrics/jni_headers/LowEntropySource_jni.h"
21*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_ANDROID)
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker namespace metrics {
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker namespace {
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_LACROS)
28*6777b538SAndroid Build Coastguard Worker // Needed for a check to see if we retrieved entropy values before we have
29*6777b538SAndroid Build Coastguard Worker // transferred them from Ash.
30*6777b538SAndroid Build Coastguard Worker bool g_entropy_source_has_been_retrieved = false;
31*6777b538SAndroid Build Coastguard Worker bool g_entropy_source_has_been_set = false;
32*6777b538SAndroid Build Coastguard Worker #endif
33*6777b538SAndroid Build Coastguard Worker 
34*6777b538SAndroid Build Coastguard Worker // Generates a new non-identifying entropy source used to seed persistent
35*6777b538SAndroid Build Coastguard Worker // activities. Make it static so that the new low entropy source value will
36*6777b538SAndroid Build Coastguard Worker // only be generated on first access. And thus, even though we may write the
37*6777b538SAndroid Build Coastguard Worker // new low entropy source value to prefs multiple times, it stays the same
38*6777b538SAndroid Build Coastguard Worker // value.
GenerateLowEntropySource()39*6777b538SAndroid Build Coastguard Worker int GenerateLowEntropySource() {
40*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
41*6777b538SAndroid Build Coastguard Worker   // Note: As in the non-Android case below, the Java implementation also uses
42*6777b538SAndroid Build Coastguard Worker   // a static cache, so subsequent invocations will return the same value.
43*6777b538SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
44*6777b538SAndroid Build Coastguard Worker   return Java_LowEntropySource_generateLowEntropySource(env);
45*6777b538SAndroid Build Coastguard Worker #else
46*6777b538SAndroid Build Coastguard Worker   static const int low_entropy_source =
47*6777b538SAndroid Build Coastguard Worker       base::RandInt(0, EntropyState::kMaxLowEntropySize - 1);
48*6777b538SAndroid Build Coastguard Worker   return low_entropy_source;
49*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_ANDROID)
50*6777b538SAndroid Build Coastguard Worker }
51*6777b538SAndroid Build Coastguard Worker 
52*6777b538SAndroid Build Coastguard Worker // Generates a new non-identifying low entropy source using the same method
53*6777b538SAndroid Build Coastguard Worker // that's used for the actual low entropy source. This one, however, is only
54*6777b538SAndroid Build Coastguard Worker // used for statistical validation, and *not* for randomization or experiment
55*6777b538SAndroid Build Coastguard Worker // assignment.
GeneratePseudoLowEntropySource()56*6777b538SAndroid Build Coastguard Worker int GeneratePseudoLowEntropySource() {
57*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
58*6777b538SAndroid Build Coastguard Worker   // Note: As in the non-Android case below, the Java implementation also uses
59*6777b538SAndroid Build Coastguard Worker   // a static cache, so subsequent invocations will return the same value.
60*6777b538SAndroid Build Coastguard Worker   JNIEnv* env = base::android::AttachCurrentThread();
61*6777b538SAndroid Build Coastguard Worker   return Java_LowEntropySource_generatePseudoLowEntropySource(env);
62*6777b538SAndroid Build Coastguard Worker #else
63*6777b538SAndroid Build Coastguard Worker   static const int pseudo_low_entropy_source =
64*6777b538SAndroid Build Coastguard Worker       base::RandInt(0, EntropyState::kMaxLowEntropySize - 1);
65*6777b538SAndroid Build Coastguard Worker   return pseudo_low_entropy_source;
66*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_ANDROID)
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker }  // namespace
70*6777b538SAndroid Build Coastguard Worker 
EntropyState(PrefService * local_state)71*6777b538SAndroid Build Coastguard Worker EntropyState::EntropyState(PrefService* local_state)
72*6777b538SAndroid Build Coastguard Worker     : local_state_(local_state) {}
73*6777b538SAndroid Build Coastguard Worker 
74*6777b538SAndroid Build Coastguard Worker // static
75*6777b538SAndroid Build Coastguard Worker constexpr int EntropyState::kLowEntropySourceNotSet;
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker // static
ClearPrefs(PrefService * local_state)78*6777b538SAndroid Build Coastguard Worker void EntropyState::ClearPrefs(PrefService* local_state) {
79*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_LACROS)
80*6777b538SAndroid Build Coastguard Worker   // There are currently multiple EntropyState objects (crbug/1495576) and as
81*6777b538SAndroid Build Coastguard Worker   // Lacros does not own the entropy values anyways, it shouldn't clear them
82*6777b538SAndroid Build Coastguard Worker   // either.
83*6777b538SAndroid Build Coastguard Worker   LOG(WARNING) << "EntropyState::ClearPrefs ignored as set remotely.";
84*6777b538SAndroid Build Coastguard Worker #else
85*6777b538SAndroid Build Coastguard Worker   local_state->ClearPref(prefs::kMetricsLowEntropySource);
86*6777b538SAndroid Build Coastguard Worker   local_state->ClearPref(prefs::kMetricsOldLowEntropySource);
87*6777b538SAndroid Build Coastguard Worker   local_state->ClearPref(prefs::kMetricsPseudoLowEntropySource);
88*6777b538SAndroid Build Coastguard Worker   local_state->ClearPref(prefs::kMetricsLimitedEntropyRandomizationSource);
89*6777b538SAndroid Build Coastguard Worker #endif
90*6777b538SAndroid Build Coastguard Worker }
91*6777b538SAndroid Build Coastguard Worker 
92*6777b538SAndroid Build Coastguard Worker // static
RegisterPrefs(PrefRegistrySimple * registry)93*6777b538SAndroid Build Coastguard Worker void EntropyState::RegisterPrefs(PrefRegistrySimple* registry) {
94*6777b538SAndroid Build Coastguard Worker   registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource,
95*6777b538SAndroid Build Coastguard Worker                                 kLowEntropySourceNotSet);
96*6777b538SAndroid Build Coastguard Worker   registry->RegisterIntegerPref(prefs::kMetricsOldLowEntropySource,
97*6777b538SAndroid Build Coastguard Worker                                 kLowEntropySourceNotSet);
98*6777b538SAndroid Build Coastguard Worker   registry->RegisterIntegerPref(prefs::kMetricsPseudoLowEntropySource,
99*6777b538SAndroid Build Coastguard Worker                                 kLowEntropySourceNotSet);
100*6777b538SAndroid Build Coastguard Worker   registry->RegisterStringPref(prefs::kMetricsLimitedEntropyRandomizationSource,
101*6777b538SAndroid Build Coastguard Worker                                std::string());
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_LACROS)
105*6777b538SAndroid Build Coastguard Worker // static
SetExternalPrefs(PrefService * local_state,int low_entropy_source,int old_low_entropy_source,int pseudo_low_entropy_source,std::string_view limited_entropy_randomization_source)106*6777b538SAndroid Build Coastguard Worker void EntropyState::SetExternalPrefs(
107*6777b538SAndroid Build Coastguard Worker     PrefService* local_state,
108*6777b538SAndroid Build Coastguard Worker     int low_entropy_source,
109*6777b538SAndroid Build Coastguard Worker     int old_low_entropy_source,
110*6777b538SAndroid Build Coastguard Worker     int pseudo_low_entropy_source,
111*6777b538SAndroid Build Coastguard Worker     std::string_view limited_entropy_randomization_source) {
112*6777b538SAndroid Build Coastguard Worker   if (!g_entropy_source_has_been_set) {
113*6777b538SAndroid Build Coastguard Worker     g_entropy_source_has_been_set = true;
114*6777b538SAndroid Build Coastguard Worker     // As an |EntropyState| object has an internal state, we need to make sure
115*6777b538SAndroid Build Coastguard Worker     // that none gets read before the Ash values have been transferred.
116*6777b538SAndroid Build Coastguard Worker     // This is usually taken care of by
117*6777b538SAndroid Build Coastguard Worker     // `ChromeMetricsServicesManagerClient::GetMetricsStateManager` which first
118*6777b538SAndroid Build Coastguard Worker     // sets the Ash values and then creates the `MetricsStateManager`.
119*6777b538SAndroid Build Coastguard Worker     if (g_entropy_source_has_been_retrieved) {
120*6777b538SAndroid Build Coastguard Worker       LOG(ERROR) << "Entropy value was retrieved before they were updated";
121*6777b538SAndroid Build Coastguard Worker     }
122*6777b538SAndroid Build Coastguard Worker     DCHECK(!g_entropy_source_has_been_retrieved);
123*6777b538SAndroid Build Coastguard Worker   }
124*6777b538SAndroid Build Coastguard Worker   local_state->SetInteger(prefs::kMetricsLowEntropySource, low_entropy_source);
125*6777b538SAndroid Build Coastguard Worker   local_state->SetInteger(prefs::kMetricsOldLowEntropySource,
126*6777b538SAndroid Build Coastguard Worker                           old_low_entropy_source);
127*6777b538SAndroid Build Coastguard Worker   local_state->SetInteger(prefs::kMetricsPseudoLowEntropySource,
128*6777b538SAndroid Build Coastguard Worker                           pseudo_low_entropy_source);
129*6777b538SAndroid Build Coastguard Worker   if (IsValidLimitedEntropyRandomizationSource(
130*6777b538SAndroid Build Coastguard Worker           limited_entropy_randomization_source)) {
131*6777b538SAndroid Build Coastguard Worker     local_state->SetString(prefs::kMetricsLimitedEntropyRandomizationSource,
132*6777b538SAndroid Build Coastguard Worker                            limited_entropy_randomization_source);
133*6777b538SAndroid Build Coastguard Worker   }
134*6777b538SAndroid Build Coastguard Worker }
135*6777b538SAndroid Build Coastguard Worker #endif
136*6777b538SAndroid Build Coastguard Worker 
GetHighEntropySource(const std::string & initial_client_id)137*6777b538SAndroid Build Coastguard Worker std::string EntropyState::GetHighEntropySource(
138*6777b538SAndroid Build Coastguard Worker     const std::string& initial_client_id) {
139*6777b538SAndroid Build Coastguard Worker   DCHECK(!initial_client_id.empty());
140*6777b538SAndroid Build Coastguard Worker   // For metrics reporting-enabled users, we combine the client ID and low
141*6777b538SAndroid Build Coastguard Worker   // entropy source to get the final entropy source.
142*6777b538SAndroid Build Coastguard Worker   // This has two useful properties:
143*6777b538SAndroid Build Coastguard Worker   //  1) It makes the entropy source less identifiable for parties that do not
144*6777b538SAndroid Build Coastguard Worker   //     know the low entropy source.
145*6777b538SAndroid Build Coastguard Worker   //  2) It makes the final entropy source resettable.
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   // If this install has an old low entropy source, continue using it, to avoid
148*6777b538SAndroid Build Coastguard Worker   // changing the group assignments of studies using high entropy. New installs
149*6777b538SAndroid Build Coastguard Worker   // only have the new low entropy source. If the number of installs with old
150*6777b538SAndroid Build Coastguard Worker   // sources ever becomes small enough (see UMA.LowEntropySourceValue), we could
151*6777b538SAndroid Build Coastguard Worker   // remove it, and just use the new source here.
152*6777b538SAndroid Build Coastguard Worker   int low_entropy_source = GetOldLowEntropySource();
153*6777b538SAndroid Build Coastguard Worker   if (low_entropy_source == kLowEntropySourceNotSet)
154*6777b538SAndroid Build Coastguard Worker     low_entropy_source = GetLowEntropySource();
155*6777b538SAndroid Build Coastguard Worker 
156*6777b538SAndroid Build Coastguard Worker   return initial_client_id + base::NumberToString(low_entropy_source);
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker 
GetLowEntropySource()159*6777b538SAndroid Build Coastguard Worker int EntropyState::GetLowEntropySource() {
160*6777b538SAndroid Build Coastguard Worker   UpdateLowEntropySources();
161*6777b538SAndroid Build Coastguard Worker   return low_entropy_source_;
162*6777b538SAndroid Build Coastguard Worker }
163*6777b538SAndroid Build Coastguard Worker 
GetPseudoLowEntropySource()164*6777b538SAndroid Build Coastguard Worker int EntropyState::GetPseudoLowEntropySource() {
165*6777b538SAndroid Build Coastguard Worker   UpdateLowEntropySources();
166*6777b538SAndroid Build Coastguard Worker   return pseudo_low_entropy_source_;
167*6777b538SAndroid Build Coastguard Worker }
168*6777b538SAndroid Build Coastguard Worker 
GetOldLowEntropySource()169*6777b538SAndroid Build Coastguard Worker int EntropyState::GetOldLowEntropySource() {
170*6777b538SAndroid Build Coastguard Worker   UpdateLowEntropySources();
171*6777b538SAndroid Build Coastguard Worker   return old_low_entropy_source_;
172*6777b538SAndroid Build Coastguard Worker }
173*6777b538SAndroid Build Coastguard Worker 
GenerateLimitedEntropyRandomizationSource()174*6777b538SAndroid Build Coastguard Worker std::string EntropyState::GenerateLimitedEntropyRandomizationSource() {
175*6777b538SAndroid Build Coastguard Worker   // Uses a cryptographically strong random source to generate a random 128 bit
176*6777b538SAndroid Build Coastguard Worker   // value. The value cannot be all zeros.
177*6777b538SAndroid Build Coastguard Worker   auto token = base::UnguessableToken::Create().ToString();
178*6777b538SAndroid Build Coastguard Worker   DCHECK(IsValidLimitedEntropyRandomizationSource(token));
179*6777b538SAndroid Build Coastguard Worker   return token;
180*6777b538SAndroid Build Coastguard Worker }
181*6777b538SAndroid Build Coastguard Worker 
GetLimitedEntropyRandomizationSource()182*6777b538SAndroid Build Coastguard Worker std::string_view EntropyState::GetLimitedEntropyRandomizationSource() {
183*6777b538SAndroid Build Coastguard Worker   UpdateLimitedEntropyRandomizationSource();
184*6777b538SAndroid Build Coastguard Worker   return limited_entropy_randomization_source_;
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker 
UpdateLimitedEntropyRandomizationSource()187*6777b538SAndroid Build Coastguard Worker void EntropyState::UpdateLimitedEntropyRandomizationSource() {
188*6777b538SAndroid Build Coastguard Worker   // The default value for limited entropy randomization source is an empty
189*6777b538SAndroid Build Coastguard Worker   // string. If it's not empty, it must have been set during this session and an
190*6777b538SAndroid Build Coastguard Worker   // update is not needed.
191*6777b538SAndroid Build Coastguard Worker   if (!limited_entropy_randomization_source_.empty()) {
192*6777b538SAndroid Build Coastguard Worker     return;
193*6777b538SAndroid Build Coastguard Worker   }
194*6777b538SAndroid Build Coastguard Worker 
195*6777b538SAndroid Build Coastguard Worker   auto* pref_name = prefs::kMetricsLimitedEntropyRandomizationSource;
196*6777b538SAndroid Build Coastguard Worker   const auto* command_line = base::CommandLine::ForCurrentProcess();
197*6777b538SAndroid Build Coastguard Worker   // Load the previously set value from prefs, unless the reset variations state
198*6777b538SAndroid Build Coastguard Worker   // command line flag is given.
199*6777b538SAndroid Build Coastguard Worker   if (!command_line->HasSwitch(switches::kResetVariationState)) {
200*6777b538SAndroid Build Coastguard Worker     auto pref_value = local_state_->GetString(pref_name);
201*6777b538SAndroid Build Coastguard Worker     if (IsValidLimitedEntropyRandomizationSource(pref_value)) {
202*6777b538SAndroid Build Coastguard Worker       limited_entropy_randomization_source_ = pref_value;
203*6777b538SAndroid Build Coastguard Worker     }
204*6777b538SAndroid Build Coastguard Worker   }
205*6777b538SAndroid Build Coastguard Worker 
206*6777b538SAndroid Build Coastguard Worker   // If a previously set value is not found, or if the the reset variations
207*6777b538SAndroid Build Coastguard Worker   // state command line flag is given, generate a new value and store it into
208*6777b538SAndroid Build Coastguard Worker   // prefs.
209*6777b538SAndroid Build Coastguard Worker   if (limited_entropy_randomization_source_.empty()) {
210*6777b538SAndroid Build Coastguard Worker     limited_entropy_randomization_source_ =
211*6777b538SAndroid Build Coastguard Worker         GenerateLimitedEntropyRandomizationSource();
212*6777b538SAndroid Build Coastguard Worker     local_state_->SetString(pref_name, limited_entropy_randomization_source_);
213*6777b538SAndroid Build Coastguard Worker   }
214*6777b538SAndroid Build Coastguard Worker 
215*6777b538SAndroid Build Coastguard Worker   CHECK(!limited_entropy_randomization_source_.empty());
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker 
UpdateLowEntropySources()218*6777b538SAndroid Build Coastguard Worker void EntropyState::UpdateLowEntropySources() {
219*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_LACROS)
220*6777b538SAndroid Build Coastguard Worker   // Coming here, someone was reading an entropy value.
221*6777b538SAndroid Build Coastguard Worker   g_entropy_source_has_been_retrieved = true;
222*6777b538SAndroid Build Coastguard Worker #endif
223*6777b538SAndroid Build Coastguard Worker   // The default value for |low_entropy_source_| and the default pref value are
224*6777b538SAndroid Build Coastguard Worker   // both |kLowEntropySourceNotSet|, which indicates the value has not been set.
225*6777b538SAndroid Build Coastguard Worker   if (low_entropy_source_ != kLowEntropySourceNotSet &&
226*6777b538SAndroid Build Coastguard Worker       pseudo_low_entropy_source_ != kLowEntropySourceNotSet)
227*6777b538SAndroid Build Coastguard Worker     return;
228*6777b538SAndroid Build Coastguard Worker 
229*6777b538SAndroid Build Coastguard Worker   const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
230*6777b538SAndroid Build Coastguard Worker   // Only try to load the value from prefs if the user did not request a reset.
231*6777b538SAndroid Build Coastguard Worker   // Otherwise, skip to generating a new value. We would have already returned
232*6777b538SAndroid Build Coastguard Worker   // if both |low_entropy_source_| and |pseudo_low_entropy_source_| were set,
233*6777b538SAndroid Build Coastguard Worker   // ensuring we only do this reset on the first call to
234*6777b538SAndroid Build Coastguard Worker   // UpdateLowEntropySources().
235*6777b538SAndroid Build Coastguard Worker   if (!command_line->HasSwitch(switches::kResetVariationState)) {
236*6777b538SAndroid Build Coastguard Worker     int new_pref = local_state_->GetInteger(prefs::kMetricsLowEntropySource);
237*6777b538SAndroid Build Coastguard Worker     if (IsValidLowEntropySource(new_pref))
238*6777b538SAndroid Build Coastguard Worker       low_entropy_source_ = new_pref;
239*6777b538SAndroid Build Coastguard Worker     int old_pref = local_state_->GetInteger(prefs::kMetricsOldLowEntropySource);
240*6777b538SAndroid Build Coastguard Worker     if (IsValidLowEntropySource(old_pref))
241*6777b538SAndroid Build Coastguard Worker       old_low_entropy_source_ = old_pref;
242*6777b538SAndroid Build Coastguard Worker     int pseudo_pref =
243*6777b538SAndroid Build Coastguard Worker         local_state_->GetInteger(prefs::kMetricsPseudoLowEntropySource);
244*6777b538SAndroid Build Coastguard Worker     if (IsValidLowEntropySource(pseudo_pref))
245*6777b538SAndroid Build Coastguard Worker       pseudo_low_entropy_source_ = pseudo_pref;
246*6777b538SAndroid Build Coastguard Worker   }
247*6777b538SAndroid Build Coastguard Worker 
248*6777b538SAndroid Build Coastguard Worker   // If the new source is missing or corrupt (or requested to be reset), then
249*6777b538SAndroid Build Coastguard Worker   // (re)create it. Don't bother recreating the old source if it's corrupt,
250*6777b538SAndroid Build Coastguard Worker   // because we only keep the old source around for consistency, and we can't
251*6777b538SAndroid Build Coastguard Worker   // maintain a consistent value if we recreate it.
252*6777b538SAndroid Build Coastguard Worker   if (low_entropy_source_ == kLowEntropySourceNotSet) {
253*6777b538SAndroid Build Coastguard Worker     low_entropy_source_ = GenerateLowEntropySource();
254*6777b538SAndroid Build Coastguard Worker     DCHECK(IsValidLowEntropySource(low_entropy_source_));
255*6777b538SAndroid Build Coastguard Worker     local_state_->SetInteger(prefs::kMetricsLowEntropySource,
256*6777b538SAndroid Build Coastguard Worker                              low_entropy_source_);
257*6777b538SAndroid Build Coastguard Worker   }
258*6777b538SAndroid Build Coastguard Worker 
259*6777b538SAndroid Build Coastguard Worker   // If the pseudo source is missing or corrupt (or requested to be reset), then
260*6777b538SAndroid Build Coastguard Worker   // (re)create it. Don't bother recreating the old source if it's corrupt,
261*6777b538SAndroid Build Coastguard Worker   // because we only keep the old source around for consistency, and we can't
262*6777b538SAndroid Build Coastguard Worker   // maintain a consistent value if we recreate it.
263*6777b538SAndroid Build Coastguard Worker   if (pseudo_low_entropy_source_ == kLowEntropySourceNotSet) {
264*6777b538SAndroid Build Coastguard Worker     pseudo_low_entropy_source_ = GeneratePseudoLowEntropySource();
265*6777b538SAndroid Build Coastguard Worker     DCHECK(IsValidLowEntropySource(pseudo_low_entropy_source_));
266*6777b538SAndroid Build Coastguard Worker     local_state_->SetInteger(prefs::kMetricsPseudoLowEntropySource,
267*6777b538SAndroid Build Coastguard Worker                              pseudo_low_entropy_source_);
268*6777b538SAndroid Build Coastguard Worker   }
269*6777b538SAndroid Build Coastguard Worker 
270*6777b538SAndroid Build Coastguard Worker   // If the old source was present but corrupt (or requested to be reset), then
271*6777b538SAndroid Build Coastguard Worker   // we'll never use it again, so delete it.
272*6777b538SAndroid Build Coastguard Worker   if (old_low_entropy_source_ == kLowEntropySourceNotSet &&
273*6777b538SAndroid Build Coastguard Worker       local_state_->HasPrefPath(prefs::kMetricsOldLowEntropySource)) {
274*6777b538SAndroid Build Coastguard Worker     local_state_->ClearPref(prefs::kMetricsOldLowEntropySource);
275*6777b538SAndroid Build Coastguard Worker   }
276*6777b538SAndroid Build Coastguard Worker 
277*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(low_entropy_source_, kLowEntropySourceNotSet);
278*6777b538SAndroid Build Coastguard Worker }
279*6777b538SAndroid Build Coastguard Worker 
280*6777b538SAndroid Build Coastguard Worker // static
IsValidLowEntropySource(int value)281*6777b538SAndroid Build Coastguard Worker bool EntropyState::IsValidLowEntropySource(int value) {
282*6777b538SAndroid Build Coastguard Worker   return value >= 0 && value < kMaxLowEntropySize;
283*6777b538SAndroid Build Coastguard Worker }
284*6777b538SAndroid Build Coastguard Worker 
285*6777b538SAndroid Build Coastguard Worker // static
IsValidLimitedEntropyRandomizationSource(std::string_view value)286*6777b538SAndroid Build Coastguard Worker bool EntropyState::IsValidLimitedEntropyRandomizationSource(
287*6777b538SAndroid Build Coastguard Worker     std::string_view value) {
288*6777b538SAndroid Build Coastguard Worker   if (value.empty()) {
289*6777b538SAndroid Build Coastguard Worker     return false;
290*6777b538SAndroid Build Coastguard Worker   }
291*6777b538SAndroid Build Coastguard Worker   // Use Token::FromString() to check whether the given value is a valid
292*6777b538SAndroid Build Coastguard Worker   // `base::UnguessableToken`.
293*6777b538SAndroid Build Coastguard Worker   auto token = base::Token::FromString(value);
294*6777b538SAndroid Build Coastguard Worker   return token.has_value() && !token.value().is_zero();
295*6777b538SAndroid Build Coastguard Worker }
296*6777b538SAndroid Build Coastguard Worker 
297*6777b538SAndroid Build Coastguard Worker }  // namespace metrics
298