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 "base/memory/weak_ptr.h"
6 #include "base/strings/string16.h"
7 #include "base/task_runner_util.h"
8 #include "base/win/win_util.h"
9 #include "base/win/windows_version.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/first_run/upgrade_util.h"
12 #include "chrome/browser/google/google_update_win.h"
13 #include "chrome/browser/lifetime/application_lifetime.h"
14 #include "chrome/browser/ui/webui/help/version_updater.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/web_contents.h"
18 #include "ui/aura/window.h"
19 #include "ui/aura/window_tree_host.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/gfx/native_widget_types.h"
25 // Windows implementation of version update functionality, used by the WebUI
27 class VersionUpdaterWin
: public VersionUpdater
, public UpdateCheckDelegate
{
29 // |owner_widget| is the parent widget hosting the update check UI. Any UI
30 // needed to install an update (e.g., a UAC prompt for a system-level install)
31 // will be parented to this widget.
32 explicit VersionUpdaterWin(gfx::AcceleratedWidget owner_widget
);
33 ~VersionUpdaterWin() override
;
36 void CheckForUpdate(const StatusCallback
& callback
) override
;
37 void RelaunchBrowser() const override
;
39 // UpdateCheckDelegate:
40 void OnUpdateCheckComplete(const base::string16
& new_version
) override
;
41 void OnUpgradeProgress(int progress
,
42 const base::string16
& new_version
) override
;
43 void OnUpgradeComplete(const base::string16
& new_version
) override
;
44 void OnError(GoogleUpdateErrorCode error_code
,
45 const base::string16
& error_message
,
46 const base::string16
& new_version
) override
;
49 void BeginUpdateCheckOnFileThread(bool install_update_if_possible
);
51 // A task run on the UI thread with the result of checking for a pending
53 void OnPendingRestartCheck(bool is_update_pending_restart
);
55 // The widget owning the UI for the update check.
56 gfx::AcceleratedWidget owner_widget_
;
58 // Callback used to communicate update status to the client.
59 StatusCallback callback_
;
61 // Used for callbacks.
62 base::WeakPtrFactory
<VersionUpdaterWin
> weak_factory_
;
64 DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin
);
67 VersionUpdaterWin::VersionUpdaterWin(gfx::AcceleratedWidget owner_widget
)
68 : owner_widget_(owner_widget
), weak_factory_(this) {
71 VersionUpdaterWin::~VersionUpdaterWin() {
74 void VersionUpdaterWin::CheckForUpdate(const StatusCallback
& callback
) {
75 // There is no supported integration with Google Update for Chromium.
78 // On-demand updates for Chrome don't work in Vista RTM when UAC is turned
79 // off. So, in this case, the version updater must not mention
80 // on-demand updates. Silent updates (in the background) should still
81 // work as before - enabling UAC or installing the latest service pack
82 // for Vista is another option.
83 if (!(base::win::GetVersion() == base::win::VERSION_VISTA
&&
84 (base::win::OSInfo::GetInstance()->service_pack().major
== 0) &&
85 !base::win::UserAccountControlIsEnabled())) {
86 callback_
.Run(CHECKING
, 0, base::string16());
87 BeginUpdateCheckOnFileThread(false /* !install_update_if_possible */);
91 void VersionUpdaterWin::RelaunchBrowser() const {
92 chrome::AttemptRestart();
95 void VersionUpdaterWin::OnUpdateCheckComplete(
96 const base::string16
& new_version
) {
97 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
98 Status status
= CHECKING
;
99 if (new_version
.empty()) {
100 // Google Update says that no new version is available. Check to see if a
101 // restart is needed for a previously-applied update to take effect.
102 if (base::PostTaskAndReplyWithResult(
103 content::BrowserThread::GetBlockingPool(),
105 base::Bind(&upgrade_util::IsUpdatePendingRestart
),
106 base::Bind(&VersionUpdaterWin::OnPendingRestartCheck
,
107 weak_factory_
.GetWeakPtr()))) {
108 // Early exit since callback_ will be Run in OnPendingRestartCheck.
111 // Failure to post the task means that Chrome is shutting down. A pending
112 // update (if there is one) will be applied as Chrome exits, so tell the
113 // caller that it is up to date in either case.
116 // Notify the caller that the update is now beginning and initiate it.
118 BeginUpdateCheckOnFileThread(true /* install_update_if_possible */);
120 callback_
.Run(status
, 0, base::string16());
123 void VersionUpdaterWin::OnUpgradeProgress(int progress
,
124 const base::string16
& new_version
) {
125 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
126 callback_
.Run(UPDATING
, progress
, base::string16());
129 void VersionUpdaterWin::OnUpgradeComplete(const base::string16
& new_version
) {
130 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
131 callback_
.Run(NEARLY_UPDATED
, 0, base::string16());
134 void VersionUpdaterWin::OnError(GoogleUpdateErrorCode error_code
,
135 const base::string16
& error_message
,
136 const base::string16
& new_version
) {
137 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
138 base::string16 message
;
140 // Current versions of Google Update provide a nice message for the policy
141 // case. Use this generic error for the policy case only if no message from
142 // Google Update is present.
143 if (error_code
!= GOOGLE_UPDATE_DISABLED_BY_POLICY
|| error_message
.empty())
144 message
= l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR
, error_code
);
146 if (!error_message
.empty()) {
147 message
+= l10n_util::GetStringFUTF16(
148 IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK
, error_message
);
150 callback_
.Run(FAILED
, 0, message
);
153 void VersionUpdaterWin::BeginUpdateCheckOnFileThread(
154 bool install_update_if_possible
) {
155 BeginUpdateCheck(content::BrowserThread::GetMessageLoopProxyForThread(
156 content::BrowserThread::FILE),
157 g_browser_process
->GetApplicationLocale(),
158 install_update_if_possible
, owner_widget_
,
159 weak_factory_
.GetWeakPtr());
162 void VersionUpdaterWin::OnPendingRestartCheck(bool is_update_pending_restart
) {
163 callback_
.Run(is_update_pending_restart
? NEARLY_UPDATED
: UPDATED
, 0,
169 VersionUpdater
* VersionUpdater::Create(content::WebContents
* web_contents
) {
170 // Retrieve the HWND for the browser window that is hosting the update check.
171 // This will be used as the parent for a UAC prompt, if needed. It's possible
172 // this this window will no longer have focus by the time UAC is needed. In
173 // that case, the UAC prompt will appear in the taskbar and will require a
174 // user click. This is the least surprising thing we can do for the user, and
175 // is the intended behavior for Windows applications. It's also possible that
176 // the browser window hosting the update check will have been closed by the
177 // time the UAC prompt is needed. This will behave similarly.
178 return new VersionUpdaterWin(web_contents
->GetTopLevelNativeWindow()
180 ->GetAcceleratedWidget());