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 |