blob: e3a378a79e31afafddad259efec486b513fbea1a [file] [log] [blame]
// Copyright (c) 2014 The Chromium OS 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 "update_engine/update_manager/real_device_policy_provider.h"
#include <stdint.h>
#include <base/logging.h>
#include <base/time/time.h>
#include <chromeos/dbus/service_constants.h>
#include <policy/device_policy.h>
#include "update_engine/glib_utils.h"
#include "update_engine/update_manager/generic_variables.h"
#include "update_engine/update_manager/real_shill_provider.h"
#include "update_engine/utils.h"
using base::TimeDelta;
using policy::DevicePolicy;
using std::set;
using std::string;
namespace {
const int kDevicePolicyRefreshRateInMinutes = 60;
} // namespace
namespace chromeos_update_manager {
RealDevicePolicyProvider::~RealDevicePolicyProvider() {
CancelMainLoopEvent(scheduled_refresh_);
// Detach signal handler, free manager proxy.
dbus_->ProxyDisconnectSignal(manager_proxy_,
login_manager::kPropertyChangeCompleteSignal,
G_CALLBACK(HandlePropertyChangedCompletedStatic),
this);
dbus_->ProxyUnref(manager_proxy_);
}
bool RealDevicePolicyProvider::Init() {
CHECK(policy_provider_ != nullptr);
// On Init() we try to get the device policy and keep updating it.
RefreshDevicePolicyAndReschedule();
// We also listen for signals from the session manager to force a device
// policy refresh.
GError* error = nullptr;
DBusGConnection* connection = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
if (!connection) {
LOG(ERROR) << "Failed to initialize DBus connection: "
<< chromeos_update_engine::utils::GetAndFreeGError(&error);
return false;
}
manager_proxy_ = dbus_->ProxyNewForName(
connection,
login_manager::kSessionManagerServiceName,
login_manager::kSessionManagerServicePath,
login_manager::kSessionManagerInterface);
// Subscribe to the session manager's PropertyChangeComplete signal.
dbus_->ProxyAddSignal_1(manager_proxy_,
login_manager::kPropertyChangeCompleteSignal,
G_TYPE_STRING);
dbus_->ProxyConnectSignal(manager_proxy_,
login_manager::kPropertyChangeCompleteSignal,
G_CALLBACK(HandlePropertyChangedCompletedStatic),
this, nullptr);
return true;
}
// static
void RealDevicePolicyProvider::HandlePropertyChangedCompletedStatic(
DBusGProxy* proxy, const char* /* payload */, void* data) {
// We refresh the policy file even if the payload string is kSignalFailure.
RealDevicePolicyProvider* policy_provider =
reinterpret_cast<RealDevicePolicyProvider*>(data);
LOG(INFO) << "Reloading device policy due to signal received.";
policy_provider->RefreshDevicePolicy();
}
void RealDevicePolicyProvider::RefreshDevicePolicyAndReschedule() {
RefreshDevicePolicy();
scheduled_refresh_ = RunFromMainLoopAfterTimeout(
base::Bind(&RealDevicePolicyProvider::RefreshDevicePolicyAndReschedule,
base::Unretained(this)),
TimeDelta::FromMinutes(kDevicePolicyRefreshRateInMinutes));
}
template<typename T>
void RealDevicePolicyProvider::UpdateVariable(
AsyncCopyVariable<T>* var,
bool (DevicePolicy::*getter_method)(T*) const) {
T new_value;
if (policy_provider_->device_policy_is_loaded() &&
(policy_provider_->GetDevicePolicy().*getter_method)(&new_value)) {
var->SetValue(new_value);
} else {
var->UnsetValue();
}
}
template<typename T>
void RealDevicePolicyProvider::UpdateVariable(
AsyncCopyVariable<T>* var,
bool (RealDevicePolicyProvider::*getter_method)(T*) const) {
T new_value;
if (policy_provider_->device_policy_is_loaded() &&
(this->*getter_method)(&new_value)) {
var->SetValue(new_value);
} else {
var->UnsetValue();
}
}
bool RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate(
set<ConnectionType>* allowed_types) const {
set<string> allowed_types_str;
if (!policy_provider_->GetDevicePolicy()
.GetAllowedConnectionTypesForUpdate(&allowed_types_str)) {
return false;
}
allowed_types->clear();
for (auto& type_str : allowed_types_str) {
ConnectionType type =
RealShillProvider::ParseConnectionType(type_str.c_str());
if (type != ConnectionType::kUnknown) {
allowed_types->insert(type);
} else {
LOG(WARNING) << "Policy includes unknown connection type: " << type_str;
}
}
return true;
}
bool RealDevicePolicyProvider::ConvertScatterFactor(
TimeDelta* scatter_factor) const {
int64_t scatter_factor_in_seconds;
if (!policy_provider_->GetDevicePolicy().GetScatterFactorInSeconds(
&scatter_factor_in_seconds)) {
return false;
}
if (scatter_factor_in_seconds < 0) {
LOG(WARNING) << "Ignoring negative scatter factor: "
<< scatter_factor_in_seconds;
return false;
}
*scatter_factor = TimeDelta::FromSeconds(scatter_factor_in_seconds);
return true;
}
void RealDevicePolicyProvider::RefreshDevicePolicy() {
if (!policy_provider_->Reload()) {
LOG(INFO) << "No device policies/settings present.";
}
var_device_policy_is_loaded_.SetValue(
policy_provider_->device_policy_is_loaded());
UpdateVariable(&var_release_channel_, &DevicePolicy::GetReleaseChannel);
UpdateVariable(&var_release_channel_delegated_,
&DevicePolicy::GetReleaseChannelDelegated);
UpdateVariable(&var_update_disabled_, &DevicePolicy::GetUpdateDisabled);
UpdateVariable(&var_target_version_prefix_,
&DevicePolicy::GetTargetVersionPrefix);
UpdateVariable(&var_scatter_factor_,
&RealDevicePolicyProvider::ConvertScatterFactor);
UpdateVariable(
&var_allowed_connection_types_for_update_,
&RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate);
UpdateVariable(&var_owner_, &DevicePolicy::GetOwner);
UpdateVariable(&var_http_downloads_enabled_,
&DevicePolicy::GetHttpDownloadsEnabled);
UpdateVariable(&var_au_p2p_enabled_, &DevicePolicy::GetAuP2PEnabled);
}
} // namespace chromeos_update_manager