Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / help / version_updater_win.cc
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.
4
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"
24
25 using content::BrowserThread;
26
27 namespace {
28
29 // Windows implementation of version update functionality, used by the WebUI
30 // About/Help page.
31 class VersionUpdaterWin : public VersionUpdater,
32                           public GoogleUpdateStatusListener {
33  private:
34   friend class VersionReader;
35   friend class VersionUpdater;
36
37   // Clients must use VersionUpdater::Create().
38   VersionUpdaterWin();
39   virtual ~VersionUpdaterWin();
40
41   // VersionUpdater implementation.
42   virtual void CheckForUpdate(const StatusCallback& callback) OVERRIDE;
43   virtual void RelaunchBrowser() const OVERRIDE;
44
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;
50
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);
55
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);
59
60   // Little helper function to create google_updater_.
61   void CreateGoogleUpdater();
62
63   // Helper function to clear google_updater_.
64   void ClearGoogleUpdater();
65
66   // Returns a window that can be used for elevation.
67   HWND GetElevationParent();
68
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_;
72
73   // Used for callbacks.
74   base::WeakPtrFactory<VersionUpdaterWin> weak_factory_;
75
76   // Callback used to communicate update status to the client.
77   StatusCallback callback_;
78
79   DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin);
80 };
81
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.
87 class VersionReader
88     : public base::RefCountedThreadSafe<VersionReader> {
89  public:
90   explicit VersionReader(
91       const base::WeakPtr<VersionUpdaterWin>& version_updater)
92       : version_updater_(version_updater) {
93   }
94
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_);
101     }
102     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
103           &VersionReader::SetVersionInUIThread, this));
104   }
105
106   void SetVersionInUIThread() {
107     if (version_updater_.get() != NULL)
108       version_updater_->GotInstalledVersion(installed_version_);
109   }
110
111  private:
112   friend class base::RefCountedThreadSafe<VersionReader>;
113
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_;
117
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_;
121 };
122
123 VersionUpdaterWin::VersionUpdaterWin()
124     : weak_factory_(this) {
125   CreateGoogleUpdater();
126 }
127
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();
132 }
133
134 void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback) {
135   callback_ = callback;
136
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,
149                  base::string16());
150     // Specify false to not upgrade yet.
151     google_updater_->CheckForUpdate(false, GetElevationParent());
152   }
153 }
154
155 void VersionUpdaterWin::RelaunchBrowser() const {
156   chrome::AttemptRestart();
157 }
158
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);
165 }
166
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;
176
177   switch (result) {
178     case UPGRADE_CHECK_STARTED: {
179       status = CHECKING;
180       break;
181     }
182     case UPGRADE_STARTED: {
183       status = UPDATING;
184       break;
185     }
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());
192       return;
193     }
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())));
202       return;
203     }
204     case UPGRADE_SUCCESSFUL: {
205       status = NEARLY_UPDATED;
206       break;
207     }
208     case UPGRADE_ERROR: {
209       status = FAILED;
210       if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY) {
211         message =
212             l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY);
213       } else if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY) {
214         message =
215             l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY_MANUAL);
216       } else {
217         message =
218             l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code);
219       }
220
221       if (!error_message.empty()) {
222         message +=
223             l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK,
224                                        error_message);
225       }
226       break;
227     }
228   }
229
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)
234 }
235
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);
239
240   // Make sure that the latest version is running and if not,
241   // notify the user by setting the status to NEARLY_UPDATED.
242   //
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
245   // out of date.
246   chrome::VersionInfo version_info;
247   Version running_version(version_info.Version());
248   callback_.Run((version.IsValid() && version.CompareTo(running_version) > 0)
249                     ? NEARLY_UPDATED
250                     : UPDATED,
251                 0,
252                 base::string16());
253 }
254
255 void VersionUpdaterWin::CreateGoogleUpdater() {
256   ClearGoogleUpdater();
257   google_updater_ = new GoogleUpdate();
258   google_updater_->set_status_listener(this);
259 }
260
261 void VersionUpdaterWin::ClearGoogleUpdater() {
262   if (google_updater_) {
263     google_updater_->set_status_listener(NULL);
264     google_updater_ = NULL;
265   }
266 }
267
268 BOOL CALLBACK WindowEnumeration(HWND window, LPARAM param) {
269   if (IsWindowVisible(window)) {
270     HWND* returned_window = reinterpret_cast<HWND*>(param);
271     *returned_window = window;
272     return FALSE;
273   }
274   return TRUE;
275 }
276
277 HWND VersionUpdaterWin::GetElevationParent() {
278   // Look for a visible window belonging to the UI thread.
279   DCHECK_CURRENTLY_ON(BrowserThread::UI);
280   HWND window = NULL;
281   EnumThreadWindows(GetCurrentThreadId(),
282                     WindowEnumeration,
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();
289 #endif
290   return window;
291 }
292
293 }  // namespace
294
295 VersionUpdater* VersionUpdater::Create() {
296   return new VersionUpdaterWin;
297 }