Index: chrome/browser/component_updater/component_unpacker.cc |
diff --git a/chrome/browser/component_updater/component_unpacker.cc b/chrome/browser/component_updater/component_unpacker.cc |
index 74b17853bacf6890421a15b6ae0302ac5ea9d0b0..6ddff606097eb5dcfe1ed01069b7d184fbe015da 100644 |
--- a/chrome/browser/component_updater/component_unpacker.cc |
+++ b/chrome/browser/component_updater/component_unpacker.cc |
@@ -31,6 +31,19 @@ namespace component_updater { |
namespace { |
+namespace serialize { |
+ |
+const char kKeyFingerprint[] = "fingerprint"; |
+const char kKeyPKHash[] = "public_key_hash"; |
+const char kKeyInProcess[] = "in_process"; |
+ |
+const base::FilePath::CharType kCrxFileName[] = |
+ FILE_PATH_LITERAL("saved_installer.crx"); |
+const base::FilePath::CharType kInstallDataFileName[] = |
+ FILE_PATH_LITERAL("metadata.json"); |
+ |
+} // namespace serialize |
+ |
// This class makes sure that the CRX digital signature is valid |
// and well formed. |
class CRXValidator { |
@@ -124,8 +137,7 @@ scoped_ptr<base::DictionaryValue> ReadManifest( |
if (!base::PathExists(manifest)) |
return scoped_ptr<base::DictionaryValue>(); |
JSONFileValueSerializer serializer(manifest); |
- std::string error; |
- scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); |
+ scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL)); |
if (!root.get()) |
return scoped_ptr<base::DictionaryValue>(); |
if (!root->IsType(base::Value::TYPE_DICTIONARY)) |
@@ -182,11 +194,19 @@ bool ComponentUnpacker::Verify() { |
return true; |
} |
+bool ComponentUnpacker::CreateUnpackDirectory(base::FilePath* new_dir) { |
+ if (unpack_base_dir_.empty()) { |
+ return base::CreateNewTempDirectory(base::FilePath::StringType(), new_dir); |
+ } |
+ |
+ return base::CreateTemporaryDirInDir( |
+ unpack_base_dir_, base::FilePath::StringType(), new_dir); |
+} |
+ |
bool ComponentUnpacker::Unzip() { |
base::FilePath& destination = is_delta_ ? unpack_diff_path_ : unpack_path_; |
VLOG(1) << "Unpacking in: " << destination.value(); |
- if (!base::CreateNewTempDirectory(base::FilePath::StringType(), |
- &destination)) { |
+ if (!CreateUnpackDirectory(&destination)) { |
VLOG(1) << "Unable to create temporary directory for unpacking."; |
error_ = kUnzipPathError; |
return false; |
@@ -203,8 +223,7 @@ bool ComponentUnpacker::Unzip() { |
bool ComponentUnpacker::BeginPatching() { |
if (is_delta_) { // Package is a diff package. |
// Use a different temp directory for the patch output files. |
- if (!base::CreateNewTempDirectory(base::FilePath::StringType(), |
- &unpack_path_)) { |
+ if (!CreateUnpackDirectory(&unpack_path_)) { |
error_ = kUnzipPathError; |
return false; |
} |
@@ -264,6 +283,14 @@ void ComponentUnpacker::Install() { |
} |
DCHECK(error_ == kNone); |
if (!installer_->Install(*manifest, unpack_path_)) { |
+ // Saves the installer files and tries to re-install which is not managed |
+ // by the component updater service. |
+ if (SaveInstallSource(installer_->GetBackupPath())) { |
+ installer_->InstallExternally(); |
+ } |
+ |
+ // But keep current install error code since we cannot get the external |
+ // install result. |
error_ = kInstallerError; |
return; |
} |
@@ -280,4 +307,92 @@ void ComponentUnpacker::Finish() { |
ComponentUnpacker::~ComponentUnpacker() { |
} |
+bool ComponentUnpacker::SaveInstallSource( |
+ const base::FilePath& backup_path) const { |
+ if (backup_path.empty()) { |
+ return false; |
+ } |
+ |
+ if (!base::CreateDirectory(backup_path)) { |
+ return false; |
+ } |
+ |
+ const base::FilePath crx_path = backup_path.Append(serialize::kCrxFileName); |
+ if (!base::CopyFile(path_, crx_path)) { |
+ return false; |
+ } |
+ |
+ const base::FilePath install_data_file_path = |
+ backup_path.Append(serialize::kInstallDataFileName); |
+ JSONFileValueSerializer serializer(install_data_file_path); |
+ |
+ scoped_ptr<base::DictionaryValue> root(new base::DictionaryValue); |
+ root->SetString(serialize::kKeyFingerprint, fingerprint_); |
+ root->SetBoolean(serialize::kKeyInProcess, in_process_); |
+ scoped_ptr<base::ListValue> pk_hash_list(new base::ListValue); |
+ for (size_t i = 0; i < pk_hash_.size(); ++i) { |
+ pk_hash_list->Append(base::Value::CreateIntegerValue( |
+ static_cast<int>(pk_hash_[i]))); |
+ } |
+ root->Set(serialize::kKeyPKHash, pk_hash_list.release()); |
+ if (!serializer.Serialize(*root)) { |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+void ComponentUnpacker::set_unpack_base_dir(const base::FilePath& path) { |
+ unpack_base_dir_ = path; |
+} |
+ |
+scoped_refptr<ComponentUnpacker> ComponentUnpacker::CreateFromBackup( |
+ const base::FilePath& backup_path, |
+ const std::vector<uint8>& pk_hash, |
+ ComponentInstaller* installer, |
+ scoped_refptr<base::SequencedTaskRunner> task_runner) { |
+ const base::FilePath crx_path = backup_path.Append(serialize::kCrxFileName); |
+ if (!base::PathExists(crx_path) || base::DirectoryExists(crx_path)) { |
+ return scoped_refptr<ComponentUnpacker>(); |
+ } |
+ |
+ std::string fingerprint; |
+ bool in_process = false; |
+ |
+ const base::FilePath install_data_file_path = |
+ backup_path.Append(serialize::kInstallDataFileName); |
+ if (!base::PathExists(install_data_file_path)) { |
+ return scoped_refptr<ComponentUnpacker>(); |
+ } |
+ |
+ JSONFileValueSerializer serialize(install_data_file_path); |
+ scoped_ptr<base::Value> root(serialize.Deserialize(NULL, NULL)); |
+ if (!root.get() || !root->IsType(base::Value::TYPE_DICTIONARY)) { |
+ return scoped_refptr<ComponentUnpacker>(); |
+ } |
+ |
+ scoped_ptr<base::DictionaryValue> metadata( |
+ static_cast<base::DictionaryValue*>(root.release())); |
+ |
+ base::ListValue* pk_hash_list = NULL; |
+ if (!metadata->GetStringASCII(serialize::kKeyFingerprint, &fingerprint) || |
+ !metadata->GetBoolean(serialize::kKeyInProcess, &in_process) || |
+ !metadata->GetList(serialize::kKeyPKHash, &pk_hash_list) || |
+ pk_hash_list == NULL || |
+ pk_hash_list->GetSize() != pk_hash.size()) { |
+ return scoped_refptr<ComponentUnpacker>(); |
+ } |
+ |
+ for (size_t i = 0; i < pk_hash.size(); ++i) { |
+ int value = 0; |
+ if (!pk_hash_list->GetInteger(i, &value) || |
+ pk_hash[i] != static_cast<uint8>(value)) { |
+ return scoped_refptr<ComponentUnpacker>(); |
+ } |
+ } |
+ |
+ return make_scoped_refptr(new ComponentUnpacker( |
+ pk_hash, crx_path, fingerprint, installer, in_process, task_runner)); |
+} |
+ |
} // namespace component_updater |