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"
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"
36 // The status of the upgrade. These values are used for a histogram. Do not
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,
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
,
92 gfx::AcceleratedWidget hwnd
,
93 void** interface_ptr
) {
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",
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
,
120 return CoCreateInstance(class_id
, NULL
, CLSCTX_LOCAL_SERVER
, interface_id
,
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
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
{
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
);
165 friend class base::DeleteHelper
<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
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
,
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
,
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
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_
;
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
286 GoogleUpdateUpgradeStatus status_
;
287 GoogleUpdateErrorCode error_code_
;
288 base::string16 error_message_
;
289 base::string16 new_version_
;
291 int installer_exit_code_
;
293 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver
);
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
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()),
323 install_update_if_possible_(install_update_if_possible
),
324 elevation_window_(elevation_window
),
326 system_level_install_(false),
327 last_reported_progress_(0),
328 status_(UPGRADE_ERROR
),
329 error_code_(GOOGLE_UPDATE_NO_ERROR
),
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_
,
340 if (status_
== UPGRADE_ERROR
) {
341 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_
,
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_
);
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_
);
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
)) {
365 task_runner_
->PostTask(FROM_HERE
,
366 base::Bind(&UpdateCheckDriver::PollGoogleUpdate
,
367 base::Unretained(this)));
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
))
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
)
390 HRESULT hresult
= CreateGoogleUpdate3WebClass(
391 system_level_install_
, install_update_if_possible_
, elevation_window_
,
393 if (FAILED(hresult
)) {
394 *error_code
= GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND
;
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());
409 hresult
= dispatch
.QueryInterface(app_bundle_
.Receive());
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();
425 if (elevation_window_
) {
426 // Likewise, a failure to set the parent window need not block an update
428 app_bundle_
->put_parentHWND(reinterpret_cast<ULONG_PTR
>(elevation_window_
));
431 base::win::ScopedComPtr
<IDispatch
> dispatch
;
433 app_bundle_
->createInstalledApp(base::win::ScopedBstr(app_guid
.c_str()));
436 hresult
= app_bundle_
->get_appWeb(0, dispatch
.Receive());
439 hresult
= dispatch
.QueryInterface(app_
.Receive());
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
))
453 *hresult
= dispatch
.QueryInterface(current_state
->Receive());
454 if (FAILED(*hresult
))
457 *hresult
= (*current_state
)->get_stateValue(&value
);
458 if (FAILED(*hresult
))
460 *state_value
= static_cast<CurrentState
>(value
);
464 bool UpdateCheckDriver::IsErrorState(
465 const base::win::ScopedComPtr
<ICurrentState
>& current_state
,
466 CurrentState state_value
,
467 GoogleUpdateErrorCode
* error_code
,
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
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.
483 *hresult
= current_state
->get_errorCode(&long_value
);
484 if (SUCCEEDED(*hresult
))
485 *hresult
= long_value
;
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.
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());
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;
515 // Return false for handling in IsIntermediateState.
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());
532 if (state_value
== STATE_INSTALL_COMPLETE
) {
533 DCHECK(install_update_if_possible_
);
534 *upgrade_status
= UPGRADE_SUCCESSFUL
;
537 if (state_value
== STATE_NO_UPDATE
) {
538 *upgrade_status
= UPGRADE_ALREADY_UP_TO_DATE
;
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_
);
556 switch (state_value
) {
558 case STATE_WAITING_TO_CHECK_FOR_UPDATE
:
559 case STATE_CHECKING_FOR_UPDATE
:
560 // There is no news to report yet.
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());
570 case STATE_WAITING_TO_DOWNLOAD
:
571 case STATE_RETRYING_DOWNLOAD
:
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
)) &&
580 // 0-50 is downloading.
581 *progress
= gfx::ToFlooredInt((static_cast<double>(bytes_downloaded
) /
582 static_cast<double>(total_bytes
)) *
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
:
596 case STATE_INSTALLING
: {
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);
607 case STATE_INSTALL_COMPLETE
:
609 case STATE_NO_UPDATE
:
613 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.UnexpectedState", state_value
);
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
;
630 if (!GetCurrentState(&state
, &state_value
, &hresult
)) {
631 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR
, hresult
, -1,
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
;
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();
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(
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.
669 // Release the reference on the COM objects before bouncing back to the
673 app_bundle_
.Release();
674 google_update_
.Release();
676 result_runner_
->DeleteSoon(FROM_HERE
, this);
679 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code
,
681 int installer_exit_code
,
682 const base::string16
& error_string
) {
683 status_
= UPGRADE_ERROR
;
684 error_code_
= error_code
;
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
);
697 error_message_
= l10n_util::GetStringFUTF16(
698 IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR
, error_string
, error_msg
);
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
);