blob: 59fcc4b122a182a0fa8874c8903143d686c004e1 [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "secagentd/policies_features_broker.h"
#include <array>
#include <memory>
#include <string>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/logging.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "featured/c_feature_library.h"
#include "featured/feature_library.h"
#include "policy/device_policy.h"
#include "policy/libpolicy.h"
namespace secagentd {
using feature::PlatformFeaturesInterface;
PoliciesFeaturesBroker::PoliciesFeaturesBroker(
std::unique_ptr<policy::PolicyProvider> policy_provider,
std::unique_ptr<PlatformFeaturesInterface> features,
base::RepeatingClosure poll_done_cb)
: weak_ptr_factory_(this),
policy_provider_(std::move(policy_provider)),
features_(std::move(features)),
poll_done_cb_(std::move(poll_done_cb)),
feature_values_{
{Feature::kCrOSLateBootSecagentdXDRReporting,
{{.name = "CrOSLateBootSecagentdXDRReporting",
.default_state = FEATURE_ENABLED_BY_DEFAULT},
false}},
{Feature::kCrOSLateBootSecagentdBatchEvents,
{{.name = "CrOSLateBootSecagentdBatchEvents",
.default_state = FEATURE_ENABLED_BY_DEFAULT},
false}},
{Feature::kCrOSLateBootSecagentdCoalesceTerminates,
{{.name = "CrOSLateBootSecagentdCoalesceTerminates",
.default_state = FEATURE_DISABLED_BY_DEFAULT},
false}},
} {
for (const auto& [k, v] : feature_values_) {
variations_to_query_.push_back(&v.variation);
}
}
void PoliciesFeaturesBroker::StartAndBlockForSync(
base::TimeDelta poll_duration) {
Poll(true);
poll_timer_.Start(FROM_HERE, poll_duration,
base::BindRepeating(&PoliciesFeaturesBroker::Poll,
weak_ptr_factory_.GetWeakPtr(), false));
}
bool PoliciesFeaturesBroker::GetFeature(Feature key) const {
base::AutoLock lock(values_lock_);
auto it = feature_values_.find(key);
CHECK(it != feature_values_.end());
return it->second.value;
}
bool PoliciesFeaturesBroker::GetDeviceReportXDREventsPolicy() const {
base::AutoLock lock(values_lock_);
return device_report_xdr_events_policy_value_;
}
void PoliciesFeaturesBroker::Poll(bool blocking) {
UpdateDeviceReportXDREventsPolicy();
if (blocking) {
UpdateFeaturesResults(
features_->GetParamsAndEnabledBlocking(variations_to_query_));
} else {
// Start a timer just in case features never runs the async callback for
// some reason. Probably not required in practice but being paranoid here
// because either the Policy or the Feature could be used to make the daemon
// stop emitting events in an emergency. So it's best for them to be as
// independent as possible.
poll_done_fallback_timer_.Start(
FROM_HERE, (poll_timer_.GetCurrentDelay() / 2),
base::BindOnce(&PoliciesFeaturesBroker::RunPollDoneCb,
weak_ptr_factory_.GetWeakPtr()));
features_->GetParamsAndEnabled(
variations_to_query_,
base::BindOnce(&PoliciesFeaturesBroker::UpdateFeaturesResults,
weak_ptr_factory_.GetWeakPtr()));
}
}
void PoliciesFeaturesBroker::UpdateFeaturesResults(
PlatformFeaturesInterface::ParamsResult result) {
VLOG(1) << "Updating Feature values.";
base::AutoLock lock(values_lock_);
for (auto& [k, v] : feature_values_) {
auto it = result.find(v.variation.name);
if (it != result.end()) {
if (v.value != it->second.enabled) {
v.value = it->second.enabled;
LOG(INFO) << "Feature " << v.variation.name << "changed to "
<< std::to_string(v.value);
}
} else {
LOG(INFO) << "Feature " << v.variation.name << "not in results";
}
}
if (poll_done_fallback_timer_.IsRunning()) {
poll_done_fallback_timer_.Stop();
}
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&PoliciesFeaturesBroker::RunPollDoneCb,
weak_ptr_factory_.GetWeakPtr()));
}
void PoliciesFeaturesBroker::UpdateDeviceReportXDREventsPolicy() {
VLOG(1) << "Updating DeviceReportXDREvents Policy.";
base::AutoLock lock(values_lock_);
// Default value is do not report.
bool new_policy = false;
policy_provider_->Reload();
if (policy_provider_->device_policy_is_loaded()) {
new_policy =
policy_provider_->GetDevicePolicy().GetDeviceReportXDREvents().value_or(
false);
}
if (new_policy != device_report_xdr_events_policy_value_) {
LOG(INFO) << "DeviceReportXDREvents policy changed to "
<< std::to_string(new_policy);
device_report_xdr_events_policy_value_ = new_policy;
}
}
void PoliciesFeaturesBroker::RunPollDoneCb() {
VLOG(1) << "Running poll_done_cb_";
poll_done_cb_.Run();
}
} // namespace secagentd