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 {