1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/upgrade_detector.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/singleton.h" 123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_util.h" 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/task.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/time.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/platform_util.h" 183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_version_info.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/browser_distribution.h" 23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/install_util.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_MACOSX) 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/cocoa/keystone_glue.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_POSIX) 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/process_util.h" 3321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/version.h" 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// How long (in milliseconds) to wait (each cycle) before checking whether 39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Chrome's been upgraded behind our back. 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kCheckForUpgradeMs = 2 * 60 * 60 * 1000; // 2 hours. 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// How long to wait (each cycle) before checking which severity level we should 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// be at. Once we reach the highest severity, the timer will stop. 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kNotifyCycleTimeMs = 20 * 60 * 1000; // 20 minutes. 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Same as kNotifyCycleTimeMs but only used during testing. 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kNotifyCycleTimeForTestingMs = 5000; // 5 seconds. 48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::string CmdLineInterval() { 50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); 51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return cmd_line.GetSwitchValueASCII(switches::kCheckForUpdateIntervalSec); 52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How often to check for an upgrade. 553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint GetCheckForUpgradeEveryMs() { 563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Check for a value passed via the command line. 573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int interval_ms; 58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string interval = CmdLineInterval(); 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!interval.empty() && base::StringToInt(interval, &interval_ms)) 60513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return interval_ms * 1000; // Command line value is in seconds. 613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return kCheckForUpgradeMs; 633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This task checks the currently running version of Chrome against the 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// installed version. If the installed version is newer, it runs the passed 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// callback task. Otherwise it just deletes the task. 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass DetectUpgradeTask : public Task { 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen explicit DetectUpgradeTask(Task* upgrade_detected_task, 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool* is_dev_channel) 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : upgrade_detected_task_(upgrade_detected_task), 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen is_dev_channel_(is_dev_channel) { 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~DetectUpgradeTask() { 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (upgrade_detected_task_) { 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This has to get deleted on the same thread it was created. 79731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new DeleteTask<Task>(upgrade_detected_task_)); 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Run() { 85513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Version> installed_version; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the version of the currently *installed* instance of Chrome, 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // which might be newer than the *running* instance if we have been 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // upgraded in the background. 9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // TODO(tommi): Check if using the default distribution is always the right 9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // thing to do. 9521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen installed_version.reset(InstallUtil::GetChromeVersion(dist, false)); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!installed_version.get()) { 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // User level Chrome is not installed, check system level. 9921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen installed_version.reset(InstallUtil::GetChromeVersion(dist, true)); 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_MACOSX) 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch installed_version.reset( 10321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen Version::GetVersionFromString(UTF16ToASCII( 10421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen keystone_glue::CurrentlyInstalledVersion()))); 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_POSIX) 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // POSIX but not Mac OS X: Linux, etc. 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CommandLine command_line(*CommandLine::ForCurrentProcess()); 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch command_line.AppendSwitch(switches::kProductVersion); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string reply; 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!base::GetAppOutput(command_line, &reply)) { 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DLOG(ERROR) << "Failed to get current file version"; 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen installed_version.reset(Version::GetVersionFromString(reply)); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::string channel = platform_util::GetVersionStringModifier(); 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *is_dev_channel_ = channel == "dev"; 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the version of the currently *running* instance of Chrome. 1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chrome::VersionInfo version_info; 1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!version_info.is_valid()) { 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Failed to get current file version"; 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Version> running_version( 12821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen Version::GetVersionFromString(version_info.Version())); 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (running_version.get() == NULL) { 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Failed to parse version info"; 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |installed_version| may be NULL when the user downgrades on Linux (by 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // switching from dev to beta channel, for example). The user needs a 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // restart in this case as well. See http://crbug.com/46547 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!installed_version.get() || 13821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen (installed_version->CompareTo(*running_version) > 0)) { 139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick upgrade_detected_task_); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch upgrade_detected_task_ = NULL; 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Task* upgrade_detected_task_; 147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool* is_dev_channel_; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpgradeDetector::RegisterPrefs(PrefService* prefs) { 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->RegisterBooleanPref(prefs::kRestartLastSessionOnShutdown, false); 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochUpgradeDetector::UpgradeDetector() 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), 159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen is_dev_channel_(false), 160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_notification_stage_(UPGRADE_ANNOYANCE_NONE), 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notify_upgrade_(false) { 162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CommandLine command_line(*CommandLine::ForCurrentProcess()); 163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (command_line.HasSwitch(switches::kDisableBackgroundNetworking)) 164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Windows: only enable upgrade notifications for official builds. 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Mac: only enable them if the updater (Keystone) is present. 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Linux (and other POSIX): always enable regardless of branding. 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if (defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)) || defined(OS_POSIX) 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX) 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (keystone_glue::KeystoneEnabled()) 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch detect_upgrade_timer_.Start( 1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::TimeDelta::FromMilliseconds(GetCheckForUpgradeEveryMs()), 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, &UpgradeDetector::CheckForUpgrade); 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochUpgradeDetector::~UpgradeDetector() { 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// static 18421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenUpgradeDetector* UpgradeDetector::GetInstance() { 18521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return Singleton<UpgradeDetector>::get(); 18621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 18721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpgradeDetector::CheckForUpgrade() { 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch method_factory_.RevokeAll(); 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Task* callback_task = 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch method_factory_.NewRunnableMethod(&UpgradeDetector::UpgradeDetected); 192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // We use FILE as the thread to run the upgrade detection code on all 193513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // platforms. For Linux, this is because we don't want to block the UI thread 194513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // while launching a background process and reading its output; on the Mac and 195513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // on Windows checking for an upgrade requires reading a file. 196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new DetectUpgradeTask(callback_task, 198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &is_dev_channel_)); 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpgradeDetector::UpgradeDetected() { 202731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Stop the recurring timer (that is checking for changes). 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch detect_upgrade_timer_.Stop(); 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_detected_time_ = base::Time::Now(); 208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::UPGRADE_DETECTED, 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<UpgradeDetector>(this), 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::NoDetails()); 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Start the repeating timer for notifying the user after a certain period. 215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The called function will eventually figure out that enough time has passed 216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // and stop the timer. 217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int cycle_time = CmdLineInterval().empty() ? kNotifyCycleTimeMs : 218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen kNotifyCycleTimeForTestingMs; 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch upgrade_notification_timer_.Start( 220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::TimeDelta::FromMilliseconds(cycle_time), 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, &UpgradeDetector::NotifyOnUpgrade); 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UpgradeDetector::NotifyOnUpgrade() { 225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::TimeDelta delta = base::Time::Now() - upgrade_detected_time_; 226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string interval = CmdLineInterval(); 227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // A command line interval implies testing, which we'll make more convenient 228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // by switching to minutes of waiting instead of hours between flipping 229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // severity. 230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int time_passed = interval.empty() ? delta.InHours() : delta.InMinutes(); 231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const int kSevereThreshold = 14 * (interval.empty() ? 24 : 1); 232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const int kHighThreshold = 7 * (interval.empty() ? 24 : 1); 233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const int kElevatedThreshold = 4 * (interval.empty() ? 24 : 1); 234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Dev channel is fixed at lowest severity after 1 hour. For other channels 235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // it is after 2 hours. And, as before, if a command line is passed in we 236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // drastically reduce the wait time. 237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const int multiplier = is_dev_channel_ ? 1 : 2; 238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const int kLowThreshold = multiplier * (interval.empty() ? 24 : 1); 239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // These if statements (except for the first one) must be sorted (highest 241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // interval first). 242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (time_passed >= kSevereThreshold) 243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_notification_stage_ = UPGRADE_ANNOYANCE_SEVERE; 244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else if (time_passed >= kHighThreshold) 245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_notification_stage_ = UPGRADE_ANNOYANCE_HIGH; 246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else if (time_passed >= kElevatedThreshold) 247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_notification_stage_ = UPGRADE_ANNOYANCE_ELEVATED; 248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else if (time_passed >= kLowThreshold) 249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_notification_stage_ = UPGRADE_ANNOYANCE_LOW; 250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else 251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; // Not ready to recommend upgrade. 252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (is_dev_channel_ || 254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_notification_stage_ == UPGRADE_ANNOYANCE_SEVERE) { 255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // We can't get any higher, baby. 256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen upgrade_notification_timer_.Stop(); 257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notify_upgrade_ = true; 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::UPGRADE_RECOMMENDED, 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<UpgradeDetector>(this), 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::NoDetails()); 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 266