blob: 71e9485bb332c56cfd6cf5c88f71889b1eee66ed [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// 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 <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h"
#include "base/values.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/updater/action_handler.h"
#include "chrome/updater/app/app_utils.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/usage_stats_permissions.h"
#include "chrome/updater/util/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 {
// Runs in thread pool, can block.
AppInfo MakeAppInfo(UpdaterScope scope,
const std::string& app_id,
const base::Version& pv,
const base::FilePath& pv_path,
const std::string& pv_key,
const std::string& ap,
const base::FilePath& ap_path,
const std::string& ap_key,
const std::string& lang,
const std::string& brand,
const base::FilePath& brand_path,
const std::string& brand_key,
const base::FilePath& ec_path) {
const base::Version pv_lookup =
LookupVersion(scope, app_id, pv_path, pv_key, pv);
return AppInfo(scope, app_id, LookupString(ap_path, ap_key, ap), lang,
LookupString(brand_path, brand_key, brand),
pv_lookup.IsValid() ? pv_lookup : base::Version(kNullVersion),
ec_path);
}
} // namespace
AppInfo::AppInfo(const UpdaterScope scope,
const std::string& app_id,
const std::string& ap,
const std::string& lang,
const std::string& brand,
const base::Version& app_version,
const base::FilePath& ecp)
: scope(scope),
app_id(app_id),
ap(ap),
lang(lang),
brand(brand),
version(app_version),
ecp(ecp) {}
AppInfo::AppInfo(const AppInfo&) = default;
AppInfo& AppInfo::operator=(const AppInfo&) = default;
AppInfo::~AppInfo() = default;
Installer::Installer(
const std::string& app_id,
const std::string& client_install_data,
const std::string& install_data_index,
const std::string& install_source,
const std::string& target_channel,
const std::string& target_version_prefix,
bool rollback_allowed,
std::optional<int> major_version_rollout_policy,
std::optional<int> minor_version_rollout_policy,
bool update_disabled,
UpdateService::PolicySameVersionUpdate policy_same_version_update,
scoped_refptr<PersistedData> persisted_data,
crx_file::VerifierFormat crx_verifier_format)
: updater_scope_(GetUpdaterScope()),
app_id_(app_id),
client_install_data_(client_install_data),
install_data_index_(install_data_index),
install_source_(install_source),
rollback_allowed_(rollback_allowed),
major_version_rollout_policy_(major_version_rollout_policy),
minor_version_rollout_policy_(minor_version_rollout_policy),
target_channel_(target_channel),
target_version_prefix_(target_version_prefix),
update_disabled_(update_disabled),
policy_same_version_update_(policy_same_version_update),
persisted_data_(persisted_data),
crx_verifier_format_(crx_verifier_format),
app_info_(AppInfo(GetUpdaterScope(), app_id, {}, {}, {}, {}, {})) {}
Installer::~Installer() = default;
void Installer::MakeCrxComponent(
base::OnceCallback<void(update_client::CrxComponent)> callback) {
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(
&MakeAppInfo, updater_scope_, app_id_,
persisted_data_->GetProductVersion(app_id_),
persisted_data_->GetProductVersionPath(app_id_),
persisted_data_->GetProductVersionKey(app_id_),
persisted_data_->GetAP(app_id_), persisted_data_->GetAPPath(app_id_),
persisted_data_->GetAPKey(app_id_), persisted_data_->GetLang(app_id_),
persisted_data_->GetBrandCode(app_id_),
persisted_data_->GetBrandPath(app_id_), "KSBrandID",
persisted_data_->GetExistenceCheckerPath(app_id_)),
base::BindOnce(&Installer::MakeCrxComponentFromAppInfo, this,
std::move(callback)));
}
void Installer::MakeCrxComponentFromAppInfo(
base::OnceCallback<void(update_client::CrxComponent)> callback,
const AppInfo& app_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
VLOG(1) << __func__ << " for " << app_id_;
app_info_ = app_info;
update_client::CrxComponent component;
component.installer = scoped_refptr<Installer>(this);
component.action_handler = MakeActionHandler();
component.requires_network_encryption = false;
component.crx_format_requirement = crx_verifier_format_;
component.app_id = app_id_;
// Query server for install data only when the client does not specify one.
if (client_install_data_.empty()) {
component.install_data_index = install_data_index_;
}
component.ap = app_info_.ap;
component.lang = app_info_.lang;
component.brand = app_info_.brand;
component.name = app_id_;
component.version = app_info_.version;
component.fingerprint = persisted_data_->GetFingerprint(app_id_);
component.channel = target_channel_;
component.rollback_allowed = rollback_allowed_;
component.same_version_update_allowed =
policy_same_version_update_ ==
UpdateService::PolicySameVersionUpdate::kAllowed;
component.target_version_prefix = target_version_prefix_;
component.updates_enabled = !update_disabled_;
component.install_source = install_source_;
if (major_version_rollout_policy_) {
component.installer_attributes.emplace(
"major_version_rollout_policy",
base::NumberToString(*major_version_rollout_policy_));
}
if (minor_version_rollout_policy_) {
component.installer_attributes.emplace(
"minor_version_rollout_policy",
base::NumberToString(*minor_version_rollout_policy_));
}
std::move(callback).Run(component);
}
Installer::Result Installer::InstallHelper(
const base::FilePath& unpack_path,
std::unique_ptr<InstallParams> install_params,
ProgressCallback progress_callback) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::WILL_BLOCK);
VLOG(1) << "Installing update for " << app_id_;
// Resolve the path to an installer file, which is included in the CRX, and
// specified by the |run| attribute in the manifest object of an update
// response.
if (!install_params || install_params->run.empty()) {
return Result(GOOPDATEINSTALL_E_FILENAME_INVALID,
kErrorMissingInstallParams);
}
// Assume the install params are ASCII for now.
// Upon success, when the control flow returns back to the |update_client|,
// the prefs are updated asynchronously with the new |pv| and |fingerprint|.
// The task sequencing guarantees that the prefs will be updated by the
// time another CrxDataCallback is invoked, which needs updated values.
return RunApplicationInstaller(
app_info_, unpack_path.AppendUTF8(install_params->run),
install_params->arguments,
WriteInstallerDataToTempFile(unpack_path,
client_install_data_.empty()
? install_params->server_install_data
: client_install_data_),
/*usage_stats_enabled=*/IsUpdaterOrCompanionApp(app_id_) &&
AnyAppEnablesUsageStats(GetUpdaterScope()),
kWaitForAppInstaller, std::move(progress_callback));
}
void Installer::InstallWithSyncPrimitives(
const base::FilePath& unpack_path,
std::unique_ptr<InstallParams> install_params,
ProgressCallback progress_callback,
Callback callback) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::WILL_BLOCK);
const auto result = InstallHelper(unpack_path, std::move(install_params),
std::move(progress_callback));
std::move(callback).Run(result);
}
void Installer::OnUpdateError(int error) {
LOG(ERROR) << "updater error: " << error << " for " << app_id_;
}
void Installer::Install(const base::FilePath& unpack_path,
const std::string& /*public_key*/,
std::unique_ptr<InstallParams> install_params,
ProgressCallback progress_callback,
Callback callback) {
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::WithBaseSyncPrimitives(),
base::TaskPriority::USER_BLOCKING,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&Installer::InstallWithSyncPrimitives, this, unpack_path,
std::move(install_params), std::move(progress_callback),
std::move(callback)));
}
std::optional<base::FilePath> Installer::GetInstalledFile(
const std::string& file) {
return std::nullopt;
}
bool Installer::Uninstall() {
return false;
}
} // namespace updater