metrics_state_manager.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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. #ifndef COMPONENTS_METRICS_METRICS_STATE_MANAGER_H_
  5. #define COMPONENTS_METRICS_METRICS_STATE_MANAGER_H_
  6. #include <memory>
  7. #include <string>
  8. #include "base/callback.h"
  9. #include "base/files/file_path.h"
  10. #include "base/gtest_prod_util.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/metrics/field_trial.h"
  13. #include "build/chromeos_buildflags.h"
  14. #include "components/metrics/clean_exit_beacon.h"
  15. #include "components/metrics/client_info.h"
  16. #include "components/metrics/cloned_install_detector.h"
  17. #include "components/metrics/entropy_state.h"
  18. #if BUILDFLAG(IS_CHROMEOS_ASH)
  19. #include "components/metrics/structured/neutrino_logging.h" // nogncheck
  20. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  21. class PrefService;
  22. class PrefRegistrySimple;
  23. namespace metrics {
  24. class EnabledStateProvider;
  25. class MetricsProvider;
  26. // Denotes whether this session is a background or foreground session at
  27. // startup. May be unknown. A background session refers to the situation in
  28. // which the browser process starts; does some work, e.g. servicing a sync; and
  29. // ends without ever becoming visible. Note that the point in startup at which
  30. // this value is determined is likely before the UI is visible.
  31. //
  32. // These values are persisted to logs. Entries should not be renumbered and
  33. // numeric values should never be reused.
  34. enum class StartupVisibility {
  35. kUnknown = 0,
  36. kBackground = 1,
  37. kForeground = 2,
  38. kMaxValue = kForeground,
  39. };
  40. // Denotes the type of EntropyProvider to use for one-time randomization.
  41. enum class EntropyProviderType {
  42. kDefault = 0, // Use CreateDefaultEntropyProvider().
  43. kLow = 1, // Use CreateLowEntropyProvider().
  44. };
  45. // Responsible for managing MetricsService state prefs, specifically the UMA
  46. // client id and low entropy source. Code outside the metrics directory should
  47. // not be instantiating or using this class directly.
  48. class MetricsStateManager final {
  49. public:
  50. // A callback that can be invoked to store client info to persistent storage.
  51. // Storing an empty client_id will resulted in the backup being voided.
  52. typedef base::RepeatingCallback<void(const ClientInfo& client_info)>
  53. StoreClientInfoCallback;
  54. // A callback that can be invoked to load client info stored through the
  55. // StoreClientInfoCallback.
  56. typedef base::RepeatingCallback<std::unique_ptr<ClientInfo>(void)>
  57. LoadClientInfoCallback;
  58. MetricsStateManager(const MetricsStateManager&) = delete;
  59. MetricsStateManager& operator=(const MetricsStateManager&) = delete;
  60. ~MetricsStateManager();
  61. std::unique_ptr<MetricsProvider> GetProvider();
  62. // Returns true if the user has consented to sending metric reports, and there
  63. // is no other reason to disable reporting. One such reason is client
  64. // sampling, and this client isn't in the sample.
  65. bool IsMetricsReportingEnabled();
  66. // Returns true if Extended Variations Safe Mode is supported on this
  67. // platform. Variations Safe Mode is a mechanism that allows Chrome to fall
  68. // back to a "safe" seed so that clients can recover from a problematic
  69. // experiment, for example, one that causes browser crashes. See the design
  70. // doc for more details:
  71. // https://docs.google.com/document/d/17UN2pLSa5JZqk8f3LeYZIftXewxqcITotgalTrJvGSY.
  72. //
  73. // Extended Variations Safe Mode builds on this by allowing clients to recover
  74. // from problematic experiments that cause browser crashes earlier on in
  75. // startup.
  76. bool IsExtendedSafeModeSupported() const;
  77. // Returns the client ID for this client, or the empty string if the user is
  78. // not opted in to metrics reporting.
  79. const std::string& client_id() const { return client_id_; }
  80. // Returns the low entropy source for this client.
  81. int GetLowEntropySource();
  82. // The CleanExitBeacon, used to determine whether the previous Chrome browser
  83. // session terminated gracefully.
  84. CleanExitBeacon* clean_exit_beacon() { return &clean_exit_beacon_; }
  85. const CleanExitBeacon* clean_exit_beacon() const {
  86. return &clean_exit_beacon_;
  87. }
  88. // Returns true if the session was deemed a background session during startup.
  89. // Note that this is not equivalent to !is_foreground_session() because the
  90. // type of session may be unknown.
  91. bool is_background_session() const {
  92. return startup_visibility_ == StartupVisibility::kBackground;
  93. }
  94. // Returns true if the session was deemed a foreground session during startup.
  95. // Note that this is not equivalent to !is_background_session() because the
  96. // type of session may be unknown.
  97. bool is_foreground_session() const {
  98. return startup_visibility_ == StartupVisibility::kForeground;
  99. }
  100. // Instantiates the FieldTrialList. Uses |enable_gpu_benchmarking_switch| to
  101. // set up the FieldTrialList for benchmarking runs. Uses
  102. // |entropy_provider_type| to determine the type of EntropyProvider to use for
  103. // one-time randomization. See CreateLowEntropyProvider() and
  104. // CreateDefaultEntropyProvider() for more details.
  105. //
  106. // Side effect: Initializes |clean_exit_beacon_|.
  107. void InstantiateFieldTrialList(
  108. const char* enable_gpu_benchmarking_switch = nullptr,
  109. EntropyProviderType entropy_provider_type =
  110. EntropyProviderType::kDefault);
  111. // Signals whether the session has shutdown cleanly. Passing `false` for
  112. // |has_session_shutdown_cleanly| means that Chrome has launched and has not
  113. // yet shut down safely. Passing `true` signals that Chrome has shut down
  114. // safely.
  115. //
  116. // Seeing a call with `false` without a matching call with `true` suggests
  117. // that Chrome crashed or otherwise did not shut down cleanly, e.g. maybe the
  118. // OS crashed.
  119. //
  120. // If |is_extended_safe_mode| is true, then |has_session_shutdown_cleanly| is
  121. // written to disk synchronously. If false, a write is scheduled, and for
  122. // clients in the Extended Variations Safe Mode experiment, a synchronous
  123. // write is done, too.
  124. //
  125. // Note: |is_extended_safe_mode| should be true only for the Extended
  126. // Variations Safe Mode experiment.
  127. void LogHasSessionShutdownCleanly(bool has_session_shutdown_cleanly,
  128. bool is_extended_safe_mode = false);
  129. // Forces the client ID to be generated. This is useful in case it's needed
  130. // before recording.
  131. void ForceClientIdCreation();
  132. // Sets the external client id. Useful for callers that want explicit control
  133. // of the next metrics client id.
  134. void SetExternalClientId(const std::string& id);
  135. // Checks if this install was cloned or imaged from another machine. If a
  136. // clone is detected, resets the client id and low entropy source. This
  137. // should not be called more than once.
  138. void CheckForClonedInstall();
  139. // Checks if the cloned install detector says that client ids should be reset.
  140. bool ShouldResetClientIdsOnClonedInstall();
  141. // Returns the preferred entropy provider used to seed persistent activities
  142. // based on whether or not metrics reporting is permitted on this client.
  143. //
  144. // If there's consent to report metrics or this is the first run of Chrome,
  145. // this method returns an entropy provider that has a high source of entropy,
  146. // partially based on the client ID or provisional client ID. Otherwise, it
  147. // returns an entropy provider that is based on a low entropy source.
  148. std::unique_ptr<const base::FieldTrial::EntropyProvider>
  149. CreateDefaultEntropyProvider();
  150. // Returns an entropy provider that is based on a low entropy source. This
  151. // provider is the same type of provider returned by
  152. // CreateDefaultEntropyProvider() when there's no consent to report metrics,
  153. // but will be a new instance.
  154. std::unique_ptr<const base::FieldTrial::EntropyProvider>
  155. CreateLowEntropyProvider();
  156. // Creates the MetricsStateManager, enforcing that only a single instance
  157. // of the class exists at a time. Returns nullptr if an instance exists
  158. // already.
  159. //
  160. // On Windows, |backup_registry_key| is used to store a backup of the clean
  161. // exit beacon. It is ignored on other platforms.
  162. //
  163. // |user_data_dir| is the path to the client's user data directory. If empty,
  164. // a separate file will not be used for Variations Safe Mode prefs.
  165. //
  166. // |startup_visibility| denotes whether this session is expected to come to
  167. // the foreground.
  168. static std::unique_ptr<MetricsStateManager> Create(
  169. PrefService* local_state,
  170. EnabledStateProvider* enabled_state_provider,
  171. const std::wstring& backup_registry_key,
  172. const base::FilePath& user_data_dir,
  173. StartupVisibility startup_visibility = StartupVisibility::kUnknown,
  174. StoreClientInfoCallback store_client_info = StoreClientInfoCallback(),
  175. LoadClientInfoCallback load_client_info = LoadClientInfoCallback(),
  176. base::StringPiece external_client_id = base::StringPiece());
  177. // Registers local state prefs used by this class.
  178. static void RegisterPrefs(PrefRegistrySimple* registry);
  179. private:
  180. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, CheckProviderResetIds);
  181. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, CheckProviderLogNormal);
  182. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
  183. CheckProviderLogNormalWithParams);
  184. FRIEND_TEST_ALL_PREFIXES(
  185. MetricsStateManagerTest,
  186. CheckProviderResetIds_PreviousIdOnlyReportInResetSession);
  187. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, EntropySourceUsed_Low);
  188. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, EntropySourceUsed_High);
  189. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
  190. ProvisionalClientId_PromotedToClientId);
  191. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
  192. ProvisionalClientId_PersistedAcrossFirstRuns);
  193. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, ResetBackup);
  194. FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, ResetMetricsIDs);
  195. // Designates which entropy source was returned from this class.
  196. // This is used for testing to validate that we return the correct source
  197. // depending on the state of the service.
  198. enum EntropySourceType {
  199. ENTROPY_SOURCE_NONE,
  200. ENTROPY_SOURCE_LOW,
  201. ENTROPY_SOURCE_HIGH,
  202. ENTROPY_SOURCE_ENUM_SIZE,
  203. };
  204. // These values are persisted to logs. Entries should not be renumbered and
  205. // numerical values should never be reused.
  206. enum class ClientIdSource {
  207. // Recorded when the client ID in Local State matches the cached copy.
  208. kClientIdMatches = 0,
  209. // Recorded when we are somehow missing the cached client ID and we are
  210. // able to recover it from the Local State.
  211. kClientIdFromLocalState = 1,
  212. // Recorded when we are somehow missing the client ID stored in Local State
  213. // yet are able to recover it from a backup location.
  214. kClientIdBackupRecovered = 2,
  215. // Recorded when we are somehow missing the client ID in Local State, cache
  216. // and backup and there is no provisional client ID, so a new client ID is
  217. // generated.
  218. kClientIdNew = 3,
  219. // Recorded when we are somehow missing the client ID in Local State, cache
  220. // and backup, so we promote the provisional client ID.
  221. kClientIdFromProvisionalId = 4,
  222. // Recorded when the client ID is passed in from external source.
  223. // This is needed for Lacros since the client id is passed in from
  224. // ash chrome.
  225. kClientIdFromExternal = 5,
  226. kMaxValue = kClientIdFromExternal,
  227. };
  228. // Creates the MetricsStateManager with the given |local_state|. Uses
  229. // |enabled_state_provider| to query whether there is consent for metrics
  230. // reporting, and if it is enabled. Clients should instead use Create(), which
  231. // enforces that a single instance of this class be alive at any given time.
  232. // |store_client_info| should back up client info to persistent storage such
  233. // that it is later retrievable by |load_client_info|.
  234. MetricsStateManager(PrefService* local_state,
  235. EnabledStateProvider* enabled_state_provider,
  236. const std::wstring& backup_registry_key,
  237. const base::FilePath& user_data_dir,
  238. StartupVisibility startup_visibility,
  239. StoreClientInfoCallback store_client_info,
  240. LoadClientInfoCallback load_client_info,
  241. base::StringPiece external_client_id);
  242. // Returns a MetricsStateManagerProvider instance and sets its
  243. // |log_normal_metric_state_.gen| with the provided random seed.
  244. std::unique_ptr<MetricsProvider> GetProviderAndSetRandomSeedForTesting(
  245. int64_t seed);
  246. // Backs up the current client info via |store_client_info_|.
  247. void BackUpCurrentClientInfo();
  248. // Loads the client info via |load_client_info_|.
  249. std::unique_ptr<ClientInfo> LoadClientInfo();
  250. // Returns the high entropy source for this client, which is composed of a
  251. // client ID and the low entropy source. This is intended to be unique for
  252. // each install. UMA must be enabled (and |client_id_| must be set) or
  253. // |kMetricsProvisionalClientID| must be set before calling this.
  254. std::string GetHighEntropySource();
  255. // Returns the old low entropy source for this client.
  256. int GetOldLowEntropySource();
  257. // Updates |entropy_source_returned_| with |type| iff the current value is
  258. // ENTROPY_SOURCE_NONE and logs the new value in a histogram.
  259. void UpdateEntropySourceReturnedValue(EntropySourceType type);
  260. // Returns the first entropy source that was returned by this service since
  261. // start up, or NONE if neither was returned yet. This is exposed for testing
  262. // only.
  263. EntropySourceType entropy_source_returned() const {
  264. return entropy_source_returned_;
  265. }
  266. std::string initial_client_id_for_testing() const {
  267. return initial_client_id_;
  268. }
  269. // Reset the client id and low entropy source if the kMetricsResetMetricIDs
  270. // pref is true.
  271. void ResetMetricsIDsIfNecessary();
  272. bool ShouldGenerateProvisionalClientId(bool is_first_run);
  273. #if BUILDFLAG(IS_CHROMEOS_ASH)
  274. // Log to structured metrics when the client id is changed.
  275. void LogClientIdChanged(metrics::structured::NeutrinoDevicesLocation location,
  276. std::string previous_client_id);
  277. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  278. // Whether an instance of this class exists. Used to enforce that there aren't
  279. // multiple instances of this class at a given time.
  280. static bool instance_exists_;
  281. // Weak pointer to the local state prefs store.
  282. const raw_ptr<PrefService> local_state_;
  283. // Weak pointer to an enabled state provider. Used to know whether the user
  284. // has consented to reporting, and if reporting should be done.
  285. raw_ptr<EnabledStateProvider> enabled_state_provider_;
  286. // A callback run during client id creation so this MetricsStateManager can
  287. // store a backup of the newly generated ID.
  288. const StoreClientInfoCallback store_client_info_;
  289. // A callback run if this MetricsStateManager can't get the client id from
  290. // its typical location and wants to attempt loading it from this backup.
  291. const LoadClientInfoCallback load_client_info_;
  292. // A beacon used to determine whether the previous Chrome browser session
  293. // terminated gracefully.
  294. CleanExitBeacon clean_exit_beacon_;
  295. // The identifier that's sent to the server with the log reports.
  296. std::string client_id_;
  297. // The client id that was used do field trial randomization. This field should
  298. // only be changed when we need to do group assignment. |initial_client_id|
  299. // should left blank iff a client id was not used to do field trial
  300. // randomization.
  301. std::string initial_client_id_;
  302. // If not empty, use an external client id passed in from another browser as
  303. // |client_id_|. This is needed for the Lacros browser where client id needs
  304. // be passed in from ash chrome.
  305. std::string external_client_id_;
  306. // An instance of EntropyState for getting the entropy source values.
  307. EntropyState entropy_state_;
  308. // The last entropy source returned by this service, used for testing.
  309. EntropySourceType entropy_source_returned_;
  310. // The value of prefs::kMetricsResetIds seen upon startup, i.e., the value
  311. // that was appropriate in the previous session. Used when reporting previous
  312. // session (stability) data.
  313. bool metrics_ids_were_reset_;
  314. // The value of the metrics id before reseting. Only possibly valid if the
  315. // metrics id was reset. May be blank if the metrics id was reset but Chrome
  316. // has no record of what the previous metrics id was.
  317. std::string previous_client_id_;
  318. // The detector for understanding the cloned nature of the install so that we
  319. // can reset client ids.
  320. ClonedInstallDetector cloned_install_detector_;
  321. // The type of session, e.g. a foreground session, at startup. This value is
  322. // used only during startup. On Android WebLayer, Android WebView, and iOS,
  323. // the visibility is unknown at this point in startup.
  324. const StartupVisibility startup_visibility_;
  325. // Force enables the creation of a provisional client ID on first run even if
  326. // this is not a Chrome-branded build. Used for testing.
  327. static bool enable_provisional_client_id_for_testing_;
  328. };
  329. } // namespace metrics
  330. #endif // COMPONENTS_METRICS_METRICS_STATE_MANAGER_H_