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/ref_counted.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/memory/weak_ptr.h"
8 #include "base/strings/string16.h"
9 #include "base/version.h"
10 #include "base/win/win_util.h"
11 #include "base/win/windows_version.h"
12 #include "chrome/browser/google/google_update_win.h"
13 #include "chrome/browser/lifetime/application_lifetime.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/webui/help/version_updater.h"
16 #include "chrome/common/chrome_version_info.h"
17 #include "chrome/grit/chromium_strings.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "chrome/installer/util/browser_distribution.h"
20 #include "chrome/installer/util/install_util.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/views/widget/widget.h"
25 using content::BrowserThread;
29 // Windows implementation of version update functionality, used by the WebUI
31 class VersionUpdaterWin : public VersionUpdater,
32 public GoogleUpdateStatusListener {
34 friend class VersionReader;
35 friend class VersionUpdater;
37 // Clients must use VersionUpdater::Create().
39 virtual ~VersionUpdaterWin();
41 // VersionUpdater implementation.
42 virtual void CheckForUpdate(const StatusCallback& callback) OVERRIDE;
43 virtual void RelaunchBrowser() const OVERRIDE;
45 // GoogleUpdateStatusListener implementation.
46 virtual void OnReportResults(GoogleUpdateUpgradeResult result,
47 GoogleUpdateErrorCode error_code,
48 const base::string16& error_message,
49 const base::string16& version) OVERRIDE;
51 // Update the UI to show the status of the upgrade.
52 void UpdateStatus(GoogleUpdateUpgradeResult result,
53 GoogleUpdateErrorCode error_code,
54 const base::string16& error_message);
56 // Got the intalled version so the handling of the UPGRADE_ALREADY_UP_TO_DATE
57 // result case can now be completeb on the UI thread.
58 void GotInstalledVersion(const Version& version);
60 // Little helper function to create google_updater_.
61 void CreateGoogleUpdater();
63 // Helper function to clear google_updater_.
64 void ClearGoogleUpdater();
66 // Returns a window that can be used for elevation.
67 HWND GetElevationParent();
69 // The class that communicates with Google Update to find out if an update is
70 // available and asks it to start an upgrade.
71 scoped_refptr<GoogleUpdate> google_updater_;
73 // Used for callbacks.
74 base::WeakPtrFactory<VersionUpdaterWin> weak_factory_;
76 // Callback used to communicate update status to the client.
77 StatusCallback callback_;
79 DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin);
82 // This class is used to read the version on the FILE thread and then call back
83 // the version updater in the UI thread. Using a class helps better control
84 // the lifespan of the Version independently of the lifespan of the version
85 // updater, which may die while asynchonicity is happening, thus the usage of
86 // the WeakPtr, which can only be used from the thread that created it.
88 : public base::RefCountedThreadSafe<VersionReader> {
90 explicit VersionReader(
91 const base::WeakPtr<VersionUpdaterWin>& version_updater)
92 : version_updater_(version_updater) {
95 void GetVersionFromFileThread() {
96 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
97 InstallUtil::GetChromeVersion(dist, false, &installed_version_);
98 if (!installed_version_.IsValid()) {
99 // User-level Chrome is not installed, check system-level.
100 InstallUtil::GetChromeVersion(dist, true, &installed_version_);
102 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
103 &VersionReader::SetVersionInUIThread, this));
106 void SetVersionInUIThread() {
107 if (version_updater_.get() != NULL)
108 version_updater_->GotInstalledVersion(installed_version_);
112 friend class base::RefCountedThreadSafe<VersionReader>;
114 // The version updater that must be called back when we are done.
115 // We use a weak pointer in case the updater gets destroyed while waiting.
116 base::WeakPtr<VersionUpdaterWin> version_updater_;
118 // This is the version that gets read in the FILE thread and set on the
119 // the updater in the UI thread.
120 Version installed_version_;
123 VersionUpdaterWin::VersionUpdaterWin()
124 : weak_factory_(this) {
125 CreateGoogleUpdater();
128 VersionUpdaterWin::~VersionUpdaterWin() {
129 // The Google Updater will hold a pointer to the listener until it reports
130 // status, so that pointer must be cleared when the listener is destoyed.
131 ClearGoogleUpdater();
134 void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback) {
135 callback_ = callback;
137 // On-demand updates for Chrome don't work in Vista RTM when UAC is turned
138 // off. So, in this case, the version updater must not mention
139 // on-demand updates. Silent updates (in the background) should still
140 // work as before - enabling UAC or installing the latest service pack
141 // for Vista is another option.
142 if (!(base::win::GetVersion() == base::win::VERSION_VISTA &&
143 (base::win::OSInfo::GetInstance()->service_pack().major == 0) &&
144 !base::win::UserAccountControlIsEnabled())) {
145 // This could happen if the page got refreshed after results were returned.
146 if (!google_updater_)
147 CreateGoogleUpdater();
148 UpdateStatus(UPGRADE_CHECK_STARTED, GOOGLE_UPDATE_NO_ERROR,
150 // Specify false to not upgrade yet.
151 google_updater_->CheckForUpdate(false, GetElevationParent());
155 void VersionUpdaterWin::RelaunchBrowser() const {
156 chrome::AttemptRestart();
159 void VersionUpdaterWin::OnReportResults(
160 GoogleUpdateUpgradeResult result, GoogleUpdateErrorCode error_code,
161 const base::string16& error_message, const base::string16& version) {
162 // Drop the last reference to the object so that it gets cleaned up here.
163 ClearGoogleUpdater();
164 UpdateStatus(result, error_code, error_message);
167 void VersionUpdaterWin::UpdateStatus(GoogleUpdateUpgradeResult result,
168 GoogleUpdateErrorCode error_code,
169 const base::string16& error_message) {
170 // For Chromium builds it would show an error message.
171 // But it looks weird because in fact there is no error,
172 // just the update server is not available for non-official builds.
173 #if defined(GOOGLE_CHROME_BUILD)
174 Status status = UPDATED;
175 base::string16 message;
178 case UPGRADE_CHECK_STARTED: {
182 case UPGRADE_STARTED: {
186 case UPGRADE_IS_AVAILABLE: {
187 DCHECK(!google_updater_); // Should have been nulled out already.
188 CreateGoogleUpdater();
189 UpdateStatus(UPGRADE_STARTED, GOOGLE_UPDATE_NO_ERROR, base::string16());
190 // Specify true to upgrade now.
191 google_updater_->CheckForUpdate(true, GetElevationParent());
194 case UPGRADE_ALREADY_UP_TO_DATE: {
195 // Google Update reported that Chrome is up-to-date.
196 // To confirm the updated version is running, the reading
197 // must be done on the file thread. The rest of this case
198 // will be handled within GotInstalledVersion.
199 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
200 &VersionReader::GetVersionFromFileThread,
201 new VersionReader(weak_factory_.GetWeakPtr())));
204 case UPGRADE_SUCCESSFUL: {
205 status = NEARLY_UPDATED;
208 case UPGRADE_ERROR: {
210 if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY) {
212 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY);
213 } else if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY) {
215 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY_MANUAL);
218 l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code);
221 if (!error_message.empty()) {
223 l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK,
230 // TODO(mad): Get proper progress value instead of passing 0.
231 // http://crbug.com/136117
232 callback_.Run(status, 0, message);
233 #endif // defined(GOOGLE_CHROME_BUILD)
236 void VersionUpdaterWin::GotInstalledVersion(const Version& version) {
237 // This must be called on the UI thread so that callback_ can be called.
238 DCHECK_CURRENTLY_ON(BrowserThread::UI);
240 // Make sure that the latest version is running and if not,
241 // notify the user by setting the status to NEARLY_UPDATED.
243 // The extra version check is necessary on Windows because the application
244 // may be already up to date on disk though the running app is still
246 chrome::VersionInfo version_info;
247 Version running_version(version_info.Version());
248 callback_.Run((version.IsValid() && version.CompareTo(running_version) > 0)
255 void VersionUpdaterWin::CreateGoogleUpdater() {
256 ClearGoogleUpdater();
257 google_updater_ = new GoogleUpdate();
258 google_updater_->set_status_listener(this);
261 void VersionUpdaterWin::ClearGoogleUpdater() {
262 if (google_updater_) {
263 google_updater_->set_status_listener(NULL);
264 google_updater_ = NULL;
268 BOOL CALLBACK WindowEnumeration(HWND window, LPARAM param) {
269 if (IsWindowVisible(window)) {
270 HWND* returned_window = reinterpret_cast<HWND*>(param);
271 *returned_window = window;
277 HWND VersionUpdaterWin::GetElevationParent() {
278 // Look for a visible window belonging to the UI thread.
279 DCHECK_CURRENTLY_ON(BrowserThread::UI);
281 EnumThreadWindows(GetCurrentThreadId(),
283 reinterpret_cast<LPARAM>(&window));
284 #if !defined(USE_AURA)
285 // If using Aura, we might not have a Visible window in this process. In
286 // theory Google update can cope with that.
287 DCHECK(window != NULL) << "Failed to find a valid window handle on thread: "
288 << GetCurrentThreadId();
295 VersionUpdater* VersionUpdater::Create() {
296 return new VersionUpdaterWin;