Index: chrome/browser/upgrade_detector_impl.cc |
diff --git a/chrome/browser/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector_impl.cc |
index 570275e391ba59c8452c3de6d6861f7f4ead8e04..910ff953d10f075aa0407c041bbf5a1138def240 100644 |
--- a/chrome/browser/upgrade_detector_impl.cc |
+++ b/chrome/browser/upgrade_detector_impl.cc |
@@ -16,13 +16,18 @@ |
#include "base/string_util.h" |
#include "base/time.h" |
#include "base/utf_string_conversions.h" |
+#include "chrome/common/chrome_notification_types.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/chrome_version_info.h" |
#include "chrome/installer/util/browser_distribution.h" |
#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/notification_service.h" |
+#include "content/public/browser/user_metrics.h" |
#include "ui/base/resource/resource_bundle.h" |
#if defined(OS_WIN) |
+#include "chrome/browser/google/google_update_win.h" |
+#include "chrome/installer/util/google_update_settings.h" |
#include "chrome/installer/util/install_util.h" |
#elif defined(OS_MACOSX) |
#include "chrome/browser/mac/keystone_glue.h" |
@@ -68,18 +73,11 @@ int GetCheckForUpgradeEveryMs() { |
return kCheckForUpgradeMs; |
} |
-// This task checks the currently running version of Chrome against the |
-// installed version. If the installed version is newer, it runs the passed |
-// callback task. Otherwise it just deletes the task. |
-void DetectUpgradeTask(const base::Closure& upgrade_detected_task, |
- bool* is_unstable_channel, |
- bool* is_critical_upgrade) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- |
- Version installed_version; |
- Version critical_update; |
- |
#if defined(OS_WIN) |
+// 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...
|
+// |critical_update| can be NULL if not needed. |
+void GetInstalledAndCriticalVersion(Version* installed_version, |
+ Version* critical_update) { |
// Get the version of the currently *installed* instance of Chrome, |
// which might be newer than the *running* instance if we have been |
// upgraded in the background. |
@@ -95,12 +93,29 @@ void DetectUpgradeTask(const base::Closure& upgrade_detected_task, |
// TODO(tommi): Check if using the default distribution is always the right |
// thing to do. |
BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
- InstallUtil::GetChromeVersion(dist, system_install, &installed_version); |
+ DCHECK(installed_version); |
+ InstallUtil::GetChromeVersion(dist, system_install, installed_version); |
- if (installed_version.IsValid()) { |
+ if (critical_update && installed_version->IsValid()) { |
InstallUtil::GetCriticalUpdateVersion(dist, system_install, |
- &critical_update); |
+ critical_update); |
} |
+} |
+#endif // defined(OS_WIN) |
+ |
+// This task checks the currently running version of Chrome against the |
+// installed version. If the installed version is newer, it runs the passed |
+// callback task. Otherwise it just deletes the task. |
+void DetectUpgradeTask(const base::Closure& upgrade_detected_task, |
+ bool* is_unstable_channel, |
+ bool* is_critical_upgrade) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ |
+ Version installed_version; |
+ Version critical_update; |
+ |
+#if defined(OS_WIN) |
+ GetInstalledAndCriticalVersion(&installed_version, &critical_update); |
#elif defined(OS_MACOSX) |
installed_version = |
Version(UTF16ToASCII(keystone_glue::CurrentlyInstalledVersion())); |
@@ -150,6 +165,132 @@ void DetectUpgradeTask(const base::Closure& upgrade_detected_task, |
} |
} |
+#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!
|
+// Implementation of a GoogleUpdateStatusListener (only available on Windows), |
+// so we can get the available version and identify if we are outdated. |
+class UpgradeStatusListener : public GoogleUpdateStatusListener { |
+ public: |
+ explicit UpgradeStatusListener(const base::Closure& notify_outdated_callback) |
+ : google_updater_(new GoogleUpdate()), |
+ got_installed_version_(false), |
+ got_available_version_(false), |
+ notify_outdated_callback_(notify_outdated_callback) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ google_updater_->set_status_listener(this); |
+ // false is for |install_if_newer|, we just want the available version. |
+ // And when we use false, we don't need to specify a |window|, so NULL. |
+ google_updater_->CheckForUpdate(false, NULL); |
+ |
+ // We use FILE as the thread to get the installed version |
+ // since it requires reading a file. And it is safe to use an unretained |
+ // this pointer since GetInstalledVersion must be called before destruction. |
+ BrowserThread::PostTask( |
+ BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&UpgradeStatusListener::GetInstalledVersion, |
+ base::Unretained(this))); |
+ } |
+ |
+ virtual ~UpgradeStatusListener() { |
+ google_updater_->set_status_listener(NULL); |
+ } |
+ |
+ // GoogleUpdateStatusListener implementation. |
+ virtual void OnReportResults(GoogleUpdateUpgradeResult result, |
+ GoogleUpdateErrorCode error_code, |
+ const string16& error_message, |
+ const string16& version) OVERRIDE { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ // 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!
|
+ DCHECK(result != UPGRADE_STARTED && result != UPGRADE_CHECK_STARTED); |
+ |
+ // Since false was specified for |install_if_newer|, this shouldn't happen. |
+ DCHECK(result != UPGRADE_SUCCESSFUL); |
+ |
+ switch (result) { |
+ case UPGRADE_ALREADY_UP_TO_DATE: { |
+ // Nothing needs to be done. |
+ break; |
+ } |
+ case UPGRADE_ERROR: { |
+ // Record these errors in UMA to see if something should be added here. |
+ content::RecordAction(content::UserMetricsAction("UpgradeCheck_Error")); |
+ break; |
+ } |
+ case UPGRADE_IS_AVAILABLE: { |
+ available_version_ = Version(UTF16ToASCII(version)); |
+ break; |
+ } |
+ default: { |
+ NOTREACHED(); |
+ } |
+ } |
+ 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!
|
+ if (got_installed_version_) |
+ CheckForOutdated(); |
+ } |
+ |
+ private: |
+ void GetInstalledVersion() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ Version installed_version; |
+ // 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!
|
+ // regular upgrades. The test is done here because it needs access to the |
+ // registry, which must be done on the FILE thread. |
+ BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
+ DCHECK(distribution); |
+ if (GoogleUpdateSettings::GetAppUpdatePolicy(distribution->GetAppGuid(), |
+ NULL) == |
+ GoogleUpdateSettings::AUTOMATIC_UPDATES) { |
+ // 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!
|
+ GetInstalledAndCriticalVersion(&installed_version, NULL); |
+ } |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&UpgradeStatusListener::GotInstalledVersion, |
+ base::Unretained(this), installed_version)); |
+ } |
+ |
+ void GotInstalledVersion(const Version& installed_version) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ installed_version_ = installed_version; |
+ got_installed_version_ = true; |
+ if (got_available_version_) |
+ CheckForOutdated(); |
+ } |
+ |
+ void CheckForOutdated() { |
Finnur
2012/12/06 19:53:16
nit: Suggest: CheckIfOutdatedVersion or NotifyIfOu
MAD
2013/01/22 15:18:29
Gone!
|
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ DCHECK(got_available_version_ && got_installed_version_); |
+ if (available_version_.IsValid() && installed_version_.IsValid() && |
+ available_version_.components()[0] > |
+ installed_version_.components()[0] + 1) { |
+ notify_outdated_callback_.Run(); |
+ } |
+ delete this; |
+ } |
+ |
+ // The class that communicates with Google Update to find out if an update is |
+ // available and asks it to start an upgrade. |
+ scoped_refptr<GoogleUpdate> google_updater_; |
+ |
+ // The value returned by GetInstalledAndCriticalVersion might be invalid |
+ // so a bool is also needed to identify that we at least tried to read it. |
+ Version installed_version_; |
+ bool got_installed_version_; |
+ |
+ // The value returned by google_updater_ might also be invalid |
+ // so a bool is also needed to identify that we at least tried to read it. |
+ Version available_version_; |
+ bool got_available_version_; |
+ |
+ // A callback to notify of an outdated install. |
+ base::Closure notify_outdated_callback_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(UpgradeStatusListener); |
+}; |
+ |
+#endif // defined(OS_WIN) |
+ |
} // namespace |
UpgradeDetectorImpl::UpgradeDetectorImpl() |
@@ -175,6 +316,13 @@ UpgradeDetectorImpl::UpgradeDetectorImpl() |
this, &UpgradeDetectorImpl::CheckForUpgrade); |
} |
#endif |
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) |
+ // On Windows, we also check for an outdated version so we use this listener |
+ // of Google update to asynchronously fetch the available version. |
+ // This object will self-destruct when done. |
+ new UpgradeStatusListener(base::Bind(&UpgradeDetectorImpl::NotifyOutdated, |
+ weak_factory_.GetWeakPtr())); |
+#endif // defined(OS_WIN) |
} |
UpgradeDetectorImpl::~UpgradeDetectorImpl() { |
@@ -268,6 +416,19 @@ void UpgradeDetectorImpl::NotifyOnUpgrade() { |
NotifyUpgradeRecommended(); |
} |
+void UpgradeDetectorImpl::NotifyOutdated() { |
+ // Stop the recurring timer (that is checking for changes). |
+ detect_upgrade_timer_.Stop(); |
+ set_upgrade_notification_stage(UPGRADE_ANNOYANCE_CRITICAL); |
+ |
+ content::NotificationService::current()->Notify( |
+ chrome::NOTIFICATION_OUTDATED_INSTALL, |
+ content::Source<UpgradeDetector>(this), |
+ content::NotificationService::NoDetails()); |
+ |
+ NotifyUpgradeRecommended(); |
+} |
+ |
// static |
UpgradeDetectorImpl* UpgradeDetectorImpl::GetInstance() { |
return Singleton<UpgradeDetectorImpl>::get(); |