Use app list item shadow for app list folders.
[chromium-blink-merge.git] / chrome / browser / google / google_update_win.cc
blob664b8be1069c4887f998c29ff5e2394a2aa6dda8
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/grit/generated_resources.h"
27 #include "chrome/installer/util/browser_distribution.h"
28 #include "chrome/installer/util/helper.h"
29 #include "chrome/installer/util/install_util.h"
30 #include "ui/base/l10n/l10n_util.h"
31 #include "ui/base/win/atl_module.h"
32 #include "ui/gfx/geometry/safe_integer_conversions.h"
34 namespace {
36 // The status of the upgrade. These values are used for a histogram. Do not
37 // reorder.
38 enum GoogleUpdateUpgradeStatus {
39 // The upgrade has started. DEPRECATED.
40 // UPGRADE_STARTED = 0,
41 // A check for upgrade has been initiated. DEPRECATED.
42 // UPGRADE_CHECK_STARTED = 1,
43 // An update is available.
44 UPGRADE_IS_AVAILABLE = 2,
45 // The upgrade happened successfully.
46 UPGRADE_SUCCESSFUL = 3,
47 // No need to upgrade, Chrome is up to date.
48 UPGRADE_ALREADY_UP_TO_DATE = 4,
49 // An error occurred.
50 UPGRADE_ERROR = 5,
51 NUM_UPGRADE_STATUS
54 GoogleUpdate3ClassFactory* g_google_update_factory = nullptr;
56 // The time interval, in milliseconds, between polls to Google Update. This
57 // value was chosen unscientificaly during an informal discussion.
58 const int64_t kGoogleUpdatePollIntervalMs = 250;
60 // Constants from Google Update.
61 const HRESULT GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY = 0x80040813;
62 const HRESULT GOOPDATEINSTALL_E_INSTALLER_FAILED = 0x80040902;
64 // Check if the currently running instance can be updated by Google Update.
65 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
66 // Chrome distribution installed in a standard location.
67 GoogleUpdateErrorCode CanUpdateCurrentChrome(
68 const base::FilePath& chrome_exe_path,
69 bool system_level_install) {
70 DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path),
71 system_level_install);
72 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
73 base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
74 base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
75 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
76 user_exe_path.value()) &&
77 !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
78 machine_exe_path.value())) {
79 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
82 return GOOGLE_UPDATE_NO_ERROR;
85 // Creates an instance of a COM Local Server class using either plain vanilla
86 // CoCreateInstance, or using the Elevation moniker if running on Vista.
87 // hwnd must refer to a foregound window in order to get the UAC prompt
88 // showing up in the foreground if running on Vista. It can also be NULL if
89 // background UAC prompts are desired.
90 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id,
91 REFIID interface_id,
92 gfx::AcceleratedWidget hwnd,
93 void** interface_ptr) {
94 if (!interface_ptr)
95 return E_POINTER;
97 // For Vista, need to instantiate the COM server via the elevation
98 // moniker. This ensures that the UAC dialog shows up.
99 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
100 wchar_t class_id_as_string[MAX_PATH] = {};
101 StringFromGUID2(class_id, class_id_as_string,
102 arraysize(class_id_as_string));
104 base::string16 elevation_moniker_name =
105 base::StringPrintf(L"Elevation:Administrator!new:%ls",
106 class_id_as_string);
108 BIND_OPTS3 bind_opts;
109 // An explicit memset is needed rather than relying on value initialization
110 // since BIND_OPTS3 is not an aggregate (it is a derived type).
111 memset(&bind_opts, 0, sizeof(bind_opts));
112 bind_opts.cbStruct = sizeof(bind_opts);
113 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
114 bind_opts.hwnd = hwnd;
116 return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id,
117 interface_ptr);
120 return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, interface_id,
121 interface_ptr);
124 HRESULT CreateGoogleUpdate3WebClass(
125 bool system_level_install,
126 bool install_update_if_possible,
127 gfx::AcceleratedWidget elevation_window,
128 base::win::ScopedComPtr<IGoogleUpdate3Web>* google_update) {
129 if (g_google_update_factory)
130 return g_google_update_factory->Run(google_update);
132 // For a user-level install, update checks and updates can both be done by a
133 // normal user with the UserClass.
134 if (!system_level_install)
135 return google_update->CreateInstance(CLSID_GoogleUpdate3WebUserClass);
137 // For a system-level install, update checks can be done by a normal user with
138 // the MachineClass.
139 if (!install_update_if_possible)
140 return google_update->CreateInstance(CLSID_GoogleUpdate3WebMachineClass);
142 // For a system-level install, an update requires Admin privileges for writing
143 // to %ProgramFiles%. Elevate while instantiating the MachineClass.
144 return CoCreateInstanceAsAdmin(CLSID_GoogleUpdate3WebMachineClass,
145 IID_IGoogleUpdate3Web, elevation_window,
146 google_update->ReceiveVoid());
149 // UpdateCheckDriver -----------------------------------------------------------
151 // A driver that is created and destroyed on the caller's thread and drives
152 // Google Update on another.
153 class UpdateCheckDriver {
154 public:
155 // Runs an update check on |task_runner|, invoking methods of |delegate| on
156 // the caller's thread to report progress and final results.
157 static void RunUpdateCheck(
158 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
159 const std::string& locale,
160 bool install_update_if_possible,
161 gfx::AcceleratedWidget elevation_window,
162 const base::WeakPtr<UpdateCheckDelegate>& delegate);
164 private:
165 friend class base::DeleteHelper<UpdateCheckDriver>;
167 UpdateCheckDriver(
168 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
169 const std::string& locale,
170 bool install_update_if_possible,
171 gfx::AcceleratedWidget elevation_window,
172 const base::WeakPtr<UpdateCheckDelegate>& delegate);
174 // Invokes a completion or error method on the caller's delegate, as
175 // appropriate.
176 ~UpdateCheckDriver();
178 // Starts an update check.
179 void BeginUpdateCheck();
181 // Returns the result of initiating an update check. Sets |error_code| if the
182 // result is any kind of failure.
183 HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code);
185 // Sets status_ to UPGRADE_ERROR, error_code_ to |error_code|, hresult_ to
186 // |hresult|, installer_exit_code_ to |installer_exit_code|, and
187 // error_message_ to a composition of all values suitable for display to the
188 // user. This call should be followed by deletion of the driver, which will
189 // result in the caller being notified via its delegate.
190 void OnUpgradeError(GoogleUpdateErrorCode error_code,
191 HRESULT hresult,
192 int installer_exit_code,
193 const base::string16& error_string);
195 // Returns true if |current_state| and |state_value| can be obtained from the
196 // ongoing update check. Otherwise, populates |hresult| with the reason they
197 // could not be obtained.
198 bool GetCurrentState(base::win::ScopedComPtr<ICurrentState>* current_state,
199 CurrentState* state_value,
200 HRESULT* hresult) const;
202 // Returns true if |current_state| and |state_value| constitute an error state
203 // for the ongoing update check, in which case |error_code| is populated with
204 // one of GOOGLE_UPDATE_ERROR_UPDATING, GOOGLE_UPDATE_DISABLED_BY_POLICY, or
205 // GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR. |hresult| is populated with
206 // the most relevant HRESULT (which may be a value from Google Update; see
207 // https://code.google.com/p/omaha/source/browse/trunk/base/error.h). In case
208 // Chrome's installer failed during execution, |installer_exit_code| may be
209 // populated with its process exit code (see enum installer::InstallStatus in
210 // chrome/installer/util/util_constants.h); otherwise, it will be -1.
211 // |error_string| will be populated with a completion message if one is
212 // provided by Google Update.
213 bool IsErrorState(const base::win::ScopedComPtr<ICurrentState>& current_state,
214 CurrentState state_value,
215 GoogleUpdateErrorCode* error_code,
216 HRESULT* hresult,
217 int* installer_exit_code,
218 base::string16* error_string) const;
220 // Returns true if |current_state| and |state_value| constitute a final state
221 // for the ongoing update check, in which case |upgrade_status| is populated
222 // with one of UPGRADE_ALREADY_UP_TO_DATE or UPGRADE_IS_AVAILABLE (in case a
223 // pure check is being performed rather than an update) or UPGRADE_SUCCESSFUL
224 // (in case an update is being performed). For the UPGRADE_IS_AVAILABLE case,
225 // |new_version| will be populated with the available version, if provided by
226 // Google Update.
227 bool IsFinalState(const base::win::ScopedComPtr<ICurrentState>& current_state,
228 CurrentState state_value,
229 GoogleUpdateUpgradeStatus* upgrade_status,
230 base::string16* new_version) const;
232 // Returns true if |current_state| and |state_value| constitute an
233 // intermediate state for the ongoing update check. |new_version| will be
234 // populated with the version to be installed if it is provided by Google
235 // Update for the current state. |progress| will be populated with a number
236 // between 0 and 100 according to how far Google Update has progressed in the
237 // download and install process.
238 bool IsIntermediateState(
239 const base::win::ScopedComPtr<ICurrentState>& current_state,
240 CurrentState state_value,
241 base::string16* new_version,
242 int* progress) const;
244 // Polls Google Update to determine the state of the ongoing check or
245 // update. If the process has reached a terminal state, this instance will be
246 // deleted and the caller will be notified of the final status. Otherwise, the
247 // caller will be notified of the intermediate state (iff it differs from a
248 // previous notification) and another future poll will be scheduled.
249 void PollGoogleUpdate();
251 // The task runner on which the update checks runs.
252 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
254 // The caller's task runner, on which methods of |delegate_| will be invoked.
255 scoped_refptr<base::SingleThreadTaskRunner> result_runner_;
257 // The UI locale.
258 std::string locale_;
260 // False to only check for an update; true to also install one if available.
261 bool install_update_if_possible_;
263 // A parent window in case any UX is required (e.g., an elevation prompt).
264 gfx::AcceleratedWidget elevation_window_;
266 // The caller's delegate by which feedback is conveyed.
267 base::WeakPtr<UpdateCheckDelegate> delegate_;
269 // True if operating on a per-machine installation rather than a per-user one.
270 bool system_level_install_;
272 // The on-demand updater that is doing the work.
273 base::win::ScopedComPtr<IGoogleUpdate3Web> google_update_;
275 // An app bundle containing the application being updated.
276 base::win::ScopedComPtr<IAppBundleWeb> app_bundle_;
278 // The application being updated (Chrome, Chrome Binaries, or Chrome SxS).
279 base::win::ScopedComPtr<IAppWeb> app_;
281 // The progress value reported most recently to the caller.
282 int last_reported_progress_;
284 // The results of the update check to be logged via UMA and/or reported to the
285 // caller.
286 GoogleUpdateUpgradeStatus status_;
287 GoogleUpdateErrorCode error_code_;
288 base::string16 error_message_;
289 base::string16 new_version_;
290 HRESULT hresult_;
291 int installer_exit_code_;
293 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
296 // static
297 void UpdateCheckDriver::RunUpdateCheck(
298 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
299 const std::string& locale,
300 bool install_update_if_possible,
301 gfx::AcceleratedWidget elevation_window,
302 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
303 // The driver is owned by itself, and will self-destruct when its work is
304 // done.
305 UpdateCheckDriver* driver =
306 new UpdateCheckDriver(task_runner, locale, install_update_if_possible,
307 elevation_window, delegate);
308 task_runner->PostTask(FROM_HERE,
309 base::Bind(&UpdateCheckDriver::BeginUpdateCheck,
310 base::Unretained(driver)));
313 // Runs on the caller's thread.
314 UpdateCheckDriver::UpdateCheckDriver(
315 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
316 const std::string& locale,
317 bool install_update_if_possible,
318 gfx::AcceleratedWidget elevation_window,
319 const base::WeakPtr<UpdateCheckDelegate>& delegate)
320 : task_runner_(task_runner),
321 result_runner_(base::ThreadTaskRunnerHandle::Get()),
322 locale_(locale),
323 install_update_if_possible_(install_update_if_possible),
324 elevation_window_(elevation_window),
325 delegate_(delegate),
326 system_level_install_(false),
327 last_reported_progress_(0),
328 status_(UPGRADE_ERROR),
329 error_code_(GOOGLE_UPDATE_NO_ERROR),
330 hresult_(S_OK),
331 installer_exit_code_(-1) {
334 UpdateCheckDriver::~UpdateCheckDriver() {
335 DCHECK(result_runner_->BelongsToCurrentThread());
336 // If there is an error, then error_code must not be blank, and vice versa.
337 DCHECK_NE(status_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR);
338 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", status_,
339 NUM_UPGRADE_STATUS);
340 if (status_ == UPGRADE_ERROR) {
341 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_,
342 NUM_ERROR_CODES);
343 if (FAILED(hresult_))
344 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_);
345 if (installer_exit_code_ != -1) {
346 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.InstallerExitCode",
347 installer_exit_code_);
350 if (delegate_) {
351 if (status_ == UPGRADE_ERROR)
352 delegate_->OnError(error_code_, error_message_, new_version_);
353 else if (install_update_if_possible_)
354 delegate_->OnUpgradeComplete(new_version_);
355 else
356 delegate_->OnUpdateCheckComplete(new_version_);
360 void UpdateCheckDriver::BeginUpdateCheck() {
361 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
362 HRESULT hresult = BeginUpdateCheckInternal(&error_code);
363 if (SUCCEEDED(hresult)) {
364 // Start polling.
365 task_runner_->PostTask(FROM_HERE,
366 base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
367 base::Unretained(this)));
368 } else {
369 // Return results immediately since the driver is not polling Google Update.
370 OnUpgradeError(error_code, hresult, -1, base::string16());
371 result_runner_->DeleteSoon(FROM_HERE, this);
375 HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
376 GoogleUpdateErrorCode* error_code) {
377 base::FilePath chrome_exe;
378 if (!PathService::Get(base::DIR_EXE, &chrome_exe))
379 NOTREACHED();
381 system_level_install_ = !InstallUtil::IsPerUserInstall(chrome_exe);
383 // Make sure ATL is initialized in this module.
384 ui::win::CreateATLModuleIfNeeded();
386 *error_code = CanUpdateCurrentChrome(chrome_exe, system_level_install_);
387 if (*error_code != GOOGLE_UPDATE_NO_ERROR)
388 return E_FAIL;
390 HRESULT hresult = CreateGoogleUpdate3WebClass(
391 system_level_install_, install_update_if_possible_, elevation_window_,
392 &google_update_);
393 if (FAILED(hresult)) {
394 *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND;
395 return hresult;
398 // The class was created, so all subsequent errors are reported as:
399 *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
400 base::string16 app_guid =
401 installer::GetAppGuidForUpdates(system_level_install_);
402 DCHECK(!app_guid.empty());
405 base::win::ScopedComPtr<IDispatch> dispatch;
406 hresult = google_update_->createAppBundleWeb(dispatch.Receive());
407 if (FAILED(hresult))
408 return hresult;
409 hresult = dispatch.QueryInterface(app_bundle_.Receive());
410 if (FAILED(hresult))
411 return hresult;
414 if (!locale_.empty()) {
415 // Ignore the result of this since, while setting the display language is
416 // nice to have, a failure to do so does not affect the likelihood that the
417 // update check and/or install will succeed.
418 app_bundle_->put_displayLanguage(
419 base::win::ScopedBstr(base::UTF8ToUTF16(locale_).c_str()));
422 hresult = app_bundle_->initialize();
423 if (FAILED(hresult))
424 return hresult;
425 if (elevation_window_) {
426 // Likewise, a failure to set the parent window need not block an update
427 // check.
428 app_bundle_->put_parentHWND(reinterpret_cast<ULONG_PTR>(elevation_window_));
431 base::win::ScopedComPtr<IDispatch> dispatch;
432 hresult =
433 app_bundle_->createInstalledApp(base::win::ScopedBstr(app_guid.c_str()));
434 if (FAILED(hresult))
435 return hresult;
436 hresult = app_bundle_->get_appWeb(0, dispatch.Receive());
437 if (FAILED(hresult))
438 return hresult;
439 hresult = dispatch.QueryInterface(app_.Receive());
440 if (FAILED(hresult))
441 return hresult;
442 return app_bundle_->checkForUpdate();
445 bool UpdateCheckDriver::GetCurrentState(
446 base::win::ScopedComPtr<ICurrentState>* current_state,
447 CurrentState* state_value,
448 HRESULT* hresult) const {
449 base::win::ScopedComPtr<IDispatch> dispatch;
450 *hresult = app_->get_currentState(dispatch.Receive());
451 if (FAILED(*hresult))
452 return false;
453 *hresult = dispatch.QueryInterface(current_state->Receive());
454 if (FAILED(*hresult))
455 return false;
456 LONG value = 0;
457 *hresult = (*current_state)->get_stateValue(&value);
458 if (FAILED(*hresult))
459 return false;
460 *state_value = static_cast<CurrentState>(value);
461 return true;
464 bool UpdateCheckDriver::IsErrorState(
465 const base::win::ScopedComPtr<ICurrentState>& current_state,
466 CurrentState state_value,
467 GoogleUpdateErrorCode* error_code,
468 HRESULT* hresult,
469 int* installer_exit_code,
470 base::string16* error_string) const {
471 if (state_value == STATE_ERROR) {
472 // In general, errors reported by Google Update fall under this category
473 // (see special case below).
474 *error_code = GOOGLE_UPDATE_ERROR_UPDATING;
476 // In general, the exit code of Chrome's installer is unknown (see special
477 // case below).
478 *installer_exit_code = -1;
480 // Report the error_code provided by Google Update if possible, or the
481 // reason it wasn't possible otherwise.
482 LONG long_value = 0;
483 *hresult = current_state->get_errorCode(&long_value);
484 if (SUCCEEDED(*hresult))
485 *hresult = long_value;
487 // Special cases:
488 // - Use a custom error code if Google Update repoted that the update was
489 // disabled by a Group Policy setting.
490 // - Extract the exit code of Chrome's installer if Google Update repoted
491 // that the update failed because of a failure in the installer.
492 LONG code = 0;
493 if (*hresult == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY) {
494 *error_code = GOOGLE_UPDATE_DISABLED_BY_POLICY;
495 } else if (*hresult == GOOPDATEINSTALL_E_INSTALLER_FAILED &&
496 SUCCEEDED(current_state->get_installerResultCode(&code))) {
497 *installer_exit_code = code;
500 base::win::ScopedBstr message;
501 if (SUCCEEDED(current_state->get_completionMessage(message.Receive())))
502 error_string->assign(message, message.Length());
504 return true;
506 if (state_value == STATE_UPDATE_AVAILABLE && install_update_if_possible_) {
507 *hresult = app_bundle_->install();
508 if (FAILED(*hresult)) {
509 // Report a failure to start the install as a general error while trying
510 // to interact with Google Update.
511 *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
512 *installer_exit_code = -1;
513 return true;
515 // Return false for handling in IsIntermediateState.
517 return false;
520 bool UpdateCheckDriver::IsFinalState(
521 const base::win::ScopedComPtr<ICurrentState>& current_state,
522 CurrentState state_value,
523 GoogleUpdateUpgradeStatus* upgrade_status,
524 base::string16* new_version) const {
525 if (state_value == STATE_UPDATE_AVAILABLE && !install_update_if_possible_) {
526 base::win::ScopedBstr version;
527 *upgrade_status = UPGRADE_IS_AVAILABLE;
528 if (SUCCEEDED(current_state->get_availableVersion(version.Receive())))
529 new_version->assign(version, version.Length());
530 return true;
532 if (state_value == STATE_INSTALL_COMPLETE) {
533 DCHECK(install_update_if_possible_);
534 *upgrade_status = UPGRADE_SUCCESSFUL;
535 return true;
537 if (state_value == STATE_NO_UPDATE) {
538 *upgrade_status = UPGRADE_ALREADY_UP_TO_DATE;
539 return true;
541 return false;
544 bool UpdateCheckDriver::IsIntermediateState(
545 const base::win::ScopedComPtr<ICurrentState>& current_state,
546 CurrentState state_value,
547 base::string16* new_version,
548 int* progress) const {
549 // ERROR will have been handled in IsErrorState. UPDATE_AVAILABLE, and
550 // NO_UPDATE will have been handled in IsFinalState if not doing an install,
551 // as will STATE_INSTALL_COMPLETE when doing an install. All other states
552 // following UPDATE_AVAILABLE will only happen when an install is to be done.
553 DCHECK(state_value < STATE_UPDATE_AVAILABLE || install_update_if_possible_);
554 *progress = 0;
556 switch (state_value) {
557 case STATE_INIT:
558 case STATE_WAITING_TO_CHECK_FOR_UPDATE:
559 case STATE_CHECKING_FOR_UPDATE:
560 // There is no news to report yet.
561 break;
563 case STATE_UPDATE_AVAILABLE: {
564 base::win::ScopedBstr version;
565 if (SUCCEEDED(current_state->get_availableVersion(version.Receive())))
566 new_version->assign(version, version.Length());
567 break;
570 case STATE_WAITING_TO_DOWNLOAD:
571 case STATE_RETRYING_DOWNLOAD:
572 break;
574 case STATE_DOWNLOADING: {
575 ULONG bytes_downloaded = 0;
576 ULONG total_bytes = 0;
577 if (SUCCEEDED(current_state->get_bytesDownloaded(&bytes_downloaded)) &&
578 SUCCEEDED(current_state->get_totalBytesToDownload(&total_bytes)) &&
579 total_bytes) {
580 // 0-50 is downloading.
581 *progress = gfx::ToFlooredInt((static_cast<double>(bytes_downloaded) /
582 static_cast<double>(total_bytes)) *
583 50.0);
585 break;
588 case STATE_DOWNLOAD_COMPLETE:
589 case STATE_EXTRACTING:
590 case STATE_APPLYING_DIFFERENTIAL_PATCH:
591 case STATE_READY_TO_INSTALL:
592 case STATE_WAITING_TO_INSTALL:
593 *progress = 50;
594 break;
596 case STATE_INSTALLING: {
597 *progress = 50;
598 LONG install_progress = 0;
599 if (SUCCEEDED(current_state->get_installProgress(&install_progress)) &&
600 install_progress >= 0 && install_progress <= 100) {
601 // 50-100 is installing.
602 *progress = (50 + install_progress / 2);
604 break;
607 case STATE_INSTALL_COMPLETE:
608 case STATE_PAUSED:
609 case STATE_NO_UPDATE:
610 case STATE_ERROR:
611 default:
612 NOTREACHED();
613 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.UnexpectedState", state_value);
614 return false;
616 return true;
619 void UpdateCheckDriver::PollGoogleUpdate() {
620 base::win::ScopedComPtr<ICurrentState> state;
621 CurrentState state_value = STATE_INIT;
622 HRESULT hresult = S_OK;
623 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
624 int installer_exit_code = -1;
625 base::string16 error_string;
626 GoogleUpdateUpgradeStatus upgrade_status = UPGRADE_ERROR;
627 base::string16 new_version;
628 int progress = 0;
630 if (!GetCurrentState(&state, &state_value, &hresult)) {
631 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult, -1,
632 base::string16());
633 } else if (IsErrorState(state, state_value, &error_code, &hresult,
634 &installer_exit_code, &error_string)) {
635 OnUpgradeError(error_code, hresult, installer_exit_code, error_string);
636 } else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) {
637 status_ = upgrade_status;
638 error_code_ = GOOGLE_UPDATE_NO_ERROR;
639 error_message_.clear();
640 if (!new_version.empty())
641 new_version_ = new_version;
642 hresult_ = S_OK;
643 installer_exit_code_ = -1;
644 } else if (IsIntermediateState(state, state_value, &new_version, &progress)) {
645 bool got_new_version = new_version_.empty() && !new_version.empty();
646 if (got_new_version)
647 new_version_ = new_version;
648 // Give the caller this status update if it differs from the last one given.
649 if (got_new_version || progress != last_reported_progress_) {
650 last_reported_progress_ = progress;
652 // It is safe to post this task with an unretained pointer since the task
653 // is guaranteed to run before a subsequent DeleteSoon is handled.
654 result_runner_->PostTask(
655 FROM_HERE,
656 base::Bind(&UpdateCheckDelegate::OnUpgradeProgress, delegate_,
657 last_reported_progress_, new_version_));
660 // Schedule the next check.
661 task_runner_->PostDelayedTask(
662 FROM_HERE, base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
663 base::Unretained(this)),
664 base::TimeDelta::FromMilliseconds(kGoogleUpdatePollIntervalMs));
665 // Early return for this non-terminal state.
666 return;
669 // Release the reference on the COM objects before bouncing back to the
670 // caller's thread.
671 state.Release();
672 app_.Release();
673 app_bundle_.Release();
674 google_update_.Release();
676 result_runner_->DeleteSoon(FROM_HERE, this);
679 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
680 HRESULT hresult,
681 int installer_exit_code,
682 const base::string16& error_string) {
683 status_ = UPGRADE_ERROR;
684 error_code_ = error_code;
685 hresult_ = hresult;
686 installer_exit_code_ = installer_exit_code;
687 base::string16 error_msg =
688 base::StringPrintf(L"%d: 0x%x", error_code_, hresult_);
689 if (installer_exit_code_ != -1)
690 error_msg += base::StringPrintf(L": %d", installer_exit_code_);
691 if (system_level_install_)
692 error_msg += L" -- system level";
693 if (error_string.empty()) {
694 error_message_ = l10n_util::GetStringFUTF16(
695 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, error_msg);
696 } else {
697 error_message_ = l10n_util::GetStringFUTF16(
698 IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR, error_string, error_msg);
702 } // namespace
705 // Globals ---------------------------------------------------------------------
707 void BeginUpdateCheck(
708 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
709 const std::string& locale,
710 bool install_update_if_possible,
711 gfx::AcceleratedWidget elevation_window,
712 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
713 UpdateCheckDriver::RunUpdateCheck(task_runner, locale,
714 install_update_if_possible,
715 elevation_window, delegate);
719 // Private API exposed for testing. --------------------------------------------
721 void SetGoogleUpdateFactoryForTesting(
722 const GoogleUpdate3ClassFactory& google_update_factory) {
723 if (g_google_update_factory) {
724 delete g_google_update_factory;
725 g_google_update_factory = nullptr;
727 if (!google_update_factory.is_null()) {
728 g_google_update_factory =
729 new GoogleUpdate3ClassFactory(google_update_factory);