1a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// found in the LICENSE file.
4a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
5a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/bind.h"
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/hash.h"
9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/location.h"
10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/metrics/histogram.h"
11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/rand_util.h"
12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/sequenced_task_runner.h"
13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/time/clock.h"
14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/time/time.h"
15a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/values.h"
160de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)#include "components/invalidation/invalidation_service.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/invalidation/object_id_invalidation_map.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/cloud_policy_client.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/enterprise_metrics.h"
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "policy/policy_constants.h"
22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)namespace policy {
24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const int CloudPolicyInvalidator::kMissingPayloadDelay = 5;
2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const int CloudPolicyInvalidator::kMaxFetchDelayDefault = 10000;
27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const int CloudPolicyInvalidator::kMaxFetchDelayMin = 1000;
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const int CloudPolicyInvalidator::kMaxFetchDelayMax = 300000;
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int CloudPolicyInvalidator::kInvalidationGracePeriod = 10;
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int CloudPolicyInvalidator::kUnknownVersionIgnorePeriod = 30;
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int CloudPolicyInvalidator::kMaxInvalidationTimeDelta = 300;
32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)CloudPolicyInvalidator::CloudPolicyInvalidator(
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    enterprise_management::DeviceRegisterRequest::Type type,
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    CloudPolicyCore* core,
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    scoped_ptr<base::Clock> clock,
386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    int64 highest_handled_invalidation_version)
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : state_(UNINITIALIZED),
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      type_(type),
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      core_(core),
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      task_runner_(task_runner),
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      clock_(clock.Pass()),
44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      invalidation_service_(NULL),
45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      invalidations_enabled_(false),
46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      invalidation_service_enabled_(false),
47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      is_registered_(false),
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      invalid_(false),
49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      invalidation_version_(0),
50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      unknown_version_invalidation_count_(0),
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      highest_handled_invalidation_version_(
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          highest_handled_invalidation_version),
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      max_fetch_delay_(kMaxFetchDelayDefault),
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      policy_hash_value_(0),
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(core);
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(task_runner.get());
586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // |highest_handled_invalidation_version_| indicates the highest actual
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // invalidation version handled. Since actual invalidations can have only
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // positive versions, this member may be zero (no versioned invalidation
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // handled yet) or positive. Negative values are not allowed:
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  //
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Negative version numbers are used internally by CloudPolicyInvalidator to
646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // keep track of unversioned invalidations. When such an invalidation is
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // handled, |highest_handled_invalidation_version_| remains unchanged and does
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // not become negative.
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK_LE(0, highest_handled_invalidation_version_);
68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)CloudPolicyInvalidator::~CloudPolicyInvalidator() {
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(state_ == SHUT_DOWN);
72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void CloudPolicyInvalidator::Initialize(
75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    invalidation::InvalidationService* invalidation_service) {
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(state_ == UNINITIALIZED);
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(invalidation_service);
79a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  invalidation_service_ = invalidation_service;
8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  state_ = STOPPED;
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  core_->AddObserver(this);
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (core_->refresh_scheduler())
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    OnRefreshSchedulerStarted(core_);
84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::Shutdown() {
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(state_ != SHUT_DOWN);
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (state_ == STARTED) {
90c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (is_registered_)
91a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      invalidation_service_->UnregisterInvalidationHandler(this);
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    core_->store()->RemoveObserver(this);
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    weak_factory_.InvalidateWeakPtrs();
94a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (state_ != UNINITIALIZED)
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    core_->RemoveObserver(this);
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  state_ = SHUT_DOWN;
98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
99a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
100a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::OnInvalidatorStateChange(
101a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    syncer::InvalidatorState state) {
10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(state_ == STARTED);
103a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  invalidation_service_enabled_ = state == syncer::INVALIDATIONS_ENABLED;
105a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  UpdateInvalidationsEnabled();
106a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
107a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
108a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::OnIncomingInvalidation(
109a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const syncer::ObjectIdInvalidationMap& invalidation_map) {
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(state_ == STARTED);
111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const syncer::SingleObjectInvalidationSet& list =
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      invalidation_map.ForObject(object_id_);
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (list.IsEmpty()) {
115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    NOTREACHED();
116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Acknowledge all except the invalidation with the highest version.
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  syncer::SingleObjectInvalidationSet::const_reverse_iterator it =
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      list.rbegin();
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ++it;
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for ( ; it != list.rend(); ++it) {
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    it->Acknowledge();
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Handle the highest version invalidation.
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  HandleInvalidation(list.back());
129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string CloudPolicyInvalidator::GetOwnerName() const { return "Cloud"; }
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void CloudPolicyInvalidator::OnCoreConnected(CloudPolicyCore* core) {}
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void CloudPolicyInvalidator::OnRefreshSchedulerStarted(CloudPolicyCore* core) {
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(state_ == STOPPED);
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  state_ = STARTED;
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  OnStoreLoaded(core_->store());
14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  core_->store()->AddObserver(this);
14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void CloudPolicyInvalidator::OnCoreDisconnecting(CloudPolicyCore* core) {
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(state_ == STARTED || state_ == STOPPED);
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (state_ == STARTED) {
14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Unregister();
14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    core_->store()->RemoveObserver(this);
14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    state_ = STOPPED;
15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
15158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::OnStoreLoaded(CloudPolicyStore* store) {
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(state_ == STARTED);
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool policy_changed = IsPolicyChanged(store->policy());
15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
158c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (is_registered_) {
1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Update the kMetricDevicePolicyRefresh/kMetricUserPolicyRefresh histogram.
1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (type_ == enterprise_management::DeviceRegisterRequest::DEVICE) {
1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION(kMetricDevicePolicyRefresh,
1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                GetPolicyRefreshMetric(policy_changed),
1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                METRIC_POLICY_REFRESH_SIZE);
1646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    } else {
1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION(kMetricUserPolicyRefresh,
1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                GetPolicyRefreshMetric(policy_changed),
1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                METRIC_POLICY_REFRESH_SIZE);
1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const int64 store_invalidation_version = store->invalidation_version();
171a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // If the policy was invalid and the version stored matches the latest
173a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // invalidation version, acknowledge the latest invalidation.
1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (invalid_ && store_invalidation_version == invalidation_version_)
175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      AcknowledgeInvalidation();
1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Update the highest invalidation version that was handled already.
1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (store_invalidation_version > highest_handled_invalidation_version_)
1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      highest_handled_invalidation_version_ = store_invalidation_version;
180a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
181a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
182a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  UpdateRegistration(store->policy());
183a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  UpdateMaxFetchDelay(store->policy_map());
184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::OnStoreError(CloudPolicyStore* store) {}
187a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::HandleInvalidation(
189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const syncer::Invalidation& invalidation) {
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Ignore old invalidations.
191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (invalid_ &&
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      !invalidation.is_unknown_version() &&
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      invalidation.version() <= invalidation_version_) {
194a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
196a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!invalidation.is_unknown_version() &&
1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      invalidation.version() <= highest_handled_invalidation_version_) {
1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // If this invalidation version was handled already, acknowledge the
2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // invalidation but ignore it otherwise.
2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    invalidation.Acknowledge();
2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
205a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // If there is still a pending invalidation, acknowledge it, since we only
206a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // care about the latest invalidation.
207a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (invalid_)
208a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    AcknowledgeInvalidation();
209a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
210c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Get the version and payload from the invalidation.
211a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // When an invalidation with unknown version is received, use negative
212a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // numbers based on the number of such invalidations received. This
213a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // ensures that the version numbers do not collide with "real" versions
214a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // (which are positive) or previous invalidations with unknown version.
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int64 version;
216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::string payload;
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (invalidation.is_unknown_version()) {
218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    version = -(++unknown_version_invalidation_count_);
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    version = invalidation.version();
221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    payload = invalidation.payload();
222c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
223c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
224c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Ignore the invalidation if it is expired.
225c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool is_expired = IsInvalidationExpired(version);
2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (type_ == enterprise_management::DeviceRegisterRequest::DEVICE) {
2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(
2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        kMetricDevicePolicyInvalidations,
2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        GetInvalidationMetric(payload.empty(), is_expired),
2316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        POLICY_INVALIDATION_TYPE_SIZE);
2326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else {
2336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(
2346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        kMetricUserPolicyInvalidations,
2356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        GetInvalidationMetric(payload.empty(), is_expired),
2366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        POLICY_INVALIDATION_TYPE_SIZE);
2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
238c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (is_expired) {
239c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    invalidation.Acknowledge();
240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
242a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Update invalidation state.
244c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  invalid_ = true;
245c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  invalidation_.reset(new syncer::Invalidation(invalidation));
246c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  invalidation_version_ = version;
247c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
248a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // In order to prevent the cloud policy server from becoming overwhelmed when
249a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // a policy with many users is modified, delay for a random period of time
250a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // before fetching the policy. Delay for at least 20ms so that if multiple
251a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // invalidations are received in quick succession, only one fetch will be
252a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // performed.
253a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::TimeDelta delay = base::TimeDelta::FromMilliseconds(
254a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::RandInt(20, max_fetch_delay_));
255a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // If there is a payload, the policy can be refreshed at any time, so set
25758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // the version and payload on the client immediately. Otherwise, the refresh
258a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // must only run after at least kMissingPayloadDelay minutes.
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!payload.empty())
260c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    core_->client()->SetInvalidationInfo(version, payload);
261a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  else
262a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    delay += base::TimeDelta::FromMinutes(kMissingPayloadDelay);
263a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Schedule the policy to be refreshed.
265a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  task_runner_->PostDelayedTask(
266a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      FROM_HERE,
267a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(
26858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          &CloudPolicyInvalidator::RefreshPolicy,
269a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          weak_factory_.GetWeakPtr(),
270a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          payload.empty() /* is_missing_payload */),
271a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      delay);
272a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
273a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
274a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::UpdateRegistration(
275a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const enterprise_management::PolicyData* policy) {
276a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Create the ObjectId based on the policy data.
277a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // If the policy does not specify an the ObjectId, then unregister.
278a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!policy ||
279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      !policy->has_invalidation_source() ||
280a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      !policy->has_invalidation_name()) {
281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    Unregister();
282a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
283a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  invalidation::ObjectId object_id(
285a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      policy->invalidation_source(),
286a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      policy->invalidation_name());
287a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
288a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // If the policy object id in the policy data is different from the currently
289a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // registered object id, update the object registration.
290c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!is_registered_ || !(object_id == object_id_))
291c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    Register(object_id);
292a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
293a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
294c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid CloudPolicyInvalidator::Register(const invalidation::ObjectId& object_id) {
295a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Register this handler with the invalidation service if needed.
296c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!is_registered_) {
297a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    OnInvalidatorStateChange(invalidation_service_->GetInvalidatorState());
298a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    invalidation_service_->RegisterInvalidationHandler(this);
299a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
300a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
301a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Update internal state.
302a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (invalid_)
303a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    AcknowledgeInvalidation();
304c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  is_registered_ = true;
305a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  object_id_ = object_id;
306a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  UpdateInvalidationsEnabled();
307a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
308a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Update registration with the invalidation service.
309a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  syncer::ObjectIdSet ids;
310a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ids.insert(object_id);
311a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  invalidation_service_->UpdateRegisteredInvalidationIds(this, ids);
312a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
313a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
314a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::Unregister() {
315c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (is_registered_) {
316a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (invalid_)
317a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      AcknowledgeInvalidation();
318a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    invalidation_service_->UpdateRegisteredInvalidationIds(
319a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        this,
320a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        syncer::ObjectIdSet());
321a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    invalidation_service_->UnregisterInvalidationHandler(this);
322c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    is_registered_ = false;
323a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    UpdateInvalidationsEnabled();
324a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
325a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
326a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
327a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::UpdateMaxFetchDelay(const PolicyMap& policy_map) {
328a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int delay;
329a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
330a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Try reading the delay from the policy.
331a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  const base::Value* delay_policy_value =
332a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      policy_map.GetValue(key::kMaxInvalidationFetchDelay);
333a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (delay_policy_value && delay_policy_value->GetAsInteger(&delay)) {
334a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    set_max_fetch_delay(delay);
335a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
336a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
337a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
338a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  set_max_fetch_delay(kMaxFetchDelayDefault);
339a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
340a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
341a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::set_max_fetch_delay(int delay) {
342a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (delay < kMaxFetchDelayMin)
343a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    max_fetch_delay_ = kMaxFetchDelayMin;
344a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  else if (delay > kMaxFetchDelayMax)
345a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    max_fetch_delay_ = kMaxFetchDelayMax;
346a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  else
347a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    max_fetch_delay_ = delay;
348a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
349a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
350a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::UpdateInvalidationsEnabled() {
351c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool invalidations_enabled = invalidation_service_enabled_ && is_registered_;
352a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (invalidations_enabled_ != invalidations_enabled) {
353a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    invalidations_enabled_ = invalidations_enabled;
354c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (invalidations_enabled)
355c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      invalidations_enabled_time_ = clock_->Now();
35658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    core_->refresh_scheduler()->SetInvalidationServiceAvailability(
35758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        invalidations_enabled);
358a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
359a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
360a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
36158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void CloudPolicyInvalidator::RefreshPolicy(bool is_missing_payload) {
362a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
363a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // In the missing payload case, the invalidation version has not been set on
364a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // the client yet, so set it now that the required time has elapsed.
36558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (is_missing_payload)
36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    core_->client()->SetInvalidationInfo(invalidation_version_, std::string());
36758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  core_->refresh_scheduler()->RefreshSoon();
368a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
369a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
370a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void CloudPolicyInvalidator::AcknowledgeInvalidation() {
371a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(invalid_);
372a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  invalid_ = false;
37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  core_->client()->SetInvalidationInfo(0, std::string());
374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  invalidation_->Acknowledge();
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  invalidation_.reset();
37658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Cancel any scheduled policy refreshes.
377a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
378a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
379a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
38058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool CloudPolicyInvalidator::IsPolicyChanged(
38158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const enterprise_management::PolicyData* policy) {
38258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Determine if the policy changed by comparing its hash value to the
38358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // previous policy's hash value.
38458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  uint32 new_hash_value = 0;
38558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (policy && policy->has_policy_value())
38658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    new_hash_value = base::Hash(policy->policy_value());
38758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool changed = new_hash_value != policy_hash_value_;
38858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  policy_hash_value_ = new_hash_value;
38958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return changed;
39058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
39158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
392c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool CloudPolicyInvalidator::IsInvalidationExpired(int64 version) {
393c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  base::Time last_fetch_time = base::Time::UnixEpoch() +
394c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::TimeDelta::FromMilliseconds(core_->store()->policy()->timestamp());
395c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
396c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // If the version is unknown, consider the invalidation invalid if the
397c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // policy was fetched very recently.
398c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (version < 0) {
399c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    base::TimeDelta elapsed = clock_->Now() - last_fetch_time;
400c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return elapsed.InSeconds() < kUnknownVersionIgnorePeriod;
401c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
402c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
403c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // The invalidation version is the timestamp in microseconds. If the
404c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // invalidation occurred before the last policy fetch, then the invalidation
405c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // is expired. Time is added to the invalidation to err on the side of not
406c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // expired.
407c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  base::Time invalidation_time = base::Time::UnixEpoch() +
408c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::TimeDelta::FromMicroseconds(version) +
409c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::TimeDelta::FromSeconds(kMaxInvalidationTimeDelta);
410c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return invalidation_time < last_fetch_time;
411c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
412c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
41358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)int CloudPolicyInvalidator::GetPolicyRefreshMetric(bool policy_changed) {
41458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (policy_changed) {
415a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (invalid_)
416a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return METRIC_POLICY_REFRESH_INVALIDATED_CHANGED;
417c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (GetInvalidationsEnabled())
418a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      return METRIC_POLICY_REFRESH_CHANGED;
419a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return METRIC_POLICY_REFRESH_CHANGED_NO_INVALIDATIONS;
420a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
421a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (invalid_)
422a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return METRIC_POLICY_REFRESH_INVALIDATED_UNCHANGED;
423a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return METRIC_POLICY_REFRESH_UNCHANGED;
424a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
425a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
426c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochint CloudPolicyInvalidator::GetInvalidationMetric(bool is_missing_payload,
427c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                                  bool is_expired) {
428c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (is_expired) {
429c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (is_missing_payload)
430c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return POLICY_INVALIDATION_TYPE_NO_PAYLOAD_EXPIRED;
431c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return POLICY_INVALIDATION_TYPE_EXPIRED;
432c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
433c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (is_missing_payload)
434c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return POLICY_INVALIDATION_TYPE_NO_PAYLOAD;
435c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return POLICY_INVALIDATION_TYPE_NORMAL;
436c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
437c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
438c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool CloudPolicyInvalidator::GetInvalidationsEnabled() {
439c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!invalidations_enabled_)
440c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return false;
441c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // If invalidations have been enabled for less than the grace period, then
442c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // consider invalidations to be disabled for metrics reporting.
443c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  base::TimeDelta elapsed = clock_->Now() - invalidations_enabled_time_;
444c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return elapsed.InSeconds() >= kInvalidationGracePeriod;
445c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
446c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
447a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}  // namespace policy
448