• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
77   void SetUtilityClientForTesting(
78       scoped_refptr<ImageWriterUtilityClient> client);
79 #endif
80 
81  protected:
82   virtual ~Operation();
83 
84   // This function should be overriden by subclasses to set up the work of the
85   // operation.  It will be called from Start().
86   virtual void StartImpl() = 0;
87 
88   // Unzips the current file if it ends in ".zip".  The current_file will be set
89   // to the unzipped file.
90   void Unzip(const base::Closure& continuation);
91 
92   // Writes the current file to device_path.
93   void Write(const base::Closure& continuation);
94 
95   // Verifies that the current file and device_path contents match.
96   void VerifyWrite(const base::Closure& continuation);
97 
98   // Completes the operation.
99   void Finish();
100 
101   // Generates an error.
102   // |error_message| is used to create an OnWriteError event which is
103   // sent to the extension
104   virtual void Error(const std::string& error_message);
105 
106   // Set |progress_| and send an event.  Progress should be in the interval
107   // [0,100]
108   void SetProgress(int progress);
109   // Change to a new |stage_| and set |progress_| to zero.  Triggers a progress
110   // event.
111   void SetStage(image_writer_api::Stage stage);
112 
113   // Can be queried to safely determine if the operation has been cancelled.
114   bool IsCancelled();
115 
116   // Adds a callback that will be called during clean-up, whether the operation
117   // is aborted, encounters and error, or finishes successfully.  These
118   // functions will be run on the FILE thread.
119   void AddCleanUpFunction(const base::Closure& callback);
120 
121   // Completes the current operation (progress set to 100) and runs the
122   // continuation.
123   void CompleteAndContinue(const base::Closure& continuation);
124 
125   // If |file_size| is non-zero, only |file_size| bytes will be read from file,
126   // otherwise the entire file will be read.
127   // |progress_scale| is a percentage to which the progress will be scale, e.g.
128   // a scale of 50 means it will increment from 0 to 50 over the course of the
129   // sum.  |progress_offset| is an percentage that will be added to the progress
130   // of the MD5 sum before updating |progress_| but after scaling.
131   void GetMD5SumOfFile(
132       const base::FilePath& file,
133       int64 file_size,
134       int progress_offset,
135       int progress_scale,
136       const base::Callback<void(const std::string&)>& callback);
137 
138   base::WeakPtr<OperationManager> manager_;
139   const ExtensionId extension_id_;
140 
141   base::FilePath image_path_;
142   base::FilePath device_path_;
143 
144   // Temporary directory to store files as we go.
145   base::ScopedTempDir temp_dir_;
146 
147  private:
148   friend class base::RefCountedThreadSafe<Operation>;
149 
150 #if !defined(OS_CHROMEOS)
151   // Ensures the client is started.  This may be called many times but will only
152   // instantiate one client which should exist for the lifetime of the
153   // Operation.
154   void StartUtilityClient();
155 
156   // Stops the client.  This must be called to ensure the utility process can
157   // shutdown.
158   void StopUtilityClient();
159 
160   // Reports progress from the client, transforming from bytes to percentage.
161   virtual void WriteImageProgress(int64 total_bytes, int64 curr_bytes);
162 
163   scoped_refptr<ImageWriterUtilityClient> image_writer_client_;
164 #endif
165 
166 #if defined(OS_CHROMEOS)
167   // Unmounts all volumes on |device_path_|.
168   void UnmountVolumes(const base::Closure& continuation);
169   // Starts the write after unmounting.
170   void UnmountVolumesCallback(const base::Closure& continuation, bool success);
171   // Starts the ImageBurner write.  Note that target_path is the file path of
172   // the device where device_path has been a system device path.
173   void StartWriteOnUIThread(const std::string& target_path,
174                             const base::Closure& continuation);
175   void OnBurnFinished(const base::Closure& continuation,
176                       const std::string& target_path,
177                       bool success,
178                       const std::string& error);
179   void OnBurnProgress(const std::string& target_path,
180                       int64 num_bytes_burnt,
181                       int64 total_size);
182   void OnBurnError();
183 #endif
184 
185   // Incrementally calculates the MD5 sum of a file.
186   void MD5Chunk(base::File file,
187                 int64 bytes_processed,
188                 int64 bytes_total,
189                 int progress_offset,
190                 int progress_scale,
191                 const base::Callback<void(const std::string&)>& callback);
192 
193   // Callbacks for zip::ZipReader.
194   void OnUnzipFailure();
195   void OnUnzipProgress(int64 total_bytes, int64 progress_bytes);
196 
197   // Runs all cleanup functions.
198   void CleanUp();
199 
200   // |stage_| and |progress_| are owned by the FILE thread, use |SetStage| and
201   // |SetProgress| to update.  Progress should be in the interval [0,100]
202   image_writer_api::Stage stage_;
203   int progress_;
204 
205   // MD5 contexts don't play well with smart pointers.  Just going to allocate
206   // memory here.  This requires that we only do one MD5 sum at a time.
207   base::MD5Context md5_context_;
208 
209   // Zip reader for unzip operations.
210   zip::ZipReader zip_reader_;
211 
212   // CleanUp operations that must be run.  All these functions are run on the
213   // FILE thread.
214   std::vector<base::Closure> cleanup_functions_;
215 };
216 
217 }  // namespace image_writer
218 }  // namespace extensions
219 
220 #endif  // CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_OPERATION_H_
221