Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(991)

Unified Diff: chrome/browser/google/google_update_win.cc

Issue 1117263002: Switch on-demand update checks to the less-old GoogleUpdate3 API. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: sync to position 329622 Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/google/google_update_win.cc
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index 1e0d1b9c18b4b0b7ff7fbe10602f972a4754041a..a913c02fc63ac986afe6e5dbe47e705e95dfb37a 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -14,34 +14,64 @@
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "base/path_service.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/task_runner.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/win/scoped_bstr.h"
#include "base/win/windows_version.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
-#include "content/public/browser/browser_thread.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/win/atl_module.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
namespace {
-OnDemandAppsClassFactory* g_google_update_factory = nullptr;
+// The status of the upgrade. These values are used for a histogram. Do not
+// reorder.
+enum GoogleUpdateUpgradeStatus {
+ // The upgrade has started. DEPRECATED.
+ // UPGRADE_STARTED = 0,
+ // A check for upgrade has been initiated. DEPRECATED.
+ // UPGRADE_CHECK_STARTED = 1,
+ // An update is available.
+ UPGRADE_IS_AVAILABLE = 2,
+ // The upgrade happened successfully.
+ UPGRADE_SUCCESSFUL = 3,
+ // No need to upgrade, Chrome is up to date.
+ UPGRADE_ALREADY_UP_TO_DATE = 4,
+ // An error occurred.
+ UPGRADE_ERROR = 5,
+ NUM_UPGRADE_STATUS
+};
+
+GoogleUpdate3ClassFactory* g_google_update_factory = nullptr;
+
+// The time interval, in milliseconds, between polls to Google Update. This
+// value was chosen unscientificaly during an informal discussion.
+const int64_t kGoogleUpdatePollIntervalMs = 250;
+
+// Constants from Google Update.
+const HRESULT GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY = 0x80040813;
+const HRESULT GOOPDATEINSTALL_E_INSTALLER_FAILED = 0x80040902;
// Check if the currently running instance can be updated by Google Update.
// Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
// Chrome distribution installed in a standard location.
GoogleUpdateErrorCode CanUpdateCurrentChrome(
const base::FilePath& chrome_exe_path,
- bool system_level) {
+ bool system_level_install) {
#if !defined(GOOGLE_CHROME_BUILD)
return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
#else
- DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path), system_level);
+ DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path),
+ system_level_install);
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
@@ -52,18 +82,6 @@ GoogleUpdateErrorCode CanUpdateCurrentChrome(
return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
}
- base::string16 app_guid = installer::GetAppGuidForUpdates(system_level);
- DCHECK(!app_guid.empty());
-
- GoogleUpdateSettings::UpdatePolicy update_policy =
- GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL);
-
- if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED)
- return GOOGLE_UPDATE_DISABLED_BY_POLICY;
-
- if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY)
- return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
-
return GOOGLE_UPDATE_NO_ERROR;
#endif
}
@@ -107,389 +125,582 @@ HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id,
interface_ptr);
}
-HRESULT CreateOnDemandAppsClass(
- bool system_level,
- bool install_if_newer,
+HRESULT CreateGoogleUpdate3WebClass(
+ bool system_level_install,
+ bool install_update_if_possible,
gfx::AcceleratedWidget elevation_window,
- base::win::ScopedComPtr<IGoogleUpdate>* on_demand) {
+ base::win::ScopedComPtr<IGoogleUpdate3Web>* google_update) {
if (g_google_update_factory)
- return g_google_update_factory->Run(on_demand);
+ return g_google_update_factory->Run(google_update);
// For a user-level install, update checks and updates can both be done by a
- // normal user with the UserAppsClass.
- if (!system_level)
- return on_demand->CreateInstance(CLSID_OnDemandUserAppsClass);
+ // normal user with the UserClass.
+ if (!system_level_install)
+ return google_update->CreateInstance(CLSID_GoogleUpdate3WebUserClass);
// For a system-level install, update checks can be done by a normal user with
- // the MachineAppsClass.
- if (!install_if_newer)
- return on_demand->CreateInstance(CLSID_OnDemandMachineAppsClass);
+ // the ServiceClass.
S. Ganesh 2015/05/13 20:21:40 MachineClass
grt (UTC plus 2) 2015/05/13 20:36:38 Nice catch. Will take care of in a follow-on CL.
+ if (!install_update_if_possible)
+ return google_update->CreateInstance(CLSID_GoogleUpdate3WebMachineClass);
// For a system-level install, an update requires Admin privileges for writing
- // to %ProgramFiles%. Elevate while instantiating the MachineAppsClass.
- return CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
- IID_IGoogleUpdate, elevation_window,
- on_demand->ReceiveVoid());
-}
-
-
-// GoogleUpdateJobObserver -----------------------------------------------------
-
-// The GoogleUpdateJobObserver COM class is responsible for receiving status
-// reports from google Update. It keeps track of the progress as Google Update
-// notifies this observer and runs a completion callback once Google Update
-// reports that it is done.
-class GoogleUpdateJobObserver : public CComObjectRootEx<CComSingleThreadModel>,
- public IJobObserver {
- public:
- BEGIN_COM_MAP(GoogleUpdateJobObserver)
- COM_INTERFACE_ENTRY(IJobObserver)
- END_COM_MAP()
-
- GoogleUpdateJobObserver();
- virtual ~GoogleUpdateJobObserver();
-
- // Sets the callback to be invoked when Google Update reports that the job is
- // done.
- void set_on_complete_callback(const base::Closure& on_complete_callback) {
- on_complete_callback_ = on_complete_callback;
- }
-
- // Returns the results of the update operation.
- GoogleUpdateUpgradeResult result() const {
- // Intermediary steps should never be reported to the client.
- DCHECK_NE(UPGRADE_STARTED, result_);
- DCHECK_NE(UPGRADE_CHECK_STARTED, result_);
- return result_;
- }
-
- // Returns which version Google Update found on the server (if a more
- // recent version was found). Otherwise, this will be blank.
- base::string16 new_version() const { return new_version_; }
-
- // Returns the Google Update supplied error string that describes the error
- // that occurred during the update check/upgrade.
- base::string16 error_message() const { return error_message_; }
-
- private:
- // IJobObserver:
- STDMETHOD(OnShow)() override;
- STDMETHOD(OnCheckingForUpdate)() override;
- STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) override;
- STDMETHOD(OnWaitingToDownload)() override;
- STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) override;
- STDMETHOD(OnWaitingToInstall)() override;
- STDMETHOD(OnInstalling)() override;
- STDMETHOD(OnPause)() override;
- STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) override;
- STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) override;
-
- // The task runner associated with the thread in which the job runs.
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
- // A callback to be run to complete processing;
- base::Closure on_complete_callback_;
-
- // The status/result of the Google Update operation.
- GoogleUpdateUpgradeResult result_;
-
- // The version string Google Update found.
- base::string16 new_version_;
-
- // An error message, if any.
- base::string16 error_message_;
-
- // Allows us control the upgrade process to a small degree. After OnComplete
- // has been called, this object can not be used.
- base::win::ScopedComPtr<IProgressWndEvents> event_sink_;
-
- DISALLOW_COPY_AND_ASSIGN(GoogleUpdateJobObserver);
-};
-
-GoogleUpdateJobObserver::GoogleUpdateJobObserver()
- : task_runner_(base::ThreadTaskRunnerHandle::Get()),
- result_(UPGRADE_ERROR) {
-}
-
-GoogleUpdateJobObserver::~GoogleUpdateJobObserver() {
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnShow() {
- return S_OK;
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnCheckingForUpdate() {
- result_ = UPGRADE_CHECK_STARTED;
- return S_OK;
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnUpdateAvailable(
- const TCHAR* version_string) {
- result_ = UPGRADE_IS_AVAILABLE;
- new_version_ = version_string;
- return S_OK;
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnWaitingToDownload() {
- return S_OK;
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnDownloading(int time_remaining_ms,
- int pos) {
- return S_OK;
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnWaitingToInstall() {
- return S_OK;
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnInstalling() {
- result_ = UPGRADE_STARTED;
- return S_OK;
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnPause() {
- return S_OK;
-}
-
-STDMETHODIMP GoogleUpdateJobObserver::OnComplete(LegacyCompletionCodes code,
- const TCHAR* text) {
- if (code == COMPLETION_CODE_ERROR) {
- error_message_ = text;
- result_ = UPGRADE_ERROR;
- } else {
- // Everything that isn't an error is some form of success. Chrome doesn't
- // support any of the fancy codes (e.g., COMPLETION_CODE_REBOOT), but they
- // shouldn't be generated anyway.
- LOG_IF(DFATAL, (code != COMPLETION_CODE_SUCCESS &&
- code != COMPLETION_CODE_SUCCESS_CLOSE_UI))
- << "Unexpected LegacyCompletionCode from IGoogleUpdate: " << code;
- if (result_ == UPGRADE_STARTED)
- result_ = UPGRADE_SUCCESSFUL;
- else if (result_ == UPGRADE_CHECK_STARTED)
- result_ = UPGRADE_ALREADY_UP_TO_DATE;
- }
-
- event_sink_ = NULL;
-
- task_runner_->PostTask(FROM_HERE, on_complete_callback_);
- return S_OK;
+ // to %ProgramFiles%. Elevate while instantiating the ServiceClass.
+ return CoCreateInstanceAsAdmin(CLSID_GoogleUpdate3WebMachineClass,
+ IID_IGoogleUpdate3Web, elevation_window,
+ google_update->ReceiveVoid());
}
-STDMETHODIMP GoogleUpdateJobObserver::SetEventSink(
- IProgressWndEvents* event_sink) {
- event_sink_ = event_sink;
- return S_OK;
-}
-
-
// UpdateCheckDriver -----------------------------------------------------------
// A driver that is created and destroyed on the caller's thread and drives
// Google Update on another.
class UpdateCheckDriver {
public:
- // Runs an update check on |task_runner|, invoking |callback| on the caller's
- // thread upon completion. |task_runner| must run a TYPE_UI message loop if
- // the default IGoogleUpdate on-demand COM class is used.
- static void RunUpdateCheck(const scoped_refptr<base::TaskRunner>& task_runner,
- bool install_if_newer,
- gfx::AcceleratedWidget elevation_window,
- const UpdateCheckCallback& callback);
+ // Runs an update check on |task_runner|, invoking methods of |delegate| on
+ // the caller's thread to report progress and final results.
+ static void RunUpdateCheck(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const std::string& locale,
+ bool install_update_if_possible,
+ gfx::AcceleratedWidget elevation_window,
+ const base::WeakPtr<UpdateCheckDelegate>& delegate);
private:
friend class base::DeleteHelper<UpdateCheckDriver>;
- explicit UpdateCheckDriver(const UpdateCheckCallback& callback);
+ UpdateCheckDriver(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const std::string& locale,
+ bool install_update_if_possible,
+ gfx::AcceleratedWidget elevation_window,
+ const base::WeakPtr<UpdateCheckDelegate>& delegate);
- // Runs the caller's update check callback with the results of the operation.
+ // Invokes a completion or error method on the caller's delegate, as
+ // appropriate.
~UpdateCheckDriver();
// Starts an update check.
- void BeginUpdateCheck(bool install_if_newer,
- gfx::AcceleratedWidget elevation_window);
+ void BeginUpdateCheck();
- // Helper function for starting an update check. Returns true if the check was
- // properly started, in which case CompleteUpdateCheck will be invoked upon
- // completion to return results to the caller on its own thread.
- bool BeginUpdateCheckInternal(bool install_if_newer,
- gfx::AcceleratedWidget elevation_window);
+ // Returns the result of initiating an update check. Sets |error_code| if the
+ // result is any kind of failure.
+ HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code);
- // Invoked when results are in from Google Update.
- void CompleteUpdateCheck();
-
- // Prepares |results| to return the upgrade error indicated by |error_code|
- // and |hr|. The string " -- system level" is included in the generated error
- // message when |system_level| is true.
+ // Sets status_ to UPGRADE_ERROR, error_code_ to |error_code|, hresult_ to
+ // |hresult|, installer_exit_code_ to |installer_exit_code|, and
+ // error_message_ to a composition of all values suitable for display to the
+ // user. This call should be followed by deletion of the driver, which will
+ // result in the caller being notified via its delegate.
void OnUpgradeError(GoogleUpdateErrorCode error_code,
- HRESULT hr,
- bool system_level);
+ HRESULT hresult,
+ int installer_exit_code,
+ const base::string16& error_string);
+
+ // Returns true if |current_state| and |state_value| can be obtained from the
+ // ongoing update check. Otherwise, populates |hresult| with the reason they
+ // could not be obtained.
+ bool GetCurrentState(base::win::ScopedComPtr<ICurrentState>* current_state,
+ CurrentState* state_value,
+ HRESULT* hresult) const;
+
+ // Returns true if |current_state| and |state_value| constitute an error state
+ // for the ongoing update check, in which case |error_code| is populated with
+ // one of GOOGLE_UPDATE_ERROR_UPDATING, GOOGLE_UPDATE_DISABLED_BY_POLICY, or
+ // GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR. |hresult| is populated with
+ // the most relevant HRESULT (which may be a value from Google Update; see
+ // 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
+ // populated with its process exit code (see enum installer::InstallStatus in
+ // chrome/installer/util/util_constants.h); otherwise, it will be -1.
+ // |error_string| will be populated with a completion message if one is
+ // provided by Google Update.
+ bool IsErrorState(const base::win::ScopedComPtr<ICurrentState>& current_state,
+ CurrentState state_value,
+ GoogleUpdateErrorCode* error_code,
+ HRESULT* hresult,
+ int* installer_exit_code,
+ base::string16* error_string) const;
+
+ // Returns true if |current_state| and |state_value| constitute a final state
+ // for the ongoing update check, in which case |upgrade_status| is populated
+ // with one of UPGRADE_ALREADY_UP_TO_DATE or UPGRADE_IS_AVAILABLE (in case a
+ // pure check is being performed rather than an update) or UPGRADE_SUCCESSFUL
+ // (in case an update is being performed). For the UPGRADE_IS_AVAILABLE case,
+ // |new_version| will be populated with the available version, if provided by
+ // Google Update.
+ bool IsFinalState(const base::win::ScopedComPtr<ICurrentState>& current_state,
+ CurrentState state_value,
+ GoogleUpdateUpgradeStatus* upgrade_status,
+ base::string16* new_version) const;
+
+ // Returns true if |current_state| and |state_value| constitute an
+ // intermediate state for the ongoing update check. |new_version| will be
+ // populated with the version to be installed if it is provided by Google
+ // Update for the current state. |progress| will be populated with a number
+ // between 0 and 100 according to how far Google Update has progressed in the
+ // download and install process.
+ bool IsIntermediateState(
+ const base::win::ScopedComPtr<ICurrentState>& current_state,
+ CurrentState state_value,
+ base::string16* new_version,
+ int* progress) const;
+
+ // Polls Google Update to determine the state of the ongoing check or
+ // update. If the process has reached a terminal state, this instance will be
+ // deleted and the caller will be notified of the final status. Otherwise, the
+ // caller will be notified of the intermediate state (iff it differs from a
+ // previous notification) and another future poll will be scheduled.
+ void PollGoogleUpdate();
+
+ // The task runner on which the update checks runs.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- // The caller's task runner, on which |result_callback_| will be run.
+ // The caller's task runner, on which methods of |delegate_| will be invoked.
scoped_refptr<base::SingleThreadTaskRunner> result_runner_;
- // The caller's callback to be run when the update check is compelte.
- UpdateCheckCallback result_callback_;
+ // The UI locale.
+ std::string locale_;
- // The results of the update check.
- GoogleUpdateUpgradeResult result_;
- GoogleUpdateErrorCode error_code_;
- base::string16 error_message_;
- base::string16 version_;
- HRESULT hresult_;
+ // False to only check for an update; true to also install one if available.
+ bool install_update_if_possible_;
+
+ // A parent window in case any UX is required (e.g., an elevation prompt).
+ gfx::AcceleratedWidget elevation_window_;
- // A direct pointer to the job observer by which the driver is notified of
- // interesting events from Google Update.
- CComObject<GoogleUpdateJobObserver>* job_observer_;
+ // The caller's delegate by which feedback is conveyed.
+ base::WeakPtr<UpdateCheckDelegate> delegate_;
- // A scoped pointer to |job_observer_| that holds a reference to it, keeping
- // it alive.
- base::win::ScopedComPtr<IJobObserver> job_holder_;
+ // True if operating on a per-machine installation rather than a per-user one.
+ bool system_level_install_;
// The on-demand updater that is doing the work.
- base::win::ScopedComPtr<IGoogleUpdate> on_demand_;
+ base::win::ScopedComPtr<IGoogleUpdate3Web> google_update_;
+
+ // An app bundle containing the application being updated.
+ base::win::ScopedComPtr<IAppBundleWeb> app_bundle_;
+
+ // The application being updated (Chrome, Chrome Binaries, or Chrome SxS).
+ base::win::ScopedComPtr<IAppWeb> app_;
+
+ // The progress value reported most recently to the caller.
+ int last_reported_progress_;
+
+ // The results of the update check to be logged via UMA and/or reported to the
+ // caller.
+ GoogleUpdateUpgradeStatus status_;
+ GoogleUpdateErrorCode error_code_;
+ base::string16 error_message_;
+ base::string16 new_version_;
+ HRESULT hresult_;
+ int installer_exit_code_;
DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
};
// static
void UpdateCheckDriver::RunUpdateCheck(
- const scoped_refptr<base::TaskRunner>& task_runner,
- bool install_if_newer,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const std::string& locale,
+ bool install_update_if_possible,
gfx::AcceleratedWidget elevation_window,
- const UpdateCheckCallback& callback) {
+ const base::WeakPtr<UpdateCheckDelegate>& delegate) {
// The driver is owned by itself, and will self-destruct when its work is
// done.
- UpdateCheckDriver* driver = new UpdateCheckDriver(callback);
- task_runner->PostTask(
- FROM_HERE,
- base::Bind(&UpdateCheckDriver::BeginUpdateCheck, base::Unretained(driver),
- install_if_newer, elevation_window));
+ UpdateCheckDriver* driver =
+ new UpdateCheckDriver(task_runner, locale, install_update_if_possible,
+ elevation_window, delegate);
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&UpdateCheckDriver::BeginUpdateCheck,
+ base::Unretained(driver)));
}
// Runs on the caller's thread.
-UpdateCheckDriver::UpdateCheckDriver(const UpdateCheckCallback& callback)
- : result_runner_(base::ThreadTaskRunnerHandle::Get()),
- result_callback_(callback),
- result_(UPGRADE_ERROR),
+UpdateCheckDriver::UpdateCheckDriver(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const std::string& locale,
+ bool install_update_if_possible,
+ gfx::AcceleratedWidget elevation_window,
+ const base::WeakPtr<UpdateCheckDelegate>& delegate)
+ : task_runner_(task_runner),
+ result_runner_(base::ThreadTaskRunnerHandle::Get()),
+ locale_(locale),
+ install_update_if_possible_(install_update_if_possible),
+ elevation_window_(elevation_window),
+ delegate_(delegate),
+ system_level_install_(false),
+ last_reported_progress_(0),
+ status_(UPGRADE_ERROR),
error_code_(GOOGLE_UPDATE_NO_ERROR),
hresult_(S_OK),
- job_observer_(nullptr) {
+ installer_exit_code_(-1) {
}
UpdateCheckDriver::~UpdateCheckDriver() {
DCHECK(result_runner_->BelongsToCurrentThread());
// If there is an error, then error_code must not be blank, and vice versa.
- DCHECK_NE(result_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR);
- UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", result_,
- NUM_UPGRADE_RESULTS);
- if (result_ == UPGRADE_ERROR) {
+ DCHECK_NE(status_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR);
+ UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_,
+ NUM_UPGRADE_STATUS);
+ if (status_ == UPGRADE_ERROR) {
UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_,
NUM_ERROR_CODES);
- if (hresult_ != S_OK)
+ if (FAILED(hresult_))
UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_);
+ if (installer_exit_code_ != -1) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.InstallerExitCode",
+ installer_exit_code_);
+ }
+ }
+ if (delegate_) {
+ if (status_ == UPGRADE_ERROR)
+ delegate_->OnError(error_code_, error_message_, new_version_);
+ else if (install_update_if_possible_)
+ delegate_->OnUpgradeComplete(new_version_);
+ else
+ delegate_->OnUpdateCheckComplete(new_version_);
}
- result_callback_.Run(result_, error_code_, error_message_, version_);
}
-void UpdateCheckDriver::BeginUpdateCheck(
- bool install_if_newer,
- gfx::AcceleratedWidget elevation_window) {
- // Return results immediately if the driver is not waiting for Google Update.
- if (!BeginUpdateCheckInternal(install_if_newer, elevation_window))
+void UpdateCheckDriver::BeginUpdateCheck() {
+ GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
+ HRESULT hresult = BeginUpdateCheckInternal(&error_code);
+ if (SUCCEEDED(hresult)) {
+ // Start polling.
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
+ base::Unretained(this)));
+ } else {
+ // Return results immediately since the driver is not polling Google Update.
+ OnUpgradeError(error_code, hresult, -1, base::string16());
result_runner_->DeleteSoon(FROM_HERE, this);
+ }
}
-bool UpdateCheckDriver::BeginUpdateCheckInternal(
- bool install_if_newer,
- gfx::AcceleratedWidget elevation_window) {
+HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
+ GoogleUpdateErrorCode* error_code) {
base::FilePath chrome_exe;
if (!PathService::Get(base::DIR_EXE, &chrome_exe))
NOTREACHED();
- const bool system_level = !InstallUtil::IsPerUserInstall(chrome_exe);
-
- // The failures handled here are:
- // CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY,
- // GOOGLE_UPDATE_DISABLED_BY_POLICY, and
- // GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY.
- error_code_ = CanUpdateCurrentChrome(chrome_exe, system_level);
- if (error_code_ != GOOGLE_UPDATE_NO_ERROR) {
- // These failures are handled in the UX with custom messages.
- result_ = UPGRADE_ERROR;
- return false;
- }
+ system_level_install_ = !InstallUtil::IsPerUserInstall(chrome_exe);
// Make sure ATL is initialized in this module.
ui::win::CreateATLModuleIfNeeded();
- HRESULT hr =
- CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer_);
- if (hr != S_OK) {
- // Most of the error messages come straight from Google Update. This one is
- // deemed worthy enough to also warrant its own error.
- OnUpgradeError(GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED, hr, false);
- return false;
+ *error_code = CanUpdateCurrentChrome(chrome_exe, system_level_install_);
+ if (*error_code != GOOGLE_UPDATE_NO_ERROR)
+ return E_FAIL;
+
+ HRESULT hresult = CreateGoogleUpdate3WebClass(
+ system_level_install_, install_update_if_possible_, elevation_window_,
+ &google_update_);
+ if (FAILED(hresult)) {
+ *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND;
+ return hresult;
}
- // Hold a reference on the observer for the lifetime of the driver.
- job_holder_ = job_observer_;
- job_observer_->set_on_complete_callback(base::Bind(
- &UpdateCheckDriver::CompleteUpdateCheck, base::Unretained(this)));
+ // The class was created, so all subsequent errors are reported as:
+ *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
+ base::string16 app_guid =
+ installer::GetAppGuidForUpdates(system_level_install_);
+ DCHECK(!app_guid.empty());
- hr = CreateOnDemandAppsClass(system_level, install_if_newer, elevation_window,
- &on_demand_);
- if (hr != S_OK) {
- OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, hr, system_level);
- return false;
+ {
+ base::win::ScopedComPtr<IDispatch> dispatch;
+ hresult = google_update_->createAppBundleWeb(dispatch.Receive());
+ if (FAILED(hresult))
+ return hresult;
+ hresult = dispatch.QueryInterface(app_bundle_.Receive());
+ if (FAILED(hresult))
+ return hresult;
}
- base::string16 app_guid = installer::GetAppGuidForUpdates(system_level);
- DCHECK(!app_guid.empty());
+ if (!locale_.empty()) {
+ // Ignore the result of this since, while setting the display language is
+ // nice to have, a failure to do so does not affect the likelihood that the
+ // update check and/or install will succeed.
+ app_bundle_->put_displayLanguage(
+ base::win::ScopedBstr(base::UTF8ToUTF16(locale_).c_str()));
+ }
+
+ hresult = app_bundle_->initialize();
+ if (FAILED(hresult))
+ return hresult;
+ if (elevation_window_) {
+ // Likewise, a failure to set the parent window need not block an update
+ // check.
+ app_bundle_->put_parentHWND(reinterpret_cast<ULONG_PTR>(elevation_window_));
+ }
- if (install_if_newer)
- hr = on_demand_->Update(app_guid.c_str(), job_observer_);
- else
- hr = on_demand_->CheckForUpdate(app_guid.c_str(), job_observer_);
+ base::win::ScopedComPtr<IDispatch> dispatch;
+ hresult =
+ app_bundle_->createInstalledApp(base::win::ScopedBstr(app_guid.c_str()));
+ if (FAILED(hresult))
+ return hresult;
+ hresult = app_bundle_->get_appWeb(0, dispatch.Receive());
+ if (FAILED(hresult))
+ return hresult;
+ hresult = dispatch.QueryInterface(app_.Receive());
+ if (FAILED(hresult))
+ return hresult;
+ return app_bundle_->checkForUpdate();
+}
- if (hr != S_OK) {
- OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hr,
- system_level);
+bool UpdateCheckDriver::GetCurrentState(
+ base::win::ScopedComPtr<ICurrentState>* current_state,
+ CurrentState* state_value,
+ HRESULT* hresult) const {
+ base::win::ScopedComPtr<IDispatch> dispatch;
+ *hresult = app_->get_currentState(dispatch.Receive());
+ if (FAILED(*hresult))
+ return false;
+ *hresult = dispatch.QueryInterface(current_state->Receive());
+ if (FAILED(*hresult))
+ return false;
+ 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 base::win::ScopedComPtr<ICurrentState>& current_state,
+ CurrentState state_value,
+ GoogleUpdateErrorCode* error_code,
+ HRESULT* hresult,
+ int* installer_exit_code,
+ base::string16* error_string) const {
+ if (state_value == STATE_ERROR) {
+ // In general, errors reported by Google Update fall under this category
+ // (see special case below).
+ *error_code = GOOGLE_UPDATE_ERROR_UPDATING;
+
+ // In general, the exit code of Chrome's installer is unknown (see special
+ // case below).
+ *installer_exit_code = -1;
+
+ // Report the error_code provided by Google Update if possible, or the
+ // reason it wasn't possible otherwise.
+ LONG long_value = 0;
+ *hresult = current_state->get_errorCode(&long_value);
+ if (SUCCEEDED(*hresult))
+ *hresult = long_value;
+
+ // Special cases:
+ // - Use a custom error code if Google Update repoted that the update was
+ // disabled by a Group Policy setting.
+ // - Extract the exit code of Chrome's installer if Google Update repoted
+ // that the update failed because of a failure in the installer.
+ LONG code = 0;
+ if (*hresult == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY) {
+ *error_code = GOOGLE_UPDATE_DISABLED_BY_POLICY;
+ } 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(message, message.Length());
+
+ return true;
+ }
+ if (state_value == STATE_UPDATE_AVAILABLE && install_update_if_possible_) {
+ *hresult = app_bundle_->install();
S. Ganesh 2015/05/13 20:21:41 It is somewhat unexpected to see IsErrorState() ca
grt (UTC plus 2) 2015/05/13 20:36:38 Understood. The reason it isn't called from PollGo
+ if (FAILED(*hresult)) {
+ // Report a failure to start the install as a general error while trying
+ // to interact with Google Update.
+ *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
+ *installer_exit_code = -1;
+ return true;
+ }
+ // Return false for handling in IsIntermediateState.
+ }
+ return false;
+}
+
+bool UpdateCheckDriver::IsFinalState(
+ const base::win::ScopedComPtr<ICurrentState>& current_state,
+ CurrentState state_value,
+ GoogleUpdateUpgradeStatus* upgrade_status,
+ base::string16* 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())))
S. Ganesh 2015/05/13 20:21:40 Minor code duplication here and in IsIntermediateS
grt (UTC plus 2) 2015/05/13 20:36:38 It would be possible, but would take some rejigger
+ new_version->assign(version, 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 base::win::ScopedComPtr<ICurrentState>& current_state,
+ CurrentState state_value,
+ base::string16* new_version,
+ int* progress) const {
+ // ERROR will have been handled in IsErrorState. UPDATE_AVAILABLE, and
+ // NO_UPDATE will have been handled in IsFinalState if not doing an install,
+ // as will STATE_INSTALL_COMPLETE when doing an install. All other states
+ // following UPDATE_AVAILABLE will only happen when an install is to be done.
+ 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:
+ // There is no news to report yet.
+ break;
+
+ case STATE_UPDATE_AVAILABLE: {
+ base::win::ScopedBstr version;
+ if (SUCCEEDED(current_state->get_availableVersion(version.Receive())))
+ new_version->assign(version, 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) {
+ // 0-50 is downloading.
+ *progress = gfx::ToFlooredInt((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) {
+ // 50-100 is installing.
+ *progress = (50 + install_progress / 2);
+ }
+ break;
+ }
+
+ case STATE_INSTALL_COMPLETE:
+ case STATE_PAUSED:
+ case STATE_NO_UPDATE:
+ case STATE_ERROR:
+ default:
+ NOTREACHED();
+ UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.UnexpectedState", state_value);
+ return false;
}
return true;
}
-void UpdateCheckDriver::CompleteUpdateCheck() {
- result_ = job_observer_->result();
- if (result_ == UPGRADE_ERROR) {
- error_code_ = GOOGLE_UPDATE_ERROR_UPDATING;
- error_message_ = job_observer_->error_message();
- } else {
- version_ = job_observer_->new_version();
+void UpdateCheckDriver::PollGoogleUpdate() {
+ base::win::ScopedComPtr<ICurrentState> state;
+ CurrentState state_value = STATE_INIT;
+ HRESULT hresult = S_OK;
+ GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
+ int installer_exit_code = -1;
+ base::string16 error_string;
+ GoogleUpdateUpgradeStatus upgrade_status = UPGRADE_ERROR;
+ base::string16 new_version;
+ int progress = 0;
+
+ if (!GetCurrentState(&state, &state_value, &hresult)) {
+ OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult, -1,
+ base::string16());
+ } 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;
+ error_code_ = GOOGLE_UPDATE_NO_ERROR;
+ error_message_.clear();
+ if (!new_version.empty())
+ new_version_ = new_version;
+ hresult_ = S_OK;
+ installer_exit_code_ = -1;
+ } else if (IsIntermediateState(state, state_value, &new_version, &progress)) {
+ bool got_new_version = new_version_.empty() && !new_version.empty();
+ if (got_new_version)
+ new_version_ = new_version;
+ // Give the caller this status update if it differs from the last one given.
+ if (got_new_version || progress != last_reported_progress_) {
+ last_reported_progress_ = progress;
+
+ // It is safe to post this task with an unretained pointer since the task
+ // is guaranteed to run before a subsequent DeleteSoon is handled.
+ result_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UpdateCheckDelegate::OnUpgradeProgress, delegate_,
+ last_reported_progress_, new_version_));
+ }
+
+ // Schedule the next check.
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
+ base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(kGoogleUpdatePollIntervalMs));
+ // Early return for this non-terminal state.
+ return;
}
// Release the reference on the COM objects before bouncing back to the
// caller's thread.
- on_demand_.Release();
- job_holder_.Release();
- job_observer_ = nullptr;
+ state.Release();
+ app_.Release();
+ app_bundle_.Release();
+ google_update_.Release();
result_runner_->DeleteSoon(FROM_HERE, this);
}
void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
- HRESULT hr,
- bool system_level) {
- result_ = UPGRADE_ERROR;
+ HRESULT hresult,
+ int installer_exit_code,
+ const base::string16& error_string) {
+ status_ = UPGRADE_ERROR;
error_code_ = error_code;
- hresult_ = hr;
+ hresult_ = hresult;
+ installer_exit_code_ = installer_exit_code;
base::string16 error_msg =
base::StringPrintf(L"%d: 0x%x", error_code_, hresult_);
- if (system_level)
+ if (installer_exit_code_ != -1)
+ error_msg += base::StringPrintf(L": %d", installer_exit_code_);
+ if (system_level_install_)
error_msg += L" -- system level";
- error_message_ = l10n_util::GetStringFUTF16(
- IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, error_msg);
+ if (error_string.empty()) {
+ error_message_ = l10n_util::GetStringFUTF16(
+ IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, error_msg);
+ } else {
+ error_message_ = l10n_util::GetStringFUTF16(
+ IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR, error_string, error_msg);
+ }
}
} // namespace
@@ -497,25 +708,28 @@ void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
// Globals ---------------------------------------------------------------------
-void BeginUpdateCheck(const scoped_refptr<base::TaskRunner>& task_runner,
- bool install_if_newer,
- gfx::AcceleratedWidget elevation_window,
- const UpdateCheckCallback& callback) {
- UpdateCheckDriver::RunUpdateCheck(task_runner, install_if_newer,
- elevation_window, callback);
+void BeginUpdateCheck(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const std::string& locale,
+ bool install_update_if_possible,
+ gfx::AcceleratedWidget elevation_window,
+ const base::WeakPtr<UpdateCheckDelegate>& delegate) {
+ UpdateCheckDriver::RunUpdateCheck(task_runner, locale,
+ install_update_if_possible,
+ elevation_window, delegate);
}
// Private API exposed for testing. --------------------------------------------
void SetGoogleUpdateFactoryForTesting(
- const OnDemandAppsClassFactory& google_update_factory) {
+ const 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 OnDemandAppsClassFactory(google_update_factory);
+ new GoogleUpdate3ClassFactory(google_update_factory);
}
}

Powered by Google App Engine
This is Rietveld 408576698