OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/policy/cloud/cloud_policy_invalidator.h" | 5 #include "chrome/browser/policy/cloud/cloud_policy_invalidator.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/hash.h" | 9 #include "base/hash.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "policy/policy_constants.h" | 23 #include "policy/policy_constants.h" |
24 #include "sync/notifier/object_id_invalidation_map.h" | 24 #include "sync/notifier/object_id_invalidation_map.h" |
25 | 25 |
26 namespace policy { | 26 namespace policy { |
27 | 27 |
28 const int CloudPolicyInvalidator::kMissingPayloadDelay = 5; | 28 const int CloudPolicyInvalidator::kMissingPayloadDelay = 5; |
29 const int CloudPolicyInvalidator::kMaxFetchDelayDefault = 120000; | 29 const int CloudPolicyInvalidator::kMaxFetchDelayDefault = 120000; |
30 const int CloudPolicyInvalidator::kMaxFetchDelayMin = 1000; | 30 const int CloudPolicyInvalidator::kMaxFetchDelayMin = 1000; |
31 const int CloudPolicyInvalidator::kMaxFetchDelayMax = 300000; | 31 const int CloudPolicyInvalidator::kMaxFetchDelayMax = 300000; |
32 const int CloudPolicyInvalidator::kInvalidationGracePeriod = 10; | 32 const int CloudPolicyInvalidator::kInvalidationGracePeriod = 10; |
| 33 const int CloudPolicyInvalidator::kUnknownVersionIgnorePeriod = 30; |
| 34 const int CloudPolicyInvalidator::kMaxInvalidationTimeDelta = 300; |
33 | 35 |
34 CloudPolicyInvalidator::CloudPolicyInvalidator( | 36 CloudPolicyInvalidator::CloudPolicyInvalidator( |
35 CloudPolicyCore* core, | 37 CloudPolicyCore* core, |
36 const scoped_refptr<base::SequencedTaskRunner>& task_runner, | 38 const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
37 scoped_ptr<base::Clock> clock) | 39 scoped_ptr<base::Clock> clock) |
38 : state_(UNINITIALIZED), | 40 : state_(UNINITIALIZED), |
39 core_(core), | 41 core_(core), |
40 task_runner_(task_runner), | 42 task_runner_(task_runner), |
41 clock_(clock.Pass()), | 43 clock_(clock.Pass()), |
42 invalidation_service_(NULL), | 44 invalidation_service_(NULL), |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 !invalidation.is_unknown_version() && | 169 !invalidation.is_unknown_version() && |
168 invalidation.version() <= invalidation_version_) { | 170 invalidation.version() <= invalidation_version_) { |
169 return; | 171 return; |
170 } | 172 } |
171 | 173 |
172 // If there is still a pending invalidation, acknowledge it, since we only | 174 // If there is still a pending invalidation, acknowledge it, since we only |
173 // care about the latest invalidation. | 175 // care about the latest invalidation. |
174 if (invalid_) | 176 if (invalid_) |
175 AcknowledgeInvalidation(); | 177 AcknowledgeInvalidation(); |
176 | 178 |
| 179 // Get the version and payload from the invalidation. |
| 180 // When an invalidation with unknown version is received, use negative |
| 181 // numbers based on the number of such invalidations received. This |
| 182 // ensures that the version numbers do not collide with "real" versions |
| 183 // (which are positive) or previous invalidations with unknown version. |
| 184 int64 version; |
| 185 std::string payload; |
| 186 if (invalidation.is_unknown_version()) { |
| 187 version = -(++unknown_version_invalidation_count_); |
| 188 } else { |
| 189 version = invalidation.version(); |
| 190 payload = invalidation.payload(); |
| 191 } |
| 192 |
| 193 // Ignore the invalidation if it is expired. |
| 194 bool is_expired = IsInvalidationExpired(version); |
| 195 UMA_HISTOGRAM_ENUMERATION( |
| 196 kMetricPolicyInvalidations, |
| 197 GetInvalidationMetric(payload.empty(), is_expired), |
| 198 POLICY_INVALIDATION_TYPE_SIZE); |
| 199 if (is_expired) { |
| 200 invalidation.Acknowledge(); |
| 201 return; |
| 202 } |
| 203 |
177 // Update invalidation state. | 204 // Update invalidation state. |
178 invalid_ = true; | 205 invalid_ = true; |
179 invalidation_.reset(new syncer::Invalidation(invalidation)); | 206 invalidation_.reset(new syncer::Invalidation(invalidation)); |
180 | 207 invalidation_version_ = version; |
181 // When an invalidation with unknown version is received, use negative | |
182 // numbers based on the number of such invalidations received. This | |
183 // ensures that the version numbers do not collide with "real" versions | |
184 // (which are positive) or previous invalidations with unknown version. | |
185 if (invalidation.is_unknown_version()) { | |
186 invalidation_version_ = -(++unknown_version_invalidation_count_); | |
187 } else { | |
188 invalidation_version_ = invalidation.version(); | |
189 } | |
190 | 208 |
191 // In order to prevent the cloud policy server from becoming overwhelmed when | 209 // In order to prevent the cloud policy server from becoming overwhelmed when |
192 // a policy with many users is modified, delay for a random period of time | 210 // a policy with many users is modified, delay for a random period of time |
193 // before fetching the policy. Delay for at least 20ms so that if multiple | 211 // before fetching the policy. Delay for at least 20ms so that if multiple |
194 // invalidations are received in quick succession, only one fetch will be | 212 // invalidations are received in quick succession, only one fetch will be |
195 // performed. | 213 // performed. |
196 base::TimeDelta delay = base::TimeDelta::FromMilliseconds( | 214 base::TimeDelta delay = base::TimeDelta::FromMilliseconds( |
197 base::RandInt(20, max_fetch_delay_)); | 215 base::RandInt(20, max_fetch_delay_)); |
198 | 216 |
199 std::string payload; | |
200 if (!invalidation.is_unknown_version()) | |
201 payload = invalidation.payload(); | |
202 | |
203 // If there is a payload, the policy can be refreshed at any time, so set | 217 // If there is a payload, the policy can be refreshed at any time, so set |
204 // the version and payload on the client immediately. Otherwise, the refresh | 218 // the version and payload on the client immediately. Otherwise, the refresh |
205 // must only run after at least kMissingPayloadDelay minutes. | 219 // must only run after at least kMissingPayloadDelay minutes. |
206 if (!payload.empty()) | 220 if (!payload.empty()) |
207 core_->client()->SetInvalidationInfo(invalidation_version_, payload); | 221 core_->client()->SetInvalidationInfo(version, payload); |
208 else | 222 else |
209 delay += base::TimeDelta::FromMinutes(kMissingPayloadDelay); | 223 delay += base::TimeDelta::FromMinutes(kMissingPayloadDelay); |
210 | 224 |
211 // Schedule the policy to be refreshed. | 225 // Schedule the policy to be refreshed. |
212 task_runner_->PostDelayedTask( | 226 task_runner_->PostDelayedTask( |
213 FROM_HERE, | 227 FROM_HERE, |
214 base::Bind( | 228 base::Bind( |
215 &CloudPolicyInvalidator::RefreshPolicy, | 229 &CloudPolicyInvalidator::RefreshPolicy, |
216 weak_factory_.GetWeakPtr(), | 230 weak_factory_.GetWeakPtr(), |
217 payload.empty() /* is_missing_payload */), | 231 payload.empty() /* is_missing_payload */), |
218 delay); | 232 delay); |
219 | |
220 // Update the kMetricPolicyInvalidations histogram. | |
221 UMA_HISTOGRAM_BOOLEAN(kMetricPolicyInvalidations, !payload.empty()); | |
222 } | 233 } |
223 | 234 |
224 void CloudPolicyInvalidator::UpdateRegistration( | 235 void CloudPolicyInvalidator::UpdateRegistration( |
225 const enterprise_management::PolicyData* policy) { | 236 const enterprise_management::PolicyData* policy) { |
226 // Create the ObjectId based on the policy data. | 237 // Create the ObjectId based on the policy data. |
227 // If the policy does not specify an the ObjectId, then unregister. | 238 // If the policy does not specify an the ObjectId, then unregister. |
228 if (!policy || | 239 if (!policy || |
229 !policy->has_invalidation_source() || | 240 !policy->has_invalidation_source() || |
230 !policy->has_invalidation_name()) { | 241 !policy->has_invalidation_name()) { |
231 Unregister(); | 242 Unregister(); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 // Determine if the policy changed by comparing its hash value to the | 352 // Determine if the policy changed by comparing its hash value to the |
342 // previous policy's hash value. | 353 // previous policy's hash value. |
343 uint32 new_hash_value = 0; | 354 uint32 new_hash_value = 0; |
344 if (policy && policy->has_policy_value()) | 355 if (policy && policy->has_policy_value()) |
345 new_hash_value = base::Hash(policy->policy_value()); | 356 new_hash_value = base::Hash(policy->policy_value()); |
346 bool changed = new_hash_value != policy_hash_value_; | 357 bool changed = new_hash_value != policy_hash_value_; |
347 policy_hash_value_ = new_hash_value; | 358 policy_hash_value_ = new_hash_value; |
348 return changed; | 359 return changed; |
349 } | 360 } |
350 | 361 |
| 362 bool CloudPolicyInvalidator::IsInvalidationExpired(int64 version) { |
| 363 base::Time last_fetch_time = base::Time::UnixEpoch() + |
| 364 base::TimeDelta::FromMilliseconds(core_->store()->policy()->timestamp()); |
| 365 |
| 366 // If the version is unknown, consider the invalidation invalid if the |
| 367 // policy was fetched very recently. |
| 368 if (version < 0) { |
| 369 base::TimeDelta elapsed = clock_->Now() - last_fetch_time; |
| 370 return elapsed.InSeconds() < kUnknownVersionIgnorePeriod; |
| 371 } |
| 372 |
| 373 // The invalidation version is the timestamp in microseconds. If the |
| 374 // invalidation occurred before the last policy fetch, then the invalidation |
| 375 // is expired. Time is added to the invalidation to err on the side of not |
| 376 // expired. |
| 377 base::Time invalidation_time = base::Time::UnixEpoch() + |
| 378 base::TimeDelta::FromMicroseconds(version) + |
| 379 base::TimeDelta::FromSeconds(kMaxInvalidationTimeDelta); |
| 380 return invalidation_time < last_fetch_time; |
| 381 } |
| 382 |
351 int CloudPolicyInvalidator::GetPolicyRefreshMetric(bool policy_changed) { | 383 int CloudPolicyInvalidator::GetPolicyRefreshMetric(bool policy_changed) { |
352 if (policy_changed) { | 384 if (policy_changed) { |
353 if (invalid_) | 385 if (invalid_) |
354 return METRIC_POLICY_REFRESH_INVALIDATED_CHANGED; | 386 return METRIC_POLICY_REFRESH_INVALIDATED_CHANGED; |
355 if (GetInvalidationsEnabled()) | 387 if (GetInvalidationsEnabled()) |
356 return METRIC_POLICY_REFRESH_CHANGED; | 388 return METRIC_POLICY_REFRESH_CHANGED; |
357 return METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS; | 389 return METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS; |
358 } | 390 } |
359 if (invalid_) | 391 if (invalid_) |
360 return METRIC_POLICY_REFRESH_INVALIDATED_UNCHANGED; | 392 return METRIC_POLICY_REFRESH_INVALIDATED_UNCHANGED; |
361 return METRIC_POLICY_REFRESH_UNCHANGED; | 393 return METRIC_POLICY_REFRESH_UNCHANGED; |
362 } | 394 } |
363 | 395 |
| 396 int CloudPolicyInvalidator::GetInvalidationMetric(bool is_missing_payload, |
| 397 bool is_expired) { |
| 398 if (is_expired) { |
| 399 if (is_missing_payload) |
| 400 return POLICY_INVALIDATION_TYPE_NO_PAYLOAD_EXPIRED; |
| 401 return POLICY_INVALIDATION_TYPE_EXPIRED; |
| 402 } |
| 403 if (is_missing_payload) |
| 404 return POLICY_INVALIDATION_TYPE_NO_PAYLOAD; |
| 405 return POLICY_INVALIDATION_TYPE_NORMAL; |
| 406 } |
| 407 |
364 bool CloudPolicyInvalidator::GetInvalidationsEnabled() { | 408 bool CloudPolicyInvalidator::GetInvalidationsEnabled() { |
365 if (!invalidations_enabled_) | 409 if (!invalidations_enabled_) |
366 return false; | 410 return false; |
367 // If invalidations have been enabled for less than the grace period, then | 411 // If invalidations have been enabled for less than the grace period, then |
368 // consider invalidations to be disabled for metrics reporting. | 412 // consider invalidations to be disabled for metrics reporting. |
369 base::TimeDelta elapsed = clock_->Now() - invalidations_enabled_time_; | 413 base::TimeDelta elapsed = clock_->Now() - invalidations_enabled_time_; |
370 return elapsed.InSeconds() >= kInvalidationGracePeriod; | 414 return elapsed.InSeconds() >= kInvalidationGracePeriod; |
371 } | 415 } |
372 | 416 |
373 } // namespace policy | 417 } // namespace policy |
OLD | NEW |