xref: /aosp_15_r20/external/cronet/base/files/important_file_writer_cleaner.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_FILES_IMPORTANT_FILE_WRITER_CLEANER_H_
6 #define BASE_FILES_IMPORTANT_FILE_WRITER_CLEANER_H_
7 
8 #include <atomic>
9 #include <vector>
10 
11 #include "base/base_export.h"
12 #include "base/containers/flat_set.h"
13 #include "base/files/file_path.h"
14 #include "base/memory/scoped_refptr.h"
15 #include "base/no_destructor.h"
16 #include "base/numerics/clamped_math.h"
17 #include "base/sequence_checker.h"
18 #include "base/synchronization/lock.h"
19 #include "base/thread_annotations.h"
20 #include "base/time/time.h"
21 
22 namespace base {
23 
24 class SequencedTaskRunner;
25 
26 // A cleaner for forgotten .tmp files left behind by ImportantFileWriter; see
27 // https://crbug.com/1075917.
28 //
29 // ImportantFileWriter has the potential to leak .tmp files in case of a crash
30 // or power failure during processing, or in case of interference by third-party
31 // software. This class implements a singleton that makes a single scan over
32 // given directories to delete any *.tmp files older than the current process.
33 // Processes that use ImportantFileWriter are expected to call the instance's
34 // Start method at some point during startup to enable the cleaner.
35 // ImportantFileWriter calls the AddDirectory method to provide the directory
36 // hosting an "important" file. Hosting processes are expected to call the Stop
37 // method at shutdown.
38 //
39 // The deletion scan takes place in a background task.
40 class BASE_EXPORT ImportantFileWriterCleaner {
41  public:
42   // Gets the process-wide single instance of the cleaner.
43   static ImportantFileWriterCleaner& GetInstance();
44 
45   ImportantFileWriterCleaner(const ImportantFileWriterCleaner&) = delete;
46   ImportantFileWriterCleaner& operator=(const ImportantFileWriterCleaner&) =
47       delete;
48   ~ImportantFileWriterCleaner() = delete;
49 
50   // Adds |directory| to the set to be cleaned if it has not already been
51   // handled. If the Start method has already been called, the cleaner will
52   // begin processing |directory| after all others that have previously been
53   // added have been cleaned (immediately, if there are no others). Any calls to
54   // this method prior to Initialize are ignored.
55   static void AddDirectory(const FilePath& directory);
56 
57   // Initializes the instance on the hosting process's main sequence (the one on
58   // which Start and Stop will ultimately be called). It is safe to call this
59   // any number of times from the main sequence.
60   void Initialize();
61 
62   // Starts the instance. If any directories have already been added, the
63   // background task is posted immediately to begin processing them. Otherwise,
64   // the next call to AddDirectory will begin processing.
65   void Start();
66 
67   // Stops the instance. The background task, if it is active, is notified to
68   // halt processing and return.
69   void Stop();
70 
71   // Brings the instance back to the uninitialized state. This should be used in
72   // tests that call Initialize so that the instance forgets about the test's
73   // main thread task runner.
74   void UninitializeForTesting();
75 
76   // Returns the upper-bound time. Files with modification times older than this
77   // are assumed to have been orphaned by a previous instance of the process.
78   base::Time GetUpperBoundTimeForTest() const;
79 
80  private:
81   friend class NoDestructor<ImportantFileWriterCleaner>;
82 
83   ImportantFileWriterCleaner();
84 
85   // True once Start() has been called; false following Stop();
is_started()86   bool is_started() const {
87     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
88     return started_;
89   }
90 
91   // True once the background task has been posted; false once it returns.
is_running()92   bool is_running() const {
93     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
94     return running_;
95   }
96 
97   // The workhorse for AddDirectory.
98   void AddDirectoryImpl(const FilePath& directory);
99 
100   // Schedules the background task to run, processing all directories that have
101   // accumulated.
102   void ScheduleTask();
103 
104   // Iterates over the contents of |directories|, deleting all *.tmp files older
105   // than |upper_bound_time|. Checks |stop_flag| after each deletion to see if
106   // the instance has been stopped by the host process. Returns false if
107   // processing was interrupted by |stop_flag| having been set, or true
108   // indicating that all directories were fully processed.
109   static bool CleanInBackground(Time upper_bound_time,
110                                 std::vector<FilePath> directories,
111                                 std::atomic_bool& stop_flag);
112 
113   // Cleans up after completion of the background task. |processing_completed|
114   // is true when all directories were fully processed, or false if the task
115   // potentially exited early in response to Stop().
116   void OnBackgroundTaskFinished(bool processing_completed);
117 
118   // Finalizes a request to stop after the background task returns.
119   void DoStop();
120 
121   // Provides exclusive access to the instance's task runner.
122   Lock task_runner_lock_;
123 
124   // The hosting process's main thread task runner.
125   scoped_refptr<SequencedTaskRunner> task_runner_ GUARDED_BY(task_runner_lock_);
126 
127   // The time before which any discovered temporary file is presumed to be
128   // unused, and therefore safe to delete.
129   const Time upper_bound_time_;
130 
131   // The set of all directories hosting files written by an ImportantFileWriter.
132   flat_set<FilePath> important_directories_
133       GUARDED_BY_CONTEXT(sequence_checker_);
134 
135   // Directories added to the instance waiting either for a call to Start() or
136   // waiting for an existing background task to complete.
137   std::vector<FilePath> pending_directories_
138       GUARDED_BY_CONTEXT(sequence_checker_);
139 
140   std::atomic_bool stop_flag_{false};
141 
142   bool started_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
143   bool running_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
144 
145   SEQUENCE_CHECKER(sequence_checker_);
146 };
147 
148 }  // namespace base
149 
150 #endif  // BASE_FILES_IMPORTANT_FILE_WRITER_CLEANER_H_
151