diff options
author | Dennis Shen <dzshen@google.com> | 2024-04-30 14:07:30 +0000 |
---|---|---|
committer | Dennis Shen <dzshen@google.com> | 2024-04-30 17:52:44 +0000 |
commit | 45c94c6421033afd1e591c1758682d2d94c16af6 (patch) | |
tree | e63d0619e842fb5180ee3e0c4605f59ed6a06d7d | |
parent | c6e4a86b0391830ccc2ee6e81be2482a2dc6e659 (diff) | |
download | build-45c94c6421033afd1e591c1758682d2d94c16af6.tar.gz |
aconfig: add a new aconfig storage file flag listing api
added a new function called list_flag_with_info to list all the flags
given all four storage files (package.map, flag.map, flag.val, flag.info).
also exported this api thru cxx interface so aconfigd can use it.
Bug: b/312444587
Test: atest -c
Change-Id: Ibbfe657b980d40e25e5e28962b930338192e2d98
19 files changed, 562 insertions, 75 deletions
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING index b7ff8eff17..421e94a8a6 100644 --- a/tools/aconfig/TEST_MAPPING +++ b/tools/aconfig/TEST_MAPPING @@ -97,5 +97,9 @@ } ], "postsubmit": [ + { + // aconfig_storage file cpp integration tests + "name": "aconfig_storage_file.test.cpp" + } ] } diff --git a/tools/aconfig/aconfig_storage_file/Android.bp b/tools/aconfig/aconfig_storage_file/Android.bp index 08c00b0d6d..e066e31ac1 100644 --- a/tools/aconfig/aconfig_storage_file/Android.bp +++ b/tools/aconfig/aconfig_storage_file/Android.bp @@ -12,6 +12,7 @@ rust_defaults { "libtempfile", "libprotobuf", "libclap", + "libcxx", "libaconfig_storage_protos", ], } @@ -77,3 +78,62 @@ cc_library { product_available: true, double_loadable: true, } + +// cxx source codegen from rust api +genrule { + name: "libcxx_aconfig_storage_file_bridge_code", + tools: ["cxxbridge"], + cmd: "$(location cxxbridge) $(in) > $(out)", + srcs: ["src/lib.rs"], + out: ["aconfig_storage/lib.rs.cc"], +} + +// cxx header codegen from rust api +genrule { + name: "libcxx_aconfig_storage_file_bridge_header", + tools: ["cxxbridge"], + cmd: "$(location cxxbridge) $(in) --header > $(out)", + srcs: ["src/lib.rs"], + out: ["aconfig_storage/lib.rs.h"], +} + +// a static cc lib based on generated code +rust_ffi_static { + name: "libaconfig_storage_file_cxx_bridge", + crate_name: "aconfig_storage_file_cxx_bridge", + host_supported: true, + vendor_available: true, + product_available: true, + srcs: ["src/lib.rs"], + defaults: ["aconfig_storage_file.defaults"], + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + min_sdk_version: "29", +} + +// storage file parse api cc interface +cc_library { + name: "libaconfig_storage_file_cc", + srcs: ["aconfig_storage_file.cpp"], + generated_headers: [ + "cxx-bridge-header", + "libcxx_aconfig_storage_file_bridge_header", + ], + generated_sources: ["libcxx_aconfig_storage_file_bridge_code"], + whole_static_libs: ["libaconfig_storage_file_cxx_bridge"], + export_include_dirs: ["include"], + host_supported: true, + vendor_available: true, + product_available: true, + shared_libs: [ + "libbase", + ], + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + min_sdk_version: "29", + double_loadable: true, +} diff --git a/tools/aconfig/aconfig_storage_file/Cargo.toml b/tools/aconfig/aconfig_storage_file/Cargo.toml index 641f481ed3..192dfad40a 100644 --- a/tools/aconfig/aconfig_storage_file/Cargo.toml +++ b/tools/aconfig/aconfig_storage_file/Cargo.toml @@ -13,6 +13,7 @@ protobuf = "3.2.0" tempfile = "3.9.0" thiserror = "1.0.56" clap = { version = "4.1.8", features = ["derive"] } +cxx = "1.0" [[bin]] name = "aconfig-storage" diff --git a/tools/aconfig/aconfig_storage_file/aconfig_storage_file.cpp b/tools/aconfig/aconfig_storage_file/aconfig_storage_file.cpp new file mode 100644 index 0000000000..548078f48f --- /dev/null +++ b/tools/aconfig/aconfig_storage_file/aconfig_storage_file.cpp @@ -0,0 +1,38 @@ +#include "rust/cxx.h" +#include "aconfig_storage/lib.rs.h" + +#include "aconfig_storage/aconfig_storage_file.hpp" + +using namespace android::base; + +namespace aconfig_storage { + +Result<std::vector<FlagValueAndInfoSummary>> list_flags_with_info( + const std::string& package_map, + const std::string& flag_map, + const std::string& flag_val, + const std::string& flag_info) { + auto flag_list_cxx = list_flags_with_info_cxx(rust::Str(package_map.c_str()), + rust::Str(flag_map.c_str()), + rust::Str(flag_val.c_str()), + rust::Str(flag_info.c_str())); + if (flag_list_cxx.query_success) { + auto flag_list = std::vector<FlagValueAndInfoSummary>(); + for (const auto& flag_cxx : flag_list_cxx.flags) { + auto flag = FlagValueAndInfoSummary(); + flag.package_name = std::string(flag_cxx.package_name); + flag.flag_name = std::string(flag_cxx.flag_name); + flag.flag_value = std::string(flag_cxx.flag_value); + flag.value_type = std::string(flag_cxx.value_type); + flag.is_readwrite = flag_cxx.is_readwrite; + flag.has_server_override = flag_cxx.has_server_override; + flag.has_local_override = flag_cxx.has_local_override; + flag_list.push_back(flag); + } + return flag_list; + } else { + return Error() << flag_list_cxx.error_message; + } +} + +} // namespace aconfig_storage diff --git a/tools/aconfig/aconfig_storage_file/build.rs b/tools/aconfig/aconfig_storage_file/build.rs index 1feeb60677..e0ade2aba0 100644 --- a/tools/aconfig/aconfig_storage_file/build.rs +++ b/tools/aconfig/aconfig_storage_file/build.rs @@ -14,4 +14,6 @@ fn main() { .inputs(proto_files) .cargo_out_dir("aconfig_storage_protos") .run_from_script(); + + let _ = cxx_build::bridge("src/lib.rs"); } diff --git a/tools/aconfig/aconfig_storage_file/include/aconfig_storage/aconfig_storage_file.hpp b/tools/aconfig/aconfig_storage_file/include/aconfig_storage/aconfig_storage_file.hpp new file mode 100644 index 0000000000..5044a4dbfc --- /dev/null +++ b/tools/aconfig/aconfig_storage_file/include/aconfig_storage/aconfig_storage_file.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <vector> +#include <string> +#include <android-base/result.h> + +namespace aconfig_storage { + +/// Flag value and info summary for a flag +struct FlagValueAndInfoSummary { + std::string package_name; + std::string flag_name; + std::string flag_value; + std::string value_type; + bool is_readwrite; + bool has_server_override; + bool has_local_override; +}; + +/// List all flag values with their flag info +/// \input package_map: package map file +/// \input flag_map: flag map file +/// \input flag_val: flag value file +/// \input flag_info: flag info file +android::base::Result<std::vector<FlagValueAndInfoSummary>> list_flags_with_info( + const std::string& package_map, + const std::string& flag_map, + const std::string& flag_val, + const std::string& flag_info); + +}// namespace aconfig_storage diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs index 2acfc7dbc7..80602bbfb0 100644 --- a/tools/aconfig/aconfig_storage_file/src/lib.rs +++ b/tools/aconfig/aconfig_storage_file/src/lib.rs @@ -278,12 +278,21 @@ pub fn read_file_to_bytes(file_path: &str) -> Result<Vec<u8>, AconfigStorageErro Ok(buffer) } +/// Flag value summary +#[derive(Debug, PartialEq)] +pub struct FlagValueSummary { + pub package_name: String, + pub flag_name: String, + pub flag_value: String, + pub value_type: StoredFlagType, +} + /// List flag values from storage files pub fn list_flags( package_map: &str, flag_map: &str, flag_val: &str, -) -> Result<Vec<(String, String, StoredFlagType, bool)>, AconfigStorageError> { +) -> Result<Vec<FlagValueSummary>, AconfigStorageError> { let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?; let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?; let flag_value_list = FlagValueList::from_bytes(&read_file_to_bytes(flag_val)?)?; @@ -295,30 +304,155 @@ pub fn list_flags( let mut flags = Vec::new(); for node in flag_table.nodes.iter() { - let (package_name, package_offset) = package_info[node.package_id as usize]; - let flag_offset = package_offset + node.flag_index as u32; - let flag_value = flag_value_list.booleans[flag_offset as usize]; - flags.push(( - String::from(package_name), - node.flag_name.clone(), - node.flag_type, - flag_value, - )); + let (package_name, boolean_start_index) = package_info[node.package_id as usize]; + let flag_index = boolean_start_index + node.flag_index as u32; + let flag_value = flag_value_list.booleans[flag_index as usize]; + flags.push(FlagValueSummary { + package_name: String::from(package_name), + flag_name: node.flag_name.clone(), + flag_value: flag_value.to_string(), + value_type: node.flag_type, + }); } - flags.sort_by(|v1, v2| match v1.0.cmp(&v2.0) { - Ordering::Equal => v1.1.cmp(&v2.1), + flags.sort_by(|v1, v2| match v1.package_name.cmp(&v2.package_name) { + Ordering::Equal => v1.flag_name.cmp(&v2.flag_name), other => other, }); Ok(flags) } +/// Flag value and info summary +#[derive(Debug, PartialEq)] +pub struct FlagValueAndInfoSummary { + pub package_name: String, + pub flag_name: String, + pub flag_value: String, + pub value_type: StoredFlagType, + pub is_readwrite: bool, + pub has_server_override: bool, + pub has_local_override: bool, +} + +/// List flag values and info from storage files +pub fn list_flags_with_info( + package_map: &str, + flag_map: &str, + flag_val: &str, + flag_info: &str, +) -> Result<Vec<FlagValueAndInfoSummary>, AconfigStorageError> { + let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?; + let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?; + let flag_value_list = FlagValueList::from_bytes(&read_file_to_bytes(flag_val)?)?; + let flag_info = FlagInfoList::from_bytes(&read_file_to_bytes(flag_info)?)?; + + let mut package_info = vec![("", 0); package_table.header.num_packages as usize]; + for node in package_table.nodes.iter() { + package_info[node.package_id as usize] = (&node.package_name, node.boolean_start_index); + } + + let mut flags = Vec::new(); + for node in flag_table.nodes.iter() { + let (package_name, boolean_start_index) = package_info[node.package_id as usize]; + let flag_index = boolean_start_index + node.flag_index as u32; + let flag_value = flag_value_list.booleans[flag_index as usize]; + let flag_attribute = flag_info.nodes[flag_index as usize].attributes; + flags.push(FlagValueAndInfoSummary { + package_name: String::from(package_name), + flag_name: node.flag_name.clone(), + flag_value: flag_value.to_string(), + value_type: node.flag_type, + is_readwrite: flag_attribute & (FlagInfoBit::IsReadWrite as u8) != 0, + has_server_override: flag_attribute & (FlagInfoBit::HasServerOverride as u8) != 0, + has_local_override: flag_attribute & (FlagInfoBit::HasLocalOverride as u8) != 0, + }); + } + + flags.sort_by(|v1, v2| match v1.package_name.cmp(&v2.package_name) { + Ordering::Equal => v1.flag_name.cmp(&v2.flag_name), + other => other, + }); + Ok(flags) +} + +// *************************************** // +// CC INTERLOP +// *************************************** // + +// Exported rust data structure and methods, c++ code will be generated +#[cxx::bridge] +mod ffi { + /// flag value and info summary cxx return + pub struct FlagValueAndInfoSummaryCXX { + pub package_name: String, + pub flag_name: String, + pub flag_value: String, + pub value_type: String, + pub is_readwrite: bool, + pub has_server_override: bool, + pub has_local_override: bool, + } + + /// list flag result cxx return + pub struct ListFlagValueAndInfoResultCXX { + pub query_success: bool, + pub error_message: String, + pub flags: Vec<FlagValueAndInfoSummaryCXX>, + } + + // Rust export to c++ + extern "Rust" { + pub fn list_flags_with_info_cxx( + package_map: &str, + flag_map: &str, + flag_val: &str, + flag_info: &str, + ) -> ListFlagValueAndInfoResultCXX; + } +} + +/// implement flag value and info summary cxx return type +impl ffi::FlagValueAndInfoSummaryCXX { + pub(crate) fn new(summary: FlagValueAndInfoSummary) -> Self { + Self { + package_name: summary.package_name, + flag_name: summary.flag_name, + flag_value: summary.flag_value, + value_type: format!("{:?}", summary.value_type), + is_readwrite: summary.is_readwrite, + has_server_override: summary.has_server_override, + has_local_override: summary.has_local_override, + } + } +} + +/// implement list flag with info cxx interlop +pub fn list_flags_with_info_cxx( + package_map: &str, + flag_map: &str, + flag_val: &str, + flag_info: &str, +) -> ffi::ListFlagValueAndInfoResultCXX { + match list_flags_with_info(package_map, flag_map, flag_val, flag_info) { + Ok(summary) => ffi::ListFlagValueAndInfoResultCXX { + query_success: true, + error_message: String::new(), + flags: summary.into_iter().map(ffi::FlagValueAndInfoSummaryCXX::new).collect(), + }, + Err(errmsg) => ffi::ListFlagValueAndInfoResultCXX { + query_success: false, + error_message: format!("{:?}", errmsg), + flags: Vec::new(), + }, + } +} + #[cfg(test)] mod tests { use super::*; use crate::test_utils::{ - create_test_flag_table, create_test_flag_value_list, create_test_package_table, - write_bytes_to_temp_file, + create_test_flag_info_list, create_test_flag_table, create_test_flag_value_list, + create_test_package_table, write_bytes_to_temp_file, }; #[test] @@ -337,54 +471,154 @@ mod tests { let flags = list_flags(&package_table_path, &flag_table_path, &flag_value_list_path).unwrap(); let expected = [ - ( - String::from("com.android.aconfig.storage.test_1"), - String::from("disabled_rw"), - StoredFlagType::ReadWriteBoolean, - false, - ), - ( - String::from("com.android.aconfig.storage.test_1"), - String::from("enabled_ro"), - StoredFlagType::ReadOnlyBoolean, - true, - ), - ( - String::from("com.android.aconfig.storage.test_1"), - String::from("enabled_rw"), - StoredFlagType::ReadWriteBoolean, - true, - ), - ( - String::from("com.android.aconfig.storage.test_2"), - String::from("disabled_rw"), - StoredFlagType::ReadWriteBoolean, - false, - ), - ( - String::from("com.android.aconfig.storage.test_2"), - String::from("enabled_fixed_ro"), - StoredFlagType::FixedReadOnlyBoolean, - true, - ), - ( - String::from("com.android.aconfig.storage.test_2"), - String::from("enabled_ro"), - StoredFlagType::ReadOnlyBoolean, - true, - ), - ( - String::from("com.android.aconfig.storage.test_4"), - String::from("enabled_fixed_ro"), - StoredFlagType::FixedReadOnlyBoolean, - true, - ), - ( - String::from("com.android.aconfig.storage.test_4"), - String::from("enabled_rw"), - StoredFlagType::ReadWriteBoolean, - true, - ), + FlagValueSummary { + package_name: String::from("com.android.aconfig.storage.test_1"), + flag_name: String::from("disabled_rw"), + value_type: StoredFlagType::ReadWriteBoolean, + flag_value: String::from("false"), + }, + FlagValueSummary { + package_name: String::from("com.android.aconfig.storage.test_1"), + flag_name: String::from("enabled_ro"), + value_type: StoredFlagType::ReadOnlyBoolean, + flag_value: String::from("true"), + }, + FlagValueSummary { + package_name: String::from("com.android.aconfig.storage.test_1"), + flag_name: String::from("enabled_rw"), + value_type: StoredFlagType::ReadWriteBoolean, + flag_value: String::from("true"), + }, + FlagValueSummary { + package_name: String::from("com.android.aconfig.storage.test_2"), + flag_name: String::from("disabled_rw"), + value_type: StoredFlagType::ReadWriteBoolean, + flag_value: String::from("false"), + }, + FlagValueSummary { + package_name: String::from("com.android.aconfig.storage.test_2"), + flag_name: String::from("enabled_fixed_ro"), + value_type: StoredFlagType::FixedReadOnlyBoolean, + flag_value: String::from("true"), + }, + FlagValueSummary { + package_name: String::from("com.android.aconfig.storage.test_2"), + flag_name: String::from("enabled_ro"), + value_type: StoredFlagType::ReadOnlyBoolean, + flag_value: String::from("true"), + }, + FlagValueSummary { + package_name: String::from("com.android.aconfig.storage.test_4"), + flag_name: String::from("enabled_fixed_ro"), + value_type: StoredFlagType::FixedReadOnlyBoolean, + flag_value: String::from("true"), + }, + FlagValueSummary { + package_name: String::from("com.android.aconfig.storage.test_4"), + flag_name: String::from("enabled_rw"), + value_type: StoredFlagType::ReadWriteBoolean, + flag_value: String::from("true"), + }, + ]; + assert_eq!(flags, expected); + } + + #[test] + // this test point locks down the flag list with info api + fn test_list_flag_with_info() { + let package_table = + write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap(); + let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap(); + let flag_value_list = + write_bytes_to_temp_file(&create_test_flag_value_list().into_bytes()).unwrap(); + let flag_info_list = + write_bytes_to_temp_file(&create_test_flag_info_list().into_bytes()).unwrap(); + + let package_table_path = package_table.path().display().to_string(); + let flag_table_path = flag_table.path().display().to_string(); + let flag_value_list_path = flag_value_list.path().display().to_string(); + let flag_info_list_path = flag_info_list.path().display().to_string(); + + let flags = list_flags_with_info( + &package_table_path, + &flag_table_path, + &flag_value_list_path, + &flag_info_list_path, + ) + .unwrap(); + let expected = [ + FlagValueAndInfoSummary { + package_name: String::from("com.android.aconfig.storage.test_1"), + flag_name: String::from("disabled_rw"), + value_type: StoredFlagType::ReadWriteBoolean, + flag_value: String::from("false"), + is_readwrite: true, + has_server_override: false, + has_local_override: false, + }, + FlagValueAndInfoSummary { + package_name: String::from("com.android.aconfig.storage.test_1"), + flag_name: String::from("enabled_ro"), + value_type: StoredFlagType::ReadOnlyBoolean, + flag_value: String::from("true"), + is_readwrite: false, + has_server_override: false, + has_local_override: false, + }, + FlagValueAndInfoSummary { + package_name: String::from("com.android.aconfig.storage.test_1"), + flag_name: String::from("enabled_rw"), + value_type: StoredFlagType::ReadWriteBoolean, + flag_value: String::from("true"), + is_readwrite: true, + has_server_override: false, + has_local_override: false, + }, + FlagValueAndInfoSummary { + package_name: String::from("com.android.aconfig.storage.test_2"), + flag_name: String::from("disabled_rw"), + value_type: StoredFlagType::ReadWriteBoolean, + flag_value: String::from("false"), + is_readwrite: true, + has_server_override: false, + has_local_override: false, + }, + FlagValueAndInfoSummary { + package_name: String::from("com.android.aconfig.storage.test_2"), + flag_name: String::from("enabled_fixed_ro"), + value_type: StoredFlagType::FixedReadOnlyBoolean, + flag_value: String::from("true"), + is_readwrite: false, + has_server_override: false, + has_local_override: false, + }, + FlagValueAndInfoSummary { + package_name: String::from("com.android.aconfig.storage.test_2"), + flag_name: String::from("enabled_ro"), + value_type: StoredFlagType::ReadOnlyBoolean, + flag_value: String::from("true"), + is_readwrite: false, + has_server_override: false, + has_local_override: false, + }, + FlagValueAndInfoSummary { + package_name: String::from("com.android.aconfig.storage.test_4"), + flag_name: String::from("enabled_fixed_ro"), + value_type: StoredFlagType::FixedReadOnlyBoolean, + flag_value: String::from("true"), + is_readwrite: false, + has_server_override: false, + has_local_override: false, + }, + FlagValueAndInfoSummary { + package_name: String::from("com.android.aconfig.storage.test_4"), + flag_name: String::from("enabled_rw"), + value_type: StoredFlagType::ReadWriteBoolean, + flag_value: String::from("true"), + is_readwrite: true, + has_server_override: false, + has_local_override: false, + }, ]; assert_eq!(flags, expected); } diff --git a/tools/aconfig/aconfig_storage_file/src/main.rs b/tools/aconfig/aconfig_storage_file/src/main.rs index b686274a2d..8b9e38da02 100644 --- a/tools/aconfig/aconfig_storage_file/src/main.rs +++ b/tools/aconfig/aconfig_storage_file/src/main.rs @@ -17,8 +17,8 @@ //! `aconfig-storage` is a debugging tool to parse storage files use aconfig_storage_file::{ - list_flags, read_file_to_bytes, AconfigStorageError, FlagInfoList, FlagTable, FlagValueList, - PackageTable, StorageFileType, + list_flags, list_flags_with_info, read_file_to_bytes, AconfigStorageError, FlagInfoList, + FlagTable, FlagValueList, PackageTable, StorageFileType, }; use clap::{builder::ArgAction, Arg, Command}; @@ -45,7 +45,10 @@ fn cli() -> Command { .action(ArgAction::Set), ) .arg(Arg::new("flag-map").long("flag-map").required(true).action(ArgAction::Set)) - .arg(Arg::new("flag-val").long("flag-val").required(true).action(ArgAction::Set)), + .arg(Arg::new("flag-val").long("flag-val").required(true).action(ArgAction::Set)) + .arg( + Arg::new("flag-info").long("flag-info").required(false).action(ArgAction::Set), + ), ) } @@ -87,9 +90,27 @@ fn main() -> Result<(), AconfigStorageError> { let package_map = sub_matches.get_one::<String>("package-map").unwrap(); let flag_map = sub_matches.get_one::<String>("flag-map").unwrap(); let flag_val = sub_matches.get_one::<String>("flag-val").unwrap(); - let flags = list_flags(package_map, flag_map, flag_val)?; - for (package_name, flag_name, flag_type, flag_value) in flags.iter() { - println!("{} {} {:?} {}", package_name, flag_name, flag_type, flag_value); + let flag_info = sub_matches.get_one::<String>("flag-info"); + match flag_info { + Some(info_file) => { + let flags = list_flags_with_info(package_map, flag_map, flag_val, info_file)?; + for flag in flags.iter() { + println!( + "{} {} {} {:?} IsReadWrite: {}, HasServerOverride: {}, HasLocalOverride: {}", + flag.package_name, flag.flag_name, flag.flag_value, flag.value_type, + flag.is_readwrite, flag.has_server_override, flag.has_local_override, + ); + } + } + None => { + let flags = list_flags(package_map, flag_map, flag_val)?; + for flag in flags.iter() { + println!( + "{} {} {} {:?}", + flag.package_name, flag.flag_name, flag.flag_value, flag.value_type, + ); + } + } } } _ => unreachable!(), diff --git a/tools/aconfig/aconfig_storage_file/tests/Android.bp b/tools/aconfig/aconfig_storage_file/tests/Android.bp new file mode 100644 index 0000000000..26b7800877 --- /dev/null +++ b/tools/aconfig/aconfig_storage_file/tests/Android.bp @@ -0,0 +1,23 @@ + +cc_test { + name: "aconfig_storage_file.test.cpp", + team: "trendy_team_android_core_experiments", + srcs: [ + "storage_file_test.cpp", + ], + static_libs: [ + "libgmock", + "libaconfig_storage_file_cc", + "libbase", + ], + data: [ + "package.map", + "flag.map", + "flag.val", + "flag.info", + ], + test_suites: [ + "device-tests", + "general-tests", + ], +} diff --git a/tools/aconfig/aconfig_storage_file/tests/flag.info b/tools/aconfig/aconfig_storage_file/tests/flag.info Binary files differnew file mode 100644 index 0000000000..6223edf369 --- /dev/null +++ b/tools/aconfig/aconfig_storage_file/tests/flag.info diff --git a/tools/aconfig/aconfig_storage_file/tests/flag.map b/tools/aconfig/aconfig_storage_file/tests/flag.map Binary files differnew file mode 100644 index 0000000000..e868f53d7e --- /dev/null +++ b/tools/aconfig/aconfig_storage_file/tests/flag.map diff --git a/tools/aconfig/aconfig_storage_file/tests/flag.val b/tools/aconfig/aconfig_storage_file/tests/flag.val Binary files differnew file mode 100644 index 0000000000..ed203d4d13 --- /dev/null +++ b/tools/aconfig/aconfig_storage_file/tests/flag.val diff --git a/tools/aconfig/aconfig_storage_file/tests/package.map b/tools/aconfig/aconfig_storage_file/tests/package.map Binary files differnew file mode 100644 index 0000000000..6c46a0339c --- /dev/null +++ b/tools/aconfig/aconfig_storage_file/tests/package.map diff --git a/tools/aconfig/aconfig_storage_file/tests/storage_file_test.cpp b/tools/aconfig/aconfig_storage_file/tests/storage_file_test.cpp new file mode 100644 index 0000000000..eccbca53d5 --- /dev/null +++ b/tools/aconfig/aconfig_storage_file/tests/storage_file_test.cpp @@ -0,0 +1,73 @@ +/* + * 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 <vector> +#include <android-base/file.h> +#include <android-base/result.h> +#include <gtest/gtest.h> +#include "aconfig_storage/aconfig_storage_file.hpp" + +using namespace android::base; +using namespace aconfig_storage; + + +void verify_flag(const FlagValueAndInfoSummary& flag, + const std::string& package_name, + const std::string& flag_name, + const std::string& flag_val, + const std::string& value_type, + bool is_readwrite, + bool has_server_override, + bool has_local_override) { + ASSERT_EQ(flag.package_name, package_name); + ASSERT_EQ(flag.flag_name, flag_name); + ASSERT_EQ(flag.flag_value, flag_val); + ASSERT_EQ(flag.value_type, value_type); + ASSERT_EQ(flag.is_readwrite, is_readwrite); + ASSERT_EQ(flag.has_server_override, has_server_override); + ASSERT_EQ(flag.has_local_override, has_local_override); +} + +TEST(AconfigStorageFileTest, test_list_flag_with_info) { + auto const test_dir = GetExecutableDirectory(); + auto const package_map = test_dir + "/package.map"; + auto const flag_map = test_dir + "/flag.map"; + auto const flag_val = test_dir + "/flag.val"; + auto const flag_info = test_dir + "/flag.info"; + auto flag_list_result = aconfig_storage::list_flags_with_info( + package_map, flag_map, flag_val, flag_info); + ASSERT_TRUE(flag_list_result.ok()); + + auto const& flag_list = *flag_list_result; + ASSERT_EQ(flag_list.size(), 8); + verify_flag(flag_list[0], "com.android.aconfig.storage.test_1", "disabled_rw", + "false", "ReadWriteBoolean", true, false, false); + verify_flag(flag_list[1], "com.android.aconfig.storage.test_1", "enabled_ro", + "true", "ReadOnlyBoolean", false, false, false); + verify_flag(flag_list[2], "com.android.aconfig.storage.test_1", "enabled_rw", + "true", "ReadWriteBoolean", true, false, false); + verify_flag(flag_list[3], "com.android.aconfig.storage.test_2", "disabled_rw", + "false", "ReadWriteBoolean", true, false, false); + verify_flag(flag_list[4], "com.android.aconfig.storage.test_2", "enabled_fixed_ro", + "true", "FixedReadOnlyBoolean", false, false, false); + verify_flag(flag_list[5], "com.android.aconfig.storage.test_2", "enabled_ro", + "true", "ReadOnlyBoolean", false, false, false); + verify_flag(flag_list[6], "com.android.aconfig.storage.test_4", "enabled_fixed_ro", + "true", "FixedReadOnlyBoolean", false, false, false); + verify_flag(flag_list[7], "com.android.aconfig.storage.test_4", "enabled_rw", + "true", "ReadWriteBoolean", true, false, false); +} diff --git a/tools/aconfig/aconfig_storage_read_api/src/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs index e65dcfbc69..e4192066d5 100644 --- a/tools/aconfig/aconfig_storage_read_api/src/lib.rs +++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs @@ -504,7 +504,7 @@ files {{ let pb_file_path = pb_file.path().display().to_string(); let flag_info_file = unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() }; - let is_rw: Vec<bool> = vec![true, false, true, false, false, false, false, false]; + let is_rw: Vec<bool> = vec![true, false, true, true, false, false, false, true]; for (offset, expected_value) in is_rw.into_iter().enumerate() { let attribute = get_flag_attribute(&flag_info_file, FlagValueType::Boolean, offset as u32).unwrap(); diff --git a/tools/aconfig/aconfig_storage_read_api/tests/flag.info b/tools/aconfig/aconfig_storage_read_api/tests/flag.info Binary files differindex 820d839363..6223edf369 100644 --- a/tools/aconfig/aconfig_storage_read_api/tests/flag.info +++ b/tools/aconfig/aconfig_storage_read_api/tests/flag.info diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp index b499c1c279..cfd128d123 100644 --- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp +++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp @@ -232,7 +232,7 @@ TEST_F(AconfigStorageTest, test_boolean_flag_info_query) { ASSERT_TRUE(mapped_file.ok()); auto expected_value = std::vector<bool>{ - true, false, true, false, false, false, false, false}; + true, false, true, true, false, false, false, true}; for (int index = 0; index < 8; ++index) { auto attribute = api::get_flag_attribute(*mapped_file, api::FlagValueType::Boolean, index); ASSERT_TRUE(attribute.ok()); diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs index ce9c0186dd..ecba573d82 100644 --- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs +++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs @@ -188,7 +188,7 @@ files {{ // The safety here is ensured as the test process will not write to temp storage file let flag_info_file = unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() }; - let is_rw: Vec<bool> = vec![true, false, true, false, false, false, false, false]; + let is_rw: Vec<bool> = vec![true, false, true, true, false, false, false, true]; for (offset, expected_value) in is_rw.into_iter().enumerate() { let attribute = get_flag_attribute(&flag_info_file, FlagValueType::Boolean, offset as u32).unwrap(); diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs index a3ca221d9e..c21c5424bb 100644 --- a/tools/aconfig/aflags/src/aconfig_storage_source.rs +++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs @@ -27,13 +27,13 @@ impl FlagSource for AconfigStorageSource { let container = file_info.container.ok_or(anyhow!("storage file is missing container"))?; - for (package, name, _flag_type, val) in + for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? { result.push(Flag { - name: name.to_string(), - package: package.to_string(), - value: FlagValue::try_from(val.to_string().as_str())?, + name: listed_flag.flag_name, + package: listed_flag.package_name, + value: FlagValue::try_from(listed_flag.flag_value.as_str())?, container: container.to_string(), // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI. |