Commit 0fbe3753 authored by Greg Thompson's avatar Greg Thompson Committed by Commit Bot

Include details of a failed on-demand update check in feedback reports.

This change adds the following four fields to feedback reports on
Windows following an on-demand update check (and to chrome://system):

- update_error_code: An int value in the GoogleUpdateErrorCode enum.
- install_location: One of ("per-machine", "per-user", "unknown")
  indicating whether the browser is installed somewhere in the ordinary
  "all users" system location (e.g., "C:\Program Files (x86)\..."), the
  ordinary user-specific location (e.g.,
  "C:\Users\USER\AppData\Local\..."), or some other unexpected location.
- update_hresult: A Windows HRESULT (hex), provided by Google Update or
  COM, in case of error.
- install_result_code: An int process exit code from the installer in
  case of error if the installer was executed.

This is made possible by the introduction of UpdateState, which holds
all state relating to an update check, and GetLastUpdateState(), which
returns said state pertaining to the most recently completed update
check.

In support of this change, the Google Update update checker now uses
base::Opional<int> (rather than a magic value of -1) for the installer
process exit code to differentiate "none provided" from any specific
value.

Bug: 985209

Change-Id: Id49c65e40c0359aed767e0404afbf07030c20e07
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1798345
Commit-Queue: Greg Thompson <grt@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#699243}
parent 6fec9cfd
...@@ -6,13 +6,19 @@ ...@@ -6,13 +6,19 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/json/json_string_value_serializer.h" #include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h" #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
...@@ -45,6 +51,9 @@ ...@@ -45,6 +51,9 @@
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/win/win_util.h" #include "base/win/win_util.h"
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
#include "chrome/browser/google/google_update_win.h"
#endif
#include "ui/base/win/hidden_window.h" #include "ui/base/win/hidden_window.h"
#endif #endif
...@@ -74,6 +83,12 @@ constexpr char kOsVersionTag[] = "OS VERSION"; ...@@ -74,6 +83,12 @@ constexpr char kOsVersionTag[] = "OS VERSION";
constexpr char kUsbKeyboardDetected[] = "usb_keyboard_detected"; constexpr char kUsbKeyboardDetected[] = "usb_keyboard_detected";
constexpr char kIsEnrolledToDomain[] = "enrolled_to_domain"; constexpr char kIsEnrolledToDomain[] = "enrolled_to_domain";
constexpr char kInstallerBrandCode[] = "installer_brand_code"; constexpr char kInstallerBrandCode[] = "installer_brand_code";
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
constexpr char kUpdateErrorCode[] = "update_error_code";
constexpr char kUpdateHresult[] = "update_hresult";
constexpr char kInstallResultCode[] = "install_result_code";
constexpr char kInstallLocation[] = "install_location";
#endif
#endif #endif
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
...@@ -192,6 +207,38 @@ void PopulateEntriesAsync(SystemLogsResponse* response) { ...@@ -192,6 +207,38 @@ void PopulateEntriesAsync(SystemLogsResponse* response) {
} }
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Returns true if the path identified by |key| with the PathService is a parent
// or ancestor of |child|.
bool IsParentOf(int key, const base::FilePath& child) {
base::FilePath path;
return base::PathService::Get(key, &path) && path.IsParent(child);
}
// Returns a string representing the overall install location of the browser.
// "Program Files" and "Program Files (x86)" are both considered "per-machine"
// locations (for all users), whereas anything in a user's local app data dir is
// considered a "per-user" location. This function returns an answer that gives,
// in essence, the broad category of location without checking that the browser
// is operating out of the exact expected install directory. It is interesting
// to know via feedback reports if updates are failing with
// CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY, which checks the exact directory,
// yet the reported install_location is not "unknown".
std::string DetermineInstallLocation() {
base::FilePath exe_path;
if (base::PathService::Get(base::FILE_EXE, &exe_path)) {
if (IsParentOf(base::DIR_PROGRAM_FILESX86, exe_path) ||
IsParentOf(base::DIR_PROGRAM_FILES, exe_path)) {
return "per-machine";
}
if (IsParentOf(base::DIR_LOCAL_APP_DATA, exe_path))
return "per-user";
}
return "unknown";
}
#endif // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
} // namespace } // namespace
ChromeInternalLogSource::ChromeInternalLogSource() ChromeInternalLogSource::ChromeInternalLogSource()
...@@ -230,6 +277,7 @@ void ChromeInternalLogSource::Fetch(SysLogsSourceCallback callback) { ...@@ -230,6 +277,7 @@ void ChromeInternalLogSource::Fetch(SysLogsSourceCallback callback) {
PopulateUsbKeyboardDetected(response.get()); PopulateUsbKeyboardDetected(response.get());
PopulateEnrolledToDomain(response.get()); PopulateEnrolledToDomain(response.get());
PopulateInstallerBrandCode(response.get()); PopulateInstallerBrandCode(response.get());
PopulateLastUpdateState(response.get());
#endif #endif
if (ProfileManager::GetLastUsedProfile()->IsChild()) if (ProfileManager::GetLastUsedProfile()->IsChild())
...@@ -410,6 +458,29 @@ void ChromeInternalLogSource::PopulateInstallerBrandCode( ...@@ -410,6 +458,29 @@ void ChromeInternalLogSource::PopulateInstallerBrandCode(
response->emplace(kInstallerBrandCode, response->emplace(kInstallerBrandCode,
brand.empty() ? "Unknown brand code" : brand); brand.empty() ? "Unknown brand code" : brand);
} }
#endif
void ChromeInternalLogSource::PopulateLastUpdateState(
SystemLogsResponse* response) {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
const base::Optional<UpdateState> update_state = GetLastUpdateState();
if (!update_state)
return; // There is nothing to include if no update check has completed.
response->emplace(kUpdateErrorCode,
base::NumberToString(update_state->error_code));
response->emplace(kInstallLocation, DetermineInstallLocation());
if (update_state->error_code == GOOGLE_UPDATE_NO_ERROR)
return; // There is nothing more to include if the last check succeeded.
response->emplace(kUpdateHresult,
base::StringPrintf("0x%08lX", update_state->hresult));
if (update_state->installer_exit_code) {
response->emplace(kInstallResultCode,
base::NumberToString(*update_state->installer_exit_code));
}
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
}
#endif // defined(OS_WIN)
} // namespace system_logs } // namespace system_logs
...@@ -38,6 +38,7 @@ class ChromeInternalLogSource : public SystemLogsSource { ...@@ -38,6 +38,7 @@ class ChromeInternalLogSource : public SystemLogsSource {
void PopulateUsbKeyboardDetected(SystemLogsResponse* response); void PopulateUsbKeyboardDetected(SystemLogsResponse* response);
void PopulateEnrolledToDomain(SystemLogsResponse* response); void PopulateEnrolledToDomain(SystemLogsResponse* response);
void PopulateInstallerBrandCode(SystemLogsResponse* response); void PopulateInstallerBrandCode(SystemLogsResponse* response);
void PopulateLastUpdateState(SystemLogsResponse* response);
#endif #endif
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -18,11 +17,13 @@ ...@@ -18,11 +17,13 @@
#include "base/location.h" #include "base/location.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/sequenced_task_runner_helpers.h" #include "base/sequenced_task_runner_helpers.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
...@@ -194,6 +195,12 @@ HRESULT CreateGoogleUpdate3WebClass( ...@@ -194,6 +195,12 @@ HRESULT CreateGoogleUpdate3WebClass(
nullptr, IID_PPV_ARGS(google_update->GetAddressOf())); nullptr, IID_PPV_ARGS(google_update->GetAddressOf()));
} }
// Returns the process-wide storage for the state of the last update check.
base::Optional<UpdateState>* GetLastUpdateStateStorage() {
static base::NoDestructor<base::Optional<UpdateState>> storage;
return storage.get();
}
// UpdateCheckDriver ----------------------------------------------------------- // UpdateCheckDriver -----------------------------------------------------------
// A driver that is created and destroyed on the caller's thread and drives // A driver that is created and destroyed on the caller's thread and drives
...@@ -239,14 +246,15 @@ class UpdateCheckDriver { ...@@ -239,14 +246,15 @@ class UpdateCheckDriver {
// steps that failed. // steps that failed.
HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code); HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code);
// Sets status_ to UPGRADE_ERROR, error_code_ to |error_code|, hresult_ to // Sets status_ to UPGRADE_ERROR, update_state_.error_code to |error_code|,
// |hresult|, installer_exit_code_ to |installer_exit_code|, and // update_state_.hresult to |hresult|, update_state_.installer_exit_code to
// html_error_message_ to a composition of all values suitable for display // |installer_exit_code|, and html_error_message_ to a composition of all
// to the user. This call should be followed by deletion of the driver, // values suitable for display to the user. This call should be followed by
// which will result in callers being notified via their delegates. // deletion of the driver, which will result in callers being notified via
// their delegates.
void OnUpgradeError(GoogleUpdateErrorCode error_code, void OnUpgradeError(GoogleUpdateErrorCode error_code,
HRESULT hresult, HRESULT hresult,
int installer_exit_code, base::Optional<int> installer_exit_code,
const base::string16& error_string); const base::string16& error_string);
// Returns true if |current_state| and |state_value| can be obtained from the // Returns true if |current_state| and |state_value| can be obtained from the
...@@ -264,14 +272,13 @@ class UpdateCheckDriver { ...@@ -264,14 +272,13 @@ class UpdateCheckDriver {
// https://code.google.com/p/omaha/source/browse/trunk/base/error.h). In case // https://code.google.com/p/omaha/source/browse/trunk/base/error.h). In case
// Chrome's installer failed during execution, |installer_exit_code| may be // Chrome's installer failed during execution, |installer_exit_code| may be
// populated with its process exit code (see enum installer::InstallStatus in // populated with its process exit code (see enum installer::InstallStatus in
// chrome/installer/util/util_constants.h); otherwise, it will be -1. // chrome/installer/util/util_constants.h). |error_string| will be populated
// |error_string| will be populated with a completion message if one is // with a completion message if one is provided by Google Update.
// provided by Google Update.
bool IsErrorState(const Microsoft::WRL::ComPtr<ICurrentState>& current_state, bool IsErrorState(const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
CurrentState state_value, CurrentState state_value,
GoogleUpdateErrorCode* error_code, GoogleUpdateErrorCode* error_code,
HRESULT* hresult, HRESULT* hresult,
int* installer_exit_code, base::Optional<int>* installer_exit_code,
base::string16* error_string) const; base::string16* error_string) const;
// Returns true if |current_state| and |state_value| constitute a final state // Returns true if |current_state| and |state_value| constitute a final state
...@@ -349,11 +356,8 @@ class UpdateCheckDriver { ...@@ -349,11 +356,8 @@ class UpdateCheckDriver {
// The results of the update check to be logged via UMA and/or reported to the // The results of the update check to be logged via UMA and/or reported to the
// caller. // caller.
GoogleUpdateUpgradeStatus status_; GoogleUpdateUpgradeStatus status_;
GoogleUpdateErrorCode error_code_; UpdateState update_state_;
base::string16 html_error_message_; base::string16 html_error_message_;
base::string16 new_version_;
HRESULT hresult_;
int installer_exit_code_;
DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver); DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
}; };
...@@ -400,25 +404,28 @@ UpdateCheckDriver::UpdateCheckDriver( ...@@ -400,25 +404,28 @@ UpdateCheckDriver::UpdateCheckDriver(
allowed_retries_(kGoogleAllowedRetries), allowed_retries_(kGoogleAllowedRetries),
system_level_install_(false), system_level_install_(false),
last_reported_progress_(0), last_reported_progress_(0),
status_(UPGRADE_ERROR), status_(UPGRADE_ERROR) {}
error_code_(GOOGLE_UPDATE_NO_ERROR),
hresult_(S_OK),
installer_exit_code_(-1) {}
UpdateCheckDriver::~UpdateCheckDriver() { UpdateCheckDriver::~UpdateCheckDriver() {
DCHECK(result_runner_->RunsTasksInCurrentSequence()); DCHECK(result_runner_->RunsTasksInCurrentSequence());
// If there is an error, then error_code must not be blank, and vice versa. // If there is an error, then error_code must not be blank, and vice versa.
DCHECK_NE(status_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR); DCHECK_NE(status_ == UPGRADE_ERROR,
update_state_.error_code == GOOGLE_UPDATE_NO_ERROR);
*GetLastUpdateStateStorage() = update_state_;
UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_, UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_,
NUM_UPGRADE_STATUS); NUM_UPGRADE_STATUS);
if (status_ == UPGRADE_ERROR) { if (status_ == UPGRADE_ERROR) {
UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_, UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode",
NUM_ERROR_CODES); update_state_.error_code, NUM_ERROR_CODES);
if (FAILED(hresult_)) if (FAILED(update_state_.hresult)) {
base::UmaHistogramSparse("GoogleUpdate.ErrorHresult", hresult_); base::UmaHistogramSparse("GoogleUpdate.ErrorHresult",
if (installer_exit_code_ != -1) { update_state_.hresult);
}
if (update_state_.installer_exit_code) {
base::UmaHistogramSparse("GoogleUpdate.InstallerExitCode", base::UmaHistogramSparse("GoogleUpdate.InstallerExitCode",
installer_exit_code_); *update_state_.installer_exit_code);
} }
} }
...@@ -429,12 +436,14 @@ UpdateCheckDriver::~UpdateCheckDriver() { ...@@ -429,12 +436,14 @@ UpdateCheckDriver::~UpdateCheckDriver() {
for (const auto& delegate : delegates_) { for (const auto& delegate : delegates_) {
if (delegate) { if (delegate) {
if (status_ == UPGRADE_ERROR) if (status_ == UPGRADE_ERROR) {
delegate->OnError(error_code_, html_error_message_, new_version_); delegate->OnError(update_state_.error_code, html_error_message_,
else if (install_update_if_possible_) update_state_.new_version);
delegate->OnUpgradeComplete(new_version_); } else if (install_update_if_possible_) {
else delegate->OnUpgradeComplete(update_state_.new_version);
delegate->OnUpdateCheckComplete(new_version_); } else {
delegate->OnUpdateCheckComplete(update_state_.new_version);
}
} }
} }
} }
...@@ -480,7 +489,7 @@ void UpdateCheckDriver::BeginUpdateCheck() { ...@@ -480,7 +489,7 @@ void UpdateCheckDriver::BeginUpdateCheck() {
} }
DCHECK(FAILED(hresult)); DCHECK(FAILED(hresult));
OnUpgradeError(error_code, hresult, -1, base::string16()); OnUpgradeError(error_code, hresult, base::nullopt, base::string16());
result_runner_->DeleteSoon(FROM_HERE, this); result_runner_->DeleteSoon(FROM_HERE, this);
} }
...@@ -609,7 +618,7 @@ bool UpdateCheckDriver::IsErrorState( ...@@ -609,7 +618,7 @@ bool UpdateCheckDriver::IsErrorState(
CurrentState state_value, CurrentState state_value,
GoogleUpdateErrorCode* error_code, GoogleUpdateErrorCode* error_code,
HRESULT* hresult, HRESULT* hresult,
int* installer_exit_code, base::Optional<int>* installer_exit_code,
base::string16* error_string) const { base::string16* error_string) const {
if (state_value == STATE_ERROR) { if (state_value == STATE_ERROR) {
// In general, errors reported by Google Update fall under this category // In general, errors reported by Google Update fall under this category
...@@ -618,7 +627,7 @@ bool UpdateCheckDriver::IsErrorState( ...@@ -618,7 +627,7 @@ bool UpdateCheckDriver::IsErrorState(
// In general, the exit code of Chrome's installer is unknown (see special // In general, the exit code of Chrome's installer is unknown (see special
// case below). // case below).
*installer_exit_code = -1; installer_exit_code->reset();
// Report the error_code provided by Google Update if possible, or the // Report the error_code provided by Google Update if possible, or the
// reason it wasn't possible otherwise. // reason it wasn't possible otherwise.
...@@ -654,7 +663,7 @@ bool UpdateCheckDriver::IsErrorState( ...@@ -654,7 +663,7 @@ bool UpdateCheckDriver::IsErrorState(
// Report a failure to start the install as a general error while trying // Report a failure to start the install as a general error while trying
// to interact with Google Update. // to interact with Google Update.
*error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
*installer_exit_code = -1; installer_exit_code->reset();
return true; return true;
} }
// Return false for handling in IsIntermediateState. // Return false for handling in IsIntermediateState.
...@@ -766,30 +775,31 @@ void UpdateCheckDriver::PollGoogleUpdate() { ...@@ -766,30 +775,31 @@ void UpdateCheckDriver::PollGoogleUpdate() {
CurrentState state_value = STATE_INIT; CurrentState state_value = STATE_INIT;
HRESULT hresult = S_OK; HRESULT hresult = S_OK;
GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR; GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
int installer_exit_code = -1; base::Optional<int> installer_exit_code;
base::string16 error_string; base::string16 error_string;
GoogleUpdateUpgradeStatus upgrade_status = UPGRADE_ERROR; GoogleUpdateUpgradeStatus upgrade_status = UPGRADE_ERROR;
base::string16 new_version; base::string16 new_version;
int progress = 0; int progress = 0;
if (!GetCurrentState(&state, &state_value, &hresult)) { if (!GetCurrentState(&state, &state_value, &hresult)) {
OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult, -1, OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult,
base::string16()); base::nullopt, base::string16());
} else if (IsErrorState(state, state_value, &error_code, &hresult, } else if (IsErrorState(state, state_value, &error_code, &hresult,
&installer_exit_code, &error_string)) { &installer_exit_code, &error_string)) {
OnUpgradeError(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)) { } else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) {
status_ = upgrade_status; status_ = upgrade_status;
error_code_ = GOOGLE_UPDATE_NO_ERROR; update_state_.error_code = GOOGLE_UPDATE_NO_ERROR;
html_error_message_.clear(); html_error_message_.clear();
if (!new_version.empty()) if (!new_version.empty())
new_version_ = new_version; update_state_.new_version = new_version;
hresult_ = S_OK; update_state_.hresult = S_OK;
installer_exit_code_ = -1; update_state_.installer_exit_code.reset();
} else if (IsIntermediateState(state, state_value, &new_version, &progress)) { } else if (IsIntermediateState(state, state_value, &new_version, &progress)) {
bool got_new_version = new_version_.empty() && !new_version.empty(); bool got_new_version =
update_state_.new_version.empty() && !new_version.empty();
if (got_new_version) if (got_new_version)
new_version_ = new_version; update_state_.new_version = new_version;
// Give the caller this status update if it differs from the last one given. // Give the caller this status update if it differs from the last one given.
if (got_new_version || progress != last_reported_progress_) { if (got_new_version || progress != last_reported_progress_) {
last_reported_progress_ = progress; last_reported_progress_ = progress;
...@@ -797,9 +807,10 @@ void UpdateCheckDriver::PollGoogleUpdate() { ...@@ -797,9 +807,10 @@ void UpdateCheckDriver::PollGoogleUpdate() {
// It is safe to post this task with an unretained pointer since the task // It is safe to post this task with an unretained pointer since the task
// is guaranteed to run before a subsequent DeleteSoon is handled. // is guaranteed to run before a subsequent DeleteSoon is handled.
result_runner_->PostTask( result_runner_->PostTask(
FROM_HERE, base::BindOnce(&UpdateCheckDriver::NotifyUpgradeProgress, FROM_HERE,
base::Unretained(this), base::BindOnce(&UpdateCheckDriver::NotifyUpgradeProgress,
last_reported_progress_, new_version_)); base::Unretained(this), last_reported_progress_,
update_state_.new_version));
} }
// Schedule the next check. // Schedule the next check.
...@@ -824,12 +835,12 @@ void UpdateCheckDriver::PollGoogleUpdate() { ...@@ -824,12 +835,12 @@ void UpdateCheckDriver::PollGoogleUpdate() {
void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
HRESULT hresult, HRESULT hresult,
int installer_exit_code, base::Optional<int> installer_exit_code,
const base::string16& error_string) { const base::string16& error_string) {
status_ = UPGRADE_ERROR; status_ = UPGRADE_ERROR;
error_code_ = error_code; update_state_.error_code = error_code;
hresult_ = hresult; update_state_.hresult = hresult;
installer_exit_code_ = installer_exit_code; update_state_.installer_exit_code = installer_exit_code;
// Some specific result codes have dedicated messages. // Some specific result codes have dedicated messages.
if (hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) { if (hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
...@@ -838,13 +849,14 @@ void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, ...@@ -838,13 +849,14 @@ void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
return; return;
} }
base::string16 html_error_msg = base::string16 html_error_msg = base::StringPrintf(
base::StringPrintf(L"%d: <a href='%ls0x%X' target=_blank>0x%X</a>", L"%d: <a href='%ls0x%X' target=_blank>0x%X</a>", update_state_.error_code,
error_code_, base::UTF8ToUTF16( base::UTF8ToUTF16(chrome::kUpgradeHelpCenterBaseURL).c_str(),
chrome::kUpgradeHelpCenterBaseURL).c_str(), update_state_.hresult, update_state_.hresult);
hresult_, hresult_); if (update_state_.installer_exit_code) {
if (installer_exit_code_ != -1) html_error_msg +=
html_error_msg += base::StringPrintf(L": %d", installer_exit_code_); L": " + base::NumberToString16(*update_state_.installer_exit_code);
}
if (system_level_install_) if (system_level_install_)
html_error_msg += L" -- system level"; html_error_msg += L" -- system level";
if (error_string.empty()) { if (error_string.empty()) {
...@@ -870,6 +882,17 @@ void BeginUpdateCheck( ...@@ -870,6 +882,17 @@ void BeginUpdateCheck(
elevation_window, delegate); elevation_window, delegate);
} }
// UpdateState -----------------------------------------------------------------
UpdateState::UpdateState() = default;
UpdateState::UpdateState(const UpdateState&) = default;
UpdateState::UpdateState(UpdateState&&) = default;
UpdateState& UpdateState::operator=(UpdateState&&) = default;
UpdateState::~UpdateState() = default;
base::Optional<UpdateState> GetLastUpdateState() {
return *GetLastUpdateStateStorage();
}
// Private API exposed for testing. -------------------------------------------- // Private API exposed for testing. --------------------------------------------
......
...@@ -7,9 +7,12 @@ ...@@ -7,9 +7,12 @@
#include <wrl/client.h> #include <wrl/client.h>
#include <string>
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "google_update/google_update_idl.h" #include "google_update/google_update_idl.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
...@@ -100,6 +103,34 @@ void BeginUpdateCheck( ...@@ -100,6 +103,34 @@ void BeginUpdateCheck(
gfx::AcceleratedWidget elevation_window, gfx::AcceleratedWidget elevation_window,
const base::WeakPtr<UpdateCheckDelegate>& delegate); const base::WeakPtr<UpdateCheckDelegate>& delegate);
// The state from a completed update check.
struct UpdateState {
UpdateState();
UpdateState(const UpdateState&);
UpdateState(UpdateState&&);
UpdateState& operator=(UpdateState&&);
~UpdateState();
// GOOGLE_UPDATE_NO_ERROR if the last check or update succeeded; otherwise,
// the nature of the failure.
GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
// The next version available or an empty string if either no update is
// available or an error occurred before the new version was discovered.
base::string16 new_version;
// S_OK if the last check or update succeeded; otherwise, the failing error
// from Google Update or COM.
HRESULT hresult = S_OK;
// If present, the process exit code from the failed run of the installer.
base::Optional<int> installer_exit_code;
};
// Returns the state from the most recent completed update check or no value if
// no such check has taken place.
base::Optional<UpdateState> GetLastUpdateState();
// A type of callback supplied by tests to provide a custom IGoogleUpdate3Web // A type of callback supplied by tests to provide a custom IGoogleUpdate3Web
// implementation (see src/google_update/google_update_idl.idl). // implementation (see src/google_update/google_update_idl.idl).
typedef base::Callback<HRESULT(Microsoft::WRL::ComPtr<IGoogleUpdate3Web>*)> typedef base::Callback<HRESULT(Microsoft::WRL::ComPtr<IGoogleUpdate3Web>*)>
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <wrl/client.h> #include <wrl/client.h>
#include <memory> #include <memory>
#include <string>
#include "base/base_paths.h" #include "base/base_paths.h"
#include "base/bind.h" #include "base/bind.h"
...@@ -684,6 +685,9 @@ TEST_P(GoogleUpdateWinTest, InvalidInstallDirectory) { ...@@ -684,6 +685,9 @@ TEST_P(GoogleUpdateWinTest, InvalidInstallDirectory) {
BeginUpdateCheck(std::string(), false, 0, BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code,
CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY);
} }
// Test the case where the GoogleUpdate class can't be created for an update // Test the case where the GoogleUpdate class can't be created for an update
...@@ -698,6 +702,9 @@ TEST_P(GoogleUpdateWinTest, NoGoogleUpdateForCheck) { ...@@ -698,6 +702,9 @@ TEST_P(GoogleUpdateWinTest, NoGoogleUpdateForCheck) {
BeginUpdateCheck(std::string(), false, 0, BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code,
GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND);
} }
// Test the case where the GoogleUpdate class can't be created for an upgrade. // Test the case where the GoogleUpdate class can't be created for an upgrade.
...@@ -711,6 +718,9 @@ TEST_P(GoogleUpdateWinTest, NoGoogleUpdateForUpgrade) { ...@@ -711,6 +718,9 @@ TEST_P(GoogleUpdateWinTest, NoGoogleUpdateForUpgrade) {
BeginUpdateCheck(std::string(), true, 0, BeginUpdateCheck(std::string(), true, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code,
GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND);
} }
// Test the case where the GoogleUpdate class returns an error when an update // Test the case where the GoogleUpdate class returns an error when an update
...@@ -728,6 +738,10 @@ TEST_P(GoogleUpdateWinTest, FailUpdateCheck) { ...@@ -728,6 +738,10 @@ TEST_P(GoogleUpdateWinTest, FailUpdateCheck) {
BeginUpdateCheck(std::string(), false, 0, BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code,
GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR);
EXPECT_EQ(GetLastUpdateState()->hresult, E_FAIL);
} }
// Test the case where the GoogleUpdate class reports that updates are disabled // Test the case where the GoogleUpdate class reports that updates are disabled
...@@ -753,6 +767,8 @@ TEST_P(GoogleUpdateWinTest, UpdatesDisabledByPolicy) { ...@@ -753,6 +767,8 @@ TEST_P(GoogleUpdateWinTest, UpdatesDisabledByPolicy) {
BeginUpdateCheck(std::string(), false, 0, BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_DISABLED_BY_POLICY);
} }
// Test the case where the GoogleUpdate class reports that manual updates are // Test the case where the GoogleUpdate class reports that manual updates are
...@@ -779,6 +795,9 @@ TEST_P(GoogleUpdateWinTest, ManualUpdatesDisabledByPolicy) { ...@@ -779,6 +795,9 @@ TEST_P(GoogleUpdateWinTest, ManualUpdatesDisabledByPolicy) {
BeginUpdateCheck(std::string(), false, 0, BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code,
GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY);
} }
// Test an update check where no update is available. // Test an update check where no update is available.
...@@ -800,6 +819,9 @@ TEST_P(GoogleUpdateWinTest, UpdateCheckNoUpdate) { ...@@ -800,6 +819,9 @@ TEST_P(GoogleUpdateWinTest, UpdateCheckNoUpdate) {
BeginUpdateCheck(std::string(), false, 0, BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
EXPECT_EQ(GetLastUpdateState()->new_version, STRING16_LITERAL(""));
} }
// Test an update check where an update is available. // Test an update check where an update is available.
...@@ -821,6 +843,9 @@ TEST_P(GoogleUpdateWinTest, UpdateCheckUpdateAvailable) { ...@@ -821,6 +843,9 @@ TEST_P(GoogleUpdateWinTest, UpdateCheckUpdateAvailable) {
BeginUpdateCheck(std::string(), false, 0, BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
} }
// Test a successful upgrade. // Test a successful upgrade.
...@@ -866,6 +891,9 @@ TEST_P(GoogleUpdateWinTest, UpdateInstalled) { ...@@ -866,6 +891,9 @@ TEST_P(GoogleUpdateWinTest, UpdateInstalled) {
BeginUpdateCheck(std::string(), true, 0, BeginUpdateCheck(std::string(), true, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
} }
// Test a failed upgrade where Google Update reports that the installer failed. // Test a failed upgrade where Google Update reports that the installer failed.
...@@ -917,6 +945,12 @@ TEST_P(GoogleUpdateWinTest, UpdateFailed) { ...@@ -917,6 +945,12 @@ TEST_P(GoogleUpdateWinTest, UpdateFailed) {
BeginUpdateCheck(std::string(), true, 0, BeginUpdateCheck(std::string(), true, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_ERROR_UPDATING);
EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
EXPECT_EQ(GetLastUpdateState()->hresult, GOOPDATEINSTALL_E_INSTALLER_FAILED);
ASSERT_TRUE(GetLastUpdateState()->installer_exit_code);
EXPECT_EQ(GetLastUpdateState()->installer_exit_code.value(), kInstallerError);
} }
// Test that a retry after a USING_EXTERNAL_UPDATER failure succeeds. // Test that a retry after a USING_EXTERNAL_UPDATER failure succeeds.
...@@ -958,6 +992,9 @@ TEST_P(GoogleUpdateWinTest, RetryAfterExternalUpdaterError) { ...@@ -958,6 +992,9 @@ TEST_P(GoogleUpdateWinTest, RetryAfterExternalUpdaterError) {
BeginUpdateCheck(std::string(), false, 0, BeginUpdateCheck(std::string(), false, 0,
mock_update_check_delegate_.AsWeakPtr()); mock_update_check_delegate_.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
EXPECT_EQ(GetLastUpdateState()->new_version, STRING16_LITERAL(""));
} }
TEST_P(GoogleUpdateWinTest, UpdateInstalledMultipleDelegates) { TEST_P(GoogleUpdateWinTest, UpdateInstalledMultipleDelegates) {
...@@ -1020,6 +1057,9 @@ TEST_P(GoogleUpdateWinTest, UpdateInstalledMultipleDelegates) { ...@@ -1020,6 +1057,9 @@ TEST_P(GoogleUpdateWinTest, UpdateInstalledMultipleDelegates) {
BeginUpdateCheck(std::string(), true, 0, BeginUpdateCheck(std::string(), true, 0,
mock_update_check_delegate_2.AsWeakPtr()); mock_update_check_delegate_2.AsWeakPtr());
task_runner_->RunUntilIdle(); task_runner_->RunUntilIdle();
ASSERT_TRUE(GetLastUpdateState());
EXPECT_EQ(GetLastUpdateState()->error_code, GOOGLE_UPDATE_NO_ERROR);
EXPECT_EQ(GetLastUpdateState()->new_version, new_version_);
} }
INSTANTIATE_TEST_SUITE_P(UserLevel, GoogleUpdateWinTest, Values(false)); INSTANTIATE_TEST_SUITE_P(UserLevel, GoogleUpdateWinTest, Values(false));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment