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/file_util.h"
19 #include "base/files/file_path.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/login/users/user_manager.h"
37 #include "chrome/browser/chromeos/system/automatic_reboot_manager_observer.h"
38 #include "chrome/common/pref_names.h"
39 #include "chromeos/chromeos_paths.h"
40 #include "chromeos/chromeos_switches.h"
41 #include "chromeos/dbus/dbus_thread_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
ReadTimeDeltaFromFile(const base::FilePath & path)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
GetSystemEventTimes(scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,base::Callback<void (const AutomaticRebootManager::SystemEventTimes &)> reply)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
SaveUpdateRebootNeededUptime()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
SystemEventTimes()127 AutomaticRebootManager::SystemEventTimes::SystemEventTimes()
128 : has_boot_time(false),
129 has_update_reboot_needed_time(false) {
130 }
131
SystemEventTimes(const base::TimeDelta & uptime,const base::TimeDelta & update_reboot_needed_uptime)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
AutomaticRebootManager(scoped_ptr<base::TickClock> clock)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 (!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
~AutomaticRebootManager()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
AddObserver(AutomaticRebootManagerObserver * observer)209 void AutomaticRebootManager::AddObserver(
210 AutomaticRebootManagerObserver* observer) {
211 observers_.AddObserver(observer);
212 }
213
RemoveObserver(AutomaticRebootManagerObserver * observer)214 void AutomaticRebootManager::RemoveObserver(
215 AutomaticRebootManagerObserver* observer) {
216 observers_.RemoveObserver(observer);
217 }
218
SuspendDone(const base::TimeDelta & sleep_duration)219 void AutomaticRebootManager::SuspendDone(
220 const base::TimeDelta& sleep_duration) {
221 MaybeReboot(true);
222 }
223
UpdateStatusChanged(const UpdateEngineClient::Status & status)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
OnUserActivity(const ui::Event * event)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
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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 (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
RegisterPrefs(PrefRegistrySimple * registry)285 void AutomaticRebootManager::RegisterPrefs(PrefRegistrySimple* registry) {
286 registry->RegisterIntegerPref(prefs::kUptimeLimit, 0);
287 registry->RegisterBooleanPref(prefs::kRebootAfterUpdate, false);
288 }
289
Init(const SystemEventTimes & system_event_times)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
Reschedule()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
RequestReboot()386 void AutomaticRebootManager::RequestReboot() {
387 reboot_requested_ = true;
388 MaybeReboot(false);
389 }
390
MaybeReboot(bool ignore_session)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 && UserManager::Get()->IsUserLoggedIn())) {
399 return;
400 }
401
402 Reboot();
403 }
404
Reboot()405 void AutomaticRebootManager::Reboot() {
406 // If a non-kiosk-app session is in progress, do not reboot.
407 if (UserManager::Get()->IsUserLoggedIn() &&
408 !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