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 "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"
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.
58 base::TimeDelta
ReadTimeDeltaFromFile(const base::FilePath
& path
) {
59 base::ThreadRestrictions::AssertIOAllowed();
61 HANDLE_EINTR(open(path
.value().c_str(), O_RDONLY
| O_NOFOLLOW
)));
63 return base::TimeDelta();
66 char buffer
[kOneKilobyte
];
68 while ((length
= HANDLE_EINTR(read(fd
.get(), buffer
, sizeof(buffer
)))) > 0)
69 contents
.append(buffer
, length
);
72 if (!base::StringToDouble(contents
.substr(0, contents
.find(' ')), &seconds
) ||
74 return base::TimeDelta();
76 return base::TimeDelta::FromMilliseconds(seconds
* 1000.0);
79 void GetSystemEventTimes(
80 scoped_refptr
<base::SingleThreadTaskRunner
> reply_task_runner
,
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
))));
94 void SaveUpdateRebootNeededUptime() {
95 base::ThreadRestrictions::AssertIOAllowed();
96 const base::TimeDelta kZeroTimeDelta
;
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
)
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
)
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
,
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());
127 AutomaticRebootManager::SystemEventTimes::SystemEventTimes()
128 : has_boot_time(false),
129 has_update_reboot_needed_time(false) {
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
)
140 boot_time
= base::TimeTicks::Now() - uptime
;
141 has_boot_time
= true;
142 if (update_reboot_needed_uptime
== kZeroTimeDelta
)
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;
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());
167 DBusThreadManager
* dbus_thread_manager
= DBusThreadManager::Get();
168 dbus_thread_manager
->GetPowerManagerClient()->AddObserver(this);
169 dbus_thread_manager
->GetUpdateEngineClient()->AddObserver(this);
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
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
);
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(
190 base::Bind(&GetSystemEventTimes
,
191 base::ThreadTaskRunnerHandle::Get(),
192 base::Bind(&AutomaticRebootManager::Init
,
193 weak_ptr_factory_
.GetWeakPtr())),
194 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
);
197 AutomaticRebootManager::~AutomaticRebootManager() {
198 FOR_EACH_OBSERVER(AutomaticRebootManagerObserver
,
200 WillDestroyAutomaticRebootManager());
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);
209 void AutomaticRebootManager::AddObserver(
210 AutomaticRebootManagerObserver
* observer
) {
211 observers_
.AddObserver(observer
);
214 void AutomaticRebootManager::RemoveObserver(
215 AutomaticRebootManagerObserver
* observer
) {
216 observers_
.RemoveObserver(observer
);
219 void AutomaticRebootManager::SuspendDone(
220 const base::TimeDelta
& sleep_duration
) {
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_
) {
234 content::BrowserThread::PostBlockingPoolTask(
235 FROM_HERE
, base::Bind(&SaveUpdateRebootNeededUptime
));
237 update_reboot_needed_time_
= clock_
->NowTicks();
238 have_update_reboot_needed_time_
= true;
243 void AutomaticRebootManager::OnUserActivity(const ui::Event
* event
) {
244 if (!login_screen_idle_timer_
)
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(
254 base::TimeDelta::FromMilliseconds(kLoginManagerIdleTimeoutMs
),
255 base::Bind(&AutomaticRebootManager::MaybeReboot
,
256 base::Unretained(this),
260 void AutomaticRebootManager::Observe(
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.
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();
285 void AutomaticRebootManager::RegisterPrefs(PrefRegistrySimple
* registry
) {
286 registry
->RegisterIntegerPref(prefs::kUptimeLimit
, 0);
287 registry
->RegisterBooleanPref(prefs::kRebootAfterUpdate
, false);
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;
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;
305 DBusThreadManager::Get()->GetUpdateEngineClient()->GetLastStatus());
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_
)
317 // Assume that no reboot has been requested.
318 reboot_requested_
= false;
320 const base::TimeDelta kZeroTimeDelta
;
321 AutomaticRebootManagerObserver::Reason reboot_reason
=
322 AutomaticRebootManagerObserver::REBOOT_REASON_UNKNOWN
;
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
;
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
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
;
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();
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)));
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)));
379 DCHECK_NE(AutomaticRebootManagerObserver::REBOOT_REASON_UNKNOWN
,
381 FOR_EACH_OBSERVER(AutomaticRebootManagerObserver
,
383 OnRebootScheduled(reboot_reason
));
386 void AutomaticRebootManager::RequestReboot() {
387 reboot_requested_
= true;
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())) {
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()) {
412 login_screen_idle_timer_
.reset();
413 grace_start_timer_
.reset();
414 grace_end_timer_
.reset();
415 DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
418 } // namespace system
419 } // namespace chromeos