xref: /aosp_15_r20/external/cronet/components/metrics/metrics_state_manager.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2014 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/metrics_state_manager.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <cstddef>
8*6777b538SAndroid Build Coastguard Worker #include <cstdint>
9*6777b538SAndroid Build Coastguard Worker #include <limits>
10*6777b538SAndroid Build Coastguard Worker #include <memory>
11*6777b538SAndroid Build Coastguard Worker #include <random>
12*6777b538SAndroid Build Coastguard Worker #include <string>
13*6777b538SAndroid Build Coastguard Worker #include <tuple>
14*6777b538SAndroid Build Coastguard Worker #include <utility>
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker #include "base/base_switches.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/command_line.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/debug/leak_annotations.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ref.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/uuid.h"
32*6777b538SAndroid Build Coastguard Worker #include "build/branding_buildflags.h"
33*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
34*6777b538SAndroid Build Coastguard Worker #include "components/metrics/cloned_install_detector.h"
35*6777b538SAndroid Build Coastguard Worker #include "components/metrics/enabled_state_provider.h"
36*6777b538SAndroid Build Coastguard Worker #include "components/metrics/entropy_state.h"
37*6777b538SAndroid Build Coastguard Worker #include "components/metrics/metrics_data_validation.h"
38*6777b538SAndroid Build Coastguard Worker #include "components/metrics/metrics_log.h"
39*6777b538SAndroid Build Coastguard Worker #include "components/metrics/metrics_pref_names.h"
40*6777b538SAndroid Build Coastguard Worker #include "components/metrics/metrics_provider.h"
41*6777b538SAndroid Build Coastguard Worker #include "components/metrics/metrics_switches.h"
42*6777b538SAndroid Build Coastguard Worker #include "components/prefs/pref_registry_simple.h"
43*6777b538SAndroid Build Coastguard Worker #include "components/prefs/pref_service.h"
44*6777b538SAndroid Build Coastguard Worker #include "components/variations/entropy_provider.h"
45*6777b538SAndroid Build Coastguard Worker #include "components/variations/field_trial_config/field_trial_util.h"
46*6777b538SAndroid Build Coastguard Worker #include "components/variations/pref_names.h"
47*6777b538SAndroid Build Coastguard Worker #include "components/variations/variations_switches.h"
48*6777b538SAndroid Build Coastguard Worker #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
49*6777b538SAndroid Build Coastguard Worker #include "third_party/metrics_proto/system_profile.pb.h"
50*6777b538SAndroid Build Coastguard Worker 
51*6777b538SAndroid Build Coastguard Worker namespace metrics {
52*6777b538SAndroid Build Coastguard Worker namespace {
53*6777b538SAndroid Build Coastguard Worker 
ReadEnabledDate(PrefService * local_state)54*6777b538SAndroid Build Coastguard Worker int64_t ReadEnabledDate(PrefService* local_state) {
55*6777b538SAndroid Build Coastguard Worker   return local_state->GetInt64(prefs::kMetricsReportingEnabledTimestamp);
56*6777b538SAndroid Build Coastguard Worker }
57*6777b538SAndroid Build Coastguard Worker 
ReadInstallDate(PrefService * local_state)58*6777b538SAndroid Build Coastguard Worker int64_t ReadInstallDate(PrefService* local_state) {
59*6777b538SAndroid Build Coastguard Worker   return local_state->GetInt64(prefs::kInstallDate);
60*6777b538SAndroid Build Coastguard Worker }
61*6777b538SAndroid Build Coastguard Worker 
ReadClientId(PrefService * local_state)62*6777b538SAndroid Build Coastguard Worker std::string ReadClientId(PrefService* local_state) {
63*6777b538SAndroid Build Coastguard Worker   return local_state->GetString(prefs::kMetricsClientID);
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker // Round a timestamp measured in seconds since epoch to one with a granularity
67*6777b538SAndroid Build Coastguard Worker // of an hour. This can be used before uploaded potentially sensitive
68*6777b538SAndroid Build Coastguard Worker // timestamps.
RoundSecondsToHour(int64_t time_in_seconds)69*6777b538SAndroid Build Coastguard Worker int64_t RoundSecondsToHour(int64_t time_in_seconds) {
70*6777b538SAndroid Build Coastguard Worker   return 3600 * (time_in_seconds / 3600);
71*6777b538SAndroid Build Coastguard Worker }
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker // Records the cloned install histogram.
LogClonedInstall()74*6777b538SAndroid Build Coastguard Worker void LogClonedInstall() {
75*6777b538SAndroid Build Coastguard Worker   // Equivalent to UMA_HISTOGRAM_BOOLEAN with the stability flag set.
76*6777b538SAndroid Build Coastguard Worker   UMA_STABILITY_HISTOGRAM_ENUMERATION("UMA.IsClonedInstall", 1, 2);
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker // No-op function used to create a MetricsStateManager.
NoOpLoadClientInfoBackup()80*6777b538SAndroid Build Coastguard Worker std::unique_ptr<metrics::ClientInfo> NoOpLoadClientInfoBackup() {
81*6777b538SAndroid Build Coastguard Worker   return nullptr;
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker // Exits the browser with a helpful error message if an invalid,
85*6777b538SAndroid Build Coastguard Worker // field-trial-related command-line flag was specified.
ExitWithMessage(const std::string & message)86*6777b538SAndroid Build Coastguard Worker void ExitWithMessage(const std::string& message) {
87*6777b538SAndroid Build Coastguard Worker   puts(message.c_str());
88*6777b538SAndroid Build Coastguard Worker   exit(1);
89*6777b538SAndroid Build Coastguard Worker }
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker // Returns a log normal distribution based on the feature params of
92*6777b538SAndroid Build Coastguard Worker // |kNonUniformityValidationFeature|.
GetLogNormalDist()93*6777b538SAndroid Build Coastguard Worker std::lognormal_distribution<double> GetLogNormalDist() {
94*6777b538SAndroid Build Coastguard Worker   double mean = kLogNormalMean.Get();
95*6777b538SAndroid Build Coastguard Worker   double delta = kLogNormalDelta.Get();
96*6777b538SAndroid Build Coastguard Worker   double std_dev = kLogNormalStdDev.Get();
97*6777b538SAndroid Build Coastguard Worker   return std::lognormal_distribution<double>(mean + std::log(1.0 + delta),
98*6777b538SAndroid Build Coastguard Worker                                              std_dev);
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker // Used to draw a data point from a log normal distribution.
102*6777b538SAndroid Build Coastguard Worker struct LogNormalMetricState {
LogNormalMetricStatemetrics::__anona85dd7410111::LogNormalMetricState103*6777b538SAndroid Build Coastguard Worker   LogNormalMetricState()
104*6777b538SAndroid Build Coastguard Worker       : dist(GetLogNormalDist()), gen(std::mt19937(base::RandUint64())) {}
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker   // Records the artificial non-uniformity histogram for data validation.
LogArtificialNonUniformitymetrics::__anona85dd7410111::LogNormalMetricState107*6777b538SAndroid Build Coastguard Worker   void LogArtificialNonUniformity() {
108*6777b538SAndroid Build Coastguard Worker     double rand = dist(gen);
109*6777b538SAndroid Build Coastguard Worker     // We pick 10k as the upper bound for this histogram so as to avoid losing
110*6777b538SAndroid Build Coastguard Worker     // precision. See comments for |kLogNormalMean|.
111*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramCounts10000("UMA.DataValidation.LogNormal",
112*6777b538SAndroid Build Coastguard Worker                                   base::saturated_cast<int>(rand));
113*6777b538SAndroid Build Coastguard Worker   }
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker   // A log normal distribution generator generated by the `GetLogNormalDist()`
116*6777b538SAndroid Build Coastguard Worker   // function.
117*6777b538SAndroid Build Coastguard Worker   std::lognormal_distribution<double> dist;
118*6777b538SAndroid Build Coastguard Worker   // The pseudo-random generator used to generate a data point from |dist|.
119*6777b538SAndroid Build Coastguard Worker   std::mt19937 gen;
120*6777b538SAndroid Build Coastguard Worker };
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker class MetricsStateMetricsProvider : public MetricsProvider {
123*6777b538SAndroid Build Coastguard Worker  public:
MetricsStateMetricsProvider(PrefService * local_state,bool metrics_ids_were_reset,std::string previous_client_id,std::string initial_client_id,ClonedInstallDetector const & cloned_install_detector)124*6777b538SAndroid Build Coastguard Worker   MetricsStateMetricsProvider(
125*6777b538SAndroid Build Coastguard Worker       PrefService* local_state,
126*6777b538SAndroid Build Coastguard Worker       bool metrics_ids_were_reset,
127*6777b538SAndroid Build Coastguard Worker       std::string previous_client_id,
128*6777b538SAndroid Build Coastguard Worker       std::string initial_client_id,
129*6777b538SAndroid Build Coastguard Worker       ClonedInstallDetector const& cloned_install_detector)
130*6777b538SAndroid Build Coastguard Worker       : local_state_(local_state),
131*6777b538SAndroid Build Coastguard Worker         metrics_ids_were_reset_(metrics_ids_were_reset),
132*6777b538SAndroid Build Coastguard Worker         previous_client_id_(std::move(previous_client_id)),
133*6777b538SAndroid Build Coastguard Worker         initial_client_id_(std::move(initial_client_id)),
134*6777b538SAndroid Build Coastguard Worker         cloned_install_detector_(cloned_install_detector) {}
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker   MetricsStateMetricsProvider(const MetricsStateMetricsProvider&) = delete;
137*6777b538SAndroid Build Coastguard Worker   MetricsStateMetricsProvider& operator=(const MetricsStateMetricsProvider&) =
138*6777b538SAndroid Build Coastguard Worker       delete;
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker   // MetricsProvider:
ProvideSystemProfileMetrics(SystemProfileProto * system_profile)141*6777b538SAndroid Build Coastguard Worker   void ProvideSystemProfileMetrics(
142*6777b538SAndroid Build Coastguard Worker       SystemProfileProto* system_profile) override {
143*6777b538SAndroid Build Coastguard Worker     system_profile->set_uma_enabled_date(
144*6777b538SAndroid Build Coastguard Worker         RoundSecondsToHour(ReadEnabledDate(local_state_)));
145*6777b538SAndroid Build Coastguard Worker     system_profile->set_install_date(
146*6777b538SAndroid Build Coastguard Worker         RoundSecondsToHour(ReadInstallDate(local_state_)));
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker     // Client id in the log shouldn't be different than the |local_state_| one
149*6777b538SAndroid Build Coastguard Worker     // except when the client disabled UMA before we populate this field to the
150*6777b538SAndroid Build Coastguard Worker     // log. If that's the case, the client id in the |local_state_| should be
151*6777b538SAndroid Build Coastguard Worker     // empty and we should set |client_id_was_used_for_trial_assignment| to
152*6777b538SAndroid Build Coastguard Worker     // false.
153*6777b538SAndroid Build Coastguard Worker     std::string client_id = ReadClientId(local_state_);
154*6777b538SAndroid Build Coastguard Worker     system_profile->set_client_id_was_used_for_trial_assignment(
155*6777b538SAndroid Build Coastguard Worker         !client_id.empty() && client_id == initial_client_id_);
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker     ClonedInstallInfo cloned =
158*6777b538SAndroid Build Coastguard Worker         ClonedInstallDetector::ReadClonedInstallInfo(local_state_);
159*6777b538SAndroid Build Coastguard Worker     if (cloned.reset_count == 0)
160*6777b538SAndroid Build Coastguard Worker       return;
161*6777b538SAndroid Build Coastguard Worker     auto* cloned_install_info = system_profile->mutable_cloned_install_info();
162*6777b538SAndroid Build Coastguard Worker     if (metrics_ids_were_reset_) {
163*6777b538SAndroid Build Coastguard Worker       // Only report the cloned from client_id in the resetting session.
164*6777b538SAndroid Build Coastguard Worker       if (!previous_client_id_.empty()) {
165*6777b538SAndroid Build Coastguard Worker         cloned_install_info->set_cloned_from_client_id(
166*6777b538SAndroid Build Coastguard Worker             MetricsLog::Hash(previous_client_id_));
167*6777b538SAndroid Build Coastguard Worker       }
168*6777b538SAndroid Build Coastguard Worker     }
169*6777b538SAndroid Build Coastguard Worker     cloned_install_info->set_last_timestamp(
170*6777b538SAndroid Build Coastguard Worker         RoundSecondsToHour(cloned.last_reset_timestamp));
171*6777b538SAndroid Build Coastguard Worker     cloned_install_info->set_first_timestamp(
172*6777b538SAndroid Build Coastguard Worker         RoundSecondsToHour(cloned.first_reset_timestamp));
173*6777b538SAndroid Build Coastguard Worker     cloned_install_info->set_count(cloned.reset_count);
174*6777b538SAndroid Build Coastguard Worker   }
175*6777b538SAndroid Build Coastguard Worker 
ProvidePreviousSessionData(ChromeUserMetricsExtension * uma_proto)176*6777b538SAndroid Build Coastguard Worker   void ProvidePreviousSessionData(
177*6777b538SAndroid Build Coastguard Worker       ChromeUserMetricsExtension* uma_proto) override {
178*6777b538SAndroid Build Coastguard Worker     if (metrics_ids_were_reset_) {
179*6777b538SAndroid Build Coastguard Worker       LogClonedInstall();
180*6777b538SAndroid Build Coastguard Worker       if (!previous_client_id_.empty()) {
181*6777b538SAndroid Build Coastguard Worker         // NOTE: If you are adding anything here, consider also changing
182*6777b538SAndroid Build Coastguard Worker         // FileMetricsProvider::ProvideIndependentMetricsOnTaskRunner().
183*6777b538SAndroid Build Coastguard Worker 
184*6777b538SAndroid Build Coastguard Worker         // If we know the previous client id, overwrite the client id for the
185*6777b538SAndroid Build Coastguard Worker         // previous session log so the log contains the client id at the time
186*6777b538SAndroid Build Coastguard Worker         // of the previous session. This allows better attribution of crashes
187*6777b538SAndroid Build Coastguard Worker         // to earlier behavior. If the previous client id is unknown, leave
188*6777b538SAndroid Build Coastguard Worker         // the current client id.
189*6777b538SAndroid Build Coastguard Worker         uma_proto->set_client_id(MetricsLog::Hash(previous_client_id_));
190*6777b538SAndroid Build Coastguard Worker       }
191*6777b538SAndroid Build Coastguard Worker     }
192*6777b538SAndroid Build Coastguard Worker   }
193*6777b538SAndroid Build Coastguard Worker 
ProvideCurrentSessionData(ChromeUserMetricsExtension * uma_proto)194*6777b538SAndroid Build Coastguard Worker   void ProvideCurrentSessionData(
195*6777b538SAndroid Build Coastguard Worker       ChromeUserMetricsExtension* uma_proto) override {
196*6777b538SAndroid Build Coastguard Worker     if (cloned_install_detector_->ClonedInstallDetectedInCurrentSession()) {
197*6777b538SAndroid Build Coastguard Worker       LogClonedInstall();
198*6777b538SAndroid Build Coastguard Worker     }
199*6777b538SAndroid Build Coastguard Worker     log_normal_metric_state_.LogArtificialNonUniformity();
200*6777b538SAndroid Build Coastguard Worker   }
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker   // Set a random seed for the random number generator.
SetRandomSeedForTesting(int64_t seed)203*6777b538SAndroid Build Coastguard Worker   void SetRandomSeedForTesting(int64_t seed) {
204*6777b538SAndroid Build Coastguard Worker     log_normal_metric_state_.gen = std::mt19937(seed);
205*6777b538SAndroid Build Coastguard Worker   }
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker  private:
208*6777b538SAndroid Build Coastguard Worker   const raw_ptr<PrefService> local_state_;
209*6777b538SAndroid Build Coastguard Worker   const bool metrics_ids_were_reset_;
210*6777b538SAndroid Build Coastguard Worker   // |previous_client_id_| is set only (if known) when
211*6777b538SAndroid Build Coastguard Worker   // |metrics_ids_were_reset_|
212*6777b538SAndroid Build Coastguard Worker   const std::string previous_client_id_;
213*6777b538SAndroid Build Coastguard Worker   // The client id that was used to randomize field trials. An empty string if
214*6777b538SAndroid Build Coastguard Worker   // the low entropy source was used to do randomization.
215*6777b538SAndroid Build Coastguard Worker   const std::string initial_client_id_;
216*6777b538SAndroid Build Coastguard Worker   const raw_ref<const ClonedInstallDetector> cloned_install_detector_;
217*6777b538SAndroid Build Coastguard Worker   LogNormalMetricState log_normal_metric_state_;
218*6777b538SAndroid Build Coastguard Worker };
219*6777b538SAndroid Build Coastguard Worker 
ShouldEnableBenchmarking(bool force_benchmarking_mode)220*6777b538SAndroid Build Coastguard Worker bool ShouldEnableBenchmarking(bool force_benchmarking_mode) {
221*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/40792683): See whether it's possible to consolidate the
222*6777b538SAndroid Build Coastguard Worker   // switches.
223*6777b538SAndroid Build Coastguard Worker   return force_benchmarking_mode ||
224*6777b538SAndroid Build Coastguard Worker          base::CommandLine::ForCurrentProcess()->HasSwitch(
225*6777b538SAndroid Build Coastguard Worker              variations::switches::kEnableBenchmarking);
226*6777b538SAndroid Build Coastguard Worker }
227*6777b538SAndroid Build Coastguard Worker 
228*6777b538SAndroid Build Coastguard Worker }  // namespace
229*6777b538SAndroid Build Coastguard Worker 
230*6777b538SAndroid Build Coastguard Worker // static
231*6777b538SAndroid Build Coastguard Worker bool MetricsStateManager::instance_exists_ = false;
232*6777b538SAndroid Build Coastguard Worker 
233*6777b538SAndroid Build Coastguard Worker // static
234*6777b538SAndroid Build Coastguard Worker bool MetricsStateManager::enable_provisional_client_id_for_testing_ = false;
235*6777b538SAndroid Build Coastguard Worker 
MetricsStateManager(PrefService * local_state,EnabledStateProvider * enabled_state_provider,const std::wstring & backup_registry_key,const base::FilePath & user_data_dir,EntropyParams entropy_params,StartupVisibility startup_visibility,StoreClientInfoCallback store_client_info,LoadClientInfoCallback retrieve_client_info,base::StringPiece external_client_id)236*6777b538SAndroid Build Coastguard Worker MetricsStateManager::MetricsStateManager(
237*6777b538SAndroid Build Coastguard Worker     PrefService* local_state,
238*6777b538SAndroid Build Coastguard Worker     EnabledStateProvider* enabled_state_provider,
239*6777b538SAndroid Build Coastguard Worker     const std::wstring& backup_registry_key,
240*6777b538SAndroid Build Coastguard Worker     const base::FilePath& user_data_dir,
241*6777b538SAndroid Build Coastguard Worker     EntropyParams entropy_params,
242*6777b538SAndroid Build Coastguard Worker     StartupVisibility startup_visibility,
243*6777b538SAndroid Build Coastguard Worker     StoreClientInfoCallback store_client_info,
244*6777b538SAndroid Build Coastguard Worker     LoadClientInfoCallback retrieve_client_info,
245*6777b538SAndroid Build Coastguard Worker     base::StringPiece external_client_id)
246*6777b538SAndroid Build Coastguard Worker     : local_state_(local_state),
247*6777b538SAndroid Build Coastguard Worker       enabled_state_provider_(enabled_state_provider),
248*6777b538SAndroid Build Coastguard Worker       entropy_params_(entropy_params),
249*6777b538SAndroid Build Coastguard Worker       store_client_info_(std::move(store_client_info)),
250*6777b538SAndroid Build Coastguard Worker       load_client_info_(std::move(retrieve_client_info)),
251*6777b538SAndroid Build Coastguard Worker       clean_exit_beacon_(backup_registry_key, user_data_dir, local_state),
252*6777b538SAndroid Build Coastguard Worker       external_client_id_(external_client_id),
253*6777b538SAndroid Build Coastguard Worker       entropy_state_(local_state),
254*6777b538SAndroid Build Coastguard Worker       entropy_source_returned_(ENTROPY_SOURCE_NONE),
255*6777b538SAndroid Build Coastguard Worker       metrics_ids_were_reset_(false),
256*6777b538SAndroid Build Coastguard Worker       startup_visibility_(startup_visibility) {
257*6777b538SAndroid Build Coastguard Worker   DCHECK(!store_client_info_.is_null());
258*6777b538SAndroid Build Coastguard Worker   DCHECK(!load_client_info_.is_null());
259*6777b538SAndroid Build Coastguard Worker   ResetMetricsIDsIfNecessary();
260*6777b538SAndroid Build Coastguard Worker 
261*6777b538SAndroid Build Coastguard Worker   [[maybe_unused]] bool is_first_run = false;
262*6777b538SAndroid Build Coastguard Worker   int64_t install_date = local_state_->GetInt64(prefs::kInstallDate);
263*6777b538SAndroid Build Coastguard Worker 
264*6777b538SAndroid Build Coastguard Worker   // Set the install date if this is our first run.
265*6777b538SAndroid Build Coastguard Worker   if (install_date == 0) {
266*6777b538SAndroid Build Coastguard Worker     local_state_->SetInt64(prefs::kInstallDate, base::Time::Now().ToTimeT());
267*6777b538SAndroid Build Coastguard Worker     is_first_run = true;
268*6777b538SAndroid Build Coastguard Worker   }
269*6777b538SAndroid Build Coastguard Worker 
270*6777b538SAndroid Build Coastguard Worker   if (enabled_state_provider_->IsConsentGiven()) {
271*6777b538SAndroid Build Coastguard Worker     ForceClientIdCreation();
272*6777b538SAndroid Build Coastguard Worker   } else {
273*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
274*6777b538SAndroid Build Coastguard Worker     // If on start up we determine that the client has not given their consent
275*6777b538SAndroid Build Coastguard Worker     // to report their metrics, the new sampling trial should be used to
276*6777b538SAndroid Build Coastguard Worker     // determine whether the client is sampled in or out (if the user ever
277*6777b538SAndroid Build Coastguard Worker     // enables metrics reporting). This covers users that are going through
278*6777b538SAndroid Build Coastguard Worker     // the first run, as well as users that have metrics reporting disabled.
279*6777b538SAndroid Build Coastguard Worker     //
280*6777b538SAndroid Build Coastguard Worker     // See crbug/1306481 and the comment above |kUsePostFREFixSamplingTrial| in
281*6777b538SAndroid Build Coastguard Worker     // components/metrics/metrics_pref_names.cc for more details.
282*6777b538SAndroid Build Coastguard Worker     local_state_->SetBoolean(metrics::prefs::kUsePostFREFixSamplingTrial, true);
283*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_ANDROID)
284*6777b538SAndroid Build Coastguard Worker   }
285*6777b538SAndroid Build Coastguard Worker 
286*6777b538SAndroid Build Coastguard Worker   // Generate and store a provisional client ID if necessary. This ID will be
287*6777b538SAndroid Build Coastguard Worker   // used for field trial randomization on first run (and possibly in future
288*6777b538SAndroid Build Coastguard Worker   // runs if the user closes Chrome during the FRE) and will be promoted to
289*6777b538SAndroid Build Coastguard Worker   // become the client ID if UMA is enabled during this session, via the logic
290*6777b538SAndroid Build Coastguard Worker   // in ForceClientIdCreation(). If UMA is disabled (refused), we discard it.
291*6777b538SAndroid Build Coastguard Worker   //
292*6777b538SAndroid Build Coastguard Worker   // Note: This means that if a provisional client ID is used for this session,
293*6777b538SAndroid Build Coastguard Worker   // and the user disables (refuses) UMA, then starting from the next run, the
294*6777b538SAndroid Build Coastguard Worker   // field trial randomization (group assignment) will be different.
295*6777b538SAndroid Build Coastguard Worker   if (ShouldGenerateProvisionalClientId(is_first_run)) {
296*6777b538SAndroid Build Coastguard Worker     local_state_->SetString(prefs::kMetricsProvisionalClientID,
297*6777b538SAndroid Build Coastguard Worker                             base::Uuid::GenerateRandomV4().AsLowercaseString());
298*6777b538SAndroid Build Coastguard Worker   }
299*6777b538SAndroid Build Coastguard Worker 
300*6777b538SAndroid Build Coastguard Worker   // `initial_client_id_` will only be set in the following cases:
301*6777b538SAndroid Build Coastguard Worker   // 1. UMA is enabled
302*6777b538SAndroid Build Coastguard Worker   // 2. there is a provisional client id (due to this being a first run)
303*6777b538SAndroid Build Coastguard Worker   // 3. there is an externally provided client ID (e.g. in Lacros, from Ash)
304*6777b538SAndroid Build Coastguard Worker   if (!client_id_.empty()) {
305*6777b538SAndroid Build Coastguard Worker     initial_client_id_ = client_id_;
306*6777b538SAndroid Build Coastguard Worker   } else if (!external_client_id_.empty()) {
307*6777b538SAndroid Build Coastguard Worker     // Typically, `client_id_` should have been set to the external client ID in
308*6777b538SAndroid Build Coastguard Worker     // the call to ForceClientIdCreation() above. However, that call is gated,
309*6777b538SAndroid Build Coastguard Worker     // and may not always happen, for example if this is a first run and the
310*6777b538SAndroid Build Coastguard Worker     // consent state is not yet known (although we know it is soon going to be
311*6777b538SAndroid Build Coastguard Worker     // set to true, since an external client ID was provided).
312*6777b538SAndroid Build Coastguard Worker     initial_client_id_ = external_client_id_;
313*6777b538SAndroid Build Coastguard Worker   } else {
314*6777b538SAndroid Build Coastguard Worker     // Note that there is possibly no provisional client ID.
315*6777b538SAndroid Build Coastguard Worker     initial_client_id_ =
316*6777b538SAndroid Build Coastguard Worker         local_state_->GetString(prefs::kMetricsProvisionalClientID);
317*6777b538SAndroid Build Coastguard Worker   }
318*6777b538SAndroid Build Coastguard Worker   CHECK(!instance_exists_);
319*6777b538SAndroid Build Coastguard Worker   instance_exists_ = true;
320*6777b538SAndroid Build Coastguard Worker }
321*6777b538SAndroid Build Coastguard Worker 
~MetricsStateManager()322*6777b538SAndroid Build Coastguard Worker MetricsStateManager::~MetricsStateManager() {
323*6777b538SAndroid Build Coastguard Worker   CHECK(instance_exists_);
324*6777b538SAndroid Build Coastguard Worker   instance_exists_ = false;
325*6777b538SAndroid Build Coastguard Worker }
326*6777b538SAndroid Build Coastguard Worker 
GetProvider()327*6777b538SAndroid Build Coastguard Worker std::unique_ptr<MetricsProvider> MetricsStateManager::GetProvider() {
328*6777b538SAndroid Build Coastguard Worker   return std::make_unique<MetricsStateMetricsProvider>(
329*6777b538SAndroid Build Coastguard Worker       local_state_, metrics_ids_were_reset_, previous_client_id_,
330*6777b538SAndroid Build Coastguard Worker       initial_client_id_, cloned_install_detector_);
331*6777b538SAndroid Build Coastguard Worker }
332*6777b538SAndroid Build Coastguard Worker 
333*6777b538SAndroid Build Coastguard Worker std::unique_ptr<MetricsProvider>
GetProviderAndSetRandomSeedForTesting(int64_t seed)334*6777b538SAndroid Build Coastguard Worker MetricsStateManager::GetProviderAndSetRandomSeedForTesting(int64_t seed) {
335*6777b538SAndroid Build Coastguard Worker   auto provider = std::make_unique<MetricsStateMetricsProvider>(
336*6777b538SAndroid Build Coastguard Worker       local_state_, metrics_ids_were_reset_, previous_client_id_,
337*6777b538SAndroid Build Coastguard Worker       initial_client_id_, cloned_install_detector_);
338*6777b538SAndroid Build Coastguard Worker   provider->SetRandomSeedForTesting(seed);  // IN-TEST
339*6777b538SAndroid Build Coastguard Worker   return provider;
340*6777b538SAndroid Build Coastguard Worker }
341*6777b538SAndroid Build Coastguard Worker 
IsMetricsReportingEnabled()342*6777b538SAndroid Build Coastguard Worker bool MetricsStateManager::IsMetricsReportingEnabled() {
343*6777b538SAndroid Build Coastguard Worker   return enabled_state_provider_->IsReportingEnabled();
344*6777b538SAndroid Build Coastguard Worker }
345*6777b538SAndroid Build Coastguard Worker 
IsExtendedSafeModeSupported() const346*6777b538SAndroid Build Coastguard Worker bool MetricsStateManager::IsExtendedSafeModeSupported() const {
347*6777b538SAndroid Build Coastguard Worker   return clean_exit_beacon_.IsExtendedSafeModeSupported();
348*6777b538SAndroid Build Coastguard Worker }
349*6777b538SAndroid Build Coastguard Worker 
GetLowEntropySource()350*6777b538SAndroid Build Coastguard Worker int MetricsStateManager::GetLowEntropySource() {
351*6777b538SAndroid Build Coastguard Worker   return entropy_state_.GetLowEntropySource();
352*6777b538SAndroid Build Coastguard Worker }
353*6777b538SAndroid Build Coastguard Worker 
GetOldLowEntropySource()354*6777b538SAndroid Build Coastguard Worker int MetricsStateManager::GetOldLowEntropySource() {
355*6777b538SAndroid Build Coastguard Worker   return entropy_state_.GetOldLowEntropySource();
356*6777b538SAndroid Build Coastguard Worker }
357*6777b538SAndroid Build Coastguard Worker 
GetPseudoLowEntropySource()358*6777b538SAndroid Build Coastguard Worker int MetricsStateManager::GetPseudoLowEntropySource() {
359*6777b538SAndroid Build Coastguard Worker   return entropy_state_.GetPseudoLowEntropySource();
360*6777b538SAndroid Build Coastguard Worker }
361*6777b538SAndroid Build Coastguard Worker 
InstantiateFieldTrialList()362*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::InstantiateFieldTrialList() {
363*6777b538SAndroid Build Coastguard Worker   // Instantiate the FieldTrialList to support field trials. If an instance
364*6777b538SAndroid Build Coastguard Worker   // already exists, this is likely a test scenario with a ScopedFeatureList, so
365*6777b538SAndroid Build Coastguard Worker   // use the existing instance so that any overrides are still applied.
366*6777b538SAndroid Build Coastguard Worker   if (!base::FieldTrialList::GetInstance()) {
367*6777b538SAndroid Build Coastguard Worker     // This is intentionally leaked since it needs to live for the duration of
368*6777b538SAndroid Build Coastguard Worker     // the browser process and there's no benefit in cleaning it up at exit.
369*6777b538SAndroid Build Coastguard Worker     base::FieldTrialList* leaked_field_trial_list = new base::FieldTrialList();
370*6777b538SAndroid Build Coastguard Worker     ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list);
371*6777b538SAndroid Build Coastguard Worker     std::ignore = leaked_field_trial_list;
372*6777b538SAndroid Build Coastguard Worker   }
373*6777b538SAndroid Build Coastguard Worker 
374*6777b538SAndroid Build Coastguard Worker   // When benchmarking is enabled, field trials' default groups are chosen, so
375*6777b538SAndroid Build Coastguard Worker   // see whether benchmarking needs to be enabled here, before any field trials
376*6777b538SAndroid Build Coastguard Worker   // are created.
377*6777b538SAndroid Build Coastguard Worker   // TODO(crbug/1257204): Some FieldTrial-setup-related code is here and some is
378*6777b538SAndroid Build Coastguard Worker   // in VariationsFieldTrialCreator::SetUpFieldTrials(). It's not ideal that
379*6777b538SAndroid Build Coastguard Worker   // it's in two places.
380*6777b538SAndroid Build Coastguard Worker   if (ShouldEnableBenchmarking(entropy_params_.force_benchmarking_mode))
381*6777b538SAndroid Build Coastguard Worker     base::FieldTrial::EnableBenchmarking();
382*6777b538SAndroid Build Coastguard Worker 
383*6777b538SAndroid Build Coastguard Worker   const base::CommandLine* command_line =
384*6777b538SAndroid Build Coastguard Worker       base::CommandLine::ForCurrentProcess();
385*6777b538SAndroid Build Coastguard Worker   if (command_line->HasSwitch(variations::switches::kForceFieldTrialParams)) {
386*6777b538SAndroid Build Coastguard Worker     bool result =
387*6777b538SAndroid Build Coastguard Worker         variations::AssociateParamsFromString(command_line->GetSwitchValueASCII(
388*6777b538SAndroid Build Coastguard Worker             variations::switches::kForceFieldTrialParams));
389*6777b538SAndroid Build Coastguard Worker     if (!result) {
390*6777b538SAndroid Build Coastguard Worker       // Some field trial params implement things like csv or json with a
391*6777b538SAndroid Build Coastguard Worker       // particular param. If some control characters are not %-encoded, it can
392*6777b538SAndroid Build Coastguard Worker       // lead to confusing error messages, so add a hint here.
393*6777b538SAndroid Build Coastguard Worker       ExitWithMessage(base::StringPrintf(
394*6777b538SAndroid Build Coastguard Worker           "Invalid --%s list specified. Make sure you %%-"
395*6777b538SAndroid Build Coastguard Worker           "encode the following characters in param values: %%:/.,",
396*6777b538SAndroid Build Coastguard Worker           variations::switches::kForceFieldTrialParams));
397*6777b538SAndroid Build Coastguard Worker     }
398*6777b538SAndroid Build Coastguard Worker   }
399*6777b538SAndroid Build Coastguard Worker 
400*6777b538SAndroid Build Coastguard Worker   // Ensure any field trials specified on the command line are initialized.
401*6777b538SAndroid Build Coastguard Worker   if (command_line->HasSwitch(::switches::kForceFieldTrials)) {
402*6777b538SAndroid Build Coastguard Worker     // Create field trials without activating them, so that this behaves in a
403*6777b538SAndroid Build Coastguard Worker     // consistent manner with field trials created from the server.
404*6777b538SAndroid Build Coastguard Worker     bool result = base::FieldTrialList::CreateTrialsFromString(
405*6777b538SAndroid Build Coastguard Worker         command_line->GetSwitchValueASCII(::switches::kForceFieldTrials));
406*6777b538SAndroid Build Coastguard Worker     if (!result) {
407*6777b538SAndroid Build Coastguard Worker       ExitWithMessage(base::StringPrintf("Invalid --%s list specified.",
408*6777b538SAndroid Build Coastguard Worker                                          ::switches::kForceFieldTrials));
409*6777b538SAndroid Build Coastguard Worker     }
410*6777b538SAndroid Build Coastguard Worker   }
411*6777b538SAndroid Build Coastguard Worker 
412*6777b538SAndroid Build Coastguard Worker   // Initializing the CleanExitBeacon is done after FieldTrialList instantiation
413*6777b538SAndroid Build Coastguard Worker   // to allow experimentation on the CleanExitBeacon.
414*6777b538SAndroid Build Coastguard Worker   clean_exit_beacon_.Initialize();
415*6777b538SAndroid Build Coastguard Worker }
416*6777b538SAndroid Build Coastguard Worker 
LogHasSessionShutdownCleanly(bool has_session_shutdown_cleanly,bool is_extended_safe_mode)417*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::LogHasSessionShutdownCleanly(
418*6777b538SAndroid Build Coastguard Worker     bool has_session_shutdown_cleanly,
419*6777b538SAndroid Build Coastguard Worker     bool is_extended_safe_mode) {
420*6777b538SAndroid Build Coastguard Worker   clean_exit_beacon_.WriteBeaconValue(has_session_shutdown_cleanly,
421*6777b538SAndroid Build Coastguard Worker                                       is_extended_safe_mode);
422*6777b538SAndroid Build Coastguard Worker }
423*6777b538SAndroid Build Coastguard Worker 
ForceClientIdCreation()424*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::ForceClientIdCreation() {
425*6777b538SAndroid Build Coastguard Worker   // TODO(asvitkine): Ideally, all tests would actually set up consent properly,
426*6777b538SAndroid Build Coastguard Worker   // so the command-line checks wouldn't be needed here.
427*6777b538SAndroid Build Coastguard Worker   // Currently, kForceEnableMetricsReporting is used by Java UkmTest and
428*6777b538SAndroid Build Coastguard Worker   // kMetricsRecordingOnly is used by Chromedriver tests.
429*6777b538SAndroid Build Coastguard Worker   DCHECK(enabled_state_provider_->IsConsentGiven() ||
430*6777b538SAndroid Build Coastguard Worker          IsMetricsReportingForceEnabled() || IsMetricsRecordingOnlyEnabled());
431*6777b538SAndroid Build Coastguard Worker   if (!external_client_id_.empty()) {
432*6777b538SAndroid Build Coastguard Worker     client_id_ = external_client_id_;
433*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramEnumeration("UMA.ClientIdSource",
434*6777b538SAndroid Build Coastguard Worker                                   ClientIdSource::kClientIdFromExternal);
435*6777b538SAndroid Build Coastguard Worker     local_state_->SetString(prefs::kMetricsClientID, client_id_);
436*6777b538SAndroid Build Coastguard Worker     return;
437*6777b538SAndroid Build Coastguard Worker   }
438*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
439*6777b538SAndroid Build Coastguard Worker   std::string previous_client_id = client_id_;
440*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
441*6777b538SAndroid Build Coastguard Worker   {
442*6777b538SAndroid Build Coastguard Worker     std::string client_id_from_prefs = ReadClientId(local_state_);
443*6777b538SAndroid Build Coastguard Worker     // If client id in prefs matches the cached copy, return early.
444*6777b538SAndroid Build Coastguard Worker     if (!client_id_from_prefs.empty() && client_id_from_prefs == client_id_) {
445*6777b538SAndroid Build Coastguard Worker       base::UmaHistogramEnumeration("UMA.ClientIdSource",
446*6777b538SAndroid Build Coastguard Worker                                     ClientIdSource::kClientIdMatches);
447*6777b538SAndroid Build Coastguard Worker       return;
448*6777b538SAndroid Build Coastguard Worker     }
449*6777b538SAndroid Build Coastguard Worker     client_id_.swap(client_id_from_prefs);
450*6777b538SAndroid Build Coastguard Worker   }
451*6777b538SAndroid Build Coastguard Worker 
452*6777b538SAndroid Build Coastguard Worker   if (!client_id_.empty()) {
453*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramEnumeration("UMA.ClientIdSource",
454*6777b538SAndroid Build Coastguard Worker                                   ClientIdSource::kClientIdFromLocalState);
455*6777b538SAndroid Build Coastguard Worker     return;
456*6777b538SAndroid Build Coastguard Worker   }
457*6777b538SAndroid Build Coastguard Worker 
458*6777b538SAndroid Build Coastguard Worker   const std::unique_ptr<ClientInfo> client_info_backup = LoadClientInfo();
459*6777b538SAndroid Build Coastguard Worker   if (client_info_backup) {
460*6777b538SAndroid Build Coastguard Worker     client_id_ = client_info_backup->client_id;
461*6777b538SAndroid Build Coastguard Worker 
462*6777b538SAndroid Build Coastguard Worker     const base::Time now = base::Time::Now();
463*6777b538SAndroid Build Coastguard Worker 
464*6777b538SAndroid Build Coastguard Worker     // Save the recovered client id and also try to reinstantiate the backup
465*6777b538SAndroid Build Coastguard Worker     // values for the dates corresponding with that client id in order to avoid
466*6777b538SAndroid Build Coastguard Worker     // weird scenarios where we could report an old client id with a recent
467*6777b538SAndroid Build Coastguard Worker     // install date.
468*6777b538SAndroid Build Coastguard Worker     local_state_->SetString(prefs::kMetricsClientID, client_id_);
469*6777b538SAndroid Build Coastguard Worker     local_state_->SetInt64(prefs::kInstallDate,
470*6777b538SAndroid Build Coastguard Worker                            client_info_backup->installation_date != 0
471*6777b538SAndroid Build Coastguard Worker                                ? client_info_backup->installation_date
472*6777b538SAndroid Build Coastguard Worker                                : now.ToTimeT());
473*6777b538SAndroid Build Coastguard Worker     local_state_->SetInt64(prefs::kMetricsReportingEnabledTimestamp,
474*6777b538SAndroid Build Coastguard Worker                            client_info_backup->reporting_enabled_date != 0
475*6777b538SAndroid Build Coastguard Worker                                ? client_info_backup->reporting_enabled_date
476*6777b538SAndroid Build Coastguard Worker                                : now.ToTimeT());
477*6777b538SAndroid Build Coastguard Worker 
478*6777b538SAndroid Build Coastguard Worker     base::TimeDelta recovered_installation_age;
479*6777b538SAndroid Build Coastguard Worker     if (client_info_backup->installation_date != 0) {
480*6777b538SAndroid Build Coastguard Worker       recovered_installation_age =
481*6777b538SAndroid Build Coastguard Worker           now - base::Time::FromTimeT(client_info_backup->installation_date);
482*6777b538SAndroid Build Coastguard Worker     }
483*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramEnumeration("UMA.ClientIdSource",
484*6777b538SAndroid Build Coastguard Worker                                   ClientIdSource::kClientIdBackupRecovered);
485*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramCounts10000("UMA.ClientIdBackupRecoveredWithAge",
486*6777b538SAndroid Build Coastguard Worker                                   recovered_installation_age.InHours());
487*6777b538SAndroid Build Coastguard Worker 
488*6777b538SAndroid Build Coastguard Worker     // Flush the backup back to persistent storage in case we re-generated
489*6777b538SAndroid Build Coastguard Worker     // missing data above.
490*6777b538SAndroid Build Coastguard Worker     BackUpCurrentClientInfo();
491*6777b538SAndroid Build Coastguard Worker     return;
492*6777b538SAndroid Build Coastguard Worker   }
493*6777b538SAndroid Build Coastguard Worker 
494*6777b538SAndroid Build Coastguard Worker   // If we're here, there was no client ID yet (either in prefs or backup),
495*6777b538SAndroid Build Coastguard Worker   // so generate a new one. If there's a provisional client id (e.g. UMA
496*6777b538SAndroid Build Coastguard Worker   // was enabled as part of first run), promote that to the client id,
497*6777b538SAndroid Build Coastguard Worker   // otherwise (e.g. UMA enabled in a future session), generate a new one.
498*6777b538SAndroid Build Coastguard Worker   std::string provisional_client_id =
499*6777b538SAndroid Build Coastguard Worker       local_state_->GetString(prefs::kMetricsProvisionalClientID);
500*6777b538SAndroid Build Coastguard Worker   if (provisional_client_id.empty()) {
501*6777b538SAndroid Build Coastguard Worker     client_id_ = base::Uuid::GenerateRandomV4().AsLowercaseString();
502*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramEnumeration("UMA.ClientIdSource",
503*6777b538SAndroid Build Coastguard Worker                                   ClientIdSource::kClientIdNew);
504*6777b538SAndroid Build Coastguard Worker   } else {
505*6777b538SAndroid Build Coastguard Worker     client_id_ = provisional_client_id;
506*6777b538SAndroid Build Coastguard Worker     local_state_->ClearPref(prefs::kMetricsProvisionalClientID);
507*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramEnumeration("UMA.ClientIdSource",
508*6777b538SAndroid Build Coastguard Worker                                   ClientIdSource::kClientIdFromProvisionalId);
509*6777b538SAndroid Build Coastguard Worker   }
510*6777b538SAndroid Build Coastguard Worker   local_state_->SetString(prefs::kMetricsClientID, client_id_);
511*6777b538SAndroid Build Coastguard Worker 
512*6777b538SAndroid Build Coastguard Worker   // Record the timestamp of when the user opted in to UMA.
513*6777b538SAndroid Build Coastguard Worker   local_state_->SetInt64(prefs::kMetricsReportingEnabledTimestamp,
514*6777b538SAndroid Build Coastguard Worker                          base::Time::Now().ToTimeT());
515*6777b538SAndroid Build Coastguard Worker 
516*6777b538SAndroid Build Coastguard Worker   BackUpCurrentClientInfo();
517*6777b538SAndroid Build Coastguard Worker }
518*6777b538SAndroid Build Coastguard Worker 
SetExternalClientId(const std::string & id)519*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::SetExternalClientId(const std::string& id) {
520*6777b538SAndroid Build Coastguard Worker   external_client_id_ = id;
521*6777b538SAndroid Build Coastguard Worker }
522*6777b538SAndroid Build Coastguard Worker 
CheckForClonedInstall()523*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::CheckForClonedInstall() {
524*6777b538SAndroid Build Coastguard Worker   cloned_install_detector_.CheckForClonedInstall(local_state_);
525*6777b538SAndroid Build Coastguard Worker }
526*6777b538SAndroid Build Coastguard Worker 
ShouldResetClientIdsOnClonedInstall()527*6777b538SAndroid Build Coastguard Worker bool MetricsStateManager::ShouldResetClientIdsOnClonedInstall() {
528*6777b538SAndroid Build Coastguard Worker   return cloned_install_detector_.ShouldResetClientIds(local_state_);
529*6777b538SAndroid Build Coastguard Worker }
530*6777b538SAndroid Build Coastguard Worker 
531*6777b538SAndroid Build Coastguard Worker base::CallbackListSubscription
AddOnClonedInstallDetectedCallback(base::OnceClosure callback)532*6777b538SAndroid Build Coastguard Worker MetricsStateManager::AddOnClonedInstallDetectedCallback(
533*6777b538SAndroid Build Coastguard Worker     base::OnceClosure callback) {
534*6777b538SAndroid Build Coastguard Worker   return cloned_install_detector_.AddOnClonedInstallDetectedCallback(
535*6777b538SAndroid Build Coastguard Worker       std::move(callback));
536*6777b538SAndroid Build Coastguard Worker }
537*6777b538SAndroid Build Coastguard Worker 
538*6777b538SAndroid Build Coastguard Worker std::unique_ptr<const variations::EntropyProviders>
CreateEntropyProviders(bool enable_limited_entropy_mode)539*6777b538SAndroid Build Coastguard Worker MetricsStateManager::CreateEntropyProviders(bool enable_limited_entropy_mode) {
540*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1508150): remove `enable_limited_entropy_mode` when it's
541*6777b538SAndroid Build Coastguard Worker   // true for all callers.
542*6777b538SAndroid Build Coastguard Worker   auto limited_entropy_randomization_source =
543*6777b538SAndroid Build Coastguard Worker       enable_limited_entropy_mode ? GetLimitedEntropyRandomizationSource()
544*6777b538SAndroid Build Coastguard Worker                                   : std::string_view();
545*6777b538SAndroid Build Coastguard Worker   return std::make_unique<variations::EntropyProviders>(
546*6777b538SAndroid Build Coastguard Worker       GetHighEntropySource(),
547*6777b538SAndroid Build Coastguard Worker       variations::ValueInRange{
548*6777b538SAndroid Build Coastguard Worker           .value = base::checked_cast<uint32_t>(GetLowEntropySource()),
549*6777b538SAndroid Build Coastguard Worker           .range = EntropyState::kMaxLowEntropySize},
550*6777b538SAndroid Build Coastguard Worker       limited_entropy_randomization_source,
551*6777b538SAndroid Build Coastguard Worker       ShouldEnableBenchmarking(entropy_params_.force_benchmarking_mode));
552*6777b538SAndroid Build Coastguard Worker }
553*6777b538SAndroid Build Coastguard Worker 
554*6777b538SAndroid Build Coastguard Worker // static
Create(PrefService * local_state,EnabledStateProvider * enabled_state_provider,const std::wstring & backup_registry_key,const base::FilePath & user_data_dir,StartupVisibility startup_visibility,EntropyParams entropy_params,StoreClientInfoCallback store_client_info,LoadClientInfoCallback retrieve_client_info,base::StringPiece external_client_id)555*6777b538SAndroid Build Coastguard Worker std::unique_ptr<MetricsStateManager> MetricsStateManager::Create(
556*6777b538SAndroid Build Coastguard Worker     PrefService* local_state,
557*6777b538SAndroid Build Coastguard Worker     EnabledStateProvider* enabled_state_provider,
558*6777b538SAndroid Build Coastguard Worker     const std::wstring& backup_registry_key,
559*6777b538SAndroid Build Coastguard Worker     const base::FilePath& user_data_dir,
560*6777b538SAndroid Build Coastguard Worker     StartupVisibility startup_visibility,
561*6777b538SAndroid Build Coastguard Worker     EntropyParams entropy_params,
562*6777b538SAndroid Build Coastguard Worker     StoreClientInfoCallback store_client_info,
563*6777b538SAndroid Build Coastguard Worker     LoadClientInfoCallback retrieve_client_info,
564*6777b538SAndroid Build Coastguard Worker     base::StringPiece external_client_id) {
565*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<MetricsStateManager> result;
566*6777b538SAndroid Build Coastguard Worker   // Note: |instance_exists_| is updated in the constructor and destructor.
567*6777b538SAndroid Build Coastguard Worker   if (!instance_exists_) {
568*6777b538SAndroid Build Coastguard Worker     result.reset(new MetricsStateManager(
569*6777b538SAndroid Build Coastguard Worker         local_state, enabled_state_provider, backup_registry_key, user_data_dir,
570*6777b538SAndroid Build Coastguard Worker         entropy_params, startup_visibility,
571*6777b538SAndroid Build Coastguard Worker         store_client_info.is_null() ? base::DoNothing()
572*6777b538SAndroid Build Coastguard Worker                                     : std::move(store_client_info),
573*6777b538SAndroid Build Coastguard Worker         retrieve_client_info.is_null()
574*6777b538SAndroid Build Coastguard Worker             ? base::BindRepeating(&NoOpLoadClientInfoBackup)
575*6777b538SAndroid Build Coastguard Worker             : std::move(retrieve_client_info),
576*6777b538SAndroid Build Coastguard Worker         external_client_id));
577*6777b538SAndroid Build Coastguard Worker   }
578*6777b538SAndroid Build Coastguard Worker   return result;
579*6777b538SAndroid Build Coastguard Worker }
580*6777b538SAndroid Build Coastguard Worker 
581*6777b538SAndroid Build Coastguard Worker // static
RegisterPrefs(PrefRegistrySimple * registry)582*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::RegisterPrefs(PrefRegistrySimple* registry) {
583*6777b538SAndroid Build Coastguard Worker   registry->RegisterStringPref(prefs::kMetricsProvisionalClientID,
584*6777b538SAndroid Build Coastguard Worker                                std::string());
585*6777b538SAndroid Build Coastguard Worker   registry->RegisterStringPref(prefs::kMetricsClientID, std::string());
586*6777b538SAndroid Build Coastguard Worker   registry->RegisterInt64Pref(prefs::kMetricsReportingEnabledTimestamp, 0);
587*6777b538SAndroid Build Coastguard Worker   registry->RegisterInt64Pref(prefs::kInstallDate, 0);
588*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
589*6777b538SAndroid Build Coastguard Worker   registry->RegisterBooleanPref(prefs::kUsePostFREFixSamplingTrial, false);
590*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_ANDROID)
591*6777b538SAndroid Build Coastguard Worker 
592*6777b538SAndroid Build Coastguard Worker   EntropyState::RegisterPrefs(registry);
593*6777b538SAndroid Build Coastguard Worker   ClonedInstallDetector::RegisterPrefs(registry);
594*6777b538SAndroid Build Coastguard Worker }
595*6777b538SAndroid Build Coastguard Worker 
BackUpCurrentClientInfo()596*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::BackUpCurrentClientInfo() {
597*6777b538SAndroid Build Coastguard Worker   ClientInfo client_info;
598*6777b538SAndroid Build Coastguard Worker   client_info.client_id = client_id_;
599*6777b538SAndroid Build Coastguard Worker   client_info.installation_date = ReadInstallDate(local_state_);
600*6777b538SAndroid Build Coastguard Worker   client_info.reporting_enabled_date = ReadEnabledDate(local_state_);
601*6777b538SAndroid Build Coastguard Worker   store_client_info_.Run(client_info);
602*6777b538SAndroid Build Coastguard Worker }
603*6777b538SAndroid Build Coastguard Worker 
LoadClientInfo()604*6777b538SAndroid Build Coastguard Worker std::unique_ptr<ClientInfo> MetricsStateManager::LoadClientInfo() {
605*6777b538SAndroid Build Coastguard Worker   // If a cloned install was detected, loading ClientInfo from backup will be
606*6777b538SAndroid Build Coastguard Worker   // a race condition with clearing the backup. Skip all backup reads for this
607*6777b538SAndroid Build Coastguard Worker   // session.
608*6777b538SAndroid Build Coastguard Worker   if (metrics_ids_were_reset_)
609*6777b538SAndroid Build Coastguard Worker     return nullptr;
610*6777b538SAndroid Build Coastguard Worker 
611*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<ClientInfo> client_info = load_client_info_.Run();
612*6777b538SAndroid Build Coastguard Worker 
613*6777b538SAndroid Build Coastguard Worker   // The GUID retrieved should be valid unless retrieval failed.
614*6777b538SAndroid Build Coastguard Worker   // If not, return nullptr. This will result in a new GUID being generated by
615*6777b538SAndroid Build Coastguard Worker   // the calling function ForceClientIdCreation().
616*6777b538SAndroid Build Coastguard Worker   if (client_info &&
617*6777b538SAndroid Build Coastguard Worker       !base::Uuid::ParseCaseInsensitive(client_info->client_id).is_valid()) {
618*6777b538SAndroid Build Coastguard Worker     return nullptr;
619*6777b538SAndroid Build Coastguard Worker   }
620*6777b538SAndroid Build Coastguard Worker 
621*6777b538SAndroid Build Coastguard Worker   return client_info;
622*6777b538SAndroid Build Coastguard Worker }
623*6777b538SAndroid Build Coastguard Worker 
GetLimitedEntropyRandomizationSource()624*6777b538SAndroid Build Coastguard Worker std::string_view MetricsStateManager::GetLimitedEntropyRandomizationSource() {
625*6777b538SAndroid Build Coastguard Worker   // No limited entropy randomization source will be generated if limited
626*6777b538SAndroid Build Coastguard Worker   // entropy randomization is not supported in this context (e.g. in Android
627*6777b538SAndroid Build Coastguard Worker   // Webview).
628*6777b538SAndroid Build Coastguard Worker   if (entropy_params_.default_entropy_provider_type ==
629*6777b538SAndroid Build Coastguard Worker       EntropyProviderType::kLow) {
630*6777b538SAndroid Build Coastguard Worker     return std::string_view();
631*6777b538SAndroid Build Coastguard Worker   }
632*6777b538SAndroid Build Coastguard Worker   return entropy_state_.GetLimitedEntropyRandomizationSource();
633*6777b538SAndroid Build Coastguard Worker }
634*6777b538SAndroid Build Coastguard Worker 
GetHighEntropySource()635*6777b538SAndroid Build Coastguard Worker std::string MetricsStateManager::GetHighEntropySource() {
636*6777b538SAndroid Build Coastguard Worker   // If high entropy randomization is not supported in this context (e.g. in
637*6777b538SAndroid Build Coastguard Worker   // Android Webview), or if UMA is not enabled (so there is no client id), then
638*6777b538SAndroid Build Coastguard Worker   // high entropy randomization is disabled.
639*6777b538SAndroid Build Coastguard Worker   if (entropy_params_.default_entropy_provider_type ==
640*6777b538SAndroid Build Coastguard Worker           EntropyProviderType::kLow ||
641*6777b538SAndroid Build Coastguard Worker       initial_client_id_.empty()) {
642*6777b538SAndroid Build Coastguard Worker     UpdateEntropySourceReturnedValue(ENTROPY_SOURCE_LOW);
643*6777b538SAndroid Build Coastguard Worker     return "";
644*6777b538SAndroid Build Coastguard Worker   }
645*6777b538SAndroid Build Coastguard Worker   UpdateEntropySourceReturnedValue(ENTROPY_SOURCE_HIGH);
646*6777b538SAndroid Build Coastguard Worker   return entropy_state_.GetHighEntropySource(initial_client_id_);
647*6777b538SAndroid Build Coastguard Worker }
648*6777b538SAndroid Build Coastguard Worker 
UpdateEntropySourceReturnedValue(EntropySourceType type)649*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::UpdateEntropySourceReturnedValue(
650*6777b538SAndroid Build Coastguard Worker     EntropySourceType type) {
651*6777b538SAndroid Build Coastguard Worker   if (entropy_source_returned_ != ENTROPY_SOURCE_NONE)
652*6777b538SAndroid Build Coastguard Worker     return;
653*6777b538SAndroid Build Coastguard Worker 
654*6777b538SAndroid Build Coastguard Worker   entropy_source_returned_ = type;
655*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramEnumeration("UMA.EntropySourceType", type,
656*6777b538SAndroid Build Coastguard Worker                                 ENTROPY_SOURCE_ENUM_SIZE);
657*6777b538SAndroid Build Coastguard Worker }
658*6777b538SAndroid Build Coastguard Worker 
ResetMetricsIDsIfNecessary()659*6777b538SAndroid Build Coastguard Worker void MetricsStateManager::ResetMetricsIDsIfNecessary() {
660*6777b538SAndroid Build Coastguard Worker   if (!ShouldResetClientIdsOnClonedInstall())
661*6777b538SAndroid Build Coastguard Worker     return;
662*6777b538SAndroid Build Coastguard Worker   metrics_ids_were_reset_ = true;
663*6777b538SAndroid Build Coastguard Worker   previous_client_id_ = ReadClientId(local_state_);
664*6777b538SAndroid Build Coastguard Worker 
665*6777b538SAndroid Build Coastguard Worker   base::UmaHistogramBoolean("UMA.MetricsIDsReset", true);
666*6777b538SAndroid Build Coastguard Worker 
667*6777b538SAndroid Build Coastguard Worker   DCHECK(client_id_.empty());
668*6777b538SAndroid Build Coastguard Worker 
669*6777b538SAndroid Build Coastguard Worker   local_state_->ClearPref(prefs::kMetricsClientID);
670*6777b538SAndroid Build Coastguard Worker   local_state_->ClearPref(prefs::kMetricsLogRecordId);
671*6777b538SAndroid Build Coastguard Worker   EntropyState::ClearPrefs(local_state_);
672*6777b538SAndroid Build Coastguard Worker 
673*6777b538SAndroid Build Coastguard Worker   ClonedInstallDetector::RecordClonedInstallInfo(local_state_);
674*6777b538SAndroid Build Coastguard Worker 
675*6777b538SAndroid Build Coastguard Worker   // Also clear the backed up client info. This is asynchronus; any reads
676*6777b538SAndroid Build Coastguard Worker   // shortly after may retrieve the old ClientInfo from the backup.
677*6777b538SAndroid Build Coastguard Worker   store_client_info_.Run(ClientInfo());
678*6777b538SAndroid Build Coastguard Worker }
679*6777b538SAndroid Build Coastguard Worker 
ShouldGenerateProvisionalClientId(bool is_first_run)680*6777b538SAndroid Build Coastguard Worker bool MetricsStateManager::ShouldGenerateProvisionalClientId(bool is_first_run) {
681*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
682*6777b538SAndroid Build Coastguard Worker   // We do not want to generate a provisional client ID on Windows because
683*6777b538SAndroid Build Coastguard Worker   // there's no UMA checkbox on first run. Instead it comes from the install
684*6777b538SAndroid Build Coastguard Worker   // page. So if UMA is not enabled at this point, it's unlikely it will be
685*6777b538SAndroid Build Coastguard Worker   // enabled in the same session since that requires the user to manually do
686*6777b538SAndroid Build Coastguard Worker   // that via settings page after they unchecked it on the download page.
687*6777b538SAndroid Build Coastguard Worker   //
688*6777b538SAndroid Build Coastguard Worker   // Note: Windows first run is covered by browser tests
689*6777b538SAndroid Build Coastguard Worker   // FirstRunMasterPrefsVariationsSeedTest.PRE_SecondRun and
690*6777b538SAndroid Build Coastguard Worker   // FirstRunMasterPrefsVariationsSeedTest.SecondRun. If the platform ifdef
691*6777b538SAndroid Build Coastguard Worker   // for this logic changes, the tests should be updated as well.
692*6777b538SAndroid Build Coastguard Worker   return false;
693*6777b538SAndroid Build Coastguard Worker #else
694*6777b538SAndroid Build Coastguard Worker   // We should only generate a provisional client ID on the first run. If for
695*6777b538SAndroid Build Coastguard Worker   // some reason there is already a client ID, we do not generate one either.
696*6777b538SAndroid Build Coastguard Worker   // This can happen if metrics reporting is managed by a policy.
697*6777b538SAndroid Build Coastguard Worker   if (!is_first_run || !client_id_.empty())
698*6777b538SAndroid Build Coastguard Worker     return false;
699*6777b538SAndroid Build Coastguard Worker 
700*6777b538SAndroid Build Coastguard Worker   // Return false if |kMetricsReportingEnabled| is managed by a policy. For
701*6777b538SAndroid Build Coastguard Worker   // example, if metrics reporting is disabled by a policy, then
702*6777b538SAndroid Build Coastguard Worker   // |kMetricsReportingEnabled| will always be set to false, so there is no
703*6777b538SAndroid Build Coastguard Worker   // reason to generate a provisional client ID. If metrics reporting is enabled
704*6777b538SAndroid Build Coastguard Worker   // by a policy, then the default value of |kMetricsReportingEnabled| will be
705*6777b538SAndroid Build Coastguard Worker   // true, and so a client ID will have already been generated (we would have
706*6777b538SAndroid Build Coastguard Worker   // returned false already because of the previous check).
707*6777b538SAndroid Build Coastguard Worker   if (local_state_->IsManagedPreference(prefs::kMetricsReportingEnabled))
708*6777b538SAndroid Build Coastguard Worker     return false;
709*6777b538SAndroid Build Coastguard Worker 
710*6777b538SAndroid Build Coastguard Worker   // If this is a non-Google-Chrome-branded build, we do not want to generate a
711*6777b538SAndroid Build Coastguard Worker   // provisional client ID because metrics reporting is not enabled on those
712*6777b538SAndroid Build Coastguard Worker   // builds. This would be problematic because we store the provisional client
713*6777b538SAndroid Build Coastguard Worker   // ID in the Local State, and clear it when either 1) we enable UMA (the
714*6777b538SAndroid Build Coastguard Worker   // provisional client ID becomes the client ID), or 2) we disable UMA. Since
715*6777b538SAndroid Build Coastguard Worker   // in non-Google-Chrome-branded builds we never actually go through the code
716*6777b538SAndroid Build Coastguard Worker   // paths to either enable or disable UMA, the pref storing the provisional
717*6777b538SAndroid Build Coastguard Worker   // client ID would never be cleared. However, for test consistency between
718*6777b538SAndroid Build Coastguard Worker   // the different builds, we do not return false here if
719*6777b538SAndroid Build Coastguard Worker   // |enable_provisional_client_id_for_testing_| is set to true.
720*6777b538SAndroid Build Coastguard Worker   if (!BUILDFLAG(GOOGLE_CHROME_BRANDING) &&
721*6777b538SAndroid Build Coastguard Worker       !enable_provisional_client_id_for_testing_) {
722*6777b538SAndroid Build Coastguard Worker     return false;
723*6777b538SAndroid Build Coastguard Worker   }
724*6777b538SAndroid Build Coastguard Worker 
725*6777b538SAndroid Build Coastguard Worker   return true;
726*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_WIN)
727*6777b538SAndroid Build Coastguard Worker }
728*6777b538SAndroid Build Coastguard Worker 
729*6777b538SAndroid Build Coastguard Worker }  // namespace metrics
730