| Index: chrome/browser/policy/policy_service_impl.cc
|
| diff --git a/chrome/browser/policy/policy_service_impl.cc b/chrome/browser/policy/policy_service_impl.cc
|
| index 961a2a4038ba704a44f4300df99d204e02badacb..d927c657cf1c381bf10f0e9bfa12ecfac031cfe4 100644
|
| --- a/chrome/browser/policy/policy_service_impl.cc
|
| +++ b/chrome/browser/policy/policy_service_impl.cc
|
| @@ -4,78 +4,61 @@
|
|
|
| #include "chrome/browser/policy/policy_service_impl.h"
|
|
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/observer_list.h"
|
| #include "base/stl_util.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -
|
| -using content::BrowserThread;
|
| +#include "chrome/browser/policy/policy_map.h"
|
|
|
| namespace policy {
|
|
|
| -struct PolicyServiceImpl::Entry {
|
| - PolicyMap policies;
|
| - ObserverList<PolicyService::Observer, true> observers;
|
| -};
|
| -
|
| -struct PolicyServiceImpl::ProviderData {
|
| - ConfigurationPolicyProvider* provider;
|
| - ConfigurationPolicyObserverRegistrar registrar;
|
| - PolicyMap policies;
|
| - bool refresh_pending;
|
| -};
|
| -
|
| PolicyServiceImpl::PolicyServiceImpl(const Providers& providers) {
|
| initialization_complete_ = true;
|
| for (size_t i = 0; i < providers.size(); ++i) {
|
| ConfigurationPolicyProvider* provider = providers[i];
|
| - ProviderData* data = new ProviderData;
|
| - data->provider = provider;
|
| - data->registrar.Init(provider, this);
|
| - data->refresh_pending = false;
|
| - if (provider->IsInitializationComplete())
|
| - provider->Provide(&data->policies);
|
| - else
|
| - initialization_complete_ = false;
|
| - providers_.push_back(data);
|
| + ConfigurationPolicyObserverRegistrar* registrar =
|
| + new ConfigurationPolicyObserverRegistrar();
|
| + registrar->Init(provider, this);
|
| + initialization_complete_ &= provider->IsInitializationComplete();
|
| + registrars_.push_back(registrar);
|
| }
|
| // There are no observers yet, but calls to GetPolicies() should already get
|
| // the processed policy values.
|
| - MergeAndTriggerUpdates(false);
|
| + MergeAndTriggerUpdates();
|
| }
|
|
|
| PolicyServiceImpl::~PolicyServiceImpl() {
|
| - STLDeleteElements(&providers_);
|
| - STLDeleteValues(&entries_);
|
| + STLDeleteElements(®istrars_);
|
| + STLDeleteValues(&observers_);
|
| }
|
|
|
| void PolicyServiceImpl::AddObserver(PolicyDomain domain,
|
| const std::string& component_id,
|
| PolicyService::Observer* observer) {
|
| - PolicyNamespace ns = std::make_pair(domain, component_id);
|
| - GetOrCreate(ns)->observers.AddObserver(observer);
|
| + PolicyBundle::PolicyNamespace ns(domain, component_id);
|
| + Observers*& list = observers_[ns];
|
| + if (!list)
|
| + list = new Observers();
|
| + list->AddObserver(observer);
|
| }
|
|
|
| void PolicyServiceImpl::RemoveObserver(PolicyDomain domain,
|
| const std::string& component_id,
|
| PolicyService::Observer* observer) {
|
| - PolicyNamespace ns = std::make_pair(domain, component_id);
|
| - EntryMap::const_iterator it = entries_.find(ns);
|
| - if (it == entries_.end()) {
|
| + PolicyBundle::PolicyNamespace ns(domain, component_id);
|
| + ObserverMap::iterator it = observers_.find(ns);
|
| + if (it == observers_.end()) {
|
| NOTREACHED();
|
| return;
|
| }
|
| - it->second->observers.RemoveObserver(observer);
|
| - MaybeCleanup(ns);
|
| + it->second->RemoveObserver(observer);
|
| + if (it->second->size() == 0) {
|
| + delete it->second;
|
| + observers_.erase(it);
|
| + }
|
| }
|
|
|
| -const PolicyMap* PolicyServiceImpl::GetPolicies(
|
| +const PolicyMap& PolicyServiceImpl::GetPolicies(
|
| PolicyDomain domain,
|
| const std::string& component_id) const {
|
| - PolicyNamespace ns = std::make_pair(domain, component_id);
|
| - EntryMap::const_iterator it = entries_.find(ns);
|
| - return it == entries_.end() ? NULL : &it->second->policies;
|
| + return policy_bundle_.Get(domain, component_id);
|
| }
|
|
|
| bool PolicyServiceImpl::IsInitializationComplete() const {
|
| @@ -86,114 +69,137 @@ void PolicyServiceImpl::RefreshPolicies(const base::Closure& callback) {
|
| if (!callback.is_null())
|
| refresh_callbacks_.push_back(callback);
|
|
|
| - if (providers_.empty()) {
|
| + if (registrars_.empty()) {
|
| // Refresh is immediately complete if there are no providers.
|
| - MergeAndTriggerUpdates(true);
|
| + MergeAndTriggerUpdates();
|
| } else {
|
| // Some providers might invoke OnUpdatePolicy synchronously while handling
|
| - // RefreshPolicies. Flag all with refresh_pending before refreshing.
|
| - ProviderList::iterator it;
|
| - for (it = providers_.begin(); it != providers_.end(); ++it)
|
| - (*it)->refresh_pending = true;
|
| - for (it = providers_.begin(); it != providers_.end(); ++it)
|
| - (*it)->provider->RefreshPolicies();
|
| + // RefreshPolicies. Mark all as pending before refreshing.
|
| + RegistrarList::iterator it;
|
| + for (it = registrars_.begin(); it != registrars_.end(); ++it)
|
| + refresh_pending_.insert((*it)->provider());
|
| + for (it = registrars_.begin(); it != registrars_.end(); ++it)
|
| + (*it)->provider()->RefreshPolicies();
|
| }
|
| }
|
|
|
| void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) {
|
| - ProviderList::iterator it = GetProviderData(provider);
|
| - if (it == providers_.end())
|
| + RegistrarList::iterator it = GetRegistrar(provider);
|
| + if (it == registrars_.end())
|
| return;
|
| - provider->Provide(&(*it)->policies);
|
| - bool did_refresh = (*it)->refresh_pending;
|
| - (*it)->refresh_pending = false;
|
| - MergeAndTriggerUpdates(did_refresh);
|
| + refresh_pending_.erase(provider);
|
| + MergeAndTriggerUpdates();
|
| }
|
|
|
| void PolicyServiceImpl::OnProviderGoingAway(
|
| ConfigurationPolicyProvider* provider) {
|
| - ProviderList::iterator it = GetProviderData(provider);
|
| - if (it == providers_.end())
|
| + RegistrarList::iterator it = GetRegistrar(provider);
|
| + if (it == registrars_.end())
|
| return;
|
| - bool did_refresh = (*it)->refresh_pending;
|
| + refresh_pending_.erase(provider);
|
| delete *it;
|
| - providers_.erase(it);
|
| - MergeAndTriggerUpdates(did_refresh);
|
| + registrars_.erase(it);
|
| + MergeAndTriggerUpdates();
|
| }
|
|
|
| -PolicyServiceImpl::Entry* PolicyServiceImpl::GetOrCreate(
|
| - const PolicyNamespace& ns) {
|
| - Entry*& entry = entries_[ns];
|
| - if (!entry)
|
| - entry = new Entry;
|
| - return entry;
|
| -}
|
| -
|
| -PolicyServiceImpl::ProviderList::iterator PolicyServiceImpl::GetProviderData(
|
| +PolicyServiceImpl::RegistrarList::iterator PolicyServiceImpl::GetRegistrar(
|
| ConfigurationPolicyProvider* provider) {
|
| - for (ProviderList::iterator it = providers_.begin();
|
| - it != providers_.end(); ++it) {
|
| - if ((*it)->provider == provider)
|
| + for (RegistrarList::iterator it = registrars_.begin();
|
| + it != registrars_.end(); ++it) {
|
| + if ((*it)->provider() == provider)
|
| return it;
|
| }
|
| NOTREACHED();
|
| - return providers_.end();
|
| + return registrars_.end();
|
| }
|
|
|
| -void PolicyServiceImpl::MaybeCleanup(const PolicyNamespace& ns) {
|
| - EntryMap::iterator it = entries_.find(ns);
|
| - if (it != entries_.end() &&
|
| - it->second->policies.empty() &&
|
| - it->second->observers.size() == 0) {
|
| - delete it->second;
|
| - entries_.erase(it);
|
| +void PolicyServiceImpl::NotifyNamespaceUpdated(
|
| + const PolicyBundle::PolicyNamespace& ns,
|
| + const PolicyMap& previous,
|
| + const PolicyMap& current) {
|
| + ObserverMap::iterator iterator = observers_.find(ns);
|
| + if (iterator != observers_.end()) {
|
| + FOR_EACH_OBSERVER(
|
| + PolicyService::Observer,
|
| + *iterator->second,
|
| + OnPolicyUpdated(ns.first, ns.second, previous, current));
|
| }
|
| }
|
|
|
| -void PolicyServiceImpl::MergeAndTriggerUpdates(bool is_refresh) {
|
| - // TODO(joaodasilva): do this for each namespace once the providers also
|
| - // provide policy for more namespaces.
|
| -
|
| - PolicyMap policies;
|
| - bool refresh_pending = false;
|
| - for (ProviderList::iterator it = providers_.begin();
|
| - it != providers_.end(); ++it) {
|
| - policies.MergeFrom((*it)->policies);
|
| - refresh_pending |= (*it)->refresh_pending;
|
| +void PolicyServiceImpl::MergeAndTriggerUpdates() {
|
| + // Merge from each provider in their order of priority.
|
| + PolicyBundle bundle;
|
| + for (RegistrarList::iterator it = registrars_.begin();
|
| + it != registrars_.end(); ++it) {
|
| + bundle.MergeFrom((*it)->provider()->policies());
|
| }
|
|
|
| - Entry* entry = GetOrCreate(std::make_pair(POLICY_DOMAIN_CHROME, ""));
|
| - if (!policies.Equals(entry->policies)) {
|
| - // Swap first, so that observers that call GetPolicies() see the current
|
| - // values.
|
| - entry->policies.Swap(&policies);
|
| - FOR_EACH_OBSERVER(
|
| - PolicyService::Observer,
|
| - entry->observers,
|
| - OnPolicyUpdated(POLICY_DOMAIN_CHROME, "", policies, entry->policies));
|
| + // Swap first, so that observers that call GetPolicies() see the current
|
| + // values.
|
| + policy_bundle_.Swap(&bundle);
|
| +
|
| + // Only notify observers of namespaces that have been modified.
|
| + const PolicyMap kEmpty;
|
| + PolicyBundle::const_iterator it_new = policy_bundle_.begin();
|
| + PolicyBundle::const_iterator end_new = policy_bundle_.end();
|
| + PolicyBundle::const_iterator it_old = bundle.begin();
|
| + PolicyBundle::const_iterator end_old = bundle.end();
|
| + while (it_new != end_new && it_old != end_old) {
|
| + if (it_new->first < it_old->first) {
|
| + // A new namespace is available.
|
| + NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
|
| + ++it_new;
|
| + } else if (it_new->first > it_old->first) {
|
| + // A previously available namespace is now gone.
|
| + NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
|
| + ++it_old;
|
| + } else {
|
| + if (!it_new->second->Equals(*it_old->second)) {
|
| + // An existing namespace's policies have changed.
|
| + NotifyNamespaceUpdated(it_new->first, *it_old->second, *it_new->second);
|
| + }
|
| + ++it_new;
|
| + ++it_old;
|
| + }
|
| }
|
|
|
| + // Send updates for the remaining new namespaces, if any.
|
| + for (; it_new != end_new; ++it_new)
|
| + NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
|
| +
|
| + // Sends updates for the remaining removed namespaces, if any.
|
| + for (; it_old != end_old; ++it_old)
|
| + NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
|
| +
|
| + CheckInitializationComplete();
|
| + CheckRefreshComplete();
|
| +}
|
| +
|
| +void PolicyServiceImpl::CheckInitializationComplete() {
|
| // Check if all providers became initialized just now, if they weren't before.
|
| if (!initialization_complete_) {
|
| initialization_complete_ = true;
|
| - for (ProviderList::iterator iter = providers_.begin();
|
| - iter != providers_.end(); ++iter) {
|
| - if (!(*iter)->provider->IsInitializationComplete()) {
|
| + for (RegistrarList::iterator iter = registrars_.begin();
|
| + iter != registrars_.end(); ++iter) {
|
| + if (!(*iter)->provider()->IsInitializationComplete()) {
|
| initialization_complete_ = false;
|
| break;
|
| }
|
| }
|
| if (initialization_complete_) {
|
| - for (EntryMap::iterator i = entries_.begin(); i != entries_.end(); ++i) {
|
| + for (ObserverMap::iterator iter = observers_.begin();
|
| + iter != observers_.end(); ++iter) {
|
| FOR_EACH_OBSERVER(PolicyService::Observer,
|
| - i->second->observers,
|
| + *iter->second,
|
| OnPolicyServiceInitialized());
|
| }
|
| }
|
| }
|
| +}
|
|
|
| +void PolicyServiceImpl::CheckRefreshComplete() {
|
| // Invoke all the callbacks if a refresh has just fully completed.
|
| - if (is_refresh && !refresh_pending) {
|
| + if (refresh_pending_.empty() && !refresh_callbacks_.empty()) {
|
| std::vector<base::Closure> callbacks;
|
| callbacks.swap(refresh_callbacks_);
|
| for (size_t i = 0; i < callbacks.size(); ++i)
|
|
|