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/policy_service_impl.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/message_loop/message_loop.h" | |
11 #include "base/stl_util.h" | |
12 #include "components/policy/core/common/policy_bundle.h" | |
13 #include "components/policy/core/common/policy_map.h" | |
14 | |
15 namespace policy { | |
16 | |
17 typedef PolicyServiceImpl::Providers::const_iterator Iterator; | |
18 | |
19 PolicyServiceImpl::PolicyServiceImpl( | |
20 const Providers& providers, | |
21 const PreprocessCallback& preprocess_callback) | |
22 : preprocess_callback_(preprocess_callback), | |
23 update_task_ptr_factory_(this) { | |
24 for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) | |
25 initialization_complete_[domain] = true; | |
26 providers_ = providers; | |
27 for (Iterator it = providers.begin(); it != providers.end(); ++it) { | |
28 ConfigurationPolicyProvider* provider = *it; | |
29 provider->AddObserver(this); | |
30 for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) { | |
31 initialization_complete_[domain] &= | |
32 provider->IsInitializationComplete(static_cast<PolicyDomain>(domain)); | |
33 } | |
34 } | |
35 // There are no observers yet, but calls to GetPolicies() should already get | |
36 // the processed policy values. | |
37 MergeAndTriggerUpdates(); | |
38 } | |
39 | |
40 PolicyServiceImpl::~PolicyServiceImpl() { | |
41 for (Iterator it = providers_.begin(); it != providers_.end(); ++it) | |
42 (*it)->RemoveObserver(this); | |
43 STLDeleteValues(&observers_); | |
44 } | |
45 | |
46 void PolicyServiceImpl::AddObserver(PolicyDomain domain, | |
47 PolicyService::Observer* observer) { | |
48 Observers*& list = observers_[domain]; | |
49 if (!list) | |
50 list = new Observers(); | |
51 list->AddObserver(observer); | |
52 } | |
53 | |
54 void PolicyServiceImpl::RemoveObserver(PolicyDomain domain, | |
55 PolicyService::Observer* observer) { | |
56 ObserverMap::iterator it = observers_.find(domain); | |
57 if (it == observers_.end()) { | |
58 NOTREACHED(); | |
59 return; | |
60 } | |
61 it->second->RemoveObserver(observer); | |
62 if (!it->second->might_have_observers()) { | |
63 delete it->second; | |
64 observers_.erase(it); | |
65 } | |
66 } | |
67 | |
68 const PolicyMap& PolicyServiceImpl::GetPolicies( | |
69 const PolicyNamespace& ns) const { | |
70 return policy_bundle_.Get(ns); | |
71 } | |
72 | |
73 bool PolicyServiceImpl::IsInitializationComplete(PolicyDomain domain) const { | |
74 DCHECK(domain >= 0 && domain < POLICY_DOMAIN_SIZE); | |
75 return initialization_complete_[domain]; | |
76 } | |
77 | |
78 void PolicyServiceImpl::RefreshPolicies(const base::Closure& callback) { | |
79 if (!callback.is_null()) | |
80 refresh_callbacks_.push_back(callback); | |
81 | |
82 if (providers_.empty()) { | |
83 // Refresh is immediately complete if there are no providers. See the note | |
84 // on OnUpdatePolicy() about why this is a posted task. | |
85 update_task_ptr_factory_.InvalidateWeakPtrs(); | |
86 base::MessageLoop::current()->PostTask( | |
87 FROM_HERE, | |
88 base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates, | |
89 update_task_ptr_factory_.GetWeakPtr())); | |
90 } else { | |
91 // Some providers might invoke OnUpdatePolicy synchronously while handling | |
92 // RefreshPolicies. Mark all as pending before refreshing. | |
93 for (Iterator it = providers_.begin(); it != providers_.end(); ++it) | |
94 refresh_pending_.insert(*it); | |
95 for (Iterator it = providers_.begin(); it != providers_.end(); ++it) | |
96 (*it)->RefreshPolicies(); | |
97 } | |
98 } | |
99 | |
100 void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) { | |
101 DCHECK_EQ(1, std::count(providers_.begin(), providers_.end(), provider)); | |
102 refresh_pending_.erase(provider); | |
103 | |
104 // Note: a policy change may trigger further policy changes in some providers. | |
105 // For example, disabling SigninAllowed would cause the CloudPolicyManager to | |
106 // drop all its policies, which makes this method enter again for that | |
107 // provider. | |
108 // | |
109 // Therefore this update is posted asynchronously, to prevent reentrancy in | |
110 // MergeAndTriggerUpdates. Also, cancel a pending update if there is any, | |
111 // since both will produce the same PolicyBundle. | |
112 update_task_ptr_factory_.InvalidateWeakPtrs(); | |
113 base::MessageLoop::current()->PostTask( | |
114 FROM_HERE, | |
115 base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates, | |
116 update_task_ptr_factory_.GetWeakPtr())); | |
117 } | |
118 | |
119 void PolicyServiceImpl::NotifyNamespaceUpdated( | |
120 const PolicyNamespace& ns, | |
121 const PolicyMap& previous, | |
122 const PolicyMap& current) { | |
123 ObserverMap::iterator iterator = observers_.find(ns.domain); | |
124 if (iterator != observers_.end()) { | |
125 FOR_EACH_OBSERVER(PolicyService::Observer, | |
126 *iterator->second, | |
127 OnPolicyUpdated(ns, previous, current)); | |
128 } | |
129 } | |
130 | |
131 void PolicyServiceImpl::MergeAndTriggerUpdates() { | |
132 // Merge from each provider in their order of priority. | |
133 PolicyBundle bundle; | |
134 for (Iterator it = providers_.begin(); it != providers_.end(); ++it) { | |
135 PolicyBundle provided_bundle; | |
136 provided_bundle.CopyFrom((*it)->policies()); | |
137 if (!preprocess_callback_.is_null()) | |
138 preprocess_callback_.Run(&provided_bundle); | |
139 bundle.MergeFrom(provided_bundle); | |
140 } | |
141 | |
142 // Swap first, so that observers that call GetPolicies() see the current | |
143 // values. | |
144 policy_bundle_.Swap(&bundle); | |
145 | |
146 // Only notify observers of namespaces that have been modified. | |
147 const PolicyMap kEmpty; | |
148 PolicyBundle::const_iterator it_new = policy_bundle_.begin(); | |
149 PolicyBundle::const_iterator end_new = policy_bundle_.end(); | |
150 PolicyBundle::const_iterator it_old = bundle.begin(); | |
151 PolicyBundle::const_iterator end_old = bundle.end(); | |
152 while (it_new != end_new && it_old != end_old) { | |
153 if (it_new->first < it_old->first) { | |
154 // A new namespace is available. | |
155 NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second); | |
156 ++it_new; | |
157 } else if (it_old->first < it_new->first) { | |
158 // A previously available namespace is now gone. | |
159 NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty); | |
160 ++it_old; | |
161 } else { | |
162 if (!it_new->second->Equals(*it_old->second)) { | |
163 // An existing namespace's policies have changed. | |
164 NotifyNamespaceUpdated(it_new->first, *it_old->second, *it_new->second); | |
165 } | |
166 ++it_new; | |
167 ++it_old; | |
168 } | |
169 } | |
170 | |
171 // Send updates for the remaining new namespaces, if any. | |
172 for (; it_new != end_new; ++it_new) | |
173 NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second); | |
174 | |
175 // Sends updates for the remaining removed namespaces, if any. | |
176 for (; it_old != end_old; ++it_old) | |
177 NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty); | |
178 | |
179 CheckInitializationComplete(); | |
180 CheckRefreshComplete(); | |
181 } | |
182 | |
183 void PolicyServiceImpl::CheckInitializationComplete() { | |
184 // Check if all the providers just became initialized for each domain; if so, | |
185 // notify that domain's observers. | |
186 for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) { | |
187 if (initialization_complete_[domain]) | |
188 continue; | |
189 | |
190 PolicyDomain policy_domain = static_cast<PolicyDomain>(domain); | |
191 | |
192 bool all_complete = true; | |
193 for (Iterator it = providers_.begin(); it != providers_.end(); ++it) { | |
194 if (!(*it)->IsInitializationComplete(policy_domain)) { | |
195 all_complete = false; | |
196 break; | |
197 } | |
198 } | |
199 if (all_complete) { | |
200 initialization_complete_[domain] = true; | |
201 ObserverMap::iterator iter = observers_.find(policy_domain); | |
202 if (iter != observers_.end()) { | |
203 FOR_EACH_OBSERVER(PolicyService::Observer, | |
204 *iter->second, | |
205 OnPolicyServiceInitialized(policy_domain)); | |
206 } | |
207 } | |
208 } | |
209 } | |
210 | |
211 void PolicyServiceImpl::CheckRefreshComplete() { | |
212 // Invoke all the callbacks if a refresh has just fully completed. | |
213 if (refresh_pending_.empty() && !refresh_callbacks_.empty()) { | |
214 std::vector<base::Closure> callbacks; | |
215 callbacks.swap(refresh_callbacks_); | |
216 std::vector<base::Closure>::iterator it; | |
217 for (it = callbacks.begin(); it != callbacks.end(); ++it) | |
218 it->Run(); | |
219 } | |
220 } | |
221 | |
222 } // namespace policy | |
OLD | NEW |