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 "chrome/browser/policy/policy_domain_descriptor.h" 13 #include "chrome/browser/policy/policy_map.h" 14 15 namespace policy { 16 17 typedef PolicyServiceImpl::Providers::const_iterator Iterator; 18 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)); 30 } 31 } 32 // There are no observers yet, but calls to GetPolicies() should already get 33 // the processed policy values. 34 MergeAndTriggerUpdates(); 35 } 36 37 PolicyServiceImpl::~PolicyServiceImpl() { 38 for (Iterator it = providers_.begin(); it != providers_.end(); ++it) 39 (*it)->RemoveObserver(this); 40 STLDeleteValues(&observers_); 41 } 42 43 void PolicyServiceImpl::AddObserver(PolicyDomain domain, 44 PolicyService::Observer* observer) { 45 Observers*& list = observers_[domain]; 46 if (!list) 47 list = new Observers(); 48 list->AddObserver(observer); 49 } 50 51 void PolicyServiceImpl::RemoveObserver(PolicyDomain domain, 52 PolicyService::Observer* observer) { 53 ObserverMap::iterator it = observers_.find(domain); 54 if (it == observers_.end()) { 55 NOTREACHED(); 56 return; 57 } 58 it->second->RemoveObserver(observer); 59 if (it->second->size() == 0) { 60 delete it->second; 61 observers_.erase(it); 62 } 63 } 64 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); 70 } 71 72 const PolicyMap& PolicyServiceImpl::GetPolicies( 73 const PolicyNamespace& ns) const { 74 return policy_bundle_.Get(ns); 75 } 76 77 scoped_refptr<const PolicyDomainDescriptor> 78 PolicyServiceImpl::GetPolicyDomainDescriptor(PolicyDomain domain) const { 79 return domain_descriptors_[domain]; 80 } 81 82 bool PolicyServiceImpl::IsInitializationComplete(PolicyDomain domain) const { 83 DCHECK(domain >= 0 && domain < POLICY_DOMAIN_SIZE); 84 return initialization_complete_[domain]; 85 } 86 87 void PolicyServiceImpl::RefreshPolicies(const base::Closure& callback) { 88 if (!callback.is_null()) 89 refresh_callbacks_.push_back(callback); 90 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( 96 FROM_HERE, 97 base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates, 98 update_task_ptr_factory_.GetWeakPtr())); 99 } else { 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(); 106 } 107 } 108 109 void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) { 110 DCHECK_EQ(1, std::count(providers_.begin(), providers_.end(), provider)); 111 refresh_pending_.erase(provider); 112 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 116 // provider. 117 // 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( 123 FROM_HERE, 124 base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates, 125 update_task_ptr_factory_.GetWeakPtr())); 126 } 127 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, 135 *iterator->second, 136 OnPolicyUpdated(ns, previous, current)); 137 } 138 } 139 140 void PolicyServiceImpl::MergeAndTriggerUpdates() { 141 // Merge from each provider in their order of priority. 142 PolicyBundle bundle; 143 for (Iterator it = providers_.begin(); it != providers_.end(); ++it) 144 bundle.MergeFrom((*it)->policies()); 145 146 // Swap first, so that observers that call GetPolicies() see the current 147 // values. 148 policy_bundle_.Swap(&bundle); 149 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); 160 ++it_new; 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); 164 ++it_old; 165 } else { 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); 169 } 170 ++it_new; 171 ++it_old; 172 } 173 } 174 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); 178 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); 182 183 CheckInitializationComplete(); 184 CheckRefreshComplete(); 185 } 186 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]) 192 continue; 193 194 PolicyDomain policy_domain = static_cast<PolicyDomain>(domain); 195 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; 200 break; 201 } 202 } 203 if (all_complete) { 204 initialization_complete_[domain] = true; 205 ObserverMap::iterator iter = observers_.find(policy_domain); 206 if (iter != observers_.end()) { 207 FOR_EACH_OBSERVER(PolicyService::Observer, 208 *iter->second, 209 OnPolicyServiceInitialized(policy_domain)); 210 } 211 } 212 } 213 } 214 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) 222 it->Run(); 223 } 224 } 225 226 } // namespace policy 227