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/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/task_runner.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "base/win/windows_version.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "chrome/installer/util/browser_distribution.h"
24 #include "chrome/installer/util/google_update_settings.h"
25 #include "chrome/installer/util/helper.h"
26 #include "chrome/installer/util/install_util.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/win/atl_module.h"
33 OnDemandAppsClassFactory
* g_google_update_factory
= nullptr;
35 // Check if the currently running instance can be updated by Google Update.
36 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
37 // Chrome distribution installed in a standard location.
38 GoogleUpdateErrorCode
CanUpdateCurrentChrome(
39 const base::FilePath
& chrome_exe_path
,
41 #if !defined(GOOGLE_CHROME_BUILD)
42 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY
;
44 DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path
), system_level
);
45 BrowserDistribution
* dist
= BrowserDistribution::GetDistribution();
46 base::FilePath user_exe_path
= installer::GetChromeInstallPath(false, dist
);
47 base::FilePath machine_exe_path
= installer::GetChromeInstallPath(true, dist
);
48 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path
.value(),
49 user_exe_path
.value()) &&
50 !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path
.value(),
51 machine_exe_path
.value())) {
52 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY
;
55 base::string16 app_guid
= installer::GetAppGuidForUpdates(system_level
);
56 DCHECK(!app_guid
.empty());
58 GoogleUpdateSettings::UpdatePolicy update_policy
=
59 GoogleUpdateSettings::GetAppUpdatePolicy(app_guid
, NULL
);
61 if (update_policy
== GoogleUpdateSettings::UPDATES_DISABLED
)
62 return GOOGLE_UPDATE_DISABLED_BY_POLICY
;
64 if (update_policy
== GoogleUpdateSettings::AUTO_UPDATES_ONLY
)
65 return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY
;
67 return GOOGLE_UPDATE_NO_ERROR
;
71 // Creates an instance of a COM Local Server class using either plain vanilla
72 // CoCreateInstance, or using the Elevation moniker if running on Vista.
73 // hwnd must refer to a foregound window in order to get the UAC prompt
74 // showing up in the foreground if running on Vista. It can also be NULL if
75 // background UAC prompts are desired.
76 HRESULT
CoCreateInstanceAsAdmin(REFCLSID class_id
,
78 gfx::AcceleratedWidget hwnd
,
79 void** interface_ptr
) {
83 // For Vista, need to instantiate the COM server via the elevation
84 // moniker. This ensures that the UAC dialog shows up.
85 if (base::win::GetVersion() >= base::win::VERSION_VISTA
) {
86 wchar_t class_id_as_string
[MAX_PATH
] = {};
87 StringFromGUID2(class_id
, class_id_as_string
,
88 arraysize(class_id_as_string
));
90 base::string16 elevation_moniker_name
=
91 base::StringPrintf(L
"Elevation:Administrator!new:%ls",
95 // An explicit memset is needed rather than relying on value initialization
96 // since BIND_OPTS3 is not an aggregate (it is a derived type).
97 memset(&bind_opts
, 0, sizeof(bind_opts
));
98 bind_opts
.cbStruct
= sizeof(bind_opts
);
99 bind_opts
.dwClassContext
= CLSCTX_LOCAL_SERVER
;
100 bind_opts
.hwnd
= hwnd
;
102 return CoGetObject(elevation_moniker_name
.c_str(), &bind_opts
, interface_id
,
106 return CoCreateInstance(class_id
, NULL
, CLSCTX_LOCAL_SERVER
, interface_id
,
110 HRESULT
CreateOnDemandAppsClass(
112 bool install_if_newer
,
113 gfx::AcceleratedWidget elevation_window
,
114 base::win::ScopedComPtr
<IGoogleUpdate
>* on_demand
) {
115 if (g_google_update_factory
)
116 return g_google_update_factory
->Run(on_demand
);
118 // For a user-level install, update checks and updates can both be done by a
119 // normal user with the UserAppsClass.
121 return on_demand
->CreateInstance(CLSID_OnDemandUserAppsClass
);
123 // For a system-level install, update checks can be done by a normal user with
124 // the MachineAppsClass.
125 if (!install_if_newer
)
126 return on_demand
->CreateInstance(CLSID_OnDemandMachineAppsClass
);
128 // For a system-level install, an update requires Admin privileges for writing
129 // to %ProgramFiles%. Elevate while instantiating the MachineAppsClass.
130 return CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass
,
131 IID_IGoogleUpdate
, elevation_window
,
132 on_demand
->ReceiveVoid());
136 // GoogleUpdateJobObserver -----------------------------------------------------
138 // The GoogleUpdateJobObserver COM class is responsible for receiving status
139 // reports from google Update. It keeps track of the progress as Google Update
140 // notifies this observer and runs a completion callback once Google Update
141 // reports that it is done.
142 class GoogleUpdateJobObserver
: public CComObjectRootEx
<CComSingleThreadModel
>,
143 public IJobObserver
{
145 BEGIN_COM_MAP(GoogleUpdateJobObserver
)
146 COM_INTERFACE_ENTRY(IJobObserver
)
149 GoogleUpdateJobObserver();
150 virtual ~GoogleUpdateJobObserver();
152 // Sets the callback to be invoked when Google Update reports that the job is
154 void set_on_complete_callback(const base::Closure
& on_complete_callback
) {
155 on_complete_callback_
= on_complete_callback
;
158 // Returns the results of the update operation.
159 GoogleUpdateUpgradeResult
result() const {
160 // Intermediary steps should never be reported to the client.
161 DCHECK_NE(UPGRADE_STARTED
, result_
);
162 DCHECK_NE(UPGRADE_CHECK_STARTED
, result_
);
166 // Returns which version Google Update found on the server (if a more
167 // recent version was found). Otherwise, this will be blank.
168 base::string16
new_version() const { return new_version_
; }
170 // Returns the Google Update supplied error string that describes the error
171 // that occurred during the update check/upgrade.
172 base::string16
error_message() const { return error_message_
; }
177 STDMETHOD(OnCheckingForUpdate
)();
178 STDMETHOD(OnUpdateAvailable
)(const TCHAR
* version_string
);
179 STDMETHOD(OnWaitingToDownload
)();
180 STDMETHOD(OnDownloading
)(int time_remaining_ms
, int pos
);
181 STDMETHOD(OnWaitingToInstall
)();
182 STDMETHOD(OnInstalling
)();
183 STDMETHOD(OnPause
)();
184 STDMETHOD(OnComplete
)(LegacyCompletionCodes code
, const TCHAR
* text
);
185 STDMETHOD(SetEventSink
)(IProgressWndEvents
* event_sink
);
187 // The task runner associated with the thread in which the job runs.
188 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
190 // A callback to be run to complete processing;
191 base::Closure on_complete_callback_
;
193 // The status/result of the Google Update operation.
194 GoogleUpdateUpgradeResult result_
;
196 // The version string Google Update found.
197 base::string16 new_version_
;
199 // An error message, if any.
200 base::string16 error_message_
;
202 // Allows us control the upgrade process to a small degree. After OnComplete
203 // has been called, this object can not be used.
204 base::win::ScopedComPtr
<IProgressWndEvents
> event_sink_
;
206 DISALLOW_COPY_AND_ASSIGN(GoogleUpdateJobObserver
);
209 GoogleUpdateJobObserver::GoogleUpdateJobObserver()
210 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
211 result_(UPGRADE_ERROR
) {
214 GoogleUpdateJobObserver::~GoogleUpdateJobObserver() {
217 STDMETHODIMP
GoogleUpdateJobObserver::OnShow() {
221 STDMETHODIMP
GoogleUpdateJobObserver::OnCheckingForUpdate() {
222 result_
= UPGRADE_CHECK_STARTED
;
226 STDMETHODIMP
GoogleUpdateJobObserver::OnUpdateAvailable(
227 const TCHAR
* version_string
) {
228 result_
= UPGRADE_IS_AVAILABLE
;
229 new_version_
= version_string
;
233 STDMETHODIMP
GoogleUpdateJobObserver::OnWaitingToDownload() {
237 STDMETHODIMP
GoogleUpdateJobObserver::OnDownloading(int time_remaining_ms
,
242 STDMETHODIMP
GoogleUpdateJobObserver::OnWaitingToInstall() {
246 STDMETHODIMP
GoogleUpdateJobObserver::OnInstalling() {
247 result_
= UPGRADE_STARTED
;
251 STDMETHODIMP
GoogleUpdateJobObserver::OnPause() {
255 STDMETHODIMP
GoogleUpdateJobObserver::OnComplete(LegacyCompletionCodes code
,
257 if (code
== COMPLETION_CODE_ERROR
) {
258 error_message_
= text
;
259 result_
= UPGRADE_ERROR
;
261 // Everything that isn't an error is some form of success. Chrome doesn't
262 // support any of the fancy codes (e.g., COMPLETION_CODE_REBOOT), but they
263 // shouldn't be generated anyway.
264 LOG_IF(DFATAL
, (code
!= COMPLETION_CODE_SUCCESS
&&
265 code
!= COMPLETION_CODE_SUCCESS_CLOSE_UI
))
266 << "Unexpected LegacyCompletionCode from IGoogleUpdate: " << code
;
267 if (result_
== UPGRADE_STARTED
)
268 result_
= UPGRADE_SUCCESSFUL
;
269 else if (result_
== UPGRADE_CHECK_STARTED
)
270 result_
= UPGRADE_ALREADY_UP_TO_DATE
;
275 task_runner_
->PostTask(FROM_HERE
, on_complete_callback_
);
279 STDMETHODIMP
GoogleUpdateJobObserver::SetEventSink(
280 IProgressWndEvents
* event_sink
) {
281 event_sink_
= event_sink
;
286 // UpdateCheckDriver -----------------------------------------------------------
288 // A driver that is created and destroyed on the caller's thread and drives
289 // Google Update on another.
290 class UpdateCheckDriver
{
292 // Runs an update check on |task_runner|, invoking |callback| on the caller's
293 // thread upon completion. |task_runner| must run a TYPE_UI message loop if
294 // the default IGoogleUpdate on-demand COM class is used.
295 static void RunUpdateCheck(const scoped_refptr
<base::TaskRunner
>& task_runner
,
296 bool install_if_newer
,
297 gfx::AcceleratedWidget elevation_window
,
298 const UpdateCheckCallback
& callback
);
301 friend class base::DeleteHelper
<UpdateCheckDriver
>;
303 explicit UpdateCheckDriver(const UpdateCheckCallback
& callback
);
305 // Runs the caller's update check callback with the results of the operation.
306 ~UpdateCheckDriver();
308 // Starts an update check.
309 void BeginUpdateCheck(bool install_if_newer
,
310 gfx::AcceleratedWidget elevation_window
);
312 // Helper function for starting an update check. Returns true if the check was
313 // properly started, in which case CompleteUpdateCheck will be invoked upon
314 // completion to return results to the caller on its own thread.
315 bool BeginUpdateCheckInternal(bool install_if_newer
,
316 gfx::AcceleratedWidget elevation_window
);
318 // Invoked when results are in from Google Update.
319 void CompleteUpdateCheck();
321 // Prepares |results| to return the upgrade error indicated by |error_code|
322 // and |hr|. The string " -- system level" is included in the generated error
323 // message when |system_level| is true.
324 void OnUpgradeError(GoogleUpdateErrorCode error_code
,
328 // The caller's task runner, on which |result_callback_| will be run.
329 scoped_refptr
<base::SingleThreadTaskRunner
> result_runner_
;
331 // The caller's callback to be run when the update check is compelte.
332 UpdateCheckCallback result_callback_
;
334 // The results of the update check.
335 GoogleUpdateUpgradeResult result_
;
336 GoogleUpdateErrorCode error_code_
;
337 base::string16 error_message_
;
338 base::string16 version_
;
341 // A direct pointer to the job observer by which the driver is notified of
342 // interesting events from Google Update.
343 CComObject
<GoogleUpdateJobObserver
>* job_observer_
;
345 // A scoped pointer to |job_observer_| that holds a reference to it, keeping
347 base::win::ScopedComPtr
<IJobObserver
> job_holder_
;
349 // The on-demand updater that is doing the work.
350 base::win::ScopedComPtr
<IGoogleUpdate
> on_demand_
;
352 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver
);
356 void UpdateCheckDriver::RunUpdateCheck(
357 const scoped_refptr
<base::TaskRunner
>& task_runner
,
358 bool install_if_newer
,
359 gfx::AcceleratedWidget elevation_window
,
360 const UpdateCheckCallback
& callback
) {
361 // The driver is owned by itself, and will self-destruct when its work is
363 UpdateCheckDriver
* driver
= new UpdateCheckDriver(callback
);
364 task_runner
->PostTask(
366 base::Bind(&UpdateCheckDriver::BeginUpdateCheck
, base::Unretained(driver
),
367 install_if_newer
, elevation_window
));
370 // Runs on the caller's thread.
371 UpdateCheckDriver::UpdateCheckDriver(const UpdateCheckCallback
& callback
)
372 : result_runner_(base::ThreadTaskRunnerHandle::Get()),
373 result_callback_(callback
),
374 result_(UPGRADE_ERROR
),
375 error_code_(GOOGLE_UPDATE_NO_ERROR
),
377 job_observer_(nullptr) {
380 UpdateCheckDriver::~UpdateCheckDriver() {
381 DCHECK(result_runner_
->BelongsToCurrentThread());
382 // If there is an error, then error_code must not be blank, and vice versa.
383 DCHECK_NE(result_
== UPGRADE_ERROR
, error_code_
== GOOGLE_UPDATE_NO_ERROR
);
384 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", result_
,
385 NUM_UPGRADE_RESULTS
);
386 if (result_
== UPGRADE_ERROR
) {
387 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_
,
389 if (hresult_
!= S_OK
)
390 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_
);
392 result_callback_
.Run(result_
, error_code_
, error_message_
, version_
);
395 void UpdateCheckDriver::BeginUpdateCheck(
396 bool install_if_newer
,
397 gfx::AcceleratedWidget elevation_window
) {
398 // Return results immediately if the driver is not waiting for Google Update.
399 if (!BeginUpdateCheckInternal(install_if_newer
, elevation_window
))
400 result_runner_
->DeleteSoon(FROM_HERE
, this);
403 bool UpdateCheckDriver::BeginUpdateCheckInternal(
404 bool install_if_newer
,
405 gfx::AcceleratedWidget elevation_window
) {
406 base::FilePath chrome_exe
;
407 if (!PathService::Get(base::DIR_EXE
, &chrome_exe
))
410 const bool system_level
= !InstallUtil::IsPerUserInstall(chrome_exe
);
412 // The failures handled here are:
413 // CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY,
414 // GOOGLE_UPDATE_DISABLED_BY_POLICY, and
415 // GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY.
416 error_code_
= CanUpdateCurrentChrome(chrome_exe
, system_level
);
417 if (error_code_
!= GOOGLE_UPDATE_NO_ERROR
) {
418 // These failures are handled in the UX with custom messages.
419 result_
= UPGRADE_ERROR
;
423 // Make sure ATL is initialized in this module.
424 ui::win::CreateATLModuleIfNeeded();
427 CComObject
<GoogleUpdateJobObserver
>::CreateInstance(&job_observer_
);
429 // Most of the error messages come straight from Google Update. This one is
430 // deemed worthy enough to also warrant its own error.
431 OnUpgradeError(GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED
, hr
, false);
434 // Hold a reference on the observer for the lifetime of the driver.
435 job_holder_
= job_observer_
;
437 job_observer_
->set_on_complete_callback(base::Bind(
438 &UpdateCheckDriver::CompleteUpdateCheck
, base::Unretained(this)));
440 hr
= CreateOnDemandAppsClass(system_level
, install_if_newer
, elevation_window
,
443 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND
, hr
, system_level
);
447 base::string16 app_guid
= installer::GetAppGuidForUpdates(system_level
);
448 DCHECK(!app_guid
.empty());
450 if (install_if_newer
)
451 hr
= on_demand_
->Update(app_guid
.c_str(), job_observer_
);
453 hr
= on_demand_
->CheckForUpdate(app_guid
.c_str(), job_observer_
);
456 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR
, hr
,
463 void UpdateCheckDriver::CompleteUpdateCheck() {
464 result_
= job_observer_
->result();
465 if (result_
== UPGRADE_ERROR
) {
466 error_code_
= GOOGLE_UPDATE_ERROR_UPDATING
;
467 error_message_
= job_observer_
->error_message();
469 version_
= job_observer_
->new_version();
472 // Release the reference on the COM objects before bouncing back to the
474 on_demand_
.Release();
475 job_holder_
.Release();
476 job_observer_
= nullptr;
478 result_runner_
->DeleteSoon(FROM_HERE
, this);
481 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code
,
484 result_
= UPGRADE_ERROR
;
485 error_code_
= error_code
;
487 base::string16 error_msg
=
488 base::StringPrintf(L
"%d: 0x%x", error_code_
, hresult_
);
490 error_msg
+= L
" -- system level";
491 error_message_
= l10n_util::GetStringFUTF16(
492 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED
, error_msg
);
498 // Globals ---------------------------------------------------------------------
500 void BeginUpdateCheck(const scoped_refptr
<base::TaskRunner
>& task_runner
,
501 bool install_if_newer
,
502 gfx::AcceleratedWidget elevation_window
,
503 const UpdateCheckCallback
& callback
) {
504 UpdateCheckDriver::RunUpdateCheck(task_runner
, install_if_newer
,
505 elevation_window
, callback
);
509 // Private API exposed for testing. --------------------------------------------
511 void SetGoogleUpdateFactoryForTesting(
512 const OnDemandAppsClassFactory
& google_update_factory
) {
513 if (g_google_update_factory
) {
514 delete g_google_update_factory
;
515 g_google_update_factory
= nullptr;
517 if (!google_update_factory
.is_null()) {
518 g_google_update_factory
=
519 new OnDemandAppsClassFactory(google_update_factory
);