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