Merge "aflags: add new storage mode" into main
This commit is contained in:
@@ -219,7 +219,7 @@ pub fn list_flags(
|
|||||||
package_map: &str,
|
package_map: &str,
|
||||||
flag_map: &str,
|
flag_map: &str,
|
||||||
flag_val: &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 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_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_value_list = FlagValueList::from_bytes(&read_file_to_bytes(flag_val)?)?;
|
||||||
@@ -232,10 +232,9 @@ pub fn list_flags(
|
|||||||
let mut flags = Vec::new();
|
let mut flags = Vec::new();
|
||||||
for node in flag_table.nodes.iter() {
|
for node in flag_table.nodes.iter() {
|
||||||
let (package_name, package_offset) = package_info[node.package_id as usize];
|
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_offset = package_offset + node.flag_id as u32;
|
||||||
let flag_value = flag_value_list.booleans[flag_offset as usize];
|
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));
|
flags.sort_by(|v1, v2| v1.0.cmp(&v2.0));
|
||||||
@@ -266,14 +265,30 @@ mod tests {
|
|||||||
let flags =
|
let flags =
|
||||||
list_flags(&package_table_path, &flag_table_path, &flag_value_list_path).unwrap();
|
list_flags(&package_table_path, &flag_table_path, &flag_value_list_path).unwrap();
|
||||||
let expected = [
|
let expected = [
|
||||||
(String::from("com.android.aconfig.storage.test_1/disabled_rw"), false),
|
(String::from("com.android.aconfig.storage.test_1"), String::from("enabled_ro"), true),
|
||||||
(String::from("com.android.aconfig.storage.test_1/enabled_ro"), true),
|
(String::from("com.android.aconfig.storage.test_1"), String::from("enabled_rw"), false),
|
||||||
(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_1"),
|
||||||
(String::from("com.android.aconfig.storage.test_2/enabled_fixed_ro"), true),
|
String::from("disabled_rw"),
|
||||||
(String::from("com.android.aconfig.storage.test_2/enabled_ro"), true),
|
false,
|
||||||
(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_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);
|
assert_eq!(flags, expected);
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,8 @@ rust_defaults {
|
|||||||
srcs: ["src/main.rs"],
|
srcs: ["src/main.rs"],
|
||||||
rustlibs: [
|
rustlibs: [
|
||||||
"libaconfig_protos",
|
"libaconfig_protos",
|
||||||
|
"libaconfig_storage_read_api",
|
||||||
|
"libaconfig_storage_file",
|
||||||
"libanyhow",
|
"libanyhow",
|
||||||
"libclap",
|
"libclap",
|
||||||
"libnix",
|
"libnix",
|
||||||
|
@@ -6,8 +6,10 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.69"
|
anyhow = "1.0.69"
|
||||||
paste = "1.0.11"
|
paste = "1.0.11"
|
||||||
clap = { version = "4", features = ["derive"] }
|
|
||||||
protobuf = "3.2.0"
|
protobuf = "3.2.0"
|
||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
aconfig_protos = { path = "../aconfig_protos" }
|
aconfig_protos = { path = "../aconfig_protos" }
|
||||||
nix = { version = "0.28.0", features = ["user"] }
|
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" }
|
||||||
|
56
tools/aconfig/aflags/src/aconfig_storage_source.rs
Normal file
56
tools/aconfig/aflags/src/aconfig_storage_source.rs
Normal file
@@ -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<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!()
|
||||||
|
}
|
||||||
|
}
|
@@ -22,6 +22,9 @@ use clap::Parser;
|
|||||||
mod device_config_source;
|
mod device_config_source;
|
||||||
use device_config_source::DeviceConfigSource;
|
use device_config_source::DeviceConfigSource;
|
||||||
|
|
||||||
|
mod aconfig_storage_source;
|
||||||
|
use aconfig_storage_source::AconfigStorageSource;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
enum FlagPermission {
|
enum FlagPermission {
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
@@ -109,6 +112,11 @@ trait FlagSource {
|
|||||||
fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>;
|
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.
|
const ABOUT_TEXT: &str = "Tool for reading and writing flags.
|
||||||
|
|
||||||
Rows in the table from the `list` command follow this format:
|
Rows in the table from the `list` command follow this format:
|
||||||
@@ -139,7 +147,11 @@ struct Cli {
|
|||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
enum Command {
|
enum Command {
|
||||||
/// List all aconfig flags on this device.
|
/// 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 an aconfig flag on this device, on the next boot.
|
||||||
Enable {
|
Enable {
|
||||||
@@ -201,8 +213,11 @@ fn set_flag(qualified_name: &str, value: &str) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list() -> Result<String> {
|
fn list(source_type: FlagSourceType) -> Result<String> {
|
||||||
let flags = DeviceConfigSource::list_flags()?;
|
let flags = match source_type {
|
||||||
|
FlagSourceType::DeviceConfig => DeviceConfigSource::list_flags()?,
|
||||||
|
FlagSourceType::AconfigStorage => AconfigStorageSource::list_flags()?,
|
||||||
|
};
|
||||||
let padding_info = PaddingInfo {
|
let padding_info = PaddingInfo {
|
||||||
longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0),
|
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),
|
longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0),
|
||||||
@@ -234,7 +249,8 @@ fn list() -> Result<String> {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let output = match cli.command {
|
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::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None),
|
||||||
Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None),
|
Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None),
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user