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