OLD | NEW |
| (Empty) |
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 "chrome/browser/policy/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/sequenced_task_runner.h" | |
13 #include "base/time/default_tick_clock.h" | |
14 #include "base/time/tick_clock.h" | |
15 #include "chrome/browser/policy/cloud_policy_constants.h" | |
16 #include "chrome/common/chrome_notification_types.h" | |
17 #include "content/public/browser/notification_details.h" | |
18 | |
19 namespace policy { | |
20 | |
21 namespace { | |
22 | |
23 // The maximum rate at which to refresh policies. | |
24 const size_t kMaxRefreshesPerHour = 5; | |
25 | |
26 } // namespace | |
27 | |
28 const int64 CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs = | |
29 3 * 60 * 60 * 1000; // 3 hours. | |
30 const int64 CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs = | |
31 24 * 60 * 60 * 1000; // 1 day. | |
32 const int64 CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs = | |
33 5 * 60 * 1000; // 5 minutes. | |
34 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMinMs = | |
35 30 * 60 * 1000; // 30 minutes. | |
36 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMaxMs = | |
37 24 * 60 * 60 * 1000; // 1 day. | |
38 | |
39 CloudPolicyRefreshScheduler::CloudPolicyRefreshScheduler( | |
40 CloudPolicyClient* client, | |
41 CloudPolicyStore* store, | |
42 const scoped_refptr<base::SequencedTaskRunner>& task_runner) | |
43 : client_(client), | |
44 store_(store), | |
45 task_runner_(task_runner), | |
46 error_retry_delay_ms_(kInitialErrorRetryDelayMs), | |
47 refresh_delay_ms_(kDefaultRefreshDelayMs), | |
48 rate_limiter_(kMaxRefreshesPerHour, | |
49 base::TimeDelta::FromHours(1), | |
50 base::Bind(&CloudPolicyRefreshScheduler::RefreshNow, | |
51 base::Unretained(this)), | |
52 task_runner_, | |
53 scoped_ptr<base::TickClock>(new base::DefaultTickClock())) { | |
54 client_->AddObserver(this); | |
55 store_->AddObserver(this); | |
56 net::NetworkChangeNotifier::AddIPAddressObserver(this); | |
57 | |
58 UpdateLastRefreshFromPolicy(); | |
59 ScheduleRefresh(); | |
60 } | |
61 | |
62 CloudPolicyRefreshScheduler::~CloudPolicyRefreshScheduler() { | |
63 store_->RemoveObserver(this); | |
64 client_->RemoveObserver(this); | |
65 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); | |
66 } | |
67 | |
68 void CloudPolicyRefreshScheduler::SetRefreshDelay(int64 refresh_delay) { | |
69 refresh_delay_ms_ = std::min(std::max(refresh_delay, kRefreshDelayMinMs), | |
70 kRefreshDelayMaxMs); | |
71 ScheduleRefresh(); | |
72 } | |
73 | |
74 void CloudPolicyRefreshScheduler::RefreshSoon() { | |
75 rate_limiter_.PostRequest(); | |
76 } | |
77 | |
78 void CloudPolicyRefreshScheduler::OnPolicyFetched(CloudPolicyClient* client) { | |
79 error_retry_delay_ms_ = kInitialErrorRetryDelayMs; | |
80 | |
81 // Schedule the next refresh. | |
82 last_refresh_ = base::Time::NowFromSystemTime(); | |
83 ScheduleRefresh(); | |
84 } | |
85 | |
86 void CloudPolicyRefreshScheduler::OnRegistrationStateChanged( | |
87 CloudPolicyClient* client) { | |
88 error_retry_delay_ms_ = kInitialErrorRetryDelayMs; | |
89 | |
90 // The client might have registered, so trigger an immediate refresh. | |
91 RefreshNow(); | |
92 } | |
93 | |
94 void CloudPolicyRefreshScheduler::OnClientError(CloudPolicyClient* client) { | |
95 // Save the status for below. | |
96 DeviceManagementStatus status = client_->status(); | |
97 | |
98 // Schedule an error retry if applicable. | |
99 last_refresh_ = base::Time::NowFromSystemTime(); | |
100 ScheduleRefresh(); | |
101 | |
102 // Update the retry delay. | |
103 if (client->is_registered() && | |
104 (status == DM_STATUS_REQUEST_FAILED || | |
105 status == DM_STATUS_TEMPORARY_UNAVAILABLE)) { | |
106 error_retry_delay_ms_ = std::min(error_retry_delay_ms_ * 2, | |
107 refresh_delay_ms_); | |
108 } else { | |
109 error_retry_delay_ms_ = kInitialErrorRetryDelayMs; | |
110 } | |
111 } | |
112 | |
113 void CloudPolicyRefreshScheduler::OnStoreLoaded(CloudPolicyStore* store) { | |
114 UpdateLastRefreshFromPolicy(); | |
115 | |
116 // Re-schedule the next refresh in case the is_managed bit changed. | |
117 ScheduleRefresh(); | |
118 } | |
119 | |
120 void CloudPolicyRefreshScheduler::OnStoreError(CloudPolicyStore* store) { | |
121 // If |store_| fails, the is_managed bit that it provides may become stale. | |
122 // The best guess in that situation is to assume is_managed didn't change and | |
123 // continue using the stale information. Thus, no specific response to a store | |
124 // error is required. NB: Changes to is_managed fire OnStoreLoaded(). | |
125 } | |
126 | |
127 void CloudPolicyRefreshScheduler::OnIPAddressChanged() { | |
128 if (client_->status() == DM_STATUS_REQUEST_FAILED) | |
129 RefreshAfter(0); | |
130 } | |
131 | |
132 void CloudPolicyRefreshScheduler::UpdateLastRefreshFromPolicy() { | |
133 if (!last_refresh_.is_null()) | |
134 return; | |
135 | |
136 // If the client has already fetched policy, assume that happened recently. If | |
137 // that assumption ever breaks, the proper thing to do probably is to move the | |
138 // |last_refresh_| bookkeeping to CloudPolicyClient. | |
139 if (!client_->responses().empty()) { | |
140 last_refresh_ = base::Time::NowFromSystemTime(); | |
141 return; | |
142 } | |
143 | |
144 // If there is a cached non-managed response, make sure to only re-query the | |
145 // server after kUnmanagedRefreshDelayMs. NB: For existing policy, an | |
146 // immediate refresh is intentional. | |
147 if (store_->has_policy() && !store_->is_managed()) { | |
148 last_refresh_ = | |
149 base::Time::UnixEpoch() + | |
150 base::TimeDelta::FromMilliseconds(store_->policy()->timestamp()); | |
151 } | |
152 } | |
153 | |
154 void CloudPolicyRefreshScheduler::RefreshNow() { | |
155 last_refresh_ = base::Time(); | |
156 ScheduleRefresh(); | |
157 } | |
158 | |
159 void CloudPolicyRefreshScheduler::ScheduleRefresh() { | |
160 // If the client isn't registered, there is nothing to do. | |
161 if (!client_->is_registered()) { | |
162 refresh_callback_.Cancel(); | |
163 return; | |
164 } | |
165 | |
166 // If there is a registration, go by the client's status. That will tell us | |
167 // what the appropriate refresh delay should be. | |
168 switch (client_->status()) { | |
169 case DM_STATUS_SUCCESS: | |
170 if (store_->is_managed()) | |
171 RefreshAfter(refresh_delay_ms_); | |
172 else | |
173 RefreshAfter(kUnmanagedRefreshDelayMs); | |
174 return; | |
175 case DM_STATUS_SERVICE_ACTIVATION_PENDING: | |
176 case DM_STATUS_SERVICE_POLICY_NOT_FOUND: | |
177 RefreshAfter(refresh_delay_ms_); | |
178 return; | |
179 case DM_STATUS_REQUEST_FAILED: | |
180 case DM_STATUS_TEMPORARY_UNAVAILABLE: | |
181 RefreshAfter(error_retry_delay_ms_); | |
182 return; | |
183 case DM_STATUS_REQUEST_INVALID: | |
184 case DM_STATUS_HTTP_STATUS_ERROR: | |
185 case DM_STATUS_RESPONSE_DECODING_ERROR: | |
186 case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED: | |
187 RefreshAfter(kUnmanagedRefreshDelayMs); | |
188 return; | |
189 case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID: | |
190 case DM_STATUS_SERVICE_DEVICE_NOT_FOUND: | |
191 case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER: | |
192 case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT: | |
193 case DM_STATUS_SERVICE_MISSING_LICENSES: | |
194 // Need a re-registration, no use in retrying. | |
195 return; | |
196 } | |
197 | |
198 NOTREACHED() << "Invalid client status " << client_->status(); | |
199 RefreshAfter(kUnmanagedRefreshDelayMs); | |
200 } | |
201 | |
202 void CloudPolicyRefreshScheduler::PerformRefresh() { | |
203 if (client_->is_registered()) { | |
204 // Update |last_refresh_| so another fetch isn't triggered inadvertently. | |
205 last_refresh_ = base::Time::NowFromSystemTime(); | |
206 | |
207 // The result of this operation will be reported through a callback, at | |
208 // which point the next refresh will be scheduled. | |
209 client_->FetchPolicy(); | |
210 return; | |
211 } | |
212 | |
213 // This should never happen, as the registration change should have been | |
214 // handled via OnRegistrationStateChanged(). | |
215 NOTREACHED(); | |
216 } | |
217 | |
218 void CloudPolicyRefreshScheduler::RefreshAfter(int delta_ms) { | |
219 base::TimeDelta delta(base::TimeDelta::FromMilliseconds(delta_ms)); | |
220 refresh_callback_.Cancel(); | |
221 | |
222 // Schedule the callback. | |
223 base::TimeDelta delay = | |
224 std::max((last_refresh_ + delta) - base::Time::NowFromSystemTime(), | |
225 base::TimeDelta()); | |
226 refresh_callback_.Reset( | |
227 base::Bind(&CloudPolicyRefreshScheduler::PerformRefresh, | |
228 base::Unretained(this))); | |
229 task_runner_->PostDelayedTask(FROM_HERE, refresh_callback_.callback(), delay); | |
230 } | |
231 | |
232 } // namespace policy | |
OLD | NEW |