xref: /aosp_15_r20/external/cronet/components/metrics/clean_exit_beacon.h (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 #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