blob: 2596aed82b8b7013eaef84a6dcb93286051e5858 [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "storage_files.h"
#include <android-base/logging.h>
#include <unistd.h>
#include <aconfig_storage/aconfig_storage_file.hpp>
#include "aconfigd.h"
#include "aconfigd_util.h"
#include "com_android_aconfig_new_storage.h"
using namespace aconfig_storage;
namespace android {
namespace aconfigd {
/// constructor for a new storage file set
StorageFiles::StorageFiles(const std::string& container,
const std::string& package_map,
const std::string& flag_map,
const std::string& flag_val,
const std::string& flag_info,
const std::string& root_dir,
base::Result<void>& status)
: container_(container)
, storage_record_()
, package_map_(nullptr)
, flag_map_(nullptr)
, flag_val_(nullptr)
, boot_flag_val_(nullptr)
, boot_flag_info_(nullptr)
, persist_flag_val_(nullptr)
, persist_flag_info_(nullptr) {
auto version = get_storage_file_version(flag_val);
if (!version.ok()) {
status = base::Error() << "failed to get file version: " << version.error();
return;
}
auto digest = GetFilesDigest({package_map, flag_map, flag_val, flag_info});
if (!digest.ok()) {
status = base::Error() << "failed to get files digest: " << digest.error();
return;
}
storage_record_.version = *version;
storage_record_.container = container;
storage_record_.package_map = package_map;
storage_record_.flag_map = flag_map;
storage_record_.flag_val = flag_val;
storage_record_.flag_info = flag_info;
storage_record_.persist_package_map =
root_dir + "/maps/" + container + ".package.map";
storage_record_.persist_flag_map =
root_dir + "/maps/" + container + ".flag.map";
storage_record_.persist_flag_val =
root_dir + "/flags/" + container + ".val";
storage_record_.persist_flag_info =
root_dir + "/flags/" + container + ".info";
storage_record_.local_overrides =
root_dir + "/flags/" + container + "_local_overrides.pb";
storage_record_.boot_flag_val =
root_dir + "/boot/" + container + ".val";
storage_record_.boot_flag_info =
root_dir + "/boot/" + container + ".info";
storage_record_.digest= *digest;
// copy package map file
auto copy_result = CopyFile(package_map, storage_record_.persist_package_map, 0444);
if (!copy_result.ok()) {
status = base::Error() << "CopyFile failed for " << package_map << ": "
<< copy_result.error();
return;
}
// copy flag map file
copy_result = CopyFile(flag_map, storage_record_.persist_flag_map, 0444);
if (!copy_result.ok()) {
status = base::Error() << "CopyFile failed for " << flag_map << ": "
<< copy_result.error();
return;
}
// copy flag value file
copy_result = CopyFile(flag_val, storage_record_.persist_flag_val, 0644);
if (!copy_result.ok()) {
status = base::Error() << "CopyFile failed for " << flag_val << ": "
<< copy_result.error();
return;
}
// copy flag info file
copy_result = CopyFile(flag_info, storage_record_.persist_flag_info, 0644);
if (!copy_result.ok()) {
status = base::Error() << "CopyFile failed for " << flag_info << ": "
<< copy_result.error();
return;
}
}
/// constructor for existing new storage file set
StorageFiles::StorageFiles(const PersistStorageRecord& pb,
const std::string& root_dir)
: container_(pb.container())
, storage_record_()
, package_map_(nullptr)
, flag_map_(nullptr)
, flag_val_(nullptr)
, boot_flag_val_(nullptr)
, boot_flag_info_(nullptr)
, persist_flag_val_(nullptr)
, persist_flag_info_(nullptr) {
storage_record_.version = pb.version();
storage_record_.container = pb.container();
storage_record_.package_map = pb.package_map();
storage_record_.flag_map = pb.flag_map();
storage_record_.flag_val = pb.flag_val();
if (pb.has_flag_info()) {
storage_record_.flag_info = pb.flag_info();
} else {
auto val_file = storage_record_.flag_val;
storage_record_.flag_info = val_file.substr(0, val_file.size()-3) + "info";
}
storage_record_.persist_package_map =
root_dir + "/maps/" + pb.container() + ".package.map";
storage_record_.persist_flag_map =
root_dir + "/maps/" + pb.container() + ".flag.map";
storage_record_.persist_flag_val =
root_dir + "/flags/" + pb.container() + ".val";
storage_record_.persist_flag_info =
root_dir + "/flags/" + pb.container() + ".info";
storage_record_.local_overrides =
root_dir + "/flags/" + pb.container() + "_local_overrides.pb";
storage_record_.boot_flag_val =
root_dir + "/boot/" + pb.container() + ".val";
storage_record_.boot_flag_info =
root_dir + "/boot/" + pb.container() + ".info";
storage_record_.digest = pb.digest();
}
/// move constructor
StorageFiles::StorageFiles(StorageFiles&& rhs) {
if (this != &rhs) {
*this = std::move(rhs);
}
}
/// move assignment
StorageFiles& StorageFiles::operator=(StorageFiles&& rhs) {
if (this != &rhs) {
container_ = rhs.container_;
storage_record_ = std::move(rhs.storage_record_);
package_map_ = std::move(rhs.package_map_);
flag_map_ = std::move(rhs.flag_map_);
flag_val_ = std::move(rhs.flag_val_);
boot_flag_val_ = std::move(rhs.boot_flag_val_);
boot_flag_info_ = std::move(rhs.boot_flag_info_);
persist_flag_val_ = std::move(rhs.persist_flag_val_);
persist_flag_info_ = std::move(rhs.persist_flag_info_);
}
return *this;
}
/// get package map
base::Result<const MappedStorageFile*> StorageFiles::GetPackageMap() {
if (!package_map_) {
if (storage_record_.persist_package_map.empty()) {
return base::Error() << "Missing persist package map file";
}
auto package_map = map_storage_file(storage_record_.persist_package_map);
RETURN_IF_ERROR(package_map, "Failed to map persist package map file for " + container_);
package_map_.reset(*package_map);
}
return package_map_.get();
}
/// get flag map
base::Result<const MappedStorageFile*> StorageFiles::GetFlagMap() {
if (!flag_map_) {
if (storage_record_.persist_flag_map.empty()) {
return base::Error() << "Missing persist flag map file";
}
auto flag_map = map_storage_file(storage_record_.persist_flag_map);
RETURN_IF_ERROR(flag_map, "Failed to map persist flag map file for " + container_);
flag_map_.reset(*flag_map);
}
return flag_map_.get();
}
/// get default flag val
base::Result<const MappedStorageFile*> StorageFiles::GetFlagVal() {
if (!flag_val_) {
if (storage_record_.flag_val.empty()) {
return base::Error() << "Missing flag val file";
}
auto flag_val = map_storage_file(storage_record_.flag_val);
RETURN_IF_ERROR(flag_val, "Failed to map flag val file for " + container_);
flag_val_.reset(*flag_val);
}
return flag_val_.get();
}
/// get boot flag val
base::Result<const MappedStorageFile*> StorageFiles::GetBootFlagVal() {
if (!boot_flag_val_) {
if (storage_record_.boot_flag_val.empty()) {
return base::Error() << "Missing boot flag val file";
}
auto flag_val = map_storage_file(storage_record_.boot_flag_val);
RETURN_IF_ERROR(flag_val, "Failed to map boot flag val file for " + container_);
boot_flag_val_.reset(*flag_val);
}
return boot_flag_val_.get();
}
/// get boot flag info
base::Result<const MappedStorageFile*> StorageFiles::GetBootFlagInfo() {
if (!boot_flag_info_) {
if (storage_record_.boot_flag_info.empty()) {
return base::Error() << "Missing boot flag info file";
}
auto flag_info = map_storage_file(storage_record_.boot_flag_info);
RETURN_IF_ERROR(flag_info, "Failed to map boot flag info file for " + container_);
boot_flag_info_.reset(*flag_info);
}
return boot_flag_info_.get();
}
/// get persist flag val
base::Result<const MutableMappedStorageFile*> StorageFiles::GetPersistFlagVal() {
if (!persist_flag_val_) {
if (storage_record_.persist_flag_val.empty()) {
return base::Error() << "Missing persist flag value file";
}
auto flag_val = map_mutable_storage_file(storage_record_.persist_flag_val);
RETURN_IF_ERROR(flag_val, "Failed to map persist flag val file for " + container_);
persist_flag_val_.reset(*flag_val);
}
return persist_flag_val_.get();
}
/// get persist flag info
base::Result<const MutableMappedStorageFile*> StorageFiles::GetPersistFlagInfo() {
if (!persist_flag_info_) {
if (storage_record_.persist_flag_info.empty()) {
return base::Error() << "Missing persist flag info file";
}
auto flag_info = map_mutable_storage_file(storage_record_.persist_flag_info);
RETURN_IF_ERROR(flag_info, "Failed to map persist flag info file for " + container_);
persist_flag_info_.reset(*flag_info);
}
return persist_flag_info_.get();
}
/// check if flag is read only
base::Result<bool> StorageFiles::IsFlagReadOnly(const PackageFlagContext& context) {
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto flag_info_file = GetPersistFlagInfo();
if (!flag_info_file.ok()) {
return base::Error() << flag_info_file.error();
}
auto attribute = get_flag_attribute(
**flag_info_file, context.value_type, context.flag_index);
if (!attribute.ok()) {
return base::Error() << "Failed to get flag attribute";
}
return !(*attribute & FlagInfoBit::IsReadWrite);
}
/// apply local update to boot flag value copy
base::Result<void> StorageFiles::ApplyLocalOverrideToBootFlagValue() {
auto flag_value_result = map_mutable_storage_file(storage_record_.boot_flag_val);
if (!flag_value_result.ok()) {
return base::Error() << "Failed to map boot flag value file for local override: "
<< flag_value_result.error();
}
auto flag_value = std::unique_ptr<MutableMappedStorageFile>(*flag_value_result);
auto pb_file = storage_record_.local_overrides;
auto pb = ReadPbFromFile<LocalFlagOverrides>(pb_file);
if (!pb.ok()) {
return base::Error() << "Failed to read pb from " << pb_file << ": " << pb.error();
}
auto applied_overrides = LocalFlagOverrides();
for (auto& entry : pb->overrides()) {
// find flag value type and index
auto context = GetPackageFlagContext(entry.package_name(), entry.flag_name());
if (!context.ok()) {
return base::Error() << "Failed to find flag: " << context.error();
}
if (!context->flag_exists) {
continue;
}
// apply a local override
switch (context->value_type) {
case FlagValueType::Boolean: {
// validate value
if (entry.flag_value() != "true" && entry.flag_value() != "false") {
return base::Error() << "Invalid boolean flag value, it should be true|false";
}
// update flag value
auto update_result = set_boolean_flag_value(
*flag_value, context->flag_index, entry.flag_value() == "true");
if (!update_result.ok()) {
return base::Error() << "Failed to update flag value: " << update_result.error();
}
break;
}
default:
return base::Error() << "Unsupported flag value type";
}
// mark it applied
auto new_applied = applied_overrides.add_overrides();
new_applied->set_package_name(entry.package_name());
new_applied->set_flag_name(entry.flag_name());
new_applied->set_flag_value(entry.flag_value());
}
if (pb->overrides_size() != applied_overrides.overrides_size()) {
auto result = WritePbToFile<LocalFlagOverrides>(applied_overrides, pb_file);
if (!result.ok()) {
return base::Error() << result.error();
}
}
return {};
}
/// has boot copy
bool StorageFiles::HasBootCopy() {
return FileExists(storage_record_.boot_flag_val)
&& FileExists(storage_record_.boot_flag_info);
}
/// Find flag value type and global index
base::Result<StorageFiles::PackageFlagContext> StorageFiles::GetPackageFlagContext(
const std::string& package,
const std::string& flag) {
auto result = PackageFlagContext(package, flag);
// early return
if (package.empty()) {
result.package_exists = false;
result.flag_exists = false;
return result;
}
// find package context
auto package_map = GetPackageMap();
if (!package_map.ok()) {
return base::Error() << package_map.error();
}
auto package_context = get_package_read_context(**package_map, package);
if (!package_context.ok()) {
return base::Error() << "Failed to get package context for " << package
<< " in " << container_ << " :" << package_context.error();
}
if (!package_context->package_exists) {
result.flag_exists = false;
return result;
} else {
result.package_exists = true;
}
// early return
if (flag.empty()) {
return result;
}
uint32_t package_id = package_context->package_id;
uint32_t boolean_flag_start_index = package_context->boolean_start_index;
// find flag context
auto flag_map = GetFlagMap();
if (!flag_map.ok()) {
return base::Error() << flag_map.error();
}
auto flag_context = get_flag_read_context(**flag_map, package_id, flag);
if (!flag_context.ok()) {
return base::Error() << "Failed to get flag context of " << package << "/"
<< flag << " in " << container_ << " :"
<< flag_context.error();
}
if (!flag_context->flag_exists) {
result.flag_exists = false;
return result;
}
StoredFlagType stored_type = flag_context->flag_type;
uint16_t within_package_flag_index = flag_context->flag_index;
auto value_type = map_to_flag_value_type(stored_type);
if (!value_type.ok()) {
return base::Error() << "Failed to get flag value type :" << value_type.error();
}
result.flag_exists = true;
result.value_type = *value_type;
result.flag_index = boolean_flag_start_index + within_package_flag_index;
return result;
}
/// check if has package
base::Result<bool> StorageFiles::HasPackage(const std::string& package) {
auto type_and_index = GetPackageFlagContext(package, "");
if (!type_and_index.ok()) {
return base::Error() << type_and_index.error();
}
return type_and_index->package_exists;
}
/// check if has flag
base::Result<bool> StorageFiles::HasFlag(const std::string& package,
const std::string& flag) {
auto type_and_index = GetPackageFlagContext(package, flag);
if (!type_and_index.ok()) {
return base::Error() << type_and_index.error();
}
return type_and_index->flag_exists;
}
/// get persistent flag attribute
base::Result<uint8_t> StorageFiles::GetFlagAttribute(
const PackageFlagContext& context) {
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto flag_info_file = GetPersistFlagInfo();
if (!flag_info_file.ok()) {
return base::Error() << flag_info_file.error();
}
auto attribute = get_flag_attribute(**flag_info_file, context.value_type, context.flag_index);
if (!attribute.ok()) {
return base::Error() << "Failed to get flag info: " << attribute.error();
}
return *attribute;
}
/// get server flag value
base::Result<std::string> StorageFiles::GetServerFlagValue(
const PackageFlagContext& context) {
auto attribute = GetFlagAttribute(context);
RETURN_IF_ERROR(attribute, "Failed to get flag attribute");
if (!(*attribute & FlagInfoBit::HasServerOverride)) {
return std::string();
}
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto flag_value_file = GetPersistFlagVal();
if (!flag_value_file.ok()) {
return base::Error() << flag_value_file.error();
}
switch (context.value_type) {
case FlagValueType::Boolean: {
auto value = get_boolean_flag_value(**flag_value_file, context.flag_index);
if (!value.ok()) {
return base::Error() << "Failed to get flag value: " << value.error();
}
return *value ? "true" : "false";
break;
}
default:
return base::Error() << "Unsupported flag value type";
}
return base::Error() << "Failed to find flag in value file";
}
/// get local flag value
base::Result<std::string> StorageFiles::GetLocalFlagValue(
const PackageFlagContext& context) {
auto attribute = GetFlagAttribute(context);
RETURN_IF_ERROR(attribute, "Failed to get flag attribute");
if (!(*attribute & FlagInfoBit::HasLocalOverride)) {
return std::string();
}
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto pb_file = storage_record_.local_overrides;
auto pb = ReadPbFromFile<LocalFlagOverrides>(pb_file);
if (!pb.ok()) {
return base::Error() << "Failed to read pb from " << pb_file << ": " << pb.error();
}
for (auto& entry : pb->overrides()) {
if (context.package == entry.package_name()
&& context.flag == entry.flag_name()) {
return entry.flag_value();
}
}
return base::Error() << "Failed to find flag local override value";
}
/// get boot flag value
base::Result<std::string> StorageFiles::GetBootFlagValue(
const PackageFlagContext& context) {
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto flag_value_file = GetBootFlagVal();
if (!flag_value_file.ok()) {
return base::Error() << flag_value_file.error();
}
switch (context.value_type) {
case FlagValueType::Boolean: {
auto value = get_boolean_flag_value(**flag_value_file, context.flag_index);
if (!value.ok()) {
return base::Error() << "Failed to get boot flag value: " << value.error();
}
return *value ? "true" : "false";
break;
}
default:
return base::Error() << "Unsupported flag value type";
}
return base::Error() << "Failed to find flag in value file";
}
/// get default flag value
base::Result<std::string> StorageFiles::GetDefaultFlagValue(
const PackageFlagContext& context) {
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto flag_value_file = GetFlagVal();
if (!flag_value_file.ok()) {
return base::Error() << flag_value_file.error();
}
switch (context.value_type) {
case FlagValueType::Boolean: {
auto value = get_boolean_flag_value(**flag_value_file, context.flag_index);
if (!value.ok()) {
return base::Error() << "Failed to get default flag value: " << value.error();
}
return *value ? "true" : "false";
break;
}
default:
return base::Error() << "Unsupported flag value type";
}
return base::Error() << "Failed to find flag in value file";
}
/// server flag override, update persistent flag value
base::Result<void> StorageFiles::SetServerFlagValue(const PackageFlagContext& context,
const std::string& flag_value) {
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto readonly = IsFlagReadOnly(context);
RETURN_IF_ERROR(readonly, "Failed to check if flag is readonly");
if (*readonly) {
return base::Error() << "Cannot update read only flag";
}
auto flag_value_file = GetPersistFlagVal();
RETURN_IF_ERROR(flag_value_file, "Cannot get persist flag value file");
switch (context.value_type) {
case FlagValueType::Boolean: {
if (flag_value != "true" && flag_value != "false") {
return base::Error() << "Invalid boolean flag value, it should be true|false";
}
auto update = set_boolean_flag_value(
**flag_value_file, context.flag_index, flag_value == "true");
RETURN_IF_ERROR(update, "Failed to update flag value");
update = SetHasServerOverride(context, true);
RETURN_IF_ERROR(update, "Failed to set flag has server override");
break;
}
default:
return base::Error() << "Unsupported flag value type";
}
return {};
}
/// Write override immediately to boot copy.
base::Result<void> StorageFiles::WriteLocalOverrideToBootCopy(
const PackageFlagContext& context, const std::string& flag_value) {
if (chmod(storage_record_.boot_flag_val.c_str(), 0644) == -1) {
return base::ErrnoError() << "chmod() failed to set to 0644";
}
auto flag_value_file =
map_mutable_storage_file(storage_record_.boot_flag_val);
auto update_result = set_boolean_flag_value(
**flag_value_file, context.flag_index, flag_value == "true");
RETURN_IF_ERROR(update_result, "Failed to update flag value");
if (chmod(storage_record_.boot_flag_val.c_str(), 0444) == -1) {
return base::ErrnoError() << "chmod() failed to set to 0444";
}
return {};
}
/// local flag override, update local flag override pb filee
base::Result<void> StorageFiles::SetLocalFlagValue(
const PackageFlagContext& context, const std::string& flag_value) {
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto readonly = IsFlagReadOnly(context);
RETURN_IF_ERROR(readonly, "Failed to check if flag is readonly")
if (*readonly) {
return base::Error() << "Cannot update read only flag";
}
auto pb_file = storage_record_.local_overrides;
auto pb = ReadPbFromFile<LocalFlagOverrides>(pb_file);
if (!pb.ok()) {
return base::Error() << "Failed to read pb from " << pb_file << ": " << pb.error();
}
bool exist = false;
for (auto& entry : *(pb->mutable_overrides())) {
if (entry.package_name() == context.package
&& entry.flag_name() == context.flag) {
if (entry.flag_value() == flag_value) {
return {};
}
exist = true;
entry.set_flag_value(flag_value);
break;
}
}
if (!exist) {
auto new_override = pb->add_overrides();
new_override->set_package_name(context.package);
new_override->set_flag_name(context.flag);
new_override->set_flag_value(flag_value);
}
auto write = WritePbToFile<LocalFlagOverrides>(*pb, pb_file);
if (!write.ok()) {
return base::Error() << "Failed to write pb to " << pb_file << ": " << write.error();
}
auto update = SetHasLocalOverride(context, true);
RETURN_IF_ERROR(update, "Failed to set flag has local override");
return {};
}
/// set has server override in flag info
base::Result<void> StorageFiles::SetHasServerOverride(const PackageFlagContext& context,
bool has_server_override) {
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto flag_info_file = GetPersistFlagInfo();
if (!flag_info_file.ok()) {
return base::Error() << flag_info_file.error();
}
auto update_result = set_flag_has_server_override(
**flag_info_file, context.value_type, context.flag_index, has_server_override);
if (!update_result.ok()) {
return base::Error() << "Failed to update flag has server override: "
<< update_result.error();
}
return {};
}
/// set has local override in flag info
base::Result<void> StorageFiles::SetHasLocalOverride(const PackageFlagContext& context,
bool has_local_override) {
if (!context.flag_exists) {
return base::Error() << "Flag does not exist";
}
auto flag_info_file = GetPersistFlagInfo();
if (!flag_info_file.ok()) {
return base::Error() << flag_info_file.error();
}
auto update_result = set_flag_has_local_override(
**flag_info_file, context.value_type, context.flag_index, has_local_override);
if (!update_result.ok()) {
return base::Error() << "Failed to update flag has local override: "
<< update_result.error();
}
return {};
}
/// remove a single flag local override, return if removed
base::Result<bool> StorageFiles::RemoveLocalFlagValue(
const PackageFlagContext& context) {
auto pb_file = storage_record_.local_overrides;
auto pb = ReadPbFromFile<LocalFlagOverrides>(pb_file);
if (!pb.ok()) {
return base::Error() << "Failed to read pb from " << pb_file << ": " << pb.error();
}
auto remaining_overrides = LocalFlagOverrides();
for (auto entry : pb->overrides()) {
if (entry.package_name() == context.package
&& entry.flag_name() == context.flag) {
continue;
}
auto kept_override = remaining_overrides.add_overrides();
kept_override->set_package_name(entry.package_name());
kept_override->set_flag_name(entry.flag_name());
kept_override->set_flag_value(entry.flag_value());
}
if (remaining_overrides.overrides_size() != pb->overrides_size()) {
auto result = WritePbToFile<LocalFlagOverrides>(remaining_overrides, pb_file);
if (!result.ok()) {
return base::Error() << result.error();
}
auto update = SetHasLocalOverride(context, false);
RETURN_IF_ERROR(update, "Failed to unset flag has local override");
return true;
} else {
return false;
}
}
/// remove all local overrides
base::Result<void> StorageFiles::RemoveAllLocalFlagValue() {
auto pb_file = storage_record_.local_overrides;
auto overrides_pb = ReadPbFromFile<LocalFlagOverrides>(pb_file);
RETURN_IF_ERROR(overrides_pb, "Failed to read local overrides");
for (auto& entry : overrides_pb->overrides()) {
auto context = GetPackageFlagContext(entry.package_name(), entry.flag_name());
RETURN_IF_ERROR(context, "Failed to find package flag context for flag "
+ entry.package_name() + "/" + entry.flag_name());
auto update = SetHasLocalOverride(*context, false);
RETURN_IF_ERROR(update, "Failed to unset flag has local override");
}
if (overrides_pb->overrides_size()) {
auto result = WritePbToFile<LocalFlagOverrides>(
LocalFlagOverrides(), pb_file);
RETURN_IF_ERROR(result, "Failed to flush local overrides pb file");
}
return {};
}
/// get all current server override
base::Result<std::vector<StorageFiles::ServerOverride>>
StorageFiles::GetServerFlagValues() {
auto listed_flags = list_flags_with_info(storage_record_.persist_package_map,
storage_record_.persist_flag_map,
storage_record_.persist_flag_val,
storage_record_.persist_flag_info);
RETURN_IF_ERROR(
listed_flags, "Failed to list all flags for " + storage_record_.container);
auto server_updated_flags = std::vector<ServerOverride>();
for (const auto& flag : *listed_flags) {
if (flag.has_server_override) {
auto server_override = ServerOverride();
server_override.package_name = std::move(flag.package_name);
server_override.flag_name = std::move(flag.flag_name);
server_override.flag_value = std::move(flag.flag_value);
server_updated_flags.push_back(server_override);
}
}
return server_updated_flags;
}
/// remove all storage files
base::Result<void> StorageFiles::RemoveAllPersistFiles() {
package_map_.reset(nullptr);
flag_map_.reset(nullptr);
flag_val_.reset(nullptr);
boot_flag_val_.reset(nullptr);
boot_flag_info_.reset(nullptr);
persist_flag_val_.reset(nullptr);
persist_flag_info_.reset(nullptr);
if (unlink(storage_record_.persist_package_map.c_str()) == -1) {
return base::ErrnoError() << "unlink() failed for "
<< storage_record_.persist_package_map;
}
if (unlink(storage_record_.persist_flag_map.c_str()) == -1) {
return base::ErrnoError() << "unlink() failed for "
<< storage_record_.persist_flag_map;
}
if (unlink(storage_record_.persist_flag_val.c_str()) == -1) {
return base::ErrnoError() << "unlink() failed for "
<< storage_record_.persist_flag_val;
}
if (unlink(storage_record_.persist_flag_info.c_str()) == -1) {
return base::ErrnoError() << "unlink() failed for "
<< storage_record_.persist_flag_info;
}
if (unlink(storage_record_.local_overrides.c_str()) == -1) {
return base::ErrnoError() << "unlink() failed for " << storage_record_.local_overrides;
}
return {};
}
/// create boot flag value and info files
base::Result<void> StorageFiles::CreateBootStorageFiles() {
// If the boot copy already exists, do nothing. Never update the boot copy, the boot
// copy should be boot stable. So in the following scenario: a container storage
// file boot copy is created, then an updated container is mounted along side existing
// container. In this case, we should update the persistent storage file copy. But
// never touch the current boot copy.
if (FileExists(storage_record_.boot_flag_val)
&& FileExists(storage_record_.boot_flag_info)) {
return {};
}
auto copy = CopyFile(
storage_record_.persist_flag_val, storage_record_.boot_flag_val, 0444);
RETURN_IF_ERROR(copy, "CopyFile failed for " + storage_record_.persist_flag_val);
copy = CopyFile(
storage_record_.persist_flag_info, storage_record_.boot_flag_info, 0444);
RETURN_IF_ERROR(copy, "CopyFile failed for " + storage_record_.persist_flag_info);
// change boot flag value file to 0644 to allow write
if (chmod(storage_record_.boot_flag_val.c_str(), 0644) == -1) {
return base::ErrnoError() << "chmod() failed to set to 0644";
};
auto apply_result = ApplyLocalOverrideToBootFlagValue();
// change boot flag value file back to 0444
if (chmod(storage_record_.boot_flag_val.c_str(), 0444) == -1) {
if (!apply_result.ok()) {
return base::ErrnoError() << apply_result.error() << ": "
<< "chmod() failed to set to 0444";
} else {
return base::ErrnoError() << "chmod() failed to set to 0444";
}
};
return apply_result;
}
/// list a flag
base::Result<StorageFiles::FlagSnapshot> StorageFiles::ListFlag(
const std::string& package,
const std::string& flag) {
auto context = GetPackageFlagContext(package, flag);
RETURN_IF_ERROR(context, "Failed to find package flag context");
if (!context->flag_exists) {
return base::Error() << "Flag " << package << "/" << flag << " does not exist";
}
auto attribute = GetFlagAttribute(*context);
RETURN_IF_ERROR(context, "Failed to get flag attribute");
auto server_value = GetServerFlagValue(*context);
RETURN_IF_ERROR(server_value, "Failed to get server flag value");
auto local_value = GetLocalFlagValue(*context);
RETURN_IF_ERROR(local_value, "Failed to get local flag value");
auto boot_value = GetBootFlagValue(*context);
RETURN_IF_ERROR(boot_value, "Failed to get boot flag value");
auto default_value = GetDefaultFlagValue(*context);
RETURN_IF_ERROR(default_value, "Failed to get default flag value");
auto snapshot = FlagSnapshot();
snapshot.package_name = package;
snapshot.flag_name = flag;
snapshot.default_flag_value = *default_value;
snapshot.boot_flag_value = *boot_value;
snapshot.server_flag_value = *server_value;
snapshot.local_flag_value = *local_value;
snapshot.is_readwrite = *attribute & FlagInfoBit::IsReadWrite;
snapshot.has_server_override = *attribute & FlagInfoBit::HasServerOverride;
snapshot.has_local_override = *attribute & FlagInfoBit::HasLocalOverride;
return snapshot;
}
/// list flags
base::Result<std::vector<StorageFiles::FlagSnapshot>> StorageFiles::ListFlags(
const std::string& package) {
if (!package.empty()) {
auto has_package = HasPackage(package);
RETURN_IF_ERROR(
has_package, package + " does not exist in " + storage_record_.container);
}
// fill default value
auto snapshots = std::vector<FlagSnapshot>();
auto idxs = std::unordered_map<std::string, size_t>();
auto listed_flags = list_flags(storage_record_.package_map,
storage_record_.flag_map,
storage_record_.flag_val);
RETURN_IF_ERROR(
listed_flags, "Failed to list default flags for " + storage_record_.container);
for (auto const& flag : *listed_flags) {
if (package.empty() || package == flag.package_name) {
idxs[flag.package_name + "/" + flag.flag_name] = snapshots.size();
snapshots.emplace_back();
auto& snapshot = snapshots.back();
snapshot.package_name = std::move(flag.package_name);
snapshot.flag_name = std::move(flag.flag_name);
snapshot.default_flag_value = std::move(flag.flag_value);
}
}
// fill boot value
listed_flags = list_flags(storage_record_.package_map,
storage_record_.flag_map,
storage_record_.boot_flag_val);
RETURN_IF_ERROR(
listed_flags, "Failed to list boot flags for " + storage_record_.container);
for (auto const& flag : *listed_flags) {
auto full_flag_name = flag.package_name + "/" + flag.flag_name;
if (!idxs.count(full_flag_name)) {
continue;
}
auto idx = idxs[full_flag_name];
snapshots[idx].boot_flag_value = std::move(flag.flag_value);
}
// fill server value and attribute
auto listed_flags_with_info = list_flags_with_info(storage_record_.package_map,
storage_record_.flag_map,
storage_record_.persist_flag_val,
storage_record_.persist_flag_info);
RETURN_IF_ERROR(listed_flags_with_info,
"Failed to list persist flags for " + storage_record_.container);
for (auto const& flag : *listed_flags_with_info) {
auto full_flag_name = flag.package_name + "/" + flag.flag_name;
if (!idxs.count(full_flag_name)) {
continue;
}
auto idx = idxs[full_flag_name];
if (flag.has_server_override) {
snapshots[idx].server_flag_value = std::move(flag.flag_value);
}
snapshots[idx].is_readwrite = flag.is_readwrite;
snapshots[idx].has_server_override = flag.has_server_override;
snapshots[idx].has_local_override = flag.has_local_override;
}
// fill local value
auto const& pb_file = storage_record_.local_overrides;
auto pb = ReadPbFromFile<LocalFlagOverrides>(pb_file);
RETURN_IF_ERROR(pb, "Failed to read pb from " + pb_file);
for (const auto& flag : pb->overrides()) {
auto full_flag_name = flag.package_name() + "/" + flag.flag_name();
if (!idxs.count(full_flag_name)) {
continue;
}
auto idx = idxs[full_flag_name];
snapshots[idx].local_flag_value = flag.flag_value();
}
auto comp = [](const auto& v1, const auto& v2){
return (v1.package_name + "/" + v1.flag_name) <
(v2.package_name + "/" + v2.flag_name);
};
std::sort(snapshots.begin(), snapshots.end(), comp);
return snapshots;
}
} // namespace aconfigd
} // namespace android