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
CloudPolicyRefreshScheduler(CloudPolicyClient * client,CloudPolicyStore * store,const scoped_refptr<base::SequencedTaskRunner> & task_runner)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
~CloudPolicyRefreshScheduler()92 CloudPolicyRefreshScheduler::~CloudPolicyRefreshScheduler() {
93 store_->RemoveObserver(this);
94 client_->RemoveObserver(this);
95 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
96 }
97
SetRefreshDelay(int64 refresh_delay)98 void CloudPolicyRefreshScheduler::SetRefreshDelay(int64 refresh_delay) {
99 refresh_delay_ms_ = std::min(std::max(refresh_delay, kRefreshDelayMinMs),
100 kRefreshDelayMaxMs);
101 ScheduleRefresh();
102 }
103
RefreshSoon()104 void CloudPolicyRefreshScheduler::RefreshSoon() {
105 rate_limiter_.PostRequest();
106 }
107
SetInvalidationServiceAvailability(bool is_available)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
OnPolicyFetched(CloudPolicyClient * client)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
OnRegistrationStateChanged(CloudPolicyClient * client)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
OnClientError(CloudPolicyClient * client)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
OnStoreLoaded(CloudPolicyStore * store)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
OnStoreError(CloudPolicyStore * store)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
OnIPAddressChanged()177 void CloudPolicyRefreshScheduler::OnIPAddressChanged() {
178 if (client_->status() == DM_STATUS_REQUEST_FAILED)
179 RefreshSoon();
180 }
181
UpdateLastRefreshFromPolicy()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
RefreshNow()234 void CloudPolicyRefreshScheduler::RefreshNow() {
235 last_refresh_ = base::Time();
236 ScheduleRefresh();
237 }
238
ScheduleRefresh()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
PerformRefresh()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
RefreshAfter(int delta_ms)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