Merge "Add soong config variable Release_expose_flagged_api" into main
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index f8dbafd..29e4ecd 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -235,6 +235,7 @@
pm \
pppd \
preinstalled-packages-platform.xml \
+ printflags \
privapp-permissions-platform.xml \
prng_seeder \
racoon \
diff --git a/tools/aconfig/printflags/Android.bp b/tools/aconfig/printflags/Android.bp
index 5d73d96..da18cdc 100644
--- a/tools/aconfig/printflags/Android.bp
+++ b/tools/aconfig/printflags/Android.bp
@@ -2,8 +2,8 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-rust_binary {
- name: "printflags",
+rust_defaults {
+ name: "printflags.defaults",
edition: "2021",
clippy_lints: "android",
lints: "android",
@@ -12,5 +12,16 @@
"libaconfig_protos",
"libanyhow",
"libprotobuf",
+ "libregex",
],
}
+
+rust_binary {
+ name: "printflags",
+ defaults: ["printflags.defaults"],
+}
+
+rust_test_host {
+ name: "printflags.test",
+ defaults: ["printflags.defaults"],
+}
diff --git a/tools/aconfig/printflags/src/main.rs b/tools/aconfig/printflags/src/main.rs
index a9f7c03..88fdea9 100644
--- a/tools/aconfig/printflags/src/main.rs
+++ b/tools/aconfig/printflags/src/main.rs
@@ -16,12 +16,43 @@
//! `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 anyhow::Result;
+use anyhow::{bail, Result};
+use regex::Regex;
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<()> {
+ // 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();
for partition in ["system", "system_ext", "product", "vendor"] {
let path = format!("/{}/etc/aconfig_flags.pb", partition);
@@ -31,15 +62,49 @@
};
let parsed_flags: ProtoParsedFlags = protobuf::Message::parse_from_bytes(&bytes)?;
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);
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
- // the flag's current state, and append value to the output
- println!("{}: {}", key, value.join(", "));
+
+ // print flags
+ for (key, mut value) in flags {
+ 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(())
}
+
+#[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);
+ }
+}
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 56ec929..a753e68 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -728,47 +728,33 @@
return input_file
-def GetTargetFilesZipForCustomImagesUpdates(input_file, custom_images):
+def GetTargetFilesZipForCustomImagesUpdates(input_file, custom_images: dict):
"""Returns a target-files.zip for custom partitions update.
This function modifies ab_partitions list with the desired custom partitions
and puts the custom images into the target target-files.zip.
Args:
- input_file: The input target-files.zip filename.
+ input_file: The input target-files extracted directory
custom_images: A map of custom partitions and custom images.
Returns:
- The filename of a target-files.zip which has renamed the custom images in
- the IMAGES/ to their partition names.
+ The extracted dir of a target-files.zip which has renamed the custom images
+ in the IMAGES/ to their partition names.
"""
+ for custom_image in custom_images.values():
+ if not os.path.exists(os.path.join(input_file, "IMAGES", custom_image)):
+ raise ValueError("Specified custom image {} not found in target files {}, available images are {}",
+ custom_image, input_file, os.listdir(os.path.join(input_file, "IMAGES")))
- # First pass: use zip2zip to copy the target files contents, excluding
- # the "custom" images that will be replaced.
- target_file = common.MakeTempFile(prefix="targetfiles-", suffix=".zip")
- cmd = ['zip2zip', '-i', input_file, '-o', target_file]
-
- images = {}
for custom_partition, custom_image in custom_images.items():
default_custom_image = '{}.img'.format(custom_partition)
if default_custom_image != custom_image:
- src = 'IMAGES/' + custom_image
- dst = 'IMAGES/' + default_custom_image
- cmd.extend(['-x', dst])
- images[dst] = src
+ src = os.path.join(input_file, 'IMAGES', custom_image)
+ dst = os.path.join(input_file, 'IMAGES', default_custom_image)
+ os.rename(src, dst)
- common.RunAndCheckOutput(cmd)
-
- # Second pass: write {custom_image}.img as {custom_partition}.img.
- with zipfile.ZipFile(input_file, allowZip64=True) as input_zip:
- with zipfile.ZipFile(target_file, 'a', allowZip64=True) as output_zip:
- for dst, src in images.items():
- data = input_zip.read(src)
- logger.info("Update custom partition '%s'", dst)
- common.ZipWriteStr(output_zip, dst, data)
- output_zip.close()
-
- return target_file
+ return input_file
def GeneratePartitionTimestampFlags(partition_state):
@@ -1238,7 +1224,7 @@
if len(words) == 2:
if not words[1].isdigit():
raise ValueError("Cannot parse value %r for option $COMPRESSION_LEVEL - only "
- "integers are allowed." % words[1])
+ "integers are allowed." % words[1])
elif o == "--security_patch_level":
OPTIONS.security_patch_level = a
elif o in ("--max_threads"):