Home | History | Annotate | Download | only in system
      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 "base/bind.h"
     16 #include "base/bind_helpers.h"
     17 #include "base/callback.h"
     18 #include "base/files/file_path.h"
     19 #include "base/files/file_util.h"
     20 #include "base/files/scoped_file.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/system/automatic_reboot_manager_observer.h"
     37 #include "chrome/common/pref_names.h"
     38 #include "chromeos/chromeos_paths.h"
     39 #include "chromeos/chromeos_switches.h"
     40 #include "chromeos/dbus/dbus_thread_manager.h"
     41 #include "components/user_manager/user_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 #include "ui/wm/core/user_activity_detector.h"
     47 
     48 namespace chromeos {
     49 namespace system {
     50 
     51 namespace {
     52 
     53 const int kMinRebootUptimeMs = 60 * 60 * 1000;     // 1 hour.
     54 const int kLoginManagerIdleTimeoutMs = 60 * 1000;  // 60 seconds.
     55 const int kGracePeriodMs = 24 * 60 * 60 * 1000;    // 24 hours.
     56 const int kOneKilobyte = 1 << 10;                  // 1 kB in bytes.
     57 
     58 base::TimeDelta ReadTimeDeltaFromFile(const base::FilePath& path) {
     59   base::ThreadRestrictions::AssertIOAllowed();
     60   base::ScopedFD fd(
     61       HANDLE_EINTR(open(path.value().c_str(), O_RDONLY | O_NOFOLLOW)));
     62   if (!fd.is_valid())
     63     return base::TimeDelta();
     64 
     65   std::string contents;
     66   char buffer[kOneKilobyte];
     67   ssize_t length;
     68   while ((length = HANDLE_EINTR(read(fd.get(), buffer, sizeof(buffer)))) > 0)
     69     contents.append(buffer, length);
     70 
     71   double seconds;
     72   if (!base::StringToDouble(contents.substr(0, contents.find(' ')), &seconds) ||
     73       seconds < 0.0) {
     74     return base::TimeDelta();
     75   }
     76   return base::TimeDelta::FromMilliseconds(seconds * 1000.0);
     77 }
     78 
     79 void GetSystemEventTimes(
     80     scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,
     81     base::Callback<void(
     82         const AutomaticRebootManager::SystemEventTimes&)> reply) {
     83   base::FilePath uptime_file;
     84   CHECK(PathService::Get(chromeos::FILE_UPTIME, &uptime_file));
     85   base::FilePath update_reboot_needed_uptime_file;
     86   CHECK(PathService::Get(chromeos::FILE_UPDATE_REBOOT_NEEDED_UPTIME,
     87                          &update_reboot_needed_uptime_file));
     88   reply_task_runner->PostTask(FROM_HERE, base::Bind(reply,
     89       AutomaticRebootManager::SystemEventTimes(
     90           ReadTimeDeltaFromFile(uptime_file),
     91           ReadTimeDeltaFromFile(update_reboot_needed_uptime_file))));
     92 }
     93 
     94 void SaveUpdateRebootNeededUptime() {
     95   base::ThreadRestrictions::AssertIOAllowed();
     96   const base::TimeDelta kZeroTimeDelta;
     97 
     98   base::FilePath update_reboot_needed_uptime_file;
     99   CHECK(PathService::Get(chromeos::FILE_UPDATE_REBOOT_NEEDED_UPTIME,
    100                          &update_reboot_needed_uptime_file));
    101   const base::TimeDelta last_update_reboot_needed_uptime =
    102       ReadTimeDeltaFromFile(update_reboot_needed_uptime_file);
    103   if (last_update_reboot_needed_uptime != kZeroTimeDelta)
    104     return;
    105 
    106   base::FilePath uptime_file;
    107   CHECK(PathService::Get(chromeos::FILE_UPTIME, &uptime_file));
    108   const base::TimeDelta uptime = ReadTimeDeltaFromFile(uptime_file);
    109   if (uptime == kZeroTimeDelta)
    110     return;
    111 
    112   base::ScopedFD fd(HANDLE_EINTR(
    113       open(update_reboot_needed_uptime_file.value().c_str(),
    114            O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW,
    115            0666)));
    116   if (!fd.is_valid())
    117     return;
    118 
    119   std::string update_reboot_needed_uptime =
    120       base::DoubleToString(uptime.InSecondsF());
    121   base::WriteFileDescriptor(fd.get(), update_reboot_needed_uptime.c_str(),
    122                             update_reboot_needed_uptime.size());
    123 }
    124 
    125 }  // namespace
    126 
    127 AutomaticRebootManager::SystemEventTimes::SystemEventTimes()
    128     : has_boot_time(false),
    129       has_update_reboot_needed_time(false) {
    130 }
    131 
    132 AutomaticRebootManager::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 
    150 AutomaticRebootManager::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 (!user_manager::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 
    197 AutomaticRebootManager::~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 
    209 void AutomaticRebootManager::AddObserver(
    210     AutomaticRebootManagerObserver* observer) {
    211   observers_.AddObserver(observer);
    212 }
    213 
    214 void AutomaticRebootManager::RemoveObserver(
    215     AutomaticRebootManagerObserver* observer) {
    216   observers_.RemoveObserver(observer);
    217 }
    218 
    219 void AutomaticRebootManager::SuspendDone(
    220     const base::TimeDelta& sleep_duration) {
    221   MaybeReboot(true);
    222 }
    223 
    224 void 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 
    243 void 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 
    260 void AutomaticRebootManager::Observe(
    261     int type,
    262     const content::NotificationSource& source,
    263     const content::NotificationDetails& details) {
    264   if (type == chrome::NOTIFICATION_APP_TERMINATING) {
    265     if (user_manager::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
    285 void AutomaticRebootManager::RegisterPrefs(PrefRegistrySimple* registry) {
    286   registry->RegisterIntegerPref(prefs::kUptimeLimit, 0);
    287   registry->RegisterBooleanPref(prefs::kRebootAfterUpdate, false);
    288 }
    289 
    290 void 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 
    311 void 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 
    386 void AutomaticRebootManager::RequestReboot() {
    387   reboot_requested_ = true;
    388   MaybeReboot(false);
    389 }
    390 
    391 void 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 && user_manager::UserManager::Get()->IsUserLoggedIn())) {
    399     return;
    400   }
    401 
    402   Reboot();
    403 }
    404 
    405 void AutomaticRebootManager::Reboot() {
    406   // If a non-kiosk-app session is in progress, do not reboot.
    407   if (user_manager::UserManager::Get()->IsUserLoggedIn() &&
    408       !user_manager::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