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