Merge "Check module existence with ALL_MODULES subvars"
diff --git a/core/Makefile b/core/Makefile
index 6926b26..7a3757c 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -204,6 +204,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)
+	$($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_STRIP) -o $(2) --strip-debug $(1)
+endef
+
 # $(1): modules list
 # $(2): output dir
 # $(3): mount point
@@ -211,9 +216,15 @@
 # $(5): module load list
 # $(6): module load list filename
 # $(7): module archive
+# $(8): staging dir for stripped modules
 # 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))) \
+  $(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/$(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 \
@@ -267,24 +278,24 @@
 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
 
 ifneq ($(BUILDING_VENDOR_BOOT_IMAGE),true)
@@ -310,37 +321,49 @@
 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)))
+      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),$(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)))
+  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),))
 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)))
+  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),$(call intermediates-dir-for,PACKAGING,depmod_vendor_ramdisk_stripped)))
+  ifneq (,$(BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD))
+    # BOARD_VENDOR_RAMDISK_KERNEL_MODULES must be the full set, or super set,
+    # of copied modules represented by BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD
+    # and BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD which are mined
+    # from modules.load which will contain relative paths, represent load order.
+    ALL_DEFAULT_INSTALLED_MODULES += $(call copy-many-files,$(call module-load-list-copy-paths,$(call intermediates-dir-for,PACKAGING,depmod_vendor_recovery_ramdisk),$(BOARD_VENDOR_RAMDISK_KERNEL_MODULES),$(BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD),modules.load.recovery,$(TARGET_VENDOR_RAMDISK_OUT),))
+  endif
 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,))
+    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 ($(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_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)))
+  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),$(VENDOR_STRIPPED_MODULE_STAGING_DIR)))
 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)))
+  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
 
 # -----------------------------------------------------------------
@@ -1389,7 +1412,7 @@
 
 recovery_kernel := $(INSTALLED_KERNEL_TARGET) # same as a non-recovery system
 recovery_ramdisk := $(PRODUCT_OUT)/ramdisk-recovery.img
-recovery_resources_common := $(call include-path-for, recovery)/res
+recovery_resources_common := bootable/recovery/res
 
 # Set recovery_density to a density bucket based on TARGET_SCREEN_DENSITY, PRODUCT_AAPT_PREF_CONFIG,
 # or mdpi, in order of preference. We support both specific buckets (e.g. xdpi) and numbers,
@@ -1417,9 +1440,9 @@
 # Note that the font selected here can be overridden for a particular device by putting a font.png
 # in its private recovery resources.
 ifneq (,$(filter xxxhdpi xxhdpi xhdpi,$(recovery_density)))
-recovery_font := $(call include-path-for, recovery)/fonts/18x32.png
+recovery_font := bootable/recovery/fonts/18x32.png
 else
-recovery_font := $(call include-path-for, recovery)/fonts/12x22.png
+recovery_font := bootable/recovery/fonts/12x22.png
 endif
 
 
@@ -1443,7 +1466,7 @@
 endif
 
 
-RECOVERY_INSTALLING_TEXT_FILE := $(call intermediates-dir-for,PACKAGING,recovery_text_res)/installing_text.png
+RECOVERY_INSTALLING_TEXT_FILE := $(call intermediates-dir-for,ETC,recovery_text_res)/installing_text.png
 RECOVERY_INSTALLING_SECURITY_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/installing_security_text.png
 RECOVERY_ERASING_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/erasing_text.png
 RECOVERY_ERROR_TEXT_FILE := $(dir $(RECOVERY_INSTALLING_TEXT_FILE))/error_text.png
@@ -1467,11 +1490,12 @@
   $(RECOVERY_WIPE_DATA_CONFIRMATION_TEXT_FILE) \
   $(RECOVERY_WIPE_DATA_MENU_HEADER_TEXT_FILE)
 
-resource_dir := $(call include-path-for, recovery)/tools/recovery_l10n/res/
+resource_dir := bootable/recovery/tools/recovery_l10n/res/
+resource_dir_deps := $(sort $(shell find $(resource_dir) -name *.xml -not -name .*))
 image_generator_jar := $(HOST_OUT_JAVA_LIBRARIES)/RecoveryImageGenerator.jar
 zopflipng := $(HOST_OUT_EXECUTABLES)/zopflipng
 $(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_SOURCE_FONTS := $(recovery_noto-fonts_dep) $(recovery_roboto-fonts_dep)
-$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RECOVERY_FONT_FILES_DIR := $(call intermediates-dir-for,PACKAGING,recovery_font_files)
+$(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RECOVERY_FONT_FILES_DIR := $(call intermediates-dir-for,ETC,recovery_font_files)
 $(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_RESOURCE_DIR := $(resource_dir)
 $(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_IMAGE_GENERATOR_JAR := $(image_generator_jar)
 $(RECOVERY_INSTALLING_TEXT_FILE): PRIVATE_ZOPFLIPNG := $(zopflipng)
@@ -1489,7 +1513,7 @@
   recovery_wipe_data_menu_header \
   recovery_wipe_data_confirmation
 $(RECOVERY_INSTALLING_TEXT_FILE): .KATI_IMPLICIT_OUTPUTS := $(filter-out $(RECOVERY_INSTALLING_TEXT_FILE),$(generated_recovery_text_files))
-$(RECOVERY_INSTALLING_TEXT_FILE): $(image_generator_jar) $(resource_dir) $(recovery_noto-fonts_dep) $(recovery_roboto-fonts_dep) $(zopflipng)
+$(RECOVERY_INSTALLING_TEXT_FILE): $(image_generator_jar) $(resource_dir_deps) $(recovery_noto-fonts_dep) $(recovery_roboto-fonts_dep) $(zopflipng)
 	# Prepares the font directory.
 	@rm -rf $(PRIVATE_RECOVERY_FONT_FILES_DIR)
 	@mkdir -p $(PRIVATE_RECOVERY_FONT_FILES_DIR)
@@ -2830,6 +2854,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)
 
@@ -3000,6 +3059,18 @@
             --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
 $(eval $(call check-and-set-avb-args,boot))
 endif
@@ -3043,6 +3114,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
@@ -3113,6 +3189,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
@@ -3180,6 +3260,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) \
@@ -3739,6 +3820,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)" >> $@
@@ -3972,6 +4063,7 @@
 	    $(INSTALLED_VBMETAIMAGE_TARGET) \
 	    $(INSTALLED_ODMIMAGE_TARGET) \
 	    $(INSTALLED_DTBOIMAGE_TARGET) \
+	    $(INSTALLED_CUSTOMIMAGES_TARGET) \
 	    $(INTERNAL_SYSTEMOTHERIMAGE_FILES) \
 	    $(INSTALLED_ANDROID_INFO_TXT_TARGET) \
 	    $(INSTALLED_KERNEL_TARGET) \
@@ -4216,6 +4308,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/config.mk b/core/config.mk
index 3d08ba4..d707275 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -1215,7 +1215,7 @@
 DEFAULT_DATA_OUT_MODULES := ltp $(ltp_packages) $(kselftest_modules)
 .KATI_READONLY := DEFAULT_DATA_OUT_MODULES
 
-# Make RECORD_ALL_DEPS readonly and also set it if deps-license is a goal.
-RECORD_ALL_DEPS :=$= $(filter true,$(RECORD_ALL_DEPS))$(filter deps-license,$(MAKECMDGOALS))
+# Make RECORD_ALL_DEPS readonly.
+RECORD_ALL_DEPS :=$= $(filter true,$(RECORD_ALL_DEPS))
 
 include $(BUILD_SYSTEM)/dumpvar.mk
diff --git a/core/ninja_config.mk b/core/ninja_config.mk
index 1ead512..336048f 100644
--- a/core/ninja_config.mk
+++ b/core/ninja_config.mk
@@ -24,7 +24,6 @@
 	continuous_native_tests \
 	cts \
 	custom_images \
-	deps-license \
 	dicttool_aosp \
 	dump-products \
 	eng \
diff --git a/core/pathmap.mk b/core/pathmap.mk
index af33f5d..dacbe21 100644
--- a/core/pathmap.mk
+++ b/core/pathmap.mk
@@ -40,7 +40,6 @@
     libhardware:hardware/libhardware/include \
     libhardware_legacy:hardware/libhardware_legacy/include \
     libril:hardware/ril/include \
-    recovery:bootable/recovery \
     system-core:system/core/include \
     audio:system/media/audio/include \
     audio-effects:system/media/audio_effects/include \
diff --git a/core/rbe.mk b/core/rbe.mk
index 019ac04..9ec8481 100644
--- a/core/rbe.mk
+++ b/core/rbe.mk
@@ -28,6 +28,12 @@
     cxx_rbe_exec_strategy := "local"
   endif
 
+  ifdef RBE_CXX_COMPARE
+    cxx_compare := $(RBE_CXX_COMPARE)
+  else
+    cxx_compare := "false"
+  endif
+
   ifdef RBE_JAVAC_EXEC_STRATEGY
     javac_exec_strategy := $(RBE_JAVAC_EXEC_STRATEGY)
   else
@@ -51,7 +57,7 @@
   java_r8_d8_platform := $(platform)",Pool=java16"
 
   RBE_WRAPPER := $(rbe_dir)/rewrapper
-  RBE_CXX := --labels=type=compile,lang=cpp,compiler=clang --env_var_whitelist=PWD --exec_strategy=$(cxx_rbe_exec_strategy) --platform="$(cxx_platform)"
+  RBE_CXX := --labels=type=compile,lang=cpp,compiler=clang --env_var_whitelist=PWD --exec_strategy=$(cxx_rbe_exec_strategy) --platform="$(cxx_platform)" --compare="$(cxx_compare)"
 
   # Append rewrapper to existing *_WRAPPER variables so it's possible to
   # use both ccache and rewrapper.
diff --git a/core/soong_android_app_set.mk b/core/soong_android_app_set.mk
index e84371c..4c27e53 100644
--- a/core/soong_android_app_set.mk
+++ b/core/soong_android_app_set.mk
@@ -24,8 +24,10 @@
 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)
+	$(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))
 
diff --git a/core/sysprop.mk b/core/sysprop.mk
index ed13c03..4311572 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -406,9 +406,7 @@
 	@echo Target product buildinfo: $@
 	@mkdir -p $(dir $@)
 	$(hide) rm -f $@ && touch $@
-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)"; \
diff --git a/core/tasks/deps_licenses.mk b/core/tasks/deps_licenses.mk
deleted file mode 100644
index daf986f..0000000
--- a/core/tasks/deps_licenses.mk
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-# Copyright (C) 2015 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.
-#
-
-# Print modules and their transitive dependencies with license files.
-# To invoke, run "make deps-license PROJ_PATH=<proj-path-patterns> DEP_PATH=<dep-path-patterns>".
-# PROJ_PATH restricts the paths of the source modules; DEP_PATH restricts the paths of the dependency modules.
-# Both can be makefile patterns supported by makefile function $(filter).
-# Example: "make deps-license packages/app/% external/%" prints all modules in packages/app/ with their dpendencies in external/.
-# The printout lines look like "<module_name> :: <module_paths> :: <license_files>".
-
-ifneq (,$(filter deps-license,$(MAKECMDGOALS)))
-ifndef PROJ_PATH
-$(error To "make deps-license" you must specify PROJ_PATH and DEP_PATH.)
-endif
-ifndef DEP_PATH
-$(error To "make deps-license" you must specify PROJ_PATH and DEP_PATH.)
-endif
-
-# Expand a module's dependencies transitively.
-# $(1): the variable name to hold the result.
-# $(2): the initial module name.
-define get-module-all-dependencies
-$(eval _gmad_new := $(sort $(filter-out $($(1)),\
-  $(foreach m,$(2),$(ALL_DEPS.$(m).ALL_DEPS)))))\
-$(if $(_gmad_new),$(eval $(1) += $(_gmad_new))\
-  $(call get-module-all-dependencies,$(1),$(_gmad_new)))
-endef
-
-define print-deps-license
-$(foreach m, $(sort $(ALL_DEPS.MODULES)),\
-  $(eval m_p := $(sort $(ALL_MODULES.$(m).PATH) $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).PATH)))\
-  $(if $(filter $(PROJ_PATH),$(m_p)),\
-    $(eval deps :=)\
-    $(eval $(call get-module-all-dependencies,deps,$(m)))\
-    $(info $(m) :: $(m_p) :: $(ALL_DEPS.$(m).LICENSE))\
-    $(foreach d,$(deps),\
-      $(eval d_p := $(sort $(ALL_MODULES.$(d).PATH) $(ALL_MODULES.$(d)$(TARGET_2ND_ARCH_MODULE_SUFFIX).PATH)))\
-      $(if $(filter $(DEP_PATH),$(d_p)),\
-        $(info $(space)$(space)$(space)$(space)$(d) :: $(d_p) :: $(ALL_DEPS.$(d).LICENSE))))))
-endef
-
-.PHONY: deps-license
-deps-license:
-	@$(call print-deps-license)
-
-endif
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/target/board/emulator_arm/AndroidBoard.mk b/target/board/emulator_arm/AndroidBoard.mk
new file mode 100644
index 0000000..7911f61
--- /dev/null
+++ b/target/board/emulator_arm/AndroidBoard.mk
@@ -0,0 +1 @@
+LOCAL_PATH := $(call my-dir)
diff --git a/target/board/emulator_arm/BoardConfig.mk b/target/board/emulator_arm/BoardConfig.mk
new file mode 100644
index 0000000..287824f
--- /dev/null
+++ b/target/board/emulator_arm/BoardConfig.mk
@@ -0,0 +1,37 @@
+# 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.
+#
+
+# arm emulator specific definitions
+TARGET_ARCH := arm
+TARGET_ARCH_VARIANT := armv7-a-neon
+TARGET_CPU_VARIANT := generic
+TARGET_CPU_ABI := armeabi-v7a
+TARGET_CPU_ABI2 := armeabi
+
+include build/make/target/board/BoardConfigGsiCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
+
+BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
+
+# Wifi.
+BOARD_WLAN_DEVICE           := emulator
+BOARD_HOSTAPD_DRIVER        := NL80211
+BOARD_WPA_SUPPLICANT_DRIVER := NL80211
+BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_simulated
+BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
+WPA_SUPPLICANT_VERSION      := VER_0_8_X
+WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
+WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
+WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
diff --git a/target/board/emulator_arm/device.mk b/target/board/emulator_arm/device.mk
new file mode 100644
index 0000000..af023eb
--- /dev/null
+++ b/target/board/emulator_arm/device.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.
+#
+
+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/emulator_arm/system_ext.prop b/target/board/emulator_arm/system_ext.prop
new file mode 100644
index 0000000..64829f3
--- /dev/null
+++ b/target/board/emulator_arm/system_ext.prop
@@ -0,0 +1,5 @@
+#
+# system.prop for generic sdk
+#
+
+rild.libpath=/vendor/lib/libreference-ril.so
diff --git a/target/board/emulator_x86/BoardConfig.mk b/target/board/emulator_x86/BoardConfig.mk
new file mode 100644
index 0000000..8f79166
--- /dev/null
+++ b/target/board/emulator_x86/BoardConfig.mk
@@ -0,0 +1,40 @@
+# 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.
+#
+
+# x86 emulator specific definitions
+TARGET_CPU_ABI := x86
+TARGET_ARCH := x86
+TARGET_ARCH_VARIANT := x86
+
+TARGET_PRELINK_MODULE := false
+
+include build/make/target/board/BoardConfigGsiCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
+
+# Resize to 4G to accommodate ASAN and CTS
+BOARD_USERDATAIMAGE_PARTITION_SIZE := 4294967296
+
+BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/x86
+
+# Wifi.
+BOARD_WLAN_DEVICE           := emulator
+BOARD_HOSTAPD_DRIVER        := NL80211
+BOARD_WPA_SUPPLICANT_DRIVER := NL80211
+BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_simulated
+BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
+WPA_SUPPLICANT_VERSION      := VER_0_8_X
+WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
+WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
+WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
diff --git a/target/board/emulator_x86/device.mk b/target/board/emulator_x86/device.mk
new file mode 100644
index 0000000..7da09a9
--- /dev/null
+++ b/target/board/emulator_x86/device.mk
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+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
+
+# Ensure we package the BIOS files too.
+PRODUCT_HOST_PACKAGES += \
+	bios.bin \
+	vgabios-cirrus.bin \
diff --git a/target/board/emulator_x86/system_ext.prop b/target/board/emulator_x86/system_ext.prop
new file mode 100644
index 0000000..64829f3
--- /dev/null
+++ b/target/board/emulator_x86/system_ext.prop
@@ -0,0 +1,5 @@
+#
+# system.prop for generic sdk
+#
+
+rild.libpath=/vendor/lib/libreference-ril.so
diff --git a/target/board/emulator_x86_64/BoardConfig.mk b/target/board/emulator_x86_64/BoardConfig.mk
new file mode 100755
index 0000000..b9cbd8a
--- /dev/null
+++ b/target/board/emulator_x86_64/BoardConfig.mk
@@ -0,0 +1,42 @@
+# 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.
+#
+
+# x86_64 emulator specific definitions
+TARGET_CPU_ABI := x86_64
+TARGET_ARCH := x86_64
+TARGET_ARCH_VARIANT := x86_64
+
+TARGET_2ND_CPU_ABI := x86
+TARGET_2ND_ARCH := x86
+TARGET_2ND_ARCH_VARIANT := x86_64
+
+TARGET_PRELINK_MODULE := false
+include build/make/target/board/BoardConfigGsiCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
+
+BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
+
+BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/x86
+
+# Wifi.
+BOARD_WLAN_DEVICE           := emulator
+BOARD_HOSTAPD_DRIVER        := NL80211
+BOARD_WPA_SUPPLICANT_DRIVER := NL80211
+BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_simulated
+BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
+WPA_SUPPLICANT_VERSION      := VER_0_8_X
+WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
+WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
+WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
diff --git a/target/board/emulator_x86_64/device.mk b/target/board/emulator_x86_64/device.mk
new file mode 100755
index 0000000..7da09a9
--- /dev/null
+++ b/target/board/emulator_x86_64/device.mk
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+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
+
+# Ensure we package the BIOS files too.
+PRODUCT_HOST_PACKAGES += \
+	bios.bin \
+	vgabios-cirrus.bin \
diff --git a/target/board/emulator_x86_64/system_ext.prop b/target/board/emulator_x86_64/system_ext.prop
new file mode 100644
index 0000000..ed9d173
--- /dev/null
+++ b/target/board/emulator_x86_64/system_ext.prop
@@ -0,0 +1,5 @@
+#
+# system.prop for generic sdk
+#
+
+rild.libpath=/vendor/lib64/libreference-ril.so
diff --git a/target/board/emulator_x86_64_arm64/BoardConfig.mk b/target/board/emulator_x86_64_arm64/BoardConfig.mk
new file mode 100755
index 0000000..26b61a6
--- /dev/null
+++ b/target/board/emulator_x86_64_arm64/BoardConfig.mk
@@ -0,0 +1,59 @@
+# 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.
+#
+
+# x86_64 emulator specific definitions
+TARGET_CPU_ABI := x86_64
+TARGET_ARCH := x86_64
+TARGET_ARCH_VARIANT := x86_64
+
+TARGET_2ND_CPU_ABI := x86
+TARGET_2ND_ARCH := x86
+TARGET_2ND_ARCH_VARIANT := x86_64
+
+TARGET_NATIVE_BRIDGE_ARCH := arm64
+TARGET_NATIVE_BRIDGE_ARCH_VARIANT := armv8-a
+TARGET_NATIVE_BRIDGE_CPU_VARIANT := generic
+TARGET_NATIVE_BRIDGE_ABI := arm64-v8a
+
+TARGET_NATIVE_BRIDGE_2ND_ARCH := arm
+TARGET_NATIVE_BRIDGE_2ND_ARCH_VARIANT := armv7-a-neon
+TARGET_NATIVE_BRIDGE_2ND_CPU_VARIANT := generic
+TARGET_NATIVE_BRIDGE_2ND_ABI := armeabi-v7a armeabi
+
+BUILD_BROKEN_DUP_RULES := true
+
+TARGET_PRELINK_MODULE := false
+
+include build/make/target/board/BoardConfigMainlineCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
+
+# the settings differ from BoardConfigMainlineCommon.mk
+BOARD_USES_SYSTEM_OTHER_ODEX :=
+
+# Resize to 4G to accommodate ASAN and CTS
+BOARD_USERDATAIMAGE_PARTITION_SIZE := 4294967296
+
+BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/x86
+
+# Wifi.
+BOARD_WLAN_DEVICE           := emulator
+BOARD_HOSTAPD_DRIVER        := NL80211
+BOARD_WPA_SUPPLICANT_DRIVER := NL80211
+BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_simulated
+BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
+WPA_SUPPLICANT_VERSION      := VER_0_8_X
+WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
+WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
+WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
diff --git a/target/board/emulator_x86_64_arm64/device.mk b/target/board/emulator_x86_64_arm64/device.mk
new file mode 100755
index 0000000..af023eb
--- /dev/null
+++ b/target/board/emulator_x86_64_arm64/device.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.
+#
+
+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/emulator_x86_64_arm64/system_ext.prop b/target/board/emulator_x86_64_arm64/system_ext.prop
new file mode 100644
index 0000000..ed9d173
--- /dev/null
+++ b/target/board/emulator_x86_64_arm64/system_ext.prop
@@ -0,0 +1,5 @@
+#
+# system.prop for generic sdk
+#
+
+rild.libpath=/vendor/lib64/libreference-ril.so
diff --git a/target/board/emulator_x86_arm/BoardConfig.mk b/target/board/emulator_x86_arm/BoardConfig.mk
new file mode 100644
index 0000000..21fdbc8
--- /dev/null
+++ b/target/board/emulator_x86_arm/BoardConfig.mk
@@ -0,0 +1,52 @@
+# 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.
+#
+
+# x86 emulator specific definitions
+TARGET_CPU_ABI := x86
+TARGET_ARCH := x86
+TARGET_ARCH_VARIANT := x86
+
+TARGET_NATIVE_BRIDGE_ARCH := arm
+TARGET_NATIVE_BRIDGE_ARCH_VARIANT := armv7-a-neon
+TARGET_NATIVE_BRIDGE_CPU_VARIANT := generic
+TARGET_NATIVE_BRIDGE_ABI := armeabi-v7a armeabi
+
+BUILD_BROKEN_DUP_RULES := true
+
+#
+# The inclusion order below is important.
+# The settings in latter makefiles overwrite those in the former.
+#
+include build/make/target/board/BoardConfigMainlineCommon.mk
+include build/make/target/board/BoardConfigEmuCommon.mk
+
+# the settings differ from BoardConfigMainlineCommon.mk
+BOARD_USES_SYSTEM_OTHER_ODEX :=
+
+# Resize to 4G to accommodate ASAN and CTS
+BOARD_USERDATAIMAGE_PARTITION_SIZE := 4294967296
+
+BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/x86
+
+# Wifi.
+BOARD_WLAN_DEVICE           := emulator
+BOARD_HOSTAPD_DRIVER        := NL80211
+BOARD_WPA_SUPPLICANT_DRIVER := NL80211
+BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_simulated
+BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_simulated
+WPA_SUPPLICANT_VERSION      := VER_0_8_X
+WIFI_DRIVER_FW_PATH_PARAM   := "/dev/null"
+WIFI_DRIVER_FW_PATH_STA     := "/dev/null"
+WIFI_DRIVER_FW_PATH_AP      := "/dev/null"
diff --git a/target/board/emulator_x86_arm/device.mk b/target/board/emulator_x86_arm/device.mk
new file mode 100644
index 0000000..af023eb
--- /dev/null
+++ b/target/board/emulator_x86_arm/device.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.
+#
+
+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/emulator_x86_arm/system_ext.prop b/target/board/emulator_x86_arm/system_ext.prop
new file mode 100644
index 0000000..64829f3
--- /dev/null
+++ b/target/board/emulator_x86_arm/system_ext.prop
@@ -0,0 +1,5 @@
+#
+# system.prop for generic sdk
+#
+
+rild.libpath=/vendor/lib/libreference-ril.so
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index 4121bc1..3949737 100644
--- a/target/product/AndroidProducts.mk
+++ b/target/product/AndroidProducts.mk
@@ -57,7 +57,6 @@
     $(LOCAL_DIR)/generic.mk \
     $(LOCAL_DIR)/generic_x86.mk \
     $(LOCAL_DIR)/gsi_arm64.mk \
-    $(LOCAL_DIR)/mainline_arm64.mk \
     $(LOCAL_DIR)/mainline_system_arm64.mk \
     $(LOCAL_DIR)/mainline_system_x86.mk \
     $(LOCAL_DIR)/mainline_system_x86_arm.mk \
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index a6dd418..b70ba3d 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -49,5 +49,5 @@
     gsi_skip_mount.cfg \
     init.gsi.rc
 
-# Support addtional P and Q VNDK packages
+# Support additional P and Q VNDK packages
 PRODUCT_EXTRA_VNDK_VERSIONS := 28 29
diff --git a/target/product/mainline_arm64.mk b/target/product/mainline_arm64.mk
deleted file mode 100644
index 850c775..0000000
--- a/target/product/mainline_arm64.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Copyright (C) 2018 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.
-#
-
-$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline.mk)
-whitelist := product_manifest.xml
-$(call enforce-product-packages-exist,$(whitelist))
-
-PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
-
-# Modules that should probably be moved to /product
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
-  system/bin/healthd \
-  system/etc/init/healthd.rc \
-  system/etc/vintf/manifest/manifest_healthd.xml \
-
-PRODUCT_SHIPPING_API_LEVEL := 29
-
-# TODO(b/137033385): change this back to "all"
-PRODUCT_RESTRICT_VENDOR_FILES := owner
-
-PRODUCT_NAME := mainline_arm64
-PRODUCT_DEVICE := mainline_arm64
-PRODUCT_BRAND := generic
diff --git a/target/product/mainline_system.mk b/target/product/mainline_system.mk
index a8b75e0..bed1b28 100644
--- a/target/product/mainline_system.mk
+++ b/target/product/mainline_system.mk
@@ -104,10 +104,11 @@
 PRODUCT_PACKAGES_DEBUG += \
     avbctl \
     bootctl \
-    tinyplay \
     tinycap \
+    tinyhostless \
     tinymix \
     tinypcminfo \
+    tinyplay \
     update_engine_client \
 
 PRODUCT_HOST_PACKAGES += \
diff --git a/target/product/sdk_phone_arm64.mk b/target/product/sdk_phone_arm64.mk
index 3ab0c57..cefa288 100644
--- a/target/product/sdk_phone_arm64.mk
+++ b/target/product/sdk_phone_arm64.mk
@@ -14,7 +14,6 @@
 # limitations under the License.
 #
 QEMU_USE_SYSTEM_EXT_PARTITIONS := true
-
 PRODUCT_USE_DYNAMIC_PARTITIONS := true
 
 # This is a build configuration for a full-featured build of the
@@ -22,6 +21,11 @@
 # build quite specifically for the emulator, and might not be
 # entirely appropriate to inherit from for on-device configurations.
 
+# Enable mainline checking for exact this product name
+ifeq (sdk_phone_arm64,$(TARGET_PRODUCT))
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
+endif
+
 #
 # All components inherited here go to system image
 #
diff --git a/target/product/sdk_phone_armv7.mk b/target/product/sdk_phone_armv7.mk
index 77b8b50..c4c5a38 100644
--- a/target/product/sdk_phone_armv7.mk
+++ b/target/product/sdk_phone_armv7.mk
@@ -14,8 +14,40 @@
 # limitations under the License.
 #
 QEMU_USE_SYSTEM_EXT_PARTITIONS := true
+PRODUCT_USE_DYNAMIC_PARTITIONS := true
 
-$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_arm.mk)
+# This is a build configuration for a full-featured build of the
+# Open-Source part of the tree. It's geared toward a US-centric
+# build quite specifically for the emulator, and might not be
+# entirely appropriate to inherit from for on-device configurations.
+
+# Enable mainline checking for exact this product name
+ifeq (sdk_phone_armv7,$(TARGET_PRODUCT))
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
+endif
+
+#
+# All components inherited here go to system image
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+
+#
+# All components inherited here go to system_ext image
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system_ext.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system_ext.mk)
+
+#
+# All components inherited here go to product image
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_product.mk)
+
+#
+# All components inherited here go to vendor image
+#
+$(call inherit-product-if-exists, device/generic/goldfish/arm32-vendor.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/board/emulator_arm/device.mk)
 
 # Define the host tools and libs that are parts of the SDK.
 $(call inherit-product, sdk/build/product_sdk.mk)
@@ -29,4 +61,5 @@
 # Overrides
 PRODUCT_BRAND := Android
 PRODUCT_NAME := sdk_phone_armv7
-PRODUCT_DEVICE := generic
+PRODUCT_DEVICE := emulator_arm
+PRODUCT_MODEL := Android SDK built for arm
diff --git a/target/product/sdk_phone_x86.mk b/target/product/sdk_phone_x86.mk
index e8c60b4..bcee066 100644
--- a/target/product/sdk_phone_x86.mk
+++ b/target/product/sdk_phone_x86.mk
@@ -16,12 +16,17 @@
 QEMU_USE_SYSTEM_EXT_PARTITIONS := true
 PRODUCT_USE_DYNAMIC_PARTITIONS := true
 
+# This is a build configuration for a full-featured build of the
+# Open-Source part of the tree. It's geared toward a US-centric
+# build quite specifically for the emulator, and might not be
+# entirely appropriate to inherit from for on-device configurations.
+
 #
 # All components inherited here go to system image
 #
 $(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
 
-# Enable mainline checking for excat this product name
+# Enable mainline checking for exact this product name
 ifeq (sdk_phone_x86,$(TARGET_PRODUCT))
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
 endif
@@ -42,7 +47,7 @@
 #
 $(call inherit-product-if-exists, device/generic/goldfish/x86-vendor.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_x86/device.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/board/emulator_x86/device.mk)
 
 # Define the host tools and libs that are parts of the SDK.
 -include sdk/build/product_sdk.mk
@@ -51,5 +56,5 @@
 # Overrides
 PRODUCT_BRAND := Android
 PRODUCT_NAME := sdk_phone_x86
-PRODUCT_DEVICE := generic_x86
+PRODUCT_DEVICE := emulator_x86
 PRODUCT_MODEL := Android SDK built for x86
diff --git a/target/product/sdk_phone_x86_64.mk b/target/product/sdk_phone_x86_64.mk
index 862c66e..82bbee5 100644
--- a/target/product/sdk_phone_x86_64.mk
+++ b/target/product/sdk_phone_x86_64.mk
@@ -16,13 +16,18 @@
 QEMU_USE_SYSTEM_EXT_PARTITIONS := true
 PRODUCT_USE_DYNAMIC_PARTITIONS := true
 
+# This is a build configuration for a full-featured build of the
+# Open-Source part of the tree. It's geared toward a US-centric
+# build quite specifically for the emulator, and might not be
+# entirely appropriate to inherit from for on-device configurations.
+
 #
 # All components inherited here go to system image
 #
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
 
-# Enable mainline checking for excat this product name
+# Enable mainline checking for exact this product name
 ifeq (sdk_phone_x86_64,$(TARGET_PRODUCT))
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
 endif
@@ -43,7 +48,7 @@
 #
 $(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
 $(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_x86_64/device.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/board/emulator_x86_64/device.mk)
 
 # Define the host tools and libs that are parts of the SDK.
 -include sdk/build/product_sdk.mk
@@ -52,5 +57,5 @@
 # Overrides
 PRODUCT_BRAND := Android
 PRODUCT_NAME := sdk_phone_x86_64
-PRODUCT_DEVICE := generic_x86_64
+PRODUCT_DEVICE := emulator_x86_64
 PRODUCT_MODEL := Android SDK built for x86_64
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 70ea967..490b44a 100755
--- 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.
@@ -831,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/common.py b/tools/releasetools/common.py
index 96f93a8..93e14e5 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1132,8 +1132,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.
@@ -1145,11 +1146,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)
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 16b278a..b753414 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
@@ -257,8 +264,8 @@
 OPTIONS.skip_compatibility_check = False
 OPTIONS.output_metadata_path = None
 OPTIONS.disable_fec_computation = False
-OPTIONS.boot_variable_values = None
 OPTIONS.force_non_ab = False
+OPTIONS.boot_variable_file = None
 
 
 METADATA_NAME = 'META-INF/com/android/metadata'
@@ -931,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'),
   }
 
@@ -955,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')
@@ -1972,24 +1992,24 @@
           output_file)
 
 
-def CalculateRuntimeFingerprints():
-  """Returns a set of runtime fingerprints based on the boot variables."""
+def CalculateRuntimeDevicesAndFingerprints(build_info, boot_variable_values):
+  """Returns a tuple of sets for runtime devices and fingerprints"""
 
-  build_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
+  device_names = {build_info.device}
   fingerprints = {build_info.fingerprint}
 
-  if not OPTIONS.boot_variable_values:
-    return fingerprints
+  if not boot_variable_values:
+    return device_names, fingerprints
 
   # Calculate all possible combinations of the values for the boot variables.
-  keys = OPTIONS.boot_variable_values.keys()
-  value_list = OPTIONS.boot_variable_values.values()
+  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(OPTIONS.info_dict)
+    info_dict = copy.deepcopy(build_info.info_dict)
     for partition in common.PARTITIONS_WITH_CARE_MAP:
       partition_prop_key = "{}.build.prop".format(partition)
       old_props = info_dict[partition_prop_key]
@@ -1997,9 +2017,10 @@
           old_props.input_file, partition, placeholder_values)
     info_dict["build.prop"] = info_dict["system.build.prop"]
 
-    build_info = common.BuildInfo(info_dict, OPTIONS.oem_dicts)
-    fingerprints.add(build_info.fingerprint)
-  return fingerprints
+    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):
@@ -2077,6 +2098,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
@@ -2114,6 +2137,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_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_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index 4077d06..7783f96 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -27,7 +27,7 @@
     GetTargetFilesZipWithoutPostinstallConfig, NonAbOtaPropertyFiles,
     Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
     StreamingPropertyFiles, WriteFingerprintAssertion,
-    CalculateRuntimeFingerprints)
+    CalculateRuntimeDevicesAndFingerprints)
 
 
 def construct_target_files(secondary=False):
@@ -1334,6 +1334,9 @@
       '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 = [
@@ -1345,11 +1348,12 @@
   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.writeFiles({'META/misc_info.txt': '\n'.join(self.MISC_INFO)},
+                    self.test_dir)
 
-  def writeFiles(self, contents_dict):
+  def writeFiles(self, contents_dict, out_dir):
     for path, content in contents_dict.items():
-      abs_path = os.path.join(self.test_dir, path)
+      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)
@@ -1371,12 +1375,14 @@
     self.writeFiles({
         'SYSTEM/build.prop': '\n'.join(build_prop),
         'VENDOR/build.prop': '\n'.join(self.VENDOR_BUILD_PROP),
-    })
-    common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
+    }, self.test_dir)
 
-    self.assertEqual({
-        self.constructFingerprint('product-brand/product-name/product-device')
-    }, CalculateRuntimeFingerprints())
+    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)
@@ -1390,20 +1396,22 @@
         'ro.product.vendor.name=vendor-product-std',
         'VENDOR/etc/build_pro.prop':
         'ro.product.vendor.name=vendor-product-pro',
-    })
-    common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
-    common.OPTIONS.boot_variable_values = {
-        'ro.boot.sku_name': ['std', 'pro']
-    }
+    }, self.test_dir)
 
-    self.assertEqual({
+    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'),
-    }, CalculateRuntimeFingerprints())
+    })
+    self.assertEqual(
+        expected, CalculateRuntimeDevicesAndFingerprints(
+            build_info, boot_variable_values))
 
   def test_CalculatePossibleFingerprints_multiple_overrides(self):
     vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
@@ -1422,14 +1430,17 @@
         'ro.product.vendor.name=vendor-product-pro',
         'VENDOR/etc/build_product2.prop':
         'ro.product.vendor.device=vendor-device-product2',
-    })
-    common.OPTIONS.info_dict = common.LoadInfoDict(self.test_dir)
-    common.OPTIONS.boot_variable_values = {
+    }, 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'],
     }
 
-    self.assertEqual({
+    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(
@@ -1439,5 +1450,108 @@
         self.constructFingerprint(
             'vendor-product-brand/vendor-product-std/vendor-device-product2'),
         self.constructFingerprint(
-            'vendor-product-brand/vendor-product-pro/vendor-device-product2'),
-    }, CalculateRuntimeFingerprints())
+            '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..69be511 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':
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