Skeleton app installer for Chrome Updater.
BUG=967689
Change-Id: I8547f5c8b047dc1ddffc99fd576eb67bf817e22f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1630519
Reviewed-by: Joshua Pawlicki <[email protected]>
Reviewed-by: Devlin <[email protected]>
Commit-Queue: Sorin Jianu <[email protected]>
Cr-Commit-Position: refs/heads/master@{#664020}
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 186a2dbd..1d13162 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -31,6 +31,8 @@
"crash_client.h",
"crash_reporter.cc",
"crash_reporter.h",
+ "installer.cc",
+ "installer.h",
"patcher.cc",
"patcher.h",
"prefs.cc",
diff --git a/chrome/updater/DEPS b/chrome/updater/DEPS
index 843c0ac..5aa062e 100644
--- a/chrome/updater/DEPS
+++ b/chrome/updater/DEPS
@@ -1,11 +1,12 @@
include_rules = [
"+components/crash/core/common",
+ "+components/crx_file",
"+components/prefs",
"+components/services/patch",
"+components/services/unzip",
"+components/update_client",
"+components/version_info",
"+courgette",
- "+third_party/zlib/google",
"+third_party/crashpad",
+ "+third_party/zlib/google",
]
diff --git a/chrome/updater/installer.cc b/chrome/updater/installer.cc
new file mode 100644
index 0000000..8b2807a
--- /dev/null
+++ b/chrome/updater/installer.cc
@@ -0,0 +1,185 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/installer.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "chrome/updater/updater_constants.h"
+#include "chrome/updater/util.h"
+#include "components/crx_file/crx_verifier.h"
+#include "components/update_client/update_client_errors.h"
+#include "components/update_client/utils.h"
+
+namespace updater {
+
+namespace {
+
+// Version "0" corresponds to no installed version.
+const char kNullVersion[] = "0.0.0.0";
+
+} // namespace
+
+Installer::InstallInfo::InstallInfo() : version(kNullVersion) {}
+Installer::InstallInfo::~InstallInfo() = default;
+
+Installer::Installer(const std::vector<uint8_t>& pk_hash)
+ : pk_hash_(pk_hash),
+ crx_id_(update_client::GetCrxIdFromPublicKeyHash(pk_hash)),
+ install_info_(std::make_unique<InstallInfo>()) {}
+
+Installer::~Installer() = default;
+
+update_client::CrxComponent Installer::MakeCrxComponent() {
+ update_client::CrxComponent component;
+ component.installer = scoped_refptr<Installer>(this);
+ component.requires_network_encryption = false;
+ component.crx_format_requirement =
+ crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF;
+ component.pk_hash = pk_hash_;
+ component.name = crx_id_;
+ component.version = install_info_->version;
+ component.fingerprint = install_info_->fingerprint;
+ return component;
+}
+
+void Installer::FindInstallOfApp() {
+ VLOG(1) << __func__ << " for " << crx_id_;
+
+ base::FilePath root_install_path;
+ if (!GetProductDataDirectory(&root_install_path)) {
+ install_info_ = std::make_unique<InstallInfo>();
+ return;
+ }
+ root_install_path = root_install_path.AppendASCII(crx_id_);
+ if (!base::PathExists(root_install_path)) {
+ install_info_ = std::make_unique<InstallInfo>();
+ return;
+ }
+
+ base::Version latest_version(kNullVersion);
+ base::FilePath latest_path;
+ std::vector<base::FilePath> older_paths;
+ base::FileEnumerator file_enumerator(root_install_path, false,
+ base::FileEnumerator::DIRECTORIES);
+ for (auto path = file_enumerator.Next(); !path.value().empty();
+ path = file_enumerator.Next()) {
+ const base::Version version(path.BaseName().MaybeAsASCII());
+
+ // Ignore folders that don't have valid version names.
+ if (!version.IsValid())
+ continue;
+
+ // The |version| not newer than the latest found version is marked for
+ // removal. |kNullVersion| is also removed.
+ if (version.CompareTo(latest_version) <= 0) {
+ older_paths.push_back(path);
+ continue;
+ }
+
+ // New valid |version| folder found.
+ if (!latest_path.empty())
+ older_paths.push_back(latest_path);
+
+ latest_version = version;
+ latest_path = path;
+ }
+
+ install_info_->version = latest_version;
+ install_info_->install_dir = latest_path;
+ install_info_->manifest = update_client::ReadManifest(latest_path);
+ base::ReadFileToString(latest_path.AppendASCII("manifest.fingerprint"),
+ &install_info_->fingerprint);
+
+ for (const auto& older_path : older_paths)
+ base::DeleteFile(older_path, true);
+}
+
+Installer::Result Installer::InstallHelper(const base::FilePath& unpack_path) {
+ auto local_manifest = update_client::ReadManifest(unpack_path);
+ if (!local_manifest)
+ return Result(update_client::InstallError::BAD_MANIFEST);
+
+ std::string version_ascii;
+ local_manifest->GetStringASCII("version", &version_ascii);
+ const base::Version manifest_version(version_ascii);
+
+ VLOG(1) << "Installed version=" << install_info_->version.GetString()
+ << ", installing version=" << manifest_version.GetString();
+
+ if (!manifest_version.IsValid())
+ return Result(update_client::InstallError::INVALID_VERSION);
+
+ if (install_info_->version.CompareTo(manifest_version) > 0)
+ return Result(update_client::InstallError::VERSION_NOT_UPGRADED);
+
+ base::FilePath root_install_path;
+ if (!GetProductDataDirectory(&root_install_path))
+ return Result(update_client::InstallError::NO_DIR_COMPONENT_USER);
+
+ root_install_path = root_install_path.AppendASCII(crx_id_);
+ if (!base::CreateDirectory(root_install_path)) {
+ return Result(
+ static_cast<int>(update_client::InstallError::CUSTOM_ERROR_BASE) +
+ kCustomInstallErrorCreateAppInstallDirectory);
+ }
+
+ const auto versioned_install_path =
+ root_install_path.AppendASCII(manifest_version.GetString());
+ if (base::PathExists(versioned_install_path)) {
+ if (!base::DeleteFile(versioned_install_path, true))
+ return Result(update_client::InstallError::CLEAN_INSTALL_DIR_FAILED);
+ }
+
+ VLOG(1) << "Install_path=" << versioned_install_path.AsUTF8Unsafe();
+
+ if (!base::Move(unpack_path, versioned_install_path)) {
+ PLOG(ERROR) << "Move failed.";
+ base::DeleteFile(versioned_install_path, true);
+ return Result(update_client::InstallError::MOVE_FILES_ERROR);
+ }
+
+ DCHECK(!base::PathExists(unpack_path));
+ DCHECK(base::PathExists(versioned_install_path));
+
+ install_info_->manifest = std::move(local_manifest);
+ install_info_->version = manifest_version;
+ install_info_->install_dir = versioned_install_path;
+ base::ReadFileToString(
+ versioned_install_path.AppendASCII("manifest.fingerprint"),
+ &install_info_->fingerprint);
+
+ return Result(update_client::InstallError::NONE);
+}
+
+void Installer::OnUpdateError(int error) {
+ LOG(ERROR) << "updater error: " << error << " for " << crx_id_;
+}
+
+void Installer::Install(const base::FilePath& unpack_path,
+ const std::string& public_key,
+ Callback callback) {
+ std::unique_ptr<base::DictionaryValue> manifest;
+ base::Version version;
+ base::FilePath install_path;
+
+ const auto result = InstallHelper(unpack_path);
+ base::DeleteFile(unpack_path, true);
+ std::move(callback).Run(result);
+}
+
+bool Installer::GetInstalledFile(const std::string& file,
+ base::FilePath* installed_file) {
+ return false;
+}
+
+bool Installer::Uninstall() {
+ return false;
+}
+
+} // namespace updater
diff --git a/chrome/updater/installer.h b/chrome/updater/installer.h
new file mode 100644
index 0000000..ef97e84
--- /dev/null
+++ b/chrome/updater/installer.h
@@ -0,0 +1,74 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_INSTALLER_H_
+#define CHROME_UPDATER_INSTALLER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "components/update_client/update_client.h"
+
+namespace updater {
+
+class Installer final : public update_client::CrxInstaller {
+ public:
+ struct InstallInfo {
+ InstallInfo();
+ ~InstallInfo();
+
+ base::FilePath install_dir;
+ base::Version version;
+ std::string fingerprint;
+ std::unique_ptr<base::DictionaryValue> manifest;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InstallInfo);
+ };
+
+ explicit Installer(const std::vector<uint8_t>& pk_hash);
+
+ const std::string crx_id() const { return crx_id_; }
+
+ // Finds the highest version install of the app, and updates the install
+ // info for this installer instance.
+ void FindInstallOfApp();
+
+ // Returns a CrxComponent instance that describes the current install
+ // state of the app.
+ update_client::CrxComponent MakeCrxComponent();
+
+ private:
+ ~Installer() override;
+
+ // Overrides from update_client::CrxInstaller.
+ void OnUpdateError(int error) override;
+ void Install(const base::FilePath& unpack_path,
+ const std::string& public_key,
+ Callback callback) override;
+ bool GetInstalledFile(const std::string& file,
+ base::FilePath* installed_file) override;
+ bool Uninstall() override;
+
+ Result InstallHelper(const base::FilePath& unpack_path);
+
+ const std::vector<uint8_t> pk_hash_;
+ const std::string crx_id_;
+ std::unique_ptr<InstallInfo> install_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(Installer);
+};
+
+} // namespace updater
+
+#endif // CHROME_UPDATER_INSTALLER_H_
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc
index ef1a9d4..0aae5e93 100644
--- a/chrome/updater/updater.cc
+++ b/chrome/updater/updater.cc
@@ -4,6 +4,8 @@
#include "chrome/updater/updater.h"
+#include <stdint.h>
+
#include <iterator>
#include <memory>
#include <string>
@@ -11,7 +13,7 @@
#include <vector>
#include "base/at_exit.h"
-#include "base/callback_forward.h"
+#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
@@ -30,6 +32,7 @@
#include "chrome/updater/configurator.h"
#include "chrome/updater/crash_client.h"
#include "chrome/updater/crash_reporter.h"
+#include "chrome/updater/installer.h"
#include "chrome/updater/updater_constants.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util.h"
@@ -68,12 +71,16 @@
// Overrides for update_client::UpdateClient::Observer.
void OnEvent(Events event, const std::string& id) override {
- update_client::CrxUpdateItem item;
- update_client_->GetCrxUpdateState(id, &item);
+ update_client_->GetCrxUpdateState(id, &crx_update_item_);
+ }
+
+ const update_client::CrxUpdateItem& crx_update_item() const {
+ return crx_update_item_;
}
private:
scoped_refptr<update_client::UpdateClient> update_client_;
+ update_client::CrxUpdateItem crx_update_item_;
DISALLOW_COPY_AND_ASSIGN(Observer);
};
@@ -100,11 +107,11 @@
"process_type");
crash_key_process_type.Set("updater");
- if (CrashClient::GetInstance()->InitializeCrashReporting()) {
+ if (CrashClient::GetInstance()->InitializeCrashReporting())
VLOG(1) << "Crash reporting initialized.";
- } else {
+ else
VLOG(1) << "Crash reporting is not available.";
- }
+
StartCrashReporter(UPDATER_VERSION_STRING);
ThreadPoolStart();
@@ -138,12 +145,16 @@
return *ptr;
}
+ auto installer = base::MakeRefCounted<Installer>(
+ std::vector<uint8_t>(std::cbegin(mimo_hash), std::cend(mimo_hash)));
+ installer->FindInstallOfApp();
+ const auto component = installer->MakeCrxComponent();
+
base::MessageLoopForUI message_loop;
base::RunLoop runloop;
DCHECK(base::ThreadTaskRunnerHandle::IsSet());
auto config = base::MakeRefCounted<Configurator>();
-
{
base::ScopedDisallowBlocking no_blocking_allowed;
@@ -152,20 +163,17 @@
Observer observer(update_client);
update_client->AddObserver(&observer);
- const std::vector<std::string> ids = {"mimojjlkmoijpicakmndhoigimigcmbb"};
+ const std::vector<std::string> ids = {installer->crx_id()};
update_client->Update(
ids,
base::BindOnce(
- [](const std::vector<std::string>& ids)
+ [](const update_client::CrxComponent& component,
+ const std::vector<std::string>& ids)
-> std::vector<base::Optional<update_client::CrxComponent>> {
- update_client::CrxComponent component;
- component.name = "mimo";
- component.pk_hash.assign(std::begin(mimo_hash),
- std::end(mimo_hash));
- component.version = base::Version("0.0");
- component.requires_network_encryption = false;
+ DCHECK_EQ(1u, ids.size());
return {component};
- }),
+ },
+ component),
true,
base::BindOnce(
[](base::OnceClosure closure, update_client::Error error) {
@@ -176,6 +184,21 @@
runloop.Run();
+ const auto& update_item = observer.crx_update_item();
+ switch (update_item.state) {
+ case update_client::ComponentState::kUpdated:
+ VLOG(1) << "Update success.";
+ break;
+ case update_client::ComponentState::kUpToDate:
+ VLOG(1) << "No updates.";
+ break;
+ case update_client::ComponentState::kUpdateError:
+ VLOG(1) << "Updater error: " << update_item.error_code << ".";
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
update_client->RemoveObserver(&observer);
update_client = nullptr;
}
diff --git a/chrome/updater/updater_constants.h b/chrome/updater/updater_constants.h
index 4b3704b..235cddd 100644
--- a/chrome/updater/updater_constants.h
+++ b/chrome/updater/updater_constants.h
@@ -31,6 +31,11 @@
extern const char kCrashUploadURL[];
extern const char kCrashStagingUploadURL[];
+// Errors.
+//
+// The install directory for the application could not be created.
+const int kCustomInstallErrorCreateAppInstallDirectory = 0;
+
} // namespace updater
#endif // CHROME_UPDATER_UPDATER_CONSTANTS_H_