Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/policy/policy_service_impl.h" | 5 #include "chrome/browser/policy/policy_service_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | |
| 8 #include "base/bind_helpers.h" | |
| 7 #include "base/observer_list.h" | 9 #include "base/observer_list.h" |
| 8 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "content/public/browser/browser_thread.h" | |
| 12 | |
| 13 using content::BrowserThread; | |
| 9 | 14 |
| 10 namespace policy { | 15 namespace policy { |
| 11 | 16 |
| 17 namespace { | |
| 18 | |
| 19 // Helper to invoke |callbacks| asynchronously. | |
| 20 void InvokeCallbacks(std::vector<base::Closure>* callbacks) { | |
| 21 for (std::vector<base::Closure>::iterator it = callbacks->begin(); | |
| 22 it != callbacks->end(); ++it) { | |
| 23 it->Run(); | |
| 24 } | |
| 25 } | |
| 26 | |
| 27 // Helper to resolve the overloading of PostTask. | |
| 28 void PostTask(BrowserThread::ID id, const base::Closure& callback) { | |
| 29 BrowserThread::PostTask(id, FROM_HERE, callback); | |
| 30 } | |
| 31 | |
| 32 } // namespace | |
| 33 | |
| 12 struct PolicyServiceImpl::Entry { | 34 struct PolicyServiceImpl::Entry { |
| 13 PolicyMap policies; | 35 PolicyMap policies; |
| 14 ObserverList<PolicyService::Observer, true> observers; | 36 ObserverList<PolicyService::Observer, true> observers; |
| 15 }; | 37 }; |
| 16 | 38 |
| 17 struct PolicyServiceImpl::ProviderData { | 39 struct PolicyServiceImpl::ProviderData { |
| 18 ConfigurationPolicyProvider* provider; | 40 ConfigurationPolicyProvider* provider; |
| 19 ConfigurationPolicyObserverRegistrar registrar; | 41 ConfigurationPolicyObserverRegistrar registrar; |
| 20 PolicyMap policies; | 42 PolicyMap policies; |
| 43 bool refresh_pending; | |
| 21 }; | 44 }; |
| 22 | 45 |
| 23 PolicyServiceImpl::PolicyServiceImpl(const Providers& providers) { | 46 PolicyServiceImpl::PolicyServiceImpl(const Providers& providers) { |
| 24 initialization_complete_ = true; | 47 initialization_complete_ = true; |
| 25 for (size_t i = 0; i < providers.size(); ++i) { | 48 for (size_t i = 0; i < providers.size(); ++i) { |
| 26 ConfigurationPolicyProvider* provider = providers[i]; | 49 ConfigurationPolicyProvider* provider = providers[i]; |
| 27 ProviderData* data = new ProviderData; | 50 ProviderData* data = new ProviderData; |
| 28 data->provider = provider; | 51 data->provider = provider; |
| 29 data->registrar.Init(provider, this); | 52 data->registrar.Init(provider, this); |
| 53 data->refresh_pending = false; | |
| 30 if (provider->IsInitializationComplete()) | 54 if (provider->IsInitializationComplete()) |
| 31 provider->Provide(&data->policies); | 55 provider->Provide(&data->policies); |
| 32 else | 56 else |
| 33 initialization_complete_ = false; | 57 initialization_complete_ = false; |
| 34 providers_.push_back(data); | 58 providers_.push_back(data); |
| 35 } | 59 } |
| 36 // There are no observers yet, but calls to GetPolicies() should already get | 60 // There are no observers yet, but calls to GetPolicies() should already get |
| 37 // the processed policy values. | 61 // the processed policy values. |
| 38 MergeAndTriggerUpdates(); | 62 MergeAndTriggerUpdates(false); |
| 39 } | 63 } |
| 40 | 64 |
| 41 PolicyServiceImpl::~PolicyServiceImpl() { | 65 PolicyServiceImpl::~PolicyServiceImpl() { |
| 42 STLDeleteElements(&providers_); | 66 STLDeleteElements(&providers_); |
| 43 STLDeleteValues(&entries_); | 67 STLDeleteValues(&entries_); |
| 44 } | 68 } |
| 45 | 69 |
| 46 void PolicyServiceImpl::AddObserver(PolicyDomain domain, | 70 void PolicyServiceImpl::AddObserver(PolicyDomain domain, |
| 47 const std::string& component_id, | 71 const std::string& component_id, |
| 48 PolicyService::Observer* observer) { | 72 PolicyService::Observer* observer) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 68 const std::string& component_id) const { | 92 const std::string& component_id) const { |
| 69 PolicyNamespace ns = std::make_pair(domain, component_id); | 93 PolicyNamespace ns = std::make_pair(domain, component_id); |
| 70 EntryMap::const_iterator it = entries_.find(ns); | 94 EntryMap::const_iterator it = entries_.find(ns); |
| 71 return it == entries_.end() ? NULL : &it->second->policies; | 95 return it == entries_.end() ? NULL : &it->second->policies; |
| 72 } | 96 } |
| 73 | 97 |
| 74 bool PolicyServiceImpl::IsInitializationComplete() const { | 98 bool PolicyServiceImpl::IsInitializationComplete() const { |
| 75 return initialization_complete_; | 99 return initialization_complete_; |
| 76 } | 100 } |
| 77 | 101 |
| 102 void PolicyServiceImpl::RefreshPolicies(const base::Closure& callback) { | |
| 103 refresh_callbacks_.push_back(callback); | |
| 104 | |
| 105 // Some providers might invoke OnUpdatePolicy synchronously while handling | |
| 106 // RefreshPolicies. Flag all with refresh_pending before starting to refresh. | |
| 107 ProviderList::iterator it; | |
| 108 for (it = providers_.begin(); it != providers_.end(); ++it) | |
| 109 (*it)->refresh_pending = true; | |
| 110 for (it = providers_.begin(); it != providers_.end(); ++it) | |
| 111 (*it)->provider->RefreshPolicies(); | |
| 112 } | |
| 113 | |
| 78 void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) { | 114 void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) { |
| 79 ProviderList::iterator it = GetProviderData(provider); | 115 ProviderList::iterator it = GetProviderData(provider); |
| 80 if (it == providers_.end()) | 116 if (it == providers_.end()) |
| 81 return; | 117 return; |
| 82 provider->Provide(&(*it)->policies); | 118 provider->Provide(&(*it)->policies); |
| 83 MergeAndTriggerUpdates(); | 119 bool did_refresh = (*it)->refresh_pending; |
| 120 (*it)->refresh_pending = false; | |
| 121 MergeAndTriggerUpdates(did_refresh); | |
| 84 } | 122 } |
| 85 | 123 |
| 86 void PolicyServiceImpl::OnProviderGoingAway( | 124 void PolicyServiceImpl::OnProviderGoingAway( |
| 87 ConfigurationPolicyProvider* provider) { | 125 ConfigurationPolicyProvider* provider) { |
| 88 ProviderList::iterator it = GetProviderData(provider); | 126 ProviderList::iterator it = GetProviderData(provider); |
| 89 if (it == providers_.end()) | 127 if (it == providers_.end()) |
| 90 return; | 128 return; |
| 129 bool did_refresh = (*it)->refresh_pending; | |
| 91 delete *it; | 130 delete *it; |
| 92 providers_.erase(it); | 131 providers_.erase(it); |
| 93 MergeAndTriggerUpdates(); | 132 MergeAndTriggerUpdates(did_refresh); |
| 94 } | 133 } |
| 95 | 134 |
| 96 PolicyServiceImpl::Entry* PolicyServiceImpl::GetOrCreate( | 135 PolicyServiceImpl::Entry* PolicyServiceImpl::GetOrCreate( |
| 97 const PolicyNamespace& ns) { | 136 const PolicyNamespace& ns) { |
| 98 Entry*& entry = entries_[ns]; | 137 Entry*& entry = entries_[ns]; |
| 99 if (!entry) | 138 if (!entry) |
| 100 entry = new Entry; | 139 entry = new Entry; |
| 101 return entry; | 140 return entry; |
| 102 } | 141 } |
| 103 | 142 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 115 void PolicyServiceImpl::MaybeCleanup(const PolicyNamespace& ns) { | 154 void PolicyServiceImpl::MaybeCleanup(const PolicyNamespace& ns) { |
| 116 EntryMap::iterator it = entries_.find(ns); | 155 EntryMap::iterator it = entries_.find(ns); |
| 117 if (it != entries_.end() && | 156 if (it != entries_.end() && |
| 118 it->second->policies.empty() && | 157 it->second->policies.empty() && |
| 119 it->second->observers.size() == 0) { | 158 it->second->observers.size() == 0) { |
| 120 delete it->second; | 159 delete it->second; |
| 121 entries_.erase(it); | 160 entries_.erase(it); |
| 122 } | 161 } |
| 123 } | 162 } |
| 124 | 163 |
| 125 void PolicyServiceImpl::MergeAndTriggerUpdates() { | 164 void PolicyServiceImpl::MergeAndTriggerUpdates(bool is_refresh) { |
| 126 // TODO(joaodasilva): do this for each namespace once the providers also | 165 // TODO(joaodasilva): do this for each namespace once the providers also |
| 127 // provide policy for more namespaces. | 166 // provide policy for more namespaces. |
| 167 | |
| 128 PolicyMap policies; | 168 PolicyMap policies; |
| 169 bool refresh_pending = false; | |
| 129 for (ProviderList::iterator it = providers_.begin(); | 170 for (ProviderList::iterator it = providers_.begin(); |
| 130 it != providers_.end(); ++it) { | 171 it != providers_.end(); ++it) { |
| 131 policies.MergeFrom((*it)->policies); | 172 policies.MergeFrom((*it)->policies); |
| 173 refresh_pending |= (*it)->refresh_pending; | |
| 132 } | 174 } |
| 133 | 175 |
| 176 if (refresh_pending) | |
|
Mattias Nissler (ping if slow)
2012/04/26 11:08:52
This results in all updates being blocked until th
Joao da Silva
2012/04/26 14:43:58
Done.
| |
| 177 return; | |
| 178 | |
| 134 Entry* entry = GetOrCreate(std::make_pair(POLICY_DOMAIN_CHROME, "")); | 179 Entry* entry = GetOrCreate(std::make_pair(POLICY_DOMAIN_CHROME, "")); |
| 135 if (!policies.Equals(entry->policies)) { | 180 if (!policies.Equals(entry->policies)) { |
| 136 // Swap first, so that observers that call GetPolicies() see the current | 181 // Swap first, so that observers that call GetPolicies() see the current |
| 137 // values. | 182 // values. |
| 138 entry->policies.Swap(&policies); | 183 entry->policies.Swap(&policies); |
| 139 FOR_EACH_OBSERVER( | 184 FOR_EACH_OBSERVER( |
| 140 PolicyService::Observer, | 185 PolicyService::Observer, |
| 141 entry->observers, | 186 entry->observers, |
| 142 OnPolicyUpdated(POLICY_DOMAIN_CHROME, "", policies, entry->policies)); | 187 OnPolicyUpdated(POLICY_DOMAIN_CHROME, "", policies, entry->policies)); |
| 143 } | 188 } |
| 144 | 189 |
| 145 // Check if all providers became initialized just now, if they weren't before. | 190 // Check if all providers became initialized just now, if they weren't before. |
| 146 if (!initialization_complete_) { | 191 if (!initialization_complete_) { |
| 147 initialization_complete_ = true; | 192 initialization_complete_ = true; |
| 148 for (ProviderList::iterator iter = providers_.begin(); | 193 for (ProviderList::iterator iter = providers_.begin(); |
| 149 iter != providers_.end(); ++iter) { | 194 iter != providers_.end(); ++iter) { |
| 150 if (!(*iter)->provider->IsInitializationComplete()) { | 195 if (!(*iter)->provider->IsInitializationComplete()) { |
| 151 initialization_complete_ = false; | 196 initialization_complete_ = false; |
| 152 break; | 197 break; |
| 153 } | 198 } |
| 154 } | 199 } |
| 155 if (initialization_complete_) { | 200 if (initialization_complete_) { |
| 156 for (EntryMap::iterator i = entries_.begin(); i != entries_.end(); ++i) { | 201 for (EntryMap::iterator i = entries_.begin(); i != entries_.end(); ++i) { |
| 157 FOR_EACH_OBSERVER(PolicyService::Observer, | 202 FOR_EACH_OBSERVER(PolicyService::Observer, |
| 158 i->second->observers, | 203 i->second->observers, |
| 159 OnPolicyServiceInitialized()); | 204 OnPolicyServiceInitialized()); |
| 160 } | 205 } |
| 161 } | 206 } |
| 162 } | 207 } |
| 208 | |
| 209 // Invoke all the callbacks if a refresh has just fully completed. | |
| 210 if (is_refresh && !refresh_pending) { | |
| 211 // Some policies (e.g. URLBlacklist) post tasks to other message loops | |
| 212 // before they start enforcing updated policy values; make sure those tasks | |
| 213 // have finished after a policy update. | |
| 214 // Updates of the URLBlacklist are done on IO, after building the blacklist | |
| 215 // on FILE, which is initiated from IO. | |
|
Mattias Nissler (ping if slow)
2012/04/26 11:08:52
This doesn't belong here. Policies might trigger v
Joao da Silva
2012/04/26 14:43:58
Right; this was introduced to fix automation tests
| |
| 216 std::vector<base::Closure>* callbacks = new std::vector<base::Closure>(); | |
| 217 callbacks->swap(refresh_callbacks_); | |
| 218 PostTask(BrowserThread::IO, | |
| 219 base::Bind(&PostTask, BrowserThread::FILE, | |
| 220 base::Bind(&PostTask, BrowserThread::IO, | |
| 221 base::Bind(&PostTask, BrowserThread::UI, | |
| 222 base::Bind(InvokeCallbacks, base::Owned(callbacks)))))); | |
| 223 } | |
| 163 } | 224 } |
| 164 | 225 |
| 165 } // namespace policy | 226 } // namespace policy |
| OLD | NEW |