Chromium Code Reviews| Index: chrome/browser/chromeos/session_length_limiter.cc |
| diff --git a/chrome/browser/chromeos/session_length_limiter.cc b/chrome/browser/chromeos/session_length_limiter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fb0d94c27f2bf3b95d53dcde766ad5c3e2dd2fa3 |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/session_length_limiter.cc |
| @@ -0,0 +1,177 @@ |
| +// 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/public/pref_service_base.h" |
| +#include "chrome/browser/chromeos/login/user_manager.h" |
| +#include "chrome/browser/lifetime/application_lifetime.h" |
| +#include "chrome/browser/prefs/pref_service.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. |
| + |
| +// The interval at which to fire periodic callbacks and check whether the |
| +// session time limit has been reached. |
| +const int kSessionLengthLimitTimerIntervalMs = 1000; |
| + |
| +// A default delegate implementation that returns the current time and does log |
| +// out the current user when requested. This can be replaced with a mock in |
| +// tests. |
| +class SessionLengthLimiterDelegateImpl : public SessionLengthLimiter::Delegate { |
| + public: |
| + SessionLengthLimiterDelegateImpl(); |
| + virtual ~SessionLengthLimiterDelegateImpl(); |
| + |
| + virtual const base::Time GetCurrentTime() const; |
| + virtual void Logout(); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(SessionLengthLimiterDelegateImpl); |
| +}; |
| + |
| +SessionLengthLimiterDelegateImpl::SessionLengthLimiterDelegateImpl() { |
| +} |
| + |
| +SessionLengthLimiterDelegateImpl::~SessionLengthLimiterDelegateImpl() { |
| +} |
| + |
| +const base::Time SessionLengthLimiterDelegateImpl::GetCurrentTime() const { |
| + return base::Time::Now(); |
| +} |
| + |
| +void SessionLengthLimiterDelegateImpl::Logout() { |
| + browser::AttemptUserExit(); |
| +} |
| + |
| +} // namespace |
| + |
| +SessionLengthLimiter::Observer::~Observer() { |
| +} |
| + |
| +SessionLengthLimiter::Delegate::~Delegate() { |
| +} |
| + |
| +SessionLengthLimiter::SessionLengthLimiter(Delegate* delegate, |
| + PrefService* prefs) |
| + : delegate_(delegate ? delegate : new SessionLengthLimiterDelegateImpl) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + // Update the session start time in prefs to the current time when going |
| + // through a user login. If the browser is restarting after a crash instead, |
| + // only update the value if it appears corrupted (value unset, value lying in |
| + // the future, zero value). |
| + int64 session_start_time = prefs->GetInt64(prefs::kSessionStartTime); |
| + int64 now = delegate_->GetCurrentTime().ToInternalValue(); |
| + if (!UserManager::Get()->HasBrowserRestarted() || |
| + session_start_time <= 0 || session_start_time > now) { |
| + prefs->SetInt64(prefs::kSessionStartTime, now); |
| + session_start_time = now; |
| + } |
| + session_start_time_ = base::Time::FromInternalValue(session_start_time); |
| + |
| + // Listen for changes to the session length limit. |
| + pref_change_registrar_.Init(prefs); |
| + pref_change_registrar_.Add( |
| + prefs::kSessionLengthLimit, |
| + base::Bind(&SessionLengthLimiter::OnSessionLengthLimitChanged, |
| + base::Unretained(this))); |
| + OnSessionLengthLimitChanged(); |
| +} |
| + |
| +SessionLengthLimiter::~SessionLengthLimiter() { |
| +} |
| + |
| +void SessionLengthLimiter::Shutdown() { |
| + pref_change_registrar_.RemoveAll(); |
|
Mattias Nissler (ping if slow)
2012/12/12 10:12:57
not needed AFAICS
bartfab (slow)
2012/12/13 16:22:48
Correct. I only did this because other PKS do it,
|
| +} |
| + |
| +void SessionLengthLimiter::AddObserver(Observer* observer) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + observers_.AddObserver(observer); |
| + observer->SessionTimeRemainingChanged(GetRemainingTime().get()); |
| +} |
| + |
| +void SessionLengthLimiter::RemoveObserver(Observer* observer) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + observers_.RemoveObserver(observer); |
| +} |
| + |
| +void SessionLengthLimiter::OnSessionLengthLimitChanged() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + int limit; |
| + const PrefServiceBase::Preference* session_length_limit_pref = |
| + pref_change_registrar_.prefs()-> |
| + FindPreference(prefs::kSessionLengthLimit); |
| + // If no session length limit is set, stop the timer, calling the observers |
| + // one last time to notify them that there is no more limit. |
| + if (session_length_limit_pref->IsDefaultValue() || |
| + !session_length_limit_pref->GetValue()->GetAsInteger(&limit)) { |
| + session_length_limit_ = base::TimeDelta(); |
| + StopTimer(); |
| + return; |
| + } |
| + // If a session length limit is set, clamp it to the valid range and start |
| + // the timer after calling the observers immediately to notify them that there |
| + // now is a limit. |
| + session_length_limit_ = base::TimeDelta::FromMilliseconds( |
| + std::min(std::max(limit, kSessionLengthLimitMinMs), |
| + kSessionLengthLimitMaxMs)); |
| + StartTimer(); |
| +} |
| + |
| +void SessionLengthLimiter::StartTimer() { |
| + TimerTick(); |
| + if (repeating_timer_.IsRunning()) |
| + return; |
| + repeating_timer_.Start( |
| + FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(kSessionLengthLimitTimerIntervalMs), |
| + this, |
| + &SessionLengthLimiter::TimerTick); |
| +} |
| + |
| +void SessionLengthLimiter::StopTimer() { |
| + if (repeating_timer_.IsRunning()) |
| + repeating_timer_.Stop(); |
| + TimerTick(); |
| +} |
| + |
| +void SessionLengthLimiter::TimerTick() { |
| + scoped_ptr<base::TimeDelta> remaining = GetRemainingTime(); |
| + FOR_EACH_OBSERVER(Observer, observers_, |
| + SessionTimeRemainingChanged(remaining.get())); |
| + // End the session if a limit is set and the remaining time reaches zero. |
| + if (remaining && *remaining == base::TimeDelta()) |
| + delegate_->Logout(); |
| +} |
| + |
| +scoped_ptr<base::TimeDelta> SessionLengthLimiter::GetRemainingTime() const { |
|
Mattias Nissler (ping if slow)
2012/12/12 10:12:57
Wrapping in a scoped_ptr for returning an optional
bartfab (slow)
2012/12/13 16:22:48
Done.
|
| + // If no limit is set, return |NULL|. |
| + const base::TimeDelta kZeroTimeDelta = base::TimeDelta(); |
| + if (session_length_limit_ == kZeroTimeDelta) |
| + return scoped_ptr<base::TimeDelta>(); |
| + // If a limit is set, return the remaining time, clamped so that it never |
| + // falls below zero. |
| + base::TimeDelta remaining = session_length_limit_ - |
| + (delegate_->GetCurrentTime() - session_start_time_); |
| + if (remaining < kZeroTimeDelta) |
| + remaining = kZeroTimeDelta; |
| + return scoped_ptr<base::TimeDelta>(new base::TimeDelta(remaining)); |
| +} |
| + |
| +} // namespace chromeos |