Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / chromeos / session_length_limiter.cc
blobf26cf448bf90f4b4cd5c6c66500f66afdcf2b3e9
1 // 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.
5 #include "chrome/browser/chromeos/session_length_limiter.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/prefs/pref_registry_simple.h"
14 #include "base/prefs/pref_service.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/lifetime/application_lifetime.h"
17 #include "chrome/common/pref_names.h"
18 #include "ui/base/user_activity/user_activity_detector.h"
19 #include "ui/events/event.h"
21 namespace chromeos {
23 namespace {
25 // The minimum session time limit that can be set.
26 const int kSessionLengthLimitMinMs = 30 * 1000; // 30 seconds.
28 // The maximum session time limit that can be set.
29 const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000; // 24 hours.
31 // A default delegate implementation that returns the current time and does end
32 // the current user's session when requested. This can be replaced with a mock
33 // in tests.
34 class SessionLengthLimiterDelegateImpl : public SessionLengthLimiter::Delegate {
35 public:
36 SessionLengthLimiterDelegateImpl();
37 ~SessionLengthLimiterDelegateImpl() override;
39 const base::TimeTicks GetCurrentTime() const override;
40 void StopSession() override;
42 private:
43 DISALLOW_COPY_AND_ASSIGN(SessionLengthLimiterDelegateImpl);
46 SessionLengthLimiterDelegateImpl::SessionLengthLimiterDelegateImpl() {
49 SessionLengthLimiterDelegateImpl::~SessionLengthLimiterDelegateImpl() {
52 const base::TimeTicks SessionLengthLimiterDelegateImpl::GetCurrentTime() const {
53 return base::TimeTicks::Now();
56 void SessionLengthLimiterDelegateImpl::StopSession() {
57 chrome::AttemptUserExit();
60 } // namespace
62 SessionLengthLimiter::Delegate::~Delegate() {
65 // static
66 void SessionLengthLimiter::RegisterPrefs(PrefRegistrySimple* registry) {
67 registry->RegisterBooleanPref(prefs::kSessionUserActivitySeen, false);
68 registry->RegisterInt64Pref(prefs::kSessionStartTime, 0);
69 registry->RegisterIntegerPref(prefs::kSessionLengthLimit, 0);
70 registry->RegisterBooleanPref(prefs::kSessionWaitForInitialUserActivity,
71 false);
74 SessionLengthLimiter::SessionLengthLimiter(Delegate* delegate,
75 bool browser_restarted)
76 : delegate_(delegate ? delegate : new SessionLengthLimiterDelegateImpl),
77 user_activity_seen_(false) {
78 DCHECK(thread_checker_.CalledOnValidThread());
80 PrefService* local_state = g_browser_process->local_state();
81 pref_change_registrar_.Init(local_state);
82 pref_change_registrar_.Add(prefs::kSessionLengthLimit,
83 base::Bind(&SessionLengthLimiter::UpdateLimit,
84 base::Unretained(this)));
85 pref_change_registrar_.Add(
86 prefs::kSessionWaitForInitialUserActivity,
87 base::Bind(&SessionLengthLimiter::UpdateSessionStartTime,
88 base::Unretained(this)));
90 // If this is a browser restart after a crash, try to restore the session
91 // start time and the boolean indicating user activity from local state. If
92 // this is not a browser restart after a crash or the attempt to restore
93 // fails, set the session start time to the current time and clear the
94 // boolean indicating user activity.
95 if (!browser_restarted || !RestoreStateAfterCrash()) {
96 local_state->ClearPref(prefs::kSessionUserActivitySeen);
97 UpdateSessionStartTime();
100 if (!user_activity_seen_ && ui::UserActivityDetector::Get())
101 ui::UserActivityDetector::Get()->AddObserver(this);
104 SessionLengthLimiter::~SessionLengthLimiter() {
105 if (!user_activity_seen_ && ui::UserActivityDetector::Get())
106 ui::UserActivityDetector::Get()->RemoveObserver(this);
109 void SessionLengthLimiter::OnUserActivity(const ui::Event* event) {
110 if (user_activity_seen_)
111 return;
112 if (ui::UserActivityDetector::Get())
113 ui::UserActivityDetector::Get()->RemoveObserver(this);
114 user_activity_seen_ = true;
116 PrefService* local_state = g_browser_process->local_state();
117 local_state->SetBoolean(prefs::kSessionUserActivitySeen, true);
118 if (session_start_time_.is_null()) {
119 // If instructed to wait for initial user activity and this is the first
120 // activity in the session, set the session start time to the current time
121 // and persist it in local state.
122 session_start_time_ = delegate_->GetCurrentTime();
123 local_state->SetInt64(prefs::kSessionStartTime,
124 session_start_time_.ToInternalValue());
126 local_state->CommitPendingWrite();
128 UpdateLimit();
131 bool SessionLengthLimiter::RestoreStateAfterCrash() {
132 PrefService* local_state = g_browser_process->local_state();
133 const base::TimeTicks session_start_time =
134 base::TimeTicks::FromInternalValue(
135 local_state->GetInt64(prefs::kSessionStartTime));
136 if (session_start_time.is_null() ||
137 session_start_time >= delegate_->GetCurrentTime()) {
138 return false;
141 session_start_time_ = session_start_time;
142 user_activity_seen_ =
143 local_state->GetBoolean(prefs::kSessionUserActivitySeen);
145 UpdateLimit();
146 return true;
149 void SessionLengthLimiter::UpdateSessionStartTime() {
150 DCHECK(thread_checker_.CalledOnValidThread());
152 if (user_activity_seen_)
153 return;
155 PrefService* local_state = g_browser_process->local_state();
156 if (local_state->GetBoolean(prefs::kSessionWaitForInitialUserActivity)) {
157 session_start_time_ = base::TimeTicks();
158 local_state->ClearPref(prefs::kSessionStartTime);
159 } else {
160 session_start_time_ = delegate_->GetCurrentTime();
161 local_state->SetInt64(prefs::kSessionStartTime,
162 session_start_time_.ToInternalValue());
164 local_state->CommitPendingWrite();
166 UpdateLimit();
169 void SessionLengthLimiter::UpdateLimit() {
170 DCHECK(thread_checker_.CalledOnValidThread());
172 // Stop any currently running timer.
173 timer_.reset();
175 // If instructed to wait for initial user activity and no user activity has
176 // occurred yet, do not start a timer.
177 if (session_start_time_.is_null())
178 return;
180 // If no session length limit is set, do not start a timer.
181 int limit;
182 const PrefService::Preference* session_length_limit_pref =
183 pref_change_registrar_.prefs()->
184 FindPreference(prefs::kSessionLengthLimit);
185 if (session_length_limit_pref->IsDefaultValue() ||
186 !session_length_limit_pref->GetValue()->GetAsInteger(&limit)) {
187 return;
190 // Clamp the session length limit to the valid range.
191 const base::TimeDelta session_length_limit =
192 base::TimeDelta::FromMilliseconds(std::min(std::max(
193 limit, kSessionLengthLimitMinMs), kSessionLengthLimitMaxMs));
195 // Calculate the remaining session time.
196 const base::TimeDelta remaining = session_length_limit -
197 (delegate_->GetCurrentTime() - session_start_time_);
199 // Log out the user immediately if the session length limit has been reached
200 // or exceeded.
201 if (remaining <= base::TimeDelta()) {
202 delegate_->StopSession();
203 return;
206 // Set a timer to log out the user when the session length limit is reached.
207 timer_.reset(new base::OneShotTimer<SessionLengthLimiter::Delegate>);
208 timer_->Start(FROM_HERE, remaining, delegate_.get(),
209 &SessionLengthLimiter::Delegate::StopSession);
212 } // namespace chromeos