blob: 4ea224a2c44b1365e540ea9412d9debb516ccbc8 [file] [log] [blame]
[email protected]cf50d182012-12-15 08:37:071// Copyright (c) 2012 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
[email protected]7b4460f2013-03-21 17:47:325#include "chrome/browser/chromeos/session_length_limiter.h"
[email protected]cf50d182012-12-15 08:37:076
7#include <algorithm>
8
[email protected]8e0ba06b2013-10-28 15:38:099#include "ash/shell.h"
10#include "ash/wm/user_activity_detector.h"
[email protected]cf50d182012-12-15 08:37:0711#include "base/bind.h"
12#include "base/bind_helpers.h"
13#include "base/location.h"
14#include "base/logging.h"
[email protected]3853a4c2013-02-11 17:15:5715#include "base/prefs/pref_registry_simple.h"
16#include "base/prefs/pref_service.h"
[email protected]cf50d182012-12-15 08:37:0717#include "chrome/browser/browser_process.h"
18#include "chrome/browser/lifetime/application_lifetime.h"
[email protected]cf50d182012-12-15 08:37:0719#include "chrome/common/pref_names.h"
[email protected]8e0ba06b2013-10-28 15:38:0920#include "ui/events/event.h"
[email protected]cf50d182012-12-15 08:37:0721
22namespace chromeos {
23
24namespace {
25
26// The minimum session time limit that can be set.
27const int kSessionLengthLimitMinMs = 30 * 1000; // 30 seconds.
28
29// The maximum session time limit that can be set.
30const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000; // 24 hours.
31
[email protected]cf50d182012-12-15 08:37:0732// A default delegate implementation that returns the current time and does end
33// the current user's session when requested. This can be replaced with a mock
34// in tests.
35class SessionLengthLimiterDelegateImpl : public SessionLengthLimiter::Delegate {
36 public:
37 SessionLengthLimiterDelegateImpl();
38 virtual ~SessionLengthLimiterDelegateImpl();
39
[email protected]7b4460f2013-03-21 17:47:3240 virtual const base::TimeTicks GetCurrentTime() const OVERRIDE;
[email protected]b9085c82013-02-06 10:00:5941 virtual void StopSession() OVERRIDE;
[email protected]cf50d182012-12-15 08:37:0742
43 private:
44 DISALLOW_COPY_AND_ASSIGN(SessionLengthLimiterDelegateImpl);
45};
46
47SessionLengthLimiterDelegateImpl::SessionLengthLimiterDelegateImpl() {
48}
49
50SessionLengthLimiterDelegateImpl::~SessionLengthLimiterDelegateImpl() {
51}
52
[email protected]7b4460f2013-03-21 17:47:3253const base::TimeTicks SessionLengthLimiterDelegateImpl::GetCurrentTime() const {
54 return base::TimeTicks::Now();
[email protected]cf50d182012-12-15 08:37:0755}
56
57void SessionLengthLimiterDelegateImpl::StopSession() {
[email protected]0c98ab652013-02-18 00:39:3758 chrome::AttemptUserExit();
[email protected]cf50d182012-12-15 08:37:0759}
60
61} // namespace
62
63SessionLengthLimiter::Delegate::~Delegate() {
64}
65
66// static
[email protected]b1de2c72013-02-06 02:45:4767void SessionLengthLimiter::RegisterPrefs(PrefRegistrySimple* registry) {
[email protected]8e0ba06b2013-10-28 15:38:0968 registry->RegisterBooleanPref(prefs::kSessionUserActivitySeen, false);
[email protected]b1de2c72013-02-06 02:45:4769 registry->RegisterInt64Pref(prefs::kSessionStartTime, 0);
70 registry->RegisterIntegerPref(prefs::kSessionLengthLimit, 0);
[email protected]8e0ba06b2013-10-28 15:38:0971 registry->RegisterBooleanPref(prefs::kSessionWaitForInitialUserActivity,
72 false);
[email protected]cf50d182012-12-15 08:37:0773}
74
75SessionLengthLimiter::SessionLengthLimiter(Delegate* delegate,
76 bool browser_restarted)
[email protected]8e0ba06b2013-10-28 15:38:0977 : delegate_(delegate ? delegate : new SessionLengthLimiterDelegateImpl),
78 user_activity_seen_(false) {
[email protected]cf50d182012-12-15 08:37:0779 DCHECK(thread_checker_.CalledOnValidThread());
80
[email protected]cf50d182012-12-15 08:37:0781 PrefService* local_state = g_browser_process->local_state();
[email protected]cf50d182012-12-15 08:37:0782 pref_change_registrar_.Init(local_state);
[email protected]8e0ba06b2013-10-28 15:38:0983 pref_change_registrar_.Add(prefs::kSessionLengthLimit,
84 base::Bind(&SessionLengthLimiter::UpdateLimit,
85 base::Unretained(this)));
[email protected]cf50d182012-12-15 08:37:0786 pref_change_registrar_.Add(
[email protected]8e0ba06b2013-10-28 15:38:0987 prefs::kSessionWaitForInitialUserActivity,
88 base::Bind(&SessionLengthLimiter::UpdateSessionStartTime,
[email protected]cf50d182012-12-15 08:37:0789 base::Unretained(this)));
[email protected]b6429222013-02-13 14:27:2790
[email protected]8e0ba06b2013-10-28 15:38:0991 // If this is a browser restart after a crash, try to restore the session
92 // start time and the boolean indicating user activity from local state. If
93 // this is not a browser restart after a crash or the attempt to restore
94 // fails, set the session start time to the current time and clear the
95 // boolean indicating user activity.
96 if (!browser_restarted || !RestoreStateAfterCrash()) {
97 local_state->ClearPref(prefs::kSessionUserActivitySeen);
98 UpdateSessionStartTime();
99 }
100
101 if (!user_activity_seen_ && ash::Shell::HasInstance())
102 ash::Shell::GetInstance()->user_activity_detector()->AddObserver(this);
[email protected]cf50d182012-12-15 08:37:07103}
104
[email protected]9be5c47c2012-12-15 08:53:17105SessionLengthLimiter::~SessionLengthLimiter() {
[email protected]8e0ba06b2013-10-28 15:38:09106 if (!user_activity_seen_ && ash::Shell::HasInstance())
107 ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
[email protected]9be5c47c2012-12-15 08:53:17108}
109
[email protected]8e0ba06b2013-10-28 15:38:09110void SessionLengthLimiter::OnUserActivity(const ui::Event* event) {
111 if (user_activity_seen_)
112 return;
113 if (ash::Shell::HasInstance())
114 ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
115 user_activity_seen_ = true;
116
117 PrefService* local_state = g_browser_process->local_state();
118 local_state->SetBoolean(prefs::kSessionUserActivitySeen, true);
119 if (session_start_time_.is_null()) {
120 // If instructed to wait for initial user activity and this is the first
121 // activity in the session, set the session start time to the current time
122 // and persist it in local state.
123 session_start_time_ = delegate_->GetCurrentTime();
124 local_state->SetInt64(prefs::kSessionStartTime,
125 session_start_time_.ToInternalValue());
126 }
127 local_state->CommitPendingWrite();
128
129 UpdateLimit();
130}
131
132bool SessionLengthLimiter::RestoreStateAfterCrash() {
133 PrefService* local_state = g_browser_process->local_state();
134 const base::TimeTicks session_start_time =
135 base::TimeTicks::FromInternalValue(
136 local_state->GetInt64(prefs::kSessionStartTime));
137 if (session_start_time.is_null() ||
138 session_start_time >= delegate_->GetCurrentTime()) {
139 return false;
140 }
141
142 session_start_time_ = session_start_time;
143 user_activity_seen_ =
144 local_state->GetBoolean(prefs::kSessionUserActivitySeen);
145
146 UpdateLimit();
147 return true;
148}
149
150void SessionLengthLimiter::UpdateSessionStartTime() {
151 DCHECK(thread_checker_.CalledOnValidThread());
152
153 if (user_activity_seen_)
154 return;
155
156 PrefService* local_state = g_browser_process->local_state();
157 if (local_state->GetBoolean(prefs::kSessionWaitForInitialUserActivity)) {
158 session_start_time_ = base::TimeTicks();
159 local_state->ClearPref(prefs::kSessionStartTime);
160 } else {
161 session_start_time_ = delegate_->GetCurrentTime();
162 local_state->SetInt64(prefs::kSessionStartTime,
163 session_start_time_.ToInternalValue());
164 }
165 local_state->CommitPendingWrite();
166
167 UpdateLimit();
168}
169
170void SessionLengthLimiter::UpdateLimit() {
[email protected]cf50d182012-12-15 08:37:07171 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]b6429222013-02-13 14:27:27172
173 // Stop any currently running timer.
[email protected]8e0ba06b2013-10-28 15:38:09174 timer_.reset();
[email protected]b6429222013-02-13 14:27:27175
[email protected]8e0ba06b2013-10-28 15:38:09176 // If instructed to wait for initial user activity and no user activity has
177 // occurred yet, do not start a timer.
178 if (session_start_time_.is_null())
179 return;
180
181 // If no session length limit is set, do not start a timer.
[email protected]cf50d182012-12-15 08:37:07182 int limit;
[email protected]d6ab8452013-02-16 04:20:59183 const PrefService::Preference* session_length_limit_pref =
[email protected]cf50d182012-12-15 08:37:07184 pref_change_registrar_.prefs()->
185 FindPreference(prefs::kSessionLengthLimit);
[email protected]cf50d182012-12-15 08:37:07186 if (session_length_limit_pref->IsDefaultValue() ||
187 !session_length_limit_pref->GetValue()->GetAsInteger(&limit)) {
[email protected]cf50d182012-12-15 08:37:07188 return;
189 }
190
[email protected]b6429222013-02-13 14:27:27191 // Clamp the session length limit to the valid range.
192 const base::TimeDelta session_length_limit =
193 base::TimeDelta::FromMilliseconds(std::min(std::max(
194 limit, kSessionLengthLimitMinMs), kSessionLengthLimitMaxMs));
[email protected]cf50d182012-12-15 08:37:07195
[email protected]b6429222013-02-13 14:27:27196 // Calculate the remaining session time.
197 const base::TimeDelta remaining = session_length_limit -
[email protected]cf50d182012-12-15 08:37:07198 (delegate_->GetCurrentTime() - session_start_time_);
[email protected]cf50d182012-12-15 08:37:07199
[email protected]b6429222013-02-13 14:27:27200 // Log out the user immediately if the session length limit has been reached
201 // or exceeded.
202 if (remaining <= base::TimeDelta()) {
[email protected]cf50d182012-12-15 08:37:07203 delegate_->StopSession();
[email protected]b6429222013-02-13 14:27:27204 return;
205 }
206
207 // Set a timer to log out the user when the session length limit is reached.
[email protected]8e0ba06b2013-10-28 15:38:09208 timer_.reset(new base::OneShotTimer<SessionLengthLimiter::Delegate>);
[email protected]b6429222013-02-13 14:27:27209 timer_->Start(FROM_HERE, remaining, delegate_.get(),
210 &SessionLengthLimiter::Delegate::StopSession);
[email protected]cf50d182012-12-15 08:37:07211}
212
213} // namespace chromeos