diff options
Diffstat (limited to 'chromium/components/policy/core/common/async_policy_loader.cc')
-rw-r--r-- | chromium/components/policy/core/common/async_policy_loader.cc | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/chromium/components/policy/core/common/async_policy_loader.cc b/chromium/components/policy/core/common/async_policy_loader.cc new file mode 100644 index 00000000000..7d40e9f3bf2 --- /dev/null +++ b/chromium/components/policy/core/common/async_policy_loader.cc @@ -0,0 +1,205 @@ +// 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/task/sequenced_task_runner.h" +#include "build/build_config.h" +#include "components/policy/core/common/management/management_service.h" +#include "components/policy/core/common/management/platform_management_service.h" +#include "components/policy/core/common/policy_bundle.h" + +using base::Time; + +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 base::TimeDelta kSettleInterval = base::Seconds(5); + +// The time interval for rechecking policy. This is the fallback in case the +// implementation never detects changes. +constexpr base::TimeDelta kReloadInterval = base::Minutes(15); + +} // namespace + +AsyncPolicyLoader::AsyncPolicyLoader( + const scoped_refptr<base::SequencedTaskRunner>& task_runner, + bool periodic_updates) + : task_runner_(task_runner), + management_service_(nullptr), + periodic_updates_(periodic_updates) {} + +AsyncPolicyLoader::AsyncPolicyLoader( + const scoped_refptr<base::SequencedTaskRunner>& task_runner, + ManagementService* management_service, + bool periodic_updates) + : task_runner_(task_runner), + management_service_(management_service), + periodic_updates_(periodic_updates) {} + +AsyncPolicyLoader::~AsyncPolicyLoader() {} + +Time AsyncPolicyLoader::LastModificationTime() { + return Time(); +} + +void AsyncPolicyLoader::Reload(bool force) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + + base::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; + } + + // `management_service_` must be called on the main thread. + // base::Unretained is okay here since `management_service_` is an instance of + // PlatformManagementService which is a singleton that outlives this class. + if (!platform_management_trustworthiness_.has_value() && + management_service_) { + DCHECK_EQ(management_service_, PlatformManagementService::GetInstance()); + ui_thread_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce( + &ManagementService::GetManagementAuthorityTrustworthiness, + base::Unretained(management_service_)), + base::BindOnce( + &AsyncPolicyLoader::SetPlatformManagementTrustworthinessAndReload, + weak_factory_.GetWeakPtr(), force)); + return; + } + + std::unique_ptr<PolicyBundle> bundle(Load()); + + // Reset so that we get the latest management trustworthiness at the next + // reload. + platform_management_trustworthiness_.reset(); + + // 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(), + /*drop_invalid_component_policies=*/true); + + update_callback_.Run(std::move(bundle)); + if (periodic_updates_) { + ScheduleNextReload(kReloadInterval); + } +} + +bool AsyncPolicyLoader::ShouldFilterSensitivePolicies() { +#if BUILDFLAG(IS_WIN) + DCHECK(platform_management_trustworthiness_); + + return *platform_management_trustworthiness_ < + ManagementAuthorityTrustworthiness::TRUSTED; +#else + return false; +#endif +} + +void AsyncPolicyLoader::SetPlatformManagementTrustworthinessAndReload( + bool force, + ManagementAuthorityTrustworthiness trustworthiness) { + platform_management_trustworthiness_ = trustworthiness; + Reload(force); +} + +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; + if (management_service_) { + DCHECK_EQ(management_service_, PlatformManagementService::GetInstance()); + platform_management_trustworthiness_ = + management_service_->GetManagementAuthorityTrustworthiness(); + } + std::unique_ptr<PolicyBundle> bundle(Load()); + platform_management_trustworthiness_.reset(); + // Filter out mismatching policies. + schema_map_->FilterBundle(bundle.get(), + /*drop_invalid_component_policies=*/true); + return bundle; +} + +void AsyncPolicyLoader::Init( + scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner, + const UpdateCallback& update_callback) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + DCHECK(update_callback_.is_null()); + DCHECK(!update_callback.is_null()); + update_callback_ = update_callback; + ui_thread_task_runner_ = ui_thread_task_runner; + + 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. + if (periodic_updates_) { + ScheduleNextReload(kReloadInterval); + } +} + +void AsyncPolicyLoader::RefreshPolicies(scoped_refptr<SchemaMap> schema_map) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + schema_map_ = schema_map; + Reload(true); +} + +void AsyncPolicyLoader::ScheduleNextReload(base::TimeDelta delay) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + weak_factory_.InvalidateWeakPtrs(); + task_runner_->PostDelayedTask( + FROM_HERE, + base::BindOnce(&AsyncPolicyLoader::Reload, weak_factory_.GetWeakPtr(), + false /* force */), + delay); +} + +bool AsyncPolicyLoader::IsSafeToReload(const Time& now, + base::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 base::TimeDelta age = now - last_modification_clock_; + if (age < kSettleInterval) { + *delay = kSettleInterval - age; + return false; + } + + return true; +} + +} // namespace policy |