[go: nahoru, domu]

blob: d77e3ec54caab55457a236f875a9a3db4474aa06 [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2011 The Chromium Authors
sky@google.com169627b2008-12-06 19:30:192// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Scott Violetebfa63c2020-01-17 21:17:285#ifndef COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_BACKEND_H_
6#define COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_BACKEND_H_
sky@google.com169627b2008-12-06 19:30:197
avif57136c12015-12-25 23:27:458#include <stddef.h>
9
dchengc51ac9e2016-04-22 04:05:5310#include <memory>
Arthur Sonzognic571efb2024-01-26 20:26:1811#include <optional>
Hans Wennborge66cdda2021-04-21 11:02:3112#include <set>
sky@google.com169627b2008-12-06 19:30:1913#include <vector>
14
Scott Violet8e3a3352020-01-17 20:37:3815#include "base/files/file_path.h"
Avi Drissman12be0312023-01-11 09:16:0916#include "base/functional/callback_forward.h"
Scott Violetc75ec382020-01-14 20:14:4717#include "base/memory/ref_counted_delete_on_sequence.h"
Sean Mahere672a662023-01-09 21:42:2818#include "base/task/sequenced_task_runner.h"
David Sanders2799ee22022-02-03 05:01:4819#include "base/time/time.h"
Scott Violet861cfb972021-01-05 20:07:3420#include "components/sessions/core/command_storage_manager.h"
blundell47c6d8a2015-09-24 11:06:4021#include "components/sessions/core/session_command.h"
22#include "components/sessions/core/sessions_export.h"
erg@google.com92926d92010-09-02 18:35:0623
hashimoto@chromium.orgaa9b03f2014-03-24 13:03:2224namespace base {
Scott Violet9604e4972023-03-27 18:38:4325class Clock;
hashimoto@chromium.orgaa9b03f2014-03-24 13:03:2226class File;
erg@google.com92926d92010-09-02 18:35:0627}
jhawkins@chromium.org5a82010a2009-02-14 01:33:0228
Scott Violet34e26272020-01-28 18:19:5929namespace crypto {
30class Aead;
31}
32
skuhned8d83f0b2014-11-15 03:51:1733namespace sessions {
sky@google.com169627b2008-12-06 19:30:1934
Scott Violetebfa63c2020-01-17 21:17:2835// CommandStorageBackend is the backend used by CommandStorageManager. It writes
Scott Violet8e3a3352020-01-17 20:37:3836// SessionCommands to disk with the ability to read back at a later date.
Scott Violet807acce32021-01-07 14:39:3137// CommandStorageBackend (mostly) does not interpret the commands in any way, it
38// simply reads/writes them.
39//
Scott Violet807acce32021-01-07 14:39:3140// CommandStorageBackend writes to a file with a suffix that indicates the
41// time the file was opened. The time stamp allows this code to determine the
42// most recently written file. When AppendCommands() is supplied a value of true
43// for `truncate`, the current file is closed and a new file is created (with
44// a newly generated timestamp). When AppendCommands() successfully writes the
45// commands to the file an internal command (whose id is
46// `kInitialStateMarkerCommandId`) is written. During startup, the most recent
47// file that has the internal command written is used. This ensures restore does
48// not attempt to use a file that did not have the complete state written
49// (this would happen if chrome crashed while writing the commands, or there
50// was a file system error part way through writing).
51//
52// AppendCommands() takes a callback that is called if there is an error in
53// writing to the file. The expectation is if there is an error, the consuming
54// code must call AppendCommands() again with `truncate` set to true. If there
55// was an error in writing to the file, calls to AppendCommands() with a value
56// of false for `truncate` are ignored. This is done to ensure the consuming
57// code correctly supplies the initial state.
Scott Violetebfa63c2020-01-17 21:17:2858class SESSIONS_EXPORT CommandStorageBackend
59 : public base::RefCountedDeleteOnSequence<CommandStorageBackend> {
sky@google.com169627b2008-12-06 19:30:1960 public:
Scott Violet6de17902021-01-26 20:56:2661 struct SESSIONS_EXPORT ReadCommandsResult {
62 ReadCommandsResult();
63 ReadCommandsResult(ReadCommandsResult&& other);
64 ReadCommandsResult& operator=(ReadCommandsResult&& other);
65 ReadCommandsResult(const ReadCommandsResult&) = delete;
66 ReadCommandsResult& operator=(const ReadCommandsResult&) = delete;
67 ~ReadCommandsResult();
68
69 std::vector<std::unique_ptr<sessions::SessionCommand>> commands;
70 bool error_reading = false;
71 };
72
Scott Violet8e3a3352020-01-17 20:37:3873 using id_type = SessionCommand::id_type;
74 using size_type = SessionCommand::size_type;
sky@google.com169627b2008-12-06 19:30:1975
76 // Initial size of the buffer used in reading the file. This is exposed
77 // for testing.
78 static const int kFileReadBufferSize;
79
Scott Violet34e26272020-01-28 18:19:5980 // Number of bytes encryption adds.
81 static const size_type kEncryptionOverheadInBytes;
82
Scott Violet861cfb972021-01-05 20:07:3483 // Represents data for a session. Public for tests.
Scott Violetebfa63c2020-01-17 21:17:2884 // Creates a CommandStorageBackend. This method is invoked on the MAIN thread,
sky@google.com169627b2008-12-06 19:30:1985 // and does no IO. The real work is done from Init, which is invoked on
Scott Violetc75ec382020-01-14 20:14:4786 // a background task runer.
sky@google.com169627b2008-12-06 19:30:1987 //
Scott Violet861cfb972021-01-05 20:07:3488 // See `CommandStorageManager` for details on `type` and `path`.
Scott Violetebfa63c2020-01-17 21:17:2889 CommandStorageBackend(
90 scoped_refptr<base::SequencedTaskRunner> owning_task_runner,
Scott Violet861cfb972021-01-05 20:07:3491 const base::FilePath& path,
Scott Violet807acce32021-01-07 14:39:3192 CommandStorageManager::SessionType type,
Scott Violet9604e4972023-03-27 18:38:4393 const std::vector<uint8_t>& decryption_key = {},
94 base::Clock* clock = nullptr);
Scott Violet2664a2c2020-07-07 20:23:3295 CommandStorageBackend(const CommandStorageBackend&) = delete;
96 CommandStorageBackend& operator=(const CommandStorageBackend&) = delete;
sky@google.com169627b2008-12-06 19:30:1997
Scott Violet95a6d682020-06-11 23:28:3298 // Returns true if the file at |path| was generated by this class.
99 static bool IsValidFile(const base::FilePath& path);
100
Scott Violet5ac0a9b2021-01-05 22:14:45101 // Returns the path the files are being written to.
Scott Violet9604e4972023-03-27 18:38:43102 const base::FilePath current_path() const {
103 return open_file_ ? open_file_->path : base::FilePath();
104 }
105
Scott Violet143d8f22023-03-30 22:56:50106 bool IsFileOpen() const { return open_file_.get() != nullptr; }
Scott Violet5ac0a9b2021-01-05 22:14:45107
Scott Violet8e3a3352020-01-17 20:37:38108 base::SequencedTaskRunner* owning_task_runner() {
109 return base::RefCountedDeleteOnSequence<
Scott Violetebfa63c2020-01-17 21:17:28110 CommandStorageBackend>::owning_task_runner();
Scott Violet8e3a3352020-01-17 20:37:38111 }
sky@google.com169627b2008-12-06 19:30:19112
Scott Violet8e3a3352020-01-17 20:37:38113 // Appends the specified commands to the current file. If |truncate| is true
Scott Violet34e26272020-01-28 18:19:59114 // the file is truncated. If |truncate| is true and |crypto_key| is non-empty,
Scott Violet807acce32021-01-07 14:39:31115 // then all commands are encrypted using the supplied key. If there is an
116 // error writing the commands, `error_callback` is run.
avi51f1cd92017-01-03 18:23:38117 void AppendCommands(
118 std::vector<std::unique_ptr<sessions::SessionCommand>> commands,
Scott Violet34e26272020-01-28 18:19:59119 bool truncate,
Scott Violet807acce32021-01-07 14:39:31120 base::OnceClosure error_callback,
Scott Violet34e26272020-01-28 18:19:59121 const std::vector<uint8_t>& crypto_key = std::vector<uint8_t>());
sky@google.com169627b2008-12-06 19:30:19122
Scott Violet8e3a3352020-01-17 20:37:38123 bool inited() const { return inited_; }
sky@google.com169627b2008-12-06 19:30:19124
Scott Violet861cfb972021-01-05 20:07:34125 // Parses out the timestamp from a path pointing to a session file.
126 static bool TimestampFromPath(const base::FilePath& path, base::Time& result);
127
Scott Violet5ac0a9b2021-01-05 22:14:45128 // Returns the set of possible session files. The returned paths are not
129 // necessarily valid session files, rather they match the naming criteria
130 // for session files.
131 static std::set<base::FilePath> GetSessionFilePaths(
132 const base::FilePath& path,
133 CommandStorageManager::SessionType type);
Scott Violet861cfb972021-01-05 20:07:34134
135 // Returns the commands from the last session file.
Scott Violet6de17902021-01-26 20:56:26136 ReadCommandsResult ReadLastSessionCommands();
Scott Violet861cfb972021-01-05 20:07:34137
138 // Deletes the file containing the commands for the last session.
139 void DeleteLastSession();
140
141 // Moves the current session file to the last session file. This is typically
142 // called during startup or if the user launches the app and no tabbed
Scott Violet807acce32021-01-07 14:39:31143 // browsers are running. After calling this, set_pending_reset() must be
144 // called.
Scott Violet861cfb972021-01-05 20:07:34145 void MoveCurrentSessionToLastSession();
146
Scott Violet807acce32021-01-07 14:39:31147 // Used in testing to emulate an error in writing to the file. The value is
148 // automatically reset after the failure.
149 void ForceAppendCommandsToFailForTesting();
150
Scott Violet861cfb972021-01-05 20:07:34151 private:
152 friend class base::RefCountedDeleteOnSequence<CommandStorageBackend>;
153 friend class base::DeleteHelper<CommandStorageBackend>;
154 friend class CommandStorageBackendTest;
155
Scott Violet807acce32021-01-07 14:39:31156 struct SessionInfo {
157 base::FilePath path;
158 base::Time timestamp;
159 };
160
Scott Violet9604e4972023-03-27 18:38:43161 struct OpenFile {
162 OpenFile();
163 ~OpenFile();
164
165 base::FilePath path;
166 std::unique_ptr<base::File> file;
167 // Set to true once `kInitialStateMarkerCommandId` is written.
168 bool did_write_marker = false;
169 };
170
Scott Violet861cfb972021-01-05 20:07:34171 ~CommandStorageBackend();
sky@google.com169627b2008-12-06 19:30:19172
Scott Violet8e3a3352020-01-17 20:37:38173 // Performs initialization on the background task run, calling DoInit() if
174 // necessary.
175 void InitIfNecessary();
176
Scott Violet5ac0a9b2021-01-05 22:14:45177 // Generates the path to a session file with the given timestamp.
178 static base::FilePath FilePathFromTime(
179 CommandStorageManager::SessionType type,
180 const base::FilePath& path,
181 base::Time time);
182
Scott Violet34e26272020-01-28 18:19:59183 // Reads the commands from the specified file. If |crypto_key| is non-empty,
Scott Violet2664a2c2020-07-07 20:23:32184 // it is used to decrypt the file.
Scott Violet6de17902021-01-26 20:56:26185 static ReadCommandsResult ReadCommandsFromFile(
186 const base::FilePath& path,
187 const std::vector<uint8_t>& crypto_key);
albertb@google.com3acb70ef2010-03-01 18:44:38188
Scott Violet8e3a3352020-01-17 20:37:38189 // Closes the file. The next time AppendCommands() is called the file will
190 // implicitly be reopened.
191 void CloseFile();
jam@chromium.orge6e6ba42009-11-07 01:56:19192
sky@google.coma1cf6072009-03-09 18:27:34193 // If current_session_file_ is open, it is truncated so that it is essentially
194 // empty (only contains the header). If current_session_file_ isn't open, it
195 // is is opened and the header is written to it. After this
196 // current_session_file_ contains no commands.
Scott Violetebfa63c2020-01-17 21:17:28197 // NOTE: current_session_file_ may be null if the file couldn't be opened or
sky@google.coma1cf6072009-03-09 18:27:34198 // the header couldn't be written.
Scott Violet807acce32021-01-07 14:39:31199 void TruncateOrOpenFile();
Scott Violet8e3a3352020-01-17 20:37:38200
sky@google.com169627b2008-12-06 19:30:19201 // Opens the current file and writes the header. On success a handle to
202 // the file is returned.
Scott Violet807acce32021-01-07 14:39:31203 std::unique_ptr<base::File> OpenAndWriteHeader(
204 const base::FilePath& path) const;
sky@google.com169627b2008-12-06 19:30:19205
206 // Appends the specified commands to the specified file.
skuhneb7409dcf2014-11-14 04:06:55207 bool AppendCommandsToFile(
208 base::File* file,
avi51f1cd92017-01-03 18:23:38209 const std::vector<std::unique_ptr<sessions::SessionCommand>>& commands);
sky@google.com169627b2008-12-06 19:30:19210
Scott Violet34e26272020-01-28 18:19:59211 // Writes |command| to |file|. Returns true on success.
212 bool AppendCommandToFile(base::File* file,
213 const sessions::SessionCommand& command);
214
215 // Encrypts |command| and writes it to |file|. Returns true on success.
216 // The contents of the command and id are encrypted together. This is
217 // preceded by the length of the command.
218 bool AppendEncryptedCommandToFile(base::File* file,
219 const sessions::SessionCommand& command);
220
221 // Returns true if commands are encrypted.
222 bool IsEncrypted() const { return !crypto_key_.empty(); }
223
Scott Violet861cfb972021-01-05 20:07:34224 // Gets data for the last session file.
Arthur Sonzognic571efb2024-01-26 20:26:18225 std::optional<SessionInfo> FindLastSessionFile() const;
Scott Violet861cfb972021-01-05 20:07:34226
227 // Attempt to delete all sessions besides the current and last. This is a
228 // best effort operation.
Scott Violet807acce32021-01-07 14:39:31229 void DeleteLastSessionFiles() const;
Scott Violet861cfb972021-01-05 20:07:34230
231 // Gets all sessions files.
Scott Violet807acce32021-01-07 14:39:31232 std::vector<SessionInfo> GetSessionFilesSortedByReverseTimestamp() const {
233 return GetSessionFilesSortedByReverseTimestamp(supplied_path_, type_);
Scott Violet5ac0a9b2021-01-05 22:14:45234 }
Scott Violet807acce32021-01-07 14:39:31235 static std::vector<SessionInfo> GetSessionFilesSortedByReverseTimestamp(
Scott Violet5ac0a9b2021-01-05 22:14:45236 const base::FilePath& path,
237 CommandStorageManager::SessionType type);
Scott Violet861cfb972021-01-05 20:07:34238
Scott Violet807acce32021-01-07 14:39:31239 static bool CompareSessionInfoTimestamps(const SessionInfo& a,
240 const SessionInfo& b) {
241 return b.timestamp < a.timestamp;
242 }
243
244 // Returns true if `path` can be used for the last session.
245 bool CanUseFileForLastSession(const base::FilePath& path) const;
246
Scott Violet861cfb972021-01-05 20:07:34247 const CommandStorageManager::SessionType type_;
248
249 // This is the path supplied to the constructor. See CommandStorageManager
250 // constructor for details.
251 const base::FilePath supplied_path_;
252
Scott Violet807acce32021-01-07 14:39:31253 // Used to decode the initial last session file.
254 // TODO(sky): this is currently required because InitIfNecessary() determines
255 // the last file. If that can be delayed, then this can be supplied to
256 // GetLastSessionCommands().
257 const std::vector<uint8_t> initial_decryption_key_;
258
259 // TaskRunner that the callback is added to.
260 scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
261
Scott Violet9604e4972023-03-27 18:38:43262 raw_ptr<base::Clock> clock_;
sky@google.com169627b2008-12-06 19:30:19263
Scott Violet9604e4972023-03-27 18:38:43264 // File and path commands are being written.
265 std::unique_ptr<OpenFile> open_file_;
sky@google.com169627b2008-12-06 19:30:19266
Scott Violet8e3a3352020-01-17 20:37:38267 // Whether DoInit() was called. DoInit() is called on the background task
268 // runner.
269 bool inited_ = false;
sky@google.com169627b2008-12-06 19:30:19270
Scott Violet34e26272020-01-28 18:19:59271 std::vector<uint8_t> crypto_key_;
272 std::unique_ptr<crypto::Aead> aead_;
273
274 // Incremented every time a command is written.
275 int commands_written_ = 0;
Scott Violet861cfb972021-01-05 20:07:34276
277 // Timestamp when this session was started.
278 base::Time timestamp_;
279
280 // Data for the last session. If unset, fallback to legacy session data.
Arthur Sonzognic571efb2024-01-26 20:26:18281 std::optional<SessionInfo> last_session_info_;
Scott Violet807acce32021-01-07 14:39:31282
Scott Violet143d8f22023-03-30 22:56:50283 // Paths of the two most recently written files with a valid marker (the
284 // first of which may be the currently open file). When a new file is
285 // successfully opened and the initial set of commands is written,
286 // `last_or_current_path_with_valid_marker_` is set to the path. At this
287 // point the previous file (initial value of
288 // `last_or_current_path_with_valid_marker_`) is no longer needed, and can be
289 // deleted. As there is no guarantee the commands have actually been written
290 // to disk, we keep one additional file around.
291 // `second_to_last_path_with_valid_marker_` maintains the previous valid file
292 // with a marker.
Arthur Sonzognic571efb2024-01-26 20:26:18293 std::optional<base::FilePath> last_or_current_path_with_valid_marker_;
294 std::optional<base::FilePath> second_to_last_path_with_valid_marker_;
Scott Violet807acce32021-01-07 14:39:31295
296 bool force_append_commands_to_fail_for_testing_ = false;
sky@google.com169627b2008-12-06 19:30:19297};
298
skuhned8d83f0b2014-11-15 03:51:17299} // namespace sessions
300
Scott Violetebfa63c2020-01-17 21:17:28301#endif // COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_BACKEND_H_