Home | History | Annotate | Download | only in policy
      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