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