#include "chrome/browser/google/google_update_win.h"
#include <objbase.h>
#include <stdint.h>
#include <string.h>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "base/numerics/safe_conversions.h"
#include "base/path_service.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/sequenced_task_runner_helpers.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/version.h"
#include "base/win/atl.h"
#include "base/win/scoped_bstr.h"
#include "base/win/win_util.h"
#include "chrome/browser/google/google_update_app_command.h"
#include "chrome/browser/google/switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/install_static/install_util.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/win/atl_module.h"
namespace {
struct UpdateCheckResult {
GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
HRESULT hresult = S_OK;
};
enum GoogleUpdateUpgradeStatus {
UPGRADE_IS_AVAILABLE = 2,
UPGRADE_SUCCESSFUL = 3,
UPGRADE_ALREADY_UP_TO_DATE = 4,
UPGRADE_ERROR = 5,
NUM_UPGRADE_STATUS
};
GoogleUpdate3ClassFactory* g_google_update_factory = nullptr;
base::SingleThreadTaskRunner* g_update_driver_task_runner = nullptr;
const int64_t kGoogleUpdatePollIntervalMs = 250;
const int kGoogleAllowedRetries = 1;
const int kGoogleRetryIntervalSeconds = 5;
const HRESULT GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY = 0x80040813;
const HRESULT GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL = 0x8004081f;
const HRESULT GOOPDATE_E_APP_USING_EXTERNAL_UPDATER = 0xA043081D;
const HRESULT GOOPDATEINSTALL_E_INSTALLER_FAILED = 0x80040902;
bool IsElevationRequiredForSystemLevelUpdates() {
const base::Version kMinGUVersionNoElevationRequired("1.3.29.1");
const base::Version current_version(
GoogleUpdateSettings::GetGoogleUpdateVersion(true));
return !current_version.IsValid() ||
current_version < kMinGUVersionNoElevationRequired;
}
GoogleUpdateErrorCode CanUpdateCurrentChrome(
const base::FilePath& chrome_exe_path,
bool system_level_install) {
DCHECK_NE(InstallUtil::IsPerUserInstall(), system_level_install);
const base::FilePath install_dir =
installer::GetInstalledDirectory(system_level_install);
return (!install_dir.empty() &&
base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
install_dir.value()))
? GOOGLE_UPDATE_NO_ERROR
: CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
}
HRESULT CoGetClassObjectAsAdmin(gfx::AcceleratedWidget hwnd,
REFCLSID class_id,
REFIID interface_id,
void** interface_ptr) {
if (!interface_ptr) {
return E_POINTER;
}
const std::wstring elevation_moniker_name =
L"Elevation:Administrator!clsid:" + base::win::WStringFromGUID(class_id);
BIND_OPTS3 bind_opts = {};
bind_opts.cbStruct = sizeof(bind_opts);
bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
bind_opts.hwnd = hwnd;
return ::CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id,
interface_ptr);
}
HRESULT CreateGoogleUpdate3WebClass(
bool system_level_install,
bool install_update_if_possible,
gfx::AcceleratedWidget elevation_window,
Microsoft::WRL::ComPtr<IGoogleUpdate3Web>* google_update) {
if (g_google_update_factory) {
return g_google_update_factory->Run(google_update);
}
const CLSID& google_update_clsid = system_level_install
? CLSID_GoogleUpdate3WebSystemClass
: CLSID_GoogleUpdate3WebUserClass;
Microsoft::WRL::ComPtr<IClassFactory> class_factory;
HRESULT hresult = S_OK;
if (!system_level_install || !install_update_if_possible ||
!IsElevationRequiredForSystemLevelUpdates()) {
hresult = ::CoGetClassObject(google_update_clsid, CLSCTX_ALL, nullptr,
IID_PPV_ARGS(&class_factory));
} else {
hresult = CoGetClassObjectAsAdmin(elevation_window, google_update_clsid,
IID_PPV_ARGS(&class_factory));
}
if (FAILED(hresult)) {
return hresult;
}
ConfigureProxyBlanket(class_factory.Get());
Microsoft::WRL::ComPtr<IUnknown> unknown;
hresult = class_factory->CreateInstance(nullptr, IID_PPV_ARGS(&unknown));
if (FAILED(hresult)) {
return hresult;
}
hresult =
unknown.CopyTo(system_level_install ? __uuidof(IGoogleUpdate3WebSystem)
: __uuidof(IGoogleUpdate3WebUser),
IID_PPV_ARGS_Helper(&(*google_update)));
return SUCCEEDED(hresult) ? hresult : unknown.As(&(*google_update));
}
std::optional<UpdateState>* GetLastUpdateStateStorage() {
static base::NoDestructor<std::optional<UpdateState>> storage;
return storage.get();
}
std::optional<UpdateCheckResult> GetSimulatedErrorForDebugging() {
const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
if (!cmd_line.HasSwitch(switches::kSimulateUpdateHresult)) {
return std::nullopt;
}
uint32_t error_from_string = 0;
std::string error_switch_value =
cmd_line.GetSwitchValueASCII(switches::kSimulateUpdateHresult);
HRESULT hresult = E_FAIL;
if (base::HexStringToUInt(error_switch_value, &error_from_string)) {
hresult = error_from_string;
}
GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_ERROR_UPDATING;
error_switch_value =
cmd_line.GetSwitchValueASCII(switches::kSimulateUpdateErrorCode);
int32_t error_code_value = 0;
if (base::StringToInt(error_switch_value, &error_code_value) &&
error_code_value >= 0 && error_code_value < NUM_ERROR_CODES) {
error_code = static_cast<GoogleUpdateErrorCode>(error_code_value);
}
return {{error_code, hresult}};
}
class UpdateCheckDriver {
public:
UpdateCheckDriver(const UpdateCheckDriver&) = delete;
UpdateCheckDriver& operator=(const UpdateCheckDriver&) = delete;
static void RunUpdateCheck(
const std::string& locale,
bool install_update_if_possible,
gfx::AcceleratedWidget elevation_window,
const base::WeakPtr<UpdateCheckDelegate>& delegate);
private:
friend class base::DeleteHelper<UpdateCheckDriver>;
UpdateCheckDriver(const std::string& locale,
bool install_update_if_possible,
gfx::AcceleratedWidget elevation_window,
const base::WeakPtr<UpdateCheckDelegate>& delegate);
~UpdateCheckDriver();
void AddDelegate(const base::WeakPtr<UpdateCheckDelegate>& delegate);
void NotifyUpgradeProgress(int progress, const std::u16string& new_version);
void BeginUpdateCheck();
UpdateCheckResult BeginUpdateCheckInternal();
void OnUpgradeError(UpdateCheckResult check_result,
std::optional<int> installer_exit_code,
const std::u16string& error_string);
bool GetCurrentState(Microsoft::WRL::ComPtr<ICurrentState>* current_state,
CurrentState* state_value,
HRESULT* hresult) const;
bool IsErrorState(const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
CurrentState state_value,
GoogleUpdateErrorCode* error_code,
HRESULT* hresult,
std::optional<int>* installer_exit_code,
std::u16string* error_string) const;
bool IsFinalState(const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
CurrentState state_value,
GoogleUpdateUpgradeStatus* upgrade_status,
std::u16string* new_version) const;
bool IsIntermediateState(
const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
CurrentState state_value,
std::u16string* new_version,
int* progress) const;
void PollGoogleUpdate();
static UpdateCheckDriver* driver_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
scoped_refptr<base::SequencedTaskRunner> result_runner_;
std::string locale_;
bool install_update_if_possible_;
gfx::AcceleratedWidget elevation_window_;
std::vector<base::WeakPtr<UpdateCheckDelegate>> delegates_;
int allowed_retries_;
bool system_level_install_;
Microsoft::WRL::ComPtr<IGoogleUpdate3Web> google_update_;
Microsoft::WRL::ComPtr<IAppBundleWeb> app_bundle_;
Microsoft::WRL::ComPtr<IAppWeb> app_;
int last_reported_progress_;
GoogleUpdateUpgradeStatus status_;
UpdateState update_state_;
std::u16string html_error_message_;
};
UpdateCheckDriver* UpdateCheckDriver::driver_ = nullptr;
void UpdateCheckDriver::RunUpdateCheck(
const std::string& locale,
bool install_update_if_possible,
gfx::AcceleratedWidget elevation_window,
const base::WeakPtr<UpdateCheckDelegate>& delegate) {
if (!driver_) {
driver_ = new UpdateCheckDriver(locale, install_update_if_possible,
elevation_window, delegate);
driver_->task_runner_->PostTask(
FROM_HERE, base::BindOnce(&UpdateCheckDriver::BeginUpdateCheck,
base::Unretained(driver_)));
} else {
driver_->AddDelegate(delegate);
}
}
UpdateCheckDriver::UpdateCheckDriver(
const std::string& locale,
bool install_update_if_possible,
gfx::AcceleratedWidget elevation_window,
const base::WeakPtr<UpdateCheckDelegate>& delegate)
: task_runner_(
g_update_driver_task_runner
? g_update_driver_task_runner
: base::ThreadPool::CreateCOMSTATaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE})),
result_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
locale_(locale),
install_update_if_possible_(install_update_if_possible),
elevation_window_(elevation_window),
delegates_(1, delegate),
allowed_retries_(kGoogleAllowedRetries),
system_level_install_(false),
last_reported_progress_(0),
status_(UPGRADE_ERROR) {}
UpdateCheckDriver::~UpdateCheckDriver() {
DCHECK(result_runner_->RunsTasksInCurrentSequence());
DCHECK_NE(status_ == UPGRADE_ERROR,
update_state_.error_code == GOOGLE_UPDATE_NO_ERROR);
*GetLastUpdateStateStorage() = update_state_;
base::UmaHistogramEnumeration("GoogleUpdate.UpgradeResult", status_,
NUM_UPGRADE_STATUS);
if (status_ == UPGRADE_ERROR) {
base::UmaHistogramEnumeration("GoogleUpdate.UpdateErrorCode",
update_state_.error_code, NUM_ERROR_CODES);
if (FAILED(update_state_.hresult)) {
base::UmaHistogramSparse("GoogleUpdate.ErrorHresult",
update_state_.hresult);
}
}
driver_ = nullptr;
for (const auto& delegate : delegates_) {
if (delegate) {
if (status_ == UPGRADE_ERROR) {
delegate->OnError(update_state_.error_code, html_error_message_,
update_state_.new_version);
} else if (install_update_if_possible_) {
delegate->OnUpgradeComplete(update_state_.new_version);
} else {
delegate->OnUpdateCheckComplete(update_state_.new_version);
}
}
}
}
void UpdateCheckDriver::AddDelegate(
const base::WeakPtr<UpdateCheckDelegate>& delegate) {
DCHECK(result_runner_->RunsTasksInCurrentSequence());
delegates_.push_back(delegate);
}
void UpdateCheckDriver::NotifyUpgradeProgress(
int progress,
const std::u16string& new_version) {
DCHECK(result_runner_->RunsTasksInCurrentSequence());
for (const auto& delegate : delegates_) {
if (delegate) {
delegate->OnUpgradeProgress(progress, new_version);
}
}
}
void UpdateCheckDriver::BeginUpdateCheck() {
UpdateCheckResult result = BeginUpdateCheckInternal();
if (SUCCEEDED(result.hresult)) {
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&UpdateCheckDriver::PollGoogleUpdate,
base::Unretained(this)));
return;
}
if (result.hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
if (allowed_retries_) {
--allowed_retries_;
task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&UpdateCheckDriver::BeginUpdateCheck,
base::Unretained(this)),
base::Seconds(kGoogleRetryIntervalSeconds));
return;
}
}
DCHECK(FAILED(result.hresult));
OnUpgradeError(result, std::nullopt, std::u16string());
result_runner_->DeleteSoon(FROM_HERE, this);
}
UpdateCheckResult UpdateCheckDriver::BeginUpdateCheckInternal() {
const auto simulated_error = GetSimulatedErrorForDebugging();
if (simulated_error.has_value()) {
return simulated_error.value();
}
HRESULT hresult = S_OK;
if (!google_update_) {
base::FilePath chrome_exe;
if (!base::PathService::Get(base::DIR_EXE, &chrome_exe)) {
NOTREACHED();
}
system_level_install_ = !InstallUtil::IsPerUserInstall();
ui::win::CreateATLModuleIfNeeded();
const GoogleUpdateErrorCode error_code =
CanUpdateCurrentChrome(chrome_exe, system_level_install_);
if (error_code != GOOGLE_UPDATE_NO_ERROR) {
return {error_code, E_FAIL};
}
hresult = CreateGoogleUpdate3WebClass(system_level_install_,
install_update_if_possible_,
elevation_window_, &google_update_);
if (FAILED(hresult)) {
return {GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, hresult};
}
ConfigureProxyBlanket(google_update_.Get());
}
constexpr GoogleUpdateErrorCode error_code =
GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
if (!app_bundle_) {
Microsoft::WRL::ComPtr<IAppBundleWeb> app_bundle;
Microsoft::WRL::ComPtr<IDispatch> dispatch;
hresult = google_update_->createAppBundleWeb(&dispatch);
if (FAILED(hresult)) {
return {error_code, hresult};
}
hresult =
dispatch.CopyTo(system_level_install_ ? __uuidof(IAppBundleWebSystem)
: __uuidof(IAppBundleWebUser),
IID_PPV_ARGS_Helper(&app_bundle));
if (FAILED(hresult)) {
hresult = dispatch.As(&app_bundle);
if (FAILED(hresult)) {
return {error_code, hresult};
}
}
dispatch.Reset();
ConfigureProxyBlanket(app_bundle.Get());
if (!locale_.empty()) {
app_bundle->put_displayLanguage(
base::win::ScopedBstr(base::UTF8ToWide(locale_)).Get());
}
hresult = app_bundle->initialize();
if (FAILED(hresult)) {
return {error_code, hresult};
}
app_bundle_.Swap(app_bundle);
}
if (!app_) {
const wchar_t* app_guid = install_static::GetAppGuid();
DCHECK(app_guid);
DCHECK(*app_guid);
Microsoft::WRL::ComPtr<IDispatch> dispatch;
hresult =
app_bundle_->createInstalledApp(base::win::ScopedBstr(app_guid).Get());
if (FAILED(hresult)) {
return {error_code, hresult};
}
Microsoft::WRL::ComPtr<IAppBundleWeb> app_bundle;
app_bundle.Swap(app_bundle_);
hresult = app_bundle->get_appWeb(0, &dispatch);
if (FAILED(hresult)) {
return {error_code, hresult};
}
Microsoft::WRL::ComPtr<IAppWeb> app;
hresult = dispatch.CopyTo(
system_level_install_ ? __uuidof(IAppWebSystem) : __uuidof(IAppWebUser),
IID_PPV_ARGS_Helper(&app));
if (FAILED(hresult)) {
hresult = dispatch.As(&app);
if (FAILED(hresult)) {
return {error_code, hresult};
}
}
ConfigureProxyBlanket(app.Get());
hresult = app_bundle->checkForUpdate();
if (FAILED(hresult)) {
return {error_code, hresult};
}
app_bundle_.Swap(app_bundle);
app_.Swap(app);
}
return {GOOGLE_UPDATE_NO_ERROR, hresult};
}
bool UpdateCheckDriver::GetCurrentState(
Microsoft::WRL::ComPtr<ICurrentState>* current_state,
CurrentState* state_value,
HRESULT* hresult) const {
Microsoft::WRL::ComPtr<IDispatch> dispatch;
*hresult = app_->get_currentState(&dispatch);
if (FAILED(*hresult)) {
return false;
}
*hresult =
dispatch.CopyTo(system_level_install_ ? __uuidof(ICurrentStateSystem)
: __uuidof(ICurrentStateUser),
IID_PPV_ARGS_Helper(&(*current_state)));
if (FAILED(*hresult)) {
*hresult = dispatch.As(&(*current_state));
if (FAILED(*hresult)) {
return false;
}
}
ConfigureProxyBlanket(current_state->Get());
LONG value = 0;
*hresult = (*current_state)->get_stateValue(&value);
if (FAILED(*hresult)) {
return false;
}
*state_value = static_cast<CurrentState>(value);
return true;
}
bool UpdateCheckDriver::IsErrorState(
const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
CurrentState state_value,
GoogleUpdateErrorCode* error_code,
HRESULT* hresult,
std::optional<int>* installer_exit_code,
std::u16string* error_string) const {
if (state_value == STATE_ERROR) {
*error_code = GOOGLE_UPDATE_ERROR_UPDATING;
installer_exit_code->reset();
LONG long_value = 0;
*hresult = current_state->get_errorCode(&long_value);
if (SUCCEEDED(*hresult)) {
*hresult = long_value;
}
LONG code = 0;
if (*hresult == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY) {
*error_code = GOOGLE_UPDATE_DISABLED_BY_POLICY;
} else if (*hresult == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL) {
*error_code = GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
} else if (*hresult == GOOPDATEINSTALL_E_INSTALLER_FAILED &&
SUCCEEDED(current_state->get_installerResultCode(&code))) {
*installer_exit_code = code;
}
base::win::ScopedBstr message;
if (SUCCEEDED(current_state->get_completionMessage(message.Receive()))) {
error_string->assign(base::as_u16cstr(message.Get()), message.Length());
}
return true;
}
if (state_value == STATE_UPDATE_AVAILABLE && install_update_if_possible_) {
*hresult = app_bundle_->install();
if (FAILED(*hresult)) {
*error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
installer_exit_code->reset();
return true;
}
}
return false;
}
bool UpdateCheckDriver::IsFinalState(
const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
CurrentState state_value,
GoogleUpdateUpgradeStatus* upgrade_status,
std::u16string* new_version) const {
if (state_value == STATE_UPDATE_AVAILABLE && !install_update_if_possible_) {
base::win::ScopedBstr version;
*upgrade_status = UPGRADE_IS_AVAILABLE;
if (SUCCEEDED(current_state->get_availableVersion(version.Receive()))) {
new_version->assign(base::as_u16cstr(version.Get()), version.Length());
}
return true;
}
if (state_value == STATE_INSTALL_COMPLETE) {
DCHECK(install_update_if_possible_);
*upgrade_status = UPGRADE_SUCCESSFUL;
return true;
}
if (state_value == STATE_NO_UPDATE) {
*upgrade_status = UPGRADE_ALREADY_UP_TO_DATE;
return true;
}
return false;
}
bool UpdateCheckDriver::IsIntermediateState(
const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
CurrentState state_value,
std::u16string* new_version,
int* progress) const {
DCHECK(state_value < STATE_UPDATE_AVAILABLE || install_update_if_possible_);
*progress = 0;
switch (state_value) {
case STATE_INIT:
case STATE_WAITING_TO_CHECK_FOR_UPDATE:
case STATE_CHECKING_FOR_UPDATE:
break;
case STATE_UPDATE_AVAILABLE: {
base::win::ScopedBstr version;
if (SUCCEEDED(current_state->get_availableVersion(version.Receive()))) {
new_version->assign(base::as_u16cstr(version.Get()), version.Length());
}
break;
}
case STATE_WAITING_TO_DOWNLOAD:
case STATE_RETRYING_DOWNLOAD:
break;
case STATE_DOWNLOADING: {
ULONG bytes_downloaded = 0;
ULONG total_bytes = 0;
if (SUCCEEDED(current_state->get_bytesDownloaded(&bytes_downloaded)) &&
SUCCEEDED(current_state->get_totalBytesToDownload(&total_bytes)) &&
total_bytes) {
*progress = base::ClampFloor((static_cast<double>(bytes_downloaded) /
static_cast<double>(total_bytes)) *
50.0);
}
break;
}
case STATE_DOWNLOAD_COMPLETE:
case STATE_EXTRACTING:
case STATE_APPLYING_DIFFERENTIAL_PATCH:
case STATE_READY_TO_INSTALL:
case STATE_WAITING_TO_INSTALL:
*progress = 50;
break;
case STATE_INSTALLING: {
*progress = 50;
LONG install_progress = 0;
if (SUCCEEDED(current_state->get_installProgress(&install_progress)) &&
install_progress >= 0 && install_progress <= 100) {
*progress = (50 + install_progress / 2);
}
break;
}
case STATE_INSTALL_COMPLETE:
case STATE_PAUSED:
case STATE_NO_UPDATE:
case STATE_ERROR:
default:
NOTREACHED();
}
return true;
}
void UpdateCheckDriver::PollGoogleUpdate() {
Microsoft::WRL::ComPtr<ICurrentState> state;
CurrentState state_value = STATE_INIT;
HRESULT hresult = S_OK;
GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
std::optional<int> installer_exit_code;
std::u16string error_string;
GoogleUpdateUpgradeStatus upgrade_status = UPGRADE_ERROR;
std::u16string new_version;
int progress = 0;
if (!GetCurrentState(&state, &state_value, &hresult)) {
OnUpgradeError({GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult},
std::nullopt, std::u16string());
} else if (IsErrorState(state, state_value, &error_code, &hresult,
&installer_exit_code, &error_string)) {
OnUpgradeError({error_code, hresult}, installer_exit_code, error_string);
} else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) {
status_ = upgrade_status;
update_state_.error_code = GOOGLE_UPDATE_NO_ERROR;
html_error_message_.clear();
if (!new_version.empty()) {
update_state_.new_version = new_version;
}
update_state_.hresult = S_OK;
update_state_.installer_exit_code.reset();
} else if (IsIntermediateState(state, state_value, &new_version, &progress)) {
bool got_new_version =
update_state_.new_version.empty() && !new_version.empty();
if (got_new_version) {
update_state_.new_version = new_version;
}
if (got_new_version || progress != last_reported_progress_) {
last_reported_progress_ = progress;
result_runner_->PostTask(
FROM_HERE,
base::BindOnce(&UpdateCheckDriver::NotifyUpgradeProgress,
base::Unretained(this), last_reported_progress_,
update_state_.new_version));
}
task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&UpdateCheckDriver::PollGoogleUpdate,
base::Unretained(this)),
base::Milliseconds(kGoogleUpdatePollIntervalMs));
return;
}
state.Reset();
app_.Reset();
app_bundle_.Reset();
google_update_.Reset();
result_runner_->DeleteSoon(FROM_HERE, this);
}
void UpdateCheckDriver::OnUpgradeError(UpdateCheckResult check_result,
std::optional<int> installer_exit_code,
const std::u16string& error_string) {
status_ = UPGRADE_ERROR;
update_state_.error_code = check_result.error_code;
update_state_.hresult = check_result.hresult;
update_state_.installer_exit_code = installer_exit_code;
if (check_result.hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
html_error_message_ =
l10n_util::GetStringUTF16(IDS_ABOUT_BOX_EXTERNAL_UPDATE_IS_RUNNING);
return;
}
std::u16string html_error_msg = base::UTF8ToUTF16(base::StringPrintf(
"%d: <a href='%s%#lX' target=_blank>%#lX</a>", update_state_.error_code,
chrome::kUpgradeHelpCenterBaseURL, update_state_.hresult,
update_state_.hresult));
if (update_state_.installer_exit_code) {
html_error_msg +=
u": " + base::NumberToString16(*update_state_.installer_exit_code);
}
if (system_level_install_) {
html_error_msg += u" -- system level";
}
if (error_string.empty()) {
html_error_message_ = l10n_util::GetStringFUTF16(
IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, html_error_msg);
} else {
html_error_message_ = l10n_util::GetStringFUTF16(
IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR, error_string, html_error_msg);
}
}
}
void BeginUpdateCheck(const std::string& locale,
bool install_update_if_possible,
gfx::AcceleratedWidget elevation_window,
const base::WeakPtr<UpdateCheckDelegate>& delegate) {
UpdateCheckDriver::RunUpdateCheck(locale, install_update_if_possible,
elevation_window, delegate);
}
UpdateState::UpdateState() = default;
UpdateState::UpdateState(const UpdateState&) = default;
UpdateState::UpdateState(UpdateState&&) = default;
UpdateState& UpdateState::operator=(UpdateState&&) = default;
UpdateState::~UpdateState() = default;
std::optional<UpdateState> GetLastUpdateState() {
return *GetLastUpdateStateStorage();
}
void SetGoogleUpdateFactoryForTesting(
GoogleUpdate3ClassFactory google_update_factory) {
if (g_google_update_factory) {
delete g_google_update_factory;
g_google_update_factory = nullptr;
}
if (!google_update_factory.is_null()) {
g_google_update_factory =
new GoogleUpdate3ClassFactory(std::move(google_update_factory));
}
}
void SetUpdateDriverTaskRunnerForTesting(
base::SingleThreadTaskRunner* task_runner) {
g_update_driver_task_runner = task_runner;
}