15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/policy_service_impl.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/values.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_bundle.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_map.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "policy/policy_constants.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef PolicyServiceImpl::Providers::const_iterator Iterator;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char* kProxyPolicies[] = {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  key::kProxyMode,
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  key::kProxyServerMode,
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  key::kProxyServer,
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  key::kProxyPacUrl,
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  key::kProxyBypassList,
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FixDeprecatedPolicies(PolicyMap* policies) {
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Proxy settings have been configured by 5 policies that didn't mix well
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // together, and maps of policies had to take this into account when merging
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // policy sources. The proxy settings will eventually be configured by a
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // single Dictionary policy when all providers have support for that. For
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // now, the individual policies are mapped here to a single Dictionary policy
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // that the rest of the policy machinery uses.
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The highest (level, scope) pair for an existing proxy policy is determined
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // first, and then only policies with those exact attributes are merged.
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PolicyMap::Entry current_priority;  // Defaults to the lowest priority.
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> proxy_settings(new base::DictionaryValue);
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kProxyPolicies); ++i) {
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PolicyMap::Entry* entry = policies->Get(kProxyPolicies[i]);
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (entry) {
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (entry->has_higher_priority_than(current_priority)) {
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        proxy_settings->Clear();
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        current_priority = *entry;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!entry->has_higher_priority_than(current_priority) &&
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          !current_priority.has_higher_priority_than(*entry)) {
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        proxy_settings->Set(kProxyPolicies[i], entry->value->DeepCopy());
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      policies->Erase(kProxyPolicies[i]);
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Sets the new |proxy_settings| if kProxySettings isn't set yet, or if the
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // new priority is higher.
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const PolicyMap::Entry* existing = policies->Get(key::kProxySettings);
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!proxy_settings->empty() &&
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (!existing || current_priority.has_higher_priority_than(*existing))) {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    policies->Set(key::kProxySettings,
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  current_priority.level,
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  current_priority.scope,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  proxy_settings.release(),
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  NULL);
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PolicyServiceImpl::PolicyServiceImpl(const Providers& providers)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : update_task_ptr_factory_(this) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    initialization_complete_[domain] = true;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  providers_ = providers;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Iterator it = providers.begin(); it != providers.end(); ++it) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ConfigurationPolicyProvider* provider = *it;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provider->AddObserver(this);
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      initialization_complete_[domain] &=
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          provider->IsInitializationComplete(static_cast<PolicyDomain>(domain));
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There are no observers yet, but calls to GetPolicies() should already get
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the processed policy values.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MergeAndTriggerUpdates();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PolicyServiceImpl::~PolicyServiceImpl() {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*it)->RemoveObserver(this);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteValues(&observers_);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PolicyServiceImpl::AddObserver(PolicyDomain domain,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    PolicyService::Observer* observer) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Observers*& list = observers_[domain];
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!list)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    list = new Observers();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  list->AddObserver(observer);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PolicyServiceImpl::RemoveObserver(PolicyDomain domain,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       PolicyService::Observer* observer) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ObserverMap::iterator it = observers_.find(domain);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == observers_.end()) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  it->second->RemoveObserver(observer);
112424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!it->second->might_have_observers()) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete it->second;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observers_.erase(it);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const PolicyMap& PolicyServiceImpl::GetPolicies(
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const PolicyNamespace& ns) const {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return policy_bundle_.Get(ns);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool PolicyServiceImpl::IsInitializationComplete(PolicyDomain domain) const {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(domain >= 0 && domain < POLICY_DOMAIN_SIZE);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return initialization_complete_[domain];
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PolicyServiceImpl::RefreshPolicies(const base::Closure& callback) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback.is_null())
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    refresh_callbacks_.push_back(callback);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (providers_.empty()) {
133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Refresh is immediately complete if there are no providers. See the note
134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // on OnUpdatePolicy() about why this is a posted task.
135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    update_task_ptr_factory_.InvalidateWeakPtrs();
136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        FROM_HERE,
138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates,
139a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                   update_task_ptr_factory_.GetWeakPtr()));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Some providers might invoke OnUpdatePolicy synchronously while handling
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // RefreshPolicies. Mark all as pending before refreshing.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      refresh_pending_.insert(*it);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (Iterator it = providers_.begin(); it != providers_.end(); ++it)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*it)->RefreshPolicies();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(1, std::count(providers_.begin(), providers_.end(), provider));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  refresh_pending_.erase(provider);
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Note: a policy change may trigger further policy changes in some providers.
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // For example, disabling SigninAllowed would cause the CloudPolicyManager to
156a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // drop all its policies, which makes this method enter again for that
157a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // provider.
158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  //
159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Therefore this update is posted asynchronously, to prevent reentrancy in
160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // MergeAndTriggerUpdates. Also, cancel a pending update if there is any,
161a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // since both will produce the same PolicyBundle.
162a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  update_task_ptr_factory_.InvalidateWeakPtrs();
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::MessageLoop::current()->PostTask(
164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      FROM_HERE,
165a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates,
166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                 update_task_ptr_factory_.GetWeakPtr()));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PolicyServiceImpl::NotifyNamespaceUpdated(
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const PolicyNamespace& ns,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PolicyMap& previous,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PolicyMap& current) {
173a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ObserverMap::iterator iterator = observers_.find(ns.domain);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iterator != observers_.end()) {
175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    FOR_EACH_OBSERVER(PolicyService::Observer,
176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                      *iterator->second,
177a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                      OnPolicyUpdated(ns, previous, current));
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PolicyServiceImpl::MergeAndTriggerUpdates() {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Merge from each provider in their order of priority.
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PolicyBundle bundle;
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (Iterator it = providers_.begin(); it != providers_.end(); ++it) {
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PolicyBundle provided_bundle;
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    provided_bundle.CopyFrom((*it)->policies());
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FixDeprecatedPolicies(&provided_bundle.Get(chrome_namespace));
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    bundle.MergeFrom(provided_bundle);
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Swap first, so that observers that call GetPolicies() see the current
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // values.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  policy_bundle_.Swap(&bundle);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only notify observers of namespaces that have been modified.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PolicyMap kEmpty;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PolicyBundle::const_iterator it_new = policy_bundle_.begin();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PolicyBundle::const_iterator end_new = policy_bundle_.end();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PolicyBundle::const_iterator it_old = bundle.begin();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PolicyBundle::const_iterator end_old = bundle.end();
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (it_new != end_new && it_old != end_old) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it_new->first < it_old->first) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A new namespace is available.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++it_new;
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (it_old->first < it_new->first) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A previously available namespace is now gone.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++it_old;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!it_new->second->Equals(*it_old->second)) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // An existing namespace's policies have changed.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NotifyNamespaceUpdated(it_new->first, *it_old->second, *it_new->second);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++it_new;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++it_old;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send updates for the remaining new namespaces, if any.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; it_new != end_new; ++it_new)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sends updates for the remaining removed namespaces, if any.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; it_old != end_old; ++it_old)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckInitializationComplete();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckRefreshComplete();
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PolicyServiceImpl::CheckInitializationComplete() {
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if all the providers just became initialized for each domain; if so,
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // notify that domain's observers.
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (initialization_complete_[domain])
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PolicyDomain policy_domain = static_cast<PolicyDomain>(domain);
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool all_complete = true;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (Iterator it = providers_.begin(); it != providers_.end(); ++it) {
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!(*it)->IsInitializationComplete(policy_domain)) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        all_complete = false;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (all_complete) {
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      initialization_complete_[domain] = true;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ObserverMap::iterator iter = observers_.find(policy_domain);
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (iter != observers_.end()) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FOR_EACH_OBSERVER(PolicyService::Observer,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          *iter->second,
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          OnPolicyServiceInitialized(policy_domain));
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PolicyServiceImpl::CheckRefreshComplete() {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invoke all the callbacks if a refresh has just fully completed.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (refresh_pending_.empty() && !refresh_callbacks_.empty()) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<base::Closure> callbacks;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callbacks.swap(refresh_callbacks_);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<base::Closure>::iterator it;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (it = callbacks.begin(); it != callbacks.end(); ++it)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it->Run();
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
273