summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos/session_length_limiter.cc
blob: 14c901b866f4065ee56ecfafdd245501ef753b90 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/session_length_limiter.h"

#include <algorithm>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/common/pref_names.h"

namespace chromeos {

namespace {

// The minimum session time limit that can be set.
const int kSessionLengthLimitMinMs = 30 * 1000; // 30 seconds.

// The maximum session time limit that can be set.
const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000; // 24 hours.

// A default delegate implementation that returns the current time and does end
// the current user's session when requested. This can be replaced with a mock
// in tests.
class SessionLengthLimiterDelegateImpl : public SessionLengthLimiter::Delegate {
 public:
  SessionLengthLimiterDelegateImpl();
  virtual ~SessionLengthLimiterDelegateImpl();

  virtual const base::TimeTicks GetCurrentTime() const OVERRIDE;
  virtual void StopSession() OVERRIDE;

 private:
  DISALLOW_COPY_AND_ASSIGN(SessionLengthLimiterDelegateImpl);
};

SessionLengthLimiterDelegateImpl::SessionLengthLimiterDelegateImpl() {
}

SessionLengthLimiterDelegateImpl::~SessionLengthLimiterDelegateImpl() {
}

const base::TimeTicks SessionLengthLimiterDelegateImpl::GetCurrentTime() const {
  return base::TimeTicks::Now();
}

void SessionLengthLimiterDelegateImpl::StopSession() {
  chrome::AttemptUserExit();
}

}  // namespace

SessionLengthLimiter::Delegate::~Delegate() {
}

// static
void SessionLengthLimiter::RegisterPrefs(PrefRegistrySimple* registry) {
  registry->RegisterInt64Pref(prefs::kSessionStartTime, 0);
  registry->RegisterIntegerPref(prefs::kSessionLengthLimit, 0);
}

SessionLengthLimiter::SessionLengthLimiter(Delegate* delegate,
                                           bool browser_restarted)
    : delegate_(delegate ? delegate : new SessionLengthLimiterDelegateImpl) {
  DCHECK(thread_checker_.CalledOnValidThread());

  // If this is a user login, set the session start time in local state to the
  // current time. If this a browser restart after a crash, set the session
  // start time only if its current value appears corrupted (value unset, value
  // lying in the future).
  PrefService* local_state = g_browser_process->local_state();
  int64 session_start_time = local_state->GetInt64(prefs::kSessionStartTime);
  const int64 now = delegate_->GetCurrentTime().ToInternalValue();
  if (!browser_restarted ||
      !local_state->HasPrefPath(prefs::kSessionStartTime) ||
      session_start_time > now) {
    local_state->SetInt64(prefs::kSessionStartTime, now);
    // Ensure that the session start time is persisted to local state.
    local_state->CommitPendingWrite();
    session_start_time = now;
  }
  session_start_time_ = base::TimeTicks::FromInternalValue(session_start_time);

  // Listen for changes to the session length limit.
  pref_change_registrar_.Init(local_state);
  pref_change_registrar_.Add(
      prefs::kSessionLengthLimit,
      base::Bind(&SessionLengthLimiter::OnSessionLengthLimitChanged,
                 base::Unretained(this)));

  // Handle the current session length limit, if any.
  OnSessionLengthLimitChanged();
}

SessionLengthLimiter::~SessionLengthLimiter() {
}

void SessionLengthLimiter::OnSessionLengthLimitChanged() {
  DCHECK(thread_checker_.CalledOnValidThread());

  // Stop any currently running timer.
  if (timer_)
    timer_->Stop();

  int limit;
  const PrefService::Preference* session_length_limit_pref =
      pref_change_registrar_.prefs()->
          FindPreference(prefs::kSessionLengthLimit);
  if (session_length_limit_pref->IsDefaultValue() ||
      !session_length_limit_pref->GetValue()->GetAsInteger(&limit)) {
    // If no session length limit is set, destroy the timer.
    timer_.reset();
    return;
  }

  // Clamp the session length limit to the valid range.
  const base::TimeDelta session_length_limit =
      base::TimeDelta::FromMilliseconds(std::min(std::max(
          limit, kSessionLengthLimitMinMs), kSessionLengthLimitMaxMs));

  // Calculate the remaining session time.
  const base::TimeDelta remaining = session_length_limit -
      (delegate_->GetCurrentTime() - session_start_time_);

  // Log out the user immediately if the session length limit has been reached
  // or exceeded.
  if (remaining <= base::TimeDelta()) {
    delegate_->StopSession();
    return;
  }

  // Set a timer to log out the user when the session length limit is reached.
  if (!timer_)
    timer_.reset(new base::OneShotTimer<SessionLengthLimiter::Delegate>);
  timer_->Start(FROM_HERE, remaining, delegate_.get(),
                &SessionLengthLimiter::Delegate::StopSession);
}

}  // namespace chromeos