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.
5 #include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
14 #include "base/bind.h"
15 #include "base/bind_helpers.h"
16 #include "base/callback.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/files/scoped_file.h"
20 #include "base/location.h"
21 #include "base/logging.h"
22 #include "base/memory/ref_counted.h"
23 #include "base/message_loop/message_loop.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/common/pref_names.h"
37 #include "chromeos/chromeos_paths.h"
38 #include "chromeos/chromeos_switches.h"
39 #include "chromeos/dbus/dbus_thread_manager.h"
40 #include "components/user_manager/user_manager.h"
41 #include "content/public/browser/browser_thread.h"
42 #include "content/public/browser/notification_details.h"
43 #include "content/public/browser/notification_service.h"
44 #include "content/public/browser/notification_source.h"
45 #include "ui/base/user_activity/user_activity_detector.h"
52 const int kMinRebootUptimeMs
= 60 * 60 * 1000; // 1 hour.
53 const int kLoginManagerIdleTimeoutMs
= 60 * 1000; // 60 seconds.
54 const int kGracePeriodMs
= 24 * 60 * 60 * 1000; // 24 hours.
55 const int kOneKilobyte
= 1 << 10; // 1 kB in bytes.
57 const char kSequenceToken
[] = "automatic-reboot-manager";
59 base::TimeDelta
ReadTimeDeltaFromFile(const base::FilePath
& path
) {
60 base::ThreadRestrictions::AssertIOAllowed();
62 HANDLE_EINTR(open(path
.value().c_str(), O_RDONLY
| O_NOFOLLOW
)));
64 return base::TimeDelta();
67 char buffer
[kOneKilobyte
];
69 while ((length
= HANDLE_EINTR(read(fd
.get(), buffer
, sizeof(buffer
)))) > 0)
70 contents
.append(buffer
, length
);
73 if (!base::StringToDouble(contents
.substr(0, contents
.find(' ')), &seconds
) ||
75 return base::TimeDelta();
77 return base::TimeDelta::FromMilliseconds(seconds
* 1000.0);
80 void GetSystemEventTimes(
81 scoped_refptr
<base::SingleThreadTaskRunner
> reply_task_runner
,
83 const AutomaticRebootManager::SystemEventTimes
&)> reply
) {
84 base::FilePath uptime_file
;
85 CHECK(PathService::Get(chromeos::FILE_UPTIME
, &uptime_file
));
86 base::FilePath update_reboot_needed_uptime_file
;
87 CHECK(PathService::Get(chromeos::FILE_UPDATE_REBOOT_NEEDED_UPTIME
,
88 &update_reboot_needed_uptime_file
));
89 reply_task_runner
->PostTask(FROM_HERE
, base::Bind(reply
,
90 AutomaticRebootManager::SystemEventTimes(
91 ReadTimeDeltaFromFile(uptime_file
),
92 ReadTimeDeltaFromFile(update_reboot_needed_uptime_file
))));
95 void SaveUpdateRebootNeededUptime() {
96 base::ThreadRestrictions::AssertIOAllowed();
97 const base::TimeDelta kZeroTimeDelta
;
99 base::FilePath update_reboot_needed_uptime_file
;
100 CHECK(PathService::Get(chromeos::FILE_UPDATE_REBOOT_NEEDED_UPTIME
,
101 &update_reboot_needed_uptime_file
));
102 const base::TimeDelta last_update_reboot_needed_uptime
=
103 ReadTimeDeltaFromFile(update_reboot_needed_uptime_file
);
104 if (last_update_reboot_needed_uptime
!= kZeroTimeDelta
)
107 base::FilePath uptime_file
;
108 CHECK(PathService::Get(chromeos::FILE_UPTIME
, &uptime_file
));
109 const base::TimeDelta uptime
= ReadTimeDeltaFromFile(uptime_file
);
110 if (uptime
== kZeroTimeDelta
)
113 base::ScopedFD
fd(HANDLE_EINTR(
114 open(update_reboot_needed_uptime_file
.value().c_str(),
115 O_CREAT
| O_WRONLY
| O_TRUNC
| O_NOFOLLOW
,
120 std::string update_reboot_needed_uptime
=
121 base::DoubleToString(uptime
.InSecondsF());
122 base::WriteFileDescriptor(fd
.get(), update_reboot_needed_uptime
.c_str(),
123 update_reboot_needed_uptime
.size());
128 AutomaticRebootManager::SystemEventTimes::SystemEventTimes()
129 : has_boot_time(false),
130 has_update_reboot_needed_time(false) {
133 AutomaticRebootManager::SystemEventTimes::SystemEventTimes(
134 const base::TimeDelta
& uptime
,
135 const base::TimeDelta
& update_reboot_needed_uptime
)
136 : has_boot_time(false),
137 has_update_reboot_needed_time(false) {
138 const base::TimeDelta kZeroTimeDelta
;
139 if (uptime
== kZeroTimeDelta
)
141 boot_time
= base::TimeTicks::Now() - uptime
;
142 has_boot_time
= true;
143 if (update_reboot_needed_uptime
== kZeroTimeDelta
)
145 // Calculate the time at which an update was applied and a reboot became
146 // necessary in base::TimeTicks::Now() ticks.
147 update_reboot_needed_time
= boot_time
+ update_reboot_needed_uptime
;
148 has_update_reboot_needed_time
= true;
151 AutomaticRebootManager::AutomaticRebootManager(
152 scoped_ptr
<base::TickClock
> clock
)
153 : clock_(clock
.Pass()),
154 have_boot_time_(false),
155 have_update_reboot_needed_time_(false),
156 reboot_reason_(AutomaticRebootManagerObserver::REBOOT_REASON_UNKNOWN
),
157 reboot_requested_(false),
158 weak_ptr_factory_(this) {
159 local_state_registrar_
.Init(g_browser_process
->local_state());
160 local_state_registrar_
.Add(prefs::kUptimeLimit
,
161 base::Bind(&AutomaticRebootManager::Reschedule
,
162 base::Unretained(this)));
163 local_state_registrar_
.Add(prefs::kRebootAfterUpdate
,
164 base::Bind(&AutomaticRebootManager::Reschedule
,
165 base::Unretained(this)));
166 notification_registrar_
.Add(this, chrome::NOTIFICATION_APP_TERMINATING
,
167 content::NotificationService::AllSources());
169 DBusThreadManager
* dbus_thread_manager
= DBusThreadManager::Get();
170 dbus_thread_manager
->GetPowerManagerClient()->AddObserver(this);
171 dbus_thread_manager
->GetUpdateEngineClient()->AddObserver(this);
173 // If no user is logged in, a reboot may be performed whenever the user is
174 // idle. Start listening for user activity to determine whether the user is
176 if (!user_manager::UserManager::Get()->IsUserLoggedIn()) {
177 if (ui::UserActivityDetector::Get())
178 ui::UserActivityDetector::Get()->AddObserver(this);
179 notification_registrar_
.Add(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED
,
180 content::NotificationService::AllSources());
181 login_screen_idle_timer_
.reset(
182 new base::OneShotTimer
<AutomaticRebootManager
>);
183 OnUserActivity(NULL
);
186 // In a regular browser, base::ThreadTaskRunnerHandle::Get() and
187 // base::MessageLoopProxy::current() return pointers to the same object.
188 // In unit tests, using base::ThreadTaskRunnerHandle::Get() has the advantage
189 // that it allows a custom base::SingleThreadTaskRunner to be injected.
190 base::SequencedWorkerPool
* worker_pool
=
191 content::BrowserThread::GetBlockingPool();
192 worker_pool
->PostSequencedWorkerTaskWithShutdownBehavior(
193 worker_pool
->GetNamedSequenceToken(kSequenceToken
),
195 base::Bind(&GetSystemEventTimes
,
196 base::ThreadTaskRunnerHandle::Get(),
197 base::Bind(&AutomaticRebootManager::Init
,
198 weak_ptr_factory_
.GetWeakPtr())),
199 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
);
202 AutomaticRebootManager::~AutomaticRebootManager() {
203 FOR_EACH_OBSERVER(AutomaticRebootManagerObserver
,
205 WillDestroyAutomaticRebootManager());
207 DBusThreadManager
* dbus_thread_manager
= DBusThreadManager::Get();
208 dbus_thread_manager
->GetPowerManagerClient()->RemoveObserver(this);
209 dbus_thread_manager
->GetUpdateEngineClient()->RemoveObserver(this);
210 if (ui::UserActivityDetector::Get())
211 ui::UserActivityDetector::Get()->RemoveObserver(this);
214 void AutomaticRebootManager::AddObserver(
215 AutomaticRebootManagerObserver
* observer
) {
216 observers_
.AddObserver(observer
);
219 void AutomaticRebootManager::RemoveObserver(
220 AutomaticRebootManagerObserver
* observer
) {
221 observers_
.RemoveObserver(observer
);
224 void AutomaticRebootManager::SuspendDone(
225 const base::TimeDelta
& sleep_duration
) {
229 void AutomaticRebootManager::UpdateStatusChanged(
230 const UpdateEngineClient::Status
& status
) {
231 // Ignore repeated notifications that a reboot is necessary. This is important
232 // so that only the time of the first notification is taken into account and
233 // repeated notifications do not postpone the reboot request and grace period.
234 if (status
.status
!= UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT
||
235 !have_boot_time_
|| have_update_reboot_needed_time_
) {
239 content::BrowserThread::PostBlockingPoolTask(
240 FROM_HERE
, base::Bind(&SaveUpdateRebootNeededUptime
));
242 update_reboot_needed_time_
= clock_
->NowTicks();
243 have_update_reboot_needed_time_
= true;
248 void AutomaticRebootManager::OnUserActivity(const ui::Event
* event
) {
249 if (!login_screen_idle_timer_
)
252 // Destroying and re-creating the timer ensures that Start() posts a fresh
253 // task with a delay of exactly |kLoginManagerIdleTimeoutMs|, ensuring that
254 // the timer fires predictably in tests.
255 login_screen_idle_timer_
.reset(
256 new base::OneShotTimer
<AutomaticRebootManager
>);
257 login_screen_idle_timer_
->Start(
259 base::TimeDelta::FromMilliseconds(kLoginManagerIdleTimeoutMs
),
260 base::Bind(&AutomaticRebootManager::MaybeReboot
,
261 base::Unretained(this),
265 void AutomaticRebootManager::Observe(
267 const content::NotificationSource
& source
,
268 const content::NotificationDetails
& details
) {
269 if (type
== chrome::NOTIFICATION_APP_TERMINATING
) {
270 if (user_manager::UserManager::Get()->IsUserLoggedIn()) {
271 // The browser is terminating during a session, either because the session
272 // is ending or because the browser is being restarted.
275 } else if (type
== chrome::NOTIFICATION_LOGIN_USER_CHANGED
) {
276 // A session is starting. Stop listening for user activity as it no longer
277 // is a relevant criterion.
278 if (ui::UserActivityDetector::Get())
279 ui::UserActivityDetector::Get()->RemoveObserver(this);
280 notification_registrar_
.Remove(
281 this, chrome::NOTIFICATION_LOGIN_USER_CHANGED
,
282 content::NotificationService::AllSources());
283 login_screen_idle_timer_
.reset();
290 void AutomaticRebootManager::RegisterPrefs(PrefRegistrySimple
* registry
) {
291 registry
->RegisterIntegerPref(prefs::kUptimeLimit
, 0);
292 registry
->RegisterBooleanPref(prefs::kRebootAfterUpdate
, false);
295 void AutomaticRebootManager::Init(const SystemEventTimes
& system_event_times
) {
296 const base::TimeDelta offset
= clock_
->NowTicks() - base::TimeTicks::Now();
297 if (system_event_times
.has_boot_time
) {
298 // Convert the time at which the device was booted to |clock_| ticks.
299 boot_time_
= system_event_times
.boot_time
+ offset
;
300 have_boot_time_
= true;
302 if (system_event_times
.has_update_reboot_needed_time
) {
303 // Convert the time at which a reboot became necessary to |clock_| ticks.
304 const base::TimeTicks update_reboot_needed_time
=
305 system_event_times
.update_reboot_needed_time
+ offset
;
306 update_reboot_needed_time_
= update_reboot_needed_time
;
307 have_update_reboot_needed_time_
= true;
310 DBusThreadManager::Get()->GetUpdateEngineClient()->GetLastStatus());
316 void AutomaticRebootManager::Reschedule() {
317 // Safeguard against reboot loops under error conditions: If the boot time is
318 // unavailable because /proc/uptime could not be read, do nothing.
319 if (!have_boot_time_
)
322 // Assume that no reboot has been requested.
323 reboot_requested_
= false;
325 const base::TimeDelta kZeroTimeDelta
;
327 // If an uptime limit is set, calculate the time at which it should cause a
328 // reboot to be requested.
329 const base::TimeDelta uptime_limit
= base::TimeDelta::FromSeconds(
330 local_state_registrar_
.prefs()->GetInteger(prefs::kUptimeLimit
));
331 base::TimeTicks reboot_request_time
= boot_time_
+ uptime_limit
;
332 bool have_reboot_request_time
= uptime_limit
!= kZeroTimeDelta
;
333 if (have_reboot_request_time
)
334 reboot_reason_
= AutomaticRebootManagerObserver::REBOOT_REASON_PERIODIC
;
336 // If the policy to automatically reboot after an update is enabled and an
337 // update has been applied, set the time at which a reboot should be
338 // requested to the minimum of its current value and the time when the reboot
340 if (have_update_reboot_needed_time_
&&
341 local_state_registrar_
.prefs()->GetBoolean(prefs::kRebootAfterUpdate
) &&
342 (!have_reboot_request_time
||
343 update_reboot_needed_time_
< reboot_request_time
)) {
344 reboot_request_time
= update_reboot_needed_time_
;
345 have_reboot_request_time
= true;
346 reboot_reason_
= AutomaticRebootManagerObserver::REBOOT_REASON_OS_UPDATE
;
349 // If no reboot should be requested, remove any grace period.
350 if (!have_reboot_request_time
) {
351 grace_start_timer_
.reset();
352 grace_end_timer_
.reset();
356 // Safeguard against reboot loops: Ensure that the uptime after which a reboot
357 // is actually requested and the grace period begins is never less than
358 // |kMinRebootUptimeMs|.
359 const base::TimeTicks now
= clock_
->NowTicks();
360 const base::TimeTicks grace_start_time
= std::max(reboot_request_time
,
361 boot_time_
+ base::TimeDelta::FromMilliseconds(kMinRebootUptimeMs
));
363 // Set up a timer for the start of the grace period. If the grace period
364 // started in the past, the timer is still used with its delay set to zero.
365 if (!grace_start_timer_
)
366 grace_start_timer_
.reset(new base::OneShotTimer
<AutomaticRebootManager
>);
367 grace_start_timer_
->Start(FROM_HERE
,
368 std::max(grace_start_time
- now
, kZeroTimeDelta
),
369 base::Bind(&AutomaticRebootManager::RequestReboot
,
370 base::Unretained(this)));
372 const base::TimeTicks grace_end_time
= grace_start_time
+
373 base::TimeDelta::FromMilliseconds(kGracePeriodMs
);
374 // Set up a timer for the end of the grace period. If the grace period ended
375 // in the past, the timer is still used with its delay set to zero.
376 if (!grace_end_timer_
)
377 grace_end_timer_
.reset(new base::OneShotTimer
<AutomaticRebootManager
>);
378 grace_end_timer_
->Start(FROM_HERE
,
379 std::max(grace_end_time
- now
, kZeroTimeDelta
),
380 base::Bind(&AutomaticRebootManager::Reboot
,
381 base::Unretained(this)));
384 void AutomaticRebootManager::RequestReboot() {
385 reboot_requested_
= true;
386 DCHECK_NE(AutomaticRebootManagerObserver::REBOOT_REASON_UNKNOWN
,
388 FOR_EACH_OBSERVER(AutomaticRebootManagerObserver
,
390 OnRebootRequested(reboot_reason_
));
394 void AutomaticRebootManager::MaybeReboot(bool ignore_session
) {
395 // Do not reboot if any of the following applies:
396 // * No reboot has been requested.
397 // * A user is interacting with the login screen.
398 // * A session is in progress and |ignore_session| is not set.
399 if (!reboot_requested_
||
400 (login_screen_idle_timer_
&& login_screen_idle_timer_
->IsRunning()) ||
401 (!ignore_session
&& user_manager::UserManager::Get()->IsUserLoggedIn())) {
408 void AutomaticRebootManager::Reboot() {
409 // If a non-kiosk-app session is in progress, do not reboot.
410 if (user_manager::UserManager::Get()->IsUserLoggedIn() &&
411 !user_manager::UserManager::Get()->IsLoggedInAsKioskApp()) {
415 login_screen_idle_timer_
.reset();
416 grace_start_timer_
.reset();
417 grace_end_timer_
.reset();
418 DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
421 } // namespace system
422 } // namespace chromeos