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
CloudPolicyRefreshScheduler(CloudPolicyClient * client,CloudPolicyStore * store,const scoped_refptr<base::SequencedTaskRunner> & task_runner)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
~CloudPolicyRefreshScheduler()77 CloudPolicyRefreshScheduler::~CloudPolicyRefreshScheduler() {
78 store_->RemoveObserver(this);
79 client_->RemoveObserver(this);
80 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
81 }
82
SetRefreshDelay(int64 refresh_delay)83 void CloudPolicyRefreshScheduler::SetRefreshDelay(int64 refresh_delay) {
84 refresh_delay_ms_ = std::min(std::max(refresh_delay, kRefreshDelayMinMs),
85 kRefreshDelayMaxMs);
86 ScheduleRefresh();
87 }
88
RefreshSoon()89 void CloudPolicyRefreshScheduler::RefreshSoon() {
90 RefreshNow();
91 }
92
SetInvalidationServiceAvailability(bool is_available)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
OnPolicyFetched(CloudPolicyClient * client)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
OnRegistrationStateChanged(CloudPolicyClient * client)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
OnClientError(CloudPolicyClient * client)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
OnStoreLoaded(CloudPolicyStore * store)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
OnStoreError(CloudPolicyStore * store)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
OnIPAddressChanged()162 void CloudPolicyRefreshScheduler::OnIPAddressChanged() {
163 if (client_->status() == DM_STATUS_REQUEST_FAILED)
164 RefreshSoon();
165 }
166
UpdateLastRefreshFromPolicy()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
RefreshNow()219 void CloudPolicyRefreshScheduler::RefreshNow() {
220 last_refresh_ = base::Time();
221 ScheduleRefresh();
222 }
223
ScheduleRefresh()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
PerformRefresh()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
RefreshAfter(int delta_ms)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