| /* |
| * 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; |
| snapshots[idx].container = storage_record_.container; |
| } |
| |
| // 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 |