Merge "Revert "Drop RRO autogeneration for soong apps"" into main
diff --git a/ci/build_device_and_tests b/ci/build_device_and_tests
new file mode 100755
index 0000000..9d11268
--- /dev/null
+++ b/ci/build_device_and_tests
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+#
+# Copyright 2024, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+build/soong/soong_ui.bash --make-mode build_test_suites || exit $?
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@ || exit $?
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index cd9d76d..4d3b546 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -89,6 +89,8 @@
       else:
         regex = r'\b(%s)\b' % re.escape(target)
         if any(re.search(regex, opt) for opt in test_discovery_zip_regexes):
+          get_metrics_agent().report_unoptimized_target(target, 'Test artifact used.')
+        else:
           get_metrics_agent().report_optimized_target(target)
 
       if self._unused_target_exclusion_enabled(
diff --git a/core/Makefile b/core/Makefile
index 5e0d4df..f15edb2 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1596,6 +1596,7 @@
 	$(AVBTOOL) add_hash_footer \
            --image $@ \
 	   $(call get-partition-size-argument,$(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE)) \
+	   --salt $$(sha256sum $(BUILD_NUMBER_FILE) $(BUILD_DATETIME_FILE) | cut -d " " -f 1 | tr -d '\n') \
 	   --partition_name init_boot $(INTERNAL_AVB_INIT_BOOT_SIGNING_ARGS) \
 	   $(BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS)
 
@@ -1654,6 +1655,8 @@
     $(ALL_DEFAULT_INSTALLED_MODULES))
 
 INTERNAL_VENDOR_RAMDISK_TARGET := $(call intermediates-dir-for,PACKAGING,vendor_boot)/vendor_ramdisk.cpio$(RAMDISK_EXT)
+vendor_ramdisk_intermediates :=$= $(call intermediates-dir-for,PACKAGING,vendor_ramdisk)
+$(eval $(call write-partition-file-list,$(vendor_ramdisk_intermediates)/file_list.txt,$(TARGET_VENDOR_RAMDISK_OUT),$(INTERNAL_VENDOR_RAMDISK_FILES)))
 
 # Exclude recovery files in the default vendor ramdisk if including a standalone
 # recovery ramdisk in vendor_boot.
@@ -1769,6 +1772,7 @@
 	$(AVBTOOL) add_hash_footer \
            --image $@ \
 	   $(call get-partition-size-argument,$(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE)) \
+	   --salt $$(sha256sum $(BUILD_NUMBER_FILE) $(BUILD_DATETIME_FILE) | cut -d " " -f 1 | tr -d '\n') \
 	   --partition_name vendor_boot $(INTERNAL_AVB_VENDOR_BOOT_SIGNING_ARGS) \
 	   $(BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS)
 else
@@ -2932,6 +2936,9 @@
 $(error MTD device is no longer supported and thus BOARD_NAND_SPARE_SIZE is deprecated.)
 endif
 
+recovery_intermediates := $(call intermediates-dir-for,PACKAGING,recovery)
+$(eval $(call write-partition-file-list,$(recovery_intermediates)/file_list.txt,$(TARGET_RECOVERY_OUT),$(INTERNAL_RECOVERYIMAGE_FILES)))
+
 
 # -----------------------------------------------------------------
 # Build debug ramdisk and debug boot image.
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 769a6f7..092ddb0 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -48,6 +48,11 @@
 RECOVERY_FSTAB_VERSION := 2
 $(call soong_config_set, recovery, recovery_api_version, $(RECOVERY_API_VERSION))
 $(call soong_config_set, recovery, recovery_fstab_version, $(RECOVERY_FSTAB_VERSION))
+$(call soong_config_set_bool, recovery ,target_userimages_use_f2fs ,$(if $(TARGET_USERIMAGES_USE_F2FS),true,false))
+$(call soong_config_set_bool, recovery ,has_board_cacheimage_partition_size ,$(if $(BOARD_CACHEIMAGE_PARTITION_SIZE),true,false))
+ifdef TARGET_RECOVERY_UI_LIB
+  $(call soong_config_set_string_list, recovery, target_recovery_ui_lib, $(TARGET_RECOVERY_UI_LIB))
+endif
 
 # For Sanitizers
 $(call soong_config_set_bool,ANDROID,ASAN_ENABLED,$(if $(filter address,$(SANITIZE_TARGET)),true,false))
@@ -262,3 +267,8 @@
 $(call soong_config_set_bool,fs_config,vendor_dlkm,$(if $(BOARD_USES_VENDOR_DLKMIMAGE)$(BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE),true,false))
 $(call soong_config_set_bool,fs_config,odm_dlkm,$(if $(BOARD_USES_ODM_DLKMIMAGE)$(BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE),true,false))
 $(call soong_config_set_bool,fs_config,system_dlkm,$(if $(BOARD_USES_SYSTEM_DLKMIMAGE)$(BOARD_SYSTEM_DLKMIMAGE_FILE_SYSTEM_TYPE),true,false))
+
+# Variables for telephony
+$(call soong_config_set_bool,telephony,sec_cp_secure_boot,$(if $(filter true,$(SEC_CP_SECURE_BOOT)),true,false))
+$(call soong_config_set_bool,telephony,cbd_protocol_sit,$(if $(filter true,$(CBD_PROTOCOL_SIT)),true,false))
+$(call soong_config_set_bool,telephony,use_radioexternal_hal_aidl,$(if $(filter true,$(USE_RADIOEXTERNAL_HAL_AIDL)),true,false))
diff --git a/core/config.mk b/core/config.mk
index 485e8cc..d62b86d 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -330,6 +330,18 @@
 $(eval SOONG_CONFIG_TYPE_$(strip $1)_$(strip $2):=bool)
 endef
 
+# soong_config_set_string_list is the same as soong_config_set, but it will
+# also type the variable as a list of strings, so that when using select() expressions
+# in blueprint files they can use list values instead of strings.
+# The values of the list must be space-separated.
+# $1 is the namespace. $2 is the variable name. $3 is the variable value.
+# Ex: $(call soong_config_set_string_list,acme,COOL_LIBS,a b)
+define soong_config_set_string_list
+$(call soong_config_define_internal,$1,$2) \
+$(eval SOONG_CONFIG_$(strip $1)_$(strip $2):=$(strip $3))
+$(eval SOONG_CONFIG_TYPE_$(strip $1)_$(strip $2):=string_list)
+endef
+
 # soong_config_append appends to the value of the variable in the given Soong
 # config namespace. If the variable does not exist, it will be defined. If the
 # namespace does not  exist, it will be defined.
@@ -1307,10 +1319,6 @@
 SOONG_VARIABLES :=
 SOONG_EXTRA_VARIABLES :=
 
--include external/ltp/android/ltp_package_list.mk
-DEFAULT_DATA_OUT_MODULES := ltp $(ltp_packages)
-.KATI_READONLY := DEFAULT_DATA_OUT_MODULES
-
 include $(BUILD_SYSTEM)/dumpvar.mk
 
 ifdef BOARD_VNDK_VERSION
diff --git a/core/definitions.mk b/core/definitions.mk
index cd1b36e..adb35e0 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2605,7 +2605,87 @@
         @$(call emit-line,$(wordlist 108501,109000,$(1)),$(2))
         @$(call emit-line,$(wordlist 109001,109500,$(1)),$(2))
         @$(call emit-line,$(wordlist 109501,110000,$(1)),$(2))
-        @$(if $(wordlist 110001,110002,$(1)),$(error dump-words-to-file: Too many words ($(words $(1)))))
+        @$(call emit-line,$(wordlist 110001,110500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 110501,111000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 111001,111500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 111501,112000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 112001,112500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 112501,113000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 113001,113500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 113501,114000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 114001,114500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 114501,115000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 115001,115500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 115501,116000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 116001,116500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 116501,117000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 117001,117500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 117501,118000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 118001,118500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 118501,119000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 119001,119500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 119501,120000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 120001,120500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 120501,121000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 121001,121500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 121501,122000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 122001,122500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 122501,123000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 123001,123500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 123501,124000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 124001,124500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 124501,125000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 125001,125500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 125501,126000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 126001,126500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 126501,127000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 127001,127500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 127501,128000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 128001,128500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 128501,129000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 129001,129500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 129501,130000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 130001,130500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 130501,131000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 131001,131500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 131501,132000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 132001,132500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 132501,133000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 133001,133500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 133501,134000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 134001,134500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 134501,135000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 135001,135500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 135501,136000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 136001,136500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 136501,137000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 137001,137500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 137501,138000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 138001,138500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 138501,139000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 139001,139500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 139501,140000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 140001,140500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 140501,141000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 141001,141500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 141501,142000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 142001,142500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 142501,143000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 143001,143500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 143501,144000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 144001,144500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 144501,145000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 145001,145500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 145501,146000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 146001,146500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 146501,147000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 147001,147500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 147501,148000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 148001,148500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 148501,149000,$(1)),$(2))
+        @$(call emit-line,$(wordlist 149001,149500,$(1)),$(2))
+        @$(call emit-line,$(wordlist 149501,150000,$(1)),$(2))
+        @$(if $(wordlist 150001,150002,$(1)),$(error dump-words-to-file: Too many words ($(words $(1)))))
 endef
 # Return jar arguments to compress files in a given directory
 # $(1): directory
diff --git a/core/java_common.mk b/core/java_common.mk
index a21f062..f574b76 100644
--- a/core/java_common.mk
+++ b/core/java_common.mk
@@ -32,7 +32,7 @@
     else ifneq (,$(LOCAL_SDK_VERSION)$(TARGET_BUILD_USE_PREBUILT_SDKS))
       # TODO(ccross): allow 1.9 for current and unbundled once we have SDK system modules
       LOCAL_JAVA_LANGUAGE_VERSION := 1.8
-    else ifeq ($(EXPERIMENTAL_TARGET_JAVA_VERSION_21),true)
+    else ifeq ($(RELEASE_TARGET_JAVA_21),true)
       LOCAL_JAVA_LANGUAGE_VERSION := 21
     else
       LOCAL_JAVA_LANGUAGE_VERSION := 17
diff --git a/core/layoutlib_data.mk b/core/layoutlib_data.mk
index 06735df..dabcfb2 100644
--- a/core/layoutlib_data.mk
+++ b/core/layoutlib_data.mk
@@ -106,6 +106,7 @@
 _layoutlib_font_config_files := $(sort $(wildcard frameworks/base/data/fonts/*.xml))
 _layoutlib_fonts_files := $(filter $(TARGET_OUT)/fonts/%.ttf $(TARGET_OUT)/fonts/%.ttc $(TARGET_OUT)/fonts/%.otf, $(INTERNAL_SYSTEMIMAGE_FILES))
 _layoutlib_keyboard_files := $(sort $(wildcard frameworks/base/data/keyboards/*.kcm))
+_layoutlib_hyphen_files := $(filter $(TARGET_OUT)/usr/hyphen-data/%.hyb, $(INTERNAL_SYSTEMIMAGE_FILES))
 
 # Find out files disted with layoutlib in Soong.
 ### Filter out static libraries for Windows and files already handled in make.
@@ -135,6 +136,13 @@
 	  echo data/keyboards/$(notdir $f),frameworks/base/data/keyboards,prebuilt_etc,,,,,$f,,, >> $@; \
 	)
 
+	$(foreach f,$(_layoutlib_hyphen_files), \
+	  $(eval _module_name := $(ALL_INSTALLED_FILES.$f)) \
+	  $(eval _module_path := $(strip $(sort $(ALL_MODULES.$(_module_name).PATH)))) \
+	  $(eval _soong_module_type := $(strip $(sort $(ALL_MODULES.$(_module_name).SOONG_MODULE_TYPE)))) \
+	  echo data/hyphen-data/$(notdir $f),$(_module_path),$(_soong_module_type),,,,,$f,,, >> $@; \
+	)
+
 	$(foreach f,$(_layoutlib_files_disted_by_soong), \
 	  $(eval _prebuilt_module_file := $(call word-colon,1,$f)) \
 	  $(eval _dist_file := $(call word-colon,2,$f)) \
@@ -163,7 +171,7 @@
 
 .PHONY: layoutlib-sbom
 layoutlib-sbom: $(LAYOUTLIB_SBOM)/layoutlib.spdx.json
-$(LAYOUTLIB_SBOM)/layoutlib.spdx.json: $(PRODUCT_OUT)/always_dirty_file.txt $(GEN_SBOM) $(LAYOUTLIB_SBOM)/sbom-metadata.csv $(_layoutlib_font_config_files) $(_layoutlib_fonts_files) $(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop $(_layoutlib_keyboard_files) $(LAYOUTLIB_RES_FILES) $(EMULATED_OVERLAYS_FILES) $(DEVICE_OVERLAYS_FILES)
+$(LAYOUTLIB_SBOM)/layoutlib.spdx.json: $(PRODUCT_OUT)/always_dirty_file.txt $(GEN_SBOM) $(LAYOUTLIB_SBOM)/sbom-metadata.csv $(_layoutlib_font_config_files) $(_layoutlib_fonts_files) $(LAYOUTLIB_BUILD_PROP)/layoutlib-build.prop $(_layoutlib_keyboard_files) $(_layoutlib_hyphen_files) $(LAYOUTLIB_RES_FILES) $(EMULATED_OVERLAYS_FILES) $(DEVICE_OVERLAYS_FILES)
 	rm -rf $@
 	$(GEN_SBOM) --output_file $@ --metadata $(LAYOUTLIB_SBOM)/sbom-metadata.csv --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --module_name "layoutlib" --json
 
diff --git a/core/main.mk b/core/main.mk
index f96cf04..624df49 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1399,6 +1399,7 @@
     $(INSTALLED_RAMDISK_TARGET) \
     $(INSTALLED_BOOTIMAGE_TARGET) \
     $(INSTALLED_INIT_BOOT_IMAGE_TARGET) \
+    $(INSTALLED_DTBOIMAGE_TARGET) \
     $(INSTALLED_RADIOIMAGE_TARGET) \
     $(INSTALLED_DEBUG_RAMDISK_TARGET) \
     $(INSTALLED_DEBUG_BOOTIMAGE_TARGET) \
diff --git a/core/packaging/flags.mk b/core/packaging/flags.mk
index ccb502c..06e5001 100644
--- a/core/packaging/flags.mk
+++ b/core/packaging/flags.mk
@@ -24,10 +24,11 @@
 # -----------------------------------------------------------------
 # Aconfig Flags
 
-# Create a summary file of build flags for each partition
+# Create a summary file of build flags for a single partition
 # $(1): built aconfig flags file (out)
 # $(2): installed aconfig flags file (out)
 # $(3): the partition (in)
+# $(4): input aconfig files for the partition (in)
 define generate-partition-aconfig-flag-file
 $(eval $(strip $(1)): PRIVATE_OUT := $(strip $(1)))
 $(eval $(strip $(1)): PRIVATE_IN := $(strip $(4)))
diff --git a/core/product.mk b/core/product.mk
index 9c567c3..1b336b0 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -284,6 +284,9 @@
 # Whether APEX should be compressed or not
 _product_single_value_vars += PRODUCT_COMPRESSED_APEX
 
+# Default fs type for APEX payload image (apex_payload.img)
+_product_single_value_vars += PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE
+
 # VNDK version of product partition. It can be 'current' if the product
 # partitions uses PLATFORM_VNDK_VERSION.
 _product_single_value_vars += PRODUCT_PRODUCT_VNDK_VERSION
diff --git a/core/product_config.mk b/core/product_config.mk
index abe6e38..68614ae 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -478,7 +478,9 @@
 
 # Show a warning wall of text if non-compliance-GSI products set this option.
 ifdef PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT
-  ifeq (,$(filter gsi_arm gsi_arm64 gsi_x86 gsi_x86_64 gsi_car_arm64 gsi_car_x86_64 gsi_tv_arm gsi_tv_arm64,$(PRODUCT_NAME)))
+  ifeq (,$(filter gsi_arm gsi_arm64 gsi_arm64_soong_system gsi_x86 gsi_x86_64 \
+                  gsi_x86_64_soong_system gsi_car_arm64 gsi_car_x86_64 \
+                  gsi_tv_arm gsi_tv_arm64,$(PRODUCT_NAME)))
     $(warning PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT is set but \
       PRODUCT_NAME ($(PRODUCT_NAME)) doesn't look like a GSI for compliance \
       testing. This is a special configuration for compliance GSI, so do make \
@@ -534,6 +536,17 @@
   PRODUCT_COMPRESSED_APEX := $(OVERRIDE_PRODUCT_COMPRESSED_APEX)
 endif
 
+ifdef OVERRIDE_PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE
+  PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE := $(OVERRIDE_PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE)
+else ifeq ($(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE),)
+  # Use ext4 as a default payload fs type
+  PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE := ext4
+endif
+ifeq ($(filter ext4 erofs,$(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE)),)
+  $(error PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE should be either erofs or ext4,\
+    not $(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE).)
+endif
+
 $(KATI_obsolete_var OVERRIDE_PRODUCT_EXTRA_VNDK_VERSIONS \
     ,Use PRODUCT_EXTRA_VNDK_VERSIONS instead)
 
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 0f82b68..06a88a3 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -194,6 +194,8 @@
 $(call add_json_str,  SystemDlkmPath,                    $(TARGET_COPY_OUT_SYSTEM_DLKM))
 $(call add_json_str,  OemPath,                           $(TARGET_COPY_OUT_OEM))
 $(call add_json_bool, MinimizeJavaDebugInfo,             $(filter true,$(PRODUCT_MINIMIZE_JAVA_DEBUG_INFO)))
+$(call add_json_str,  RecoveryPath,                      $(TARGET_COPY_OUT_RECOVERY))
+$(call add_json_bool, BuildingRecoveryImage,             $(BUILDING_RECOVERY_IMAGE))
 
 $(call add_json_bool, UseGoma,                           $(filter-out false,$(USE_GOMA)))
 $(call add_json_bool, UseRBE,                            $(filter-out false,$(USE_RBE)))
@@ -274,6 +276,7 @@
 $(call add_json_str,  DeviceCurrentApiLevelForVendorModules,  $(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES))
 
 $(call add_json_bool, CompressedApex, $(filter true,$(PRODUCT_COMPRESSED_APEX)))
+$(call add_json_str, DefaultApexPayloadType, $(PRODUCT_DEFAULT_APEX_PAYLOAD_TYPE))
 
 $(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
 
@@ -379,7 +382,7 @@
   $(call add_json_str,  ProductDirectory,    $(dir $(INTERNAL_PRODUCT)))
 
   $(call add_json_map,PartitionQualifiedVariables)
-  $(foreach image_type,SYSTEM VENDOR CACHE USERDATA PRODUCT SYSTEM_EXT OEM ODM VENDOR_DLKM ODM_DLKM SYSTEM_DLKM, \
+  $(foreach image_type,INIT_BOOT BOOT VENDOR_BOOT SYSTEM VENDOR CACHE USERDATA PRODUCT SYSTEM_EXT OEM ODM VENDOR_DLKM ODM_DLKM SYSTEM_DLKM, \
     $(call add_json_map,$(call to-lower,$(image_type))) \
     $(call add_json_bool, BuildingImage, $(filter true,$(BUILDING_$(image_type)_IMAGE))) \
     $(call add_json_str, BoardErofsCompressor, $(BOARD_$(image_type)IMAGE_EROFS_COMPRESSOR)) \
@@ -426,6 +429,29 @@
   $(call add_json_str, BoardFlashLogicalBlockSize, $(BOARD_FLASH_LOGICAL_BLOCK_SIZE))
   $(call add_json_str, BoardFlashEraseBlockSize, $(BOARD_FLASH_ERASE_BLOCK_SIZE))
   $(call add_json_bool, BuildingVbmetaImage, $(BUILDING_VBMETA_IMAGE))
+
+  # boot image stuff
+  $(call add_json_bool, BuildingRamdiskImage, $(filter true,$(BUILDING_RAMDISK_IMAGE)))
+  $(call add_json_bool, ProductBuildBootImage, $(filter true,$(PRODUCT_BUILD_BOOT_IMAGE)))
+  $(call add_json_str, ProductBuildVendorBootImage, $(PRODUCT_BUILD_VENDOR_BOOT_IMAGE))
+  $(call add_json_bool, ProductBuildInitBootImage, $(filter true,$(PRODUCT_BUILD_INIT_BOOT_IMAGE)))
+  $(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
+  $(call add_json_str, BoardPrebuiltBootimage, $(BOARD_PREBUILT_BOOT_IMAGE))
+  $(call add_json_str, BoardPrebuiltInitBootimage, $(BOARD_PREBUILT_INIT_BOOT_IMAGE))
+  $(call add_json_str, BoardBootimagePartitionSize, $(BOARD_BOOTIMAGE_PARTITION_SIZE))
+  $(call add_json_str, BoardInitBootimagePartitionSize, $(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE))
+  $(call add_json_str, BoardBootHeaderVersion, $(BOARD_BOOT_HEADER_VERSION))
+  $(call add_json_str, TargetKernelPath, $(TARGET_KERNEL_PATH))
+  $(call add_json_bool, BoardUsesGenericKernelImage, $(BOARD_USES_GENERIC_KERNEL_IMAGE))
+  $(call add_json_str, BootSecurityPatch, $(BOOT_SECURITY_PATCH))
+  $(call add_json_str, InitBootSecurityPatch, $(INIT_BOOT_SECURITY_PATCH))
+  $(call add_json_str, VendorSecurityPatch, $(VENDOR_SECURITY_PATCH))
+  $(call add_json_bool, BoardIncludeDtbInBootimg, $(BOARD_INCLUDE_DTB_IN_BOOTIMG))
+  $(call add_json_list, InternalKernelCmdline, $(INTERNAL_KERNEL_CMDLINE))
+  $(call add_json_list, InternalBootconfig, $(INTERNAL_BOOTCONFIG))
+  $(call add_json_str, InternalBootconfigFile, $(INTERNAL_BOOTCONFIG_FILE))
+
+  # Avb (android verified boot) stuff
   $(call add_json_bool, BoardAvbEnable, $(filter true,$(BOARD_AVB_ENABLE)))
   $(call add_json_str, BoardAvbAlgorithm, $(BOARD_AVB_ALGORITHM))
   $(call add_json_str, BoardAvbKeyPath, $(BOARD_AVB_KEY_PATH))
@@ -441,7 +467,6 @@
     $(call end_json_map))
   $(call end_json_map)
 
-  $(call add_json_bool, BoardUsesRecoveryAsBoot, $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
   $(call add_json_bool, ProductUseDynamicPartitionSize, $(filter true,$(PRODUCT_USE_DYNAMIC_PARTITION_SIZE)))
   $(call add_json_bool, CopyImagesForTargetFilesZip, $(filter true,$(COPY_IMAGES_FOR_TARGET_FILES_ZIP)))
 
@@ -463,6 +488,10 @@
   $(call add_json_bool, BuildingOdmDlkmImage,               $(BUILDING_ODM_DLKM_IMAGE))
   $(call add_json_list, OdmKernelModules, $(BOARD_ODM_KERNEL_MODULES))
   $(call add_json_str, OdmKernelBlocklistFile, $(BOARD_ODM_KERNEL_MODULES_BLOCKLIST_FILE))
+  $(call add_json_list, VendorRamdiskKernelModules, $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES))
+  $(call add_json_str, VendorRamdiskKernelBlocklistFile, $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_BLOCKLIST_FILE))
+  $(call add_json_list, VendorRamdiskKernelLoadModules, $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD))
+  $(call add_json_str, VendorRamdiskKernelOptionsFile, $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_OPTIONS_FILE))
 
   # Used to generate /vendor/build.prop
   $(call add_json_list, BoardInfoFiles, $(if $(TARGET_BOARD_INFO_FILES),$(TARGET_BOARD_INFO_FILES),$(firstword $(TARGET_BOARD_INFO_FILE) $(wildcard $(TARGET_DEVICE_DIR)/board-info.txt))))
@@ -470,6 +499,9 @@
 
   $(call add_json_list, ProductCopyFiles, $(PRODUCT_COPY_FILES))
 
+  # Used to generate fsv meta
+  $(call add_json_bool, ProductFsverityGenerateMetadata,               $(PRODUCT_FSVERITY_GENERATE_METADATA))
+
 $(call end_json_map)
 
 # For converting vintf_data
diff --git a/core/tasks/general-tests-shared-libs.mk b/core/tasks/general-tests-shared-libs.mk
deleted file mode 100644
index 2405140..0000000
--- a/core/tasks/general-tests-shared-libs.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2024 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-.PHONY: general-tests-shared-libs
-
-intermediates_dir := $(call intermediates-dir-for,PACKAGING,general-tests-shared-libs)
-
-general_tests_shared_libs_zip := $(PRODUCT_OUT)/general-tests_host-shared-libs.zip
-
-# Filter shared entries between general-tests and device-tests's HOST_SHARED_LIBRARY.FILES,
-# to avoid warning about overriding commands.
-my_host_shared_lib_for_general_tests := \
-  $(foreach m,$(filter $(COMPATIBILITY.device-tests.HOST_SHARED_LIBRARY.FILES),\
-	   $(COMPATIBILITY.general-tests.HOST_SHARED_LIBRARY.FILES)),$(call word-colon,2,$(m)))
-my_general_tests_shared_lib_files := \
-  $(filter-out $(COMPATIBILITY.device-tests.HOST_SHARED_LIBRARY.FILES),\
-	 $(COMPATIBILITY.general-tests.HOST_SHARED_LIBRARY.FILES))
-
-my_host_shared_lib_for_general_tests += $(call copy-many-files,$(my_general_tests_shared_lib_files))
-
-$(general_tests_shared_libs_zip) : PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
-$(general_tests_shared_libs_zip) : PRIVATE_HOST_SHARED_LIBS := $(my_host_shared_lib_for_general_tests)
-$(general_tests_shared_libs_zip) : PRIVATE_general_host_shared_libs_zip := $(general_tests_shared_libs_zip)
-$(general_tests_shared_libs_zip) : $(my_host_shared_lib_for_general_tests) $(SOONG_ZIP)
-	rm -rf $(PRIVATE_INTERMEDIATES_DIR)
-	mkdir -p $(PRIVATE_INTERMEDIATES_DIR) $(PRIVATE_INTERMEDIATES_DIR)/tools
-	$(hide) for shared_lib in $(PRIVATE_HOST_SHARED_LIBS); do \
-	  echo $$shared_lib >> $(PRIVATE_INTERMEDIATES_DIR)/shared-libs.list; \
-	done
-	grep $(HOST_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/shared-libs.list > $(PRIVATE_INTERMEDIATES_DIR)/host-shared-libs.list || true
-	$(SOONG_ZIP) -d -o $(PRIVATE_general_host_shared_libs_zip) \
-	  -P host -C $(HOST_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/host-shared-libs.list
-
-general-tests-shared-libs: $(general_tests_shared_libs_zip)
-$(call dist-for-goals, general-tests-shared-libs, $(general_tests_shared_libs_zip))
-
-$(call declare-1p-container,$(general_tests_shared_libs_zip),)
-$(call declare-container-license-deps,$(general_tests_shared_libs_zip),$(my_host_shared_lib_for_general_tests),$(PRODUCT_OUT)/:/)
-
-intermediates_dir :=
-general_tests_shared_libs_zip :=
diff --git a/core/tasks/general-tests.mk b/core/tasks/general-tests.mk
index d6fc072..dcfcfad 100644
--- a/core/tasks/general-tests.mk
+++ b/core/tasks/general-tests.mk
@@ -27,32 +27,61 @@
 # Create an artifact to include all test config files in general-tests.
 general_tests_configs_zip := $(PRODUCT_OUT)/general-tests_configs.zip
 
-# Copy kernel test modules to testcases directories
-include $(BUILD_SYSTEM)/tasks/tools/vts-kernel-tests.mk
-ltp_copy_pairs := \
-  $(call target-native-copy-pairs,$(kernel_ltp_modules),$(kernel_ltp_host_out))
-copy_ltp_tests := $(call copy-many-files,$(ltp_copy_pairs))
+# Filter shared entries between general-tests and device-tests's HOST_SHARED_LIBRARY.FILES,
+# to avoid warning about overriding commands.
+my_host_shared_lib_for_general_tests := \
+  $(foreach m,$(filter $(COMPATIBILITY.device-tests.HOST_SHARED_LIBRARY.FILES),\
+	   $(COMPATIBILITY.general-tests.HOST_SHARED_LIBRARY.FILES)),$(call word-colon,2,$(m)))
+my_general_tests_shared_lib_files := \
+  $(filter-out $(COMPATIBILITY.device-tests.HOST_SHARED_LIBRARY.FILES),\
+	 $(COMPATIBILITY.general-tests.HOST_SHARED_LIBRARY.FILES))
 
-# PHONY target to be used to build and test `vts_ltp_tests` without building full vts
-.PHONY: vts_kernel_ltp_tests
-vts_kernel_ltp_tests: $(copy_ltp_tests)
+my_host_shared_lib_for_general_tests += $(call copy-many-files,$(my_general_tests_shared_lib_files))
 
-general_tests_shared_libs_zip := $(PRODUCT_OUT)/general-tests_host-shared-libs.zip
+my_host_shared_lib_symlinks := \
+    $(filter $(COMPATIBILITY.host-unit-tests.SYMLINKS),\
+	$(COMPATIBILITY.general-tests.SYMLINKS))
 
-$(general_tests_zip) : $(general_tests_shared_libs_zip)
-$(general_tests_zip) : $(copy_ltp_tests)
-$(general_tests_zip) : PRIVATE_KERNEL_LTP_HOST_OUT := $(kernel_ltp_host_out)
+my_general_tests_symlinks := \
+    $(filter-out $(COMPATIBILITY.camera-hal-tests.SYMLINKS),\
+    $(filter-out $(COMPATIBILITY.host-unit-tests.SYMLINKS),\
+	 $(COMPATIBILITY.general-tests.SYMLINKS)))
+
+my_symlinks_for_general_tests := $(foreach f,$(my_general_tests_symlinks),\
+	$(strip $(eval _cmf_tuple := $(subst :, ,$(f))) \
+	$(eval _cmf_dep := $(word 1,$(_cmf_tuple))) \
+	$(eval _cmf_src := $(word 2,$(_cmf_tuple))) \
+	$(eval _cmf_dest := $(word 3,$(_cmf_tuple))) \
+	$(call symlink-file,$(_cmf_dep),$(_cmf_src),$(_cmf_dest)) \
+	$(_cmf_dest)))
+
+# In this one directly take the overlap into the zip since we can't rewrite rules
+my_symlinks_for_general_tests += $(foreach f,$(my_host_shared_lib_symlinks),\
+        $(strip $(eval _cmf_tuple := $(subst :, ,$(f))) \
+        $(eval _cmf_dep := $(word 1,$(_cmf_tuple))) \
+        $(eval _cmf_src := $(word 2,$(_cmf_tuple))) \
+        $(eval _cmf_dest := $(word 3,$(_cmf_tuple))) \
+        $(_cmf_dest)))
+
 $(general_tests_zip) : PRIVATE_general_tests_list_zip := $(general_tests_list_zip)
 $(general_tests_zip) : .KATI_IMPLICIT_OUTPUTS := $(general_tests_list_zip) $(general_tests_configs_zip)
 $(general_tests_zip) : PRIVATE_TOOLS := $(general_tests_tools)
 $(general_tests_zip) : PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
+$(general_tests_zip) : PRIVATE_HOST_SHARED_LIBS := $(my_host_shared_lib_for_general_tests)
+$(general_tests_zip) : PRIVATE_SYMLINKS := $(my_symlinks_for_general_tests)
 $(general_tests_zip) : PRIVATE_general_tests_configs_zip := $(general_tests_configs_zip)
-$(general_tests_zip) : $(COMPATIBILITY.general-tests.FILES) $(COMPATIBILITY.general-tests.SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES) $(general_tests_tools) $(SOONG_ZIP)
+$(general_tests_zip) : $(COMPATIBILITY.general-tests.FILES) $(my_host_shared_lib_for_general_tests) $(COMPATIBILITY.general-tests.SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES) $(general_tests_tools) $(my_symlinks_for_general_tests) $(SOONG_ZIP)
 	rm -rf $(PRIVATE_INTERMEDIATES_DIR)
 	rm -f $@ $(PRIVATE_general_tests_list_zip)
 	mkdir -p $(PRIVATE_INTERMEDIATES_DIR) $(PRIVATE_INTERMEDIATES_DIR)/tools
 	echo $(sort $(COMPATIBILITY.general-tests.FILES) $(COMPATIBILITY.general-tests.SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES)) | tr " " "\n" > $(PRIVATE_INTERMEDIATES_DIR)/list
-	find $(PRIVATE_KERNEL_LTP_HOST_OUT) >> $(PRIVATE_INTERMEDIATES_DIR)/list
+	for symlink in $(PRIVATE_SYMLINKS); do \
+	  echo $$symlink >> $(PRIVATE_INTERMEDIATES_DIR)/list; \
+	done
+	$(hide) for shared_lib in $(PRIVATE_HOST_SHARED_LIBS); do \
+	  echo $$shared_lib >> $(PRIVATE_INTERMEDIATES_DIR)/shared-libs.list; \
+	done
+	grep $(HOST_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/shared-libs.list > $(PRIVATE_INTERMEDIATES_DIR)/host-shared-libs.list || true
 	grep $(HOST_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/list > $(PRIVATE_INTERMEDIATES_DIR)/host.list || true
 	grep $(TARGET_OUT_TESTCASES) $(PRIVATE_INTERMEDIATES_DIR)/list > $(PRIVATE_INTERMEDIATES_DIR)/target.list || true
 	grep -e .*\\.config$$ $(PRIVATE_INTERMEDIATES_DIR)/host.list > $(PRIVATE_INTERMEDIATES_DIR)/host-test-configs.list || true
@@ -62,6 +91,7 @@
 	  -P host -C $(PRIVATE_INTERMEDIATES_DIR) -D $(PRIVATE_INTERMEDIATES_DIR)/tools \
 	  -P host -C $(HOST_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/host.list \
 	  -P target -C $(PRODUCT_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/target.list \
+	  -P host -C $(HOST_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/host-shared-libs.list \
 	  -sha256
 	$(SOONG_ZIP) -d -o $(PRIVATE_general_tests_configs_zip) \
 	  -P host -C $(HOST_OUT) -l $(PRIVATE_INTERMEDIATES_DIR)/host-test-configs.list \
@@ -82,3 +112,8 @@
 general_tests_list_zip :=
 general_tests_configs_zip :=
 general_tests_shared_libs_zip :=
+my_host_shared_lib_for_general_tests :=
+my_symlinks_for_general_tests :=
+my_general_tests_shared_lib_files :=
+my_general_tests_symlinks :=
+my_host_shared_lib_symlinks :=
diff --git a/core/tasks/tools/vts-kernel-tests.mk b/core/tasks/tools/vts-kernel-tests.mk
deleted file mode 100644
index e727dc1..0000000
--- a/core/tasks/tools/vts-kernel-tests.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2022 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
--include external/ltp/android/ltp_package_list.mk
-
-include $(BUILD_SYSTEM)/tasks/tools/vts_package_utils.mk
-
-# Copy kernel test modules to testcases directories
-kernel_ltp_host_out := $(HOST_OUT_TESTCASES)/vts_kernel_ltp_tests
-kernel_ltp_vts_out := $(HOST_OUT)/$(test_suite_name)/android-$(test_suite_name)/testcases/vts_kernel_ltp_tests
-kernel_ltp_modules := \
-    ltp \
-    $(ltp_packages)
diff --git a/core/tasks/tools/vts_package_utils.mk b/core/tasks/tools/vts_package_utils.mk
deleted file mode 100644
index 1a819f2..0000000
--- a/core/tasks/tools/vts_package_utils.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Copyright (C) 2020 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# $(1): List of target native files to copy.
-# $(2): Copy destination directory.
-# Evaluates to a list of ":"-separated pairs src:dst.
-define target-native-copy-pairs
-$(foreach m,$(1),\
-  $(eval _built_files := $(strip $(ALL_MODULES.$(m).BUILT_INSTALLED)\
-  $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).BUILT_INSTALLED)))\
-  $(foreach i, $(sort $(_built_files)),\
-    $(eval bui_ins := $(subst :,$(space),$(i)))\
-    $(eval ins := $(word 2,$(bui_ins)))\
-    $(if $(filter $(TARGET_OUT_ROOT)/%,$(ins)),\
-      $(eval bui := $(word 1,$(bui_ins)))\
-      $(eval my_copy_dest := $(patsubst data/%,DATA/%,\
-                               $(patsubst system/%,DATA/%,\
-                                   $(patsubst $(PRODUCT_OUT)/%,%,$(ins)))))\
-      $(call declare-copy-target-license-metadata,$(2)/$(my_copy_dest),$(bui))\
-      $(bui):$(2)/$(my_copy_dest))))
-endef
diff --git a/core/tasks/vts-core-tests.mk b/core/tasks/vts-core-tests.mk
index 1eeb078..11bb932 100644
--- a/core/tasks/vts-core-tests.mk
+++ b/core/tasks/vts-core-tests.mk
@@ -16,15 +16,6 @@
 test_suite_tradefed := vts-tradefed
 test_suite_readme := test/vts/tools/vts-core-tradefed/README
 
-include $(BUILD_SYSTEM)/tasks/tools/vts-kernel-tests.mk
-
-ltp_copy_pairs := \
-  $(call target-native-copy-pairs,$(kernel_ltp_modules),$(kernel_ltp_vts_out))
-
-copy_ltp_tests := $(call copy-many-files,$(ltp_copy_pairs))
-
-test_suite_extra_deps := $(copy_ltp_tests)
-
 include $(BUILD_SYSTEM)/tasks/tools/compatibility.mk
 
 .PHONY: vts
diff --git a/core/version_util.mk b/core/version_util.mk
index 0e34634..2bf41ec 100644
--- a/core/version_util.mk
+++ b/core/version_util.mk
@@ -23,6 +23,7 @@
 #     PLATFORM_DISPLAY_VERSION
 #     PLATFORM_SDK_VERSION
 #     PLATFORM_SDK_EXTENSION_VERSION
+#     PLATFORM_BASE_SDK_EXTENSION_VERSION
 #     PLATFORM_VERSION_CODENAME
 #     DEFAULT_APP_TARGET_SDK
 #     BUILD_ID
@@ -67,8 +68,16 @@
 PLATFORM_SDK_EXTENSION_VERSION := $(RELEASE_PLATFORM_SDK_EXTENSION_VERSION)
 .KATI_READONLY := PLATFORM_SDK_EXTENSION_VERSION
 
-# This is the sdk extension version that PLATFORM_SDK_VERSION ships with.
-PLATFORM_BASE_SDK_EXTENSION_VERSION := $(PLATFORM_SDK_EXTENSION_VERSION)
+ifdef PLATFORM_BASE_SDK_EXTENSION_VERSION
+  $(error Do not set PLATFORM_BASE_SDK_EXTENSION_VERSION directly. Use RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION. value: $(PLATFORM_BASE_SDK_EXTENSION_VERSION))
+endif
+ifdef RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION
+  # This is the sdk extension version that PLATFORM_SDK_VERSION ships with.
+  PLATFORM_BASE_SDK_EXTENSION_VERSION := $(RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION)
+else
+  # Fallback to PLATFORM_SDK_EXTENSION_VERSION if RELEASE_PLATFORM_BASE_SDK_EXTENSION_VERSION is undefined.
+  PLATFORM_BASE_SDK_EXTENSION_VERSION := $(PLATFORM_SDK_EXTENSION_VERSION)
+endif
 .KATI_READONLY := PLATFORM_BASE_SDK_EXTENSION_VERSION
 
 ifdef PLATFORM_VERSION_CODENAME
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 3a7256e..b9b226b 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -17,7 +17,6 @@
 # Base modules and settings for the system partition.
 PRODUCT_PACKAGES += \
     abx \
-    aconfigd \
     aconfigd-system \
     adbd_system_api \
     aflags \
@@ -249,6 +248,7 @@
     pintool \
     platform.xml \
     pm \
+    prefetch \
     preinstalled-packages-asl-files.xml \
     preinstalled-packages-platform.xml \
     preinstalled-packages-strict-signature.xml \
diff --git a/target/product/build_variables.mk b/target/product/build_variables.mk
index 7661e06..3326b87 100644
--- a/target/product/build_variables.mk
+++ b/target/product/build_variables.mk
@@ -20,6 +20,9 @@
 # Control libbinder client caching
 $(call soong_config_set, libbinder, release_libbinder_client_cache, $(RELEASE_LIBBINDER_CLIENT_CACHE))
 
+# Control caching while adding service in libbinder cache
+$(call soong_config_set, libbinder, release_libbinder_addservice_cache, $(RELEASE_LIBBINDER_ADDSERVICE_CACHE))
+
 # Use the configured release of sqlite
 $(call soong_config_set, libsqlite3, release_package_libsqlite3, $(RELEASE_PACKAGE_LIBSQLITE3))
 
diff --git a/target/product/generic/Android.bp b/target/product/generic/Android.bp
index ea49af4..bca4fcd 100644
--- a/target/product/generic/Android.bp
+++ b/target/product/generic/Android.bp
@@ -56,10 +56,6 @@
         name: "bugreports",
     },
     {
-        target: "/data/cache",
-        name: "cache",
-    },
-    {
         target: "/sys/kernel/debug",
         name: "d",
     },
@@ -125,6 +121,10 @@
         target: "/system_ext",
         name: "system/system_ext",
     },
+    {
+        target: "/data/cache",
+        name: "cache",
+    },
 ]
 
 filegroup {
@@ -346,11 +346,6 @@
     ],
 }
 
-filegroup {
-    name: "system_image_erofs_compress_hints.txt",
-    srcs: ["erofs_compress_hints.txt"],
-}
-
 android_filesystem_defaults {
     name: "system_image_defaults",
     partition_name: "system",
@@ -374,11 +369,6 @@
         ],
         libs: [":framework-res{.export-package.apk}"],
     },
-    type: "erofs",
-    erofs: {
-        compressor: "lz4hc,9",
-        compress_hints: ":system_image_erofs_compress_hints.txt",
-    },
     build_logtags: true,
     gen_aconfig_flags_pb: true,
 
@@ -391,7 +381,6 @@
 
     deps: [
         "abx",
-        "aconfigd",
         "aconfigd-system",
         "aflags",
         "am",
@@ -510,6 +499,7 @@
         "pintool", // base_system
         "platform.xml", // base_system
         "pm", // base_system
+        "prefetch", //base_system
         "preinstalled-packages-asl-files.xml", // base_system
         "preinstalled-packages-platform-generic-system.xml", // generic_system
         "preinstalled-packages-platform-handheld-system.xml", // handheld_system
@@ -885,8 +875,13 @@
 }
 
 android_system_image {
-    name: "generic_system_image",
+    name: "aosp_shared_system_image",
     defaults: ["system_image_defaults"],
     dirs: android_rootdirs,
     symlinks: android_symlinks,
+    type: "erofs",
+    erofs: {
+        compressor: "lz4hc,9",
+        compress_hints: "erofs_compress_hints.txt",
+    },
 }
diff --git a/target/product/gsi/Android.bp b/target/product/gsi/Android.bp
index 1b8f2d7..9e8946d 100644
--- a/target/product/gsi/Android.bp
+++ b/target/product/gsi/Android.bp
@@ -71,12 +71,21 @@
         target: "/system/product",
         name: "product",
     },
+    {
+        target: "/odm/odm_dlkm/etc",
+        name: "odm_dlkm/etc",
+    },
+    {
+        target: "/vendor/vendor_dlkm/etc",
+        name: "vendor_dlkm/etc",
+    },
 ]
 
 android_system_image {
     name: "android_gsi",
     defaults: ["system_image_defaults"],
     symlinks: gsi_symlinks,
+    dirs: ["cache"],
     deps: [
         ///////////////////////////////////////////
         // gsi_system_ext
@@ -196,4 +205,5 @@
         "true": true,
         default: false,
     }),
+    type: "ext4",
 }
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index 39428d2..f00c38c 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -82,6 +82,7 @@
 # Additional settings used in all GSI builds
 PRODUCT_PRODUCT_PROPERTIES += \
     ro.crypto.metadata_init_delete_all_keys.enabled=false \
+    debug.codec2.bqpool_dealloc_after_stop=1 \
 
 # Window Extensions
 ifneq ($(PRODUCT_IS_ATV),true)
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 15e4187..043a956 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -106,8 +106,12 @@
   ],
   "postsubmit": [
     {
-      // aconfig_storage read api java integration tests
-      "name": "aconfig_storage_read_api.test.java"
+      // aconfig_storage read functional test
+      "name": "aconfig_storage_read_functional"
+    },
+    {
+      // aconfig_storage read unit test
+      "name": "aconfig_storage_read_unit"
     }
   ]
 }
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index bfdf1a7..2f2889c 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -32,6 +32,7 @@
     codegen_mode: CodegenMode,
     flag_ids: HashMap<String, u16>,
     allow_instrumentation: bool,
+    package_fingerprint: u64,
 ) -> Result<Vec<OutputFile>>
 where
     I: Iterator<Item = ProtoParsedFlag>,
@@ -46,6 +47,7 @@
     let runtime_lookup_required =
         flag_elements.iter().any(|elem| elem.is_read_write) || library_exported;
     let container = (flag_elements.first().expect("zero template flags").container).to_string();
+    let is_platform_container = matches!(container.as_str(), "system" | "product" | "vendor");
     let context = Context {
         flag_elements,
         namespace_flags,
@@ -56,6 +58,8 @@
         library_exported,
         allow_instrumentation,
         container,
+        is_platform_container,
+        package_fingerprint: format!("0x{:X}L", package_fingerprint),
     };
     let mut template = TinyTemplate::new();
     template.add_template("Flags.java", include_str!("../../templates/Flags.java.template"))?;
@@ -123,6 +127,8 @@
     pub library_exported: bool,
     pub allow_instrumentation: bool,
     pub container: String,
+    pub is_platform_container: bool,
+    pub package_fingerprint: String,
 }
 
 #[derive(Serialize, Debug)]
@@ -502,6 +508,7 @@
             mode,
             flag_ids,
             true,
+            5801144784618221668,
         )
         .unwrap();
         let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
@@ -513,86 +520,56 @@
         package com.android.aconfig.test;
         // TODO(b/303773055): Remove the annotation after access issue is resolved.
         import android.compat.annotation.UnsupportedAppUsage;
-        import android.os.Binder;
-        import android.provider.DeviceConfig;
-        import android.provider.DeviceConfig.Properties;
-        import android.aconfig.storage.StorageInternalReader;
-        import java.nio.file.Files;
-        import java.nio.file.Paths;
-
+        import android.os.Build;
+        import android.os.flagging.PlatformAconfigPackageInternal;
+        import android.os.flagging.AconfigStorageReadException;
+        import android.util.Log;
         /** @hide */
         public final class FeatureFlagsImpl implements FeatureFlags {
-            private static final boolean isReadFromNew = Files.exists(Paths.get("/metadata/aconfig/boot/enable_only_new_storage"));
+            private static final String TAG = "com.android.aconfig.test.FeatureFlagsImpl";
             private static volatile boolean isCached = false;
-            private static volatile boolean aconfig_test_is_cached = false;
-            private static volatile boolean other_namespace_is_cached = false;
             private static boolean disabledRw = false;
             private static boolean disabledRwExported = false;
             private static boolean disabledRwInOtherNamespace = false;
             private static boolean enabledRw = true;
             private void init() {
-                StorageInternalReader reader = null;
-                boolean foundPackage = true;
                 try {
-                    reader = new StorageInternalReader("system", "com.android.aconfig.test");
+                    PlatformAconfigPackageInternal reader = PlatformAconfigPackageInternal.load("system", "com.android.aconfig.test", 0x5081CE7221C77064L);
+                    AconfigStorageReadException error = reader.getException();
+                    if (error == null) {
+                        disabledRw = reader.getBooleanFlagValue(1);
+                        disabledRwExported = reader.getBooleanFlagValue(2);
+                        enabledRw = reader.getBooleanFlagValue(8);
+                        disabledRwInOtherNamespace = reader.getBooleanFlagValue(3);
+                    } else if (Build.VERSION.SDK_INT > 35 && error.getErrorCode() == 5 /* fingerprint doesn't match*/) {
+                        disabledRw = reader.getBooleanFlagValue("disabled_rw", false);
+                        disabledRwExported = reader.getBooleanFlagValue("disabled_rw_exported", false);
+                        enabledRw = reader.getBooleanFlagValue("enabled_rw", true);
+                        disabledRwInOtherNamespace = reader.getBooleanFlagValue("disabled_rw_in_other_namespace", false);
+                    } else {
+                        if (error.getMessage() != null) {
+                            Log.e(TAG, error.getMessage());
+                        } else {
+                            Log.e(TAG, "Encountered a null AconfigStorageReadException");
+                        }
+                    }
                 } catch (Exception e) {
-                    foundPackage = false;
+                    if (e.getMessage() != null) {
+                        Log.e(TAG, e.getMessage());
+                    } else {
+                        Log.e(TAG, "Encountered a null Exception");
+                    }
+                } catch (NoClassDefFoundError e) {
+                    // for mainline module running on older devices.
+                    // This should be replaces to version check, after the version bump.
+                    if (e.getMessage() != null) {
+                        Log.e(TAG, e.getMessage());
+                    } else {
+                        Log.e(TAG, "Encountered a null NoClassDefFoundError");
+                    }
                 }
-                disabledRw = foundPackage ? reader.getBooleanFlagValue(1) : false;
-                disabledRwExported = foundPackage ? reader.getBooleanFlagValue(2) : false;
-                enabledRw = foundPackage ? reader.getBooleanFlagValue(8) : true;
-                disabledRwInOtherNamespace = foundPackage ? reader.getBooleanFlagValue(3) : false;
                 isCached = true;
             }
-            private void load_overrides_aconfig_test() {
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    Properties properties = DeviceConfig.getProperties("aconfig_test");
-                    disabledRw =
-                        properties.getBoolean(Flags.FLAG_DISABLED_RW, false);
-                    disabledRwExported =
-                        properties.getBoolean(Flags.FLAG_DISABLED_RW_EXPORTED, false);
-                    enabledRw =
-                        properties.getBoolean(Flags.FLAG_ENABLED_RW, true);
-                } catch (NullPointerException e) {
-                    throw new RuntimeException(
-                        "Cannot read value from namespace aconfig_test "
-                        + "from DeviceConfig. It could be that the code using flag "
-                        + "executed before SettingsProvider initialization. Please use "
-                        + "fixed read-only flag by adding is_fixed_read_only: true in "
-                        + "flag declaration.",
-                        e
-                    );
-                } catch (SecurityException e) {
-                    // for isolated process case, skip loading flag value from the storage, use the default
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-                aconfig_test_is_cached = true;
-            }
-
-            private void load_overrides_other_namespace() {
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    Properties properties = DeviceConfig.getProperties("other_namespace");
-                    disabledRwInOtherNamespace =
-                        properties.getBoolean(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false);
-                } catch (NullPointerException e) {
-                    throw new RuntimeException(
-                        "Cannot read value from namespace other_namespace "
-                        + "from DeviceConfig. It could be that the code using flag "
-                        + "executed before SettingsProvider initialization. Please use "
-                        + "fixed read-only flag by adding is_fixed_read_only: true in "
-                        + "flag declaration.",
-                        e
-                    );
-                } catch (SecurityException e) {
-                    // for isolated process case, skip loading flag value from the storage, use the default
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-                other_namespace_is_cached = true;
-            }
 
             @Override
             @com.android.aconfig.annotations.AconfigFlagAccessor
@@ -604,14 +581,8 @@
             @com.android.aconfig.annotations.AconfigFlagAccessor
             @UnsupportedAppUsage
             public boolean disabledRw() {
-                if (isReadFromNew) {
-                    if (!isCached) {
-                        init();
-                    }
-                } else {
-                    if (!aconfig_test_is_cached) {
-                        load_overrides_aconfig_test();
-                    }
+                if (!isCached) {
+                    init();
                 }
                 return disabledRw;
             }
@@ -619,14 +590,8 @@
             @com.android.aconfig.annotations.AconfigFlagAccessor
             @UnsupportedAppUsage
             public boolean disabledRwExported() {
-                if (isReadFromNew) {
-                    if (!isCached) {
-                        init();
-                    }
-                } else {
-                    if (!aconfig_test_is_cached) {
-                        load_overrides_aconfig_test();
-                    }
+                if (!isCached) {
+                    init();
                 }
                 return disabledRwExported;
             }
@@ -634,14 +599,8 @@
             @com.android.aconfig.annotations.AconfigFlagAccessor
             @UnsupportedAppUsage
             public boolean disabledRwInOtherNamespace() {
-                if (isReadFromNew) {
-                    if (!isCached) {
-                        init();
-                    }
-                } else {
-                    if (!other_namespace_is_cached) {
-                        load_overrides_other_namespace();
-                    }
+                if (!isCached) {
+                    init();
                 }
                 return disabledRwInOtherNamespace;
             }
@@ -673,14 +632,8 @@
             @com.android.aconfig.annotations.AconfigFlagAccessor
             @UnsupportedAppUsage
             public boolean enabledRw() {
-                if (isReadFromNew) {
-                    if (!isCached) {
-                        init();
-                    }
-                } else {
-                    if (!aconfig_test_is_cached) {
-                        load_overrides_aconfig_test();
-                    }
+                if (!isCached) {
+                    init();
                 }
                 return enabledRw;
             }
@@ -733,6 +686,7 @@
             mode,
             flag_ids,
             true,
+            5801144784618221668,
         )
         .unwrap();
 
@@ -931,6 +885,7 @@
             mode,
             flag_ids,
             true,
+            5801144784618221668,
         )
         .unwrap();
 
@@ -1052,6 +1007,7 @@
             mode,
             flag_ids,
             true,
+            5801144784618221668,
         )
         .unwrap();
         let expect_featureflags_content = r#"
diff --git a/tools/aconfig/aconfig/src/codegen/rust.rs b/tools/aconfig/aconfig/src/codegen/rust.rs
index 569a34b..82a6ebc 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -259,10 +259,6 @@
 /// flag provider
 pub struct FlagProvider;
 
-static READ_FROM_NEW_STORAGE: LazyLock<bool> = LazyLock::new(|| unsafe {
-    Path::new("/metadata/aconfig/boot/enable_only_new_storage").exists()
-});
-
 static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe {
     get_mapped_storage_file("system", StorageFileType::PackageMap)
     .and_then(|package_map| get_package_read_context(&package_map, "com.android.aconfig.test"))
@@ -275,54 +271,46 @@
 
 /// flag value cache for disabled_rw
 static CACHED_disabled_rw: LazyLock<bool> = LazyLock::new(|| {
-    if *READ_FROM_NEW_STORAGE {
-        // This will be called multiple times. Subsequent calls after the first are noops.
-        logger::init(
-            logger::Config::default()
-                .with_tag_on_device("aconfig_rust_codegen")
-                .with_max_level(LevelFilter::Info));
+    // This will be called multiple times. Subsequent calls after the first are noops.
+    logger::init(
+        logger::Config::default()
+            .with_tag_on_device("aconfig_rust_codegen")
+            .with_max_level(LevelFilter::Info));
 
-        let flag_value_result = FLAG_VAL_MAP
-            .as_ref()
-            .map_err(|err| format!("failed to get flag val map: {err}"))
-            .and_then(|flag_val_map| {
-                PACKAGE_OFFSET
-                    .as_ref()
-                    .map_err(|err| format!("failed to get package read offset: {err}"))
-                    .and_then(|package_offset| {
-                        match package_offset {
-                            Some(offset) => {
-                                get_boolean_flag_value(&flag_val_map, offset + 1)
-                                    .map_err(|err| format!("failed to get flag: {err}"))
-                            },
-                            None => {
-                                log!(Level::Error, "no context found for package com.android.aconfig.test");
-                                Err(format!("failed to flag package com.android.aconfig.test"))
-                            }
-                        }
-                    })
-                });
+    let flag_value_result = FLAG_VAL_MAP
+        .as_ref()
+        .map_err(|err| format!("failed to get flag val map: {err}"))
+        .and_then(|flag_val_map| {
+            PACKAGE_OFFSET
+               .as_ref()
+               .map_err(|err| format!("failed to get package read offset: {err}"))
+               .and_then(|package_offset| {
+                   match package_offset {
+                       Some(offset) => {
+                           get_boolean_flag_value(&flag_val_map, offset + 1)
+                               .map_err(|err| format!("failed to get flag: {err}"))
+                       },
+                       None => {
+                           log!(Level::Error, "no context found for package com.android.aconfig.test");
+                           Err(format!("failed to flag package com.android.aconfig.test"))
+                       }
+                    }
+                })
+            });
 
-        match flag_value_result {
-            Ok(flag_value) => {
-                 return flag_value;
-            },
-            Err(err) => {
-                log!(Level::Error, "aconfig_rust_codegen: error: {err}");
-                return false;
-            }
+    match flag_value_result {
+        Ok(flag_value) => {
+            return flag_value;
+        },
+        Err(err) => {
+            log!(Level::Error, "aconfig_rust_codegen: error: {err}");
+            return false;
         }
-    } else {
-        flags_rust::GetServerConfigurableFlag(
-            "aconfig_flags.aconfig_test",
-            "com.android.aconfig.test.disabled_rw",
-            "false") == "true"
     }
 });
 
 /// flag value cache for disabled_rw_exported
 static CACHED_disabled_rw_exported: LazyLock<bool> = LazyLock::new(|| {
-    if *READ_FROM_NEW_STORAGE {
         // This will be called multiple times. Subsequent calls after the first are noops.
         logger::init(
             logger::Config::default()
@@ -359,17 +347,10 @@
                 return false;
             }
         }
-    } else {
-        flags_rust::GetServerConfigurableFlag(
-            "aconfig_flags.aconfig_test",
-            "com.android.aconfig.test.disabled_rw_exported",
-            "false") == "true"
-    }
 });
 
 /// flag value cache for disabled_rw_in_other_namespace
 static CACHED_disabled_rw_in_other_namespace: LazyLock<bool> = LazyLock::new(|| {
-    if *READ_FROM_NEW_STORAGE {
         // This will be called multiple times. Subsequent calls after the first are noops.
         logger::init(
             logger::Config::default()
@@ -406,18 +387,11 @@
                 return false;
             }
         }
-    } else {
-        flags_rust::GetServerConfigurableFlag(
-            "aconfig_flags.other_namespace",
-            "com.android.aconfig.test.disabled_rw_in_other_namespace",
-            "false") == "true"
-    }
 });
 
 
 /// flag value cache for enabled_rw
 static CACHED_enabled_rw: LazyLock<bool> = LazyLock::new(|| {
-    if *READ_FROM_NEW_STORAGE {
         // This will be called multiple times. Subsequent calls after the first are noops.
         logger::init(
             logger::Config::default()
@@ -454,12 +428,6 @@
                 return true;
             }
         }
-    } else {
-        flags_rust::GetServerConfigurableFlag(
-            "aconfig_flags.aconfig_test",
-            "com.android.aconfig.test.enabled_rw",
-            "true") == "true"
-    }
 });
 
 impl FlagProvider {
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 0ad3d97..c1989a2 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -69,6 +69,7 @@
     declarations: Vec<Input>,
     values: Vec<Input>,
     default_permission: ProtoFlagPermission,
+    allow_read_write: bool,
 ) -> Result<Vec<u8>> {
     let mut parsed_flags = ProtoParsedFlags::new();
 
@@ -195,6 +196,16 @@
         }
     }
 
+    if !allow_read_write {
+        if let Some(pf) = parsed_flags
+            .parsed_flag
+            .iter()
+            .find(|pf| pf.permission() == ProtoFlagPermission::READ_WRITE)
+        {
+            bail!("flag {} has permission READ_WRITE, but allow_read_write is false", pf.name());
+        }
+    }
+
     // Create a sorted parsed_flags
     aconfig_protos::parsed_flags::sort_parsed_flags(&mut parsed_flags);
     aconfig_protos::parsed_flags::verify_fields(&parsed_flags)?;
@@ -214,6 +225,9 @@
         bail!("no parsed flags, or the parsed flags use different packages");
     };
     let package = package.to_string();
+    let mut flag_names =
+        modified_parsed_flags.iter().map(|pf| pf.name().to_string()).collect::<Vec<_>>();
+    let package_fingerprint = compute_flags_fingerprint(&mut flag_names);
     let flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
     generate_java_code(
         &package,
@@ -221,6 +235,7 @@
         codegen_mode,
         flag_ids,
         allow_instrumentation,
+        package_fingerprint,
     )
 }
 
@@ -427,14 +442,14 @@
                     // protect hardcoded offset reads.
                     // Creates a fingerprint of the flag names (which requires sorting the vector).
                     // Fingerprint is used by both codegen and storage files.
-pub fn compute_flags_fingerprint(flag_names: &mut Vec<String>) -> Result<u64> {
+pub fn compute_flags_fingerprint(flag_names: &mut Vec<String>) -> u64 {
     flag_names.sort();
 
     let mut hasher = SipHasher13::new();
     for flag in flag_names {
         hasher.write(flag.as_bytes());
     }
-    Ok(hasher.finish())
+    hasher.finish()
 }
 
 #[allow(dead_code)] // TODO: b/316357686 - Use fingerprint in codegen to
@@ -466,7 +481,7 @@
         let mut extracted_flags = extract_flag_names(parsed_flags).unwrap();
         let hash_result = compute_flags_fingerprint(&mut extracted_flags);
 
-        assert_eq!(hash_result.unwrap(), expected_fingerprint);
+        assert_eq!(hash_result, expected_fingerprint);
     }
 
     #[test]
@@ -487,7 +502,7 @@
         let result_from_names = compute_flags_fingerprint(&mut flag_names_vec);
 
         // Assert the same hash is generated for each case.
-        assert_eq!(result_from_parsed_flags.unwrap(), result_from_names.unwrap());
+        assert_eq!(result_from_parsed_flags, result_from_names);
     }
 
     #[test]
@@ -497,9 +512,9 @@
         let second_parsed_flags = crate::test::parse_second_package_flags();
 
         let mut extracted_flags = extract_flag_names(parsed_flags).unwrap();
-        let result_from_parsed_flags = compute_flags_fingerprint(&mut extracted_flags).unwrap();
+        let result_from_parsed_flags = compute_flags_fingerprint(&mut extracted_flags);
         let mut second_extracted_flags = extract_flag_names(second_parsed_flags).unwrap();
-        let second_result = compute_flags_fingerprint(&mut second_extracted_flags).unwrap();
+        let second_result = compute_flags_fingerprint(&mut second_extracted_flags);
 
         // Different flags should have a different fingerprint.
         assert_ne!(result_from_parsed_flags, second_result);
@@ -576,6 +591,7 @@
             declaration,
             value,
             ProtoFlagPermission::READ_ONLY,
+            true,
         )
         .unwrap();
         let parsed_flags =
@@ -609,6 +625,7 @@
             declaration,
             value,
             ProtoFlagPermission::READ_WRITE,
+            true,
         )
         .unwrap_err();
         assert_eq!(
@@ -640,6 +657,7 @@
             declaration,
             value,
             ProtoFlagPermission::READ_WRITE,
+            true,
         )
         .unwrap_err();
         assert_eq!(
@@ -647,6 +665,121 @@
             "failed to parse memory: expected container argument.container, got declaration.container"
         );
     }
+    #[test]
+    fn test_parse_flags_no_allow_read_write_default_error() {
+        let first_flag = r#"
+        package: "com.first"
+        container: "com.first.container"
+        flag {
+            name: "first"
+            namespace: "first_ns"
+            description: "This is the description of the first flag."
+            bug: "123"
+        }
+        "#;
+        let declaration =
+            vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+        let error = crate::commands::parse_flags(
+            "com.first",
+            Some("com.first.container"),
+            declaration,
+            vec![],
+            ProtoFlagPermission::READ_WRITE,
+            false,
+        )
+        .unwrap_err();
+        assert_eq!(
+            format!("{:?}", error),
+            "flag first has permission READ_WRITE, but allow_read_write is false"
+        );
+    }
+
+    #[test]
+    fn test_parse_flags_no_allow_read_write_value_error() {
+        let first_flag = r#"
+        package: "com.first"
+        container: "com.first.container"
+        flag {
+            name: "first"
+            namespace: "first_ns"
+            description: "This is the description of the first flag."
+            bug: "123"
+        }
+        "#;
+        let declaration =
+            vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+        let first_flag_value = r#"
+        flag_value {
+            package: "com.first"
+            name: "first"
+            state: DISABLED
+            permission: READ_WRITE
+        }
+        "#;
+        let value = vec![Input {
+            source: "memory".to_string(),
+            reader: Box::new(first_flag_value.as_bytes()),
+        }];
+        let error = crate::commands::parse_flags(
+            "com.first",
+            Some("com.first.container"),
+            declaration,
+            value,
+            ProtoFlagPermission::READ_ONLY,
+            false,
+        )
+        .unwrap_err();
+        assert_eq!(
+            format!("{:?}", error),
+            "flag first has permission READ_WRITE, but allow_read_write is false"
+        );
+    }
+
+    #[test]
+    fn test_parse_flags_no_allow_read_write_success() {
+        let first_flag = r#"
+        package: "com.first"
+        container: "com.first.container"
+        flag {
+            name: "first"
+            namespace: "first_ns"
+            description: "This is the description of the first flag."
+            bug: "123"
+        }
+        "#;
+        let declaration =
+            vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+        let first_flag_value = r#"
+        flag_value {
+            package: "com.first"
+            name: "first"
+            state: DISABLED
+            permission: READ_ONLY
+        }
+        "#;
+        let value = vec![Input {
+            source: "memory".to_string(),
+            reader: Box::new(first_flag_value.as_bytes()),
+        }];
+        let flags_bytes = crate::commands::parse_flags(
+            "com.first",
+            Some("com.first.container"),
+            declaration,
+            value,
+            ProtoFlagPermission::READ_ONLY,
+            false,
+        )
+        .unwrap();
+        let parsed_flags =
+            aconfig_protos::parsed_flags::try_from_binary_proto(&flags_bytes).unwrap();
+        assert_eq!(1, parsed_flags.parsed_flag.len());
+        let parsed_flag = parsed_flags.parsed_flag.first().unwrap();
+        assert_eq!(ProtoFlagState::DISABLED, parsed_flag.state());
+        assert_eq!(ProtoFlagPermission::READ_ONLY, parsed_flag.permission());
+    }
 
     #[test]
     fn test_parse_flags_override_fixed_read_only() {
@@ -682,6 +815,7 @@
             declaration,
             value,
             ProtoFlagPermission::READ_WRITE,
+            true,
         )
         .unwrap_err();
         assert_eq!(
@@ -716,6 +850,7 @@
             declaration,
             value,
             ProtoFlagPermission::READ_ONLY,
+            true,
         )
         .unwrap();
         let parsed_flags =
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index e184efe..c390288 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -62,6 +62,12 @@
                             &commands::DEFAULT_FLAG_PERMISSION,
                         )),
                 )
+                .arg(
+                    Arg::new("allow-read-write")
+                        .long("allow-read-write")
+                        .value_parser(clap::value_parser!(bool))
+                        .default_value("true"),
+                )
                 .arg(Arg::new("cache").long("cache").required(true)),
         )
         .subcommand(
@@ -242,12 +248,15 @@
                 sub_matches,
                 "default-permission",
             )?;
+            let allow_read_write = get_optional_arg::<bool>(sub_matches, "allow-read-write")
+                .expect("failed to parse allow-read-write");
             let output = commands::parse_flags(
                 package,
                 container,
                 declarations,
                 values,
                 *default_permission,
+                *allow_read_write,
             )
             .context("failed to create cache")?;
             let path = get_required_arg::<String>(sub_matches, "cache")?;
diff --git a/tools/aconfig/aconfig/src/storage/flag_info.rs b/tools/aconfig/aconfig/src/storage/flag_info.rs
index 5d565e8..0b5a67b 100644
--- a/tools/aconfig/aconfig/src/storage/flag_info.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_info.rs
@@ -73,7 +73,7 @@
 
     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());
+        let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
         create_flag_info("mockup", &packages, DEFAULT_FILE_VERSION)
     }
 
diff --git a/tools/aconfig/aconfig/src/storage/flag_table.rs b/tools/aconfig/aconfig/src/storage/flag_table.rs
index 8856eb6..ae5a16c 100644
--- a/tools/aconfig/aconfig/src/storage/flag_table.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_table.rs
@@ -148,7 +148,7 @@
 
     fn create_test_flag_table_from_source() -> Result<FlagTable> {
         let caches = parse_all_test_flags();
-        let packages = group_flags_by_package(caches.iter());
+        let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
         create_flag_table("mockup", &packages, DEFAULT_FILE_VERSION)
     }
 
diff --git a/tools/aconfig/aconfig/src/storage/flag_value.rs b/tools/aconfig/aconfig/src/storage/flag_value.rs
index 0dd5a9d..065b7e3 100644
--- a/tools/aconfig/aconfig/src/storage/flag_value.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_value.rs
@@ -72,7 +72,7 @@
 
     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());
+        let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
         create_flag_value("mockup", &packages, DEFAULT_FILE_VERSION)
     }
 
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index c7fd55a..4bc72f7 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -22,6 +22,7 @@
 use anyhow::Result;
 use std::collections::{HashMap, HashSet};
 
+use crate::commands::compute_flags_fingerprint;
 use crate::storage::{
     flag_info::create_flag_info, flag_table::create_flag_table, flag_value::create_flag_value,
     package_table::create_package_table,
@@ -59,7 +60,7 @@
     }
 }
 
-pub fn group_flags_by_package<'a, I>(parsed_flags_vec_iter: I) -> Vec<FlagPackage<'a>>
+pub fn group_flags_by_package<'a, I>(parsed_flags_vec_iter: I, version: u32) -> Vec<FlagPackage<'a>>
 where
     I: Iterator<Item = &'a ProtoParsedFlags>,
 {
@@ -76,13 +77,18 @@
         }
     }
 
-    // cacluate boolean flag start index for each package
+    // Calculate boolean flag start index for each package
     let mut boolean_start_index = 0;
     for p in packages.iter_mut() {
         p.boolean_start_index = boolean_start_index;
         boolean_start_index += p.boolean_flags.len() as u32;
 
-        // TODO: b/316357686 - Calculate fingerprint and add to package.
+        if version >= 2 {
+            let mut flag_names_vec =
+                p.flag_names.clone().into_iter().map(String::from).collect::<Vec<_>>();
+            let fingerprint = compute_flags_fingerprint(&mut flag_names_vec);
+            p.fingerprint = fingerprint;
+        }
     }
 
     packages
@@ -97,7 +103,7 @@
 where
     I: Iterator<Item = &'a ProtoParsedFlags>,
 {
-    let packages = group_flags_by_package(parsed_flags_vec_iter);
+    let packages = group_flags_by_package(parsed_flags_vec_iter, version);
 
     match file {
         StorageFileType::PackageMap => {
@@ -121,6 +127,8 @@
 
 #[cfg(test)]
 mod tests {
+    use aconfig_storage_file::DEFAULT_FILE_VERSION;
+
     use super::*;
     use crate::Input;
 
@@ -163,6 +171,7 @@
                         reader: Box::new(value_content),
                     }],
                     crate::commands::DEFAULT_FLAG_PERMISSION,
+                    true,
                 )
                 .unwrap();
                 aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -173,7 +182,7 @@
     #[test]
     fn test_flag_package() {
         let caches = parse_all_test_flags();
-        let packages = group_flags_by_package(caches.iter());
+        let packages = group_flags_by_package(caches.iter(), DEFAULT_FILE_VERSION);
 
         for pkg in packages.iter() {
             let pkg_name = pkg.package_name;
@@ -193,6 +202,7 @@
         assert!(packages[0].flag_names.contains("disabled_rw"));
         assert!(packages[0].flag_names.contains("enabled_ro"));
         assert_eq!(packages[0].boolean_start_index, 0);
+        assert_eq!(packages[0].fingerprint, 0);
 
         assert_eq!(packages[1].package_name, "com.android.aconfig.storage.test_2");
         assert_eq!(packages[1].package_id, 1);
@@ -201,6 +211,7 @@
         assert!(packages[1].flag_names.contains("disabled_rw"));
         assert!(packages[1].flag_names.contains("enabled_fixed_ro"));
         assert_eq!(packages[1].boolean_start_index, 3);
+        assert_eq!(packages[0].fingerprint, 0);
 
         assert_eq!(packages[2].package_name, "com.android.aconfig.storage.test_4");
         assert_eq!(packages[2].package_id, 2);
@@ -208,5 +219,49 @@
         assert!(packages[2].flag_names.contains("enabled_rw"));
         assert!(packages[2].flag_names.contains("enabled_fixed_ro"));
         assert_eq!(packages[2].boolean_start_index, 6);
+        assert_eq!(packages[2].fingerprint, 0);
+    }
+
+    #[test]
+    fn test_flag_package_with_fingerprint() {
+        let caches = parse_all_test_flags();
+        let packages = group_flags_by_package(caches.iter(), 2);
+
+        for pkg in packages.iter() {
+            let pkg_name = pkg.package_name;
+            assert_eq!(pkg.flag_names.len(), pkg.boolean_flags.len());
+            for pf in pkg.boolean_flags.iter() {
+                assert!(pkg.flag_names.contains(pf.name()));
+                assert_eq!(pf.package(), pkg_name);
+            }
+        }
+
+        assert_eq!(packages.len(), 3);
+
+        assert_eq!(packages[0].package_name, "com.android.aconfig.storage.test_1");
+        assert_eq!(packages[0].package_id, 0);
+        assert_eq!(packages[0].flag_names.len(), 3);
+        assert!(packages[0].flag_names.contains("enabled_rw"));
+        assert!(packages[0].flag_names.contains("disabled_rw"));
+        assert!(packages[0].flag_names.contains("enabled_ro"));
+        assert_eq!(packages[0].boolean_start_index, 0);
+        assert_eq!(packages[0].fingerprint, 15248948510590158086u64);
+
+        assert_eq!(packages[1].package_name, "com.android.aconfig.storage.test_2");
+        assert_eq!(packages[1].package_id, 1);
+        assert_eq!(packages[1].flag_names.len(), 3);
+        assert!(packages[1].flag_names.contains("enabled_ro"));
+        assert!(packages[1].flag_names.contains("disabled_rw"));
+        assert!(packages[1].flag_names.contains("enabled_fixed_ro"));
+        assert_eq!(packages[1].boolean_start_index, 3);
+        assert_eq!(packages[1].fingerprint, 4431940502274857964u64);
+
+        assert_eq!(packages[2].package_name, "com.android.aconfig.storage.test_4");
+        assert_eq!(packages[2].package_id, 2);
+        assert_eq!(packages[2].flag_names.len(), 2);
+        assert!(packages[2].flag_names.contains("enabled_rw"));
+        assert!(packages[2].flag_names.contains("enabled_fixed_ro"));
+        assert_eq!(packages[2].boolean_start_index, 6);
+        assert_eq!(packages[2].fingerprint, 16233229917711622375u64);
     }
 }
diff --git a/tools/aconfig/aconfig/src/storage/package_table.rs b/tools/aconfig/aconfig/src/storage/package_table.rs
index e46607b..53daa7f 100644
--- a/tools/aconfig/aconfig/src/storage/package_table.rs
+++ b/tools/aconfig/aconfig/src/storage/package_table.rs
@@ -112,24 +112,59 @@
 
 #[cfg(test)]
 mod tests {
-    use aconfig_storage_file::DEFAULT_FILE_VERSION;
+    use aconfig_storage_file::{DEFAULT_FILE_VERSION, MAX_SUPPORTED_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> {
+    pub fn create_test_package_table_from_source(version: u32) -> Result<PackageTable> {
         let caches = parse_all_test_flags();
-        let packages = group_flags_by_package(caches.iter());
-        create_package_table("mockup", &packages, DEFAULT_FILE_VERSION)
+        let packages = group_flags_by_package(caches.iter(), version);
+        create_package_table("mockup", &packages, version)
     }
 
     #[test]
     // this test point locks down the table creation and each field
-    fn test_table_contents() {
-        let package_table = create_test_package_table_from_source();
-        assert!(package_table.is_ok());
+    fn test_table_contents_default_version() {
+        let package_table_result = create_test_package_table_from_source(DEFAULT_FILE_VERSION);
+        assert!(package_table_result.is_ok());
+        let package_table = package_table_result.unwrap();
+
         let expected_package_table =
             aconfig_storage_file::test_utils::create_test_package_table(DEFAULT_FILE_VERSION);
-        assert_eq!(package_table.unwrap(), expected_package_table);
+
+        assert_eq!(package_table.header, expected_package_table.header);
+        assert_eq!(package_table.buckets, expected_package_table.buckets);
+        for (node, expected_node) in
+            package_table.nodes.iter().zip(expected_package_table.nodes.iter())
+        {
+            assert_eq!(node.package_name, expected_node.package_name);
+            assert_eq!(node.package_id, expected_node.package_id);
+            assert_eq!(node.boolean_start_index, expected_node.boolean_start_index);
+            assert_eq!(node.next_offset, expected_node.next_offset);
+        }
+    }
+
+    #[test]
+    // this test point locks down the table creation and each field
+    fn test_table_contents_max_version() {
+        let package_table_result =
+            create_test_package_table_from_source(MAX_SUPPORTED_FILE_VERSION);
+        assert!(package_table_result.is_ok());
+        let package_table = package_table_result.unwrap();
+
+        let expected_package_table =
+            aconfig_storage_file::test_utils::create_test_package_table(MAX_SUPPORTED_FILE_VERSION);
+
+        assert_eq!(package_table.header, expected_package_table.header);
+        assert_eq!(package_table.buckets, expected_package_table.buckets);
+        for (node, expected_node) in
+            package_table.nodes.iter().zip(expected_package_table.nodes.iter())
+        {
+            assert_eq!(node.package_name, expected_node.package_name);
+            assert_eq!(node.package_id, expected_node.package_id);
+            assert_eq!(node.boolean_start_index, expected_node.boolean_start_index);
+            assert_eq!(node.next_offset, expected_node.next_offset);
+        }
     }
 }
diff --git a/tools/aconfig/aconfig/src/test.rs b/tools/aconfig/aconfig/src/test.rs
index a19b372..10da252 100644
--- a/tools/aconfig/aconfig/src/test.rs
+++ b/tools/aconfig/aconfig/src/test.rs
@@ -266,6 +266,7 @@
                 reader: Box::new(include_bytes!("../tests/read_only_test.values").as_slice()),
             }],
             crate::commands::DEFAULT_FLAG_PERMISSION,
+            true,
         )
         .unwrap();
         aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -290,6 +291,7 @@
                 },
             ],
             crate::commands::DEFAULT_FLAG_PERMISSION,
+            true,
         )
         .unwrap();
         aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
@@ -308,6 +310,7 @@
                 reader: Box::new(include_bytes!("../tests/third.values").as_slice()),
             }],
             crate::commands::DEFAULT_FLAG_PERMISSION,
+            true,
         )
         .unwrap();
         aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index cb52150..3fc444a 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -1,61 +1,109 @@
 package {package_name};
 {{ -if not is_test_mode }}
 {{ -if allow_instrumentation }}
-{{ if not library_exported- }}
+{{ if not library_exported- }}{#- only new storage for prod mode #}
 // TODO(b/303773055): Remove the annotation after access issue is resolved.
 import android.compat.annotation.UnsupportedAppUsage;
-{{ -endif }}
-
 {{ -if runtime_lookup_required }}
-import android.os.Binder;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
-
-{{ -if not library_exported }}
-import android.aconfig.storage.StorageInternalReader;
-import java.nio.file.Files;
-import java.nio.file.Paths;
+import android.os.Build;
+{{ if is_platform_container }}
+import android.os.flagging.PlatformAconfigPackageInternal;
+{{ -else }}
+import android.os.flagging.AconfigPackageInternal;
 {{ -endif }}
-
+import android.os.flagging.AconfigStorageReadException;
+import android.util.Log;
 {{ -endif }}
 /** @hide */
 public final class FeatureFlagsImpl implements FeatureFlags \{
 {{ -if runtime_lookup_required }}
-{{ -if not library_exported }}
-    private static final boolean isReadFromNew = Files.exists(Paths.get("/metadata/aconfig/boot/enable_only_new_storage"));
+    private static final String TAG = "{package_name}.FeatureFlagsImpl";
     private static volatile boolean isCached = false;
-{{ -endif }}
-{{ -for namespace_with_flags in namespace_flags }}
-    private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
-{{ -endfor- }}
-
 {{ for flag in flag_elements }}
 {{ -if flag.is_read_write }}
     private static boolean {flag.method_name} = {flag.default_value};
 {{ -endif }}
 {{ -endfor }}
 
-{{ if not library_exported }}
     private void init() \{
-        StorageInternalReader reader = null;
-        boolean foundPackage = true;
         try \{
-            reader = new StorageInternalReader("{container}", "{package_name}");
+{{ if is_platform_container }}
+            PlatformAconfigPackageInternal reader = PlatformAconfigPackageInternal.load("{container}", "{package_name}", {package_fingerprint});
+{{ -else }}
+            AconfigPackageInternal reader = AconfigPackageInternal.load("{container}", "{package_name}", {package_fingerprint});
+{{ -endif }}
+            AconfigStorageReadException error = reader.getException();
+            if (error == null) \{
+            {{ for namespace_with_flags in namespace_flags }}
+            {{ -for flag in namespace_with_flags.flags }}
+            {{ -if flag.is_read_write }}
+                {flag.method_name} = reader.getBooleanFlagValue({flag.flag_offset});
+            {{ endif }}
+            {{ -endfor }}
+            {{ -endfor }}
+            } else if (Build.VERSION.SDK_INT > 35 && error.getErrorCode() == 5 /* fingerprint doesn't match*/) \{
+            {{ for namespace_with_flags in namespace_flags }}
+            {{ -for flag in namespace_with_flags.flags }}
+            {{ -if flag.is_read_write }}
+                {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
+            {{ -endif }}
+            {{ -endfor }}
+            {{ -endfor }}
+            } else \{
+                if (error.getMessage() != null) \{
+                    Log.e(TAG, error.getMessage());
+                } else \{
+                    Log.e(TAG, "Encountered a null AconfigStorageReadException");
+                }
+            }
         } catch (Exception e) \{
-            foundPackage = false;
+            if (e.getMessage() != null) \{
+                Log.e(TAG, e.getMessage());
+            } else \{
+                Log.e(TAG, "Encountered a null Exception");
+            }
+        } catch (NoClassDefFoundError e) \{
+            // for mainline module running on older devices.
+            // This should be replaces to version check, after the version bump.
+            if (e.getMessage() != null) \{
+                Log.e(TAG, e.getMessage());
+            } else \{
+                Log.e(TAG, "Encountered a null NoClassDefFoundError");
+            }
         }
-        {{ for namespace_with_flags in namespace_flags }}
-        {{ -for flag in namespace_with_flags.flags }}
-        {{ if flag.is_read_write }}
-            {flag.method_name} = foundPackage ? reader.getBooleanFlagValue({flag.flag_offset}) : {flag.default_value};
-        {{ endif }}
-        {{ -endfor }}
-        {{ -endfor }}
         isCached = true;
     }
-{{ endif }}
-
-
+{{ -endif }}{#- end of runtime_lookup_required #}
+{{ -for flag in flag_elements }}
+    @Override
+    @com.android.aconfig.annotations.AconfigFlagAccessor
+    @UnsupportedAppUsage
+    public boolean {flag.method_name}() \{
+{{ -if flag.is_read_write }}
+        if (!isCached) \{
+            init();
+        }
+        return {flag.method_name};
+{{ -else }}
+        return {flag.default_value};
+{{ -endif }}
+    }
+{{ endfor }}
+}
+{{ -else- }}{#- device config for exproted mode #}
+import android.os.Binder;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+/** @hide */
+public final class FeatureFlagsImpl implements FeatureFlags \{
+{{ -for namespace_with_flags in namespace_flags }}
+    private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
+{{ -endfor- }}
+{{ for flag in flag_elements }}
+{{ -if flag.is_read_write }}
+    private static boolean {flag.method_name} = {flag.default_value};
+{{ -endif }}
+{{ -endfor }}
 {{ for namespace_with_flags in namespace_flags }}
     private void load_overrides_{namespace_with_flags.namespace}() \{
         final long ident = Binder.clearCallingIdentity();
@@ -84,40 +132,17 @@
         {namespace_with_flags.namespace}_is_cached = true;
     }
 {{ endfor- }}
-
-{{ -endif }}{#- end of runtime_lookup_required #}
 {{ -for flag in flag_elements }}
     @Override
-{{ -if not library_exported }}
-    @com.android.aconfig.annotations.AconfigFlagAccessor
-    @UnsupportedAppUsage
-{{ -endif }}
     public boolean {flag.method_name}() \{
-{{ -if not library_exported }}
-{{ -if flag.is_read_write }}
-        if (isReadFromNew) \{
-            if (!isCached) \{
-                init();
-            }
-        } else \{
-            if (!{flag.device_config_namespace}_is_cached) \{
-                load_overrides_{flag.device_config_namespace}();
-            }
-        }
-        return {flag.method_name};
-{{ -else }}
-        return {flag.default_value};
-{{ -endif }}
-{{ else }}
         if (!{flag.device_config_namespace}_is_cached) \{
             load_overrides_{flag.device_config_namespace}();
         }
         return {flag.method_name};
-{{ -endif }}
     }
 {{ endfor }}
 }
-
+{{ -endif- }} {#- end exported mode #}
 {{ else }} {#- else for allow_instrumentation is not enabled #}
 {{ if not library_exported- }}
 // TODO(b/303773055): Remove the annotation after access issue is resolved.
diff --git a/tools/aconfig/aconfig/templates/cpp_source_file.template b/tools/aconfig/aconfig/templates/cpp_source_file.template
index df3b10d..9be59e0 100644
--- a/tools/aconfig/aconfig/templates/cpp_source_file.template
+++ b/tools/aconfig/aconfig/templates/cpp_source_file.template
@@ -76,17 +76,8 @@
             : boolean_start_index_()
             {{ -endif }}
             , flag_value_file_(nullptr)
-            , read_from_new_storage_(false)
             , package_exists_in_storage_(true) \{
 
-            if (access("/metadata/aconfig/boot/enable_only_new_storage", F_OK) == 0) \{
-               read_from_new_storage_ = true;
-            }
-
-            if (!read_from_new_storage_) \{
-               return;
-            }
-
             auto package_map_file = aconfig_storage::get_mapped_file(
                  "{container}",
                  aconfig_storage::StorageFileType::package_map);
@@ -137,26 +128,19 @@
             {{ -if item.readwrite }}
             if (cache_[{item.readwrite_idx}] == -1) \{
             {{ if allow_instrumentation- }}
-                if (read_from_new_storage_) \{
-                    if (!package_exists_in_storage_) \{
-                       return {item.default_value};
-                    }
-
-                    auto value = aconfig_storage::get_boolean_flag_value(
-                        *flag_value_file_,
-                        boolean_start_index_ + {item.flag_offset});
-
-                    if (!value.ok()) \{
-                        ALOGE("error: failed to read flag value: %s", value.error().c_str());
-                    }
-
-                    cache_[{item.readwrite_idx}] = *value;
-                } else \{
-                    cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
-                        "aconfig_flags.{item.device_config_namespace}",
-                        "{item.device_config_flag}",
-                        "{item.default_value}") == "true";
+                if (!package_exists_in_storage_) \{
+                    return {item.default_value};
                 }
+
+                auto value = aconfig_storage::get_boolean_flag_value(
+                    *flag_value_file_,
+                    boolean_start_index_ + {item.flag_offset});
+
+                if (!value.ok()) \{
+                    ALOGE("error: failed to read flag value: %s", value.error().c_str());
+                }
+
+                cache_[{item.readwrite_idx}] = *value;
             {{ -else- }}
                 cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
                     "aconfig_flags.{item.device_config_namespace}",
@@ -183,8 +167,6 @@
 
         std::unique_ptr<aconfig_storage::MappedStorageFile> flag_value_file_;
 
-        bool read_from_new_storage_;
-
         bool package_exists_in_storage_;
     {{ -endif }}
     {{ -endif }}
diff --git a/tools/aconfig/aconfig/templates/rust.template b/tools/aconfig/aconfig/templates/rust.template
index d0079d4..e9e1032 100644
--- a/tools/aconfig/aconfig/templates/rust.template
+++ b/tools/aconfig/aconfig/templates/rust.template
@@ -10,10 +10,6 @@
 
 {{ if has_readwrite- }}
 {{ if allow_instrumentation }}
-static READ_FROM_NEW_STORAGE: LazyLock<bool> = LazyLock::new(|| unsafe \{
-    Path::new("/metadata/aconfig/boot/enable_only_new_storage").exists()
-});
-
 static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe \{
     get_mapped_storage_file("{container}", StorageFileType::PackageMap)
     .and_then(|package_map| get_package_read_context(&package_map, "{package}"))
@@ -31,48 +27,41 @@
 {{ if allow_instrumentation }}
 static CACHED_{flag.name}: LazyLock<bool> = LazyLock::new(|| \{
 
-    if *READ_FROM_NEW_STORAGE \{
-        // This will be called multiple times. Subsequent calls after the first are noops.
-        logger::init(
-            logger::Config::default()
-                .with_tag_on_device("aconfig_rust_codegen")
-                .with_max_level(LevelFilter::Info));
+    // This will be called multiple times. Subsequent calls after the first are noops.
+    logger::init(
+        logger::Config::default()
+            .with_tag_on_device("aconfig_rust_codegen")
+            .with_max_level(LevelFilter::Info));
 
-        let flag_value_result = FLAG_VAL_MAP
-            .as_ref()
-            .map_err(|err| format!("failed to get flag val map: \{err}"))
-            .and_then(|flag_val_map| \{
-                PACKAGE_OFFSET
-                    .as_ref()
-                    .map_err(|err| format!("failed to get package read offset: \{err}"))
-                    .and_then(|package_offset| \{
-                        match package_offset \{
-                            Some(offset) => \{
-                                get_boolean_flag_value(&flag_val_map, offset + {flag.flag_offset})
-                                    .map_err(|err| format!("failed to get flag: \{err}"))
-                            },
-                            None => \{
-                                 log!(Level::Error, "no context found for package {package}");
-                                 Err(format!("failed to flag package {package}"))
-                            }
+    let flag_value_result = FLAG_VAL_MAP
+        .as_ref()
+        .map_err(|err| format!("failed to get flag val map: \{err}"))
+        .and_then(|flag_val_map| \{
+            PACKAGE_OFFSET
+                .as_ref()
+                .map_err(|err| format!("failed to get package read offset: \{err}"))
+                .and_then(|package_offset| \{
+                    match package_offset \{
+                        Some(offset) => \{
+                            get_boolean_flag_value(&flag_val_map, offset + {flag.flag_offset})
+                                .map_err(|err| format!("failed to get flag: \{err}"))
+                        },
+                        None => \{
+                            log!(Level::Error, "no context found for package {package}");
+                            Err(format!("failed to flag package {package}"))
                         }
-                    })
-                });
+                    }
+                })
+            });
 
-        match flag_value_result \{
-            Ok(flag_value) => \{
-                return flag_value;
-            },
-            Err(err) => \{
-                log!(Level::Error, "aconfig_rust_codegen: error: \{err}");
-                return {flag.default_value};
-            }
+    match flag_value_result \{
+        Ok(flag_value) => \{
+            return flag_value;
+        },
+        Err(err) => \{
+            log!(Level::Error, "aconfig_rust_codegen: error: \{err}");
+            return {flag.default_value};
         }
-    } else \{
-        flags_rust::GetServerConfigurableFlag(
-            "aconfig_flags.{flag.device_config_namespace}",
-            "{flag.device_config_flag}",
-            "{flag.default_value}") == "true"
     }
 
 });
diff --git a/tools/aconfig/aconfig_flags/flags.aconfig b/tools/aconfig/aconfig_flags/flags.aconfig
index b66d282..0a004ca 100644
--- a/tools/aconfig/aconfig_flags/flags.aconfig
+++ b/tools/aconfig/aconfig_flags/flags.aconfig
@@ -14,11 +14,3 @@
   bug: "369808805"
   description: "When enabled, launch aconfigd from config infra module."
 }
-
-flag {
-  name: "enable_system_aconfigd_rust"
-  namespace: "core_experiments_team_internal"
-  bug: "378079539"
-  description: "When enabled, the aconfigd cc_binary target becomes a no-op, and the rust_binary aconfigd-system target starts up."
-  is_fixed_read_only: true
-}
diff --git a/tools/aconfig/aconfig_flags/src/lib.rs b/tools/aconfig/aconfig_flags/src/lib.rs
index b413c62..2e89127 100644
--- a/tools/aconfig/aconfig_flags/src/lib.rs
+++ b/tools/aconfig/aconfig_flags/src/lib.rs
@@ -39,11 +39,6 @@
     pub fn enable_aconfigd_from_mainline() -> bool {
         aconfig_flags_rust::enable_only_new_storage()
     }
-
-    /// Returns the value for the enable_system_aconfigd_rust flag.
-    pub fn enable_system_aconfigd_rust() -> bool {
-        aconfig_flags_rust::enable_system_aconfigd_rust()
-    }
 }
 
 /// Module used when building with cargo
@@ -60,10 +55,4 @@
         // Used only to enable typechecking and testing with cargo
         true
     }
-
-    /// Returns a placeholder value for the enable_system_aconfigd_rust flag.
-    pub fn enable_system_aconfigd_rust() -> bool {
-        // Used only to enable typechecking and testing with cargo
-        true
-    }
 }
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
index 55780ed..7c603df 100644
--- a/tools/aconfig/aconfig_storage_file/src/test_utils.rs
+++ b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
@@ -46,14 +46,22 @@
     let first_node = PackageTableNode {
         package_name: String::from("com.android.aconfig.storage.test_2"),
         package_id: 1,
-        fingerprint: 0,
+        fingerprint: match version {
+            1 => 0,
+            2 => 4431940502274857964u64,
+            _ => panic!("Unsupported version."),
+        },
         boolean_start_index: 3,
         next_offset: None,
     };
     let second_node = PackageTableNode {
         package_name: String::from("com.android.aconfig.storage.test_1"),
         package_id: 0,
-        fingerprint: 0,
+        fingerprint: match version {
+            1 => 0,
+            2 => 15248948510590158086u64,
+            _ => panic!("Unsupported version."),
+        },
         boolean_start_index: 0,
         next_offset: match version {
             1 => Some(159),
@@ -64,7 +72,11 @@
     let third_node = PackageTableNode {
         package_name: String::from("com.android.aconfig.storage.test_4"),
         package_id: 2,
-        fingerprint: 0,
+        fingerprint: match version {
+            1 => 0,
+            2 => 16233229917711622375u64,
+            _ => panic!("Unsupported version."),
+        },
         boolean_start_index: 6,
         next_offset: None,
     };
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
index b1c7ee7..324c55d 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
@@ -39,6 +39,8 @@
     /** Error code indicating that there was an error reading the Aconfig Storage file. */
     public static final int ERROR_CANNOT_READ_STORAGE_FILE = 4;
 
+    public static final int ERROR_FILE_FINGERPRINT_MISMATCH = 5;
+
     private final int mErrorCode;
 
     /**
@@ -126,6 +128,8 @@
                 return "ERROR_CONTAINER_NOT_FOUND";
             case ERROR_CANNOT_READ_STORAGE_FILE:
                 return "ERROR_CANNOT_READ_STORAGE_FILE";
+            case ERROR_FILE_FINGERPRINT_MISMATCH:
+                return "ERROR_FILE_FINGERPRINT_MISMATCH";
             default:
                 return "<Unknown error code " + mErrorCode + ">";
         }
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
index b0b1b9b..c354873 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
@@ -42,4 +42,20 @@
                 return null;
         }
     }
+
+    @Override
+    public String toString() {
+        switch (type) {
+            case 0:
+                return "PACKAGE_MAP";
+            case 1:
+                return "FLAG_MAP";
+            case 2:
+                return "FLAG_VAL";
+            case 3:
+                return "FLAG_INFO";
+            default:
+                return "unrecognized type";
+        }
+    }
 }
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
index 8306cc6..f1a4e26 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
@@ -26,7 +26,10 @@
 import java.nio.file.Paths;
 import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /** @hide */
 public class StorageFileProvider {
@@ -52,13 +55,20 @@
     }
 
     /** @hide */
-    public List<Path> listPackageMapFiles() {
-        List<Path> result = new ArrayList<>();
+    public List<String> listContainers(String[] excludes) {
+        List<String> result = new ArrayList<>();
+        Set<String> set = new HashSet<>(Arrays.asList(excludes));
+
         try {
             DirectoryStream<Path> stream =
                     Files.newDirectoryStream(Paths.get(mMapPath), "*" + PMAP_FILE_EXT);
             for (Path entry : stream) {
-                result.add(entry);
+                String fileName = entry.getFileName().toString();
+                String container =
+                        fileName.substring(0, fileName.length() - PMAP_FILE_EXT.length());
+                if (!set.contains(container)) {
+                    result.add(container);
+                }
             }
         } catch (NoSuchFileException e) {
             return result;
@@ -77,22 +87,23 @@
 
     /** @hide */
     public FlagTable getFlagTable(String container) {
-        return FlagTable.fromBytes(mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT)));
+        return FlagTable.fromBytes(
+                mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT), FileType.FLAG_MAP));
     }
 
     /** @hide */
     public FlagValueList getFlagValueList(String container) {
         return FlagValueList.fromBytes(
-                mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT)));
+                mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT), FileType.FLAG_VAL));
     }
 
     /** @hide */
     public static PackageTable getPackageTable(Path path) {
-        return PackageTable.fromBytes(mapStorageFile(path));
+        return PackageTable.fromBytes(mapStorageFile(path, FileType.PACKAGE_MAP));
     }
 
     // Map a storage file given file path
-    private static MappedByteBuffer mapStorageFile(Path file) {
+    private static MappedByteBuffer mapStorageFile(Path file, FileType type) {
         FileChannel channel = null;
         try {
             channel = FileChannel.open(file, StandardOpenOption.READ);
@@ -100,7 +111,7 @@
         } catch (Exception e) {
             throw new AconfigStorageException(
                     AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                    String.format("Fail to mmap storage file %s", file),
+                    String.format("Fail to mmap storage %s file %s", type.toString(), file),
                     e);
         } finally {
             quietlyDispose(channel);
diff --git a/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map b/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
index 16f4054..0a9f95e 100644
--- a/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
+++ b/tools/aconfig/aconfig_storage_file/tests/data/v2/package_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
index 4d7ab2a..5906d8b 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
@@ -116,5 +116,9 @@
         assertTrue(node1.hasPackageFingerprint());
         assertTrue(node2.hasPackageFingerprint());
         assertTrue(node4.hasPackageFingerprint());
+
+        assertEquals(-3197795563119393530L, node1.getPackageFingerprint());
+        assertEquals(4431940502274857964L, node2.getPackageFingerprint());
+        assertEquals(-2213514155997929241L, node4.getPackageFingerprint());
     }
 }
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
index 4e90e6c..a820970 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
@@ -29,7 +29,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.List;
 
@@ -37,15 +36,20 @@
 public class StorageFileProviderTest {
 
     @Test
-    public void testListpackageMapFiles() throws Exception {
+    public void testlistContainers() throws Exception {
         StorageFileProvider p =
                 new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
-        List<Path> file = p.listPackageMapFiles();
-        assertEquals(2, file.size());
+        String[] excludes = {};
+        List<String> containers = p.listContainers(excludes);
+        assertEquals(2, containers.size());
+
+        excludes = new String[] {"mock.v1"};
+        containers = p.listContainers(excludes);
+        assertEquals(1, containers.size());
 
         p = new StorageFileProvider("fake/path/", "fake/path/");
-        file = p.listPackageMapFiles();
-        assertTrue(file.isEmpty());
+        containers = p.listContainers(excludes);
+        assertTrue(containers.isEmpty());
     }
 
     @Test
@@ -56,8 +60,7 @@
         assertNotNull(pt);
         pt =
                 StorageFileProvider.getPackageTable(
-                        Paths.get(
-                                TestDataUtils.TESTDATA_PATH, "mock.v1.package.map"));
+                        Paths.get(TestDataUtils.TESTDATA_PATH, "mock.v1.package.map"));
         assertNotNull(pt);
         FlagTable f = p.getFlagTable("mock.v1");
         assertNotNull(f);
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 3238d79..6214e2c 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -154,39 +154,21 @@
 java_library {
     name: "aconfig_storage_reader_java",
     srcs: [
-        "srcs/android/aconfig/storage/AconfigPackageImpl.java",
         "srcs/android/aconfig/storage/StorageInternalReader.java",
+        "srcs/android/os/flagging/PlatformAconfigPackageInternal.java",
     ],
     libs: [
         "unsupportedappusage",
         "strict_mode_stub",
+        "aconfig_storage_stub",
     ],
     static_libs: [
         "aconfig_storage_file_java",
     ],
     sdk_version: "core_current",
     host_supported: true,
-    min_sdk_version: "29",
-    apex_available: [
-        "//apex_available:platform",
-        "//apex_available:anyapex",
+    visibility: [
+        "//frameworks/base",
+        "//build/make/tools/aconfig/aconfig_storage_read_api/tests",
     ],
 }
-
-java_library {
-    name: "aconfig_storage_reader_java_none",
-    srcs: [
-        "srcs/android/aconfig/storage/AconfigPackageImpl.java",
-        "srcs/android/aconfig/storage/StorageInternalReader.java",
-    ],
-    libs: [
-        "unsupportedappusage-sdk-none",
-        "fake_device_config",
-    ],
-    static_libs: [
-        "aconfig_storage_file_java_none",
-    ],
-    sdk_version: "none",
-    system_modules: "core-all-system-modules",
-    host_supported: true,
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
index 6e98fe9..d3cc9d4 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
@@ -433,21 +433,24 @@
             get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
+        let expected_package_context =
+            PackageReadContext { package_id: 0, boolean_start_index: 0, fingerprint: 0 };
         assert_eq!(package_context, expected_package_context);
 
         let package_context =
             get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
+        let expected_package_context =
+            PackageReadContext { package_id: 1, boolean_start_index: 3, fingerprint: 0 };
         assert_eq!(package_context, expected_package_context);
 
         let package_context =
             get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
+        let expected_package_context =
+            PackageReadContext { package_id: 2, boolean_start_index: 6, fingerprint: 0 };
         assert_eq!(package_context, expected_package_context);
     }
 
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 a4b63ab..b20668f 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
@@ -28,6 +28,7 @@
 pub struct PackageReadContext {
     pub package_id: u32,
     pub boolean_start_index: u32,
+    pub fingerprint: u64,
 }
 
 /// Query package read context: package id and start index
@@ -62,6 +63,7 @@
             return Ok(Some(PackageReadContext {
                 package_id: interpreted_node.package_id,
                 boolean_start_index: interpreted_node.boolean_start_index,
+                fingerprint: interpreted_node.fingerprint,
             }));
         }
         match interpreted_node.next_offset {
@@ -84,19 +86,58 @@
             find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
+        let expected_package_context =
+            PackageReadContext { package_id: 0, boolean_start_index: 0, fingerprint: 0 };
         assert_eq!(package_context, expected_package_context);
         let package_context =
             find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_2")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
+        let expected_package_context =
+            PackageReadContext { package_id: 1, boolean_start_index: 3, fingerprint: 0 };
         assert_eq!(package_context, expected_package_context);
         let package_context =
             find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_4")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
+        let expected_package_context =
+            PackageReadContext { package_id: 2, boolean_start_index: 6, fingerprint: 0 };
+        assert_eq!(package_context, expected_package_context);
+    }
+
+    #[test]
+    // this test point locks down table query
+    fn test_package_query_v2() {
+        let package_table = create_test_package_table(2).into_bytes();
+        let package_context =
+            find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_1")
+                .unwrap()
+                .unwrap();
+        let expected_package_context = PackageReadContext {
+            package_id: 0,
+            boolean_start_index: 0,
+            fingerprint: 15248948510590158086u64,
+        };
+        assert_eq!(package_context, expected_package_context);
+        let package_context =
+            find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_2")
+                .unwrap()
+                .unwrap();
+        let expected_package_context = PackageReadContext {
+            package_id: 1,
+            boolean_start_index: 3,
+            fingerprint: 4431940502274857964u64,
+        };
+        assert_eq!(package_context, expected_package_context);
+        let package_context =
+            find_package_read_context(&package_table[..], "com.android.aconfig.storage.test_4")
+                .unwrap()
+                .unwrap();
+        let expected_package_context = PackageReadContext {
+            package_id: 2,
+            boolean_start_index: 6,
+            fingerprint: 16233229917711622375u64,
+        };
         assert_eq!(package_context, expected_package_context);
     }
 
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
deleted file mode 100644
index 6bf4e05..0000000
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.aconfig.storage;
-
-import android.os.StrictMode;
-
-import java.nio.file.Path;
-
-/** @hide */
-public class AconfigPackageImpl {
-    private FlagTable mFlagTable;
-    private FlagValueList mFlagValueList;
-    private PackageTable.Node mPNode;
-    private final int mPackageId;
-    private final int mBooleanStartIndex;
-
-    private AconfigPackageImpl(
-            FlagTable flagTable,
-            FlagValueList flagValueList,
-            int packageId,
-            int booleanStartIndex) {
-        this.mFlagTable = flagTable;
-        this.mFlagValueList = flagValueList;
-        this.mPackageId = packageId;
-        this.mBooleanStartIndex = booleanStartIndex;
-    }
-
-    public static AconfigPackageImpl load(String packageName, StorageFileProvider fileProvider) {
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        PackageTable.Node pNode = null;
-        try {
-            // First try to find the package in the "system" container.
-            pNode = fileProvider.getPackageTable("system").get(packageName);
-        } catch (Exception e) {
-            //
-        }
-        try {
-            if (pNode != null) {
-                return new AconfigPackageImpl(
-                        fileProvider.getFlagTable("system"),
-                        fileProvider.getFlagValueList("system"),
-                        pNode.getPackageId(),
-                        pNode.getBooleanStartIndex());
-            }
-
-            // If not found in "system", search all package map files.
-            for (Path p : fileProvider.listPackageMapFiles()) {
-                PackageTable pTable = fileProvider.getPackageTable(p);
-                pNode = pTable.get(packageName);
-                if (pNode != null) {
-                    return new AconfigPackageImpl(
-                            fileProvider.getFlagTable(pTable.getHeader().getContainer()),
-                            fileProvider.getFlagValueList(pTable.getHeader().getContainer()),
-                            pNode.getPackageId(),
-                            pNode.getBooleanStartIndex());
-                }
-            }
-        } catch (AconfigStorageException e) {
-            // Consider logging the exception.
-            throw e;
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
-        // Package not found.
-        throw new AconfigStorageException(
-                AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
-                "Package " + packageName + " not found.");
-    }
-
-    public static AconfigPackageImpl load(
-            String container, String packageName, StorageFileProvider fileProvider) {
-
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        try {
-            PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
-            if (pNode != null) {
-                return new AconfigPackageImpl(
-                        fileProvider.getFlagTable(container),
-                        fileProvider.getFlagValueList(container),
-                        pNode.getPackageId(),
-                        pNode.getBooleanStartIndex());
-            }
-        } catch (AconfigStorageException e) {
-            // Consider logging the exception.
-            throw e;
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
-
-        throw new AconfigStorageException(
-                AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
-                "package "
-                        + packageName
-                        + " in container "
-                        + container
-                        + " cannot be found on the device");
-    }
-
-    public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
-        FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
-        if (fNode == null) return defaultValue;
-        return mFlagValueList.getBoolean(fNode.getFlagIndex() + mBooleanStartIndex);
-    }
-
-    public boolean getBooleanFlagValue(int index) {
-        return mFlagValueList.getBoolean(index + mBooleanStartIndex);
-    }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
new file mode 100644
index 0000000..e6b6db4
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.flagging;
+
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.StrictMode;
+
+/**
+ * An {@code aconfig} package containing the enabled state of its flags.
+ *
+ * <p><strong>Note: this is intended only to be used by generated code. To determine if a given flag
+ * is enabled in app code, the generated android flags should be used.</strong>
+ *
+ * <p>This class is not part of the public API and should be used by Acnofig Flag internally </b> It
+ * is intended for internal use only and will be changed or removed without notice.
+ *
+ * <p>This class is used to read the flag from Aconfig Package.Each instance of this class will
+ * cache information related to one package. To read flags from a different package, a new instance
+ * of this class should be {@link #load loaded}.
+ *
+ * @hide
+ */
+public class PlatformAconfigPackageInternal {
+
+    private final FlagTable mFlagTable;
+    private final FlagValueList mFlagValueList;
+    private final int mPackageId;
+    private final int mPackageBooleanStartOffset;
+    private final AconfigStorageReadException mException;
+
+    private PlatformAconfigPackageInternal(
+            FlagValueList flagValueList,
+            FlagTable flagTable,
+            int packageBooleanStartOffset,
+            int packageId,
+            AconfigStorageReadException exception) {
+        this.mFlagValueList = flagValueList;
+        this.mFlagTable = flagTable;
+        this.mPackageBooleanStartOffset = packageBooleanStartOffset;
+        this.mPackageId = packageId;
+        this.mException = exception;
+    }
+
+    /**
+     * Loads an Aconfig Package from platform Aconfig Storage.
+     *
+     * <p>This method is intended for internal use only and may be changed or removed without
+     * notice.
+     *
+     * <p>This method loads the specified Aconfig Package from the given container.
+     *
+     * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
+     * The specific error code can be got using {@link #getException()}.
+     *
+     * @param container The name of the container.
+     * @param packageName The name of the Aconfig package to load.
+     * @return An instance of {@link PlatformAconfigPackageInternal}
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public static PlatformAconfigPackageInternal load(String container, String packageName) {
+        return load(container, packageName, StorageFileProvider.getDefaultProvider());
+    }
+
+    /** @hide */
+    public static PlatformAconfigPackageInternal load(
+            String container, String packageName, StorageFileProvider fileProvider) {
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
+
+            if (pNode == null) {
+                return createExceptionInstance(
+                        AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+                        "package "
+                                + packageName
+                                + " in container "
+                                + container
+                                + " cannot be found on the device");
+            }
+
+            return new PlatformAconfigPackageInternal(
+                    fileProvider.getFlagValueList(container),
+                    fileProvider.getFlagTable(container),
+                    pNode.getBooleanStartIndex(),
+                    pNode.getPackageId(),
+                    null);
+
+        } catch (AconfigStorageException e) {
+            return createExceptionInstance(e.getErrorCode(), e.getMessage());
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+    }
+
+    /**
+     * Loads an Aconfig package from the specified container and verifies its fingerprint.
+     *
+     * <p>This method is intended for internal use only and may be changed or removed without
+     * notice.
+     *
+     * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
+     * The specific error code can be got using {@link #getException()}.
+     *
+     * @param container The name of the container.
+     * @param packageName The name of the Aconfig package.
+     * @param packageFingerprint The expected fingerprint of the package.
+     * @return An instance of {@link PlatformAconfigPackageInternal} representing the loaded
+     *     package.
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public static PlatformAconfigPackageInternal load(
+            String container, String packageName, long packageFingerprint) {
+        return load(
+                container,
+                packageName,
+                packageFingerprint,
+                StorageFileProvider.getDefaultProvider());
+    }
+
+    /** @hide */
+    public static PlatformAconfigPackageInternal load(
+            String container,
+            String packageName,
+            long packageFingerprint,
+            StorageFileProvider fileProvider) {
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
+
+            if (pNode == null) {
+                return createExceptionInstance(
+                        AconfigStorageReadException.ERROR_PACKAGE_NOT_FOUND,
+                        "package "
+                                + packageName
+                                + " in container "
+                                + container
+                                + " cannot be found on the device");
+            }
+
+            if (pNode.hasPackageFingerprint()
+                    && packageFingerprint != pNode.getPackageFingerprint()) {
+                return new PlatformAconfigPackageInternal(
+                        fileProvider.getFlagValueList(container),
+                        fileProvider.getFlagTable(container),
+                        pNode.getBooleanStartIndex(),
+                        pNode.getPackageId(),
+                        new AconfigStorageReadException(
+                                AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+                                "The fingerprint provided for the Aconfig package "
+                                        + packageName
+                                        + " in container "
+                                        + container
+                                        + " does not match"
+                                        + " the fingerprint of the package found on the device."));
+            }
+
+            return new PlatformAconfigPackageInternal(
+                    fileProvider.getFlagValueList(container),
+                    null,
+                    pNode.getBooleanStartIndex(),
+                    0,
+                    null);
+
+        } catch (AconfigStorageException e) {
+            return createExceptionInstance(e.getErrorCode(), e.getMessage());
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+    }
+
+    /**
+     * Retrieves the value of a boolean flag using its index.
+     *
+     * <p>This method is intended for internal use only and may be changed or removed without
+     * notice.
+     *
+     * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
+     * index. The index is generated at build time and may vary between builds.
+     *
+     * <p>To ensure you are using the correct index, verify that the package's fingerprint matches
+     * the expected fingerprint before calling this method. If the fingerprints do not match, use
+     * {@link #getBooleanFlagValue(String, boolean)} instead.
+     *
+     * @param index The index of the flag within the package.
+     * @return The boolean value of the flag.
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public boolean getBooleanFlagValue(int index) {
+        return mFlagValueList.getBoolean(index + mPackageBooleanStartOffset);
+    }
+
+    /**
+     * Retrieves the value of a boolean flag using its name.
+     *
+     * <p>This method is intended for internal use only and may be changed or removed without
+     * notice.
+     *
+     * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
+     * name.
+     *
+     * @param flagName The name of the flag.
+     * @param defaultValue The default value to return if the flag is not found.
+     * @return The boolean value of the flag.
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+        FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
+        if (fNode == null) {
+            return defaultValue;
+        }
+        return mFlagValueList.getBoolean(fNode.getFlagIndex() + mPackageBooleanStartOffset);
+    }
+
+    /**
+     * Returns any exception that occurred during the loading of the Aconfig package.
+     *
+     * <p>This method is intended for internal use only and may be changed or removed without
+     * notice.
+     *
+     * @return The exception that occurred, or {@code null} if no exception occurred.
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public AconfigStorageReadException getException() {
+        return mException;
+    }
+
+    /**
+     * Creates a new {@link PlatformAconfigPackageInternal} instance with an {@link
+     * AconfigStorageException}.
+     *
+     * @param errorCode The error code for the exception.
+     * @param message The error message for the exception.
+     * @return A new {@link PlatformAconfigPackageInternal} instance with the specified exception.
+     */
+    private static PlatformAconfigPackageInternal createExceptionInstance(
+            int errorCode, String message) {
+        return new PlatformAconfigPackageInternal(
+                null, null, 0, 0, new AconfigStorageReadException(errorCode, message));
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
similarity index 95%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
index 7ffa18c..ee50060 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
@@ -26,7 +26,7 @@
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
-        <option name="test-file-name" value="aconfig_storage_read_api.test.java.apk" />
+        <option name="test-file-name" value="aconfig_storage_read_functional.apk" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer" />
@@ -45,7 +45,7 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
-        <option name="package" value="android.aconfig_storage.test" />
+        <option name="package" value="android.aconfig.storage.test" />
         <option name="runtime-hint" value="1m" />
     </test>
-</configuration>
+</configuration>
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
similarity index 69%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
index 861b9b5..e528dd5 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
@@ -17,15 +17,15 @@
 <configuration description="Test aconfig storage java tests">
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="aconfig_storage_package.apk" />
+        <option name="test-file-name" value="aconfig_storage_read_unit.apk" />
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
-        <option name="push" value="package_v1.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.package.map" />
-        <option name="push" value="flag_v1.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.flag.map" />
-        <option name="push" value="flag_v1.val->/data/local/tmp/aconfig_storage_package/testdata/mockup.val" />
-        <option name="push" value="flag_v1.info->/data/local/tmp/aconfig_storage_package/testdata/mockup.info" />
-        <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_package/testdata/" />
+        <option name="push" value="package_v2.map->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.package.map" />
+        <option name="push" value="flag_v2.map->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.flag.map" />
+        <option name="push" value="flag_v2.val->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.val" />
+        <option name="push" value="flag_v2.info->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.info" />
+        <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_read_unit/testdata/" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.aconfig.storage.test" />
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
index 6b8942b..702325d 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
@@ -48,3 +48,52 @@
         "general-tests",
     ],
 }
+
+android_test {
+    name: "aconfig_storage_read_functional",
+    srcs: [
+        "functional/srcs/**/*.java",
+    ],
+    static_libs: [
+        "aconfig_device_paths_java",
+        "aconfig_storage_file_java",
+        "androidx.test.rules",
+        "libaconfig_storage_read_api_java",
+        "junit",
+    ],
+    jni_libs: [
+        "libaconfig_storage_read_api_rust_jni",
+    ],
+    data: [
+        ":read_api_test_storage_files",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    test_suites: [
+        "general-tests",
+    ],
+    test_config: "AconfigStorageReadFunctionalTest.xml",
+    team: "trendy_team_android_core_experiments",
+}
+
+android_test {
+    name: "aconfig_storage_read_unit",
+    team: "trendy_team_android_core_experiments",
+    srcs: [
+        "unit/srcs/**/*.java",
+    ],
+    static_libs: [
+        "androidx.test.runner",
+        "junit",
+        "aconfig_storage_reader_java",
+    ],
+    sdk_version: "test_current",
+    data: [
+        ":read_api_test_storage_files",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+    test_config: "AconfigStorageReadUnitTest.xml",
+    jarjar_rules: "jarjar.txt",
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AndroidManifest.xml
similarity index 100%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AndroidManifest.xml
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
index 16f4054..0a9f95e 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
+++ b/tools/aconfig/aconfig_storage_read_api/tests/data/v2/package_v2.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
similarity index 99%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
rename to tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
index 191741e..6dd1bce 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
@@ -267,4 +267,4 @@
             assertEquals(rVal, jVal);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
new file mode 100644
index 0000000..c4a5560
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aconfig.storage.test;
+
+import static android.aconfig.nano.Aconfig.ENABLED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.aconfig.DeviceProtos;
+import android.aconfig.nano.Aconfig.parsed_flag;
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.PlatformAconfigPackageInternal;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(JUnit4.class)
+public class PlatformAconfigPackageInternalTest {
+
+    private static final Set<String> PLATFORM_CONTAINERS = Set.of("system", "vendor", "product");
+
+    @Test
+    public void testAconfigPackageInternal_load() throws IOException {
+        List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+        Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
+        StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+        for (parsed_flag flag : flags) {
+
+            String container = flag.container;
+            String packageName = flag.package_;
+            String flagName = flag.name;
+            if (!PLATFORM_CONTAINERS.contains(container)) continue;
+
+            PackageTable pTable = fp.getPackageTable(container);
+            PackageTable.Node pNode = pTable.get(packageName);
+            FlagTable fTable = fp.getFlagTable(container);
+            FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
+            FlagValueList fList = fp.getFlagValueList(container);
+
+            int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
+            boolean rVal = fList.getBoolean(index);
+
+            PlatformAconfigPackageInternal reader = readerMap.get(packageName);
+            if (reader == null) {
+                reader = PlatformAconfigPackageInternal.load(container, packageName);
+                assertNull(reader.getException());
+                readerMap.put(packageName, reader);
+            }
+            boolean jVal = reader.getBooleanFlagValue(flagName, !rVal);
+
+            assertEquals(rVal, jVal);
+        }
+    }
+
+    @Test
+    public void testPlatformAconfigPackageInternal_load_with_fingerprint() throws IOException {
+        List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+        Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
+        StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+        for (parsed_flag flag : flags) {
+
+            String container = flag.container;
+            String packageName = flag.package_;
+            String flagName = flag.name;
+            if (!PLATFORM_CONTAINERS.contains(container)) continue;
+
+            PackageTable pTable = fp.getPackageTable(container);
+            PackageTable.Node pNode = pTable.get(packageName);
+            FlagTable fTable = fp.getFlagTable(container);
+            FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
+            FlagValueList fList = fp.getFlagValueList(container);
+
+            int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
+            boolean rVal = fList.getBoolean(index);
+
+            long fingerprint = pNode.getPackageFingerprint();
+
+            PlatformAconfigPackageInternal reader = readerMap.get(packageName);
+            if (reader == null) {
+                reader = PlatformAconfigPackageInternal.load(container, packageName, fingerprint);
+                assertNull(reader.getException());
+                readerMap.put(packageName, reader);
+            }
+            boolean jVal = reader.getBooleanFlagValue(fNode.getFlagIndex());
+
+            assertEquals(rVal, jVal);
+        }
+    }
+
+    @Test
+    public void testAconfigPackage_load_withError() throws IOException {
+        // container not found fake_container
+        PlatformAconfigPackageInternal aPackage =
+                PlatformAconfigPackageInternal.load("fake_container", "fake_package", 0);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                aPackage.getException().getErrorCode());
+
+        // package not found
+        aPackage = PlatformAconfigPackageInternal.load("system", "fake_container", 0);
+        assertEquals(
+                AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+                aPackage.getException().getErrorCode());
+
+        // fingerprint doesn't match
+        List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+        StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+        parsed_flag flag = flags.get(0);
+
+        String container = flag.container;
+        String packageName = flag.package_;
+        boolean value = flag.state == ENABLED;
+
+        PackageTable pTable = fp.getPackageTable(container);
+        PackageTable.Node pNode = pTable.get(packageName);
+
+        if (pNode.hasPackageFingerprint()) {
+            long fingerprint = pNode.getPackageFingerprint();
+            aPackage = PlatformAconfigPackageInternal.load(container, packageName, fingerprint + 1);
+            assertEquals(
+                    // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+                    5, aPackage.getException().getErrorCode());
+            assertEquals(aPackage.getBooleanFlagValue(flag.name, !value), value);
+        }
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
similarity index 99%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
rename to tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
index 3a1bba0..8a8f054 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
@@ -42,4 +42,4 @@
         assertFalse(reader.getBooleanFlagValue(0));
         assertTrue(reader.getBooleanFlagValue(1));
     }
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt b/tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
similarity index 91%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
rename to tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
index 24952ec..49250d4 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
+++ b/tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
@@ -15,3 +15,5 @@
 rule android.aconfig.storage.PackageTable$* android.aconfig.storage.test.PackageTable$@1
 rule android.aconfig.storage.FlagValueList$* android.aconfig.storage.test.FlagValueList@1
 rule android.aconfig.storage.SipHasher13$* android.aconfig.storage.test.SipHasher13@1
+
+rule android.os.flagging.PlatformAconfigPackageInternal android.aconfig.storage.test.PlatformAconfigPackageInternal
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
deleted file mode 100644
index 80c0994..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.aconfig.storage.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
-
-import android.aconfig.storage.AconfigPackageImpl;
-import android.aconfig.storage.AconfigStorageException;
-import android.aconfig.storage.StorageFileProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class AconfigPackageImplTest {
-
-    private StorageFileProvider pr;
-
-    @Before
-    public void setup() {
-        pr = new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
-    }
-
-    @Test
-    public void testLoad_onlyPackageName() throws Exception {
-        AconfigPackageImpl p = AconfigPackageImpl.load("com.android.aconfig.storage.test_1", pr);
-        assertNotNull(p);
-    }
-
-    @Test
-    public void testLoad_groupNameFingerprint() throws Exception {
-        AconfigPackageImpl p =
-                AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
-        assertNotNull(p);
-    }
-
-    @Test
-    public void testLoad_error() throws Exception {
-        AconfigPackageImpl p;
-        // cannot find package
-        AconfigStorageException e =
-                assertThrows(
-                        AconfigStorageException.class,
-                        () ->
-                                AconfigPackageImpl.load(
-                                        "mockup", "com.android.aconfig.storage.test_10", pr));
-        assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
-        // cannot find package
-        e =
-                assertThrows(
-                        AconfigStorageException.class,
-                        () -> AconfigPackageImpl.load("com.android.aconfig.storage.test_10", pr));
-        assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
-        // cannot find container
-        e =
-                assertThrows(
-                        AconfigStorageException.class,
-                        () ->
-                                AconfigPackageImpl.load(
-                                        null, "com.android.aconfig.storage.test_1", pr));
-        assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
-        e =
-                assertThrows(
-                        AconfigStorageException.class,
-                        () ->
-                                AconfigPackageImpl.load(
-                                        "test", "com.android.aconfig.storage.test_1", pr));
-        assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
-
-        // new storage doesn't exist
-        pr = new StorageFileProvider("fake/path/", "fake/path/");
-        e =
-                assertThrows(
-                        AconfigStorageException.class,
-                        () -> AconfigPackageImpl.load("fake_package", pr));
-        assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
-
-        // file read issue
-        pr = new StorageFileProvider(TestDataUtils.TESTDATA_PATH, "fake/path/");
-        e =
-                assertThrows(
-                        AconfigStorageException.class,
-                        () ->
-                                AconfigPackageImpl.load(
-                                        "mockup", "com.android.aconfig.storage.test_1", pr));
-        assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
-    }
-
-    @Test
-    public void testGetBooleanFlagValue_flagName() throws Exception {
-        AconfigPackageImpl p =
-                AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
-        assertFalse(p.getBooleanFlagValue("disabled_rw", true));
-        assertTrue(p.getBooleanFlagValue("enabled_ro", false));
-        assertTrue(p.getBooleanFlagValue("enabled_rw", false));
-        assertFalse(p.getBooleanFlagValue("fake", false));
-    }
-
-    @Test
-    public void testGetBooleanFlagValue_index() throws Exception {
-        AconfigPackageImpl p =
-                AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
-        assertFalse(p.getBooleanFlagValue(0));
-        assertTrue(p.getBooleanFlagValue(1));
-        assertTrue(p.getBooleanFlagValue(2));
-    }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
deleted file mode 100644
index 0de34a6..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
+++ /dev/null
@@ -1,48 +0,0 @@
-android_test {
-    name: "aconfig_storage_read_api.test.java",
-    srcs: ["./**/*.java"],
-    static_libs: [
-        "aconfig_device_paths_java",
-        "aconfig_storage_file_java",
-        "aconfig_storage_reader_java",
-        "androidx.test.rules",
-        "libaconfig_storage_read_api_java",
-        "junit",
-    ],
-    jni_libs: [
-        "libaconfig_storage_read_api_rust_jni",
-    ],
-    data: [
-        ":read_api_test_storage_files",
-    ],
-    platform_apis: true,
-    certificate: "platform",
-    test_suites: [
-        "general-tests",
-    ],
-    team: "trendy_team_android_core_experiments",
-}
-
-android_test {
-    name: "aconfig_storage_package",
-    team: "trendy_team_android_core_experiments",
-    srcs: [
-        "AconfigPackageImplTest.java",
-        "TestDataUtils.java",
-    ],
-    static_libs: [
-        "androidx.test.runner",
-        "junit",
-        "aconfig_storage_reader_java",
-    ],
-    test_config: "AndroidStorageJaveTest.xml",
-    manifest: "AndroidPackageTestManifest.xml",
-    sdk_version: "test_current",
-    data: [
-        ":read_api_test_storage_files",
-    ],
-    test_suites: [
-        "general-tests",
-    ],
-    jarjar_rules: "jarjar.txt",
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml
deleted file mode 100644
index 78bfb37..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2024 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.aconfig_storage.test">
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.aconfig_storage.test" />
-
-</manifest>
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java b/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
deleted file mode 100644
index d5cddc7..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.aconfig.storage.test;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-public final class TestDataUtils {
-    public static final String TEST_PACKAGE_MAP_PATH = "mockup.package.map";
-    public static final String TEST_FLAG_MAP_PATH = "mockup.flag.map";
-    public static final String TEST_FLAG_VAL_PATH = "mockup.val";
-    public static final String TEST_FLAG_INFO_PATH = "mockup.info";
-
-    public static final String TESTDATA_PATH =
-            "/data/local/tmp/aconfig_storage_package/testdata/";
-
-    public static ByteBuffer getTestPackageMapByteBuffer() throws Exception {
-        return readFile(TESTDATA_PATH + TEST_PACKAGE_MAP_PATH);
-    }
-
-    public static ByteBuffer getTestFlagMapByteBuffer() throws Exception {
-        return readFile(TESTDATA_PATH + TEST_FLAG_MAP_PATH);
-    }
-
-    public static ByteBuffer getTestFlagValByteBuffer() throws Exception {
-        return readFile(TESTDATA_PATH + TEST_FLAG_VAL_PATH);
-    }
-
-    public static ByteBuffer getTestFlagInfoByteBuffer() throws Exception {
-        return readFile(TESTDATA_PATH + TEST_FLAG_INFO_PATH);
-    }
-
-    private static ByteBuffer readFile(String fileName) throws Exception {
-        InputStream input = new FileInputStream(fileName);
-        return ByteBuffer.wrap(input.readAllBytes());
-    }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
index 5605a41..2a8edf3 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
+++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
@@ -64,21 +64,67 @@
             get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 0, boolean_start_index: 0 };
+        let expected_package_context =
+            PackageReadContext { package_id: 0, boolean_start_index: 0, fingerprint: 0 };
         assert_eq!(package_context, expected_package_context);
 
         let package_context =
             get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 1, boolean_start_index: 3 };
+        let expected_package_context =
+            PackageReadContext { package_id: 1, boolean_start_index: 3, fingerprint: 0 };
         assert_eq!(package_context, expected_package_context);
 
         let package_context =
             get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
                 .unwrap()
                 .unwrap();
-        let expected_package_context = PackageReadContext { package_id: 2, boolean_start_index: 6 };
+        let expected_package_context =
+            PackageReadContext { package_id: 2, boolean_start_index: 6, fingerprint: 0 };
+        assert_eq!(package_context, expected_package_context);
+    }
+
+    #[test]
+    fn test_package_context_query_with_fingerprint() {
+        let storage_dir = create_test_storage_files(2);
+        // SAFETY:
+        // The safety here is ensured as the test process will not write to temp storage file
+        let package_mapped_file = unsafe {
+            get_mapped_file(&storage_dir, "mockup", StorageFileType::PackageMap).unwrap()
+        };
+
+        let package_context =
+            get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_1")
+                .unwrap()
+                .unwrap();
+        let expected_package_context = PackageReadContext {
+            package_id: 0,
+            boolean_start_index: 0,
+            fingerprint: 15248948510590158086u64,
+        };
+        assert_eq!(package_context, expected_package_context);
+
+        let package_context =
+            get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_2")
+                .unwrap()
+                .unwrap();
+        let expected_package_context = PackageReadContext {
+            package_id: 1,
+            boolean_start_index: 3,
+            fingerprint: 4431940502274857964u64,
+        };
+        assert_eq!(package_context, expected_package_context);
+
+        let package_context =
+            get_package_read_context(&package_mapped_file, "com.android.aconfig.storage.test_4")
+                .unwrap()
+                .unwrap();
+        let expected_package_context = PackageReadContext {
+            package_id: 2,
+            boolean_start_index: 6,
+            fingerprint: 16233229917711622375u64,
+        };
         assert_eq!(package_context, expected_package_context);
     }
 
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
new file mode 100644
index 0000000..ce3786a
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aconfig.storage.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.PlatformAconfigPackageInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PlatformAconfigPackageInternalTest {
+
+    public static final String TESTDATA_PATH =
+            "/data/local/tmp/aconfig_storage_read_unit/testdata/";
+
+    private StorageFileProvider pr;
+
+    @Before
+    public void setup() {
+        pr = new StorageFileProvider(TESTDATA_PATH, TESTDATA_PATH);
+    }
+
+    @Test
+    public void testLoad_container_package() throws Exception {
+        PlatformAconfigPackageInternal p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_1", pr);
+        assertNull(p.getException());
+    }
+
+    @Test
+    public void testLoad_container_package_error() throws Exception {
+        // cannot find package
+        PlatformAconfigPackageInternal p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_10", pr);
+
+        assertEquals(
+                AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+                p.getException().getErrorCode());
+
+        // cannot find container
+        p = PlatformAconfigPackageInternal.load(null, "com.android.aconfig.storage.test_1", pr);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                p.getException().getErrorCode());
+        p = PlatformAconfigPackageInternal.load("test", "com.android.aconfig.storage.test_1", pr);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                p.getException().getErrorCode());
+
+        // new storage doesn't exist
+        pr = new StorageFileProvider("fake/path/", "fake/path/");
+        p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                p.getException().getErrorCode());
+
+        // file read issue
+        pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+        p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                p.getException().getErrorCode());
+    }
+
+    @Test
+    public void testLoad_container_package_fingerprint() throws Exception {
+        PackageTable packageTable = pr.getPackageTable("mockup");
+
+        PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+        long fingerprint = node1.getPackageFingerprint();
+        PlatformAconfigPackageInternal p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+        assertNull(p.getException());
+    }
+
+    @Test
+    public void testLoad_container_package_fingerprint_error() throws Exception {
+
+        PackageTable packageTable = pr.getPackageTable("mockup");
+
+        PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+        long fingerprint = node1.getPackageFingerprint();
+
+        // cannot find package
+        PlatformAconfigPackageInternal p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_10", fingerprint, pr);
+
+        assertEquals(
+                AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+                p.getException().getErrorCode());
+
+        // cannot find container
+        p =
+                PlatformAconfigPackageInternal.load(
+                        null, "com.android.aconfig.storage.test_1", fingerprint, pr);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                p.getException().getErrorCode());
+        p =
+                PlatformAconfigPackageInternal.load(
+                        "test", "com.android.aconfig.storage.test_1", fingerprint, pr);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                p.getException().getErrorCode());
+        // fingerprint doesn't match
+        p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_1", fingerprint + 1, pr);
+        assertEquals(
+                // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+                5, p.getException().getErrorCode());
+
+        // new storage doesn't exist
+        pr = new StorageFileProvider("fake/path/", "fake/path/");
+        p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                p.getException().getErrorCode());
+
+        // file read issue
+        pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+        p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+        assertEquals(
+                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+                p.getException().getErrorCode());
+    }
+
+    @Test
+    public void testGetBooleanFlagValue_flagName() throws Exception {
+        PlatformAconfigPackageInternal p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_1", pr);
+        assertFalse(p.getBooleanFlagValue("disabled_rw", true));
+        assertTrue(p.getBooleanFlagValue("enabled_ro", false));
+        assertTrue(p.getBooleanFlagValue("enabled_rw", false));
+        assertFalse(p.getBooleanFlagValue("fake", false));
+    }
+
+    @Test
+    public void testGetBooleanFlagValue_index() throws Exception {
+
+        PackageTable packageTable = pr.getPackageTable("mockup");
+
+        PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+        long fingerprint = node1.getPackageFingerprint();
+        PlatformAconfigPackageInternal p =
+                PlatformAconfigPackageInternal.load(
+                        "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+        assertFalse(p.getBooleanFlagValue(0));
+        assertTrue(p.getBooleanFlagValue(1));
+        assertTrue(p.getBooleanFlagValue(2));
+    }
+}
diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs
index 3f593fe..aef7d7e 100644
--- a/tools/aconfig/aflags/src/aconfig_storage_source.rs
+++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs
@@ -93,11 +93,7 @@
         special_fields: SpecialFields::new(),
     };
 
-    let socket_name = if aconfig_flags::auto_generated::enable_system_aconfigd_rust() {
-        "/dev/socket/aconfigd_system"
-    } else {
-        "/dev/socket/aconfigd"
-    };
+    let socket_name = "/dev/socket/aconfigd_system";
     let mut socket = UnixStream::connect(socket_name)?;
 
     let message_buffer = messages.write_to_bytes()?;
diff --git a/tools/aconfig/fake_device_config/Android.bp b/tools/aconfig/fake_device_config/Android.bp
index 1f17e6b..1c5b7c5 100644
--- a/tools/aconfig/fake_device_config/Android.bp
+++ b/tools/aconfig/fake_device_config/Android.bp
@@ -32,3 +32,24 @@
     host_supported: true,
     is_stubs_module: true,
 }
+
+java_library {
+    name: "aconfig_storage_stub",
+    srcs: [
+        "src/android/os/flagging/**/*.java",
+    ],
+    sdk_version: "core_current",
+    host_supported: true,
+    is_stubs_module: true,
+}
+
+java_library {
+    name: "aconfig_storage_stub_none",
+    srcs: [
+        "src/android/os/flagging/**/*.java",
+    ],
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
+    host_supported: true,
+    is_stubs_module: true,
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/Build.java b/tools/aconfig/fake_device_config/src/android/os/Build.java
new file mode 100644
index 0000000..8ec72fb
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/Build.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+public class Build {
+    public static class VERSION {
+        public static final int SDK_INT = 0;
+    }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java
new file mode 100644
index 0000000..3cac516
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackage.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.flagging;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class AconfigPackage {
+    public static AconfigPackage load(String packageName) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
new file mode 100644
index 0000000..5f066a8
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.flagging;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class AconfigPackageInternal {
+
+    public static AconfigPackageInternal load(String container, String packageName) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public static AconfigPackageInternal load(
+            String container, String packageName, long packageFingerprint) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public boolean getBooleanFlagValue(int index) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public AconfigStorageReadException getException() {
+        throw new UnsupportedOperationException("Stub!");
+    }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java
new file mode 100644
index 0000000..bfec98c
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.flagging;
+
+public class AconfigStorageReadException extends RuntimeException {
+
+    /** Generic error code indicating an unspecified Aconfig Storage error. */
+    public static final int ERROR_GENERIC = 0;
+
+    /** Error code indicating that the Aconfig Storage system is not found on the device. */
+    public static final int ERROR_STORAGE_SYSTEM_NOT_FOUND = 1;
+
+    /** Error code indicating that the requested configuration package is not found. */
+    public static final int ERROR_PACKAGE_NOT_FOUND = 2;
+
+    /** Error code indicating that the specified container is not found. */
+    public static final int ERROR_CONTAINER_NOT_FOUND = 3;
+
+    /** Error code indicating that there was an error reading the Aconfig Storage file. */
+    public static final int ERROR_CANNOT_READ_STORAGE_FILE = 4;
+
+    public static final int ERROR_FILE_FINGERPRINT_MISMATCH = 5;
+
+    public AconfigStorageReadException(int errorCode, String msg) {
+        super(msg);
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public AconfigStorageReadException(int errorCode, String msg, Throwable cause) {
+        super(msg, cause);
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public AconfigStorageReadException(int errorCode, Throwable cause) {
+        super(cause);
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public int getErrorCode() {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    @Override
+    public String getMessage() {
+        throw new UnsupportedOperationException("Stub!");
+    }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
new file mode 100644
index 0000000..c1bc19b
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.flagging;
+
+/*
+ * This class allows generated aconfig code to compile independently of the framework.
+ */
+public class PlatformAconfigPackageInternal {
+
+    public static PlatformAconfigPackageInternal load(String container, String packageName) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public static PlatformAconfigPackageInternal load(
+            String container, String packageName, long packageFingerprint) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public boolean getBooleanFlagValue(int index) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    public AconfigStorageReadException getException() {
+        throw new UnsupportedOperationException("Stub!");
+    }
+}
diff --git a/tools/aconfig/fake_device_config/src/android/provider/AconfigPackage.java b/tools/aconfig/fake_device_config/src/android/provider/AconfigPackage.java
deleted file mode 100644
index 2f01b8c..0000000
--- a/tools/aconfig/fake_device_config/src/android/provider/AconfigPackage.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.provider;
-
-/*
- * This class allows generated aconfig code to compile independently of the framework.
- */
-public class AconfigPackage {
-
-    /** Flag value is true */
-    public static final int FLAG_BOOLEAN_VALUE_TRUE = 1;
-
-    /** Flag value is false */
-    public static final int FLAG_BOOLEAN_VALUE_FALSE = 0;
-
-    /** Flag value doesn't exist */
-    public static final int FLAG_BOOLEAN_VALUE_NOT_EXIST = 2;
-
-    public static int getBooleanFlagValue(String packageName, String flagName) {
-        return 0;
-    }
-
-    public AconfigPackage(String packageName) {}
-
-    public int getBooleanFlagValue(String flagName) {
-        return 0;
-    }
-}
\ No newline at end of file
diff --git a/tools/edit_monitor/daemon_manager.py b/tools/edit_monitor/daemon_manager.py
index da85c11..0c31ab8 100644
--- a/tools/edit_monitor/daemon_manager.py
+++ b/tools/edit_monitor/daemon_manager.py
@@ -33,7 +33,7 @@
 
 DEFAULT_PROCESS_TERMINATION_TIMEOUT_SECONDS = 5
 DEFAULT_MONITOR_INTERVAL_SECONDS = 5
-DEFAULT_MEMORY_USAGE_THRESHOLD = 3 * 1024  # 3GB
+DEFAULT_MEMORY_USAGE_THRESHOLD = 0.02  # 2% of total memory
 DEFAULT_CPU_USAGE_THRESHOLD = 200
 DEFAULT_REBOOT_TIMEOUT_SECONDS = 60 * 60 * 24
 BLOCK_SIGN_FILE = "edit_monitor_block_sign"
@@ -70,6 +70,9 @@
 
     self.max_memory_usage = 0
     self.max_cpu_usage = 0
+    self.total_memory_size = os.sysconf("SC_PAGE_SIZE") * os.sysconf(
+        "SC_PHYS_PAGES"
+    )
 
     pid_file_dir = pathlib.Path(tempfile.gettempdir()).joinpath("edit_monitor")
     pid_file_dir.mkdir(parents=True, exist_ok=True)
@@ -84,7 +87,7 @@
         "edit_monitor",
         self.user_name,
         "ENABLE_ANDROID_EDIT_MONITOR",
-        10,
+        100,
     ):
       logging.warning("Edit monitor is disabled, exiting...")
       return
@@ -142,10 +145,20 @@
         logging.warning("Failed to monitor daemon process with error: %s", e)
 
       if self.max_memory_usage >= memory_threshold:
-        self._handle_resource_exhausted_error("memory")
+        self._send_error_event_to_clearcut(
+            edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE
+        )
+        logging.error(
+            "Daemon process is consuming too much memory, rebooting...")
+        self.reboot()
 
       if self.max_cpu_usage >= cpu_threshold:
-        self._handle_resource_exhausted_error("cpu")
+        self._send_error_event_to_clearcut(
+            edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_CPU_USAGE
+        )
+        logging.error(
+            "Daemon process is consuming too much cpu, killing...")
+        self._terminate_process(self.daemon_process.pid)
 
     logging.info(
         "Daemon process %d terminated. Max memory usage: %f, Max cpu"
@@ -345,7 +358,13 @@
       stat_data = f.readline().split()
       # RSS is the 24th field in /proc/[pid]/stat
       rss_pages = int(stat_data[23])
-      return rss_pages * 4 / 1024  # Covert to MB
+      process_memory = rss_pages * 4 * 1024  # Convert to bytes
+
+    return (
+        process_memory / self.total_memory_size
+        if self.total_memory_size
+        else 0.0
+    )
 
   def _get_process_cpu_percent(self, pid: int, interval: int = 1) -> float:
     total_start_time = self._get_total_cpu_time(pid)
@@ -386,20 +405,6 @@
 
     return pids
 
-  def _handle_resource_exhausted_error(self, resource_type:str):
-    if resource_type == "memory":
-      self._send_error_event_to_clearcut(
-          edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE
-      )
-    else:
-      self._send_error_event_to_clearcut(
-          edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_CPU_USAGE
-      )
-    logging.error(
-        "Daemon process is consuming too much %s, killing...", resource_type
-    ),
-    self._terminate_process(self.daemon_process.pid)
-
   def _send_error_event_to_clearcut(self, error_type):
     edit_monitor_error_event_proto = edit_event_pb2.EditEvent(
         user_name=self.user_name,
diff --git a/tools/edit_monitor/daemon_manager_test.py b/tools/edit_monitor/daemon_manager_test.py
index 12aaab3..350739d 100644
--- a/tools/edit_monitor/daemon_manager_test.py
+++ b/tools/edit_monitor/daemon_manager_test.py
@@ -202,23 +202,31 @@
         fake_cclient, edit_event_pb2.EditEvent.FAILED_TO_START_EDIT_MONITOR
     )
 
-  def test_monitor_daemon_subprocess_killed_high_memory_usage(self):
+  @mock.patch('os.execv')
+  def test_monitor_reboot_with_high_memory_usage(self, mock_execv):
     fake_cclient = FakeClearcutClient()
+    binary_file = tempfile.NamedTemporaryFile(
+        dir=self.working_dir.name, delete=False
+    )
+
     dm = daemon_manager.DaemonManager(
-        TEST_BINARY_FILE,
+        binary_file.name,
         daemon_target=memory_consume_daemon_target,
         daemon_args=(2,),
         cclient=fake_cclient,
     )
+    # set the fake total_memory_size
+    dm.total_memory_size = 100 * 1024 *1024
     dm.start()
-    dm.monitor_daemon(interval=1, memory_threshold=2)
+    dm.monitor_daemon(interval=1)
 
-    self.assertTrue(dm.max_memory_usage >= 2)
+    self.assertTrue(dm.max_memory_usage >= 0.02)
     self.assert_no_subprocess_running()
     self._assert_error_event_logged(
         fake_cclient,
         edit_event_pb2.EditEvent.KILLED_DUE_TO_EXCEEDED_MEMORY_USAGE,
     )
+    mock_execv.assert_called_once()
 
   def test_monitor_daemon_subprocess_killed_high_cpu_usage(self):
     fake_cclient = FakeClearcutClient()
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index c25ff27..30a6acc 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -1100,7 +1100,7 @@
     vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(avb_custom_partitions)
 
     vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
-    if vbmeta_system:
+    if vbmeta_system and set(vbmeta_system.split()).intersection(partitions):
       banner("vbmeta_system")
       partitions["vbmeta_system"] = AddVBMeta(
           output_zip, partitions, "vbmeta_system", vbmeta_system.split())
@@ -1110,7 +1110,7 @@
       vbmeta_partitions.append("vbmeta_system")
 
     vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip()
-    if vbmeta_vendor:
+    if vbmeta_vendor and set(vbmeta_vendor.split()).intersection(partitions):
       banner("vbmeta_vendor")
       partitions["vbmeta_vendor"] = AddVBMeta(
           output_zip, partitions, "vbmeta_vendor", vbmeta_vendor.split())
@@ -1137,7 +1137,7 @@
             if item not in included_partitions]
         vbmeta_partitions.append(partition_name)
 
-    if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
+    if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true" and set(vbmeta_partitions).intersection(partitions):
       banner("vbmeta")
       AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)