diff options
Diffstat (limited to 'components/policy/core/common/async_policy_loader.cc')
-rw-r--r-- | components/policy/core/common/async_policy_loader.cc | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/components/policy/core/common/async_policy_loader.cc b/components/policy/core/common/async_policy_loader.cc new file mode 100644 index 0000000000..b0edee2ea7 --- /dev/null +++ b/components/policy/core/common/async_policy_loader.cc @@ -0,0 +1,137 @@ +// Copyright 2013 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. + +#include "components/policy/core/common/async_policy_loader.h" + +#include <utility> + +#include "base/bind.h" +#include "base/location.h" +#include "base/sequenced_task_runner.h" +#include "components/policy/core/common/policy_bundle.h" + +using base::Time; +using base::TimeDelta; + +namespace policy { + +namespace { + +// Amount of time to wait for the files on disk to settle before trying to load +// them. This alleviates the problem of reading partially written files and +// makes it possible to batch quasi-simultaneous changes. +constexpr TimeDelta kSettleInterval = TimeDelta::FromSeconds(5); + +// The time interval for rechecking policy. This is the fallback in case the +// implementation never detects changes. +constexpr TimeDelta kReloadInterval = TimeDelta::FromMinutes(15); + +} // namespace + +AsyncPolicyLoader::AsyncPolicyLoader( + const scoped_refptr<base::SequencedTaskRunner>& task_runner) + : task_runner_(task_runner) {} + +AsyncPolicyLoader::~AsyncPolicyLoader() {} + +Time AsyncPolicyLoader::LastModificationTime() { + return Time(); +} + +void AsyncPolicyLoader::Reload(bool force) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + + TimeDelta delay; + Time now = Time::Now(); + // Check if there was a recent modification to the underlying files. + if (!force && !IsSafeToReload(now, &delay)) { + ScheduleNextReload(delay); + return; + } + + std::unique_ptr<PolicyBundle> bundle(Load()); + + // Check if there was a modification while reading. + if (!force && !IsSafeToReload(now, &delay)) { + ScheduleNextReload(delay); + return; + } + + // Filter out mismatching policies. + schema_map_->FilterBundle(bundle.get()); + + update_callback_.Run(std::move(bundle)); + ScheduleNextReload(kReloadInterval); +} + +std::unique_ptr<PolicyBundle> AsyncPolicyLoader::InitialLoad( + const scoped_refptr<SchemaMap>& schema_map) { + // This is the first load, early during startup. Use this to record the + // initial |last_modification_time_|, so that potential changes made before + // installing the watches can be detected. + last_modification_time_ = LastModificationTime(); + schema_map_ = schema_map; + std::unique_ptr<PolicyBundle> bundle(Load()); + // Filter out mismatching policies. + schema_map_->FilterBundle(bundle.get()); + return bundle; +} + +void AsyncPolicyLoader::Init(const UpdateCallback& update_callback) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + DCHECK(update_callback_.is_null()); + DCHECK(!update_callback.is_null()); + update_callback_ = update_callback; + + InitOnBackgroundThread(); + + // There might have been changes to the underlying files since the initial + // load and before the watchers have been created. + if (LastModificationTime() != last_modification_time_) + Reload(false); + + // Start periodic refreshes. + ScheduleNextReload(kReloadInterval); +} + +void AsyncPolicyLoader::RefreshPolicies(scoped_refptr<SchemaMap> schema_map) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + schema_map_ = schema_map; + Reload(true); +} + +void AsyncPolicyLoader::ScheduleNextReload(TimeDelta delay) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + weak_factory_.InvalidateWeakPtrs(); + task_runner_->PostDelayedTask(FROM_HERE, + base::Bind(&AsyncPolicyLoader::Reload, + weak_factory_.GetWeakPtr(), + false /* force */), + delay); +} + +bool AsyncPolicyLoader::IsSafeToReload(const Time& now, TimeDelta* delay) { + Time last_modification = LastModificationTime(); + if (last_modification.is_null()) + return true; + + // If there was a change since the last recorded modification, wait some more. + if (last_modification != last_modification_time_) { + last_modification_time_ = last_modification; + last_modification_clock_ = now; + *delay = kSettleInterval; + return false; + } + + // Check whether the settle interval has elapsed. + const TimeDelta age = now - last_modification_clock_; + if (age < kSettleInterval) { + *delay = kSettleInterval - age; + return false; + } + + return true; +} + +} // namespace policy |