1// Copyright (c) 2013 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/chromeos/system/automatic_reboot_manager.h" 6 7#include <fcntl.h> 8#include <sys/stat.h> 9#include <sys/types.h> 10 11#include <algorithm> 12#include <string> 13 14#include "ash/shell.h" 15#include "ash/wm/user_activity_detector.h" 16#include "base/bind.h" 17#include "base/bind_helpers.h" 18#include "base/callback.h" 19#include "base/file_util.h" 20#include "base/files/file_path.h" 21#include "base/location.h" 22#include "base/logging.h" 23#include "base/memory/ref_counted.h" 24#include "base/path_service.h" 25#include "base/posix/eintr_wrapper.h" 26#include "base/prefs/pref_registry_simple.h" 27#include "base/prefs/pref_service.h" 28#include "base/single_thread_task_runner.h" 29#include "base/strings/string_number_conversions.h" 30#include "base/thread_task_runner_handle.h" 31#include "base/threading/sequenced_worker_pool.h" 32#include "base/threading/thread_restrictions.h" 33#include "base/time/tick_clock.h" 34#include "chrome/browser/browser_process.h" 35#include "chrome/browser/chrome_notification_types.h" 36#include "chrome/browser/chromeos/login/user_manager.h" 37#include "chrome/browser/chromeos/system/automatic_reboot_manager_observer.h" 38#include "chrome/common/pref_names.h" 39#include "chromeos/chromeos_paths.h" 40#include "chromeos/chromeos_switches.h" 41#include "chromeos/dbus/dbus_thread_manager.h" 42#include "content/public/browser/browser_thread.h" 43#include "content/public/browser/notification_details.h" 44#include "content/public/browser/notification_service.h" 45#include "content/public/browser/notification_source.h" 46 47namespace chromeos { 48namespace system { 49 50namespace { 51 52const int kMinRebootUptimeMs = 60 * 60 * 1000; // 1 hour. 53const int kLoginManagerIdleTimeoutMs = 60 * 1000; // 60 seconds. 54const int kGracePeriodMs = 24 * 60 * 60 * 1000; // 24 hours. 55const int kOneKilobyte = 1 << 10; // 1 kB in bytes. 56 57base::TimeDelta ReadTimeDeltaFromFile(const base::FilePath& path) { 58 base::ThreadRestrictions::AssertIOAllowed(); 59 int fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY | O_NOFOLLOW)); 60 if (fd < 0) 61 return base::TimeDelta(); 62 file_util::ScopedFD fd_closer(&fd); 63 64 std::string contents; 65 char buffer[kOneKilobyte]; 66 ssize_t length; 67 while ((length = read(fd, buffer, sizeof(buffer))) > 0) 68 contents.append(buffer, length); 69 70 double seconds; 71 if (!base::StringToDouble(contents.substr(0, contents.find(' ')), &seconds) || 72 seconds < 0.0) { 73 return base::TimeDelta(); 74 } 75 return base::TimeDelta::FromMilliseconds(seconds * 1000.0); 76} 77 78void GetSystemEventTimes( 79 scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner, 80 base::Callback<void( 81 const AutomaticRebootManager::SystemEventTimes&)> reply) { 82 base::FilePath uptime_file; 83 CHECK(PathService::Get(chromeos::FILE_UPTIME, &uptime_file)); 84 base::FilePath update_reboot_needed_uptime_file; 85 CHECK(PathService::Get(chromeos::FILE_UPDATE_REBOOT_NEEDED_UPTIME, 86 &update_reboot_needed_uptime_file)); 87 reply_task_runner->PostTask(FROM_HERE, base::Bind(reply, 88 AutomaticRebootManager::SystemEventTimes( 89 ReadTimeDeltaFromFile(uptime_file), 90 ReadTimeDeltaFromFile(update_reboot_needed_uptime_file)))); 91} 92 93void SaveUpdateRebootNeededUptime() { 94 base::ThreadRestrictions::AssertIOAllowed(); 95 const base::TimeDelta kZeroTimeDelta; 96 97 base::FilePath update_reboot_needed_uptime_file; 98 CHECK(PathService::Get(chromeos::FILE_UPDATE_REBOOT_NEEDED_UPTIME, 99 &update_reboot_needed_uptime_file)); 100 const base::TimeDelta last_update_reboot_needed_uptime = 101 ReadTimeDeltaFromFile(update_reboot_needed_uptime_file); 102 if (last_update_reboot_needed_uptime != kZeroTimeDelta) 103 return; 104 105 base::FilePath uptime_file; 106 CHECK(PathService::Get(chromeos::FILE_UPTIME, &uptime_file)); 107 const base::TimeDelta uptime = ReadTimeDeltaFromFile(uptime_file); 108 if (uptime == kZeroTimeDelta) 109 return; 110 111 int fd = HANDLE_EINTR(open(update_reboot_needed_uptime_file.value().c_str(), 112 O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 113 0666)); 114 if (fd < 0) 115 return; 116 file_util::ScopedFD fd_closer(&fd); 117 118 std::string update_reboot_needed_uptime = 119 base::DoubleToString(uptime.InSecondsF()); 120 file_util::WriteFileDescriptor(fd, 121 update_reboot_needed_uptime.c_str(), 122 update_reboot_needed_uptime.size()); 123} 124 125} // namespace 126 127AutomaticRebootManager::SystemEventTimes::SystemEventTimes() 128 : has_boot_time(false), 129 has_update_reboot_needed_time(false) { 130} 131 132AutomaticRebootManager::SystemEventTimes::SystemEventTimes( 133 const base::TimeDelta& uptime, 134 const base::TimeDelta& update_reboot_needed_uptime) 135 : has_boot_time(false), 136 has_update_reboot_needed_time(false) { 137 const base::TimeDelta kZeroTimeDelta; 138 if (uptime == kZeroTimeDelta) 139 return; 140 boot_time = base::TimeTicks::Now() - uptime; 141 has_boot_time = true; 142 if (update_reboot_needed_uptime == kZeroTimeDelta) 143 return; 144 // Calculate the time at which an update was applied and a reboot became 145 // necessary in base::TimeTicks::Now() ticks. 146 update_reboot_needed_time = boot_time + update_reboot_needed_uptime; 147 has_update_reboot_needed_time = true; 148} 149 150AutomaticRebootManager::AutomaticRebootManager( 151 scoped_ptr<base::TickClock> clock) 152 : clock_(clock.Pass()), 153 have_boot_time_(false), 154 have_update_reboot_needed_time_(false), 155 reboot_requested_(false), 156 weak_ptr_factory_(this) { 157 local_state_registrar_.Init(g_browser_process->local_state()); 158 local_state_registrar_.Add(prefs::kUptimeLimit, 159 base::Bind(&AutomaticRebootManager::Reschedule, 160 base::Unretained(this))); 161 local_state_registrar_.Add(prefs::kRebootAfterUpdate, 162 base::Bind(&AutomaticRebootManager::Reschedule, 163 base::Unretained(this))); 164 notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, 165 content::NotificationService::AllSources()); 166 167 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get(); 168 dbus_thread_manager->GetPowerManagerClient()->AddObserver(this); 169 dbus_thread_manager->GetUpdateEngineClient()->AddObserver(this); 170 171 // If no user is logged in, a reboot may be performed whenever the user is 172 // idle. Start listening for user activity to determine whether the user is 173 // idle or not. 174 if (!UserManager::Get()->IsUserLoggedIn()) { 175 if (ash::Shell::HasInstance()) 176 ash::Shell::GetInstance()->user_activity_detector()->AddObserver(this); 177 notification_registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED, 178 content::NotificationService::AllSources()); 179 login_screen_idle_timer_.reset( 180 new base::OneShotTimer<AutomaticRebootManager>); 181 OnUserActivity(NULL); 182 } 183 184 // In a regular browser, base::ThreadTaskRunnerHandle::Get() and 185 // base::MessageLoopProxy::current() return pointers to the same object. 186 // In unit tests, using base::ThreadTaskRunnerHandle::Get() has the advantage 187 // that it allows a custom base::SingleThreadTaskRunner to be injected. 188 content::BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( 189 FROM_HERE, 190 base::Bind(&GetSystemEventTimes, 191 base::ThreadTaskRunnerHandle::Get(), 192 base::Bind(&AutomaticRebootManager::Init, 193 weak_ptr_factory_.GetWeakPtr())), 194 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); 195} 196 197AutomaticRebootManager::~AutomaticRebootManager() { 198 FOR_EACH_OBSERVER(AutomaticRebootManagerObserver, 199 observers_, 200 WillDestroyAutomaticRebootManager()); 201 202 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get(); 203 dbus_thread_manager->GetPowerManagerClient()->RemoveObserver(this); 204 dbus_thread_manager->GetUpdateEngineClient()->RemoveObserver(this); 205 if (ash::Shell::HasInstance()) 206 ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this); 207} 208 209void AutomaticRebootManager::AddObserver( 210 AutomaticRebootManagerObserver* observer) { 211 observers_.AddObserver(observer); 212} 213 214void AutomaticRebootManager::RemoveObserver( 215 AutomaticRebootManagerObserver* observer) { 216 observers_.RemoveObserver(observer); 217} 218 219void AutomaticRebootManager::SystemResumed( 220 const base::TimeDelta& sleep_duration) { 221 MaybeReboot(true); 222} 223 224void AutomaticRebootManager::UpdateStatusChanged( 225 const UpdateEngineClient::Status& status) { 226 // Ignore repeated notifications that a reboot is necessary. This is important 227 // so that only the time of the first notification is taken into account and 228 // repeated notifications do not postpone the reboot request and grace period. 229 if (status.status != UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT || 230 !have_boot_time_ || have_update_reboot_needed_time_) { 231 return; 232 } 233 234 content::BrowserThread::PostBlockingPoolTask( 235 FROM_HERE, base::Bind(&SaveUpdateRebootNeededUptime)); 236 237 update_reboot_needed_time_ = clock_->NowTicks(); 238 have_update_reboot_needed_time_ = true; 239 240 Reschedule(); 241} 242 243void AutomaticRebootManager::OnUserActivity(const ui::Event* event) { 244 if (!login_screen_idle_timer_) 245 return; 246 247 // Destroying and re-creating the timer ensures that Start() posts a fresh 248 // task with a delay of exactly |kLoginManagerIdleTimeoutMs|, ensuring that 249 // the timer fires predictably in tests. 250 login_screen_idle_timer_.reset( 251 new base::OneShotTimer<AutomaticRebootManager>); 252 login_screen_idle_timer_->Start( 253 FROM_HERE, 254 base::TimeDelta::FromMilliseconds(kLoginManagerIdleTimeoutMs), 255 base::Bind(&AutomaticRebootManager::MaybeReboot, 256 base::Unretained(this), 257 false)); 258} 259 260void AutomaticRebootManager::Observe( 261 int type, 262 const content::NotificationSource& source, 263 const content::NotificationDetails& details) { 264 if (type == chrome::NOTIFICATION_APP_TERMINATING) { 265 if (UserManager::Get()->IsUserLoggedIn()) { 266 // The browser is terminating during a session, either because the session 267 // is ending or because the browser is being restarted. 268 MaybeReboot(true); 269 } 270 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED) { 271 // A session is starting. Stop listening for user activity as it no longer 272 // is a relevant criterion. 273 if (ash::Shell::HasInstance()) 274 ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this); 275 notification_registrar_.Remove( 276 this, chrome::NOTIFICATION_LOGIN_USER_CHANGED, 277 content::NotificationService::AllSources()); 278 login_screen_idle_timer_.reset(); 279 } else { 280 NOTREACHED(); 281 } 282} 283 284// static 285void AutomaticRebootManager::RegisterPrefs(PrefRegistrySimple* registry) { 286 registry->RegisterIntegerPref(prefs::kUptimeLimit, 0); 287 registry->RegisterBooleanPref(prefs::kRebootAfterUpdate, false); 288} 289 290void AutomaticRebootManager::Init(const SystemEventTimes& system_event_times) { 291 const base::TimeDelta offset = clock_->NowTicks() - base::TimeTicks::Now(); 292 if (system_event_times.has_boot_time) { 293 // Convert the time at which the device was booted to |clock_| ticks. 294 boot_time_ = system_event_times.boot_time + offset; 295 have_boot_time_ = true; 296 } 297 if (system_event_times.has_update_reboot_needed_time) { 298 // Convert the time at which a reboot became necessary to |clock_| ticks. 299 const base::TimeTicks update_reboot_needed_time = 300 system_event_times.update_reboot_needed_time + offset; 301 update_reboot_needed_time_ = update_reboot_needed_time; 302 have_update_reboot_needed_time_ = true; 303 } else { 304 UpdateStatusChanged( 305 DBusThreadManager::Get()->GetUpdateEngineClient()->GetLastStatus()); 306 } 307 308 Reschedule(); 309} 310 311void AutomaticRebootManager::Reschedule() { 312 // Safeguard against reboot loops under error conditions: If the boot time is 313 // unavailable because /proc/uptime could not be read, do nothing. 314 if (!have_boot_time_) 315 return; 316 317 // Assume that no reboot has been requested. 318 reboot_requested_ = false; 319 320 const base::TimeDelta kZeroTimeDelta; 321 AutomaticRebootManagerObserver::Reason reboot_reason = 322 AutomaticRebootManagerObserver::REBOOT_REASON_UNKNOWN; 323 324 // If an uptime limit is set, calculate the time at which it should cause a 325 // reboot to be requested. 326 const base::TimeDelta uptime_limit = base::TimeDelta::FromSeconds( 327 local_state_registrar_.prefs()->GetInteger(prefs::kUptimeLimit)); 328 base::TimeTicks reboot_request_time = boot_time_ + uptime_limit; 329 bool have_reboot_request_time = uptime_limit != kZeroTimeDelta; 330 if (have_reboot_request_time) 331 reboot_reason = AutomaticRebootManagerObserver::REBOOT_REASON_PERIODIC; 332 333 // If the policy to automatically reboot after an update is enabled and an 334 // update has been applied, set the time at which a reboot should be 335 // requested to the minimum of its current value and the time when the reboot 336 // became necessary. 337 if (have_update_reboot_needed_time_ && 338 local_state_registrar_.prefs()->GetBoolean(prefs::kRebootAfterUpdate) && 339 (!have_reboot_request_time || 340 update_reboot_needed_time_ < reboot_request_time)) { 341 reboot_request_time = update_reboot_needed_time_; 342 have_reboot_request_time = true; 343 reboot_reason = AutomaticRebootManagerObserver::REBOOT_REASON_OS_UPDATE; 344 } 345 346 // If no reboot should be requested, remove any grace period. 347 if (!have_reboot_request_time) { 348 grace_start_timer_.reset(); 349 grace_end_timer_.reset(); 350 return; 351 } 352 353 // Safeguard against reboot loops: Ensure that the uptime after which a reboot 354 // is actually requested and the grace period begins is never less than 355 // |kMinRebootUptimeMs|. 356 const base::TimeTicks now = clock_->NowTicks(); 357 const base::TimeTicks grace_start_time = std::max(reboot_request_time, 358 boot_time_ + base::TimeDelta::FromMilliseconds(kMinRebootUptimeMs)); 359 // Set up a timer for the start of the grace period. If the grace period 360 // started in the past, the timer is still used with its delay set to zero. 361 if (!grace_start_timer_) 362 grace_start_timer_.reset(new base::OneShotTimer<AutomaticRebootManager>); 363 grace_start_timer_->Start(FROM_HERE, 364 std::max(grace_start_time - now, kZeroTimeDelta), 365 base::Bind(&AutomaticRebootManager::RequestReboot, 366 base::Unretained(this))); 367 368 const base::TimeTicks grace_end_time = grace_start_time + 369 base::TimeDelta::FromMilliseconds(kGracePeriodMs); 370 // Set up a timer for the end of the grace period. If the grace period ended 371 // in the past, the timer is still used with its delay set to zero. 372 if (!grace_end_timer_) 373 grace_end_timer_.reset(new base::OneShotTimer<AutomaticRebootManager>); 374 grace_end_timer_->Start(FROM_HERE, 375 std::max(grace_end_time - now, kZeroTimeDelta), 376 base::Bind(&AutomaticRebootManager::Reboot, 377 base::Unretained(this))); 378 379 DCHECK_NE(AutomaticRebootManagerObserver::REBOOT_REASON_UNKNOWN, 380 reboot_reason); 381 FOR_EACH_OBSERVER(AutomaticRebootManagerObserver, 382 observers_, 383 OnRebootScheduled(reboot_reason)); 384} 385 386void AutomaticRebootManager::RequestReboot() { 387 reboot_requested_ = true; 388 MaybeReboot(false); 389} 390 391void AutomaticRebootManager::MaybeReboot(bool ignore_session) { 392 // Do not reboot if any of the following applies: 393 // * No reboot has been requested. 394 // * A user is interacting with the login screen. 395 // * A session is in progress and |ignore_session| is not set. 396 if (!reboot_requested_ || 397 (login_screen_idle_timer_ && login_screen_idle_timer_->IsRunning()) || 398 (!ignore_session && UserManager::Get()->IsUserLoggedIn())) { 399 return; 400 } 401 402 Reboot(); 403} 404 405void AutomaticRebootManager::Reboot() { 406 // If a non-kiosk-app session is in progress, do not reboot. 407 if (UserManager::Get()->IsUserLoggedIn() && 408 !UserManager::Get()->IsLoggedInAsKioskApp()) { 409 return; 410 } 411 412 login_screen_idle_timer_.reset(); 413 grace_start_timer_.reset(); 414 grace_end_timer_.reset(); 415 DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); 416} 417 418} // namespace system 419} // namespace chromeos 420