| 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 |