File: clean_exit_beacon.h

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (228 lines) | stat: -rw-r--r-- 8,825 bytes parent folder | download | duplicates (2)
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_