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.
5 #include "chrome/browser/policy/policy_service_impl.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/stl_util.h"
12 #include "chrome/browser/policy/policy_domain_descriptor.h"
13 #include "chrome/browser/policy/policy_map.h"
17 typedef PolicyServiceImpl::Providers::const_iterator Iterator;
19 PolicyServiceImpl::PolicyServiceImpl(const Providers& providers)
20 : update_task_ptr_factory_(this) {
21 for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain)
22 initialization_complete_[domain] = true;
23 providers_ = providers;
24 for (Iterator it = providers.begin(); it != providers.end(); ++it) {
25 ConfigurationPolicyProvider* provider = *it;
26 provider->AddObserver(this);
27 for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
28 initialization_complete_[domain] &=
29 provider->IsInitializationComplete(static_cast<PolicyDomain>(domain));
32 // There are no observers yet, but calls to GetPolicies() should already get
33 // the processed policy values.
34 MergeAndTriggerUpdates();
37 PolicyServiceImpl::~PolicyServiceImpl() {
38 for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
39 (*it)->RemoveObserver(this);
40 STLDeleteValues(&observers_);
43 void PolicyServiceImpl::AddObserver(PolicyDomain domain,
44 PolicyService::Observer* observer) {
45 Observers*& list = observers_[domain];
47 list = new Observers();
48 list->AddObserver(observer);
51 void PolicyServiceImpl::RemoveObserver(PolicyDomain domain,
52 PolicyService::Observer* observer) {
53 ObserverMap::iterator it = observers_.find(domain);
54 if (it == observers_.end()) {
58 it->second->RemoveObserver(observer);
59 if (!it->second->might_have_observers()) {
65 void PolicyServiceImpl::RegisterPolicyDomain(
66 scoped_refptr<const PolicyDomainDescriptor> descriptor) {
67 domain_descriptors_[descriptor->domain()] = descriptor;
68 for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
69 (*it)->RegisterPolicyDomain(descriptor);
72 const PolicyMap& PolicyServiceImpl::GetPolicies(
73 const PolicyNamespace& ns) const {
74 return policy_bundle_.Get(ns);
77 scoped_refptr<const PolicyDomainDescriptor>
78 PolicyServiceImpl::GetPolicyDomainDescriptor(PolicyDomain domain) const {
79 return domain_descriptors_[domain];
82 bool PolicyServiceImpl::IsInitializationComplete(PolicyDomain domain) const {
83 DCHECK(domain >= 0 && domain < POLICY_DOMAIN_SIZE);
84 return initialization_complete_[domain];
87 void PolicyServiceImpl::RefreshPolicies(const base::Closure& callback) {
88 if (!callback.is_null())
89 refresh_callbacks_.push_back(callback);
91 if (providers_.empty()) {
92 // Refresh is immediately complete if there are no providers. See the note
93 // on OnUpdatePolicy() about why this is a posted task.
94 update_task_ptr_factory_.InvalidateWeakPtrs();
95 base::MessageLoop::current()->PostTask(
97 base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates,
98 update_task_ptr_factory_.GetWeakPtr()));
100 // Some providers might invoke OnUpdatePolicy synchronously while handling
101 // RefreshPolicies. Mark all as pending before refreshing.
102 for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
103 refresh_pending_.insert(*it);
104 for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
105 (*it)->RefreshPolicies();
109 void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) {
110 DCHECK_EQ(1, std::count(providers_.begin(), providers_.end(), provider));
111 refresh_pending_.erase(provider);
113 // Note: a policy change may trigger further policy changes in some providers.
114 // For example, disabling SigninAllowed would cause the CloudPolicyManager to
115 // drop all its policies, which makes this method enter again for that
118 // Therefore this update is posted asynchronously, to prevent reentrancy in
119 // MergeAndTriggerUpdates. Also, cancel a pending update if there is any,
120 // since both will produce the same PolicyBundle.
121 update_task_ptr_factory_.InvalidateWeakPtrs();
122 base::MessageLoop::current()->PostTask(
124 base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates,
125 update_task_ptr_factory_.GetWeakPtr()));
128 void PolicyServiceImpl::NotifyNamespaceUpdated(
129 const PolicyNamespace& ns,
130 const PolicyMap& previous,
131 const PolicyMap& current) {
132 ObserverMap::iterator iterator = observers_.find(ns.domain);
133 if (iterator != observers_.end()) {
134 FOR_EACH_OBSERVER(PolicyService::Observer,
136 OnPolicyUpdated(ns, previous, current));
140 void PolicyServiceImpl::MergeAndTriggerUpdates() {
141 // Merge from each provider in their order of priority.
143 for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
144 bundle.MergeFrom((*it)->policies());
146 // Swap first, so that observers that call GetPolicies() see the current
148 policy_bundle_.Swap(&bundle);
150 // Only notify observers of namespaces that have been modified.
151 const PolicyMap kEmpty;
152 PolicyBundle::const_iterator it_new = policy_bundle_.begin();
153 PolicyBundle::const_iterator end_new = policy_bundle_.end();
154 PolicyBundle::const_iterator it_old = bundle.begin();
155 PolicyBundle::const_iterator end_old = bundle.end();
156 while (it_new != end_new && it_old != end_old) {
157 if (it_new->first < it_old->first) {
158 // A new namespace is available.
159 NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
161 } else if (it_old->first < it_new->first) {
162 // A previously available namespace is now gone.
163 NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
166 if (!it_new->second->Equals(*it_old->second)) {
167 // An existing namespace's policies have changed.
168 NotifyNamespaceUpdated(it_new->first, *it_old->second, *it_new->second);
175 // Send updates for the remaining new namespaces, if any.
176 for (; it_new != end_new; ++it_new)
177 NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
179 // Sends updates for the remaining removed namespaces, if any.
180 for (; it_old != end_old; ++it_old)
181 NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
183 CheckInitializationComplete();
184 CheckRefreshComplete();
187 void PolicyServiceImpl::CheckInitializationComplete() {
188 // Check if all the providers just became initialized for each domain; if so,
189 // notify that domain's observers.
190 for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
191 if (initialization_complete_[domain])
194 PolicyDomain policy_domain = static_cast<PolicyDomain>(domain);
196 bool all_complete = true;
197 for (Iterator it = providers_.begin(); it != providers_.end(); ++it) {
198 if (!(*it)->IsInitializationComplete(policy_domain)) {
199 all_complete = false;
204 initialization_complete_[domain] = true;
205 ObserverMap::iterator iter = observers_.find(policy_domain);
206 if (iter != observers_.end()) {
207 FOR_EACH_OBSERVER(PolicyService::Observer,
209 OnPolicyServiceInitialized(policy_domain));
215 void PolicyServiceImpl::CheckRefreshComplete() {
216 // Invoke all the callbacks if a refresh has just fully completed.
217 if (refresh_pending_.empty() && !refresh_callbacks_.empty()) {
218 std::vector<base::Closure> callbacks;
219 callbacks.swap(refresh_callbacks_);
220 std::vector<base::Closure>::iterator it;
221 for (it = callbacks.begin(); it != callbacks.end(); ++it)
226 } // namespace policy