| 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 |