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