Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / chrome / browser / google / google_update_win.cc
blob3eae688025b1565de9666e2e13114afe1f0110cd
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.
5 #include "chrome/browser/google/google_update_win.h"
7 #include <atlbase.h>
8 #include <atlcom.h>
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file_path.h"
13 #include "base/location.h"
14 #include "base/metrics/histogram.h"
15 #include "base/metrics/sparse_histogram.h"
16 #include "base/path_service.h"
17 #include "base/sequenced_task_runner_helpers.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/thread_task_runner_handle.h"
23 #include "base/time/time.h"
24 #include "base/win/scoped_bstr.h"
25 #include "base/win/windows_version.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "chrome/installer/util/browser_distribution.h"
29 #include "chrome/installer/util/helper.h"
30 #include "chrome/installer/util/install_util.h"
31 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/base/win/atl_module.h"
33 #include "ui/gfx/geometry/safe_integer_conversions.h"
35 namespace {
37 // The status of the upgrade. These values are used for a histogram. Do not
38 // reorder.
39 enum GoogleUpdateUpgradeStatus {
40 // The upgrade has started. DEPRECATED.
41 // UPGRADE_STARTED = 0,
42 // A check for upgrade has been initiated. DEPRECATED.
43 // UPGRADE_CHECK_STARTED = 1,
44 // An update is available.
45 UPGRADE_IS_AVAILABLE = 2,
46 // The upgrade happened successfully.
47 UPGRADE_SUCCESSFUL = 3,
48 // No need to upgrade, Chrome is up to date.
49 UPGRADE_ALREADY_UP_TO_DATE = 4,
50 // An error occurred.
51 UPGRADE_ERROR = 5,
52 NUM_UPGRADE_STATUS
55 GoogleUpdate3ClassFactory* g_google_update_factory = nullptr;
57 // The time interval, in milliseconds, between polls to Google Update. This
58 // value was chosen unscientificaly during an informal discussion.
59 const int64_t kGoogleUpdatePollIntervalMs = 250;
61 // Constants from Google Update.
62 const HRESULT GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY = 0x80040813;
63 const HRESULT GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL = 0x8004081f;
64 const HRESULT GOOPDATEINSTALL_E_INSTALLER_FAILED = 0x80040902;
66 // Check if the currently running instance can be updated by Google Update.
67 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
68 // Chrome distribution installed in a standard location.
69 GoogleUpdateErrorCode CanUpdateCurrentChrome(
70 const base::FilePath& chrome_exe_path,
71 bool system_level_install) {
72 DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path),
73 system_level_install);
74 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
75 base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
76 base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
77 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
78 user_exe_path.value()) &&
79 !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
80 machine_exe_path.value())) {
81 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
84 return GOOGLE_UPDATE_NO_ERROR;
87 // Explicitly allow the Google Update service to impersonate the client since
88 // some COM code elsewhere in the browser process may have previously used
89 // CoInitializeSecurity to set the impersonation level to something other than
90 // the default. Ignore errors since an attempt to use Google Update may succeed
91 // regardless.
92 void ConfigureProxyBlanket(IUnknown* interface_pointer) {
93 ::CoSetProxyBlanket(interface_pointer,
94 RPC_C_AUTHN_DEFAULT,
95 RPC_C_AUTHZ_DEFAULT,
96 COLE_DEFAULT_PRINCIPAL,
97 RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
98 RPC_C_IMP_LEVEL_IMPERSONATE,
99 nullptr,
100 EOAC_DYNAMIC_CLOAKING);
103 // Creates a class factory for a COM Local Server class using either plain
104 // vanilla CoGetClassObject, or using the Elevation moniker if running on
105 // Vista+. |hwnd| must refer to a foregound window in order to get the UAC
106 // prompt to appear in the foreground if running on Vista+. It can also be NULL
107 // if background UAC prompts are desired.
108 HRESULT CoGetClassObjectAsAdmin(REFCLSID class_id,
109 REFIID interface_id,
110 gfx::AcceleratedWidget hwnd,
111 void** interface_ptr) {
112 if (!interface_ptr)
113 return E_POINTER;
115 // For Vista+, need to instantiate the class factory via the elevation
116 // moniker. This ensures that the UAC dialog shows up.
117 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
118 wchar_t class_id_as_string[MAX_PATH] = {};
119 StringFromGUID2(class_id, class_id_as_string,
120 arraysize(class_id_as_string));
122 base::string16 elevation_moniker_name = base::StringPrintf(
123 L"Elevation:Administrator!clsid:%ls", class_id_as_string);
125 BIND_OPTS3 bind_opts;
126 // An explicit memset is needed rather than relying on value initialization
127 // since BIND_OPTS3 is not an aggregate (it is a derived type).
128 memset(&bind_opts, 0, sizeof(bind_opts));
129 bind_opts.cbStruct = sizeof(bind_opts);
130 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
131 bind_opts.hwnd = hwnd;
133 return ::CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
134 interface_id, interface_ptr);
137 return ::CoGetClassObject(class_id, CLSCTX_LOCAL_SERVER, nullptr,
138 interface_id, interface_ptr);
141 HRESULT CreateGoogleUpdate3WebClass(
142 bool system_level_install,
143 bool install_update_if_possible,
144 gfx::AcceleratedWidget elevation_window,
145 base::win::ScopedComPtr<IGoogleUpdate3Web>* google_update) {
146 if (g_google_update_factory)
147 return g_google_update_factory->Run(google_update);
149 const CLSID& google_update_clsid = system_level_install ?
150 CLSID_GoogleUpdate3WebMachineClass :
151 CLSID_GoogleUpdate3WebUserClass;
152 base::win::ScopedComPtr<IClassFactory> class_factory;
153 HRESULT hresult = S_OK;
155 // For a user-level install, update checks and updates can both be done by a
156 // normal user with the UserClass. For a system-level install, update checks
157 // can be done by a normal user with the MachineClass.
158 if (!system_level_install || !install_update_if_possible) {
159 hresult = ::CoGetClassObject(google_update_clsid, CLSCTX_ALL, nullptr,
160 base::win::ScopedComPtr<IClassFactory>::iid(),
161 class_factory.ReceiveVoid());
162 } else {
163 // For a system-level install, an update requires Admin privileges for
164 // writing to %ProgramFiles%. Elevate while instantiating the MachineClass.
165 hresult = CoGetClassObjectAsAdmin(
166 google_update_clsid, base::win::ScopedComPtr<IClassFactory>::iid(),
167 elevation_window, class_factory.ReceiveVoid());
169 if (FAILED(hresult))
170 return hresult;
172 ConfigureProxyBlanket(class_factory.get());
174 return class_factory->CreateInstance(
175 nullptr,
176 base::win::ScopedComPtr<IGoogleUpdate3Web>::iid(),
177 google_update->ReceiveVoid());
180 // UpdateCheckDriver -----------------------------------------------------------
182 // A driver that is created and destroyed on the caller's thread and drives
183 // Google Update on another.
184 class UpdateCheckDriver {
185 public:
186 // Runs an update check on |task_runner|, invoking methods of |delegate| on
187 // the caller's thread to report progress and final results.
188 static void RunUpdateCheck(
189 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
190 const std::string& locale,
191 bool install_update_if_possible,
192 gfx::AcceleratedWidget elevation_window,
193 const base::WeakPtr<UpdateCheckDelegate>& delegate);
195 private:
196 friend class base::DeleteHelper<UpdateCheckDriver>;
198 UpdateCheckDriver(
199 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
200 const std::string& locale,
201 bool install_update_if_possible,
202 gfx::AcceleratedWidget elevation_window,
203 const base::WeakPtr<UpdateCheckDelegate>& delegate);
205 // Invokes a completion or error method on the caller's delegate, as
206 // appropriate.
207 ~UpdateCheckDriver();
209 // Starts an update check.
210 void BeginUpdateCheck();
212 // Returns the result of initiating an update check. Sets |error_code| if the
213 // result is any kind of failure.
214 HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code);
216 // Sets status_ to UPGRADE_ERROR, error_code_ to |error_code|, hresult_ to
217 // |hresult|, installer_exit_code_ to |installer_exit_code|, and
218 // html_error_message_ to a composition of all values suitable for display
219 // to the user. This call should be followed by deletion of the driver,
220 // which will result in the caller being notified via its delegate.
221 void OnUpgradeError(GoogleUpdateErrorCode error_code,
222 HRESULT hresult,
223 int installer_exit_code,
224 const base::string16& error_string);
226 // Returns true if |current_state| and |state_value| can be obtained from the
227 // ongoing update check. Otherwise, populates |hresult| with the reason they
228 // could not be obtained.
229 bool GetCurrentState(base::win::ScopedComPtr<ICurrentState>* current_state,
230 CurrentState* state_value,
231 HRESULT* hresult) const;
233 // Returns true if |current_state| and |state_value| constitute an error state
234 // for the ongoing update check, in which case |error_code| is populated with
235 // one of GOOGLE_UPDATE_ERROR_UPDATING, GOOGLE_UPDATE_DISABLED_BY_POLICY, or
236 // GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR. |hresult| is populated with
237 // the most relevant HRESULT (which may be a value from Google Update; see
238 // https://code.google.com/p/omaha/source/browse/trunk/base/error.h). In case
239 // Chrome's installer failed during execution, |installer_exit_code| may be
240 // populated with its process exit code (see enum installer::InstallStatus in
241 // chrome/installer/util/util_constants.h); otherwise, it will be -1.
242 // |error_string| will be populated with a completion message if one is
243 // provided by Google Update.
244 bool IsErrorState(const base::win::ScopedComPtr<ICurrentState>& current_state,
245 CurrentState state_value,
246 GoogleUpdateErrorCode* error_code,
247 HRESULT* hresult,
248 int* installer_exit_code,
249 base::string16* error_string) const;
251 // Returns true if |current_state| and |state_value| constitute a final state
252 // for the ongoing update check, in which case |upgrade_status| is populated
253 // with one of UPGRADE_ALREADY_UP_TO_DATE or UPGRADE_IS_AVAILABLE (in case a
254 // pure check is being performed rather than an update) or UPGRADE_SUCCESSFUL
255 // (in case an update is being performed). For the UPGRADE_IS_AVAILABLE case,
256 // |new_version| will be populated with the available version, if provided by
257 // Google Update.
258 bool IsFinalState(const base::win::ScopedComPtr<ICurrentState>& current_state,
259 CurrentState state_value,
260 GoogleUpdateUpgradeStatus* upgrade_status,
261 base::string16* new_version) const;
263 // Returns true if |current_state| and |state_value| constitute an
264 // intermediate state for the ongoing update check. |new_version| will be
265 // populated with the version to be installed if it is provided by Google
266 // Update for the current state. |progress| will be populated with a number
267 // between 0 and 100 according to how far Google Update has progressed in the
268 // download and install process.
269 bool IsIntermediateState(
270 const base::win::ScopedComPtr<ICurrentState>& current_state,
271 CurrentState state_value,
272 base::string16* new_version,
273 int* progress) const;
275 // Polls Google Update to determine the state of the ongoing check or
276 // update. If the process has reached a terminal state, this instance will be
277 // deleted and the caller will be notified of the final status. Otherwise, the
278 // caller will be notified of the intermediate state (iff it differs from a
279 // previous notification) and another future poll will be scheduled.
280 void PollGoogleUpdate();
282 // The task runner on which the update checks runs.
283 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
285 // The caller's task runner, on which methods of |delegate_| will be invoked.
286 scoped_refptr<base::SingleThreadTaskRunner> result_runner_;
288 // The UI locale.
289 std::string locale_;
291 // False to only check for an update; true to also install one if available.
292 bool install_update_if_possible_;
294 // A parent window in case any UX is required (e.g., an elevation prompt).
295 gfx::AcceleratedWidget elevation_window_;
297 // The caller's delegate by which feedback is conveyed.
298 base::WeakPtr<UpdateCheckDelegate> delegate_;
300 // True if operating on a per-machine installation rather than a per-user one.
301 bool system_level_install_;
303 // The on-demand updater that is doing the work.
304 base::win::ScopedComPtr<IGoogleUpdate3Web> google_update_;
306 // An app bundle containing the application being updated.
307 base::win::ScopedComPtr<IAppBundleWeb> app_bundle_;
309 // The application being updated (Chrome, Chrome Binaries, or Chrome SxS).
310 base::win::ScopedComPtr<IAppWeb> app_;
312 // The progress value reported most recently to the caller.
313 int last_reported_progress_;
315 // The results of the update check to be logged via UMA and/or reported to the
316 // caller.
317 GoogleUpdateUpgradeStatus status_;
318 GoogleUpdateErrorCode error_code_;
319 base::string16 html_error_message_;
320 base::string16 new_version_;
321 HRESULT hresult_;
322 int installer_exit_code_;
324 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
327 // static
328 void UpdateCheckDriver::RunUpdateCheck(
329 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
330 const std::string& locale,
331 bool install_update_if_possible,
332 gfx::AcceleratedWidget elevation_window,
333 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
334 // The driver is owned by itself, and will self-destruct when its work is
335 // done.
336 UpdateCheckDriver* driver =
337 new UpdateCheckDriver(task_runner, locale, install_update_if_possible,
338 elevation_window, delegate);
339 task_runner->PostTask(FROM_HERE,
340 base::Bind(&UpdateCheckDriver::BeginUpdateCheck,
341 base::Unretained(driver)));
344 // Runs on the caller's thread.
345 UpdateCheckDriver::UpdateCheckDriver(
346 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
347 const std::string& locale,
348 bool install_update_if_possible,
349 gfx::AcceleratedWidget elevation_window,
350 const base::WeakPtr<UpdateCheckDelegate>& delegate)
351 : task_runner_(task_runner),
352 result_runner_(base::ThreadTaskRunnerHandle::Get()),
353 locale_(locale),
354 install_update_if_possible_(install_update_if_possible),
355 elevation_window_(elevation_window),
356 delegate_(delegate),
357 system_level_install_(false),
358 last_reported_progress_(0),
359 status_(UPGRADE_ERROR),
360 error_code_(GOOGLE_UPDATE_NO_ERROR),
361 hresult_(S_OK),
362 installer_exit_code_(-1) {
365 UpdateCheckDriver::~UpdateCheckDriver() {
366 DCHECK(result_runner_->BelongsToCurrentThread());
367 // If there is an error, then error_code must not be blank, and vice versa.
368 DCHECK_NE(status_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR);
369 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_,
370 NUM_UPGRADE_STATUS);
371 if (status_ == UPGRADE_ERROR) {
372 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_,
373 NUM_ERROR_CODES);
374 if (FAILED(hresult_))
375 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_);
376 if (installer_exit_code_ != -1) {
377 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.InstallerExitCode",
378 installer_exit_code_);
381 if (delegate_) {
382 if (status_ == UPGRADE_ERROR)
383 delegate_->OnError(error_code_, html_error_message_, new_version_);
384 else if (install_update_if_possible_)
385 delegate_->OnUpgradeComplete(new_version_);
386 else
387 delegate_->OnUpdateCheckComplete(new_version_);
391 void UpdateCheckDriver::BeginUpdateCheck() {
392 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
393 HRESULT hresult = BeginUpdateCheckInternal(&error_code);
394 if (SUCCEEDED(hresult)) {
395 // Start polling.
396 task_runner_->PostTask(FROM_HERE,
397 base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
398 base::Unretained(this)));
399 } else {
400 // Return results immediately since the driver is not polling Google Update.
401 OnUpgradeError(error_code, hresult, -1, base::string16());
402 result_runner_->DeleteSoon(FROM_HERE, this);
406 HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
407 GoogleUpdateErrorCode* error_code) {
408 base::FilePath chrome_exe;
409 if (!PathService::Get(base::DIR_EXE, &chrome_exe))
410 NOTREACHED();
412 system_level_install_ = !InstallUtil::IsPerUserInstall(chrome_exe);
414 // Make sure ATL is initialized in this module.
415 ui::win::CreateATLModuleIfNeeded();
417 *error_code = CanUpdateCurrentChrome(chrome_exe, system_level_install_);
418 if (*error_code != GOOGLE_UPDATE_NO_ERROR)
419 return E_FAIL;
421 HRESULT hresult = CreateGoogleUpdate3WebClass(
422 system_level_install_, install_update_if_possible_, elevation_window_,
423 &google_update_);
424 if (FAILED(hresult)) {
425 *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND;
426 return hresult;
429 ConfigureProxyBlanket(google_update_.get());
431 // The class was created, so all subsequent errors are reported as:
432 *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
433 base::string16 app_guid =
434 installer::GetAppGuidForUpdates(system_level_install_);
435 DCHECK(!app_guid.empty());
438 base::win::ScopedComPtr<IDispatch> dispatch;
439 hresult = google_update_->createAppBundleWeb(dispatch.Receive());
440 if (FAILED(hresult))
441 return hresult;
442 hresult = dispatch.QueryInterface(app_bundle_.Receive());
443 if (FAILED(hresult))
444 return hresult;
446 ConfigureProxyBlanket(app_bundle_.get());
448 if (!locale_.empty()) {
449 // Ignore the result of this since, while setting the display language is
450 // nice to have, a failure to do so does not affect the likelihood that the
451 // update check and/or install will succeed.
452 app_bundle_->put_displayLanguage(
453 base::win::ScopedBstr(base::UTF8ToUTF16(locale_).c_str()));
456 hresult = app_bundle_->initialize();
457 if (FAILED(hresult))
458 return hresult;
459 if (elevation_window_) {
460 // Likewise, a failure to set the parent window need not block an update
461 // check.
462 app_bundle_->put_parentHWND(reinterpret_cast<ULONG_PTR>(elevation_window_));
465 base::win::ScopedComPtr<IDispatch> dispatch;
466 hresult =
467 app_bundle_->createInstalledApp(base::win::ScopedBstr(app_guid.c_str()));
468 if (FAILED(hresult))
469 return hresult;
470 hresult = app_bundle_->get_appWeb(0, dispatch.Receive());
471 if (FAILED(hresult))
472 return hresult;
473 hresult = dispatch.QueryInterface(app_.Receive());
474 if (FAILED(hresult))
475 return hresult;
476 ConfigureProxyBlanket(app_.get());
477 return app_bundle_->checkForUpdate();
480 bool UpdateCheckDriver::GetCurrentState(
481 base::win::ScopedComPtr<ICurrentState>* current_state,
482 CurrentState* state_value,
483 HRESULT* hresult) const {
484 base::win::ScopedComPtr<IDispatch> dispatch;
485 *hresult = app_->get_currentState(dispatch.Receive());
486 if (FAILED(*hresult))
487 return false;
488 *hresult = dispatch.QueryInterface(current_state->Receive());
489 if (FAILED(*hresult))
490 return false;
491 ConfigureProxyBlanket(current_state->get());
492 LONG value = 0;
493 *hresult = (*current_state)->get_stateValue(&value);
494 if (FAILED(*hresult))
495 return false;
496 *state_value = static_cast<CurrentState>(value);
497 return true;
500 bool UpdateCheckDriver::IsErrorState(
501 const base::win::ScopedComPtr<ICurrentState>& current_state,
502 CurrentState state_value,
503 GoogleUpdateErrorCode* error_code,
504 HRESULT* hresult,
505 int* installer_exit_code,
506 base::string16* error_string) const {
507 if (state_value == STATE_ERROR) {
508 // In general, errors reported by Google Update fall under this category
509 // (see special case below).
510 *error_code = GOOGLE_UPDATE_ERROR_UPDATING;
512 // In general, the exit code of Chrome's installer is unknown (see special
513 // case below).
514 *installer_exit_code = -1;
516 // Report the error_code provided by Google Update if possible, or the
517 // reason it wasn't possible otherwise.
518 LONG long_value = 0;
519 *hresult = current_state->get_errorCode(&long_value);
520 if (SUCCEEDED(*hresult))
521 *hresult = long_value;
523 // Special cases:
524 // - Use a custom error code if Google Update repoted that the update was
525 // disabled by a Group Policy setting.
526 // - Extract the exit code of Chrome's installer if Google Update repoted
527 // that the update failed because of a failure in the installer.
528 LONG code = 0;
529 if (*hresult == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY) {
530 *error_code = GOOGLE_UPDATE_DISABLED_BY_POLICY;
531 } else if (*hresult == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL) {
532 *error_code = GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
533 } else if (*hresult == GOOPDATEINSTALL_E_INSTALLER_FAILED &&
534 SUCCEEDED(current_state->get_installerResultCode(&code))) {
535 *installer_exit_code = code;
538 base::win::ScopedBstr message;
539 if (SUCCEEDED(current_state->get_completionMessage(message.Receive())))
540 error_string->assign(message, message.Length());
542 return true;
544 if (state_value == STATE_UPDATE_AVAILABLE && install_update_if_possible_) {
545 *hresult = app_bundle_->install();
546 if (FAILED(*hresult)) {
547 // Report a failure to start the install as a general error while trying
548 // to interact with Google Update.
549 *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
550 *installer_exit_code = -1;
551 return true;
553 // Return false for handling in IsIntermediateState.
555 return false;
558 bool UpdateCheckDriver::IsFinalState(
559 const base::win::ScopedComPtr<ICurrentState>& current_state,
560 CurrentState state_value,
561 GoogleUpdateUpgradeStatus* upgrade_status,
562 base::string16* new_version) const {
563 if (state_value == STATE_UPDATE_AVAILABLE && !install_update_if_possible_) {
564 base::win::ScopedBstr version;
565 *upgrade_status = UPGRADE_IS_AVAILABLE;
566 if (SUCCEEDED(current_state->get_availableVersion(version.Receive())))
567 new_version->assign(version, version.Length());
568 return true;
570 if (state_value == STATE_INSTALL_COMPLETE) {
571 DCHECK(install_update_if_possible_);
572 *upgrade_status = UPGRADE_SUCCESSFUL;
573 return true;
575 if (state_value == STATE_NO_UPDATE) {
576 *upgrade_status = UPGRADE_ALREADY_UP_TO_DATE;
577 return true;
579 return false;
582 bool UpdateCheckDriver::IsIntermediateState(
583 const base::win::ScopedComPtr<ICurrentState>& current_state,
584 CurrentState state_value,
585 base::string16* new_version,
586 int* progress) const {
587 // ERROR will have been handled in IsErrorState. UPDATE_AVAILABLE, and
588 // NO_UPDATE will have been handled in IsFinalState if not doing an install,
589 // as will STATE_INSTALL_COMPLETE when doing an install. All other states
590 // following UPDATE_AVAILABLE will only happen when an install is to be done.
591 DCHECK(state_value < STATE_UPDATE_AVAILABLE || install_update_if_possible_);
592 *progress = 0;
594 switch (state_value) {
595 case STATE_INIT:
596 case STATE_WAITING_TO_CHECK_FOR_UPDATE:
597 case STATE_CHECKING_FOR_UPDATE:
598 // There is no news to report yet.
599 break;
601 case STATE_UPDATE_AVAILABLE: {
602 base::win::ScopedBstr version;
603 if (SUCCEEDED(current_state->get_availableVersion(version.Receive())))
604 new_version->assign(version, version.Length());
605 break;
608 case STATE_WAITING_TO_DOWNLOAD:
609 case STATE_RETRYING_DOWNLOAD:
610 break;
612 case STATE_DOWNLOADING: {
613 ULONG bytes_downloaded = 0;
614 ULONG total_bytes = 0;
615 if (SUCCEEDED(current_state->get_bytesDownloaded(&bytes_downloaded)) &&
616 SUCCEEDED(current_state->get_totalBytesToDownload(&total_bytes)) &&
617 total_bytes) {
618 // 0-50 is downloading.
619 *progress = gfx::ToFlooredInt((static_cast<double>(bytes_downloaded) /
620 static_cast<double>(total_bytes)) *
621 50.0);
623 break;
626 case STATE_DOWNLOAD_COMPLETE:
627 case STATE_EXTRACTING:
628 case STATE_APPLYING_DIFFERENTIAL_PATCH:
629 case STATE_READY_TO_INSTALL:
630 case STATE_WAITING_TO_INSTALL:
631 *progress = 50;
632 break;
634 case STATE_INSTALLING: {
635 *progress = 50;
636 LONG install_progress = 0;
637 if (SUCCEEDED(current_state->get_installProgress(&install_progress)) &&
638 install_progress >= 0 && install_progress <= 100) {
639 // 50-100 is installing.
640 *progress = (50 + install_progress / 2);
642 break;
645 case STATE_INSTALL_COMPLETE:
646 case STATE_PAUSED:
647 case STATE_NO_UPDATE:
648 case STATE_ERROR:
649 default:
650 NOTREACHED();
651 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.UnexpectedState", state_value);
652 return false;
654 return true;
657 void UpdateCheckDriver::PollGoogleUpdate() {
658 base::win::ScopedComPtr<ICurrentState> state;
659 CurrentState state_value = STATE_INIT;
660 HRESULT hresult = S_OK;
661 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
662 int installer_exit_code = -1;
663 base::string16 error_string;
664 GoogleUpdateUpgradeStatus upgrade_status = UPGRADE_ERROR;
665 base::string16 new_version;
666 int progress = 0;
668 if (!GetCurrentState(&state, &state_value, &hresult)) {
669 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult, -1,
670 base::string16());
671 } else if (IsErrorState(state, state_value, &error_code, &hresult,
672 &installer_exit_code, &error_string)) {
673 OnUpgradeError(error_code, hresult, installer_exit_code, error_string);
674 } else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) {
675 status_ = upgrade_status;
676 error_code_ = GOOGLE_UPDATE_NO_ERROR;
677 html_error_message_.clear();
678 if (!new_version.empty())
679 new_version_ = new_version;
680 hresult_ = S_OK;
681 installer_exit_code_ = -1;
682 } else if (IsIntermediateState(state, state_value, &new_version, &progress)) {
683 bool got_new_version = new_version_.empty() && !new_version.empty();
684 if (got_new_version)
685 new_version_ = new_version;
686 // Give the caller this status update if it differs from the last one given.
687 if (got_new_version || progress != last_reported_progress_) {
688 last_reported_progress_ = progress;
690 // It is safe to post this task with an unretained pointer since the task
691 // is guaranteed to run before a subsequent DeleteSoon is handled.
692 result_runner_->PostTask(
693 FROM_HERE,
694 base::Bind(&UpdateCheckDelegate::OnUpgradeProgress, delegate_,
695 last_reported_progress_, new_version_));
698 // Schedule the next check.
699 task_runner_->PostDelayedTask(
700 FROM_HERE, base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
701 base::Unretained(this)),
702 base::TimeDelta::FromMilliseconds(kGoogleUpdatePollIntervalMs));
703 // Early return for this non-terminal state.
704 return;
707 // Release the reference on the COM objects before bouncing back to the
708 // caller's thread.
709 state.Release();
710 app_.Release();
711 app_bundle_.Release();
712 google_update_.Release();
714 result_runner_->DeleteSoon(FROM_HERE, this);
717 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
718 HRESULT hresult,
719 int installer_exit_code,
720 const base::string16& error_string) {
721 status_ = UPGRADE_ERROR;
722 error_code_ = error_code;
723 hresult_ = hresult;
724 installer_exit_code_ = installer_exit_code;
725 base::string16 html_error_msg =
726 base::StringPrintf(L"%d: <a href='%ls0x%X' target=_blank>0x%X</a>",
727 error_code_, base::UTF8ToUTF16(
728 chrome::kUpgradeHelpCenterBaseURL).c_str(),
729 hresult_, hresult_);
730 if (installer_exit_code_ != -1)
731 html_error_msg += base::StringPrintf(L": %d", installer_exit_code_);
732 if (system_level_install_)
733 html_error_msg += L" -- system level";
734 if (error_string.empty()) {
735 html_error_message_ = l10n_util::GetStringFUTF16(
736 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, html_error_msg);
737 } else {
738 html_error_message_ = l10n_util::GetStringFUTF16(
739 IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR, error_string, html_error_msg);
743 } // namespace
746 // Globals ---------------------------------------------------------------------
748 void BeginUpdateCheck(
749 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
750 const std::string& locale,
751 bool install_update_if_possible,
752 gfx::AcceleratedWidget elevation_window,
753 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
754 UpdateCheckDriver::RunUpdateCheck(task_runner, locale,
755 install_update_if_possible,
756 elevation_window, delegate);
760 // Private API exposed for testing. --------------------------------------------
762 void SetGoogleUpdateFactoryForTesting(
763 const GoogleUpdate3ClassFactory& google_update_factory) {
764 if (g_google_update_factory) {
765 delete g_google_update_factory;
766 g_google_update_factory = nullptr;
768 if (!google_update_factory.is_null()) {
769 g_google_update_factory =
770 new GoogleUpdate3ClassFactory(google_update_factory);