blob: 0d1a4b36335ffb3209ed0a052f9e285844446210 [file]
/*
* 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 <string>
#include <unordered_map>
#include <dirent.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <protos/aconfig_storage_metadata.pb.h>
#include "storage_files_manager.h"
#include "storage_files.h"
#include "aconfigd_util.h"
#include "aconfigd.h"
using storage_records_pb = android::aconfig_storage_metadata::storage_files;
using storage_record_pb = android::aconfig_storage_metadata::storage_file_info;
using namespace android::base;
using namespace aconfig_storage;
namespace android {
namespace aconfigd {
/// Mapped files manager
static StorageFilesManager storage_files_manager;
namespace {
/// Write in memory aconfig storage records to the persistent pb file
Result<void> WritePersistentStorageRecordsToFile() {
auto records_pb = aconfig_storage_metadata::storage_files();
for (auto const& record : storage_files_manager.GetAllStorageRecords()) {
auto* record_pb = records_pb.add_files();
record_pb->set_version(record->version);
record_pb->set_container(record->container);
record_pb->set_package_map(record->package_map);
record_pb->set_flag_map(record->flag_map);
record_pb->set_flag_val(record->flag_val);
record_pb->set_flag_info(record->flag_info);
record_pb->set_local_overrides(record->local_overrides);
record_pb->set_timestamp(record->timestamp);
}
return WritePbToFile<storage_records_pb>(records_pb, kPersistentStorageRecordsFileName);
}
Result<void> ApplyLocalOverridesToBootCopy(const std::string& container,
const std::string& flag_value_file) {
auto storage_files = storage_files_manager.GetStorageFiles(container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
// change boot flag value file to 0644 to allow write
if (chmod(flag_value_file.c_str(), 0644) == -1) {
return base::ErrnoError() << "chmod() failed";
};
auto applied = (**storage_files).ApplyLocalOverride(flag_value_file);
RETURN_IF_ERROR(applied, "Failed to apply local override");
// change boot flag value file back to 0444
if (chmod(flag_value_file.c_str(), 0444) == -1) {
return base::ErrnoError() << "chmod() failed";
};
return {};
}
/// Create boot flag value copy for a container
Result<void> CreateBootSnapshotForContainer(const std::string& container) {
if (!storage_files_manager.HasContainer(container)) {
return Error() << "Cannot create boot copy without persist copy for " << container;
}
// create boot copy
auto src_value_file = std::string("/metadata/aconfig/flags/") + container + ".val";
auto dst_value_file = std::string("/metadata/aconfig/boot/") + container + ".val";
auto src_info_file = std::string("/metadata/aconfig/flags/") + container + ".info";
auto dst_info_file = std::string("/metadata/aconfig/boot/") + container + ".info";
// 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(dst_value_file) && FileExists(dst_info_file)) {
return {};
}
auto copy_result = CopyFile(src_value_file, dst_value_file, 0444);
RETURN_IF_ERROR(copy_result, "CopyFile failed for " + src_value_file);
auto apply_result = ApplyLocalOverridesToBootCopy(container, dst_value_file);
RETURN_IF_ERROR(apply_result, "Failed to apply local overrides to " + dst_value_file);
copy_result = CopyFile(src_info_file, dst_info_file, 0444);
RETURN_IF_ERROR(copy_result, "CopyFile failed for " + src_info_file);
// update available storage records pb
auto storage_files = storage_files_manager.GetStorageFiles(container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
const auto& record = (**storage_files).GetStorageRecord();
auto available_pb = ReadPbFromFile<storage_records_pb>(kAvailableStorageRecordsFileName);
RETURN_IF_ERROR(available_pb, "Unable to read available storage records");
auto* record_pb = available_pb->add_files();
record_pb->set_version(record.version);
record_pb->set_container(record.container);
record_pb->set_package_map(record.package_map);
record_pb->set_flag_map(record.flag_map);
record_pb->set_flag_val(dst_value_file);
record_pb->set_flag_info(dst_info_file);
record_pb->set_timestamp(record.timestamp);
auto write_result = WritePbToFile<storage_records_pb>(
*available_pb, kAvailableStorageRecordsFileName);
RETURN_IF_ERROR(write_result, "Failed to write available storage records pb");
return {};
}
/// Persist local flag overrides bit in flag info file
Result<bool> PersistLocalOverrides(const std::string& container) {
auto storage_files = storage_files_manager.GetStorageFiles(container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
// mark exsting local overrides on new flag info file
auto pb_file = (**storage_files).GetStorageRecord().local_overrides;
auto pb = ReadPbFromFile<LocalFlagOverrides>(pb_file);
RETURN_IF_ERROR(pb, "Failed to read pb from " + pb_file);
for (const auto& entry : pb->overrides()) {
auto has_flag = (**storage_files).HasFlag(entry.package_name(), entry.flag_name());
RETURN_IF_ERROR(has_flag, "Failed to check if has flag for " + entry.package_name()
+ "/" + entry.flag_name());
if (*has_flag) {
auto context = (**storage_files).GetPackageFlagContext(
entry.package_name(), entry.flag_name());
RETURN_IF_ERROR(context, "Failed to find package flag context for " +
entry.package_name() + "/" + entry.flag_name());
auto update = (**storage_files).SetHasLocalOverride(*context, true);
RETURN_IF_ERROR(update, "Failed to set flag has local override");
}
}
return {};
}
/// Add a container storage if not existed, otherwise update if needed
Result<bool> AddOrUpdateStorageForContainer(const std::string& container,
const std::string& package_file,
const std::string& flag_file,
const std::string& value_file) {
auto timestamp = GetFileTimeStamp(value_file);
RETURN_IF_ERROR(timestamp, "Failed to get timestamp of " + value_file);
// the storage record of a container needs to be updated if this is the first time
// we encountered this container or the container has been updated.
bool new_container = !storage_files_manager.HasContainer(container);
bool update_existing_container = false;
if (!new_container) {
auto storage_files = storage_files_manager.GetStorageFiles(container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
if ((**storage_files).GetStorageRecord().timestamp != *timestamp) {
update_existing_container = true;
}
}
if (!(new_container || update_existing_container)) {
return false;
}
// copy flag value file
auto flags_dir = std::string("/metadata/aconfig/flags/");
auto target_value_file = flags_dir + container + ".val";
auto copy_result = CopyFile(value_file, target_value_file, 0644);
RETURN_IF_ERROR(copy_result, "CopyFile failed for " + value_file);
// create flag info file
auto flag_info_file = std::string("/metadata/aconfig/flags/") + container + ".info";
auto create_result = create_flag_info(package_file, flag_file, flag_info_file);
RETURN_IF_ERROR(create_result, "Failed to create flag info file for " + container);
// add to in memory storage file records
auto version = get_storage_file_version(value_file);
RETURN_IF_ERROR(version, "Failed to get storage version");
auto record = StorageRecord();
record.version = *version;
record.container = container;
record.package_map = package_file;
record.flag_map = flag_file;
record.flag_val = target_value_file;
record.flag_info = flag_info_file;
record.local_overrides = flags_dir + container + "_local_overrides.pb";
record.timestamp = *timestamp;
if (new_container) {
storage_files_manager.AddStorageFiles(container, record);
} else {
auto storage_files = storage_files_manager.GetStorageFiles(container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
(**storage_files).SetStorageRecord(record);
auto update = PersistLocalOverrides(container);
RETURN_IF_ERROR(update, "Failed to persist local overrides");
}
// write to persistent storage records file
auto write_result = WritePersistentStorageRecordsToFile();
RETURN_IF_ERROR(write_result, "Failed to write to persistent storage records");
return true;
}
/// Handle new storage request
void HandleNewStorage(const StorageRequestMessage::NewStorageMessage& msg,
StorageReturnMessage& return_msg) {
auto updated = AddOrUpdateStorageForContainer(
msg.container(), msg.package_map(), msg.flag_map(), msg.flag_value());
if (!updated.ok()) {
auto* errmsg = return_msg.mutable_error_message();
*errmsg = "Failed to add or update container " + msg.container()
+ ": " + updated.error().message();
return;
}
auto copy = CreateBootSnapshotForContainer(msg.container());
if (!copy.ok()) {
auto* errmsg = return_msg.mutable_error_message();
*errmsg = "Failed to make a boot copy for " + msg.container()
+ ": " + copy.error().message();
return;
}
auto result_msg = return_msg.mutable_new_storage_message();
result_msg->set_storage_updated(*updated);
}
/// Handle a local flag override request
Result<void> HandleLocalFlagOverride(const std::string& package,
const std::string& flag,
const std::string& flag_value) {
auto container = storage_files_manager.GetContainer(package);
RETURN_IF_ERROR(container, "Failed to find owning container");
auto storage_files = storage_files_manager.GetStorageFiles(*container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
auto context = (**storage_files).GetPackageFlagContext(package, flag);
RETURN_IF_ERROR(context, "Failed to find package flag context");
auto update = (**storage_files).SetLocalFlagValue(*context, flag_value);
RETURN_IF_ERROR(update, "Failed to set local flag override");
return {};
}
/// Handle a server flag override request
Result<void> HandleServerFlagOverride(const std::string& package,
const std::string& flag,
const std::string& flag_value) {
auto container = storage_files_manager.GetContainer(package);
RETURN_IF_ERROR(container, "Failed to find owning container");
auto storage_files = storage_files_manager.GetStorageFiles(*container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
auto context = (**storage_files).GetPackageFlagContext(package, flag);
RETURN_IF_ERROR(context, "Failed to find package flag context");
auto update =(**storage_files).SetServerFlagValue(*context, flag_value);
RETURN_IF_ERROR(update, "Failed to set server flag value");
return {};
}
/// Handle a flag override request
void HandleFlagOverride(const StorageRequestMessage::FlagOverrideMessage& msg,
StorageReturnMessage& return_msg) {
auto result = Result<void>();
if (msg.is_local()) {
result = HandleLocalFlagOverride(msg.package_name(),
msg.flag_name(),
msg.flag_value());
} else {
result = HandleServerFlagOverride(msg.package_name(),
msg.flag_name(),
msg.flag_value());
}
if (!result.ok()) {
auto* errmsg = return_msg.mutable_error_message();
*errmsg = "Failed to set flag " + msg.package_name() + "/" + msg.flag_name() +
": " + result.error().message();
} else {
return_msg.mutable_flag_override_message();
}
}
/// Get flag server value, local value and attribute
Result<std::tuple<std::string, std::string, uint8_t>> GetFlagValueAndAttribute(
const std::string& package,
const std::string& flag) {
auto container = storage_files_manager.GetContainer(package);
RETURN_IF_ERROR(container, "Failed to find owning container");
auto storage_files = storage_files_manager.GetStorageFiles(*container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
auto context = (**storage_files).GetPackageFlagContext(package, flag);
RETURN_IF_ERROR(context, "Failed to find package flag context");
auto server_value = (**storage_files).GetServerFlagValue(*context);
RETURN_IF_ERROR(server_value, "Failed to get server flag value");
auto attribute = (**storage_files).GetFlagAttribute(*context);
RETURN_IF_ERROR(context, "Failed to get flag attribute");
auto local_value = std::string();
if (*attribute & FlagInfoBit::HasLocalOverride) {
auto value = (**storage_files).GetLocalFlagValue(*context);
RETURN_IF_ERROR(value, "Failed to get local flag value");
local_value = *value;
}
return std::make_tuple(*server_value, local_value, *attribute);
}
/// Handle a flag query request
void HandlePersistFlagQuery(const StorageRequestMessage::FlagQueryMessage& msg,
StorageReturnMessage& return_msg) {
auto result = GetFlagValueAndAttribute(msg.package_name(), msg.flag_name());
if (!result.ok()) {
auto* errmsg = return_msg.mutable_error_message();
*errmsg = "Flag query failed: " + result.error().message();
} else {
auto [server_value, local_value, attribute] = *result;
auto result_msg = return_msg.mutable_flag_query_message();
result_msg->set_server_flag_value(server_value);
result_msg->set_local_flag_value(local_value);
result_msg->set_has_server_override(attribute & FlagInfoBit::HasServerOverride);
result_msg->set_is_readwrite(attribute & FlagInfoBit::IsReadWrite);
result_msg->set_has_local_override(attribute & FlagInfoBit::HasLocalOverride);
}
}
/// Remove all local overrides
Result<void> RemoveAllLocalOverrides() {
for (auto const& record : storage_files_manager.GetAllStorageRecords()) {
auto storage_files = storage_files_manager.GetStorageFiles(record->container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
auto update = (**storage_files).RemoveAllLocalFlagValue();
RETURN_IF_ERROR(update, "Failed to remove all flag local overrides for "
+ record->container);
}
return {};
}
/// Remove a local override
Result<void> RemoveFlagLocalOverride(const std::string& package,
const std::string& flag) {
auto container = storage_files_manager.GetContainer(package);
RETURN_IF_ERROR(container, "Failed to find owning container");
auto storage_files = storage_files_manager.GetStorageFiles(*container);
RETURN_IF_ERROR(storage_files, "Failed to get storage files object");
auto context = (**storage_files).GetPackageFlagContext(package, flag);
RETURN_IF_ERROR(context, "Failed to find package flag context");
auto removed = (**storage_files).RemoveLocalFlagValue(*context);
RETURN_IF_ERROR(removed, "Failed to remove local override");
return {};
}
/// Handle override removal request
void HandleLocalOverrideRemoval(
const StorageRequestMessage::RemoveLocalOverrideMessage& msg,
StorageReturnMessage& return_msg) {
auto result = Result<void>();
if (msg.remove_all()) {
result = RemoveAllLocalOverrides();
} else {
result = RemoveFlagLocalOverride(msg.package_name(), msg.flag_name());
}
if (!result.ok()) {
auto* errmsg = return_msg.mutable_error_message();
*errmsg = result.error().message();
} else {
return_msg.mutable_remove_local_override_message();
}
}
} // namespace
/// Initialize in memory aconfig storage records
Result<void> InitializeInMemoryStorageRecords() {
auto records_pb = ReadPbFromFile<storage_records_pb>(kPersistentStorageRecordsFileName);
RETURN_IF_ERROR(records_pb, "Unable to read persistent storage records");
for (auto& entry : records_pb->files()) {
auto storage_record = StorageRecord();
storage_record.version = entry.version();
storage_record.container = entry.container();
storage_record.package_map = entry.package_map();
storage_record.flag_map = entry.flag_map();
storage_record.flag_val = entry.flag_val();
storage_record.flag_info = entry.flag_info();
storage_record.local_overrides = entry.local_overrides();
storage_record.timestamp = entry.timestamp();
storage_files_manager.AddStorageFiles(entry.container(), storage_record);
}
return {};
}
/// Initialize platform RO partition flag storage
Result<void> InitializePlatformStorage() {
auto value_files = std::vector<std::pair<std::string, std::string>>{
{"system", "/system/etc/aconfig"},
{"system_ext", "/system_ext/etc/aconfig"},
{"vendor", "/vendor/etc/aconfig"},
{"product", "/product/etc/aconfig"}};
for (auto const& [container, storage_dir] : value_files) {
auto package_file = std::string(storage_dir) + "/package.map";
auto flag_file = std::string(storage_dir) + "/flag.map";
auto value_file = std::string(storage_dir) + "/flag.val";
if (!FileExists(value_file)) {
continue;
}
auto updated = AddOrUpdateStorageForContainer(
container, package_file, flag_file, value_file);
RETURN_IF_ERROR(updated, "Failed to add or update storage for container "
+ container);
auto copied = CreateBootSnapshotForContainer(container);
RETURN_IF_ERROR(copied, "Failed to create boot snapshot for container "
+ container)
}
return {};
}
/// Handle incoming messages to aconfigd socket
void HandleSocketRequest(const StorageRequestMessage& message,
StorageReturnMessage& return_message) {
switch (message.msg_case()) {
case StorageRequestMessage::kNewStorageMessage: {
LOG(INFO) << "received a new storage request";
auto msg = message.new_storage_message();
HandleNewStorage(msg, return_message);
break;
}
case StorageRequestMessage::kFlagOverrideMessage: {
LOG(INFO) << "received a flag override request";
auto msg = message.flag_override_message();
HandleFlagOverride(msg, return_message);
break;
}
case StorageRequestMessage::kFlagQueryMessage: {
LOG(INFO) << "received a flag query request";
auto msg = message.flag_query_message();
HandlePersistFlagQuery(msg, return_message);
break;
}
case StorageRequestMessage::kRemoveLocalOverrideMessage: {
LOG(INFO) << "received a local override removal request";
auto msg = message.remove_local_override_message();
HandleLocalOverrideRemoval(msg, return_message);
break;
}
default:
auto* errmsg = return_message.mutable_error_message();
*errmsg = "Unknown message type from aconfigd socket";
break;
}
}
} // namespace aconfigd
} // namespace android