1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_METRICS_CLEAN_EXIT_BEACON_H_
#define COMPONENTS_METRICS_CLEAN_EXIT_BEACON_H_
#include <string>
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
class PrefRegistrySimple;
class PrefService;
namespace metrics {
// The name of the beacon file, which is relative to the user data directory
// and used to store the CleanExitBeacon value and the variations crash streak.
extern const base::FilePath::CharType kCleanExitBeaconFilename[];
// Captures all possible beacon value permutations for two distinct beacons.
// Exposed for testing.
//
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class CleanExitBeaconConsistency {
kCleanClean = 0,
kCleanDirty = 1,
kCleanMissing = 2,
kDirtyClean = 3,
kDirtyDirty = 4,
kDirtyMissing = 5,
kMissingClean = 6,
kMissingDirty = 7,
kMissingMissing = 8,
kMaxValue = kMissingMissing,
};
// Denotes the state of the beacon file. Exposed for testing.
//
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class BeaconFileState {
kReadable = 0,
kNotDeserializable = 1,
kMissingDictionary = 2,
kMissingCrashStreak = 3,
kMissingBeacon = 4,
kMaxValue = kMissingBeacon,
};
// Reads and updates a beacon used to detect whether the previous browser
// process exited cleanly.
class CleanExitBeacon {
public:
// Instantiates a CleanExitBeacon whose value is stored in
// |has_exited_cleanly_|. The value is persisted in the beacon file on
// platforms that support this mechanism and in Local State on platforms that
// don't.
//
// On Windows, |backup_registry_key| stores a backup of the beacon to verify
// that the pref's value corresponds to the registry's. |backup_registry_key|
// is ignored on other platforms, but iOS has a similar verification
// mechanism embedded inside CleanExitBeacon.
//
// |user_data_dir| is the path to the client's user data directory. If empty,
// the beacon file is not used.
CleanExitBeacon(const std::wstring& backup_registry_key,
const base::FilePath& user_data_dir,
PrefService* local_state);
virtual ~CleanExitBeacon() = default;
// Not copyable or movable.
CleanExitBeacon(const CleanExitBeacon&) = delete;
CleanExitBeacon& operator=(const CleanExitBeacon&) = delete;
// Initializes the CleanExitBeacon. This includes the following tasks:
// 1. Determining if the last session exited cleanly,
// 2. Incrementing the crash streak, if necessary, and
// 3. Emitting some metrics.
void Initialize();
// Returns the original value of the beacon.
bool exited_cleanly() const { return did_previous_session_exit_cleanly_; }
// Returns the original value of the last live timestamp.
base::Time browser_last_live_timestamp() const {
return initial_browser_last_live_timestamp_;
}
// Returns true if Extended Variations Safe Mode is supported on this
// platform. Android WebLayer and WebView do not support this.
bool IsExtendedSafeModeSupported() const;
// Sets the beacon value to |exited_cleanly| and writes the value to disk if
// the current value (see has_exited_cleanly_) is not already
// |exited_cleanly|. Note that on platforms that do not support the beacon
// file, the write is scheduled, so the value may not be persisted if the
// browser process crashes.
//
// Also, updates the last live timestamp.
//
// |is_extended_safe_mode| denotes whether Chrome is about to start watching
// for browser crashes early on in startup as a part of Extended Variations
// Safe Mode, which is supported by most, but not all, platforms.
//
// TODO(crbug/1341125): Consider removing |is_extended_safe_mode|.
void WriteBeaconValue(bool exited_cleanly,
bool is_extended_safe_mode = false);
// Updates the last live timestamp.
void UpdateLastLiveTimestamp();
const base::FilePath GetUserDataDirForTesting() const;
base::FilePath GetBeaconFilePathForTesting() const;
// Registers local state prefs used by this class.
static void RegisterPrefs(PrefRegistrySimple* registry);
// Updates both Local State and NSUserDefaults beacon values.
static void SetStabilityExitedCleanlyForTesting(PrefService* local_state,
bool exited_cleanly);
// Creates and returns a well-formed beacon file contents with the given
// values.
static std::string CreateBeaconFileContentsForTesting(bool exited_cleanly,
int crash_streak);
// Resets both Local State and NSUserDefaults beacon values.
static void ResetStabilityExitedCleanlyForTesting(PrefService* local_state);
// CHECKs that Chrome exited cleanly.
static void EnsureCleanShutdown(PrefService* local_state);
#if BUILDFLAG(IS_IOS)
// Sets the NSUserDefaults beacon value.
static void SetUserDefaultsBeacon(bool exited_cleanly);
// Checks user default value of kUseUserDefaultsForExitedCleanlyBeacon.
// Because variations are not initialized early in startup, pair a user
// defaults value with the variations config.
static bool ShouldUseUserDefaultsBeacon();
// Syncs feature kUseUserDefaultsForExitedCleanlyBeacon to NSUserDefaults
// kUserDefaultsFeatureFlagForExitedCleanlyBeacon.
static void SyncUseUserDefaultsBeacon();
#endif // BUILDFLAG(IS_IOS)
// Prevents a test browser from performing two clean shutdown steps. First, it
// prevents the beacon value from being updated after this function is called.
// This prevents the the test browser from signaling that Chrome is shutting
// down cleanly. Second, it makes EnsureCleanShutdown() a no-op.
static void SkipCleanShutdownStepsForTesting();
private:
// Returns true if the previous session exited cleanly. Either Local State
// or |beacon_file_contents| is used to get this information. Which is used
// depends on the client's platform and the existence of a valid beacon file.
// Also, records several metrics.
//
// Should be called only once: at startup.
bool DidPreviousSessionExitCleanly(base::Value* beacon_file_contents);
// Returns true if the beacon file is supported on this platform. Android
// WebLayer and WebView do not support this.
bool IsBeaconFileSupported() const;
// Writes |exited_cleanly| and the crash streak to the file located at
// |beacon_file_path_|.
void WriteBeaconFile(bool exited_cleanly) const;
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
// Returns whether Chrome exited cleanly in the previous session according to
// the platform-specific beacon (the registry for Windows or NSUserDefaults
// for iOS). Returns absl::nullopt if the platform-specific location does not
// have beacon info.
absl::optional<bool> ExitedCleanly();
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
#if BUILDFLAG(IS_IOS)
// Returns true if the NSUserDefaults beacon value is set.
static bool HasUserDefaultsBeacon();
// Returns the NSUserDefaults beacon value.
static bool GetUserDefaultsBeacon();
// Clears the NSUserDefaults beacon value.
static void ResetUserDefaultsBeacon();
#endif // BUILDFLAG(IS_IOS)
// Indicates whether the CleanExitBeacon has been initialized.
bool initialized_ = false;
// Stores a backup of the beacon. Windows only.
const std::wstring backup_registry_key_;
// Path to the client's user data directory. May be empty.
const base::FilePath user_data_dir_;
const raw_ptr<PrefService> local_state_;
// This is the value of the last live timestamp from local state at the time
// of construction. It is a timestamp from the previous browser session when
// the browser was known to be alive.
const base::Time initial_browser_last_live_timestamp_;
bool did_previous_session_exit_cleanly_ = false;
// Denotes the current beacon value for this session, which is updated via
// CleanExitBeacon::WriteBeaconValue(). When `false`, Chrome is watching for
// browser crashes. When `true`, Chrome has stopped watching for crashes. When
// unset, Chrome has neither started nor stopped watching for crashes.
absl::optional<bool> has_exited_cleanly_ = absl::nullopt;
// Where the clean exit beacon and the variations crash streak are stored on
// platforms that support the beacon file.
base::FilePath beacon_file_path_;
};
} // namespace metrics
#endif // COMPONENTS_METRICS_CLEAN_EXIT_BEACON_H_
|