Loading tools/aconfig/aconfig_storage_file/src/lib.rs +26 −11 Original line number Diff line number Diff line Loading @@ -219,7 +219,7 @@ pub fn list_flags( package_map: &str, flag_map: &str, flag_val: &str, ) -> Result<Vec<(String, bool)>, AconfigStorageError> { ) -> Result<Vec<(String, String, bool)>, 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)?)?; Loading @@ -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)); Loading Loading @@ -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); } Loading tools/aconfig/aflags/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ rust_defaults { srcs: ["src/main.rs"], rustlibs: [ "libaconfig_protos", "libaconfig_storage_read_api", "libaconfig_storage_file", "libanyhow", "libclap", "libnix", Loading tools/aconfig/aflags/Cargo.toml +3 −1 Original line number Diff line number Diff line Loading @@ -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" } tools/aconfig/aflags/src/aconfig_storage_source.rs 0 → 100644 +56 −0 Original line number Diff line number Diff line 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<Vec<Flag>> { 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!() } } tools/aconfig/aflags/src/main.rs +20 −4 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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: Loading Loading @@ -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 { Loading Loading @@ -201,8 +213,11 @@ fn set_flag(qualified_name: &str, value: &str) -> Result<()> { Ok(()) } fn list() -> Result<String> { let flags = DeviceConfigSource::list_flags()?; fn list(source_type: FlagSourceType) -> Result<String> { 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), Loading Loading @@ -234,7 +249,8 @@ fn list() -> Result<String> { 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), }; Loading Loading
tools/aconfig/aconfig_storage_file/src/lib.rs +26 −11 Original line number Diff line number Diff line Loading @@ -219,7 +219,7 @@ pub fn list_flags( package_map: &str, flag_map: &str, flag_val: &str, ) -> Result<Vec<(String, bool)>, AconfigStorageError> { ) -> Result<Vec<(String, String, bool)>, 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)?)?; Loading @@ -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)); Loading Loading @@ -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); } Loading
tools/aconfig/aflags/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ rust_defaults { srcs: ["src/main.rs"], rustlibs: [ "libaconfig_protos", "libaconfig_storage_read_api", "libaconfig_storage_file", "libanyhow", "libclap", "libnix", Loading
tools/aconfig/aflags/Cargo.toml +3 −1 Original line number Diff line number Diff line Loading @@ -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" }
tools/aconfig/aflags/src/aconfig_storage_source.rs 0 → 100644 +56 −0 Original line number Diff line number Diff line 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<Vec<Flag>> { 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!() } }
tools/aconfig/aflags/src/main.rs +20 −4 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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: Loading Loading @@ -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 { Loading Loading @@ -201,8 +213,11 @@ fn set_flag(qualified_name: &str, value: &str) -> Result<()> { Ok(()) } fn list() -> Result<String> { let flags = DeviceConfigSource::list_flags()?; fn list(source_type: FlagSourceType) -> Result<String> { 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), Loading Loading @@ -234,7 +249,8 @@ fn list() -> Result<String> { 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), }; Loading