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