Merge "Add license metadata declaration in device/generic/goldfish" into main
diff --git a/CleanSpec.mk b/CleanSpec.mk
index f8c96ff..f562279 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -787,6 +787,10 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/)
 $(call add-clean-step, find $(OUT_DIR) -type f -name "*.jar" -print0 | xargs -0 rm -f)
 
+# Remove obsolete dexpreopt_config artifacts
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/dexpreopt_config/dexpreopt.config)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/dexpreopt_config/dexpreopt_soong.config)
+
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/core/Makefile b/core/Makefile
index a215d31..a16365d 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -7055,18 +7055,19 @@
 
 endif
 
-$(DEXPREOPT_CONFIG_ZIP): $(SOONG_ZIP)
-	$(hide) mkdir -p $(dir $@) $(PRODUCT_OUT)/dexpreopt_config
-
+$(DEXPREOPT_CONFIG_ZIP): PRIVATE_DEXPREOPT_CONFIG_ZIP_PARAMS :=
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
 ifneq (,$(DEX_PREOPT_CONFIG_FOR_MAKE))
-	$(hide) cp $(DEX_PREOPT_CONFIG_FOR_MAKE) $(PRODUCT_OUT)/dexpreopt_config
+$(DEXPREOPT_CONFIG_ZIP): PRIVATE_DEXPREOPT_CONFIG_ZIP_PARAMS += -e $(notdir $(DEX_PREOPT_CONFIG_FOR_MAKE)) -f $(DEX_PREOPT_CONFIG_FOR_MAKE)
 endif
 ifneq (,$(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE))
-	$(hide) cp $(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE) $(PRODUCT_OUT)/dexpreopt_config
+$(DEXPREOPT_CONFIG_ZIP): PRIVATE_DEXPREOPT_CONFIG_ZIP_PARAMS += -e $(notdir $(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE)) -f $(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE)
 endif
 endif #!TARGET_BUILD_UNBUNDLED
-	$(hide) $(SOONG_ZIP) -d -o $@ -C $(PRODUCT_OUT)/dexpreopt_config -D $(PRODUCT_OUT)/dexpreopt_config
+
+$(DEXPREOPT_CONFIG_ZIP): $(SOONG_ZIP)
+	$(hide) mkdir -p $(dir $@) $(PRODUCT_OUT)/dexpreopt_config
+	$(hide) $(SOONG_ZIP) -d -o $@ -C $(PRODUCT_OUT)/dexpreopt_config -D $(PRODUCT_OUT)/dexpreopt_config $(PRIVATE_DEXPREOPT_CONFIG_ZIP_PARAMS)
 
 .PHONY: dexpreopt_config_zip
 dexpreopt_config_zip: $(DEXPREOPT_CONFIG_ZIP)
@@ -7605,6 +7606,7 @@
 sdk_dep_file := $(sdk_dir)/sdk_deps.mk
 
 ATREE_FILES :=
+include development/build/tools/sdk-preprocess-files.mk
 -include $(sdk_dep_file)
 
 # if we don't have a real list, then use "everything"
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index ea6ebd3..274a7de 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -111,6 +111,8 @@
 
 $(call add_soong_config_var_value,ANDROID,release_binder_death_recipient_weak_from_jni,$(RELEASE_BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI))
 
+$(call add_soong_config_var_value,ANDROID,release_libpower_no_lock_binder_txn,$(RELEASE_LIBPOWER_NO_LOCK_BINDER_TXN))
+
 $(call add_soong_config_var_value,ANDROID,release_package_libandroid_runtime_punch_holes,$(RELEASE_PACKAGE_LIBANDROID_RUNTIME_PUNCH_HOLES))
 
 $(call add_soong_config_var_value,ANDROID,release_selinux_data_data_ignore,$(RELEASE_SELINUX_DATA_DATA_IGNORE))
diff --git a/core/check_elf_file.mk b/core/check_elf_file.mk
index b5be81f..ec3c4b0 100644
--- a/core/check_elf_file.mk
+++ b/core/check_elf_file.mk
@@ -7,9 +7,12 @@
 #
 # Inputs:
 # - LOCAL_ALLOW_UNDEFINED_SYMBOLS
+# - LOCAL_IGNORE_MAX_PAGE_SIZE
 # - LOCAL_BUILT_MODULE
 # - LOCAL_IS_HOST_MODULE
 # - LOCAL_MODULE_CLASS
+# - TARGET_CHECK_PREBUILT_MAX_PAGE_SIZE
+# - TARGET_MAX_PAGE_SIZE_SUPPORTED
 # - intermediates
 # - my_installed_module_stem
 # - my_prebuilt_src_file
@@ -26,6 +29,21 @@
 # In addition to $(my_check_elf_file_shared_lib_files), some file paths are
 # added by `resolve-shared-libs-for-elf-file-check` from `core/main.mk`.
 $(check_elf_files_stamp): PRIVATE_SHARED_LIBRARY_FILES := $(my_check_elf_file_shared_lib_files)
+
+# For different page sizes to work, we must support a larger max page size
+# as well as properly reflect page size at runtime. Limit this check, since many
+# devices set the max page size (for future proof) than actually use the
+# larger page size.
+ifeq ($(strip $(TARGET_CHECK_PREBUILT_MAX_PAGE_SIZE)),true)
+ifeq ($(strip $(LOCAL_IGNORE_MAX_PAGE_SIZE)),true)
+$(check_elf_files_stamp): PRIVATE_MAX_PAGE_SIZE :=
+else
+$(check_elf_files_stamp): PRIVATE_MAX_PAGE_SIZE := $(TARGET_MAX_PAGE_SIZE_SUPPORTED)
+endif
+else
+$(check_elf_files_stamp): PRIVATE_MAX_PAGE_SIZE :=
+endif
+
 $(check_elf_files_stamp): $(my_prebuilt_src_file) $(my_check_elf_file_shared_lib_files) $(CHECK_ELF_FILE) $(LLVM_READOBJ)
 	@echo Check prebuilt ELF binary: $<
 	$(hide) mkdir -p $(dir $@)
@@ -33,6 +51,7 @@
 	$(hide) $(CHECK_ELF_FILE) \
 	    --skip-bad-elf-magic \
 	    --skip-unknown-elf-machine \
+	    $(if $(PRIVATE_MAX_PAGE_SIZE),--max-page-size=$(PRIVATE_MAX_PAGE_SIZE)) \
 	    $(if $(PRIVATE_SONAME),--soname $(PRIVATE_SONAME)) \
 	    $(foreach l,$(PRIVATE_SHARED_LIBRARY_FILES),--shared-lib $(l)) \
 	    $(foreach l,$(PRIVATE_SYSTEM_SHARED_LIBRARIES),--system-shared-lib $(l)) \
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 2b1e436..6192690 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -106,6 +106,7 @@
 LOCAL_HEADER_LIBRARIES:=
 LOCAL_HOST_PREFIX:=
 LOCAL_HOST_REQUIRED_MODULES:=
+LOCAL_IGNORE_MAX_PAGE_SIZE:=
 LOCAL_INIT_RC:=
 LOCAL_INJECT_BSSL_HASH:=
 LOCAL_INSTALLED_MODULE:=
diff --git a/core/config.mk b/core/config.mk
index ce11b1d..43304d5 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -419,6 +419,13 @@
 endif
 .KATI_READONLY := TARGET_MAX_PAGE_SIZE_SUPPORTED
 
+ifdef PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE
+  TARGET_CHECK_PREBUILT_MAX_PAGE_SIZE := $(PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE)
+else
+  TARGET_CHECK_PREBUILT_MAX_PAGE_SIZE := false
+endif
+.KATI_READONLY := TARGET_CHECK_PREBUILT_MAX_PAGE_SIZE
+
 # Boolean variable determining if AOSP relies on bionic's PAGE_SIZE macro.
 ifdef PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO
   TARGET_NO_BIONIC_PAGE_SIZE_MACRO := $(PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO)
@@ -1248,14 +1255,12 @@
 
 include $(BUILD_SYSTEM)/dumpvar.mk
 
-ifneq ($(KEEP_VNDK),true)
 ifdef BOARD_VNDK_VERSION
 BOARD_VNDK_VERSION=
 endif
 ifdef PLATFORM_VNDK_VERSION
 PLATFORM_VNDK_VERSION=
 endif
-endif
 
 ifeq (true,$(FULL_SYSTEM_OPTIMIZE_JAVA))
 ifeq (false,$(SYSTEM_OPTIMIZE_JAVA))
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 93cec64..c063f60 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -50,13 +50,6 @@
 # Release config
 include $(BUILD_SYSTEM)/release_config.mk
 
-# Set default value of KEEP_VNDK.
-ifeq ($(RELEASE_DEPRECATE_VNDK),true)
-  KEEP_VNDK ?= false
-else
-  KEEP_VNDK ?= true
-endif
-
 # ---------------------------------------------------------------
 # Set up version information
 include $(BUILD_SYSTEM)/version_util.mk
diff --git a/core/node_fns.mk b/core/node_fns.mk
index 144eb8b..d2cee9e 100644
--- a/core/node_fns.mk
+++ b/core/node_fns.mk
@@ -203,7 +203,7 @@
   $(call _expand-inherited-values,$(1),$(2),$(3),$(4))
 
   $(eval $(1).$(2).inherited :=)
-  $(eval _include_stack := $(wordlist 2,9999,$$(_include_stack)))
+  $(eval _include_stack := $(wordlist 2,9999,$(_include_stack)))
 endef
 
 #
diff --git a/core/packaging/flags.mk b/core/packaging/flags.mk
index e715fd1..a96ea8f 100644
--- a/core/packaging/flags.mk
+++ b/core/packaging/flags.mk
@@ -22,50 +22,6 @@
 
 
 # -----------------------------------------------------------------
-# Release Config Flags
-
-# Create a summary file of build flags for each partition
-# $(1): built build flags json file
-# $(2): installed build flags json file
-# $(3): flag names
-define generate-partition-build-flag-file
-$(eval $(strip $(1)): PRIVATE_OUT := $(strip $(1)))
-$(eval $(strip $(1)): PRIVATE_FLAG_NAMES := $(strip $(3)))
-$(strip $(1)):
-	mkdir -p $$(dir $$(PRIVATE_OUT))
-	echo '{' > $$(PRIVATE_OUT)
-	echo '"flags": [' >> $$(PRIVATE_OUT)
-	$$(foreach flag, $$(PRIVATE_FLAG_NAMES), \
-		( \
-			printf '  { "name": "%s", "value": "%s", ' \
-					'$$(flag)' \
-					'$$(_ALL_RELEASE_FLAGS.$$(flag).VALUE)' \
-					; \
-			printf '"set": "%s", "default": "%s", "declared": "%s" }' \
-					'$$(_ALL_RELEASE_FLAGS.$$(flag).SET_IN)' \
-					'$$(_ALL_RELEASE_FLAGS.$$(flag).DEFAULT)' \
-					'$$(_ALL_RELEASE_FLAGS.$$(flag).DECLARED_IN)' \
-					; \
-			printf '$$(if $$(filter $$(lastword $$(PRIVATE_FLAG_NAMES)),$$(flag)),,$$(comma))\n' ; \
-		) >> $$(PRIVATE_OUT) ; \
-	)
-	echo "]" >> $$(PRIVATE_OUT)
-	echo "}" >> $$(PRIVATE_OUT)
-$(call copy-one-file, $(1), $(2))
-endef
-
-$(foreach partition, $(_FLAG_PARTITIONS), \
-	$(eval build_flag_summaries.$(partition) := $(PRODUCT_OUT)/$(partition)/etc/build_flags.json) \
-	$(eval $(call generate-partition-build-flag-file, \
-				$(TARGET_OUT_FLAGS)/$(partition)/build_flags.json, \
-				$(build_flag_summaries.$(partition)), \
-				$(_ALL_RELEASE_FLAGS.PARTITIONS.$(partition)) \
-			) \
-	) \
-)
-
-
-# -----------------------------------------------------------------
 # Aconfig Flags
 
 # Create a summary file of build flags for each partition
diff --git a/core/product.mk b/core/product.mk
index 9a49927..7908e1d 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -32,6 +32,7 @@
 # PRODUCT_MAX_PAGE_SIZE_SUPPORTED=65536, the possible values for PAGE_SIZE could be
 # 4096, 16384 and 65536.
 _product_single_value_vars += PRODUCT_MAX_PAGE_SIZE_SUPPORTED
+_product_single_value_vars += PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE
 
 # Boolean variable determining if AOSP relies on bionic's PAGE_SIZE macro.
 _product_single_value_vars += PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO
@@ -303,9 +304,6 @@
 # This flag implies PRODUCT_USE_DYNAMIC_PARTITIONS.
 _product_single_value_vars += PRODUCT_RETROFIT_DYNAMIC_PARTITIONS
 
-# List of tags that will be used to gate blueprint modules from the build graph
-_product_list_vars += PRODUCT_INCLUDE_TAGS
-
 # List of directories that will be used to gate blueprint modules from the build graph
 _product_list_vars += PRODUCT_SOURCE_ROOT_DIRS
 
@@ -490,6 +488,11 @@
 # Enables 16KB developer option for device if set.
 _product_single_value_vars += PRODUCT_16K_DEVELOPER_OPTION
 
+# If set, adb root will be disabled (really ro.debuggable=0) in userdebug
+# builds. It's already off disabled in user builds. Eng builds are unaffected
+# by this flag.
+_product_single_value_vars += PRODUCT_NOT_DEBUGGABLE_IN_USERDEBUG
+
 .KATI_READONLY := _product_single_value_vars _product_list_vars
 _product_var_list :=$= $(_product_single_value_vars) $(_product_list_vars)
 
diff --git a/core/product_config.mk b/core/product_config.mk
index f21c1c4..f939690 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -280,27 +280,6 @@
 
 current_product_makefile :=
 
-#############################################################################
-# Check product include tag allowlist
-BLUEPRINT_INCLUDE_TAGS_ALLOWLIST := \
-  com.android.mainline_go \
-  com.android.mainline \
-  mainline_module_prebuilt_nightly \
-  mainline_module_prebuilt_monthly_release
-.KATI_READONLY := BLUEPRINT_INCLUDE_TAGS_ALLOWLIST
-$(foreach include_tag,$(PRODUCT_INCLUDE_TAGS), \
-	$(if $(filter $(include_tag),$(BLUEPRINT_INCLUDE_TAGS_ALLOWLIST)),,\
-	$(call pretty-error, $(include_tag) is not in BLUEPRINT_INCLUDE_TAGS_ALLOWLIST: $(BLUEPRINT_INCLUDE_TAGS_ALLOWLIST))))
-# Create default PRODUCT_INCLUDE_TAGS
-ifeq (, $(PRODUCT_INCLUDE_TAGS))
-# Soong analysis is global: even though a module might not be relevant to a specific product (e.g. build_tools for aosp_arm),
-# we still analyse it.
-# This means that in setups where we two have two prebuilts of module_sdk, we need a "default" to use in analysis
-# This should be a no-op in aosp and internal since no Android.bp file contains blueprint_package_includes
-# Use the big android one and main-based prebuilts by default
-PRODUCT_INCLUDE_TAGS += com.android.mainline mainline_module_prebuilt_nightly
-endif
-
 # AOSP and Google products currently share the same `apex_contributions` in next.
 # This causes issues when building <aosp_product>-next-userdebug in main.
 # Create a temporary allowlist to ignore the google apexes listed in `contents` of apex_contributions of `next`
diff --git a/core/release_config.mk b/core/release_config.mk
index 4fdd279..2898868 100644
--- a/core/release_config.mk
+++ b/core/release_config.mk
@@ -130,6 +130,7 @@
         # Disable the build flag in release-config.
         _args += --guard=false
     endif
+    _args += --allow-missing=true
     _flags_dir:=$(OUT_DIR)/soong/release-config
     _flags_file:=$(_flags_dir)/release_config-$(TARGET_PRODUCT)-$(TARGET_RELEASE).vars
     # release-config generates $(_flags_varmk)
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 7402d2b..dd7e4e6 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -144,8 +144,6 @@
 $(call add_json_list, NativeCoveragePaths,               $(NATIVE_COVERAGE_PATHS))
 $(call add_json_list, NativeCoverageExcludePaths,        $(NATIVE_COVERAGE_EXCLUDE_PATHS))
 
-$(call add_json_bool, SamplingPGO,                       $(filter true,$(SAMPLING_PGO)))
-
 $(call add_json_bool, ArtUseReadBarrier,                 $(call invert_bool,$(filter false,$(PRODUCT_ART_USE_READ_BARRIER))))
 $(call add_json_str,  BtConfigIncludeDir,                $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR))
 $(call add_json_list, DeviceKernelHeaders,               $(TARGET_DEVICE_KERNEL_HEADERS) $(TARGET_BOARD_KERNEL_HEADERS) $(TARGET_PRODUCT_KERNEL_HEADERS))
@@ -204,9 +202,6 @@
 $(call add_json_bool, Uml,                               $(filter true,$(TARGET_USER_MODE_LINUX)))
 $(call add_json_str,  VendorPath,                        $(TARGET_COPY_OUT_VENDOR))
 $(call add_json_str,  OdmPath,                           $(TARGET_COPY_OUT_ODM))
-$(call add_json_str,  VendorDlkmPath,                    $(TARGET_COPY_OUT_VENDOR_DLKM))
-$(call add_json_str,  OdmDlkmPath,                       $(TARGET_COPY_OUT_ODM_DLKM))
-$(call add_json_str,  SystemDlkmPath,                    $(TARGET_COPY_OUT_SYSTEM_DLKM))
 $(call add_json_str,  ProductPath,                       $(TARGET_COPY_OUT_PRODUCT))
 $(call add_json_str,  SystemExtPath,                     $(TARGET_COPY_OUT_SYSTEM_EXT))
 $(call add_json_bool, MinimizeJavaDebugInfo,             $(filter true,$(PRODUCT_MINIMIZE_JAVA_DEBUG_INFO)))
@@ -287,7 +282,7 @@
 $(call add_json_bool, BoardMoveRecoveryResourcesToVendorBoot, $(filter true,$(BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT)))
 $(call add_json_str,  PrebuiltHiddenApiDir, $(BOARD_PREBUILT_HIDDENAPI_DIR))
 
-$(call add_json_str,  ShippingApiLevel, $(PRODUCT_SHIPPING_API_LEVEL))
+$(call add_json_str,  Shipping_api_level, $(PRODUCT_SHIPPING_API_LEVEL))
 
 $(call add_json_list, BuildBrokenPluginValidation,         $(BUILD_BROKEN_PLUGIN_VALIDATION))
 $(call add_json_bool, BuildBrokenClangProperty,            $(filter true,$(BUILD_BROKEN_CLANG_PROPERTY)))
@@ -318,7 +313,6 @@
 
 $(call add_json_bool, IgnorePrefer32OnDevice, $(filter true,$(IGNORE_PREFER32_ON_DEVICE)))
 
-$(call add_json_list, IncludeTags,                $(PRODUCT_INCLUDE_TAGS))
 $(call add_json_list, SourceRootDirs,             $(PRODUCT_SOURCE_ROOT_DIRS))
 
 $(call add_json_list, AfdoProfiles,                $(ALL_AFDO_PROFILES))
@@ -332,73 +326,10 @@
 
 $(call add_json_bool, ReleaseDefaultModuleBuildFromSource,   $(RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE))
 
-$(call add_json_bool, KeepVndk, $(filter true,$(KEEP_VNDK)))
-
 $(call add_json_bool, CheckVendorSeappViolations, $(filter true,$(CHECK_VENDOR_SEAPP_VIOLATIONS)))
 
 $(call add_json_bool, BuildIgnoreApexContributionContents, $(PRODUCT_BUILD_IGNORE_APEX_CONTRIBUTION_CONTENTS))
 
-$(call add_json_map, PartitionVarsForBazelMigrationOnlyDoNotUse)
-  $(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, \
-    $(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)) \
-    $(call add_json_str, BoardErofsCompressHints, $(BOARD_$(image_type)IMAGE_EROFS_COMPRESS_HINTS)) \
-    $(call add_json_str, BoardErofsPclusterSize, $(BOARD_$(image_type)IMAGE_EROFS_PCLUSTER_SIZE)) \
-    $(call add_json_str, BoardExtfsInodeCount, $(BOARD_$(image_type)IMAGE_EXTFS_INODE_COUNT)) \
-    $(call add_json_str, BoardExtfsRsvPct, $(BOARD_$(image_type)IMAGE_EXTFS_RSV_PCT)) \
-    $(call add_json_str, BoardF2fsSloadCompressFlags, $(BOARD_$(image_type)IMAGE_F2FS_SLOAD_COMPRESS_FLAGS)) \
-    $(call add_json_str, BoardFileSystemCompress, $(BOARD_$(image_type)IMAGE_FILE_SYSTEM_COMPRESS)) \
-    $(call add_json_str, BoardFileSystemType, $(BOARD_$(image_type)IMAGE_FILE_SYSTEM_TYPE)) \
-    $(call add_json_str, BoardJournalSize, $(BOARD_$(image_type)IMAGE_JOURNAL_SIZE)) \
-    $(call add_json_str, BoardPartitionReservedSize, $(BOARD_$(image_type)IMAGE_PARTITION_RESERVED_SIZE)) \
-    $(call add_json_str, BoardPartitionSize, $(BOARD_$(image_type)IMAGE_PARTITION_SIZE)) \
-    $(call add_json_str, BoardSquashfsBlockSize, $(BOARD_$(image_type)IMAGE_SQUASHFS_BLOCK_SIZE)) \
-    $(call add_json_str, BoardSquashfsCompressor, $(BOARD_$(image_type)IMAGE_SQUASHFS_COMPRESSOR)) \
-    $(call add_json_str, BoardSquashfsCompressorOpt, $(BOARD_$(image_type)IMAGE_SQUASHFS_COMPRESSOR_OPT)) \
-    $(call add_json_str, BoardSquashfsDisable4kAlign, $(BOARD_$(image_type)IMAGE_SQUASHFS_DISABLE_4K_ALIGN)) \
-    $(call add_json_str, ProductBaseFsPath, $(PRODUCT_$(image_type)_BASE_FS_PATH)) \
-    $(call add_json_str, ProductHeadroom, $(PRODUCT_$(image_type)_HEADROOM)) \
-    $(call add_json_str, ProductVerityPartition, $(PRODUCT_$(image_type)_VERITY_PARTITION)) \
-    $(call add_json_str, BoardAvbAddHashtreeFooterArgs, $(BOARD_AVB_$(image_type)_ADD_HASHTREE_FOOTER_ARGS)) \
-    $(call add_json_str, BoardAvbKeyPath, $(BOARD_AVB_$(image_type)_KEY_PATH)) \
-    $(call add_json_str, BoardAvbAlgorithm, $(BOARD_AVB_$(image_type)_ALGORITHM)) \
-    $(call add_json_str, BoardAvbRollbackIndex, $(BOARD_AVB_$(image_type)_ROLLBACK_INDEX)) \
-    $(call add_json_str, BoardAvbRollbackIndexLocation, $(BOARD_AVB_$(image_type)_ROLLBACK_INDEX_LOCATION)) \
-    $(call end_json_map) \
-  )
-  $(call end_json_map)
-
-  $(call add_json_bool, TargetUserimagesUseExt2, $(filter true,$(TARGET_USERIMAGES_USE_EXT2)))
-  $(call add_json_bool, TargetUserimagesUseExt3, $(filter true,$(TARGET_USERIMAGES_USE_EXT3)))
-  $(call add_json_bool, TargetUserimagesUseExt4, $(filter true,$(TARGET_USERIMAGES_USE_EXT4)))
-
-  $(call add_json_bool, TargetUserimagesSparseExtDisabled, $(filter true,$(TARGET_USERIMAGES_SPARSE_EXT_DISABLED)))
-  $(call add_json_bool, TargetUserimagesSparseErofsDisabled, $(filter true,$(TARGET_USERIMAGES_SPARSE_EROFS_DISABLED)))
-  $(call add_json_bool, TargetUserimagesSparseSquashfsDisabled, $(filter true,$(TARGET_USERIMAGES_SPARSE_SQUASHFS_DISABLED)))
-  $(call add_json_bool, TargetUserimagesSparseF2fsDisabled, $(filter true,$(TARGET_USERIMAGES_SPARSE_F2FS_DISABLED)))
-
-  $(call add_json_str, BoardErofsCompressor, $(BOARD_EROFS_COMPRESSOR))
-  $(call add_json_str, BoardErofsCompressorHints, $(BOARD_EROFS_COMPRESS_HINTS))
-  $(call add_json_str, BoardErofsPclusterSize, $(BOARD_EROFS_PCLUSTER_SIZE))
-  $(call add_json_str, BoardErofsShareDupBlocks, $(BOARD_EROFS_SHARE_DUP_BLOCKS))
-  $(call add_json_str, BoardErofsUseLegacyCompression, $(BOARD_EROFS_USE_LEGACY_COMPRESSION))
-  $(call add_json_str, BoardExt4ShareDupBlocks, $(BOARD_EXT4_SHARE_DUP_BLOCKS))
-  $(call add_json_str, BoardFlashLogicalBlockSize, $(BOARD_FLASH_LOGICAL_BLOCK_SIZE))
-  $(call add_json_str, BoardFlashEraseBlockSize, $(BOARD_FLASH_ERASE_BLOCK_SIZE))
-
-  $(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)))
-
-  $(call add_json_bool, BoardAvbEnable, $(filter true,$(BOARD_AVB_ENABLE)))
-
-  $(call add_json_list, ProductPackages, $(sort $(PRODUCT_PACKAGES)))
-$(call end_json_map)
-
 $(call add_json_bool, BuildFromSourceStub, $(findstring true,$(PRODUCT_BUILD_FROM_SOURCE_STUB) $(BUILD_FROM_SOURCE_STUB)))
 
 $(call add_json_bool, HiddenapiExportableStubs, $(filter true,$(PRODUCT_HIDDEN_API_EXPORTABLE_STUBS)))
diff --git a/core/sysprop_config.mk b/core/sysprop_config.mk
index e8428c8..6e3da72 100644
--- a/core/sysprop_config.mk
+++ b/core/sysprop_config.mk
@@ -195,6 +195,7 @@
 
 user_variant := $(filter user userdebug,$(TARGET_BUILD_VARIANT))
 enable_target_debugging := true
+enable_dalvik_lock_contention_logging := true
 ifneq (,$(user_variant))
   # Target is secure in user builds.
   ADDITIONAL_SYSTEM_PROPERTIES += ro.secure=1
@@ -207,6 +208,13 @@
   ifneq ($(user_variant),userdebug)
     # Disable debugging in plain user builds.
     enable_target_debugging :=
+    enable_dalvik_lock_contention_logging :=
+  else
+    # Disable debugging in userdebug builds if PRODUCT_NOT_DEBUGGABLE_IN_USERDEBUG
+    # is set.
+    ifneq (,$(strip $(PRODUCT_NOT_DEBUGGABLE_IN_USERDEBUG)))
+      enable_target_debugging :=
+    endif
   endif
 
   # Disallow mock locations by default for user builds
@@ -221,16 +229,22 @@
   ADDITIONAL_SYSTEM_PROPERTIES += ro.allow.mock.location=1
 endif # !user_variant
 
+ifeq (true,$(strip $(enable_dalvik_lock_contention_logging)))
+  # Enable Dalvik lock contention logging.
+  ADDITIONAL_SYSTEM_PROPERTIES += dalvik.vm.lockprof.threshold=500
+endif # !enable_dalvik_lock_contention_logging
+
 ifeq (true,$(strip $(enable_target_debugging)))
   # Target is more debuggable and adbd is on by default
   ADDITIONAL_SYSTEM_PROPERTIES += ro.debuggable=1
-  # Enable Dalvik lock contention logging.
-  ADDITIONAL_SYSTEM_PROPERTIES += dalvik.vm.lockprof.threshold=500
 else # !enable_target_debugging
   # Target is less debuggable and adbd is off by default
   ADDITIONAL_SYSTEM_PROPERTIES += ro.debuggable=0
 endif # !enable_target_debugging
 
+enable_target_debugging:=
+enable_dalvik_lock_contention_logging:=
+
 ifneq ($(filter sdk sdk_addon,$(MAKECMDGOALS)),)
 _is_sdk_build := true
 endif
diff --git a/envsetup.sh b/envsetup.sh
index 647c106..0ccb631 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -385,6 +385,7 @@
         complete -F _bazel__complete -o nospace b
     fi
     complete -F _lunch lunch
+    complete -F _lunch_completion lunch2
 
     complete -F _complete_android_module_names pathmod
     complete -F _complete_android_module_names gomod
@@ -496,9 +497,18 @@
         return 1
     fi
 
+    _lunch_meat $product $release $variant
+}
+
+function _lunch_meat()
+{
+    local product=$1
+    local release=$2
+    local variant=$3
+
     TARGET_PRODUCT=$product \
-    TARGET_BUILD_VARIANT=$variant \
     TARGET_RELEASE=$release \
+    TARGET_BUILD_VARIANT=$variant \
     build_build_var_cache
     if [ $? -ne 0 ]
     then
@@ -519,14 +529,11 @@
     set_stuff_for_environment
     [[ -n "${ANDROID_QUIET_BUILD:-}" ]] || printconfig
 
-    if [ "${TARGET_BUILD_VARIANT}" = "userdebug" ] && [[  -z "${ANDROID_QUIET_BUILD}" ]]; then
-      echo
-      echo "Want FASTER LOCAL BUILDS? Use -eng instead of -userdebug (however for" \
-        "performance benchmarking continue to use userdebug)"
-    fi
-    if [ $used_lunch_menu -eq 1 ]; then
-      echo
-      echo "Hint: next time you can simply run 'lunch $selection'"
+    if [[ -z "${ANDROID_QUIET_BUILD}" ]]; then
+        local spam_for_lunch=$(gettop)/build/make/tools/envsetup/spam_for_lunch
+        if [[ -x $spam_for_lunch ]]; then
+            $spam_for_lunch
+        fi
     fi
 
     destroy_build_var_cache
@@ -553,6 +560,112 @@
     return 0
 }
 
+function _lunch_usage()
+{
+    (
+        echo "The lunch command selects the configuration to use for subsequent"
+        echo "Android builds."
+        echo
+        echo "Usage: lunch TARGET_PRODUCT [TARGET_RELEASE [TARGET_BUILD_VARIANT]]"
+        echo
+        echo "  Choose the product, release and variant to use. If not"
+        echo "  supplied, TARGET_RELEASE will be 'trunk_staging' and"
+        echo "  TARGET_BUILD_VARIANT will be 'eng'"
+        echo
+        echo
+        echo "Usage: lunch TARGET_PRODUCT-TARGET_RELEASE-TARGET_BUILD_VARIANT"
+        echo
+        echo "  Chose the product, release and variant to use. This"
+        echo "  legacy format is maintained for compatibility."
+        echo
+        echo
+        echo "Note that the previous interactive menu and list of hard-coded"
+        echo "list of curated targets has been removed. If you would like the"
+        echo "list of products, release configs for a particular product, or"
+        echo "variants, run list_products, list_release_configs, list_variants"
+        echo "respectively."
+        echo
+    ) 1>&2
+}
+
+function lunch2()
+{
+    if [[ $# -eq 1 && $1 = "--help" ]]; then
+        _lunch_usage
+        return 0
+    fi
+    if [[ $# -eq 0 ]]; then
+        echo "No target specified. See lunch --help" 1>&2
+        return 1
+    fi
+    if [[ $# -gt 3 ]]; then
+        echo "Too many parameters given. See lunch --help" 1>&2
+        return 1
+    fi
+
+    local product release variant
+
+    # Handle the legacy format
+    local legacy=$(echo $1 | grep "-")
+    if [[ $# -eq 1 && -n $legacy ]]; then
+        IFS="-" read -r product release variant <<< "$1"
+        if [[ -z "$product" ]] || [[ -z "$release" ]] || [[ -z "$variant" ]]; then
+            echo "Invalid lunch combo: $1" 1>&2
+            echo "Valid combos must be of the form <product>-<release>-<variant> when using" 1>&2
+            echo "the legacy format.  Run 'lunch --help' for usage." 1>&2
+            return 1
+        fi
+    fi
+
+    # Handle the new format.
+    if [[ -z $legacy ]]; then
+        product=$1
+        release=$2
+        if [[ -z $release ]]; then
+            release=trunk_staging
+        fi
+        variant=$3
+        if [[ -z $variant ]]; then
+            variant=eng
+        fi
+    fi
+
+    # Validate the selection and set all the environment stuff
+    _lunch_meat $product $release $variant
+}
+
+unset ANDROID_LUNCH_COMPLETION_PRODUCT_CACHE
+unset ANDROID_LUNCH_COMPLETION_CHOSEN_PRODUCT
+unset ANDROID_LUNCH_COMPLETION_RELEASE_CACHE
+# Tab completion for lunch.
+function _lunch_completion()
+{
+    # Available products
+    if [[ $COMP_CWORD -eq 1 ]] ; then
+        if [[ -z $ANDROID_LUNCH_COMPLETION_PRODUCT_CACHE ]]; then
+            ANDROID_LUNCH_COMPLETION_PRODUCT_CACHE=$(list_products)
+        fi
+        COMPREPLY=( $(compgen -W "${ANDROID_LUNCH_COMPLETION_PRODUCT_CACHE}" -- "${COMP_WORDS[COMP_CWORD]}") )
+    fi
+
+    # Available release configs
+    if [[ $COMP_CWORD -eq 2 ]] ; then
+        if [[ -z $ANDROID_LUNCH_COMPLETION_RELEASE_CACHE || $ANDROID_LUNCH_COMPLETION_CHOSEN_PRODUCT != ${COMP_WORDS[1]} ]] ; then
+            ANDROID_LUNCH_COMPLETION_RELEASE_CACHE=$(list_releases ${COMP_WORDS[1]})
+            ANDROID_LUNCH_COMPLETION_CHOSEN_PRODUCT=${COMP_WORDS[1]}
+        fi
+        COMPREPLY=( $(compgen -W "${ANDROID_LUNCH_COMPLETION_RELEASE_CACHE}" -- "${COMP_WORDS[COMP_CWORD]}") )
+    fi
+
+    # Available variants
+    if [[ $COMP_CWORD -eq 3 ]] ; then
+        COMPREPLY=(user userdebug eng)
+    fi
+
+    return 0
+}
+
+
 # Configures the build to build unbundled apps.
 # Run tapas with one or more app names (from LOCAL_PACKAGE_NAME)
 function tapas()
@@ -752,49 +865,6 @@
     run_tool_with_logging "ADB" $ADB "${@}"
 }
 
-function run_tool_with_logging() {
-  # Run commands in a subshell for us to handle forced terminations with a trap
-  # handler.
-  (
-  local tool_tag="$1"
-  shift
-  local tool_binary="$1"
-  shift
-
-  # If the logger is not configured, run the original command and return.
-  if [[ -z "${ANDROID_TOOL_LOGGER}" ]]; then
-     "${tool_binary}" "${@}"
-     return $?
-  fi
-
-  # Otherwise, run the original command and call the logger when done.
-  local start_time
-  start_time=$(date +%s.%N)
-  local logger=${ANDROID_TOOL_LOGGER}
-
-  # Install a trap to call the logger even when the process terminates abnormally.
-  # The logger is run in the background and its output suppressed to avoid
-  # interference with the user flow.
-  trap '
-  exit_code=$?;
-  # Remove the trap to prevent duplicate log.
-  trap - EXIT;
-  "${logger}" \
-    --tool_tag="${tool_tag}" \
-    --start_timestamp="${start_time}" \
-    --end_timestamp="$(date +%s.%N)" \
-    --tool_args="$*" \
-    --exit_code="${exit_code}" \
-    ${ANDROID_TOOL_LOGGER_EXTRA_ARGS} \
-    > /dev/null 2>&1 &
-  exit ${exit_code}
-  ' SIGINT SIGTERM SIGQUIT EXIT
-
-  # Run the original command.
-  "${tool_binary}" "${@}"
-  )
-}
-
 # communicate with a running device or emulator, set up necessary state,
 # and run the hat command.
 function runhat()
@@ -1082,6 +1152,7 @@
 unset refreshmod
 unset resgrep
 unset rsgrep
+unset run_tool_with_logging
 unset sepgrep
 unset sgrep
 unset startviewserver
diff --git a/shell_utils.sh b/shell_utils.sh
index 450bb83..86f3f49 100644
--- a/shell_utils.sh
+++ b/shell_utils.sh
@@ -126,4 +126,27 @@
 }
 
 
+function log_tool_invocation()
+{
+    if [[ -z $ANDROID_TOOL_LOGGER ]]; then
+        return
+    fi
+
+    LOG_TOOL_TAG=$1
+    LOG_START_TIME=$(date +%s.%N)
+    trap '
+        exit_code=$?;
+        # Remove the trap to prevent duplicate log.
+        trap - EXIT;
+        $ANDROID_TOOL_LOGGER \
+                --tool_tag="${LOG_TOOL_TAG}" \
+                --start_timestamp="${LOG_START_TIME}" \
+                --end_timestamp="$(date +%s.%N)" \
+                --tool_args="$*" \
+                --exit_code="${exit_code}" \
+                ${ANDROID_TOOL_LOGGER_EXTRA_ARGS} \
+           > /dev/null 2>&1 &
+        exit ${exit_code}
+    ' SIGINT SIGTERM SIGQUIT EXIT
+}
 
diff --git a/target/product/base_product.mk b/target/product/base_product.mk
index 5446064..0ac220b 100644
--- a/target/product/base_product.mk
+++ b/target/product/base_product.mk
@@ -16,6 +16,7 @@
 
 # Base modules and settings for the product partition.
 PRODUCT_PACKAGES += \
+    build_flag_product \
     fs_config_dirs_product \
     fs_config_files_product \
     group_product \
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 634bf66..98adba5 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -45,6 +45,7 @@
     bu \
     bugreport \
     bugreportz \
+    build_flag_system \
     cgroups.json \
     charger \
     cmd \
diff --git a/target/product/base_system_ext.mk b/target/product/base_system_ext.mk
index 76f008f..92ca227 100644
--- a/target/product/base_system_ext.mk
+++ b/target/product/base_system_ext.mk
@@ -16,6 +16,7 @@
 
 # Base modules and settings for the system_ext partition.
 PRODUCT_PACKAGES += \
+    build_flag_system_ext \
     fs_config_dirs_system_ext \
     fs_config_files_system_ext \
     group_system_ext \
diff --git a/target/product/base_vendor.mk b/target/product/base_vendor.mk
index ec3de75..1854f97 100644
--- a/target/product/base_vendor.mk
+++ b/target/product/base_vendor.mk
@@ -18,6 +18,7 @@
 PRODUCT_PACKAGES += \
     adbd.recovery \
     android.hardware.health@2.0-impl-default.recovery \
+    build_flag_vendor \
     cgroups.recovery.json \
     charger.recovery \
     init_second_stage.recovery \
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index 5044a39..da1284e 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -58,9 +58,6 @@
         device/generic/common/overlays/overlay-config.xml:$(TARGET_COPY_OUT_SYSTEM_EXT)/overlay/config/config.xml
 endif
 
-# b/308878144 no more VNDK on 24Q1 and beyond
-KEEP_VNDK ?= false
-
 # Support additional VNDK snapshots
 PRODUCT_EXTRA_VNDK_VERSIONS := \
     30 \
diff --git a/tests/Android.bp b/tests/Android.bp
deleted file mode 100644
index 39debf5..0000000
--- a/tests/Android.bp
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2024 Google Inc. All rights reserved.
-//
-// 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 {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-    default_team: "trendy_team_build",
-}
-
-python_test_host {
-    name: "run_tool_with_logging_test",
-    main: "run_tool_with_logging_test.py",
-    pkg_path: "testdata",
-    srcs: [
-        "run_tool_with_logging_test.py",
-    ],
-    test_options: {
-        unit_test: true,
-    },
-    data: [
-        ":envsetup_minimum.zip",
-        ":tool_event_logger",
-    ],
-    test_suites: [
-        "general-tests",
-    ],
-    version: {
-        py3: {
-            embedded_launcher: true,
-        },
-    },
-}
diff --git a/tests/run_tool_with_logging_test.py b/tests/run_tool_with_logging_test.py
deleted file mode 100644
index 6f9b59c..0000000
--- a/tests/run_tool_with_logging_test.py
+++ /dev/null
@@ -1,345 +0,0 @@
-# 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.
-
-import dataclasses
-import glob
-from importlib import resources
-import logging
-import os
-from pathlib import Path
-import re
-import shutil
-import signal
-import stat
-import subprocess
-import sys
-import tempfile
-import textwrap
-import time
-import unittest
-import zipfile
-
-EXII_RETURN_CODE = 0
-INTERRUPTED_RETURN_CODE = 130
-
-
-class RunToolWithLoggingTest(unittest.TestCase):
-
-  @classmethod
-  def setUpClass(cls):
-    super().setUpClass()
-    # Configure to print logging to stdout.
-    logging.basicConfig(filename=None, level=logging.DEBUG)
-    console = logging.StreamHandler(sys.stdout)
-    logging.getLogger("").addHandler(console)
-
-  def setUp(self):
-    super().setUp()
-    self.working_dir = tempfile.TemporaryDirectory()
-    # Run all the tests from working_dir which is our temp Android build top.
-    os.chdir(self.working_dir.name)
-    # Extract envsetup.zip which contains the envsetup.sh and other dependent
-    # scripts required to set up the build environments.
-    with resources.files("testdata").joinpath("envsetup.zip").open("rb") as p:
-      with zipfile.ZipFile(p, "r") as zip_f:
-        zip_f.extractall()
-
-  def tearDown(self):
-    self.working_dir.cleanup()
-    super().tearDown()
-
-  def test_does_not_log_when_logger_var_empty(self):
-    test_tool = TestScript.create(self.working_dir)
-
-    self._run_script_and_wait(f"""
-      ANDROID_TOOL_LOGGER=""
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    test_tool.assert_called_once_with_args("arg1 arg2")
-
-  def test_does_not_log_with_logger_unset(self):
-    test_tool = TestScript.create(self.working_dir)
-
-    self._run_script_and_wait(f"""
-      unset ANDROID_TOOL_LOGGER
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    test_tool.assert_called_once_with_args("arg1 arg2")
-
-  def test_log_success_with_logger_enabled(self):
-    test_tool = TestScript.create(self.working_dir)
-    test_logger = TestScript.create(self.working_dir)
-
-    self._run_script_and_wait(f"""
-      ANDROID_TOOL_LOGGER="{test_logger.executable}"
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    test_tool.assert_called_once_with_args("arg1 arg2")
-    expected_logger_args = (
-        "--tool_tag=FAKE_TOOL --start_timestamp=\d+\.\d+ --end_timestamp="
-        "\d+\.\d+ --tool_args=arg1 arg2 --exit_code=0"
-    )
-    test_logger.assert_called_once_with_args(expected_logger_args)
-
-  def test_run_tool_output_is_same_with_and_without_logging(self):
-    test_tool = TestScript.create(self.working_dir, "echo 'tool called'")
-    test_logger = TestScript.create(self.working_dir)
-
-    run_tool_with_logging_stdout, run_tool_with_logging_stderr = (
-        self._run_script_and_wait(f"""
-      ANDROID_TOOL_LOGGER="{test_logger.executable}"
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-    )
-
-    run_tool_without_logging_stdout, run_tool_without_logging_stderr = (
-        self._run_script_and_wait(f"""
-      ANDROID_TOOL_LOGGER="{test_logger.executable}"
-      {test_tool.executable} arg1 arg2
-    """)
-    )
-
-    self.assertEqual(
-        run_tool_with_logging_stdout, run_tool_without_logging_stdout
-    )
-    self.assertEqual(
-        run_tool_with_logging_stderr, run_tool_without_logging_stderr
-    )
-
-  def test_logger_output_is_suppressed(self):
-    test_tool = TestScript.create(self.working_dir)
-    test_logger = TestScript.create(self.working_dir, "echo 'logger called'")
-
-    run_tool_with_logging_output, _ = self._run_script_and_wait(f"""
-      ANDROID_TOOL_LOGGER="{test_logger.executable}"
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    self.assertNotIn("logger called", run_tool_with_logging_output)
-
-  def test_logger_error_is_suppressed(self):
-    test_tool = TestScript.create(self.working_dir)
-    test_logger = TestScript.create(
-        self.working_dir, "echo 'logger failed' > /dev/stderr; exit 1"
-    )
-
-    _, err = self._run_script_and_wait(f"""
-      ANDROID_TOOL_LOGGER="{test_logger.executable}"
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    self.assertNotIn("logger failed", err)
-
-  def test_log_success_when_tool_interrupted(self):
-    test_tool = TestScript.create(self.working_dir, script_body="sleep 100")
-    test_logger = TestScript.create(self.working_dir)
-
-    process = self._run_script_in_build_env(f"""
-      ANDROID_TOOL_LOGGER="{test_logger.executable}"
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    pgid = os.getpgid(process.pid)
-    # Give sometime for the subprocess to start.
-    time.sleep(1)
-    # Kill the subprocess and any processes created in the same group.
-    os.killpg(pgid, signal.SIGINT)
-
-    returncode, _, _ = self._wait_for_process(process)
-    self.assertEqual(returncode, INTERRUPTED_RETURN_CODE)
-
-    expected_logger_args = (
-        "--tool_tag=FAKE_TOOL --start_timestamp=\d+\.\d+ --end_timestamp="
-        "\d+\.\d+ --tool_args=arg1 arg2 --exit_code=130"
-    )
-    test_logger.assert_called_once_with_args(expected_logger_args)
-
-  def test_logger_can_be_toggled_on(self):
-    test_tool = TestScript.create(self.working_dir)
-    test_logger = TestScript.create(self.working_dir)
-
-    self._run_script_and_wait(f"""
-      ANDROID_TOOL_LOGGER=""
-      ANDROID_TOOL_LOGGER="{test_logger.executable}"
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    test_logger.assert_called_with_times(1)
-
-  def test_logger_can_be_toggled_off(self):
-    test_tool = TestScript.create(self.working_dir)
-    test_logger = TestScript.create(self.working_dir)
-
-    self._run_script_and_wait(f"""
-      ANDROID_TOOL_LOGGER="{test_logger.executable}"
-      ANDROID_TOOL_LOGGER=""
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    test_logger.assert_not_called()
-
-  def test_integration_tool_event_logger_dry_run(self):
-    test_tool = TestScript.create(self.working_dir)
-    logger_path = self._import_logger()
-
-    self._run_script_and_wait(f"""
-      TMPDIR="{self.working_dir.name}"
-      ANDROID_TOOL_LOGGER="{logger_path}"
-      ANDROID_TOOL_LOGGER_EXTRA_ARGS="--dry_run"
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} arg1 arg2
-    """)
-
-    self._assert_logger_dry_run()
-
-  def test_tool_args_do_not_fail_logger(self):
-    test_tool = TestScript.create(self.working_dir)
-    logger_path = self._import_logger()
-
-    self._run_script_and_wait(f"""
-      TMPDIR="{self.working_dir.name}"
-      ANDROID_TOOL_LOGGER="{logger_path}"
-      ANDROID_TOOL_LOGGER_EXTRA_ARGS="--dry_run"
-      run_tool_with_logging "FAKE_TOOL" {test_tool.executable} --tool-arg1
-    """)
-
-    self._assert_logger_dry_run()
-
-  def _import_logger(self) -> Path:
-    logger = "tool_event_logger"
-    logger_path = Path(self.working_dir.name).joinpath(logger)
-    with resources.as_file(resources.files("testdata").joinpath(logger)) as p:
-      shutil.copy(p, logger_path)
-    Path.chmod(logger_path, 0o755)
-    return logger_path
-
-  def _assert_logger_dry_run(self):
-    log_files = glob.glob(self.working_dir.name + "/tool_event_logger_*/*.log")
-    self.assertEqual(len(log_files), 1)
-
-    with open(log_files[0], "r") as f:
-      lines = f.readlines()
-      self.assertEqual(len(lines), 1)
-      self.assertIn("dry run", lines[0])
-
-  def _create_build_env_script(self) -> str:
-    return f"""
-      source {Path(self.working_dir.name).joinpath("build/make/envsetup.sh")}
-    """
-
-  def _run_script_and_wait(self, test_script: str) -> tuple[str, str]:
-    process = self._run_script_in_build_env(test_script)
-    returncode, out, err = self._wait_for_process(process)
-    logging.debug("script stdout: %s", out)
-    logging.debug("script stderr: %s", err)
-    self.assertEqual(returncode, EXII_RETURN_CODE)
-    return out, err
-
-  def _run_script_in_build_env(self, test_script: str) -> subprocess.Popen:
-    setup_build_env_script = self._create_build_env_script()
-    return subprocess.Popen(
-        setup_build_env_script + test_script,
-        shell=True,
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE,
-        text=True,
-        start_new_session=True,
-        executable="/bin/bash",
-        )
-
-  def _wait_for_process(
-      self, process: subprocess.Popen
-  ) -> tuple[int, str, str]:
-    pgid = os.getpgid(process.pid)
-    out, err = process.communicate()
-    # Wait for all process in the same group to complete since the logger runs
-    # as a separate detached process.
-    self._wait_for_process_group(pgid)
-    return (process.returncode, out, err)
-
-  def _wait_for_process_group(self, pgid: int, timeout: int = 5):
-    """Waits for all subprocesses within the process group to complete."""
-    start_time = time.time()
-    while True:
-      if time.time() - start_time > timeout:
-        raise TimeoutError(
-            f"Process group did not complete after {timeout} seconds"
-        )
-      for pid in os.listdir("/proc"):
-        if pid.isdigit():
-          try:
-            if os.getpgid(int(pid)) == pgid:
-              time.sleep(0.1)
-              break
-          except (FileNotFoundError, PermissionError, ProcessLookupError):
-            pass
-      else:
-        # All processes have completed.
-        break
-
-
-@dataclasses.dataclass
-class TestScript:
-  executable: Path
-  output_file: Path
-
-  def create(temp_dir: Path, script_body: str = ""):
-    with tempfile.NamedTemporaryFile(dir=temp_dir.name, delete=False) as f:
-      output_file = f.name
-
-    with tempfile.NamedTemporaryFile(dir=temp_dir.name, delete=False) as f:
-      executable = f.name
-      executable_contents = textwrap.dedent(f"""
-      #!/bin/bash
-
-      echo "${{@}}" >> {output_file}
-      {script_body}
-      """)
-      f.write(executable_contents.encode("utf-8"))
-
-    Path.chmod(f.name, os.stat(f.name).st_mode | stat.S_IEXEC)
-
-    return TestScript(executable, output_file)
-
-  def assert_called_with_times(self, expected_call_times: int):
-    lines = self._read_contents_from_output_file()
-    assert len(lines) == expected_call_times, (
-        f"Expect to call {expected_call_times} times, but actually called"
-        f" {len(lines)} times."
-    )
-
-  def assert_called_with_args(self, expected_args: str):
-    lines = self._read_contents_from_output_file()
-    assert len(lines) > 0
-    assert re.search(expected_args, lines[0]), (
-        f"Expect to call with args {expected_args}, but actually called with"
-        f" args {lines[0]}."
-    )
-
-  def assert_not_called(self):
-    self.assert_called_with_times(0)
-
-  def assert_called_once_with_args(self, expected_args: str):
-    self.assert_called_with_times(1)
-    self.assert_called_with_args(expected_args)
-
-  def _read_contents_from_output_file(self) -> list[str]:
-    with open(self.output_file, "r") as f:
-      return f.readlines()
-
-
-if __name__ == "__main__":
-  unittest.main()
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigStorageReadAPI.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigStorageReadAPI.java
index 7746b58..406ff24 100644
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigStorageReadAPI.java
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigStorageReadAPI.java
@@ -19,13 +19,13 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.nio.MappedByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileChannel.MapMode;
 
 import android.aconfig.storage.PackageReadContext;
 import android.aconfig.storage.FlagReadContext;
-import android.aconfig.storage.BooleanFlagValue;
 
 import dalvik.annotation.optimization.FastNative;
 
@@ -68,19 +68,55 @@
     }
 
     // JNI interface to get package read context
+    // @param mappedFile: memory mapped package map file
+    // @param packageName: package name
+    // @throws IOException if the passed in file is not a valid package map file
     @FastNative
-    public static native PackageReadContext getPackageReadContext(
-        ByteBuffer mappedFile, String packageName);
+    private static native ByteBuffer getPackageReadContextImpl(
+        ByteBuffer mappedFile, String packageName) throws IOException;
+
+    // API to get package read context
+    // @param mappedFile: memory mapped package map file
+    // @param packageName: package name
+    // @throws IOException if the passed in file is not a valid package map file
+    static public PackageReadContext getPackageReadContext (
+        ByteBuffer mappedFile, String packageName) throws IOException {
+        ByteBuffer buffer = getPackageReadContextImpl(mappedFile, packageName);
+        buffer.order(ByteOrder.LITTLE_ENDIAN);
+        return new PackageReadContext(buffer.getInt(), buffer.getInt(4));
+    }
 
     // JNI interface to get flag read context
+    // @param mappedFile: memory mapped flag map file
+    // @param packageId: package id to represent a specific package, obtained from
+    // package map file
+    // @param flagName: flag name
+    // @throws IOException if the passed in file is not a valid flag map file
     @FastNative
-    public static native FlagReadContext getFlagReadContext(
-        ByteBuffer mappedFile, int packageId, String flagName);
+    private static native ByteBuffer getFlagReadContextImpl(
+        ByteBuffer mappedFile, int packageId, String flagName) throws IOException;
+
+    // API to get flag read context
+    // @param mappedFile: memory mapped flag map file
+    // @param packageId: package id to represent a specific package, obtained from
+    // package map file
+    // @param flagName: flag name
+    // @throws IOException if the passed in file is not a valid flag map file
+    public static FlagReadContext getFlagReadContext(
+        ByteBuffer mappedFile, int packageId, String flagName) throws IOException {
+        ByteBuffer buffer = getFlagReadContextImpl(mappedFile, packageId, flagName);
+        buffer.order(ByteOrder.LITTLE_ENDIAN);
+        return new FlagReadContext(buffer.getInt(), buffer.getInt(4));
+    }
 
     // JNI interface to get boolean flag value
+    // @param mappedFile: memory mapped flag value file
+    // @param flagIndex: flag global index in the flag value array
+    // @throws IOException if the passed in file is not a valid flag value file or the
+    // flag index went over the file boundary.
     @FastNative
-    public static native BooleanFlagValue getBooleanFlagValue(
-        ByteBuffer mappedFile, int flagIndex);
+    public static native boolean getBooleanFlagValue(
+        ByteBuffer mappedFile, int flagIndex) throws IOException;
 
     static {
         System.loadLibrary("aconfig_storage_read_api_rust_jni");
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/BooleanFlagValue.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/BooleanFlagValue.java
deleted file mode 100644
index 11fe447..0000000
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/BooleanFlagValue.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package android.aconfig.storage;
-/*
- * 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.
- */
-
-public class BooleanFlagValue {
-    public boolean mQuerySuccess;
-    public String mErrorMessage;
-    public boolean mFlagValue;
-
-    public BooleanFlagValue(boolean querySuccess,
-            String errorMessage,
-            boolean value) {
-        mQuerySuccess = querySuccess;
-        mErrorMessage = errorMessage;
-        mFlagValue = value;
-    }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/FlagReadContext.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/FlagReadContext.java
index 57a36ca..60559a9 100644
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/FlagReadContext.java
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/FlagReadContext.java
@@ -16,20 +16,11 @@
  */
 
 public class FlagReadContext {
-    public boolean mQuerySuccess;
-    public String mErrorMessage;
-    public boolean mFlagExists;
     public StoredFlagType mFlagType;
     public int mFlagIndex;
 
-    public FlagReadContext(boolean querySuccess,
-            String errorMessage,
-            boolean flagExists,
-            int flagType,
+    public FlagReadContext(int flagType,
             int flagIndex) {
-        mQuerySuccess = querySuccess;
-        mErrorMessage = errorMessage;
-        mFlagExists = flagExists;
         mFlagType = StoredFlagType.fromInteger(flagType);
         mFlagIndex = flagIndex;
     }
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/PackageReadContext.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/PackageReadContext.java
index 60d6b66..b781d9b 100644
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/PackageReadContext.java
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/PackageReadContext.java
@@ -16,20 +16,11 @@
  */
 
 public class PackageReadContext {
-    public boolean mQuerySuccess;
-    public String mErrorMessage;
-    public boolean mPackageExists;
     public int mPackageId;
     public int mBooleanStartIndex;
 
-    public PackageReadContext(boolean querySuccess,
-                              String errorMessage,
-                              boolean packageExists,
-                              int packageId,
+    public PackageReadContext(int packageId,
                               int booleanStartIndex) {
-        mQuerySuccess = querySuccess;
-        mErrorMessage = errorMessage;
-        mPackageExists = packageExists;
         mPackageId = packageId;
         mBooleanStartIndex = booleanStartIndex;
     }
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/lib.rs b/tools/aconfig/aconfig_storage_read_api/srcs/lib.rs
index e195eb8..304a059 100644
--- a/tools/aconfig/aconfig_storage_read_api/srcs/lib.rs
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/lib.rs
@@ -6,8 +6,8 @@
 use aconfig_storage_read_api::{FlagReadContext, PackageReadContext};
 
 use anyhow::Result;
-use jni::objects::{JByteBuffer, JClass, JString, JValue};
-use jni::sys::{jint, jobject};
+use jni::objects::{JByteBuffer, JClass, JString};
+use jni::sys::{jboolean, jint};
 use jni::JNIEnv;
 
 /// Call rust find package read context
@@ -28,55 +28,42 @@
     Ok(find_package_read_context(buffer, &package_name)?)
 }
 
-/// Create java package read context return
-fn create_java_package_read_context(
-    env: &mut JNIEnv,
-    success_query: bool,
-    error_message: String,
-    pkg_found: bool,
-    pkg_id: u32,
-    start_index: u32,
-) -> jobject {
-    let query_success = JValue::Bool(success_query as u8);
-    let errmsg = env.new_string(error_message).expect("failed to create JString");
-    let package_exists = JValue::Bool(pkg_found as u8);
-    let package_id = JValue::Int(pkg_id as i32);
-    let boolean_start_index = JValue::Int(start_index as i32);
-    let context = env.new_object(
-        "android/aconfig/storage/PackageReadContext",
-        "(ZLjava/lang/String;ZII)V",
-        &[query_success, (&errmsg).into(), package_exists, package_id, boolean_start_index],
-    );
-    context.expect("failed to call PackageReadContext constructor").into_raw()
-}
-
 /// Get package read context JNI
 #[no_mangle]
 #[allow(unused)]
-pub extern "system" fn Java_android_aconfig_storage_AconfigStorageReadAPI_getPackageReadContext<
+pub extern "system" fn Java_android_aconfig_storage_AconfigStorageReadAPI_getPackageReadContextImpl<
     'local,
 >(
     mut env: JNIEnv<'local>,
     class: JClass<'local>,
     file: JByteBuffer<'local>,
     package: JString<'local>,
-) -> jobject {
+) -> JByteBuffer<'local> {
+    let mut package_id = -1;
+    let mut boolean_start_index = -1;
+
     match get_package_read_context_java(&mut env, file, package) {
-        Ok(context_opt) => match context_opt {
-            Some(context) => create_java_package_read_context(
-                &mut env,
-                true,
-                String::from(""),
-                true,
-                context.package_id,
-                context.boolean_start_index,
-            ),
-            None => create_java_package_read_context(&mut env, true, String::from(""), false, 0, 0),
-        },
+        Ok(context_opt) => {
+            if let Some(context) = context_opt {
+                package_id = context.package_id as i32;
+                boolean_start_index = context.boolean_start_index as i32;
+            }
+        }
         Err(errmsg) => {
-            create_java_package_read_context(&mut env, false, format!("{:?}", errmsg), false, 0, 0)
+            env.throw(("java/io/IOException", errmsg.to_string())).expect("failed to throw");
         }
     }
+
+    let mut bytes = Vec::new();
+    bytes.extend_from_slice(&package_id.to_le_bytes());
+    bytes.extend_from_slice(&boolean_start_index.to_le_bytes());
+    let (addr, len) = {
+        let buf = bytes.leak();
+        (buf.as_mut_ptr(), buf.len())
+    };
+    // SAFETY:
+    // The safety here is ensured as the content is ensured to be valid
+    unsafe { env.new_direct_byte_buffer(addr, len).expect("failed to create byte buffer") }
 }
 
 /// Call rust find flag read context
@@ -98,32 +85,10 @@
     Ok(find_flag_read_context(buffer, package_id as u32, &flag_name)?)
 }
 
-/// Create java flag read context return
-fn create_java_flag_read_context(
-    env: &mut JNIEnv,
-    success_query: bool,
-    error_message: String,
-    flg_found: bool,
-    flg_type: u32,
-    flg_index: u32,
-) -> jobject {
-    let query_success = JValue::Bool(success_query as u8);
-    let errmsg = env.new_string(error_message).expect("failed to create JString");
-    let flag_exists = JValue::Bool(flg_found as u8);
-    let flag_type = JValue::Int(flg_type as i32);
-    let flag_index = JValue::Int(flg_index as i32);
-    let context = env.new_object(
-        "android/aconfig/storage/FlagReadContext",
-        "(ZLjava/lang/String;ZII)V",
-        &[query_success, (&errmsg).into(), flag_exists, flag_type, flag_index],
-    );
-    context.expect("failed to call FlagReadContext constructor").into_raw()
-}
-
 /// Get flag read context JNI
 #[no_mangle]
 #[allow(unused)]
-pub extern "system" fn Java_android_aconfig_storage_AconfigStorageReadAPI_getFlagReadContext<
+pub extern "system" fn Java_android_aconfig_storage_AconfigStorageReadAPI_getFlagReadContextImpl<
     'local,
 >(
     mut env: JNIEnv<'local>,
@@ -131,41 +96,32 @@
     file: JByteBuffer<'local>,
     package_id: jint,
     flag: JString<'local>,
-) -> jobject {
+) -> JByteBuffer<'local> {
+    let mut flag_type = -1;
+    let mut flag_index = -1;
+
     match get_flag_read_context_java(&mut env, file, package_id, flag) {
-        Ok(context_opt) => match context_opt {
-            Some(context) => create_java_flag_read_context(
-                &mut env,
-                true,
-                String::from(""),
-                true,
-                context.flag_type as u32,
-                context.flag_index as u32,
-            ),
-            None => create_java_flag_read_context(&mut env, true, String::from(""), false, 9999, 0),
-        },
+        Ok(context_opt) => {
+            if let Some(context) = context_opt {
+                flag_type = context.flag_type as i32;
+                flag_index = context.flag_index as i32;
+            }
+        }
         Err(errmsg) => {
-            create_java_flag_read_context(&mut env, false, format!("{:?}", errmsg), false, 9999, 0)
+            env.throw(("java/io/IOException", errmsg.to_string())).expect("failed to throw");
         }
     }
-}
 
-/// Create java boolean flag value return
-fn create_java_boolean_flag_value(
-    env: &mut JNIEnv,
-    success_query: bool,
-    error_message: String,
-    value: bool,
-) -> jobject {
-    let query_success = JValue::Bool(success_query as u8);
-    let errmsg = env.new_string(error_message).expect("failed to create JString");
-    let flag_value = JValue::Bool(value as u8);
-    let context = env.new_object(
-        "android/aconfig/storage/BooleanFlagValue",
-        "(ZLjava/lang/String;Z)V",
-        &[query_success, (&errmsg).into(), flag_value],
-    );
-    context.expect("failed to call BooleanFlagValue constructor").into_raw()
+    let mut bytes = Vec::new();
+    bytes.extend_from_slice(&flag_type.to_le_bytes());
+    bytes.extend_from_slice(&flag_index.to_le_bytes());
+    let (addr, len) = {
+        let buf = bytes.leak();
+        (buf.as_mut_ptr(), buf.len())
+    };
+    // SAFETY:
+    // The safety here is ensured as the content is ensured to be valid
+    unsafe { env.new_direct_byte_buffer(addr, len).expect("failed to create byte buffer") }
 }
 
 /// Call rust find boolean flag value
@@ -193,11 +149,12 @@
     class: JClass<'local>,
     file: JByteBuffer<'local>,
     flag_index: jint,
-) -> jobject {
+) -> jboolean {
     match get_boolean_flag_value_java(&mut env, file, flag_index) {
-        Ok(value) => create_java_boolean_flag_value(&mut env, true, String::from(""), value),
+        Ok(value) => value as u8,
         Err(errmsg) => {
-            create_java_boolean_flag_value(&mut env, false, format!("{:?}", errmsg), false)
+            env.throw(("java/io/IOException", errmsg.to_string())).expect("failed to throw");
+            0u8
         }
     }
 }
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
index cf4cfe6..a26b257 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
@@ -18,6 +18,8 @@
 
 import java.io.IOException;
 import java.nio.MappedByteBuffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
@@ -33,7 +35,6 @@
 import android.aconfig.storage.PackageReadContext;
 import android.aconfig.storage.FlagReadContext;
 import android.aconfig.storage.FlagReadContext.StoredFlagType;
-import android.aconfig.storage.BooleanFlagValue;
 
 @RunWith(JUnit4.class)
 public class AconfigStorageReadAPITest{
@@ -51,29 +52,24 @@
         }
         assertTrue(packageMap != null);
 
-        PackageReadContext context = AconfigStorageReadAPI.getPackageReadContext(
-            packageMap, "com.android.aconfig.storage.test_1");
-        assertTrue(context.mQuerySuccess);
-        assertTrue(context.mErrorMessage, context.mErrorMessage.equals(""));
-        assertTrue(context.mPackageExists);
-        assertEquals(context.mPackageId, 0);
-        assertEquals(context.mBooleanStartIndex, 0);
+        try {
+            PackageReadContext context = AconfigStorageReadAPI.getPackageReadContext(
+                packageMap, "com.android.aconfig.storage.test_1");
+            assertEquals(context.mPackageId, 0);
+            assertEquals(context.mBooleanStartIndex, 0);
 
-        context = AconfigStorageReadAPI.getPackageReadContext(
-            packageMap, "com.android.aconfig.storage.test_2");
-        assertTrue(context.mQuerySuccess);
-        assertTrue(context.mErrorMessage, context.mErrorMessage.equals(""));
-        assertTrue(context.mPackageExists);
-        assertEquals(context.mPackageId, 1);
-        assertEquals(context.mBooleanStartIndex, 3);
+            context = AconfigStorageReadAPI.getPackageReadContext(
+                packageMap, "com.android.aconfig.storage.test_2");
+            assertEquals(context.mPackageId, 1);
+            assertEquals(context.mBooleanStartIndex, 3);
 
-        context = AconfigStorageReadAPI.getPackageReadContext(
-            packageMap, "com.android.aconfig.storage.test_4");
-        assertTrue(context.mQuerySuccess);
-        assertTrue(context.mErrorMessage, context.mErrorMessage.equals(""));
-        assertTrue(context.mPackageExists);
-        assertEquals(context.mPackageId, 2);
-        assertEquals(context.mBooleanStartIndex, 6);
+            context = AconfigStorageReadAPI.getPackageReadContext(
+                packageMap, "com.android.aconfig.storage.test_4");
+            assertEquals(context.mPackageId, 2);
+            assertEquals(context.mBooleanStartIndex, 6);
+        } catch (IOException ex) {
+            assertTrue(ex.toString(), false);
+        }
     }
 
     @Test
@@ -87,13 +83,14 @@
         }
         assertTrue(packageMap != null);
 
-        PackageReadContext context = AconfigStorageReadAPI.getPackageReadContext(
-            packageMap, "unknown");
-        assertTrue(context.mQuerySuccess);
-        assertTrue(context.mErrorMessage, context.mErrorMessage.equals(""));
-        assertFalse(context.mPackageExists);
-        assertEquals(context.mPackageId, 0);
-        assertEquals(context.mBooleanStartIndex, 0);
+        try {
+            PackageReadContext context = AconfigStorageReadAPI.getPackageReadContext(
+                packageMap, "unknown");
+            assertEquals(context.mPackageId, -1);
+            assertEquals(context.mBooleanStartIndex, -1);
+        } catch(IOException ex){
+            assertTrue(ex.toString(), false);
+        }
     }
 
     @Test
@@ -134,14 +131,15 @@
         baselines.add(new Baseline(2, "enabled_fixed_ro", StoredFlagType.FixedReadOnlyBoolean, 0));
         baselines.add(new Baseline(0, "disabled_rw", StoredFlagType.ReadWriteBoolean, 0));
 
-        for (Baseline baseline : baselines) {
-            FlagReadContext context = AconfigStorageReadAPI.getFlagReadContext(
-                flagMap, baseline.mPackageId,  baseline.mFlagName);
-            assertTrue(context.mQuerySuccess);
-            assertTrue(context.mErrorMessage, context.mErrorMessage.equals(""));
-            assertTrue(context.mFlagExists);
-            assertEquals(context.mFlagType, baseline.mFlagType);
-            assertEquals(context.mFlagIndex, baseline.mFlagIndex);
+        try {
+            for (Baseline baseline : baselines) {
+                FlagReadContext context = AconfigStorageReadAPI.getFlagReadContext(
+                    flagMap, baseline.mPackageId,  baseline.mFlagName);
+                assertEquals(context.mFlagType, baseline.mFlagType);
+                assertEquals(context.mFlagIndex, baseline.mFlagIndex);
+            }
+        } catch (IOException ex) {
+            assertTrue(ex.toString(), false);
         }
     }
 
@@ -156,21 +154,19 @@
         }
         assertTrue(flagMap!= null);
 
-        FlagReadContext context = AconfigStorageReadAPI.getFlagReadContext(
-            flagMap, 0,  "unknown");
-        assertTrue(context.mQuerySuccess);
-        assertTrue(context.mErrorMessage, context.mErrorMessage.equals(""));
-        assertFalse(context.mFlagExists);
-        assertEquals(context.mFlagType, null);
-        assertEquals(context.mFlagIndex, 0);
+        try {
+            FlagReadContext context = AconfigStorageReadAPI.getFlagReadContext(
+                flagMap, 0,  "unknown");
+            assertEquals(context.mFlagType, null);
+            assertEquals(context.mFlagIndex, -1);
 
-        context = AconfigStorageReadAPI.getFlagReadContext(
-            flagMap, 3,  "enabled_ro");
-        assertTrue(context.mQuerySuccess);
-        assertTrue(context.mErrorMessage, context.mErrorMessage.equals(""));
-        assertFalse(context.mFlagExists);
-        assertEquals(context.mFlagType, null);
-        assertEquals(context.mFlagIndex, 0);
+            context = AconfigStorageReadAPI.getFlagReadContext(
+                flagMap, 3,  "enabled_ro");
+            assertEquals(context.mFlagType, null);
+            assertEquals(context.mFlagIndex, -1);
+        } catch (IOException ex) {
+            assertTrue(ex.toString(), false);
+        }
     }
 
     @Test
@@ -179,17 +175,19 @@
         try {
             flagVal = AconfigStorageReadAPI.mapStorageFile(
                 mStorageDir + "/boot/mockup.val");
-        } catch(IOException ex){
+        } catch (IOException ex) {
             assertTrue(ex.toString(), false);
         }
         assertTrue(flagVal!= null);
 
         boolean[] baselines = {false, true, true, false, true, true, true, true};
         for (int i = 0; i < 8; ++i) {
-            BooleanFlagValue value = AconfigStorageReadAPI.getBooleanFlagValue(flagVal, i);
-            assertTrue(value.mQuerySuccess);
-            assertTrue(value.mErrorMessage, value.mErrorMessage.equals(""));
-            assertEquals(value.mFlagValue, baselines[i]);
+            try {
+                Boolean value = AconfigStorageReadAPI.getBooleanFlagValue(flagVal, i);
+                assertEquals(value, baselines[i]);
+            } catch (IOException ex) {
+                assertTrue(ex.toString(), false);
+            }
         }
     }
 
@@ -199,14 +197,17 @@
         try {
             flagVal = AconfigStorageReadAPI.mapStorageFile(
                 mStorageDir + "/boot/mockup.val");
-        } catch(IOException ex){
+        } catch (IOException ex) {
             assertTrue(ex.toString(), false);
         }
         assertTrue(flagVal!= null);
 
-        BooleanFlagValue value = AconfigStorageReadAPI.getBooleanFlagValue(flagVal, 9);
-        String expectedErrmsg = "Flag value offset goes beyond the end of the file";
-        assertFalse(value.mQuerySuccess);
-        assertTrue(value.mErrorMessage, value.mErrorMessage.contains(expectedErrmsg));
+        try {
+            Boolean value = AconfigStorageReadAPI.getBooleanFlagValue(flagVal, 9);
+            assertTrue("should throw", false);
+        } catch (IOException ex) {
+            String expectedErrmsg = "invalid storage file byte offset";
+            assertTrue(ex.toString(), ex.toString().contains(expectedErrmsg));
+        }
     }
  }
diff --git a/tools/check_elf_file.py b/tools/check_elf_file.py
index 51ec23b..1fd7950 100755
--- a/tools/check_elf_file.py
+++ b/tools/check_elf_file.py
@@ -67,7 +67,7 @@
 
 ELF = collections.namedtuple(
   'ELF',
-  ('dt_soname', 'dt_needed', 'imported', 'exported', 'header'))
+  ('alignments', 'dt_soname', 'dt_needed', 'imported', 'exported', 'header'))
 
 
 def _get_os_name():
@@ -195,7 +195,8 @@
   @classmethod
   def _read_llvm_readobj(cls, elf_file_path, header, llvm_readobj):
     """Run llvm-readobj and parse the output."""
-    cmd = [llvm_readobj, '--dynamic-table', '--dyn-symbols', elf_file_path]
+    cmd = [llvm_readobj, '--program-headers', '--dynamic-table',
+           '--dyn-symbols', elf_file_path]
     out = subprocess.check_output(cmd, text=True)
     lines = out.splitlines()
     return cls._parse_llvm_readobj(elf_file_path, header, lines)
@@ -205,9 +206,56 @@
   def _parse_llvm_readobj(cls, elf_file_path, header, lines):
     """Parse the output of llvm-readobj."""
     lines_it = iter(lines)
+    alignments = cls._parse_program_headers(lines_it)
     dt_soname, dt_needed = cls._parse_dynamic_table(elf_file_path, lines_it)
     imported, exported = cls._parse_dynamic_symbols(lines_it)
-    return ELF(dt_soname, dt_needed, imported, exported, header)
+    return ELF(alignments, dt_soname, dt_needed, imported, exported, header)
+
+
+  _PROGRAM_HEADERS_START_PATTERN = 'ProgramHeaders ['
+  _PROGRAM_HEADERS_END_PATTERN = ']'
+  _PROGRAM_HEADER_START_PATTERN = 'ProgramHeader {'
+  _PROGRAM_HEADER_TYPE_PATTERN = re.compile('^\\s+Type:\\s+(.*)$')
+  _PROGRAM_HEADER_ALIGN_PATTERN = re.compile('^\\s+Alignment:\\s+(.*)$')
+  _PROGRAM_HEADER_END_PATTERN = '}'
+
+
+  @classmethod
+  def _parse_program_headers(cls, lines_it):
+    """Parse the dynamic table section."""
+    alignments = []
+
+    if not cls._find_prefix(cls._PROGRAM_HEADERS_START_PATTERN, lines_it):
+      raise ELFError()
+
+    for line in lines_it:
+      # Parse each program header
+      if line.strip() == cls._PROGRAM_HEADER_START_PATTERN:
+        p_align = None
+        p_type = None
+        for line in lines_it:
+          if line.strip() == cls._PROGRAM_HEADER_END_PATTERN:
+            if not p_align:
+              raise ELFError("Could not parse alignment from program header!")
+            if not p_type:
+              raise ELFError("Could not parse type from program header!")
+
+            if p_type.startswith("PT_LOAD "):
+              alignments.append(int(p_align))
+            break
+
+          match = cls._PROGRAM_HEADER_TYPE_PATTERN.match(line)
+          if match:
+            p_type = match.group(1)
+
+          match = cls._PROGRAM_HEADER_ALIGN_PATTERN.match(line)
+          if match:
+            p_align = match.group(1)
+
+      if line == cls._PROGRAM_HEADERS_END_PATTERN:
+        break
+
+    return alignments
 
 
   _DYNAMIC_SECTION_START_PATTERN = 'DynamicSection ['
@@ -434,6 +482,24 @@
 
       sys.exit(2)
 
+  def check_max_page_size(self, max_page_size):
+    for alignment in self._file_under_test.alignments:
+      if alignment % max_page_size != 0:
+        self._error(f'Load segment has alignment {alignment} but '
+                    f'{max_page_size} required.')
+        self._note()
+        self._note('Fix suggestions:')
+        self._note(f'  use linker flag "-Wl,-z,max-page-size={max_page_size}" '
+                   f'when compiling this lib')
+        self._note()
+        self._note('If the fix above doesn\'t work, bypass this check with:')
+        self._note('  Android.bp: ignore_max_page_size: true,')
+        self._note('  Android.mk: LOCAL_IGNORE_MAX_PAGE_SIZE := true')
+        self._note('  Device mk: PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE := false')
+
+        # TODO: instead of exiting immediately, we may want to collect the
+        # errors from all checks and emit them at once
+        sys.exit(2)
 
   @staticmethod
   def _find_symbol(lib, name, version):
@@ -514,6 +580,8 @@
                       help='Ignore the input file with unknown machine ID')
   parser.add_argument('--allow-undefined-symbols', action='store_true',
                       help='Ignore unresolved undefined symbols')
+  parser.add_argument('--max-page-size', action='store', type=int,
+                      help='Required page size alignment support')
 
   # Other options
   parser.add_argument('--llvm-readobj',
@@ -542,6 +610,9 @@
 
   checker.check_dt_needed(args.system_shared_lib)
 
+  if args.max_page_size:
+    checker.check_max_page_size(args.max_page_size)
+
   if not args.allow_undefined_symbols:
     checker.check_symbols()
 
diff --git a/tools/envsetup/run_envsetup_tests b/tools/envsetup/run_envsetup_tests
new file mode 100755
index 0000000..5977448
--- /dev/null
+++ b/tools/envsetup/run_envsetup_tests
@@ -0,0 +1,229 @@
+#!/usr/bin/env python3
+
+# 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.
+
+import os
+import pathlib
+import subprocess
+import sys
+
+SOURCE_ENVSETUP="source build/make/envsetup.sh && "
+
+def update_display():
+    sys.stderr.write("passed\n")
+
+def go_to_root():
+    while True:
+        if os.path.exists("build/make/envsetup.sh"):
+            return
+        if os.getcwd() == "/":
+            sys.stderr.write("Can't find root of the source tree\n");
+            print("\nFAILED")
+            sys.exit(1)
+        os.chdir("..")
+
+def is_test(name, thing):
+    if not callable(thing):
+        return False
+    if name == "test":
+        return False
+    return name.startswith("test")
+
+
+def test(shell, command, expected_return, expected_stdout, expected_stderr, expected_env):
+    command += "; _rc=$?"
+    for env in expected_env.keys():
+        command += f"; echo ENV: {env}=\\\"${env}\\\""
+    command += "; exit $_rc"
+
+    cmd = [shell, "-c", command]
+    result = subprocess.run(cmd, capture_output=True, text=True)
+
+    status = True
+
+    if result.returncode != expected_return:
+        print()
+        print(f"Expected return code: {expected_return}")
+        print(f"Actual return code:   {result.returncode}")
+        status = False
+
+    printed_stdout = False
+    if expected_stdout and expected_stdout not in result.stdout:
+        print()
+        print(f"Expected stdout to contain:\n{expected_stdout}")
+        print(f"\nActual stdout:\n{result.stdout}")
+        printed_stdout = True
+        status = False
+
+    if expected_stderr and expected_stderr not in result.stderr:
+        print()
+        print(f"Expected stderr to contain:\n{expected_stderr}")
+        print(f"\nActual stderr:\n{result.stderr}")
+        status = False
+
+    env_failure = False
+    for k, v in expected_env.items():
+        if f"{k}=\"{v}\"" not in result.stdout:
+            print()
+            print(f"Expected environment variable {k} to be: {v} --- {k}=\"{v}\"")
+            env_failure = True
+            status = False
+
+    if env_failure and not printed_stdout:
+        print()
+        print("See stdout:")
+        print(result.stdout)
+
+    if not status:
+        print()
+        print("Command to reproduce:")
+        print(command)
+        print()
+
+    return status
+
+NO_LUNCH = {
+    "TARGET_PRODUCT": "",
+    "TARGET_RELEASE": "",
+    "TARGET_BUILD_VARIANT": "",
+}
+
+def test_invalid_lunch_target(shell):
+    return test(shell, SOURCE_ENVSETUP + "lunch invalid-trunk_staging-eng",
+         expected_return=1, expected_stdout=None,
+         expected_stderr="Cannot locate config makefile for product",
+         expected_env=NO_LUNCH)
+
+
+def test_aosp_arm(shell):
+    return test(shell, SOURCE_ENVSETUP + "lunch aosp_arm-trunk_staging-eng",
+         expected_return=0, expected_stdout=None, expected_stderr=None,
+         expected_env={
+            "TARGET_PRODUCT": "aosp_arm",
+            "TARGET_RELEASE": "trunk_staging",
+            "TARGET_BUILD_VARIANT": "eng",
+        })
+
+
+def test_lunch2_empty(shell):
+    return test(shell, SOURCE_ENVSETUP + "lunch2",
+         expected_return=1, expected_stdout=None,
+         expected_stderr="No target specified. See lunch --help",
+         expected_env=NO_LUNCH)
+
+def test_lunch2_four_params(shell):
+    return test(shell, SOURCE_ENVSETUP + "lunch2 a b c d",
+         expected_return=1, expected_stdout=None,
+         expected_stderr="Too many parameters given. See lunch --help",
+         expected_env=NO_LUNCH)
+
+def test_lunch2_aosp_arm(shell):
+    return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm",
+         expected_return=0, expected_stdout="=========", expected_stderr=None,
+         expected_env={
+            "TARGET_PRODUCT": "aosp_arm",
+            "TARGET_RELEASE": "trunk_staging",
+            "TARGET_BUILD_VARIANT": "eng",
+        })
+
+def test_lunch2_aosp_arm_trunk_staging(shell):
+    # Somewhat unfortunate because trunk_staging is the only config in
+    # aosp so we can't really test that this isn't just getting the default
+    return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm trunk_staging",
+         expected_return=0, expected_stdout="=========", expected_stderr=None,
+         expected_env={
+            "TARGET_PRODUCT": "aosp_arm",
+            "TARGET_RELEASE": "trunk_staging",
+            "TARGET_BUILD_VARIANT": "eng",
+        })
+
+def test_lunch2_aosp_arm_trunk_staging_userdebug(shell):
+    return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm trunk_staging userdebug",
+         expected_return=0, expected_stdout="=========", expected_stderr=None,
+         expected_env={
+            "TARGET_PRODUCT": "aosp_arm",
+            "TARGET_RELEASE": "trunk_staging",
+            "TARGET_BUILD_VARIANT": "userdebug",
+        })
+
+def test_list_products(shell):
+    return test(shell, "build/soong/bin/list_products",
+         expected_return=0, expected_stdout="aosp_arm", expected_stderr=None,
+         expected_env=NO_LUNCH)
+
+def test_list_releases_param(shell):
+    return test(shell, "build/soong/bin/list_releases aosp_arm",
+         expected_return=0, expected_stdout="trunk_staging", expected_stderr=None,
+         expected_env=NO_LUNCH)
+
+def test_list_releases_env(shell):
+    return test(shell, "TARGET_PRODUCT=aosp_arm build/soong/bin/list_releases",
+         expected_return=0, expected_stdout="trunk_staging", expected_stderr=None,
+         expected_env=NO_LUNCH)
+
+def test_list_releases_no_product(shell):
+    return test(shell, "build/soong/bin/list_releases",
+         expected_return=1, expected_stdout=None, expected_stderr=None,
+         expected_env=NO_LUNCH)
+
+def test_list_variants(shell):
+    return test(shell, "build/soong/bin/list_variants",
+         expected_return=0, expected_stdout="userdebug", expected_stderr=None,
+         expected_env=NO_LUNCH)
+
+
+def test_get_build_var_in_path(shell):
+    return test(shell, SOURCE_ENVSETUP + "which get_build_var ",
+         expected_return=0, expected_stdout="soong/bin", expected_stderr=None,
+         expected_env=NO_LUNCH)
+
+
+
+TESTS=sorted([(name, thing) for name, thing in locals().items() if is_test(name, thing)])
+
+def main():
+    if any([x.endswith("/soong/bin") for x in os.getenv("PATH").split(":")]):
+        sys.stderr.write("run_envsetup_tests must be run in a shell that has not sourced"
+                + " envsetup.sh\n\nFAILED\n")
+        return 1
+
+    go_to_root()
+
+    tests = TESTS
+    if len(sys.argv) > 1:
+        tests = [(name, func) for name, func in tests if name in sys.argv]
+
+    shells = ["/usr/bin/bash", "/usr/bin/zsh"]
+    total_count = len(tests) * len(shells)
+    index = 1
+    failed_tests = 0
+
+    for name, func in tests:
+        for shell in shells:
+            sys.stdout.write(f"\33[2K\r{index} of {total_count}: {name} in {shell}")
+            passed = func(shell)
+            if not passed:
+                failed_tests += 1
+            index += 1
+
+    if failed_tests > 0:
+        print(f"\n\nFAILED: {failed_tests} of {total_count}")
+        return 1
+    else:
+        print("\n\nSUCCESS")
+        return 0
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/tools/envsetup/spam_for_lunch b/tools/envsetup/spam_for_lunch
new file mode 100755
index 0000000..2e150a6
--- /dev/null
+++ b/tools/envsetup/spam_for_lunch
@@ -0,0 +1,34 @@
+#!/bin/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.
+
+# This ad is kind of big, so only show it if this appears to be a clean build.
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../shell_utils.sh
+if [[ ! -e $(getoutdir)/soong/build.${TARGET_PRODUCT}.ninja ]]; then
+  echo
+  echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+  echo "  Wondering whether to use user, userdebug or eng?"
+  echo
+  echo "  user        The builds that ship to users. Reduced debugability."
+  echo "  userdebug   High fidelity to user builds but with some debugging options"
+  echo "              enabled. Best suited for performance testing or day-to-day use"
+  echo "              with debugging enabled."
+  echo "  eng         More debugging options enabled and faster build times, but"
+  echo "              runtime performance tradeoffs. Best suited for day-to-day"
+  echo "              local development when not doing performance testing."
+  echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+  echo
+fi
+