| // Copyright 2023 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/handle_inconsistent_apps_task.h" |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/containers/contains.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/sequence_checker.h" |
| #include "base/strings/string_util.h" |
| #include "base/task/bind_post_task.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "base/version.h" |
| #include "chrome/updater/configurator.h" |
| #include "chrome/updater/installer.h" |
| #include "chrome/updater/persisted_data.h" |
| #include "chrome/updater/ping_configurator.h" |
| #include "chrome/updater/registration_data.h" |
| #include "chrome/updater/updater_scope.h" |
| #include "chrome/updater/util/util.h" |
| #include "components/update_client/protocol_definition.h" |
| #include "components/update_client/update_client.h" |
| #include "components/update_client/update_client_errors.h" |
| |
| namespace updater { |
| namespace { |
| |
| struct ProductInfo { |
| std::string app_id; |
| base::Version pv; |
| std::string pv_key; |
| base::FilePath pv_path; |
| }; |
| |
| std::vector<update_client::CrxComponent> MakeOverinstallPings( |
| UpdaterScope scope, |
| std::vector<ProductInfo> products) { |
| std::vector<update_client::CrxComponent> pings; |
| for (const ProductInfo& product : products) { |
| const base::Version actual_version = |
| LookupVersion(scope, product.app_id, product.pv_path, product.pv_key, |
| base::Version()); |
| if (!actual_version.IsValid()) { |
| VLOG(2) << "Failed to lookup version for " << product.app_id |
| << ". Not sending an overinstall ping."; |
| continue; |
| } else if (product.pv == actual_version) { |
| continue; |
| } |
| |
| VLOG(1) << "App " << product.app_id |
| << " has a different version than what is installed. Expected: " |
| << product.pv << ", actually installed: " << actual_version |
| << ". An install ping will be sent."; |
| |
| update_client::CrxComponent ping_data; |
| ping_data.app_id = product.app_id; |
| ping_data.version = actual_version; |
| ping_data.requires_network_encryption = false; |
| pings.push_back(ping_data); |
| } |
| return pings; |
| } |
| |
| } // namespace |
| |
| HandleInconsistentAppsTask::HandleInconsistentAppsTask( |
| scoped_refptr<Configurator> config, |
| UpdaterScope scope) |
| : config_(config), |
| scope_(scope), |
| blocking_task_runner_( |
| base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})) {} |
| |
| HandleInconsistentAppsTask::~HandleInconsistentAppsTask() = default; |
| |
| void HandleInconsistentAppsTask::Run(base::OnceClosure callback) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| FindUnregisteredApps( |
| base::BindOnce(&HandleInconsistentAppsTask::PingOverinstalledApps, |
| base::WrapRefCounted(this), std::move(callback))); |
| } |
| |
| void HandleInconsistentAppsTask::FindUnregisteredApps( |
| base::OnceClosure callback) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| MigrateLegacyUpdaters( |
| scope_, base::BindRepeating( |
| [](scoped_refptr<PersistedData> persisted_data, |
| const RegistrationRequest& req) { |
| if (!base::Contains(persisted_data->GetAppIds(), |
| base::ToLowerASCII(req.app_id))) { |
| VLOG(1) << "Registering app from legacy updater: " |
| << req.app_id; |
| persisted_data->RegisterApp(req); |
| } |
| }, |
| config_->GetUpdaterPersistedData())); |
| base::SequencedTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE, |
| std::move(callback)); |
| } |
| |
| void HandleInconsistentAppsTask::PingOverinstalledApps( |
| base::OnceClosure callback) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| scoped_refptr<PersistedData> prefs = config_->GetUpdaterPersistedData(); |
| std::vector<ProductInfo> products; |
| for (const std::string& app_id : prefs->GetAppIds()) { |
| products.push_back({.app_id = app_id, |
| .pv = prefs->GetProductVersion(app_id), |
| .pv_key = prefs->GetProductVersionKey(app_id), |
| .pv_path = prefs->GetProductVersionPath(app_id)}); |
| } |
| blocking_task_runner_->PostTaskAndReplyWithResult( |
| FROM_HERE, |
| base::BindOnce(&MakeOverinstallPings, scope_, std::move(products)), |
| base::BindOnce(&HandleInconsistentAppsTask::SendOverinstallPings, |
| base::WrapRefCounted(this), std::move(callback))); |
| } |
| |
| void HandleInconsistentAppsTask::SendOverinstallPings( |
| base::OnceClosure callback, |
| std::vector<update_client::CrxComponent> pings) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (pings.empty()) { |
| base::SequencedTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, std::move(callback)); |
| return; |
| } |
| |
| const update_client::CrxComponent ping_data = pings.back(); |
| pings.pop_back(); |
| config_->GetUpdaterPersistedData()->SetProductVersion(ping_data.app_id, |
| ping_data.version); |
| |
| blocking_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| [](const update_client::CrxComponent& ping_data, |
| base::OnceClosure callback) { |
| update_client::UpdateClientFactory(CreatePingConfigurator()) |
| ->SendPing( |
| ping_data, |
| {.event_type = |
| update_client::protocol_request::kEventInstall, |
| .result = |
| update_client::protocol_request::kEventResultSuccess}, |
| base::BindOnce([](update_client::Error error) { |
| VLOG_IF(1, error != update_client::Error::NONE) |
| << "Failed to send overinstall ping: " << error; |
| }).Then(std::move(callback))); |
| }, |
| ping_data, |
| base::BindPostTaskToCurrentDefault( |
| base::BindOnce(&HandleInconsistentAppsTask::SendOverinstallPings, |
| base::WrapRefCounted(this), std::move(callback), |
| std::move(pings))))); |
| } |
| |
| } // namespace updater |