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