| Index: remoting/host/policy_hack/policy_watcher.cc
|
| diff --git a/remoting/host/policy_hack/policy_watcher.cc b/remoting/host/policy_hack/policy_watcher.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..23320eaf0f9d3bb20a1caebc6a44c72935028fac
|
| --- /dev/null
|
| +++ b/remoting/host/policy_hack/policy_watcher.cc
|
| @@ -0,0 +1,163 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// Most of this code is copied from:
|
| +// src/chrome/browser/policy/asynchronous_policy_loader.{h,cc}
|
| +
|
| +#include "remoting/host/policy_hack/policy_watcher.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/compiler_specific.h"
|
| +#include "base/location.h"
|
| +#include "base/memory/weak_ptr.h"
|
| +#include "base/single_thread_task_runner.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/time.h"
|
| +#include "base/values.h"
|
| +
|
| +namespace remoting {
|
| +namespace policy_hack {
|
| +
|
| +namespace {
|
| +// The time interval for rechecking policy. This is our fallback in case the
|
| +// delegate never reports a change to the ReloadObserver.
|
| +const int kFallbackReloadDelayMinutes = 15;
|
| +
|
| +// Gets a boolean from a dictionary, or returns a default value if the boolean
|
| +// couldn't be read.
|
| +bool GetBooleanOrDefault(const base::DictionaryValue* dict, const char* key,
|
| + bool default_if_value_missing,
|
| + bool default_if_value_not_boolean) {
|
| + if (!dict->HasKey(key)) {
|
| + return default_if_value_missing;
|
| + }
|
| + base::Value* value;
|
| + if (dict->Get(key, &value) && value->IsType(base::Value::TYPE_BOOLEAN)) {
|
| + bool bool_value;
|
| + CHECK(value->GetAsBoolean(&bool_value));
|
| + return bool_value;
|
| + }
|
| + return default_if_value_not_boolean;
|
| +}
|
| +
|
| +// Copies a boolean from one dictionary to another, using a default value
|
| +// if the boolean couldn't be read from the first dictionary.
|
| +void CopyBooleanOrDefault(base::DictionaryValue* to,
|
| + const base::DictionaryValue* from, const char* key,
|
| + bool default_if_value_missing,
|
| + bool default_if_value_not_boolean) {
|
| + to->Set(key, base::Value::CreateBooleanValue(
|
| + GetBooleanOrDefault(from, key, default_if_value_missing,
|
| + default_if_value_not_boolean)));
|
| +}
|
| +
|
| +// Copies all policy values from one dictionary to another, using default values
|
| +// when necessary.
|
| +scoped_ptr<base::DictionaryValue> AddDefaultValuesWhenNecessary(
|
| + const base::DictionaryValue* from) {
|
| + scoped_ptr<base::DictionaryValue> to(new base::DictionaryValue());
|
| + CopyBooleanOrDefault(to.get(), from,
|
| + PolicyWatcher::kNatPolicyName, true, false);
|
| + return to.Pass();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +const char PolicyWatcher::kNatPolicyName[] =
|
| + "RemoteAccessHostFirewallTraversal";
|
| +
|
| +const char* const PolicyWatcher::kBooleanPolicyNames[] =
|
| + { PolicyWatcher::kNatPolicyName };
|
| +
|
| +const int PolicyWatcher::kBooleanPolicyNamesNum =
|
| + arraysize(kBooleanPolicyNames);
|
| +
|
| +PolicyWatcher::PolicyWatcher(
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner)
|
| + : task_runner_(task_runner),
|
| + old_policies_(new base::DictionaryValue()),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
|
| +}
|
| +
|
| +PolicyWatcher::~PolicyWatcher() {
|
| +}
|
| +
|
| +void PolicyWatcher::StartWatching(const PolicyCallback& policy_callback) {
|
| + if (!OnPolicyWatcherThread()) {
|
| + task_runner_->PostTask(FROM_HERE,
|
| + base::Bind(&PolicyWatcher::StartWatching,
|
| + base::Unretained(this),
|
| + policy_callback));
|
| + return;
|
| + }
|
| +
|
| + policy_callback_ = policy_callback;
|
| + StartWatchingInternal();
|
| +}
|
| +
|
| +void PolicyWatcher::StopWatching(base::WaitableEvent* done) {
|
| + if (!OnPolicyWatcherThread()) {
|
| + task_runner_->PostTask(FROM_HERE,
|
| + base::Bind(&PolicyWatcher::StopWatching,
|
| + base::Unretained(this), done));
|
| + return;
|
| + }
|
| +
|
| + StopWatchingInternal();
|
| + weak_factory_.InvalidateWeakPtrs();
|
| + policy_callback_.Reset();
|
| +
|
| + done->Signal();
|
| +}
|
| +
|
| +void PolicyWatcher::ScheduleFallbackReloadTask() {
|
| + DCHECK(OnPolicyWatcherThread());
|
| + ScheduleReloadTask(
|
| + base::TimeDelta::FromMinutes(kFallbackReloadDelayMinutes));
|
| +}
|
| +
|
| +void PolicyWatcher::ScheduleReloadTask(const base::TimeDelta& delay) {
|
| + DCHECK(OnPolicyWatcherThread());
|
| + task_runner_->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&PolicyWatcher::Reload, weak_factory_.GetWeakPtr()),
|
| + delay);
|
| +}
|
| +
|
| +bool PolicyWatcher::OnPolicyWatcherThread() const {
|
| + return task_runner_->BelongsToCurrentThread();
|
| +}
|
| +
|
| +void PolicyWatcher::UpdatePolicies(
|
| + const base::DictionaryValue* new_policies_raw) {
|
| + DCHECK(OnPolicyWatcherThread());
|
| +
|
| + // Use default values for any missing policies.
|
| + scoped_ptr<base::DictionaryValue> new_policies =
|
| + AddDefaultValuesWhenNecessary(new_policies_raw);
|
| +
|
| + // Find the changed policies.
|
| + scoped_ptr<base::DictionaryValue> changed_policies(
|
| + new base::DictionaryValue());
|
| + base::DictionaryValue::Iterator iter(*new_policies);
|
| + while (iter.HasNext()) {
|
| + base::Value* old_policy;
|
| + if (!(old_policies_->Get(iter.key(), &old_policy) &&
|
| + old_policy->Equals(&iter.value()))) {
|
| + changed_policies->Set(iter.key(), iter.value().DeepCopy());
|
| + }
|
| + iter.Advance();
|
| + }
|
| +
|
| + // Save the new policies.
|
| + old_policies_.swap(new_policies);
|
| +
|
| + // Notify our client of the changed policies.
|
| + if (!changed_policies->empty()) {
|
| + policy_callback_.Run(changed_policies.Pass());
|
| + }
|
| +}
|
| +
|
| +} // namespace policy_hack
|
| +} // namespace remoting
|
|
|