summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/api/image_writer_private
diff options
context:
space:
mode:
authorhaven@google.com <haven@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-21 03:59:32 +0000
committerhaven@google.com <haven@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-21 03:59:32 +0000
commit22c4f736fb51b5ebafb15f93aa431ca1a46868ca (patch)
treee61e298d480e4653174a56499a2616d68e811b75 /chrome/browser/extensions/api/image_writer_private
parent3427a9c9c714562fbc800a741e70244f1c767d2b (diff)
downloadchromium_src-22c4f736fb51b5ebafb15f93aa431ca1a46868ca.zip
chromium_src-22c4f736fb51b5ebafb15f93aa431ca1a46868ca.tar.gz
chromium_src-22c4f736fb51b5ebafb15f93aa431ca1a46868ca.tar.bz2
Implements Image Writer API for ChromeOS.
BUG=279327 Review URL: https://chromiumcodereview.appspot.com/23785007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224553 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions/api/image_writer_private')
-rw-r--r--chrome/browser/extensions/api/image_writer_private/error_messages.cc1
-rw-r--r--chrome/browser/extensions/api/image_writer_private/error_messages.h1
-rw-r--r--chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc6
-rw-r--r--chrome/browser/extensions/api/image_writer_private/operation.cc132
-rw-r--r--chrome/browser/extensions/api/image_writer_private/operation.h75
-rw-r--r--chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc77
-rw-r--r--chrome/browser/extensions/api/image_writer_private/operation_linux.cc38
-rw-r--r--chrome/browser/extensions/api/image_writer_private/operation_manager.cc23
-rw-r--r--chrome/browser/extensions/api/image_writer_private/operation_manager.h6
-rw-r--r--chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc6
-rw-r--r--chrome/browser/extensions/api/image_writer_private/write_from_file_operation.h6
-rw-r--r--chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc88
-rw-r--r--chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h9
13 files changed, 326 insertions, 142 deletions
diff --git a/chrome/browser/extensions/api/image_writer_private/error_messages.cc b/chrome/browser/extensions/api/image_writer_private/error_messages.cc
index ad92476..5b7060d9 100644
--- a/chrome/browser/extensions/api/image_writer_private/error_messages.cc
+++ b/chrome/browser/extensions/api/image_writer_private/error_messages.cc
@@ -19,6 +19,7 @@ const char kDownloadInterrupted[] = "Download interrupted.";
const char kDownloadMD5[] = "Failed to calculate MD5 sum for download.";
const char kEmptyUnzip[] = "Unzipped image contained no files.";
const char kFileOperationsNotImplemented[] = "Write-from file not implemented.";
+const char kImageBurnerError[] = "Error contacting Image Burner process.";
const char kImageMD5[] = "Failed to calculate MD5 sum for unzipped image.";
const char kImageNotFound[] = "Unpacked image not found.";
const char kImageSize[] = "Could not determine image size.";
diff --git a/chrome/browser/extensions/api/image_writer_private/error_messages.h b/chrome/browser/extensions/api/image_writer_private/error_messages.h
index 0042426..a45c775 100644
--- a/chrome/browser/extensions/api/image_writer_private/error_messages.h
+++ b/chrome/browser/extensions/api/image_writer_private/error_messages.h
@@ -20,6 +20,7 @@ extern const char kDownloadInterrupted[];
extern const char kDownloadMD5[];
extern const char kEmptyUnzip[];
extern const char kFileOperationsNotImplemented[];
+extern const char kImageBurnerError[];
extern const char kImageMD5[];
extern const char kImageNotFound[];
extern const char kImageSize[];
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
index 0fb3b97..a9834be 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
@@ -30,10 +30,16 @@ bool ImageWriterPrivateWriteFromUrlFunction::RunImpl() {
return false;
}
+#if defined(OS_CHROMEOS)
+ // The Chrome OS temporary partition is too small for Chrome OS images, thus
+ // we must always use the downloads folder.
+ bool save_image_as_download = true;
+#else
bool save_image_as_download = false;
if (params->options.get() && params->options->save_as_download.get()) {
save_image_as_download = true;
}
+#endif
std::string hash;
if (params->options.get() && params->options->image_hash.get()) {
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.cc b/chrome/browser/extensions/api/image_writer_private/operation.cc
index 510030c..711badb 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation.cc
@@ -16,10 +16,17 @@ namespace image_writer {
using content::BrowserThread;
-const int kBurningBlockSize = 8 * 1024; // 8 KiB
+namespace {
+
const int kMD5BufferSize = 1024;
-Operation::Operation(OperationManager* manager,
+void RemoveTempDirectory(const base::FilePath path) {
+ base::DeleteFile(path, true);
+}
+
+} // namespace
+
+Operation::Operation(base::WeakPtr<OperationManager> manager,
const ExtensionId& extension_id,
const std::string& storage_unit_id)
: manager_(manager),
@@ -36,55 +43,129 @@ void Operation::Cancel() {
DVLOG(1) << "Cancelling image writing operation for ext: " << extension_id_;
stage_ = image_writer_api::STAGE_NONE;
+
+ CleanUp();
}
void Operation::Abort() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
Error(error::kAborted);
}
void Operation::Error(const std::string& error_message) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
+ BrowserThread::PostTask(BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&Operation::Error, this, error_message));
+ return;
+ }
+
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&OperationManager::OnError,
- manager_->AsWeakPtr(),
+ manager_,
extension_id_,
stage_,
progress_,
error_message));
+
+ CleanUp();
}
-void Operation::SendProgress() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+void Operation::SetProgress(int progress) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&Operation::SetProgress,
+ this,
+ progress));
+ return;
+ }
+
+ if (IsCancelled()) {
+ return;
+ }
+
+ progress_ = progress;
+
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&OperationManager::OnProgress,
- manager_->AsWeakPtr(),
+ manager_,
+ extension_id_,
+ stage_,
+ progress_));
+}
+
+void Operation::SetStage(image_writer_api::Stage stage) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&Operation::SetStage,
+ this,
+ stage));
+ return;
+ }
+
+ if (IsCancelled()) {
+ return;
+ }
+
+ stage_ = stage;
+ progress_ = 0;
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&OperationManager::OnProgress,
+ manager_,
extension_id_,
stage_,
progress_));
}
void Operation::Finish() {
+ if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
+ BrowserThread::PostTask(BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&Operation::Finish, this));
+ }
DVLOG(1) << "Write operation complete.";
- stage_ = image_writer_api::STAGE_NONE;
- progress_ = 0;
+ CleanUp();
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&OperationManager::OnComplete,
- manager_->AsWeakPtr(),
+ manager_,
extension_id_));
}
bool Operation::IsCancelled() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
return stage_ == image_writer_api::STAGE_NONE;
}
+void Operation::AddCleanUpFunction(base::Closure callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ cleanup_functions_.push_back(callback);
+}
+
+void Operation::CleanUp() {
+ for (std::vector<base::Closure>::iterator it = cleanup_functions_.begin();
+ it != cleanup_functions_.end();
+ ++it) {
+ it->Run();
+ }
+ cleanup_functions_.clear();
+}
+
void Operation::UnzipStart(scoped_ptr<base::FilePath> zip_file) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
if (IsCancelled()) {
@@ -93,17 +174,18 @@ void Operation::UnzipStart(scoped_ptr<base::FilePath> zip_file) {
DVLOG(1) << "Starting unzip stage for " << zip_file->value();
- stage_ = image_writer_api::STAGE_UNZIP;
- progress_ = 0;
-
- SendProgress();
+ SetStage(image_writer_api::STAGE_UNZIP);
base::FilePath tmp_dir;
- if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""), &tmp_dir)) {
+ if (!file_util::CreateTemporaryDirInDir(zip_file->DirName(),
+ FILE_PATH_LITERAL("image_writer"),
+ &tmp_dir)) {
Error(error::kTempDir);
return;
}
+ AddCleanUpFunction(base::Bind(&RemoveTempDirectory, tmp_dir));
+
if (!zip::Unzip(*zip_file, tmp_dir)) {
Error(error::kUnzip);
return;
@@ -128,8 +210,7 @@ void Operation::UnzipStart(scoped_ptr<base::FilePath> zip_file) {
DVLOG(1) << "Successfully unzipped as " << unzipped_file->value();
- progress_ = 100;
- SendProgress();
+ SetProgress(kProgressComplete);
image_path_ = *unzipped_file;
@@ -197,14 +278,13 @@ void Operation::MD5Chunk(
if (len > 0) {
base::MD5Update(&md5_context_, base::StringPiece(buffer, len));
- int percent_prev = (bytes_processed * progress_scale + progress_offset)
- / (bytes_total);
- int percent_curr = ((bytes_processed + len) * progress_scale
- + progress_offset) / (bytes_total);
- progress_ = percent_curr;
-
+ int percent_prev = (bytes_processed * progress_scale + progress_offset) /
+ (bytes_total);
+ int percent_curr = ((bytes_processed + len) * progress_scale +
+ progress_offset) /
+ (bytes_total);
if (percent_curr > percent_prev) {
- SendProgress();
+ SetProgress(progress_);
}
BrowserThread::PostTask(BrowserThread::FILE,
@@ -234,5 +314,5 @@ void Operation::MD5Chunk(
}
}
-} // namespace image_writer
-} // namespace extensions
+} // namespace image_writer
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.h b/chrome/browser/extensions/api/image_writer_private/operation.h
index 5cc06f2..17a88e9 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation.h
+++ b/chrome/browser/extensions/api/image_writer_private/operation.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/md5.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "chrome/browser/extensions/api/image_writer_private/image_writer_utils.h"
#include "chrome/common/cancelable_task_tracker.h"
@@ -16,14 +17,14 @@
namespace image_writer_api = extensions::api::image_writer_private;
namespace base {
-
class FilePath;
-
-} // namespace base
+} // namespace base
namespace extensions {
namespace image_writer {
+const int kProgressComplete = 100;
+
class OperationManager;
// Encapsulates an operation being run on behalf of the
@@ -43,7 +44,7 @@ class Operation
typedef base::Callback<void(bool, const std::string&)> CancelWriteCallback;
typedef std::string ExtensionId;
- Operation(OperationManager* manager,
+ Operation(base::WeakPtr<OperationManager> manager,
const ExtensionId& extension_id,
const std::string& storage_unit_id);
@@ -52,12 +53,11 @@ class Operation
// Cancel the operation. This must be called to clean up internal state and
// cause the the operation to actually stop. It will not be destroyed until
- // all callbacks have completed. This method may be overridden to provide
- // subclass cancelling. It should still call the superclass method.
- virtual void Cancel();
+ // all callbacks have completed.
+ void Cancel();
// Aborts the operation, cancelling it and generating an error.
- virtual void Abort();
+ void Abort();
protected:
virtual ~Operation();
@@ -65,12 +65,21 @@ class Operation
// |error_message| is used to create an OnWriteError event which is
// sent to the extension
virtual void Error(const std::string& error_message);
- // Sends a progress notification.
- void SendProgress();
+
+ // Set |progress_| and send an event. Progress should be in the interval
+ // [0,100]
+ void SetProgress(int progress);
+ // Change to a new |stage_| and set |progress_| to zero.
+ void SetStage(image_writer_api::Stage stage);
// Can be queried to safely determine if the operation has been cancelled.
bool IsCancelled();
+ // Adds a callback that will be called during clean-up, whether the operation
+ // is aborted, encounters and error, or finishes successfully. These
+ // functions will be run on the FILE thread.
+ void AddCleanUpFunction(base::Closure);
+
void UnzipStart(scoped_ptr<base::FilePath> zip_file);
void WriteStart();
void VerifyWriteStart();
@@ -89,34 +98,21 @@ class Operation
int progress_scale,
const base::Callback<void(scoped_ptr<std::string>)>& callback);
- OperationManager* manager_;
+ base::WeakPtr<OperationManager> manager_;
const ExtensionId extension_id_;
- // This field is owned by the UI thread.
- image_writer_api::Stage stage_;
-
- // The amount of work completed for the current stage as a percentage. This
- // variable may be modified by both the FILE and UI threads, but it is only
- // modified by the basic activity flow of the operation which is logically
- // single threaded. Progress events will read this variable from the UI
- // thread which has the potential to read a value newer than when the event
- // was posted. However, the stage is never advanced except on the UI thread
- // and so will be later in the queue than those progress events. Thus
- // progress events may report higher progress numbers than when queued, but
- // will never report the wrong stage and appear to move backwards.
- int progress_;
-
base::FilePath image_path_;
const std::string storage_unit_id_;
private:
friend class base::RefCountedThreadSafe<Operation>;
+ // TODO(haven): Clean up these switches. http://crbug.com/292956
#if defined(OS_LINUX) && !defined(CHROMEOS)
void WriteRun();
void WriteChunk(scoped_ptr<image_writer_utils::ImageReader> reader,
scoped_ptr<image_writer_utils::ImageWriter> writer,
int64 bytes_written);
- bool WriteCleanup(scoped_ptr<image_writer_utils::ImageReader> reader,
+ bool WriteCleanUp(scoped_ptr<image_writer_utils::ImageReader> reader,
scoped_ptr<image_writer_utils::ImageWriter> writer);
void WriteComplete();
@@ -125,6 +121,18 @@ class Operation
scoped_ptr<std::string> device_hash);
#endif
+#if defined(OS_CHROMEOS)
+ void StartWriteOnUIThread();
+
+ void OnBurnFinished(const std::string& target_path,
+ bool success,
+ const std::string& error);
+ void OnBurnProgress(const std::string& target_path,
+ int64 num_bytes_burnt,
+ int64 total_size);
+ void OnBurnError();
+#endif
+
void MD5Chunk(scoped_ptr<image_writer_utils::ImageReader> reader,
int64 bytes_processed,
int64 bytes_total,
@@ -132,13 +140,24 @@ class Operation
int progress_scale,
const base::Callback<void(scoped_ptr<std::string>)>& callback);
+ // Runs all cleanup functions.
+ void CleanUp();
+
+ // |stage_| and |progress_| are owned by the FILE thread, use |SetStage| and
+ // |SetProgress| to update. Progress should be in the interval [0,100]
+ image_writer_api::Stage stage_;
+ int progress_;
+
// MD5 contexts don't play well with smart pointers. Just going to allocate
// memory here. This requires that we only do one MD5 sum at a time.
base::MD5Context md5_context_;
+ // CleanUp operations that must be run. All these functions are run on the
+ // FILE thread.
+ std::vector<base::Closure> cleanup_functions_;
};
-} // namespace image_writer
-} // namespace extensions
+} // namespace image_writer
+} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_OPERATION_H_
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc b/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
index 5aeb7f5..067614d 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
@@ -4,17 +4,84 @@
#include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
#include "chrome/browser/extensions/api/image_writer_private/operation.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/image_burner_client.h"
+#include "content/public/browser/browser_thread.h"
namespace extensions {
namespace image_writer {
+using chromeos::ImageBurnerClient;
+using content::BrowserThread;
+
+namespace {
+
+void ClearImageBurner() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ chromeos::DBusThreadManager::Get()->
+ GetImageBurnerClient()->
+ ResetEventHandlers();
+}
+
+void CleanUpImageBurner() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ClearImageBurner));
+}
+
+} // namespace
+
void Operation::WriteStart() {
- Error(error::kUnsupportedOperation);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ SetStage(image_writer_api::STAGE_WRITE);
+
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&Operation::StartWriteOnUIThread, this));
+
+ AddCleanUpFunction(base::Bind(&CleanUpImageBurner));
+}
+
+void Operation::StartWriteOnUIThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DVLOG(1) << "Starting burn.";
+
+ ImageBurnerClient* burner =
+ chromeos::DBusThreadManager::Get()->GetImageBurnerClient();
+
+ burner->SetEventHandlers(
+ base::Bind(&Operation::OnBurnFinished, this),
+ base::Bind(&Operation::OnBurnProgress, this));
+
+ burner->BurnImage(image_path_.value(),
+ storage_unit_id_,
+ base::Bind(&Operation::OnBurnError, this));
+}
+
+void Operation::OnBurnFinished(const std::string& target_path,
+ bool success,
+ const std::string& error) {
+ DVLOG(1) << "Burn finished: " << success;
+
+ if (success) {
+ SetProgress(kProgressComplete);
+ Finish();
+ } else {
+ Error(error);
+ }
+}
+
+void Operation::OnBurnProgress(const std::string& target_path,
+ int64 num_bytes_burnt,
+ int64 total_size) {
+ int progress = kProgressComplete * num_bytes_burnt / total_size;
+ SetProgress(progress);
}
-void Operation::VerifyWriteStart() {
- Error(error::kUnsupportedOperation);
+void Operation::OnBurnError() {
+ Error(error::kImageBurnerError);
}
-} // namespace image_writer
-} // namespace extensions
+} // namespace image_writer
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_linux.cc b/chrome/browser/extensions/api/image_writer_private/operation_linux.cc
index 1945053..8250363 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_linux.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_linux.cc
@@ -32,9 +32,7 @@ void Operation::WriteStart() {
DVLOG(1) << "Starting write of " << image_path_.value()
<< " to " << storage_unit_id_;
- stage_ = image_writer_api::STAGE_WRITE;
- progress_ = 0;
- SendProgress();
+ SetStage(image_writer_api::STAGE_WRITE);
// TODO (haven): Unmount partitions before writing. http://crbug.com/284834
@@ -70,7 +68,7 @@ void Operation::WriteChunk(
scoped_ptr<image_writer_utils::ImageWriter> writer,
int64 bytes_written) {
if (IsCancelled()) {
- WriteCleanup(reader.Pass(), writer.Pass());
+ WriteCleanUp(reader.Pass(), writer.Pass());
return;
}
@@ -80,12 +78,11 @@ void Operation::WriteChunk(
if (len > 0) {
if (writer->Write(buffer, len) == len) {
- int percent_prev = bytes_written * 100 / image_size;
- int percent_curr = (bytes_written + len) * 100 / image_size;
- progress_ = (bytes_written + len) * 100 / image_size;
+ int percent_prev = kProgressComplete * bytes_written / image_size;
+ int percent_curr = kProgressComplete * (bytes_written + len) / image_size;
if (percent_curr > percent_prev) {
- SendProgress();
+ SetProgress(percent_curr);
}
BrowserThread::PostTask(
@@ -97,12 +94,12 @@ void Operation::WriteChunk(
base::Passed(&writer),
bytes_written + len));
} else {
- WriteCleanup(reader.Pass(), writer.Pass());
+ WriteCleanUp(reader.Pass(), writer.Pass());
Error(error::kWriteImage);
}
} else if (len == 0) {
if (bytes_written == image_size) {
- if (WriteCleanup(reader.Pass(), writer.Pass())) {
+ if (WriteCleanUp(reader.Pass(), writer.Pass())) {
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
@@ -110,16 +107,16 @@ void Operation::WriteChunk(
this));
}
} else {
- WriteCleanup(reader.Pass(), writer.Pass());
+ WriteCleanUp(reader.Pass(), writer.Pass());
Error(error::kPrematureEndOfFile);
}
} else { // len < 0
- WriteCleanup(reader.Pass(), writer.Pass());
+ WriteCleanUp(reader.Pass(), writer.Pass());
Error(error::kReadImage);
}
}
-bool Operation::WriteCleanup(
+bool Operation::WriteCleanUp(
scoped_ptr<image_writer_utils::ImageReader> reader,
scoped_ptr<image_writer_utils::ImageWriter> writer) {
@@ -139,8 +136,7 @@ bool Operation::WriteCleanup(
void Operation::WriteComplete() {
DVLOG(2) << "Completed write of " << image_path_.value();
- progress_ = 100;
- SendProgress();
+ SetProgress(kProgressComplete);
BrowserThread::PostTask(
BrowserThread::FILE,
@@ -157,9 +153,7 @@ void Operation::VerifyWriteStart() {
DVLOG(1) << "Starting verification stage.";
- stage_ = image_writer_api::STAGE_VERIFYWRITE;
- progress_ = 0;
- SendProgress();
+ SetStage(image_writer_api::STAGE_VERIFYWRITE);
scoped_ptr<base::FilePath> image_path(new base::FilePath(image_path_));
@@ -206,10 +200,10 @@ void Operation::VerifyWriteCompare(
DVLOG(2) << "Completed write verification of " << image_path_.value();
- progress_ = 100;
- SendProgress();
+ SetProgress(kProgressComplete);
+
Finish();
}
-} // namespace image_writer
-} // namespace extensions
+} // namespace image_writer
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_manager.cc b/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
index 3f34675..c6d8c85 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
@@ -27,7 +27,8 @@ namespace image_writer {
using content::BrowserThread;
OperationManager::OperationManager(Profile* profile)
- : profile_(profile) {
+ : profile_(profile),
+ weak_factory_(this) {
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
content::Source<Profile>(profile_));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
@@ -71,8 +72,12 @@ void OperationManager::StartWriteFromUrl(
}
scoped_refptr<Operation> operation(
- new WriteFromUrlOperation(this, extension_id, rvh, url,
- hash, saveImageAsDownload,
+ new WriteFromUrlOperation(weak_factory_.GetWeakPtr(),
+ extension_id,
+ rvh,
+ url,
+ hash,
+ saveImageAsDownload,
storage_unit_id));
operations_[extension_id] = operation;
@@ -101,6 +106,9 @@ void OperationManager::CancelWrite(
if (existing_operation == NULL) {
callback.Run(false, error::kNoOperationInProgress);
} else {
+ BrowserThread::PostTask(BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&Operation::Cancel, existing_operation));
DeleteOperation(extension_id);
callback.Run(true, "");
}
@@ -148,7 +156,6 @@ void OperationManager::OnError(const ExtensionId& extension_id,
DLOG(ERROR) << "ImageWriter error: " << error_message;
// TODO(haven): Set up error messages. http://crbug.com/284880
-
info.stage = stage;
info.percent_complete = progress;
@@ -174,10 +181,6 @@ Operation* OperationManager::GetOperation(const ExtensionId& extension_id) {
void OperationManager::DeleteOperation(const ExtensionId& extension_id) {
OperationMap::iterator existing_operation = operations_.find(extension_id);
if (existing_operation != operations_.end()) {
- BrowserThread::PostTask(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&Operation::Cancel,
- existing_operation->second));
operations_.erase(existing_operation);
}
}
@@ -229,5 +232,5 @@ ProfileKeyedAPIFactory<OperationManager>*
}
-} // namespace image_writer
-} // namespace extensions
+} // namespace image_writer
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_manager.h b/chrome/browser/extensions/api/image_writer_private/operation_manager.h
index f959745..d801e86 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_manager.h
+++ b/chrome/browser/extensions/api/image_writer_private/operation_manager.h
@@ -102,10 +102,12 @@ class OperationManager
OperationMap operations_;
content::NotificationRegistrar registrar_;
+ base::WeakPtrFactory<OperationManager> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(OperationManager);
};
-} // namespace image_writer
-} // namespace extensions
+} // namespace image_writer
+} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_OPERATION_MANAGER_H_
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc b/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc
index 73ecece..ddcf032 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.cc
@@ -10,7 +10,7 @@ namespace extensions {
namespace image_writer {
WriteFromFileOperation::WriteFromFileOperation(
- OperationManager* manager,
+ base::WeakPtr<OperationManager> manager,
const ExtensionId& extension_id,
const base::FilePath& path,
const std::string& storage_unit_id)
@@ -25,5 +25,5 @@ void WriteFromFileOperation::Start() {
Error(error::kUnsupportedOperation);
}
-} // namespace image_writer
-} // namespace extensions
+} // namespace image_writer
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.h b/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.h
index 478ae85..702bdf2 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.h
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_file_operation.h
@@ -13,7 +13,7 @@ namespace image_writer {
// Encapsulates a write of an image from a local file.
class WriteFromFileOperation : public Operation {
public:
- WriteFromFileOperation(OperationManager* manager,
+ WriteFromFileOperation(base::WeakPtr<OperationManager> manager,
const ExtensionId& extension_id,
const base::FilePath& path,
const std::string& storage_unit_id);
@@ -24,7 +24,7 @@ class WriteFromFileOperation : public Operation {
const base::FilePath path_;
};
-} // namespace image_writer
-} // namespace extensions
+} // namespace image_writer
+} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_WRITE_FROM_FILE_OPERATION_H_
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
index ad446ea..dec61bf 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
@@ -21,7 +21,7 @@ namespace image_writer {
using content::BrowserThread;
WriteFromUrlOperation::WriteFromUrlOperation(
- OperationManager* manager,
+ base::WeakPtr<OperationManager> manager,
const ExtensionId& extension_id,
content::RenderViewHost* rvh,
GURL url,
@@ -33,20 +33,17 @@ WriteFromUrlOperation::WriteFromUrlOperation(
url_(url),
hash_(hash),
saveImageAsDownload_(saveImageAsDownload),
- download_(NULL){
+ download_stopped_(false),
+ download_(NULL) {
}
WriteFromUrlOperation::~WriteFromUrlOperation() {
- if (stage_ == image_writer_api::STAGE_DOWNLOAD && download_) {
- download_->RemoveObserver(this);
- download_->Cancel(false);
- }
}
+
void WriteFromUrlOperation::Start() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- stage_ = image_writer_api::STAGE_DOWNLOAD;
- progress_ = 0;
+ SetStage(image_writer_api::STAGE_DOWNLOAD);
if (saveImageAsDownload_){
BrowserThread::PostTask(
@@ -59,16 +56,8 @@ void WriteFromUrlOperation::Start() {
FROM_HERE,
base::Bind(&WriteFromUrlOperation::CreateTempFile, this));
}
-}
-void WriteFromUrlOperation::Cancel() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- if (stage_ == image_writer_api::STAGE_DOWNLOAD && download_) {
- download_->RemoveObserver(this);
- download_->Cancel(true);
- }
-
- Operation::Cancel();
+ AddCleanUpFunction(base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this));
}
void WriteFromUrlOperation::CreateTempFile() {
@@ -91,14 +80,12 @@ void WriteFromUrlOperation::CreateTempFile() {
// The downloader runs on the UI thread.
void WriteFromUrlOperation::DownloadStart() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DVLOG(1) << "Starting download of URL: " << url_;
- if (IsCancelled()) {
+ if (download_stopped_) {
return;
}
- stage_ = image_writer_api::STAGE_DOWNLOAD;
- progress_ = 0;
+ DVLOG(1) << "Starting download of URL: " << url_;
Profile* current_profile = manager_->profile();
@@ -124,6 +111,14 @@ void WriteFromUrlOperation::DownloadStart() {
void WriteFromUrlOperation::OnDownloadStarted(content::DownloadItem* item,
net::Error error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (download_stopped_) {
+ // At this point DownloadCleanUp was called but the |download_| wasn't
+ // stored yet and still hasn't been cancelled.
+ item->Cancel(true);
+ return;
+ }
+
if (item) {
DCHECK_EQ(net::OK, error);
@@ -142,20 +137,14 @@ void WriteFromUrlOperation::OnDownloadStarted(content::DownloadItem* item,
}
// Always called from the UI thread.
-void WriteFromUrlOperation::OnDownloadUpdated(
- content::DownloadItem* download) {
+void WriteFromUrlOperation::OnDownloadUpdated(content::DownloadItem* download) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (IsCancelled()) {
- download->Cancel(false);
+ if (download_stopped_) {
return;
}
- progress_ = download->PercentComplete();
-
- BrowserThread::PostTask(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&WriteFromUrlOperation::SendProgress, this));
+ SetProgress(download->PercentComplete());
if (download->GetState() == content::DownloadItem::COMPLETE) {
download_path_ = download_->GetTargetFilePath();
@@ -176,15 +165,35 @@ void WriteFromUrlOperation::OnDownloadUpdated(
}
void WriteFromUrlOperation::DownloadComplete() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DVLOG(1) << "Download complete.";
- progress_ = 100;
- SendProgress();
+ SetProgress(kProgressComplete);
VerifyDownloadStart();
}
+void WriteFromUrlOperation::DownloadCleanUp() {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&WriteFromUrlOperation::DownloadCleanUp, this));
+ return;
+ }
+
+ download_stopped_ = true;
+
+ if (download_) {
+ download_->RemoveObserver(this);
+ download_->Cancel(true);
+ download_ = NULL;
+ }
+}
+
void WriteFromUrlOperation::VerifyDownloadStart() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
if (IsCancelled()) {
return;
}
@@ -199,10 +208,7 @@ void WriteFromUrlOperation::VerifyDownloadStart() {
DVLOG(1) << "Download verification started.";
- stage_ = image_writer_api::STAGE_VERIFYDOWNLOAD;
- progress_ = 0;
-
- SendProgress();
+ SetStage(image_writer_api::STAGE_VERIFYDOWNLOAD);
BrowserThread::PostTask(
BrowserThread::FILE,
@@ -211,17 +217,19 @@ void WriteFromUrlOperation::VerifyDownloadStart() {
}
void WriteFromUrlOperation::VerifyDownloadRun() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
GetMD5SumOfFile(
download_path.Pass(),
0,
0,
- 100,
+ kProgressComplete,
base::Bind(&WriteFromUrlOperation::VerifyDownloadCompare, this));
}
void WriteFromUrlOperation::VerifyDownloadCompare(
scoped_ptr<std::string> download_hash) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
if (*download_hash != hash_) {
Error(error::kDownloadHash);
return;
@@ -234,14 +242,14 @@ void WriteFromUrlOperation::VerifyDownloadCompare(
}
void WriteFromUrlOperation::VerifyDownloadComplete() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
if (IsCancelled()) {
return;
}
DVLOG(1) << "Download verification complete.";
- progress_ = 100;
- SendProgress();
+ SetProgress(kProgressComplete);
scoped_ptr<base::FilePath> download_path(new base::FilePath(download_path_));
UnzipStart(download_path.Pass());
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h
index 8ae0aa2..95e5574 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h
@@ -26,14 +26,13 @@ class OperationManager;
class WriteFromUrlOperation : public Operation,
public content::DownloadItem::Observer {
public:
- WriteFromUrlOperation(OperationManager* manager,
+ WriteFromUrlOperation(base::WeakPtr<OperationManager> manager,
const ExtensionId& extension_id,
content::RenderViewHost* rvh,
GURL url,
const std::string& hash,
bool saveImageAsDownload,
const std::string& storage_unit_id);
- virtual void Cancel() OVERRIDE;
virtual void Start() OVERRIDE;
private:
virtual ~WriteFromUrlOperation();
@@ -43,19 +42,23 @@ class WriteFromUrlOperation : public Operation,
void OnDownloadStarted(content::DownloadItem*, net::Error);
virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
void DownloadComplete();
+ void DownloadCleanUp();
void VerifyDownloadStart();
void VerifyDownloadRun();
void VerifyDownloadCompare(scoped_ptr<std::string> download_hash);
void VerifyDownloadComplete();
+ // Arguments
content::RenderViewHost* rvh_;
GURL url_;
const std::string hash_;
const bool saveImageAsDownload_;
+
+ // Local state
scoped_ptr<base::FilePath> tmp_file_;
+ bool download_stopped_;
content::DownloadItem* download_;
-
base::FilePath download_path_;
};