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. |owner_widget| may be given a value of
32 // nullptr in which case the UAC prompt will be parented to the desktop.
33 explicit VersionUpdaterWin(gfx::AcceleratedWidget owner_widget
);
34 ~VersionUpdaterWin() override
;
37 void CheckForUpdate(const StatusCallback
& callback
) override
;
38 void RelaunchBrowser() const override
;
40 // UpdateCheckDelegate:
41 void OnUpdateCheckComplete(const base::string16
& new_version
) override
;
42 void OnUpgradeProgress(int progress
,
43 const base::string16
& new_version
) override
;
44 void OnUpgradeComplete(const base::string16
& new_version
) override
;
45 void OnError(GoogleUpdateErrorCode error_code
,
46 const base::string16
& html_error_message
,
47 const base::string16
& new_version
) override
;
50 void BeginUpdateCheckOnFileThread(bool install_update_if_possible
);
52 // A task run on the UI thread with the result of checking for a pending
54 void OnPendingRestartCheck(bool is_update_pending_restart
);
56 // The widget owning the UI for the update check.
57 gfx::AcceleratedWidget owner_widget_
;
59 // Callback used to communicate update status to the client.
60 StatusCallback callback_
;
62 // Used for callbacks.
63 base::WeakPtrFactory
<VersionUpdaterWin
> weak_factory_
;
65 DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin
);
68 VersionUpdaterWin::VersionUpdaterWin(gfx::AcceleratedWidget owner_widget
)
69 : owner_widget_(owner_widget
), weak_factory_(this) {
72 VersionUpdaterWin::~VersionUpdaterWin() {
75 void VersionUpdaterWin::CheckForUpdate(const StatusCallback
& callback
) {
76 // There is no supported integration with Google Update for Chromium.
79 // On-demand updates for Chrome don't work in Vista RTM when UAC is turned
80 // off. So, in this case, the version updater must not mention
81 // on-demand updates. Silent updates (in the background) should still
82 // work as before - enabling UAC or installing the latest service pack
83 // for Vista is another option.
84 if (!(base::win::GetVersion() == base::win::VERSION_VISTA
&&
85 (base::win::OSInfo::GetInstance()->service_pack().major
== 0) &&
86 !base::win::UserAccountControlIsEnabled())) {
87 callback_
.Run(CHECKING
, 0, base::string16());
88 BeginUpdateCheckOnFileThread(false /* !install_update_if_possible */);
92 void VersionUpdaterWin::RelaunchBrowser() const {
93 chrome::AttemptRestart();
96 void VersionUpdaterWin::OnUpdateCheckComplete(
97 const base::string16
& new_version
) {
98 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
99 Status status
= CHECKING
;
100 if (new_version
.empty()) {
101 // Google Update says that no new version is available. Check to see if a
102 // restart is needed for a previously-applied update to take effect.
103 if (base::PostTaskAndReplyWithResult(
104 content::BrowserThread::GetBlockingPool(),
106 base::Bind(&upgrade_util::IsUpdatePendingRestart
),
107 base::Bind(&VersionUpdaterWin::OnPendingRestartCheck
,
108 weak_factory_
.GetWeakPtr()))) {
109 // Early exit since callback_ will be Run in OnPendingRestartCheck.
112 // Failure to post the task means that Chrome is shutting down. A pending
113 // update (if there is one) will be applied as Chrome exits, so tell the
114 // caller that it is up to date in either case.
117 // Notify the caller that the update is now beginning and initiate it.
119 BeginUpdateCheckOnFileThread(true /* install_update_if_possible */);
121 callback_
.Run(status
, 0, base::string16());
124 void VersionUpdaterWin::OnUpgradeProgress(int progress
,
125 const base::string16
& new_version
) {
126 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
127 callback_
.Run(UPDATING
, progress
, base::string16());
130 void VersionUpdaterWin::OnUpgradeComplete(const base::string16
& new_version
) {
131 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
132 callback_
.Run(NEARLY_UPDATED
, 0, base::string16());
135 void VersionUpdaterWin::OnError(GoogleUpdateErrorCode error_code
,
136 const base::string16
& html_error_message
,
137 const base::string16
& new_version
) {
138 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
139 base::string16 message
;
141 switch (error_code
) {
142 case GOOGLE_UPDATE_DISABLED_BY_POLICY
:
144 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY
);
146 case GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY
:
148 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY_MANUAL
);
151 // html_error_message mentions error_code so don't combine messages.
152 if (html_error_message
.empty()) {
153 message
= l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR
, error_code
);
155 message
= l10n_util::GetStringFUTF16(
156 IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK
, html_error_message
);
160 callback_
.Run(FAILED
, 0, message
);
163 void VersionUpdaterWin::BeginUpdateCheckOnFileThread(
164 bool install_update_if_possible
) {
165 BeginUpdateCheck(content::BrowserThread::GetMessageLoopProxyForThread(
166 content::BrowserThread::FILE),
167 g_browser_process
->GetApplicationLocale(),
168 install_update_if_possible
, owner_widget_
,
169 weak_factory_
.GetWeakPtr());
172 void VersionUpdaterWin::OnPendingRestartCheck(bool is_update_pending_restart
) {
173 callback_
.Run(is_update_pending_restart
? NEARLY_UPDATED
: UPDATED
, 0,
179 VersionUpdater
* VersionUpdater::Create(content::WebContents
* web_contents
) {
180 // Retrieve the HWND for the browser window that is hosting the update check.
181 // This will be used as the parent for a UAC prompt, if needed. It's possible
182 // this this window will no longer have focus by the time UAC is needed. In
183 // that case, the UAC prompt will appear in the taskbar and will require a
184 // user click. This is the least surprising thing we can do for the user, and
185 // is the intended behavior for Windows applications.
186 // It's also possible that the browser window hosting the update check will
187 // have been closed by the time the UAC prompt is needed. In this case, the
188 // web contents may no longer be hosted in a window, leading either
189 // GetTopLevelNativeWindow or GetHost to return null. Passing nullptr to
190 // VersionUpdaterWin will then also cause the UAC prompt to appear in the task
192 gfx::NativeWindow window
= web_contents
->GetTopLevelNativeWindow();
193 aura::WindowTreeHost
* window_tree_host
= window
? window
->GetHost() : nullptr;
194 return new VersionUpdaterWin(
195 window_tree_host
? window_tree_host
->GetAcceleratedWidget() : nullptr);