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