Merge "Drop dexpreopt files of service-compos from install diff allowlist" into main
diff --git a/ci/build_metadata b/ci/build_metadata
index a8eb65d..cd011c8 100755
--- a/ci/build_metadata
+++ b/ci/build_metadata
@@ -20,6 +20,9 @@
export TARGET_RELEASE=trunk_staging
export TARGET_BUILD_VARIANT=eng
-build/soong/bin/m dist \
+TARGETS=(
all_teams
+ release_config_metadata
+)
+build/soong/bin/m dist ${TARGETS[@]}
diff --git a/core/Makefile b/core/Makefile
index 2cdb24f..96d0357 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -7950,9 +7950,14 @@
# Desktop pack recovery image hook.
ifneq (,$(strip $(PACK_DESKTOP_RECOVERY_IMAGE)))
PACK_RECOVERY_IMAGE_TARGET := $(PRODUCT_OUT)/android-desktop_recovery_image.bin
+PACK_RECOVERY_IMAGE_ARGS := --noarchive --recovery
+
+ifneq (,$(strip $(PACK_RECOVERY_IMAGE_EXPERIMENTAL)))
+PACK_RECOVERY_IMAGE_ARGS += --experimental
+endif # PACK_RECOVERY_IMAGE_EXPERIMENTAL
$(PACK_RECOVERY_IMAGE_TARGET): $(IMAGES) $(PACK_IMAGE_SCRIPT)
- $(PACK_IMAGE_SCRIPT) --out_dir $(PRODUCT_OUT) --noarchive --recovery
+ $(PACK_IMAGE_SCRIPT) --out_dir $(PRODUCT_OUT) $(PACK_RECOVERY_IMAGE_ARGS)
PACKED_RECOVERY_IMAGE_ARCHIVE_TARGET := $(PACK_RECOVERY_IMAGE_TARGET).gz
@@ -7986,6 +7991,28 @@
endif # PACK_DESKTOP_UPDATE_IMAGE
+PACK_MIGRATION_IMAGE_SCRIPT := $(HOST_OUT_EXECUTABLES)/pack_migration_image
+
+# -----------------------------------------------------------------
+# Desktop pack migration image hook.
+ifeq ($(ANDROID_DESKTOP_MIGRATION_IMAGE),true)
+PACK_MIGRATION_IMAGE_TARGET := $(PRODUCT_OUT)/android-desktop_migration_image.bin
+
+$(PACK_MIGRATION_IMAGE_TARGET): $(IMAGES) $(PACK_MIGRATION_IMAGE_SCRIPT)
+ $(PACK_MIGRATION_IMAGE_SCRIPT) --out_dir $(PRODUCT_OUT) --noarchive
+
+PACKED_MIGRATION_IMAGE_ARCHIVE_TARGET := $(PACK_MIGRATION_IMAGE_TARGET).gz
+
+$(PACKED_MIGRATION_IMAGE_ARCHIVE_TARGET): $(PACK_MIGRATION_IMAGE_TARGET) | $(GZIP)
+ $(GZIP) -fk $(PACK_MIGRATION_IMAGE_TARGET)
+
+$(call dist-for-goals,dist_files,$(PACKED_MIGRATION_IMAGE_ARCHIVE_TARGET))
+
+.PHONY: pack-migration-image
+pack-migration-image: $(PACK_MIGRATION_IMAGE_TARGET)
+
+endif # ANDROID_DESKTOP_MIGRATION_IMAGE
+
# -----------------------------------------------------------------
# OS Licensing
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index cb5575b..f66bdd9 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -192,3 +192,15 @@
ifneq ($(strip $(AUDIOSERVER_MULTILIB)),)
$(call soong_config_set,soundtrigger,audioserver_multilib,$(AUDIOSERVER_MULTILIB))
endif
+
+# Add sim_count, disable_rild_oem_hook, and use_aosp_rild flag for ril related modules
+$(call soong_config_set,ril,sim_count,$(SIM_COUNT))
+ifneq ($(DISABLE_RILD_OEM_HOOK), false)
+ $(call soong_config_set_bool,ril,disable_rild_oem_hook,true)
+endif
+ifneq ($(ENABLE_VENDOR_RIL_SERVICE), true)
+ $(call soong_config_set_bool,ril,use_aosp_rild,true)
+endif
+
+# Export target_board_platform to soong for hardware/google/graphics/common/libmemtrack:memtrack.$(TARGET_BOARD_PLATFORM)
+$(call soong_config_set,ANDROID,target_board_platform,$(TARGET_BOARD_PLATFORM))
diff --git a/core/config_sanitizers.mk b/core/config_sanitizers.mk
index c0f2c68..ab2d5c1 100644
--- a/core/config_sanitizers.mk
+++ b/core/config_sanitizers.mk
@@ -284,9 +284,9 @@
ifneq ($(filter memtag_stack,$(my_sanitize)),)
my_cflags += -fsanitize=memtag-stack
my_ldflags += -fsanitize=memtag-stack
- my_cflags += -Xclang -target-feature -Xclang +mte
- my_ldflags += -Xclang -target-feature -Xclang +mte
- my_asflags += -Xclang -target-feature -Xclang +mte
+ my_cflags += -march=armv8a+memtag
+ my_ldflags += -march=armv8a+memtag
+ my_asflags += -march=armv8a+memtag
my_sanitize := $(filter-out memtag_stack,$(my_sanitize))
endif
diff --git a/target/product/generic_system.mk b/target/product/generic_system.mk
index 0a09eb1..b9a623d 100644
--- a/target/product/generic_system.mk
+++ b/target/product/generic_system.mk
@@ -152,4 +152,5 @@
$(call require-artifacts-in-path, $(_my_paths), $(_my_allowed_list))
# Product config map to toggle between sources and prebuilts of required mainline modules
+PRODUCT_RELEASE_CONFIG_MAPS += $(wildcard build/release/gms_mainline/required/release_config_map.textproto)
PRODUCT_RELEASE_CONFIG_MAPS += $(wildcard vendor/google_shared/build/release/gms_mainline/required/release_config_map.textproto)
diff --git a/target/product/go_defaults.mk b/target/product/go_defaults.mk
index c928530..ccc4f36 100644
--- a/target/product/go_defaults.mk
+++ b/target/product/go_defaults.mk
@@ -18,6 +18,7 @@
$(call inherit-product, build/make/target/product/go_defaults_common.mk)
# Product config map to toggle between sources and prebuilts of required mainline modules
+PRODUCT_RELEASE_CONFIG_MAPS += $(wildcard build/release/gms_mainline_go/required/release_config_map.textproto)
PRODUCT_RELEASE_CONFIG_MAPS += $(wildcard vendor/google_shared/build/release/gms_mainline_go/required/release_config_map.textproto)
# Add the system properties.
diff --git a/target/product/gsi/Android.bp b/target/product/gsi/Android.bp
index 45ba143..f18f35a 100644
--- a/target/product/gsi/Android.bp
+++ b/target/product/gsi/Android.bp
@@ -46,3 +46,18 @@
installed_location: "etc/init/config",
symlink_target: "/system/system_ext/etc/init/config",
}
+
+// init.gsi.rc, GSI-specific init script.
+prebuilt_etc {
+ name: "init.gsi.rc",
+ src: "init.gsi.rc",
+ system_ext_specific: true,
+ relative_install_path: "init",
+}
+
+prebuilt_etc {
+ name: "init.vndk-nodef.rc",
+ src: "init.vndk-nodef.rc",
+ system_ext_specific: true,
+ relative_install_path: "gsi",
+}
diff --git a/target/product/gsi/Android.mk b/target/product/gsi/Android.mk
index 36897fe..7291059 100644
--- a/target/product/gsi/Android.mk
+++ b/target/product/gsi/Android.mk
@@ -138,31 +138,3 @@
include $(BUILD_PHONY_PACKAGE)
-
-#####################################################################
-# init.gsi.rc, GSI-specific init script.
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := init.gsi.rc
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := build/soong/licenses/LICENSE
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_SYSTEM_EXT_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := init
-
-include $(BUILD_PREBUILT)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := init.vndk-nodef.rc
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := build/soong/licenses/LICENSE
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_SYSTEM_EXT_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := gsi
-
-include $(BUILD_PREBUILT)
diff --git a/tools/aconfig/aconfig/Android.bp b/tools/aconfig/aconfig/Android.bp
index 68521af..f4dd103 100644
--- a/tools/aconfig/aconfig/Android.bp
+++ b/tools/aconfig/aconfig/Android.bp
@@ -234,6 +234,7 @@
name: "libaconfig_test_rust_library",
crate_name: "aconfig_test_rust_library",
aconfig_declarations: "aconfig.test.flags",
+ host_supported: true,
}
rust_test {
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 797a893..496876e 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -280,10 +280,11 @@
caches: Vec<Input>,
container: &str,
file: &StorageFileType,
+ version: u32,
) -> Result<Vec<u8>> {
let parsed_flags_vec: Vec<ProtoParsedFlags> =
caches.into_iter().map(|mut input| input.try_parse_flags()).collect::<Result<Vec<_>>>()?;
- generate_storage_file(container, parsed_flags_vec.iter(), file)
+ generate_storage_file(container, parsed_flags_vec.iter(), file, version)
}
pub fn create_device_config_defaults(mut input: Input) -> Result<Vec<u8>> {
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index 1fb64f9..edb4fd3 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -16,6 +16,8 @@
//! `aconfig` is a build time tool to manage build time configurations, such as feature flags.
+use aconfig_storage_file::DEFAULT_FILE_VERSION;
+use aconfig_storage_file::MAX_SUPPORTED_FILE_VERSION;
use anyhow::{anyhow, bail, Context, Result};
use clap::{builder::ArgAction, builder::EnumValueParser, Arg, ArgMatches, Command};
use core::any::Any;
@@ -159,7 +161,13 @@
.value_parser(|s: &str| StorageFileType::try_from(s)),
)
.arg(Arg::new("cache").long("cache").action(ArgAction::Append).required(true))
- .arg(Arg::new("out").long("out").required(true)),
+ .arg(Arg::new("out").long("out").required(true))
+ .arg(
+ Arg::new("version")
+ .long("version")
+ .required(false)
+ .value_parser(|s: &str| s.parse::<u32>()),
+ ),
)
}
@@ -309,12 +317,18 @@
write_output_to_file_or_stdout(path, &output)?;
}
Some(("create-storage", sub_matches)) => {
+ let version =
+ get_optional_arg::<u32>(sub_matches, "version").unwrap_or(&DEFAULT_FILE_VERSION);
+ if *version > MAX_SUPPORTED_FILE_VERSION {
+ bail!("Invalid version selected ({})", version);
+ }
let file = get_required_arg::<StorageFileType>(sub_matches, "file")
.context("Invalid storage file selection")?;
let cache = open_zero_or_more_files(sub_matches, "cache")?;
let container = get_required_arg::<String>(sub_matches, "container")?;
let path = get_required_arg::<String>(sub_matches, "out")?;
- let output = commands::create_storage(cache, container, file)
+
+ let output = commands::create_storage(cache, container, file, *version)
.context("failed to create storage files")?;
write_output_to_file_or_stdout(path, &output)?;
}
diff --git a/tools/aconfig/aconfig/src/storage/flag_info.rs b/tools/aconfig/aconfig/src/storage/flag_info.rs
index 04e2b93..2532609 100644
--- a/tools/aconfig/aconfig/src/storage/flag_info.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_info.rs
@@ -17,14 +17,12 @@
use crate::commands::assign_flag_ids;
use crate::storage::FlagPackage;
use aconfig_protos::ProtoFlagPermission;
-use aconfig_storage_file::{
- FlagInfoHeader, FlagInfoList, FlagInfoNode, StorageFileType, FILE_VERSION,
-};
+use aconfig_storage_file::{FlagInfoHeader, FlagInfoList, FlagInfoNode, StorageFileType};
use anyhow::{anyhow, Result};
-fn new_header(container: &str, num_flags: u32) -> FlagInfoHeader {
+fn new_header(container: &str, num_flags: u32, version: u32) -> FlagInfoHeader {
FlagInfoHeader {
- version: FILE_VERSION,
+ version,
container: String::from(container),
file_type: StorageFileType::FlagInfo as u8,
file_size: 0,
@@ -33,7 +31,11 @@
}
}
-pub fn create_flag_info(container: &str, packages: &[FlagPackage]) -> Result<FlagInfoList> {
+pub fn create_flag_info(
+ container: &str,
+ packages: &[FlagPackage],
+ version: u32,
+) -> Result<FlagInfoList> {
// create list
let num_flags = packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
@@ -51,7 +53,7 @@
}
let mut list = FlagInfoList {
- header: new_header(container, num_flags),
+ header: new_header(container, num_flags, version),
nodes: is_flag_rw.iter().map(|&rw| FlagInfoNode::create(rw)).collect(),
};
@@ -67,11 +69,12 @@
mod tests {
use super::*;
use crate::storage::{group_flags_by_package, tests::parse_all_test_flags};
+ use aconfig_storage_file::DEFAULT_FILE_VERSION;
pub fn create_test_flag_info_list_from_source() -> Result<FlagInfoList> {
let caches = parse_all_test_flags();
let packages = group_flags_by_package(caches.iter());
- create_flag_info("mockup", &packages)
+ create_flag_info("mockup", &packages, DEFAULT_FILE_VERSION)
}
#[test]
diff --git a/tools/aconfig/aconfig/src/storage/flag_table.rs b/tools/aconfig/aconfig/src/storage/flag_table.rs
index a971211..6046d7e 100644
--- a/tools/aconfig/aconfig/src/storage/flag_table.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_table.rs
@@ -19,13 +19,12 @@
use aconfig_protos::ProtoFlagPermission;
use aconfig_storage_file::{
get_table_size, FlagTable, FlagTableHeader, FlagTableNode, StorageFileType, StoredFlagType,
- FILE_VERSION,
};
use anyhow::{anyhow, Result};
-fn new_header(container: &str, num_flags: u32) -> FlagTableHeader {
+fn new_header(container: &str, num_flags: u32, version: u32) -> FlagTableHeader {
FlagTableHeader {
- version: FILE_VERSION,
+ version,
container: String::from(container),
file_type: StorageFileType::FlagMap as u8,
file_size: 0,
@@ -86,12 +85,16 @@
}
}
-pub fn create_flag_table(container: &str, packages: &[FlagPackage]) -> Result<FlagTable> {
+pub fn create_flag_table(
+ container: &str,
+ packages: &[FlagPackage],
+ version: u32,
+) -> Result<FlagTable> {
// create table
let num_flags = packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
let num_buckets = get_table_size(num_flags)?;
- let mut header = new_header(container, num_flags);
+ let mut header = new_header(container, num_flags, version);
let mut buckets = vec![None; num_buckets as usize];
let mut node_wrappers = packages
.iter()
@@ -138,13 +141,15 @@
#[cfg(test)]
mod tests {
+ use aconfig_storage_file::DEFAULT_FILE_VERSION;
+
use super::*;
use crate::storage::{group_flags_by_package, tests::parse_all_test_flags};
fn create_test_flag_table_from_source() -> Result<FlagTable> {
let caches = parse_all_test_flags();
let packages = group_flags_by_package(caches.iter());
- create_flag_table("mockup", &packages)
+ create_flag_table("mockup", &packages, DEFAULT_FILE_VERSION)
}
#[test]
diff --git a/tools/aconfig/aconfig/src/storage/flag_value.rs b/tools/aconfig/aconfig/src/storage/flag_value.rs
index c15ba54..6a655b9 100644
--- a/tools/aconfig/aconfig/src/storage/flag_value.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_value.rs
@@ -17,12 +17,12 @@
use crate::commands::assign_flag_ids;
use crate::storage::FlagPackage;
use aconfig_protos::ProtoFlagState;
-use aconfig_storage_file::{FlagValueHeader, FlagValueList, StorageFileType, FILE_VERSION};
+use aconfig_storage_file::{FlagValueHeader, FlagValueList, StorageFileType};
use anyhow::{anyhow, Result};
-fn new_header(container: &str, num_flags: u32) -> FlagValueHeader {
+fn new_header(container: &str, num_flags: u32, version: u32) -> FlagValueHeader {
FlagValueHeader {
- version: FILE_VERSION,
+ version,
container: String::from(container),
file_type: StorageFileType::FlagVal as u8,
file_size: 0,
@@ -31,12 +31,16 @@
}
}
-pub fn create_flag_value(container: &str, packages: &[FlagPackage]) -> Result<FlagValueList> {
+pub fn create_flag_value(
+ container: &str,
+ packages: &[FlagPackage],
+ version: u32,
+) -> Result<FlagValueList> {
// create list
let num_flags = packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
let mut list = FlagValueList {
- header: new_header(container, num_flags),
+ header: new_header(container, num_flags, version),
booleans: vec![false; num_flags as usize],
};
@@ -61,13 +65,15 @@
#[cfg(test)]
mod tests {
+ use aconfig_storage_file::DEFAULT_FILE_VERSION;
+
use super::*;
use crate::storage::{group_flags_by_package, tests::parse_all_test_flags};
pub fn create_test_flag_value_list_from_source() -> Result<FlagValueList> {
let caches = parse_all_test_flags();
let packages = group_flags_by_package(caches.iter());
- create_flag_value("mockup", &packages)
+ create_flag_value("mockup", &packages, DEFAULT_FILE_VERSION)
}
#[test]
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index 1d8dcfc..9e5dad5 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -88,6 +88,7 @@
container: &str,
parsed_flags_vec_iter: I,
file: &StorageFileType,
+ version: u32,
) -> Result<Vec<u8>>
where
I: Iterator<Item = &'a ProtoParsedFlags>,
@@ -96,19 +97,19 @@
match file {
StorageFileType::PackageMap => {
- let package_table = create_package_table(container, &packages)?;
+ let package_table = create_package_table(container, &packages, version)?;
Ok(package_table.into_bytes())
}
StorageFileType::FlagMap => {
- let flag_table = create_flag_table(container, &packages)?;
+ let flag_table = create_flag_table(container, &packages, version)?;
Ok(flag_table.into_bytes())
}
StorageFileType::FlagVal => {
- let flag_value = create_flag_value(container, &packages)?;
+ let flag_value = create_flag_value(container, &packages, version)?;
Ok(flag_value.into_bytes())
}
StorageFileType::FlagInfo => {
- let flag_info = create_flag_info(container, &packages)?;
+ let flag_info = create_flag_info(container, &packages, version)?;
Ok(flag_info.into_bytes())
}
}
diff --git a/tools/aconfig/aconfig/src/storage/package_table.rs b/tools/aconfig/aconfig/src/storage/package_table.rs
index c53602f..56559f8 100644
--- a/tools/aconfig/aconfig/src/storage/package_table.rs
+++ b/tools/aconfig/aconfig/src/storage/package_table.rs
@@ -18,14 +18,13 @@
use aconfig_storage_file::{
get_table_size, PackageTable, PackageTableHeader, PackageTableNode, StorageFileType,
- FILE_VERSION,
};
use crate::storage::FlagPackage;
-fn new_header(container: &str, num_packages: u32) -> PackageTableHeader {
+fn new_header(container: &str, num_packages: u32, version: u32) -> PackageTableHeader {
PackageTableHeader {
- version: FILE_VERSION,
+ version,
container: String::from(container),
file_type: StorageFileType::PackageMap as u8,
file_size: 0,
@@ -56,20 +55,26 @@
}
}
-pub fn create_package_table(container: &str, packages: &[FlagPackage]) -> Result<PackageTable> {
+pub fn create_package_table(
+ container: &str,
+ packages: &[FlagPackage],
+ version: u32,
+) -> Result<PackageTable> {
// create table
let num_packages = packages.len() as u32;
let num_buckets = get_table_size(num_packages)?;
- let mut header = new_header(container, num_packages);
+ let mut header = new_header(container, num_packages, version);
let mut buckets = vec![None; num_buckets as usize];
- let mut node_wrappers: Vec<_> =
- packages.iter().map(|pkg| PackageTableNodeWrapper::new(pkg, num_buckets)).collect();
+ let mut node_wrappers: Vec<_> = packages
+ .iter()
+ .map(|pkg: &FlagPackage<'_>| PackageTableNodeWrapper::new(pkg, num_buckets))
+ .collect();
// initialize all header fields
header.bucket_offset = header.into_bytes().len() as u32;
header.node_offset = header.bucket_offset + num_buckets * 4;
header.file_size = header.node_offset
- + node_wrappers.iter().map(|x| x.node.into_bytes().len()).sum::<usize>() as u32;
+ + node_wrappers.iter().map(|x| x.node.into_bytes(version).len()).sum::<usize>() as u32;
// sort node_wrappers by bucket index for efficiency
node_wrappers.sort_by(|a, b| a.bucket_index.cmp(&b.bucket_index));
@@ -87,7 +92,7 @@
if buckets[node_bucket_idx as usize].is_none() {
buckets[node_bucket_idx as usize] = Some(offset);
}
- offset += node_wrappers[i].node.into_bytes().len() as u32;
+ offset += node_wrappers[i].node.into_bytes(version).len() as u32;
if let Some(index) = next_node_bucket_idx {
if index == node_bucket_idx {
@@ -106,13 +111,15 @@
#[cfg(test)]
mod tests {
+ use aconfig_storage_file::DEFAULT_FILE_VERSION;
+
use super::*;
use crate::storage::{group_flags_by_package, tests::parse_all_test_flags};
pub fn create_test_package_table_from_source() -> Result<PackageTable> {
let caches = parse_all_test_flags();
let packages = group_flags_by_package(caches.iter());
- create_package_table("mockup", &packages)
+ create_package_table("mockup", &packages, DEFAULT_FILE_VERSION)
}
#[test]
diff --git a/tools/aconfig/aconfig_device_paths/Android.bp b/tools/aconfig/aconfig_device_paths/Android.bp
index dda7a55..bdf96ed 100644
--- a/tools/aconfig/aconfig_device_paths/Android.bp
+++ b/tools/aconfig/aconfig_device_paths/Android.bp
@@ -61,8 +61,12 @@
name: "libaconfig_java_host_device_paths_src",
srcs: ["src/HostDeviceProtosTemplate.java"],
out: ["HostDeviceProtos.java"],
- tool_files: ["partition_aconfig_flags_paths.txt"],
- cmd: "sed -e '/TEMPLATE/{r$(location partition_aconfig_flags_paths.txt)' -e 'd}' $(in) > $(out)",
+ tool_files: [
+ "partition_aconfig_flags_paths.txt",
+ "mainline_aconfig_flags_paths.txt",
+ ],
+ cmd: "sed -e '/TEMPLATE/{r$(location partition_aconfig_flags_paths.txt)' -e 'd}' $(in) > $(out).tmp && " +
+ "sed -e '/MAINLINE_T/{r$(location mainline_aconfig_flags_paths.txt)' -e 'd}' $(out).tmp > $(out)",
}
java_library_host {
diff --git a/tools/aconfig/aconfig_device_paths/mainline_aconfig_flags_paths.txt b/tools/aconfig/aconfig_device_paths/mainline_aconfig_flags_paths.txt
new file mode 100644
index 0000000..af73a84
--- /dev/null
+++ b/tools/aconfig/aconfig_device_paths/mainline_aconfig_flags_paths.txt
@@ -0,0 +1,20 @@
+"/apex/com.android.adservices/etc/aconfig_flags.pb",
+"/apex/com.android.appsearch/etc/aconfig_flags.pb",
+"/apex/com.android.art/etc/aconfig_flags.pb",
+"/apex/com.android.btservices/etc/aconfig_flags.pb",
+"/apex/com.android.cellbroadcast/etc/aconfig_flags.pb",
+"/apex/com.android.configinfrastructure/etc/aconfig_flags.pb",
+"/apex/com.android.conscrypt/etc/aconfig_flags.pb",
+"/apex/com.android.devicelock/etc/aconfig_flags.pb",
+"/apex/com.android.healthfitness/etc/aconfig_flags.pb",
+"/apex/com.android.ipsec/etc/aconfig_flags.pb",
+"/apex/com.android.media/etc/aconfig_flags.pb",
+"/apex/com.android.mediaprovider/etc/aconfig_flags.pb",
+"/apex/com.android.ondevicepersonalization/etc/aconfig_flags.pb",
+"/apex/com.android.os.statsd/etc/aconfig_flags.pb",
+"/apex/com.android.permission/etc/aconfig_flags.pb",
+"/apex/com.android.profiling/etc/aconfig_flags.pb",
+"/apex/com.android.tethering/etc/aconfig_flags.pb",
+"/apex/com.android.uwb/etc/aconfig_flags.pb",
+"/apex/com.android.virt/etc/aconfig_flags.pb",
+"/apex/com.android.wifi/etc/aconfig_flags.pb",
diff --git a/tools/aconfig/aconfig_device_paths/src/HostDeviceProtosTemplate.java b/tools/aconfig/aconfig_device_paths/src/HostDeviceProtosTemplate.java
index e2ad40a..e7d0a76 100644
--- a/tools/aconfig/aconfig_device_paths/src/HostDeviceProtosTemplate.java
+++ b/tools/aconfig/aconfig_device_paths/src/HostDeviceProtosTemplate.java
@@ -40,6 +40,10 @@
TEMPLATE
};
+ static final String[] MAINLINE_PATHS = {
+ MAINLINE_T
+ };
+
private static final String APEX_DIR = "/apex";
private static final String RECURSIVELY_LIST_APEX_DIR_COMMAND =
"shell su 0 find /apex | grep aconfig_flags";
@@ -55,7 +59,8 @@
String adbCommandOutput = adbCommandExecutor.executeAdbCommand(
RECURSIVELY_LIST_APEX_DIR_COMMAND);
- if (adbCommandOutput == null) {
+ if (adbCommandOutput == null || adbCommandOutput.isEmpty()) {
+ paths.addAll(Arrays.asList(MAINLINE_PATHS));
return paths;
}
diff --git a/tools/aconfig/aconfig_flags/Android.bp b/tools/aconfig/aconfig_flags/Android.bp
index e327ced..4c1fd4e 100644
--- a/tools/aconfig/aconfig_flags/Android.bp
+++ b/tools/aconfig/aconfig_flags/Android.bp
@@ -44,3 +44,8 @@
name: "libaconfig_flags_cc",
aconfig_declarations: "aconfig_flags",
}
+
+java_aconfig_library {
+ name: "aconfig_flags_java",
+ aconfig_declarations: "aconfig_flags",
+}
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index cf52bc0..1d92ba4 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -57,8 +57,13 @@
BytesParseFail, HashTableSizeLimit, InvalidFlagValueType, InvalidStoredFlagType,
};
-/// Storage file version
-pub const FILE_VERSION: u32 = 1;
+/// The max storage file version from which we can safely read/write. May be
+/// experimental.
+pub const MAX_SUPPORTED_FILE_VERSION: u32 = 2;
+
+/// The newest fully-released version. Unless otherwise specified, this is the
+/// version we will write.
+pub const DEFAULT_FILE_VERSION: u32 = 1;
/// Good hash table prime number
pub(crate) const HASH_PRIMES: [u32; 29] = [
@@ -244,6 +249,11 @@
Ok(val)
}
+/// Read and parse the first 4 bytes of buf as u32.
+pub fn read_u32_from_start_of_bytes(buf: &[u8]) -> Result<u32, AconfigStorageError> {
+ read_u32_from_bytes(buf, &mut 0)
+}
+
/// Read and parse bytes as u32
pub fn read_u32_from_bytes(buf: &[u8], head: &mut usize) -> Result<u32, AconfigStorageError> {
let val =
@@ -254,6 +264,16 @@
Ok(val)
}
+// Read and parse bytes as u64
+pub fn read_u64_from_bytes(buf: &[u8], head: &mut usize) -> Result<u64, AconfigStorageError> {
+ let val =
+ u64::from_le_bytes(buf[*head..*head + 8].try_into().map_err(|errmsg| {
+ BytesParseFail(anyhow!("fail to parse u64 from bytes: {}", errmsg))
+ })?);
+ *head += 8;
+ Ok(val)
+}
+
/// Read and parse bytes as string
pub(crate) fn read_str_from_bytes(
buf: &[u8],
diff --git a/tools/aconfig/aconfig_storage_file/src/package_table.rs b/tools/aconfig/aconfig_storage_file/src/package_table.rs
index a5bd9e6..af39fbc 100644
--- a/tools/aconfig/aconfig_storage_file/src/package_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/package_table.rs
@@ -17,7 +17,10 @@
//! package table module defines the package table file format and methods for serialization
//! and deserialization
-use crate::{get_bucket_index, read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
+use crate::{
+ get_bucket_index, read_str_from_bytes, read_u32_from_bytes, read_u64_from_bytes,
+ read_u8_from_bytes,
+};
use crate::{AconfigStorageError, StorageFileType};
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
@@ -117,7 +120,16 @@
impl PackageTableNode {
/// Serialize to bytes
- pub fn into_bytes(&self) -> Vec<u8> {
+ pub fn into_bytes(&self, version: u32) -> Vec<u8> {
+ match version {
+ 1 => Self::into_bytes_v1(self),
+ 2 => Self::into_bytes_v2(self),
+ // TODO(b/316357686): into_bytes should return a Result.
+ _ => Self::into_bytes_v2(&self),
+ }
+ }
+
+ fn into_bytes_v1(&self) -> Vec<u8> {
let mut result = Vec::new();
let name_bytes = self.package_name.as_bytes();
result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
@@ -128,18 +140,64 @@
result
}
- /// Deserialize from bytes
- pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
+ fn into_bytes_v2(&self) -> Vec<u8> {
+ let mut result = Vec::new();
+ let name_bytes = self.package_name.as_bytes();
+ result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
+ result.extend_from_slice(name_bytes);
+ result.extend_from_slice(&self.package_id.to_le_bytes());
+ // V2 storage files have a fingerprint. Current struct (v1) does not, so
+ // we write 0.
+ result.extend_from_slice(&0u64.to_le_bytes());
+ result.extend_from_slice(&self.boolean_start_index.to_le_bytes());
+ result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
+ result
+ }
+
+ /// Deserialize from bytes based on file version.
+ pub fn from_bytes(bytes: &[u8], version: u32) -> Result<Self, AconfigStorageError> {
+ match version {
+ 1 => Self::from_bytes_v1(bytes),
+ 2 => Self::from_bytes_v2(bytes),
+ _ => {
+ return Err(AconfigStorageError::BytesParseFail(anyhow!(
+ "Binary file is an unsupported version: {}",
+ version
+ )))
+ }
+ }
+ }
+
+ fn from_bytes_v1(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
let mut head = 0;
- let node = Self {
- package_name: read_str_from_bytes(bytes, &mut head)?,
- package_id: read_u32_from_bytes(bytes, &mut head)?,
- boolean_start_index: read_u32_from_bytes(bytes, &mut head)?,
- next_offset: match read_u32_from_bytes(bytes, &mut head)? {
- 0 => None,
- val => Some(val),
- },
+ let package_name = read_str_from_bytes(bytes, &mut head)?;
+ let package_id = read_u32_from_bytes(bytes, &mut head)?;
+ let boolean_start_index = read_u32_from_bytes(bytes, &mut head)?;
+ let next_offset = match read_u32_from_bytes(bytes, &mut head)? {
+ 0 => None,
+ val => Some(val),
};
+
+ let node = Self { package_name, package_id, boolean_start_index, next_offset };
+ Ok(node)
+ }
+
+ fn from_bytes_v2(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
+ let mut head = 0;
+ let package_name = read_str_from_bytes(bytes, &mut head)?;
+ let package_id = read_u32_from_bytes(bytes, &mut head)?;
+
+ // Fingerprint is unused in the current struct (v1), but we need to read
+ // the bytes if the storage file type is v2 or else the subsequent
+ // fields will be inaccurate.
+ let _fingerprint = read_u64_from_bytes(bytes, &mut head)?;
+ let boolean_start_index = read_u32_from_bytes(bytes, &mut head)?;
+ let next_offset = match read_u32_from_bytes(bytes, &mut head)? {
+ 0 => None,
+ val => Some(val),
+ };
+
+ let node = Self { package_name, package_id, boolean_start_index, next_offset };
Ok(node)
}
@@ -180,7 +238,11 @@
[
self.header.into_bytes(),
self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(),
- self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
+ self.nodes
+ .iter()
+ .map(|v| v.into_bytes(self.header.version))
+ .collect::<Vec<_>>()
+ .concat(),
]
.concat()
}
@@ -199,8 +261,8 @@
.collect();
let nodes = (0..num_packages)
.map(|_| {
- let node = PackageTableNode::from_bytes(&bytes[head..])?;
- head += node.into_bytes().len();
+ let node = PackageTableNode::from_bytes(&bytes[head..], header.version)?;
+ head += node.into_bytes(header.version).len();
Ok(node)
})
.collect::<Result<Vec<_>, AconfigStorageError>>()
@@ -219,7 +281,8 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::test_utils::create_test_package_table;
+ use crate::read_u32_from_start_of_bytes;
+ use crate::{test_utils::create_test_package_table, DEFAULT_FILE_VERSION};
#[test]
// this test point locks down the table serialization
@@ -232,7 +295,9 @@
let nodes: &Vec<PackageTableNode> = &package_table.nodes;
for node in nodes.iter() {
- let reinterpreted_node = PackageTableNode::from_bytes(&node.into_bytes()).unwrap();
+ let reinterpreted_node =
+ PackageTableNode::from_bytes(&node.into_bytes(header.version), header.version)
+ .unwrap();
assert_eq!(node, &reinterpreted_node);
}
@@ -249,9 +314,36 @@
fn test_version_number() {
let package_table = create_test_package_table();
let bytes = &package_table.into_bytes();
- let mut head = 0;
- let version = read_u32_from_bytes(bytes, &mut head).unwrap();
- assert_eq!(version, 1);
+ let version = read_u32_from_start_of_bytes(bytes).unwrap();
+ assert_eq!(version, DEFAULT_FILE_VERSION);
+ }
+
+ #[test]
+ fn test_round_trip_v1() {
+ let table_v1: PackageTable = create_test_package_table();
+ let table_bytes_v1 = table_v1.into_bytes();
+
+ // Will automatically read from version 2 as the version code is encoded
+ // into the bytes.
+ let reinterpreted_table = PackageTable::from_bytes(&table_bytes_v1).unwrap();
+
+ assert_eq!(table_v1, reinterpreted_table);
+ }
+
+ #[test]
+ fn test_round_trip_v2() {
+ // Have to fake v2 because though we will set the version to v2
+ // and write the bytes as v2, we don't have the ability to actually set
+ // the fingerprint yet.
+ let mut fake_table_v2 = create_test_package_table();
+ fake_table_v2.header.version = 2;
+ let table_bytes_v2 = fake_table_v2.into_bytes();
+
+ // Will automatically read from version 2 as the version code is encoded
+ // into the bytes.
+ let reinterpreted_table = PackageTable::from_bytes(&table_bytes_v2).unwrap();
+
+ assert_eq!(fake_table_v2, reinterpreted_table);
}
#[test]
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
index 106666c..5c364f6 100644
--- a/tools/aconfig/aconfig_storage_file/src/test_utils.rs
+++ b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
@@ -18,7 +18,7 @@
use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
use crate::flag_value::{FlagValueHeader, FlagValueList};
use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
-use crate::{AconfigStorageError, StorageFileType, StoredFlagType};
+use crate::{AconfigStorageError, StorageFileType, StoredFlagType, DEFAULT_FILE_VERSION};
use anyhow::anyhow;
use std::io::Write;
@@ -26,7 +26,7 @@
pub fn create_test_package_table() -> PackageTable {
let header = PackageTableHeader {
- version: 1,
+ version: DEFAULT_FILE_VERSION,
container: String::from("mockup"),
file_type: StorageFileType::PackageMap as u8,
file_size: 209,
@@ -78,7 +78,7 @@
pub fn create_test_flag_table() -> FlagTable {
let header = FlagTableHeader {
- version: 1,
+ version: DEFAULT_FILE_VERSION,
container: String::from("mockup"),
file_type: StorageFileType::FlagMap as u8,
file_size: 321,
@@ -120,7 +120,7 @@
pub fn create_test_flag_value_list() -> FlagValueList {
let header = FlagValueHeader {
- version: 1,
+ version: DEFAULT_FILE_VERSION,
container: String::from("mockup"),
file_type: StorageFileType::FlagVal as u8,
file_size: 35,
@@ -133,7 +133,7 @@
pub fn create_test_flag_info_list() -> FlagInfoList {
let header = FlagInfoHeader {
- version: 1,
+ version: DEFAULT_FILE_VERSION,
container: String::from("mockup"),
file_type: StorageFileType::FlagInfo as u8,
file_size: 35,
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
index dc1c583..39b7e59 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
@@ -50,7 +50,7 @@
while (nodeIndex != -1) {
mReader.position(nodeIndex);
- Node node = Node.fromBytes(mReader);
+ Node node = Node.fromBytes(mReader, mHeader.mVersion);
if (Objects.equals(packageName, node.mPackageName)) {
return node;
}
@@ -74,7 +74,7 @@
private int mBucketOffset;
private int mNodeOffset;
- public static Header fromBytes(ByteBufferReader reader) {
+ private static Header fromBytes(ByteBufferReader reader) {
Header header = new Header();
header.mVersion = reader.readInt();
header.mContainer = reader.readString();
@@ -127,7 +127,29 @@
private int mBooleanStartIndex;
private int mNextOffset;
- public static Node fromBytes(ByteBufferReader reader) {
+ private static Node fromBytes(ByteBufferReader reader, int version) {
+ switch (version) {
+ case 1:
+ return fromBytesV1(reader);
+ case 2:
+ return fromBytesV2(reader);
+ default:
+ // Do we want to throw here?
+ return new Node();
+ }
+ }
+
+ private static Node fromBytesV1(ByteBufferReader reader) {
+ Node node = new Node();
+ node.mPackageName = reader.readString();
+ node.mPackageId = reader.readInt();
+ node.mBooleanStartIndex = reader.readInt();
+ node.mNextOffset = reader.readInt();
+ node.mNextOffset = node.mNextOffset == 0 ? -1 : node.mNextOffset;
+ return node;
+ }
+
+ private static Node fromBytesV2(ByteBufferReader reader) {
Node node = new Node();
node.mPackageName = reader.readString();
node.mPackageId = reader.readInt();
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
index 6d03377..fe57a6d 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
@@ -16,8 +16,10 @@
//! flag value query module defines the flag value file read from mapped bytes
-use crate::{AconfigStorageError, FILE_VERSION};
-use aconfig_storage_file::{flag_info::FlagInfoHeader, read_u8_from_bytes, FlagValueType};
+use crate::AconfigStorageError;
+use aconfig_storage_file::{
+ flag_info::FlagInfoHeader, read_u8_from_bytes, FlagValueType, MAX_SUPPORTED_FILE_VERSION,
+};
use anyhow::anyhow;
/// Get flag attribute bitfield
@@ -27,11 +29,11 @@
flag_index: u32,
) -> Result<u8, AconfigStorageError> {
let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
- if interpreted_header.version > crate::FILE_VERSION {
+ if interpreted_header.version > MAX_SUPPORTED_FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
"Cannot read storage file with a higher version of {} with lib version {}",
interpreted_header.version,
- FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION
)));
}
@@ -108,15 +110,15 @@
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
let mut info_list = create_test_flag_info_list();
- info_list.header.version = crate::FILE_VERSION + 1;
+ info_list.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let flag_info = info_list.into_bytes();
let error = find_flag_attribute(&flag_info[..], FlagValueType::Boolean, 4).unwrap_err();
assert_eq!(
format!("{:?}", error),
format!(
"HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
- crate::FILE_VERSION + 1,
- crate::FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION + 1,
+ MAX_SUPPORTED_FILE_VERSION
)
);
}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
index a1a4793..e9bc604 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
@@ -16,9 +16,10 @@
//! flag table query module defines the flag table file read from mapped bytes
-use crate::{AconfigStorageError, FILE_VERSION};
+use crate::AconfigStorageError;
use aconfig_storage_file::{
flag_table::FlagTableHeader, flag_table::FlagTableNode, read_u32_from_bytes, StoredFlagType,
+ MAX_SUPPORTED_FILE_VERSION,
};
use anyhow::anyhow;
@@ -36,11 +37,11 @@
flag: &str,
) -> Result<Option<FlagReadContext>, AconfigStorageError> {
let interpreted_header = FlagTableHeader::from_bytes(buf)?;
- if interpreted_header.version > crate::FILE_VERSION {
+ if interpreted_header.version > MAX_SUPPORTED_FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
"Cannot read storage file with a higher version of {} with lib version {}",
interpreted_header.version,
- FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION
)));
}
@@ -111,15 +112,15 @@
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
let mut table = create_test_flag_table();
- table.header.version = crate::FILE_VERSION + 1;
+ table.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let flag_table = table.into_bytes();
let error = find_flag_read_context(&flag_table[..], 0, "enabled_ro").unwrap_err();
assert_eq!(
format!("{:?}", error),
format!(
"HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
- crate::FILE_VERSION + 1,
- crate::FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION + 1,
+ MAX_SUPPORTED_FILE_VERSION
)
);
}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
index 9d32a16..12c1e83 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
@@ -16,18 +16,20 @@
//! flag value query module defines the flag value file read from mapped bytes
-use crate::{AconfigStorageError, FILE_VERSION};
-use aconfig_storage_file::{flag_value::FlagValueHeader, read_u8_from_bytes};
+use crate::AconfigStorageError;
+use aconfig_storage_file::{
+ flag_value::FlagValueHeader, read_u8_from_bytes, MAX_SUPPORTED_FILE_VERSION,
+};
use anyhow::anyhow;
/// Query flag value
pub fn find_boolean_flag_value(buf: &[u8], flag_index: u32) -> Result<bool, AconfigStorageError> {
let interpreted_header = FlagValueHeader::from_bytes(buf)?;
- if interpreted_header.version > crate::FILE_VERSION {
+ if interpreted_header.version > MAX_SUPPORTED_FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
"Cannot read storage file with a higher version of {} with lib version {}",
interpreted_header.version,
- FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION
)));
}
@@ -74,15 +76,15 @@
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
let mut value_list = create_test_flag_value_list();
- value_list.header.version = crate::FILE_VERSION + 1;
+ value_list.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let flag_value = value_list.into_bytes();
let error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
assert_eq!(
format!("{:?}", error),
format!(
"HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
- crate::FILE_VERSION + 1,
- crate::FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION + 1,
+ MAX_SUPPORTED_FILE_VERSION
)
);
}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
index d76cf3f..988ce63 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
@@ -46,7 +46,7 @@
pub use flag_table_query::FlagReadContext;
pub use package_table_query::PackageReadContext;
-use aconfig_storage_file::{read_u32_from_bytes, FILE_VERSION};
+use aconfig_storage_file::read_u32_from_bytes;
use flag_info_query::find_flag_attribute;
use flag_table_query::find_flag_read_context;
use flag_value_query::find_boolean_flag_value;
diff --git a/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
index 2cb854b..acb60f6 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
@@ -16,9 +16,10 @@
//! package table query module defines the package table file read from mapped bytes
-use crate::{AconfigStorageError, FILE_VERSION};
+use crate::AconfigStorageError;
use aconfig_storage_file::{
package_table::PackageTableHeader, package_table::PackageTableNode, read_u32_from_bytes,
+ MAX_SUPPORTED_FILE_VERSION,
};
use anyhow::anyhow;
@@ -35,11 +36,11 @@
package: &str,
) -> Result<Option<PackageReadContext>, AconfigStorageError> {
let interpreted_header = PackageTableHeader::from_bytes(buf)?;
- if interpreted_header.version > FILE_VERSION {
+ if interpreted_header.version > MAX_SUPPORTED_FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
"Cannot read storage file with a higher version of {} with lib version {}",
interpreted_header.version,
- FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION
)));
}
@@ -55,7 +56,8 @@
}
loop {
- let interpreted_node = PackageTableNode::from_bytes(&buf[package_node_offset..])?;
+ let interpreted_node =
+ PackageTableNode::from_bytes(&buf[package_node_offset..], interpreted_header.version)?;
if interpreted_node.package_name == package {
return Ok(Some(PackageReadContext {
package_id: interpreted_node.package_id,
@@ -118,7 +120,7 @@
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
let mut table = create_test_package_table();
- table.header.version = crate::FILE_VERSION + 1;
+ table.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let package_table = table.into_bytes();
let error =
find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
@@ -127,8 +129,8 @@
format!("{:?}", error),
format!(
"HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
- crate::FILE_VERSION + 1,
- crate::FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION + 1,
+ MAX_SUPPORTED_FILE_VERSION
)
);
}
diff --git a/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs b/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs
index 7e60713..5640922 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs
@@ -18,7 +18,7 @@
use aconfig_storage_file::{
read_u8_from_bytes, AconfigStorageError, FlagInfoBit, FlagInfoHeader, FlagValueType,
- FILE_VERSION,
+ MAX_SUPPORTED_FILE_VERSION,
};
use anyhow::anyhow;
@@ -28,11 +28,11 @@
flag_index: u32,
) -> Result<usize, AconfigStorageError> {
let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
- if interpreted_header.version > FILE_VERSION {
+ if interpreted_header.version > MAX_SUPPORTED_FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
"Cannot write to storage file with a higher version of {} with lib version {}",
interpreted_header.version,
- FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION
)));
}
diff --git a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
index dd15c99..06a9b15 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
@@ -16,7 +16,7 @@
//! flag value update module defines the flag value file write to mapped bytes
-use aconfig_storage_file::{AconfigStorageError, FlagValueHeader, FILE_VERSION};
+use aconfig_storage_file::{AconfigStorageError, FlagValueHeader, MAX_SUPPORTED_FILE_VERSION};
use anyhow::anyhow;
/// Set flag value
@@ -26,11 +26,11 @@
flag_value: bool,
) -> Result<usize, AconfigStorageError> {
let interpreted_header = FlagValueHeader::from_bytes(buf)?;
- if interpreted_header.version > FILE_VERSION {
+ if interpreted_header.version > MAX_SUPPORTED_FILE_VERSION {
return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
"Cannot write to storage file with a higher version of {} with lib version {}",
interpreted_header.version,
- FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION
)));
}
@@ -84,15 +84,15 @@
// this test point locks down query error when file has a higher version
fn test_higher_version_storage_file() {
let mut value_list = create_test_flag_value_list();
- value_list.header.version = FILE_VERSION + 1;
+ value_list.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
let mut flag_value = value_list.into_bytes();
let error = update_boolean_flag_value(&mut flag_value[..], 4, true).unwrap_err();
assert_eq!(
format!("{:?}", error),
format!(
"HigherStorageFileVersion(Cannot write to storage file with a higher version of {} with lib version {})",
- FILE_VERSION + 1,
- FILE_VERSION
+ MAX_SUPPORTED_FILE_VERSION + 1,
+ MAX_SUPPORTED_FILE_VERSION
)
);
}
diff --git a/tools/aconfig/aflags/Android.bp b/tools/aconfig/aflags/Android.bp
index 2040cc6..a7aceee 100644
--- a/tools/aconfig/aflags/Android.bp
+++ b/tools/aconfig/aflags/Android.bp
@@ -12,7 +12,7 @@
"libaconfig_device_paths",
"libaconfig_flags",
"libaconfig_protos",
- "libaconfigd_protos",
+ "libaconfigd_protos_rust",
"libaconfig_storage_read_api",
"libaconfig_storage_file",
"libanyhow",
@@ -20,6 +20,10 @@
"libnix",
"libprotobuf",
"libregex",
+ // TODO: b/371021174 remove this fake dependency once we find a proper strategy to
+ // deal with test aconfig libs are not present in storage because they are never used
+ // by the actual build
+ "libaconfig_test_rust_library",
],
}
diff --git a/tools/edit_monitor/Android.bp b/tools/edit_monitor/Android.bp
index b939633..3497821 100644
--- a/tools/edit_monitor/Android.bp
+++ b/tools/edit_monitor/Android.bp
@@ -21,6 +21,16 @@
}
python_library_host {
+ name: "edit_event_proto",
+ srcs: [
+ "proto/edit_event.proto",
+ ],
+ proto: {
+ canonical_path_from_root: false,
+ },
+}
+
+python_library_host {
name: "edit_monitor_lib",
pkg_path: "edit_monitor",
srcs: [
@@ -42,3 +52,15 @@
unit_test: true,
},
}
+
+python_binary_host {
+ name: "edit_monitor",
+ pkg_path: "edit_monitor",
+ srcs: [
+ "main.py",
+ ],
+ libs: [
+ "edit_monitor_lib",
+ ],
+ main: "main.py",
+}
diff --git a/tools/edit_monitor/daemon_manager.py b/tools/edit_monitor/daemon_manager.py
index 1876451..445d849 100644
--- a/tools/edit_monitor/daemon_manager.py
+++ b/tools/edit_monitor/daemon_manager.py
@@ -30,6 +30,7 @@
DEFAULT_MEMORY_USAGE_THRESHOLD = 2000
DEFAULT_CPU_USAGE_THRESHOLD = 200
DEFAULT_REBOOT_TIMEOUT_SECONDS = 60 * 60 * 24
+BLOCK_SIGN_FILE = "edit_monitor_block_sign"
def default_daemon_target():
@@ -59,15 +60,19 @@
pid_file_dir = pathlib.Path(tempfile.gettempdir()).joinpath("edit_monitor")
pid_file_dir.mkdir(parents=True, exist_ok=True)
self.pid_file_path = self._get_pid_file_path(pid_file_dir)
+ self.block_sign = pathlib.Path(tempfile.gettempdir()).joinpath(
+ BLOCK_SIGN_FILE
+ )
def start(self):
"""Writes the pidfile and starts the daemon proces."""
- try:
- self._stop_any_existing_instance()
- self._write_pid_to_pidfile()
- self._start_daemon_process()
- except Exception as e:
- logging.exception("Failed to start daemon manager with error %s", e)
+ if self.block_sign.exists():
+ logging.warning("Block sign found, exiting...")
+ return
+
+ self._stop_any_existing_instance()
+ self._write_pid_to_pidfile()
+ self._start_daemon_process()
def monitor_daemon(
self,
@@ -82,6 +87,9 @@
process is still running and kill the process if the resource usage is above
given thresholds.
"""
+ if not self.daemon_process:
+ return
+
logging.info("start monitoring daemon process %d.", self.daemon_process.pid)
reboot_time = time.time() + reboot_timeout
while self.daemon_process.is_alive():
@@ -150,6 +158,33 @@
logging.exception("Failed to reboot process with error: %s.", e)
sys.exit(1) # Indicate an error occurred
+ def cleanup(self):
+ """Wipes out all edit monitor instances in the system.
+
+ Stops all the existing edit monitor instances and place a block sign
+ to prevent any edit monitor process to start. This method is only used
+ in emergency case when there's something goes wrong with the edit monitor
+ that requires immediate cleanup to prevent damanger to the system.
+ """
+ logging.debug("Start cleaning up all existing instances.")
+
+ try:
+ # First places a block sign to prevent any edit monitor process to start.
+ self.block_sign.touch()
+ except (FileNotFoundError, PermissionError, OSError):
+ logging.exception("Failed to place the block sign")
+
+ # Finds and kills all the existing instances of edit monitor.
+ existing_instances_pids = self._find_all_instances_pids()
+ for pid in existing_instances_pids:
+ logging.info(
+ "Found existing edit monitor instance with pid %d, killing...", pid
+ )
+ try:
+ self._terminate_process(pid)
+ except Exception:
+ logging.exception("Failed to terminate process %d", pid)
+
def _stop_any_existing_instance(self):
if not self.pid_file_path.exists():
logging.debug("No existing instances.")
@@ -300,3 +335,15 @@
stime = int(stats[14])
return (utime + stime) / os.sysconf(os.sysconf_names["SC_CLK_TCK"])
+ def _find_all_instances_pids(self) -> list[int]:
+ pids = []
+
+ for file in os.listdir(self.pid_file_path.parent):
+ if file.endswith(".lock"):
+ try:
+ with open(self.pid_file_path.parent.joinpath(file), "r") as f:
+ pids.append(int(f.read().strip()))
+ except (FileNotFoundError, IOError, ValueError, TypeError):
+ logging.exception("Failed to get pid from file path: %s", file)
+
+ return pids
\ No newline at end of file
diff --git a/tools/edit_monitor/daemon_manager_test.py b/tools/edit_monitor/daemon_manager_test.py
index bcfa850..d62eade 100644
--- a/tools/edit_monitor/daemon_manager_test.py
+++ b/tools/edit_monitor/daemon_manager_test.py
@@ -27,6 +27,7 @@
from unittest import mock
from edit_monitor import daemon_manager
+
TEST_BINARY_FILE = '/path/to/test_binary'
TEST_PID_FILE_PATH = (
'587239c2d1050afdf54512e2d799f3b929f86b43575eb3c7b4bab105dd9bd25e.lock'
@@ -92,20 +93,10 @@
self.assert_run_simple_daemon_success()
def test_start_success_with_existing_instance_running(self):
- # Create a long running subprocess
- p = multiprocessing.Process(target=long_running_daemon)
- p.start()
-
- # Create a pidfile with the subprocess pid
- pid_file_path_dir = pathlib.Path(self.working_dir.name).joinpath(
- 'edit_monitor'
- )
- pid_file_path_dir.mkdir(parents=True, exist_ok=True)
- with open(pid_file_path_dir.joinpath(TEST_PID_FILE_PATH), 'w') as f:
- f.write(str(p.pid))
+ # Create a running daemon subprocess
+ p = self._create_fake_deamon_process()
self.assert_run_simple_daemon_success()
- p.terminate()
def test_start_success_with_existing_instance_already_dead(self):
# Create a pidfile with pid that does not exist.
@@ -129,6 +120,17 @@
self.assert_run_simple_daemon_success()
existing_dm.stop()
+ def test_start_return_directly_if_block_sign_exists(self):
+ # Creates the block sign.
+ pathlib.Path(self.working_dir.name).joinpath(
+ daemon_manager.BLOCK_SIGN_FILE
+ ).touch()
+
+ dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
+ dm.start()
+ # Verify no daemon process is started.
+ self.assertIsNone(dm.daemon_process)
+
@mock.patch('os.kill')
def test_start_failed_to_kill_existing_instance(self, mock_kill):
mock_kill.side_effect = OSError('Unknown OSError')
@@ -139,11 +141,9 @@
with open(pid_file_path_dir.joinpath(TEST_PID_FILE_PATH), 'w') as f:
f.write('123456')
- dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
- dm.start()
-
- # Verify no daemon process is started.
- self.assertIsNone(dm.daemon_process)
+ with self.assertRaises(OSError) as error:
+ dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
+ dm.start()
def test_start_failed_to_write_pidfile(self):
pid_file_path_dir = pathlib.Path(self.working_dir.name).joinpath(
@@ -153,20 +153,16 @@
# Makes the directory read-only so write pidfile will fail.
os.chmod(pid_file_path_dir, 0o555)
- dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
- dm.start()
-
- # Verifies no daemon process is started.
- self.assertIsNone(dm.daemon_process)
+ with self.assertRaises(PermissionError) as error:
+ dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
+ dm.start()
def test_start_failed_to_start_daemon_process(self):
- dm = daemon_manager.DaemonManager(
- TEST_BINARY_FILE, daemon_target='wrong_target', daemon_args=(1)
- )
- dm.start()
-
- # Verifies no daemon process is started.
- self.assertIsNone(dm.daemon_process)
+ with self.assertRaises(TypeError) as error:
+ dm = daemon_manager.DaemonManager(
+ TEST_BINARY_FILE, daemon_target='wrong_target', daemon_args=(1)
+ )
+ dm.start()
def test_monitor_daemon_subprocess_killed_high_memory_usage(self):
dm = daemon_manager.DaemonManager(
@@ -321,7 +317,7 @@
self._is_process_alive(child_pid), f'process {child_pid} still alive'
)
- def _get_child_processes(self, parent_pid):
+ def _get_child_processes(self, parent_pid: int) -> list[int]:
try:
output = subprocess.check_output(
['ps', '-o', 'pid,ppid', '--no-headers'], text=True
@@ -336,7 +332,7 @@
except subprocess.CalledProcessError as e:
self.fail(f'failed to get child process, error: {e}')
- def _is_process_alive(self, pid):
+ def _is_process_alive(self, pid: int) -> bool:
try:
output = subprocess.check_output(
['ps', '-p', str(pid), '-o', 'state='], text=True
@@ -355,6 +351,22 @@
# process already terminated
pass
+ def _create_fake_deamon_process(
+ self, name: str = ''
+ ) -> multiprocessing.Process:
+ # Create a long running subprocess
+ p = multiprocessing.Process(target=long_running_daemon)
+ p.start()
+
+ # Create the pidfile with the subprocess pid
+ pid_file_path_dir = pathlib.Path(self.working_dir.name).joinpath(
+ 'edit_monitor'
+ )
+ pid_file_path_dir.mkdir(parents=True, exist_ok=True)
+ with open(pid_file_path_dir.joinpath(name + 'pid.lock'), 'w') as f:
+ f.write(str(p.pid))
+ return p
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/edit_monitor/main.py b/tools/edit_monitor/main.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/edit_monitor/main.py
diff --git a/tools/edit_monitor/proto/edit_event.proto b/tools/edit_monitor/proto/edit_event.proto
new file mode 100644
index 0000000..b3630bc
--- /dev/null
+++ b/tools/edit_monitor/proto/edit_event.proto
@@ -0,0 +1,58 @@
+syntax = "proto3";
+
+package tools.asuite.edit_monitor;
+
+message EditEvent {
+ enum EditType {
+ UNSUPPORTED_TYPE = 0;
+ CREATE = 1;
+ MODIFY = 2;
+ DELETE = 3;
+ MOVE = 4;
+ }
+
+ enum ErrorType {
+ UNKNOWN_ERROR = 0;
+ FAILED_TO_START_EDIT_MONITOR = 1;
+ FAILED_TO_STOP_EDIT_MONITOR = 2;
+ FAILED_TO_REBOOT_EDIT_MONITOR = 3;
+ KILLED_DUE_TO_EXCEEDED_RESOURCE_USAGE = 4;
+ FORCE_CLEANUP = 5;
+ }
+
+ // Event that logs a single edit
+ message SingleEditEvent {
+ // Full path of the file that edited.
+ string file_path = 1;
+ // Type of the edit.
+ EditType edit_type = 2;
+ }
+
+ // Event that logs aggregated info for a set of edits.
+ message AggregatedEditEvent {
+ int32 num_edits = 1;
+ }
+
+ // Event that logs errors happened in the edit monitor.
+ message EditMonitorErrorEvent {
+ ErrorType error_type = 1;
+ string error_msg = 2;
+ string stack_trace = 3;
+ }
+
+ // ------------------------
+ // FIELDS FOR EditEvent
+ // ------------------------
+ // Internal user name.
+ string user_name = 1;
+ // The root of Android source.
+ string source_root = 2;
+ // Name of the host workstation.
+ string host_name = 3;
+
+ oneof event {
+ SingleEditEvent single_edit_event = 4;
+ AggregatedEditEvent aggregated_edit_event = 5;
+ EditMonitorErrorEvent edit_monitor_error_event = 6;
+ }
+}
diff --git a/tools/ide_query/ide_query.go b/tools/ide_query/ide_query.go
index 23c7abd..89ac78f 100644
--- a/tools/ide_query/ide_query.go
+++ b/tools/ide_query/ide_query.go
@@ -363,6 +363,7 @@
Id: name,
SourceFilePaths: mod.Srcs,
GeneratedFiles: genFiles(env, paths),
+ DependencyIds: mod.Deps,
}
for _, d := range mod.Deps {