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/policy/cloud/cloud_policy_refresh_scheduler.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/metrics/histogram.h" 13 #include "base/sequenced_task_runner.h" 14 #include "base/time/default_tick_clock.h" 15 #include "base/time/tick_clock.h" 16 #include "chrome/browser/chrome_notification_types.h" 17 #include "chrome/browser/policy/cloud/cloud_policy_constants.h" 18 #include "content/public/browser/notification_details.h" 19 20 namespace policy { 21 22 namespace { 23 24 // The maximum rate at which to refresh policies. 25 const size_t kMaxRefreshesPerHour = 5; 26 27 // The maximum time to wait for the invalidations service to become available 28 // before starting to issue requests. 29 // TODO(joaodasilva): set this to a non-zero value once the invalidations 30 // service is wired to this class and we have a good estimate of how long 31 // to wait. 32 const int kWaitForInvalidationsTimeoutSeconds = 0; 33 34 } // namespace 35 36 #if defined(OS_ANDROID) 37 38 const int64 CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs = 39 24 * 60 * 60 * 1000; // 1 day. 40 const int64 CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs = 41 24 * 60 * 60 * 1000; // 1 day. 42 // Delay for periodic refreshes when the invalidations service is available, 43 // in milliseconds. 44 // TODO(joaodasilva): increase this value once we're confident that the 45 // invalidations channel works as expected. 46 const int64 CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs = 47 24 * 60 * 60 * 1000; // 1 day. 48 const int64 CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs = 49 5 * 60 * 1000; // 5 minutes. 50 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMinMs = 51 30 * 60 * 1000; // 30 minutes. 52 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMaxMs = 53 7 * 24 * 60 * 60 * 1000; // 1 week. 54 55 #else 56 57 const int64 CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs = 58 3 * 60 * 60 * 1000; // 3 hours. 59 const int64 CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs = 60 24 * 60 * 60 * 1000; // 1 day. 61 // Delay for periodic refreshes when the invalidations service is available, 62 // in milliseconds. 63 // TODO(joaodasilva): increase this value once we're confident that the 64 // invalidations channel works as expected. 65 const int64 CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs = 66 24 * 60 * 60 * 1000; // 1 day. 67 const int64 CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs = 68 5 * 60 * 1000; // 5 minutes. 69 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMinMs = 70 30 * 60 * 1000; // 30 minutes. 71 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMaxMs = 72 24 * 60 * 60 * 1000; // 1 day. 73 74 #endif 75 76 CloudPolicyRefreshScheduler::CloudPolicyRefreshScheduler( 77 CloudPolicyClient* client, 78 CloudPolicyStore* store, 79 const scoped_refptr<base::SequencedTaskRunner>& task_runner) 80 : client_(client), 81 store_(store), 82 task_runner_(task_runner), 83 error_retry_delay_ms_(kInitialErrorRetryDelayMs), 84 refresh_delay_ms_(kDefaultRefreshDelayMs), 85 rate_limiter_(kMaxRefreshesPerHour, 86 base::TimeDelta::FromHours(1), 87 base::Bind(&CloudPolicyRefreshScheduler::RefreshNow, 88 base::Unretained(this)), 89 task_runner_, 90 scoped_ptr<base::TickClock>(new base::DefaultTickClock())), 91 invalidations_available_(false), 92 creation_time_(base::Time::NowFromSystemTime()) { 93 client_->AddObserver(this); 94 store_->AddObserver(this); 95 net::NetworkChangeNotifier::AddIPAddressObserver(this); 96 97 UpdateLastRefreshFromPolicy(); 98 WaitForInvalidationService(); 99 } 100 101 CloudPolicyRefreshScheduler::~CloudPolicyRefreshScheduler() { 102 store_->RemoveObserver(this); 103 client_->RemoveObserver(this); 104 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); 105 } 106 107 void CloudPolicyRefreshScheduler::SetRefreshDelay(int64 refresh_delay) { 108 refresh_delay_ms_ = std::min(std::max(refresh_delay, kRefreshDelayMinMs), 109 kRefreshDelayMaxMs); 110 ScheduleRefresh(); 111 } 112 113 void CloudPolicyRefreshScheduler::RefreshSoon() { 114 // An external consumer needs a policy update now (e.g. a new extension, or 115 // the InvalidationService received a policy invalidation), so don't wait 116 // before fetching anymore. 117 wait_for_invalidations_timeout_callback_.Cancel(); 118 rate_limiter_.PostRequest(); 119 } 120 121 void CloudPolicyRefreshScheduler::SetInvalidationServiceAvailability( 122 bool is_available) { 123 if (!creation_time_.is_null()) { 124 base::TimeDelta elapsed = base::Time::NowFromSystemTime() - creation_time_; 125 UMA_HISTOGRAM_MEDIUM_TIMES("Enterprise.PolicyInvalidationsStartupTime", 126 elapsed); 127 creation_time_ = base::Time(); 128 } 129 130 if (is_available == invalidations_available_) { 131 // No change in state. If we're currently WaitingForInvalidationService 132 // then the timeout task will eventually execute and trigger a reschedule; 133 // let the InvalidationService keep retrying until that happens. 134 return; 135 } 136 137 wait_for_invalidations_timeout_callback_.Cancel(); 138 invalidations_available_ = is_available; 139 140 if (invalidations_available_) { 141 ScheduleRefresh(); 142 } else { 143 // If the invalidation service was previously available but is now offline 144 // then this may be a temporary failure; give it some time to recover before 145 // falling back on the polling behavior. 146 WaitForInvalidationService(); 147 } 148 } 149 150 void CloudPolicyRefreshScheduler::OnPolicyFetched(CloudPolicyClient* client) { 151 error_retry_delay_ms_ = kInitialErrorRetryDelayMs; 152 153 // Schedule the next refresh. 154 last_refresh_ = base::Time::NowFromSystemTime(); 155 ScheduleRefresh(); 156 } 157 158 void CloudPolicyRefreshScheduler::OnRegistrationStateChanged( 159 CloudPolicyClient* client) { 160 error_retry_delay_ms_ = kInitialErrorRetryDelayMs; 161 162 // The client might have registered, so trigger an immediate refresh. 163 RefreshNow(); 164 } 165 166 void CloudPolicyRefreshScheduler::OnClientError(CloudPolicyClient* client) { 167 // Save the status for below. 168 DeviceManagementStatus status = client_->status(); 169 170 // Schedule an error retry if applicable. 171 last_refresh_ = base::Time::NowFromSystemTime(); 172 ScheduleRefresh(); 173 174 // Update the retry delay. 175 if (client->is_registered() && 176 (status == DM_STATUS_REQUEST_FAILED || 177 status == DM_STATUS_TEMPORARY_UNAVAILABLE)) { 178 error_retry_delay_ms_ = std::min(error_retry_delay_ms_ * 2, 179 refresh_delay_ms_); 180 } else { 181 error_retry_delay_ms_ = kInitialErrorRetryDelayMs; 182 } 183 } 184 185 void CloudPolicyRefreshScheduler::OnStoreLoaded(CloudPolicyStore* store) { 186 UpdateLastRefreshFromPolicy(); 187 188 // Re-schedule the next refresh in case the is_managed bit changed. 189 ScheduleRefresh(); 190 } 191 192 void CloudPolicyRefreshScheduler::OnStoreError(CloudPolicyStore* store) { 193 // If |store_| fails, the is_managed bit that it provides may become stale. 194 // The best guess in that situation is to assume is_managed didn't change and 195 // continue using the stale information. Thus, no specific response to a store 196 // error is required. NB: Changes to is_managed fire OnStoreLoaded(). 197 } 198 199 void CloudPolicyRefreshScheduler::OnIPAddressChanged() { 200 if (client_->status() == DM_STATUS_REQUEST_FAILED) 201 RefreshSoon(); 202 } 203 204 void CloudPolicyRefreshScheduler::UpdateLastRefreshFromPolicy() { 205 if (!last_refresh_.is_null()) 206 return; 207 208 // If the client has already fetched policy, assume that happened recently. If 209 // that assumption ever breaks, the proper thing to do probably is to move the 210 // |last_refresh_| bookkeeping to CloudPolicyClient. 211 if (!client_->responses().empty()) { 212 last_refresh_ = base::Time::NowFromSystemTime(); 213 return; 214 } 215 216 #if defined(OS_ANDROID) 217 // Refreshing on Android: 218 // - if no user is signed-in then the |client_| is never registered and 219 // nothing happens here. 220 // - if the user is signed-in but isn't enterprise then the |client_| is 221 // never registered and nothing happens here. 222 // - if the user is signed-in but isn't registered for policy yet then the 223 // |client_| isn't registered either; the UserPolicySigninService will try 224 // to register, and OnRegistrationStateChanged() will be invoked later. 225 // - if the client is signed-in and has policy then its timestamp is used to 226 // determine when to perform the next fetch, which will be once the cached 227 // version is considered "old enough". 228 // 229 // If there is an old policy cache then a fetch will be performed "soon"; if 230 // that fetch fails then a retry is attempted after a delay, with exponential 231 // backoff. If those fetches keep failing then the cached timestamp is *not* 232 // updated, and another fetch (and subsequent retries) will be attempted 233 // again on the next startup. 234 // 235 // But if the cached policy is considered fresh enough then we try to avoid 236 // fetching again on startup; the Android logic differs from the desktop in 237 // this aspect. 238 if (store_->has_policy() && store_->policy()->has_timestamp()) { 239 last_refresh_ = 240 base::Time::UnixEpoch() + 241 base::TimeDelta::FromMilliseconds(store_->policy()->timestamp()); 242 } 243 #else 244 // If there is a cached non-managed response, make sure to only re-query the 245 // server after kUnmanagedRefreshDelayMs. NB: For existing policy, an 246 // immediate refresh is intentional. 247 if (store_->has_policy() && store_->policy()->has_timestamp() && 248 !store_->is_managed()) { 249 last_refresh_ = 250 base::Time::UnixEpoch() + 251 base::TimeDelta::FromMilliseconds(store_->policy()->timestamp()); 252 } 253 #endif 254 } 255 256 void CloudPolicyRefreshScheduler::RefreshNow() { 257 last_refresh_ = base::Time(); 258 ScheduleRefresh(); 259 } 260 261 void CloudPolicyRefreshScheduler::ScheduleRefresh() { 262 // If the client isn't registered, there is nothing to do. 263 if (!client_->is_registered()) { 264 refresh_callback_.Cancel(); 265 return; 266 } 267 268 // Don't schedule anything yet if we're still waiting for the invalidations 269 // service. 270 if (WaitingForInvalidationService()) 271 return; 272 273 // If policy invalidations are available then periodic updates are done at 274 // a much lower rate; otherwise use the |refresh_delay_ms_| value. 275 int64 refresh_delay_ms = 276 invalidations_available_ ? kWithInvalidationsRefreshDelayMs 277 : refresh_delay_ms_; 278 279 // If there is a registration, go by the client's status. That will tell us 280 // what the appropriate refresh delay should be. 281 switch (client_->status()) { 282 case DM_STATUS_SUCCESS: 283 if (store_->is_managed()) 284 RefreshAfter(refresh_delay_ms); 285 else 286 RefreshAfter(kUnmanagedRefreshDelayMs); 287 return; 288 case DM_STATUS_SERVICE_ACTIVATION_PENDING: 289 case DM_STATUS_SERVICE_POLICY_NOT_FOUND: 290 RefreshAfter(refresh_delay_ms); 291 return; 292 case DM_STATUS_REQUEST_FAILED: 293 case DM_STATUS_TEMPORARY_UNAVAILABLE: 294 RefreshAfter(error_retry_delay_ms_); 295 return; 296 case DM_STATUS_REQUEST_INVALID: 297 case DM_STATUS_HTTP_STATUS_ERROR: 298 case DM_STATUS_RESPONSE_DECODING_ERROR: 299 case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED: 300 RefreshAfter(kUnmanagedRefreshDelayMs); 301 return; 302 case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID: 303 case DM_STATUS_SERVICE_DEVICE_NOT_FOUND: 304 case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER: 305 case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT: 306 case DM_STATUS_SERVICE_MISSING_LICENSES: 307 // Need a re-registration, no use in retrying. 308 refresh_callback_.Cancel(); 309 return; 310 } 311 312 NOTREACHED() << "Invalid client status " << client_->status(); 313 RefreshAfter(kUnmanagedRefreshDelayMs); 314 } 315 316 void CloudPolicyRefreshScheduler::PerformRefresh() { 317 if (client_->is_registered()) { 318 // Update |last_refresh_| so another fetch isn't triggered inadvertently. 319 last_refresh_ = base::Time::NowFromSystemTime(); 320 321 // The result of this operation will be reported through a callback, at 322 // which point the next refresh will be scheduled. 323 client_->FetchPolicy(); 324 return; 325 } 326 327 // This should never happen, as the registration change should have been 328 // handled via OnRegistrationStateChanged(). 329 NOTREACHED(); 330 } 331 332 void CloudPolicyRefreshScheduler::RefreshAfter(int delta_ms) { 333 base::TimeDelta delta(base::TimeDelta::FromMilliseconds(delta_ms)); 334 refresh_callback_.Cancel(); 335 336 // Schedule the callback. 337 base::TimeDelta delay = 338 std::max((last_refresh_ + delta) - base::Time::NowFromSystemTime(), 339 base::TimeDelta()); 340 refresh_callback_.Reset( 341 base::Bind(&CloudPolicyRefreshScheduler::PerformRefresh, 342 base::Unretained(this))); 343 task_runner_->PostDelayedTask(FROM_HERE, refresh_callback_.callback(), delay); 344 } 345 346 void CloudPolicyRefreshScheduler::WaitForInvalidationService() { 347 DCHECK(!WaitingForInvalidationService()); 348 wait_for_invalidations_timeout_callback_.Reset( 349 base::Bind( 350 &CloudPolicyRefreshScheduler::OnWaitForInvalidationServiceTimeout, 351 base::Unretained(this))); 352 task_runner_->PostDelayedTask( 353 FROM_HERE, 354 wait_for_invalidations_timeout_callback_.callback(), 355 base::TimeDelta::FromSeconds(kWaitForInvalidationsTimeoutSeconds)); 356 } 357 358 void CloudPolicyRefreshScheduler::OnWaitForInvalidationServiceTimeout() { 359 wait_for_invalidations_timeout_callback_.Cancel(); 360 ScheduleRefresh(); 361 } 362 363 bool CloudPolicyRefreshScheduler::WaitingForInvalidationService() const { 364 return !wait_for_invalidations_timeout_callback_.IsCancelled(); 365 } 366 367 } // namespace policy 368