| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/google/google_update.h" | |
| 6 | |
| 7 #include <atlbase.h> | |
| 8 #include <atlcom.h> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/file_path.h" | |
| 12 #include "base/message_loop.h" | |
| 13 #include "base/path_service.h" | |
| 14 #include "base/string_util.h" | |
| 15 #include "base/stringprintf.h" | |
| 16 #include "base/threading/thread.h" | |
| 17 #include "base/win/scoped_comptr.h" | |
| 18 #include "base/win/windows_version.h" | |
| 19 #include "chrome/installer/util/browser_distribution.h" | |
| 20 #include "chrome/installer/util/google_update_settings.h" | |
| 21 #include "chrome/installer/util/helper.h" | |
| 22 #include "chrome/installer/util/install_util.h" | |
| 23 #include "content/public/browser/browser_thread.h" | |
| 24 #include "google_update/google_update_idl.h" | |
| 25 #include "grit/generated_resources.h" | |
| 26 #include "ui/base/l10n/l10n_util.h" | |
| 27 #include "ui/views/widget/widget.h" | |
| 28 | |
| 29 using content::BrowserThread; | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 // Check if the currently running instance can be updated by Google Update. | |
| 34 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google | |
| 35 // Chrome distribution installed in a standard location. | |
| 36 GoogleUpdateErrorCode CanUpdateCurrentChrome( | |
| 37 const FilePath& chrome_exe_path) { | |
| 38 #if !defined(GOOGLE_CHROME_BUILD) | |
| 39 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; | |
| 40 #else | |
| 41 // TODO(tommi): Check if using the default distribution is always the right | |
| 42 // thing to do. | |
| 43 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 44 FilePath user_exe_path = installer::GetChromeInstallPath(false, dist); | |
| 45 FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist); | |
| 46 if (!FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), | |
| 47 user_exe_path.value()) && | |
| 48 !FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), | |
| 49 machine_exe_path.value())) { | |
| 50 LOG(ERROR) << L"Google Update cannot update Chrome installed in a " | |
| 51 << L"non-standard location: " << chrome_exe_path.value().c_str() | |
| 52 << L". The standard location is: " | |
| 53 << user_exe_path.value().c_str() | |
| 54 << L" or " << machine_exe_path.value().c_str() << L"."; | |
| 55 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; | |
| 56 } | |
| 57 | |
| 58 string16 app_guid = installer::GetAppGuidForUpdates( | |
| 59 !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str())); | |
| 60 DCHECK(!app_guid.empty()); | |
| 61 | |
| 62 if (GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL) == | |
| 63 GoogleUpdateSettings::UPDATES_DISABLED) | |
| 64 return GOOGLE_UPDATE_DISABLED_BY_POLICY; | |
| 65 | |
| 66 return GOOGLE_UPDATE_NO_ERROR; | |
| 67 #endif | |
| 68 } | |
| 69 | |
| 70 // Creates an instance of a COM Local Server class using either plain vanilla | |
| 71 // CoCreateInstance, or using the Elevation moniker if running on Vista. | |
| 72 // hwnd must refer to a foregound window in order to get the UAC prompt | |
| 73 // showing up in the foreground if running on Vista. It can also be NULL if | |
| 74 // background UAC prompts are desired. | |
| 75 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id, | |
| 76 HWND hwnd, void** interface_ptr) { | |
| 77 if (!interface_ptr) | |
| 78 return E_POINTER; | |
| 79 | |
| 80 // For Vista we need to instantiate the COM server via the elevation | |
| 81 // moniker. This ensures that the UAC dialog shows up. | |
| 82 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { | |
| 83 wchar_t class_id_as_string[MAX_PATH] = {0}; | |
| 84 StringFromGUID2(class_id, class_id_as_string, | |
| 85 arraysize(class_id_as_string)); | |
| 86 | |
| 87 string16 elevation_moniker_name = | |
| 88 base::StringPrintf(L"Elevation:Administrator!new:%ls", | |
| 89 class_id_as_string); | |
| 90 | |
| 91 BIND_OPTS3 bind_opts; | |
| 92 memset(&bind_opts, 0, sizeof(bind_opts)); | |
| 93 bind_opts.cbStruct = sizeof(bind_opts); | |
| 94 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER; | |
| 95 bind_opts.hwnd = hwnd; | |
| 96 | |
| 97 return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, | |
| 98 interface_id, reinterpret_cast<void**>(interface_ptr)); | |
| 99 } | |
| 100 | |
| 101 return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, | |
| 102 interface_id, | |
| 103 reinterpret_cast<void**>(interface_ptr)); | |
| 104 } | |
| 105 | |
| 106 | |
| 107 } // namespace | |
| 108 | |
| 109 //////////////////////////////////////////////////////////////////////////////// | |
| 110 // | |
| 111 // The GoogleUpdateJobObserver COM class is responsible for receiving status | |
| 112 // reports from google Update. It keeps track of the progress as Google Update | |
| 113 // notifies us and ends the message loop we are spinning in once Google Update | |
| 114 // reports that it is done. | |
| 115 // | |
| 116 //////////////////////////////////////////////////////////////////////////////// | |
| 117 class GoogleUpdateJobObserver | |
| 118 : public CComObjectRootEx<CComSingleThreadModel>, | |
| 119 public IJobObserver { | |
| 120 public: | |
| 121 BEGIN_COM_MAP(GoogleUpdateJobObserver) | |
| 122 COM_INTERFACE_ENTRY(IJobObserver) | |
| 123 END_COM_MAP() | |
| 124 | |
| 125 GoogleUpdateJobObserver() | |
| 126 : result_(UPGRADE_ERROR) { | |
| 127 } | |
| 128 virtual ~GoogleUpdateJobObserver() {} | |
| 129 | |
| 130 // Notifications from Google Update: | |
| 131 STDMETHOD(OnShow)() { | |
| 132 return S_OK; | |
| 133 } | |
| 134 STDMETHOD(OnCheckingForUpdate)() { | |
| 135 result_ = UPGRADE_CHECK_STARTED; | |
| 136 return S_OK; | |
| 137 } | |
| 138 STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) { | |
| 139 result_ = UPGRADE_IS_AVAILABLE; | |
| 140 new_version_ = version_string; | |
| 141 return S_OK; | |
| 142 } | |
| 143 STDMETHOD(OnWaitingToDownload)() { | |
| 144 return S_OK; | |
| 145 } | |
| 146 STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) { | |
| 147 return S_OK; | |
| 148 } | |
| 149 STDMETHOD(OnWaitingToInstall)() { | |
| 150 return S_OK; | |
| 151 } | |
| 152 STDMETHOD(OnInstalling)() { | |
| 153 result_ = UPGRADE_STARTED; | |
| 154 return S_OK; | |
| 155 } | |
| 156 STDMETHOD(OnPause)() { | |
| 157 return S_OK; | |
| 158 } | |
| 159 STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) { | |
| 160 switch (code) { | |
| 161 case COMPLETION_CODE_SUCCESS_CLOSE_UI: | |
| 162 case COMPLETION_CODE_SUCCESS: { | |
| 163 if (result_ == UPGRADE_STARTED) | |
| 164 result_ = UPGRADE_SUCCESSFUL; | |
| 165 else if (result_ == UPGRADE_CHECK_STARTED) | |
| 166 result_ = UPGRADE_ALREADY_UP_TO_DATE; | |
| 167 break; | |
| 168 } | |
| 169 case COMPLETION_CODE_ERROR: | |
| 170 error_message_ = text; | |
| 171 default: { | |
| 172 NOTREACHED(); | |
| 173 result_ = UPGRADE_ERROR; | |
| 174 break; | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 event_sink_ = NULL; | |
| 179 | |
| 180 // We no longer need to spin the message loop that we started spinning in | |
| 181 // InitiateGoogleUpdateCheck. | |
| 182 MessageLoop::current()->Quit(); | |
| 183 return S_OK; | |
| 184 } | |
| 185 STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) { | |
| 186 event_sink_ = event_sink; | |
| 187 return S_OK; | |
| 188 } | |
| 189 | |
| 190 // Returns the results of the update operation. | |
| 191 STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) { | |
| 192 // Intermediary steps should never be reported to the client. | |
| 193 DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED); | |
| 194 | |
| 195 *result = result_; | |
| 196 return S_OK; | |
| 197 } | |
| 198 | |
| 199 // Returns which version Google Update found on the server (if a more | |
| 200 // recent version was found). Otherwise, this will be blank. | |
| 201 STDMETHOD(GetVersionInfo)(string16* version_string) { | |
| 202 *version_string = new_version_; | |
| 203 return S_OK; | |
| 204 } | |
| 205 | |
| 206 // Returns the Google Update supplied error string that describes the error | |
| 207 // that occurred during the update check/upgrade. | |
| 208 STDMETHOD(GetErrorMessage)(string16* error_message) { | |
| 209 *error_message = error_message_; | |
| 210 return S_OK; | |
| 211 } | |
| 212 | |
| 213 private: | |
| 214 // The status/result of the Google Update operation. | |
| 215 GoogleUpdateUpgradeResult result_; | |
| 216 | |
| 217 // The version string Google Update found. | |
| 218 string16 new_version_; | |
| 219 | |
| 220 // An error message, if any. | |
| 221 string16 error_message_; | |
| 222 | |
| 223 // Allows us control the upgrade process to a small degree. After OnComplete | |
| 224 // has been called, this object can not be used. | |
| 225 base::win::ScopedComPtr<IProgressWndEvents> event_sink_; | |
| 226 }; | |
| 227 | |
| 228 //////////////////////////////////////////////////////////////////////////////// | |
| 229 // GoogleUpdate, public: | |
| 230 | |
| 231 GoogleUpdate::GoogleUpdate() | |
| 232 : listener_(NULL) { | |
| 233 } | |
| 234 | |
| 235 GoogleUpdate::~GoogleUpdate() { | |
| 236 } | |
| 237 | |
| 238 void GoogleUpdate::CheckForUpdate(bool install_if_newer, | |
| 239 views::Widget* window) { | |
| 240 // We need to shunt this request over to InitiateGoogleUpdateCheck and have | |
| 241 // it run in the file thread. | |
| 242 BrowserThread::PostTask( | |
| 243 BrowserThread::FILE, FROM_HERE, | |
| 244 base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this, | |
| 245 install_if_newer, window, MessageLoop::current())); | |
| 246 } | |
| 247 | |
| 248 //////////////////////////////////////////////////////////////////////////////// | |
| 249 // GoogleUpdate, private: | |
| 250 | |
| 251 void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer, | |
| 252 views::Widget* window, | |
| 253 MessageLoop* main_loop) { | |
| 254 FilePath chrome_exe; | |
| 255 if (!PathService::Get(base::DIR_EXE, &chrome_exe)) | |
| 256 NOTREACHED(); | |
| 257 | |
| 258 GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe); | |
| 259 if (error_code != GOOGLE_UPDATE_NO_ERROR) { | |
| 260 main_loop->PostTask( | |
| 261 FROM_HERE, | |
| 262 base::Bind(&GoogleUpdate::ReportResults, this, | |
| 263 UPGRADE_ERROR, error_code, string16())); | |
| 264 return; | |
| 265 } | |
| 266 | |
| 267 CComObject<GoogleUpdateJobObserver>* job_observer; | |
| 268 HRESULT hr = | |
| 269 CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer); | |
| 270 if (hr != S_OK) { | |
| 271 // Most of the error messages come straight from Google Update. This one is | |
| 272 // deemed worthy enough to also warrant its own error. | |
| 273 GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED; | |
| 274 string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | |
| 275 ReportFailure( | |
| 276 hr, error, | |
| 277 l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | |
| 278 error_code), | |
| 279 main_loop); | |
| 280 return; | |
| 281 } | |
| 282 | |
| 283 base::win::ScopedComPtr<IJobObserver> job_holder(job_observer); | |
| 284 | |
| 285 base::win::ScopedComPtr<IGoogleUpdate> on_demand; | |
| 286 | |
| 287 bool system_level = false; | |
| 288 | |
| 289 if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) { | |
| 290 hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass); | |
| 291 } else { | |
| 292 // The Update operation needs Admin privileges for writing | |
| 293 // to %ProgramFiles%. On Vista we need to elevate before instantiating | |
| 294 // the updater instance. | |
| 295 if (!install_if_newer) { | |
| 296 hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass); | |
| 297 } else { | |
| 298 HWND foreground_hwnd = NULL; | |
| 299 if (window != NULL) { | |
| 300 foreground_hwnd = window->GetNativeWindow(); | |
| 301 } | |
| 302 | |
| 303 hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass, | |
| 304 IID_IGoogleUpdate, foreground_hwnd, | |
| 305 reinterpret_cast<void**>(on_demand.Receive())); | |
| 306 } | |
| 307 system_level = true; | |
| 308 } | |
| 309 | |
| 310 if (hr != S_OK) { | |
| 311 GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; | |
| 312 string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | |
| 313 if (system_level) | |
| 314 error_code += L" -- system level"; | |
| 315 ReportFailure(hr, error, | |
| 316 l10n_util::GetStringFUTF16( | |
| 317 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | |
| 318 error_code), | |
| 319 main_loop); | |
| 320 return; | |
| 321 } | |
| 322 | |
| 323 string16 app_guid = installer::GetAppGuidForUpdates(system_level); | |
| 324 DCHECK(!app_guid.empty()); | |
| 325 | |
| 326 if (!install_if_newer) | |
| 327 hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer); | |
| 328 else | |
| 329 hr = on_demand->Update(app_guid.c_str(), job_observer); | |
| 330 | |
| 331 if (hr != S_OK) { | |
| 332 GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; | |
| 333 string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | |
| 334 ReportFailure(hr, error, | |
| 335 l10n_util::GetStringFUTF16( | |
| 336 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | |
| 337 error_code), | |
| 338 main_loop); | |
| 339 return; | |
| 340 } | |
| 341 | |
| 342 // We need to spin the message loop while Google Update is running so that it | |
| 343 // can report back to us through GoogleUpdateJobObserver. This message loop | |
| 344 // will terminate once Google Update sends us the completion status | |
| 345 // (success/error). See OnComplete(). | |
| 346 MessageLoop::current()->Run(); | |
| 347 | |
| 348 GoogleUpdateUpgradeResult results; | |
| 349 hr = job_observer->GetResult(&results); | |
| 350 | |
| 351 if (hr != S_OK) { | |
| 352 GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED; | |
| 353 string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | |
| 354 ReportFailure(hr, error, | |
| 355 l10n_util::GetStringFUTF16( | |
| 356 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | |
| 357 error_code), | |
| 358 main_loop); | |
| 359 return; | |
| 360 } | |
| 361 | |
| 362 if (results == UPGRADE_ERROR) { | |
| 363 string16 error_message; | |
| 364 job_observer->GetErrorMessage(&error_message); | |
| 365 ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop); | |
| 366 return; | |
| 367 } | |
| 368 | |
| 369 hr = job_observer->GetVersionInfo(&version_available_); | |
| 370 if (hr != S_OK) { | |
| 371 GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED; | |
| 372 string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); | |
| 373 ReportFailure(hr, error, | |
| 374 l10n_util::GetStringFUTF16( | |
| 375 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, | |
| 376 error_code), | |
| 377 main_loop); | |
| 378 return; | |
| 379 } | |
| 380 | |
| 381 main_loop->PostTask( | |
| 382 FROM_HERE, | |
| 383 base::Bind(&GoogleUpdate::ReportResults, this, | |
| 384 results, GOOGLE_UPDATE_NO_ERROR, string16())); | |
| 385 job_holder = NULL; | |
| 386 on_demand = NULL; | |
| 387 } | |
| 388 | |
| 389 void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results, | |
| 390 GoogleUpdateErrorCode error_code, | |
| 391 const string16& error_message) { | |
| 392 // If we get an error, then error code must not be blank, and vice versa. | |
| 393 DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR : | |
| 394 error_code == GOOGLE_UPDATE_NO_ERROR); | |
| 395 if (listener_) { | |
| 396 listener_->OnReportResults( | |
| 397 results, error_code, error_message, version_available_); | |
| 398 } | |
| 399 } | |
| 400 | |
| 401 bool GoogleUpdate::ReportFailure(HRESULT hr, | |
| 402 GoogleUpdateErrorCode error_code, | |
| 403 const string16& error_message, | |
| 404 MessageLoop* main_loop) { | |
| 405 NOTREACHED() << "Communication with Google Update failed: " << hr | |
| 406 << " error: " << error_code | |
| 407 << ", message: " << error_message.c_str(); | |
| 408 main_loop->PostTask( | |
| 409 FROM_HERE, | |
| 410 base::Bind(&GoogleUpdate::ReportResults, this, | |
| 411 UPGRADE_ERROR, error_code, error_message)); | |
| 412 return false; | |
| 413 } | |
| OLD | NEW |