1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/google/google_update_win.h"
6
7 #include <objbase.h>
8 #include <stdint.h>
9 #include <string.h>
10
11 #include <utility>
12 #include <vector>
13
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/command_line.h"
17 #include "base/files/file_path.h"
18 #include "base/location.h"
19 #include "base/metrics/histogram_functions.h"
20 #include "base/no_destructor.h"
21 #include "base/numerics/safe_conversions.h"
22 #include "base/path_service.h"
23 #include "base/sequenced_task_runner.h"
24 #include "base/sequenced_task_runner_helpers.h"
25 #include "base/single_thread_task_runner.h"
26 #include "base/stl_util.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_util.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "base/task/post_task.h"
32 #include "base/task/task_traits.h"
33 #include "base/task/thread_pool.h"
34 #include "base/threading/sequenced_task_runner_handle.h"
35 #include "base/time/time.h"
36 #include "base/version.h"
37 #include "base/win/atl.h"
38 #include "base/win/scoped_bstr.h"
39 #include "base/win/win_util.h"
40 #include "chrome/browser/google/switches.h"
41 #include "chrome/common/url_constants.h"
42 #include "chrome/grit/generated_resources.h"
43 #include "chrome/install_static/install_util.h"
44 #include "chrome/installer/util/google_update_settings.h"
45 #include "chrome/installer/util/helper.h"
46 #include "chrome/installer/util/install_util.h"
47 #include "ui/base/l10n/l10n_util.h"
48 #include "ui/base/win/atl_module.h"
49
50 namespace {
51
52 struct UpdateCheckResult {
53 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
54 HRESULT hresult = S_OK;
55 };
56
57 // The status of the upgrade. These values are used for a histogram. Do not
58 // reorder.
59 enum GoogleUpdateUpgradeStatus {
60 // The upgrade has started. DEPRECATED.
61 // UPGRADE_STARTED = 0,
62 // A check for upgrade has been initiated. DEPRECATED.
63 // UPGRADE_CHECK_STARTED = 1,
64 // An update is available.
65 UPGRADE_IS_AVAILABLE = 2,
66 // The upgrade happened successfully.
67 UPGRADE_SUCCESSFUL = 3,
68 // No need to upgrade, Chrome is up to date.
69 UPGRADE_ALREADY_UP_TO_DATE = 4,
70 // An error occurred.
71 UPGRADE_ERROR = 5,
72 NUM_UPGRADE_STATUS
73 };
74
75 GoogleUpdate3ClassFactory* g_google_update_factory = nullptr;
76 base::SingleThreadTaskRunner* g_update_driver_task_runner = nullptr;
77
78 // The time interval, in milliseconds, between polls to Google Update. This
79 // value was chosen unscientificaly during an informal discussion.
80 const int64_t kGoogleUpdatePollIntervalMs = 250;
81
82 const int kGoogleAllowedRetries = 1;
83 const int kGoogleRetryIntervalSeconds = 5;
84
85 // Constants from Google Update.
86 const HRESULT GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY = 0x80040813;
87 const HRESULT GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL = 0x8004081f;
88 const HRESULT GOOPDATE_E_APP_USING_EXTERNAL_UPDATER = 0xA043081D;
89 const HRESULT GOOPDATEINSTALL_E_INSTALLER_FAILED = 0x80040902;
90
91 // Older versions of GoogleUpdate require elevation for system-level updates.
IsElevationRequiredForSystemLevelUpdates()92 bool IsElevationRequiredForSystemLevelUpdates() {
93 const base::Version kMinGUVersionNoElevationRequired("1.3.29.1");
94 const base::Version current_version(
95 GoogleUpdateSettings::GetGoogleUpdateVersion(true));
96
97 return !current_version.IsValid() ||
98 current_version < kMinGUVersionNoElevationRequired;
99 }
100
101 // Check if the currently running instance can be updated by Google Update.
102 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
103 // Chrome distribution installed in a standard location.
CanUpdateCurrentChrome(const base::FilePath & chrome_exe_path,bool system_level_install)104 GoogleUpdateErrorCode CanUpdateCurrentChrome(
105 const base::FilePath& chrome_exe_path,
106 bool system_level_install) {
107 DCHECK_NE(InstallUtil::IsPerUserInstall(), system_level_install);
108 base::FilePath user_exe_path = installer::GetChromeInstallPath(false);
109 base::FilePath machine_exe_path = installer::GetChromeInstallPath(true);
110 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
111 user_exe_path.value()) &&
112 !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
113 machine_exe_path.value())) {
114 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
115 }
116
117 return GOOGLE_UPDATE_NO_ERROR;
118 }
119
120 // Explicitly allow the Google Update service to impersonate the client since
121 // some COM code elsewhere in the browser process may have previously used
122 // CoInitializeSecurity to set the impersonation level to something other than
123 // the default. Ignore errors since an attempt to use Google Update may succeed
124 // regardless.
ConfigureProxyBlanket(IUnknown * interface_pointer)125 void ConfigureProxyBlanket(IUnknown* interface_pointer) {
126 ::CoSetProxyBlanket(interface_pointer,
127 RPC_C_AUTHN_DEFAULT,
128 RPC_C_AUTHZ_DEFAULT,
129 COLE_DEFAULT_PRINCIPAL,
130 RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
131 RPC_C_IMP_LEVEL_IMPERSONATE,
132 nullptr,
133 EOAC_DYNAMIC_CLOAKING);
134 }
135
136 // Creates a class factory for a COM Local Server class using the Elevation
137 // moniker. |hwnd| must refer to a foregound window in order to get the UAC
138 // prompt to appear in the foreground if running on Vista+. It can also be NULL
139 // if background UAC prompts are desired.
CoGetClassObjectAsAdmin(gfx::AcceleratedWidget hwnd,REFCLSID class_id,REFIID interface_id,void ** interface_ptr)140 HRESULT CoGetClassObjectAsAdmin(gfx::AcceleratedWidget hwnd,
141 REFCLSID class_id,
142 REFIID interface_id,
143 void** interface_ptr) {
144 if (!interface_ptr)
145 return E_POINTER;
146
147 // For Vista+, need to instantiate the class factory via the elevation
148 // moniker. This ensures that the UAC dialog shows up.
149 auto class_id_as_string = base::win::WStringFromGUID(class_id);
150
151 base::string16 elevation_moniker_name = base::StringPrintf(
152 L"Elevation:Administrator!clsid:%ls", class_id_as_string.c_str());
153
154 BIND_OPTS3 bind_opts;
155 // An explicit memset is needed rather than relying on value initialization
156 // since BIND_OPTS3 is not an aggregate (it is a derived type).
157 memset(&bind_opts, 0, sizeof(bind_opts));
158 bind_opts.cbStruct = sizeof(bind_opts);
159 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
160 bind_opts.hwnd = hwnd;
161
162 return ::CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id,
163 interface_ptr);
164 }
165
CreateGoogleUpdate3WebClass(bool system_level_install,bool install_update_if_possible,gfx::AcceleratedWidget elevation_window,Microsoft::WRL::ComPtr<IGoogleUpdate3Web> * google_update)166 HRESULT CreateGoogleUpdate3WebClass(
167 bool system_level_install,
168 bool install_update_if_possible,
169 gfx::AcceleratedWidget elevation_window,
170 Microsoft::WRL::ComPtr<IGoogleUpdate3Web>* google_update) {
171 if (g_google_update_factory)
172 return g_google_update_factory->Run(google_update);
173
174 const CLSID& google_update_clsid = system_level_install ?
175 CLSID_GoogleUpdate3WebMachineClass :
176 CLSID_GoogleUpdate3WebUserClass;
177 Microsoft::WRL::ComPtr<IClassFactory> class_factory;
178 HRESULT hresult = S_OK;
179
180 // For a user-level install, update checks and updates can both be done by a
181 // normal user with the UserClass. For a system-level install, update checks
182 // can be done by a normal user with the MachineClass. Newer versions of
183 // GoogleUpdate allow normal users to also install system-level updates
184 // without requiring elevation.
185 if (!system_level_install ||
186 !install_update_if_possible ||
187 !IsElevationRequiredForSystemLevelUpdates()) {
188 hresult = ::CoGetClassObject(google_update_clsid, CLSCTX_ALL, nullptr,
189 IID_PPV_ARGS(&class_factory));
190 } else {
191 // With older versions of GoogleUpdate, a system-level update requires Admin
192 // privileges. Elevate while instantiating the MachineClass.
193 hresult = CoGetClassObjectAsAdmin(elevation_window, google_update_clsid,
194 IID_PPV_ARGS(&class_factory));
195 }
196 if (FAILED(hresult))
197 return hresult;
198
199 ConfigureProxyBlanket(class_factory.Get());
200
201 return class_factory->CreateInstance(nullptr,
202 IID_PPV_ARGS(&(*google_update)));
203 }
204
205 // Returns the process-wide storage for the state of the last update check.
GetLastUpdateStateStorage()206 base::Optional<UpdateState>* GetLastUpdateStateStorage() {
207 static base::NoDestructor<base::Optional<UpdateState>> storage;
208 return storage.get();
209 }
210
211 // Checks if --simulate-update-hresult is present in the command line and
212 // returns either: nullopt if switch not present, or E_FAIL if the switch
213 // was present without the value, or the value of the switch as an HRESULT.
214 // Additionally the returned structure contains the default error code
215 // GOOGLE_UPDATE_ERROR_UPDATING or the value of --simulate-update-error-code.
GetSimulatedErrorForDebugging()216 base::Optional<UpdateCheckResult> GetSimulatedErrorForDebugging() {
217 const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
218 if (!cmd_line.HasSwitch(switches::kSimulateUpdateHresult))
219 return base::nullopt;
220
221 uint32_t error_from_string = 0;
222 std::string error_switch_value =
223 cmd_line.GetSwitchValueASCII(switches::kSimulateUpdateHresult);
224 HRESULT hresult = E_FAIL;
225 if (base::HexStringToUInt(error_switch_value, &error_from_string))
226 hresult = error_from_string;
227
228 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_ERROR_UPDATING;
229 error_switch_value =
230 cmd_line.GetSwitchValueASCII(switches::kSimulateUpdateErrorCode);
231 int32_t error_code_value = 0;
232 if (base::StringToInt(error_switch_value, &error_code_value) &&
233 error_code_value >= 0 && error_code_value < NUM_ERROR_CODES) {
234 error_code = static_cast<GoogleUpdateErrorCode>(error_code_value);
235 }
236
237 return {{error_code, hresult}};
238 }
239
240 // UpdateCheckDriver -----------------------------------------------------------
241
242 // A driver that is created and destroyed on the caller's thread and drives
243 // Google Update on another.
244 class UpdateCheckDriver {
245 public:
246 // Runs an update check, invoking methods of |delegate| on the caller's thread
247 // to report progress and final results.
248 static void RunUpdateCheck(
249 const std::string& locale,
250 bool install_update_if_possible,
251 gfx::AcceleratedWidget elevation_window,
252 const base::WeakPtr<UpdateCheckDelegate>& delegate);
253
254 private:
255 friend class base::DeleteHelper<UpdateCheckDriver>;
256
257 UpdateCheckDriver(
258 const std::string& locale,
259 bool install_update_if_possible,
260 gfx::AcceleratedWidget elevation_window,
261 const base::WeakPtr<UpdateCheckDelegate>& delegate);
262
263 // Invokes a completion or error method on all delegates, as appropriate.
264 ~UpdateCheckDriver();
265
266 // If an UpdateCheckDriver is already running, the delegate is added to the
267 // existing one instead of creating a new one.
268 void AddDelegate(const base::WeakPtr<UpdateCheckDelegate>& delegate);
269
270 // Notifies delegates of an update's progress. |progress|, a number between 0
271 // and 100 (inclusive), is an estimation as to what percentage of the upgrade
272 // has completed. |new_version| indicates the version that is being download
273 // and installed.
274 void NotifyUpgradeProgress(int progress, const base::string16& new_version);
275
276 // Starts an update check.
277 void BeginUpdateCheck();
278
279 // Returns the result of initiating an update check. On failure, the instance
280 // is left in a consistent state so that this method can be invoked later to
281 // retry the steps that failed.
282 UpdateCheckResult BeginUpdateCheckInternal();
283
284 // Sets status_ to UPGRADE_ERROR, update_state_.error_code to |error_code|,
285 // update_state_.hresult to |check_result.hresult|,
286 // update_state_.installer_exit_code to |installer_exit_code|,
287 // and html_error_message_ to a composition of all values suitable for display
288 // to the user. This call should be followed by deletion of the driver, which
289 // will result in callers being notified via their delegates.
290 void OnUpgradeError(UpdateCheckResult check_result,
291 base::Optional<int> installer_exit_code,
292 const base::string16& error_string);
293
294 // Returns true if |current_state| and |state_value| can be obtained from the
295 // ongoing update check. Otherwise, populates |hresult| with the reason they
296 // could not be obtained.
297 bool GetCurrentState(Microsoft::WRL::ComPtr<ICurrentState>* current_state,
298 CurrentState* state_value,
299 HRESULT* hresult) const;
300
301 // Returns true if |current_state| and |state_value| constitute an error state
302 // for the ongoing update check, in which case |error_code| is populated with
303 // one of GOOGLE_UPDATE_ERROR_UPDATING, GOOGLE_UPDATE_DISABLED_BY_POLICY, or
304 // GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR. |hresult| is populated with
305 // the most relevant HRESULT (which may be a value from Google Update; see
306 // https://code.google.com/p/omaha/source/browse/trunk/base/error.h). In case
307 // Chrome's installer failed during execution, |installer_exit_code| may be
308 // populated with its process exit code (see enum installer::InstallStatus in
309 // chrome/installer/util/util_constants.h). |error_string| will be populated
310 // with a completion message if one is provided by Google Update.
311 bool IsErrorState(const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
312 CurrentState state_value,
313 GoogleUpdateErrorCode* error_code,
314 HRESULT* hresult,
315 base::Optional<int>* installer_exit_code,
316 base::string16* error_string) const;
317
318 // Returns true if |current_state| and |state_value| constitute a final state
319 // for the ongoing update check, in which case |upgrade_status| is populated
320 // with one of UPGRADE_ALREADY_UP_TO_DATE or UPGRADE_IS_AVAILABLE (in case a
321 // pure check is being performed rather than an update) or UPGRADE_SUCCESSFUL
322 // (in case an update is being performed). For the UPGRADE_IS_AVAILABLE case,
323 // |new_version| will be populated with the available version, if provided by
324 // Google Update.
325 bool IsFinalState(const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
326 CurrentState state_value,
327 GoogleUpdateUpgradeStatus* upgrade_status,
328 base::string16* new_version) const;
329
330 // Returns true if |current_state| and |state_value| constitute an
331 // intermediate state for the ongoing update check. |new_version| will be
332 // populated with the version to be installed if it is provided by Google
333 // Update for the current state. |progress| will be populated with a number
334 // between 0 and 100 according to how far Google Update has progressed in the
335 // download and install process.
336 bool IsIntermediateState(
337 const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
338 CurrentState state_value,
339 base::string16* new_version,
340 int* progress) const;
341
342 // Polls Google Update to determine the state of the ongoing check or
343 // update. If the process has reached a terminal state, this instance will be
344 // deleted and the caller will be notified of the final status. Otherwise, the
345 // caller will be notified of the intermediate state (iff it differs from a
346 // previous notification) and another future poll will be scheduled.
347 void PollGoogleUpdate();
348
349 // The global driver instance. Accessed only on the caller's thread.
350 static UpdateCheckDriver* driver_;
351
352 // The task runner on which the update checks runs.
353 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
354
355 // The caller's task runner, on which methods of the |delegates_| will be
356 // invoked.
357 scoped_refptr<base::SequencedTaskRunner> result_runner_;
358
359 // The UI locale.
360 std::string locale_;
361
362 // False to only check for an update; true to also install one if available.
363 bool install_update_if_possible_;
364
365 // A parent window in case any UX is required (e.g., an elevation prompt).
366 gfx::AcceleratedWidget elevation_window_;
367
368 // Contains all delegates by which feedback is conveyed. Accessed only on the
369 // caller's thread.
370 std::vector<base::WeakPtr<UpdateCheckDelegate>> delegates_;
371
372 // Number of remaining retries allowed when errors occur.
373 int allowed_retries_;
374
375 // True if operating on a per-machine installation rather than a per-user one.
376 bool system_level_install_;
377
378 // The on-demand updater that is doing the work.
379 Microsoft::WRL::ComPtr<IGoogleUpdate3Web> google_update_;
380
381 // An app bundle containing the application being updated.
382 Microsoft::WRL::ComPtr<IAppBundleWeb> app_bundle_;
383
384 // The application being updated (Chrome, Chrome Binaries, or Chrome SxS).
385 Microsoft::WRL::ComPtr<IAppWeb> app_;
386
387 // The progress value reported most recently to the caller.
388 int last_reported_progress_;
389
390 // The results of the update check to be logged via UMA and/or reported to the
391 // caller.
392 GoogleUpdateUpgradeStatus status_;
393 UpdateState update_state_;
394 base::string16 html_error_message_;
395
396 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
397 };
398
399 UpdateCheckDriver* UpdateCheckDriver::driver_ = nullptr;
400
401 // static
RunUpdateCheck(const std::string & locale,bool install_update_if_possible,gfx::AcceleratedWidget elevation_window,const base::WeakPtr<UpdateCheckDelegate> & delegate)402 void UpdateCheckDriver::RunUpdateCheck(
403 const std::string& locale,
404 bool install_update_if_possible,
405 gfx::AcceleratedWidget elevation_window,
406 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
407 // Create the driver if it doesn't exist, or add the delegate to the existing
408 // one.
409 if (!driver_) {
410 // The driver is owned by itself, and will self-destruct when its work is
411 // done.
412 driver_ = new UpdateCheckDriver(locale, install_update_if_possible,
413 elevation_window, delegate);
414 driver_->task_runner_->PostTask(
415 FROM_HERE, base::BindOnce(&UpdateCheckDriver::BeginUpdateCheck,
416 base::Unretained(driver_)));
417 } else {
418 driver_->AddDelegate(delegate);
419 }
420 }
421
422 // Runs on the caller's thread.
UpdateCheckDriver(const std::string & locale,bool install_update_if_possible,gfx::AcceleratedWidget elevation_window,const base::WeakPtr<UpdateCheckDelegate> & delegate)423 UpdateCheckDriver::UpdateCheckDriver(
424 const std::string& locale,
425 bool install_update_if_possible,
426 gfx::AcceleratedWidget elevation_window,
427 const base::WeakPtr<UpdateCheckDelegate>& delegate)
428 : task_runner_(
429 g_update_driver_task_runner
430 ? g_update_driver_task_runner
431 : base::ThreadPool::CreateCOMSTATaskRunner(
432 {base::MayBlock(), base::TaskPriority::USER_VISIBLE})),
433 result_runner_(base::SequencedTaskRunnerHandle::Get()),
434 locale_(locale),
435 install_update_if_possible_(install_update_if_possible),
436 elevation_window_(elevation_window),
437 delegates_(1, delegate),
438 allowed_retries_(kGoogleAllowedRetries),
439 system_level_install_(false),
440 last_reported_progress_(0),
441 status_(UPGRADE_ERROR) {}
442
~UpdateCheckDriver()443 UpdateCheckDriver::~UpdateCheckDriver() {
444 DCHECK(result_runner_->RunsTasksInCurrentSequence());
445 // If there is an error, then error_code must not be blank, and vice versa.
446 DCHECK_NE(status_ == UPGRADE_ERROR,
447 update_state_.error_code == GOOGLE_UPDATE_NO_ERROR);
448
449 *GetLastUpdateStateStorage() = update_state_;
450
451 base::UmaHistogramEnumeration("GoogleUpdate.UpgradeResult", status_,
452 NUM_UPGRADE_STATUS);
453 if (status_ == UPGRADE_ERROR) {
454 base::UmaHistogramEnumeration("GoogleUpdate.UpdateErrorCode",
455 update_state_.error_code, NUM_ERROR_CODES);
456 if (FAILED(update_state_.hresult)) {
457 base::UmaHistogramSparse("GoogleUpdate.ErrorHresult",
458 update_state_.hresult);
459 }
460 }
461
462 // Clear the driver before calling the delegates because they might call
463 // BeginUpdateCheck() and they must not add themselves to the current
464 // instance of UpdateCheckDriver, which is being destroyed.
465 driver_ = nullptr;
466
467 for (const auto& delegate : delegates_) {
468 if (delegate) {
469 if (status_ == UPGRADE_ERROR) {
470 delegate->OnError(update_state_.error_code, html_error_message_,
471 update_state_.new_version);
472 } else if (install_update_if_possible_) {
473 delegate->OnUpgradeComplete(update_state_.new_version);
474 } else {
475 delegate->OnUpdateCheckComplete(update_state_.new_version);
476 }
477 }
478 }
479 }
480
AddDelegate(const base::WeakPtr<UpdateCheckDelegate> & delegate)481 void UpdateCheckDriver::AddDelegate(
482 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
483 DCHECK(result_runner_->RunsTasksInCurrentSequence());
484 delegates_.push_back(delegate);
485 }
486
NotifyUpgradeProgress(int progress,const base::string16 & new_version)487 void UpdateCheckDriver::NotifyUpgradeProgress(
488 int progress,
489 const base::string16& new_version) {
490 DCHECK(result_runner_->RunsTasksInCurrentSequence());
491
492 for (const auto& delegate : delegates_) {
493 if (delegate)
494 delegate->OnUpgradeProgress(progress, new_version);
495 }
496 }
497
BeginUpdateCheck()498 void UpdateCheckDriver::BeginUpdateCheck() {
499 UpdateCheckResult result = BeginUpdateCheckInternal();
500 if (SUCCEEDED(result.hresult)) {
501 // Start polling.
502 task_runner_->PostTask(FROM_HERE,
503 base::BindOnce(&UpdateCheckDriver::PollGoogleUpdate,
504 base::Unretained(this)));
505 return;
506 }
507 if (result.hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
508 // This particular transient error is worth retrying.
509 if (allowed_retries_) {
510 --allowed_retries_;
511 task_runner_->PostDelayedTask(
512 FROM_HERE,
513 base::BindOnce(&UpdateCheckDriver::BeginUpdateCheck,
514 base::Unretained(this)),
515 base::TimeDelta::FromSeconds(kGoogleRetryIntervalSeconds));
516 return;
517 }
518 }
519
520 DCHECK(FAILED(result.hresult));
521 OnUpgradeError(result, base::nullopt, base::string16());
522 result_runner_->DeleteSoon(FROM_HERE, this);
523 }
524
BeginUpdateCheckInternal()525 UpdateCheckResult UpdateCheckDriver::BeginUpdateCheckInternal() {
526 const auto simulated_error = GetSimulatedErrorForDebugging();
527 if (simulated_error.has_value())
528 return simulated_error.value();
529
530 HRESULT hresult = S_OK;
531
532 // Instantiate GoogleUpdate3Web{Machine,User}Class.
533 if (!google_update_) {
534 base::FilePath chrome_exe;
535 if (!base::PathService::Get(base::DIR_EXE, &chrome_exe))
536 NOTREACHED();
537
538 system_level_install_ = !InstallUtil::IsPerUserInstall();
539
540 // Make sure ATL is initialized in this module.
541 ui::win::CreateATLModuleIfNeeded();
542
543 const GoogleUpdateErrorCode error_code =
544 CanUpdateCurrentChrome(chrome_exe, system_level_install_);
545 if (error_code != GOOGLE_UPDATE_NO_ERROR)
546 return {error_code, E_FAIL};
547
548 hresult = CreateGoogleUpdate3WebClass(system_level_install_,
549 install_update_if_possible_,
550 elevation_window_, &google_update_);
551 if (FAILED(hresult))
552 return {GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, hresult};
553
554 ConfigureProxyBlanket(google_update_.Get());
555 }
556
557 // The class was created, so all subsequent errors are reported as:
558 constexpr GoogleUpdateErrorCode error_code =
559 GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
560
561 // Create an app bundle.
562 if (!app_bundle_) {
563 Microsoft::WRL::ComPtr<IAppBundleWeb> app_bundle;
564 Microsoft::WRL::ComPtr<IDispatch> dispatch;
565 hresult = google_update_->createAppBundleWeb(&dispatch);
566 if (FAILED(hresult))
567 return {error_code, hresult};
568 hresult = dispatch.As(&app_bundle);
569 if (FAILED(hresult))
570 return {error_code, hresult};
571 dispatch.Reset();
572
573 ConfigureProxyBlanket(app_bundle.Get());
574
575 if (!locale_.empty()) {
576 // Ignore the result of this since, while setting the display language is
577 // nice to have, a failure to do so does not affect the likelihood that
578 // the update check and/or install will succeed.
579 app_bundle->put_displayLanguage(
580 base::win::ScopedBstr(base::UTF8ToUTF16(locale_)).Get());
581 }
582
583 hresult = app_bundle->initialize();
584 if (FAILED(hresult))
585 return {error_code, hresult};
586 if (elevation_window_) {
587 // Likewise, a failure to set the parent window need not block an update
588 // check.
589 app_bundle->put_parentHWND(
590 reinterpret_cast<ULONG_PTR>(elevation_window_));
591 }
592 app_bundle_.Swap(app_bundle);
593 }
594
595 // Get a reference to the Chrome app in the bundle.
596 if (!app_) {
597 const wchar_t* app_guid = install_static::GetAppGuid();
598 DCHECK(app_guid);
599 DCHECK(*app_guid);
600
601 Microsoft::WRL::ComPtr<IDispatch> dispatch;
602 // It is common for this call to fail with APP_USING_EXTERNAL_UPDATER if
603 // an auto update is in progress.
604 hresult =
605 app_bundle_->createInstalledApp(base::win::ScopedBstr(app_guid).Get());
606 if (FAILED(hresult))
607 return {error_code, hresult};
608 // Move the IAppBundleWeb reference into a local now so that failures from
609 // this point onward result in it being released.
610 Microsoft::WRL::ComPtr<IAppBundleWeb> app_bundle;
611 app_bundle.Swap(app_bundle_);
612 hresult = app_bundle->get_appWeb(0, &dispatch);
613 if (FAILED(hresult))
614 return {error_code, hresult};
615 Microsoft::WRL::ComPtr<IAppWeb> app;
616 hresult = dispatch.As(&app);
617 if (FAILED(hresult))
618 return {error_code, hresult};
619 ConfigureProxyBlanket(app.Get());
620 hresult = app_bundle->checkForUpdate();
621 if (FAILED(hresult))
622 return {error_code, hresult};
623 app_bundle_.Swap(app_bundle);
624 app_.Swap(app);
625 }
626
627 return {GOOGLE_UPDATE_NO_ERROR, hresult};
628 }
629
GetCurrentState(Microsoft::WRL::ComPtr<ICurrentState> * current_state,CurrentState * state_value,HRESULT * hresult) const630 bool UpdateCheckDriver::GetCurrentState(
631 Microsoft::WRL::ComPtr<ICurrentState>* current_state,
632 CurrentState* state_value,
633 HRESULT* hresult) const {
634 Microsoft::WRL::ComPtr<IDispatch> dispatch;
635 *hresult = app_->get_currentState(&dispatch);
636 if (FAILED(*hresult))
637 return false;
638 *hresult = dispatch.As(&(*current_state));
639 if (FAILED(*hresult))
640 return false;
641 ConfigureProxyBlanket(current_state->Get());
642 LONG value = 0;
643 *hresult = (*current_state)->get_stateValue(&value);
644 if (FAILED(*hresult))
645 return false;
646 *state_value = static_cast<CurrentState>(value);
647 return true;
648 }
649
IsErrorState(const Microsoft::WRL::ComPtr<ICurrentState> & current_state,CurrentState state_value,GoogleUpdateErrorCode * error_code,HRESULT * hresult,base::Optional<int> * installer_exit_code,base::string16 * error_string) const650 bool UpdateCheckDriver::IsErrorState(
651 const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
652 CurrentState state_value,
653 GoogleUpdateErrorCode* error_code,
654 HRESULT* hresult,
655 base::Optional<int>* installer_exit_code,
656 base::string16* error_string) const {
657 if (state_value == STATE_ERROR) {
658 // In general, errors reported by Google Update fall under this category
659 // (see special case below).
660 *error_code = GOOGLE_UPDATE_ERROR_UPDATING;
661
662 // In general, the exit code of Chrome's installer is unknown (see special
663 // case below).
664 installer_exit_code->reset();
665
666 // Report the error_code provided by Google Update if possible, or the
667 // reason it wasn't possible otherwise.
668 LONG long_value = 0;
669 *hresult = current_state->get_errorCode(&long_value);
670 if (SUCCEEDED(*hresult))
671 *hresult = long_value;
672
673 // Special cases:
674 // - Use a custom error code if Google Update repoted that the update was
675 // disabled by a Group Policy setting.
676 // - Extract the exit code of Chrome's installer if Google Update repoted
677 // that the update failed because of a failure in the installer.
678 LONG code = 0;
679 if (*hresult == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY) {
680 *error_code = GOOGLE_UPDATE_DISABLED_BY_POLICY;
681 } else if (*hresult == GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL) {
682 *error_code = GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
683 } else if (*hresult == GOOPDATEINSTALL_E_INSTALLER_FAILED &&
684 SUCCEEDED(current_state->get_installerResultCode(&code))) {
685 *installer_exit_code = code;
686 }
687
688 base::win::ScopedBstr message;
689 if (SUCCEEDED(current_state->get_completionMessage(message.Receive())))
690 error_string->assign(message.Get(), message.Length());
691
692 return true;
693 }
694 if (state_value == STATE_UPDATE_AVAILABLE && install_update_if_possible_) {
695 *hresult = app_bundle_->install();
696 if (FAILED(*hresult)) {
697 // Report a failure to start the install as a general error while trying
698 // to interact with Google Update.
699 *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
700 installer_exit_code->reset();
701 return true;
702 }
703 // Return false for handling in IsIntermediateState.
704 }
705 return false;
706 }
707
IsFinalState(const Microsoft::WRL::ComPtr<ICurrentState> & current_state,CurrentState state_value,GoogleUpdateUpgradeStatus * upgrade_status,base::string16 * new_version) const708 bool UpdateCheckDriver::IsFinalState(
709 const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
710 CurrentState state_value,
711 GoogleUpdateUpgradeStatus* upgrade_status,
712 base::string16* new_version) const {
713 if (state_value == STATE_UPDATE_AVAILABLE && !install_update_if_possible_) {
714 base::win::ScopedBstr version;
715 *upgrade_status = UPGRADE_IS_AVAILABLE;
716 if (SUCCEEDED(current_state->get_availableVersion(version.Receive())))
717 new_version->assign(version.Get(), version.Length());
718 return true;
719 }
720 if (state_value == STATE_INSTALL_COMPLETE) {
721 DCHECK(install_update_if_possible_);
722 *upgrade_status = UPGRADE_SUCCESSFUL;
723 return true;
724 }
725 if (state_value == STATE_NO_UPDATE) {
726 *upgrade_status = UPGRADE_ALREADY_UP_TO_DATE;
727 return true;
728 }
729 return false;
730 }
731
IsIntermediateState(const Microsoft::WRL::ComPtr<ICurrentState> & current_state,CurrentState state_value,base::string16 * new_version,int * progress) const732 bool UpdateCheckDriver::IsIntermediateState(
733 const Microsoft::WRL::ComPtr<ICurrentState>& current_state,
734 CurrentState state_value,
735 base::string16* new_version,
736 int* progress) const {
737 // ERROR will have been handled in IsErrorState. UPDATE_AVAILABLE, and
738 // NO_UPDATE will have been handled in IsFinalState if not doing an install,
739 // as will STATE_INSTALL_COMPLETE when doing an install. All other states
740 // following UPDATE_AVAILABLE will only happen when an install is to be done.
741 DCHECK(state_value < STATE_UPDATE_AVAILABLE || install_update_if_possible_);
742 *progress = 0;
743
744 switch (state_value) {
745 case STATE_INIT:
746 case STATE_WAITING_TO_CHECK_FOR_UPDATE:
747 case STATE_CHECKING_FOR_UPDATE:
748 // There is no news to report yet.
749 break;
750
751 case STATE_UPDATE_AVAILABLE: {
752 base::win::ScopedBstr version;
753 if (SUCCEEDED(current_state->get_availableVersion(version.Receive())))
754 new_version->assign(version.Get(), version.Length());
755 break;
756 }
757
758 case STATE_WAITING_TO_DOWNLOAD:
759 case STATE_RETRYING_DOWNLOAD:
760 break;
761
762 case STATE_DOWNLOADING: {
763 ULONG bytes_downloaded = 0;
764 ULONG total_bytes = 0;
765 if (SUCCEEDED(current_state->get_bytesDownloaded(&bytes_downloaded)) &&
766 SUCCEEDED(current_state->get_totalBytesToDownload(&total_bytes)) &&
767 total_bytes) {
768 // 0-50 is downloading.
769 *progress = base::ClampFloor((static_cast<double>(bytes_downloaded) /
770 static_cast<double>(total_bytes)) *
771 50.0);
772 }
773 break;
774 }
775
776 case STATE_DOWNLOAD_COMPLETE:
777 case STATE_EXTRACTING:
778 case STATE_APPLYING_DIFFERENTIAL_PATCH:
779 case STATE_READY_TO_INSTALL:
780 case STATE_WAITING_TO_INSTALL:
781 *progress = 50;
782 break;
783
784 case STATE_INSTALLING: {
785 *progress = 50;
786 LONG install_progress = 0;
787 if (SUCCEEDED(current_state->get_installProgress(&install_progress)) &&
788 install_progress >= 0 && install_progress <= 100) {
789 // 50-100 is installing.
790 *progress = (50 + install_progress / 2);
791 }
792 break;
793 }
794
795 case STATE_INSTALL_COMPLETE:
796 case STATE_PAUSED:
797 case STATE_NO_UPDATE:
798 case STATE_ERROR:
799 default:
800 NOTREACHED();
801 return false;
802 }
803 return true;
804 }
805
PollGoogleUpdate()806 void UpdateCheckDriver::PollGoogleUpdate() {
807 Microsoft::WRL::ComPtr<ICurrentState> state;
808 CurrentState state_value = STATE_INIT;
809 HRESULT hresult = S_OK;
810 GoogleUpdateErrorCode error_code = GOOGLE_UPDATE_NO_ERROR;
811 base::Optional<int> installer_exit_code;
812 base::string16 error_string;
813 GoogleUpdateUpgradeStatus upgrade_status = UPGRADE_ERROR;
814 base::string16 new_version;
815 int progress = 0;
816
817 if (!GetCurrentState(&state, &state_value, &hresult)) {
818 OnUpgradeError({GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hresult},
819 base::nullopt, base::string16());
820 } else if (IsErrorState(state, state_value, &error_code, &hresult,
821 &installer_exit_code, &error_string)) {
822 OnUpgradeError({error_code, hresult}, installer_exit_code, error_string);
823 } else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) {
824 status_ = upgrade_status;
825 update_state_.error_code = GOOGLE_UPDATE_NO_ERROR;
826 html_error_message_.clear();
827 if (!new_version.empty())
828 update_state_.new_version = new_version;
829 update_state_.hresult = S_OK;
830 update_state_.installer_exit_code.reset();
831 } else if (IsIntermediateState(state, state_value, &new_version, &progress)) {
832 bool got_new_version =
833 update_state_.new_version.empty() && !new_version.empty();
834 if (got_new_version)
835 update_state_.new_version = new_version;
836 // Give the caller this status update if it differs from the last one given.
837 if (got_new_version || progress != last_reported_progress_) {
838 last_reported_progress_ = progress;
839
840 // It is safe to post this task with an unretained pointer since the task
841 // is guaranteed to run before a subsequent DeleteSoon is handled.
842 result_runner_->PostTask(
843 FROM_HERE,
844 base::BindOnce(&UpdateCheckDriver::NotifyUpgradeProgress,
845 base::Unretained(this), last_reported_progress_,
846 update_state_.new_version));
847 }
848
849 // Schedule the next check.
850 task_runner_->PostDelayedTask(
851 FROM_HERE,
852 base::BindOnce(&UpdateCheckDriver::PollGoogleUpdate,
853 base::Unretained(this)),
854 base::TimeDelta::FromMilliseconds(kGoogleUpdatePollIntervalMs));
855 // Early return for this non-terminal state.
856 return;
857 }
858
859 // Release the reference on the COM objects before bouncing back to the
860 // caller's thread.
861 state.Reset();
862 app_.Reset();
863 app_bundle_.Reset();
864 google_update_.Reset();
865
866 result_runner_->DeleteSoon(FROM_HERE, this);
867 }
868
OnUpgradeError(UpdateCheckResult check_result,base::Optional<int> installer_exit_code,const base::string16 & error_string)869 void UpdateCheckDriver::OnUpgradeError(UpdateCheckResult check_result,
870 base::Optional<int> installer_exit_code,
871 const base::string16& error_string) {
872 status_ = UPGRADE_ERROR;
873 update_state_.error_code = check_result.error_code;
874 update_state_.hresult = check_result.hresult;
875 update_state_.installer_exit_code = installer_exit_code;
876
877 // Some specific result codes have dedicated messages.
878 if (check_result.hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
879 html_error_message_ = l10n_util::GetStringUTF16(
880 IDS_ABOUT_BOX_EXTERNAL_UPDATE_IS_RUNNING);
881 return;
882 }
883
884 base::string16 html_error_msg = base::StringPrintf(
885 L"%d: <a href='%ls0x%X' target=_blank>0x%X</a>", update_state_.error_code,
886 base::UTF8ToUTF16(chrome::kUpgradeHelpCenterBaseURL).c_str(),
887 update_state_.hresult, update_state_.hresult);
888 if (update_state_.installer_exit_code) {
889 html_error_msg +=
890 L": " + base::NumberToString16(*update_state_.installer_exit_code);
891 }
892 if (system_level_install_)
893 html_error_msg += L" -- system level";
894 if (error_string.empty()) {
895 html_error_message_ = l10n_util::GetStringFUTF16(
896 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, html_error_msg);
897 } else {
898 html_error_message_ = l10n_util::GetStringFUTF16(
899 IDS_ABOUT_BOX_GOOGLE_UPDATE_ERROR, error_string, html_error_msg);
900 }
901 }
902
903 } // namespace
904
905
906 // Globals ---------------------------------------------------------------------
907
BeginUpdateCheck(const std::string & locale,bool install_update_if_possible,gfx::AcceleratedWidget elevation_window,const base::WeakPtr<UpdateCheckDelegate> & delegate)908 void BeginUpdateCheck(
909 const std::string& locale,
910 bool install_update_if_possible,
911 gfx::AcceleratedWidget elevation_window,
912 const base::WeakPtr<UpdateCheckDelegate>& delegate) {
913 UpdateCheckDriver::RunUpdateCheck(locale, install_update_if_possible,
914 elevation_window, delegate);
915 }
916
917 // UpdateState -----------------------------------------------------------------
918
919 UpdateState::UpdateState() = default;
920 UpdateState::UpdateState(const UpdateState&) = default;
921 UpdateState::UpdateState(UpdateState&&) = default;
922 UpdateState& UpdateState::operator=(UpdateState&&) = default;
923 UpdateState::~UpdateState() = default;
924
GetLastUpdateState()925 base::Optional<UpdateState> GetLastUpdateState() {
926 return *GetLastUpdateStateStorage();
927 }
928
929 // Private API exposed for testing. --------------------------------------------
930
SetGoogleUpdateFactoryForTesting(GoogleUpdate3ClassFactory google_update_factory)931 void SetGoogleUpdateFactoryForTesting(
932 GoogleUpdate3ClassFactory google_update_factory) {
933 if (g_google_update_factory) {
934 delete g_google_update_factory;
935 g_google_update_factory = nullptr;
936 }
937 if (!google_update_factory.is_null()) {
938 g_google_update_factory =
939 new GoogleUpdate3ClassFactory(std::move(google_update_factory));
940 }
941 }
942
943 // TODO(calamity): Remove once a MockTimer is implemented in
944 // TaskEnvironment. See https://crbug.com/708584.
SetUpdateDriverTaskRunnerForTesting(base::SingleThreadTaskRunner * task_runner)945 void SetUpdateDriverTaskRunnerForTesting(
946 base::SingleThreadTaskRunner* task_runner) {
947 g_update_driver_task_runner = task_runner;
948 }
949