blob: 14c901b866f4065ee56ecfafdd245501ef753b90 [file] [log] [blame]
// 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