Merge "Unset AB_OTA_UPDATER from BoardConfigMainlineCommon."
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 3f1721f..a93e79e 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -625,6 +625,13 @@
 
 # Clean up adb_debug.propr
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/adb_debug.prop)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib*/libjavacrypto.so)
+
+# Clean up old verity tools.
+$(call add-clean-step, rm -rf $(HOST_OUT_JAVA_LIBRARIES)/BootSignature.jar)
+$(call add-clean-step, rm -rf $(HOST_OUT_JAVA_LIBRARIES)/VeritySigner.jar)
+$(call add-clean-step, rm -rf $(HOST_OUT_EXECUTABLES)/build_verity_metadata.py)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/Deprecation.md b/Deprecation.md
index 6468f46..01825b2 100644
--- a/Deprecation.md
+++ b/Deprecation.md
@@ -14,8 +14,8 @@
 
 | Module type                | State     |
 | -------------------------- | --------- |
-| `BUILD_HOST_TEST_CONFIG`   | Warning   |
-| `BUILD_TARGET_TEST_CONFIG` | Warning   |
+| `BUILD_HOST_TEST_CONFIG`   | Error     |
+| `BUILD_TARGET_TEST_CONFIG` | Error     |
 | `BUILD_*`                  | Available |
 
 ## Module Type Deprecation Process
diff --git a/core/Makefile b/core/Makefile
index 7361550..dba0fd8 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -459,10 +459,11 @@
 
 build_desc :=
 
-ifeq (,$(filter true, $(TARGET_NO_KERNEL) $(TARGET_NO_RECOVERY)))
-INSTALLED_RECOVERYIMAGE_TARGET := $(PRODUCT_OUT)/recovery.img
-else
 INSTALLED_RECOVERYIMAGE_TARGET :=
+ifdef BUILDING_RECOVERY_IMAGE
+ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+INSTALLED_RECOVERYIMAGE_TARGET := $(PRODUCT_OUT)/recovery.img
+endif
 endif
 
 $(INSTALLED_BUILD_PROP_TARGET): $(intermediate_system_build_prop) $(INSTALLED_RECOVERYIMAGE_TARGET)
@@ -504,7 +505,9 @@
 	$(hide) echo "#" >> $@; \
 	        echo "# BOOTIMAGE_BUILD_PROPERTIES" >> $@; \
 	        echo "#" >> $@;
-	$(hide) $(call generate-common-build-props,bootimage,$@)
+	$(hide) echo ro.bootimage.build.date=`$(DATE_FROM_FILE)`>>$@
+	$(hide) echo ro.bootimage.build.date.utc=`$(DATE_FROM_FILE) +%s`>>$@
+	$(hide) echo ro.bootimage.build.fingerprint="$(BUILD_FINGERPRINT_FROM_FILE)">>$@
 	$(hide) echo "#" >> $@; \
 	        echo "# ADDITIONAL VENDOR BUILD PROPERTIES" >> $@; \
 	        echo "#" >> $@;
@@ -898,13 +901,14 @@
 
 endif # BUILDING_RAMDISK_IMAGE
 
-
-INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
-
-ifneq ($(strip $(TARGET_NO_KERNEL)),true)
-
 # -----------------------------------------------------------------
 # the boot image, which is a collection of other images.
+
+# This is defined here since we may be building recovery as boot
+# below and only want to define this once
+BUILT_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
+
+ifneq ($(strip $(TARGET_NO_KERNEL)),true)
 INTERNAL_BOOTIMAGE_ARGS := \
 	$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
 	--kernel $(INSTALLED_KERNEL_TARGET)
@@ -943,8 +947,10 @@
     --os_version $(PLATFORM_VERSION) \
     --os_patch_level $(PLATFORM_SECURITY_PATCH)
 
-# We build recovery as boot image if BOARD_USES_RECOVERY_AS_BOOT is true.
-ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+# Define these only if we are building boot
+ifdef BUILDING_BOOT_IMAGE
+INSTALLED_BOOTIMAGE_TARGET := $(BUILT_BOOTIMAGE_TARGET)
+
 ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)
 $(error TARGET_BOOTIMAGE_USE_EXT2 is not supported anymore)
 
@@ -1015,7 +1021,7 @@
 	$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
 
 endif # TARGET_BOOTIMAGE_USE_EXT2
-endif # BOARD_USES_RECOVERY_AS_BOOT
+endif # BUILDING_BOOT_IMAGE
 
 else # TARGET_NO_KERNEL == "true"
 ifdef BOARD_PREBUILT_BOOTIMAGE
@@ -1491,7 +1497,7 @@
 # Recovery image
 
 # Recovery image exists if we are building recovery, or building recovery as boot.
-ifneq (,$(INSTALLED_RECOVERYIMAGE_TARGET)$(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
+ifdef BUILDING_RECOVERY_IMAGE
 
 INTERNAL_RECOVERYIMAGE_FILES := $(filter $(TARGET_RECOVERY_OUT)/%, \
     $(ALL_DEFAULT_INSTALLED_MODULES))
@@ -1504,6 +1510,7 @@
 # build-recoveryimage-target, which would touch the files under TARGET_RECOVERY_OUT and race with
 # the call to FILELIST.
 ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+INSTALLED_BOOTIMAGE_TARGET := $(BUILT_BOOTIMAGE_TARGET)
 $(INSTALLED_FILES_FILE_RECOVERY): $(INSTALLED_BOOTIMAGE_TARGET)
 else
 $(INSTALLED_FILES_FILE_RECOVERY): $(INSTALLED_RECOVERYIMAGE_TARGET)
@@ -1922,9 +1929,9 @@
 	@echo "make $@: ignoring dependencies"
 	$(call build-recoveryimage-target, $(INSTALLED_RECOVERYIMAGE_TARGET))
 
-else # INSTALLED_RECOVERYIMAGE_TARGET not defined
+else # BUILDING_RECOVERY_IMAGE
 RECOVERY_RESOURCE_ZIP :=
-endif
+endif # BUILDING_RECOVERY_IMAGE
 
 .PHONY: recoveryimage
 recoveryimage: $(INSTALLED_RECOVERYIMAGE_TARGET) $(RECOVERY_RESOURCE_ZIP)
@@ -1982,14 +1989,19 @@
 
 $(INSTALLED_DEBUG_RAMDISK_TARGET): DEBUG_RAMDISK_SYNC_DIR := $(my_debug_ramdisk_sync_dir)
 $(INSTALLED_DEBUG_RAMDISK_TARGET): DEBUG_RAMDISK_ROOT_DIR := $(my_debug_ramdisk_root_dir)
-# We should have just depended on ramdisk.img or ramdisk-recovery.img.
-# But ramdisk-recovery.img is not a make target, so let's depend on the boot.img directly.
+
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+# ramdisk-recovery.img isn't a make target, need to depend on boot.img if it's for recovery.
 $(INSTALLED_DEBUG_RAMDISK_TARGET): $(INSTALLED_BOOTIMAGE_TARGET)
+else
+# Depends on ramdisk.img, note that some target has ramdisk.img but no boot.img, e.g., emulator.
+$(INSTALLED_DEBUG_RAMDISK_TARGET): $(INSTALLED_RAMDISK_TARGET)
+endif # BOARD_USES_RECOVERY_AS_BOOT
 $(INSTALLED_DEBUG_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_DEBUG_RAMDISK_FILES) | $(MINIGZIP)
 	$(call pretty,"Target debug ram disk: $@")
 	mkdir -p $(TARGET_DEBUG_RAMDISK_OUT)
 	touch $(TARGET_DEBUG_RAMDISK_OUT)/force_debuggable
-	rsync -a $(DEBUG_RAMDISK_SYNC_DIR)/* $(DEBUG_RAMDISK_ROOT_DIR)
+	rsync -a $(DEBUG_RAMDISK_SYNC_DIR)/ $(DEBUG_RAMDISK_ROOT_DIR)
 	$(MKBOOTFS) -d $(TARGET_OUT) $(DEBUG_RAMDISK_ROOT_DIR) | $(MINIGZIP) > $@
 
 .PHONY: ramdisk_debug-nodeps
@@ -1999,7 +2011,7 @@
 	echo "make $@: ignoring dependencies"
 	mkdir -p $(TARGET_DEBUG_RAMDISK_OUT)
 	touch $(TARGET_DEBUG_RAMDISK_OUT)/force_debuggable
-	rsync -a $(DEBUG_RAMDISK_SYNC_DIR)/* $(DEBUG_RAMDISK_ROOT_DIR)
+	rsync -a $(DEBUG_RAMDISK_SYNC_DIR)/ $(DEBUG_RAMDISK_ROOT_DIR)
 	$(MKBOOTFS) -d $(TARGET_OUT) $(DEBUG_RAMDISK_ROOT_DIR) | $(MINIGZIP) > $(INSTALLED_DEBUG_RAMDISK_TARGET)
 
 my_debug_ramdisk_sync_dir :=
@@ -2023,17 +2035,40 @@
 INTERNAL_DEBUG_BOOTIMAGE_ARGS := $(subst $(INSTALLED_RAMDISK_TARGET),$(INSTALLED_DEBUG_RAMDISK_TARGET), $(INTERNAL_BOOTIMAGE_ARGS))
 endif
 
+# If boot.img is chained but boot-debug.img is not signed, libavb in bootloader
+# will fail to find valid AVB metadata from the end of /boot, thus stop booting.
+# Using a test key to sign boot-debug.img to continue booting with the mismatched
+# public key, if the device is unlocked.
+ifneq ($(BOARD_AVB_BOOT_KEY_PATH),)
+BOARD_AVB_DEBUG_BOOT_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
+$(INSTALLED_DEBUG_BOOTIMAGE_TARGET): PRIVATE_AVB_DEBUG_BOOT_SIGNING_ARGS := \
+  --algorithm SHA256_RSA2048 --key $(BOARD_AVB_DEBUG_BOOT_KEY_PATH)
+$(INSTALLED_DEBUG_BOOTIMAGE_TARGET): $(AVBTOOL) $(BOARD_AVB_DEBUG_BOOT_KEY_PATH)
+endif
+
 # Depends on original boot.img and ramdisk-debug.img, to build the new boot-debug.img
 $(INSTALLED_DEBUG_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INSTALLED_BOOTIMAGE_TARGET) $(INSTALLED_DEBUG_RAMDISK_TARGET)
 	$(call pretty,"Target boot debug image: $@")
 	$(MKBOOTIMG) $(INTERNAL_DEBUG_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
-	$(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+	$(if $(BOARD_AVB_BOOT_KEY_PATH),\
+	  $(call assert-max-image-size,$@,$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE))); \
+	  $(AVBTOOL) add_hash_footer \
+	    --image $@ \
+	    --partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \
+	    --partition_name boot $(PRIVATE_AVB_DEBUG_BOOT_SIGNING_ARGS), \
+	  $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE)))
 
 .PHONY: bootimage_debug-nodeps
 bootimage_debug-nodeps: $(MKBOOTIMG)
 	echo "make $@: ignoring dependencies"
 	$(MKBOOTIMG) $(INTERNAL_DEBUG_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_DEBUG_BOOTIMAGE_TARGET)
-	$(call assert-max-image-size,$(INSTALLED_DEBUG_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+	$(if $(BOARD_AVB_BOOT_KEY_PATH),\
+	  $(call assert-max-image-size,$(INSTALLED_DEBUG_BOOTIMAGE_TARGET),$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE))); \
+	  $(AVBTOOL) add_hash_footer \
+	    --image $(INSTALLED_DEBUG_BOOTIMAGE_TARGET) \
+	    --partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \
+	    --partition_name boot $(PRIVATE_AVB_DEBUG_BOOT_SIGNING_ARGS), \
+	  $(call assert-max-image-size,$(INSTALLED_DEBUG_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE)))
 
 endif # TARGET_NO_KERNEL
 
@@ -2065,29 +2100,6 @@
 FULL_SYSTEMIMAGE_DEPS += $(INTERNAL_ROOT_FILES) $(INSTALLED_FILES_FILE_ROOT)
 
 # -----------------------------------------------------------------
-# Final System VINTF manifest including fragments. This is not assembled
-# on the device because it depends on everything in a given device
-# image which defines a vintf_fragment.
-
-ifdef BUILDING_SYSTEM_IMAGE
-
-BUILT_ASSEMBLED_SYSTEM_MANIFEST := $(PRODUCT_OUT)/verified_assembled_system_manifest.xml
-$(BUILT_ASSEMBLED_SYSTEM_MANIFEST): $(HOST_OUT_EXECUTABLES)/assemble_vintf
-$(BUILT_ASSEMBLED_SYSTEM_MANIFEST): $(BUILT_VENDOR_MATRIX)
-$(BUILT_ASSEMBLED_SYSTEM_MANIFEST): $(BUILT_SYSTEM_MANIFEST)
-$(BUILT_ASSEMBLED_SYSTEM_MANIFEST): $(FULL_SYSTEMIMAGE_DEPS)
-	@echo "Verifying system VINTF manifest."
-	PRODUCT_ENFORCE_VINTF_MANIFEST=$(PRODUCT_ENFORCE_VINTF_MANIFEST) \
-	$(HOST_OUT_EXECUTABLES)/assemble_vintf \
-	    -c $(BUILT_VENDOR_MATRIX) \
-	    -i $(BUILT_SYSTEM_MANIFEST) \
-	    $$([ -d $(TARGET_OUT)/etc/vintf/manifest ] && \
-	        find $(TARGET_OUT)/etc/vintf/manifest -type f -name "*.xml" | \
-	        sed "s/^/-i /" | tr '\n' ' ') -o $@
-
-endif # BUILDING_SYSTEM_IMAGE
-
-# -----------------------------------------------------------------
 ifdef BUILDING_SYSTEM_IMAGE
 
 # installed file list
@@ -2174,101 +2186,13 @@
 endef
 endif
 
-# Check that libraries that should only be in APEXes don't end up in the system
-# image. For the Runtime APEX this complements the checks in
-# art/build/apex/art_apex_test.py.
-# TODO(b/128708192): Implement this restriction in Soong instead.
-
-# TODO(b/124293228): Fix remaining bugs and add these libraries to the list:
-#   libart-compiler.so
-#   libart-dexlayout.so
-#   libart.so
-#   libartbase.so
-#   libartpalette.so
-#   libdexfile.so
-#   libdexfile_external.so  - aosp_marlin-userdebug gets this in a vndk-sp-Q subdirectory.
-#   libicui18n.so
-#   libicuuc.so
-#   libnativehelper.so  - cf_x86_phone-userdebug builds get this in system/lib/arm
-#   libprofile.so
-#   libsigchain.so  - cf_x86_phone-userdebug builds get this in system/lib/arm
-#   libtombstoned_client.so
-APEX_MODULE_LIBS= \
-  libadbconnection.so \
-  libandroidicu.so \
-  libdt_fd_forward.so \
-  libdt_socket.so \
-  libjavacore.so \
-  libjdwp.so \
-  libnativebridge.so \
-  libnativeloader.so \
-  libnpt.so \
-  libopenjdk.so \
-  libopenjdkjvm.so \
-  libopenjdkjvmti.so \
-  libpac.so \
-
-# An option to disable the check below, for local use since some build targets
-# still may create these libraries in /system (b/129006418).
-DISABLE_APEX_LIBS_ABSENCE_CHECK ?=
-
-# Exclude lib/arm and lib/arm64 which contain the native bridge proxy libs.
-# They are compiled for the guest architecture and used with an entirely
-# different linker config. The native libs are then linked to as usual via
-# exported interfaces, so the proxy libs do not violate the interface boundaries
-# on the native architecture.
-# TODO(b/130630776): Introduce a make variable for the appropriate directory
-# when native bridge is active.
-APEX_LIBS_ABSENCE_CHECK_EXCLUDE=lib/arm lib/arm64
-
-# If the check below fails, some library has ended up in system/lib or
-# system/lib64 that is intended to only go into some APEX package. The likely
-# cause is that a library or binary in /system has grown a dependency that
-# directly or indirectly pulls in the prohibited library.
-#
-# To resolve this, look for the APEX package that the library belong to - search
-# for it in 'native_shared_lib' properties in 'apex' build modules (see
-# art/build/apex/Android.bp for an example). Then check if there is an exported
-# library in that APEX package that should be used instead, i.e. one listed in
-# its 'native_shared_lib' property for which the corresponding 'cc_library'
-# module has a 'stubs' clause (like libdexfile_external in
-# art/libdexfile/Android.bp).
-#
-# If you cannot find an APEX exported library that fits your needs, or you think
-# that the library you want to depend on should be allowed in /system, then
-# please contact the owners of the APEX package containing the library.
-#
-# If you get this error for a library that is exported in an APEX, then the APEX
-# might be misconfigured or something is wrong in the build system. Please reach
-# out to the APEX package owners and/or soong-team@, or
-# android-building@googlegroups.com externally.
-ifndef DISABLE_APEX_LIBS_ABSENCE_CHECK
-define check-apex-libs-absence
-$(hide) ( \
-  cd $(TARGET_OUT) && \
-  findres=$$(find lib* \
-    $(foreach dir,$(APEX_LIBS_ABSENCE_CHECK_EXCLUDE),-path $(dir) -prune -o) \
-    -type f \( -false $(foreach lib,$(APEX_MODULE_LIBS),-o -name $(lib)) \) \
-    -print) && \
-  if [ -n "$$findres" ]; then \
-    echo "APEX libraries found in system image (see comment in build/make/core/Makefile for details):" 1>&2; \
-    echo "$$findres" | sort 1>&2; \
-    false; \
-  fi; \
-)
-endef
-else
-define check-apex-libs-absence
-endef
-endif
-
 # $(1): output file
 define build-systemimage-target
   @echo "Target system fs image: $(1)"
   $(call create-system-vendor-symlink)
   $(call create-system-product-symlink)
   $(call create-system-product_services-symlink)
-  $(call check-apex-libs-absence)
+  $(call check-apex-libs-absence-on-disk)
   @mkdir -p $(dir $(1)) $(systemimage_intermediates) && rm -rf $(systemimage_intermediates)/system_image_info.txt
   $(call generate-image-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt,system, \
       skip_fsck=true)
@@ -2279,7 +2203,6 @@
            exit 1 )
 endef
 
-$(BUILT_SYSTEMIMAGE): $(BUILT_ASSEMBLED_SYSTEM_MANIFEST)
 $(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE) $(BUILD_IMAGE_SRCS)
 	$(call build-systemimage-target,$@)
 
@@ -2913,6 +2836,52 @@
 endif
 
 # -----------------------------------------------------------------
+# Final Framework VINTF manifest including fragments. This is not assembled
+# on the device because it depends on everything in a given device
+# image which defines a vintf_fragment.
+
+ifdef BUILDING_SYSTEM_IMAGE
+
+ifndef BOARD_USES_PRODUCTIMAGE
+  # If no product image at all, check system manifest directly against device matrix.
+  check_framework_manifest := true
+else ifdef BUILDING_PRODUCT_IMAGE
+  # If device has a product image, only check if the product image is built.
+  check_framework_manifest := true
+endif
+
+# TODO (b/131425279): delete this line once build_mixed script can correctly merge system and
+# product manifests.
+check_framework_manifest := true
+
+ifeq ($(check_framework_manifest),true)
+
+BUILT_ASSEMBLED_FRAMEWORK_MANIFEST := $(PRODUCT_OUT)/verified_assembled_framework_manifest.xml
+$(BUILT_ASSEMBLED_FRAMEWORK_MANIFEST): $(HOST_OUT_EXECUTABLES)/assemble_vintf \
+                                       $(BUILT_VENDOR_MATRIX) \
+                                       $(BUILT_SYSTEM_MANIFEST) \
+                                       $(FULL_SYSTEMIMAGE_DEPS) \
+                                       $(BUILT_PRODUCT_MANIFEST) \
+                                       $(BUILT_PRODUCTIMAGE_TARGET)
+	@echo "Verifying framework VINTF manifest."
+	PRODUCT_ENFORCE_VINTF_MANIFEST=$(PRODUCT_ENFORCE_VINTF_MANIFEST) \
+	$(HOST_OUT_EXECUTABLES)/assemble_vintf \
+	    -o $@ \
+	    -c $(BUILT_VENDOR_MATRIX) \
+	    -i $(BUILT_SYSTEM_MANIFEST) \
+	    $(addprefix -i ,\
+	      $(filter $(TARGET_OUT)/etc/vintf/manifest/%.xml,$(FULL_SYSTEMIMAGE_DEPS)) \
+	      $(BUILT_PRODUCT_MANIFEST) \
+	      $(filter $(TARGET_OUT_PRODUCT)/etc/vintf/manifest/%.xml,$(INTERNAL_PRODUCTIMAGE_FILES)))
+
+droidcore: $(BUILT_ASSEMBLED_FRAMEWORK_MANIFEST)
+
+endif # check_framework_manifest
+check_framework_manifest :=
+
+endif # BUILDING_SYSTEM_IMAGE
+
+# -----------------------------------------------------------------
 # product_services partition image
 ifdef BUILDING_PRODUCT_SERVICES_IMAGE
 INTERNAL_PRODUCT_SERVICESIMAGE_FILES := \
@@ -3518,134 +3487,112 @@
 endif
 
 ifeq ($(build_otatools_package),true)
-OTATOOLS :=  $(HOST_OUT_EXECUTABLES)/minigzip \
-  $(HOST_OUT_EXECUTABLES)/aapt \
-  $(HOST_OUT_EXECUTABLES)/checkvintf \
-  $(HOST_OUT_EXECUTABLES)/mkbootfs \
-  $(HOST_OUT_EXECUTABLES)/mkbootimg \
-  $(HOST_OUT_EXECUTABLES)/fs_config \
-  $(HOST_OUT_EXECUTABLES)/zipalign \
-  $(HOST_OUT_EXECUTABLES)/bsdiff \
-  $(HOST_OUT_EXECUTABLES)/imgdiff \
-  $(HOST_OUT_JAVA_LIBRARIES)/signapk.jar \
-  $(HOST_OUT_JAVA_LIBRARIES)/BootSignature.jar \
-  $(HOST_OUT_JAVA_LIBRARIES)/VeritySigner.jar \
-  $(HOST_OUT_EXECUTABLES)/mke2fs \
-  $(HOST_OUT_EXECUTABLES)/mkuserimg_mke2fs \
-  $(HOST_OUT_EXECUTABLES)/e2fsdroid \
-  $(HOST_OUT_EXECUTABLES)/tune2fs \
-  $(HOST_OUT_EXECUTABLES)/mksquashfsimage.sh \
-  $(HOST_OUT_EXECUTABLES)/mksquashfs \
-  $(HOST_OUT_EXECUTABLES)/mkf2fsuserimg.sh \
-  $(HOST_OUT_EXECUTABLES)/make_f2fs \
-  $(HOST_OUT_EXECUTABLES)/sload_f2fs \
-  $(HOST_OUT_EXECUTABLES)/simg2img \
-  $(HOST_OUT_EXECUTABLES)/e2fsck \
-  $(HOST_OUT_EXECUTABLES)/generate_verity_key \
-  $(HOST_OUT_EXECUTABLES)/verity_signer \
-  $(HOST_OUT_EXECUTABLES)/verity_verifier \
-  $(HOST_OUT_EXECUTABLES)/append2simg \
-  $(HOST_OUT_EXECUTABLES)/img2simg \
-  $(HOST_OUT_EXECUTABLES)/boot_signer \
-  $(HOST_OUT_EXECUTABLES)/fec \
-  $(HOST_OUT_EXECUTABLES)/brillo_update_payload \
-  $(HOST_OUT_EXECUTABLES)/lib/shflags/shflags \
-  $(HOST_OUT_EXECUTABLES)/delta_generator \
-  $(HOST_OUT_EXECUTABLES)/care_map_generator \
-  $(HOST_OUT_EXECUTABLES)/fc_sort \
-  $(HOST_OUT_EXECUTABLES)/sefcontext_compile \
-  $(LPMAKE) \
-  $(AVBTOOL) \
-  $(BLK_ALLOC_TO_BASE_FS) \
-  $(BROTLI) \
-  $(BUILD_VERITY_METADATA) \
-  $(BUILD_VERITY_TREE)
+
+INTERNAL_OTATOOLS_MODULES := \
+  aapt \
+  append2simg \
+  avbtool \
+  blk_alloc_to_base_fs \
+  boot_signer \
+  brillo_update_payload \
+  brotli \
+  bsdiff \
+  build_verity_metadata \
+  build_verity_tree \
+  care_map_generator \
+  checkvintf \
+  delta_generator \
+  e2fsck \
+  e2fsdroid \
+  fc_sort \
+  fec \
+  fs_config \
+  generate_verity_key \
+  img2simg \
+  imgdiff \
+  libconscrypt_openjdk_jni \
+  lpmake \
+  make_f2fs \
+  minigzip \
+  mkbootfs \
+  mkbootimg \
+  mke2fs \
+  mke2fs.conf \
+  mkf2fsuserimg.sh \
+  mksquashfs \
+  mksquashfsimage.sh \
+  mkuserimg_mke2fs \
+  sefcontext_compile \
+  shflags \
+  signapk \
+  simg2img \
+  sload_f2fs \
+  tune2fs \
+  verity_signer \
+  verity_verifier \
+  zipalign \
 
 ifeq (true,$(PRODUCT_SUPPORTS_VBOOT))
-OTATOOLS += \
-  $(FUTILITY) \
-  $(VBOOT_SIGNER)
+INTERNAL_OTATOOLS_MODULES += \
+  futility \
+  vboot_signer
 endif
 
-# Shared libraries.
-OTATOOLS += \
-  $(HOST_LIBRARY_PATH)/libc++$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/liblog$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libcutils$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libselinux$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libcrypto_utils$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libcrypto-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext2fs-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext2_blkid-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext2_com_err-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext2_e2p-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext2_misc$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext2_profile-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext2_quota-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext2_uuid-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libconscrypt_openjdk_jni$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libbrillo$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libbrillo-stream$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libchrome$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libcurl-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libevent-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libprotobuf-cpp-lite$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libssl-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libz-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libsparse-host$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libbase$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libpcre2$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libbrotli$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/liblp$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libext4_utils$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libfec$(HOST_SHLIB_SUFFIX) \
-  $(HOST_LIBRARY_PATH)/libsquashfs_utils$(HOST_SHLIB_SUFFIX)
-
+INTERNAL_OTATOOLS_FILES := \
+  $(filter $(HOST_OUT)/%,$(call module-installed-files,$(INTERNAL_OTATOOLS_MODULES)))
 
 .PHONY: otatools
-otatools: $(OTATOOLS)
+otatools: $(INTERNAL_OTATOOLS_FILES)
 
-BUILT_OTATOOLS_PACKAGE := $(PRODUCT_OUT)/otatools.zip
-$(BUILT_OTATOOLS_PACKAGE): zip_root := $(call intermediates-dir-for,PACKAGING,otatools)/otatools
+# For each module, recursively resolve its host shared library dependencies. Then we have a full
+# list of modules whose installed files need to be packed.
+INTERNAL_OTATOOLS_MODULES_WITH_DEPS := \
+  $(sort $(INTERNAL_OTATOOLS_MODULES) \
+      $(foreach m,$(INTERNAL_OTATOOLS_MODULES),$(call get-all-shared-libs-deps,$(m))))
 
-OTATOOLS_DEPS := \
-  system/extras/ext4_utils/mke2fs.conf \
-  $(sort $(shell find build/make/target/product/security -type f -name "*.x509.pem" -o -name "*.pk8" -o \
-      -name verity_key))
+INTERNAL_OTATOOLS_PACKAGE_FILES := \
+  $(filter $(HOST_OUT)/%,$(call module-installed-files,$(INTERNAL_OTATOOLS_MODULES_WITH_DEPS)))
+
+INTERNAL_OTATOOLS_PACKAGE_FILES += \
+  $(sort $(shell find build/make/target/product/security -type f -name "*.x509.pem" -o \
+      -name "*.pk8" -o -name verity_key))
 
 ifneq (,$(wildcard device))
-OTATOOLS_DEPS += \
+INTERNAL_OTATOOLS_PACKAGE_FILES += \
   $(sort $(shell find device $(wildcard vendor) -type f -name "*.pk8" -o -name "verifiedboot*" -o \
       -name "*.x509.pem" -o -name "oem*.prop"))
 endif
 ifneq (,$(wildcard external/avb))
-OTATOOLS_DEPS += \
+INTERNAL_OTATOOLS_PACKAGE_FILES += \
   $(sort $(shell find external/avb/test/data -type f -name "testkey_*.pem" -o \
       -name "atx_metadata.bin"))
 endif
 ifneq (,$(wildcard system/update_engine))
-OTATOOLS_DEPS += \
+INTERNAL_OTATOOLS_PACKAGE_FILES += \
   $(sort $(shell find system/update_engine/scripts -name "*.pyc" -prune -o -type f -print))
 endif
-
-OTATOOLS_RELEASETOOLS := \
-  $(sort $(shell find build/make/tools/releasetools -name "*.pyc" -prune -o -type f))
-
 ifeq (true,$(PRODUCT_SUPPORTS_VBOOT))
-OTATOOLS_DEPS += \
+INTERNAL_OTATOOLS_PACKAGE_FILES += \
   $(sort $(shell find external/vboot_reference/tests/devkeys -type f))
 endif
 
-$(BUILT_OTATOOLS_PACKAGE): $(OTATOOLS) $(OTATOOLS_DEPS) $(OTATOOLS_RELEASETOOLS) $(SOONG_ZIP)
+INTERNAL_OTATOOLS_RELEASETOOLS := \
+  $(sort $(shell find build/make/tools/releasetools -name "*.pyc" -prune -o \
+      \( -type f -o -type l \) -print))
+
+BUILT_OTATOOLS_PACKAGE := $(PRODUCT_OUT)/otatools.zip
+$(BUILT_OTATOOLS_PACKAGE): PRIVATE_ZIP_ROOT := $(call intermediates-dir-for,PACKAGING,otatools)/otatools
+$(BUILT_OTATOOLS_PACKAGE): PRIVATE_OTATOOLS_PACKAGE_FILES := $(INTERNAL_OTATOOLS_PACKAGE_FILES)
+$(BUILT_OTATOOLS_PACKAGE): PRIVATE_OTATOOLS_RELEASETOOLS := $(INTERNAL_OTATOOLS_RELEASETOOLS)
+$(BUILT_OTATOOLS_PACKAGE): $(INTERNAL_OTATOOLS_PACKAGE_FILES) $(INTERNAL_OTATOOLS_RELEASETOOLS)
+$(BUILT_OTATOOLS_PACKAGE): $(SOONG_ZIP)
 	@echo "Package OTA tools: $@"
-	$(hide) rm -rf $@ $(zip_root)
-	$(hide) mkdir -p $(dir $@) $(zip_root)/bin $(zip_root)/framework $(zip_root)/releasetools
-	$(call copy-files-with-structure,$(OTATOOLS),$(HOST_OUT)/,$(zip_root))
-	$(hide) cp $(SOONG_ZIP) $(zip_root)/bin/
-	$(hide) cp -r -d -p build/make/tools/releasetools/* $(zip_root)/releasetools
-	$(hide) rm -rf $@ $(zip_root)/releasetools/*.pyc
-	$(hide) $(SOONG_ZIP) -o $@ -C $(zip_root) -D $(zip_root) \
-	  -C . $(addprefix -f ,$(OTATOOLS_DEPS))
+	rm -rf $@ $(PRIVATE_ZIP_ROOT)
+	mkdir -p $(dir $@)
+	$(call copy-files-with-structure,$(PRIVATE_OTATOOLS_PACKAGE_FILES),$(HOST_OUT)/,$(PRIVATE_ZIP_ROOT))
+	$(call copy-files-with-structure,$(PRIVATE_OTATOOLS_RELEASETOOLS),build/make/tools/,$(PRIVATE_ZIP_ROOT))
+	cp $(SOONG_ZIP) $(PRIVATE_ZIP_ROOT)/bin/
+	$(SOONG_ZIP) -o $@ -C $(PRIVATE_ZIP_ROOT) -D $(PRIVATE_ZIP_ROOT)
 
 .PHONY: otatools-package
 otatools-package: $(BUILT_OTATOOLS_PACKAGE)
@@ -3758,6 +3705,8 @@
       echo "super_$(group)_partition_list=$(BOARD_$(call to-upper,$(group))_PARTITION_LIST)" >> $(1);))
   $(if $(filter true,$(TARGET_USERIMAGES_SPARSE_EXT_DISABLED)), \
     echo "build_non_sparse_super_partition=true" >> $(1))
+  $(if $(filter true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE)), \
+    echo "super_image_in_update_package=true" >> $(1))
 endef
 
 # By conditionally including the dependency of the target files package on the
@@ -3804,7 +3753,7 @@
 	    $(HOST_OUT_EXECUTABLES)/bsdiff \
 	    $(HOST_OUT_EXECUTABLES)/care_map_generator \
 	    $(BUILD_IMAGE_SRCS) \
-	    $(BUILT_ASSEMBLED_SYSTEM_MANIFEST) \
+	    $(BUILT_ASSEMBLED_FRAMEWORK_MANIFEST) \
 	    $(BUILT_ASSEMBLED_VENDOR_MANIFEST) \
 	    $(BUILT_SYSTEM_MATRIX) \
 	    $(BUILT_VENDOR_MATRIX) \
@@ -3945,6 +3894,9 @@
 ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
 	$(hide) echo "boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
 endif
+ifeq ($(INSTALLED_BOOTIMAGE_TARGET),)
+	$(hide) echo "no_boot=true" >> $(zip_root)/META/misc_info.txt
+endif
 ifeq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
 	$(hide) echo "no_recovery=true" >> $(zip_root)/META/misc_info.txt
 endif
@@ -4151,8 +4103,8 @@
 endif
 	@# Metadata for compatibility verification.
 	$(hide) cp $(BUILT_SYSTEM_MATRIX) $(zip_root)/META/system_matrix.xml
-ifdef BUILT_ASSEMBLED_SYSTEM_MANIFEST
-	$(hide) cp $(BUILT_ASSEMBLED_SYSTEM_MANIFEST) $(zip_root)/META/system_manifest.xml
+ifdef BUILT_ASSEMBLED_FRAMEWORK_MANIFEST
+	$(hide) cp $(BUILT_ASSEMBLED_FRAMEWORK_MANIFEST) $(zip_root)/META/system_manifest.xml
 endif
 ifdef BUILT_ASSEMBLED_VENDOR_MANIFEST
 	$(hide) cp $(BUILT_ASSEMBLED_VENDOR_MANIFEST) $(zip_root)/META/vendor_manifest.xml
@@ -4272,25 +4224,6 @@
 endif    # build_ota_package
 
 # -----------------------------------------------------------------
-# The update package
-
-name := $(TARGET_PRODUCT)
-ifeq ($(TARGET_BUILD_TYPE),debug)
-  name := $(name)_debug
-endif
-name := $(name)-img-$(FILE_NAME_TAG)
-
-INTERNAL_UPDATE_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
-
-$(INTERNAL_UPDATE_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(ZIP2ZIP)
-	@echo "Package: $@"
-	$(hide) $(ZIP2ZIP) -i $(BUILT_TARGET_FILES_PACKAGE) -o $@ \
-	   OTA/android-info.txt:android-info.txt "IMAGES/*.img:."
-
-.PHONY: updatepackage
-updatepackage: $(INTERNAL_UPDATE_PACKAGE_TARGET)
-
-# -----------------------------------------------------------------
 # A zip of the appcompat directory containing logs
 APPCOMPAT_ZIP := $(PRODUCT_OUT)/appcompat.zip
 # For apps_only build we'll establish the dependency later in build/make/core/main.mk.
@@ -4311,7 +4244,6 @@
 	$(hide) find $(PRODUCT_OUT)/appcompat | sort >$(PRIVATE_LIST_FILE)
 	$(hide) $(SOONG_ZIP) -d -o $@ -C $(PRODUCT_OUT)/appcompat -l $(PRIVATE_LIST_FILE)
 
-
 # -----------------------------------------------------------------
 # A zip of the symbols directory.  Keep the full paths to make it
 # more obvious where these files came from.
@@ -4341,7 +4273,7 @@
 	$(hide) rm -rf $@ $(PRIVATE_LIST_FILE)
 	$(hide) mkdir -p $(dir $@) $(TARGET_OUT_UNSTRIPPED) $(dir $(PRIVATE_LIST_FILE))
 	$(hide) find -L $(TARGET_OUT_UNSTRIPPED) -type f | sort >$(PRIVATE_LIST_FILE)
-	$(hide) $(SOONG_ZIP) -d -o $@ -C $(OUT_DIR)/.. -l $(PRIVATE_LIST_FILE)
+	$(hide) $(SOONG_ZIP) --ignore_missing_files -d -o $@ -C $(OUT_DIR)/.. -l $(PRIVATE_LIST_FILE)
 # -----------------------------------------------------------------
 # A zip of the coverage directory.
 #
@@ -4436,7 +4368,7 @@
 endif # TARGET_BUILD_APPS
 
 # -----------------------------------------------------------------
-# super partition image
+# super partition image (dist)
 
 ifeq (true,$(PRODUCT_BUILD_SUPER_PARTITION))
 
@@ -4451,31 +4383,86 @@
 endef
 
 ifneq (true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS))
-INSTALLED_SUPERIMAGE_TARGET := $(call intermediates-dir-for,PACKAGING,super.img)/super.img
-$(INSTALLED_SUPERIMAGE_TARGET): extracted_input_target_files := $(patsubst %.zip,%,$(BUILT_TARGET_FILES_PACKAGE))
-$(INSTALLED_SUPERIMAGE_TARGET): $(LPMAKE) $(BUILT_TARGET_FILES_PACKAGE) $(BUILD_SUPER_IMAGE)
-	$(call pretty,"Target super fs image: $@")
+
+# For real devices and for dist builds, build super image from target files to an intermediate directory.
+INTERNAL_SUPERIMAGE_DIST_TARGET := $(call intermediates-dir-for,PACKAGING,super.img)/super.img
+$(INTERNAL_SUPERIMAGE_DIST_TARGET): extracted_input_target_files := $(patsubst %.zip,%,$(BUILT_TARGET_FILES_PACKAGE))
+$(INTERNAL_SUPERIMAGE_DIST_TARGET): $(LPMAKE) $(BUILT_TARGET_FILES_PACKAGE) $(BUILD_SUPER_IMAGE)
+	$(call pretty,"Target super fs image from target files: $@")
 	PATH=$(dir $(LPMAKE)):$$PATH \
 	    $(BUILD_SUPER_IMAGE) -v $(extracted_input_target_files) $@
 
-# supernod uses images in the $(PRODUCT_OUT) directory instead of images from target files package.
-.PHONY: superimage-nodeps supernod
-superimage-nodeps supernod: intermediates := $(call intermediates-dir-for,PACKAGING,superimage-nodeps)
-superimage-nodeps supernod: | $(LPMAKE) $(BUILD_SUPER_IMAGE) \
-    $(foreach p, $(BOARD_SUPER_PARTITION_PARTITION_LIST), $(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET))
-	$(call pretty,"make $(INSTALLED_SUPERIMAGE_TARGET): ignoring dependencies")
-	mkdir -p $(intermediates)
-	rm -rf $(intermediates)/misc_info.txt
-	$(call dump-super-image-info,$(intermediates)/misc_info.txt)
-	$(foreach p,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \
-	  echo "$(p)_image=$(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET)" >> $(intermediates)/misc_info.txt;)
-	mkdir -p $(dir $(INSTALLED_SUPERIMAGE_TARGET))
-	PATH=$(dir $(LPMAKE)):$$PATH \
-	  $(BUILD_SUPER_IMAGE) -v $(intermediates)/misc_info.txt $(INSTALLED_SUPERIMAGE_TARGET)
+# Skip packing it in dist package because it is in update package.
+ifneq (true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE))
+$(call dist-for-goals,dist_files,$(INTERNAL_SUPERIMAGE_DIST_TARGET))
+endif
+
+.PHONY: superimage_dist
+superimage_dist: $(INTERNAL_SUPERIMAGE_DIST_TARGET)
 
 endif # PRODUCT_RETROFIT_DYNAMIC_PARTITIONS != "true"
+endif # BOARD_SUPER_PARTITION_SIZE != ""
+endif # PRODUCT_BUILD_SUPER_PARTITION == "true"
 
-$(call dist-for-goals,dist_files,$(INSTALLED_SUPERIMAGE_TARGET))
+# -----------------------------------------------------------------
+# super partition image for development
+
+ifeq (true,$(PRODUCT_BUILD_SUPER_PARTITION))
+ifneq ($(BOARD_SUPER_PARTITION_SIZE),)
+ifneq (true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS))
+
+# Build super.img by using $(INSTALLED_*IMAGE_TARGET) to $(1)
+# $(1): built image path
+# $(2): misc_info.txt path; its contents should match expectation of build_super_image.py
+define build-superimage-target
+  mkdir -p $(dir $(2))
+  rm -rf $(2)
+  $(call dump-super-image-info,$(2))
+  $(foreach p,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \
+    echo "$(p)_image=$(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET)" >> $(2);)
+  mkdir -p $(dir $(1))
+  PATH=$(dir $(LPMAKE)):$$PATH \
+    $(BUILD_SUPER_IMAGE) -v $(2) $(1)
+endef
+
+INSTALLED_SUPERIMAGE_TARGET := $(PRODUCT_OUT)/super.img
+INSTALLED_SUPERIMAGE_DEPENDENCIES := $(LPMAKE) $(BUILD_SUPER_IMAGE) \
+    $(foreach p, $(BOARD_SUPER_PARTITION_PARTITION_LIST), $(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET))
+
+# If BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT is set, super.img is built from images in the
+# $(PRODUCT_OUT) directory, and is built to $(PRODUCT_OUT)/super.img. Also, it will
+# be built for non-dist builds. This is useful for devices that uses super.img directly, e.g.
+# virtual devices.
+ifeq (true,$(BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT))
+$(INSTALLED_SUPERIMAGE_TARGET): $(INSTALLED_SUPERIMAGE_DEPENDENCIES)
+	$(call pretty,"Target super fs image for debug: $@")
+	$(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\
+	  $(call intermediates-dir-for,PACKAGING,superimage_debug)/misc_info.txt)
+
+droidcore: $(INSTALLED_SUPERIMAGE_TARGET)
+
+# For devices that uses super image directly, the superimage target points to the file in $(PRODUCT_OUT).
+.PHONY: superimage
+superimage: $(INSTALLED_SUPERIMAGE_TARGET)
+endif # BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT
+
+# Build $(PRODUCT_OUT)/super.img without dependencies.
+.PHONY: superimage-nodeps supernod
+superimage-nodeps supernod: intermediates :=
+superimage-nodeps supernod: | $(INSTALLED_SUPERIMAGE_DEPENDENCIES)
+	$(call pretty,"make $(INSTALLED_SUPERIMAGE_TARGET): ignoring dependencies")
+	$(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\
+	  $(call intermediates-dir-for,PACKAGING,superimage-nodeps)/misc_info.txt)
+
+endif # PRODUCT_RETROFIT_DYNAMIC_PARTITIONS != "true"
+endif # BOARD_SUPER_PARTITION_SIZE != ""
+endif # PRODUCT_BUILD_SUPER_PARTITION == "true"
+
+# -----------------------------------------------------------------
+# super empty image
+
+ifeq (true,$(PRODUCT_BUILD_SUPER_PARTITION))
+ifneq ($(BOARD_SUPER_PARTITION_SIZE),)
 
 INSTALLED_SUPERIMAGE_EMPTY_TARGET := $(PRODUCT_OUT)/super_empty.img
 $(INSTALLED_SUPERIMAGE_EMPTY_TARGET): intermediates := $(call intermediates-dir-for,PACKAGING,super_empty)
@@ -4492,6 +4479,50 @@
 endif # BOARD_SUPER_PARTITION_SIZE != ""
 endif # PRODUCT_BUILD_SUPER_PARTITION == "true"
 
+
+# -----------------------------------------------------------------
+# The update package
+
+name := $(TARGET_PRODUCT)
+ifeq ($(TARGET_BUILD_TYPE),debug)
+  name := $(name)_debug
+endif
+name := $(name)-img-$(FILE_NAME_TAG)
+
+INTERNAL_UPDATE_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
+
+$(INTERNAL_UPDATE_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(ZIP2ZIP)
+
+ifeq (true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE))
+$(INTERNAL_UPDATE_PACKAGE_TARGET): $(INTERNAL_SUPERIMAGE_DIST_TARGET)
+	@echo "Package: $@"
+	# Filter out super_empty and images in BOARD_SUPER_PARTITION_PARTITION_LIST.
+	# Filter out system_other for launch DAP devices because it is in super image.
+	# Include OTA/super_*.img for retrofit devices and super.img for non-retrofit
+	# devices.
+	$(hide) $(ZIP2ZIP) -i $(BUILT_TARGET_FILES_PACKAGE) -o $@ \
+	  -x IMAGES/super_empty.img \
+	  $(foreach partition,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \
+	    -x IMAGES/$(partition).img) \
+	  $(if $(filter system, $(BOARD_SUPER_PARTITION_PARTITION_LIST)), \
+	    $(if $(filter true, $(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)),, \
+	      -x IMAGES/system_other.img)) \
+	  $(if $(filter true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)), \
+	    $(foreach device,$(BOARD_SUPER_PARTITION_BLOCK_DEVICES), \
+	      OTA/super_$(device).img:super_$(device).img)) \
+	  OTA/android-info.txt:android-info.txt "IMAGES/*.img:."
+	$(if $(INTERNAL_SUPERIMAGE_DIST_TARGET), zip -q -j -u $@ $(INTERNAL_SUPERIMAGE_DIST_TARGET))
+else
+$(INTERNAL_UPDATE_PACKAGE_TARGET):
+	@echo "Package: $@"
+	$(hide) $(ZIP2ZIP) -i $(BUILT_TARGET_FILES_PACKAGE) -o $@ \
+	  OTA/android-info.txt:android-info.txt "IMAGES/*.img:."
+endif # BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE
+
+.PHONY: updatepackage
+updatepackage: $(INTERNAL_UPDATE_PACKAGE_TARGET)
+
+
 # -----------------------------------------------------------------
 # dalvik something
 .PHONY: dalvikfiles
@@ -4499,13 +4530,20 @@
 
 ifeq ($(BUILD_QEMU_IMAGES),true)
 MK_QEMU_IMAGE_SH := device/generic/goldfish/tools/mk_qemu_image.sh
+MK_COMBINE_QEMU_IMAGE_SH := device/generic/goldfish/tools/mk_combined_img.py
 SGDISK_HOST := $(HOST_OUT_EXECUTABLES)/sgdisk
 
 ifdef INSTALLED_SYSTEMIMAGE_TARGET
 INSTALLED_QEMU_SYSTEMIMAGE := $(PRODUCT_OUT)/system-qemu.img
-$(INSTALLED_QEMU_SYSTEMIMAGE): $(INSTALLED_SYSTEMIMAGE_TARGET) $(MK_QEMU_IMAGE_SH) $(SGDISK_HOST) $(SIMG2IMG)
-	@echo Create system-qemu.img
-	(export SGDISK=$(SGDISK_HOST) SIMG2IMG=$(SIMG2IMG); $(MK_QEMU_IMAGE_SH) $(INSTALLED_SYSTEMIMAGE_TARGET))
+INSTALLED_SYSTEM_QEMU_CONFIG := $(PRODUCT_OUT)/system-qemu-config.txt
+$(INSTALLED_SYSTEM_QEMU_CONFIG): $(INSTALLED_SUPERIMAGE_TARGET) $(INSTALLED_VBMETAIMAGE_TARGET)
+	@echo "$(PRODUCT_OUT)/vbmeta.img vbmeta 1" > $@
+	@echo "$(INSTALLED_SUPERIMAGE_TARGET) super 2" >> $@
+$(INSTALLED_QEMU_SYSTEMIMAGE): $(INSTALLED_VBMETAIMAGE_TARGET) $(MK_COMBINE_QEMU_IMAGE_SH) $(SGDISK_HOST) $(SIMG2IMG) \
+    $(INSTALLED_SUPERIMAGE_TARGET) $(INSTALLED_SYSTEM_QEMU_CONFIG)
+	@echo Create system-qemu.img now
+	(export SGDISK=$(SGDISK_HOST) SIMG2IMG=$(SIMG2IMG); \
+     $(MK_COMBINE_QEMU_IMAGE_SH) -i $(INSTALLED_SYSTEM_QEMU_CONFIG) -o $@)
 
 systemimage: $(INSTALLED_QEMU_SYSTEMIMAGE)
 droidcore: $(INSTALLED_QEMU_SYSTEMIMAGE)
@@ -4547,17 +4585,17 @@
 droidcore: $(INSTALLED_QEMU_ODMIMAGE)
 endif
 
-ifeq ($(BOARD_AVB_ENABLE),true)
 QEMU_VERIFIED_BOOT_PARAMS := $(PRODUCT_OUT)/VerifiedBootParams.textproto
-MK_VERIFIED_BOOT_KERNEL_CMDLINE_SH := device/generic/goldfish/tools/mk_verified_boot_params.sh
-$(QEMU_VERIFIED_BOOT_PARAMS): $(INSTALLED_QEMU_SYSTEMIMAGE) $(MK_VERIFIED_BOOT_KERNEL_CMDLINE_SH) $(INSTALLED_VBMETAIMAGE_TARGET) $(SGDISK_HOST) $(AVBTOOL)
+MK_VBMETA_BOOT_KERNEL_CMDLINE_SH := device/generic/goldfish/tools/mk_vbmeta_boot_params.sh
+$(QEMU_VERIFIED_BOOT_PARAMS): $(INSTALLED_VBMETAIMAGE_TARGET) $(INSTALLED_SYSTEMIMAGE_TARGET) \
+    $(MK_VBMETA_BOOT_KERNEL_CMDLINE_SH) $(AVBTOOL)
 	@echo Creating $@
-	(export SGDISK=$(SGDISK_HOST) AVBTOOL=$(AVBTOOL); $(MK_VERIFIED_BOOT_KERNEL_CMDLINE_SH) $(INSTALLED_VBMETAIMAGE_TARGET) $(INSTALLED_QEMU_SYSTEMIMAGE) $(QEMU_VERIFIED_BOOT_PARAMS))
-
+	(export AVBTOOL=$(AVBTOOL); $(MK_VBMETA_BOOT_KERNEL_CMDLINE_SH) $(INSTALLED_VBMETAIMAGE_TARGET) \
+    $(INSTALLED_SYSTEMIMAGE_TARGET) $(QEMU_VERIFIED_BOOT_PARAMS))
 
 systemimage: $(QEMU_VERIFIED_BOOT_PARAMS)
 droidcore: $(QEMU_VERIFIED_BOOT_PARAMS)
-endif
+
 endif
 # -----------------------------------------------------------------
 # The emulator package
diff --git a/core/board_config.mk b/core/board_config.mk
index 2580a33..62d779c 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -290,8 +290,33 @@
 endif
 .KATI_READONLY := BUILDING_CACHE_IMAGE
 
-# TODO: Add BUILDING_BOOT_IMAGE / BUILDING_RECOVERY_IMAGE
-# This gets complicated with BOARD_USES_RECOVERY_AS_BOOT, so skipping for now.
+# Are we building a boot image
+BUILDING_BOOT_IMAGE :=
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+  BUILDING_BOOT_IMAGE :=
+else ifeq ($(PRODUCT_BUILD_BOOT_IMAGE),)
+  ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
+    BUILDING_BOOT_IMAGE := true
+  endif
+else ifeq ($(PRODUCT_BUILD_BOOT_IMAGE),true)
+  BUILDING_BOOT_IMAGE := true
+endif
+.KATI_READONLY := BUILDING_BOOT_IMAGE
+
+# Are we building a recovery image
+BUILDING_RECOVERY_IMAGE :=
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+  BUILDING_RECOVERY_IMAGE := true
+else ifeq ($(PRODUCT_BUILD_RECOVERY_IMAGE),)
+  ifdef BOARD_RECOVERYIMAGE_PARTITION_SIZE
+    ifeq (,$(filter true, $(TARGET_NO_KERNEL) $(TARGET_NO_RECOVERY)))
+      BUILDING_RECOVERY_IMAGE := true
+    endif
+  endif
+else ifeq ($(PRODUCT_BUILD_RECOVERY_IMAGE),true)
+  BUILDING_RECOVERY_IMAGE := true
+endif
+.KATI_READONLY := BUILDING_RECOVERY_IMAGE
 
 # Are we building a ramdisk image
 BUILDING_RAMDISK_IMAGE := true
diff --git a/core/config.mk b/core/config.mk
index 94928a2..1db37ef 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -604,11 +604,11 @@
 BUILD_IMAGE_SRCS := $(wildcard build/make/tools/releasetools/*.py)
 APPEND2SIMG := $(HOST_OUT_EXECUTABLES)/append2simg
 VERITY_SIGNER := $(HOST_OUT_EXECUTABLES)/verity_signer
-BUILD_VERITY_METADATA := $(HOST_OUT_EXECUTABLES)/build_verity_metadata.py
+BUILD_VERITY_METADATA := $(HOST_OUT_EXECUTABLES)/build_verity_metadata
 BUILD_VERITY_TREE := $(HOST_OUT_EXECUTABLES)/build_verity_tree
 BOOT_SIGNER := $(HOST_OUT_EXECUTABLES)/boot_signer
 FUTILITY := $(HOST_OUT_EXECUTABLES)/futility-host
-VBOOT_SIGNER := prebuilts/misc/scripts/vboot_signer/vboot_signer.sh
+VBOOT_SIGNER := $(HOST_OUT_EXECUTABLES)/vboot_signer
 FEC := $(HOST_OUT_EXECUTABLES)/fec
 BRILLO_UPDATE_PAYLOAD := $(HOST_OUT_EXECUTABLES)/brillo_update_payload
 
diff --git a/core/definitions.mk b/core/definitions.mk
index 1f5c5ce..af6248d 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -1997,26 +1997,6 @@
         @$(call emit-line,$(wordlist 13001,13500,$(1)),$(2))
         @$(if $(wordlist 13501,13502,$(1)),$(error Too many words ($(words $(1)))))
 endef
-
-# For a list of jar files, unzip them to a specified directory,
-# but make sure that no META-INF files come along for the ride,
-# unless PRIVATE_DONT_DELETE_JAR_META_INF is set.
-#
-# $(1): files to unzip
-# $(2): destination directory
-define unzip-jar-files
-  $(hide) for f in $(1); \
-  do \
-    if [ ! -f $$f ]; then \
-      echo Missing file $$f; \
-      exit 1; \
-    fi; \
-    unzip -qo $$f -d $(2); \
-    rm -f $(2)/module-info.class; \
-  done
-  $(if $(PRIVATE_DONT_DELETE_JAR_META_INF),,$(hide) rm -rf $(2)/META-INF)
-endef
-
 # Return jar arguments to compress files in a given directory
 # $(1): directory
 #
@@ -2114,9 +2094,9 @@
     $(addprefix --bootclasspath ,$(strip $(PRIVATE_BOOTCLASSPATH))) \
     $(addprefix --classpath ,$(strip $(PRIVATE_ALL_JAVA_HEADER_LIBRARIES))) \
     || ( rm -rf $(dir $@)/classes-turbine ; exit 41 ) && \
-    $(MERGE_ZIPS) -j --ignore-duplicates -stripDir META-INF $@.tmp $@.premerged $(call reverse-list,$(PRIVATE_STATIC_JAVA_HEADER_LIBRARIES)) ; \
+    $(MERGE_ZIPS) -j --ignore-duplicates -stripDir META-INF $@.tmp $@.premerged $(PRIVATE_STATIC_JAVA_HEADER_LIBRARIES) ; \
 else \
-    $(MERGE_ZIPS) -j --ignore-duplicates -stripDir META-INF $@.tmp $(call reverse-list,$(PRIVATE_STATIC_JAVA_HEADER_LIBRARIES)) ; \
+    $(MERGE_ZIPS) -j --ignore-duplicates -stripDir META-INF $@.tmp $(PRIVATE_STATIC_JAVA_HEADER_LIBRARIES) ; \
 fi
 $(hide) $(ZIPTIME) $@.tmp
 $(hide) $(call commit-change-for-toc,$@)
diff --git a/core/deprecation.mk b/core/deprecation.mk
index cbc938a..9d57527 100644
--- a/core/deprecation.mk
+++ b/core/deprecation.mk
@@ -37,13 +37,13 @@
 # relevant BUILD_BROKEN_USES_BUILD_* variables, then these would move to
 # DEFAULT_ERROR_BUILD_MODULE_TYPES.
 DEFAULT_WARNING_BUILD_MODULE_TYPES :=$= \
-  BUILD_HOST_TEST_CONFIG \
-  BUILD_TARGET_TEST_CONFIG \
 
 # These are BUILD_* variables that are errors to reference, but you can set
 # BUILD_BROKEN_USES_BUILD_* in your BoardConfig.mk in order to turn them back
 # to warnings.
 DEFAULT_ERROR_BUILD_MODULE_TYPES :=$= \
+  BUILD_HOST_TEST_CONFIG \
+  BUILD_TARGET_TEST_CONFIG \
 
 # These are BUILD_* variables that are always errors to reference.
 # Setting the BUILD_BROKEN_USES_BUILD_* variables is also an error.
diff --git a/core/dex_preopt.mk b/core/dex_preopt.mk
index 180edaf..32690fe 100644
--- a/core/dex_preopt.mk
+++ b/core/dex_preopt.mk
@@ -26,7 +26,7 @@
 # We can do this only if preopt is enabled and if the product uses libart config (which sets the
 # default properties for preopting).
 ifeq ($(WITH_DEXPREOPT), true)
-ifeq ($(PRODUCT_USES_ART), true)
+ifeq ($(PRODUCT_USES_DEFAULT_ART_CONFIG), true)
 
 boot_zip := $(PRODUCT_OUT)/boot.zip
 bootclasspath_jars := $(DEXPREOPT_BOOTCLASSPATH_DEX_FILES)
@@ -45,5 +45,5 @@
 
 $(call dist-for-goals, droidcore, $(boot_zip))
 
-endif  #PRODUCT_USES_ART
+endif  #PRODUCT_USES_DEFAULT_ART_CONFIG
 endif  #WITH_DEXPREOPT
diff --git a/core/dex_preopt_config.mk b/core/dex_preopt_config.mk
index a494991..b5834b0 100644
--- a/core/dex_preopt_config.mk
+++ b/core/dex_preopt_config.mk
@@ -111,6 +111,7 @@
   $(call add_json_bool, GenerateDmFiles,                    $(PRODUCT_DEX_PREOPT_GENERATE_DM_FILES))
   $(call add_json_bool, NeverAllowStripping,                $(PRODUCT_DEX_PREOPT_NEVER_ALLOW_STRIPPING))
   $(call add_json_bool, NoDebugInfo,                        $(filter false,$(WITH_DEXPREOPT_DEBUG_INFO)))
+  $(call add_json_bool, DontResolveStartupStrings,          $(filter false,$(PRODUCT_DEX_PREOPT_RESOLVE_STARTUP_STRINGS)))
   $(call add_json_bool, AlwaysSystemServerDebugInfo,        $(filter true,$(PRODUCT_SYSTEM_SERVER_DEBUG_INFO)))
   $(call add_json_bool, NeverSystemServerDebugInfo,         $(filter false,$(PRODUCT_SYSTEM_SERVER_DEBUG_INFO)))
   $(call add_json_bool, AlwaysOtherDebugInfo,               $(filter true,$(PRODUCT_OTHER_JAVA_DEBUG_INFO)))
diff --git a/core/generate_enforce_rro.mk b/core/generate_enforce_rro.mk
index f7877f2..6a23aeb 100644
--- a/core/generate_enforce_rro.mk
+++ b/core/generate_enforce_rro.mk
@@ -34,7 +34,6 @@
 endif
 
 LOCAL_FULL_MANIFEST_FILE := $(rro_android_manifest_file)
-LOCAL_CERTIFICATE := platform
 
 LOCAL_AAPT_FLAGS += --auto-add-overlay
 LOCAL_RESOURCE_DIR := $(enforce_rro_source_overlays)
diff --git a/core/host_dalvik_java_library.mk b/core/host_dalvik_java_library.mk
index 2a251e8..423575c 100644
--- a/core/host_dalvik_java_library.mk
+++ b/core/host_dalvik_java_library.mk
@@ -104,7 +104,6 @@
 ifneq ($(TURBINE_ENABLED),false)
 
 $(full_classes_turbine_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS) $(annotation_processor_flags)
-$(full_classes_turbine_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
 $(full_classes_turbine_jar): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
 $(full_classes_turbine_jar): \
     $(java_source_list_file) \
@@ -142,7 +141,7 @@
             $(PRIVATE_JAR_MANIFEST) > $(dir $@)/manifest.mf)
 	$(MERGE_ZIPS) -j --ignore-duplicates $(if $(PRIVATE_JAR_MANIFEST),-m $(dir $@)/manifest.mf) \
             $(if $(PRIVATE_DONT_DELETE_JAR_META_INF),,-stripDir META-INF -zipToNotStrip $<) \
-            $@ $< $(call reverse-list,$(PRIVATE_STATIC_JAVA_LIBRARIES))
+            $@ $< $(PRIVATE_STATIC_JAVA_LIBRARIES)
 
 # Run jarjar if necessary, otherwise just copy the file.
 ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
diff --git a/core/host_java_library.mk b/core/host_java_library.mk
index c8d2ee7..1225fa9 100644
--- a/core/host_java_library.mk
+++ b/core/host_java_library.mk
@@ -95,13 +95,15 @@
 javac-check-$(LOCAL_MODULE) : $(full_classes_compiled_jar)
 .PHONY: javac-check-$(LOCAL_MODULE)
 
+$(full_classes_combined_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
 $(full_classes_combined_jar): $(full_classes_compiled_jar) \
                               $(jar_manifest_file) \
                               $(full_static_java_libs) | $(MERGE_ZIPS)
 	$(if $(PRIVATE_JAR_MANIFEST), $(hide) sed -e "s/%BUILD_NUMBER%/$(BUILD_NUMBER_FROM_FILE)/" \
             $(PRIVATE_JAR_MANIFEST) > $(dir $@)/manifest.mf)
 	$(MERGE_ZIPS) -j --ignore-duplicates $(if $(PRIVATE_JAR_MANIFEST),-m $(dir $@)/manifest.mf) \
-            -stripDir META-INF -zipToNotStrip $< $@ $< $(call reverse-list,$(PRIVATE_STATIC_JAVA_LIBRARIES))
+            $(if $(PRIVATE_DONT_DELETE_JAR_META_INF),,-stripDir META-INF -zipToNotStrip $<) \
+            $@ $< $(PRIVATE_STATIC_JAVA_LIBRARIES)
 
 # Run jarjar if necessary, otherwise just copy the file.
 ifneq ($(strip $(LOCAL_JARJAR_RULES)),)
diff --git a/core/java.mk b/core/java.mk
index 40fa594..b951f14 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -244,7 +244,6 @@
 
 $(full_classes_turbine_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS) $(annotation_processor_flags)
 $(full_classes_turbine_jar): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
-$(full_classes_turbine_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
 $(full_classes_turbine_jar): \
     $(java_source_list_file) \
     $(java_sources_deps) \
@@ -278,7 +277,6 @@
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES := $(LOCAL_JAR_EXCLUDE_FILES)
 $(full_classes_compiled_jar): PRIVATE_JAR_PACKAGES := $(LOCAL_JAR_PACKAGES)
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_PACKAGES := $(LOCAL_JAR_EXCLUDE_PACKAGES)
-$(full_classes_compiled_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
 $(full_classes_compiled_jar): PRIVATE_JAVA_SOURCE_LIST := $(java_source_list_file)
 $(full_classes_compiled_jar): PRIVATE_ALL_JAVA_HEADER_LIBRARIES := $(full_java_header_libs)
 $(full_classes_compiled_jar): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
@@ -311,7 +309,7 @@
             $(PRIVATE_JAR_MANIFEST) > $(dir $@)/manifest.mf)
 	$(MERGE_ZIPS) -j --ignore-duplicates $(if $(PRIVATE_JAR_MANIFEST),-m $(dir $@)/manifest.mf) \
             $(if $(PRIVATE_DONT_DELETE_JAR_META_INF),,-stripDir META-INF -zipToNotStrip $<) \
-            $@ $< $(call reverse-list,$(PRIVATE_STATIC_JAVA_LIBRARIES))
+            $@ $< $(PRIVATE_STATIC_JAVA_LIBRARIES)
 
 ifdef LOCAL_JAR_PROCESSOR
 # LOCAL_JAR_PROCESSOR_ARGS must be evaluated here to set up the rule-local
diff --git a/core/main.mk b/core/main.mk
index af26705..6f92ff1 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1200,6 +1200,117 @@
 )
 endef
 
+# Check that libraries that should only be in APEXes don't end up in the system
+# image. For the Runtime APEX this complements the checks in
+# art/build/apex/art_apex_test.py.
+# TODO(b/128708192): Implement this restriction in Soong instead.
+
+# Runtime APEX libraries
+APEX_MODULE_LIBS := \
+  libadbconnection.so \
+  libandroidicu.so \
+  libandroidio.so \
+  libart-compiler.so \
+  libart-dexlayout.so \
+  libart.so \
+  libartbase.so \
+  libartpalette.so \
+  libdexfile.so \
+  libdexfile_external.so \
+  libdexfiled_external.so \
+  libdt_fd_forward.so \
+  libdt_socket.so \
+  libicui18n.so \
+  libicuuc.so \
+  libjavacore.so \
+  libjdwp.so \
+  libnativebridge.so \
+  libnativehelper.so \
+  libnativeloader.so \
+  libnpt.so \
+  libopenjdk.so \
+  libopenjdkjvm.so \
+  libopenjdkjvmti.so \
+  libpac.so \
+  libprofile.so \
+  libsigchain.so \
+
+# Conscrypt APEX libraries
+APEX_MODULE_LIBS += \
+  libjavacrypto.so \
+
+# An option to disable the check below, for local use since some build targets
+# still may create these libraries in /system (b/129006418).
+DISABLE_APEX_LIBS_ABSENCE_CHECK ?=
+
+# Exclude lib/arm and lib/arm64 which contain the native bridge proxy libs. They
+# are compiled for the guest architecture and used with an entirely different
+# linker config. The native libs are then linked to as usual via exported
+# interfaces, so the proxy libs do not violate the interface boundaries on the
+# native architecture.
+# TODO(b/130630776): Introduce a make variable for the appropriate directory
+# when native bridge is active.
+APEX_LIBS_ABSENCE_CHECK_EXCLUDE := lib/arm lib/arm64
+
+# Exclude vndk-* subdirectories which contain prebuilts from older releases.
+APEX_LIBS_ABSENCE_CHECK_EXCLUDE += lib/vndk-% lib64/vndk-%
+
+ifdef DISABLE_APEX_LIBS_ABSENCE_CHECK
+  check-apex-libs-absence :=
+  check-apex-libs-absence-on-disk :=
+else
+  # If the check below fails, some library has ended up in system/lib or
+  # system/lib64 that is intended to only go into some APEX package. The likely
+  # cause is that a library or binary in /system has grown a dependency that
+  # directly or indirectly pulls in the prohibited library.
+  #
+  # To resolve this, look for the APEX package that the library belong to -
+  # search for it in 'native_shared_lib' properties in 'apex' build modules (see
+  # art/build/apex/Android.bp for an example). Then check if there is an
+  # exported library in that APEX package that should be used instead, i.e. one
+  # listed in its 'native_shared_lib' property for which the corresponding
+  # 'cc_library' module has a 'stubs' clause (like libdexfile_external in
+  # art/libdexfile/Android.bp).
+  #
+  # If you cannot find an APEX exported library that fits your needs, or you
+  # think that the library you want to depend on should be allowed in /system,
+  # then please contact the owners of the APEX package containing the library.
+  #
+  # If you get this error for a library that is exported in an APEX, then the
+  # APEX might be misconfigured or something is wrong in the build system.
+  # Please reach out to the APEX package owners and/or soong-team@, or
+  # android-building@googlegroups.com externally.
+  define check-apex-libs-absence
+    $(call maybe-print-list-and-error, \
+      $(filter $(foreach lib,$(APEX_MODULE_LIBS),%/$(lib)), \
+        $(filter-out $(foreach dir,$(APEX_LIBS_ABSENCE_CHECK_EXCLUDE), \
+                       $(TARGET_OUT)/$(if $(findstring %,$(dir)),$(dir),$(dir)/%)), \
+          $(filter $(TARGET_OUT)/lib/% $(TARGET_OUT)/lib64/%,$(1)))), \
+      APEX libraries found in system image (see comment for check-apex-libs-absence in \
+      build/make/core/main.mk for details))
+  endef
+
+  # TODO(b/129006418): The check above catches libraries through product
+  # dependencies visible to make, but as long as they have install rules in
+  # /system they may still be created there through other make targets. To catch
+  # that we also do a check on disk just before the system image is built.
+  define check-apex-libs-absence-on-disk
+    $(hide) ( \
+      cd $(TARGET_OUT) && \
+      findres=$$(find lib* \
+        $(foreach dir,$(APEX_LIBS_ABSENCE_CHECK_EXCLUDE),-path "$(subst %,*,$(dir))" -prune -o) \
+        -type f \( -false $(foreach lib,$(APEX_MODULE_LIBS),-o -name $(lib)) \) \
+        -print) && \
+      if [ -n "$$findres" ]; then \
+        echo "APEX libraries found in system image (see comment for check-apex-libs-absence" 1>&2; \
+        echo "in build/make/core/main.mk for details):" 1>&2; \
+        echo "$$findres" | sort 1>&2; \
+        false; \
+      fi; \
+    )
+  endef
+endif
+
 ifdef FULL_BUILD
   ifneq (true,$(ALLOW_MISSING_DEPENDENCIES))
     # Check to ensure that all modules in PRODUCT_PACKAGES exist (opt in per product)
@@ -1312,6 +1423,8 @@
 	rm -f $@
 	$(foreach f,$(sort $(all_offending_files)),echo $(f) >> $@;)
   endif
+
+  $(call check-apex-libs-absence,$(product_target_FILES))
 else
   # We're not doing a full build, and are probably only including
   # a subset of the module makefiles.  Don't try to build any modules
@@ -1469,9 +1582,6 @@
 .PHONY: systemotherimage
 systemotherimage: $(INSTALLED_SYSTEMOTHERIMAGE_TARGET)
 
-.PHONY: superimage
-superimage: $(INSTALLED_SUPERIMAGE_TARGET)
-
 .PHONY: superimage_empty
 superimage_empty: $(INSTALLED_SUPERIMAGE_EMPTY_TARGET)
 
diff --git a/core/node_fns.mk b/core/node_fns.mk
index ccfcc25..b81d60c 100644
--- a/core/node_fns.mk
+++ b/core/node_fns.mk
@@ -142,7 +142,8 @@
 #
 # $(1): context prefix
 # $(2): name of this node
-# $(3): list of variable names
+# $(3): list of node variable names
+# $(4): list of single value variable names (subset of $(3))
 #
 define _expand-inherited-values
   $(foreach v,$(3), \
@@ -154,15 +155,21 @@
             $(patsubst $(INHERIT_TAG)%,%, \
                 $(filter $(INHERIT_TAG)%, $($(_eiv_tv)) \
      )))) \
+    $(eval ### "Whether this variable should only take a single value") \
+    $(eval _eiv_sv := $(filter $(v),$(4))) \
     $(foreach i,$(_eiv_i), \
       $(eval ### "Make sure that this inherit appears only once") \
       $(eval $(_eiv_tv) := \
           $(call uniq-word,$($(_eiv_tv)),$(INHERIT_TAG)$(i))) \
+      $(eval ### "The expanded value, empty if we want a single value and have one") \
+      $(eval _eiv_ev := \
+        $(if $(and $(_eiv_sv),$(filter-out $(INHERIT_TAG)%,$($(_eiv_tv)))),,\
+          $($(1).$(i).$(v)) \
+        ) \
+      ) \
       $(eval ### "Expand the inherit tag") \
       $(eval $(_eiv_tv) := \
-          $(strip \
-              $(patsubst $(INHERIT_TAG)$(i),$($(1).$(i).$(v)), \
-                  $($(_eiv_tv))))) \
+          $(strip $(patsubst $(INHERIT_TAG)$(i),$(_eiv_ev),$($(_eiv_tv))))) \
       $(eval ### "Clear the child so DAGs don't create duplicate entries" ) \
       $(eval $(1).$(i).$(v) :=) \
       $(eval ### "If we just inherited ourselves, it's a cycle.") \
@@ -180,6 +187,7 @@
 # $(1): context prefix
 # $(2): makefile representing this node
 # $(3): list of node variable names
+# $(4): list of single value variable names (subset of $(3))
 #
 # _include_stack contains the list of included files, with the most recent files first.
 define _import-node
@@ -198,7 +206,7 @@
       $(call get-inherited-nodes,$(1).$(2),$(3)))
   $(call _import-nodes-inner,$(1),$($(1).$(2).inherited),$(3))
 
-  $(call _expand-inherited-values,$(1),$(2),$(3))
+  $(call _expand-inherited-values,$(1),$(2),$(3),$(4))
 
   $(eval $(1).$(2).inherited :=)
   $(eval _include_stack := $(wordlist 2,9999,$$(_include_stack)))
@@ -215,6 +223,7 @@
 # $(1): context prefix
 # $(2): list of makefiles representing nodes to import
 # $(3): list of node variable names
+# $(4): list of single value variable names (subset of $(3))
 #
 #TODO: Make the "does not exist" message more helpful;
 #      should print out the name of the file trying to include it.
@@ -225,7 +234,7 @@
         $(eval ### "skipping already-imported $(_in)") \
        , \
         $(eval $(1).$(_in).seen := true) \
-        $(call _import-node,$(1),$(strip $(_in)),$(3)) \
+        $(call _import-node,$(1),$(strip $(_in)),$(3),$(4)) \
        ) \
      , \
       $(error $(1): "$(_in)" does not exist) \
@@ -237,6 +246,8 @@
 # $(1): output list variable name, like "PRODUCTS" or "DEVICES"
 # $(2): list of makefiles representing nodes to import
 # $(3): list of node variable names
+# $(4): list with subset of variable names that take only a single value, instead
+#       of the default list semantics
 #
 define import-nodes
 $(if \
@@ -245,7 +256,7 @@
     $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
                 should be empty here: $(_include_stack))),) \
     $(eval _include_stack := ) \
-    $(call _import-nodes-inner,$(_node_import_context),$(_in),$(3)) \
+    $(call _import-nodes-inner,$(_node_import_context),$(_in),$(3),$(4)) \
     $(call move-var-list,$(_node_import_context).$(_in),$(1).$(_in),$(3)) \
     $(eval _node_import_context :=) \
     $(eval $(1) := $($(1)) $(_in)) \
diff --git a/core/product.mk b/core/product.mk
index 192d58c..8716e3e 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -106,30 +106,37 @@
 $(call get-product-makefiles,$(_find-android-products-files))
 endef
 
-_product_var_list :=
-_product_var_list += PRODUCT_NAME
-_product_var_list += PRODUCT_MODEL
+# Variables that are meant to hold only a single value.
+# - The value set in the current makefile takes precedence over inherited values
+# - If multiple inherited makefiles set the var, the first-inherited value wins
+_product_single_value_vars :=
+
+# Variables that are lists of values.
+_product_list_vars :=
+
+_product_single_value_vars += PRODUCT_NAME
+_product_single_value_vars += PRODUCT_MODEL
 
 # The resoure configuration options to use for this product.
-_product_var_list += PRODUCT_LOCALES
-_product_var_list += PRODUCT_AAPT_CONFIG
-_product_var_list += PRODUCT_AAPT_PREF_CONFIG
-_product_var_list += PRODUCT_AAPT_PREBUILT_DPI
-_product_var_list += PRODUCT_HOST_PACKAGES
-_product_var_list += PRODUCT_PACKAGES
-_product_var_list += PRODUCT_PACKAGES_DEBUG
-_product_var_list += PRODUCT_PACKAGES_DEBUG_ASAN
-_product_var_list += PRODUCT_PACKAGES_ENG
-_product_var_list += PRODUCT_PACKAGES_TESTS
+_product_list_vars += PRODUCT_LOCALES
+_product_list_vars += PRODUCT_AAPT_CONFIG
+_product_list_vars += PRODUCT_AAPT_PREF_CONFIG
+_product_list_vars += PRODUCT_AAPT_PREBUILT_DPI
+_product_list_vars += PRODUCT_HOST_PACKAGES
+_product_list_vars += PRODUCT_PACKAGES
+_product_list_vars += PRODUCT_PACKAGES_DEBUG
+_product_list_vars += PRODUCT_PACKAGES_DEBUG_ASAN
+_product_list_vars += PRODUCT_PACKAGES_ENG
+_product_list_vars += PRODUCT_PACKAGES_TESTS
 
 # The device that this product maps to.
-_product_var_list += PRODUCT_DEVICE
-_product_var_list += PRODUCT_MANUFACTURER
-_product_var_list += PRODUCT_BRAND
+_product_single_value_vars += PRODUCT_DEVICE
+_product_single_value_vars += PRODUCT_MANUFACTURER
+_product_single_value_vars += PRODUCT_BRAND
 
 # These PRODUCT_SYSTEM_* flags, if defined, are used in place of the
 # corresponding PRODUCT_* flags for the sysprops on /system.
-_product_var_list += \
+_product_single_value_vars += \
     PRODUCT_SYSTEM_NAME \
     PRODUCT_SYSTEM_MODEL \
     PRODUCT_SYSTEM_DEVICE \
@@ -138,24 +145,24 @@
 
 # A list of property assignments, like "key = value", with zero or more
 # whitespace characters on either side of the '='.
-_product_var_list += PRODUCT_PROPERTY_OVERRIDES
+_product_list_vars += PRODUCT_PROPERTY_OVERRIDES
 
 # A list of property assignments, like "key = value", with zero or more
 # whitespace characters on either side of the '='.
 # used for adding properties to default.prop
-_product_var_list += PRODUCT_DEFAULT_PROPERTY_OVERRIDES
+_product_list_vars += PRODUCT_DEFAULT_PROPERTY_OVERRIDES
 
 # A list of property assignments, like "key = value", with zero or more
 # whitespace characters on either side of the '='.
 # used for adding properties to build.prop of product partition
-_product_var_list += PRODUCT_PRODUCT_PROPERTIES
+_product_list_vars += PRODUCT_PRODUCT_PROPERTIES
 
 # A list of property assignments, like "key = value", with zero or more
 # whitespace characters on either side of the '='.
 # used for adding properties to build.prop of product partition
-_product_var_list += PRODUCT_PRODUCT_SERVICES_PROPERTIES
-_product_var_list += PRODUCT_ODM_PROPERTIES
-_product_var_list += PRODUCT_CHARACTERISTICS
+_product_list_vars += PRODUCT_PRODUCT_SERVICES_PROPERTIES
+_product_list_vars += PRODUCT_ODM_PROPERTIES
+_product_list_vars += PRODUCT_CHARACTERISTICS
 
 # A list of words like <source path>:<destination path>[:<owner>].
 # The file at the source path should be copied to the destination path
@@ -163,156 +170,160 @@
 # $(PRODUCT_OUT), so it should look like, e.g., "system/etc/file.xml".
 # The rules for these copy steps are defined in build/make/core/Makefile.
 # The optional :<owner> is used to indicate the owner of a vendor file.
-_product_var_list += PRODUCT_COPY_FILES
+_product_list_vars += PRODUCT_COPY_FILES
 
 # The OTA key(s) specified by the product config, if any.  The names
 # of these keys are stored in the target-files zip so that post-build
 # signing tools can substitute them for the test key embedded by
 # default.
-_product_var_list += PRODUCT_OTA_PUBLIC_KEYS
-_product_var_list += PRODUCT_EXTRA_RECOVERY_KEYS
+_product_list_vars += PRODUCT_OTA_PUBLIC_KEYS
+_product_list_vars += PRODUCT_EXTRA_RECOVERY_KEYS
 
 # Should we use the default resources or add any product specific overlays
-_product_var_list += PRODUCT_PACKAGE_OVERLAYS
-_product_var_list += DEVICE_PACKAGE_OVERLAYS
+_product_list_vars += PRODUCT_PACKAGE_OVERLAYS
+_product_list_vars += DEVICE_PACKAGE_OVERLAYS
 
 # Resource overlay list which must be excluded from enforcing RRO.
-_product_var_list += PRODUCT_ENFORCE_RRO_EXCLUDED_OVERLAYS
+_product_list_vars += PRODUCT_ENFORCE_RRO_EXCLUDED_OVERLAYS
 
 # Package list to apply enforcing RRO.
-_product_var_list += PRODUCT_ENFORCE_RRO_TARGETS
+_product_list_vars += PRODUCT_ENFORCE_RRO_TARGETS
 
-_product_var_list += PRODUCT_SDK_ATREE_FILES
-_product_var_list += PRODUCT_SDK_ADDON_NAME
-_product_var_list += PRODUCT_SDK_ADDON_COPY_FILES
-_product_var_list += PRODUCT_SDK_ADDON_COPY_MODULES
-_product_var_list += PRODUCT_SDK_ADDON_DOC_MODULES
-_product_var_list += PRODUCT_SDK_ADDON_SYS_IMG_SOURCE_PROP
+_product_list_vars += PRODUCT_SDK_ATREE_FILES
+_product_list_vars += PRODUCT_SDK_ADDON_NAME
+_product_list_vars += PRODUCT_SDK_ADDON_COPY_FILES
+_product_list_vars += PRODUCT_SDK_ADDON_COPY_MODULES
+_product_list_vars += PRODUCT_SDK_ADDON_DOC_MODULES
+_product_list_vars += PRODUCT_SDK_ADDON_SYS_IMG_SOURCE_PROP
 
 # which Soong namespaces to export to Make
-_product_var_list += PRODUCT_SOONG_NAMESPACES
+_product_list_vars += PRODUCT_SOONG_NAMESPACES
 
-_product_var_list += PRODUCT_DEFAULT_WIFI_CHANNELS
-_product_var_list += PRODUCT_DEFAULT_DEV_CERTIFICATE
-_product_var_list += PRODUCT_RESTRICT_VENDOR_FILES
+_product_list_vars += PRODUCT_DEFAULT_WIFI_CHANNELS
+_product_list_vars += PRODUCT_DEFAULT_DEV_CERTIFICATE
+_product_list_vars += PRODUCT_RESTRICT_VENDOR_FILES
 
 # The list of product-specific kernel header dirs
-_product_var_list += PRODUCT_VENDOR_KERNEL_HEADERS
+_product_list_vars += PRODUCT_VENDOR_KERNEL_HEADERS
 
 # A list of module names of BOOTCLASSPATH (jar files)
-_product_var_list += PRODUCT_BOOT_JARS
-_product_var_list += PRODUCT_SUPPORTS_BOOT_SIGNER
-_product_var_list += PRODUCT_SUPPORTS_VBOOT
-_product_var_list += PRODUCT_SUPPORTS_VERITY
-_product_var_list += PRODUCT_SUPPORTS_VERITY_FEC
-_product_var_list += PRODUCT_OEM_PROPERTIES
+_product_list_vars += PRODUCT_BOOT_JARS
+_product_list_vars += PRODUCT_SUPPORTS_BOOT_SIGNER
+_product_list_vars += PRODUCT_SUPPORTS_VBOOT
+_product_list_vars += PRODUCT_SUPPORTS_VERITY
+_product_list_vars += PRODUCT_SUPPORTS_VERITY_FEC
+_product_list_vars += PRODUCT_OEM_PROPERTIES
 
 # A list of property assignments, like "key = value", with zero or more
 # whitespace characters on either side of the '='.
 # used for adding properties to default.prop of system partition
-_product_var_list += PRODUCT_SYSTEM_DEFAULT_PROPERTIES
+_product_list_vars += PRODUCT_SYSTEM_DEFAULT_PROPERTIES
 
-_product_var_list += PRODUCT_SYSTEM_PROPERTY_BLACKLIST
-_product_var_list += PRODUCT_VENDOR_PROPERTY_BLACKLIST
-_product_var_list += PRODUCT_SYSTEM_SERVER_APPS
-_product_var_list += PRODUCT_SYSTEM_SERVER_JARS
+_product_list_vars += PRODUCT_SYSTEM_PROPERTY_BLACKLIST
+_product_list_vars += PRODUCT_VENDOR_PROPERTY_BLACKLIST
+_product_list_vars += PRODUCT_SYSTEM_SERVER_APPS
+_product_list_vars += PRODUCT_SYSTEM_SERVER_JARS
 
 # All of the apps that we force preopt, this overrides WITH_DEXPREOPT.
-_product_var_list += PRODUCT_ALWAYS_PREOPT_EXTRACTED_APK
-_product_var_list += PRODUCT_DEXPREOPT_SPEED_APPS
-_product_var_list += PRODUCT_LOADED_BY_PRIVILEGED_MODULES
-_product_var_list += PRODUCT_VBOOT_SIGNING_KEY
-_product_var_list += PRODUCT_VBOOT_SIGNING_SUBKEY
-_product_var_list += PRODUCT_VERITY_SIGNING_KEY
-_product_var_list += PRODUCT_SYSTEM_VERITY_PARTITION
-_product_var_list += PRODUCT_VENDOR_VERITY_PARTITION
-_product_var_list += PRODUCT_PRODUCT_VERITY_PARTITION
-_product_var_list += PRODUCT_PRODUCT_SERVICES_VERITY_PARTITION
-_product_var_list += PRODUCT_ODM_VERITY_PARTITION
-_product_var_list += PRODUCT_SYSTEM_SERVER_DEBUG_INFO
-_product_var_list += PRODUCT_OTHER_JAVA_DEBUG_INFO
+_product_list_vars += PRODUCT_ALWAYS_PREOPT_EXTRACTED_APK
+_product_list_vars += PRODUCT_DEXPREOPT_SPEED_APPS
+_product_list_vars += PRODUCT_LOADED_BY_PRIVILEGED_MODULES
+_product_single_value_vars += PRODUCT_VBOOT_SIGNING_KEY
+_product_single_value_vars += PRODUCT_VBOOT_SIGNING_SUBKEY
+_product_single_value_vars += PRODUCT_VERITY_SIGNING_KEY
+_product_single_value_vars += PRODUCT_SYSTEM_VERITY_PARTITION
+_product_single_value_vars += PRODUCT_VENDOR_VERITY_PARTITION
+_product_single_value_vars += PRODUCT_PRODUCT_VERITY_PARTITION
+_product_single_value_vars += PRODUCT_PRODUCT_SERVICES_VERITY_PARTITION
+_product_single_value_vars += PRODUCT_ODM_VERITY_PARTITION
+_product_single_value_vars += PRODUCT_SYSTEM_SERVER_DEBUG_INFO
+_product_single_value_vars += PRODUCT_OTHER_JAVA_DEBUG_INFO
 
 # Per-module dex-preopt configs.
-_product_var_list += PRODUCT_DEX_PREOPT_MODULE_CONFIGS
-_product_var_list += PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
-_product_var_list += PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
-_product_var_list += PRODUCT_DEX_PREOPT_BOOT_FLAGS
-_product_var_list += PRODUCT_DEX_PREOPT_PROFILE_DIR
-_product_var_list += PRODUCT_DEX_PREOPT_GENERATE_DM_FILES
-_product_var_list += PRODUCT_DEX_PREOPT_NEVER_ALLOW_STRIPPING
+_product_list_vars += PRODUCT_DEX_PREOPT_MODULE_CONFIGS
+_product_list_vars += PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
+_product_list_vars += PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
+_product_list_vars += PRODUCT_DEX_PREOPT_BOOT_FLAGS
+_product_list_vars += PRODUCT_DEX_PREOPT_PROFILE_DIR
+_product_list_vars += PRODUCT_DEX_PREOPT_GENERATE_DM_FILES
+_product_list_vars += PRODUCT_DEX_PREOPT_NEVER_ALLOW_STRIPPING
+_product_list_vars += PRODUCT_DEX_PREOPT_RESOLVE_STARTUP_STRINGS
 
 # Boot image options.
-_product_var_list += \
+_product_single_value_vars += \
     PRODUCT_USE_PROFILE_FOR_BOOT_IMAGE \
     PRODUCT_DEX_PREOPT_BOOT_IMAGE_PROFILE_LOCATION \
-    PRODUCT_USES_ART \
+    PRODUCT_USES_DEFAULT_ART_CONFIG \
 
-_product_var_list += PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
+_product_list_vars += PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
 # Per-module sanitizer configs
-_product_var_list += PRODUCT_SANITIZER_MODULE_CONFIGS
-_product_var_list += PRODUCT_SYSTEM_BASE_FS_PATH
-_product_var_list += PRODUCT_VENDOR_BASE_FS_PATH
-_product_var_list += PRODUCT_PRODUCT_BASE_FS_PATH
-_product_var_list += PRODUCT_PRODUCT_SERVICES_BASE_FS_PATH
-_product_var_list += PRODUCT_ODM_BASE_FS_PATH
-_product_var_list += PRODUCT_SHIPPING_API_LEVEL
-_product_var_list += VENDOR_PRODUCT_RESTRICT_VENDOR_FILES
-_product_var_list += VENDOR_EXCEPTION_MODULES
-_product_var_list += VENDOR_EXCEPTION_PATHS
+_product_list_vars += PRODUCT_SANITIZER_MODULE_CONFIGS
+_product_single_value_vars += PRODUCT_SYSTEM_BASE_FS_PATH
+_product_single_value_vars += PRODUCT_VENDOR_BASE_FS_PATH
+_product_single_value_vars += PRODUCT_PRODUCT_BASE_FS_PATH
+_product_single_value_vars += PRODUCT_PRODUCT_SERVICES_BASE_FS_PATH
+_product_single_value_vars += PRODUCT_ODM_BASE_FS_PATH
 
+# The first API level this product shipped with
+_product_single_value_vars += PRODUCT_SHIPPING_API_LEVEL
+
+_product_list_vars += VENDOR_PRODUCT_RESTRICT_VENDOR_FILES
+_product_list_vars += VENDOR_EXCEPTION_MODULES
+_product_list_vars += VENDOR_EXCEPTION_PATHS
 # Whether the product wants to ship libartd. For rules and meaning, see art/Android.mk.
-_product_var_list += PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD
+_product_single_value_vars += PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD
 
 # Make this art variable visible to soong_config.mk.
-_product_var_list += PRODUCT_ART_USE_READ_BARRIER
+_product_single_value_vars += PRODUCT_ART_USE_READ_BARRIER
 
 # Whether the product is an Android Things variant.
-_product_var_list += PRODUCT_IOT
+_product_single_value_vars += PRODUCT_IOT
 
 # Add reserved headroom to a system image.
-_product_var_list += PRODUCT_SYSTEM_HEADROOM
+_product_single_value_vars += PRODUCT_SYSTEM_HEADROOM
 
 # Whether to save disk space by minimizing java debug info
-_product_var_list += PRODUCT_MINIMIZE_JAVA_DEBUG_INFO
+_product_single_value_vars += PRODUCT_MINIMIZE_JAVA_DEBUG_INFO
 
 # Whether any paths are excluded from sanitization when SANITIZE_TARGET=integer_overflow
-_product_var_list += PRODUCT_INTEGER_OVERFLOW_EXCLUDE_PATHS
+_product_list_vars += PRODUCT_INTEGER_OVERFLOW_EXCLUDE_PATHS
 
-_product_var_list += PRODUCT_ADB_KEYS
+_product_single_value_vars += PRODUCT_ADB_KEYS
 
 # Whether any paths should have CFI enabled for components
-_product_var_list += PRODUCT_CFI_INCLUDE_PATHS
+_product_list_vars += PRODUCT_CFI_INCLUDE_PATHS
 
 # Whether any paths are excluded from sanitization when SANITIZE_TARGET=cfi
-_product_var_list += PRODUCT_CFI_EXCLUDE_PATHS
+_product_list_vars += PRODUCT_CFI_EXCLUDE_PATHS
 
 # Whether the Scudo hardened allocator is disabled platform-wide
-_product_var_list += PRODUCT_DISABLE_SCUDO
+_product_single_value_vars += PRODUCT_DISABLE_SCUDO
 
 # A flag to override PRODUCT_COMPATIBLE_PROPERTY
-_product_var_list += PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE
+_product_single_value_vars += PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE
 
 # Whether the whitelist of actionable compatible properties should be disabled or not
-_product_var_list += PRODUCT_ACTIONABLE_COMPATIBLE_PROPERTY_DISABLE
-_product_var_list += PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
-_product_var_list += PRODUCT_ENFORCE_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT
-_product_var_list += PRODUCT_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT_WHITELIST
-_product_var_list += PRODUCT_ARTIFACT_PATH_REQUIREMENT_HINT
-_product_var_list += PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST
+_product_single_value_vars += PRODUCT_ACTIONABLE_COMPATIBLE_PROPERTY_DISABLE
+
+_product_single_value_vars += PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
+_product_single_value_vars += PRODUCT_ENFORCE_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT
+_product_list_vars += PRODUCT_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT_WHITELIST
+_product_list_vars += PRODUCT_ARTIFACT_PATH_REQUIREMENT_HINT
+_product_list_vars += PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST
 
 # List of modules that should be forcefully unmarked from being LOCAL_PRODUCT_MODULE, and hence
 # installed on /system directory by default.
-_product_var_list += PRODUCT_FORCE_PRODUCT_MODULES_TO_SYSTEM_PARTITION
+_product_list_vars += PRODUCT_FORCE_PRODUCT_MODULES_TO_SYSTEM_PARTITION
 
 # When this is true, dynamic partitions is retrofitted on a device that has
 # already been launched without dynamic partitions. Otherwise, the device
 # is launched with dynamic partitions.
 # This flag implies PRODUCT_USE_DYNAMIC_PARTITIONS.
-_product_var_list += PRODUCT_RETROFIT_DYNAMIC_PARTITIONS
+_product_single_value_vars += PRODUCT_RETROFIT_DYNAMIC_PARTITIONS
 
 # Other dynamic partition feature flags.PRODUCT_USE_DYNAMIC_PARTITION_SIZE and
 # PRODUCT_BUILD_SUPER_PARTITION default to the value of PRODUCT_USE_DYNAMIC_PARTITIONS.
-_product_var_list += \
+_product_single_value_vars += \
     PRODUCT_USE_DYNAMIC_PARTITIONS \
     PRODUCT_USE_DYNAMIC_PARTITION_SIZE \
     PRODUCT_BUILD_SUPER_PARTITION \
@@ -321,33 +332,40 @@
 # during OTA). Otherwise, kernel configuration requirements are enforced in VTS.
 # Devices that checks the running kernel (instead of the kernel in OTA package) should not
 # set this variable to prevent OTA failures.
-_product_var_list += PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS
+_product_list_vars += PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS
 
 # If set to true, this product builds a generic OTA package, which installs generic system images
 # onto matching devices. The product may only build a subset of system images (e.g. only
 # system.img), so devices need to install the package in a system-only OTA manner.
-_product_var_list += PRODUCT_BUILD_GENERIC_OTA_PACKAGE
+_product_single_value_vars += PRODUCT_BUILD_GENERIC_OTA_PACKAGE
 
 # Whether any paths are excluded from being set XOM when ENABLE_XOM=true
-_product_var_list += PRODUCT_XOM_EXCLUDE_PATHS
-_product_var_list += PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
-_product_var_list += PRODUCT_PACKAGE_NAME_OVERRIDES
-_product_var_list += PRODUCT_CERTIFICATE_OVERRIDES
-_product_var_list += PRODUCT_BUILD_SYSTEM_IMAGE
-_product_var_list += PRODUCT_BUILD_SYSTEM_OTHER_IMAGE
-_product_var_list += PRODUCT_BUILD_VENDOR_IMAGE
-_product_var_list += PRODUCT_BUILD_PRODUCT_IMAGE
-_product_var_list += PRODUCT_BUILD_PRODUCT_SERVICES_IMAGE
-_product_var_list += PRODUCT_BUILD_ODM_IMAGE
-_product_var_list += PRODUCT_BUILD_CACHE_IMAGE
-_product_var_list += PRODUCT_BUILD_RAMDISK_IMAGE
-_product_var_list += PRODUCT_BUILD_USERDATA_IMAGE
-_product_var_list += PRODUCT_UPDATABLE_BOOT_MODULES
-_product_var_list += PRODUCT_UPDATABLE_BOOT_LOCATIONS
+_product_list_vars += PRODUCT_XOM_EXCLUDE_PATHS
+_product_list_vars += PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
+_product_list_vars += PRODUCT_PACKAGE_NAME_OVERRIDES
+_product_list_vars += PRODUCT_CERTIFICATE_OVERRIDES
+
+# Controls for whether different partitions are built for the current product.
+_product_single_value_vars += PRODUCT_BUILD_SYSTEM_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_SYSTEM_OTHER_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_VENDOR_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_PRODUCT_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_PRODUCT_SERVICES_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_ODM_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_CACHE_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_RAMDISK_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_USERDATA_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_RECOVERY_IMAGE
+_product_single_value_vars += PRODUCT_BUILD_BOOT_IMAGE
+
+_product_list_vars += PRODUCT_UPDATABLE_BOOT_MODULES
+_product_list_vars += PRODUCT_UPDATABLE_BOOT_LOCATIONS
 
 # Whether the product would like to check prebuilt ELF files.
-_product_var_list += PRODUCT_CHECK_ELF_FILES
-.KATI_READONLY := _product_var_list
+_product_single_value_vars += PRODUCT_CHECK_ELF_FILES
+
+.KATI_READONLY := _product_single_value_vars _product_list_vars
+_product_var_list :=$= $(_product_single_value_vars) $(_product_list_vars)
 
 define dump-product
 $(warning ==== $(1) ====)\
@@ -421,7 +439,7 @@
 #
 #TODO: check to make sure that products have all the necessary vars defined
 define import-products
-$(call import-nodes,PRODUCTS,$(1),$(_product_var_list))
+$(call import-nodes,PRODUCTS,$(1),$(_product_var_list),$(_product_single_value_vars))
 endef
 
 
diff --git a/core/product_config.mk b/core/product_config.mk
index a088f06..8c739a4 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -390,7 +390,6 @@
 
 # Macro to use below. $(1) is the name of the partition
 define product-build-image-config
-PRODUCT_BUILD_$(1)_IMAGE := $$(firstword $$(PRODUCT_BUILD_$(1)_IMAGE))
 ifneq ($$(filter-out true false,$$(PRODUCT_BUILD_$(1)_IMAGE)),)
     $$(error Invalid PRODUCT_BUILD_$(1)_IMAGE: $$(PRODUCT_BUILD_$(1)_IMAGE) -- true false and empty are supported)
 endif
@@ -406,7 +405,9 @@
     ODM \
     CACHE \
     RAMDISK \
-    USERDATA, \
+    USERDATA \
+    BOOT \
+    RECOVERY, \
   $(eval $(call product-build-image-config,$(image))))
 
 product-build-image-config :=
diff --git a/core/soong_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index 8153d78..d873cc4 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -129,7 +129,15 @@
 my_2nd_arch_prefix :=
 
 PACKAGES := $(PACKAGES) $(LOCAL_MODULE)
-ifdef LOCAL_CERTIFICATE
+ifeq ($(LOCAL_CERTIFICATE),PRESIGNED)
+  # The magic string "PRESIGNED" means this package is already checked
+  # signed with its release key.
+  #
+  # By setting .CERTIFICATE but not .PRIVATE_KEY, this package will be
+  # mentioned in apkcerts.txt (with certificate set to "PRESIGNED")
+  # but the dexpreopt process will not try to re-sign the app.
+  PACKAGES.$(LOCAL_MODULE).CERTIFICATE := PRESIGNED
+else ifneq ($(LOCAL_CERTIFICATE),)
   PACKAGES.$(LOCAL_MODULE).CERTIFICATE := $(LOCAL_CERTIFICATE)
   PACKAGES.$(LOCAL_MODULE).PRIVATE_KEY := $(patsubst %.x509.pem,%.pk8,$(LOCAL_CERTIFICATE))
 endif
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 46e026a..48db6b1 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -58,6 +58,16 @@
 $(call add_json_str,  DeviceSecondaryCpuVariant,         $(TARGET_2ND_CPU_VARIANT))
 $(call add_json_list, DeviceSecondaryAbi,                $(TARGET_2ND_CPU_ABI) $(TARGET_2ND_CPU_ABI2))
 
+$(call add_json_str,  NativeBridgeArch,                  $(TARGET_NATIVE_BRIDGE_ARCH))
+$(call add_json_str,  NativeBridgeArchVariant,           $(TARGET_NATIVE_BRIDGE_ARCH_VARIANT))
+$(call add_json_str,  NativeBridgeCpuVariant,            $(TARGET_NATIVE_BRIDGE_CPU_VARIANT))
+$(call add_json_list, NativeBridgeAbi,                   $(TARGET_NATIVE_BRIDGE_ABI))
+
+$(call add_json_str,  NativeBridgeSecondaryArch,         $(TARGET_NATIVE_BRIDGE_2ND_ARCH))
+$(call add_json_str,  NativeBridgeSecondaryArchVariant,  $(TARGET_NATIVE_BRIDGE_2ND_ARCH_VARIANT))
+$(call add_json_str,  NativeBridgeSecondaryCpuVariant,   $(TARGET_NATIVE_BRIDGE_2ND_CPU_VARIANT))
+$(call add_json_list, NativeBridgeSecondaryAbi,          $(TARGET_NATIVE_BRIDGE_2ND_ABI))
+
 $(call add_json_str,  HostArch,                          $(HOST_ARCH))
 $(call add_json_str,  HostSecondaryArch,                 $(HOST_2ND_ARCH))
 $(call add_json_bool, HostStaticBinaries,                $(BUILD_HOST_static))
@@ -149,6 +159,7 @@
 $(call add_json_list, BoardOdmSepolicyDirs,              $(BOARD_ODM_SEPOLICY_DIRS))
 $(call add_json_list, BoardPlatPublicSepolicyDirs,       $(BOARD_PLAT_PUBLIC_SEPOLICY_DIR))
 $(call add_json_list, BoardPlatPrivateSepolicyDirs,      $(BOARD_PLAT_PRIVATE_SEPOLICY_DIR))
+$(call add_json_list, BoardSepolicyM4Defs,               $(BOARD_SEPOLICY_M4DEFS))
 
 $(call add_json_bool, FlattenApex,                       $(filter true,$(TARGET_FLATTEN_APEX)))
 
@@ -165,6 +176,10 @@
 $(call add_json_list, ProductHiddenAPIStubsSystem,       $(PRODUCT_HIDDENAPI_STUBS_SYSTEM))
 $(call add_json_list, ProductHiddenAPIStubsTest,         $(PRODUCT_HIDDENAPI_STUBS_TEST))
 
+$(call add_json_list, ProductPublicSepolicyDirs,         $(PRODUCT_PUBLIC_SEPOLICY_DIRS))
+$(call add_json_list, ProductPrivateSepolicyDirs,        $(PRODUCT_PRIVATE_SEPOLICY_DIRS))
+$(call add_json_bool, ProductCompatibleProperty,         $(PRODUCT_COMPATIBLE_PROPERTY))
+
 $(call add_json_list, TargetFSConfigGen,                 $(TARGET_FS_CONFIG_GEN))
 
 $(call add_json_map, VendorVars)
diff --git a/core/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index 9692a99..6a76fc4 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -51,6 +51,13 @@
     $(intermediates.COMMON)/jacoco-report-classes.jar)
 endif
 
+ifdef LOCAL_SOONG_PROGUARD_DICT
+  $(eval $(call copy-one-file,$(LOCAL_SOONG_PROGUARD_DICT),\
+    $(intermediates.COMMON)/proguard_dictionary))
+  $(call add-dependency,$(LOCAL_BUILT_MODULE),\
+    $(intermediates.COMMON)/proguard_dictionary)
+endif
+
 ifdef LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE
   my_res_package := $(intermediates.COMMON)/package-res.apk
 
diff --git a/envsetup.sh b/envsetup.sh
index 9e381a2..5292d38 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -22,7 +22,7 @@
 - jgrep:      Greps on all local Java files.
 - resgrep:    Greps on all local res/*.xml files.
 - mangrep:    Greps on all local AndroidManifest.xml files.
-- mgrep:      Greps on all local Makefiles files.
+- mgrep:      Greps on all local Makefiles and *.bp files.
 - sepgrep:    Greps on all local sepolicy files.
 - sgrep:      Greps on all local source files.
 - godir:      Go to the directory containing a file.
diff --git a/target/board/BoardConfigEmuCommon.mk b/target/board/BoardConfigEmuCommon.mk
index c871d7e..3ab5f12 100644
--- a/target/board/BoardConfigEmuCommon.mk
+++ b/target/board/BoardConfigEmuCommon.mk
@@ -23,15 +23,35 @@
 # Emulator doesn't support sparse image format.
 TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
 
-# ~140 MB vendor image. Please adjust system image / vendor image sizes
-# when finalizing them. The partition size needs to be a multiple of image
-# block size: 4096.
-BOARD_VENDORIMAGE_PARTITION_SIZE := 140963840
+ifeq ($(PRODUCT_USE_DYNAMIC_PARTITIONS),true)
+  # emulator is Non-A/B device
+  AB_OTA_UPDATER := false
+
+  # emulator needs super.img
+  BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true
+
+  BOARD_EXT4_SHARE_DUP_BLOCKS := true
+
+  # 3G + header
+  BOARD_SUPER_PARTITION_SIZE := 3229614080
+  BOARD_SUPER_PARTITION_GROUPS := emulator_dynamic_partitions
+  BOARD_EMULATOR_DYNAMIC_PARTITIONS_PARTITION_LIST := \
+      system \
+      vendor
+
+  # 3G
+  BOARD_EMULATOR_DYNAMIC_PARTITIONS_SIZE := 3221225472
+else ifeq ($(PRODUCT_USE_DYNAMIC_PARTITION_SIZE),true)
+  # Enable dynamic system image size and reserved 64MB in it.
+  BOARD_SYSTEMIMAGE_PARTITION_RESERVED_SIZE := 67108864
+  BOARD_VENDORIMAGE_PARTITION_RESERVED_SIZE := 67108864
+else
+  BOARD_SYSTEMIMAGE_PARTITION_SIZE := 3221225472
+  BOARD_VENDORIMAGE_PARTITION_SIZE := 146800640
+endif
+
 BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_FLASH_BLOCK_SIZE := 512
 DEVICE_MATRIX_FILE   := device/generic/goldfish/compatibility_matrix.xml
 
 BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/common
-
-# TODO(b/125540538): Remove when emulator uses dynamic partitions
-BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
diff --git a/target/board/BoardConfigGsiCommon.mk b/target/board/BoardConfigGsiCommon.mk
index d4025c3..96fd07b 100644
--- a/target/board/BoardConfigGsiCommon.mk
+++ b/target/board/BoardConfigGsiCommon.mk
@@ -28,16 +28,9 @@
 BOARD_USES_METADATA_PARTITION := true
 
 # Android Verified Boot (AVB):
-#   Set AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED (--flags 2) in
-#   vbmeta.img to disable AVB verification. Also set the rollback index
-#   to zero, to prevent the device bootloader from updating the last seen
-#   rollback index in the tamper-evident storage.
-#
-# To disable AVB for GSI, use the vbmeta.img and the GSI together.
-# To enable AVB for GSI, include the GSI public key into the device-specific
-# vbmeta.img.
+#   Set the rollback index to zero, to prevent the device bootloader from
+#   updating the last seen rollback index in the tamper-evident storage.
 BOARD_AVB_ROLLBACK_INDEX := 0
-BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS += --flags 2
 
 # Enable chain partition for system.
 BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
diff --git a/target/board/generic/BoardConfig.mk b/target/board/generic/BoardConfig.mk
index b61a7fd..8624ed7 100644
--- a/target/board/generic/BoardConfig.mk
+++ b/target/board/generic/BoardConfig.mk
@@ -29,8 +29,8 @@
 TARGET_CPU_ABI := armeabi-v7a
 TARGET_CPU_ABI2 := armeabi
 
-include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
 
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
 
diff --git a/target/board/generic_arm64/BoardConfig.mk b/target/board/generic_arm64/BoardConfig.mk
index 7d92b7d..ecc547f 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -52,8 +52,8 @@
 TARGET_2ND_CPU_VARIANT := generic
 endif
 
-include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
 
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
 
diff --git a/target/board/generic_x86/BoardConfig.mk b/target/board/generic_x86/BoardConfig.mk
index 650073e..83d7ecc 100644
--- a/target/board/generic_x86/BoardConfig.mk
+++ b/target/board/generic_x86/BoardConfig.mk
@@ -20,8 +20,8 @@
 
 TARGET_PRELINK_MODULE := false
 
-include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
 
 # Resize to 4G to accomodate ASAN and CTS
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 4294967296
diff --git a/target/board/generic_x86_64/BoardConfig.mk b/target/board/generic_x86_64/BoardConfig.mk
index 1426630..07bbc07 100755
--- a/target/board/generic_x86_64/BoardConfig.mk
+++ b/target/board/generic_x86_64/BoardConfig.mk
@@ -23,9 +23,8 @@
 TARGET_2ND_ARCH_VARIANT := x86_64
 
 TARGET_PRELINK_MODULE := false
-
-include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
 
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
 
diff --git a/target/board/generic_x86_arm/BoardConfig.mk b/target/board/generic_x86_arm/BoardConfig.mk
index ab2089d..6fae411 100644
--- a/target/board/generic_x86_arm/BoardConfig.mk
+++ b/target/board/generic_x86_arm/BoardConfig.mk
@@ -30,8 +30,8 @@
 BUILD_BROKEN_DUP_RULES := true
 
 
-include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
 
 # Resize to 4G to accomodate ASAN and CTS
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 4294967296
diff --git a/target/product/aosp_arm.mk b/target/product/aosp_arm.mk
index 400fa6a..0fdd313 100644
--- a/target/product/aosp_arm.mk
+++ b/target/product/aosp_arm.mk
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
+
 # The system image of aosp_arm-userdebug is a GSI for the devices with:
 # - ARM 32 bits user space
 # - 64 bits binder interface
diff --git a/target/product/aosp_arm64.mk b/target/product/aosp_arm64.mk
index aa6ec4d..8ef2023 100644
--- a/target/product/aosp_arm64.mk
+++ b/target/product/aosp_arm64.mk
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
+
 # The system image of aosp_arm64-userdebug is a GSI for the devices with:
 # - ARM 64 bits user space
 # - 64 bits binder interface
diff --git a/target/product/aosp_x86.mk b/target/product/aosp_x86.mk
index b16b5ed..1c71948 100644
--- a/target/product/aosp_x86.mk
+++ b/target/product/aosp_x86.mk
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
+
 # The system image of aosp_x86-userdebug is a GSI for the devices with:
 # - x86 32 bits user space
 # - 64 bits binder interface
diff --git a/target/product/aosp_x86_64.mk b/target/product/aosp_x86_64.mk
index f7e2056..9dfa2f4 100644
--- a/target/product/aosp_x86_64.mk
+++ b/target/product/aosp_x86_64.mk
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
+
 # The system image of aosp_x86_64-userdebug is a GSI for the devices with:
 # - x86 64 bits user space
 # - 64 bits binder interface
diff --git a/target/product/aosp_x86_arm.mk b/target/product/aosp_x86_arm.mk
index b921c97..70aa64e 100644
--- a/target/product/aosp_x86_arm.mk
+++ b/target/product/aosp_x86_arm.mk
@@ -14,6 +14,7 @@
 # limitations under the License.
 #
 
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
 
 # aosp_x86 with arm libraries needed by binary translation.
 
@@ -31,13 +32,6 @@
 # Enable dynamic partition size
 PRODUCT_USE_DYNAMIC_PARTITION_SIZE := true
 
-# Enable A/B update
-AB_OTA_UPDATER := true
-AB_OTA_PARTITIONS := system
-PRODUCT_PACKAGES += \
-    update_engine \
-    update_verifier
-
 # Needed by Pi newly launched device to pass VtsTrebleSysProp on GSI
 PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE := true
 
diff --git a/target/product/base_product.mk b/target/product/base_product.mk
index 1ed9e83..82557bf 100644
--- a/target/product/base_product.mk
+++ b/target/product/base_product.mk
@@ -19,3 +19,4 @@
     healthd \
     ModuleMetadata \
     product_compatibility_matrix.xml \
+    product_manifest.xml \
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index e9e8b49..23289f5 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -268,7 +268,7 @@
 
 # VINTF data for system image
 PRODUCT_PACKAGES += \
-    framework_manifest.xml \
+    system_manifest.xml \
     system_compatibility_matrix.xml \
 
 # Host tools to install
diff --git a/target/product/mainline_system.mk b/target/product/mainline_system.mk
index 66207df..87393d4 100644
--- a/target/product/mainline_system.mk
+++ b/target/product/mainline_system.mk
@@ -19,7 +19,7 @@
 $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/languages_default.mk)
 # Enable updating of APEXes
-$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
+#$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
 # Add adb keys to debuggable AOSP builds (if they exist)
 $(call inherit-product-if-exists, vendor/google/security/adb/vendor_key.mk)
 
diff --git a/target/product/runtime_libart.mk b/target/product/runtime_libart.mk
index a88ba3c..5db32f2 100644
--- a/target/product/runtime_libart.mk
+++ b/target/product/runtime_libart.mk
@@ -96,4 +96,4 @@
 PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
     ro.iorapd.enable=false
 
-PRODUCT_USES_ART := true
+PRODUCT_USES_DEFAULT_ART_CONFIG := true
diff --git a/target/product/security/Android.bp b/target/product/security/Android.bp
new file mode 100644
index 0000000..080706b
--- /dev/null
+++ b/target/product/security/Android.bp
@@ -0,0 +1,5 @@
+// AOSP test certificate
+android_app_certificate {
+    name: "aosp-testkey",
+    certificate: "testkey",
+}
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 10aecf9..4156c8b 100755
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -113,22 +113,33 @@
 
   Returns:
     (which, care_map_ranges): care_map_ranges is the raw string of the care_map
-    RangeSet.
+    RangeSet; or None.
   """
   assert which in common.PARTITIONS_WITH_CARE_MAP
 
-  simg = sparse_img.SparseImage(imgname)
-  care_map_ranges = simg.care_map
-  size_key = which + "_image_size"
-  image_size = OPTIONS.info_dict.get(size_key)
-  if image_size:
-    # excludes the verity metadata blocks of the given image. When AVB is enabled,
-    # this size is the max image size returned by the AVB tool
-    image_blocks = int(image_size) / 4096 - 1
-    assert image_blocks > 0, "blocks for {} must be positive".format(which)
-    care_map_ranges = care_map_ranges.intersect(
+  # which + "_image_size" contains the size that the actual filesystem image
+  # resides in, which is all that needs to be verified. The additional blocks in
+  # the image file contain verity metadata, by reading which would trigger
+  # invalid reads.
+  image_size = OPTIONS.info_dict.get(which + "_image_size")
+  if not image_size:
+    return None
+
+  image_blocks = int(image_size) / 4096 - 1
+  assert image_blocks > 0, "blocks for {} must be positive".format(which)
+
+  # For sparse images, we will only check the blocks that are listed in the care
+  # map, i.e. the ones with meaningful data.
+  if "extfs_sparse_flag" in OPTIONS.info_dict:
+    simg = sparse_img.SparseImage(imgname)
+    care_map_ranges = simg.care_map.intersect(
         rangelib.RangeSet("0-{}".format(image_blocks)))
 
+  # Otherwise for non-sparse images, we read all the blocks in the filesystem
+  # image.
+  else:
+    care_map_ranges = rangelib.RangeSet("0-{}".format(image_blocks))
+
   return [which, care_map_ranges.to_string_raw()]
 
 
@@ -581,7 +592,11 @@
         OPTIONS.info_dict.get(avb_hashtree_enable) == "true"):
       image_path = image_paths[partition]
       assert os.path.exists(image_path)
-      care_map_list += GetCareMap(partition, image_path)
+
+      care_map = GetCareMap(partition, image_path)
+      if not care_map:
+        continue
+      care_map_list += care_map
 
       # adds fingerprint field to the care_map
       build_props = OPTIONS.info_dict.get(partition + ".build.prop", {})
@@ -715,6 +730,7 @@
   OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, repacking=True)
 
   has_recovery = OPTIONS.info_dict.get("no_recovery") != "true"
+  has_boot = OPTIONS.info_dict.get("no_boot") != "true"
 
   # {vendor,odm,product,product_services}.img are unlike system.img or
   # system_other.img. Because it could be built from source, or dropped into
@@ -762,17 +778,19 @@
   def banner(s):
     logger.info("\n\n++++ " + s + " ++++\n\n")
 
-  banner("boot")
-  # common.GetBootableImage() returns the image directly if present.
-  boot_image = common.GetBootableImage(
-      "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
-  # boot.img may be unavailable in some targets (e.g. aosp_arm64).
-  if boot_image:
-    partitions['boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
-    if not os.path.exists(partitions['boot']):
-      boot_image.WriteToDir(OPTIONS.input_tmp)
-      if output_zip:
-        boot_image.AddToZip(output_zip)
+  boot_image = None
+  if has_boot:
+    banner("boot")
+    # common.GetBootableImage() returns the image directly if present.
+    boot_image = common.GetBootableImage(
+        "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
+    # boot.img may be unavailable in some targets (e.g. aosp_arm64).
+    if boot_image:
+      partitions['boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
+      if not os.path.exists(partitions['boot']):
+        boot_image.WriteToDir(OPTIONS.input_tmp)
+        if output_zip:
+          boot_image.AddToZip(output_zip)
 
   recovery_image = None
   if has_recovery:
diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
index 941ef65..6165d96 100755
--- a/tools/releasetools/img_from_target_files.py
+++ b/tools/releasetools/img_from_target_files.py
@@ -15,11 +15,19 @@
 # limitations under the License.
 
 """
-Given a target-files zipfile, produces an image zipfile suitable for
-use with 'fastboot update'.
+Given target-files, produces an image zipfile suitable for use
+with 'fastboot update'.
 
 Usage:  img_from_target_files [flags] input_target_files output_image_zip
 
+input_target_files: one of the following:
+  - directory containing extracted target files. It will load info from
+    OTA/android-info.txt, META/misc_info.txt and build the image zipfile using
+    images from IMAGES/.
+  - target files package. Same as above, but extracts the archive before
+    building the image zipfile.
+
+Flags:
   -z  (--bootable_zip)
       Include only the bootable images (eg 'boot' and 'recovery') in
       the output.
@@ -35,6 +43,7 @@
 import zipfile
 
 import common
+from build_super_image import BuildSuperImage
 
 if sys.hexversion < 0x02070000:
   print("Python 2.7 or newer is required.", file=sys.stderr)
@@ -45,13 +54,102 @@
 OPTIONS = common.OPTIONS
 
 
-def CopyInfo(output_zip):
+def LoadOptions(input_file):
+  """
+  Load information from input_file to OPTIONS.
+
+  Args:
+    input_file: A Zipfile instance of input zip file, or path to the directory
+      of extracted zip.
+  """
+  info = OPTIONS.info_dict = common.LoadInfoDict(input_file)
+
+  OPTIONS.put_super = info.get("super_image_in_update_package") == "true"
+  OPTIONS.dynamic_partition_list = info.get("dynamic_partition_list",
+                                            "").strip().split()
+  OPTIONS.super_device_list = info.get("super_block_devices",
+                                       "").strip().split()
+  OPTIONS.retrofit_dap = info.get("dynamic_partition_retrofit") == "true"
+  OPTIONS.build_super = info.get("build_super_partition") == "true"
+  OPTIONS.sparse_userimages = bool(info.get("extfs_sparse_flag"))
+
+
+def CopyInfo(input_tmp, output_zip):
   """Copy the android-info.txt file from the input to the output."""
   common.ZipWrite(
-      output_zip, os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"),
+      output_zip, os.path.join(input_tmp, "OTA", "android-info.txt"),
       "android-info.txt")
 
 
+def CopyUserImages(input_tmp, output_zip):
+  """
+  Copy user images from the unzipped input and write to output_zip.
+
+  Args:
+    input_tmp: path to the unzipped input.
+    output_zip: a ZipFile instance to write images to.
+  """
+  dynamic_images = [p + ".img" for p in OPTIONS.dynamic_partition_list]
+
+  # Filter out system_other for launch DAP devices because it is in super image.
+  if not OPTIONS.retrofit_dap and "system" in OPTIONS.dynamic_partition_list:
+    dynamic_images.append("system_other.img")
+
+  images_path = os.path.join(input_tmp, "IMAGES")
+  # A target-files zip must contain the images since Lollipop.
+  assert os.path.exists(images_path)
+  for image in sorted(os.listdir(images_path)):
+    if OPTIONS.bootable_only and image not in ("boot.img", "recovery.img"):
+      continue
+    if not image.endswith(".img"):
+      continue
+    if image == "recovery-two-step.img":
+      continue
+    if OPTIONS.put_super:
+      if image == "super_empty.img":
+        continue
+      if image in dynamic_images:
+        continue
+    logger.info("writing %s to archive...", os.path.join("IMAGES", image))
+    common.ZipWrite(output_zip, os.path.join(images_path, image), image)
+
+
+def WriteSuperImages(input_tmp, output_zip):
+  """
+  Write super images from the unzipped input and write to output_zip. This is
+  only done if super_image_in_update_package is set to "true".
+
+  - For retrofit dynamic partition devices, copy split super images from target
+    files package.
+  - For devices launched with dynamic partitions, build super image from target
+    files package.
+
+  Args:
+    input_tmp: path to the unzipped input.
+    output_zip: a ZipFile instance to write images to.
+  """
+  if not OPTIONS.build_super or not OPTIONS.put_super:
+    return
+
+  if OPTIONS.retrofit_dap:
+    # retrofit devices already have split super images under OTA/
+    images_path = os.path.join(input_tmp, "OTA")
+    for device in OPTIONS.super_device_list:
+      image = "super_%s.img" % device
+      image_path = os.path.join(images_path, image)
+      assert os.path.exists(image_path)
+      logger.info("writing %s to archive...", os.path.join("OTA", image))
+      common.ZipWrite(output_zip, image_path, image)
+  else:
+    # super image for non-retrofit devices aren't in target files package,
+    # so build it.
+    super_file = common.MakeTempFile("super_", ".img")
+    logger.info("building super image %s...", super_file)
+    BuildSuperImage(input_tmp, super_file)
+    logger.info("writing super.img to archive...")
+    common.ZipWrite(output_zip, super_file, "super.img")
+
+
 def main(argv):
   # This allows modifying the value from inner function.
   bootable_only_array = [False]
@@ -68,7 +166,7 @@
                              extra_long_opts=["bootable_zip"],
                              extra_option_handler=option_handler)
 
-  bootable_only = bootable_only_array[0]
+  OPTIONS.bootable_only = bootable_only_array[0]
 
   if len(args) != 2:
     common.Usage(__doc__)
@@ -76,23 +174,25 @@
 
   common.InitLogging()
 
-  OPTIONS.input_tmp = common.UnzipTemp(args[0], ["IMAGES/*", "OTA/*"])
-  output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
-  CopyInfo(output_zip)
+  target_files = args[0]
+  if os.path.isdir(target_files):
+    logger.info("Building image zip from extracted target files.")
+    OPTIONS.input_tmp = target_files
+  elif zipfile.is_zipfile(target_files):
+    logger.info("Building image zip from target files zip.")
+    OPTIONS.input_tmp = common.UnzipTemp(target_files,
+                                         ["IMAGES/*", "OTA/*", "META/*"])
+  else:
+    raise ValueError("%s is not a valid path." % target_files)
+
+  LoadOptions(OPTIONS.input_tmp)
+  output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED,
+                               allowZip64=not OPTIONS.sparse_userimages)
 
   try:
-    images_path = os.path.join(OPTIONS.input_tmp, "IMAGES")
-    # A target-files zip must contain the images since Lollipop.
-    assert os.path.exists(images_path)
-    for image in sorted(os.listdir(images_path)):
-      if bootable_only and image not in ("boot.img", "recovery.img"):
-        continue
-      if not image.endswith(".img"):
-        continue
-      if image == "recovery-two-step.img":
-        continue
-      common.ZipWrite(output_zip, os.path.join(images_path, image), image)
-
+    CopyInfo(OPTIONS.input_tmp, output_zip)
+    CopyUserImages(OPTIONS.input_tmp, output_zip)
+    WriteSuperImages(OPTIONS.input_tmp, output_zip)
   finally:
     logger.info("cleaning up...")
     common.ZipClose(output_zip)
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index 2e5cbca..20a9c64 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -80,6 +80,7 @@
 import logging
 import os
 import shutil
+import subprocess
 import sys
 import zipfile
 
@@ -159,6 +160,7 @@
 
 default_other_item_list = [
     'META/boot_filesystem_config.txt',
+    'META/file_contexts.bin',
     'META/otakeys.txt',
     'META/releasetools.py',
     'META/vendor_filesystem_config.txt',
@@ -370,6 +372,63 @@
             'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
 
 
+def merge_dynamic_partition_info_dicts(system_dict,
+                                       other_dict,
+                                       include_dynamic_partition_list=True,
+                                       size_prefix='',
+                                       size_suffix='',
+                                       list_prefix='',
+                                       list_suffix=''):
+  """Merges dynamic partition info variables.
+
+  Args:
+    system_dict: The dictionary of dynamic partition info variables from the
+      partial system target files.
+    other_dict: The dictionary of dynamic partition info variables from the
+      partial other target files.
+    include_dynamic_partition_list: If true, merges the dynamic_partition_list
+      variable. Not all use cases need this variable merged.
+    size_prefix: The prefix in partition group size variables that precedes the
+      name of the partition group. For example, partition group 'group_a' with
+      corresponding size variable 'super_group_a_group_size' would have the
+      size_prefix 'super_'.
+    size_suffix: Similar to size_prefix but for the variable's suffix. For
+      example, 'super_group_a_group_size' would have size_suffix '_group_size'.
+    list_prefix: Similar to size_prefix but for the partition group's
+      partition_list variable.
+    list_suffix: Similar to size_suffix but for the partition group's
+      partition_list variable.
+
+  Returns:
+    The merged dynamic partition info dictionary.
+  """
+  merged_dict = {}
+  # Partition groups and group sizes are defined by the other (non-system)
+  # dict because these values may vary for each board that uses a shared system
+  # image.
+  merged_dict['super_partition_groups'] = other_dict['super_partition_groups']
+  if include_dynamic_partition_list:
+    system_dynamic_partition_list = system_dict.get('dynamic_partition_list',
+                                                    '')
+    other_dynamic_partition_list = other_dict.get('dynamic_partition_list', '')
+    merged_dict['dynamic_partition_list'] = (
+        '%s %s' %
+        (system_dynamic_partition_list, other_dynamic_partition_list)).strip()
+  for partition_group in merged_dict['super_partition_groups'].split(' '):
+    # Set the partition group's size using the value from the other dict.
+    key = '%s%s%s' % (size_prefix, partition_group, size_suffix)
+    if key not in other_dict:
+      raise ValueError('Other dict does not contain required key %s.' % key)
+    merged_dict[key] = other_dict[key]
+
+    # Set the partition group's partition list using a concatenation of the
+    # system and other partition lists.
+    key = '%s%s%s' % (list_prefix, partition_group, list_suffix)
+    merged_dict[key] = (
+        '%s %s' % (system_dict.get(key, ''), other_dict.get(key, ''))).strip()
+  return merged_dict
+
+
 def process_misc_info_txt(system_target_files_temp_dir,
                           other_target_files_temp_dir,
                           output_target_files_temp_dir, system_misc_info_keys):
@@ -415,107 +474,77 @@
   # Merge misc info keys used for Dynamic Partitions.
   if (merged_info_dict.get('use_dynamic_partitions') == 'true') and (
       system_info_dict.get('use_dynamic_partitions') == 'true'):
-    merged_info_dict['dynamic_partition_list'] = '%s %s' % (
-        system_info_dict.get('dynamic_partition_list', ''),
-        merged_info_dict.get('dynamic_partition_list', ''))
-    # Partition groups and group sizes are defined by the other (non-system)
-    # misc info file because these values may vary for each board that uses
-    # a shared system image.
-    for partition_group in merged_info_dict['super_partition_groups'].split(
-        ' '):
-      if ('super_%s_group_size' % partition_group) not in merged_info_dict:
-        raise ValueError(
-            'Other META/misc_info.txt does not contain required key '
-            'super_%s_group_size.' % partition_group)
-      key = 'super_%s_partition_list' % partition_group
-      merged_info_dict[key] = '%s %s' % (system_info_dict.get(
-          key, ''), merged_info_dict.get(key, ''))
+    merged_dynamic_partitions_dict = merge_dynamic_partition_info_dicts(
+        system_dict=system_info_dict,
+        other_dict=merged_info_dict,
+        size_prefix='super_',
+        size_suffix='_group_size',
+        list_prefix='super_',
+        list_suffix='_partition_list')
+    merged_info_dict.update(merged_dynamic_partitions_dict)
 
   output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
                                       'misc_info.txt')
-
-  sorted_keys = sorted(merged_info_dict.keys())
-
   with open(output_misc_info_txt, 'w') as output:
+    sorted_keys = sorted(merged_info_dict.keys())
     for key in sorted_keys:
       output.write('{}={}\n'.format(key, merged_info_dict[key]))
 
 
-def process_file_contexts_bin(temp_dir, output_target_files_temp_dir):
-  """Perform special processing for META/file_contexts.bin.
+def process_dynamic_partitions_info_txt(system_target_files_dir,
+                                        other_target_files_dir,
+                                        output_target_files_dir):
+  """Perform special processing for META/dynamic_partitions_info.txt.
 
-  This function combines plat_file_contexts and vendor_file_contexts, which are
-  expected to already be extracted in temp_dir, to produce a merged
-  file_contexts.bin that will land in temp_dir at META/file_contexts.bin.
+  This function merges the contents of the META/dynamic_partitions_info.txt
+  files from the system directory and the other directory, placing the merged
+  result in the output directory.
+
+  This function does nothing if META/dynamic_partitions_info.txt from the other
+  directory does not exist.
 
   Args:
-    temp_dir: The name of a scratch directory that this function can use for
-      intermediate files generated during processing.
-    output_target_files_temp_dir: The name of the working directory that must
-      already contain plat_file_contexts and vendor_file_contexts (in the
-      appropriate sub directories), and to which META/file_contexts.bin will be
-      written.
+    system_target_files_dir: The name of a directory containing the special
+      items extracted from the system target files package.
+    other_target_files_dir: The name of a directory containing the special items
+      extracted from the other target files package.
+    output_target_files_dir: The name of a directory that will be used to create
+      the output target files package after all the special cases are processed.
   """
 
-  # To create a merged file_contexts.bin file, we use the system and vendor
-  # file contexts files as input, the m4 tool to combine them, the sorting tool
-  # to sort, and finally the sefcontext_compile tool to generate the final
-  # output. We currently omit a checkfc step since the files had been checked
-  # as part of the build.
+  if not os.path.exists(
+      os.path.join(other_target_files_dir, 'META',
+                   'dynamic_partitions_info.txt')):
+    return
 
-  # The m4 step concatenates the two input files contexts files. Since m4
-  # writes to stdout, we receive that into an array of bytes, and then write it
-  # to a file.
+  def read_helper(d):
+    dynamic_partitions_info_txt = os.path.join(d, 'META',
+                                               'dynamic_partitions_info.txt')
+    with open(dynamic_partitions_info_txt) as f:
+      return list(f.read().splitlines())
 
-  # Collect the file contexts that we're going to combine from SYSTEM, VENDOR,
-  # PRODUCT, and ODM. We require SYSTEM and VENDOR, but others are optional.
+  system_dynamic_partitions_dict = common.LoadDictionaryFromLines(
+      read_helper(system_target_files_dir))
+  other_dynamic_partitions_dict = common.LoadDictionaryFromLines(
+      read_helper(other_target_files_dir))
 
-  file_contexts_list = []
+  merged_dynamic_partitions_dict = merge_dynamic_partition_info_dicts(
+      system_dict=system_dynamic_partitions_dict,
+      other_dict=other_dynamic_partitions_dict,
+      # META/dynamic_partitions_info.txt does not use dynamic_partition_list.
+      include_dynamic_partition_list=False,
+      size_suffix='_size',
+      list_suffix='_partition_list')
 
-  for partition in ['SYSTEM', 'VENDOR', 'PRODUCT', 'ODM']:
-    prefix = 'plat' if partition == 'SYSTEM' else partition.lower()
-
-    file_contexts = os.path.join(output_target_files_temp_dir, partition, 'etc',
-                                 'selinux', prefix + '_file_contexts')
-
-    mandatory = partition in ['SYSTEM', 'VENDOR']
-
-    if mandatory or os.path.isfile(file_contexts):
-      file_contexts_list.append(file_contexts)
-    else:
-      logger.warning('file not found: %s', file_contexts)
-
-  command = ['m4', '--fatal-warnings', '-s'] + file_contexts_list
-
-  merged_content = common.RunAndCheckOutput(command, verbose=False)
-
-  merged_file_contexts_txt = os.path.join(temp_dir, 'merged_file_contexts.txt')
-
-  with open(merged_file_contexts_txt, 'wb') as f:
-    f.write(merged_content)
-
-  # The sort step sorts the concatenated file.
-
-  sorted_file_contexts_txt = os.path.join(temp_dir, 'sorted_file_contexts.txt')
-  command = ['fc_sort', merged_file_contexts_txt, sorted_file_contexts_txt]
-  common.RunAndWait(command, verbose=True)
-
-  # Finally, the compile step creates the final META/file_contexts.bin.
-
-  file_contexts_bin = os.path.join(output_target_files_temp_dir, 'META',
-                                   'file_contexts.bin')
-
-  command = [
-      'sefcontext_compile',
-      '-o',
-      file_contexts_bin,
-      sorted_file_contexts_txt,
-  ]
-
-  common.RunAndWait(command, verbose=True)
+  output_dynamic_partitions_info_txt = os.path.join(
+      output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
+  with open(output_dynamic_partitions_info_txt, 'w') as output:
+    sorted_keys = sorted(merged_dynamic_partitions_dict.keys())
+    for key in sorted_keys:
+      output.write('{}={}\n'.format(key, merged_dynamic_partitions_dict[key]))
 
 
-def process_special_cases(temp_dir, system_target_files_temp_dir,
+def process_special_cases(system_target_files_temp_dir,
                           other_target_files_temp_dir,
                           output_target_files_temp_dir, system_misc_info_keys,
                           rebuild_recovery):
@@ -525,8 +554,6 @@
   processing. This function performs all that special-case processing.
 
   Args:
-    temp_dir: The name of a scratch directory that this function can use for
-      intermediate files generated during processing.
     system_target_files_temp_dir: The name of a directory containing the special
       items extracted from the system target files package.
     other_target_files_temp_dir: The name of a directory containing the special
@@ -556,8 +583,9 @@
       output_target_files_temp_dir=output_target_files_temp_dir,
       system_misc_info_keys=system_misc_info_keys)
 
-  process_file_contexts_bin(
-      temp_dir=temp_dir,
+  process_dynamic_partitions_info_txt(
+      system_target_files_temp_dir=system_target_files_temp_dir,
+      other_target_files_temp_dir=other_target_files_temp_dir,
       output_target_files_temp_dir=output_target_files_temp_dir)
 
 
@@ -654,7 +682,6 @@
   # files package are in place.
 
   process_special_cases(
-      temp_dir=temp_dir,
       system_target_files_temp_dir=system_target_files_temp_dir,
       other_target_files_temp_dir=other_target_files_temp_dir,
       output_target_files_temp_dir=output_target_files_temp_dir,
@@ -698,6 +725,16 @@
     if output_super_empty:
       shutil.copyfile(super_empty_img, output_super_empty)
 
+  # Create the IMG package from the merged target files (before zipping, in
+  # order to avoid an unnecessary unzip and copy).
+
+  if output_img:
+    img_from_target_files_args = [
+        output_target_files_temp_dir,
+        output_img,
+    ]
+    img_from_target_files.main(img_from_target_files_args)
+
   # Finally, create the output target files zip archive and/or copy the
   # output items to the output target files directory.
 
@@ -712,18 +749,23 @@
   output_target_files_meta_dir = os.path.join(output_target_files_temp_dir,
                                               'META')
 
-  command = [
+  find_command = [
       'find',
       output_target_files_meta_dir,
   ]
-  # TODO(bpeckham): sort this to be more like build.
-  meta_content = common.RunAndCheckOutput(command, verbose=False)
-  command = [
+  find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
+  meta_content = common.RunAndCheckOutput(['sort'],
+                                          stdin=find_process.stdout,
+                                          verbose=False)
+
+  find_command = [
       'find', output_target_files_temp_dir, '-path',
       output_target_files_meta_dir, '-prune', '-o', '-print'
   ]
-  # TODO(bpeckham): sort this to be more like build.
-  other_content = common.RunAndCheckOutput(command, verbose=False)
+  find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
+  other_content = common.RunAndCheckOutput(['sort'],
+                                           stdin=find_process.stdout,
+                                           verbose=False)
 
   with open(output_target_files_list, 'wb') as f:
     f.write(meta_content)
@@ -751,15 +793,6 @@
     ]
     ota_from_target_files.main(ota_from_target_files_args)
 
-  # Create the IMG package from the merged target files package.
-
-  if output_img:
-    img_from_target_files_args = [
-        output_zip,
-        output_img,
-    ]
-    img_from_target_files.main(img_from_target_files_args)
-
 
 def call_func_with_temp_dir(func, keep_tmp):
   """Manage the creation and cleanup of the temporary directory.
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index dd3e190..f686ca0 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -318,13 +318,24 @@
 
   @property
   def vendor_fingerprint(self):
-    if "vendor.build.prop" not in self.info_dict:
+    return self._fingerprint_of("vendor")
+
+  @property
+  def product_fingerprint(self):
+    return self._fingerprint_of("product")
+
+  @property
+  def odm_fingerprint(self):
+    return self._fingerprint_of("odm")
+
+  def _fingerprint_of(self, partition):
+    if partition + ".build.prop" not in self.info_dict:
       return None
-    vendor_build_prop = self.info_dict["vendor.build.prop"]
-    if "ro.vendor.build.fingerprint" in vendor_build_prop:
-      return vendor_build_prop["ro.vendor.build.fingerprint"]
-    if "ro.vendor.build.thumbprint" in vendor_build_prop:
-      return vendor_build_prop["ro.vendor.build.thumbprint"]
+    build_prop = self.info_dict[partition + ".build.prop"]
+    if "ro." + partition + ".build.fingerprint" in build_prop:
+      return build_prop["ro." + partition + ".build.fingerprint"]
+    if "ro." + partition + ".build.thumbprint" in build_prop:
+      return build_prop["ro." + partition + ".build.thumbprint"]
     return None
 
   @property
@@ -692,14 +703,26 @@
           "SYSTEM/etc/recovery.img" in namelist)
 
 
-def HasVendorPartition(target_files_zip):
+def HasPartition(target_files_zip, partition):
   try:
-    target_files_zip.getinfo("VENDOR/")
+    target_files_zip.getinfo(partition.upper() + "/")
     return True
   except KeyError:
     return False
 
 
+def HasVendorPartition(target_files_zip):
+  return HasPartition(target_files_zip, "vendor")
+
+
+def HasProductPartition(target_files_zip):
+  return HasPartition(target_files_zip, "product")
+
+
+def HasOdmPartition(target_files_zip):
+  return HasPartition(target_files_zip, "odm")
+
+
 def HasTrebleEnabled(target_files_zip, target_info):
   return (HasVendorPartition(target_files_zip) and
           target_info.GetBuildProp("ro.treble.enabled") == "true")
@@ -745,23 +768,24 @@
         generating an incremental OTA; None otherwise.
   """
 
-  def AddCompatibilityArchive(system_updated, vendor_updated):
-    """Adds compatibility info based on system/vendor update status.
+  def AddCompatibilityArchive(framework_updated, device_updated):
+    """Adds compatibility info based on update status of both sides of Treble
+    boundary.
 
     Args:
-      system_updated: If True, the system image will be updated and therefore
-          its metadata should be included.
-      vendor_updated: If True, the vendor image will be updated and therefore
-          its metadata should be included.
+      framework_updated: If True, the system / product image will be updated
+          and therefore their metadata should be included.
+      device_updated: If True, the vendor / odm image will be updated and
+          therefore their metadata should be included.
     """
     # Determine what metadata we need. Files are names relative to META/.
     compatibility_files = []
-    vendor_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
-    system_metadata = ("system_manifest.xml", "system_matrix.xml")
-    if vendor_updated:
-      compatibility_files += vendor_metadata
-    if system_updated:
-      compatibility_files += system_metadata
+    device_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
+    framework_metadata = ("system_manifest.xml", "system_matrix.xml")
+    if device_updated:
+      compatibility_files += device_metadata
+    if framework_updated:
+      compatibility_files += framework_metadata
 
     # Create new archive.
     compatibility_archive = tempfile.NamedTemporaryFile()
@@ -785,6 +809,11 @@
                       arcname="compatibility.zip",
                       compress_type=zipfile.ZIP_STORED)
 
+  def FingerprintChanged(source_fp, target_fp):
+    if source_fp is None or target_fp is None:
+      return True
+    return source_fp != target_fp
+
   # Will only proceed if the target has enabled the Treble support (as well as
   # having a /vendor partition).
   if not HasTrebleEnabled(target_zip, target_info):
@@ -795,7 +824,7 @@
   if OPTIONS.skip_compatibility_check:
     return
 
-  # Full OTA carries the info for system/vendor both.
+  # Full OTA carries the info for system/vendor/product/odm
   if source_info is None:
     AddCompatibilityArchive(True, True)
     return
@@ -804,16 +833,19 @@
   target_fp = target_info.fingerprint
   system_updated = source_fp != target_fp
 
-  source_fp_vendor = source_info.vendor_fingerprint
-  target_fp_vendor = target_info.vendor_fingerprint
-  # vendor build fingerprints could be possibly blacklisted at build time. For
-  # such a case, we consider the vendor images being changed.
-  if source_fp_vendor is None or target_fp_vendor is None:
-    vendor_updated = True
-  else:
-    vendor_updated = source_fp_vendor != target_fp_vendor
+  # other build fingerprints could be possibly blacklisted at build time. For
+  # such a case, we consider those images being changed.
+  vendor_updated = FingerprintChanged(source_info.vendor_fingerprint,
+                                      target_info.vendor_fingerprint)
+  product_updated = HasProductPartition(target_zip) and \
+                    FingerprintChanged(source_info.product_fingerprint,
+                                       target_info.product_fingerprint)
+  odm_updated = HasOdmPartition(target_zip) and \
+                FingerprintChanged(source_info.odm_fingerprint,
+                                   target_info.odm_fingerprint)
 
-  AddCompatibilityArchive(system_updated, vendor_updated)
+  AddCompatibilityArchive(system_updated or product_updated,
+                          vendor_updated or odm_updated)
 
 
 def WriteFullOTAPackage(input_zip, output_file):
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index 9aa9499..24ee91b 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -91,12 +91,15 @@
       Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
       with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
 
-  --avb_{boot,system,system_other,vendor,dtbo,vbmeta}_algorithm <algorithm>
-  --avb_{boot,system,system_other,vendor,dtbo,vbmeta}_key <key>
+  --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
+         vbmeta_vendor}_algorithm <algorithm>
+  --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
+         vbmeta_vendor}_key <key>
       Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
       the specified image. Otherwise it uses the existing values in info dict.
 
-  --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta}_extra_args <args>
+  --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
+         vbmeta_vendor}_extra_args <args>
       Specify any additional args that are needed to AVB-sign the image
       (e.g. "--signing_helper /path/to/helper"). The args will be appended to
       the existing ones in info dict.
@@ -176,6 +179,9 @@
   Returns:
     A dict that contains the updated APEX key mapping, which should be used for
     the current signing.
+
+  Raises:
+    AssertionError: On invalid container / payload key overrides.
   """
   # Apply all the --extra_apex_payload_key options to override the payload
   # signing keys in the given keys_info.
@@ -197,6 +203,24 @@
       key = 'PRESIGNED'
     keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
 
+  # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
+  # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
+  # (overridden via commandline) indicates a config error, which should not be
+  # allowed.
+  for apex, (payload_key, container_key) in keys_info.items():
+    if container_key != 'PRESIGNED':
+      continue
+    if apex in OPTIONS.extra_apex_payload_keys:
+      payload_override = OPTIONS.extra_apex_payload_keys[apex]
+      assert payload_override == '', \
+          ("Invalid APEX key overrides: {} has PRESIGNED container but "
+           "non-PRESIGNED payload key {}").format(apex, payload_override)
+    if payload_key != 'PRESIGNED':
+      print(
+          "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
+              apex))
+    keys_info[apex] = ('PRESIGNED', 'PRESIGNED')
+
   return keys_info
 
 
@@ -289,7 +313,9 @@
        "not sign this apk).".format("\n  ".join(unknown_files)))
 
   # For all the APEXes, double check that we won't have an APEX that has only
-  # one of the payload / container keys set.
+  # one of the payload / container keys set. Note that non-PRESIGNED container
+  # with PRESIGNED payload could be allowed but currently unsupported. It would
+  # require changing SignApex implementation.
   if not apex_keys:
     return
 
@@ -535,6 +561,13 @@
     # System properties.
     elif filename in ("SYSTEM/build.prop",
                       "VENDOR/build.prop",
+                      "SYSTEM/vendor/build.prop",
+                      "ODM/build.prop",
+                      "VENDOR/odm/build.prop",
+                      "PRODUCT/build.prop",
+                      "SYSTEM/product/build.prop",
+                      "PRODUCT_SERVICES/build.prop",
+                      "SYSTEM/product_services/build.prop",
                       "SYSTEM/etc/prop.default",
                       "BOOT/RAMDISK/prop.default",
                       "BOOT/RAMDISK/default.prop",  # legacy
@@ -729,8 +762,8 @@
     original_line = line
     if line and line[0] != '#' and "=" in line:
       key, value = line.split("=", 1)
-      if key in ("ro.build.fingerprint", "ro.build.thumbprint",
-                 "ro.vendor.build.fingerprint", "ro.vendor.build.thumbprint"):
+      if (key.startswith("ro.") and
+          key.endswith((".build.fingerprint", ".build.thumbprint"))):
         pieces = value.split("/")
         pieces[-1] = EditTags(pieces[-1])
         value = "/".join(pieces)
@@ -743,7 +776,7 @@
         assert len(pieces) == 5
         pieces[-1] = EditTags(pieces[-1])
         value = " ".join(pieces)
-      elif key == "ro.build.tags":
+      elif key.startswith("ro.") and key.endswith(".build.tags"):
         value = EditTags(value)
       elif key == "ro.build.display.id":
         # change, eg, "JWR66N dev-keys" to "JWR66N"
@@ -936,6 +969,8 @@
       'system_other' : 'avb_system_other_add_hashtree_footer_args',
       'vendor' : 'avb_vendor_add_hashtree_footer_args',
       'vbmeta' : 'avb_vbmeta_args',
+      'vbmeta_system' : 'avb_vbmeta_system_args',
+      'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
   }
 
   def ReplaceAvbPartitionSigningKey(partition):
@@ -1074,13 +1109,16 @@
     # full names only.
     container_cert = matches.group("CONTAINER_CERT")
     container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
-    if not CompareKeys(
+    if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
+      container_key = 'PRESIGNED'
+    elif CompareKeys(
         container_cert, OPTIONS.public_key_suffix,
         container_private_key, OPTIONS.private_key_suffix):
+      container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
+    else:
       raise ValueError("Failed to parse container keys: \n{}".format(line))
 
-    keys[name] = (payload_private_key,
-                  container_cert[:-len(OPTIONS.public_key_suffix)])
+    keys[name] = (payload_private_key, container_key)
 
   return keys
 
@@ -1160,6 +1198,18 @@
       OPTIONS.avb_algorithms['vendor'] = a
     elif o == "--avb_vendor_extra_args":
       OPTIONS.avb_extra_args['vendor'] = a
+    elif o == "--avb_vbmeta_system_key":
+      OPTIONS.avb_keys['vbmeta_system'] = a
+    elif o == "--avb_vbmeta_system_algorithm":
+      OPTIONS.avb_algorithms['vbmeta_system'] = a
+    elif o == "--avb_vbmeta_system_extra_args":
+      OPTIONS.avb_extra_args['vbmeta_system'] = a
+    elif o == "--avb_vbmeta_vendor_key":
+      OPTIONS.avb_keys['vbmeta_vendor'] = a
+    elif o == "--avb_vbmeta_vendor_algorithm":
+      OPTIONS.avb_algorithms['vbmeta_vendor'] = a
+    elif o == "--avb_vbmeta_vendor_extra_args":
+      OPTIONS.avb_extra_args['vbmeta_vendor'] = a
     elif o == "--avb_apex_extra_args":
       OPTIONS.avb_extra_args['apex'] = a
     else:
@@ -1199,6 +1249,12 @@
           "avb_vendor_algorithm=",
           "avb_vendor_key=",
           "avb_vendor_extra_args=",
+          "avb_vbmeta_system_algorithm=",
+          "avb_vbmeta_system_key=",
+          "avb_vbmeta_system_extra_args=",
+          "avb_vbmeta_vendor_algorithm=",
+          "avb_vbmeta_vendor_key=",
+          "avb_vbmeta_vendor_extra_args=",
       ],
       extra_option_handler=option_handler)
 
diff --git a/tools/releasetools/test_add_img_to_target_files.py b/tools/releasetools/test_add_img_to_target_files.py
index 013ade6..08e0190 100644
--- a/tools/releasetools/test_add_img_to_target_files.py
+++ b/tools/releasetools/test_add_img_to_target_files.py
@@ -123,6 +123,9 @@
   def _test_AddCareMapForAbOta():
     """Helper function to set up the test for test_AddCareMapForAbOta()."""
     OPTIONS.info_dict = {
+        'extfs_sparse_flag' : '-s',
+        'system_image_size' : 65536,
+        'vendor_image_size' : 40960,
         'system_verity_block_device': '/dev/block/system',
         'vendor_verity_block_device': '/dev/block/vendor',
         'system.build.prop': {
@@ -131,7 +134,7 @@
         },
         'vendor.build.prop': {
             'ro.vendor.build.fingerprint': 'google/sailfish/678:user/dev-keys',
-        }
+        },
     }
 
     # Prepare the META/ folder.
@@ -142,9 +145,9 @@
     system_image = test_utils.construct_sparse_image([
         (0xCAC1, 6),
         (0xCAC3, 4),
-        (0xCAC1, 6)])
+        (0xCAC1, 8)])
     vendor_image = test_utils.construct_sparse_image([
-        (0xCAC2, 10)])
+        (0xCAC2, 12)])
 
     image_paths = {
         'system' : system_image,
@@ -203,6 +206,9 @@
     """Tests the case for device using AVB."""
     image_paths = self._test_AddCareMapForAbOta()
     OPTIONS.info_dict = {
+        'extfs_sparse_flag' : '-s',
+        'system_image_size' : 65536,
+        'vendor_image_size' : 40960,
         'avb_system_hashtree_enable' : 'true',
         'avb_vendor_hashtree_enable' : 'true',
         'system.build.prop': {
@@ -231,6 +237,9 @@
     """Tests the case for partitions without fingerprint."""
     image_paths = self._test_AddCareMapForAbOta()
     OPTIONS.info_dict = {
+        'extfs_sparse_flag' : '-s',
+        'system_image_size' : 65536,
+        'vendor_image_size' : 40960,
         'system_verity_block_device': '/dev/block/system',
         'vendor_verity_block_device': '/dev/block/vendor',
     }
@@ -249,6 +258,9 @@
     """Tests the case for partitions with thumbprint."""
     image_paths = self._test_AddCareMapForAbOta()
     OPTIONS.info_dict = {
+        'extfs_sparse_flag' : '-s',
+        'system_image_size' : 65536,
+        'vendor_image_size' : 40960,
         'system_verity_block_device': '/dev/block/system',
         'vendor_verity_block_device': '/dev/block/vendor',
         'system.build.prop': {
@@ -256,7 +268,7 @@
         },
         'vendor.build.prop' : {
             'ro.vendor.build.thumbprint': 'google/sailfish/456:user/dev-keys',
-        }
+        },
     }
 
     AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
@@ -271,6 +283,35 @@
 
     self._verifyCareMap(expected, care_map_file)
 
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_AddCareMapForAbOta_skipPartition(self):
+    image_paths = self._test_AddCareMapForAbOta()
+
+    # Remove vendor_image_size to invalidate the care_map for vendor.img.
+    del OPTIONS.info_dict['vendor_image_size']
+
+    AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
+
+    care_map_file = os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')
+    expected = ['system', RangeSet("0-5 10-15").to_string_raw(),
+                "ro.system.build.fingerprint",
+                "google/sailfish/12345:user/dev-keys"]
+
+    self._verifyCareMap(expected, care_map_file)
+
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_AddCareMapForAbOta_skipAllPartitions(self):
+    image_paths = self._test_AddCareMapForAbOta()
+
+    # Remove the image_size properties for all the partitions.
+    del OPTIONS.info_dict['system_image_size']
+    del OPTIONS.info_dict['vendor_image_size']
+
+    AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
+
+    self.assertFalse(
+        os.path.exists(os.path.join(OPTIONS.input_tmp, 'META', 'care_map.pb')))
+
   def test_AddCareMapForAbOta_verityNotEnabled(self):
     """No care_map.pb should be generated if verity not enabled."""
     image_paths = self._test_AddCareMapForAbOta()
@@ -370,6 +411,7 @@
         (0xCAC3, 4),
         (0xCAC1, 6)])
     OPTIONS.info_dict = {
+        'extfs_sparse_flag' : '-s',
         'system_image_size' : 53248,
     }
     name, care_map = GetCareMap('system', sparse_image)
@@ -385,6 +427,17 @@
         (0xCAC3, 4),
         (0xCAC1, 6)])
     OPTIONS.info_dict = {
+        'extfs_sparse_flag' : '-s',
         'system_image_size' : -45056,
     }
     self.assertRaises(AssertionError, GetCareMap, 'system', sparse_image)
+
+  def test_GetCareMap_nonSparseImage(self):
+    OPTIONS.info_dict = {
+        'system_image_size' : 53248,
+    }
+    # 'foo' is the image filename, which is expected to be not used by
+    # GetCareMap().
+    name, care_map = GetCareMap('system', 'foo')
+    self.assertEqual('system', name)
+    self.assertEqual(RangeSet("0-12").to_string_raw(), care_map)
diff --git a/tools/releasetools/test_merge_target_files.py b/tools/releasetools/test_merge_target_files.py
index 7e18a34..3f15d8f 100644
--- a/tools/releasetools/test_merge_target_files.py
+++ b/tools/releasetools/test_merge_target_files.py
@@ -21,7 +21,8 @@
 from merge_target_files import (read_config_list, validate_config_lists,
                                 default_system_item_list,
                                 default_other_item_list,
-                                default_system_misc_info_keys, copy_items)
+                                default_system_misc_info_keys, copy_items,
+                                merge_dynamic_partition_info_dicts)
 
 
 class MergeTargetFilesTest(test_utils.ReleaseToolsTestCase):
@@ -128,3 +129,34 @@
       self.assertFalse(
           validate_config_lists(default_system_item_list, system_misc_info_keys,
                                 default_other_item_list))
+
+  def test_merge_dynamic_partition_info_dicts_ReturnsMergedDict(self):
+    system_dict = {
+        'super_partition_groups': 'group_a',
+        'dynamic_partition_list': 'system',
+        'super_group_a_list': 'system',
+    }
+    other_dict = {
+        'super_partition_groups': 'group_a group_b',
+        'dynamic_partition_list': 'vendor product',
+        'super_group_a_list': 'vendor',
+        'super_group_a_size': '1000',
+        'super_group_b_list': 'product',
+        'super_group_b_size': '2000',
+    }
+    merged_dict = merge_dynamic_partition_info_dicts(
+        system_dict=system_dict,
+        other_dict=other_dict,
+        size_prefix='super_',
+        size_suffix='_size',
+        list_prefix='super_',
+        list_suffix='_list')
+    expected_merged_dict = {
+        'super_partition_groups': 'group_a group_b',
+        'dynamic_partition_list': 'system vendor product',
+        'super_group_a_list': 'system vendor',
+        'super_group_a_size': '1000',
+        'super_group_b_list': 'product',
+        'super_group_b_size': '2000',
+    }
+    self.assertEqual(merged_dict, expected_merged_dict)
diff --git a/tools/releasetools/test_sign_target_files_apks.py b/tools/releasetools/test_sign_target_files_apks.py
index d745200..e142ebb 100644
--- a/tools/releasetools/test_sign_target_files_apks.py
+++ b/tools/releasetools/test_sign_target_files_apks.py
@@ -53,36 +53,60 @@
 
   def test_RewriteProps(self):
     props = (
-        ('', '\n'),
+        ('', ''),
         ('ro.build.fingerprint=foo/bar/dev-keys',
-         'ro.build.fingerprint=foo/bar/release-keys\n'),
+         'ro.build.fingerprint=foo/bar/release-keys'),
         ('ro.build.thumbprint=foo/bar/dev-keys',
-         'ro.build.thumbprint=foo/bar/release-keys\n'),
+         'ro.build.thumbprint=foo/bar/release-keys'),
         ('ro.vendor.build.fingerprint=foo/bar/dev-keys',
-         'ro.vendor.build.fingerprint=foo/bar/release-keys\n'),
+         'ro.vendor.build.fingerprint=foo/bar/release-keys'),
         ('ro.vendor.build.thumbprint=foo/bar/dev-keys',
-         'ro.vendor.build.thumbprint=foo/bar/release-keys\n'),
-        ('# comment line 1', '# comment line 1\n'),
+         'ro.vendor.build.thumbprint=foo/bar/release-keys'),
+        ('ro.odm.build.fingerprint=foo/bar/test-keys',
+         'ro.odm.build.fingerprint=foo/bar/release-keys'),
+        ('ro.odm.build.thumbprint=foo/bar/test-keys',
+         'ro.odm.build.thumbprint=foo/bar/release-keys'),
+        ('ro.product.build.fingerprint=foo/bar/dev-keys',
+         'ro.product.build.fingerprint=foo/bar/release-keys'),
+        ('ro.product.build.thumbprint=foo/bar/dev-keys',
+         'ro.product.build.thumbprint=foo/bar/release-keys'),
+        ('ro.product_services.build.fingerprint=foo/bar/test-keys',
+         'ro.product_services.build.fingerprint=foo/bar/release-keys'),
+        ('ro.product_services.build.thumbprint=foo/bar/test-keys',
+         'ro.product_services.build.thumbprint=foo/bar/release-keys'),
+        ('# comment line 1', '# comment line 1'),
         ('ro.bootimage.build.fingerprint=foo/bar/dev-keys',
-         'ro.bootimage.build.fingerprint=foo/bar/release-keys\n'),
+         'ro.bootimage.build.fingerprint=foo/bar/release-keys'),
         ('ro.build.description='
          'sailfish-user 8.0.0 OPR6.170623.012 4283428 dev-keys',
          'ro.build.description='
-         'sailfish-user 8.0.0 OPR6.170623.012 4283428 release-keys\n'),
-        ('ro.build.tags=dev-keys', 'ro.build.tags=release-keys\n'),
-        ('# comment line 2', '# comment line 2\n'),
+         'sailfish-user 8.0.0 OPR6.170623.012 4283428 release-keys'),
+        ('ro.build.tags=dev-keys', 'ro.build.tags=release-keys'),
+        ('ro.build.tags=test-keys', 'ro.build.tags=release-keys'),
+        ('ro.system.build.tags=dev-keys',
+         'ro.system.build.tags=release-keys'),
+        ('ro.vendor.build.tags=dev-keys',
+         'ro.vendor.build.tags=release-keys'),
+        ('ro.odm.build.tags=dev-keys',
+         'ro.odm.build.tags=release-keys'),
+        ('ro.product.build.tags=dev-keys',
+         'ro.product.build.tags=release-keys'),
+        ('ro.product_services.build.tags=dev-keys',
+         'ro.product_services.build.tags=release-keys'),
+        ('# comment line 2', '# comment line 2'),
         ('ro.build.display.id=OPR6.170623.012 dev-keys',
-         'ro.build.display.id=OPR6.170623.012\n'),
-        ('# comment line 3', '# comment line 3\n'),
+         'ro.build.display.id=OPR6.170623.012'),
+        ('# comment line 3', '# comment line 3'),
     )
 
     # Assert the case for each individual line.
-    for prop, output in props:
-      self.assertEqual(RewriteProps(prop), output)
+    for prop, expected in props:
+      self.assertEqual(expected + '\n', RewriteProps(prop))
 
     # Concatenate all the input lines.
-    self.assertEqual(RewriteProps('\n'.join([prop[0] for prop in props])),
-                     ''.join([prop[1] for prop in props]))
+    self.assertEqual(
+        '\n'.join([prop[1] for prop in props]) + '\n',
+        RewriteProps('\n'.join([prop[0] for prop in props])))
 
   def test_ReplaceVerityKeyId(self):
     BOOT_CMDLINE1 = (
@@ -461,3 +485,26 @@
             'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
             'build/make/target/product/security/testkey'),
         }, keys_info)
+
+  def test_ReadApexKeysInfo_presignedKeys(self):
+    apex_keys = self.APEX_KEYS_TXT + (
+        'name="apex.apexd_test_different_app2.apex" '
+        'private_key="PRESIGNED" '
+        'public_key="PRESIGNED" '
+        'container_certificate="PRESIGNED" '
+        'container_private_key="PRESIGNED"')
+    target_files = common.MakeTempFile(suffix='.zip')
+    with zipfile.ZipFile(target_files, 'w') as target_files_zip:
+      target_files_zip.writestr('META/apexkeys.txt', apex_keys)
+
+    with zipfile.ZipFile(target_files) as target_files_zip:
+      keys_info = ReadApexKeysInfo(target_files_zip)
+
+    self.assertEqual({
+        'apex.apexd_test.apex': (
+            'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
+            'build/make/target/product/security/testkey'),
+        'apex.apexd_test_different_app.apex': (
+            'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
+            'build/make/target/product/security/testkey'),
+        }, keys_info)
diff --git a/tools/releasetools/verity_utils.py b/tools/releasetools/verity_utils.py
index 3a58755..3063800 100644
--- a/tools/releasetools/verity_utils.py
+++ b/tools/releasetools/verity_utils.py
@@ -52,7 +52,7 @@
 
 
 def GetVerityMetadataSize(image_size):
-  cmd = ["build_verity_metadata.py", "size", str(image_size)]
+  cmd = ["build_verity_metadata", "size", str(image_size)]
   output = common.RunAndCheckOutput(cmd, verbose=False)
   return int(output)
 
@@ -97,7 +97,7 @@
 def BuildVerityMetadata(image_size, verity_metadata_path, root_hash, salt,
                         block_device, signer_path, key, signer_args,
                         verity_disable):
-  cmd = ["build_verity_metadata.py", "build", str(image_size),
+  cmd = ["build_verity_metadata", "build", str(image_size),
          verity_metadata_path, root_hash, salt, block_device, signer_path, key]
   if signer_args:
     cmd.append("--signer_args=\"%s\"" % (' '.join(signer_args),))