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