| 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 = 5; |
| 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::FromMinutes(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 |