Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(558)

Side by Side Diff: chrome/browser/policy/cloud/cloud_policy_invalidator.cc

Issue 19733003: Implement cloud policy invalidations using the invalidation service framework. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 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/cloud_policy_invalidator.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
Joao da Silva 2013/07/25 18:03:53 not used
Steve Condie 2013/07/26 01:39:25 Done.
10 #include "base/metrics/histogram.h"
11 #include "base/rand_util.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "chrome/browser/invalidation/invalidation_service.h"
17 #include "chrome/browser/policy/cloud/cloud_policy_client.h"
18 #include "chrome/browser/policy/cloud/cloud_policy_store.h"
Joao da Silva 2013/07/25 18:03:53 alread included in the header
Steve Condie 2013/07/26 01:39:25 Done.
19 #include "chrome/browser/policy/cloud/enterprise_metrics.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "policy/policy_constants.h"
22 #include "sync/notifier/object_id_invalidation_map.h"
23
24 namespace policy {
25
26 const int CloudPolicyInvalidator::kMissingPayloadDelay = 5;
27 const int CloudPolicyInvalidator::kMaxFetchDelayDefault = 5000;
28 const int CloudPolicyInvalidator::kMaxFetchDelayMin = 1000;
29 const int CloudPolicyInvalidator::kMaxFetchDelayMax = 300000;
30
31 CloudPolicyInvalidator::CloudPolicyInvalidator(
32 invalidation::InvalidationService* invalidation_service,
33 CloudPolicyClient* client,
34 CloudPolicyStore* store,
35 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
36 CloudPolicyInvalidationHandler* invalidation_handler)
37 : invalidation_service_(invalidation_service),
38 client_(client),
39 store_(store),
40 task_runner_(task_runner),
41 invalidation_handler_(invalidation_handler),
42 invalidations_enabled_(false),
43 invalidation_service_enabled_(false),
44 registered_timestamp_(0),
45 invalid_(false),
46 invalidation_version_(0),
47 unknown_version_invalidation_count_(0),
48 ack_handle_(syncer::AckHandle::InvalidAckHandle()),
49 weak_factory_(this),
50 max_fetch_delay_(kMaxFetchDelayDefault) {
51 DCHECK(invalidation_service);
52 DCHECK(client);
53 DCHECK(store);
54 DCHECK(task_runner.get());
55 DCHECK(invalidation_handler);
56
57 OnInvalidatorStateChange(invalidation_service->GetInvalidatorState());
58 invalidation_service->RegisterInvalidationHandler(this);
59 OnStoreLoaded(store);
60 store->AddObserver(this);
61 }
62
63 CloudPolicyInvalidator::~CloudPolicyInvalidator() {
64 invalidation_service_->UnregisterInvalidationHandler(this);
65 store_->RemoveObserver(this);
66 }
67
68 void CloudPolicyInvalidator::Unregister() {
69 if (invalid_)
70 AcknowledgeInvalidation();
71 invalidation_service_->UpdateRegisteredInvalidationIds(
72 this,
73 syncer::ObjectIdSet());
74 registered_timestamp_ = 0;
75 UpdateInvalidationsEnabled();
76 }
77
78 void CloudPolicyInvalidator::OnInvalidatorStateChange(
79 syncer::InvalidatorState state) {
80 invalidation_service_enabled_ = state == syncer::INVALIDATIONS_ENABLED;
81 UpdateInvalidationsEnabled();
82 }
83
84 void CloudPolicyInvalidator::OnIncomingInvalidation(
85 const syncer::ObjectIdInvalidationMap& invalidation_map) {
86 DCHECK(thread_checker_.CalledOnValidThread());
87 const syncer::ObjectIdInvalidationMap::const_iterator invalidation =
88 invalidation_map.find(object_id_);
89 if (invalidation == invalidation_map.end()) {
90 NOTREACHED();
91 return;
92 }
93 HandleInvalidation(invalidation->second);
94 }
95
96 void CloudPolicyInvalidator::OnStoreLoaded(CloudPolicyStore* store) {
97 DCHECK(thread_checker_.CalledOnValidThread());
98 if (registered_timestamp_) {
99 // Update the kMetricPolicyRefresh histogram. In some cases, this object can
100 // be constructed during an OnStoreLoaded callback, which causes
101 // OnStoreLoaded to be called twice at initialization time, so make sure
102 // that the timestamp does not match the timestamp at which registration
103 // occurred. We only measure changes which occur after registration.
104 if (!store->policy() || !store->policy()->has_timestamp() ||
105 store->policy()->timestamp() != registered_timestamp_) {
106 UMA_HISTOGRAM_ENUMERATION(
107 kMetricPolicyRefresh,
108 GetPolicyRefreshMetric(),
109 kMetricPolicyRefreshSize);
110 }
111
112 // If the policy was invalid and the version stored matches the latest
113 // invalidation version, acknowledge the latest invalidation.
114 if (invalid_ && store->invalidation_version() == invalidation_version_)
115 AcknowledgeInvalidation();
116 }
117
118 UpdateRegistration(store->policy());
119 UpdateMaxFetchDelay(store->policy_map());
120 }
121
122 void CloudPolicyInvalidator::OnStoreError(CloudPolicyStore* store) {}
123
124 void CloudPolicyInvalidator::HandleInvalidation(
125 const syncer::Invalidation& invalidation) {
126 // The invalidation service may send an invalidation more than once if there
127 // is a delay in acknowledging it. Duplicate invalidations are ignored.
128 if (invalid_ && ack_handle_.Equals(invalidation.ack_handle))
129 return;
130
131 // If there is still a pending invalidation, acknowledge it, since we only
132 // care about the latest invalidation.
133 if (invalid_)
134 AcknowledgeInvalidation();
135
136 // Update invalidation state.
137 invalid_ = true;
138 ack_handle_ = invalidation.ack_handle;
139 invalidation_version_ = invalidation.version;
140
141 // When an invalidation with unknown version is received, use negative
142 // numbers based on the number of such invalidations received. This
143 // ensures that the version numbers do not collide with "real" versions
144 // (which are positive) or previous invalidations with unknown version.
145 if (invalidation_version_ == syncer::Invalidation::kUnknownVersion)
146 invalidation_version_ = -(++unknown_version_invalidation_count_);
147
148 // In order to prevent the cloud policy server from becoming overwhelmed when
149 // a policy with many users is modified, delay for a random period of time
150 // before fetching the policy. Delay for at least 20ms so that if multiple
151 // invalidations are received in quick succession, only one fetch will be
152 // performed.
153 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(
154 base::RandInt(20, max_fetch_delay_));
155
156 // If there is a payload, the invalidate callback can run at any time, so set
157 // the version and payload on the client immediately. Otherwise, the callback
158 // must only run after at least kMissingPayloadDelay minutes.
159 const std::string& payload = invalidation.payload;
160 if (!invalidation.payload.empty())
161 client_->SetInvalidationInfo(invalidation_version_, payload);
162 else
163 delay += base::TimeDelta::FromMinutes(kMissingPayloadDelay);
164
165 // Schedule the invalidate callback to run.
166 task_runner_->PostDelayedTask(
167 FROM_HERE,
168 base::Bind(
169 &CloudPolicyInvalidator::RunInvalidateCallback,
170 weak_factory_.GetWeakPtr(),
171 payload.empty() /* is_missing_payload */),
172 delay);
173
174 // Update the kMetricPolicyInvalidations histogram.
175 UMA_HISTOGRAM_ENUMERATION(
176 kMetricPolicyInvalidations,
177 payload.empty() ?
178 kMetricPolicyInvalidationsNoPayload :
179 kMetricPolicyInvalidationsPayload,
180 kMetricPolicyInvalidationsSize);
181 }
182
183 void CloudPolicyInvalidator::UpdateRegistration(
184 const enterprise_management::PolicyData* policy) {
185 // Create the ObjectId based on the policy data.
186 // If the policy does not specify an the ObjectId, then unregister.
187 if (!policy ||
188 !policy->has_timestamp() ||
189 !policy->has_invalidation_source() ||
190 !policy->has_invalidation_name()) {
191 if (registered_timestamp_)
192 Unregister();
193 return;
194 }
195 invalidation::ObjectId object_id(
196 policy->invalidation_source(),
197 policy->invalidation_name());
198
199 // If the policy object id in the policy data is different from the currently
200 // registered object id, update the object registration.
201 if (!registered_timestamp_ || !(object_id == object_id_)) {
202 if (invalid_)
203 AcknowledgeInvalidation();
204 registered_timestamp_ = policy->timestamp();
205 object_id_ = object_id;
206 UpdateInvalidationsEnabled();
207
208 syncer::ObjectIdSet ids;
209 ids.insert(object_id);
210 invalidation_service_->UpdateRegisteredInvalidationIds(this, ids);
211 }
212 }
213
214 void CloudPolicyInvalidator::UpdateMaxFetchDelay(const PolicyMap& policy_map) {
215 int delay;
216
217 // Try reading the delay from the policy.
218 const base::Value* delay_policy_value =
219 policy_map.GetValue(key::kMaxInvalidationFetchDelay);
220 if (delay_policy_value && delay_policy_value->GetAsInteger(&delay)) {
221 set_max_fetch_delay(delay);
222 return;
223 }
224
225 // Try reading the delay from the command line switch.
226 std::string delay_string =
227 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
228 switches::kCloudPolicyInvalidationDelay);
229 if (base::StringToInt(delay_string, &delay)) {
230 set_max_fetch_delay(delay);
231 return;
232 }
233
234 max_fetch_delay_ = kMaxFetchDelayDefault;
Joao da Silva 2013/07/25 18:03:53 For consistency: set_max_fetch_delay(kMaxFetchD
Steve Condie 2013/07/26 01:39:25 Done.
235 }
236
237 void CloudPolicyInvalidator::set_max_fetch_delay(int delay) {
238 if (delay < kMaxFetchDelayMin)
239 max_fetch_delay_ = kMaxFetchDelayMin;
240 else if (delay > kMaxFetchDelayMax)
241 max_fetch_delay_ = kMaxFetchDelayMax;
242 else
243 max_fetch_delay_ = delay;
244 }
245
246 void CloudPolicyInvalidator::UpdateInvalidationsEnabled() {
247 bool invalidations_enabled =
248 invalidation_service_enabled_ && registered_timestamp_;
249 if (invalidations_enabled_ != invalidations_enabled) {
250 invalidations_enabled_ = invalidations_enabled;
251 invalidation_handler_->OnInvalidatorStateChanged(invalidations_enabled);
252 }
253 }
254
255 void CloudPolicyInvalidator::RunInvalidateCallback(bool is_missing_payload) {
256 DCHECK(thread_checker_.CalledOnValidThread());
257 // In the missing payload case, the invalidation version has not been set on
258 // the client yet, so set it now that the required time has elapsed.
259 if (is_missing_payload)
260 client_->SetInvalidationInfo(invalidation_version_, std::string());
261 invalidation_handler_->InvalidatePolicy();
262 }
263
264 void CloudPolicyInvalidator::AcknowledgeInvalidation() {
265 DCHECK(invalid_);
266 invalid_ = false;
267 client_->SetInvalidationInfo(0, std::string());
268 invalidation_service_->AcknowledgeInvalidation(object_id_, ack_handle_);
269 // Cancel any scheduled invalidate callbacks.
270 weak_factory_.InvalidateWeakPtrs();
271 }
272
273 int CloudPolicyInvalidator::GetPolicyRefreshMetric() {
274 if (store_->policy_changed()) {
275 if (invalid_)
276 return kMetricPolicyRefreshInvalidatedChanged;
277 if (invalidations_enabled_)
278 return kMetricPolicyRefreshChanged;
279 return kMetricPolicyRefreshChangedNoInvalidations;
280 }
281 if (invalid_)
282 return kMetricPolicyRefreshInvalidatedUnchanged;
283 return kMetricPolicyRefreshUnchanged;
284 }
285
286 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698