Chromium Code Reviews| Index: chrome/browser/component_updater/component_patcher_operation.cc |
| diff --git a/chrome/browser/component_updater/component_patcher_operation.cc b/chrome/browser/component_updater/component_patcher_operation.cc |
| index 6b86d9fc8a6dc241caa3db8eced617f6e5887f3b..616d01496c5e48fbee338e4c67d34f7866135d4d 100644 |
| --- a/chrome/browser/component_updater/component_patcher_operation.cc |
| +++ b/chrome/browser/component_updater/component_patcher_operation.cc |
| @@ -7,6 +7,7 @@ |
| #include <string> |
| #include <vector> |
| +#include "base/bind.h" |
| #include "base/file_util.h" |
| #include "base/files/memory_mapped_file.h" |
| #include "base/json/json_file_value_serializer.h" |
| @@ -15,11 +16,17 @@ |
| #include "base/strings/string_number_conversions.h" |
| #include "chrome/browser/component_updater/component_patcher.h" |
| #include "chrome/browser/component_updater/component_updater_service.h" |
| +#include "chrome/common/chrome_utility_messages.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/utility_process_host.h" |
| +#include "courgette/courgette.h" |
| +#include "courgette/third_party/bsdiff.h" |
| #include "crypto/secure_hash.h" |
| #include "crypto/sha2.h" |
| #include "crypto/signature_verifier.h" |
| #include "extensions/common/crx_file.h" |
| +#include "ipc/ipc_message_macros.h" |
| #include "third_party/zlib/google/zip.h" |
| using crypto::SecureHash; |
| @@ -34,6 +41,11 @@ const char kOutput[] = "output"; |
| const char kPatch[] = "patch"; |
| const char kSha256[] = "sha256"; |
| +// These error ranges are overlapping, so we use an offset to disambiguate |
|
Sorin Jianu
2014/02/03 20:57:57
The integer offset disambiguates between overlappi
waffles
2014/02/07 01:00:59
Done.
|
| +// them. |
| +const int kCourgetteErrorOffset = 300; |
| +const int kBsdiffErrorOffset = 600; |
| + |
| } // namespace |
| DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) { |
|
Sorin Jianu
2014/02/03 20:57:57
can the argument be const?
waffles
2014/02/07 01:00:59
Done.
|
| @@ -45,45 +57,61 @@ DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) { |
| else if (operation == "create") |
| return new DeltaUpdateOpCreate(); |
| else if (operation == "bsdiff") |
| - return new DeltaUpdateOpPatchBsdiff(); |
| + return new DeltaUpdateOpPatch(component_updater::kPatchTypeBsdiff); |
| else if (operation == "courgette") |
| - return new DeltaUpdateOpPatchCourgette(); |
| + return new DeltaUpdateOpPatch(component_updater::kPatchTypeCourgette); |
| return NULL; |
| } |
| -DeltaUpdateOp::DeltaUpdateOp() {} |
| +DeltaUpdateOp::DeltaUpdateOp() : in_process_(false), ptr_factory_(this) {} |
| DeltaUpdateOp::~DeltaUpdateOp() {} |
| -ComponentUnpacker::Error DeltaUpdateOp::Run(base::DictionaryValue* command_args, |
| - const base::FilePath& input_dir, |
| - const base::FilePath& unpack_dir, |
| - ComponentPatcher* patcher, |
| - ComponentInstaller* installer, |
| - int* error) { |
| +void DeltaUpdateOp::Run( |
| + base::DictionaryValue* command_args, |
| + const base::FilePath& input_dir, |
| + const base::FilePath& unpack_dir, |
| + ComponentInstaller* installer, |
| + bool in_process, |
| + const base::Callback<void(ComponentUnpacker::Error, int)>& callback, |
| + scoped_refptr<base::SequencedTaskRunner> task_runner) { |
| + callback_ = callback; |
| + in_process_ = in_process; |
| + task_runner_ = task_runner; |
| std::string output_rel_path; |
| if (!command_args->GetString(kOutput, &output_rel_path) || |
| - !command_args->GetString(kSha256, &output_sha256_)) |
| - return ComponentUnpacker::kDeltaBadCommands; |
| + !command_args->GetString(kSha256, &output_sha256_)) { |
| + DoneRunning(ComponentUnpacker::kDeltaBadCommands, 0); |
| + return; |
| + } |
| output_abs_path_ = unpack_dir.Append( |
| base::FilePath::FromUTF8Unsafe(output_rel_path)); |
| ComponentUnpacker::Error parse_result = DoParseArguments( |
| command_args, input_dir, installer); |
| - if (parse_result != ComponentUnpacker::kNone) |
| - return parse_result; |
| + if (parse_result != ComponentUnpacker::kNone) { |
| + DoneRunning(parse_result, 0); |
| + return; |
| + } |
| const base::FilePath parent = output_abs_path_.DirName(); |
| if (!base::DirectoryExists(parent)) { |
| - if (!base::CreateDirectory(parent)) |
| - return ComponentUnpacker::kIoError; |
| + if (!base::CreateDirectory(parent)) { |
| + DoneRunning(ComponentUnpacker::kIoError, 0); |
| + return; |
| + } |
| } |
| - ComponentUnpacker::Error run_result = DoRun(patcher, error); |
| - if (run_result != ComponentUnpacker::kNone) |
| - return run_result; |
| + DoRun(base::Bind(&DeltaUpdateOp::DoneRunning, GetWeakPtr())); |
| +} |
| - return CheckHash(); |
| +void DeltaUpdateOp::DoneRunning( |
| + ComponentUnpacker::Error error, int extended_error) { |
|
Sorin Jianu
2014/02/03 20:57:57
does this line fit on the line above?
Sorin Jianu
2014/02/03 20:57:57
Coding style nit: http://google-styleguide.googlec
waffles
2014/02/07 01:00:59
Not the whole line, no.
waffles
2014/02/07 01:00:59
Done.
|
| + if (error == ComponentUnpacker::kNone) |
| + error = CheckHash(); |
| + task_runner_->PostTask( |
| + FROM_HERE, |
|
Sorin Jianu
2014/02/03 20:57:57
params vertical align as above?
waffles
2014/02/07 01:00:59
Done.
|
| + base::Bind(callback_, error, extended_error)); |
| } |
| // Uses the hash as a checksum to confirm that the file now residing in the |
| @@ -108,6 +136,10 @@ ComponentUnpacker::Error DeltaUpdateOp::CheckHash() { |
| return ComponentUnpacker::kNone; |
| } |
| +base::WeakPtr<DeltaUpdateOp> DeltaUpdateOp::GetWeakPtr() { |
| + return ptr_factory_.GetWeakPtr(); |
| +} |
| + |
| DeltaUpdateOpCopy::DeltaUpdateOpCopy() {} |
| ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments( |
| @@ -124,13 +156,12 @@ ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments( |
| return ComponentUnpacker::kNone; |
| } |
| -ComponentUnpacker::Error DeltaUpdateOpCopy::DoRun(ComponentPatcher*, |
| - int* error) { |
| - *error = 0; |
| +void DeltaUpdateOpCopy::DoRun( |
| + const base::Callback<void(ComponentUnpacker::Error, int)>& callback) { |
| if (!base::CopyFile(input_abs_path_, output_abs_path_)) |
| - return ComponentUnpacker::kDeltaOperationFailure; |
| - |
| - return ComponentUnpacker::kNone; |
| + callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0); |
| + else |
| + callback.Run(ComponentUnpacker::kNone, 0); |
| } |
| DeltaUpdateOpCreate::DeltaUpdateOpCreate() {} |
| @@ -149,18 +180,23 @@ ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments( |
| return ComponentUnpacker::kNone; |
| } |
| -ComponentUnpacker::Error DeltaUpdateOpCreate::DoRun(ComponentPatcher*, |
| - int* error) { |
| - *error = 0; |
| +void DeltaUpdateOpCreate::DoRun( |
| + const base::Callback<void(ComponentUnpacker::Error, int)>& callback) { |
| if (!base::Move(patch_abs_path_, output_abs_path_)) |
| - return ComponentUnpacker::kDeltaOperationFailure; |
| + callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0); |
| + else |
| + callback.Run(ComponentUnpacker::kNone, 0); |
| +} |
| - return ComponentUnpacker::kNone; |
| + |
| +DeltaUpdateOpPatch::DeltaUpdateOpPatch( |
| + component_updater::PatchType patch_type) : patch_type_(patch_type) { |
|
Sorin Jianu
2014/02/03 20:57:57
Formatting of function params and initializers.
waffles
2014/02/07 01:00:59
Done.
|
| } |
| -DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {} |
| +DeltaUpdateOpPatch::~DeltaUpdateOpPatch() { |
| +} |
| -ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments( |
| +ComponentUnpacker::Error DeltaUpdateOpPatch::DoParseArguments( |
| base::DictionaryValue* command_args, |
| const base::FilePath& input_dir, |
| ComponentInstaller* installer) { |
| @@ -179,47 +215,110 @@ ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments( |
| return ComponentUnpacker::kNone; |
| } |
| -ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoRun( |
| - ComponentPatcher* patcher, |
| - int* error) { |
| - *error = 0; |
| - return patcher->Patch(ComponentPatcher::kPatchTypeBsdiff, |
| - input_abs_path_, |
| - patch_abs_path_, |
| - output_abs_path_, |
| - error); |
| +void DeltaUpdateOpPatch::DoRun( |
| + const base::Callback<void(ComponentUnpacker::Error, int)>& callback) { |
| + callback_ = callback; |
| + if (!in_process_) { |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&DeltaUpdateOpPatch::StartProcess, base::Unretained(this))); |
|
Sorin Jianu
2014/02/03 20:57:57
Can we have a race here due to ownership issues, n
waffles
2014/02/07 01:00:59
Yes - this should be resolved now that this class
|
| + return; |
| + } |
| + switch (patch_type_) { |
| + case component_updater::kPatchTypeCourgette: { |
| + const int result = courgette::ApplyEnsemblePatch( |
| + input_abs_path_.value().c_str(), |
| + patch_abs_path_.value().c_str(), |
| + output_abs_path_.value().c_str()); |
| + if (result == courgette::C_OK) |
| + callback_.Run(ComponentUnpacker::kNone, 0); |
| + else |
| + DonePatching(false, result); |
|
Sorin Jianu
2014/02/03 20:57:57
I've noticed that is most cases DonePatching is ca
waffles
2014/02/07 01:00:59
This should all be much more organized now.
|
| + break; |
| + } |
| + case component_updater::kPatchTypeBsdiff: { |
| + const int result = courgette::ApplyBinaryPatch( |
| + input_abs_path_, patch_abs_path_, output_abs_path_); |
| + if (result == courgette::OK) |
| + callback_.Run(ComponentUnpacker::kNone, 0); |
| + else |
| + DonePatching(false, result); |
| + break; |
| + } |
| + default: { |
| + NOTREACHED() << "Invalid patch type."; |
| + callback_.Run(ComponentUnpacker::kDeltaUnsupportedCommand, 0); |
| + } |
| + } |
| } |
| -DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {} |
| +void DeltaUpdateOpPatch::StartProcess() { |
| + content::UtilityProcessHost* host = content::UtilityProcessHost::Create( |
| + new PatcherBridge(this), base::MessageLoopProxy::current().get()); |
| + host->DisableSandbox(); |
| + switch (patch_type_) { |
| + case component_updater::kPatchTypeCourgette: { |
| + host->Send(new ChromeUtilityMsg_PatchFileCourgette( |
| + input_abs_path_, patch_abs_path_, output_abs_path_)); |
| + break; |
| + } |
| + case component_updater::kPatchTypeBsdiff: { |
| + host->Send(new ChromeUtilityMsg_PatchFileBsdiff( |
| + input_abs_path_, patch_abs_path_, output_abs_path_)); |
| + break; |
| + } |
| + default: { |
| + NOTREACHED() << "Invalid patch type."; |
| + callback_.Run(ComponentUnpacker::kDeltaUnsupportedCommand, 0); |
| + } |
| + } |
| +} |
| -ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoParseArguments( |
| - base::DictionaryValue* command_args, |
| - const base::FilePath& input_dir, |
| - ComponentInstaller* installer) { |
| - std::string patch_rel_path; |
| - std::string input_rel_path; |
| - if (!command_args->GetString(kPatch, &patch_rel_path) || |
| - !command_args->GetString(kInput, &input_rel_path)) |
| - return ComponentUnpacker::kDeltaBadCommands; |
| +void DeltaUpdateOpPatch::DonePatching(bool success, int error_code) { |
| + if (success) { |
| + callback_.Run(ComponentUnpacker::kNone, error_code); |
| + } else { |
| + int offset = patch_type_ == component_updater::kPatchTypeCourgette |
|
Sorin Jianu
2014/02/03 20:57:57
we have the switch on the patch_type_ in three dif
waffles
2014/02/07 01:00:59
I've tried out a using a traits class - let me kno
|
| + ? kCourgetteErrorOffset : kBsdiffErrorOffset; |
| + callback_.Run(ComponentUnpacker::kDeltaOperationFailure, |
| + error_code + offset); |
| + } |
| +} |
| - if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) |
| - return ComponentUnpacker::kDeltaMissingExistingFile; |
| +DeltaUpdateOpPatch::PatcherBridge::PatcherBridge(DeltaUpdateOpPatch* op) |
| + : op_(op) { |
| +} |
| - patch_abs_path_ = input_dir.Append( |
| - base::FilePath::FromUTF8Unsafe(patch_rel_path)); |
| +DeltaUpdateOpPatch::PatcherBridge::~PatcherBridge() { |
| +} |
| - return ComponentUnpacker::kNone; |
| +bool DeltaUpdateOpPatch::PatcherBridge::OnMessageReceived( |
| + const IPC::Message& message) { |
| + bool handled = true; |
| + IPC_BEGIN_MESSAGE_MAP(PatcherBridge, message) |
| + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PatchFile_Succeeded, |
| + OnPatchSucceeded) |
| + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PatchFile_Failed, |
| + OnPatchFailed) |
| + IPC_MESSAGE_UNHANDLED(handled = false) |
| + IPC_END_MESSAGE_MAP() |
| + return handled; |
| +} |
| + |
| +void DeltaUpdateOpPatch::PatcherBridge::OnProcessCrashed(int exit_code) { |
| + if (op_) |
| + op_->callback_.Run(ComponentUnpacker::kDeltaPatchProcessFailure, exit_code); |
| +} |
| + |
| +void DeltaUpdateOpPatch::PatcherBridge::OnPatchSucceeded() { |
| + if (op_) |
| + op_->DonePatching(true, 0); |
| } |
| -ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoRun( |
| - ComponentPatcher* patcher, |
| - int* error) { |
| - *error = 0; |
| - return patcher->Patch(ComponentPatcher::kPatchTypeCourgette, |
| - input_abs_path_, |
| - patch_abs_path_, |
| - output_abs_path_, |
| - error); |
| +void DeltaUpdateOpPatch::PatcherBridge::OnPatchFailed(int error_code) { |
| + if (op_) |
| + op_->DonePatching(false, error_code); |
| } |
| } // namespace component_updater |