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