Home | History | Annotate | Download | only in chromeos
      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 "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 
     19 namespace chromeos {
     20 
     21 namespace {
     22 
     23 // The minimum session time limit that can be set.
     24 const int kSessionLengthLimitMinMs = 30 * 1000; // 30 seconds.
     25 
     26 // The maximum session time limit that can be set.
     27 const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000; // 24 hours.
     28 
     29 // A default delegate implementation that returns the current time and does end
     30 // the current user's session when requested. This can be replaced with a mock
     31 // in tests.
     32 class SessionLengthLimiterDelegateImpl : public SessionLengthLimiter::Delegate {
     33  public:
     34   SessionLengthLimiterDelegateImpl();
     35   virtual ~SessionLengthLimiterDelegateImpl();
     36 
     37   virtual const base::TimeTicks GetCurrentTime() const OVERRIDE;
     38   virtual void StopSession() OVERRIDE;
     39 
     40  private:
     41   DISALLOW_COPY_AND_ASSIGN(SessionLengthLimiterDelegateImpl);
     42 };
     43 
     44 SessionLengthLimiterDelegateImpl::SessionLengthLimiterDelegateImpl() {
     45 }
     46 
     47 SessionLengthLimiterDelegateImpl::~SessionLengthLimiterDelegateImpl() {
     48 }
     49 
     50 const base::TimeTicks SessionLengthLimiterDelegateImpl::GetCurrentTime() const {
     51   return base::TimeTicks::Now();
     52 }
     53 
     54 void SessionLengthLimiterDelegateImpl::StopSession() {
     55   chrome::AttemptUserExit();
     56 }
     57 
     58 }  // namespace
     59 
     60 SessionLengthLimiter::Delegate::~Delegate() {
     61 }
     62 
     63 // static
     64 void SessionLengthLimiter::RegisterPrefs(PrefRegistrySimple* registry) {
     65   registry->RegisterInt64Pref(prefs::kSessionStartTime, 0);
     66   registry->RegisterIntegerPref(prefs::kSessionLengthLimit, 0);
     67 }
     68 
     69 SessionLengthLimiter::SessionLengthLimiter(Delegate* delegate,
     70                                            bool browser_restarted)
     71     : delegate_(delegate ? delegate : new SessionLengthLimiterDelegateImpl) {
     72   DCHECK(thread_checker_.CalledOnValidThread());
     73 
     74   // If this is a user login, set the session start time in local state to the
     75   // current time. If this a browser restart after a crash, set the session
     76   // start time only if its current value appears corrupted (value unset, value
     77   // lying in the future).
     78   PrefService* local_state = g_browser_process->local_state();
     79   int64 session_start_time = local_state->GetInt64(prefs::kSessionStartTime);
     80   const int64 now = delegate_->GetCurrentTime().ToInternalValue();
     81   if (!browser_restarted ||
     82       !local_state->HasPrefPath(prefs::kSessionStartTime) ||
     83       session_start_time > now) {
     84     local_state->SetInt64(prefs::kSessionStartTime, now);
     85     // Ensure that the session start time is persisted to local state.
     86     local_state->CommitPendingWrite();
     87     session_start_time = now;
     88   }
     89   session_start_time_ = base::TimeTicks::FromInternalValue(session_start_time);
     90 
     91   // Listen for changes to the session length limit.
     92   pref_change_registrar_.Init(local_state);
     93   pref_change_registrar_.Add(
     94       prefs::kSessionLengthLimit,
     95       base::Bind(&SessionLengthLimiter::OnSessionLengthLimitChanged,
     96                  base::Unretained(this)));
     97 
     98   // Handle the current session length limit, if any.
     99   OnSessionLengthLimitChanged();
    100 }
    101 
    102 SessionLengthLimiter::~SessionLengthLimiter() {
    103 }
    104 
    105 void SessionLengthLimiter::OnSessionLengthLimitChanged() {
    106   DCHECK(thread_checker_.CalledOnValidThread());
    107 
    108   // Stop any currently running timer.
    109   if (timer_)
    110     timer_->Stop();
    111 
    112   int limit;
    113   const PrefService::Preference* session_length_limit_pref =
    114       pref_change_registrar_.prefs()->
    115           FindPreference(prefs::kSessionLengthLimit);
    116   if (session_length_limit_pref->IsDefaultValue() ||
    117       !session_length_limit_pref->GetValue()->GetAsInteger(&limit)) {
    118     // If no session length limit is set, destroy the timer.
    119     timer_.reset();
    120     return;
    121   }
    122 
    123   // Clamp the session length limit to the valid range.
    124   const base::TimeDelta session_length_limit =
    125       base::TimeDelta::FromMilliseconds(std::min(std::max(
    126           limit, kSessionLengthLimitMinMs), kSessionLengthLimitMaxMs));
    127 
    128   // Calculate the remaining session time.
    129   const base::TimeDelta remaining = session_length_limit -
    130       (delegate_->GetCurrentTime() - session_start_time_);
    131 
    132   // Log out the user immediately if the session length limit has been reached
    133   // or exceeded.
    134   if (remaining <= base::TimeDelta()) {
    135     delegate_->StopSession();
    136     return;
    137   }
    138 
    139   // Set a timer to log out the user when the session length limit is reached.
    140   if (!timer_)
    141     timer_.reset(new base::OneShotTimer<SessionLengthLimiter::Delegate>);
    142   timer_->Start(FROM_HERE, remaining, delegate_.get(),
    143                 &SessionLengthLimiter::Delegate::StopSession);
    144 }
    145 
    146 }  // namespace chromeos
    147