910e62b5创建于 1月15日历史提交
// 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_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)) &&
                        !req.app_id.empty()) {
                      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