Chromium Code Reviews| 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 |