safe_seed_manager.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright 2017 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. #include "components/variations/service/safe_seed_manager.h"
  5. #include "base/base_switches.h"
  6. #include "base/command_line.h"
  7. #include "base/cxx17_backports.h"
  8. #include "base/metrics/histogram_functions.h"
  9. #include "base/metrics/histogram_macros.h"
  10. #include "components/prefs/pref_registry.h"
  11. #include "components/prefs/pref_registry_simple.h"
  12. #include "components/prefs/pref_service.h"
  13. #include "components/variations/client_filterable_state.h"
  14. #include "components/variations/pref_names.h"
  15. #include "components/variations/variations_seed_store.h"
  16. #include "components/variations/variations_switches.h"
  17. namespace variations {
  18. // Consecutive seed fetch failures are, unfortunately, a bit more common. As of
  19. // January 2018, users at the 99.5th percentile tend to see fewer than 4
  20. // consecutive fetch failures on mobile platforms; and users at the 99th
  21. // percentile tend to see fewer than 5 or 6 consecutive failures on desktop
  22. // platforms. It makes sense that the characteristics differ on mobile
  23. // vs. desktop platforms, given that the two use different scheduling algorithms
  24. // for the fetches. Graphs:
  25. // [1] Android, all channels (consistently connected):
  26. // https://uma.googleplex.com/timeline_v2?sid=99d1d4c2490c60bcbde7afeb77c12a28
  27. // [2] High-connectivity platforms, Stable and Beta channel (consistently
  28. // connected):
  29. // https://uma.googleplex.com/timeline_v2?sid=2db5b7278dad41cbf349f5f2cb30efd9
  30. // [3] Other platforms, Stable and Beta channel (slightly less connected):
  31. // https://uma.googleplex.com/timeline_v2?sid=d4ba2f3751d211898f8e69214147c2ec
  32. // [4] All platforms, Dev (even less connected):
  33. // https://uma.googleplex.com/timeline_v2?sid=5740fb22b17faa823822adfd8e00ec1a
  34. // [5] All platforms, Canary (actually fairly well-connected!):
  35. // https://uma.googleplex.com/timeline_v2?sid=3e14d3e4887792bb614db9f3f2c1d48c
  36. // Note the all of the graphs show a spike on a particular day, presumably due
  37. // to server-side instability. Moreover, the Dev channel on desktop is an
  38. // outlier – users on the Dev channel can experience just shy of 9 consecutive
  39. // failures on some platforms.
  40. // Decision: There is not an obvious threshold that both achieves a low
  41. // false-positive rate and provides good coverage for true positives. For now,
  42. // set a threshold that should minimize false-positives.
  43. // TODO(isherman): Check in with the networking team about their thoughts on how
  44. // to find a better balance here.
  45. constexpr int kFetchFailureStreakThreshold = 25;
  46. SafeSeedManager::SafeSeedManager(PrefService* local_state)
  47. : local_state_(local_state) {
  48. int num_failed_fetches =
  49. local_state_->GetInteger(prefs::kVariationsFailedToFetchSeedStreak);
  50. base::UmaHistogramSparse("Variations.SafeMode.Streak.FetchFailures",
  51. base::clamp(num_failed_fetches, 0, 100));
  52. }
  53. SafeSeedManager::~SafeSeedManager() = default;
  54. // static
  55. void SafeSeedManager::RegisterPrefs(PrefRegistrySimple* registry) {
  56. // Verify that the crash streak pref has already been registered.
  57. DCHECK(
  58. registry->defaults()->GetValue(prefs::kVariationsCrashStreak, nullptr));
  59. // Registers one of two prefs used for tracking variations-seed-related
  60. // failures. The other pref, kVariationsCrashStreak, is registered in
  61. // CleanExitBeacon::RegisterPrefs(). See components/metrics/
  62. // clean_exit_beacon.cc for more details.
  63. registry->RegisterIntegerPref(prefs::kVariationsFailedToFetchSeedStreak, 0);
  64. }
  65. bool SafeSeedManager::ShouldRunInSafeMode() const {
  66. // Ignore any number of failures if the --disable-variations-safe-mode flag is
  67. // set.
  68. if (base::CommandLine::ForCurrentProcess()->HasSwitch(
  69. switches::kDisableVariationsSafeMode)) {
  70. return false;
  71. }
  72. int num_crashes = local_state_->GetInteger(prefs::kVariationsCrashStreak);
  73. int num_failed_fetches =
  74. local_state_->GetInteger(prefs::kVariationsFailedToFetchSeedStreak);
  75. return num_crashes >= kCrashStreakThreshold ||
  76. num_failed_fetches >= kFetchFailureStreakThreshold;
  77. }
  78. void SafeSeedManager::SetActiveSeedState(
  79. const std::string& seed_data,
  80. const std::string& base64_seed_signature,
  81. int seed_milestone,
  82. std::unique_ptr<ClientFilterableState> client_filterable_state,
  83. base::Time seed_fetch_time) {
  84. DCHECK(!has_set_active_seed_state_);
  85. has_set_active_seed_state_ = true;
  86. active_seed_state_ = std::make_unique<ActiveSeedState>(
  87. seed_data, base64_seed_signature, seed_milestone,
  88. std::move(client_filterable_state), seed_fetch_time);
  89. }
  90. void SafeSeedManager::RecordFetchStarted() {
  91. // Pessimistically assume the fetch will fail. The failure streak will be
  92. // reset upon success.
  93. int num_failures_to_fetch =
  94. local_state_->GetInteger(prefs::kVariationsFailedToFetchSeedStreak);
  95. local_state_->SetInteger(prefs::kVariationsFailedToFetchSeedStreak,
  96. num_failures_to_fetch + 1);
  97. }
  98. void SafeSeedManager::RecordSuccessfulFetch(VariationsSeedStore* seed_store) {
  99. // The first time a fetch succeeds for a given run of Chrome, save the active
  100. // seed+filter configuration as safe. Note that it's sufficient to do this
  101. // only on the first successful fetch because the active configuration does
  102. // not change while Chrome is running. Also, note that it's fine to do this
  103. // even if running in safe mode, as the saved seed in that case will just be
  104. // the existing safe seed.
  105. if (active_seed_state_) {
  106. seed_store->StoreSafeSeed(active_seed_state_->seed_data,
  107. active_seed_state_->base64_seed_signature,
  108. active_seed_state_->seed_milestone,
  109. *active_seed_state_->client_filterable_state,
  110. active_seed_state_->seed_fetch_time);
  111. // The active seed state is only needed for the first time this code path is
  112. // reached, so free up its memory once the data is no longer needed.
  113. active_seed_state_.reset();
  114. }
  115. // Note: It's important to clear the crash streak as well as the fetch
  116. // failures streak. Crashes that occur after a successful seed fetch do not
  117. // prevent updating to a new seed, and therefore do not necessitate falling
  118. // back to a safe seed.
  119. local_state_->SetInteger(prefs::kVariationsCrashStreak, 0);
  120. local_state_->SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 0);
  121. }
  122. SafeSeedManager::ActiveSeedState::ActiveSeedState(
  123. const std::string& seed_data,
  124. const std::string& base64_seed_signature,
  125. int seed_milestone,
  126. std::unique_ptr<ClientFilterableState> client_filterable_state,
  127. base::Time seed_fetch_time)
  128. : seed_data(seed_data),
  129. base64_seed_signature(base64_seed_signature),
  130. seed_milestone(seed_milestone),
  131. client_filterable_state(std::move(client_filterable_state)),
  132. seed_fetch_time(seed_fetch_time) {}
  133. SafeSeedManager::ActiveSeedState::~ActiveSeedState() = default;
  134. } // namespace variations