- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / session_length_limiter.cc
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.
4
5 #include "chrome/browser/chromeos/session_length_limiter.h"
6
7 #include <algorithm>
8
9 #include "ash/shell.h"
10 #include "ash/wm/user_activity_detector.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/prefs/pref_registry_simple.h"
16 #include "base/prefs/pref_service.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/lifetime/application_lifetime.h"
19 #include "chrome/common/pref_names.h"
20 #include "ui/events/event.h"
21
22 namespace chromeos {
23
24 namespace {
25
26 // The minimum session time limit that can be set.
27 const int kSessionLengthLimitMinMs = 30 * 1000; // 30 seconds.
28
29 // The maximum session time limit that can be set.
30 const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000; // 24 hours.
31
32 // 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.
35 class SessionLengthLimiterDelegateImpl : public SessionLengthLimiter::Delegate {
36  public:
37   SessionLengthLimiterDelegateImpl();
38   virtual ~SessionLengthLimiterDelegateImpl();
39
40   virtual const base::TimeTicks GetCurrentTime() const OVERRIDE;
41   virtual void StopSession() OVERRIDE;
42
43  private:
44   DISALLOW_COPY_AND_ASSIGN(SessionLengthLimiterDelegateImpl);
45 };
46
47 SessionLengthLimiterDelegateImpl::SessionLengthLimiterDelegateImpl() {
48 }
49
50 SessionLengthLimiterDelegateImpl::~SessionLengthLimiterDelegateImpl() {
51 }
52
53 const base::TimeTicks SessionLengthLimiterDelegateImpl::GetCurrentTime() const {
54   return base::TimeTicks::Now();
55 }
56
57 void SessionLengthLimiterDelegateImpl::StopSession() {
58   chrome::AttemptUserExit();
59 }
60
61 }  // namespace
62
63 SessionLengthLimiter::Delegate::~Delegate() {
64 }
65
66 // static
67 void SessionLengthLimiter::RegisterPrefs(PrefRegistrySimple* registry) {
68   registry->RegisterBooleanPref(prefs::kSessionUserActivitySeen, false);
69   registry->RegisterInt64Pref(prefs::kSessionStartTime, 0);
70   registry->RegisterIntegerPref(prefs::kSessionLengthLimit, 0);
71   registry->RegisterBooleanPref(prefs::kSessionWaitForInitialUserActivity,
72                                 false);
73 }
74
75 SessionLengthLimiter::SessionLengthLimiter(Delegate* delegate,
76                                            bool browser_restarted)
77     : delegate_(delegate ? delegate : new SessionLengthLimiterDelegateImpl),
78       user_activity_seen_(false) {
79   DCHECK(thread_checker_.CalledOnValidThread());
80
81   PrefService* local_state = g_browser_process->local_state();
82   pref_change_registrar_.Init(local_state);
83   pref_change_registrar_.Add(prefs::kSessionLengthLimit,
84                              base::Bind(&SessionLengthLimiter::UpdateLimit,
85                                         base::Unretained(this)));
86   pref_change_registrar_.Add(
87       prefs::kSessionWaitForInitialUserActivity,
88       base::Bind(&SessionLengthLimiter::UpdateSessionStartTime,
89                  base::Unretained(this)));
90
91   // 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);
103 }
104
105 SessionLengthLimiter::~SessionLengthLimiter() {
106   if (!user_activity_seen_ && ash::Shell::HasInstance())
107     ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
108 }
109
110 void 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
132 bool 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
150 void 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
170 void SessionLengthLimiter::UpdateLimit() {
171   DCHECK(thread_checker_.CalledOnValidThread());
172
173   // Stop any currently running timer.
174   timer_.reset();
175
176   // 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.
182   int limit;
183   const PrefService::Preference* session_length_limit_pref =
184       pref_change_registrar_.prefs()->
185           FindPreference(prefs::kSessionLengthLimit);
186   if (session_length_limit_pref->IsDefaultValue() ||
187       !session_length_limit_pref->GetValue()->GetAsInteger(&limit)) {
188     return;
189   }
190
191   // 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));
195
196   // Calculate the remaining session time.
197   const base::TimeDelta remaining = session_length_limit -
198       (delegate_->GetCurrentTime() - session_start_time_);
199
200   // Log out the user immediately if the session length limit has been reached
201   // or exceeded.
202   if (remaining <= base::TimeDelta()) {
203     delegate_->StopSession();
204     return;
205   }
206
207   // Set a timer to log out the user when the session length limit is reached.
208   timer_.reset(new base::OneShotTimer<SessionLengthLimiter::Delegate>);
209   timer_->Start(FROM_HERE, remaining, delegate_.get(),
210                 &SessionLengthLimiter::Delegate::StopSession);
211 }
212
213 }  // namespace chromeos