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
48namespace chromeos {
49namespace system {
50
51namespace {
52
53const int kMinRebootUptimeMs = 60 * 60 * 1000;     // 1 hour.
54const int kLoginManagerIdleTimeoutMs = 60 * 1000;  // 60 seconds.
55const int kGracePeriodMs = 24 * 60 * 60 * 1000;    // 24 hours.
56const int kOneKilobyte = 1 << 10;                  // 1 kB in bytes.
57
58base::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
79void 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
94void 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
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 (!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
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::SuspendDone(
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 (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
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 && user_manager::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 (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