chromium/chrome/updater/update_service_impl_impl.cc

// Copyright 2020 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/update_service_impl_impl.h"

#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/barrier_callback.h"
#include "base/barrier_closure.h"
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/debug/alias.h"
#include "base/debug/dump_without_crashing.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/updater/auto_run_on_os_upgrade_task.h"
#include "chrome/updater/change_owners_task.h"
#include "chrome/updater/check_for_updates_task.h"
#include "chrome/updater/cleanup_task.h"
#include "chrome/updater/configurator.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/find_unregistered_apps_task.h"
#include "chrome/updater/installer.h"
#include "chrome/updater/persisted_data.h"
#include "chrome/updater/policy/service.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/registration_data.h"
#include "chrome/updater/remove_uninstalled_apps_task.h"
#include "chrome/updater/update_block_check.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/update_usage_stats_task.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util/util.h"
#include "components/prefs/pref_service.h"
#include "components/update_client/crx_update_item.h"
#include "components/update_client/protocol_definition.h"
#include "components/update_client/update_client.h"
#include "components/update_client/update_client_errors.h"

#if BUILDFLAG(IS_MAC)
#include <sys/mount.h>
#endif  // BUILDFLAG(IS_MAC)

#if BUILDFLAG(IS_WIN)
#include <winhttp.h>

#include "base/win/registry.h"
#include "chrome/updater/util/win_util.h"
#include "chrome/updater/win/ui/l10n_util.h"
#include "chrome/updater/win/ui/resources/resources.grh"
#include "chrome/updater/win/ui/resources/updater_installer_strings.h"
#include "chrome/updater/win/win_constants.h"
#endif  // BUILDFLAG(IS_WIN)

namespace updater {

// The functions below are various adaptors between |update_client| and
// |UpdateService| types.

namespace internal {
UpdateService::Result ToResult(update_client::Error error) {}

void GetComponents(
    scoped_refptr<PolicyService> policy_service,
    crx_file::VerifierFormat verifier_format,
    scoped_refptr<PersistedData> persisted_data,
    const base::flat_map<std::string, std::string>& app_client_install_data,
    const base::flat_map<std::string, std::string>& app_install_data_index,
    const std::string& install_source,
    UpdateService::Priority priority,
    bool update_blocked,
    UpdateService::PolicySameVersionUpdate policy_same_version_update,
    const std::vector<std::string>& ids,
    base::OnceCallback<
        void(const std::vector<std::optional<update_client::CrxComponent>>&)>
        callback) {}

#if BUILDFLAG(IS_WIN)
namespace {

std::wstring GetTextForUpdateClientInstallError(int error_code) {
#define INSTALL_SWITCH_ENTRY

  switch (error_code) {
    INSTALL_SWITCH_ENTRY(update_client::InstallError::NONE);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::FINGERPRINT_WRITE_FAILED);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::BAD_MANIFEST);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::GENERIC_ERROR);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::MOVE_FILES_ERROR);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::SET_PERMISSIONS_FAILED);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::INVALID_VERSION);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::VERSION_NOT_UPGRADED);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::NO_DIR_COMPONENT_USER);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::CLEAN_INSTALL_DIR_FAILED);
    INSTALL_SWITCH_ENTRY(
        update_client::InstallError::INSTALL_VERIFICATION_FAILED);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::MISSING_INSTALL_PARAMS);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::LAUNCH_PROCESS_FAILED);
    INSTALL_SWITCH_ENTRY(update_client::InstallError::CUSTOM_ERROR_BASE);
    default:
      return GetLocalizedStringF(IDS_GENERIC_INSTALL_ERROR_BASE,
                                 GetTextForSystemError(error_code));
  }
#undef INSTALL_SWITCH_ENTRY
}

std::wstring GetTextForDownloadError(int error) {
#define DOWNLOAD_SWITCH_ENTRY

  switch (error) {
    DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::NO_URL);
    DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::NO_HASH);
    DOWNLOAD_SWITCH_ENTRY(
        update_client::CrxDownloaderError::BITS_TOO_MANY_JOBS);
    DOWNLOAD_SWITCH_ENTRY(update_client::CrxDownloaderError::GENERIC_ERROR);

    case static_cast<int>(update_client::CrxDownloaderError::BAD_HASH):
      return GetLocalizedString(IDS_DOWNLOAD_HASH_MISMATCH_BASE);

    default:
      return GetLocalizedStringF(IDS_GENERIC_DOWNLOAD_ERROR_BASE,
                                 GetTextForSystemError(error));
  }
#undef DOWNLOAD_SWITCH_ENTRY
}

std::wstring GetTextForUnpackError(int error) {
#define UNPACK_SWITCH_ENTRY
#define UNPACK_CACHING_SWITCH_ENTRY

  switch (error) {
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kInvalidParams);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kInvalidFile);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kUnzipPathError);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kUnzipFailed);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kBadManifest);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kBadExtension);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kIoError);
    UNPACK_SWITCH_ENTRY(
        update_client::UnpackerError::kDeltaVerificationFailure);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaBadCommands);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaUnsupportedCommand);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kDeltaOperationFailure);
    UNPACK_SWITCH_ENTRY(
        update_client::UnpackerError::kDeltaPatchProcessFailure);
    UNPACK_SWITCH_ENTRY(
        update_client::UnpackerError::kDeltaMissingExistingFile);
    UNPACK_SWITCH_ENTRY(
        update_client::UnpackerError::kPuffinMissingPreviousCrx);
    UNPACK_SWITCH_ENTRY(update_client::UnpackerError::kCrxCacheNotProvided);

    UNPACK_CACHING_SWITCH_ENTRY(
        update_client::UnpackerError::kFailedToAddToCache);
    UNPACK_CACHING_SWITCH_ENTRY(
        update_client::UnpackerError::kFailedToCreateCacheDir);

    default:
      return GetLocalizedStringF(IDS_GENERIC_UNPACK_ERROR_BASE,
                                 GetTextForSystemError(error));
  }
#undef UNPACK_SWITCH_ENTRY
#undef UNPACK_CACHING_SWITCH_ENTRY
}

std::wstring GetTextForServiceError(int error) {
#define SERVICE_SWITCH_ENTRY

  switch (error) {
    SERVICE_SWITCH_ENTRY(update_client::ServiceError::SERVICE_WAIT_FAILED);
    SERVICE_SWITCH_ENTRY(update_client::ServiceError::UPDATE_DISABLED);
    SERVICE_SWITCH_ENTRY(update_client::ServiceError::CHECK_FOR_UPDATE_ONLY);

    case static_cast<int>(update_client::ServiceError::CANCELLED):
      return GetLocalizedString(IDS_SERVICE_ERROR_CANCELLED_BASE);

    default:
      return GetLocalizedStringF(IDS_GENERIC_SERVICE_ERROR_BASE,
                                 GetTextForSystemError(error));
  }
#undef SERVICE_SWITCH_ENTRY
}

std::wstring GetTextForUpdateCheckError(int error) {
#define UPDATE_CHECK_SWITCH_ENTRY

  switch (error) {
    UPDATE_CHECK_SWITCH_ENTRY(
        update_client::ProtocolError::RESPONSE_NOT_TRUSTED);
    UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::MISSING_PUBLIC_KEY);
    UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::MISSING_URLS);
    UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::PARSE_FAILED);
    UPDATE_CHECK_SWITCH_ENTRY(
        update_client::ProtocolError::UPDATE_RESPONSE_NOT_FOUND);
    UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::URL_FETCHER_FAILED);
    UPDATE_CHECK_SWITCH_ENTRY(update_client::ProtocolError::INVALID_APPID);

    case static_cast<int>(update_client::ProtocolError::UNKNOWN_APPLICATION):
      return GetLocalizedString(IDS_UNKNOWN_APPLICATION_BASE);

    case static_cast<int>(update_client::ProtocolError::RESTRICTED_APPLICATION):
      return GetLocalizedString(IDS_RESTRICTED_RESPONSE_FROM_SERVER_BASE);

    case static_cast<int>(update_client::ProtocolError::OS_NOT_SUPPORTED):
      return GetLocalizedString(IDS_OS_NOT_SUPPORTED_BASE);

    case static_cast<int>(update_client::ProtocolError::HW_NOT_SUPPORTED):
      return GetLocalizedString(IDS_HW_NOT_SUPPORTED_BASE);

    case static_cast<int>(update_client::ProtocolError::NO_HASH):
      return GetLocalizedString(IDS_NO_HASH_BASE);

    case static_cast<int>(update_client::ProtocolError::UNSUPPORTED_PROTOCOL):
      return GetLocalizedString(IDS_UNSUPPORTED_PROTOCOL_BASE);

    case static_cast<int>(update_client::ProtocolError::INTERNAL):
      return GetLocalizedString(IDS_INTERNAL_BASE);

    // Http Status Code `401` Unauthorized.
    case 401:
      return GetLocalizedString(IDS_ERROR_HTTPSTATUS_UNAUTHORIZED_BASE);

    // Http Status Code `403` Forbidden.
    case 403:
      return GetLocalizedString(IDS_ERROR_HTTPSTATUS_FORBIDDEN_BASE);

    // Http Status Code `407` Proxy Authentication Required.
    case 407:
      return GetLocalizedString(IDS_ERROR_HTTPSTATUS_PROXY_AUTH_REQUIRED_BASE);

    case HRESULT_FROM_WIN32(ERROR_WINHTTP_NAME_NOT_RESOLVED):
      return GetLocalizedStringF(IDS_NO_NETWORK_PRESENT_ERROR_BASE,
                                 GetExecutableRelativePath().value());
    default:
      return GetLocalizedStringF(
          IDS_GENERIC_UPDATE_CHECK_ERROR_BASE,
          error >= 400 && error < 600
              ? base::UTF8ToWide(base::StringPrintf("HTTP %d", error))
              : GetTextForSystemError(error));
  }
#undef UPDATE_CHECK_SWITCH_ENTRY
}

std::wstring GetTextForInstallerError(int error_code) {
#define POLICY_ERROR_SWITCH_ENTRY

  switch (error_code) {
    POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY);
    POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY);
    POLICY_ERROR_SWITCH_ENTRY(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL);

    case GOOPDATEINSTALL_E_FILENAME_INVALID:
      return GetLocalizedString(IDS_INVALID_INSTALLER_FILENAME_BASE);

    case GOOPDATEINSTALL_E_INSTALLER_FAILED_START:
      return GetLocalizedString(IDS_INSTALLER_FAILED_TO_START_BASE);

    case GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT:
      return GetLocalizedString(IDS_INSTALLER_TIMED_OUT_BASE);

    case GOOPDATEINSTALL_E_INSTALL_ALREADY_RUNNING:
      return GetLocalizedStringF(
          IDS_GENERIC_INSTALLER_ERROR_BASE,
          GetTextForSystemError(ERROR_INSTALL_ALREADY_RUNNING));

    case ERROR_SUCCESS_REBOOT_INITIATED:
    case ERROR_SUCCESS_REBOOT_REQUIRED:
    case ERROR_SUCCESS_RESTART_REQUIRED:
      return GetLocalizedStringF(IDS_INSTALL_REBOOT_BASE,
                                 GetTextForSystemError(error_code));

    default:
      return GetLocalizedStringF(IDS_GENERIC_INSTALLER_ERROR_BASE,
                                 GetTextForSystemError(error_code));
  }
#undef POLICY_ERROR_SWITCH_ENTRY
}

}  // namespace

std::string GetInstallerText(UpdateService::ErrorCategory error_category,
                             int error_code,
                             int extra_code) {
  if (!error_code) {
    return {};
  }
  return base::WideToUTF8(base::StrCat(
      {[&] {
         switch (error_category) {
           case UpdateService::ErrorCategory::kInstall:
             return GetTextForUpdateClientInstallError(error_code);
           case UpdateService::ErrorCategory::kDownload:
             return GetTextForDownloadError(error_code);
           case UpdateService::ErrorCategory::kUnpack:
             return GetTextForUnpackError(error_code);
           case UpdateService::ErrorCategory::kService:
             return GetTextForServiceError(error_code);
           case UpdateService::ErrorCategory::kUpdateCheck:
             return GetTextForUpdateCheckError(error_code);
           case UpdateService::ErrorCategory::kInstaller:
             return GetTextForInstallerError(error_code);
           default:
             LOG(ERROR) << "Unknown error category: " << error_category;
             return std::wstring();
         }
       }(),
       [&] {
         if (!extra_code) {
           return std::wstring();
         }
         return base::StrCat(
             {L"\n", GetLocalizedStringF(IDS_EXTRA_CODE_BASE,
                                         base::ASCIIToWide(base::StringPrintf(
                                             "%#x", extra_code)))});
       }()}));
}
#endif  // BUILDFLAG(IS_WIN)

base::Version GetRegisteredInstallerVersion(const std::string& app_id) {}

}  // namespace internal

namespace {

constexpr base::flat_map<std::string, std::string> kEmptyFlatMap;

update_client::Callback MakeUpdateClientCallback(
    base::OnceCallback<void(UpdateService::Result)> callback) {}

UpdateService::UpdateState::State ToUpdateState(
    update_client::ComponentState component_state) {}

UpdateService::ErrorCategory ToErrorCategory(
    update_client::ErrorCategory error_category) {}

update_client::UpdateClient::CrxStateChangeCallback
MakeUpdateClientCrxStateChangeCallback(
    scoped_refptr<update_client::Configurator> config,
    scoped_refptr<PersistedData> persisted_data,
    const bool new_install,
    base::RepeatingCallback<void(const UpdateService::UpdateState&)> callback) {}

bool IsPathOnReadOnlyMount(const base::FilePath& path) {}

}  // namespace

UpdateServiceImplImpl::UpdateServiceImplImpl(scoped_refptr<Configurator> config)
    :{}

void UpdateServiceImplImpl::GetVersion(
    base::OnceCallback<void(const base::Version&)> callback) {}

void UpdateServiceImplImpl::FetchPolicies(
    base::OnceCallback<void(int)> callback) {}

void UpdateServiceImplImpl::RegisterApp(
    const RegistrationRequest& request,
    base::OnceCallback<void(int)> callback) {}

void UpdateServiceImplImpl::GetAppStates(
    base::OnceCallback<void(const std::vector<AppState>&)> callback) {}

void UpdateServiceImplImpl::RunPeriodicTasks(base::OnceClosure callback) {}

void UpdateServiceImplImpl::TaskStart() {}

void UpdateServiceImplImpl::TaskDone() {}

void UpdateServiceImplImpl::ForceInstall(
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback) {}

void UpdateServiceImplImpl::CheckForUpdate(
    const std::string& app_id,
    Priority priority,
    PolicySameVersionUpdate policy_same_version_update,
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback) {}

void UpdateServiceImplImpl::Update(
    const std::string& app_id,
    const std::string& install_data_index,
    Priority priority,
    PolicySameVersionUpdate policy_same_version_update,
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback) {}

void UpdateServiceImplImpl::UpdateAll(
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback) {}

void UpdateServiceImplImpl::Install(
    const RegistrationRequest& registration,
    const std::string& client_install_data,
    const std::string& install_data_index,
    Priority priority,
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback) {}

void UpdateServiceImplImpl::CancelInstalls(const std::string& app_id) {}

void UpdateServiceImplImpl::RunInstaller(
    const std::string& app_id,
    const base::FilePath& installer_path,
    const std::string& install_args,
    const std::string& install_data,
    const std::string& install_settings,
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback) {}

bool UpdateServiceImplImpl::IsUpdateDisabledByPolicy(const std::string& app_id,
                                                     Priority priority,
                                                     bool is_install,
                                                     int& policy) {}

void UpdateServiceImplImpl::HandleUpdateDisabledByPolicy(
    const std::string& app_id,
    int policy,
    bool is_install,
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback) {}

void UpdateServiceImplImpl::OnShouldBlockCheckForUpdateForMeteredNetwork(
    const std::string& app_id,
    Priority priority,
    PolicySameVersionUpdate policy_same_version_update,
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback,
    bool update_blocked) {}

void UpdateServiceImplImpl::OnShouldBlockUpdateForMeteredNetwork(
    const std::vector<std::string>& app_ids,
    const base::flat_map<std::string, std::string>& app_client_install_data,
    const base::flat_map<std::string, std::string>& app_install_data_index,
    Priority priority,
    PolicySameVersionUpdate policy_same_version_update,
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback,
    bool update_blocked) {}

void UpdateServiceImplImpl::OnShouldBlockForceInstallForMeteredNetwork(
    const std::vector<std::string>& app_ids,
    const base::flat_map<std::string, std::string>& app_client_install_data,
    const base::flat_map<std::string, std::string>& app_install_data_index,
    PolicySameVersionUpdate policy_same_version_update,
    base::RepeatingCallback<void(const UpdateState&)> state_update,
    base::OnceCallback<void(Result)> callback,
    bool update_blocked) {}

UpdateServiceImplImpl::~UpdateServiceImplImpl() {}

}  // namespace updater