Merge "Fix up _CheckSecondTokenNotSlotSuffixed function." into rvc-dev
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 623dc39..3fc7cbc 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -713,6 +713,9 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/apex/com.android.cellbroadcast.apex)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/apex/com.android.cellbroadcast)
 
+# Remove CellBroadcastLegacyApp for Go devices
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/CellBroadcastLegacyApp)
+
 # Remove MediaProvider after moving into APEX
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/MediaProvider)
 
diff --git a/core/Makefile b/core/Makefile
index 11684f9..06cc876 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -587,9 +587,7 @@
 	@echo Target product buildinfo: $@
 	@mkdir -p $(dir $@)
 	$(hide) echo > $@
-ifdef BOARD_USES_PRODUCTIMAGE
 	$(hide) $(call generate-common-build-props,product,$@)
-endif  # BOARD_USES_PRODUCTIMAGE
 	$(hide) $(foreach file,$(product_prop_files), \
 	    if [ -f "$(file)" ]; then \
 	        echo Target product properties from: "$(file)"; \
@@ -721,6 +719,11 @@
 # Depmod requires a well-formed kernel version so 0.0 is used as a placeholder.
 DEPMOD_STAGING_SUBDIR :=$= lib/modules/0.0
 
+define copy-and-strip-kernel-module
+$(2): $(1)
+	$(LLVM_STRIP) -o $(2) --strip-debug $(1)
+endef
+
 # $(1): modules list
 # $(2): output dir
 # $(3): mount point
@@ -728,14 +731,24 @@
 # $(5): module load list
 # $(6): module load list filename
 # $(7): module archive
+# $(8): staging dir for stripped modules
+# $(9): module directory name
 # Returns the a list of src:dest pairs to install the modules using copy-many-files.
 define build-image-kernel-modules
-  $(foreach module,$(1),$(module):$(2)/lib/modules/$(notdir $(module))) \
-  $(eval $(call build-image-kernel-modules-depmod,$(1),$(3),$(4),$(5),$(6),$(7),$(2))) \
-  $(4)/$(DEPMOD_STAGING_SUBDIR)/modules.dep:$(2)/lib/modules/modules.dep \
-  $(4)/$(DEPMOD_STAGING_SUBDIR)/modules.alias:$(2)/lib/modules/modules.alias \
-  $(4)/$(DEPMOD_STAGING_SUBDIR)/modules.softdep:$(2)/lib/modules/modules.softdep \
-  $(4)/$(DEPMOD_STAGING_SUBDIR)/$(6):$(2)/lib/modules/$(6)
+  $(if $(9), \
+    $(eval _dir := $(9)/), \
+    $(eval _dir :=)) \
+  $(foreach module,$(1), \
+    $(eval _src := $(module)) \
+    $(if $(8), \
+      $(eval _src := $(8)/$(notdir $(module))) \
+      $(eval $(call copy-and-strip-kernel-module,$(module),$(_src)))) \
+    $(_src):$(2)/lib/modules/$(_dir)$(notdir $(module))) \
+  $(eval $(call build-image-kernel-modules-depmod,$(1),$(3),$(4),$(5),$(6),$(7),$(2),$(9))) \
+  $(4)/$(DEPMOD_STAGING_SUBDIR)/modules.dep:$(2)/lib/modules/$(_dir)modules.dep \
+  $(4)/$(DEPMOD_STAGING_SUBDIR)/modules.alias:$(2)/lib/modules/$(_dir)modules.alias \
+  $(4)/$(DEPMOD_STAGING_SUBDIR)/modules.softdep:$(2)/lib/modules/$(_dir)modules.softdep \
+  $(4)/$(DEPMOD_STAGING_SUBDIR)/$(6):$(2)/lib/modules/$(_dir)$(6)
 endef
 
 # $(1): modules list
@@ -745,6 +758,7 @@
 # $(5): module load list filename
 # $(6): module archive
 # $(7): output dir
+# $(8): module directory name
 # TODO(b/144844424): If a module archive is being used, this step (which
 # generates obj/PACKAGING/.../modules.dep) also unzips the module archive into
 # the output directory. This should be moved to a module with a
@@ -755,7 +769,7 @@
 $(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: $(DEPMOD)
 $(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MODULES := $(1)
 $(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MOUNT_POINT := $(2)
-$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MODULE_DIR := $(3)/$(DEPMOD_STAGING_SUBDIR)/$(2)/lib/modules
+$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MODULE_DIR := $(3)/$(DEPMOD_STAGING_SUBDIR)/$(2)/lib/modules/$(8)
 $(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_STAGING_DIR := $(3)
 $(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_LOAD_MODULES := $(4)
 $(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_LOAD_FILE := $(3)/$(DEPMOD_STAGING_SUBDIR)/$(5)
@@ -768,7 +782,7 @@
 	$(if $(6),\
 	  unzip -qo -d $$(PRIVATE_MODULE_DIR) $$(PRIVATE_MODULE_ARCHIVE); \
 	  mkdir -p $$(PRIVATE_OUTPUT_DIR)/lib; \
-	  cp -r $$(PRIVATE_MODULE_DIR) $$(PRIVATE_OUTPUT_DIR)/lib/; \
+	  cp -r  $(3)/$(DEPMOD_STAGING_SUBDIR)/$(2)/lib/modules $$(PRIVATE_OUTPUT_DIR)/lib/; \
 	  find $$(PRIVATE_MODULE_DIR) -type f -name *.ko | xargs basename -a > $$(PRIVATE_LOAD_FILE); \
 	)
 	$(if $(1),\
@@ -784,24 +798,61 @@
 endef
 
 # $(1): staging dir
-# $(2): module load list
-# $(3): module load list filename
-# $(4): output dir
+# $(2): modules list
+# $(3): module load list
+# $(4): module load list filename
+# $(5): output dir
 define module-load-list-copy-paths
-  $(eval $(call build-image-module-load-list,$(1),$(2),$(3))) \
-  $(1)/$(DEPMOD_STAGING_SUBDIR)/$(3):$(4)/lib/modules/$(3)
+  $(eval $(call build-image-module-load-list,$(1),$(2),$(3),$(4))) \
+  $(1)/$(DEPMOD_STAGING_SUBDIR)/$(4):$(5)/lib/modules/$(4)
 endef
 
 # $(1): staging dir
-# $(2): module load list
-# $(3): module load list filename
+# $(2): modules list
+# $(3): module load list
+# $(4): module load list filename
 define build-image-module-load-list
-$(1)/$(DEPMOD_STAGING_SUBDIR)/$(3): PRIVATE_STAGING_DIR := $(1)
-$(1)/$(DEPMOD_STAGING_SUBDIR)/$(3): PRIVATE_LOAD_MODULES := $(2)
-$(1)/$(DEPMOD_STAGING_SUBDIR)/$(3): PRIVATE_LOAD_FILENAME := $(3)
-$(1)/$(DEPMOD_STAGING_SUBDIR)/$(3): $(2)
-	rm -f $$@
-	(for MODULE in $$(PRIVATE_LOAD_MODULES); do basename $$$$MODULE >> $$@; done)
+$(1)/$(DEPMOD_STAGING_SUBDIR)/$(4): PRIVATE_LOAD_MODULES := $(3)
+$(1)/$(DEPMOD_STAGING_SUBDIR)/$(4): $(2)
+	@echo load-list $$(@)
+	@echo '$$(strip $$(notdir $$(PRIVATE_LOAD_MODULES)))' | tr ' ' '\n' > $$(@)
+endef
+
+# $(1): image name
+# $(2): build output directory (TARGET_OUT_VENDOR, TARGET_RECOVERY_ROOT_OUT, etc)
+# $(3): mount point
+# $(4): module load filename
+# $(5): stripped staging directory
+# $(6): kernel module directory name (top is an out of band value for no directory)
+define build-image-kernel-modules-dir
+$(if $(filter top,$(6)),\
+  $(eval _kver :=)$(eval _sep :=),\
+  $(eval _kver := $(6))$(eval _sep :=_))\
+$(if $(5),\
+  $(eval _stripped_staging_dir := $(5)$(_sep)$(_kver)),\
+  $(eval _stripped_staging_dir :=))\
+$(if $(strip $(BOARD_$(1)_KERNEL_MODULES$(_sep)$(_kver))$(BOARD_$(1)_KERNEL_MODULES_ARCHIVE$(_sep)$(_kver))),\
+  $(if $(BOARD_$(1)_KERNEL_MODULES_LOAD$(_sep)$(_kver)),,\
+    $(eval BOARD_$(1)_KERNEL_MODULES_LOAD$(_sep)$(_kver) := $(BOARD_$(1)_KERNEL_MODULES$(_sep)$(_kver)))) \
+  $(call copy-many-files,$(call build-image-kernel-modules,$(BOARD_$(1)_KERNEL_MODULES$(_sep)$(_kver)),$(2),$(3),$(call intermediates-dir-for,PACKAGING,depmod_$(1)$(_sep)$(_kver)),$(BOARD_$(1)_KERNEL_MODULES_LOAD$(_sep)$(_kver)),$(4),$(BOARD_$(1)_KERNEL_MODULES_ARCHIVE$(_sep)$(_kver)),$(_stripped_staging_dir),$(_kver))))
+endef
+
+# $(1): kernel module directory name (top is an out of band value for no directory)
+define build-recovery-as-boot-load
+$(if $(filter top,$(1)),\
+  $(eval _kver :=)$(eval _sep :=),\
+  $(eval _kver := $(1))$(eval _sep :=_))\
+  $(if $(BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD$(_sep)$(_kver)),\
+    $(call copy-many-files,$(call module-load-list-copy-paths,$(call intermediates-dir-for,PACKAGING,ramdisk_module_list$(_sep)$(_kver)),$(BOARD_GENERIC_RAMDISK_KERNEL_MODULES$(_sep)$(_kver)),$(BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD$(_sep)$(_kver)),modules.load,$(TARGET_RECOVERY_ROOT_OUT))))
+endef
+
+# $(1): kernel module directory name (top is an out of band value for no directory)
+define build-vendor-ramdisk-recovery-load
+$(if $(filter top,$(1)),\
+  $(eval _kver :=)$(eval _sep :=),\
+  $(eval _kver := $(1))$(eval _sep :=_))\
+  $(if $(BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD$(_sep)$(_kver)),\
+    $(call copy-many-files,$(call module-load-list-copy-paths,$(call intermediates-dir-for,PACKAGING,vendor_ramdisk_recovery_module_list$(_sep)$(_kver)),$(BOARD_VENDOR_RAMDISK_KERNEL_MODULES$(_sep)$(_kver)),$(BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD$(_sep)$(_kver)),modules.load.recovery,$(TARGET_VENDOR_RAMDISK_OUT))))
 endef
 
 ifneq ($(BUILDING_VENDOR_BOOT_IMAGE),true)
@@ -811,9 +862,6 @@
   BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD += $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD)
 endif
 
-ifeq ($(BOARD_RECOVERY_KERNEL_MODULES_LOAD),)
-  BOARD_RECOVERY_KERNEL_MODULES_LOAD := $(BOARD_RECOVERY_KERNEL_MODULES)
-endif
 ifeq ($(BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD),)
   BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := $(BOARD_GENERIC_RAMDISK_KERNEL_MODULES)
 endif
@@ -824,41 +872,28 @@
   endif
 endif
 
-ifneq ($(strip $(BOARD_RECOVERY_KERNEL_MODULES))$(strip $(BOARD_RECOVERY_KERNEL_MODULES_ARCHIVE)),)
-  ifeq ($(BOARD_USES_RECOVERY_AS_BOOT), true)
-    ifdef BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD
-      ALL_DEFAULT_INSTALLED_MODULES += $(call copy-many-files,$(call module-load-list-copy-paths,$(call intermediates-dir-for,PACKAGING,ramdisk_modules),$(BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD),modules.load,$(TARGET_RECOVERY_ROOT_OUT)))
-    endif
-  endif
-  ALL_DEFAULT_INSTALLED_MODULES += $(call copy-many-files,$(call build-image-kernel-modules,$(BOARD_RECOVERY_KERNEL_MODULES),$(TARGET_RECOVERY_ROOT_OUT),,$(call intermediates-dir-for,PACKAGING,depmod_recovery),$(BOARD_RECOVERY_KERNEL_MODULES_LOAD),modules.load.recovery,$(BOARD_RECOVERY_KERNEL_MODULES_ARCHIVE)))
+ifneq ($(BOARD_DO_NOT_STRIP_VENDOR_MODULES),true)
+	VENDOR_STRIPPED_MODULE_STAGING_DIR := $(call intermediates-dir-for,PACKAGING,depmod_vendor_stripped)
+else
+	VENDOR_STRIPPED_MODULE_STAGING_DIR :=
 endif
 
-ifneq ($(strip $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES))$(strip $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_ARCHIVE)),)
-  ifeq ($(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD),)
-    BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD := $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES)
-  endif
-  ALL_DEFAULT_INSTALLED_MODULES += $(call copy-many-files,$(call build-image-kernel-modules,$(BOARD_VENDOR_RAMDISK_KERNEL_MODULES),$(TARGET_VENDOR_RAMDISK_OUT),,$(call intermediates-dir-for,PACKAGING,depmod_vendor_ramdisk),$(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD),modules.load,$(BOARD_VENDOR_RAMDISK_KERNEL_MODULES_ARCHIVE)))
+ifneq ($(BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES),true)
+  VENDOR_RAMDISK_STRIPPED_MODULE_STAGING_DIR := $(call intermediates-dir-for,PACKAGING,depmod_vendor_ramdisk_stripped)
+else
+  VENDOR_RAMDISK_STRIPPED_MODULE_STAGING_DIR :=
 endif
 
-ifneq ($(BOARD_USES_RECOVERY_AS_BOOT), true)
-  ifneq ($(strip $(BOARD_GENERIC_RAMDISK_KERNEL_MODULES)),)
-    ALL_DEFAULT_INSTALLED_MODULES += $(call copy-many-files,$(call build-image-kernel-modules,$(BOARD_GENERIC_RAMDISK_KERNEL_MODULES),$(TARGET_RAMDISK_OUT),,$(call intermediates-dir-for,PACKAGING,depmod_ramdisk),$(BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD),modules.load,))
-  endif
-endif
-
-ifneq ($(strip $(BOARD_VENDOR_KERNEL_MODULES)$(strip $(BOARD_VENDOR_KERNEL_MODULES_ARCHIVE))),)
-  ifeq ($(BOARD_VENDOR_KERNEL_MODULES_LOAD),)
-    BOARD_VENDOR_KERNEL_MODULES_LOAD := $(BOARD_VENDOR_KERNEL_MODULES)
-  endif
-  ALL_DEFAULT_INSTALLED_MODULES += $(call copy-many-files,$(call build-image-kernel-modules,$(BOARD_VENDOR_KERNEL_MODULES),$(TARGET_OUT_VENDOR),vendor,$(call intermediates-dir-for,PACKAGING,depmod_vendor),$(BOARD_VENDOR_KERNEL_MODULES_LOAD),modules.load,$(BOARD_VENDOR_KERNEL_MODULES_ARCHIVE)))
-endif
-
-ifneq ($(strip $(BOARD_ODM_KERNEL_MODULES))$(strip $(BOARD_ODM_KERNEL_MODULES_ARCHIVE)),)
-  ifeq ($(BOARD_RECOVERY_KERNEL_MODULES_LOAD),)
-    BOARD_ODM_KERNEL_MODULES_LOAD := $(BOARD_ODM_KERNEL_MODULES)
-  endif
-  ALL_DEFAULT_INSTALLED_MODULES += $(call copy-many-files,$(call build-image-kernel-modules,$(BOARD_ODM_KERNEL_MODULES),$(TARGET_OUT_ODM),odm,$(call intermediates-dir-for,PACKAGING,depmod_odm),$(BOARD_ODM_KERNEL_MODULES_LOAD),modules.load,$(BOARD_ODM_KERNEL_MODULES_ARCHIVE)))
-endif
+BOARD_KERNEL_MODULE_DIRS += top
+$(foreach dir,$(BOARD_KERNEL_MODULE_DIRS), \
+  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,RECOVERY,$(TARGET_RECOVERY_ROOT_OUT),,modules.load.recovery,,$(dir))) \
+  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,VENDOR_RAMDISK,$(TARGET_VENDOR_RAMDISK_OUT),,modules.load,$(VENDOR_RAMDISK_STRIPPED_MODULE_STAGING_DIR),$(dir))) \
+  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-vendor-ramdisk-recovery-load,$(dir))) \
+  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,VENDOR,$(TARGET_OUT_VENDOR),vendor,modules.load,$(VENDOR_STRIPPED_MODULE_STAGING_DIR),$(dir))) \
+  $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,ODM,$(TARGET_OUT_ODM),odm,modules.load,,$(dir))) \
+  $(if $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)),\
+    $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-recovery-as-boot-load,$(dir))),\
+    $(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,GENERIC_RAMDISK,$(TARGET_RAMDISK_OUT),,modules.load,,$(dir)))))
 
 # -----------------------------------------------------------------
 # Cert-to-package mapping.  Used by the post-build signing tools.
@@ -877,6 +912,16 @@
 
 endef
 
+# -----------------------------------------------------------------
+# Merge an individual apkcerts output into the final apkcerts.txt output.
+# Use a macro to make it compatible with _apkcerts_write_line
+# $1 apkcerts file to be merged
+# $2 output file
+define _apkcerts_merge
+$(hide) cat $1 >> $2
+
+endef
+
 name := $(TARGET_PRODUCT)
 ifeq ($(TARGET_BUILD_TYPE),debug)
   name := $(name)_debug
@@ -885,6 +930,8 @@
 intermediates := \
 	$(call intermediates-dir-for,PACKAGING,apkcerts)
 APKCERTS_FILE := $(intermediates)/$(name).txt
+all_apkcerts_files := $(sort $(foreach p,$(PACKAGES),$(PACKAGES.$(p).APKCERTS_FILE)))
+$(APKCERTS_FILE): $(all_apkcerts_files)
 # We don't need to really build all the modules.
 # TODO: rebuild APKCERTS_FILE if any app change its cert.
 $(APKCERTS_FILE):
@@ -892,9 +939,11 @@
 	@mkdir -p $(dir $@)
 	@rm -f $@
 	$(foreach p,$(sort $(PACKAGES)),\
-	  $(if $(PACKAGES.$(p).EXTERNAL_KEY),\
-	    $(call _apkcerts_write_line,$(PACKAGES.$(p).STEM),"EXTERNAL","",$(PACKAGES.$(p).COMPRESSED),$(PACKAGES.$(p).PARTITION),$@),\
-	    $(call _apkcerts_write_line,$(PACKAGES.$(p).STEM),$(PACKAGES.$(p).CERTIFICATE),$(PACKAGES.$(p).PRIVATE_KEY),$(PACKAGES.$(p).COMPRESSED),$(PACKAGES.$(p).PARTITION),$@)))
+	  $(if $(PACKAGES.$(p).APKCERTS_FILE),\
+	    $(call _apkcerts_merge,$(PACKAGES.$(p).APKCERTS_FILE), $@),\
+	    $(if $(PACKAGES.$(p).EXTERNAL_KEY),\
+	      $(call _apkcerts_write_line,$(PACKAGES.$(p).STEM),"EXTERNAL","",$(PACKAGES.$(p).COMPRESSED),$(PACKAGES.$(p).PARTITION),$@),\
+	      $(call _apkcerts_write_line,$(PACKAGES.$(p).STEM),$(PACKAGES.$(p).CERTIFICATE),$(PACKAGES.$(p).PRIVATE_KEY),$(PACKAGES.$(p).COMPRESSED),$(PACKAGES.$(p).PARTITION),$@))))
 	# In case value of PACKAGES is empty.
 	$(hide) touch $@
 
@@ -1100,16 +1149,27 @@
 $(call dist-for-goals, sdk win_sdk sdk_addon, $(INSTALLED_FILES_FILE_RAMDISK))
 BUILT_RAMDISK_TARGET := $(PRODUCT_OUT)/ramdisk.img
 
+ifeq ($(BOARD_RAMDISK_USE_LZ4),true)
+# -l enables the legacy format used by the Linux kernel
+COMPRESSION_COMMAND_DEPS := $(LZ4)
+COMPRESSION_COMMAND := $(LZ4) -l -12 --favor-decSpeed
+RAMDISK_EXT := .lz4
+else
+COMPRESSION_COMMAND_DEPS := $(MINIGZIP)
+COMPRESSION_COMMAND := $(MINIGZIP)
+RAMDISK_EXT := .gz
+endif
+
 # We just build this directly to the install location.
 INSTALLED_RAMDISK_TARGET := $(BUILT_RAMDISK_TARGET)
-$(INSTALLED_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_RAMDISK_FILES) $(INSTALLED_FILES_FILE_RAMDISK) | $(MINIGZIP)
+$(INSTALLED_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_RAMDISK_FILES) $(INSTALLED_FILES_FILE_RAMDISK) | $(COMPRESSION_COMMAND_DEPS)
 	$(call pretty,"Target ram disk: $@")
-	$(hide) $(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_RAMDISK_OUT) | $(MINIGZIP) > $@
+	$(hide) $(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_RAMDISK_OUT) | $(COMPRESSION_COMMAND) > $@
 
 .PHONY: ramdisk-nodeps
-ramdisk-nodeps: $(MKBOOTFS) | $(MINIGZIP)
+ramdisk-nodeps: $(MKBOOTFS) | $(COMPRESSION_COMMAND_DEPS)
 	@echo "make $@: ignoring dependencies"
-	$(hide) $(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_RAMDISK_OUT) | $(MINIGZIP) > $(INSTALLED_RAMDISK_TARGET)
+	$(hide) $(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_RAMDISK_OUT) | $(COMPRESSION_COMMAND) > $(INSTALLED_RAMDISK_TARGET)
 
 endif # BUILDING_RAMDISK_IMAGE
 
@@ -1124,6 +1184,15 @@
   BUILT_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
 endif
 
+ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
+  BOARD_KERNEL_BOOTIMAGE_PARTITION_SIZE := $(BOARD_BOOTIMAGE_PARTITION_SIZE)
+endif
+
+# $1: boot image file name
+# $2: boot image variant (boot, boot-debug)
+define get-bootimage-partition-size
+  $(BOARD_$(call to-upper,$(subst .img,,$(subst $(2),kernel,$(notdir $(1)))))_BOOTIMAGE_PARTITION_SIZE)
+endef
 
 ifneq ($(strip $(TARGET_NO_KERNEL)),true)
 INTERNAL_BOOTIMAGE_ARGS := \
@@ -1274,8 +1343,8 @@
     $(ALL_DEFAULT_INSTALLED_MODULES))
 
 INTERNAL_VENDOR_RAMDISK_TARGET := $(call intermediates-dir-for,PACKAGING,vendor-boot)/vendor-ramdisk.cpio.gz
-$(INTERNAL_VENDOR_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_VENDOR_RAMDISK_FILES) | $(MINIGZIP)
-	$(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_VENDOR_RAMDISK_OUT) | $(MINIGZIP) > $@
+$(INTERNAL_VENDOR_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_VENDOR_RAMDISK_FILES) | $(COMPRESSION_COMMAND_DEPS)
+	$(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_VENDOR_RAMDISK_OUT) | $(COMPRESSION_COMMAND) > $@
 
 ifdef BOARD_INCLUDE_DTB_IN_BOOTIMG
   INTERNAL_VENDOR_BOOTIMAGE_ARGS += --dtb $(INSTALLED_DTBIMAGE_TARGET)
@@ -1424,6 +1493,8 @@
 # testcases are not relevant to the system image.
 license_modules := $(filter-out $(TARGET_OUT_TESTCASES)/%,$(license_modules))
 license_modules_system := $(filter $(TARGET_OUT)/%,$(license_modules))
+# system_other is relevant to system partition.
+license_modules_system += $(filter $(TARGET_OUT_SYSTEM_OTHER)/%,$(license_modules))
 license_modules_vendor := $(filter $(TARGET_OUT_VENDOR)/%,$(license_modules))
 license_modules_product := $(filter $(TARGET_OUT_PRODUCT)/%,$(license_modules))
 license_modules_system_ext := $(filter $(TARGET_OUT_SYSTEM_EXT)/%,$(license_modules))
@@ -2116,7 +2187,7 @@
   BOARD_RECOVERY_MKBOOTIMG_ARGS := $(BOARD_MKBOOTIMG_ARGS)
 endif
 
-$(recovery_ramdisk): $(MKBOOTFS) $(MINIGZIP) \
+$(recovery_ramdisk): $(MKBOOTFS) $(COMPRESSION_COMMAND_DEPS) \
 	    $(INTERNAL_ROOT_FILES) \
 	    $(INSTALLED_RAMDISK_TARGET) \
 	    $(INTERNAL_RECOVERYIMAGE_FILES) \
@@ -2151,7 +2222,7 @@
 	  cp -f $(recovery_wipe) $(TARGET_RECOVERY_ROOT_OUT)/system/etc/recovery.wipe)
 	ln -sf prop.default $(TARGET_RECOVERY_ROOT_OUT)/default.prop
 	$(BOARD_RECOVERY_IMAGE_PREPARE)
-	$(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_RECOVERY_ROOT_OUT) | $(MINIGZIP) > $(recovery_ramdisk)
+	$(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_RECOVERY_ROOT_OUT) | $(COMPRESSION_COMMAND) > $(recovery_ramdisk)
 
 # $(1): output file
 # $(2): kernel file
@@ -2172,60 +2243,45 @@
   $(if $(filter true,$(PRODUCT_SUPPORTS_VBOOT)), \
     $(VBOOT_SIGNER) $(FUTILITY) $(1).unsigned $(PRODUCT_VBOOT_SIGNING_KEY).vbpubk $(PRODUCT_VBOOT_SIGNING_KEY).vbprivk $(PRODUCT_VBOOT_SIGNING_SUBKEY).vbprivk $(1).keyblock $(1))
   $(if $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)), \
-    $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE))), \
+    $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(call get-bootimage-partition-size,$(1),boot))), \
     $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE))))
   $(if $(filter true,$(BOARD_AVB_ENABLE)), \
     $(if $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)), \
-      $(AVBTOOL) add_hash_footer --image $(1) --partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS),\
+      $(AVBTOOL) add_hash_footer --image $(1) --partition_size $(call get-bootimage-partition-size,$(1),boot) --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS),\
       $(AVBTOOL) add_hash_footer --image $(1) --partition_size $(BOARD_RECOVERYIMAGE_PARTITION_SIZE) --partition_name recovery $(INTERNAL_AVB_RECOVERY_SIGNING_ARGS) $(BOARD_AVB_RECOVERY_ADD_HASH_FOOTER_ARGS)))
 endef
 
-ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+recoveryimage-deps := $(MKBOOTIMG) $(recovery_ramdisk) $(recovery_kernel)
 ifeq (true,$(PRODUCT_SUPPORTS_BOOT_SIGNER))
-$(INSTALLED_BOOTIMAGE_TARGET) : $(BOOT_SIGNER)
+  recoveryimage-deps += $(BOOT_SIGNER)
 endif
 ifeq (true,$(PRODUCT_SUPPORTS_VBOOT))
-$(INSTALLED_BOOTIMAGE_TARGET) : $(VBOOT_SIGNER)
+  recoveryimage-deps += $(VBOOT_SIGNER)
 endif
 ifeq (true,$(BOARD_AVB_ENABLE))
-$(INSTALLED_BOOTIMAGE_TARGET) : $(AVBTOOL) $(BOARD_AVB_BOOT_KEY_PATH)
+  recoveryimage-deps += $(AVBTOOL) $(BOARD_AVB_BOOT_KEY_PATH)
 endif
 ifdef BOARD_INCLUDE_RECOVERY_DTBO
-ifdef BOARD_PREBUILT_RECOVERY_DTBOIMAGE
-$(INSTALLED_BOOTIMAGE_TARGET): $(BOARD_PREBUILT_RECOVERY_DTBOIMAGE)
-else
-$(INSTALLED_BOOTIMAGE_TARGET): $(BOARD_PREBUILT_DTBOIMAGE)
-endif
+  ifdef BOARD_PREBUILT_RECOVERY_DTBOIMAGE
+    recoveryimage-deps += $(BOARD_PREBUILT_RECOVERY_DTBOIMAGE)
+  else
+    recoveryimage-deps += $(BOARD_PREBUILT_DTBOIMAGE)
+  endif
 endif
 ifdef BOARD_INCLUDE_RECOVERY_ACPIO
-$(INSTALLED_BOOTIMAGE_TARGET): $(BOARD_RECOVERY_ACPIO)
+  recoveryimage-deps += $(BOARD_RECOVERY_ACPIO)
 endif
 ifdef BOARD_INCLUDE_DTB_IN_BOOTIMG
-$(INSTALLED_BOOTIMAGE_TARGET): $(INSTALLED_DTBIMAGE_TARGET)
+  recoveryimage-deps += $(INSTALLED_DTBIMAGE_TARGET)
 endif
 
-$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(recovery_ramdisk) \
-	    $(recovery_kernel)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+$(INSTALLED_BOOTIMAGE_TARGET): $(recoveryimage-deps)
 	$(call pretty,"Target boot image from recovery: $@")
 	$(call build-recoveryimage-target, $@, $(PRODUCT_OUT)/$(subst .img,,$(subst boot,kernel,$(notdir $@))))
 endif # BOARD_USES_RECOVERY_AS_BOOT
 
-ifdef BOARD_INCLUDE_RECOVERY_DTBO
-ifdef BOARD_PREBUILT_RECOVERY_DTBOIMAGE
-$(INSTALLED_RECOVERYIMAGE_TARGET): $(BOARD_PREBUILT_RECOVERY_DTBOIMAGE)
-else
-$(INSTALLED_RECOVERYIMAGE_TARGET): $(BOARD_PREBUILT_DTBOIMAGE)
-endif
-endif
-ifdef BOARD_INCLUDE_RECOVERY_ACPIO
-$(INSTALLED_RECOVERYIMAGE_TARGET): $(BOARD_RECOVERY_ACPIO)
-endif
-ifdef BOARD_INCLUDE_DTB_IN_BOOTIMG
-$(INSTALLED_RECOVERYIMAGE_TARGET): $(INSTALLED_DTBIMAGE_TARGET)
-endif
-
-$(INSTALLED_RECOVERYIMAGE_TARGET): $(MKBOOTIMG) $(recovery_ramdisk) \
-	    $(recovery_kernel)
+$(INSTALLED_RECOVERYIMAGE_TARGET): $(recoveryimage-deps)
 	$(call build-recoveryimage-target, $@, $(recovery_kernel))
 
 ifdef RECOVERY_RESOURCE_ZIP
@@ -2309,22 +2365,22 @@
 # 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)
+$(INSTALLED_DEBUG_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_DEBUG_RAMDISK_FILES) | $(COMPRESSION_COMMAND_DEPS)
 	$(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)
-	$(MKBOOTFS) -d $(TARGET_OUT) $(DEBUG_RAMDISK_ROOT_DIR) | $(MINIGZIP) > $@
+	$(MKBOOTFS) -d $(TARGET_OUT) $(DEBUG_RAMDISK_ROOT_DIR) | $(COMPRESSION_COMMAND) > $@
 
 .PHONY: ramdisk_debug-nodeps
 ramdisk_debug-nodeps: DEBUG_RAMDISK_SYNC_DIR := $(my_debug_ramdisk_sync_dir)
 ramdisk_debug-nodeps: DEBUG_RAMDISK_ROOT_DIR := $(my_debug_ramdisk_root_dir)
-ramdisk_debug-nodeps: $(MKBOOTFS) | $(MINIGZIP)
+ramdisk_debug-nodeps: $(MKBOOTFS) | $(COMPRESSION_COMMAND_DEPS)
 	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)
-	$(MKBOOTFS) -d $(TARGET_OUT) $(DEBUG_RAMDISK_ROOT_DIR) | $(MINIGZIP) > $(INSTALLED_DEBUG_RAMDISK_TARGET)
+	$(MKBOOTFS) -d $(TARGET_OUT) $(DEBUG_RAMDISK_ROOT_DIR) | $(COMPRESSION_COMMAND) > $(INSTALLED_DEBUG_RAMDISK_TARGET)
 
 my_debug_ramdisk_sync_dir :=
 my_debug_ramdisk_root_dir :=
@@ -2363,13 +2419,13 @@
 INTERNAL_AVB_BOOT_TEST_SIGNING_ARGS := --algorithm SHA256_RSA2048 --key $(BOARD_AVB_BOOT_TEST_KEY_PATH)
 # $(1): the bootimage to sign
 define test-key-sign-bootimage
-$(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE)))
+$(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(call get-bootimage-partition-size,$(1),boot-debug)))
 $(AVBTOOL) add_hash_footer \
   --image $(1) \
-  --partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \
+  --partition_size $(call get-bootimage-partition-size,$(1),boot-debug)\
   --partition_name boot $(INTERNAL_AVB_BOOT_TEST_SIGNING_ARGS) \
   $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
-$(call assert-max-image-size,$(1),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+$(call assert-max-image-size,$(1),$(call get-bootimage-partition-size,$(1),boot-debug))
 endef
 
 # $(1): output file
@@ -2396,7 +2452,7 @@
 # -----------------------------------------------------------------
 # vendor debug ramdisk
 # Combines vendor ramdisk files and debug ramdisk files to build the vendor debug ramdisk.
-INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET := $(PRODUCT_OUT)/vendor-ramdisk-debug.cpio.gz
+INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET := $(PRODUCT_OUT)/vendor-ramdisk-debug.cpio$(RAMDISK_EXT)
 $(INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET): DEBUG_RAMDISK_FILES := $(INTERNAL_DEBUG_RAMDISK_FILES)
 $(INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET): VENDOR_RAMDISK_DIR := $(TARGET_VENDOR_RAMDISK_OUT)
 
@@ -2410,14 +2466,14 @@
 # $(PRODUCT_OUT)/vendor_debug_ramdisk.
 $(INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET): VENDOR_DEBUG_RAMDISK_DIR := $(PRODUCT_OUT)/vendor_debug_ramdisk
 $(INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET): $(INTERNAL_VENDOR_RAMDISK_TARGET) $(INSTALLED_DEBUG_RAMDISK_TARGET)
-$(INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_VENDOR_DEBUG_RAMDISK_FILES) | $(MINIGZIP)
+$(INSTALLED_VENDOR_DEBUG_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_VENDOR_DEBUG_RAMDISK_FILES) | $(COMPRESSION_COMMAND_DEPS)
 	$(call pretty,"Target vendor debug ram disk: $@")
 	mkdir -p $(TARGET_VENDOR_DEBUG_RAMDISK_OUT)
 	touch $(TARGET_VENDOR_DEBUG_RAMDISK_OUT)/force_debuggable
 	$(foreach debug_file,$(DEBUG_RAMDISK_FILES), \
 	  cp -f $(debug_file) $(subst $(PRODUCT_OUT)/debug_ramdisk,$(PRODUCT_OUT)/vendor_debug_ramdisk,$(debug_file)) &&) true
 	rsync -a $(VENDOR_RAMDISK_DIR)/ $(VENDOR_DEBUG_RAMDISK_DIR)
-	$(MKBOOTFS) -d $(TARGET_OUT) $(VENDOR_DEBUG_RAMDISK_DIR) | $(MINIGZIP) > $@
+	$(MKBOOTFS) -d $(TARGET_OUT) $(VENDOR_DEBUG_RAMDISK_DIR) | $(COMPRESSION_COMMAND) > $@
 
 INSTALLED_FILES_FILE_VENDOR_DEBUG_RAMDISK := $(PRODUCT_OUT)/installed-files-vendor-ramdisk-debug.txt
 INSTALLED_FILES_JSON_VENDOR_DEBUG_RAMDISK := $(INSTALLED_FILES_FILE_VENDOR_DEBUG_RAMDISK:.txt=.json)
@@ -2495,18 +2551,18 @@
 endef
 
 $(INSTALLED_TEST_HARNESS_RAMDISK_TARGET): $(INSTALLED_DEBUG_RAMDISK_TARGET)
-$(INSTALLED_TEST_HARNESS_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_TEST_HARNESS_RAMDISK_FILES) | $(MINIGZIP)
+$(INSTALLED_TEST_HARNESS_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_TEST_HARNESS_RAMDISK_FILES) | $(COMPRESSION_COMMAND_DEPS)
 	$(call pretty,"Target test harness ram disk: $@")
 	rsync -a $(TEST_HARNESS_RAMDISK_SYNC_DIR)/ $(TEST_HARNESS_RAMDISK_ROOT_DIR)
 	$(call append-test-harness-props,$(ADDITIONAL_TEST_HARNESS_PROPERTIES),$(TEST_HARNESS_PROP_TARGET))
-	$(MKBOOTFS) -d $(TARGET_OUT) $(TEST_HARNESS_RAMDISK_ROOT_DIR) | $(MINIGZIP) > $@
+	$(MKBOOTFS) -d $(TARGET_OUT) $(TEST_HARNESS_RAMDISK_ROOT_DIR) | $(COMPRESSION_COMMAND) > $@
 
 .PHONY: ramdisk_test_harness-nodeps
-ramdisk_test_harness-nodeps: $(MKBOOTFS) | $(MINIGZIP)
+ramdisk_test_harness-nodeps: $(MKBOOTFS) | $(COMPRESSION_COMMAND_DEPS)
 	echo "make $@: ignoring dependencies"
 	rsync -a $(TEST_HARNESS_RAMDISK_SYNC_DIR)/ $(TEST_HARNESS_RAMDISK_ROOT_DIR)
 	$(call append-test-harness-props,$(ADDITIONAL_TEST_HARNESS_PROPERTIES),$(TEST_HARNESS_PROP_TARGET))
-	$(MKBOOTFS) -d $(TARGET_OUT) $(TEST_HARNESS_RAMDISK_ROOT_DIR) | $(MINIGZIP) > $(INSTALLED_TEST_HARNESS_RAMDISK_TARGET)
+	$(MKBOOTFS) -d $(TARGET_OUT) $(TEST_HARNESS_RAMDISK_ROOT_DIR) | $(COMPRESSION_COMMAND) > $(INSTALLED_TEST_HARNESS_RAMDISK_TARGET)
 
 endif # BUILDING_RAMDISK_IMAGE
 
@@ -3301,6 +3357,41 @@
 endef
 
 # -----------------------------------------------------------------
+# custom images
+INSTALLED_CUSTOMIMAGES_TARGET :=
+
+ifneq ($(strip $(BOARD_CUSTOMIMAGES_PARTITION_LIST)),)
+INTERNAL_AVB_CUSTOMIMAGES_SIGNING_ARGS :=
+
+# Sign custom image.
+# $(1): the prebuilt custom image.
+# $(2): the mount point of the prebuilt custom image.
+# $(3): the signed custom image target.
+define sign_custom_image
+$(3): $(1) $(INTERNAL_USERIMAGES_DEPS)
+	@echo Target custom image: $(3)
+	mkdir -p $(dir $(3))
+	cp $(1) $(3)
+ifeq ($(BOARD_AVB_ENABLE),true)
+	PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$$$PATH \
+          $(AVBTOOL) add_hashtree_footer \
+          --image $(3) \
+          --key $(BOARD_AVB_$(call to-upper,$(2))_KEY_PATH) \
+          --algorithm $(BOARD_AVB_$(call to-upper,$(2))_ALGORITHM) \
+          --partition_size $(BOARD_AVB_$(call to-upper,$(2))_PARTITION_SIZE) \
+          --partition_name $(2) \
+          $(INTERNAL_AVB_CUSTOMIMAGES_SIGNING_ARGS) \
+          $(BOARD_AVB_$(call to-upper,$(2))_ADD_HASHTREE_FOOTER_ARGS)
+endif
+INSTALLED_CUSTOMIMAGES_TARGET += $(3)
+endef
+
+$(foreach partition,$(BOARD_CUSTOMIMAGES_PARTITION_LIST), \
+  $(foreach image,$(BOARD_AVB_$(call to-upper,$(partition))_IMAGE_LIST), \
+     $(eval $(call sign_custom_image,$(image),$(partition),$(PRODUCT_OUT)/$(notdir $(image))))))
+endif
+
+# -----------------------------------------------------------------
 # vbmeta image
 ifeq ($(BOARD_AVB_ENABLE),true)
 
@@ -3459,6 +3550,9 @@
 # configured as a chained partition, if BOARD_AVB_<partition>_KEY_PATH is defined. Otherwise the
 # image descriptor will be included into vbmeta.img, unless it has been already added to any chained
 # VBMeta image.
+# Multiple boot images can be generated based on BOARD_KERNEL_BINARIES
+# but vbmeta would capture the image descriptor of only the first boot
+# image specified in BUILT_BOOTIMAGE_TARGET.
 # $(1): Partition name, e.g. boot or system.
 define check-and-set-avb-args
 $(eval _in_chained_vbmeta := $(filter $(1),$(INTERNAL_AVB_PARTITIONS_IN_CHAINED_VBMETA_IMAGES)))
@@ -3467,17 +3561,28 @@
         $(error Chaining partition "$(1)" in chained VBMeta image is not supported)) \
     $(call _check-and-set-avb-chain-args,$(1)),\
     $(if $(_in_chained_vbmeta),,\
-        $(eval INTERNAL_AVB_MAKE_VBMETA_IMAGE_ARGS += \
-            --include_descriptors_from_image $(call images-for-partitions,$(1)))))
+        $(if $(filter boot,$(1)),\
+            $(eval INTERNAL_AVB_MAKE_VBMETA_IMAGE_ARGS += \
+                --include_descriptors_from_image $(firstword $(call images-for-partitions,$(1)))),\
+            $(eval INTERNAL_AVB_MAKE_VBMETA_IMAGE_ARGS += \
+                --include_descriptors_from_image $(call images-for-partitions,$(1))))))
+endef
+
+# Checks and sets build variables for a custom chained partition to include it into vbmeta.img.
+# $(1): the custom partition to enable AVB chain.
+define check-and-set-custom-avb-chain-args
+$(eval part := $(1))
+$(eval PART=$(call to-upper,$(part)))
+$(eval _rollback_index_location := BOARD_AVB_$(PART)_ROLLBACK_INDEX_LOCATION)
+$(if $($(_rollback_index_location)),,$(error $(_rollback_index_location) is not defined))
+
+INTERNAL_AVB_MAKE_VBMETA_IMAGE_ARGS += \
+    --chain_partition $(part):$($(_rollback_index_location)):$(AVB_CHAIN_KEY_DIR)/$(part).avbpubkey
 endef
 
 ifdef INSTALLED_BOOTIMAGE_TARGET
-# multiple hashes for an image are not yet supported, fortunately this
-# only arises for GKI where the boot descriptor can be left out
-ifeq ($(strip $(BOARD_KERNEL_BINARIES)),)
 $(eval $(call check-and-set-avb-args,boot))
 endif
-endif
 
 ifdef INSTALLED_VENDOR_BOOTIMAGE_TARGET
 $(eval $(call check-and-set-avb-args,vendor_boot))
@@ -3518,6 +3623,11 @@
 $(eval $(call check-and-set-avb-args,vbmeta_vendor))
 endif
 
+ifneq ($(strip $(BOARD_CUSTOMIMAGES_PARTITION_LIST)),)
+$(foreach partition,$(BOARD_CUSTOMIMAGES_PARTITION_LIST), \
+    $(eval $(call check-and-set-custom-avb-chain-args,$(partition))))
+endif
+
 # Add kernel cmdline descriptor for kernel to mount system.img as root with
 # dm-verity. This works when system.img is either chained or not-chained:
 # - chained: The --setup_as_rootfs_from_kernel option will add dm-verity kernel
@@ -3588,6 +3698,10 @@
   $(if $(BOARD_AVB_VBMETA_VENDOR_KEY_PATH),\
     $(hide) $(AVBTOOL) extract_public_key --key $(BOARD_AVB_VBMETA_VENDOR_KEY_PATH) \
         --output $(1)/vbmeta_vendor.avbpubkey)
+  $(if $(BOARD_CUSTOMIMAGES_PARTITION_LIST),\
+    $(hide) $(foreach partition,$(BOARD_CUSTOMIMAGES_PARTITION_LIST), \
+        $(AVBTOOL) extract_public_key --key $(BOARD_AVB_$(call to-upper,$(partition))_KEY_PATH) \
+            --output $(1)/$(partition).avbpubkey;))
 endef
 
 # Builds a chained VBMeta image. This VBMeta image will contain the descriptors for the partitions
@@ -3655,6 +3769,7 @@
 	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
 	    $(INSTALLED_DTBOIMAGE_TARGET) \
+	    $(INSTALLED_CUSTOMIMAGES_TARGET) \
 	    $(INSTALLED_RECOVERYIMAGE_TARGET) \
 	    $(INSTALLED_VBMETA_SYSTEMIMAGE_TARGET) \
 	    $(INSTALLED_VBMETA_VENDORIMAGE_TARGET) \
@@ -3976,6 +4091,7 @@
 INTERNAL_OTATOOLS_MODULES := \
   aapt2 \
   add_img_to_target_files \
+  apksigner \
   append2simg \
   avbtool \
   blk_alloc_to_base_fs \
@@ -4005,6 +4121,7 @@
   libconscrypt_openjdk_jni \
   lpmake \
   lpunpack \
+  lz4 \
   make_f2fs \
   merge_target_files \
   minigzip \
@@ -4119,6 +4236,11 @@
 endif
 .KATI_READONLY := tool_extensions
 
+# $1: boot image file name
+define misc_boot_size
+$(subst .img,_size,$(1))=$(BOARD_KERNEL$(call to-upper,$(subst boot,,$(subst .img,,$(1))))_BOOTIMAGE_PARTITION_SIZE)
+endef
+
 $(INSTALLED_MISC_INFO_TARGET):
 	rm -f $@
 	$(call pretty,"Target misc_info.txt: $@")
@@ -4127,14 +4249,18 @@
 ifdef BOARD_FLASH_BLOCK_SIZE
 	$(hide) echo "blocksize=$(BOARD_FLASH_BLOCK_SIZE)" >> $@
 endif
-ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
-	$(hide) echo "boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)" >> $@
+ifneq ($(strip $(BOARD_BOOTIMAGE_PARTITION_SIZE))$(strip $(BOARD_KERNEL_BINARIES)),)
+	$(foreach b,$(INSTALLED_BOOTIMAGE_TARGET),\
+		echo "$(call misc_boot_size,$(notdir $(b)))" >> $@;)
 endif
 ifeq ($(INSTALLED_BOOTIMAGE_TARGET),)
 	$(hide) echo "no_boot=true" >> $@
 else
 	echo "boot_images=$(foreach b,$(INSTALLED_BOOTIMAGE_TARGET),$(notdir $(b)))" >> $@
 endif
+ifeq ($(BOARD_RAMDISK_USE_LZ4),true)
+	echo "lz4_ramdisks=true" >> $@
+endif
 ifneq ($(INSTALLED_VENDOR_BOOTIMAGE_TARGET),)
 	echo "vendor_boot=true" >> $@
 	echo "vendor_boot_size=$(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE)" >> $@
@@ -4207,6 +4333,16 @@
 	$(hide) echo "avb_recovery_algorithm=$(BOARD_AVB_RECOVERY_ALGORITHM)" >> $@
 	$(hide) echo "avb_recovery_rollback_index_location=$(BOARD_AVB_RECOVERY_ROLLBACK_INDEX_LOCATION)" >> $@
 endif # BOARD_AVB_RECOVERY_KEY_PATH
+ifneq (,$(strip $(BOARD_CUSTOMIMAGES_PARTITION_LIST)))
+	$(hide) echo "avb_custom_images_partition_list=$(BOARD_CUSTOMIMAGES_PARTITION_LIST)" >> $@
+	$(hide) $(foreach partition,$(BOARD_CUSTOMIMAGES_PARTITION_LIST), \
+	    echo "avb_$(partition)_key_path=$(BOARD_AVB_$(call to-upper,$(partition))_KEY_PATH)"  >> $@; \
+	    echo "avb_$(partition)_algorithm=$(BOARD_AVB_$(call to-upper,$(partition))_ALGORITHM)"  >> $@; \
+	    echo "avb_$(partition)_add_hashtree_footer_args=$(BOARD_AVB_$(call to-upper,$(partition))_ADD_HASHTREE_FOOTER_ARGS)"  >> $@; \
+	    echo "avb_$(partition)_rollback_index_location=$(BOARD_AVB_$(call to-upper,$(partition))_ROLLBACK_INDEX_LOCATION)"  >> $@; \
+	    echo "avb_$(partition)_partition_size=$(BOARD_AVB_$(call to-upper,$(partition))_PARTITION_SIZE)"  >> $@; \
+	    echo "avb_$(partition)_image_list=$(foreach image,$(BOARD_AVB_$(call to-upper,$(partition))_IMAGE_LIST),$(notdir $(image)))" >> $@;)
+endif # BOARD_CUSTOMIMAGES_PARTITION_LIST
 ifneq (,$(strip $(BOARD_AVB_VBMETA_SYSTEM)))
 	$(hide) echo "avb_vbmeta_system=$(BOARD_AVB_VBMETA_SYSTEM)" >> $@
 	$(hide) echo "avb_vbmeta_system_args=$(BOARD_AVB_MAKE_VBMETA_SYSTEM_IMAGE_ARGS)" >> $@
@@ -4440,6 +4576,7 @@
 	    $(INSTALLED_VBMETAIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
 	    $(INSTALLED_DTBOIMAGE_TARGET) \
+	    $(INSTALLED_CUSTOMIMAGES_TARGET) \
 	    $(INTERNAL_SYSTEMOTHERIMAGE_FILES) \
 	    $(INSTALLED_ANDROID_INFO_TXT_TARGET) \
 	    $(INSTALLED_KERNEL_TARGET) \
@@ -4684,6 +4821,11 @@
 	$(hide) mkdir -p $(zip_root)/PREBUILT_IMAGES
 	$(hide) cp $(INSTALLED_DTBOIMAGE_TARGET) $(zip_root)/PREBUILT_IMAGES/
 endif # BOARD_PREBUILT_DTBOIMAGE
+ifneq ($(strip $(BOARD_CUSTOMIMAGES_PARTITION_LIST)),)
+	$(hide) mkdir -p $(zip_root)/PREBUILT_IMAGES
+	$(hide) $(foreach partition,$(BOARD_CUSTOMIMAGES_PARTITION_LIST), \
+	    $(foreach image,$(BOARD_AVB_$(call to-upper,$(partition))_IMAGE_LIST),cp $(image) $(zip_root)/PREBUILT_IMAGES/;))
+endif # BOARD_CUSTOMIMAGES_PARTITION_LIST
 	@# The radio images in BOARD_PACK_RADIOIMAGES will be additionally copied from RADIO/ into
 	@# IMAGES/, which then will be added into <product>-img.zip. Such images must be listed in
 	@# INSTALLED_RADIOIMAGE_TARGET.
diff --git a/core/app_certificate_validate.mk b/core/app_certificate_validate.mk
index c01526a..1ccacfb 100644
--- a/core/app_certificate_validate.mk
+++ b/core/app_certificate_validate.mk
@@ -3,7 +3,7 @@
   ifneq (,$(filter $(dir $(DEFAULT_SYSTEM_DEV_CERTIFICATE))%,$(LOCAL_CERTIFICATE)))
     CERTIFICATE_VIOLATION_MODULES += $(LOCAL_MODULE)
     ifeq (true,$(PRODUCT_ENFORCE_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT))
-      $(if $(filter $(LOCAL_MODULE),$(PRODUCT_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT_WHITELIST)),,\
+      $(if $(filter $(LOCAL_MODULE),$(PRODUCT_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT_ALLOW_LIST)),,\
         $(call pretty-error,The module in product partition cannot be signed with certificate in system.))
     endif
   endif
diff --git a/core/base_rules.mk b/core/base_rules.mk
index 15d7a0e..e608ee7 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -183,11 +183,10 @@
 # file, tag the module as "gnu".  Search for "*_GPL*", "*_LGPL*" and "*_MPL*"
 # so that we can also find files like MODULE_LICENSE_GPL_AND_AFL
 #
-license_files := $(call find-parent-file,$(LOCAL_PATH),MODULE_LICENSE*)
 gpl_license_file := $(call find-parent-file,$(LOCAL_PATH),MODULE_LICENSE*_GPL* MODULE_LICENSE*_MPL* MODULE_LICENSE*_LGPL*)
 ifneq ($(gpl_license_file),)
   my_module_tags += gnu
-  ALL_GPL_MODULE_LICENSE_FILES := $(sort $(ALL_GPL_MODULE_LICENSE_FILES) $(gpl_license_file))
+  ALL_GPL_MODULE_LICENSE_FILES += $(gpl_license_file)
 endif
 
 LOCAL_MODULE_CLASS := $(strip $(LOCAL_MODULE_CLASS))
@@ -327,9 +326,19 @@
 endif
 $(module_id) := $(LOCAL_PATH)
 
-intermediates := $(call local-intermediates-dir,,$(LOCAL_2ND_ARCH_VAR_PREFIX),$(my_host_cross))
-intermediates.COMMON := $(call local-intermediates-dir,COMMON)
-generated_sources_dir := $(call local-generated-sources-dir)
+# These are the same as local-intermediates-dir / local-generated-sources dir, but faster
+intermediates.COMMON := $($(my_prefix)OUT_COMMON_INTERMEDIATES)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates
+ifneq (,$(filter $(my_prefix)$(LOCAL_MODULE_CLASS),$(COMMON_MODULE_CLASSES)))
+  intermediates := $($(my_prefix)OUT_COMMON_INTERMEDIATES)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates
+  generated_sources_dir := $($(my_prefix)OUT_COMMON_GEN)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates
+else
+  ifneq (,$(filter $(LOCAL_MODULE_CLASS),$(PER_ARCH_MODULE_CLASSES)))
+    intermediates := $($(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)OUT_INTERMEDIATES)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates
+  else
+    intermediates := $($(my_prefix)OUT_INTERMEDIATES)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates
+  endif
+  generated_sources_dir := $($(my_prefix)OUT_GEN)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates
+endif
 
 ifneq ($(LOCAL_OVERRIDES_MODULES),)
   ifndef LOCAL_IS_HOST_MODULE
@@ -574,17 +583,35 @@
 ifneq ($(strip $(LOCAL_TEST_DATA)),)
 ifneq (true,$(LOCAL_UNINSTALLABLE_MODULE))
 
-my_test_data_pairs := $(strip $(foreach td,$(LOCAL_TEST_DATA), \
-    $(eval _file := $(call word-colon,2,$(td))) \
-    $(if $(_file), \
-      $(eval _src_base := $(call word-colon,1,$(td))), \
-      $(eval _src_base := $(LOCAL_PATH)) \
-        $(eval _file := $(call word-colon,1,$(td)))) \
-    $(if $(call streq,$(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK)),, \
-      $(if $(findstring ..,$(_file)),$(error $(LOCAL_MODULE_MAKEFILE): LOCAL_TEST_DATA may not include '..': $(_file))) \
-      $(if $(filter /%,$(_src_base) $(_file)),$(error $(LOCAL_MODULE_MAKEFILE): LOCAL_TEST_DATA may not include absolute paths: $(_src_base) $(_file)))) \
-    $(eval my_test_data_file_pairs := $(my_test_data_file_pairs) $(call append-path,$(_src_base),$(_file)):$(_file)) \
-    $(call append-path,$(_src_base),$(_file)):$(call append-path,$(my_module_path),$(_file))))
+ifeq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
+  define copy_test_data_pairs
+    _src_base := $$(call word-colon,1,$$(td))
+    _file := $$(call word-colon,2,$$(td))
+    my_test_data_pairs += $$(call append-path,$$(_src_base),$$(_file)):$$(call append-path,$$(my_module_path),$$(_file))
+    my_test_data_file_pairs += $$(call append-path,$$(_src_base),$$(_file)):$$(_file)
+  endef
+else
+  define copy_test_data_pairs
+    _src_base := $$(call word-colon,1,$$(td))
+    _file := $$(call word-colon,2,$$(td))
+    ifndef _file
+      _file := $$(_src_base)
+      _src_base := $$(LOCAL_PATH)
+    endif
+    ifneq (,$$(findstring ..,$$(_file)))
+      $$(call pretty-error,LOCAL_TEST_DATA may not include '..': $$(_file))
+    endif
+    ifneq (,$$(filter/%,$$(_src_base) $$(_file)))
+      $$(call pretty-error,LOCAL_TEST_DATA may not include absolute paths: $$(_src_base) $$(_file))
+    endif
+    my_test_data_pairs += $$(call append-path,$$(_src_base),$$(_file)):$$(call append-path,$$(my_module_path),$$(_file))
+    my_test_data_file_pairs += $$(call append-path,$$(_src_base),$$(_file)):$$(_file)
+  endef
+endif
+
+$(foreach td,$(LOCAL_TEST_DATA),$(eval $(copy_test_data_pairs)))
+
+copy_test_data_pairs :=
 
 my_installed_test_data := $(call copy-many-files,$(my_test_data_pairs))
 $(LOCAL_INSTALLED_MODULE): $(my_installed_test_data)
@@ -912,7 +939,7 @@
 # Track module-level dependencies.
 # Use $(LOCAL_MODULE) instead of $(my_register_name) to ignore module's bitness.
 ifneq (,$(filter deps-license,$(MAKECMDGOALS)))
-ALL_DEPS.MODULES := $(ALL_DEPS.MODULES) $(LOCAL_MODULE)
+ALL_DEPS.MODULES += $(LOCAL_MODULE)
 ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS := $(sort \
   $(ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS) \
   $(LOCAL_STATIC_LIBRARIES) \
@@ -926,6 +953,7 @@
   $(LOCAL_JAVA_LIBRARIES) \
   $(LOCAL_JNI_SHARED_LIBRARIES))
 
+license_files := $(call find-parent-file,$(LOCAL_PATH),MODULE_LICENSE*)
 ALL_DEPS.$(LOCAL_MODULE).LICENSE := $(sort $(ALL_DEPS.$(LOCAL_MODULE).LICENSE) $(license_files))
 endif
 
diff --git a/core/binary.mk b/core/binary.mk
index 75f4874..7ee8c5c 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -84,7 +84,7 @@
   my_native_coverage := false
 endif
 
-# Exclude directories from manual binder interface whitelisting.
+# Exclude directories from checking allowed manual binder interface lists.
 # TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths.
 ifneq (,$(filter $(addsuffix %,$(ALLOWED_MANUAL_INTERFACE_PATHS)),$(LOCAL_PATH)))
   my_cflags += -DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES
@@ -1816,7 +1816,7 @@
      $(call intermediates-dir-for,HEADER_LIBRARIES,$(l),$(my_kind),,$(LOCAL_2ND_ARCH_VAR_PREFIX),$(my_host_cross))))
 
 ifneq ($(strip $(my_export_c_include_dirs)$(export_include_deps)),)
-  EXPORTS_LIST := $(EXPORTS_LIST) $(intermediates)
+  EXPORTS_LIST += $(intermediates)
   EXPORTS.$(intermediates).FLAGS := $(foreach d,$(my_export_c_include_dirs),-I $(call clean-path,$(d)))
   EXPORTS.$(intermediates).REEXPORT := $(export_include_deps)
   EXPORTS.$(intermediates).DEPS := $(my_export_c_include_deps) $(my_generated_sources) $(LOCAL_EXPORT_C_INCLUDE_DEPS)
diff --git a/core/cc_prebuilt_internal.mk b/core/cc_prebuilt_internal.mk
index 1d959b5..99b7d0f 100644
--- a/core/cc_prebuilt_internal.mk
+++ b/core/cc_prebuilt_internal.mk
@@ -75,7 +75,7 @@
   built_module := $(LOCAL_BUILT_MODULE)
 
 ifdef prebuilt_module_is_a_library
-EXPORTS_LIST := $(EXPORTS_LIST) $(intermediates)
+EXPORTS_LIST += $(intermediates)
 EXPORTS.$(intermediates).FLAGS := $(foreach d,$(LOCAL_EXPORT_C_INCLUDE_DIRS),-I $(d))
 EXPORTS.$(intermediates).DEPS := $(LOCAL_EXPORT_C_INCLUDE_DEPS)
 
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 0c613fa..b9f439f 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -21,6 +21,8 @@
 LOCAL_APIDIFF_NEWAPI:=
 LOCAL_APIDIFF_OLDAPI:=
 LOCAL_APK_LIBRARIES:=
+LOCAL_APK_SET_MASTER_FILE:=
+LOCAL_APKCERTS_FILE:=
 LOCAL_ARM_MODE:=
 LOCAL_ASFLAGS:=
 LOCAL_ASSET_DIR:=
diff --git a/core/config.mk b/core/config.mk
index 699202f..90eea5b 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -122,6 +122,8 @@
 $(KATI_obsolete_var MD5SUM)
 $(KATI_obsolete_var BOARD_HAL_STATIC_LIBRARIES, See $(CHANGES_URL)#BOARD_HAL_STATIC_LIBRARIES)
 $(KATI_obsolete_var LOCAL_HAL_STATIC_LIBRARIES, See $(CHANGES_URL)#BOARD_HAL_STATIC_LIBRARIES)
+$(KATI_obsolete_var PRODUCT_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT_WHITELIST,Use PRODUCT_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT_ALLOW_LIST.)
+$(KATI_obsolete_var PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST,Use PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST.)
 
 # Used to force goals to build.  Only use for conditionally defined goals.
 .PHONY: FORCE
@@ -599,6 +601,7 @@
 VTSC := $(HOST_OUT_EXECUTABLES)/vtsc$(HOST_EXECUTABLE_SUFFIX)
 MKBOOTFS := $(HOST_OUT_EXECUTABLES)/mkbootfs$(HOST_EXECUTABLE_SUFFIX)
 MINIGZIP := $(HOST_OUT_EXECUTABLES)/minigzip$(HOST_EXECUTABLE_SUFFIX)
+LZ4 := $(HOST_OUT_EXECUTABLES)/lz4$(HOST_EXECUTABLE_SUFFIX)
 ifeq (,$(strip $(BOARD_CUSTOM_MKBOOTIMG)))
 MKBOOTIMG := $(HOST_OUT_EXECUTABLES)/mkbootimg$(HOST_EXECUTABLE_SUFFIX)
 else
@@ -666,7 +669,7 @@
 
 APICHECK_COMMAND := $(JAVA) -Xmx4g -jar $(APICHECK) --no-banner --compatible-output=yes
 
-# Boolean variable determining if the whitelist for compatible properties is enabled
+# Boolean variable determining if the allow list for compatible properties is enabled
 PRODUCT_COMPATIBLE_PROPERTY := false
 ifneq ($(PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE),)
   PRODUCT_COMPATIBLE_PROPERTY := $(PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE)
diff --git a/core/definitions.mk b/core/definitions.mk
index 91a873b..89c2e27 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -111,6 +111,18 @@
 # All compatibility suites mentioned in LOCAL_COMPATIBILITY_SUITES
 ALL_COMPATIBILITY_SUITES :=
 
+# All LINK_TYPE entries
+ALL_LINK_TYPES :=
+
+# All exported/imported include entries
+EXPORTS_LIST :=
+
+# All modules already converted to Soong
+SOONG_ALREADY_CONV :=
+
+# ALL_DEPS.*.ALL_DEPS keys
+ALL_DEPS.MODULES :=
+
 ###########################################################
 ## Debugging; prints a variable list to stdout
 ###########################################################
@@ -556,7 +568,7 @@
         $(error $(LOCAL_PATH): Name not defined in call to intermediates-dir-for)) \
     $(eval _idfPrefix := $(call find-idf-prefix,$(3),$(6))) \
     $(eval _idf2ndArchPrefix := $(if $(strip $(5)),$(TARGET_2ND_ARCH_VAR_PREFIX))) \
-    $(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \
+    $(if $(filter $(_idfPrefix)_$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \
         $(eval _idfIntBase := $($(_idfPrefix)_OUT_COMMON_INTERMEDIATES)) \
       ,$(if $(filter $(_idfClass),$(PER_ARCH_MODULE_CLASSES)),\
           $(eval _idfIntBase := $($(_idf2ndArchPrefix)$(_idfPrefix)_OUT_INTERMEDIATES)) \
@@ -605,7 +617,7 @@
     $(if $(_idfName),, \
         $(error $(LOCAL_PATH): Name not defined in call to generated-sources-dir-for)) \
     $(eval _idfPrefix := $(call find-idf-prefix,$(3),)) \
-    $(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \
+    $(if $(filter $(_idfPrefix)_$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \
         $(eval _idfIntBase := $($(_idfPrefix)_OUT_COMMON_GEN)) \
       , \
         $(eval _idfIntBase := $($(_idfPrefix)_OUT_GEN)) \
@@ -2895,12 +2907,14 @@
 #    and use my_compat_dist_$(suite) to define the others.
 define create-suite-dependencies
 $(foreach suite, $(LOCAL_COMPATIBILITY_SUITE), \
-  $(if $(filter $(suite),$(ALL_COMPATIBILITY_SUITES)),,$(eval ALL_COMPATIBILITY_SUITES += $(suite))) \
-  $(eval COMPATIBILITY.$(suite).FILES := \
-    $$(COMPATIBILITY.$(suite).FILES) $$(foreach f,$$(my_compat_dist_$(suite)),$$(call word-colon,2,$$(f))) \
-      $$(foreach f,$$(my_compat_dist_config_$(suite)),$$(call word-colon,2,$$(f)))) \
-  $(eval COMPATIBILITY.$(suite).MODULES := \
-    $$(COMPATIBILITY.$(suite).MODULES) $$(my_register_name))) \
+  $(if $(filter $(suite),$(ALL_COMPATIBILITY_SUITES)),,\
+    $(eval ALL_COMPATIBILITY_SUITES += $(suite)) \
+    $(eval COMPATIBILITY.$(suite).FILES :=) \
+    $(eval COMPATIBILITY.$(suite).MODULES :=)) \
+  $(eval COMPATIBILITY.$(suite).FILES += \
+    $$(foreach f,$$(my_compat_dist_$(suite)),$$(call word-colon,2,$$(f))) \
+    $$(foreach f,$$(my_compat_dist_config_$(suite)),$$(call word-colon,2,$$(f)))) \
+  $(eval COMPATIBILITY.$(suite).MODULES += $$(my_register_name))) \
 $(eval $(my_all_targets) : $(call copy-many-files, \
   $(sort $(foreach suite,$(LOCAL_COMPATIBILITY_SUITE),$(my_compat_dist_$(suite))))) \
   $(call copy-many-xml-files-checked, \
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 862d874..f4650f9 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -856,7 +856,7 @@
   TARGET_INSTALLER_ROOT_OUT \
   TARGET_INSTALLER_SYSTEM_OUT
 
-COMMON_MODULE_CLASSES := TARGET-NOTICE_FILES HOST-NOTICE_FILES HOST-JAVA_LIBRARIES
+COMMON_MODULE_CLASSES := TARGET_NOTICE_FILES HOST_NOTICE_FILES HOST_JAVA_LIBRARIES
 PER_ARCH_MODULE_CLASSES := SHARED_LIBRARIES STATIC_LIBRARIES EXECUTABLES GYP RENDERSCRIPT_BITCODE NATIVE_TESTS HEADER_LIBRARIES RLIB_LIBRARIES DYLIB_LIBRARIES
 .KATI_READONLY := COMMON_MODULE_CLASSES PER_ARCH_MODULE_CLASSES
 
diff --git a/core/install_jni_libs_internal.mk b/core/install_jni_libs_internal.mk
index b482eb5..48c93de 100644
--- a/core/install_jni_libs_internal.mk
+++ b/core/install_jni_libs_internal.mk
@@ -124,17 +124,15 @@
     my_allowed_types := $(my_allowed_ndk_types) native:platform native:product native:vendor native:vndk native:vndk_private native:platform_vndk
   endif
 
-  ifneq (,$(LOCAL_SDK_VERSION))
-    ifeq ($(SOONG_ANDROID_MK),$(LOCAL_MODULE_MAKEFILE))
-      # SOONG_SDK_VARIANT_MODULES isn't complete yet while parsing Soong modules, and Soong has
-      # already ensured that apps link against the correct SDK variants, rewrite all JNI libraries
-      # to the SDK variant.
-      my_link_deps := $(addprefix SHARED_LIBRARIES:,$(addsuffix .sdk,$(LOCAL_JNI_SHARED_LIBRARIES)))
-    else
-      my_link_deps := $(addprefix SHARED_LIBRARIES:,$(call use_soong_sdk_libraries,$(LOCAL_JNI_SHARED_LIBRARIES)))
-    endif
+  ifeq ($(SOONG_ANDROID_MK),$(LOCAL_MODULE_MAKEFILE))
+    # SOONG_SDK_VARIANT_MODULES isn't complete yet while parsing Soong modules, and Soong has
+    # already ensured that apps link against the correct SDK variants, don't check them.
   else
-    my_link_deps := $(addprefix SHARED_LIBRARIES:,$(LOCAL_JNI_SHARED_LIBRARIES))
+    ifneq (,$(LOCAL_SDK_VERSION))
+      my_link_deps := $(addprefix SHARED_LIBRARIES:,$(call use_soong_sdk_libraries,$(LOCAL_JNI_SHARED_LIBRARIES)))
+    else
+      my_link_deps := $(addprefix SHARED_LIBRARIES:,$(LOCAL_JNI_SHARED_LIBRARIES))
+    endif
   endif
 
   my_common :=
diff --git a/core/instrumentation_test_config_template.xml b/core/instrumentation_test_config_template.xml
index 18ea676..6ca964e 100644
--- a/core/instrumentation_test_config_template.xml
+++ b/core/instrumentation_test_config_template.xml
@@ -17,6 +17,7 @@
 <configuration description="Runs {LABEL}.">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-instrumentation" />
+    {EXTRA_CONFIGS}
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="{MODULE}.apk" />
diff --git a/core/link_type.mk b/core/link_type.mk
index f7604ff..e8cfd2e 100644
--- a/core/link_type.mk
+++ b/core/link_type.mk
@@ -12,7 +12,7 @@
 
 my_link_prefix := LINK_TYPE:$(call find-idf-prefix,$(my_kind),$(my_host_cross))$(if $(filter AUX,$(my_kind)),-$(AUX_OS_VARIANT)):$(if $(my_common),$(my_common):_,_:$(if $(my_2nd_arch_prefix),$(my_2nd_arch_prefix),_))
 link_type := $(my_link_prefix):$(LOCAL_MODULE_CLASS):$(LOCAL_MODULE)
-ALL_LINK_TYPES := $(ALL_LINK_TYPES) $(link_type)
+ALL_LINK_TYPES += $(link_type)
 $(link_type).TYPE := $(my_link_type)
 $(link_type).MAKEFILE := $(LOCAL_MODULE_MAKEFILE)
 $(link_type).WARN := $(my_warn_types)
diff --git a/core/main.mk b/core/main.mk
index f8b06b9..9e1d6b7 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -206,8 +206,8 @@
 	variables like PRODUCT_SEPOLICY_SPLIT should be used until that is \
 	possible.)
 
-# Sets ro.actionable_compatible_property.enabled to know on runtime whether the whitelist
-# of actionable compatible properties is enabled or not.
+# Sets ro.actionable_compatible_property.enabled to know on runtime whether the
+# allowed list of actionable compatible properties is enabled or not.
 ifeq ($(PRODUCT_ACTIONABLE_COMPATIBLE_PROPERTY_DISABLE),true)
 ADDITIONAL_DEFAULT_PROPERTIES += ro.actionable_compatible_property.enabled=false
 else
@@ -426,7 +426,7 @@
 # Include all of the makefiles in the system
 #
 
-subdir_makefiles := $(SOONG_ANDROID_MK) $(file <$(OUT_DIR)/.module_paths/Android.mk.list)
+subdir_makefiles := $(SOONG_ANDROID_MK) $(file <$(OUT_DIR)/.module_paths/Android.mk.list) $(SOONG_OUT_DIR)/late-$(TARGET_PRODUCT).mk
 subdir_makefiles_total := $(words int $(subdir_makefiles) post finish)
 .KATI_READONLY := subdir_makefiles_total
 
@@ -1119,7 +1119,7 @@
   ifneq (true,$(ALLOW_MISSING_DEPENDENCIES))
     # Check to ensure that all modules in PRODUCT_PACKAGES exist (opt in per product)
     ifeq (true,$(PRODUCT_ENFORCE_PACKAGES_EXIST))
-      _whitelist := $(PRODUCT_ENFORCE_PACKAGES_EXIST_WHITELIST)
+      _allow_list := $(PRODUCT_ENFORCE_PACKAGES_EXIST_ALLOW_LIST)
       _modules := $(PRODUCT_PACKAGES)
       # Strip :32 and :64 suffixes
       _modules := $(patsubst %:32,%,$(_modules))
@@ -1129,10 +1129,10 @@
       _nonexistent_modules := $(filter-out $(ALL_MODULES),$(_modules))
       _nonexistent_modules := $(foreach m,$(_nonexistent_modules),\
         $(if $(call get-32-bit-modules,$(m)),,$(m)))
-      $(call maybe-print-list-and-error,$(filter-out $(_whitelist),$(_nonexistent_modules)),\
+      $(call maybe-print-list-and-error,$(filter-out $(_allow_list),$(_nonexistent_modules)),\
         $(INTERNAL_PRODUCT) includes non-existent modules in PRODUCT_PACKAGES)
-      $(call maybe-print-list-and-error,$(filter-out $(_nonexistent_modules),$(_whitelist)),\
-        $(INTERNAL_PRODUCT) includes redundant whitelist entries for nonexistent PRODUCT_PACKAGES)
+      $(call maybe-print-list-and-error,$(filter-out $(_nonexistent_modules),$(_allow_list)),\
+        $(INTERNAL_PRODUCT) includes redundant allow list entries for non-existent PRODUCT_PACKAGES)
     endif
 
     # Check to ensure that all modules in PRODUCT_HOST_PACKAGES exist
@@ -1174,21 +1174,21 @@
   is_asan := $(if $(filter address,$(SANITIZE_TARGET)),true)
   ifneq (true,$(or $(is_asan),$(DISABLE_ARTIFACT_PATH_REQUIREMENTS)))
   # Fakes don't get installed, and NDK stubs aren't installed to device.
-  static_whitelist_patterns := $(TARGET_OUT_FAKE)/% $(SOONG_OUT_DIR)/ndk/%
+  static_allowed_patterns := $(TARGET_OUT_FAKE)/% $(SOONG_OUT_DIR)/ndk/%
   # RROs become REQUIRED by the source module, but are always placed on the vendor partition.
-  static_whitelist_patterns += %__auto_generated_rro_product.apk
-  static_whitelist_patterns += %__auto_generated_rro_vendor.apk
+  static_allowed_patterns += %__auto_generated_rro_product.apk
+  static_allowed_patterns += %__auto_generated_rro_vendor.apk
   # Auto-included targets are not considered
-  static_whitelist_patterns += $(call product-installed-files,)
+  static_allowed_patterns += $(call product-installed-files,)
   # $(PRODUCT_OUT)/apex is where shared libraries in APEXes get installed.
   # The path can be considered as a fake path, as the shared libraries
   # are installed there just to have symbols files for them under
   # $(PRODUCT_OUT)/symbols/apex for debugging purpose. The /apex directory
   # is never compiled into a filesystem image.
-  static_whitelist_patterns += $(PRODUCT_OUT)/apex/%
+  static_allowed_patterns += $(PRODUCT_OUT)/apex/%
   ifeq (true,$(BOARD_USES_SYSTEM_OTHER_ODEX))
     # Allow system_other odex space optimization.
-    static_whitelist_patterns += \
+    static_allowed_patterns += \
       $(TARGET_OUT_SYSTEM_OTHER)/%.odex \
       $(TARGET_OUT_SYSTEM_OTHER)/%.vdex \
       $(TARGET_OUT_SYSTEM_OTHER)/%.art
@@ -1204,31 +1204,31 @@
   $(foreach makefile,$(ARTIFACT_PATH_REQUIREMENT_PRODUCTS),\
     $(eval requirements := $(PRODUCTS.$(makefile).ARTIFACT_PATH_REQUIREMENTS)) \
     $(eval ### Verify that the product only produces files inside its path requirements.) \
-    $(eval whitelist := $(PRODUCTS.$(makefile).ARTIFACT_PATH_WHITELIST)) \
+    $(eval allowed := $(PRODUCTS.$(makefile).ARTIFACT_PATH_ALLOWED_LIST)) \
     $(eval path_patterns := $(call resolve-product-relative-paths,$(requirements),%)) \
-    $(eval whitelist_patterns := $(call resolve-product-relative-paths,$(whitelist))) \
+    $(eval allowed_patterns := $(call resolve-product-relative-paths,$(allowed))) \
     $(eval files := $(call product-installed-files, $(makefile))) \
-    $(eval offending_files := $(filter-out $(path_patterns) $(whitelist_patterns) $(static_whitelist_patterns),$(files))) \
+    $(eval offending_files := $(filter-out $(path_patterns) $(allowed_patterns) $(static_allowed_patterns),$(files))) \
     $(call maybe-print-list-and-error,$(offending_files),\
       $(makefile) produces files outside its artifact path requirement. \
       Allowed paths are $(subst $(space),$(comma)$(space),$(addsuffix *,$(requirements)))) \
-    $(eval unused_whitelist := $(filter-out $(files),$(whitelist_patterns))) \
-    $(call maybe-print-list-and-error,$(unused_whitelist),$(makefile) includes redundant whitelist entries in its artifact path requirement.) \
+    $(eval unused_allowed := $(filter-out $(files),$(allowed_patterns))) \
+    $(call maybe-print-list-and-error,$(unused_allowed),$(makefile) includes redundant allowed entries in its artifact path requirement.) \
     $(eval ### Optionally verify that nothing else produces files inside this artifact path requirement.) \
     $(eval extra_files := $(filter-out $(files) $(HOST_OUT)/%,$(product_target_FILES))) \
     $(eval files_in_requirement := $(filter $(path_patterns),$(extra_files))) \
     $(eval all_offending_files += $(files_in_requirement)) \
-    $(eval whitelist := $(PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST)) \
-    $(eval whitelist_patterns := $(call resolve-product-relative-paths,$(whitelist))) \
-    $(eval offending_files := $(filter-out $(whitelist_patterns),$(files_in_requirement))) \
+    $(eval allowed := $(PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST)) \
+    $(eval allowed_patterns := $(call resolve-product-relative-paths,$(allowed))) \
+    $(eval offending_files := $(filter-out $(allowed_patterns),$(files_in_requirement))) \
     $(eval enforcement := $(PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS)) \
     $(if $(enforcement),\
       $(call maybe-print-list-and-error,$(offending_files),\
         $(INTERNAL_PRODUCT) produces files inside $(makefile)s artifact path requirement. \
         $(PRODUCT_ARTIFACT_PATH_REQUIREMENT_HINT)) \
-      $(eval unused_whitelist := $(if $(filter true strict,$(enforcement)),\
-        $(foreach p,$(whitelist_patterns),$(if $(filter $(p),$(extra_files)),,$(p))))) \
-      $(call maybe-print-list-and-error,$(unused_whitelist),$(INTERNAL_PRODUCT) includes redundant artifact path requirement whitelist entries.) \
+      $(eval unused_allowed := $(if $(filter true strict,$(enforcement)),\
+        $(foreach p,$(allowed_patterns),$(if $(filter $(p),$(extra_files)),,$(p))))) \
+      $(call maybe-print-list-and-error,$(unused_allowed),$(INTERNAL_PRODUCT) includes redundant artifact path requirement allowed list entries.) \
     ) \
   )
 $(PRODUCT_OUT)/offending_artifacts.txt:
diff --git a/core/product.mk b/core/product.mk
index 0aa07ef..f8ba593 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -326,14 +326,14 @@
 # partitions uses PLATFORM_VNDK_VERSION.
 _product_single_value_var += PRODUCT_PRODUCT_VNDK_VERSION
 
-# Whether the whitelist of actionable compatible properties should be disabled or not
+# Whether the list of allowed of actionable compatible properties should be disabled or not
 _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_SYSTEM_CERTIFICATE_REQUIREMENT_ALLOW_LIST
 _product_list_vars += PRODUCT_ARTIFACT_PATH_REQUIREMENT_HINT
-_product_list_vars += PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST
+_product_list_vars += PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
 
 # List of modules that should be forcefully unmarked from being LOCAL_PRODUCT_MODULE, and hence
 # installed on /system directory by default.
@@ -453,19 +453,19 @@
 define require-artifacts-in-path
   $(eval current_mk := $(strip $(word 1,$(_include_stack)))) \
   $(eval PRODUCTS.$(current_mk).ARTIFACT_PATH_REQUIREMENTS := $(strip $(1))) \
-  $(eval PRODUCTS.$(current_mk).ARTIFACT_PATH_WHITELIST := $(strip $(2))) \
+  $(eval PRODUCTS.$(current_mk).ARTIFACT_PATH_ALLOWED_LIST := $(strip $(2))) \
   $(eval ARTIFACT_PATH_REQUIREMENT_PRODUCTS := \
     $(sort $(ARTIFACT_PATH_REQUIREMENT_PRODUCTS) $(current_mk)))
 endef
 
-# Makes including non-existant modules in PRODUCT_PACKAGES an error.
-# $(1): whitelist of non-existant modules to allow.
+# Makes including non-existent modules in PRODUCT_PACKAGES an error.
+# $(1): list of non-existent modules to allow.
 define enforce-product-packages-exist
   $(eval current_mk := $(strip $(word 1,$(_include_stack)))) \
   $(eval PRODUCTS.$(current_mk).PRODUCT_ENFORCE_PACKAGES_EXIST := true) \
-  $(eval PRODUCTS.$(current_mk).PRODUCT_ENFORCE_PACKAGES_EXIST_WHITELIST := $(1)) \
+  $(eval PRODUCTS.$(current_mk).PRODUCT_ENFORCE_PACKAGES_EXIST_ALLOW_LIST := $(1)) \
   $(eval .KATI_READONLY := PRODUCTS.$(current_mk).PRODUCT_ENFORCE_PACKAGES_EXIST) \
-  $(eval .KATI_READONLY := PRODUCTS.$(current_mk).PRODUCT_ENFORCE_PACKAGES_EXIST_WHITELIST)
+  $(eval .KATI_READONLY := PRODUCTS.$(current_mk).PRODUCT_ENFORCE_PACKAGES_EXIST_ALLOW_LIST)
 endef
 
 #
@@ -587,7 +587,7 @@
 $(foreach v,\
   $(_product_var_list) \
     PRODUCT_ENFORCE_PACKAGES_EXIST \
-    PRODUCT_ENFORCE_PACKAGES_EXIST_WHITELIST, \
+    PRODUCT_ENFORCE_PACKAGES_EXIST_ALLOW_LIST, \
   $(eval $(v) := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).$(v)))) \
   $(eval get-product-var = $$(if $$(filter $$(1),$$(INTERNAL_PRODUCT)),$$($$(2)),$$(PRODUCTS.$$(strip $$(1)).$$(2)))) \
   $(KATI_obsolete_var PRODUCTS.$(INTERNAL_PRODUCT).$(v),Use $(v) instead) \
diff --git a/core/product_config.mk b/core/product_config.mk
index 699d62a..a16af05 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -278,7 +278,7 @@
 )
 
 ENFORCE_SYSTEM_CERTIFICATE := $(PRODUCT_ENFORCE_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT)
-ENFORCE_SYSTEM_CERTIFICATE_WHITELIST := $(PRODUCT_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT_WHITELIST)
+ENFORCE_SYSTEM_CERTIFICATE_ALLOW_LIST := $(PRODUCT_ARTIFACT_SYSTEM_CERTIFICATE_REQUIREMENT_ALLOW_LIST)
 
 PRODUCT_OTA_PUBLIC_KEYS := $(sort $(PRODUCT_OTA_PUBLIC_KEYS))
 PRODUCT_EXTRA_RECOVERY_KEYS := $(sort $(PRODUCT_EXTRA_RECOVERY_KEYS))
diff --git a/core/sdk_check.mk b/core/sdk_check.mk
index c09fc7c..09fd0eb 100644
--- a/core/sdk_check.mk
+++ b/core/sdk_check.mk
@@ -6,7 +6,7 @@
 # be set to a particular module class to enable warnings and errors for that
 # subtype.
 
-whitelisted_modules := framework-res__auto_generated_rro
+allowed_modules := framework-res__auto_generated_rro
 
 
 ifeq (,$(JAVA_SDK_ENFORCEMENT_ERROR))
@@ -14,7 +14,7 @@
 endif
 
 ifeq ($(LOCAL_SDK_VERSION)$(LOCAL_PRIVATE_PLATFORM_APIS),)
-  ifeq (,$(filter $(LOCAL_MODULE),$(whitelisted_modules)))
+  ifeq (,$(filter $(LOCAL_MODULE),$(allowed_modules)))
     ifneq ($(JAVA_SDK_ENFORCEMENT_WARNING)$(JAVA_SDK_ENFORCEMENT_ERROR),)
       my_message := Must specify LOCAL_SDK_VERSION or LOCAL_PRIVATE_PLATFORM_APIS,
       ifeq ($(LOCAL_MODULE_CLASS),$(JAVA_SDK_ENFORCEMENT_ERROR))
diff --git a/core/shell_test_config_template.xml b/core/shell_test_config_template.xml
new file mode 100644
index 0000000..5e1c8ee
--- /dev/null
+++ b/core/shell_test_config_template.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- This test config file is auto-generated. -->
+<configuration description="Config for running {MODULE} through Atest or in Infra">
+    <option name="test-suite-tag" value="{MODULE}" />
+
+    {EXTRA_CONFIGS}
+
+    <!-- This test requires a device, so it's not annotated with a null-device. -->
+    <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
+        <option name="binary" value="{OUTPUT_FILENAME}" />
+        <!-- Test script assumes a relative path with the tests/ folders. -->
+        <option name="relative-path-execution" value="true" />
+        <!-- Tests shouldn't be that long but set 15m to be safe. -->
+        <option name="per-binary-timeout" value="15m" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/core/soong_android_app_set.mk b/core/soong_android_app_set.mk
new file mode 100644
index 0000000..c884894
--- /dev/null
+++ b/core/soong_android_app_set.mk
@@ -0,0 +1,39 @@
+# App prebuilt coming from Soong.
+# Extra inputs:
+# LOCAL_APK_SET_MASTER_FILE
+
+ifneq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
+  $(call pretty-error,soong_apk_set.mk may only be used from Soong)
+endif
+
+LOCAL_BUILT_MODULE_STEM := $(LOCAL_APK_SET_MASTER_FILE)
+LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_APK_SET_MASTER_FILE)
+
+#######################################
+include $(BUILD_SYSTEM)/base_rules.mk
+#######################################
+
+## Extract master APK from APK set into given directory
+# $(1) APK set
+# $(2) master APK entry (e.g., splits/base-master.apk
+
+define extract-master-from-apk-set
+$(LOCAL_BUILT_MODULE): $(1)
+	@echo "Extracting $$@"
+	unzip -pq $$< $(2) >$$@
+endef
+
+$(eval $(call extract-master-from-apk-set,$(LOCAL_PREBUILT_MODULE_FILE),$(LOCAL_APK_SET_MASTER_FILE)))
+# unzip returns 11 it there was nothing to extract, which is expected,
+# $(LOCAL_APK_SET_MASTER_FILE) has is already there.
+LOCAL_POST_INSTALL_CMD := unzip -qo -j -d $(dir $(LOCAL_INSTALLED_MODULE)) \
+	$(LOCAL_PREBUILT_MODULE_FILE) -x $(LOCAL_APK_SET_MASTER_FILE) || [[ $$? -eq 11 ]]
+$(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD := $(LOCAL_POST_INSTALL_CMD)
+PACKAGES.$(LOCAL_MODULE).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))
+
+PACKAGES := $(PACKAGES) $(LOCAL_MODULE)
+# We can't know exactly what apk files would be outputted yet.
+# Let extract_apks generate apkcerts.txt and merge it later.
+PACKAGES.$(LOCAL_MODULE).APKCERTS_FILE := $(LOCAL_APKCERTS_FILE)
+
+SOONG_ALREADY_CONV += $(LOCAL_MODULE)
diff --git a/core/soong_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index 4197c58..01e9800 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -218,4 +218,4 @@
   $(LOCAL_INSTALLED_MODULE): $(my_coverage_files)
 endif
 
-SOONG_ALREADY_CONV := $(SOONG_ALREADY_CONV) $(LOCAL_MODULE)
+SOONG_ALREADY_CONV += $(LOCAL_MODULE)
diff --git a/core/soong_cc_prebuilt.mk b/core/soong_cc_prebuilt.mk
index 7853890..51549bd 100644
--- a/core/soong_cc_prebuilt.mk
+++ b/core/soong_cc_prebuilt.mk
@@ -51,7 +51,7 @@
 
 ifneq ($(filter STATIC_LIBRARIES SHARED_LIBRARIES HEADER_LIBRARIES,$(LOCAL_MODULE_CLASS)),)
   # Soong module is a static or shared library
-  EXPORTS_LIST := $(EXPORTS_LIST) $(intermediates)
+  EXPORTS_LIST += $(intermediates)
   EXPORTS.$(intermediates).FLAGS := $(LOCAL_EXPORT_CFLAGS)
   EXPORTS.$(intermediates).DEPS := $(LOCAL_EXPORT_C_INCLUDE_DEPS)
 
@@ -61,7 +61,7 @@
     $(my_all_targets): $(LOCAL_BUILT_MODULE).toc
   endif
 
-  SOONG_ALREADY_CONV := $(SOONG_ALREADY_CONV) $(LOCAL_MODULE)
+  SOONG_ALREADY_CONV += $(LOCAL_MODULE)
 
   my_link_type := $(LOCAL_SOONG_LINK_TYPE)
   my_warn_types :=
diff --git a/core/soong_config.mk b/core/soong_config.mk
index cbc2dd1..3f4ba24 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -182,7 +182,7 @@
 $(call add_json_list, CertificateOverrides,              $(PRODUCT_CERTIFICATE_OVERRIDES))
 
 $(call add_json_bool, EnforceSystemCertificate,          $(ENFORCE_SYSTEM_CERTIFICATE))
-$(call add_json_list, EnforceSystemCertificateWhitelist, $(ENFORCE_SYSTEM_CERTIFICATE_WHITELIST))
+$(call add_json_list, EnforceSystemCertificateAllowList, $(ENFORCE_SYSTEM_CERTIFICATE_ALLOW_LIST))
 
 $(call add_json_list, ProductHiddenAPIStubs,             $(PRODUCT_HIDDENAPI_STUBS))
 $(call add_json_list, ProductHiddenAPIStubsSystem,       $(PRODUCT_HIDDENAPI_STUBS_SYSTEM))
diff --git a/core/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index 1496d56..bfde944 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -172,4 +172,4 @@
 		$(hide) echo $(PRIVATE_EXPORTED_SDK_LIBS) | tr ' ' '\n' > $@,\
 		$(hide) touch $@)
 
-SOONG_ALREADY_CONV := $(SOONG_ALREADY_CONV) $(LOCAL_MODULE)
+SOONG_ALREADY_CONV += $(LOCAL_MODULE)
diff --git a/core/tasks/boot_jars_package_check.mk b/core/tasks/boot_jars_package_check.mk
index 05243e5..825bbc3 100644
--- a/core/tasks/boot_jars_package_check.mk
+++ b/core/tasks/boot_jars_package_check.mk
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 #
-# Rules to check if classes in the boot jars are from the whitelisted packages.
+# Rules to check if classes in the boot jars are from the list of allowed packages.
 #
 
 ifneq ($(SKIP_BOOT_JARS_CHECK),true)
@@ -37,14 +37,14 @@
 built_boot_jars := $(foreach j, $(updatable_boot_jars) $(art_boot_jars) $(platform_boot_jars), \
   $(call intermediates-dir-for, JAVA_LIBRARIES, $(j),,COMMON)/classes.jar)
 script := build/make/core/tasks/check_boot_jars/check_boot_jars.py
-whitelist_file := build/make/core/tasks/check_boot_jars/package_whitelist.txt
+allowed_file := build/make/core/tasks/check_boot_jars/package_allowed_list.txt
 
 $(stamp): PRIVATE_BOOT_JARS := $(built_boot_jars)
 $(stamp): PRIVATE_SCRIPT := $(script)
-$(stamp): PRIVATE_WHITELIST := $(whitelist_file)
-$(stamp) : $(built_boot_jars) $(script) $(whitelist_file)
+$(stamp): PRIVATE_ALLOWED := $(allowed_file)
+$(stamp) : $(built_boot_jars) $(script) $(allowed_file)
 	@echo "Check package name for $(PRIVATE_BOOT_JARS)"
-	$(hide) $(PRIVATE_SCRIPT) $(PRIVATE_WHITELIST) $(PRIVATE_BOOT_JARS)
+	$(hide) $(PRIVATE_SCRIPT) $(PRIVATE_ALLOWED) $(PRIVATE_BOOT_JARS)
 	$(hide) mkdir -p $(dir $@) && touch $@
 
 .PHONY: check-boot-jars
diff --git a/core/tasks/check_boot_jars/check_boot_jars.py b/core/tasks/check_boot_jars/check_boot_jars.py
index 67b73d5..cf4ef27 100755
--- a/core/tasks/check_boot_jars/check_boot_jars.py
+++ b/core/tasks/check_boot_jars/check_boot_jars.py
@@ -3,7 +3,7 @@
 """
 Check boot jars.
 
-Usage: check_boot_jars.py <package_whitelist_file> <jar1> <jar2> ...
+Usage: check_boot_jars.py <package_allow_list_file> <jar1> <jar2> ...
 """
 import logging
 import os.path
@@ -12,12 +12,12 @@
 import sys
 
 
-# The compiled whitelist RE.
-whitelist_re = None
+# The compiled allow list RE.
+allow_list_re = None
 
 
-def LoadWhitelist(filename):
-  """ Load and compile whitelist regular expressions from filename.
+def LoadAllowList(filename):
+  """ Load and compile allow list regular expressions from filename.
   """
   lines = []
   with open(filename, 'r') as f:
@@ -27,19 +27,19 @@
         continue
       lines.append(line)
   combined_re = r'^(%s)$' % '|'.join(lines)
-  global whitelist_re
+  global allow_list_re
   try:
-    whitelist_re = re.compile(combined_re)
+    allow_list_re = re.compile(combined_re)
   except re.error:
     logging.exception(
-        'Cannot compile package whitelist regular expression: %r',
+        'Cannot compile package allow list regular expression: %r',
         combined_re)
-    whitelist_re = None
+    allow_list_re = None
     return False
   return True
 
 
-def CheckJar(whitelist_path, jar):
+def CheckJar(allow_list_path, jar):
   """Check a jar file.
   """
   # Get the list of files inside the jar file.
@@ -49,15 +49,20 @@
   if p.returncode != 0:
     return False
   items = stdout.split()
+  classes = 0
   for f in items:
     if f.endswith('.class'):
+      classes += 1
       package_name = os.path.dirname(f)
       package_name = package_name.replace('/', '.')
-      if not package_name or not whitelist_re.match(package_name):
+      if not package_name or not allow_list_re.match(package_name):
         print >> sys.stderr, ('Error: %s contains class file %s, whose package name %s is empty or'
-                              ' not in the whitelist %s of packages allowed on the bootclasspath.'
-                              % (jar, f, package_name, whitelist_path))
+                              ' not in the allow list %s of packages allowed on the bootclasspath.'
+                              % (jar, f, package_name, allow_list_path))
         return False
+  if classes == 0:
+    print >> sys.stderr, ('Error: %s does not contain any class files.' % jar)
+    return False
   return True
 
 
@@ -65,14 +70,14 @@
   if len(argv) < 2:
     print __doc__
     return 1
-  whitelist_path = argv[0]
+  allow_list_path = argv[0]
 
-  if not LoadWhitelist(whitelist_path):
+  if not LoadAllowList(allow_list_path):
     return 1
 
   passed = True
   for jar in argv[1:]:
-    if not CheckJar(whitelist_path, jar):
+    if not CheckJar(allow_list_path, jar):
       passed = False
   if not passed:
     return 1
diff --git a/core/tasks/check_boot_jars/package_whitelist.txt b/core/tasks/check_boot_jars/package_allowed_list.txt
similarity index 99%
rename from core/tasks/check_boot_jars/package_whitelist.txt
rename to core/tasks/check_boot_jars/package_allowed_list.txt
index 8adf877..18ab427 100644
--- a/core/tasks/check_boot_jars/package_whitelist.txt
+++ b/core/tasks/check_boot_jars/package_allowed_list.txt
@@ -1,4 +1,4 @@
-# Boot jar package name whitelist.
+# Boot jar package name allowed list.
 # Each line is interpreted as a regular expression.
 
 ###################################################
diff --git a/core/tasks/collect_gpl_sources.mk b/core/tasks/collect_gpl_sources.mk
index acbe9be..ebc4181 100644
--- a/core/tasks/collect_gpl_sources.mk
+++ b/core/tasks/collect_gpl_sources.mk
@@ -17,6 +17,8 @@
 # in installclean between incremental builds on build servers.
 gpl_source_tgz := $(call intermediates-dir-for,PACKAGING,gpl_source)/gpl_source.tgz
 
+ALL_GPL_MODULE_LICENSE_FILES := $(sort $(ALL_GPL_MODULE_LICENSE_FILES))
+
 # FORCE since we can't know whether any of the sources changed
 $(gpl_source_tgz): PRIVATE_PATHS := $(sort $(patsubst %/, %, $(dir $(ALL_GPL_MODULE_LICENSE_FILES))))
 $(gpl_source_tgz) : $(ALL_GPL_MODULE_LICENSE_FILES)
diff --git a/core/tasks/tools/compatibility.mk b/core/tasks/tools/compatibility.mk
index 87582a5..89b0b9b 100644
--- a/core/tasks/tools/compatibility.mk
+++ b/core/tasks/tools/compatibility.mk
@@ -30,6 +30,7 @@
 test_artifacts := $(COMPATIBILITY.$(test_suite_name).FILES)
 test_tools := $(HOST_OUT_JAVA_LIBRARIES)/hosttestlib.jar \
   $(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar \
+  $(HOST_OUT_JAVA_LIBRARIES)/tradefed-test-framework.jar \
   $(HOST_OUT_JAVA_LIBRARIES)/loganalysis.jar \
   $(HOST_OUT_JAVA_LIBRARIES)/compatibility-host-util.jar \
   $(HOST_OUT_JAVA_LIBRARIES)/compatibility-host-util-tests.jar \
diff --git a/core/tasks/vendor_module_check.mk b/core/tasks/vendor_module_check.mk
index 0b8f1e8..b4c5a3b 100644
--- a/core/tasks/vendor_module_check.mk
+++ b/core/tasks/vendor_module_check.mk
@@ -15,7 +15,7 @@
 #
 
 # Restrict the vendor module owners here.
-_vendor_owner_whitelist := \
+_vendor_owner_allowed_list := \
         asus \
         audience \
         atmel \
@@ -87,14 +87,14 @@
     $(filter vendor/%, $(PRODUCT_COPY_FILES)))
 ifneq (,$(_vendor_check_copy_files))
 $(foreach c, $(_vendor_check_copy_files), \
-  $(if $(filter $(_vendor_owner_whitelist), $(call word-colon,3,$(c))),,\
+  $(if $(filter $(_vendor_owner_allowed_list), $(call word-colon,3,$(c))),,\
     $(error Error: vendor PRODUCT_COPY_FILES file "$(c)" has unknown owner))\
   $(eval _vendor_module_owner_info += $(call word-colon,2,$(c)):$(call word-colon,3,$(c))))
 endif
 _vendor_check_copy_files :=
 
 $(foreach m, $(_vendor_check_modules), \
-  $(if $(filter $(_vendor_owner_whitelist), $(ALL_MODULES.$(m).OWNER)),,\
+  $(if $(filter $(_vendor_owner_allowed_list), $(ALL_MODULES.$(m).OWNER)),,\
     $(error Error: vendor module "$(m)" in $(ALL_MODULES.$(m).PATH) with unknown owner \
       "$(ALL_MODULES.$(m).OWNER)" in product "$(TARGET_PRODUCT)"))\
   $(if $(ALL_MODULES.$(m).INSTALLED),\
diff --git a/core/tasks/vts-core-tests.mk b/core/tasks/vts-core-tests.mk
index 4e83de5..a3247da 100644
--- a/core/tasks/vts-core-tests.mk
+++ b/core/tasks/vts-core-tests.mk
@@ -12,15 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+-include external/linux-kselftest/android/kselftest_test_list.mk
+-include external/ltp/android/ltp_package_list.mk
+
 test_suite_name := vts
 test_suite_tradefed := vts-tradefed
 test_suite_readme := test/vts/tools/vts-core-tradefed/README
 
-# TODO(b/149249068): Clean up after all VTS tests are converted.
-vts_test_artifact_paths :=
-# Some repo may not include vts project.
--include test/vts/tools/build/tasks/framework/vts_for_core_suite.mk
-
 # Copy kernel test modules to testcases directories
 kernel_test_host_out := $(HOST_OUT_TESTCASES)/vts_kernel_tests
 kernel_test_vts_out := $(HOST_OUT)/$(test_suite_name)/android-$(test_suite_name)/testcases/vts_kernel_tests
@@ -44,7 +42,6 @@
 $(compatibility_zip): $(copy_kernel_tests)
 
 .PHONY: vts
-$(compatibility_zip): $(vts_test_artifact_paths)
 vts: $(compatibility_zip)
 $(call dist-for-goals, vts, $(compatibility_zip))
 
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 645c648..c28c2fa 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -240,7 +240,7 @@
     #  It must be of the form "YYYY-MM-DD" on production devices.
     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
-      PLATFORM_SECURITY_PATCH := 2020-06-05
+      PLATFORM_SECURITY_PATCH := 2020-09-01
 endif
 .KATI_READONLY := PLATFORM_SECURITY_PATCH
 
diff --git a/target/board/BoardConfigEmuCommon.mk b/target/board/BoardConfigEmuCommon.mk
index a2e5518..e9fb096 100644
--- a/target/board/BoardConfigEmuCommon.mk
+++ b/target/board/BoardConfigEmuCommon.mk
@@ -33,8 +33,6 @@
   # 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
diff --git a/target/board/BoardConfigGsiCommon.mk b/target/board/BoardConfigGsiCommon.mk
index c89e203..49f6edc 100644
--- a/target/board/BoardConfigGsiCommon.mk
+++ b/target/board/BoardConfigGsiCommon.mk
@@ -40,6 +40,12 @@
 BOARD_AVB_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
 BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
 
+# Enable chain partition for boot, mainly for GKI images.
+BOARD_AVB_BOOT_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
+BOARD_AVB_BOOT_ALGORITHM := SHA256_RSA2048
+BOARD_AVB_BOOT_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
+BOARD_AVB_BOOT_ROLLBACK_INDEX_LOCATION := 2
+
 # GSI specific System Properties
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 TARGET_SYSTEM_EXT_PROP := build/make/target/board/gsi_system_ext.prop
diff --git a/target/board/BoardConfigMainlineCommon.mk b/target/board/BoardConfigMainlineCommon.mk
index c57968e..bf015e5 100644
--- a/target/board/BoardConfigMainlineCommon.mk
+++ b/target/board/BoardConfigMainlineCommon.mk
@@ -6,6 +6,8 @@
 TARGET_NO_BOOTLOADER := true
 TARGET_NO_RECOVERY := true
 
+BOARD_EXT4_SHARE_DUP_BLOCKS := true
+
 TARGET_USERIMAGES_USE_EXT4 := true
 
 # Mainline devices must have /system_ext, /vendor and /product partitions.
diff --git a/target/board/emulator_arm64/device.mk b/target/board/emulator_arm64/device.mk
index 6753c11..57675d0 100644
--- a/target/board/emulator_arm64/device.mk
+++ b/target/board/emulator_arm64/device.mk
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish # for libwifi-hal-emu
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for goldfish deps.
+
 # Cuttlefish has GKI kernel prebuilts, so use those for the GKI boot.img.
 ifeq ($(TARGET_PREBUILT_KERNEL),)
     LOCAL_KERNEL := device/google/cuttlefish_kernel/5.4-arm64/kernel
diff --git a/target/board/generic/device.mk b/target/board/generic/device.mk
index 0a32415..cfb15f0 100644
--- a/target/board/generic/device.mk
+++ b/target/board/generic/device.mk
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish # for libwifi-hal-emu
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for goldfish deps.
+
 # NFC:
 #   Provide default libnfc-nci.conf file for devices that does not have one in
 #   vendor/etc because aosp system image (of aosp_$arch products) is going to
diff --git a/target/board/generic_arm64/BoardConfig.mk b/target/board/generic_arm64/BoardConfig.mk
index d793c38..ba69623 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -54,19 +54,21 @@
 
 include build/make/target/board/BoardConfigGsiCommon.mk
 
-BOARD_EXT4_SHARE_DUP_BLOCKS := true
-
 TARGET_NO_KERNEL := false
 TARGET_NO_VENDOR_BOOT := true
 BOARD_USES_RECOVERY_AS_BOOT := true
 
-BOARD_BOOTIMAGE_PARTITION_SIZE := 0x04000000
+BOARD_KERNEL-4.19-GZ_BOOTIMAGE_PARTITION_SIZE := 47185920
+BOARD_KERNEL-5.4_BOOTIMAGE_PARTITION_SIZE := 67108864
+BOARD_KERNEL-5.4-GZ_BOOTIMAGE_PARTITION_SIZE := 47185920
+BOARD_KERNEL-5.4-LZ4_BOOTIMAGE_PARTITION_SIZE := 53477376
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
 
+BOARD_RAMDISK_USE_LZ4 := true
 BOARD_BOOT_HEADER_VERSION := 3
 BOARD_MKBOOTIMG_ARGS += --header_version $(BOARD_BOOT_HEADER_VERSION)
 
-BOARD_KERNEL_BINARIES := kernel-5.4 kernel-5.4-gz kernel-5.4-lz4
+BOARD_KERNEL_BINARIES := kernel-4.19-gz kernel-5.4 kernel-5.4-gz kernel-5.4-lz4
 
 # Some vendors still haven't cleaned up all device specific directories under
 # root!
diff --git a/target/board/generic_arm64/device.mk b/target/board/generic_arm64/device.mk
index 3b7cd44..d96bfc2 100644
--- a/target/board/generic_arm64/device.mk
+++ b/target/board/generic_arm64/device.mk
@@ -15,6 +15,7 @@
 #
 
 PRODUCT_COPY_FILES += \
+    kernel/prebuilts/4.19/arm64/Image.gz:kernel-4.19-gz \
     device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4:kernel-5.4 \
     device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4-gz:kernel-5.4-gz \
     device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4-lz4:kernel-5.4-lz4
diff --git a/target/board/generic_x86/device.mk b/target/board/generic_x86/device.mk
index bbab2b4..2b10a3d 100644
--- a/target/board/generic_x86/device.mk
+++ b/target/board/generic_x86/device.mk
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish # for libwifi-hal-emu
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for goldfish deps.
+
 ifdef NET_ETH0_STARTONBOOT
   PRODUCT_PROPERTY_OVERRIDES += net.eth0.startonboot=1
 endif
diff --git a/target/board/generic_x86_64/device.mk b/target/board/generic_x86_64/device.mk
index bbab2b4..2b10a3d 100755
--- a/target/board/generic_x86_64/device.mk
+++ b/target/board/generic_x86_64/device.mk
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish # for libwifi-hal-emu
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for goldfish deps.
+
 ifdef NET_ETH0_STARTONBOOT
   PRODUCT_PROPERTY_OVERRIDES += net.eth0.startonboot=1
 endif
diff --git a/target/board/generic_x86_64_arm64/device.mk b/target/board/generic_x86_64_arm64/device.mk
index fa1eb67..76242c9 100755
--- a/target/board/generic_x86_64_arm64/device.mk
+++ b/target/board/generic_x86_64_arm64/device.mk
@@ -13,3 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish # for libwifi-hal-emu
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for goldfish deps.
diff --git a/target/board/generic_x86_arm/device.mk b/target/board/generic_x86_arm/device.mk
index fa1eb67..76242c9 100644
--- a/target/board/generic_x86_arm/device.mk
+++ b/target/board/generic_x86_arm/device.mk
@@ -13,3 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish # for libwifi-hal-emu
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for goldfish deps.
diff --git a/target/product/aosp_arm.mk b/target/product/aosp_arm.mk
index 0607717..0cec14b 100644
--- a/target/product/aosp_arm.mk
+++ b/target/product/aosp_arm.mk
@@ -33,7 +33,7 @@
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
 endif
 
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
 
 #
 # All components inherited here go to system_ext image
diff --git a/target/product/aosp_x86_arm.mk b/target/product/aosp_x86_arm.mk
index 7b9b89c..deba3d9 100644
--- a/target/product/aosp_x86_arm.mk
+++ b/target/product/aosp_x86_arm.mk
@@ -27,7 +27,7 @@
 endif
 
 # TODO (b/138382074): remove following setting after enable product/system_ext
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
     system/product/% \
     system/system_ext/%
 
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index c346c13..4569bce 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -16,7 +16,7 @@
 
 # Base modules and settings for the system partition.
 PRODUCT_PACKAGES += \
-    adbd_system_binaries \
+    adbd_system_api \
     am \
     android.hidl.allocator@1.0-service \
     android.hidl.base-V1.0-java \
@@ -27,7 +27,6 @@
     android.test.base \
     android.test.mock \
     android.test.runner \
-    ANGLE \
     apexd \
     appops \
     app_process \
@@ -51,7 +50,6 @@
     charger \
     cmd \
     com.android.adbd \
-    com.android.apex.cts.shim.v1 \
     com.android.conscrypt \
     com.android.extservices \
     com.android.i18n \
@@ -71,6 +69,8 @@
     ContactsProvider \
     content \
     crash_dump \
+    CtsShimPrebuilt \
+    CtsShimPrivPrebuilt \
     debuggerd\
     device_config \
     dmctl \
@@ -118,6 +118,7 @@
     javax.obex \
     service-jobscheduler \
     keystore \
+    credstore \
     ld.mc \
     libaaudio \
     libamidi \
@@ -211,7 +212,7 @@
     mtpd \
     ndc \
     netd \
-    NetworkStackNext \
+    NetworkStack \
     org.apache.http.legacy \
     otacerts \
     PackageInstaller \
diff --git a/target/product/emulated_storage.mk b/target/product/emulated_storage.mk
index d7cc9ce..ea5d9ad 100644
--- a/target/product/emulated_storage.mk
+++ b/target/product/emulated_storage.mk
@@ -19,3 +19,5 @@
 
 PRODUCT_FS_CASEFOLD := 1
 PRODUCT_PROPERTY_OVERRIDES += external_storage.casefold.enabled=1
+
+PRODUCT_PROPERTY_OVERRIDES += external_storage.sdcardfs.enabled=0
diff --git a/target/product/emulator_system.mk b/target/product/emulator_system.mk
index 4b6987c..b7e7cfa 100644
--- a/target/product/emulator_system.mk
+++ b/target/product/emulator_system.mk
@@ -16,7 +16,7 @@
 # This file lists emulator experimental modules added to PRODUCT_PACKAGES,
 # only included by targets sdk_phone_x86/64 and sdk_gphone_x86/64
 
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST := \
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST := \
     system/lib/libemulator_multidisplay_jni.so \
     system/lib64/libemulator_multidisplay_jni.so \
     system/priv-app/MultiDisplayProvider/MultiDisplayProvider.apk \
diff --git a/target/product/generic.mk b/target/product/generic.mk
index 68130e3..d3f81b1 100644
--- a/target/product/generic.mk
+++ b/target/product/generic.mk
@@ -14,6 +14,9 @@
 # limitations under the License.
 #
 
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish # for libwifi-hal-emu
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for goldfish deps.
+
 # This is a generic phone product that isn't specialized for a specific device.
 # It includes the base Android platform.
 
@@ -25,5 +28,5 @@
 PRODUCT_DEVICE := generic
 PRODUCT_NAME := generic
 
-whitelist := product_manifest.xml
-$(call enforce-product-packages-exist,$(whitelist))
+allowed_list := product_manifest.xml
+$(call enforce-product-packages-exist,$(allowed_list))
diff --git a/target/product/gsi/30.txt b/target/product/gsi/30.txt
index cc2d36d..0589517 100644
--- a/target/product/gsi/30.txt
+++ b/target/product/gsi/30.txt
@@ -150,11 +150,11 @@
 VNDK-core: android.hardware.health@1.0.so
 VNDK-core: android.hardware.health@2.0.so
 VNDK-core: android.hardware.health@2.1.so
-VNDK-core: android.hardware.identity-V1-ndk_platform.so
+VNDK-core: android.hardware.identity-V2-ndk_platform.so
 VNDK-core: android.hardware.input.classifier@1.0.so
 VNDK-core: android.hardware.input.common@1.0.so
 VNDK-core: android.hardware.ir@1.0.so
-VNDK-core: android.hardware.keymaster-V1-ndk_platform.so
+VNDK-core: android.hardware.keymaster-V2-ndk_platform.so
 VNDK-core: android.hardware.keymaster@3.0.so
 VNDK-core: android.hardware.keymaster@4.0.so
 VNDK-core: android.hardware.keymaster@4.1.so
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index cc2d36d..0589517 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -150,11 +150,11 @@
 VNDK-core: android.hardware.health@1.0.so
 VNDK-core: android.hardware.health@2.0.so
 VNDK-core: android.hardware.health@2.1.so
-VNDK-core: android.hardware.identity-V1-ndk_platform.so
+VNDK-core: android.hardware.identity-V2-ndk_platform.so
 VNDK-core: android.hardware.input.classifier@1.0.so
 VNDK-core: android.hardware.input.common@1.0.so
 VNDK-core: android.hardware.ir@1.0.so
-VNDK-core: android.hardware.keymaster-V1-ndk_platform.so
+VNDK-core: android.hardware.keymaster-V2-ndk_platform.so
 VNDK-core: android.hardware.keymaster@3.0.so
 VNDK-core: android.hardware.keymaster@4.0.so
 VNDK-core: android.hardware.keymaster@4.1.so
diff --git a/target/product/gsi/gsi_skip_mount.cfg b/target/product/gsi/gsi_skip_mount.cfg
index 3f812cb..ad3c7d9 100644
--- a/target/product/gsi/gsi_skip_mount.cfg
+++ b/target/product/gsi/gsi_skip_mount.cfg
@@ -1,2 +1,3 @@
+/oem
 /product
 /system_ext
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index a6dd418..d3521fc 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -25,7 +25,7 @@
 #
 
 # Exclude all files under system/product and system/system_ext
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
     system/product/% \
     system/system_ext/%
 
@@ -44,6 +44,11 @@
 # GSI targets should install "flattened" APEXes in /system_ext as well
 PRODUCT_INSTALL_EXTRA_FLATTENED_APEXES := true
 
+# The flattened version of com.android.apex.cts.shim.v1 should be explicitly installed
+# because the shim apex is prebuilt one and PRODUCT_INSTALL_EXTRA_FLATTENED_APEXES is not
+# supported for prebuilt_apex modules yet.
+PRODUCT_PACKAGES += com.android.apex.cts.shim.v1_with_prebuilts.flattened
+
 # GSI specific tasks on boot
 PRODUCT_PACKAGES += \
     gsi_skip_mount.cfg \
diff --git a/target/product/iorap_large_memory_config.mk b/target/product/iorap_large_memory_config.mk
new file mode 100644
index 0000000..9aa6642
--- /dev/null
+++ b/target/product/iorap_large_memory_config.mk
@@ -0,0 +1,18 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Disable Camera pinner by default
+PRODUCT_PRODUCT_PROPERTIES += \
+    pinner.pin_camera=false
diff --git a/target/product/legacy_gsi_release.mk b/target/product/legacy_gsi_release.mk
index f072481..c1646bb 100644
--- a/target/product/legacy_gsi_release.mk
+++ b/target/product/legacy_gsi_release.mk
@@ -16,7 +16,7 @@
 
 include $(SRC_TARGET_DIR)/product/gsi_release.mk
 
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
     system/etc/init/init.legacy-gsi.rc \
     system/etc/init/gsi/init.vndk-27.rc \
     system/etc/ld.config.vndk_lite.txt \
diff --git a/target/product/mainline_system.mk b/target/product/mainline_system.mk
index f8d85bf..a787707 100644
--- a/target/product/mainline_system.mk
+++ b/target/product/mainline_system.mk
@@ -131,13 +131,13 @@
 PRODUCT_SYSTEM_MODEL := mainline
 PRODUCT_SYSTEM_DEVICE := generic
 
-_base_mk_whitelist :=
+_base_mk_allowed_list :=
 
-_my_whitelist := $(_base_mk_whitelist)
+_my_allowed_list := $(_base_mk_allowed_list)
 
 # For mainline, system.img should be mounted at /, so we include ROOT here.
 _my_paths := \
   $(TARGET_COPY_OUT_ROOT)/ \
   $(TARGET_COPY_OUT_SYSTEM)/ \
 
-$(call require-artifacts-in-path, $(_my_paths), $(_my_whitelist))
+$(call require-artifacts-in-path, $(_my_paths), $(_my_allowed_list))
diff --git a/target/product/telephony_system.mk b/target/product/telephony_system.mk
index 9c585b3..ef48719 100644
--- a/target/product/telephony_system.mk
+++ b/target/product/telephony_system.mk
@@ -22,5 +22,6 @@
     CarrierDefaultApp \
     CallLogBackup \
     com.android.cellbroadcast \
+    CellBroadcastLegacyApp \
 
 PRODUCT_COPY_FILES := \
diff --git a/target/product/updatable_apex.mk b/target/product/updatable_apex.mk
index e5a647c..a84a0d2 100644
--- a/target/product/updatable_apex.mk
+++ b/target/product/updatable_apex.mk
@@ -17,6 +17,8 @@
 # Inherit this when the target needs to support updating APEXes
 
 ifneq ($(OVERRIDE_TARGET_FLATTEN_APEX),true)
+  # com.android.apex.cts.shim.v1_prebuilt overrides CtsShimPrebuilt
+  # and CtsShimPrivPrebuilt since they are packaged inside the APEX.
   PRODUCT_PACKAGES += com.android.apex.cts.shim.v1_prebuilt
   PRODUCT_PROPERTY_OVERRIDES := ro.apex.updatable=true
   TARGET_FLATTEN_APEX := false
diff --git a/tools/auto_gen_test_config.py b/tools/auto_gen_test_config.py
index c7c5bdc..943f238 100755
--- a/tools/auto_gen_test_config.py
+++ b/tools/auto_gen_test_config.py
@@ -27,6 +27,7 @@
 ATTRIBUTE_PACKAGE = 'package'
 
 PLACEHOLDER_LABEL = '{LABEL}'
+PLACEHOLDER_EXTRA_CONFIGS = '{EXTRA_CONFIGS}'
 PLACEHOLDER_MODULE = '{MODULE}'
 PLACEHOLDER_PACKAGE = '{PACKAGE}'
 PLACEHOLDER_RUNNER = '{RUNNER}'
@@ -41,16 +42,20 @@
   Returns:
     0 if no error, otherwise 1.
   """
-  if len(argv) != 4:
+  if len(argv) != 4 and len(argv) != 6:
     sys.stderr.write(
-        'Invalid arguements. The script requires 4 arguments for file paths: '
+        'Invalid arguments. The script requires 4 arguments for file paths: '
         'target_config android_manifest empty_config '
-        'instrumentation_test_config_template.\n')
+        'instrumentation_test_config_template '
+        'and 2 optional arguments for extra configs: '
+        '--extra-configs \'EXTRA_CONFIGS\'.\n')
     return 1
+
   target_config = argv[0]
   android_manifest = argv[1]
   empty_config = argv[2]
   instrumentation_test_config_template = argv[3]
+  extra_configs = '\n'.join(argv[5].split('\\n')) if len(argv) == 6 else ''
 
   manifest = parse(android_manifest)
   instrumentation_elements = manifest.getElementsByTagName('instrumentation')
@@ -80,6 +85,7 @@
     config = config.replace(PLACEHOLDER_MODULE, module)
     config = config.replace(PLACEHOLDER_PACKAGE, package)
     config = config.replace(PLACEHOLDER_TEST_TYPE, test_type)
+    config = config.replace(PLACEHOLDER_EXTRA_CONFIGS, extra_configs)
     config = config.replace(PLACEHOLDER_RUNNER, runner)
     with open(target_config, 'w') as config_file:
       config_file.write(config)
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index 90a6485..5785688 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -187,7 +187,9 @@
         "bsdiff",
         "imgdiff",
         "minigzip",
+        "lz4",
         "mkbootfs",
+        "signapk",
     ],
 }
 
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
old mode 100755
new mode 100644
index 7db506c..f58b697
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -60,6 +60,7 @@
 import common
 import rangelib
 import sparse_img
+import verity_utils
 
 if sys.hexversion < 0x02070000:
   print("Python 2.7 or newer is required.", file=sys.stderr)
@@ -312,6 +313,56 @@
   img.Write()
   return img.name
 
+def AddCustomImages(output_zip, partition_name):
+  """Adds and signs custom images in IMAGES/.
+
+  Args:
+    output_zip: The output zip file (needs to be already open), or None to
+        write images to OPTIONS.input_tmp/.
+
+  Uses the image under IMAGES/ if it already exists. Otherwise looks for the
+  image under PREBUILT_IMAGES/, signs it as needed, and returns the image name.
+
+  Raises:
+    AssertionError: If image can't be found.
+  """
+
+  partition_size = OPTIONS.info_dict.get(
+      "avb_{}_partition_size".format(partition_name))
+  key_path = OPTIONS.info_dict.get("avb_{}_key_path".format(partition_name))
+  algorithm = OPTIONS.info_dict.get("avb_{}_algorithm".format(partition_name))
+  extra_args = OPTIONS.info_dict.get(
+      "avb_{}_add_hashtree_footer_args".format(partition_name))
+  partition_size = OPTIONS.info_dict.get(
+      "avb_{}_partition_size".format(partition_name))
+
+  builder = verity_utils.CreateCustomImageBuilder(
+      OPTIONS.info_dict, partition_name, partition_size,
+      key_path, algorithm, extra_args)
+
+  for img_name in OPTIONS.info_dict.get(
+      "avb_{}_image_list".format(partition_name)).split():
+    custom_image = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", img_name)
+    if os.path.exists(custom_image.name):
+      continue
+
+    custom_image_prebuilt_path = os.path.join(
+        OPTIONS.input_tmp, "PREBUILT_IMAGES", img_name)
+    assert os.path.exists(custom_image_prebuilt_path), \
+      "Failed to find %s at %s" % (img_name, custom_image_prebuilt_path)
+
+    shutil.copy(custom_image_prebuilt_path, custom_image.name)
+
+    if builder is not None:
+      builder.Build(custom_image.name)
+
+    custom_image.Write()
+
+  default = os.path.join(OPTIONS.input_tmp, "IMAGES", partition_name + ".img")
+  assert os.path.exists(default), \
+      "There should be one %s.img" % (partition_name)
+  return default
+
 
 def CreateImage(input_dir, info_dict, what, output_file, block_list=None):
   logger.info("creating %s.img...", what)
@@ -411,8 +462,9 @@
   Args:
     output_zip: The output zip file, which needs to be already open.
     partitions: A dict that's keyed by partition names with image paths as
-        values. Only valid partition names are accepted, as listed in
-        common.AVB_PARTITIONS.
+        values. Only valid partition names are accepted, as partitions listed
+        in common.AVB_PARTITIONS and custom partitions listed in
+        OPTIONS.info_dict.get("avb_custom_images_partition_list")
     name: Name of the VBMeta partition, e.g. 'vbmeta', 'vbmeta_system'.
     needed_partitions: Partitions whose descriptors should be included into the
         generated VBMeta image.
@@ -548,17 +600,19 @@
       care_map_list += care_map
 
       # adds fingerprint field to the care_map
-      build_props = OPTIONS.info_dict.get(partition + ".build.prop", {})
+      # TODO(xunchang) revisit the fingerprint calculation for care_map.
+      partition_props = OPTIONS.info_dict.get(partition + ".build.prop")
       prop_name_list = ["ro.{}.build.fingerprint".format(partition),
                         "ro.{}.build.thumbprint".format(partition)]
 
-      present_props = [x for x in prop_name_list if x in build_props]
+      present_props = [x for x in prop_name_list if
+                       partition_props and partition_props.GetProp(x)]
       if not present_props:
         logger.warning("fingerprint is not present for partition %s", partition)
         property_id, fingerprint = "unknown", "unknown"
       else:
         property_id = present_props[0]
-        fingerprint = build_props[property_id]
+        fingerprint = partition_props.GetProp(property_id)
       care_map_list += [property_id, fingerprint]
 
   if not care_map_list:
@@ -734,16 +788,16 @@
     boot_images = OPTIONS.info_dict.get("boot_images")
     if boot_images is None:
       boot_images = "boot.img"
-    for b in boot_images.split():
+    for index,b in enumerate(boot_images.split()):
       # common.GetBootableImage() returns the image directly if present.
       boot_image = common.GetBootableImage(
           "IMAGES/" + b, b, OPTIONS.input_tmp, "BOOT")
       # boot.img may be unavailable in some targets (e.g. aosp_arm64).
       if boot_image:
         boot_image_path = os.path.join(OPTIONS.input_tmp, "IMAGES", b)
-        # vbmeta does not need to include boot.img with multiple boot.img files,
-        # which is only used for aosp_arm64 for GKI
-        if len(boot_images.split()) == 1:
+        # Although multiple boot images can be generated, include the image
+        # descriptor of only the first boot image in vbmeta
+        if index == 0:
           partitions['boot'] = boot_image_path
         if not os.path.exists(boot_image_path):
           boot_image.WriteToDir(OPTIONS.input_tmp)
@@ -829,11 +883,20 @@
     banner("dtbo")
     partitions['dtbo'] = AddDtbo(output_zip)
 
+  # Custom images.
+  custom_partitions = OPTIONS.info_dict.get(
+      "avb_custom_images_partition_list", "").strip().split()
+  for partition_name in custom_partitions:
+    partition_name = partition_name.strip()
+    banner("custom images for " + partition_name)
+    partitions[partition_name] = AddCustomImages(output_zip, partition_name)
+
   if OPTIONS.info_dict.get("avb_enable") == "true":
     # vbmeta_partitions includes the partitions that should be included into
     # top-level vbmeta.img, which are the ones that are not included in any
     # chained VBMeta image plus the chained VBMeta images themselves.
-    vbmeta_partitions = common.AVB_PARTITIONS[:]
+    # Currently custom_partitions are all chained to VBMeta image.
+    vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(custom_partitions)
 
     vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
     if vbmeta_system:
diff --git a/tools/releasetools/apex_utils.py b/tools/releasetools/apex_utils.py
index ae9b793..1c61938 100644
--- a/tools/releasetools/apex_utils.py
+++ b/tools/releasetools/apex_utils.py
@@ -169,7 +169,7 @@
 
 
 def SignApexPayload(avbtool, payload_file, payload_key_path, payload_key_name,
-                    algorithm, salt, no_hashtree, signing_args=None):
+                    algorithm, salt, hash_algorithm, no_hashtree, signing_args=None):
   """Signs a given payload_file with the payload key."""
   # Add the new footer. Old footer, if any, will be replaced by avbtool.
   cmd = [avbtool, 'add_hashtree_footer',
@@ -178,7 +178,8 @@
          '--key', payload_key_path,
          '--prop', 'apex.key:{}'.format(payload_key_name),
          '--image', payload_file,
-         '--salt', salt]
+         '--salt', salt,
+         '--hash_algorithm', hash_algorithm]
   if no_hashtree:
     cmd.append('--no_hashtree')
   if signing_args:
@@ -235,11 +236,11 @@
         'Failed to get APEX payload info for {}:\n{}'.format(
             payload_path, e))
 
-  # Extract the Algorithm / Salt / Prop info / Tree size from payload (i.e. an
-  # image signed with avbtool). For example,
+  # Extract the Algorithm / Hash Algorithm / Salt / Prop info / Tree size from
+  # payload (i.e. an image signed with avbtool). For example,
   # Algorithm:                SHA256_RSA4096
   PAYLOAD_INFO_PATTERN = (
-      r'^\s*(?P<key>Algorithm|Salt|Prop|Tree Size)\:\s*(?P<value>.*?)$')
+      r'^\s*(?P<key>Algorithm|Hash Algorithm|Salt|Prop|Tree Size)\:\s*(?P<value>.*?)$')
   payload_info_matcher = re.compile(PAYLOAD_INFO_PATTERN)
 
   payload_info = {}
@@ -273,7 +274,7 @@
       payload_info[key] = value
 
   # Sanity check.
-  for key in ('Algorithm', 'Salt', 'apex.key'):
+  for key in ('Algorithm', 'Salt', 'apex.key', 'Hash Algorithm'):
     if key not in payload_info:
       raise ApexInfoError(
           'Failed to find {} prop in {}'.format(key, payload_path))
@@ -326,6 +327,7 @@
       payload_info['apex.key'],
       payload_info['Algorithm'],
       payload_info['Salt'],
+      payload_info['Hash Algorithm'],
       no_hashtree,
       signing_args)
 
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 54bb857..8cf0741 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -509,9 +509,9 @@
   d = {}
 
   if "build.prop" in glob_dict:
-    bp = glob_dict["build.prop"]
-    if "ro.build.date.utc" in bp:
-      d["timestamp"] = bp["ro.build.date.utc"]
+    timestamp = glob_dict["build.prop"].GetProp("ro.build.date.utc")
+    if timestamp:
+      d["timestamp"] = timestamp
 
   def copy_prop(src_p, dest_p):
     """Copy a property from the global dictionary.
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
index b3d491f..95d09cc 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -80,8 +80,9 @@
            '--property', 'ro.boot.product.vendor.sku=' + vendor_sku]
           for odm_sku in odm_skus for vendor_sku in vendor_skus]
 
+
 def GetArgsForShippingApiLevel(info_dict):
-  shipping_api_level = info_dict['vendor.build.prop'].get(
+  shipping_api_level = info_dict['vendor.build.prop'].GetProp(
       'ro.product.first_api_level')
   if not shipping_api_level:
     logger.warning('Cannot determine ro.product.first_api_level')
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index c3d3394..ae7da2f 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -422,6 +422,14 @@
   def items(self):
     return self.info_dict.items()
 
+  def _GetRawBuildProp(self, prop, partition):
+    prop_file = '{}.build.prop'.format(
+        partition) if partition else 'build.prop'
+    partition_props = self.info_dict.get(prop_file)
+    if not partition_props:
+      return None
+    return partition_props.GetProp(prop)
+
   def GetPartitionBuildProp(self, prop, partition):
     """Returns the inquired build property for the provided partition."""
     # If provided a partition for this property, only look within that
@@ -430,31 +438,33 @@
       prop = prop.replace("ro.product", "ro.product.{}".format(partition))
     else:
       prop = prop.replace("ro.", "ro.{}.".format(partition))
-    try:
-      return self.info_dict.get("{}.build.prop".format(partition), {})[prop]
-    except KeyError:
-      raise ExternalError("couldn't find %s in %s.build.prop" %
-                          (prop, partition))
+
+    prop_val = self._GetRawBuildProp(prop, partition)
+    if prop_val is not None:
+      return prop_val
+    raise ExternalError("couldn't find %s in %s.build.prop" %
+                        (prop, partition))
 
   def GetBuildProp(self, prop):
     """Returns the inquired build property from the standard build.prop file."""
     if prop in BuildInfo._RO_PRODUCT_RESOLVE_PROPS:
       return self._ResolveRoProductBuildProp(prop)
 
-    try:
-      return self.info_dict.get("build.prop", {})[prop]
-    except KeyError:
-      raise ExternalError("couldn't find %s in build.prop" % (prop,))
+    prop_val = self._GetRawBuildProp(prop, None)
+    if prop_val is not None:
+      return prop_val
+
+    raise ExternalError("couldn't find %s in build.prop" % (prop,))
 
   def _ResolveRoProductBuildProp(self, prop):
     """Resolves the inquired ro.product.* build property"""
-    prop_val = self.info_dict.get("build.prop", {}).get(prop)
+    prop_val = self._GetRawBuildProp(prop, None)
     if prop_val:
       return prop_val
 
     default_source_order = self._GetRoProductPropsDefaultSourceOrder()
-    source_order_val = self.info_dict.get("build.prop", {}).get(
-        "ro.product.property_source_order")
+    source_order_val = self._GetRawBuildProp(
+        "ro.product.property_source_order", None)
     if source_order_val:
       source_order = source_order_val.split(",")
     else:
@@ -465,11 +475,10 @@
       raise ExternalError(
           "Invalid ro.product.property_source_order '{}'".format(source_order))
 
-    for source in source_order:
+    for source_partition in source_order:
       source_prop = prop.replace(
-          "ro.product", "ro.product.{}".format(source), 1)
-      prop_val = self.info_dict.get(
-          "{}.build.prop".format(source), {}).get(source_prop)
+          "ro.product", "ro.product.{}".format(source_partition), 1)
+      prop_val = self._GetRawBuildProp(source_prop, source_partition)
       if prop_val:
         return prop_val
 
@@ -478,11 +487,9 @@
   def _GetRoProductPropsDefaultSourceOrder(self):
     # NOTE: refer to CDDs and android.os.Build.VERSION for the definition and
     # values of these properties for each Android release.
-    android_codename = self.info_dict.get("build.prop", {}).get(
-        "ro.build.version.codename")
+    android_codename = self._GetRawBuildProp("ro.build.version.codename", None)
     if android_codename == "REL":
-      android_version = self.info_dict.get("build.prop", {}).get(
-          "ro.build.version.release")
+      android_version = self._GetRawBuildProp("ro.build.version.release", None)
       if android_version == "10":
         return BuildInfo._RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER_ANDROID_10
       # NOTE: float() conversion of android_version will have rounding error.
@@ -565,6 +572,20 @@
       script.AssertOemProperty(prop, values, oem_no_mount)
 
 
+def ReadFromInputFile(input_file, fn):
+  """Reads the contents of fn from input zipfile or directory."""
+  if isinstance(input_file, zipfile.ZipFile):
+    return input_file.read(fn).decode()
+  else:
+    path = os.path.join(input_file, *fn.split("/"))
+    try:
+      with open(path) as f:
+        return f.read()
+    except IOError as e:
+      if e.errno == errno.ENOENT:
+        raise KeyError(fn)
+
+
 def LoadInfoDict(input_file, repacking=False):
   """Loads the key/value pairs from the given input target_files.
 
@@ -602,16 +623,7 @@
         "input_file must be a path str when doing repacking"
 
   def read_helper(fn):
-    if isinstance(input_file, zipfile.ZipFile):
-      return input_file.read(fn).decode()
-    else:
-      path = os.path.join(input_file, *fn.split("/"))
-      try:
-        with open(path) as f:
-          return f.read()
-      except IOError as e:
-        if e.errno == errno.ENOENT:
-          raise KeyError(fn)
+    return ReadFromInputFile(input_file, fn)
 
   try:
     d = LoadDictionaryFromLines(read_helper("META/misc_info.txt").split("\n"))
@@ -664,9 +676,14 @@
   makeint("userdata_size")
   makeint("cache_size")
   makeint("recovery_size")
-  makeint("boot_size")
   makeint("fstab_version")
 
+  boot_images = "boot.img"
+  if "boot_images" in d:
+    boot_images = d["boot_images"]
+  for b in boot_images.split():
+    makeint(b.replace(".img","_size"))
+
   # Load recovery fstab if applicable.
   d["fstab"] = _FindAndLoadRecoveryFstab(d, input_file, read_helper)
 
@@ -674,13 +691,8 @@
   # system and vendor.
   for partition in PARTITIONS_WITH_CARE_MAP:
     partition_prop = "{}.build.prop".format(partition)
-    d[partition_prop] = LoadBuildProp(
-        read_helper, "{}/build.prop".format(partition.upper()))
-    # Some partition might use /<partition>/etc/build.prop as the new path.
-    # TODO: try new path first when majority of them switch to the new path.
-    if not d[partition_prop]:
-      d[partition_prop] = LoadBuildProp(
-          read_helper, "{}/etc/build.prop".format(partition.upper()))
+    d[partition_prop] = PartitionBuildProps.FromInputFile(
+        input_file, partition)
   d["build.prop"] = d["system.build.prop"]
 
   # Set up the salt (based on fingerprint) that will be used when adding AVB
@@ -695,15 +707,6 @@
   return d
 
 
-def LoadBuildProp(read_helper, prop_file):
-  try:
-    data = read_helper(prop_file)
-  except KeyError:
-    logger.warning("Failed to read %s", prop_file)
-    data = ""
-  return LoadDictionaryFromLines(data.split("\n"))
-
-
 def LoadListFromFile(file_path):
   with open(file_path) as f:
     return f.read().splitlines()
@@ -726,6 +729,121 @@
   return d
 
 
+class PartitionBuildProps(object):
+  """The class holds the build prop of a particular partition.
+
+  This class loads the build.prop and holds the build properties for a given
+  partition. It also partially recognizes the 'import' statement in the
+  build.prop; and calculates alternative values of some specific build
+  properties during runtime.
+
+  Attributes:
+    input_file: a zipped target-file or an unzipped target-file directory.
+    partition: name of the partition.
+    props_allow_override: a list of build properties to search for the
+        alternative values during runtime.
+    build_props: a dict of build properties for the given partition.
+    prop_overrides: a set of props that are overridden by import.
+    placeholder_values: A dict of runtime variables' values to replace the
+        placeholders in the build.prop file. We expect exactly one value for
+        each of the variables.
+  """
+  def __init__(self, input_file, name, placeholder_values=None):
+    self.input_file = input_file
+    self.partition = name
+    self.props_allow_override = [props.format(name) for props in [
+        'ro.product.{}.brand', 'ro.product.{}.name', 'ro.product.{}.device']]
+    self.build_props = {}
+    self.prop_overrides = set()
+    self.placeholder_values = {}
+    if placeholder_values:
+      self.placeholder_values = copy.deepcopy(placeholder_values)
+
+  @staticmethod
+  def FromDictionary(name, build_props):
+    """Constructs an instance from a build prop dictionary."""
+
+    props = PartitionBuildProps("unknown", name)
+    props.build_props = build_props.copy()
+    return props
+
+  @staticmethod
+  def FromInputFile(input_file, name, placeholder_values=None):
+    """Loads the build.prop file and builds the attributes."""
+    data = ''
+    for prop_file in ['{}/etc/build.prop'.format(name.upper()),
+                      '{}/build.prop'.format(name.upper())]:
+      try:
+        data = ReadFromInputFile(input_file, prop_file)
+        break
+      except KeyError:
+        logger.warning('Failed to read %s', prop_file)
+
+    props = PartitionBuildProps(input_file, name, placeholder_values)
+    props._LoadBuildProp(data)
+    return props
+
+  def _LoadBuildProp(self, data):
+    for line in data.split('\n'):
+      line = line.strip()
+      if not line or line.startswith("#"):
+        continue
+      if line.startswith("import"):
+        overrides = self._ImportParser(line)
+        duplicates = self.prop_overrides.intersection(overrides.keys())
+        if duplicates:
+          raise ValueError('prop {} is overridden multiple times'.format(
+              ','.join(duplicates)))
+        self.prop_overrides = self.prop_overrides.union(overrides.keys())
+        self.build_props.update(overrides)
+      elif "=" in line:
+        name, value = line.split("=", 1)
+        if name in self.prop_overrides:
+          raise ValueError('prop {} is set again after overridden by import '
+                           'statement'.format(name))
+        self.build_props[name] = value
+
+  def _ImportParser(self, line):
+    """Parses the build prop in a given import statement."""
+
+    tokens = line.split()
+    if tokens[0] != 'import' or (len(tokens) != 2 and len(tokens) != 3) :
+      raise ValueError('Unrecognized import statement {}'.format(line))
+
+    if len(tokens) == 3:
+      logger.info("Import %s from %s, skip", tokens[2], tokens[1])
+      return {}
+
+    import_path = tokens[1]
+    if not re.match(r'^/{}/.*\.prop$'.format(self.partition), import_path):
+      raise ValueError('Unrecognized import path {}'.format(line))
+
+    # We only recognize a subset of import statement that the init process
+    # supports. And we can loose the restriction based on how the dynamic
+    # fingerprint is used in practice. The placeholder format should be
+    # ${placeholder}, and its value should be provided by the caller through
+    # the placeholder_values.
+    for prop, value in self.placeholder_values.items():
+      prop_place_holder = '${{{}}}'.format(prop)
+      if prop_place_holder in import_path:
+        import_path = import_path.replace(prop_place_holder, value)
+    if '$' in import_path:
+      logger.info('Unresolved place holder in import path %s', import_path)
+      return {}
+
+    import_path = import_path.replace('/{}'.format(self.partition),
+                                      self.partition.upper())
+    logger.info('Parsing build props override from %s', import_path)
+
+    lines = ReadFromInputFile(self.input_file, import_path).split('\n')
+    d = LoadDictionaryFromLines(lines)
+    return {key: val for key, val in d.items()
+            if key in self.props_allow_override}
+
+  def GetProp(self, prop):
+    return self.build_props.get(prop)
+
+
 def LoadRecoveryFSTab(read_helper, fstab_version, recovery_fstab_path,
                       system_root_image=False):
   class Partition(object):
@@ -973,8 +1091,9 @@
   Args:
     image_path: The output path for the new VBMeta image.
     partitions: A dict that's keyed by partition names with image paths as
-        values. Only valid partition names are accepted, as listed in
-        common.AVB_PARTITIONS.
+        values. Only valid partition names are accepted, as partitions listed
+        in common.AVB_PARTITIONS and custom partitions listed in
+        OPTIONS.info_dict.get("avb_custom_images_partition_list")
     name: Name of the VBMeta partition, e.g. 'vbmeta', 'vbmeta_system'.
     needed_partitions: Partitions whose descriptors should be included into the
         generated VBMeta image.
@@ -986,11 +1105,15 @@
   cmd = [avbtool, "make_vbmeta_image", "--output", image_path]
   AppendAVBSigningArgs(cmd, name)
 
+  custom_partitions = OPTIONS.info_dict.get(
+      "avb_custom_images_partition_list", "").strip().split()
+
   for partition, path in partitions.items():
     if partition not in needed_partitions:
       continue
     assert (partition in AVB_PARTITIONS or
-            partition in AVB_VBMETA_PARTITIONS), \
+            partition in AVB_VBMETA_PARTITIONS or
+            partition in custom_partitions), \
         'Unknown partition: {}'.format(partition)
     assert os.path.exists(path), \
         'Failed to find {} for {}'.format(path, partition)
@@ -1029,7 +1152,7 @@
     assert OPTIONS.aftl_signer_helper is not None, 'No AFTL signer helper provided.'
     # AFTL inclusion proof generation code will go here.
 
-def _MakeRamdisk(sourcedir, fs_config_file=None):
+def _MakeRamdisk(sourcedir, fs_config_file=None, lz4_ramdisks=False):
   ramdisk_img = tempfile.NamedTemporaryFile()
 
   if fs_config_file is not None and os.access(fs_config_file, os.F_OK):
@@ -1038,12 +1161,16 @@
   else:
     cmd = ["mkbootfs", os.path.join(sourcedir, "RAMDISK")]
   p1 = Run(cmd, stdout=subprocess.PIPE)
-  p2 = Run(["minigzip"], stdin=p1.stdout, stdout=ramdisk_img.file.fileno())
+  if lz4_ramdisks:
+    p2 = Run(["lz4", "-l", "-12" , "--favor-decSpeed"], stdin=p1.stdout,
+             stdout=ramdisk_img.file.fileno())
+  else:
+    p2 = Run(["minigzip"], stdin=p1.stdout, stdout=ramdisk_img.file.fileno())
 
   p2.wait()
   p1.wait()
   assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (sourcedir,)
-  assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (sourcedir,)
+  assert p2.returncode == 0, "compression of %s ramdisk failed" % (sourcedir,)
 
   return ramdisk_img
 
@@ -1081,7 +1208,8 @@
   img = tempfile.NamedTemporaryFile()
 
   if has_ramdisk:
-    ramdisk_img = _MakeRamdisk(sourcedir, fs_config_file)
+    use_lz4 = info_dict.get("lz4_ramdisks") == 'true'
+    ramdisk_img = _MakeRamdisk(sourcedir, fs_config_file, lz4_ramdisks=use_lz4)
 
   # use MKBOOTIMG from environ, or "mkbootimg" if empty or not set
   mkbootimg = os.getenv('MKBOOTIMG') or "mkbootimg"
@@ -1188,7 +1316,10 @@
   # AVB: if enabled, calculate and add hash to boot.img or recovery.img.
   if info_dict.get("avb_enable") == "true":
     avbtool = info_dict["avb_avbtool"]
-    part_size = info_dict[partition_name + "_size"]
+    if partition_name == "recovery":
+      part_size = info_dict["recovery_size"]
+    else:
+      part_size = info_dict[image_name.replace(".img","_size")]
     cmd = [avbtool, "add_hash_footer", "--image", img.name,
            "--partition_size", str(part_size), "--partition_name",
            partition_name]
@@ -1262,7 +1393,8 @@
 
   img = tempfile.NamedTemporaryFile()
 
-  ramdisk_img = _MakeRamdisk(sourcedir)
+  use_lz4 = info_dict.get("lz4_ramdisks") == 'true'
+  ramdisk_img = _MakeRamdisk(sourcedir, lz4_ramdisks=use_lz4)
 
   # use MKBOOTIMG from environ, or "mkbootimg" if empty or not set
   mkbootimg = os.getenv('MKBOOTIMG') or "mkbootimg"
@@ -2976,8 +3108,8 @@
        'recovery_sha1': recovery_img.sha1,
        'boot_type': boot_type,
        'boot_device': boot_device + '$(getprop ro.boot.slot_suffix)',
-       'recovery_type': recovery_type + '$(getprop ro.boot.slot_suffix)',
-       'recovery_device': recovery_device,
+       'recovery_type': recovery_type,
+       'recovery_device': recovery_device + '$(getprop ro.boot.slot_suffix)',
        'bonus_args': bonus_args}
 
   # The install script location moved from /system/etc to /system/bin in the L
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 01d33ea..3b68439 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -189,6 +189,13 @@
   --payload_signer_key_size <key_size>
       Deprecated. Use the '--payload_signer_maximum_signature_size' instead.
 
+  --boot_variable_file <path>
+      A file that contains the possible values of ro.boot.* properties. It's
+      used to calculate the possible runtime fingerprints when some
+      ro.product.* properties are overridden by the 'import' statement.
+      The file expects one property per line, and each line has the following
+      format: 'prop_name=value1,value2'. e.g. 'ro.boot.product.sku=std,pro'
+
   --skip_postinstall
       Skip the postinstall hooks when generating an A/B OTA package (default:
       False). Note that this discards ALL the hooks, including non-optional
@@ -200,6 +207,8 @@
 from __future__ import print_function
 
 import collections
+import copy
+import itertools
 import logging
 import multiprocessing
 import os.path
@@ -236,6 +245,7 @@
 OPTIONS.no_signing = False
 OPTIONS.block_based = True
 OPTIONS.updater_binary = None
+OPTIONS.oem_dicts = None
 OPTIONS.oem_source = None
 OPTIONS.oem_no_mount = False
 OPTIONS.full_radio = False
@@ -255,6 +265,7 @@
 OPTIONS.output_metadata_path = None
 OPTIONS.disable_fec_computation = False
 OPTIONS.force_non_ab = False
+OPTIONS.boot_variable_file = None
 
 
 METADATA_NAME = 'META-INF/com/android/metadata'
@@ -271,7 +282,8 @@
 # 'system_other' and bootloader partitions.
 SECONDARY_PAYLOAD_SKIPPED_IMAGES = [
     'boot', 'dtbo', 'modem', 'odm', 'product', 'radio', 'recovery',
-    'system_ext', 'vbmeta', 'vbmeta_system', 'vbmeta_vendor', 'vendor']
+    'system_ext', 'vbmeta', 'vbmeta_system', 'vbmeta_vendor', 'vendor',
+    'vendor_boot']
 
 
 class PayloadSigner(object):
@@ -926,13 +938,23 @@
   assert isinstance(target_info, common.BuildInfo)
   assert source_info is None or isinstance(source_info, common.BuildInfo)
 
+  separator = '|'
+
+  boot_variable_values = {}
+  if OPTIONS.boot_variable_file:
+    d = common.LoadDictionaryFromFile(OPTIONS.boot_variable_file)
+    for key, values in d.items():
+      boot_variable_values[key] = [val.strip() for val in values.split(',')]
+
+  post_build_devices, post_build_fingerprints = \
+      CalculateRuntimeDevicesAndFingerprints(target_info, boot_variable_values)
   metadata = {
-      'post-build' : target_info.fingerprint,
-      'post-build-incremental' : target_info.GetBuildProp(
+      'post-build': separator.join(sorted(post_build_fingerprints)),
+      'post-build-incremental': target_info.GetBuildProp(
           'ro.build.version.incremental'),
-      'post-sdk-level' : target_info.GetBuildProp(
+      'post-sdk-level': target_info.GetBuildProp(
           'ro.build.version.sdk'),
-      'post-security-patch-level' : target_info.GetBuildProp(
+      'post-security-patch-level': target_info.GetBuildProp(
           'ro.build.version.security_patch'),
   }
 
@@ -950,12 +972,15 @@
 
   is_incremental = source_info is not None
   if is_incremental:
-    metadata['pre-build'] = source_info.fingerprint
+    pre_build_devices, pre_build_fingerprints = \
+        CalculateRuntimeDevicesAndFingerprints(source_info,
+                                               boot_variable_values)
+    metadata['pre-build'] = separator.join(sorted(pre_build_fingerprints))
     metadata['pre-build-incremental'] = source_info.GetBuildProp(
         'ro.build.version.incremental')
-    metadata['pre-device'] = source_info.device
+    metadata['pre-device'] = separator.join(sorted(pre_build_devices))
   else:
-    metadata['pre-device'] = target_info.device
+    metadata['pre-device'] = separator.join(sorted(post_build_devices))
 
   # Use the actual post-timestamp, even for a downgrade case.
   metadata['post-timestamp'] = target_info.GetBuildProp('ro.build.date.utc')
@@ -1967,6 +1992,44 @@
           output_file)
 
 
+def CalculateRuntimeDevicesAndFingerprints(build_info, boot_variable_values):
+  """Returns a tuple of sets for runtime devices and fingerprints"""
+
+  device_names = {build_info.device}
+  fingerprints = {build_info.fingerprint}
+
+  if not boot_variable_values:
+    return device_names, fingerprints
+
+  # Calculate all possible combinations of the values for the boot variables.
+  keys = boot_variable_values.keys()
+  value_list = boot_variable_values.values()
+  combinations = [dict(zip(keys, values))
+                  for values in itertools.product(*value_list)]
+  for placeholder_values in combinations:
+    # Reload the info_dict as some build properties may change their values
+    # based on the value of ro.boot* properties.
+    info_dict = copy.deepcopy(build_info.info_dict)
+    for partition in common.PARTITIONS_WITH_CARE_MAP:
+      partition_prop_key = "{}.build.prop".format(partition)
+      input_file = info_dict[partition_prop_key].input_file
+      if isinstance(input_file, zipfile.ZipFile):
+        with zipfile.ZipFile(input_file.filename) as input_zip:
+          info_dict[partition_prop_key] = \
+              common.PartitionBuildProps.FromInputFile(input_zip, partition,
+                                                       placeholder_values)
+      else:
+        info_dict[partition_prop_key] = \
+            common.PartitionBuildProps.FromInputFile(input_file, partition,
+                                                     placeholder_values)
+    info_dict["build.prop"] = info_dict["system.build.prop"]
+
+    new_build_info = common.BuildInfo(info_dict, build_info.oem_dicts)
+    device_names.add(new_build_info.device)
+    fingerprints.add(new_build_info.fingerprint)
+  return device_names, fingerprints
+
+
 def main(argv):
 
   def option_handler(o, a):
@@ -2042,6 +2105,8 @@
       OPTIONS.disable_fec_computation = True
     elif o == "--force_non_ab":
       OPTIONS.force_non_ab = True
+    elif o == "--boot_variable_file":
+      OPTIONS.boot_variable_file = a
     else:
       return False
     return True
@@ -2079,6 +2144,7 @@
                                  "output_metadata_path=",
                                  "disable_fec_computation",
                                  "force_non_ab",
+                                 "boot_variable_file=",
                              ], extra_option_handler=option_handler)
 
   if len(args) != 2:
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index 52cd9a8..47360c9 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -112,6 +112,17 @@
       (e.g. "--signing_helper /path/to/helper"). The args will be appended to
       the existing ones in info dict.
 
+  --avb_extra_custom_image_key <partition=key>
+  --avb_extra_custom_image_algorithm <partition=algorithm>
+      Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
+      the specified custom images mounted on the partition. Otherwise it uses
+      the existing values in info dict.
+
+  --avb_extra_custom_image_extra_args <partition=extra_args>
+      Specify any additional args that are needed to AVB-sign the custom images
+      mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
+      args will be appended to the existing ones in info dict.
+
   --android_jar_path <path>
       Path to the android.jar to repack the apex file.
 """
@@ -956,12 +967,20 @@
     if extra_args:
       print('Setting extra AVB signing args for %s to "%s"' % (
           partition, extra_args))
-      args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
+      if partition in AVB_FOOTER_ARGS_BY_PARTITION:
+        args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
+      else:
+        # custom partition
+        args_key = "avb_{}_add_hashtree_footer_args".format(partition)
       misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
 
   for partition in AVB_FOOTER_ARGS_BY_PARTITION:
     ReplaceAvbPartitionSigningKey(partition)
 
+  for custom_partition in misc_info.get(
+      "avb_custom_images_partition_list", "").strip().split():
+    ReplaceAvbPartitionSigningKey(custom_partition)
+
 
 def RewriteAvbProps(misc_info):
   """Rewrites the props in AVB signing args."""
@@ -1208,6 +1227,18 @@
       OPTIONS.avb_extra_args['vbmeta_vendor'] = a
     elif o == "--avb_apex_extra_args":
       OPTIONS.avb_extra_args['apex'] = a
+    elif o == "--avb_extra_custom_image_key":
+      partition, key = a.split("=")
+      OPTIONS.avb_keys[partition] = key
+    elif o == "--avb_extra_custom_image_algorithm":
+      partition, algorithm = a.split("=")
+      OPTIONS.avb_algorithms[partition] = algorithm
+    elif o == "--avb_extra_custom_image_extra_args":
+      # Setting the maxsplit parameter to one, which will return a list with
+      # two elements. e.g., the second '=' should not be splitted for
+      # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
+      partition, extra_args = a.split("=", 1)
+      OPTIONS.avb_extra_args[partition] = extra_args
     else:
       return False
     return True
@@ -1252,6 +1283,9 @@
           "avb_vbmeta_vendor_algorithm=",
           "avb_vbmeta_vendor_key=",
           "avb_vbmeta_vendor_extra_args=",
+          "avb_extra_custom_image_key=",
+          "avb_extra_custom_image_algorithm=",
+          "avb_extra_custom_image_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 3d0766f..c82a40b 100644
--- a/tools/releasetools/test_add_img_to_target_files.py
+++ b/tools/releasetools/test_add_img_to_target_files.py
@@ -128,13 +128,16 @@
         'vendor_image_size' : 40960,
         'system_verity_block_device': '/dev/block/system',
         'vendor_verity_block_device': '/dev/block/vendor',
-        'system.build.prop': {
-            'ro.system.build.fingerprint':
-                'google/sailfish/12345:user/dev-keys',
-        },
-        'vendor.build.prop': {
-            'ro.vendor.build.fingerprint': 'google/sailfish/678:user/dev-keys',
-        },
+        'system.build.prop': common.PartitionBuildProps.FromDictionary(
+            'system', {
+                'ro.system.build.fingerprint':
+                'google/sailfish/12345:user/dev-keys'}
+        ),
+        'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+            'vendor', {
+                'ro.vendor.build.fingerprint':
+                'google/sailfish/678:user/dev-keys'}
+        ),
     }
 
     # Prepare the META/ folder.
@@ -206,18 +209,21 @@
     """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': {
-            'ro.system.build.fingerprint':
-                'google/sailfish/12345:user/dev-keys',
-        },
-        'vendor.build.prop': {
-            'ro.vendor.build.fingerprint': 'google/sailfish/678:user/dev-keys',
-        }
+        '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': common.PartitionBuildProps.FromDictionary(
+            'system', {
+                'ro.system.build.fingerprint':
+                'google/sailfish/12345:user/dev-keys'}
+        ),
+        'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+            'vendor', {
+                'ro.vendor.build.fingerprint':
+                'google/sailfish/678:user/dev-keys'}
+        ),
     }
 
     AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
@@ -258,17 +264,21 @@
     """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,
+        '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': {
-            'ro.system.build.thumbprint': 'google/sailfish/123:user/dev-keys',
-        },
-        'vendor.build.prop' : {
-            'ro.vendor.build.thumbprint': 'google/sailfish/456:user/dev-keys',
-        },
+        'system.build.prop': common.PartitionBuildProps.FromDictionary(
+            'system', {
+                'ro.system.build.thumbprint':
+                'google/sailfish/123:user/dev-keys'}
+        ),
+        'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+            'vendor', {
+                'ro.vendor.build.thumbprint':
+                'google/sailfish/456:user/dev-keys'}
+        ),
     }
 
     AddCareMapForAbOta(None, ['system', 'vendor'], image_paths)
diff --git a/tools/releasetools/test_apex_utils.py b/tools/releasetools/test_apex_utils.py
index e19bc90..7b4a4b0 100644
--- a/tools/releasetools/test_apex_utils.py
+++ b/tools/releasetools/test_apex_utils.py
@@ -50,11 +50,12 @@
     payload_file = self._GetTestPayload()
     apex_utils.SignApexPayload(
         'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048',
-        self.SALT, no_hashtree=True)
+        self.SALT, 'sha256', no_hashtree=True)
     payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file)
     self.assertEqual('SHA256_RSA2048', payload_info['Algorithm'])
     self.assertEqual(self.SALT, payload_info['Salt'])
     self.assertEqual('testkey', payload_info['apex.key'])
+    self.assertEqual('sha256', payload_info['Hash Algorithm'])
     self.assertEqual('0 bytes', payload_info['Tree Size'])
 
   @test_utils.SkipIfExternalToolsUnavailable()
@@ -62,7 +63,7 @@
     payload_file = self._GetTestPayload()
     apex_utils.SignApexPayload(
         'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048',
-        self.SALT, no_hashtree=True)
+        self.SALT, 'sha256', no_hashtree=True)
     apex_utils.VerifyApexPayload(
         'avbtool', payload_file, self.payload_key, True)
 
@@ -71,7 +72,7 @@
     payload_file = self._GetTestPayload()
     apex_utils.SignApexPayload(
         'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048',
-        self.SALT, no_hashtree=False)
+        self.SALT, 'sha256', no_hashtree=False)
     apex_utils.VerifyApexPayload('avbtool', payload_file, self.payload_key)
     payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file)
     self.assertEqual('4096 bytes', payload_info['Tree Size'])
@@ -81,7 +82,7 @@
     payload_file = self._GetTestPayload()
     apex_utils.SignApexPayload(
         'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048',
-        self.SALT, no_hashtree=True)
+        self.SALT, 'sha256', no_hashtree=True)
     apex_utils.VerifyApexPayload('avbtool', payload_file, self.payload_key,
                                  no_hashtree=True)
     payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file)
@@ -98,7 +99,7 @@
         'avbtool',
         payload_file,
         self.payload_key,
-        'testkey', 'SHA256_RSA2048', self.SALT,
+        'testkey', 'SHA256_RSA2048', self.SALT, 'sha256',
         True,
         payload_signer_args)
     apex_utils.VerifyApexPayload(
@@ -115,6 +116,7 @@
         'testkey',
         'SHA256_RSA2048',
         self.SALT,
+        'sha256',
         no_hashtree=True)
 
   @test_utils.SkipIfExternalToolsUnavailable()
@@ -122,7 +124,7 @@
     payload_file = self._GetTestPayload()
     apex_utils.SignApexPayload(
         'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048',
-        self.SALT, True)
+        self.SALT, 'sha256', True)
     apex_utils.VerifyApexPayload(
         'avbtool', payload_file, self.payload_key, True)
     self.assertRaises(
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index 173ef53..e4f0812 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -47,109 +47,124 @@
 class BuildInfoTest(test_utils.ReleaseToolsTestCase):
 
   TEST_INFO_DICT = {
-      'build.prop' : {
-          'ro.product.device' : 'product-device',
-          'ro.product.name' : 'product-name',
-          'ro.build.fingerprint' : 'build-fingerprint',
-          'ro.build.foo' : 'build-foo',
-      },
-      'system.build.prop' : {
-          'ro.product.system.brand' : 'product-brand',
-          'ro.product.system.name' : 'product-name',
-          'ro.product.system.device' : 'product-device',
-          'ro.system.build.version.release' : 'version-release',
-          'ro.system.build.id' : 'build-id',
-          'ro.system.build.version.incremental' : 'version-incremental',
-          'ro.system.build.type' : 'build-type',
-          'ro.system.build.tags' : 'build-tags',
-          'ro.system.build.foo' : 'build-foo',
-      },
-      'vendor.build.prop' : {
-          'ro.product.vendor.brand' : 'vendor-product-brand',
-          'ro.product.vendor.name' : 'vendor-product-name',
-          'ro.product.vendor.device' : 'vendor-product-device',
-          'ro.vendor.build.version.release' : 'vendor-version-release',
-          'ro.vendor.build.id' : 'vendor-build-id',
-          'ro.vendor.build.version.incremental' : 'vendor-version-incremental',
-          'ro.vendor.build.type' : 'vendor-build-type',
-          'ro.vendor.build.tags' : 'vendor-build-tags',
-      },
-      'property1' : 'value1',
-      'property2' : 4096,
+      'build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.device': 'product-device',
+              'ro.product.name': 'product-name',
+              'ro.build.fingerprint': 'build-fingerprint',
+              'ro.build.foo': 'build-foo'}
+      ),
+      'system.build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.system.brand': 'product-brand',
+              'ro.product.system.name': 'product-name',
+              'ro.product.system.device': 'product-device',
+              'ro.system.build.version.release': 'version-release',
+              'ro.system.build.id': 'build-id',
+              'ro.system.build.version.incremental': 'version-incremental',
+              'ro.system.build.type': 'build-type',
+              'ro.system.build.tags': 'build-tags',
+              'ro.system.build.foo': 'build-foo'}
+      ),
+      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+          'vendor', {
+              'ro.product.vendor.brand': 'vendor-product-brand',
+              'ro.product.vendor.name': 'vendor-product-name',
+              'ro.product.vendor.device': 'vendor-product-device',
+              'ro.vendor.build.version.release': 'vendor-version-release',
+              'ro.vendor.build.id': 'vendor-build-id',
+              'ro.vendor.build.version.incremental':
+              'vendor-version-incremental',
+              'ro.vendor.build.type': 'vendor-build-type',
+              'ro.vendor.build.tags': 'vendor-build-tags'}
+      ),
+      'property1': 'value1',
+      'property2': 4096,
   }
 
   TEST_INFO_DICT_USES_OEM_PROPS = {
-      'build.prop' : {
-          'ro.product.name' : 'product-name',
-          'ro.build.thumbprint' : 'build-thumbprint',
-          'ro.build.bar' : 'build-bar',
-      },
-      'vendor.build.prop' : {
-          'ro.vendor.build.fingerprint' : 'vendor-build-fingerprint',
-      },
-      'property1' : 'value1',
-      'property2' : 4096,
-      'oem_fingerprint_properties' : 'ro.product.device ro.product.brand',
+      'build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.name': 'product-name',
+              'ro.build.thumbprint': 'build-thumbprint',
+              'ro.build.bar': 'build-bar'}
+      ),
+      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+          'vendor', {
+              'ro.vendor.build.fingerprint': 'vendor-build-fingerprint'}
+      ),
+      'property1': 'value1',
+      'property2': 4096,
+      'oem_fingerprint_properties': 'ro.product.device ro.product.brand',
   }
 
   TEST_OEM_DICTS = [
       {
-          'ro.product.brand' : 'brand1',
-          'ro.product.device' : 'device1',
+          'ro.product.brand': 'brand1',
+          'ro.product.device': 'device1',
       },
       {
-          'ro.product.brand' : 'brand2',
-          'ro.product.device' : 'device2',
+          'ro.product.brand': 'brand2',
+          'ro.product.device': 'device2',
       },
       {
-          'ro.product.brand' : 'brand3',
-          'ro.product.device' : 'device3',
+          'ro.product.brand': 'brand3',
+          'ro.product.device': 'device3',
       },
   ]
 
   TEST_INFO_DICT_PROPERTY_SOURCE_ORDER = {
-      'build.prop' : {
-          'ro.build.fingerprint' : 'build-fingerprint',
-          'ro.product.property_source_order' :
-              'product,odm,vendor,system_ext,system',
-      },
-      'system.build.prop' : {
-          'ro.product.system.device' : 'system-product-device',
-      },
-      'vendor.build.prop' : {
-          'ro.product.vendor.device' : 'vendor-product-device',
-      },
+      'build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.build.fingerprint': 'build-fingerprint',
+              'ro.product.property_source_order':
+                  'product,odm,vendor,system_ext,system'}
+      ),
+      'system.build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.system.device': 'system-product-device'}
+      ),
+      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+          'vendor', {
+              'ro.product.vendor.device': 'vendor-product-device'}
+      ),
   }
 
   TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_10 = {
-      'build.prop' : {
-          'ro.build.fingerprint' : 'build-fingerprint',
-          'ro.product.property_source_order' :
-              'product,product_services,odm,vendor,system',
-          'ro.build.version.release' : '10',
-          'ro.build.version.codename' : 'REL',
-      },
-      'system.build.prop' : {
-          'ro.product.system.device' : 'system-product-device',
-      },
-      'vendor.build.prop' : {
-          'ro.product.vendor.device' : 'vendor-product-device',
-      },
+      'build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.build.fingerprint': 'build-fingerprint',
+              'ro.product.property_source_order':
+                  'product,product_services,odm,vendor,system',
+              'ro.build.version.release': '10',
+              'ro.build.version.codename': 'REL'}
+      ),
+      'system.build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.system.device': 'system-product-device'}
+      ),
+      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+          'vendor', {
+              'ro.product.vendor.device': 'vendor-product-device'}
+      ),
   }
 
   TEST_INFO_DICT_PROPERTY_SOURCE_ORDER_ANDROID_9 = {
-      'build.prop' : {
-          'ro.product.device' : 'product-device',
-          'ro.build.fingerprint' : 'build-fingerprint',
-          'ro.build.version.release' : '9',
-          'ro.build.version.codename' : 'REL',
-      },
-      'system.build.prop' : {
-          'ro.product.system.device' : 'system-product-device',
-      },
-      'vendor.build.prop' : {
-          'ro.product.vendor.device' : 'vendor-product-device',
-      },
+      'build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.device': 'product-device',
+              'ro.build.fingerprint': 'build-fingerprint',
+              'ro.build.version.release': '9',
+              'ro.build.version.codename': 'REL'}
+      ),
+      'system.build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.system.device': 'system-product-device'}
+      ),
+      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+          'vendor', {
+              'ro.product.vendor.device': 'vendor-product-device'}
+      ),
   }
 
   def test_init(self):
@@ -177,25 +192,27 @@
 
   def test_init_badFingerprint(self):
     info_dict = copy.deepcopy(self.TEST_INFO_DICT)
-    info_dict['build.prop']['ro.build.fingerprint'] = 'bad fingerprint'
+    info_dict['build.prop'].build_props[
+        'ro.build.fingerprint'] = 'bad fingerprint'
     self.assertRaises(ValueError, common.BuildInfo, info_dict, None)
 
-    info_dict['build.prop']['ro.build.fingerprint'] = 'bad\x80fingerprint'
+    info_dict['build.prop'].build_props[
+        'ro.build.fingerprint'] = 'bad\x80fingerprint'
     self.assertRaises(ValueError, common.BuildInfo, info_dict, None)
 
   def test___getitem__(self):
     target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
     self.assertEqual('value1', target_info['property1'])
     self.assertEqual(4096, target_info['property2'])
-    self.assertEqual('build-foo', target_info['build.prop']['ro.build.foo'])
+    self.assertEqual('build-foo',
+                     target_info['build.prop'].GetProp('ro.build.foo'))
 
   def test___getitem__with_oem_props(self):
     target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
                                    self.TEST_OEM_DICTS)
     self.assertEqual('value1', target_info['property1'])
     self.assertEqual(4096, target_info['property2'])
-    self.assertRaises(KeyError,
-                      lambda: target_info['build.prop']['ro.build.foo'])
+    self.assertIsNone(target_info['build.prop'].GetProp('ro.build.foo'))
 
   def test___setitem__(self):
     target_info = common.BuildInfo(copy.deepcopy(self.TEST_INFO_DICT), None)
@@ -203,9 +220,11 @@
     target_info['property1'] = 'value2'
     self.assertEqual('value2', target_info['property1'])
 
-    self.assertEqual('build-foo', target_info['build.prop']['ro.build.foo'])
-    target_info['build.prop']['ro.build.foo'] = 'build-bar'
-    self.assertEqual('build-bar', target_info['build.prop']['ro.build.foo'])
+    self.assertEqual('build-foo',
+                     target_info['build.prop'].GetProp('ro.build.foo'))
+    target_info['build.prop'].build_props['ro.build.foo'] = 'build-bar'
+    self.assertEqual('build-bar',
+                     target_info['build.prop'].GetProp('ro.build.foo'))
 
   def test_get(self):
     target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
@@ -213,7 +232,8 @@
     self.assertEqual(4096, target_info.get('property2'))
     self.assertEqual(4096, target_info.get('property2', 1024))
     self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
-    self.assertEqual('build-foo', target_info.get('build.prop')['ro.build.foo'])
+    self.assertEqual('build-foo',
+                     target_info.get('build.prop').GetProp('ro.build.foo'))
 
   def test_get_with_oem_props(self):
     target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
@@ -222,9 +242,7 @@
     self.assertEqual(4096, target_info.get('property2'))
     self.assertEqual(4096, target_info.get('property2', 1024))
     self.assertEqual(1024, target_info.get('property-nonexistent', 1024))
-    self.assertIsNone(target_info.get('build.prop').get('ro.build.foo'))
-    self.assertRaises(KeyError,
-                      lambda: target_info.get('build.prop')['ro.build.foo'])
+    self.assertIsNone(target_info.get('build.prop').GetProp('ro.build.foo'))
 
   def test_items(self):
     target_info = common.BuildInfo(self.TEST_INFO_DICT, None)
@@ -261,7 +279,8 @@
 
   def test_GetPartitionFingerprint_uses_fingerprint_prop_if_available(self):
     info_dict = copy.deepcopy(self.TEST_INFO_DICT)
-    info_dict['vendor.build.prop']['ro.vendor.build.fingerprint'] = 'vendor:fingerprint'
+    info_dict['vendor.build.prop'].build_props[
+        'ro.vendor.build.fingerprint'] = 'vendor:fingerprint'
     target_info = common.BuildInfo(info_dict, None)
     self.assertEqual(
         target_info.GetPartitionFingerprint('vendor'),
@@ -302,14 +321,15 @@
 
   def test_ResolveRoProductProperty_FromSystem(self):
     info_dict = copy.deepcopy(self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER)
-    del info_dict['vendor.build.prop']['ro.product.vendor.device']
+    del info_dict['vendor.build.prop'].build_props['ro.product.vendor.device']
     info = common.BuildInfo(info_dict, None)
     self.assertEqual('system-product-device',
                      info.GetBuildProp('ro.product.device'))
 
   def test_ResolveRoProductProperty_InvalidPropertySearchOrder(self):
     info_dict = copy.deepcopy(self.TEST_INFO_DICT_PROPERTY_SOURCE_ORDER)
-    info_dict['build.prop']['ro.product.property_source_order'] = 'bad-source'
+    info_dict['build.prop'].build_props[
+        'ro.product.property_source_order'] = 'bad-source'
     with self.assertRaisesRegexp(common.ExternalError,
         'Invalid ro.product.property_source_order'):
       info = common.BuildInfo(info_dict, None)
@@ -1792,3 +1812,241 @@
 
     lines = self.get_op_list(self.output_path)
     self.assertEqual(lines, ["remove foo"])
+
+
+class PartitionBuildPropsTest(test_utils.ReleaseToolsTestCase):
+  def setUp(self):
+    self.odm_build_prop = [
+        'ro.odm.build.date.utc=1578430045',
+        'ro.odm.build.fingerprint='
+        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
+        'ro.product.odm.device=coral',
+        'import /odm/etc/build_${ro.boot.product.device_name}.prop',
+    ]
+
+  @staticmethod
+  def _BuildZipFile(entries):
+    input_file = common.MakeTempFile(prefix='target_files-', suffix='.zip')
+    with zipfile.ZipFile(input_file, 'w') as input_zip:
+      for name, content in entries.items():
+        input_zip.writestr(name, content)
+
+    return input_file
+
+  def test_parseBuildProps_noImportStatement(self):
+    build_prop = [
+        'ro.odm.build.date.utc=1578430045',
+        'ro.odm.build.fingerprint='
+        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
+        'ro.product.odm.device=coral',
+    ]
+    input_file = self._BuildZipFile({
+        'ODM/etc/build.prop': '\n'.join(build_prop),
+    })
+
+    with zipfile.ZipFile(input_file, 'r') as input_zip:
+      placeholder_values = {
+          'ro.boot.product.device_name': ['std', 'pro']
+      }
+      partition_props = common.PartitionBuildProps.FromInputFile(
+          input_zip, 'odm', placeholder_values)
+
+    self.assertEqual({
+        'ro.odm.build.date.utc': '1578430045',
+        'ro.odm.build.fingerprint':
+        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
+        'ro.product.odm.device': 'coral',
+    }, partition_props.build_props)
+
+    self.assertEqual(set(), partition_props.prop_overrides)
+
+  def test_parseBuildProps_singleImportStatement(self):
+    build_std_prop = [
+        'ro.product.odm.device=coral',
+        'ro.product.odm.name=product1',
+    ]
+    build_pro_prop = [
+        'ro.product.odm.device=coralpro',
+        'ro.product.odm.name=product2',
+    ]
+
+    input_file = self._BuildZipFile({
+        'ODM/etc/build.prop': '\n'.join(self.odm_build_prop),
+        'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
+        'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
+    })
+
+    with zipfile.ZipFile(input_file, 'r') as input_zip:
+      placeholder_values = {
+          'ro.boot.product.device_name': 'std'
+      }
+      partition_props = common.PartitionBuildProps.FromInputFile(
+          input_zip, 'odm', placeholder_values)
+
+    self.assertEqual({
+      'ro.odm.build.date.utc': '1578430045',
+      'ro.odm.build.fingerprint':
+      'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
+      'ro.product.odm.device': 'coral',
+      'ro.product.odm.name': 'product1',
+    }, partition_props.build_props)
+
+    with zipfile.ZipFile(input_file, 'r') as input_zip:
+      placeholder_values = {
+          'ro.boot.product.device_name': 'pro'
+      }
+      partition_props = common.PartitionBuildProps.FromInputFile(
+          input_zip, 'odm', placeholder_values)
+
+    self.assertEqual({
+        'ro.odm.build.date.utc': '1578430045',
+        'ro.odm.build.fingerprint':
+        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
+        'ro.product.odm.device': 'coralpro',
+        'ro.product.odm.name': 'product2',
+    }, partition_props.build_props)
+
+  def test_parseBuildProps_noPlaceHolders(self):
+    build_prop = copy.copy(self.odm_build_prop)
+    input_file = self._BuildZipFile({
+        'ODM/etc/build.prop': '\n'.join(build_prop),
+    })
+
+    with zipfile.ZipFile(input_file, 'r') as input_zip:
+      partition_props = common.PartitionBuildProps.FromInputFile(
+          input_zip, 'odm')
+
+    self.assertEqual({
+        'ro.odm.build.date.utc': '1578430045',
+        'ro.odm.build.fingerprint':
+        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
+        'ro.product.odm.device': 'coral',
+    }, partition_props.build_props)
+
+    self.assertEqual(set(), partition_props.prop_overrides)
+
+  def test_parseBuildProps_multipleImportStatements(self):
+    build_prop = copy.deepcopy(self.odm_build_prop)
+    build_prop.append(
+        'import /odm/etc/build_${ro.boot.product.product_name}.prop')
+
+    build_std_prop = [
+        'ro.product.odm.device=coral',
+    ]
+    build_pro_prop = [
+        'ro.product.odm.device=coralpro',
+    ]
+
+    product1_prop = [
+        'ro.product.odm.name=product1',
+        'ro.product.not_care=not_care',
+    ]
+
+    product2_prop = [
+        'ro.product.odm.name=product2',
+        'ro.product.not_care=not_care',
+    ]
+
+    input_file = self._BuildZipFile({
+        'ODM/etc/build.prop': '\n'.join(build_prop),
+        'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
+        'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
+        'ODM/etc/build_product1.prop': '\n'.join(product1_prop),
+        'ODM/etc/build_product2.prop': '\n'.join(product2_prop),
+    })
+
+    with zipfile.ZipFile(input_file, 'r') as input_zip:
+      placeholder_values = {
+          'ro.boot.product.device_name': 'std',
+          'ro.boot.product.product_name': 'product1',
+          'ro.boot.product.not_care': 'not_care',
+      }
+      partition_props = common.PartitionBuildProps.FromInputFile(
+          input_zip, 'odm', placeholder_values)
+
+    self.assertEqual({
+        'ro.odm.build.date.utc': '1578430045',
+        'ro.odm.build.fingerprint':
+        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
+        'ro.product.odm.device': 'coral',
+        'ro.product.odm.name': 'product1'
+    }, partition_props.build_props)
+
+    with zipfile.ZipFile(input_file, 'r') as input_zip:
+      placeholder_values = {
+          'ro.boot.product.device_name': 'pro',
+          'ro.boot.product.product_name': 'product2',
+          'ro.boot.product.not_care': 'not_care',
+      }
+      partition_props = common.PartitionBuildProps.FromInputFile(
+          input_zip, 'odm', placeholder_values)
+
+    self.assertEqual({
+        'ro.odm.build.date.utc': '1578430045',
+        'ro.odm.build.fingerprint':
+        'google/coral/coral:10/RP1A.200325.001/6337676:user/dev-keys',
+        'ro.product.odm.device': 'coralpro',
+        'ro.product.odm.name': 'product2'
+    }, partition_props.build_props)
+
+  def test_parseBuildProps_defineAfterOverride(self):
+    build_prop = copy.deepcopy(self.odm_build_prop)
+    build_prop.append('ro.product.odm.device=coral')
+
+    build_std_prop = [
+        'ro.product.odm.device=coral',
+    ]
+    build_pro_prop = [
+        'ro.product.odm.device=coralpro',
+    ]
+
+    input_file = self._BuildZipFile({
+        'ODM/etc/build.prop': '\n'.join(build_prop),
+        'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
+        'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
+    })
+
+    with zipfile.ZipFile(input_file, 'r') as input_zip:
+      placeholder_values = {
+          'ro.boot.product.device_name': 'std',
+      }
+
+      self.assertRaises(ValueError, common.PartitionBuildProps.FromInputFile,
+                        input_zip, 'odm', placeholder_values)
+
+  def test_parseBuildProps_duplicateOverride(self):
+    build_prop = copy.deepcopy(self.odm_build_prop)
+    build_prop.append(
+        'import /odm/etc/build_${ro.boot.product.product_name}.prop')
+
+    build_std_prop = [
+        'ro.product.odm.device=coral',
+        'ro.product.odm.name=product1',
+    ]
+    build_pro_prop = [
+        'ro.product.odm.device=coralpro',
+    ]
+
+    product1_prop = [
+        'ro.product.odm.name=product1',
+    ]
+
+    product2_prop = [
+        'ro.product.odm.name=product2',
+    ]
+
+    input_file = self._BuildZipFile({
+        'ODM/etc/build.prop': '\n'.join(build_prop),
+        'ODM/etc/build_std.prop': '\n'.join(build_std_prop),
+        'ODM/etc/build_pro.prop': '\n'.join(build_pro_prop),
+        'ODM/etc/build_product1.prop': '\n'.join(product1_prop),
+        'ODM/etc/build_product2.prop': '\n'.join(product2_prop),
+    })
+
+    with zipfile.ZipFile(input_file, 'r') as input_zip:
+      placeholder_values = {
+          'ro.boot.product.device_name': 'std',
+          'ro.boot.product.product_name': 'product1',
+      }
+      self.assertRaises(ValueError, common.PartitionBuildProps.FromInputFile,
+                        input_zip, 'odm', placeholder_values)
diff --git a/tools/releasetools/test_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index 38faf64..7783f96 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -26,7 +26,8 @@
     GetPackageMetadata, GetTargetFilesZipForSecondaryImages,
     GetTargetFilesZipWithoutPostinstallConfig, NonAbOtaPropertyFiles,
     Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
-    StreamingPropertyFiles, WriteFingerprintAssertion)
+    StreamingPropertyFiles, WriteFingerprintAssertion,
+    CalculateRuntimeDevicesAndFingerprints)
 
 
 def construct_target_files(secondary=False):
@@ -108,55 +109,58 @@
 
 
 class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
-
   TEST_TARGET_INFO_DICT = {
-      'build.prop' : {
-          'ro.product.device' : 'product-device',
-          'ro.build.fingerprint' : 'build-fingerprint-target',
-          'ro.build.version.incremental' : 'build-version-incremental-target',
-          'ro.build.version.sdk' : '27',
-          'ro.build.version.security_patch' : '2017-12-01',
-          'ro.build.date.utc' : '1500000000',
-      },
+      'build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.device': 'product-device',
+              'ro.build.fingerprint': 'build-fingerprint-target',
+              'ro.build.version.incremental': 'build-version-incremental-target',
+              'ro.build.version.sdk': '27',
+              'ro.build.version.security_patch': '2017-12-01',
+              'ro.build.date.utc': '1500000000'}
+      )
   }
 
   TEST_SOURCE_INFO_DICT = {
-      'build.prop' : {
-          'ro.product.device' : 'product-device',
-          'ro.build.fingerprint' : 'build-fingerprint-source',
-          'ro.build.version.incremental' : 'build-version-incremental-source',
-          'ro.build.version.sdk' : '25',
-          'ro.build.version.security_patch' : '2016-12-01',
-          'ro.build.date.utc' : '1400000000',
-      },
+      'build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.device': 'product-device',
+              'ro.build.fingerprint': 'build-fingerprint-source',
+              'ro.build.version.incremental': 'build-version-incremental-source',
+              'ro.build.version.sdk': '25',
+              'ro.build.version.security_patch': '2016-12-01',
+              'ro.build.date.utc': '1400000000'}
+      )
   }
 
   TEST_INFO_DICT_USES_OEM_PROPS = {
-      'build.prop' : {
-          'ro.product.name' : 'product-name',
-          'ro.build.thumbprint' : 'build-thumbprint',
-          'ro.build.bar' : 'build-bar',
-      },
-      'vendor.build.prop' : {
-          'ro.vendor.build.fingerprint' : 'vendor-build-fingerprint',
-      },
-      'property1' : 'value1',
-      'property2' : 4096,
-      'oem_fingerprint_properties' : 'ro.product.device ro.product.brand',
+      'build.prop': common.PartitionBuildProps.FromDictionary(
+          'system', {
+              'ro.product.name': 'product-name',
+              'ro.build.thumbprint': 'build-thumbprint',
+              'ro.build.bar': 'build-bar'}
+      ),
+      'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
+          'vendor', {
+               'ro.vendor.build.fingerprint': 'vendor-build-fingerprint'}
+      ),
+      'property1': 'value1',
+      'property2': 4096,
+      'oem_fingerprint_properties': 'ro.product.device ro.product.brand',
   }
 
   TEST_OEM_DICTS = [
       {
-          'ro.product.brand' : 'brand1',
-          'ro.product.device' : 'device1',
+          'ro.product.brand': 'brand1',
+          'ro.product.device': 'device1',
       },
       {
-          'ro.product.brand' : 'brand2',
-          'ro.product.device' : 'device2',
+          'ro.product.brand': 'brand2',
+          'ro.product.device': 'device2',
       },
       {
-          'ro.product.brand' : 'brand3',
-          'ro.product.device' : 'device3',
+          'ro.product.brand': 'brand3',
+          'ro.product.device': 'device3',
       },
   ]
 
@@ -288,10 +292,10 @@
 
   @staticmethod
   def _test_GetPackageMetadata_swapBuildTimestamps(target_info, source_info):
-    (target_info['build.prop']['ro.build.date.utc'],
-     source_info['build.prop']['ro.build.date.utc']) = (
-         source_info['build.prop']['ro.build.date.utc'],
-         target_info['build.prop']['ro.build.date.utc'])
+    (target_info['build.prop'].build_props['ro.build.date.utc'],
+     source_info['build.prop'].build_props['ro.build.date.utc']) = (
+         source_info['build.prop'].build_props['ro.build.date.utc'],
+         target_info['build.prop'].build_props['ro.build.date.utc'])
 
   def test_GetPackageMetadata_unintentionalDowngradeDetected(self):
     target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
@@ -528,7 +532,7 @@
   def test_WriteFingerprintAssertion_without_oem_props(self):
     target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
     source_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
-    source_info_dict['build.prop']['ro.build.fingerprint'] = (
+    source_info_dict['build.prop'].build_props['ro.build.fingerprint'] = (
         'source-build-fingerprint')
     source_info = common.BuildInfo(source_info_dict, None)
 
@@ -567,7 +571,7 @@
     target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
                                    self.TEST_OEM_DICTS)
     source_info_dict = copy.deepcopy(self.TEST_INFO_DICT_USES_OEM_PROPS)
-    source_info_dict['build.prop']['ro.build.thumbprint'] = (
+    source_info_dict['build.prop'].build_props['ro.build.thumbprint'] = (
         'source-build-thumbprint')
     source_info = common.BuildInfo(source_info_dict, self.TEST_OEM_DICTS)
 
@@ -1315,3 +1319,239 @@
             Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
           continue
         self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
+
+
+class RuntimeFingerprintTest(test_utils.ReleaseToolsTestCase):
+  MISC_INFO = [
+      'recovery_api_version=3',
+      'fstab_version=2',
+      'recovery_as_boot=true',
+  ]
+
+  BUILD_PROP = [
+      'ro.build.version.release=version-release',
+      'ro.build.id=build-id',
+      'ro.build.version.incremental=version-incremental',
+      'ro.build.type=build-type',
+      'ro.build.tags=build-tags',
+      'ro.build.version.sdk=30',
+      'ro.build.version.security_patch=2020',
+      'ro.build.date.utc=12345678'
+  ]
+
+  VENDOR_BUILD_PROP = [
+      'ro.product.vendor.brand=vendor-product-brand',
+      'ro.product.vendor.name=vendor-product-name',
+      'ro.product.vendor.device=vendor-product-device'
+  ]
+
+  def setUp(self):
+    common.OPTIONS.oem_dicts = None
+    self.test_dir = common.MakeTempDir()
+    self.writeFiles({'META/misc_info.txt': '\n'.join(self.MISC_INFO)},
+                    self.test_dir)
+
+  def writeFiles(self, contents_dict, out_dir):
+    for path, content in contents_dict.items():
+      abs_path = os.path.join(out_dir, path)
+      dir_name = os.path.dirname(abs_path)
+      if not os.path.exists(dir_name):
+        os.makedirs(dir_name)
+      with open(abs_path, 'w') as f:
+        f.write(content)
+
+  @staticmethod
+  def constructFingerprint(prefix):
+    return '{}:version-release/build-id/version-incremental:' \
+           'build-type/build-tags'.format(prefix)
+
+  def test_CalculatePossibleFingerprints_no_dynamic_fingerprint(self):
+    build_prop = copy.deepcopy(self.BUILD_PROP)
+    build_prop.extend([
+        'ro.product.brand=product-brand',
+        'ro.product.name=product-name',
+        'ro.product.device=product-device',
+    ])
+    self.writeFiles({
+        'SYSTEM/build.prop': '\n'.join(build_prop),
+        'VENDOR/build.prop': '\n'.join(self.VENDOR_BUILD_PROP),
+    }, self.test_dir)
+
+    build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
+    expected = ({'product-device'},
+                {self.constructFingerprint(
+                    'product-brand/product-name/product-device')})
+    self.assertEqual(expected,
+                     CalculateRuntimeDevicesAndFingerprints(build_info, {}))
+
+  def test_CalculatePossibleFingerprints_single_override(self):
+    vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
+    vendor_build_prop.extend([
+        'import /vendor/etc/build_${ro.boot.sku_name}.prop',
+    ])
+    self.writeFiles({
+        'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
+        'VENDOR/build.prop': '\n'.join(vendor_build_prop),
+        'VENDOR/etc/build_std.prop':
+        'ro.product.vendor.name=vendor-product-std',
+        'VENDOR/etc/build_pro.prop':
+        'ro.product.vendor.name=vendor-product-pro',
+    }, self.test_dir)
+
+    build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
+    boot_variable_values = {'ro.boot.sku_name': ['std', 'pro']}
+
+    expected = ({'vendor-product-device'}, {
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-name/vendor-product-device'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-std/vendor-product-device'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-pro/vendor-product-device'),
+    })
+    self.assertEqual(
+        expected, CalculateRuntimeDevicesAndFingerprints(
+            build_info, boot_variable_values))
+
+  def test_CalculatePossibleFingerprints_multiple_overrides(self):
+    vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
+    vendor_build_prop.extend([
+        'import /vendor/etc/build_${ro.boot.sku_name}.prop',
+        'import /vendor/etc/build_${ro.boot.device_name}.prop',
+    ])
+    self.writeFiles({
+        'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
+        'VENDOR/build.prop': '\n'.join(vendor_build_prop),
+        'VENDOR/etc/build_std.prop':
+        'ro.product.vendor.name=vendor-product-std',
+        'VENDOR/etc/build_product1.prop':
+        'ro.product.vendor.device=vendor-device-product1',
+        'VENDOR/etc/build_pro.prop':
+        'ro.product.vendor.name=vendor-product-pro',
+        'VENDOR/etc/build_product2.prop':
+        'ro.product.vendor.device=vendor-device-product2',
+    }, self.test_dir)
+
+    build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
+    boot_variable_values = {
+        'ro.boot.sku_name': ['std', 'pro'],
+        'ro.boot.device_name': ['product1', 'product2'],
+    }
+
+    expected_devices = {'vendor-product-device', 'vendor-device-product1',
+                        'vendor-device-product2'}
+    expected_fingerprints = {
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-name/vendor-product-device'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-std/vendor-device-product1'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-pro/vendor-device-product1'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-std/vendor-device-product2'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-pro/vendor-device-product2')
+    }
+    self.assertEqual((expected_devices, expected_fingerprints),
+                     CalculateRuntimeDevicesAndFingerprints(
+                         build_info, boot_variable_values))
+
+  def test_GetPackageMetadata_full_package(self):
+    vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
+    vendor_build_prop.extend([
+        'import /vendor/etc/build_${ro.boot.sku_name}.prop',
+    ])
+    self.writeFiles({
+        'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
+        'VENDOR/build.prop': '\n'.join(vendor_build_prop),
+        'VENDOR/etc/build_std.prop':
+        'ro.product.vendor.name=vendor-product-std',
+        'VENDOR/etc/build_pro.prop':
+        'ro.product.vendor.name=vendor-product-pro',
+    }, self.test_dir)
+
+    common.OPTIONS.boot_variable_file = common.MakeTempFile()
+    with open(common.OPTIONS.boot_variable_file, 'w') as f:
+      f.write('ro.boot.sku_name=std,pro')
+
+    build_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
+    metadata = GetPackageMetadata(build_info)
+    self.assertEqual('vendor-product-device', metadata['pre-device'])
+    fingerprints = [
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-name/vendor-product-device'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-pro/vendor-product-device'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-std/vendor-product-device'),
+    ]
+    self.assertEqual('|'.join(fingerprints), metadata['post-build'])
+
+  def test_GetPackageMetadata_incremental_package(self):
+    vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
+    vendor_build_prop.extend([
+        'import /vendor/etc/build_${ro.boot.sku_name}.prop',
+    ])
+    self.writeFiles({
+        'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
+        'VENDOR/build.prop': '\n'.join(vendor_build_prop),
+        'VENDOR/etc/build_std.prop':
+        'ro.product.vendor.device=vendor-device-std',
+        'VENDOR/etc/build_pro.prop':
+        'ro.product.vendor.device=vendor-device-pro',
+    }, self.test_dir)
+
+    common.OPTIONS.boot_variable_file = common.MakeTempFile()
+    with open(common.OPTIONS.boot_variable_file, 'w') as f:
+      f.write('ro.boot.sku_name=std,pro')
+
+    source_dir = common.MakeTempDir()
+    source_build_prop = [
+        'ro.build.version.release=source-version-release',
+        'ro.build.id=source-build-id',
+        'ro.build.version.incremental=source-version-incremental',
+        'ro.build.type=build-type',
+        'ro.build.tags=build-tags',
+        'ro.build.version.sdk=29',
+        'ro.build.version.security_patch=2020',
+        'ro.build.date.utc=12340000'
+    ]
+    self.writeFiles({
+        'META/misc_info.txt': '\n'.join(self.MISC_INFO),
+        'SYSTEM/build.prop': '\n'.join(source_build_prop),
+        'VENDOR/build.prop': '\n'.join(vendor_build_prop),
+        'VENDOR/etc/build_std.prop':
+        'ro.product.vendor.device=vendor-device-std',
+        'VENDOR/etc/build_pro.prop':
+        'ro.product.vendor.device=vendor-device-pro',
+    }, source_dir)
+    common.OPTIONS.incremental_source = source_dir
+
+    target_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
+    source_info = common.BuildInfo(common.LoadInfoDict(source_dir))
+
+    metadata = GetPackageMetadata(target_info, source_info)
+    self.assertEqual(
+        'vendor-device-pro|vendor-device-std|vendor-product-device',
+        metadata['pre-device'])
+    suffix = ':source-version-release/source-build-id/' \
+             'source-version-incremental:build-type/build-tags'
+    pre_fingerprints = [
+        'vendor-product-brand/vendor-product-name/vendor-device-pro'
+        '{}'.format(suffix),
+        'vendor-product-brand/vendor-product-name/vendor-device-std'
+        '{}'.format(suffix),
+        'vendor-product-brand/vendor-product-name/vendor-product-device'
+        '{}'.format(suffix),
+    ]
+    self.assertEqual('|'.join(pre_fingerprints), metadata['pre-build'])
+
+    post_fingerprints = [
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-name/vendor-device-pro'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-name/vendor-device-std'),
+        self.constructFingerprint(
+            'vendor-product-brand/vendor-product-name/vendor-product-device'),
+    ]
+    self.assertEqual('|'.join(post_fingerprints), metadata['post-build'])
diff --git a/tools/releasetools/validate_target_files.py b/tools/releasetools/validate_target_files.py
index 1b918cc..ac469eb 100755
--- a/tools/releasetools/validate_target_files.py
+++ b/tools/releasetools/validate_target_files.py
@@ -352,8 +352,13 @@
     cmd = [info_dict['avb_avbtool'], 'verify_image', '--image', image,
            '--follow_chain_partitions']
 
+    # Custom images.
+    custom_partitions = info_dict.get(
+        "avb_custom_images_partition_list", "").strip().split()
+
     # Append the args for chained partitions if any.
-    for partition in common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS:
+    for partition in (common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS +
+                      tuple(custom_partitions)):
       key_name = 'avb_' + partition + '_key_path'
       if info_dict.get(key_name) is not None:
         if info_dict.get('ab_update') != 'true' and partition == 'recovery':
@@ -366,6 +371,17 @@
             partition, info_dict, key_file)
         cmd.extend(['--expected_chain_partition', chained_partition_arg])
 
+    # Handle the boot image with a non-default name, e.g. boot-5.4.img
+    boot_images = info_dict.get("boot_images")
+    if boot_images:
+      # we used the 1st boot image to generate the vbmeta. Rename the filename
+      # to boot.img so that avbtool can find it correctly.
+      first_image_name = boot_images.split()[0]
+      first_image_path = os.path.join(input_tmp, 'IMAGES', first_image_name)
+      assert os.path.isfile(first_image_path)
+      renamed_boot_image_path = os.path.join(input_tmp, 'IMAGES', 'boot.img')
+      os.rename(first_image_path, renamed_boot_image_path)
+
     proc = common.Run(cmd)
     stdoutdata, _ = proc.communicate()
     assert proc.returncode == 0, \
diff --git a/tools/releasetools/verity_utils.py b/tools/releasetools/verity_utils.py
index e7f84f5..fc83689 100644
--- a/tools/releasetools/verity_utils.py
+++ b/tools/releasetools/verity_utils.py
@@ -695,3 +695,22 @@
       raise HashtreeInfoGenerationError("Failed to reconstruct the verity tree")
 
     return self.hashtree_info
+
+
+def CreateCustomImageBuilder(info_dict, partition_name, partition_size,
+                            key_path, algorithm, signing_args):
+  builder = None
+  if info_dict.get("avb_enable") == "true":
+    builder = VerifiedBootVersion2VerityImageBuilder(
+        partition_name,
+        partition_size,
+        VerifiedBootVersion2VerityImageBuilder.AVB_HASHTREE_FOOTER,
+        info_dict.get("avb_avbtool"),
+        key_path,
+        algorithm,
+        # Salt is None because custom images have no fingerprint property to be
+        # used as the salt.
+        None,
+        signing_args)
+
+  return builder