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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/upgrade_detector_impl.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/build_time.h" 11 #include "base/command_line.h" 12 #include "base/cpu.h" 13 #include "base/files/file_path.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/singleton.h" 16 #include "base/path_service.h" 17 #include "base/prefs/pref_service.h" 18 #include "base/process/launch.h" 19 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/string_util.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "base/time/time.h" 23 #include "chrome/browser/browser_process.h" 24 #include "chrome/browser/google/google_brand.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/chrome_version_info.h" 27 #include "chrome/common/pref_names.h" 28 #include "components/network_time/network_time_tracker.h" 29 #include "content/public/browser/browser_thread.h" 30 #include "ui/base/resource/resource_bundle.h" 31 32 #if defined(OS_WIN) 33 #include "base/win/win_util.h" 34 #include "chrome/installer/util/browser_distribution.h" 35 #include "chrome/installer/util/google_update_settings.h" 36 #include "chrome/installer/util/helper.h" 37 #include "chrome/installer/util/install_util.h" 38 #elif defined(OS_MACOSX) 39 #include "chrome/browser/mac/keystone_glue.h" 40 #endif 41 42 using content::BrowserThread; 43 44 namespace { 45 46 // How long (in milliseconds) to wait (each cycle) before checking whether 47 // Chrome's been upgraded behind our back. 48 const int kCheckForUpgradeMs = 2 * 60 * 60 * 1000; // 2 hours. 49 50 // How long to wait (each cycle) before checking which severity level we should 51 // be at. Once we reach the highest severity, the timer will stop. 52 const int kNotifyCycleTimeMs = 20 * 60 * 1000; // 20 minutes. 53 54 // Same as kNotifyCycleTimeMs but only used during testing. 55 const int kNotifyCycleTimeForTestingMs = 500; // Half a second. 56 57 // The number of days after which we identify a build/install as outdated. 58 const uint64 kOutdatedBuildAgeInDays = 12 * 7; 59 60 // Return the string that was passed as a value for the 61 // kCheckForUpdateIntervalSec switch. 62 std::string CmdLineInterval() { 63 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); 64 return cmd_line.GetSwitchValueASCII(switches::kCheckForUpdateIntervalSec); 65 } 66 67 // Check if one of the outdated simulation switches was present on the command 68 // line. 69 bool SimulatingOutdated() { 70 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); 71 return cmd_line.HasSwitch(switches::kSimulateOutdated) || 72 cmd_line.HasSwitch(switches::kSimulateOutdatedNoAU); 73 } 74 75 // Check if any of the testing switches was present on the command line. 76 bool IsTesting() { 77 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); 78 return cmd_line.HasSwitch(switches::kSimulateUpgrade) || 79 cmd_line.HasSwitch(switches::kCheckForUpdateIntervalSec) || 80 cmd_line.HasSwitch(switches::kSimulateCriticalUpdate) || 81 SimulatingOutdated(); 82 } 83 84 // How often to check for an upgrade. 85 int GetCheckForUpgradeEveryMs() { 86 // Check for a value passed via the command line. 87 int interval_ms; 88 std::string interval = CmdLineInterval(); 89 if (!interval.empty() && base::StringToInt(interval, &interval_ms)) 90 return interval_ms * 1000; // Command line value is in seconds. 91 92 return kCheckForUpgradeMs; 93 } 94 95 // Return true if the current build is one of the unstable channels. 96 bool IsUnstableChannel() { 97 // TODO(mad): Investigate whether we still need to be on the file thread for 98 // this. On Windows, the file thread used to be required for registry access 99 // but no anymore. But other platform may still need the file thread. 100 // crbug.com/366647. 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 102 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); 103 return channel == chrome::VersionInfo::CHANNEL_DEV || 104 channel == chrome::VersionInfo::CHANNEL_CANARY; 105 } 106 107 // This task identifies whether we are running an unstable version. And then it 108 // unconditionally calls back the provided task. 109 void CheckForUnstableChannel(const base::Closure& callback_task, 110 bool* is_unstable_channel) { 111 *is_unstable_channel = IsUnstableChannel(); 112 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback_task); 113 } 114 115 #if defined(OS_WIN) 116 // Return true if the currently running Chrome is a system install. 117 bool IsSystemInstall() { 118 // Get the version of the currently *installed* instance of Chrome, 119 // which might be newer than the *running* instance if we have been 120 // upgraded in the background. 121 base::FilePath exe_path; 122 if (!PathService::Get(base::DIR_EXE, &exe_path)) { 123 NOTREACHED() << "Failed to find executable path"; 124 return false; 125 } 126 127 return !InstallUtil::IsPerUserInstall(exe_path.value().c_str()); 128 } 129 130 // Sets |is_unstable_channel| to true if the current chrome is on the dev or 131 // canary channels. Sets |is_auto_update_enabled| to true if Google Update will 132 // update the current chrome. Unconditionally posts |callback_task| to the UI 133 // thread to continue processing. 134 void DetectUpdatability(const base::Closure& callback_task, 135 bool* is_unstable_channel, 136 bool* is_auto_update_enabled) { 137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 138 139 base::string16 app_guid = installer::GetAppGuidForUpdates(IsSystemInstall()); 140 DCHECK(!app_guid.empty()); 141 // Don't try to turn on autoupdate when we failed previously. 142 if (is_auto_update_enabled) { 143 *is_auto_update_enabled = 144 GoogleUpdateSettings::AreAutoupdatesEnabled(app_guid); 145 } 146 *is_unstable_channel = IsUnstableChannel(); 147 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback_task); 148 } 149 #endif // defined(OS_WIN) 150 151 // Gets the currently installed version. On Windows, if |critical_update| is not 152 // NULL, also retrieves the critical update version info if available. 153 base::Version GetCurrentlyInstalledVersionImpl(Version* critical_update) { 154 base::ThreadRestrictions::AssertIOAllowed(); 155 156 Version installed_version; 157 #if defined(OS_WIN) 158 // Get the version of the currently *installed* instance of Chrome, 159 // which might be newer than the *running* instance if we have been 160 // upgraded in the background. 161 bool system_install = IsSystemInstall(); 162 163 // TODO(tommi): Check if using the default distribution is always the right 164 // thing to do. 165 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 166 InstallUtil::GetChromeVersion(dist, system_install, &installed_version); 167 if (critical_update && installed_version.IsValid()) { 168 InstallUtil::GetCriticalUpdateVersion(dist, system_install, 169 critical_update); 170 } 171 #elif defined(OS_MACOSX) 172 installed_version = 173 Version(base::UTF16ToASCII(keystone_glue::CurrentlyInstalledVersion())); 174 #elif defined(OS_POSIX) 175 // POSIX but not Mac OS X: Linux, etc. 176 CommandLine command_line(*CommandLine::ForCurrentProcess()); 177 command_line.AppendSwitch(switches::kProductVersion); 178 std::string reply; 179 if (!base::GetAppOutput(command_line, &reply)) { 180 DLOG(ERROR) << "Failed to get current file version"; 181 return installed_version; 182 } 183 184 installed_version = Version(reply); 185 #endif 186 return installed_version; 187 } 188 189 } // namespace 190 191 UpgradeDetectorImpl::UpgradeDetectorImpl() 192 : weak_factory_(this), 193 is_unstable_channel_(false), 194 is_auto_update_enabled_(true), 195 build_date_(base::GetBuildTime()) { 196 CommandLine command_line(*CommandLine::ForCurrentProcess()); 197 // The different command line switches that affect testing can't be used 198 // simultaneously, if they do, here's the precedence order, based on the order 199 // of the if statements below: 200 // - kDisableBackgroundNetworking prevents any of the other command line 201 // switch from being taken into account. 202 // - kSimulateUpgrade supersedes critical or outdated upgrade switches. 203 // - kSimulateCriticalUpdate has precedence over kSimulateOutdated. 204 // - kSimulateOutdatedNoAU has precedence over kSimulateOutdated. 205 // - kSimulateOutdated[NoAu] can work on its own, or with a specified date. 206 if (command_line.HasSwitch(switches::kDisableBackgroundNetworking)) 207 return; 208 if (command_line.HasSwitch(switches::kSimulateUpgrade)) { 209 UpgradeDetected(UPGRADE_AVAILABLE_REGULAR); 210 return; 211 } 212 if (command_line.HasSwitch(switches::kSimulateCriticalUpdate)) { 213 UpgradeDetected(UPGRADE_AVAILABLE_CRITICAL); 214 return; 215 } 216 if (SimulatingOutdated()) { 217 // The outdated simulation can work without a value, which means outdated 218 // now, or with a value that must be a well formed date/time string that 219 // overrides the build date. 220 // Also note that to test with a given time/date, until the network time 221 // tracking moves off of the VariationsService, the "variations-server-url" 222 // command line switch must also be specified for the service to be 223 // available on non GOOGLE_CHROME_BUILD. 224 std::string switch_name; 225 if (command_line.HasSwitch(switches::kSimulateOutdatedNoAU)) { 226 is_auto_update_enabled_ = false; 227 switch_name = switches::kSimulateOutdatedNoAU; 228 } else { 229 switch_name = switches::kSimulateOutdated; 230 } 231 std::string build_date = command_line.GetSwitchValueASCII(switch_name); 232 base::Time maybe_build_time; 233 bool result = base::Time::FromString(build_date.c_str(), &maybe_build_time); 234 if (result && !maybe_build_time.is_null()) { 235 // We got a valid build date simulation so use it and check for upgrades. 236 build_date_ = maybe_build_time; 237 StartTimerForUpgradeCheck(); 238 } else { 239 // Without a valid date, we simulate that we are already outdated... 240 UpgradeDetected( 241 is_auto_update_enabled_ ? UPGRADE_NEEDED_OUTDATED_INSTALL 242 : UPGRADE_NEEDED_OUTDATED_INSTALL_NO_AU); 243 } 244 return; 245 } 246 247 base::Closure start_upgrade_check_timer_task = 248 base::Bind(&UpgradeDetectorImpl::StartTimerForUpgradeCheck, 249 weak_factory_.GetWeakPtr()); 250 251 #if defined(OS_WIN) 252 // Only enable upgrade notifications for official builds. Chromium has no 253 // upgrade channel. 254 #if defined(GOOGLE_CHROME_BUILD) 255 // On Windows, there might be a policy/enterprise environment preventing 256 // updates, so validate updatability, and then call StartTimerForUpgradeCheck 257 // appropriately. And don't check for autoupdate if we already attempted to 258 // enable it in the past. 259 bool attempted_enabling_autoupdate = g_browser_process->local_state() && 260 g_browser_process->local_state()->GetBoolean( 261 prefs::kAttemptedToEnableAutoupdate); 262 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 263 base::Bind(&DetectUpdatability, 264 start_upgrade_check_timer_task, 265 &is_unstable_channel_, 266 attempted_enabling_autoupdate ? 267 NULL : &is_auto_update_enabled_)); 268 #endif 269 #else 270 #if defined(OS_MACOSX) 271 // Only enable upgrade notifications if the updater (Keystone) is present. 272 if (!keystone_glue::KeystoneEnabled()) { 273 is_auto_update_enabled_ = false; 274 return; 275 } 276 #elif defined(OS_POSIX) 277 // Always enable upgrade notifications regardless of branding. 278 #else 279 return; 280 #endif 281 // Check whether the build is an unstable channel before starting the timer. 282 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 283 base::Bind(&CheckForUnstableChannel, 284 start_upgrade_check_timer_task, 285 &is_unstable_channel_)); 286 #endif 287 } 288 289 UpgradeDetectorImpl::~UpgradeDetectorImpl() { 290 } 291 292 // static 293 base::Version UpgradeDetectorImpl::GetCurrentlyInstalledVersion() { 294 return GetCurrentlyInstalledVersionImpl(NULL); 295 } 296 297 // static 298 // This task checks the currently running version of Chrome against the 299 // installed version. If the installed version is newer, it calls back 300 // UpgradeDetectorImpl::UpgradeDetected using a weak pointer so that it can 301 // be interrupted from the UI thread. 302 void UpgradeDetectorImpl::DetectUpgradeTask( 303 base::WeakPtr<UpgradeDetectorImpl> upgrade_detector) { 304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 305 306 Version critical_update; 307 Version installed_version = 308 GetCurrentlyInstalledVersionImpl(&critical_update); 309 310 // Get the version of the currently *running* instance of Chrome. 311 chrome::VersionInfo version_info; 312 if (!version_info.is_valid()) { 313 NOTREACHED() << "Failed to get current file version"; 314 return; 315 } 316 Version running_version(version_info.Version()); 317 if (!running_version.IsValid()) { 318 NOTREACHED(); 319 return; 320 } 321 322 // |installed_version| may be NULL when the user downgrades on Linux (by 323 // switching from dev to beta channel, for example). The user needs a 324 // restart in this case as well. See http://crbug.com/46547 325 if (!installed_version.IsValid() || 326 (installed_version.CompareTo(running_version) > 0)) { 327 // If a more recent version is available, it might be that we are lacking 328 // a critical update, such as a zero-day fix. 329 UpgradeAvailable upgrade_available = UPGRADE_AVAILABLE_REGULAR; 330 if (critical_update.IsValid() && 331 critical_update.CompareTo(running_version) > 0) { 332 upgrade_available = UPGRADE_AVAILABLE_CRITICAL; 333 } 334 335 // Fire off the upgrade detected task. 336 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 337 base::Bind(&UpgradeDetectorImpl::UpgradeDetected, 338 upgrade_detector, 339 upgrade_available)); 340 } 341 } 342 343 void UpgradeDetectorImpl::StartTimerForUpgradeCheck() { 344 detect_upgrade_timer_.Start(FROM_HERE, 345 base::TimeDelta::FromMilliseconds(GetCheckForUpgradeEveryMs()), 346 this, &UpgradeDetectorImpl::CheckForUpgrade); 347 } 348 349 void UpgradeDetectorImpl::CheckForUpgrade() { 350 // Interrupt any (unlikely) unfinished execution of DetectUpgradeTask, or at 351 // least prevent the callback from being executed, because we will potentially 352 // call it from within DetectOutdatedInstall() or will post 353 // DetectUpgradeTask again below anyway. 354 weak_factory_.InvalidateWeakPtrs(); 355 356 // No need to look for upgrades if the install is outdated. 357 if (DetectOutdatedInstall()) 358 return; 359 360 // We use FILE as the thread to run the upgrade detection code on all 361 // platforms. For Linux, this is because we don't want to block the UI thread 362 // while launching a background process and reading its output; on the Mac and 363 // on Windows checking for an upgrade requires reading a file. 364 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 365 base::Bind(&UpgradeDetectorImpl::DetectUpgradeTask, 366 weak_factory_.GetWeakPtr())); 367 } 368 369 bool UpgradeDetectorImpl::DetectOutdatedInstall() { 370 // Don't show the bubble if we have a brand code that is NOT organic, unless 371 // an outdated build is being simulated by command line switches. 372 static bool simulate_outdated = SimulatingOutdated(); 373 if (!simulate_outdated) { 374 std::string brand; 375 if (google_brand::GetBrand(&brand) && !google_brand::IsOrganic(brand)) 376 return false; 377 378 #if defined(OS_WIN) 379 // Don't show the update bubbles to entreprise users (i.e., on a domain). 380 if (base::win::IsEnrolledToDomain()) 381 return false; 382 383 // On Windows, we don't want to warn about outdated installs when the 384 // machine doesn't support SSE2, it's been deprecated starting with M35. 385 if (!base::CPU().has_sse2()) 386 return false; 387 #endif 388 } 389 390 base::Time network_time; 391 base::TimeDelta uncertainty; 392 if (!g_browser_process->network_time_tracker()->GetNetworkTime( 393 base::TimeTicks::Now(), &network_time, &uncertainty)) { 394 // When network time has not been initialized yet, simply rely on the 395 // machine's current time. 396 network_time = base::Time::Now(); 397 } 398 399 if (network_time.is_null() || build_date_.is_null() || 400 build_date_ > network_time) { 401 NOTREACHED(); 402 return false; 403 } 404 405 if (network_time - build_date_ > 406 base::TimeDelta::FromDays(kOutdatedBuildAgeInDays)) { 407 UpgradeDetected(is_auto_update_enabled_ ? 408 UPGRADE_NEEDED_OUTDATED_INSTALL : 409 UPGRADE_NEEDED_OUTDATED_INSTALL_NO_AU); 410 return true; 411 } 412 // If we simlated an outdated install with a date, we don't want to keep 413 // checking for version upgrades, which happens on non-official builds. 414 return simulate_outdated; 415 } 416 417 void UpgradeDetectorImpl::UpgradeDetected(UpgradeAvailable upgrade_available) { 418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 419 upgrade_available_ = upgrade_available; 420 421 // Stop the recurring timer (that is checking for changes). 422 detect_upgrade_timer_.Stop(); 423 424 NotifyUpgradeDetected(); 425 426 // Start the repeating timer for notifying the user after a certain period. 427 // The called function will eventually figure out that enough time has passed 428 // and stop the timer. 429 int cycle_time = IsTesting() ? 430 kNotifyCycleTimeForTestingMs : kNotifyCycleTimeMs; 431 upgrade_notification_timer_.Start(FROM_HERE, 432 base::TimeDelta::FromMilliseconds(cycle_time), 433 this, &UpgradeDetectorImpl::NotifyOnUpgrade); 434 } 435 436 void UpgradeDetectorImpl::NotifyOnUpgrade() { 437 base::TimeDelta delta = base::Time::Now() - upgrade_detected_time(); 438 439 // We'll make testing more convenient by switching to seconds of waiting 440 // instead of days between flipping severity. 441 bool is_testing = IsTesting(); 442 int64 time_passed = is_testing ? delta.InSeconds() : delta.InHours(); 443 444 bool is_critical_or_outdated = upgrade_available_ > UPGRADE_AVAILABLE_REGULAR; 445 if (is_unstable_channel_) { 446 // There's only one threat level for unstable channels like dev and 447 // canary, and it hits after one hour. During testing, it hits after one 448 // second. 449 const int kUnstableThreshold = 1; 450 451 if (is_critical_or_outdated) { 452 set_upgrade_notification_stage(UPGRADE_ANNOYANCE_CRITICAL); 453 } else if (time_passed >= kUnstableThreshold) { 454 set_upgrade_notification_stage(UPGRADE_ANNOYANCE_LOW); 455 456 // That's as high as it goes. 457 upgrade_notification_timer_.Stop(); 458 } else { 459 return; // Not ready to recommend upgrade. 460 } 461 } else { 462 const int kMultiplier = is_testing ? 10 : 24; 463 // 14 days when not testing, otherwise 14 seconds. 464 const int kSevereThreshold = 14 * kMultiplier; 465 const int kHighThreshold = 7 * kMultiplier; 466 const int kElevatedThreshold = 4 * kMultiplier; 467 const int kLowThreshold = 2 * kMultiplier; 468 469 // These if statements must be sorted (highest interval first). 470 if (time_passed >= kSevereThreshold || is_critical_or_outdated) { 471 set_upgrade_notification_stage( 472 is_critical_or_outdated ? UPGRADE_ANNOYANCE_CRITICAL : 473 UPGRADE_ANNOYANCE_SEVERE); 474 475 // We can't get any higher, baby. 476 upgrade_notification_timer_.Stop(); 477 } else if (time_passed >= kHighThreshold) { 478 set_upgrade_notification_stage(UPGRADE_ANNOYANCE_HIGH); 479 } else if (time_passed >= kElevatedThreshold) { 480 set_upgrade_notification_stage(UPGRADE_ANNOYANCE_ELEVATED); 481 } else if (time_passed >= kLowThreshold) { 482 set_upgrade_notification_stage(UPGRADE_ANNOYANCE_LOW); 483 } else { 484 return; // Not ready to recommend upgrade. 485 } 486 } 487 488 NotifyUpgradeRecommended(); 489 } 490 491 // static 492 UpgradeDetectorImpl* UpgradeDetectorImpl::GetInstance() { 493 return Singleton<UpgradeDetectorImpl>::get(); 494 } 495 496 // static 497 UpgradeDetector* UpgradeDetector::GetInstance() { 498 return UpgradeDetectorImpl::GetInstance(); 499 } 500