Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / webui / help / version_updater_win.cc
blob5f487be4d1591afbdb557fdbcb290c01e00498ec
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"
23 namespace {
25 // Windows implementation of version update functionality, used by the WebUI
26 // About/Help page.
27 class VersionUpdaterWin : public VersionUpdater, public UpdateCheckDelegate {
28 public:
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;
36 // VersionUpdater:
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;
49 private:
50 void BeginUpdateCheckOnFileThread(bool install_update_if_possible);
52 // A task run on the UI thread with the result of checking for a pending
53 // restart.
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.
77 callback_ = callback;
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(),
105 FROM_HERE,
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.
110 return;
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.
115 status = UPDATED;
116 } else {
117 // Notify the caller that the update is now beginning and initiate it.
118 status = UPDATING;
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:
143 message =
144 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY);
145 break;
146 case GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY:
147 message =
148 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY_MANUAL);
149 break;
150 default:
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);
154 } else {
155 message = l10n_util::GetStringFUTF16(
156 IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK, html_error_message);
158 break;
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,
174 base::string16());
177 } // namespace
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
191 // bar.
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);