Merge changes from topic "printflags-include-device-config" into main
* changes: printflags: add printflags to PRODUCT_PACKAGES printflags: include device_config values
This commit is contained in:
@@ -235,6 +235,7 @@ PRODUCT_PACKAGES += \
|
|||||||
pm \
|
pm \
|
||||||
pppd \
|
pppd \
|
||||||
preinstalled-packages-platform.xml \
|
preinstalled-packages-platform.xml \
|
||||||
|
printflags \
|
||||||
privapp-permissions-platform.xml \
|
privapp-permissions-platform.xml \
|
||||||
prng_seeder \
|
prng_seeder \
|
||||||
racoon \
|
racoon \
|
||||||
|
@@ -2,8 +2,8 @@ package {
|
|||||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||||
}
|
}
|
||||||
|
|
||||||
rust_binary {
|
rust_defaults {
|
||||||
name: "printflags",
|
name: "printflags.defaults",
|
||||||
edition: "2021",
|
edition: "2021",
|
||||||
clippy_lints: "android",
|
clippy_lints: "android",
|
||||||
lints: "android",
|
lints: "android",
|
||||||
@@ -12,5 +12,16 @@ rust_binary {
|
|||||||
"libaconfig_protos",
|
"libaconfig_protos",
|
||||||
"libanyhow",
|
"libanyhow",
|
||||||
"libprotobuf",
|
"libprotobuf",
|
||||||
|
"libregex",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rust_binary {
|
||||||
|
name: "printflags",
|
||||||
|
defaults: ["printflags.defaults"],
|
||||||
|
}
|
||||||
|
|
||||||
|
rust_test_host {
|
||||||
|
name: "printflags.test",
|
||||||
|
defaults: ["printflags.defaults"],
|
||||||
|
}
|
||||||
|
@@ -16,12 +16,43 @@
|
|||||||
|
|
||||||
//! `printflags` is a device binary to print feature flags.
|
//! `printflags` is a device binary to print feature flags.
|
||||||
|
|
||||||
|
use aconfig_protos::aconfig::Flag_state as State;
|
||||||
use aconfig_protos::aconfig::Parsed_flags as ProtoParsedFlags;
|
use aconfig_protos::aconfig::Parsed_flags as ProtoParsedFlags;
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Result};
|
||||||
|
use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::process::Command;
|
||||||
|
use std::{fs, str};
|
||||||
|
|
||||||
|
fn parse_device_config(raw: &str) -> HashMap<String, String> {
|
||||||
|
let mut flags = HashMap::new();
|
||||||
|
let regex = Regex::new(r"(?m)^([[[:alnum:]]_]+/[[[:alnum:]]_\.]+)=(true|false)$").unwrap();
|
||||||
|
for capture in regex.captures_iter(raw) {
|
||||||
|
let key = capture.get(1).unwrap().as_str().to_string();
|
||||||
|
let value = match capture.get(2).unwrap().as_str() {
|
||||||
|
"true" => format!("{:?} (device_config)", State::ENABLED),
|
||||||
|
"false" => format!("{:?} (device_config)", State::DISABLED),
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
flags.insert(key, value);
|
||||||
|
}
|
||||||
|
flags
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
// read device_config
|
||||||
|
let output = Command::new("/system/bin/device_config").arg("list").output()?;
|
||||||
|
if !output.status.success() {
|
||||||
|
let reason = match output.status.code() {
|
||||||
|
Some(code) => format!("exit code {}", code),
|
||||||
|
None => "terminated by signal".to_string(),
|
||||||
|
};
|
||||||
|
bail!("failed to execute device_config: {}", reason);
|
||||||
|
}
|
||||||
|
let dc_stdout = str::from_utf8(&output.stdout)?;
|
||||||
|
let device_config_flags = parse_device_config(dc_stdout);
|
||||||
|
|
||||||
|
// read aconfig_flags.pb files
|
||||||
let mut flags: HashMap<String, Vec<String>> = HashMap::new();
|
let mut flags: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
for partition in ["system", "system_ext", "product", "vendor"] {
|
for partition in ["system", "system_ext", "product", "vendor"] {
|
||||||
let path = format!("/{}/etc/aconfig_flags.pb", partition);
|
let path = format!("/{}/etc/aconfig_flags.pb", partition);
|
||||||
@@ -31,15 +62,49 @@ fn main() -> Result<()> {
|
|||||||
};
|
};
|
||||||
let parsed_flags: ProtoParsedFlags = protobuf::Message::parse_from_bytes(&bytes)?;
|
let parsed_flags: ProtoParsedFlags = protobuf::Message::parse_from_bytes(&bytes)?;
|
||||||
for flag in parsed_flags.parsed_flag {
|
for flag in parsed_flags.parsed_flag {
|
||||||
let key = format!("{}.{}", flag.package(), flag.name());
|
let key = format!("{}/{}.{}", flag.namespace(), flag.package(), flag.name());
|
||||||
let value = format!("{:?} + {:?} ({})", flag.permission(), flag.state(), partition);
|
let value = format!("{:?} + {:?} ({})", flag.permission(), flag.state(), partition);
|
||||||
flags.entry(key).or_default().push(value);
|
flags.entry(key).or_default().push(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (key, value) in flags {
|
|
||||||
// TODO: if the flag is READ_WRITE (for any partition), call "device_config get" to obtain
|
// print flags
|
||||||
// the flag's current state, and append value to the output
|
for (key, mut value) in flags {
|
||||||
println!("{}: {}", key, value.join(", "));
|
let (_, package_and_name) = key.split_once('/').unwrap();
|
||||||
|
if let Some(dc_value) = device_config_flags.get(&key) {
|
||||||
|
value.push(dc_value.to_string());
|
||||||
|
}
|
||||||
|
println!("{}: {}", package_and_name, value.join(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_foo() {
|
||||||
|
let input = r#"
|
||||||
|
namespace_one/com.foo.bar.flag_one=true
|
||||||
|
namespace_one/com.foo.bar.flag_two=false
|
||||||
|
random_noise;
|
||||||
|
namespace_two/android.flag_one=true
|
||||||
|
namespace_two/android.flag_two=nonsense
|
||||||
|
"#;
|
||||||
|
let expected = HashMap::from([
|
||||||
|
(
|
||||||
|
"namespace_one/com.foo.bar.flag_one".to_string(),
|
||||||
|
"ENABLED (device_config)".to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"namespace_one/com.foo.bar.flag_two".to_string(),
|
||||||
|
"DISABLED (device_config)".to_string(),
|
||||||
|
),
|
||||||
|
("namespace_two/android.flag_one".to_string(), "ENABLED (device_config)".to_string()),
|
||||||
|
]);
|
||||||
|
let actual = parse_device_config(input);
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user