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 "chrome/browser/upgrade_detector_impl.h" | 5 #include "chrome/browser/upgrade_detector_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/file_path.h" | 11 #include "base/file_path.h" |
12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
13 #include "base/memory/singleton.h" | 13 #include "base/memory/singleton.h" |
14 #include "base/path_service.h" | 14 #include "base/path_service.h" |
15 #include "base/string_number_conversions.h" | 15 #include "base/string_number_conversions.h" |
16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
17 #include "base/time.h" | 17 #include "base/time.h" |
18 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
19 #include "chrome/common/chrome_notification_types.h" | |
19 #include "chrome/common/chrome_switches.h" | 20 #include "chrome/common/chrome_switches.h" |
20 #include "chrome/common/chrome_version_info.h" | 21 #include "chrome/common/chrome_version_info.h" |
21 #include "chrome/installer/util/browser_distribution.h" | 22 #include "chrome/installer/util/browser_distribution.h" |
22 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
24 #include "content/public/browser/notification_service.h" | |
25 #include "content/public/browser/user_metrics.h" | |
23 #include "ui/base/resource/resource_bundle.h" | 26 #include "ui/base/resource/resource_bundle.h" |
24 | 27 |
25 #if defined(OS_WIN) | 28 #if defined(OS_WIN) |
29 #include "chrome/browser/google/google_update_win.h" | |
30 #include "chrome/installer/util/google_update_settings.h" | |
26 #include "chrome/installer/util/install_util.h" | 31 #include "chrome/installer/util/install_util.h" |
27 #elif defined(OS_MACOSX) | 32 #elif defined(OS_MACOSX) |
28 #include "chrome/browser/mac/keystone_glue.h" | 33 #include "chrome/browser/mac/keystone_glue.h" |
29 #elif defined(OS_POSIX) | 34 #elif defined(OS_POSIX) |
30 #include "base/process_util.h" | 35 #include "base/process_util.h" |
31 #include "base/version.h" | 36 #include "base/version.h" |
32 #endif | 37 #endif |
33 | 38 |
34 using content::BrowserThread; | 39 using content::BrowserThread; |
35 | 40 |
(...skipping 25 matching lines...) Expand all Loading... | |
61 int GetCheckForUpgradeEveryMs() { | 66 int GetCheckForUpgradeEveryMs() { |
62 // Check for a value passed via the command line. | 67 // Check for a value passed via the command line. |
63 int interval_ms; | 68 int interval_ms; |
64 std::string interval = CmdLineInterval(); | 69 std::string interval = CmdLineInterval(); |
65 if (!interval.empty() && base::StringToInt(interval, &interval_ms)) | 70 if (!interval.empty() && base::StringToInt(interval, &interval_ms)) |
66 return interval_ms * 1000; // Command line value is in seconds. | 71 return interval_ms * 1000; // Command line value is in seconds. |
67 | 72 |
68 return kCheckForUpgradeMs; | 73 return kCheckForUpgradeMs; |
69 } | 74 } |
70 | 75 |
71 // This task checks the currently running version of Chrome against the | |
72 // installed version. If the installed version is newer, it runs the passed | |
73 // callback task. Otherwise it just deletes the task. | |
74 void DetectUpgradeTask(const base::Closure& upgrade_detected_task, | |
75 bool* is_unstable_channel, | |
76 bool* is_critical_upgrade) { | |
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
78 | |
79 Version installed_version; | |
80 Version critical_update; | |
81 | |
82 #if defined(OS_WIN) | 76 #if defined(OS_WIN) |
77 // This code can be used by both regular and outdated upgrades. | |
Finnur
2012/12/06 19:53:16
nit: suggest: by both regular upgrades and for che
MAD
2013/01/22 15:18:29
This is gone... Reworking the whole thing...
| |
78 // |critical_update| can be NULL if not needed. | |
79 void GetInstalledAndCriticalVersion(Version* installed_version, | |
80 Version* critical_update) { | |
83 // Get the version of the currently *installed* instance of Chrome, | 81 // Get the version of the currently *installed* instance of Chrome, |
84 // which might be newer than the *running* instance if we have been | 82 // which might be newer than the *running* instance if we have been |
85 // upgraded in the background. | 83 // upgraded in the background. |
86 FilePath exe_path; | 84 FilePath exe_path; |
87 if (!PathService::Get(base::DIR_EXE, &exe_path)) { | 85 if (!PathService::Get(base::DIR_EXE, &exe_path)) { |
88 NOTREACHED() << "Failed to find executable path"; | 86 NOTREACHED() << "Failed to find executable path"; |
89 return; | 87 return; |
90 } | 88 } |
91 | 89 |
92 bool system_install = | 90 bool system_install = |
93 !InstallUtil::IsPerUserInstall(exe_path.value().c_str()); | 91 !InstallUtil::IsPerUserInstall(exe_path.value().c_str()); |
94 | 92 |
95 // TODO(tommi): Check if using the default distribution is always the right | 93 // TODO(tommi): Check if using the default distribution is always the right |
96 // thing to do. | 94 // thing to do. |
97 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | 95 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
98 InstallUtil::GetChromeVersion(dist, system_install, &installed_version); | 96 DCHECK(installed_version); |
97 InstallUtil::GetChromeVersion(dist, system_install, installed_version); | |
99 | 98 |
100 if (installed_version.IsValid()) { | 99 if (critical_update && installed_version->IsValid()) { |
101 InstallUtil::GetCriticalUpdateVersion(dist, system_install, | 100 InstallUtil::GetCriticalUpdateVersion(dist, system_install, |
102 &critical_update); | 101 critical_update); |
103 } | 102 } |
103 } | |
104 #endif // defined(OS_WIN) | |
105 | |
106 // This task checks the currently running version of Chrome against the | |
107 // installed version. If the installed version is newer, it runs the passed | |
108 // callback task. Otherwise it just deletes the task. | |
109 void DetectUpgradeTask(const base::Closure& upgrade_detected_task, | |
110 bool* is_unstable_channel, | |
111 bool* is_critical_upgrade) { | |
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
113 | |
114 Version installed_version; | |
115 Version critical_update; | |
116 | |
117 #if defined(OS_WIN) | |
118 GetInstalledAndCriticalVersion(&installed_version, &critical_update); | |
104 #elif defined(OS_MACOSX) | 119 #elif defined(OS_MACOSX) |
105 installed_version = | 120 installed_version = |
106 Version(UTF16ToASCII(keystone_glue::CurrentlyInstalledVersion())); | 121 Version(UTF16ToASCII(keystone_glue::CurrentlyInstalledVersion())); |
107 #elif defined(OS_POSIX) | 122 #elif defined(OS_POSIX) |
108 // POSIX but not Mac OS X: Linux, etc. | 123 // POSIX but not Mac OS X: Linux, etc. |
109 CommandLine command_line(*CommandLine::ForCurrentProcess()); | 124 CommandLine command_line(*CommandLine::ForCurrentProcess()); |
110 command_line.AppendSwitch(switches::kProductVersion); | 125 command_line.AppendSwitch(switches::kProductVersion); |
111 std::string reply; | 126 std::string reply; |
112 if (!base::GetAppOutput(command_line, &reply)) { | 127 if (!base::GetAppOutput(command_line, &reply)) { |
113 DLOG(ERROR) << "Failed to get current file version"; | 128 DLOG(ERROR) << "Failed to get current file version"; |
(...skipping 29 matching lines...) Expand all Loading... | |
143 *is_critical_upgrade = | 158 *is_critical_upgrade = |
144 critical_update.IsValid() && | 159 critical_update.IsValid() && |
145 (critical_update.CompareTo(running_version) > 0); | 160 (critical_update.CompareTo(running_version) > 0); |
146 | 161 |
147 // Fire off the upgrade detected task. | 162 // Fire off the upgrade detected task. |
148 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 163 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
149 upgrade_detected_task); | 164 upgrade_detected_task); |
150 } | 165 } |
151 } | 166 } |
152 | 167 |
168 #if defined(OS_WIN) | |
Finnur
2012/12/06 19:53:16
I would probably have moved this to a _win.cc file
MAD
2013/01/22 15:18:29
Gone!
| |
169 // Implementation of a GoogleUpdateStatusListener (only available on Windows), | |
170 // so we can get the available version and identify if we are outdated. | |
171 class UpgradeStatusListener : public GoogleUpdateStatusListener { | |
172 public: | |
173 explicit UpgradeStatusListener(const base::Closure& notify_outdated_callback) | |
174 : google_updater_(new GoogleUpdate()), | |
175 got_installed_version_(false), | |
176 got_available_version_(false), | |
177 notify_outdated_callback_(notify_outdated_callback) { | |
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
179 google_updater_->set_status_listener(this); | |
180 // false is for |install_if_newer|, we just want the available version. | |
181 // And when we use false, we don't need to specify a |window|, so NULL. | |
182 google_updater_->CheckForUpdate(false, NULL); | |
183 | |
184 // We use FILE as the thread to get the installed version | |
185 // since it requires reading a file. And it is safe to use an unretained | |
186 // this pointer since GetInstalledVersion must be called before destruction. | |
187 BrowserThread::PostTask( | |
188 BrowserThread::FILE, FROM_HERE, | |
189 base::Bind(&UpgradeStatusListener::GetInstalledVersion, | |
190 base::Unretained(this))); | |
191 } | |
192 | |
193 virtual ~UpgradeStatusListener() { | |
194 google_updater_->set_status_listener(NULL); | |
195 } | |
196 | |
197 // GoogleUpdateStatusListener implementation. | |
198 virtual void OnReportResults(GoogleUpdateUpgradeResult result, | |
199 GoogleUpdateErrorCode error_code, | |
200 const string16& error_message, | |
201 const string16& version) OVERRIDE { | |
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
203 // The google update class is never supposed to sent these two to listeners. | |
Finnur
2012/12/06 19:53:16
nit: s/sent/send/
MAD
2013/01/22 15:18:29
Gone!
| |
204 DCHECK(result != UPGRADE_STARTED && result != UPGRADE_CHECK_STARTED); | |
205 | |
206 // Since false was specified for |install_if_newer|, this shouldn't happen. | |
207 DCHECK(result != UPGRADE_SUCCESSFUL); | |
208 | |
209 switch (result) { | |
210 case UPGRADE_ALREADY_UP_TO_DATE: { | |
211 // Nothing needs to be done. | |
212 break; | |
213 } | |
214 case UPGRADE_ERROR: { | |
215 // Record these errors in UMA to see if something should be added here. | |
216 content::RecordAction(content::UserMetricsAction("UpgradeCheck_Error")); | |
217 break; | |
218 } | |
219 case UPGRADE_IS_AVAILABLE: { | |
220 available_version_ = Version(UTF16ToASCII(version)); | |
221 break; | |
222 } | |
223 default: { | |
224 NOTREACHED(); | |
225 } | |
226 } | |
227 got_available_version_ = true; | |
Finnur
2012/12/06 19:53:16
This variable is actually misnamed because you don
MAD
2013/01/22 15:18:29
Gone!
| |
228 if (got_installed_version_) | |
229 CheckForOutdated(); | |
230 } | |
231 | |
232 private: | |
233 void GetInstalledVersion() { | |
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
235 Version installed_version; | |
236 // We only check for outdated when there are no group policies preventing | |
Finnur
2012/12/06 19:53:16
s/outdated/outdated version/
MAD
2013/01/22 15:18:29
Gone!
| |
237 // regular upgrades. The test is done here because it needs access to the | |
238 // registry, which must be done on the FILE thread. | |
239 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | |
240 DCHECK(distribution); | |
241 if (GoogleUpdateSettings::GetAppUpdatePolicy(distribution->GetAppGuid(), | |
242 NULL) == | |
243 GoogleUpdateSettings::AUTOMATIC_UPDATES) { | |
244 // An uninitialized install version prevents an outdated notification. | |
Finnur
2012/12/06 19:53:16
Not sure I understand this comment...
MAD
2013/01/22 15:18:29
Gone!
| |
245 GetInstalledAndCriticalVersion(&installed_version, NULL); | |
246 } | |
247 BrowserThread::PostTask( | |
248 BrowserThread::UI, FROM_HERE, | |
249 base::Bind(&UpgradeStatusListener::GotInstalledVersion, | |
250 base::Unretained(this), installed_version)); | |
251 } | |
252 | |
253 void GotInstalledVersion(const Version& installed_version) { | |
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
255 installed_version_ = installed_version; | |
256 got_installed_version_ = true; | |
257 if (got_available_version_) | |
258 CheckForOutdated(); | |
259 } | |
260 | |
261 void CheckForOutdated() { | |
Finnur
2012/12/06 19:53:16
nit: Suggest: CheckIfOutdatedVersion or NotifyIfOu
MAD
2013/01/22 15:18:29
Gone!
| |
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
263 DCHECK(got_available_version_ && got_installed_version_); | |
264 if (available_version_.IsValid() && installed_version_.IsValid() && | |
265 available_version_.components()[0] > | |
266 installed_version_.components()[0] + 1) { | |
267 notify_outdated_callback_.Run(); | |
268 } | |
269 delete this; | |
270 } | |
271 | |
272 // The class that communicates with Google Update to find out if an update is | |
273 // available and asks it to start an upgrade. | |
274 scoped_refptr<GoogleUpdate> google_updater_; | |
275 | |
276 // The value returned by GetInstalledAndCriticalVersion might be invalid | |
277 // so a bool is also needed to identify that we at least tried to read it. | |
278 Version installed_version_; | |
279 bool got_installed_version_; | |
280 | |
281 // The value returned by google_updater_ might also be invalid | |
282 // so a bool is also needed to identify that we at least tried to read it. | |
283 Version available_version_; | |
284 bool got_available_version_; | |
285 | |
286 // A callback to notify of an outdated install. | |
287 base::Closure notify_outdated_callback_; | |
288 | |
289 DISALLOW_COPY_AND_ASSIGN(UpgradeStatusListener); | |
290 }; | |
291 | |
292 #endif // defined(OS_WIN) | |
293 | |
153 } // namespace | 294 } // namespace |
154 | 295 |
155 UpgradeDetectorImpl::UpgradeDetectorImpl() | 296 UpgradeDetectorImpl::UpgradeDetectorImpl() |
156 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 297 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
157 is_unstable_channel_(false) { | 298 is_unstable_channel_(false) { |
158 CommandLine command_line(*CommandLine::ForCurrentProcess()); | 299 CommandLine command_line(*CommandLine::ForCurrentProcess()); |
159 if (command_line.HasSwitch(switches::kDisableBackgroundNetworking)) | 300 if (command_line.HasSwitch(switches::kDisableBackgroundNetworking)) |
160 return; | 301 return; |
161 if (command_line.HasSwitch(switches::kSimulateUpgrade)) { | 302 if (command_line.HasSwitch(switches::kSimulateUpgrade)) { |
162 UpgradeDetected(); | 303 UpgradeDetected(); |
163 return; | 304 return; |
164 } | 305 } |
165 // Windows: only enable upgrade notifications for official builds. | 306 // Windows: only enable upgrade notifications for official builds. |
166 // Mac: only enable them if the updater (Keystone) is present. | 307 // Mac: only enable them if the updater (Keystone) is present. |
167 // Linux (and other POSIX): always enable regardless of branding. | 308 // Linux (and other POSIX): always enable regardless of branding. |
168 #if (defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)) || defined(OS_POSIX) | 309 #if (defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)) || defined(OS_POSIX) |
169 #if defined(OS_MACOSX) | 310 #if defined(OS_MACOSX) |
170 if (keystone_glue::KeystoneEnabled()) | 311 if (keystone_glue::KeystoneEnabled()) |
171 #endif | 312 #endif |
172 { | 313 { |
173 detect_upgrade_timer_.Start(FROM_HERE, | 314 detect_upgrade_timer_.Start(FROM_HERE, |
174 base::TimeDelta::FromMilliseconds(GetCheckForUpgradeEveryMs()), | 315 base::TimeDelta::FromMilliseconds(GetCheckForUpgradeEveryMs()), |
175 this, &UpgradeDetectorImpl::CheckForUpgrade); | 316 this, &UpgradeDetectorImpl::CheckForUpgrade); |
176 } | 317 } |
177 #endif | 318 #endif |
319 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) | |
320 // On Windows, we also check for an outdated version so we use this listener | |
321 // of Google update to asynchronously fetch the available version. | |
322 // This object will self-destruct when done. | |
323 new UpgradeStatusListener(base::Bind(&UpgradeDetectorImpl::NotifyOutdated, | |
324 weak_factory_.GetWeakPtr())); | |
325 #endif // defined(OS_WIN) | |
178 } | 326 } |
179 | 327 |
180 UpgradeDetectorImpl::~UpgradeDetectorImpl() { | 328 UpgradeDetectorImpl::~UpgradeDetectorImpl() { |
181 } | 329 } |
182 | 330 |
183 void UpgradeDetectorImpl::CheckForUpgrade() { | 331 void UpgradeDetectorImpl::CheckForUpgrade() { |
184 weak_factory_.InvalidateWeakPtrs(); | 332 weak_factory_.InvalidateWeakPtrs(); |
185 base::Closure callback_task = | 333 base::Closure callback_task = |
186 base::Bind(&UpgradeDetectorImpl::UpgradeDetected, | 334 base::Bind(&UpgradeDetectorImpl::UpgradeDetected, |
187 weak_factory_.GetWeakPtr()); | 335 weak_factory_.GetWeakPtr()); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
261 } else if (time_passed >= kLowThreshold) { | 409 } else if (time_passed >= kLowThreshold) { |
262 set_upgrade_notification_stage(UPGRADE_ANNOYANCE_LOW); | 410 set_upgrade_notification_stage(UPGRADE_ANNOYANCE_LOW); |
263 } else { | 411 } else { |
264 return; // Not ready to recommend upgrade. | 412 return; // Not ready to recommend upgrade. |
265 } | 413 } |
266 } | 414 } |
267 | 415 |
268 NotifyUpgradeRecommended(); | 416 NotifyUpgradeRecommended(); |
269 } | 417 } |
270 | 418 |
419 void UpgradeDetectorImpl::NotifyOutdated() { | |
420 // Stop the recurring timer (that is checking for changes). | |
421 detect_upgrade_timer_.Stop(); | |
422 set_upgrade_notification_stage(UPGRADE_ANNOYANCE_CRITICAL); | |
423 | |
424 content::NotificationService::current()->Notify( | |
425 chrome::NOTIFICATION_OUTDATED_INSTALL, | |
426 content::Source<UpgradeDetector>(this), | |
427 content::NotificationService::NoDetails()); | |
428 | |
429 NotifyUpgradeRecommended(); | |
430 } | |
431 | |
271 // static | 432 // static |
272 UpgradeDetectorImpl* UpgradeDetectorImpl::GetInstance() { | 433 UpgradeDetectorImpl* UpgradeDetectorImpl::GetInstance() { |
273 return Singleton<UpgradeDetectorImpl>::get(); | 434 return Singleton<UpgradeDetectorImpl>::get(); |
274 } | 435 } |
275 | 436 |
276 // static | 437 // static |
277 UpgradeDetector* UpgradeDetector::GetInstance() { | 438 UpgradeDetector* UpgradeDetector::GetInstance() { |
278 return UpgradeDetectorImpl::GetInstance(); | 439 return UpgradeDetectorImpl::GetInstance(); |
279 } | 440 } |
OLD | NEW |