blob: 00758ac70eb2cd3fb8188787bf67458817c49d5a [file] [log] [blame]
// Copyright 2021 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 "rmad/utils/cros_config_utils_impl.h"
#include <fstream>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <base/json/json_reader.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <chromeos-config/libcros_config/cros_config.h>
#include "rmad/utils/json_store.h"
namespace rmad {
namespace {
// TODO(genechang): We should build the configuration ourselves to
// prevent possible changes to the configuration file in the future.
const std::string kChromeosConfigPath(
"/usr/share/chromeos-config/yaml/config.yaml");
constexpr char kChromeos[] = "chromeos";
constexpr char kChromeosConfigs[] = "configs";
constexpr char kCrosRootKey[] = "/";
constexpr char kCrosModelNameKey[] = "name";
constexpr char kCrosIdentityKey[] = "identity";
constexpr char kCrosIdentitySkuKey[] = "sku-id";
constexpr char kCrosIdentityWhitelabelKey[] = "whitelabel-tag";
} // namespace
CrosConfigUtilsImpl::CrosConfigUtilsImpl()
: config_file_path_(kChromeosConfigPath) {
cros_config_ = std::make_unique<brillo::CrosConfig>();
}
CrosConfigUtilsImpl::CrosConfigUtilsImpl(
const std::string& config_file_path,
std::unique_ptr<brillo::CrosConfigInterface> cros_config)
: config_file_path_(config_file_path),
cros_config_(std::move(cros_config)) {}
bool CrosConfigUtilsImpl::GetModelName(std::string* model_name) const {
DCHECK(model_name);
return cros_config_->GetString(kCrosRootKey, kCrosModelNameKey, model_name);
}
bool CrosConfigUtilsImpl::GetCurrentSkuId(int* sku_id) const {
DCHECK(sku_id);
std::string sku_id_str;
if (!cros_config_->GetString(
std::string(kCrosRootKey) + std::string(kCrosIdentityKey),
kCrosIdentitySkuKey, &sku_id_str)) {
return false;
}
return base::StringToInt(sku_id_str, sku_id);
}
bool CrosConfigUtilsImpl::GetCurrentWhitelabelTag(
std::string* whitelabel_tag) const {
DCHECK(whitelabel_tag);
return cros_config_->GetString(
std::string(kCrosRootKey) + std::string(kCrosIdentityKey),
kCrosIdentityWhitelabelKey, whitelabel_tag);
}
bool CrosConfigUtilsImpl::GetSkuIdList(std::vector<int>* sku_id_list) const {
DCHECK(sku_id_list);
std::vector<base::Value> values;
if (!GetMatchedItemsFromIdentity(kCrosIdentitySkuKey, &values)) {
return false;
}
sku_id_list->clear();
for (auto& value : values) {
int sku;
if (value.GetAsInteger(&sku)) {
sku_id_list->push_back(sku);
}
}
return true;
}
bool CrosConfigUtilsImpl::GetWhitelabelTagList(
std::vector<std::string>* whitelabel_tag_list) const {
DCHECK(whitelabel_tag_list);
std::vector<base::Value> values;
if (!GetMatchedItemsFromIdentity(kCrosIdentityWhitelabelKey, &values)) {
return false;
}
whitelabel_tag_list->clear();
for (auto& value : values) {
std::string tag;
if (value.GetAsString(&tag)) {
whitelabel_tag_list->push_back(tag);
}
}
return true;
}
bool CrosConfigUtilsImpl::GetMatchedItemsFromIdentity(
const std::string& key, std::vector<base::Value>* list) const {
DCHECK(list);
list->clear();
std::set<base::Value> items;
std::string model_name;
if (!GetModelName(&model_name)) {
LOG(ERROR) << "Failed to get model name for comparison";
return false;
}
scoped_refptr<JsonStore> json_store =
base::MakeRefCounted<JsonStore>(base::FilePath(config_file_path_));
if (auto error = json_store->GetReadError();
error != JsonStore::READ_ERROR_NONE) {
LOG_STREAM(ERROR) << "Failed to parse file due to error code #" << error;
return false;
}
base::Value cros;
if (!json_store->GetValue(kChromeos, &cros)) {
LOG(ERROR) << "Failed to get the chromeos section from the file";
return false;
}
DCHECK(cros.is_dict());
base::Value* cros_configs = cros.FindListKey(kChromeosConfigs);
if (!cros_configs) {
LOG(ERROR) << "Failed to get the configs section from the file";
return false;
}
DCHECK(cros_configs->is_list());
auto list_configs = cros_configs->GetList();
for (auto& config : list_configs) {
DCHECK(config.is_dict());
const std::string* name = config.FindStringKey(kCrosModelNameKey);
if (!name || *name != model_name) {
continue;
}
const base::Value* identity = config.FindKey(kCrosIdentityKey);
DCHECK(identity->is_dict());
const base::Value* item = identity->FindKey(key);
if (item) {
items.insert(item->Clone());
}
}
for (auto& item : items) {
list->push_back(item.Clone());
}
return true;
}
} // namespace rmad