blob: 835f4330f8b428d524335750869f24d2bc9a70e2 [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 "rmad/segmentation/segmentation_utils_impl.h"
#include <memory>
#include <string>
#include <utility>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <google/protobuf/text_format.h>
#include <libsegmentation/feature_management.h>
#include "rmad/constants.h"
#include "rmad/feature_enabled_devices.pb.h"
#include "rmad/system/tpm_manager_client_impl.h"
#include "rmad/utils/cros_config_utils_impl.h"
#include "rmad/utils/dbus_utils.h"
#include "rmad/utils/gsc_utils_impl.h"
namespace {
constexpr char kDevicesTextProtoFilePath[] = "devices.textproto";
constexpr char kEmptyBoardIdType[] = "ffffffff";
} // namespace
namespace rmad {
SegmentationUtilsImpl::SegmentationUtilsImpl()
: config_dir_path_(kDefaultConfigDirPath),
feature_enabled_devices_(),
feature_management_() {
tpm_manager_client_ = std::make_unique<TpmManagerClientImpl>(GetSystemBus());
cros_config_utils_ = std::make_unique<CrosConfigUtilsImpl>();
gsc_utils_ = std::make_unique<GscUtilsImpl>();
ReadFeatureEnabledDevices();
}
SegmentationUtilsImpl::SegmentationUtilsImpl(
const base::FilePath& config_dir_path,
std::unique_ptr<segmentation::FeatureManagementInterface>
feature_management_interface,
std::unique_ptr<TpmManagerClient> tpm_manager_client,
std::unique_ptr<CrosConfigUtils> cros_config_utils,
std::unique_ptr<GscUtils> gsc_utils)
: config_dir_path_(config_dir_path),
feature_enabled_devices_(),
feature_management_(std::move(feature_management_interface)),
tpm_manager_client_(std::move(tpm_manager_client)),
cros_config_utils_(std::move(cros_config_utils)),
gsc_utils_(std::move(gsc_utils)) {
ReadFeatureEnabledDevices();
}
void SegmentationUtilsImpl::ReadFeatureEnabledDevices() {
if (std::string textproto_str;
ReadFeatureEnabledDevicesTextProto(&textproto_str)) {
if (google::protobuf::TextFormat::ParseFromString(
textproto_str, &feature_enabled_devices_)) {
DLOG(INFO) << "Successfully get feature enabled device list";
} else {
DLOG(ERROR) << "Failed to parse feature enabled device list";
}
}
}
bool SegmentationUtilsImpl::ReadFeatureEnabledDevicesTextProto(
std::string* result) const {
std::string model_name;
if (!cros_config_utils_->GetModelName(&model_name)) {
LOG(ERROR) << "Failed to get model name";
return false;
}
const base::FilePath textproto_file_path =
config_dir_path_.Append(model_name).Append(kDevicesTextProtoFilePath);
if (!base::PathExists(textproto_file_path)) {
// This is expected for projects that don't support features.
DLOG(INFO) << textproto_file_path.value() << " doesn't exist";
return false;
}
if (!base::ReadFileToString(textproto_file_path, result)) {
LOG(ERROR) << "Failed to read " << textproto_file_path.value();
return false;
}
return true;
}
bool SegmentationUtilsImpl::IsFeatureEnabled() const {
// Feature is enabled if any of the RLZ supports the feature.
return !feature_enabled_devices_.devices().empty();
}
bool SegmentationUtilsImpl::IsFeatureMutable() const {
// If anything goes wrong, assume feature is immutable to prevent someone
// attempting to set the feature flags.
GscVersion gsc_version;
if (!tpm_manager_client_->GetGscVersion(&gsc_version)) {
LOG(ERROR) << "Failed to get GSC version";
return false;
}
// Condition is different for Cr50 and Ti50.
switch (gsc_version) {
case GscVersion::GSC_VERSION_NOT_GSC:
return false;
case GscVersion::GSC_VERSION_CR50:
return IsBoardIdTypeEmpty();
case GscVersion::GSC_VERSION_TI50:
return IsInitialFactoryMode();
}
return false;
}
int SegmentationUtilsImpl::GetFeatureLevel() const {
return feature_management_.GetFeatureLevel();
}
bool SegmentationUtilsImpl::GetFeatureFlags(bool* is_chassis_branded,
int* hw_compliance_version) const {
return gsc_utils_->GetFactoryConfig(is_chassis_branded,
hw_compliance_version);
}
bool SegmentationUtilsImpl::SetFeatureFlags(bool is_chassis_branded,
int hw_compliance_version) {
return gsc_utils_->SetFactoryConfig(is_chassis_branded,
hw_compliance_version);
}
bool SegmentationUtilsImpl::IsBoardIdTypeEmpty() const {
std::string board_id_type;
if (!gsc_utils_->GetBoardIdType(&board_id_type)) {
LOG(ERROR) << "Failed to get board ID type";
return false;
}
return board_id_type == kEmptyBoardIdType;
}
bool SegmentationUtilsImpl::IsInitialFactoryMode() const {
return gsc_utils_->IsInitialFactoryModeEnabled();
}
} // namespace rmad