Chromium Code Reviews| 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 adeb33c8f729d951267472dfaec3b6f3f0bc6457..97920cd435f787993fc26f7dbe7a7becac530fc0 100644 |
| --- a/chrome/browser/google/google_update_win.cc |
| +++ b/chrome/browser/google/google_update_win.cc |
| @@ -8,15 +8,16 @@ |
| #include <atlcom.h> |
| #include "base/bind.h" |
| +#include "base/callback.h" |
| #include "base/files/file_path.h" |
| -#include "base/message_loop/message_loop.h" |
| +#include "base/location.h" |
| #include "base/metrics/histogram.h" |
| #include "base/metrics/sparse_histogram.h" |
| #include "base/path_service.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| -#include "base/threading/thread.h" |
| -#include "base/win/scoped_comptr.h" |
| +#include "base/task_runner.h" |
| +#include "base/thread_task_runner_handle.h" |
| #include "base/win/windows_version.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "chrome/installer/util/browser_distribution.h" |
| @@ -24,25 +25,24 @@ |
| #include "chrome/installer/util/helper.h" |
| #include "chrome/installer/util/install_util.h" |
| #include "content/public/browser/browser_thread.h" |
| -#include "google_update/google_update_idl.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/win/atl_module.h" |
| -#include "ui/views/widget/widget.h" |
| - |
| -using content::BrowserThread; |
| namespace { |
| +internal::OnDemandAppsClassFactory* g_google_update_factory = nullptr; |
| + |
| // 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) { |
| + const base::FilePath& chrome_exe_path, |
| + bool system_level) { |
| #if !defined(GOOGLE_CHROME_BUILD) |
| return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; |
| #else |
| - // TODO(tommi): Check if using the default distribution is always the right |
| - // thing to do. |
| + DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()), |
| + system_level); |
| BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist); |
| base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist); |
| @@ -50,16 +50,10 @@ GoogleUpdateErrorCode CanUpdateCurrentChrome( |
| user_exe_path.value()) && |
| !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), |
| machine_exe_path.value())) { |
| - LOG(ERROR) << L"Google Update cannot update Chrome installed in a " |
| - << L"non-standard location: " << chrome_exe_path.value().c_str() |
| - << L". The standard location is: " |
| - << user_exe_path.value().c_str() |
| - << L" or " << machine_exe_path.value().c_str() << L"."; |
| return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; |
| } |
| - base::string16 app_guid = installer::GetAppGuidForUpdates( |
| - !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str())); |
| + base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); |
| DCHECK(!app_guid.empty()); |
| GoogleUpdateSettings::UpdatePolicy update_policy = |
| @@ -88,7 +82,7 @@ HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id, |
| // For Vista, need to instantiate the COM server via the elevation |
| // moniker. This ensures that the UAC dialog shows up. |
| if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
| - wchar_t class_id_as_string[MAX_PATH] = {0}; |
| + wchar_t class_id_as_string[MAX_PATH] = {}; |
| StringFromGUID2(class_id, class_id_as_string, |
| arraysize(class_id_as_string)); |
| @@ -96,125 +90,99 @@ HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id, |
| base::StringPrintf(L"Elevation:Administrator!new:%ls", |
| class_id_as_string); |
| - BIND_OPTS3 bind_opts; |
| - memset(&bind_opts, 0, sizeof(bind_opts)); |
| + 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, reinterpret_cast<void**>(interface_ptr)); |
| + return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id, |
| + interface_ptr); |
| } |
| - return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, |
| - interface_id, |
| - reinterpret_cast<void**>(interface_ptr)); |
| + return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, interface_id, |
| + interface_ptr); |
| } |
| +HRESULT CreateOnDemandAppsClass( |
| + bool system_level, |
| + bool install_if_newer, |
| + HWND elevation_window, |
| + base::win::ScopedComPtr<IGoogleUpdate>* on_demand) { |
| + if (g_google_update_factory) |
| + return g_google_update_factory->Run(on_demand); |
| + |
| + // 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); |
| + |
| + // 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); |
| -} // namespace |
| + // 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()); |
| +} |
| // The GoogleUpdateJobObserver COM class is responsible for receiving status |
| -// reports from google Update. It keeps track of the progress as GoogleUpdate |
| -// notifies this observer and ends the message loop that is spinning in once |
| -// GoogleUpdate reports that it is done. |
| -class GoogleUpdateJobObserver |
| - : public CComObjectRootEx<CComSingleThreadModel>, |
| - public IJobObserver { |
| +// 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>, |
|
Peter Kasting
2014/11/26 22:13:05
Nit: Because this file has several classes in it,
grt (UTC plus 2)
2014/11/27 04:44:57
git cl format doesn't like the extra blank line. :
Peter Kasting
2014/11/27 08:07:34
I prefer that people not run git cl format at all.
|
| + public IJobObserver { |
| public: |
| BEGIN_COM_MAP(GoogleUpdateJobObserver) |
| COM_INTERFACE_ENTRY(IJobObserver) |
| END_COM_MAP() |
| - GoogleUpdateJobObserver() |
| - : result_(UPGRADE_ERROR) { |
| - } |
| - virtual ~GoogleUpdateJobObserver() {} |
| + GoogleUpdateJobObserver(); |
| + virtual ~GoogleUpdateJobObserver(); |
| - // Notifications from Google Update: |
| - STDMETHOD(OnShow)() { |
| - return S_OK; |
| - } |
| - STDMETHOD(OnCheckingForUpdate)() { |
| - result_ = UPGRADE_CHECK_STARTED; |
| - return S_OK; |
| - } |
| - STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) { |
| - result_ = UPGRADE_IS_AVAILABLE; |
| - new_version_ = version_string; |
| - return S_OK; |
| - } |
| - STDMETHOD(OnWaitingToDownload)() { |
| - return S_OK; |
| - } |
| - STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) { |
| - return S_OK; |
| - } |
| - STDMETHOD(OnWaitingToInstall)() { |
| - return S_OK; |
| - } |
| - STDMETHOD(OnInstalling)() { |
| - result_ = UPGRADE_STARTED; |
| - return S_OK; |
| - } |
| - STDMETHOD(OnPause)() { |
| - return S_OK; |
| - } |
| - STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) { |
| - switch (code) { |
| - case COMPLETION_CODE_SUCCESS_CLOSE_UI: |
| - case COMPLETION_CODE_SUCCESS: { |
| - if (result_ == UPGRADE_STARTED) |
| - result_ = UPGRADE_SUCCESSFUL; |
| - else if (result_ == UPGRADE_CHECK_STARTED) |
| - result_ = UPGRADE_ALREADY_UP_TO_DATE; |
| - break; |
| - } |
| - case COMPLETION_CODE_ERROR: |
| - error_message_ = text; |
| - default: { |
| - NOTREACHED(); |
| - result_ = UPGRADE_ERROR; |
| - break; |
| - } |
| - } |
| - |
| - event_sink_ = NULL; |
| - |
| - // No longer need to spin the message loop that started spinning in |
| - // InitiateGoogleUpdateCheck. |
| - base::MessageLoop::current()->Quit(); |
| - return S_OK; |
| - } |
| - STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) { |
| - event_sink_ = event_sink; |
| - return S_OK; |
| + // 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. |
| - STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) { |
| + GoogleUpdateUpgradeResult result() const { |
| // Intermediary steps should never be reported to the client. |
| - DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED); |
| - |
| - *result = result_; |
| - return S_OK; |
| + DCHECK_NE(result_, UPGRADE_STARTED); |
| + DCHECK_NE(result_, UPGRADE_CHECK_STARTED); |
|
Peter Kasting
2014/11/26 22:13:05
Nit: (expected, actual) for DCHECK_NE/EQ
grt (UTC plus 2)
2014/11/27 04:44:57
Is this for consistency with Google Tests's EXPECT
Peter Kasting
2014/11/27 08:07:34
Yes, that's why we instituted that practice. (We
|
| + return result_; |
| } |
| // Returns which version Google Update found on the server (if a more |
| // recent version was found). Otherwise, this will be blank. |
| - STDMETHOD(GetVersionInfo)(base::string16* version_string) { |
| - *version_string = new_version_; |
| - return S_OK; |
| - } |
| + 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. |
| - STDMETHOD(GetErrorMessage)(base::string16* error_message) { |
| - *error_message = error_message_; |
| - return S_OK; |
| - } |
| + base::string16 error_message() const { return error_message_; } |
| private: |
| + // IJobObserver: |
| + STDMETHOD(OnShow)(); |
| + STDMETHOD(OnCheckingForUpdate)(); |
| + STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string); |
| + STDMETHOD(OnWaitingToDownload)(); |
| + STDMETHOD(OnDownloading)(int time_remaining_ms, int pos); |
| + STDMETHOD(OnWaitingToInstall)(); |
| + STDMETHOD(OnInstalling)(); |
| + STDMETHOD(OnPause)(); |
| + STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text); |
| + STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink); |
| + |
| + // 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_; |
| @@ -227,195 +195,320 @@ class GoogleUpdateJobObserver |
| // 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); |
| }; |
| -//////////////////////////////////////////////////////////////////////////////// |
| -// GoogleUpdate, public: |
| +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; |
| +} |
| + |
| +STDMETHODIMP GoogleUpdateJobObserver::SetEventSink( |
| + IProgressWndEvents* event_sink) { |
| + event_sink_ = event_sink; |
| + return S_OK; |
| +} |
| + |
| +// 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. |
| + static void RunUpdateCheck(const scoped_refptr<base::TaskRunner>& task_runner, |
| + bool install_if_newer, |
| + HWND elevation_window, |
| + const UpdateCheckCallback& callback); |
| + |
| + private: |
| + friend class base::DeleteHelper<UpdateCheckDriver>; |
| + |
| + explicit UpdateCheckDriver(const UpdateCheckCallback& callback); |
| + |
| + // Runs the caller's update check callback with the results of the operation. |
| + ~UpdateCheckDriver(); |
| + |
| + // Starts an update check. |
| + void BeginUpdateCheck(bool install_if_newer, HWND elevation_window); |
| + |
| + // 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, HWND elevation_window); |
| + |
| + // 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. |
| + void OnUpgradeError(GoogleUpdateErrorCode error_code, |
| + HRESULT hr, |
| + bool system_level); |
| -GoogleUpdate::GoogleUpdate() |
| - : listener_(NULL) { |
| + // The caller's task runner, on which |result_callback_| will be run. |
| + scoped_refptr<base::SingleThreadTaskRunner> result_runner_; |
| + |
| + // The caller's callback to be run when the update check is compelte. |
| + UpdateCheckCallback result_callback_; |
| + |
| + // The results of the update check. |
| + GoogleUpdateUpgradeResult result_; |
| + GoogleUpdateErrorCode error_code_; |
| + base::string16 error_message_; |
| + base::string16 version_; |
| + HRESULT hresult_; |
| + |
| + // A direct pointer to the job observer by which the driver is notified of |
| + // interesting events from Google Update. |
| + CComObject<GoogleUpdateJobObserver>* job_observer_; |
| + |
| + // A scoped pointer to |job_observer_| that holds a reference to it, keeping |
| + // it alive. |
| + base::win::ScopedComPtr<IJobObserver> job_holder_; |
| + |
| + // The on-demand updater that is doing the work. |
| + base::win::ScopedComPtr<IGoogleUpdate> on_demand_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver); |
| +}; |
| + |
| +// static |
| +void UpdateCheckDriver::RunUpdateCheck( |
| + const scoped_refptr<base::TaskRunner>& task_runner, |
| + bool install_if_newer, |
| + HWND elevation_window, |
| + const UpdateCheckCallback& callback) { |
| + // 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)); |
| } |
| -GoogleUpdate::~GoogleUpdate() { |
| +// Runs on the caller's thread. |
| +UpdateCheckDriver::UpdateCheckDriver(const UpdateCheckCallback& callback) |
| + : result_runner_(base::ThreadTaskRunnerHandle::Get()), |
| + result_callback_(callback), |
| + result_(UPGRADE_ERROR), |
| + error_code_(GOOGLE_UPDATE_NO_ERROR), |
| + hresult_(S_OK), |
| + job_observer_(nullptr) { |
| } |
| -void GoogleUpdate::CheckForUpdate(bool install_if_newer, HWND window) { |
| - // Need to shunt this request over to InitiateGoogleUpdateCheck and have |
| - // it run in the file thread. |
| - BrowserThread::PostTask( |
| - BrowserThread::FILE, FROM_HERE, |
| - base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this, |
| - install_if_newer, window, base::MessageLoop::current())); |
| +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); |
|
Peter Kasting
2014/11/26 22:13:05
Nit: Please flip the "!="s to "=="s ... trying to
grt (UTC plus 2)
2014/11/27 04:44:57
Oops. I mis-read your previous comment. I wondered
|
| + UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", result_, |
| + NUM_UPGRADE_RESULTS); |
| + if (result_ == UPGRADE_ERROR) { |
| + UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_, |
| + NUM_ERROR_CODES); |
| + if (hresult_ != S_OK) |
| + UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_); |
| + } |
| + result_callback_.Run(result_, error_code_, error_message_, version_); |
| } |
| -//////////////////////////////////////////////////////////////////////////////// |
| -// GoogleUpdate, private: |
| +void UpdateCheckDriver::BeginUpdateCheck(bool install_if_newer, |
| + HWND elevation_window) { |
| + // Return results immediately if the driver is not waiting for Google Update. |
| + if (!BeginUpdateCheckInternal(install_if_newer, elevation_window)) |
| + result_runner_->DeleteSoon(FROM_HERE, this); |
| +} |
| -void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer, |
| - HWND window, |
| - base::MessageLoop* main_loop) { |
| +bool UpdateCheckDriver::BeginUpdateCheckInternal(bool install_if_newer, |
| + HWND elevation_window) { |
| base::FilePath chrome_exe; |
| if (!PathService::Get(base::DIR_EXE, &chrome_exe)) |
| NOTREACHED(); |
| - GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe); |
| - if (error_code != GOOGLE_UPDATE_NO_ERROR) { |
| - main_loop->PostTask( |
| - FROM_HERE, |
| - base::Bind(&GoogleUpdate::ReportResults, this, |
| - UPGRADE_ERROR, error_code, base::string16())); |
| - return; |
| + const bool system_level = |
| + !InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()); |
| + |
| + // 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; |
| } |
| // Make sure ATL is initialized in this module. |
| ui::win::CreateATLModuleIfNeeded(); |
| - CComObject<GoogleUpdateJobObserver>* job_observer; |
| HRESULT hr = |
| - CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer); |
| + 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. |
| - GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED; |
| - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); |
| - ReportFailure( |
| - hr, error, |
| - l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, |
| - error_code), |
| - main_loop); |
| - return; |
| + OnUpgradeError(GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED, hr, false); |
| + return false; |
| } |
| + // Hold a reference on the observer for the lifetime of the driver. |
| + job_holder_ = job_observer_; |
| - base::win::ScopedComPtr<IJobObserver> job_holder(job_observer); |
| - |
| - base::win::ScopedComPtr<IGoogleUpdate> on_demand; |
| - |
| - bool system_level = false; |
| - |
| - if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) { |
| - hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass); |
| - } else { |
| - // The Update operation needs Admin privileges for writing |
| - // to %ProgramFiles%. On Vista, need to elevate before instantiating |
| - // the updater instance. |
| - if (!install_if_newer) { |
| - hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass); |
| - } else { |
| - hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass, |
| - IID_IGoogleUpdate, window, |
| - reinterpret_cast<void**>(on_demand.Receive())); |
| - } |
| - system_level = true; |
| - } |
| + job_observer_->set_on_complete_callback(base::Bind( |
| + &UpdateCheckDriver::CompleteUpdateCheck, base::Unretained(this))); |
| + hr = CreateOnDemandAppsClass(system_level, install_if_newer, elevation_window, |
| + &on_demand_); |
| if (hr != S_OK) { |
| - GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; |
| - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); |
| - if (system_level) |
| - error_code += L" -- system level"; |
| - ReportFailure(hr, error, |
| - l10n_util::GetStringFUTF16( |
| - IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, |
| - error_code), |
| - main_loop); |
| - return; |
| + OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, hr, system_level); |
| + return false; |
| } |
| base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); |
| DCHECK(!app_guid.empty()); |
| - if (!install_if_newer) |
| - hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer); |
| + if (install_if_newer) |
| + hr = on_demand_->Update(app_guid.c_str(), job_observer_); |
| else |
| - hr = on_demand->Update(app_guid.c_str(), job_observer); |
| + hr = on_demand_->CheckForUpdate(app_guid.c_str(), job_observer_); |
| if (hr != S_OK) { |
| - GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; |
| - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); |
| - ReportFailure(hr, error, |
| - l10n_util::GetStringFUTF16( |
| - IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, |
| - error_code), |
| - main_loop); |
| - return; |
| + OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hr, |
| + system_level); |
| + return false; |
| } |
| + return true; |
| +} |
| - // Need to spin the message loop while Google Update is running so that it |
| - // can report back to us through GoogleUpdateJobObserver. This message loop |
| - // will terminate once Google Update sends us the completion status |
| - // (success/error). See OnComplete(). |
| - base::MessageLoop::current()->Run(); |
| +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(); |
| + } |
| + // Release the reference on the COM objects. |
| + on_demand_ = nullptr; |
| + job_observer_ = nullptr; |
| + job_holder_ = nullptr; |
| - GoogleUpdateUpgradeResult results; |
| - hr = job_observer->GetResult(&results); |
| + result_runner_->DeleteSoon(FROM_HERE, this); |
| +} |
| - if (hr != S_OK) { |
| - GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED; |
| - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); |
| - ReportFailure(hr, error, |
| - l10n_util::GetStringFUTF16( |
| - IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, |
| - error_code), |
| - main_loop); |
| - return; |
| - } |
| +void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, |
| + HRESULT hr, |
| + bool system_level) { |
| + result_ = UPGRADE_ERROR; |
| + error_code_ = error_code; |
| + hresult_ = hr; |
| + base::string16 error_msg = |
| + base::StringPrintf(L"%d: 0x%x", error_code_, hresult_); |
| + if (system_level) |
| + error_msg += L" -- system level"; |
| + error_message_ = l10n_util::GetStringFUTF16( |
| + IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, error_msg); |
| +} |
| - if (results == UPGRADE_ERROR) { |
| - base::string16 error_message; |
| - job_observer->GetErrorMessage(&error_message); |
| - ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop); |
| - return; |
| - } |
| +} // namespace |
| - hr = job_observer->GetVersionInfo(&version_available_); |
| - if (hr != S_OK) { |
| - GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED; |
| - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); |
| - ReportFailure(hr, error, |
| - l10n_util::GetStringFUTF16( |
| - IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, |
| - error_code), |
| - main_loop); |
| - return; |
| - } |
| +void CheckForUpdate(bool install_if_newer, |
| + HWND elevation_window, |
| + const UpdateCheckCallback& callback) { |
| + scoped_refptr<base::TaskRunner> task_runner( |
| + content::BrowserThread::GetMessageLoopProxyForThread( |
| + content::BrowserThread::FILE)); |
| - main_loop->PostTask( |
| - FROM_HERE, |
| - base::Bind(&GoogleUpdate::ReportResults, this, |
| - results, GOOGLE_UPDATE_NO_ERROR, base::string16())); |
| - job_holder = NULL; |
| - on_demand = NULL; |
| + internal::CheckForUpdate(task_runner, install_if_newer, elevation_window, |
| + callback); |
| } |
| -void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results, |
| - GoogleUpdateErrorCode error_code, |
| - const base::string16& error_message) { |
| - // If there is an error, then error code must not be blank, and vice versa. |
| - DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR : |
| - error_code == GOOGLE_UPDATE_NO_ERROR); |
| - UMA_HISTOGRAM_ENUMERATION( |
| - "GoogleUpdate.UpgradeResult", results, NUM_UPGRADE_RESULTS); |
| - if (results == UPGRADE_ERROR) { |
| - UMA_HISTOGRAM_ENUMERATION( |
| - "GoogleUpdate.UpdateErrorCode", error_code, NUM_ERROR_CODES); |
| +namespace internal { |
| + |
| +void SetGoogleUpdateFactory( |
| + const OnDemandAppsClassFactory& google_update_factory) { |
| + if (g_google_update_factory) { |
| + delete g_google_update_factory; |
| + g_google_update_factory = nullptr; |
| } |
| - if (listener_) { |
| - listener_->OnReportResults( |
| - results, error_code, error_message, version_available_); |
| + if (!google_update_factory.is_null()) { |
| + g_google_update_factory = |
| + new OnDemandAppsClassFactory(google_update_factory); |
| } |
| } |
| -bool GoogleUpdate::ReportFailure(HRESULT hr, |
| - GoogleUpdateErrorCode error_code, |
| - const base::string16& error_message, |
| - base::MessageLoop* main_loop) { |
| - DLOG(ERROR) << "Communication with Google Update failed: " << hr |
| - << " error: " << error_code |
| - << ", message: " << error_message.c_str(); |
| - UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hr); |
| - main_loop->PostTask( |
| - FROM_HERE, |
| - base::Bind(&GoogleUpdate::ReportResults, this, |
| - UPGRADE_ERROR, error_code, error_message)); |
| - return false; |
| +void CheckForUpdate(const scoped_refptr<base::TaskRunner>& task_runner, |
| + bool install_if_newer, |
| + HWND elevation_window, |
| + const UpdateCheckCallback& callback) { |
| + UpdateCheckDriver::RunUpdateCheck(task_runner, install_if_newer, |
| + elevation_window, callback); |
| } |
| + |
| +} // namespace internal |