Loading tools/aconfig/aflags/src/device_config_source.rs +11 −5 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ fn convert_parsed_flag(flag: &ProtoParsedFlag) -> Flag { fn read_pb_files() -> Result<Vec<Flag>> { let mut flags: BTreeMap<String, Flag> = BTreeMap::new(); for partition in ["system", "system_ext", "product", "vendor"] { let path = format!("/{}/etc/aconfig_flags.pb", partition); let path = format!("/{partition}/etc/aconfig_flags.pb"); let Ok(bytes) = fs::read(&path) else { eprintln!("warning: failed to read {}", path); continue; Loading Loading @@ -98,11 +98,13 @@ fn parse_device_config(raw: &str) -> Result<HashMap<String, String>> { Ok(flags) } fn read_device_config_output(command: &str) -> Result<String> { let output = Command::new("/system/bin/device_config").arg(command).output()?; fn read_device_config_output(command: &[&str]) -> Result<String> { let output = Command::new("/system/bin/device_config").args(command).output()?; if !output.status.success() { let reason = match output.status.code() { Some(code) => format!("exit code {}", code), Some(code) => { format!("exit code {}, output was {}", code, str::from_utf8(&output.stdout)?) } None => "terminated by signal".to_string(), }; bail!("failed to execute device_config: {}", reason); Loading @@ -111,7 +113,7 @@ fn read_device_config_output(command: &str) -> Result<String> { } fn read_device_config_flags() -> Result<HashMap<String, String>> { let list_output = read_device_config_output("list")?; let list_output = read_device_config_output(&["list"])?; parse_device_config(&list_output) } Loading Loading @@ -145,6 +147,10 @@ impl FlagSource for DeviceConfigSource { let flags = reconcile(&pb_flags, dc_flags); Ok(flags) } fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()> { read_device_config_output(&["put", namespace, qualified_name, value]).map(|_| ()) } } #[cfg(test)] Loading tools/aconfig/aflags/src/main.rs +43 −4 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ //! `aflags` is a device binary to read and write aconfig flags. use anyhow::Result; use anyhow::{anyhow, Result}; use clap::Parser; mod device_config_source; Loading Loading @@ -63,8 +63,15 @@ struct Flag { value_picked_from: ValuePickedFrom, } impl Flag { fn qualified_name(&self) -> String { format!("{}.{}", self.package, self.name) } } trait FlagSource { fn list_flags() -> Result<Vec<Flag>>; fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>; } const ABOUT_TEXT: &str = "Tool for reading and writing flags. Loading Loading @@ -94,6 +101,18 @@ struct Cli { enum Command { /// List all aconfig flags on this device. List, /// Enable an aconfig flag on this device, on the next boot. Enable { /// <package>.<flag_name> qualified_name: String, }, /// Disable an aconfig flag on this device, on the next boot. Disable { /// <package>.<flag_name> qualified_name: String, }, } struct PaddingInfo { Loading Loading @@ -125,6 +144,23 @@ fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String { format!("{pkg:p0$}{name:p1$}{val:p2$}{value_picked_from:p3$}{perm:p4$}{container}\n") } fn set_flag(qualified_name: &str, value: &str) -> Result<()> { let flags_binding = DeviceConfigSource::list_flags()?; let flag = flags_binding.iter().find(|f| f.qualified_name() == qualified_name).ok_or( anyhow!("no aconfig flag '{qualified_name}'. Does the flag have an .aconfig definition?"), )?; if let FlagPermission::ReadOnly = flag.permission { return Err(anyhow!( "could not write flag '{qualified_name}', it is read-only for the current release configuration.", )); } DeviceConfigSource::override_flag(&flag.namespace, qualified_name, value)?; Ok(()) } fn list() -> Result<String> { let flags = DeviceConfigSource::list_flags()?; let padding_info = PaddingInfo { Loading Loading @@ -154,10 +190,13 @@ fn list() -> Result<String> { fn main() { let cli = Cli::parse(); let output = match cli.command { Command::List => list(), Command::List => list().map(Some), Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None), Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None), }; match output { Ok(text) => println!("{text}"), Err(msg) => println!("Error: {}", msg), Ok(Some(text)) => println!("{text}"), Ok(None) => (), Err(message) => println!("Error: {message}"), } } Loading
tools/aconfig/aflags/src/device_config_source.rs +11 −5 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ fn convert_parsed_flag(flag: &ProtoParsedFlag) -> Flag { fn read_pb_files() -> Result<Vec<Flag>> { let mut flags: BTreeMap<String, Flag> = BTreeMap::new(); for partition in ["system", "system_ext", "product", "vendor"] { let path = format!("/{}/etc/aconfig_flags.pb", partition); let path = format!("/{partition}/etc/aconfig_flags.pb"); let Ok(bytes) = fs::read(&path) else { eprintln!("warning: failed to read {}", path); continue; Loading Loading @@ -98,11 +98,13 @@ fn parse_device_config(raw: &str) -> Result<HashMap<String, String>> { Ok(flags) } fn read_device_config_output(command: &str) -> Result<String> { let output = Command::new("/system/bin/device_config").arg(command).output()?; fn read_device_config_output(command: &[&str]) -> Result<String> { let output = Command::new("/system/bin/device_config").args(command).output()?; if !output.status.success() { let reason = match output.status.code() { Some(code) => format!("exit code {}", code), Some(code) => { format!("exit code {}, output was {}", code, str::from_utf8(&output.stdout)?) } None => "terminated by signal".to_string(), }; bail!("failed to execute device_config: {}", reason); Loading @@ -111,7 +113,7 @@ fn read_device_config_output(command: &str) -> Result<String> { } fn read_device_config_flags() -> Result<HashMap<String, String>> { let list_output = read_device_config_output("list")?; let list_output = read_device_config_output(&["list"])?; parse_device_config(&list_output) } Loading Loading @@ -145,6 +147,10 @@ impl FlagSource for DeviceConfigSource { let flags = reconcile(&pb_flags, dc_flags); Ok(flags) } fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()> { read_device_config_output(&["put", namespace, qualified_name, value]).map(|_| ()) } } #[cfg(test)] Loading
tools/aconfig/aflags/src/main.rs +43 −4 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ //! `aflags` is a device binary to read and write aconfig flags. use anyhow::Result; use anyhow::{anyhow, Result}; use clap::Parser; mod device_config_source; Loading Loading @@ -63,8 +63,15 @@ struct Flag { value_picked_from: ValuePickedFrom, } impl Flag { fn qualified_name(&self) -> String { format!("{}.{}", self.package, self.name) } } trait FlagSource { fn list_flags() -> Result<Vec<Flag>>; fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>; } const ABOUT_TEXT: &str = "Tool for reading and writing flags. Loading Loading @@ -94,6 +101,18 @@ struct Cli { enum Command { /// List all aconfig flags on this device. List, /// Enable an aconfig flag on this device, on the next boot. Enable { /// <package>.<flag_name> qualified_name: String, }, /// Disable an aconfig flag on this device, on the next boot. Disable { /// <package>.<flag_name> qualified_name: String, }, } struct PaddingInfo { Loading Loading @@ -125,6 +144,23 @@ fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String { format!("{pkg:p0$}{name:p1$}{val:p2$}{value_picked_from:p3$}{perm:p4$}{container}\n") } fn set_flag(qualified_name: &str, value: &str) -> Result<()> { let flags_binding = DeviceConfigSource::list_flags()?; let flag = flags_binding.iter().find(|f| f.qualified_name() == qualified_name).ok_or( anyhow!("no aconfig flag '{qualified_name}'. Does the flag have an .aconfig definition?"), )?; if let FlagPermission::ReadOnly = flag.permission { return Err(anyhow!( "could not write flag '{qualified_name}', it is read-only for the current release configuration.", )); } DeviceConfigSource::override_flag(&flag.namespace, qualified_name, value)?; Ok(()) } fn list() -> Result<String> { let flags = DeviceConfigSource::list_flags()?; let padding_info = PaddingInfo { Loading Loading @@ -154,10 +190,13 @@ fn list() -> Result<String> { fn main() { let cli = Cli::parse(); let output = match cli.command { Command::List => list(), Command::List => list().map(Some), Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None), Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None), }; match output { Ok(text) => println!("{text}"), Err(msg) => println!("Error: {}", msg), Ok(Some(text)) => println!("{text}"), Ok(None) => (), Err(message) => println!("Error: {message}"), } }