From 6d4db660268f3890d30561d63fd449d6db5bb18d Mon Sep 17 00:00:00 2001 From: Ted Bauer Date: Wed, 6 Mar 2024 18:08:32 -0500 Subject: [PATCH] aflags: add new storage mode Add a mode that lets the user use the new aconfig storage. Bug: 324436145 Test: adb shell aflags list --use-new-storage Change-Id: I97d7a229a64c6ef1aea844281298ce5449b02570 --- tools/aconfig/aconfig_storage_file/src/lib.rs | 37 ++++++++---- tools/aconfig/aflags/Android.bp | 2 + tools/aconfig/aflags/Cargo.toml | 4 +- .../aflags/src/aconfig_storage_source.rs | 56 +++++++++++++++++++ tools/aconfig/aflags/src/main.rs | 24 ++++++-- 5 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 tools/aconfig/aflags/src/aconfig_storage_source.rs diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs index 24b16a1a47..1e1e4d9368 100644 --- a/tools/aconfig/aconfig_storage_file/src/lib.rs +++ b/tools/aconfig/aconfig_storage_file/src/lib.rs @@ -219,7 +219,7 @@ pub fn list_flags( package_map: &str, flag_map: &str, flag_val: &str, -) -> Result, AconfigStorageError> { +) -> Result, 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)?)?; @@ -232,10 +232,9 @@ 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 full_flag_name = String::from(package_name) + "/" + &node.flag_name; let flag_offset = package_offset + node.flag_id as u32; let flag_value = flag_value_list.booleans[flag_offset as usize]; - flags.push((full_flag_name, flag_value)); + flags.push((String::from(package_name), node.flag_name.clone(), flag_value)); } flags.sort_by(|v1, v2| v1.0.cmp(&v2.0)); @@ -266,14 +265,30 @@ 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/disabled_rw"), false), - (String::from("com.android.aconfig.storage.test_1/enabled_ro"), true), - (String::from("com.android.aconfig.storage.test_1/enabled_rw"), false), - (String::from("com.android.aconfig.storage.test_2/disabled_ro"), false), - (String::from("com.android.aconfig.storage.test_2/enabled_fixed_ro"), true), - (String::from("com.android.aconfig.storage.test_2/enabled_ro"), true), - (String::from("com.android.aconfig.storage.test_4/enabled_fixed_ro"), false), - (String::from("com.android.aconfig.storage.test_4/enabled_ro"), true), + (String::from("com.android.aconfig.storage.test_1"), String::from("enabled_ro"), true), + (String::from("com.android.aconfig.storage.test_1"), String::from("enabled_rw"), false), + ( + String::from("com.android.aconfig.storage.test_1"), + String::from("disabled_rw"), + false, + ), + ( + String::from("com.android.aconfig.storage.test_2"), + String::from("disabled_ro"), + false, + ), + ( + String::from("com.android.aconfig.storage.test_2"), + String::from("enabled_fixed_ro"), + true, + ), + (String::from("com.android.aconfig.storage.test_2"), String::from("enabled_ro"), true), + (String::from("com.android.aconfig.storage.test_4"), String::from("enabled_ro"), true), + ( + String::from("com.android.aconfig.storage.test_4"), + String::from("enabled_fixed_ro"), + false, + ), ]; assert_eq!(flags, expected); } diff --git a/tools/aconfig/aflags/Android.bp b/tools/aconfig/aflags/Android.bp index b36aa34c64..4920a6fd81 100644 --- a/tools/aconfig/aflags/Android.bp +++ b/tools/aconfig/aflags/Android.bp @@ -10,6 +10,8 @@ rust_defaults { srcs: ["src/main.rs"], rustlibs: [ "libaconfig_protos", + "libaconfig_storage_read_api", + "libaconfig_storage_file", "libanyhow", "libclap", "libnix", diff --git a/tools/aconfig/aflags/Cargo.toml b/tools/aconfig/aflags/Cargo.toml index 6a08da6745..cce7f9d6cc 100644 --- a/tools/aconfig/aflags/Cargo.toml +++ b/tools/aconfig/aflags/Cargo.toml @@ -6,8 +6,10 @@ edition = "2021" [dependencies] anyhow = "1.0.69" paste = "1.0.11" -clap = { version = "4", features = ["derive"] } protobuf = "3.2.0" regex = "1.10.3" aconfig_protos = { path = "../aconfig_protos" } nix = { version = "0.28.0", features = ["user"] } +aconfig_storage_file = { version = "0.1.0", path = "../aconfig_storage_file" } +aconfig_storage_read_api = { version = "0.1.0", path = "../aconfig_storage_read_api" } +clap = {version = "4.5.2" } diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs new file mode 100644 index 0000000000..1d73688603 --- /dev/null +++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs @@ -0,0 +1,56 @@ +use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom}; +use anyhow::{anyhow, Result}; + +use std::fs::File; +use std::io::Read; + +pub struct AconfigStorageSource {} + +use aconfig_storage_file::protos::ProtoStorageFiles; + +static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/persistent_storage_file_records.pb"; + +impl FlagSource for AconfigStorageSource { + fn list_flags() -> Result> { + let mut result = Vec::new(); + + let mut file = File::open(STORAGE_INFO_FILE_PATH)?; + let mut bytes = Vec::new(); + file.read_to_end(&mut bytes)?; + let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?; + + for file_info in storage_file_info.files { + let package_map = + file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?; + let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?; + let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?; + let container = + file_info.container.ok_or(anyhow!("storage file is missing container"))?; + + for (package, name, val) 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())?, + container: container.to_string(), + + // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI. + namespace: "-".to_string(), + + // TODO(b/324436145): Populate with real values once API is available. + staged_value: None, + permission: FlagPermission::ReadOnly, + value_picked_from: ValuePickedFrom::Default, + }); + } + } + + Ok(result) + } + + fn override_flag(_namespace: &str, _qualified_name: &str, _value: &str) -> Result<()> { + todo!() + } +} diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs index 808ffa0da8..1c453c52c3 100644 --- a/tools/aconfig/aflags/src/main.rs +++ b/tools/aconfig/aflags/src/main.rs @@ -22,6 +22,9 @@ use clap::Parser; mod device_config_source; use device_config_source::DeviceConfigSource; +mod aconfig_storage_source; +use aconfig_storage_source::AconfigStorageSource; + #[derive(Clone, PartialEq, Debug)] enum FlagPermission { ReadOnly, @@ -109,6 +112,11 @@ trait FlagSource { fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>; } +enum FlagSourceType { + DeviceConfig, + AconfigStorage, +} + const ABOUT_TEXT: &str = "Tool for reading and writing flags. Rows in the table from the `list` command follow this format: @@ -139,7 +147,11 @@ struct Cli { #[derive(Parser, Debug)] enum Command { /// List all aconfig flags on this device. - List, + List { + /// Read from the new flag storage. + #[clap(long)] + use_new_storage: bool, + }, /// Enable an aconfig flag on this device, on the next boot. Enable { @@ -201,8 +213,11 @@ fn set_flag(qualified_name: &str, value: &str) -> Result<()> { Ok(()) } -fn list() -> Result { - let flags = DeviceConfigSource::list_flags()?; +fn list(source_type: FlagSourceType) -> Result { + let flags = match source_type { + FlagSourceType::DeviceConfig => DeviceConfigSource::list_flags()?, + FlagSourceType::AconfigStorage => AconfigStorageSource::list_flags()?, + }; let padding_info = PaddingInfo { longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0), longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0), @@ -234,7 +249,8 @@ fn list() -> Result { fn main() { let cli = Cli::parse(); let output = match cli.command { - Command::List => list().map(Some), + Command::List { use_new_storage: true } => list(FlagSourceType::AconfigStorage).map(Some), + Command::List { use_new_storage: false } => list(FlagSourceType::DeviceConfig).map(Some), Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None), Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None), };