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