diff options
-rw-r--r-- | chrome/browser/chromeos/upgrade_detector_chromeos.cc | 78 | ||||
-rw-r--r-- | chrome/browser/chromeos/upgrade_detector_chromeos.h | 40 | ||||
-rw-r--r-- | chrome/browser/upgrade_detector.cc | 259 | ||||
-rw-r--r-- | chrome/browser/upgrade_detector.h | 44 | ||||
-rw-r--r-- | chrome/browser/upgrade_detector_impl.cc | 265 | ||||
-rw-r--r-- | chrome/browser/upgrade_detector_impl.h | 57 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 6 |
7 files changed, 464 insertions, 285 deletions
diff --git a/chrome/browser/chromeos/upgrade_detector_chromeos.cc b/chrome/browser/chromeos/upgrade_detector_chromeos.cc new file mode 100644 index 0000000..45ad77a --- /dev/null +++ b/chrome/browser/chromeos/upgrade_detector_chromeos.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/upgrade_detector_chromeos.h" + +#include "base/memory/singleton.h" +#include "chrome/browser/chromeos/cros/cros_library.h" + +namespace { + +// How long to wait (each cycle) before checking which severity level we should +// be at. Once we reach the highest severity, the timer will stop. +const int kNotifyCycleTimeMs = 20 * 60 * 1000; // 20 minutes. + +} // namespace + +UpgradeDetectorChromeos::UpgradeDetectorChromeos() { + chromeos::CrosLibrary::Get()->GetUpdateLibrary()->AddObserver(this); +} + +UpgradeDetectorChromeos::~UpgradeDetectorChromeos() { + chromeos::CrosLibrary::Get()->GetUpdateLibrary()->RemoveObserver(this); +} + +void UpgradeDetectorChromeos::UpdateStatusChanged( + chromeos::UpdateLibrary* library) { + if (library->status().status != chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT) + return; + + NotifyUpgradeDetected(); + + // ChromeOS shows upgrade arrow once the upgrade becomes available. + NotifyOnUpgrade(); + + // Setup timer to to move along the upgrade advisory system. + upgrade_notification_timer_.Start( + base::TimeDelta::FromMilliseconds(kNotifyCycleTimeMs), + this, &UpgradeDetectorChromeos::NotifyOnUpgrade); +} + +void UpgradeDetectorChromeos::NotifyOnUpgrade() { + base::TimeDelta delta = base::Time::Now() - upgrade_detected_time(); + int64 time_passed = delta.InDays(); + + const int kSevereThreshold = 7; + const int kHighThreshold = 4; + const int kElevatedThreshold = 2; + const int kLowThreshold = 0; + + // These if statements must be sorted (highest interval first). + if (time_passed >= kSevereThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_SEVERE); + + // We can't get any higher, baby. + upgrade_notification_timer_.Stop(); + } else if (time_passed >= kHighThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_HIGH); + } else if (time_passed >= kElevatedThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_ELEVATED); + } else if (time_passed >= kLowThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_LOW); + } else { + return; // Not ready to recommend upgrade. + } + + NotifyUpgradeRecommended(); +} + +// static +UpgradeDetectorChromeos* UpgradeDetectorChromeos::GetInstance() { + return Singleton<UpgradeDetectorChromeos>::get(); +} + +// static +UpgradeDetector* UpgradeDetector::GetInstance() { + return UpgradeDetectorChromeos::GetInstance(); +} diff --git a/chrome/browser/chromeos/upgrade_detector_chromeos.h b/chrome/browser/chromeos/upgrade_detector_chromeos.h new file mode 100644 index 0000000..09f2f70 --- /dev/null +++ b/chrome/browser/chromeos/upgrade_detector_chromeos.h @@ -0,0 +1,40 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_UPGRADE_DETECTOR_CHROMEOS_H_ +#define CHROME_BROWSER_CHROMEOS_UPGRADE_DETECTOR_CHROMEOS_H_ +#pragma once + +#include "base/timer.h" +#include "chrome/browser/chromeos/cros/update_library.h" +#include "chrome/browser/upgrade_detector.h" + +template <typename T> struct DefaultSingletonTraits; + +class UpgradeDetectorChromeos : public UpgradeDetector, + public chromeos::UpdateLibrary::Observer { + public: + virtual ~UpgradeDetectorChromeos(); + + static UpgradeDetectorChromeos* GetInstance(); + + private: + friend struct DefaultSingletonTraits<UpgradeDetectorChromeos>; + + UpgradeDetectorChromeos(); + + // chromeos::UpdateLibrary::Observer implementation. + virtual void UpdateStatusChanged(chromeos::UpdateLibrary* library); + + // The function that sends out a notification (after a certain time has + // elapsed) that lets the rest of the UI know we should start notifying the + // user that a new version is available. + void NotifyOnUpgrade(); + + // After we detect an upgrade we start a recurring timer to see if enough time + // has passed and we should start notifying the user. + base::RepeatingTimer<UpgradeDetectorChromeos> upgrade_notification_timer_; +}; + +#endif // CHROME_BROWSER_CHROMEOS_UPGRADE_DETECTOR_CHROMEOS_H_ diff --git a/chrome/browser/upgrade_detector.cc b/chrome/browser/upgrade_detector.cc index a0d8f0c..e0fb2d5 100644 --- a/chrome/browser/upgrade_detector.cc +++ b/chrome/browser/upgrade_detector.cc @@ -4,158 +4,11 @@ #include "chrome/browser/upgrade_detector.h" -#include <string> - -#include "base/command_line.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/string_number_conversions.h" -#include "base/string_util.h" -#include "base/task.h" -#include "base/time.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/platform_util.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/chrome_version_info.h" #include "chrome/common/pref_names.h" -#include "chrome/installer/util/browser_distribution.h" -#include "content/browser/browser_thread.h" #include "content/common/notification_service.h" #include "content/common/notification_type.h" #include "grit/theme_resources.h" -#include "ui/base/resource/resource_bundle.h" - -#if defined(OS_WIN) -#include "chrome/installer/util/install_util.h" -#elif defined(OS_MACOSX) -#include "chrome/browser/cocoa/keystone_glue.h" -#elif defined(OS_POSIX) -#include "base/process_util.h" -#include "base/version.h" -#endif - -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/cros/cros_library.h" -#include "chrome/browser/chromeos/cros/update_library.h" -#endif - -namespace { - -// How long (in milliseconds) to wait (each cycle) before checking whether -// Chrome's been upgraded behind our back. -const int kCheckForUpgradeMs = 2 * 60 * 60 * 1000; // 2 hours. - -// How long to wait (each cycle) before checking which severity level we should -// be at. Once we reach the highest severity, the timer will stop. -const int kNotifyCycleTimeMs = 20 * 60 * 1000; // 20 minutes. - -// Same as kNotifyCycleTimeMs but only used during testing. -const int kNotifyCycleTimeForTestingMs = 500; // Half a second. - -std::string CmdLineInterval() { - const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); - return cmd_line.GetSwitchValueASCII(switches::kCheckForUpdateIntervalSec); -} - -// How often to check for an upgrade. -int GetCheckForUpgradeEveryMs() { - // Check for a value passed via the command line. - int interval_ms; - std::string interval = CmdLineInterval(); - if (!interval.empty() && base::StringToInt(interval, &interval_ms)) - return interval_ms * 1000; // Command line value is in seconds. - - 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. -class DetectUpgradeTask : public Task { - public: - explicit DetectUpgradeTask(Task* upgrade_detected_task, - bool* is_unstable_channel) - : upgrade_detected_task_(upgrade_detected_task), - is_unstable_channel_(is_unstable_channel) { - } - - virtual ~DetectUpgradeTask() { - if (upgrade_detected_task_) { - // This has to get deleted on the same thread it was created. - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - new DeleteTask<Task>(upgrade_detected_task_)); - } - } - - virtual void Run() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - scoped_ptr<Version> installed_version; - -#if defined(OS_WIN) - // 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. - // TODO(tommi): Check if using the default distribution is always the right - // thing to do. - BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - installed_version.reset(InstallUtil::GetChromeVersion(dist, false)); - if (!installed_version.get()) { - // User level Chrome is not installed, check system level. - installed_version.reset(InstallUtil::GetChromeVersion(dist, true)); - } -#elif defined(OS_MACOSX) - installed_version.reset( - Version::GetVersionFromString(UTF16ToASCII( - keystone_glue::CurrentlyInstalledVersion()))); -#elif defined(OS_POSIX) - // POSIX but not Mac OS X: Linux, etc. - CommandLine command_line(*CommandLine::ForCurrentProcess()); - command_line.AppendSwitch(switches::kProductVersion); - std::string reply; - if (!base::GetAppOutput(command_line, &reply)) { - DLOG(ERROR) << "Failed to get current file version"; - return; - } - - installed_version.reset(Version::GetVersionFromString(reply)); -#endif - - platform_util::Channel channel = platform_util::GetChannel(); - *is_unstable_channel_ = channel == platform_util::CHANNEL_DEV || - channel == platform_util::CHANNEL_CANARY; - - // Get the version of the currently *running* instance of Chrome. - chrome::VersionInfo version_info; - if (!version_info.is_valid()) { - NOTREACHED() << "Failed to get current file version"; - return; - } - scoped_ptr<Version> running_version( - Version::GetVersionFromString(version_info.Version())); - if (running_version.get() == NULL) { - NOTREACHED() << "Failed to parse version info"; - return; - } - - // |installed_version| may be NULL when the user downgrades on Linux (by - // switching from dev to beta channel, for example). The user needs a - // restart in this case as well. See http://crbug.com/46547 - if (!installed_version.get() || - (installed_version->CompareTo(*running_version) > 0)) { - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - upgrade_detected_task_); - upgrade_detected_task_ = NULL; - } - } - - private: - Task* upgrade_detected_task_; - bool* is_unstable_channel_; -}; - -} // namespace // static void UpgradeDetector::RegisterPrefs(PrefService* prefs) { @@ -179,129 +32,23 @@ int UpgradeDetector::GetIconResourceID(UpgradeNotificationIconType type) { } UpgradeDetector::UpgradeDetector() - : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), - is_unstable_channel_(false), - upgrade_notification_stage_(UPGRADE_ANNOYANCE_NONE), + : upgrade_notification_stage_(UPGRADE_ANNOYANCE_NONE), notify_upgrade_(false) { - CommandLine command_line(*CommandLine::ForCurrentProcess()); - if (command_line.HasSwitch(switches::kDisableBackgroundNetworking)) - return; - // Windows: only enable upgrade notifications for official builds. - // Mac: only enable them if the updater (Keystone) is present. - // Linux (and other POSIX): always enable regardless of branding. -#if (defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)) || defined(OS_POSIX) -#if defined(OS_MACOSX) - if (keystone_glue::KeystoneEnabled()) -#endif - { - detect_upgrade_timer_.Start( - base::TimeDelta::FromMilliseconds(GetCheckForUpgradeEveryMs()), - this, &UpgradeDetector::CheckForUpgrade); - } -#endif } UpgradeDetector::~UpgradeDetector() { } -// static -UpgradeDetector* UpgradeDetector::GetInstance() { - return Singleton<UpgradeDetector>::get(); -} - -void UpgradeDetector::CheckForUpgrade() { -#if defined(OS_CHROMEOS) - // For ChromeOS, check update library status to detect upgrade. - if (chromeos::CrosLibrary::Get()->GetUpdateLibrary()->status().status == - chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT) { - UpgradeDetected(); - } -#else - method_factory_.RevokeAll(); - Task* callback_task = - method_factory_.NewRunnableMethod(&UpgradeDetector::UpgradeDetected); - // We use FILE as the thread to run the upgrade detection code on all - // platforms. For Linux, this is because we don't want to block the UI thread - // while launching a background process and reading its output; on the Mac and - // on Windows checking for an upgrade requires reading a file. - BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, - new DetectUpgradeTask(callback_task, - &is_unstable_channel_)); -#endif -} - -void UpgradeDetector::UpgradeDetected() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // Stop the recurring timer (that is checking for changes). - detect_upgrade_timer_.Stop(); - +void UpgradeDetector::NotifyUpgradeDetected() { upgrade_detected_time_ = base::Time::Now(); NotificationService::current()->Notify( NotificationType::UPGRADE_DETECTED, Source<UpgradeDetector>(this), NotificationService::NoDetails()); - - // Start the repeating timer for notifying the user after a certain period. - // The called function will eventually figure out that enough time has passed - // and stop the timer. - int cycle_time = CmdLineInterval().empty() ? kNotifyCycleTimeMs : - kNotifyCycleTimeForTestingMs; - upgrade_notification_timer_.Start( - base::TimeDelta::FromMilliseconds(cycle_time), - this, &UpgradeDetector::NotifyOnUpgrade); } -void UpgradeDetector::NotifyOnUpgrade() { - base::TimeDelta delta = base::Time::Now() - upgrade_detected_time_; - std::string interval = CmdLineInterval(); - - // A command line interval implies testing, which we'll make more convenient - // by switching to seconds of waiting instead of days between flipping - // severity. This works in conjunction with the similar interval.empty() - // check below. - int64 time_passed = interval.empty() ? delta.InHours() : delta.InSeconds(); - - if (is_unstable_channel_) { - // There's only one threat level for unstable channels like dev and - // canary, and it hits after one hour. During testing, it hits after one - // minute. - const int kUnstableThreshold = 1; - - if (time_passed >= kUnstableThreshold) { - upgrade_notification_stage_ = UPGRADE_ANNOYANCE_LOW; - - // That's as high as it goes. - upgrade_notification_timer_.Stop(); - } else { - return; // Not ready to recommend upgrade. - } - } else { - const int kMultiplier = interval.empty() ? 24 : 1; - // 14 days when not testing, otherwise 14 seconds. - const int kSevereThreshold = 14 * kMultiplier; - const int kHighThreshold = 7 * kMultiplier; - const int kElevatedThreshold = 4 * kMultiplier; - const int kLowThreshold = 2 * kMultiplier; - - // These if statements must be sorted (highest interval first). - if (time_passed >= kSevereThreshold) { - upgrade_notification_stage_ = UPGRADE_ANNOYANCE_SEVERE; - - // We can't get any higher, baby. - upgrade_notification_timer_.Stop(); - } else if (time_passed >= kHighThreshold) { - upgrade_notification_stage_ = UPGRADE_ANNOYANCE_HIGH; - } else if (time_passed >= kElevatedThreshold) { - upgrade_notification_stage_ = UPGRADE_ANNOYANCE_ELEVATED; - } else if (time_passed >= kLowThreshold) { - upgrade_notification_stage_ = UPGRADE_ANNOYANCE_LOW; - } else { - return; // Not ready to recommend upgrade. - } - } - +void UpgradeDetector::NotifyUpgradeRecommended() { notify_upgrade_ = true; NotificationService::current()->Notify( diff --git a/chrome/browser/upgrade_detector.h b/chrome/browser/upgrade_detector.h index 00227d5..31ac709 100644 --- a/chrome/browser/upgrade_detector.h +++ b/chrome/browser/upgrade_detector.h @@ -9,7 +9,6 @@ #include "base/timer.h" #include "ui/gfx/image.h" -template <typename T> struct DefaultSingletonTraits; class PrefService; /////////////////////////////////////////////////////////////////////////////// @@ -39,10 +38,10 @@ class UpgradeDetector { UPGRADE_ICON_TYPE_MENU_ICON, // For showing in the wrench menu. }; - // Returns the singleton instance. + // Returns the singleton implementation instance. static UpgradeDetector* GetInstance(); - ~UpgradeDetector(); + virtual ~UpgradeDetector(); static void RegisterPrefs(PrefService* prefs); @@ -55,41 +54,28 @@ class UpgradeDetector { // within the wrench menu. int GetIconResourceID(UpgradeNotificationIconType type); - private: - friend struct DefaultSingletonTraits<UpgradeDetector>; - + protected: UpgradeDetector(); - // Launches a task on the file thread to check if we have the latest version. - void CheckForUpgrade(); - - // Sends out a notification and starts a one shot timer to wait until - // notifying the user. - void UpgradeDetected(); + // Sends out UPGRADE_DETECTED notification and record upgrade_detected_time_. + void NotifyUpgradeDetected(); - // The function that sends out a notification (after a certain time has - // elapsed) that lets the rest of the UI know we should start notifying the - // user that a new version is available. - void NotifyOnUpgrade(); + // Sends out UPGRADE_RECOMMENDED notification and set notify_upgrade_. + void NotifyUpgradeRecommended(); - // We periodically check to see if Chrome has been upgraded. - base::RepeatingTimer<UpgradeDetector> detect_upgrade_timer_; + // Accessors. + const base::Time& upgrade_detected_time() const { + return upgrade_detected_time_; + } - // After we detect an upgrade we start a recurring timer to see if enough time - // has passed and we should start notifying the user. - base::RepeatingTimer<UpgradeDetector> upgrade_notification_timer_; - - // We use this factory to create callback tasks for UpgradeDetected. We pass - // the task to the actual upgrade detection code, which is in - // DetectUpgradeTask. - ScopedRunnableMethodFactory<UpgradeDetector> method_factory_; + void set_upgrade_notification_stage(UpgradeNotificationAnnoyanceLevel stage) { + upgrade_notification_stage_ = stage; + } + private: // When the upgrade was detected. base::Time upgrade_detected_time_; - // True if this build is a dev or canary channel build. - bool is_unstable_channel_; - // The stage at which the annoyance level for upgrade notifications is at. UpgradeNotificationAnnoyanceLevel upgrade_notification_stage_; diff --git a/chrome/browser/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector_impl.cc new file mode 100644 index 0000000..23f747a --- /dev/null +++ b/chrome/browser/upgrade_detector_impl.cc @@ -0,0 +1,265 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/upgrade_detector_impl.h" + +#include <string> + +#include "base/command_line.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "base/task.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/platform_util.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_version_info.h" +#include "chrome/installer/util/browser_distribution.h" +#include "content/browser/browser_thread.h" +#include "ui/base/resource/resource_bundle.h" + +#if defined(OS_WIN) +#include "chrome/installer/util/install_util.h" +#elif defined(OS_MACOSX) +#include "chrome/browser/cocoa/keystone_glue.h" +#elif defined(OS_POSIX) +#include "base/process_util.h" +#include "base/version.h" +#endif + +namespace { + +// How long (in milliseconds) to wait (each cycle) before checking whether +// Chrome's been upgraded behind our back. +const int kCheckForUpgradeMs = 2 * 60 * 60 * 1000; // 2 hours. + +// How long to wait (each cycle) before checking which severity level we should +// be at. Once we reach the highest severity, the timer will stop. +const int kNotifyCycleTimeMs = 20 * 60 * 1000; // 20 minutes. + +// Same as kNotifyCycleTimeMs but only used during testing. +const int kNotifyCycleTimeForTestingMs = 500; // Half a second. + +std::string CmdLineInterval() { + const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); + return cmd_line.GetSwitchValueASCII(switches::kCheckForUpdateIntervalSec); +} + +// How often to check for an upgrade. +int GetCheckForUpgradeEveryMs() { + // Check for a value passed via the command line. + int interval_ms; + std::string interval = CmdLineInterval(); + if (!interval.empty() && base::StringToInt(interval, &interval_ms)) + return interval_ms * 1000; // Command line value is in seconds. + + 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. +class DetectUpgradeTask : public Task { + public: + explicit DetectUpgradeTask(Task* upgrade_detected_task, + bool* is_unstable_channel) + : upgrade_detected_task_(upgrade_detected_task), + is_unstable_channel_(is_unstable_channel) { + } + + virtual ~DetectUpgradeTask() { + if (upgrade_detected_task_) { + // This has to get deleted on the same thread it was created. + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + new DeleteTask<Task>(upgrade_detected_task_)); + } + } + + virtual void Run() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + scoped_ptr<Version> installed_version; + +#if defined(OS_WIN) + // 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. + // TODO(tommi): Check if using the default distribution is always the right + // thing to do. + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + installed_version.reset(InstallUtil::GetChromeVersion(dist, false)); + if (!installed_version.get()) { + // User level Chrome is not installed, check system level. + installed_version.reset(InstallUtil::GetChromeVersion(dist, true)); + } +#elif defined(OS_MACOSX) + installed_version.reset( + Version::GetVersionFromString(UTF16ToASCII( + keystone_glue::CurrentlyInstalledVersion()))); +#elif defined(OS_POSIX) + // POSIX but not Mac OS X: Linux, etc. + CommandLine command_line(*CommandLine::ForCurrentProcess()); + command_line.AppendSwitch(switches::kProductVersion); + std::string reply; + if (!base::GetAppOutput(command_line, &reply)) { + DLOG(ERROR) << "Failed to get current file version"; + return; + } + + installed_version.reset(Version::GetVersionFromString(reply)); +#endif + + platform_util::Channel channel = platform_util::GetChannel(); + *is_unstable_channel_ = channel == platform_util::CHANNEL_DEV || + channel == platform_util::CHANNEL_CANARY; + + // Get the version of the currently *running* instance of Chrome. + chrome::VersionInfo version_info; + if (!version_info.is_valid()) { + NOTREACHED() << "Failed to get current file version"; + return; + } + scoped_ptr<Version> running_version( + Version::GetVersionFromString(version_info.Version())); + if (running_version.get() == NULL) { + NOTREACHED() << "Failed to parse version info"; + return; + } + + // |installed_version| may be NULL when the user downgrades on Linux (by + // switching from dev to beta channel, for example). The user needs a + // restart in this case as well. See http://crbug.com/46547 + if (!installed_version.get() || + (installed_version->CompareTo(*running_version) > 0)) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + upgrade_detected_task_); + upgrade_detected_task_ = NULL; + } + } + + private: + Task* upgrade_detected_task_; + bool* is_unstable_channel_; +}; + +} // namespace + +UpgradeDetectorImpl::UpgradeDetectorImpl() + : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), + is_unstable_channel_(false) { + CommandLine command_line(*CommandLine::ForCurrentProcess()); + if (command_line.HasSwitch(switches::kDisableBackgroundNetworking)) + return; + // Windows: only enable upgrade notifications for official builds. + // Mac: only enable them if the updater (Keystone) is present. + // Linux (and other POSIX): always enable regardless of branding. +#if (defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)) || defined(OS_POSIX) +#if defined(OS_MACOSX) + if (keystone_glue::KeystoneEnabled()) +#endif + { + detect_upgrade_timer_.Start( + base::TimeDelta::FromMilliseconds(GetCheckForUpgradeEveryMs()), + this, &UpgradeDetectorImpl::CheckForUpgrade); + } +#endif +} + +UpgradeDetectorImpl::~UpgradeDetectorImpl() { +} + +void UpgradeDetectorImpl::CheckForUpgrade() { + method_factory_.RevokeAll(); + Task* callback_task = + method_factory_.NewRunnableMethod(&UpgradeDetectorImpl::UpgradeDetected); + // We use FILE as the thread to run the upgrade detection code on all + // platforms. For Linux, this is because we don't want to block the UI thread + // while launching a background process and reading its output; on the Mac and + // on Windows checking for an upgrade requires reading a file. + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + new DetectUpgradeTask(callback_task, + &is_unstable_channel_)); +} + +void UpgradeDetectorImpl::UpgradeDetected() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // Stop the recurring timer (that is checking for changes). + detect_upgrade_timer_.Stop(); + + NotifyUpgradeDetected(); + + // Start the repeating timer for notifying the user after a certain period. + // The called function will eventually figure out that enough time has passed + // and stop the timer. + int cycle_time = CmdLineInterval().empty() ? kNotifyCycleTimeMs : + kNotifyCycleTimeForTestingMs; + upgrade_notification_timer_.Start( + base::TimeDelta::FromMilliseconds(cycle_time), + this, &UpgradeDetectorImpl::NotifyOnUpgrade); +} + +void UpgradeDetectorImpl::NotifyOnUpgrade() { + base::TimeDelta delta = base::Time::Now() - upgrade_detected_time(); + std::string interval = CmdLineInterval(); + + // A command line interval implies testing, which we'll make more convenient + // by switching to seconds of waiting instead of days between flipping + // severity. This works in conjunction with the similar interval.empty() + // check below. + int64 time_passed = interval.empty() ? delta.InHours() : delta.InSeconds(); + + if (is_unstable_channel_) { + // There's only one threat level for unstable channels like dev and + // canary, and it hits after one hour. During testing, it hits after one + // minute. + const int kUnstableThreshold = 1; + + if (time_passed >= kUnstableThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_LOW); + + // That's as high as it goes. + upgrade_notification_timer_.Stop(); + } else { + return; // Not ready to recommend upgrade. + } + } else { + const int kMultiplier = interval.empty() ? 24 : 1; + // 14 days when not testing, otherwise 14 seconds. + const int kSevereThreshold = 14 * kMultiplier; + const int kHighThreshold = 7 * kMultiplier; + const int kElevatedThreshold = 4 * kMultiplier; + const int kLowThreshold = 2 * kMultiplier; + + // These if statements must be sorted (highest interval first). + if (time_passed >= kSevereThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_SEVERE); + + // We can't get any higher, baby. + upgrade_notification_timer_.Stop(); + } else if (time_passed >= kHighThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_HIGH); + } else if (time_passed >= kElevatedThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_ELEVATED); + } else if (time_passed >= kLowThreshold) { + set_upgrade_notification_stage(UPGRADE_ANNOYANCE_LOW); + } else { + return; // Not ready to recommend upgrade. + } + } + + NotifyUpgradeRecommended(); +} + +// static +UpgradeDetectorImpl* UpgradeDetectorImpl::GetInstance() { + return Singleton<UpgradeDetectorImpl>::get(); +} + +// static +UpgradeDetector* UpgradeDetector::GetInstance() { + return UpgradeDetectorImpl::GetInstance(); +} diff --git a/chrome/browser/upgrade_detector_impl.h b/chrome/browser/upgrade_detector_impl.h new file mode 100644 index 0000000..ee6e3fa --- /dev/null +++ b/chrome/browser/upgrade_detector_impl.h @@ -0,0 +1,57 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UPGRADE_DETECTOR_IMPL_H_ +#define CHROME_BROWSER_UPGRADE_DETECTOR_IMPL_H_ +#pragma once + +#include "base/timer.h" +#include "chrome/browser/upgrade_detector.h" + +template <typename T> struct DefaultSingletonTraits; + +class UpgradeDetectorImpl : public UpgradeDetector { + public: + virtual ~UpgradeDetectorImpl(); + + // Returns the singleton instance. + static UpgradeDetectorImpl* GetInstance(); + + private: + friend struct DefaultSingletonTraits<UpgradeDetectorImpl>; + + UpgradeDetectorImpl(); + + // Launches a task on the file thread to check if we have the latest version. + void CheckForUpgrade(); + + // Sends out a notification and starts a one shot timer to wait until + // notifying the user. + void UpgradeDetected(); + + // The function that sends out a notification (after a certain time has + // elapsed) that lets the rest of the UI know we should start notifying the + // user that a new version is available. + void NotifyOnUpgrade(); + + // We periodically check to see if Chrome has been upgraded. + base::RepeatingTimer<UpgradeDetectorImpl> detect_upgrade_timer_; + + // After we detect an upgrade we start a recurring timer to see if enough time + // has passed and we should start notifying the user. + base::RepeatingTimer<UpgradeDetectorImpl> upgrade_notification_timer_; + + // We use this factory to create callback tasks for UpgradeDetected. We pass + // the task to the actual upgrade detection code, which is in + // DetectUpgradeTask. + ScopedRunnableMethodFactory<UpgradeDetectorImpl> method_factory_; + + // True if this build is a dev or canary channel build. + bool is_unstable_channel_; + + DISALLOW_COPY_AND_ASSIGN(UpgradeDetectorImpl); +}; + + +#endif // CHROME_BROWSER_UPGRADE_DETECTOR_IMPL_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index e1fde1a..15793e6 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -721,6 +721,8 @@ 'browser/chromeos/tab_closeable_state_watcher.h', 'browser/chromeos/update_observer.cc', 'browser/chromeos/update_observer.h', + 'browser/chromeos/upgrade_detector_chromeos.cc', + 'browser/chromeos/upgrade_detector_chromeos.h', 'browser/chromeos/user_cros_settings_provider.cc', 'browser/chromeos/user_cros_settings_provider.h', 'browser/chromeos/version_loader.cc', @@ -3511,6 +3513,8 @@ 'browser/ui/window_snapshot/window_snapshot_x.cc', 'browser/upgrade_detector.cc', 'browser/upgrade_detector.h', + 'browser/upgrade_detector_impl.cc', + 'browser/upgrade_detector_impl.h', 'browser/user_style_sheet_watcher.cc', 'browser/user_style_sheet_watcher.h', 'browser/visitedlink/visitedlink_event_listener.cc', @@ -3627,6 +3631,8 @@ 'browser/password_manager/native_backend_kwallet_x.cc', 'browser/password_manager/native_backend_kwallet_x.h', 'browser/platform_util_linux.cc', + 'browser/upgrade_detector_impl.cc', + 'browser/upgrade_detector_impl.h', ], }], ['use_cups==1', { |