Upstream version 9.38.198.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 "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