OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/memory/ref_counted.h" | |
6 #include "base/memory/scoped_ptr.h" | |
7 #include "base/memory/weak_ptr.h" | 5 #include "base/memory/weak_ptr.h" |
8 #include "base/strings/string16.h" | 6 #include "base/strings/string16.h" |
9 #include "base/version.h" | |
10 #include "base/win/win_util.h" | 7 #include "base/win/win_util.h" |
11 #include "base/win/windows_version.h" | 8 #include "base/win/windows_version.h" |
9 #include "chrome/browser/browser_process.h" | |
10 #include "chrome/browser/first_run/upgrade_util_win.h" | |
12 #include "chrome/browser/google/google_update_win.h" | 11 #include "chrome/browser/google/google_update_win.h" |
13 #include "chrome/browser/lifetime/application_lifetime.h" | 12 #include "chrome/browser/lifetime/application_lifetime.h" |
14 #include "chrome/browser/ui/browser.h" | |
15 #include "chrome/browser/ui/webui/help/version_updater.h" | 13 #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" | 14 #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" | 15 #include "content/public/browser/browser_thread.h" |
22 #include "ui/base/l10n/l10n_util.h" | 16 #include "ui/base/l10n/l10n_util.h" |
23 #include "ui/gfx/native_widget_types.h" | 17 #include "ui/gfx/native_widget_types.h" |
24 #include "ui/views/widget/widget.h" | |
25 | |
26 using content::BrowserThread; | |
27 | 18 |
28 namespace { | 19 namespace { |
29 | 20 |
21 // An EnumThreadWndProc that returns the first visible window via |param|, | |
22 // stopping the enumeration when one is found. | |
23 BOOL CALLBACK WindowEnumeration(HWND window, LPARAM param) { | |
24 if (!IsWindowVisible(window)) | |
25 return TRUE; | |
26 HWND* returned_window = reinterpret_cast<HWND*>(param); | |
Peter Kasting
2015/05/09 02:19:02
Nit: I'd probably just inline this into the next l
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
27 *returned_window = window; | |
28 return FALSE; | |
29 } | |
30 | |
31 // Returns a visible Chrome Window, or null if none is found. | |
32 gfx::AcceleratedWidget FindVisibleWindow() { | |
33 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
34 HWND window = nullptr; | |
35 EnumThreadWindows(GetCurrentThreadId(), &WindowEnumeration, | |
Peter Kasting
2015/05/09 02:19:02
It makes me uncomfortable to have Windows calls do
grt (UTC plus 2)
2015/05/12 20:21:52
Done. There's a slight change in behavior, but aft
| |
36 reinterpret_cast<LPARAM>(&window)); | |
37 return window; | |
38 } | |
39 | |
30 // Windows implementation of version update functionality, used by the WebUI | 40 // Windows implementation of version update functionality, used by the WebUI |
31 // About/Help page. | 41 // About/Help page. |
32 class VersionUpdaterWin : public VersionUpdater { | 42 class VersionUpdaterWin : public VersionUpdater, public UpdateCheckDelegate { |
33 private: | 43 public: |
34 friend class VersionReader; | |
35 friend class VersionUpdater; | |
36 | |
37 // Clients must use VersionUpdater::Create(). | |
38 VersionUpdaterWin(); | 44 VersionUpdaterWin(); |
39 ~VersionUpdaterWin() override; | 45 ~VersionUpdaterWin() override; |
40 | 46 |
41 // VersionUpdater implementation. | 47 // VersionUpdater |
Peter Kasting
2015/05/09 02:19:02
Tiny nit: I'd put a colon after these base class n
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
42 void CheckForUpdate(const StatusCallback& callback) override; | 48 void CheckForUpdate(const StatusCallback& callback) override; |
43 void RelaunchBrowser() const override; | 49 void RelaunchBrowser() const override; |
44 | 50 |
45 // chrome::UpdateCheckCallback. | 51 // UpdateCheckDelegate |
46 void OnUpdateCheckResults(GoogleUpdateUpgradeResult result, | 52 void OnUpdateCheckComplete(const base::string16& new_version) override; |
47 GoogleUpdateErrorCode error_code, | 53 void OnUpgradeProgress(int progress, |
48 const base::string16& error_message, | 54 const base::string16& new_version) override; |
49 const base::string16& version); | 55 void OnUpgradeComplete(const base::string16& new_version) override; |
56 void OnError(GoogleUpdateErrorCode error_code, | |
57 const base::string16& error_message, | |
58 const base::string16& new_version) override; | |
50 | 59 |
51 // Update the UI to show the status of the upgrade. | 60 private: |
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 // Returns a window that can be used for elevation. | |
61 gfx::AcceleratedWidget GetElevationParent(); | |
62 | |
63 void BeginUpdateCheckOnFileThread(bool install_if_newer); | 61 void BeginUpdateCheckOnFileThread(bool install_if_newer); |
Peter Kasting
2015/05/09 02:19:02
Nit: Probably want to change the name of |install_
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
64 | 62 |
65 // Callback used to communicate update status to the client. | 63 // Callback used to communicate update status to the client. |
66 StatusCallback callback_; | 64 StatusCallback callback_; |
67 | 65 |
68 // Used for callbacks. | 66 // Used for callbacks. |
69 base::WeakPtrFactory<VersionUpdaterWin> weak_factory_; | 67 base::WeakPtrFactory<VersionUpdaterWin> weak_factory_; |
70 | 68 |
71 DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin); | 69 DISALLOW_COPY_AND_ASSIGN(VersionUpdaterWin); |
72 }; | 70 }; |
73 | 71 |
74 // This class is used to read the version on the FILE thread and then call back | |
75 // the version updater in the UI thread. Using a class helps better control | |
76 // the lifespan of the Version independently of the lifespan of the version | |
77 // updater, which may die while asynchonicity is happening, thus the usage of | |
78 // the WeakPtr, which can only be used from the thread that created it. | |
79 class VersionReader | |
80 : public base::RefCountedThreadSafe<VersionReader> { | |
81 public: | |
82 explicit VersionReader( | |
83 const base::WeakPtr<VersionUpdaterWin>& version_updater) | |
84 : version_updater_(version_updater) { | |
85 } | |
86 | |
87 void GetVersionFromFileThread() { | |
88 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
89 InstallUtil::GetChromeVersion(dist, false, &installed_version_); | |
90 if (!installed_version_.IsValid()) { | |
91 // User-level Chrome is not installed, check system-level. | |
92 InstallUtil::GetChromeVersion(dist, true, &installed_version_); | |
93 } | |
94 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | |
95 &VersionReader::SetVersionInUIThread, this)); | |
96 } | |
97 | |
98 void SetVersionInUIThread() { | |
99 if (version_updater_.get() != NULL) | |
100 version_updater_->GotInstalledVersion(installed_version_); | |
101 } | |
102 | |
103 private: | |
104 friend class base::RefCountedThreadSafe<VersionReader>; | |
105 | |
106 ~VersionReader() {} | |
107 | |
108 // The version updater that must be called back when we are done. | |
109 // We use a weak pointer in case the updater gets destroyed while waiting. | |
110 base::WeakPtr<VersionUpdaterWin> version_updater_; | |
111 | |
112 // This is the version that gets read in the FILE thread and set on the | |
113 // the updater in the UI thread. | |
114 Version installed_version_; | |
115 }; | |
116 | |
117 VersionUpdaterWin::VersionUpdaterWin() | 72 VersionUpdaterWin::VersionUpdaterWin() |
118 : weak_factory_(this) { | 73 : weak_factory_(this) { |
119 } | 74 } |
120 | 75 |
121 VersionUpdaterWin::~VersionUpdaterWin() { | 76 VersionUpdaterWin::~VersionUpdaterWin() { |
122 } | 77 } |
123 | 78 |
124 void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback) { | 79 void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback) { |
125 callback_ = callback; | 80 callback_ = callback; |
126 | 81 |
127 // On-demand updates for Chrome don't work in Vista RTM when UAC is turned | 82 // On-demand updates for Chrome don't work in Vista RTM when UAC is turned |
128 // off. So, in this case, the version updater must not mention | 83 // off. So, in this case, the version updater must not mention |
129 // on-demand updates. Silent updates (in the background) should still | 84 // on-demand updates. Silent updates (in the background) should still |
130 // work as before - enabling UAC or installing the latest service pack | 85 // work as before - enabling UAC or installing the latest service pack |
131 // for Vista is another option. | 86 // for Vista is another option. |
132 if (!(base::win::GetVersion() == base::win::VERSION_VISTA && | 87 if (!(base::win::GetVersion() == base::win::VERSION_VISTA && |
133 (base::win::OSInfo::GetInstance()->service_pack().major == 0) && | 88 (base::win::OSInfo::GetInstance()->service_pack().major == 0) && |
134 !base::win::UserAccountControlIsEnabled())) { | 89 !base::win::UserAccountControlIsEnabled())) { |
135 UpdateStatus(UPGRADE_CHECK_STARTED, GOOGLE_UPDATE_NO_ERROR, | 90 callback_.Run(CHECKING, 0, base::string16()); |
136 base::string16()); | 91 BeginUpdateCheckOnFileThread(false /* !install_if_newer */); |
Peter Kasting
2015/05/09 02:19:02
Nit: I'm not in love with these comments when ther
grt (UTC plus 2)
2015/05/12 20:21:52
I've been asked by other reviewers to add these co
| |
137 // Specify false to not upgrade yet. | |
138 BeginUpdateCheckOnFileThread(false); | |
139 } | 92 } |
140 } | 93 } |
141 | 94 |
142 void VersionUpdaterWin::RelaunchBrowser() const { | 95 void VersionUpdaterWin::RelaunchBrowser() const { |
143 chrome::AttemptRestart(); | 96 chrome::AttemptRestart(); |
144 } | 97 } |
145 | 98 |
146 void VersionUpdaterWin::OnUpdateCheckResults( | 99 void VersionUpdaterWin::OnUpdateCheckComplete( |
147 GoogleUpdateUpgradeResult result, | 100 const base::string16& new_version) { |
148 GoogleUpdateErrorCode error_code, | 101 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
149 const base::string16& error_message, | 102 Status status = CHECKING; |
150 const base::string16& version) { | 103 if (new_version.empty()) { |
151 UpdateStatus(result, error_code, error_message); | 104 // Google Update says that no new version is available. Check to see if a |
105 // restart is needed for it to take effect. | |
Peter Kasting
2015/05/09 02:19:02
Nit: Maybe "Check if we need to restart to pick up
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
106 status = upgrade_util::IsRunningOldChrome() ? NEARLY_UPDATED : UPDATED; | |
107 } else { | |
108 // Notify the caller that the update is now beginning and initiate it. | |
109 status = UPDATING; | |
110 BeginUpdateCheckOnFileThread(true /* install_if_newer */); | |
111 } | |
112 callback_.Run(status, 0, base::string16()); | |
152 } | 113 } |
153 | 114 |
154 void VersionUpdaterWin::UpdateStatus(GoogleUpdateUpgradeResult result, | 115 void VersionUpdaterWin::OnUpgradeProgress(int progress, |
155 GoogleUpdateErrorCode error_code, | 116 const base::string16& new_version) { |
156 const base::string16& error_message) { | 117 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
157 // For Chromium builds it would show an error message. | 118 callback_.Run(UPDATING, progress, base::string16()); |
158 // But it looks weird because in fact there is no error, | 119 } |
159 // just the update server is not available for non-official builds. | 120 |
121 void VersionUpdaterWin::OnUpgradeComplete(const base::string16& new_version) { | |
122 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
123 callback_.Run(NEARLY_UPDATED, 0, base::string16()); | |
124 } | |
125 | |
126 void VersionUpdaterWin::OnError(GoogleUpdateErrorCode error_code, | |
127 const base::string16& error_message, | |
128 const base::string16& new_version) { | |
129 // Chromium builds will unconditionally get a | |
130 // CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY error since there is no supported | |
131 // integration with Google Update for Chromium. Ignore the error notification | |
132 // so that the spinner just spins rather than show an error message when there | |
Peter Kasting
2015/05/09 02:19:02
Nit: showing
grt (UTC plus 2)
2015/05/12 20:21:52
Done.
| |
133 // is, in fact, no error. | |
Peter Kasting
2015/05/09 02:19:02
Is there a way to not spin but instead show the "n
grt (UTC plus 2)
2015/05/12 20:21:52
I make a chromium-branded build and found that I w
| |
160 #if defined(GOOGLE_CHROME_BUILD) | 134 #if defined(GOOGLE_CHROME_BUILD) |
161 Status status = UPDATED; | 135 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
162 base::string16 message; | 136 base::string16 message; |
163 | 137 |
164 switch (result) { | 138 // Google Update provides a nice message for the policy case. Use this |
Peter Kasting
2015/05/09 02:19:02
Nit: "usually provides"? (If it always provided t
grt (UTC plus 2)
2015/05/12 20:21:52
Just being defensive here. I don't believe Google
| |
165 case UPGRADE_CHECK_STARTED: { | 139 // generic error for the policy case only if no message from Google Update |
166 status = CHECKING; | 140 // is present. |
167 break; | 141 if (error_code != GOOGLE_UPDATE_DISABLED_BY_POLICY || error_message.empty()) |
168 } | 142 message = l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code); |
169 case UPGRADE_STARTED: { | |
170 status = UPDATING; | |
171 break; | |
172 } | |
173 case UPGRADE_IS_AVAILABLE: { | |
174 UpdateStatus(UPGRADE_STARTED, GOOGLE_UPDATE_NO_ERROR, base::string16()); | |
175 // Specify true to upgrade now. | |
176 BeginUpdateCheckOnFileThread(true); | |
177 return; | |
178 } | |
179 case UPGRADE_ALREADY_UP_TO_DATE: { | |
180 // Google Update reported that Chrome is up-to-date. | |
181 // To confirm the updated version is running, the reading | |
182 // must be done on the file thread. The rest of this case | |
183 // will be handled within GotInstalledVersion. | |
184 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( | |
185 &VersionReader::GetVersionFromFileThread, | |
186 new VersionReader(weak_factory_.GetWeakPtr()))); | |
187 return; | |
188 } | |
189 case UPGRADE_SUCCESSFUL: { | |
190 status = NEARLY_UPDATED; | |
191 break; | |
192 } | |
193 case UPGRADE_ERROR: { | |
194 status = FAILED; | |
195 if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY) { | |
196 message = | |
197 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY); | |
198 } else if (error_code == GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY) { | |
199 message = | |
200 l10n_util::GetStringUTF16(IDS_UPGRADE_DISABLED_BY_POLICY_MANUAL); | |
201 } else { | |
202 message = | |
203 l10n_util::GetStringFUTF16Int(IDS_UPGRADE_ERROR, error_code); | |
204 } | |
205 | 143 |
206 if (!error_message.empty()) { | 144 if (!error_message.empty()) { |
207 message += | 145 message += l10n_util::GetStringFUTF16( |
208 l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK, | 146 IDS_ABOUT_BOX_ERROR_DURING_UPDATE_CHECK, error_message); |
209 error_message); | |
210 } | |
211 break; | |
212 } | |
213 } | 147 } |
214 | 148 callback_.Run(FAILED, 0, message); |
215 // TODO(mad): Get proper progress value instead of passing 0. | 149 #endif |
216 // http://crbug.com/136117 | |
217 callback_.Run(status, 0, message); | |
218 #endif // defined(GOOGLE_CHROME_BUILD) | |
219 } | |
220 | |
221 void VersionUpdaterWin::GotInstalledVersion(const Version& version) { | |
222 // This must be called on the UI thread so that callback_ can be called. | |
223 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
224 | |
225 // Make sure that the latest version is running and if not, | |
226 // notify the user by setting the status to NEARLY_UPDATED. | |
227 // | |
228 // The extra version check is necessary on Windows because the application | |
229 // may be already up to date on disk though the running app is still | |
230 // out of date. | |
231 chrome::VersionInfo version_info; | |
232 Version running_version(version_info.Version()); | |
233 callback_.Run((version.IsValid() && version.CompareTo(running_version) > 0) | |
234 ? NEARLY_UPDATED | |
235 : UPDATED, | |
236 0, | |
237 base::string16()); | |
238 } | |
239 | |
240 BOOL CALLBACK WindowEnumeration(HWND window, LPARAM param) { | |
241 if (IsWindowVisible(window)) { | |
242 HWND* returned_window = reinterpret_cast<HWND*>(param); | |
243 *returned_window = window; | |
244 return FALSE; | |
245 } | |
246 return TRUE; | |
247 } | |
248 | |
249 gfx::AcceleratedWidget VersionUpdaterWin::GetElevationParent() { | |
250 // Look for a visible window belonging to the UI thread. | |
251 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
252 HWND window = NULL; | |
253 EnumThreadWindows(GetCurrentThreadId(), | |
254 WindowEnumeration, | |
255 reinterpret_cast<LPARAM>(&window)); | |
256 return window; | |
257 } | 150 } |
258 | 151 |
259 void VersionUpdaterWin::BeginUpdateCheckOnFileThread(bool install_if_newer) { | 152 void VersionUpdaterWin::BeginUpdateCheckOnFileThread(bool install_if_newer) { |
260 scoped_refptr<base::TaskRunner> task_runner( | 153 BeginUpdateCheck(content::BrowserThread::GetMessageLoopProxyForThread( |
261 content::BrowserThread::GetMessageLoopProxyForThread( | 154 content::BrowserThread::FILE), |
262 content::BrowserThread::FILE)); | 155 g_browser_process->GetApplicationLocale(), install_if_newer, |
263 BeginUpdateCheck(task_runner, install_if_newer, GetElevationParent(), | 156 FindVisibleWindow(), weak_factory_.GetWeakPtr()); |
264 base::Bind(&VersionUpdaterWin::OnUpdateCheckResults, | |
265 weak_factory_.GetWeakPtr())); | |
266 } | 157 } |
267 | 158 |
268 } // namespace | 159 } // namespace |
269 | 160 |
270 VersionUpdater* VersionUpdater::Create(content::BrowserContext* /* context */) { | 161 VersionUpdater* VersionUpdater::Create(content::BrowserContext* /* context */) { |
271 return new VersionUpdaterWin; | 162 return new VersionUpdaterWin; |
272 } | 163 } |
OLD | NEW |