1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_OPERATION_H_ 6 #define CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_OPERATION_H_ 7 8 #include "base/callback.h" 9 #include "base/files/file.h" 10 #include "base/files/scoped_temp_dir.h" 11 #include "base/md5.h" 12 #include "base/memory/ref_counted_memory.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/task/cancelable_task_tracker.h" 15 #include "base/timer/timer.h" 16 #include "chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h" 17 #include "chrome/common/extensions/api/image_writer_private.h" 18 #include "third_party/zlib/google/zip_reader.h" 19 20 namespace image_writer_api = extensions::api::image_writer_private; 21 22 namespace base { 23 class FilePath; 24 } // namespace base 25 26 namespace extensions { 27 namespace image_writer { 28 29 const int kProgressComplete = 100; 30 31 class OperationManager; 32 33 // Encapsulates an operation being run on behalf of the 34 // OperationManager. Construction of the operation does not start 35 // anything. The operation's Start method should be called to start it, and 36 // then the Cancel method will stop it. The operation will call back to the 37 // OperationManager periodically or on any significant event. 38 // 39 // Each stage of the operation is generally divided into three phases: Start, 40 // Run, Complete. Start and Complete run on the UI thread and are responsible 41 // for advancing to the next stage and other UI interaction. The Run phase does 42 // the work on the FILE thread and calls SendProgress or Error as appropriate. 43 // 44 // TODO(haven): This class is current refcounted because it is owned by the 45 // OperationManager on the UI thread but needs to do work on the FILE thread. 46 // There is probably a better way to organize this so that it can be represented 47 // by a WeakPtr, but those are not thread-safe. Additionally, if destruction is 48 // done on the UI thread then that causes problems if any of the fields were 49 // allocated/accessed on the FILE thread. http://crbug.com/344713 50 class Operation : public base::RefCountedThreadSafe<Operation> { 51 public: 52 typedef base::Callback<void(bool, const std::string&)> StartWriteCallback; 53 typedef base::Callback<void(bool, const std::string&)> CancelWriteCallback; 54 typedef std::string ExtensionId; 55 56 Operation(base::WeakPtr<OperationManager> manager, 57 const ExtensionId& extension_id, 58 const std::string& device_path); 59 60 // Starts the operation. 61 void Start(); 62 63 // Cancel the operation. This must be called to clean up internal state and 64 // cause the the operation to actually stop. It will not be destroyed until 65 // all callbacks have completed. 66 void Cancel(); 67 68 // Aborts the operation, cancelling it and generating an error. 69 void Abort(); 70 71 // Informational getters. 72 int GetProgress(); 73 image_writer_api::Stage GetStage(); 74 75 #if !defined(OS_CHROMEOS) 76 // Set an ImageWriterClient to use. Should be called only when testing. This 77 // does not set up automatic shutdown of the client and it must be shutdown 78 // manually. 79 static void SetUtilityClientForTesting( 80 scoped_refptr<ImageWriterUtilityClient> client); 81 #endif 82 83 protected: 84 virtual ~Operation(); 85 86 // This function should be overriden by subclasses to set up the work of the 87 // operation. It will be called from Start(). 88 virtual void StartImpl() = 0; 89 90 // Unzips the current file if it ends in ".zip". The current_file will be set 91 // to the unzipped file. 92 void Unzip(const base::Closure& continuation); 93 94 // Writes the current file to device_path. 95 void Write(const base::Closure& continuation); 96 97 // Verifies that the current file and device_path contents match. 98 void VerifyWrite(const base::Closure& continuation); 99 100 // Completes the operation. 101 void Finish(); 102 103 // Generates an error. 104 // |error_message| is used to create an OnWriteError event which is 105 // sent to the extension 106 virtual void Error(const std::string& error_message); 107 108 // Set |progress_| and send an event. Progress should be in the interval 109 // [0,100] 110 void SetProgress(int progress); 111 // Change to a new |stage_| and set |progress_| to zero. Triggers a progress 112 // event. 113 void SetStage(image_writer_api::Stage stage); 114 115 // Can be queried to safely determine if the operation has been cancelled. 116 bool IsCancelled(); 117 118 // Adds a callback that will be called during clean-up, whether the operation 119 // is aborted, encounters and error, or finishes successfully. These 120 // functions will be run on the FILE thread. 121 void AddCleanUpFunction(const base::Closure& callback); 122 123 // Completes the current operation (progress set to 100) and runs the 124 // continuation. 125 void CompleteAndContinue(const base::Closure& continuation); 126 127 // If |file_size| is non-zero, only |file_size| bytes will be read from file, 128 // otherwise the entire file will be read. 129 // |progress_scale| is a percentage to which the progress will be scale, e.g. 130 // a scale of 50 means it will increment from 0 to 50 over the course of the 131 // sum. |progress_offset| is an percentage that will be added to the progress 132 // of the MD5 sum before updating |progress_| but after scaling. 133 void GetMD5SumOfFile( 134 const base::FilePath& file, 135 int64 file_size, 136 int progress_offset, 137 int progress_scale, 138 const base::Callback<void(const std::string&)>& callback); 139 140 base::WeakPtr<OperationManager> manager_; 141 const ExtensionId extension_id_; 142 143 base::FilePath image_path_; 144 base::FilePath device_path_; 145 146 // Temporary directory to store files as we go. 147 base::ScopedTempDir temp_dir_; 148 149 private: 150 friend class base::RefCountedThreadSafe<Operation>; 151 152 #if !defined(OS_CHROMEOS) 153 // Ensures the client is started. This may be called many times but will only 154 // instantiate one client which should exist for the lifetime of the 155 // Operation. 156 void StartUtilityClient(); 157 158 // Stops the client. This must be called to ensure the utility process can 159 // shutdown. 160 void StopUtilityClient(); 161 162 // Reports progress from the client, transforming from bytes to percentage. 163 virtual void WriteImageProgress(int64 total_bytes, int64 curr_bytes); 164 165 scoped_refptr<ImageWriterUtilityClient> image_writer_client_; 166 #endif 167 168 #if defined(OS_CHROMEOS) 169 // Unmounts all volumes on |device_path_|. 170 void UnmountVolumes(const base::Closure& continuation); 171 // Starts the write after unmounting. 172 void UnmountVolumesCallback(const base::Closure& continuation, bool success); 173 // Starts the ImageBurner write. Note that target_path is the file path of 174 // the device where device_path has been a system device path. 175 void StartWriteOnUIThread(const std::string& target_path, 176 const base::Closure& continuation); 177 void OnBurnFinished(const base::Closure& continuation, 178 const std::string& target_path, 179 bool success, 180 const std::string& error); 181 void OnBurnProgress(const std::string& target_path, 182 int64 num_bytes_burnt, 183 int64 total_size); 184 void OnBurnError(); 185 #endif 186 187 // Incrementally calculates the MD5 sum of a file. 188 void MD5Chunk(base::File file, 189 int64 bytes_processed, 190 int64 bytes_total, 191 int progress_offset, 192 int progress_scale, 193 const base::Callback<void(const std::string&)>& callback); 194 195 // Callbacks for zip::ZipReader. 196 void OnUnzipFailure(); 197 void OnUnzipProgress(int64 total_bytes, int64 progress_bytes); 198 199 // Runs all cleanup functions. 200 void CleanUp(); 201 202 // |stage_| and |progress_| are owned by the FILE thread, use |SetStage| and 203 // |SetProgress| to update. Progress should be in the interval [0,100] 204 image_writer_api::Stage stage_; 205 int progress_; 206 207 // MD5 contexts don't play well with smart pointers. Just going to allocate 208 // memory here. This requires that we only do one MD5 sum at a time. 209 base::MD5Context md5_context_; 210 211 // Zip reader for unzip operations. 212 zip::ZipReader zip_reader_; 213 214 // CleanUp operations that must be run. All these functions are run on the 215 // FILE thread. 216 std::vector<base::Closure> cleanup_functions_; 217 }; 218 219 } // namespace image_writer 220 } // namespace extensions 221 222 #endif // CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_OPERATION_H_ 223