BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / chromeos / system / automatic_reboot_manager.cc
bloba15e3a733755cbafa610020362c5466d4ee65e39
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"
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
11 #include <algorithm>
12 #include <string>
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"
47 namespace chromeos {
48 namespace system {
50 namespace {
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();
61 base::ScopedFD fd(
62 HANDLE_EINTR(open(path.value().c_str(), O_RDONLY | O_NOFOLLOW)));
63 if (!fd.is_valid())
64 return base::TimeDelta();
66 std::string contents;
67 char buffer[kOneKilobyte];
68 ssize_t length;
69 while ((length = HANDLE_EINTR(read(fd.get(), buffer, sizeof(buffer)))) > 0)
70 contents.append(buffer, length);
72 double seconds;
73 if (!base::StringToDouble(contents.substr(0, contents.find(' ')), &seconds) ||
74 seconds < 0.0) {
75 return base::TimeDelta();
77 return base::TimeDelta::FromMilliseconds(seconds * 1000.0);
80 void GetSystemEventTimes(
81 scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,
82 base::Callback<void(
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)
105 return;
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)
111 return;
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,
116 0666)));
117 if (!fd.is_valid())
118 return;
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());
126 } // namespace
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)
140 return;
141 boot_time = base::TimeTicks::Now() - uptime;
142 has_boot_time = true;
143 if (update_reboot_needed_uptime == kZeroTimeDelta)
144 return;
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
175 // idle or not.
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::ThreadTaskRunnerHandle::Get() 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),
194 FROM_HERE,
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,
204 observers_,
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) {
226 MaybeReboot(true);
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_) {
236 return;
239 content::BrowserThread::PostBlockingPoolTask(
240 FROM_HERE, base::Bind(&SaveUpdateRebootNeededUptime));
242 update_reboot_needed_time_ = clock_->NowTicks();
243 have_update_reboot_needed_time_ = true;
245 Reschedule();
248 void AutomaticRebootManager::OnUserActivity(const ui::Event* event) {
249 if (!login_screen_idle_timer_)
250 return;
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(
258 FROM_HERE,
259 base::TimeDelta::FromMilliseconds(kLoginManagerIdleTimeoutMs),
260 base::Bind(&AutomaticRebootManager::MaybeReboot,
261 base::Unretained(this),
262 false));
265 void AutomaticRebootManager::Observe(
266 int type,
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.
273 MaybeReboot(true);
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();
284 } else {
285 NOTREACHED();
289 // static
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;
308 } else {
309 UpdateStatusChanged(
310 DBusThreadManager::Get()->GetUpdateEngineClient()->GetLastStatus());
313 Reschedule();
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_)
320 return;
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
339 // became necessary.
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();
353 return;
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,
387 reboot_reason_);
388 FOR_EACH_OBSERVER(AutomaticRebootManagerObserver,
389 observers_,
390 OnRebootRequested(reboot_reason_));
391 MaybeReboot(false);
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())) {
402 return;
405 Reboot();
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()) {
412 return;
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