Home | History | Annotate | Download | only in image_writer_private
      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