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