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_win.h" 6 7 #include <atlbase.h> 8 #include <atlcom.h> 9 10 #include "base/bind.h" 11 #include "base/files/file_path.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/metrics/histogram.h" 14 #include "base/metrics/sparse_histogram.h" 15 #include "base/path_service.h" 16 #include "base/strings/string_util.h" 17 #include "base/strings/stringprintf.h" 18 #include "base/threading/thread.h" 19 #include "base/win/scoped_comptr.h" 20 #include "base/win/windows_version.h" 21 #include "chrome/grit/generated_resources.h" 22 #include "chrome/installer/util/browser_distribution.h" 23 #include "chrome/installer/util/google_update_settings.h" 24 #include "chrome/installer/util/helper.h" 25 #include "chrome/installer/util/install_util.h" 26 #include "content/public/browser/browser_thread.h" 27 #include "google_update/google_update_idl.h" 28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/win/atl_module.h" 30 #include "ui/views/widget/widget.h" 31 32 using content::BrowserThread; 33 34 namespace { 35 36 // 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 38 // Chrome distribution installed in a standard location. 39 GoogleUpdateErrorCode CanUpdateCurrentChrome( 40 const base::FilePath& chrome_exe_path) { 41 #if !defined(GOOGLE_CHROME_BUILD) 42 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; 43 #else 44 // TODO(tommi): Check if using the default distribution is always the right 45 // thing to do. 46 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 47 base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist); 48 base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist); 49 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), 50 user_exe_path.value()) && 51 !base::FilePath::CompareEqualIgnoreCase(chrome_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; 59 } 60 61 base::string16 app_guid = installer::GetAppGuidForUpdates( 62 !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str())); 63 DCHECK(!app_guid.empty()); 64 65 GoogleUpdateSettings::UpdatePolicy update_policy = 66 GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL); 67 68 if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED) 69 return GOOGLE_UPDATE_DISABLED_BY_POLICY; 70 71 if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY) 72 return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY; 73 74 return GOOGLE_UPDATE_NO_ERROR; 75 #endif 76 } 77 78 // Creates an instance of a COM Local Server class using either plain vanilla 79 // 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 81 // showing up in the foreground if running on Vista. It can also be NULL if 82 // background UAC prompts are desired. 83 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id, 84 HWND hwnd, void** interface_ptr) { 85 if (!interface_ptr) 86 return E_POINTER; 87 88 // For Vista, need to instantiate the COM server via the elevation 89 // moniker. This ensures that the UAC dialog shows up. 90 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 91 wchar_t class_id_as_string[MAX_PATH] = {0}; 92 StringFromGUID2(class_id, class_id_as_string, 93 arraysize(class_id_as_string)); 94 95 base::string16 elevation_moniker_name = 96 base::StringPrintf(L"Elevation:Administrator!new:%ls", 97 class_id_as_string); 98 99 BIND_OPTS3 bind_opts; 100 memset(&bind_opts, 0, sizeof(bind_opts)); 101 bind_opts.cbStruct = sizeof(bind_opts); 102 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER; 103 bind_opts.hwnd = hwnd; 104 105 return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, 106 interface_id, reinterpret_cast<void**>(interface_ptr)); 107 } 108 109 return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, 110 interface_id, 111 reinterpret_cast<void**>(interface_ptr)); 112 } 113 114 115 } // namespace 116 117 // The GoogleUpdateJobObserver COM class is responsible for receiving status 118 // reports from google Update. It keeps track of the progress as GoogleUpdate 119 // notifies this observer and ends the message loop that is spinning in once 120 // GoogleUpdate reports that it is done. 121 class GoogleUpdateJobObserver 122 : public CComObjectRootEx<CComSingleThreadModel>, 123 public IJobObserver { 124 public: 125 BEGIN_COM_MAP(GoogleUpdateJobObserver) 126 COM_INTERFACE_ENTRY(IJobObserver) 127 END_COM_MAP() 128 129 GoogleUpdateJobObserver() 130 : result_(UPGRADE_ERROR) { 131 } 132 virtual ~GoogleUpdateJobObserver() {} 133 134 // Notifications from Google Update: 135 STDMETHOD(OnShow)() { 136 return S_OK; 137 } 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 } 193 194 // Returns the results of the update operation. 195 STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) { 196 // Intermediary steps should never be reported to the client. 197 DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED); 198 199 *result = result_; 200 return S_OK; 201 } 202 203 // Returns which version Google Update found on the server (if a more 204 // recent version was found). Otherwise, this will be blank. 205 STDMETHOD(GetVersionInfo)(base::string16* version_string) { 206 *version_string = new_version_; 207 return S_OK; 208 } 209 210 // Returns the Google Update supplied error string that describes the error 211 // that occurred during the update check/upgrade. 212 STDMETHOD(GetErrorMessage)(base::string16* error_message) { 213 *error_message = error_message_; 214 return S_OK; 215 } 216 217 private: 218 // The status/result of the Google Update operation. 219 GoogleUpdateUpgradeResult result_; 220 221 // The version string Google Update found. 222 base::string16 new_version_; 223 224 // An error message, if any. 225 base::string16 error_message_; 226 227 // Allows us control the upgrade process to a small degree. After OnComplete 228 // has been called, this object can not be used. 229 base::win::ScopedComPtr<IProgressWndEvents> event_sink_; 230 }; 231 232 //////////////////////////////////////////////////////////////////////////////// 233 // GoogleUpdate, public: 234 235 GoogleUpdate::GoogleUpdate() 236 : listener_(NULL) { 237 } 238 239 GoogleUpdate::~GoogleUpdate() { 240 } 241 242 void GoogleUpdate::CheckForUpdate(bool install_if_newer, HWND window) { 243 // Need to shunt this request over to InitiateGoogleUpdateCheck and have 244 // it run in the file thread. 245 BrowserThread::PostTask( 246 BrowserThread::FILE, FROM_HERE, 247 base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this, 248 install_if_newer, window, base::MessageLoop::current())); 249 } 250 251 //////////////////////////////////////////////////////////////////////////////// 252 // GoogleUpdate, private: 253 254 void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer, 255 HWND window, 256 base::MessageLoop* main_loop) { 257 base::FilePath chrome_exe; 258 if (!PathService::Get(base::DIR_EXE, &chrome_exe)) 259 NOTREACHED(); 260 261 GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe); 262 if (error_code != GOOGLE_UPDATE_NO_ERROR) { 263 main_loop->PostTask( 264 FROM_HERE, 265 base::Bind(&GoogleUpdate::ReportResults, this, 266 UPGRADE_ERROR, error_code, base::string16())); 267 return; 268 } 269 270 // Make sure ATL is initialized in this module. 271 ui::win::CreateATLModuleIfNeeded(); 272 273 CComObject<GoogleUpdateJobObserver>* job_observer; 274 HRESULT hr = 275 CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer); 276 if (hr != S_OK) { 277 // Most of the error messages come straight from Google Update. This one is 278 // deemed worthy enough to also warrant its own error. 279 GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED; 280 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 281 ReportFailure( 282 hr, error, 283 l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, 284 error_code), 285 main_loop); 286 return; 287 } 288 289 base::win::ScopedComPtr<IJobObserver> job_holder(job_observer); 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) { 312 GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; 313 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 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 } 323 324 base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); 325 DCHECK(!app_guid.empty()); 326 327 if (!install_if_newer) 328 hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer); 329 else 330 hr = on_demand->Update(app_guid.c_str(), job_observer); 331 332 if (hr != S_OK) { 333 GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; 334 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 335 ReportFailure(hr, error, 336 l10n_util::GetStringFUTF16( 337 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, 338 error_code), 339 main_loop); 340 return; 341 } 342 343 // Need to spin the message loop while Google Update is running so that it 344 // can report back to us through GoogleUpdateJobObserver. This message loop 345 // will terminate once Google Update sends us the completion status 346 // (success/error). See OnComplete(). 347 base::MessageLoop::current()->Run(); 348 349 GoogleUpdateUpgradeResult results; 350 hr = job_observer->GetResult(&results); 351 352 if (hr != S_OK) { 353 GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED; 354 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 355 ReportFailure(hr, error, 356 l10n_util::GetStringFUTF16( 357 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, 358 error_code), 359 main_loop); 360 return; 361 } 362 363 if (results == UPGRADE_ERROR) { 364 base::string16 error_message; 365 job_observer->GetErrorMessage(&error_message); 366 ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop); 367 return; 368 } 369 370 hr = job_observer->GetVersionInfo(&version_available_); 371 if (hr != S_OK) { 372 GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED; 373 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 374 ReportFailure(hr, error, 375 l10n_util::GetStringFUTF16( 376 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, 377 error_code), 378 main_loop); 379 return; 380 } 381 382 main_loop->PostTask( 383 FROM_HERE, 384 base::Bind(&GoogleUpdate::ReportResults, this, 385 results, GOOGLE_UPDATE_NO_ERROR, base::string16())); 386 job_holder = NULL; 387 on_demand = NULL; 388 } 389 390 void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results, 391 GoogleUpdateErrorCode error_code, 392 const base::string16& error_message) { 393 // If there is an error, then error code must not be blank, and vice versa. 394 DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR : 395 error_code == GOOGLE_UPDATE_NO_ERROR); 396 UMA_HISTOGRAM_ENUMERATION( 397 "GoogleUpdate.UpgradeResult", results, NUM_UPGRADE_RESULTS); 398 if (results == UPGRADE_ERROR) { 399 UMA_HISTOGRAM_ENUMERATION( 400 "GoogleUpdate.UpdateErrorCode", error_code, NUM_ERROR_CODES); 401 } 402 if (listener_) { 403 listener_->OnReportResults( 404 results, error_code, error_message, version_available_); 405 } 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 } 422