Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/google/google_update_win.h" | 5 #include "chrome/browser/google/google_update_win.h" |
| 6 | 6 |
| 7 #include <atlbase.h> | 7 #include <atlbase.h> |
| 8 #include <atlcom.h> | 8 #include <atlcom.h> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/callback.h" | |
| 11 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 12 #include "base/message_loop/message_loop.h" | 13 #include "base/location.h" |
| 13 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 14 #include "base/metrics/sparse_histogram.h" | 15 #include "base/metrics/sparse_histogram.h" |
| 15 #include "base/path_service.h" | 16 #include "base/path_service.h" |
| 16 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 17 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 18 #include "base/threading/thread.h" | 19 #include "base/task_runner.h" |
| 19 #include "base/win/scoped_comptr.h" | 20 #include "base/thread_task_runner_handle.h" |
| 20 #include "base/win/windows_version.h" | 21 #include "base/win/windows_version.h" |
| 21 #include "chrome/grit/generated_resources.h" | 22 #include "chrome/grit/generated_resources.h" |
| 22 #include "chrome/installer/util/browser_distribution.h" | 23 #include "chrome/installer/util/browser_distribution.h" |
| 23 #include "chrome/installer/util/google_update_settings.h" | 24 #include "chrome/installer/util/google_update_settings.h" |
| 24 #include "chrome/installer/util/helper.h" | 25 #include "chrome/installer/util/helper.h" |
| 25 #include "chrome/installer/util/install_util.h" | 26 #include "chrome/installer/util/install_util.h" |
| 26 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" |
| 27 #include "google_update/google_update_idl.h" | |
| 28 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
| 29 #include "ui/base/win/atl_module.h" | 29 #include "ui/base/win/atl_module.h" |
| 30 #include "ui/views/widget/widget.h" | |
| 31 | |
| 32 using content::BrowserThread; | |
| 33 | 30 |
| 34 namespace { | 31 namespace { |
| 35 | 32 |
| 33 internal::OnDemandAppsClassFactory* g_google_update_factory = nullptr; | |
| 34 | |
| 36 // Check if the currently running instance can be updated by Google Update. | 35 // Check if the currently running instance can be updated by Google Update. |
| 37 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google | 36 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google |
| 38 // Chrome distribution installed in a standard location. | 37 // Chrome distribution installed in a standard location. |
| 39 GoogleUpdateErrorCode CanUpdateCurrentChrome( | 38 GoogleUpdateErrorCode CanUpdateCurrentChrome( |
| 40 const base::FilePath& chrome_exe_path) { | 39 const base::FilePath& chrome_exe_path, |
| 40 bool system_level) { | |
| 41 #if !defined(GOOGLE_CHROME_BUILD) | 41 #if !defined(GOOGLE_CHROME_BUILD) |
| 42 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; | 42 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; |
| 43 #else | 43 #else |
| 44 // TODO(tommi): Check if using the default distribution is always the right | 44 DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()), |
| 45 // thing to do. | 45 system_level); |
| 46 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | 46 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| 47 base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist); | 47 base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist); |
| 48 base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist); | 48 base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist); |
| 49 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), | 49 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), |
| 50 user_exe_path.value()) && | 50 user_exe_path.value()) && |
| 51 !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), | 51 !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), |
| 52 machine_exe_path.value())) { | 52 machine_exe_path.value())) { |
| 53 LOG(ERROR) << L"Google Update cannot update Chrome installed in a " | |
| 54 << L"non-standard location: " << chrome_exe_path.value().c_str() | |
| 55 << L". The standard location is: " | |
| 56 << user_exe_path.value().c_str() | |
| 57 << L" or " << machine_exe_path.value().c_str() << L"."; | |
| 58 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; | 53 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; |
| 59 } | 54 } |
| 60 | 55 |
| 61 base::string16 app_guid = installer::GetAppGuidForUpdates( | 56 base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); |
| 62 !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str())); | |
| 63 DCHECK(!app_guid.empty()); | 57 DCHECK(!app_guid.empty()); |
| 64 | 58 |
| 65 GoogleUpdateSettings::UpdatePolicy update_policy = | 59 GoogleUpdateSettings::UpdatePolicy update_policy = |
| 66 GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL); | 60 GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL); |
| 67 | 61 |
| 68 if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED) | 62 if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED) |
| 69 return GOOGLE_UPDATE_DISABLED_BY_POLICY; | 63 return GOOGLE_UPDATE_DISABLED_BY_POLICY; |
| 70 | 64 |
| 71 if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY) | 65 if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY) |
| 72 return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY; | 66 return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY; |
| 73 | 67 |
| 74 return GOOGLE_UPDATE_NO_ERROR; | 68 return GOOGLE_UPDATE_NO_ERROR; |
| 75 #endif | 69 #endif |
| 76 } | 70 } |
| 77 | 71 |
| 78 // Creates an instance of a COM Local Server class using either plain vanilla | 72 // Creates an instance of a COM Local Server class using either plain vanilla |
| 79 // CoCreateInstance, or using the Elevation moniker if running on Vista. | 73 // CoCreateInstance, or using the Elevation moniker if running on Vista. |
| 80 // hwnd must refer to a foregound window in order to get the UAC prompt | 74 // hwnd must refer to a foregound window in order to get the UAC prompt |
| 81 // showing up in the foreground if running on Vista. It can also be NULL if | 75 // showing up in the foreground if running on Vista. It can also be NULL if |
| 82 // background UAC prompts are desired. | 76 // background UAC prompts are desired. |
| 83 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id, | 77 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id, |
| 84 HWND hwnd, void** interface_ptr) { | 78 HWND hwnd, void** interface_ptr) { |
| 85 if (!interface_ptr) | 79 if (!interface_ptr) |
| 86 return E_POINTER; | 80 return E_POINTER; |
| 87 | 81 |
| 88 // For Vista, need to instantiate the COM server via the elevation | 82 // For Vista, need to instantiate the COM server via the elevation |
| 89 // moniker. This ensures that the UAC dialog shows up. | 83 // moniker. This ensures that the UAC dialog shows up. |
| 90 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { | 84 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
| 91 wchar_t class_id_as_string[MAX_PATH] = {0}; | 85 wchar_t class_id_as_string[MAX_PATH] = {}; |
| 92 StringFromGUID2(class_id, class_id_as_string, | 86 StringFromGUID2(class_id, class_id_as_string, |
| 93 arraysize(class_id_as_string)); | 87 arraysize(class_id_as_string)); |
| 94 | 88 |
| 95 base::string16 elevation_moniker_name = | 89 base::string16 elevation_moniker_name = |
| 96 base::StringPrintf(L"Elevation:Administrator!new:%ls", | 90 base::StringPrintf(L"Elevation:Administrator!new:%ls", |
| 97 class_id_as_string); | 91 class_id_as_string); |
| 98 | 92 |
| 99 BIND_OPTS3 bind_opts; | 93 BIND_OPTS3 bind_opts = {}; |
| 100 memset(&bind_opts, 0, sizeof(bind_opts)); | |
| 101 bind_opts.cbStruct = sizeof(bind_opts); | 94 bind_opts.cbStruct = sizeof(bind_opts); |
| 102 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER; | 95 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER; |
| 103 bind_opts.hwnd = hwnd; | 96 bind_opts.hwnd = hwnd; |
| 104 | 97 |
| 105 return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, | 98 return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id, |
| 106 interface_id, reinterpret_cast<void**>(interface_ptr)); | 99 interface_ptr); |
| 107 } | 100 } |
| 108 | 101 |
| 109 return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, | 102 return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, interface_id, |
| 110 interface_id, | 103 interface_ptr); |
| 111 reinterpret_cast<void**>(interface_ptr)); | |
| 112 } | 104 } |
| 113 | 105 |
| 106 HRESULT CreateOnDemandAppsClass( | |
| 107 bool system_level, | |
| 108 bool install_if_newer, | |
| 109 HWND elevation_window, | |
| 110 base::win::ScopedComPtr<IGoogleUpdate>* on_demand) { | |
| 111 if (g_google_update_factory) | |
| 112 return g_google_update_factory->Run(on_demand); | |
| 114 | 113 |
| 115 } // namespace | 114 // For a user-level install, update checks and updates can both be done by a |
| 115 // normal user with the UserAppsClass. | |
| 116 if (!system_level) | |
| 117 return on_demand->CreateInstance(CLSID_OnDemandUserAppsClass); | |
| 118 | |
| 119 // For a system-level install, update checks can be done by a normal user with | |
| 120 // the MachineAppsClass. | |
| 121 if (!install_if_newer) | |
| 122 return on_demand->CreateInstance(CLSID_OnDemandMachineAppsClass); | |
| 123 | |
| 124 // For a system-level install, an update requires Admin privileges for writing | |
| 125 // to %ProgramFiles%. Elevate while instantiating the MachineAppsClass. | |
| 126 return CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass, | |
| 127 IID_IGoogleUpdate, elevation_window, | |
| 128 on_demand->ReceiveVoid()); | |
| 129 } | |
| 116 | 130 |
| 117 // The GoogleUpdateJobObserver COM class is responsible for receiving status | 131 // The GoogleUpdateJobObserver COM class is responsible for receiving status |
| 118 // reports from google Update. It keeps track of the progress as GoogleUpdate | 132 // reports from google Update. It keeps track of the progress as Google Update |
| 119 // notifies this observer and ends the message loop that is spinning in once | 133 // notifies this observer and runs a completion callback once Google Update |
| 120 // GoogleUpdate reports that it is done. | 134 // reports that it is done. |
| 121 class GoogleUpdateJobObserver | 135 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.
| |
| 122 : public CComObjectRootEx<CComSingleThreadModel>, | 136 public IJobObserver { |
| 123 public IJobObserver { | |
| 124 public: | 137 public: |
| 125 BEGIN_COM_MAP(GoogleUpdateJobObserver) | 138 BEGIN_COM_MAP(GoogleUpdateJobObserver) |
| 126 COM_INTERFACE_ENTRY(IJobObserver) | 139 COM_INTERFACE_ENTRY(IJobObserver) |
| 127 END_COM_MAP() | 140 END_COM_MAP() |
| 128 | 141 |
| 129 GoogleUpdateJobObserver() | 142 GoogleUpdateJobObserver(); |
| 130 : result_(UPGRADE_ERROR) { | 143 virtual ~GoogleUpdateJobObserver(); |
| 131 } | |
| 132 virtual ~GoogleUpdateJobObserver() {} | |
| 133 | 144 |
| 134 // Notifications from Google Update: | 145 // Sets the callback to be invoked when Google Update reports that the job is |
| 135 STDMETHOD(OnShow)() { | 146 // done. |
| 136 return S_OK; | 147 void set_on_complete_callback(const base::Closure& on_complete_callback) { |
| 137 } | 148 on_complete_callback_ = on_complete_callback; |
| 138 STDMETHOD(OnCheckingForUpdate)() { | |
| 139 result_ = UPGRADE_CHECK_STARTED; | |
| 140 return S_OK; | |
| 141 } | |
| 142 STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) { | |
| 143 result_ = UPGRADE_IS_AVAILABLE; | |
| 144 new_version_ = version_string; | |
| 145 return S_OK; | |
| 146 } | |
| 147 STDMETHOD(OnWaitingToDownload)() { | |
| 148 return S_OK; | |
| 149 } | |
| 150 STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) { | |
| 151 return S_OK; | |
| 152 } | |
| 153 STDMETHOD(OnWaitingToInstall)() { | |
| 154 return S_OK; | |
| 155 } | |
| 156 STDMETHOD(OnInstalling)() { | |
| 157 result_ = UPGRADE_STARTED; | |
| 158 return S_OK; | |
| 159 } | |
| 160 STDMETHOD(OnPause)() { | |
| 161 return S_OK; | |
| 162 } | |
| 163 STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) { | |
| 164 switch (code) { | |
| 165 case COMPLETION_CODE_SUCCESS_CLOSE_UI: | |
| 166 case COMPLETION_CODE_SUCCESS: { | |
| 167 if (result_ == UPGRADE_STARTED) | |
| 168 result_ = UPGRADE_SUCCESSFUL; | |
| 169 else if (result_ == UPGRADE_CHECK_STARTED) | |
| 170 result_ = UPGRADE_ALREADY_UP_TO_DATE; | |
| 171 break; | |
| 172 } | |
| 173 case COMPLETION_CODE_ERROR: | |
| 174 error_message_ = text; | |
| 175 default: { | |
| 176 NOTREACHED(); | |
| 177 result_ = UPGRADE_ERROR; | |
| 178 break; | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 event_sink_ = NULL; | |
| 183 | |
| 184 // No longer need to spin the message loop that started spinning in | |
| 185 // InitiateGoogleUpdateCheck. | |
| 186 base::MessageLoop::current()->Quit(); | |
| 187 return S_OK; | |
| 188 } | |
| 189 STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) { | |
| 190 event_sink_ = event_sink; | |
| 191 return S_OK; | |
| 192 } | 149 } |
| 193 | 150 |
| 194 // Returns the results of the update operation. | 151 // Returns the results of the update operation. |
| 195 STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) { | 152 GoogleUpdateUpgradeResult result() const { |
| 196 // Intermediary steps should never be reported to the client. | 153 // Intermediary steps should never be reported to the client. |
| 197 DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED); | 154 DCHECK_NE(result_, UPGRADE_STARTED); |
| 198 | 155 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
| |
| 199 *result = result_; | 156 return result_; |
| 200 return S_OK; | |
| 201 } | 157 } |
| 202 | 158 |
| 203 // Returns which version Google Update found on the server (if a more | 159 // Returns which version Google Update found on the server (if a more |
| 204 // recent version was found). Otherwise, this will be blank. | 160 // recent version was found). Otherwise, this will be blank. |
| 205 STDMETHOD(GetVersionInfo)(base::string16* version_string) { | 161 base::string16 new_version() const { return new_version_; } |
| 206 *version_string = new_version_; | |
| 207 return S_OK; | |
| 208 } | |
| 209 | 162 |
| 210 // Returns the Google Update supplied error string that describes the error | 163 // Returns the Google Update supplied error string that describes the error |
| 211 // that occurred during the update check/upgrade. | 164 // that occurred during the update check/upgrade. |
| 212 STDMETHOD(GetErrorMessage)(base::string16* error_message) { | 165 base::string16 error_message() const { return error_message_; } |
| 213 *error_message = error_message_; | |
| 214 return S_OK; | |
| 215 } | |
| 216 | 166 |
| 217 private: | 167 private: |
| 168 // IJobObserver: | |
| 169 STDMETHOD(OnShow)(); | |
| 170 STDMETHOD(OnCheckingForUpdate)(); | |
| 171 STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string); | |
| 172 STDMETHOD(OnWaitingToDownload)(); | |
| 173 STDMETHOD(OnDownloading)(int time_remaining_ms, int pos); | |
| 174 STDMETHOD(OnWaitingToInstall)(); | |
| 175 STDMETHOD(OnInstalling)(); | |
| 176 STDMETHOD(OnPause)(); | |
| 177 STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text); | |
| 178 STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink); | |
| 179 | |
| 180 // The task runner associated with the thread in which the job runs. | |
| 181 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
| 182 | |
| 183 // A callback to be run to complete processing; | |
| 184 base::Closure on_complete_callback_; | |
| 185 | |
| 218 // The status/result of the Google Update operation. | 186 // The status/result of the Google Update operation. |
| 219 GoogleUpdateUpgradeResult result_; | 187 GoogleUpdateUpgradeResult result_; |
| 220 | 188 |
| 221 // The version string Google Update found. | 189 // The version string Google Update found. |
| 222 base::string16 new_version_; | 190 base::string16 new_version_; |
| 223 | 191 |
| 224 // An error message, if any. | 192 // An error message, if any. |
| 225 base::string16 error_message_; | 193 base::string16 error_message_; |
| 226 | 194 |
| 227 // Allows us control the upgrade process to a small degree. After OnComplete | 195 // Allows us control the upgrade process to a small degree. After OnComplete |
| 228 // has been called, this object can not be used. | 196 // has been called, this object can not be used. |
| 229 base::win::ScopedComPtr<IProgressWndEvents> event_sink_; | 197 base::win::ScopedComPtr<IProgressWndEvents> event_sink_; |
| 198 | |
| 199 DISALLOW_COPY_AND_ASSIGN(GoogleUpdateJobObserver); | |
| 230 }; | 200 }; |
| 231 | 201 |
| 232 //////////////////////////////////////////////////////////////////////////////// | 202 GoogleUpdateJobObserver::GoogleUpdateJobObserver() |
| 233 // GoogleUpdate, public: | 203 : task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 234 | 204 result_(UPGRADE_ERROR) { |
| 235 GoogleUpdate::GoogleUpdate() | 205 } |
| 236 : listener_(NULL) { | 206 |
| 237 } | 207 GoogleUpdateJobObserver::~GoogleUpdateJobObserver() { |
| 238 | 208 } |
| 239 GoogleUpdate::~GoogleUpdate() { | 209 |
| 240 } | 210 STDMETHODIMP GoogleUpdateJobObserver::OnShow() { |
| 241 | 211 return S_OK; |
| 242 void GoogleUpdate::CheckForUpdate(bool install_if_newer, HWND window) { | 212 } |
| 243 // Need to shunt this request over to InitiateGoogleUpdateCheck and have | 213 |
| 244 // it run in the file thread. | 214 STDMETHODIMP GoogleUpdateJobObserver::OnCheckingForUpdate() { |
| 245 BrowserThread::PostTask( | 215 result_ = UPGRADE_CHECK_STARTED; |
| 246 BrowserThread::FILE, FROM_HERE, | 216 return S_OK; |
| 247 base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this, | 217 } |
| 248 install_if_newer, window, base::MessageLoop::current())); | 218 |
| 249 } | 219 STDMETHODIMP GoogleUpdateJobObserver::OnUpdateAvailable( |
| 250 | 220 const TCHAR* version_string) { |
| 251 //////////////////////////////////////////////////////////////////////////////// | 221 result_ = UPGRADE_IS_AVAILABLE; |
| 252 // GoogleUpdate, private: | 222 new_version_ = version_string; |
| 253 | 223 return S_OK; |
| 254 void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer, | 224 } |
| 255 HWND window, | 225 |
| 256 base::MessageLoop* main_loop) { | 226 STDMETHODIMP GoogleUpdateJobObserver::OnWaitingToDownload() { |
| 227 return S_OK; | |
| 228 } | |
| 229 | |
| 230 STDMETHODIMP GoogleUpdateJobObserver::OnDownloading(int time_remaining_ms, | |
| 231 int pos) { | |
| 232 return S_OK; | |
| 233 } | |
| 234 | |
| 235 STDMETHODIMP GoogleUpdateJobObserver::OnWaitingToInstall() { | |
| 236 return S_OK; | |
| 237 } | |
| 238 | |
| 239 STDMETHODIMP GoogleUpdateJobObserver::OnInstalling() { | |
| 240 result_ = UPGRADE_STARTED; | |
| 241 return S_OK; | |
| 242 } | |
| 243 | |
| 244 STDMETHODIMP GoogleUpdateJobObserver::OnPause() { | |
| 245 return S_OK; | |
| 246 } | |
| 247 | |
| 248 STDMETHODIMP GoogleUpdateJobObserver::OnComplete(LegacyCompletionCodes code, | |
| 249 const TCHAR* text) { | |
| 250 if (code == COMPLETION_CODE_ERROR) { | |
| 251 error_message_ = text; | |
| 252 result_ = UPGRADE_ERROR; | |
| 253 } else { | |
| 254 // Everything that isn't an error is some form of success. Chrome doesn't | |
| 255 // support any of the fancy codes (e.g., COMPLETION_CODE_REBOOT), but they | |
| 256 // shouldn't be generated anyway. | |
| 257 LOG_IF(DFATAL, (code != COMPLETION_CODE_SUCCESS && | |
| 258 code != COMPLETION_CODE_SUCCESS_CLOSE_UI)) | |
| 259 << "Unexpected LegacyCompletionCode from IGoogleUpdate: " << code; | |
| 260 if (result_ == UPGRADE_STARTED) | |
| 261 result_ = UPGRADE_SUCCESSFUL; | |
| 262 else if (result_ == UPGRADE_CHECK_STARTED) | |
| 263 result_ = UPGRADE_ALREADY_UP_TO_DATE; | |
| 264 } | |
| 265 | |
| 266 event_sink_ = NULL; | |
| 267 | |
| 268 task_runner_->PostTask(FROM_HERE, on_complete_callback_); | |
| 269 return S_OK; | |
| 270 } | |
| 271 | |
| 272 STDMETHODIMP GoogleUpdateJobObserver::SetEventSink( | |
| 273 IProgressWndEvents* event_sink) { | |
| 274 event_sink_ = event_sink; | |
| 275 return S_OK; | |
| 276 } | |
| 277 | |
| 278 // A driver that is created and destroyed on the caller's thread and drives | |
| 279 // Google Update on another. | |
| 280 class UpdateCheckDriver { | |
| 281 public: | |
| 282 // Runs an update check on |task_runner|, invoking |callback| on the caller's | |
| 283 // thread upon completion. | |
| 284 static void RunUpdateCheck(const scoped_refptr<base::TaskRunner>& task_runner, | |
| 285 bool install_if_newer, | |
| 286 HWND elevation_window, | |
| 287 const UpdateCheckCallback& callback); | |
| 288 | |
| 289 private: | |
| 290 friend class base::DeleteHelper<UpdateCheckDriver>; | |
| 291 | |
| 292 explicit UpdateCheckDriver(const UpdateCheckCallback& callback); | |
| 293 | |
| 294 // Runs the caller's update check callback with the results of the operation. | |
| 295 ~UpdateCheckDriver(); | |
| 296 | |
| 297 // Starts an update check. | |
| 298 void BeginUpdateCheck(bool install_if_newer, HWND elevation_window); | |
| 299 | |
| 300 // Helper function for starting an update check. Returns true if the check was | |
| 301 // properly started, in which case CompleteUpdateCheck will be invoked upon | |
| 302 // completion to return results to the caller on its own thread. | |
| 303 bool BeginUpdateCheckInternal(bool install_if_newer, HWND elevation_window); | |
| 304 | |
| 305 // Invoked when results are in from Google Update. | |
| 306 void CompleteUpdateCheck(); | |
| 307 | |
| 308 // Prepares |results| to return the upgrade error indicated by |error_code| | |
| 309 // and |hr|. The string " -- system level" is included in the generated error | |
| 310 // message when |system_level| is true. | |
| 311 void OnUpgradeError(GoogleUpdateErrorCode error_code, | |
| 312 HRESULT hr, | |
| 313 bool system_level); | |
| 314 | |
| 315 // The caller's task runner, on which |result_callback_| will be run. | |
| 316 scoped_refptr<base::SingleThreadTaskRunner> result_runner_; | |
| 317 | |
| 318 // The caller's callback to be run when the update check is compelte. | |
| 319 UpdateCheckCallback result_callback_; | |
| 320 | |
| 321 // The results of the update check. | |
| 322 GoogleUpdateUpgradeResult result_; | |
| 323 GoogleUpdateErrorCode error_code_; | |
| 324 base::string16 error_message_; | |
| 325 base::string16 version_; | |
| 326 HRESULT hresult_; | |
| 327 | |
| 328 // A direct pointer to the job observer by which the driver is notified of | |
| 329 // interesting events from Google Update. | |
| 330 CComObject<GoogleUpdateJobObserver>* job_observer_; | |
| 331 | |
| 332 // A scoped pointer to |job_observer_| that holds a reference to it, keeping | |
| 333 // it alive. | |
| 334 base::win::ScopedComPtr<IJobObserver> job_holder_; | |
| 335 | |
| 336 // The on-demand updater that is doing the work. | |
| 337 base::win::ScopedComPtr<IGoogleUpdate> on_demand_; | |
| 338 | |
| 339 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver); | |
| 340 }; | |
| 341 | |
| 342 // static | |
| 343 void UpdateCheckDriver::RunUpdateCheck( | |
| 344 const scoped_refptr<base::TaskRunner>& task_runner, | |
| 345 bool install_if_newer, | |
| 346 HWND elevation_window, | |
| 347 const UpdateCheckCallback& callback) { | |
| 348 // The driver is owned by itself, and will self-destruct when its work is | |
| 349 // done. | |
| 350 UpdateCheckDriver* driver = new UpdateCheckDriver(callback); | |
| 351 task_runner->PostTask( | |
| 352 FROM_HERE, | |
| 353 base::Bind(&UpdateCheckDriver::BeginUpdateCheck, base::Unretained(driver), | |
| 354 install_if_newer, elevation_window)); | |
| 355 } | |
| 356 | |
| 357 // Runs on the caller's thread. | |
| 358 UpdateCheckDriver::UpdateCheckDriver(const UpdateCheckCallback& callback) | |
| 359 : result_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 360 result_callback_(callback), | |
| 361 result_(UPGRADE_ERROR), | |
| 362 error_code_(GOOGLE_UPDATE_NO_ERROR), | |
| 363 hresult_(S_OK), | |
| 364 job_observer_(nullptr) { | |
| 365 } | |
| 366 | |
| 367 UpdateCheckDriver::~UpdateCheckDriver() { | |
| 368 DCHECK(result_runner_->BelongsToCurrentThread()); | |
| 369 // If there is an error, then error_code must not be blank, and vice versa. | |
| 370 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
| |
| 371 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", result_, | |
| 372 NUM_UPGRADE_RESULTS); | |
| 373 if (result_ == UPGRADE_ERROR) { | |
| 374 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_, | |
| 375 NUM_ERROR_CODES); | |
| 376 if (hresult_ != S_OK) | |
| 377 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_); | |
| 378 } | |
| 379 result_callback_.Run(result_, error_code_, error_message_, version_); | |
| 380 } | |
| 381 | |
| 382 void UpdateCheckDriver::BeginUpdateCheck(bool install_if_newer, | |
| 383 HWND elevation_window) { | |
| 384 // Return results immediately if the driver is not waiting for Google Update. | |
| 385 if (!BeginUpdateCheckInternal(install_if_newer, elevation_window)) | |
| 386 result_runner_->DeleteSoon(FROM_HERE, this); | |
| 387 } | |
| 388 | |
| 389 bool UpdateCheckDriver::BeginUpdateCheckInternal(bool install_if_newer, | |
| 390 HWND elevation_window) { | |
| 257 base::FilePath chrome_exe; | 391 base::FilePath chrome_exe; |
| 258 if (!PathService::Get(base::DIR_EXE, &chrome_exe)) | 392 if (!PathService::Get(base::DIR_EXE, &chrome_exe)) |
| 259 NOTREACHED(); | 393 NOTREACHED(); |
| 260 | 394 |
| 261 GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe); | 395 const bool system_level = |
| 262 if (error_code != GOOGLE_UPDATE_NO_ERROR) { | 396 !InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()); |
| 263 main_loop->PostTask( | 397 |
| 264 FROM_HERE, | 398 // The failures handled here are: |
| 265 base::Bind(&GoogleUpdate::ReportResults, this, | 399 // CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY, |
| 266 UPGRADE_ERROR, error_code, base::string16())); | 400 // GOOGLE_UPDATE_DISABLED_BY_POLICY, and |
| 267 return; | 401 // GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY. |
| 402 error_code_ = CanUpdateCurrentChrome(chrome_exe, system_level); | |
| 403 if (error_code_ != GOOGLE_UPDATE_NO_ERROR) { | |
| 404 // These failures are handled in the UX with custom messages. | |
| 405 result_ = UPGRADE_ERROR; | |
| 406 return false; | |
| 268 } | 407 } |
| 269 | 408 |
| 270 // Make sure ATL is initialized in this module. | 409 // Make sure ATL is initialized in this module. |
| 271 ui::win::CreateATLModuleIfNeeded(); | 410 ui::win::CreateATLModuleIfNeeded(); |
| 272 | 411 |
| 273 CComObject<GoogleUpdateJobObserver>* job_observer; | |
| 274 HRESULT hr = | 412 HRESULT hr = |
| 275 CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer); | 413 CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer_); |
| 276 if (hr != S_OK) { | 414 if (hr != S_OK) { |
| 277 // Most of the error messages come straight from Google Update. This one is | 415 // Most of the error messages come straight from Google Update. This one is |
| 278 // deemed worthy enough to also warrant its own error. | 416 // deemed worthy enough to also warrant its own error. |
| 279 GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED; | 417 OnUpgradeError(GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED, hr, false); |
| 280 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | 418 return false; |
| 281 ReportFailure( | 419 } |
| 282 hr, error, | 420 // Hold a reference on the observer for the lifetime of the driver. |
| 283 l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | 421 job_holder_ = job_observer_; |
| 284 error_code), | 422 |
| 285 main_loop); | 423 job_observer_->set_on_complete_callback(base::Bind( |
| 286 return; | 424 &UpdateCheckDriver::CompleteUpdateCheck, base::Unretained(this))); |
| 287 } | 425 |
| 288 | 426 hr = CreateOnDemandAppsClass(system_level, install_if_newer, elevation_window, |
| 289 base::win::ScopedComPtr<IJobObserver> job_holder(job_observer); | 427 &on_demand_); |
| 290 | |
| 291 base::win::ScopedComPtr<IGoogleUpdate> on_demand; | |
| 292 | |
| 293 bool system_level = false; | |
| 294 | |
| 295 if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) { | |
| 296 hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass); | |
| 297 } else { | |
| 298 // The Update operation needs Admin privileges for writing | |
| 299 // to %ProgramFiles%. On Vista, need to elevate before instantiating | |
| 300 // the updater instance. | |
| 301 if (!install_if_newer) { | |
| 302 hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass); | |
| 303 } else { | |
| 304 hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass, | |
| 305 IID_IGoogleUpdate, window, | |
| 306 reinterpret_cast<void**>(on_demand.Receive())); | |
| 307 } | |
| 308 system_level = true; | |
| 309 } | |
| 310 | |
| 311 if (hr != S_OK) { | 428 if (hr != S_OK) { |
| 312 GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; | 429 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, hr, system_level); |
| 313 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | 430 return false; |
| 314 if (system_level) | |
| 315 error_code += L" -- system level"; | |
| 316 ReportFailure(hr, error, | |
| 317 l10n_util::GetStringFUTF16( | |
| 318 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | |
| 319 error_code), | |
| 320 main_loop); | |
| 321 return; | |
| 322 } | 431 } |
| 323 | 432 |
| 324 base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); | 433 base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); |
| 325 DCHECK(!app_guid.empty()); | 434 DCHECK(!app_guid.empty()); |
| 326 | 435 |
| 327 if (!install_if_newer) | 436 if (install_if_newer) |
| 328 hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer); | 437 hr = on_demand_->Update(app_guid.c_str(), job_observer_); |
| 329 else | 438 else |
| 330 hr = on_demand->Update(app_guid.c_str(), job_observer); | 439 hr = on_demand_->CheckForUpdate(app_guid.c_str(), job_observer_); |
| 331 | 440 |
| 332 if (hr != S_OK) { | 441 if (hr != S_OK) { |
| 333 GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; | 442 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hr, |
| 334 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | 443 system_level); |
| 335 ReportFailure(hr, error, | 444 return false; |
| 336 l10n_util::GetStringFUTF16( | 445 } |
| 337 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | 446 return true; |
| 338 error_code), | 447 } |
| 339 main_loop); | 448 |
| 340 return; | 449 void UpdateCheckDriver::CompleteUpdateCheck() { |
| 341 } | 450 result_ = job_observer_->result(); |
| 342 | 451 if (result_ == UPGRADE_ERROR) { |
| 343 // Need to spin the message loop while Google Update is running so that it | 452 error_code_ = GOOGLE_UPDATE_ERROR_UPDATING; |
| 344 // can report back to us through GoogleUpdateJobObserver. This message loop | 453 error_message_ = job_observer_->error_message(); |
| 345 // will terminate once Google Update sends us the completion status | 454 } else { |
| 346 // (success/error). See OnComplete(). | 455 version_ = job_observer_->new_version(); |
| 347 base::MessageLoop::current()->Run(); | 456 } |
| 348 | 457 // Release the reference on the COM objects. |
| 349 GoogleUpdateUpgradeResult results; | 458 on_demand_ = nullptr; |
| 350 hr = job_observer->GetResult(&results); | 459 job_observer_ = nullptr; |
| 351 | 460 job_holder_ = nullptr; |
| 352 if (hr != S_OK) { | 461 |
| 353 GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED; | 462 result_runner_->DeleteSoon(FROM_HERE, this); |
| 354 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | 463 } |
| 355 ReportFailure(hr, error, | 464 |
| 356 l10n_util::GetStringFUTF16( | 465 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, |
| 357 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | 466 HRESULT hr, |
| 358 error_code), | 467 bool system_level) { |
| 359 main_loop); | 468 result_ = UPGRADE_ERROR; |
| 360 return; | 469 error_code_ = error_code; |
| 361 } | 470 hresult_ = hr; |
| 362 | 471 base::string16 error_msg = |
| 363 if (results == UPGRADE_ERROR) { | 472 base::StringPrintf(L"%d: 0x%x", error_code_, hresult_); |
| 364 base::string16 error_message; | 473 if (system_level) |
| 365 job_observer->GetErrorMessage(&error_message); | 474 error_msg += L" -- system level"; |
| 366 ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop); | 475 error_message_ = l10n_util::GetStringFUTF16( |
| 367 return; | 476 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, error_msg); |
| 368 } | 477 } |
| 369 | 478 |
| 370 hr = job_observer->GetVersionInfo(&version_available_); | 479 } // namespace |
| 371 if (hr != S_OK) { | 480 |
| 372 GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED; | 481 void CheckForUpdate(bool install_if_newer, |
| 373 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | 482 HWND elevation_window, |
| 374 ReportFailure(hr, error, | 483 const UpdateCheckCallback& callback) { |
| 375 l10n_util::GetStringFUTF16( | 484 scoped_refptr<base::TaskRunner> task_runner( |
| 376 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | 485 content::BrowserThread::GetMessageLoopProxyForThread( |
| 377 error_code), | 486 content::BrowserThread::FILE)); |
| 378 main_loop); | 487 |
| 379 return; | 488 internal::CheckForUpdate(task_runner, install_if_newer, elevation_window, |
| 380 } | 489 callback); |
| 381 | 490 } |
| 382 main_loop->PostTask( | 491 |
| 383 FROM_HERE, | 492 namespace internal { |
| 384 base::Bind(&GoogleUpdate::ReportResults, this, | 493 |
| 385 results, GOOGLE_UPDATE_NO_ERROR, base::string16())); | 494 void SetGoogleUpdateFactory( |
| 386 job_holder = NULL; | 495 const OnDemandAppsClassFactory& google_update_factory) { |
| 387 on_demand = NULL; | 496 if (g_google_update_factory) { |
| 388 } | 497 delete g_google_update_factory; |
| 389 | 498 g_google_update_factory = nullptr; |
| 390 void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results, | 499 } |
| 391 GoogleUpdateErrorCode error_code, | 500 if (!google_update_factory.is_null()) { |
| 392 const base::string16& error_message) { | 501 g_google_update_factory = |
| 393 // If there is an error, then error code must not be blank, and vice versa. | 502 new OnDemandAppsClassFactory(google_update_factory); |
| 394 DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR : | 503 } |
| 395 error_code == GOOGLE_UPDATE_NO_ERROR); | 504 } |
| 396 UMA_HISTOGRAM_ENUMERATION( | 505 |
| 397 "GoogleUpdate.UpgradeResult", results, NUM_UPGRADE_RESULTS); | 506 void CheckForUpdate(const scoped_refptr<base::TaskRunner>& task_runner, |
| 398 if (results == UPGRADE_ERROR) { | 507 bool install_if_newer, |
| 399 UMA_HISTOGRAM_ENUMERATION( | 508 HWND elevation_window, |
| 400 "GoogleUpdate.UpdateErrorCode", error_code, NUM_ERROR_CODES); | 509 const UpdateCheckCallback& callback) { |
| 401 } | 510 UpdateCheckDriver::RunUpdateCheck(task_runner, install_if_newer, |
| 402 if (listener_) { | 511 elevation_window, callback); |
| 403 listener_->OnReportResults( | 512 } |
| 404 results, error_code, error_message, version_available_); | 513 |
| 405 } | 514 } // namespace internal |
| 406 } | |
| 407 | |
| 408 bool GoogleUpdate::ReportFailure(HRESULT hr, | |
| 409 GoogleUpdateErrorCode error_code, | |
| 410 const base::string16& error_message, | |
| 411 base::MessageLoop* main_loop) { | |
| 412 DLOG(ERROR) << "Communication with Google Update failed: " << hr | |
| 413 << " error: " << error_code | |
| 414 << ", message: " << error_message.c_str(); | |
| 415 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hr); | |
| 416 main_loop->PostTask( | |
| 417 FROM_HERE, | |
| 418 base::Bind(&GoogleUpdate::ReportResults, this, | |
| 419 UPGRADE_ERROR, error_code, error_message)); | |
| 420 return false; | |
| 421 } | |
| OLD | NEW |