Merge "tasks: find-sharedui-violation: Partition location"
diff --git a/Changes.md b/Changes.md
index 3109e9b..84c8d95 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,15 @@
 # Build System Changes for Android.mk Writers
 
+## `LOCAL_REQUIRED_MODULES` requires listed modules to exist {#BUILD_BROKEN_MISSING_REQUIRED_MODULES}
+
+Modules listed in `LOCAL_REQUIRED_MODULES`, `LOCAL_HOST_REQUIRED_MODULES` and
+`LOCAL_TARGET_REQUIRED_MODULES` need to exist unless `ALLOW_MISSING_DEPENDENCIES`
+is set.
+
+To temporarily relax missing required modules check, use:
+
+`BUILD_BROKEN_MISSING_REQUIRED_MODULES := true`
+
 ## Changes in system properties settings
 
 ### Product variables
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 6352e38..67aca7c 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -505,9 +505,9 @@
 
 # Remove *_OUT_INTERMEDIATE_LIBRARIES
 $(call add-clean-step, rm -rf $(addsuffix /lib,\
-  $(HOST_OUT_INTERMEDIATES) $(2ND_HOST_OUT_INTERMEDIATES) \
-  $(HOST_CROSS_OUT_INTERMEDIATES) $(2ND_HOST_CROSS_OUT_INTERMEDIATES) \
-  $(TARGET_OUT_INTERMEDIATES) $(2ND_TARGET_OUT_INTERMEDIATES)))
+$(HOST_OUT_INTERMEDIATES) $(2ND_HOST_OUT_INTERMEDIATES) \
+$(HOST_CROSS_OUT_INTERMEDIATES) $(2ND_HOST_CROSS_OUT_INTERMEDIATES) \
+$(TARGET_OUT_INTERMEDIATES) $(2ND_TARGET_OUT_INTERMEDIATES)))
 
 # Remove strip.sh intermediates to save space
 $(call add-clean-step, find $(OUT_DIR) \( -name "*.so.debug" -o -name "*.so.dynsyms" -o -name "*.so.funcsyms" -o -name "*.so.keep_symbols" -o -name "*.so.mini_debuginfo.xz" \) -print0 | xargs -0 rm -f)
@@ -646,6 +646,8 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/odm/build.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/odm/build.prop)
 
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/apex)
+
 # Remove libcameraservice and libcamera_client from base_system
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib*/libcameraservice.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib*/libcamera_client.so)
@@ -685,6 +687,9 @@
 # Migrate preopt files to system_other for some devices
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/*/*app/*/oat)
 
+# Migrate preopt files from system_other for some devices
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system_other)
+
 # Remove Android Core Library artifacts from the system partition, now
 # that they live in the ART APEX (b/142944799).
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/*.jar)
@@ -699,9 +704,27 @@
 # again, as the original change removing them was reverted.
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/*.jar)
 
+# Remove cas@1.1 from the vendor partition
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@1.1*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*)
+
+# Remove com.android.cellbroadcast apex for Go devices
+$(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)
+
 # The core image variant has been renamed to ""
 $(call add-clean-step, find $(SOONG_OUT_DIR)/.intermediates -type d -name "android_*_core*" -print0 | xargs -0 rm -rf)
 
+# Remove 'media' command
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/media)
+
 # Remove CtsShim apks from system partition, since the have been moved inside
 # the cts shim apex. Also remove the cts shim apex prebuilt since it has been
 # removed in flattened apexs configurations.
@@ -713,6 +736,9 @@
 $(call add-clean-step, find $(SOONG_OUT_DIR)/.intermediates -type d -name "android_*_recovery*" -print0 | xargs -0 rm -rf)
 $(call add-clean-step, find $(SOONG_OUT_DIR)/.intermediates -type d -name "android_*_vendor*" -print0 | xargs -0 rm -rf)
 
+# Remove PermissionController after moving into APEX
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/*PermissionController)
+
 # Clean up VTS-Core and VTS10 related artifacts.
 $(call add-clean-step, rm -rf $(HOST_OUT)/vts-core/*)
 $(call add-clean-step, rm -rf $(HOST_OUT)/framework/vts-core-tradefed.jar)
diff --git a/core/Makefile b/core/Makefile
index 0541f22..467db19 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -495,9 +495,20 @@
 		--title="Remaining Android.mk files for $(TARGET_DEVICE)-$(TARGET_BUILD_VARIANT)" \
 		--codesearch=$(PRIVATE_CODE_SEARCH_BASE_URL) \
 		--out_dir="$(OUT_DIR)" \
+		--mode=html \
 		> $@
 $(call dist-for-goals,droidcore,$(MK2BP_REMAINING_HTML))
 
+MK2BP_REMAINING_CSV := $(PRODUCT_OUT)/mk2bp_remaining.csv
+$(MK2BP_REMAINING_CSV): $(SOONG_CONV_DATA) $(MK2BP_CATALOG_SCRIPT)
+	@rm -f $@
+	$(hide) $(MK2BP_CATALOG_SCRIPT) \
+		--device=$(TARGET_DEVICE) \
+		--out_dir="$(OUT_DIR)" \
+		--mode=csv \
+		> $@
+$(call dist-for-goals,droidcore,$(MK2BP_REMAINING_CSV))
+
 # -----------------------------------------------------------------
 # Modules use -Wno-error, or added default -Wall -Werror
 WALL_WERROR := $(PRODUCT_OUT)/wall_werror.txt
@@ -553,12 +564,8 @@
 all_event_log_tags_src := \
     $(sort $(foreach m, $(ALL_MODULES), $(ALL_MODULES.$(m).EVENT_LOG_TAGS)))
 
-# PDK builds will already have a full list of tags that needs to get merged
-# in with the ones from source
-pdk_fusion_log_tags_file := $(patsubst $(PRODUCT_OUT)/%,$(_pdk_fusion_intermediates)/%,$(filter $(event_log_tags_file),$(ALL_PDK_FUSION_FILES)))
-
-$(all_event_log_tags_file): PRIVATE_SRC_FILES := $(all_event_log_tags_src) $(pdk_fusion_log_tags_file)
-$(all_event_log_tags_file): $(all_event_log_tags_src) $(pdk_fusion_log_tags_file) $(MERGETAGS) build/make/tools/event_log_tags.py
+$(all_event_log_tags_file): PRIVATE_SRC_FILES := $(all_event_log_tags_src)
+$(all_event_log_tags_file): $(all_event_log_tags_src) $(MERGETAGS) build/make/tools/event_log_tags.py
 	$(hide) mkdir -p $(dir $@)
 	$(hide) $(MERGETAGS) -o $@ $(PRIVATE_SRC_FILES)
 
@@ -572,9 +579,9 @@
       $(ALL_MODULES.$(m).EVENT_LOG_TAGS)) \
       $(filter-out vendor/% device/% out/%,$(all_event_log_tags_src)))
 
-$(event_log_tags_file): PRIVATE_SRC_FILES := $(event_log_tags_src) $(pdk_fusion_log_tags_file)
+$(event_log_tags_file): PRIVATE_SRC_FILES := $(event_log_tags_src)
 $(event_log_tags_file): PRIVATE_MERGED_FILE := $(all_event_log_tags_file)
-$(event_log_tags_file): $(event_log_tags_src) $(all_event_log_tags_file) $(pdk_fusion_log_tags_file) $(MERGETAGS) build/make/tools/event_log_tags.py
+$(event_log_tags_file): $(event_log_tags_src) $(all_event_log_tags_file) $(MERGETAGS) build/make/tools/event_log_tags.py
 	$(hide) mkdir -p $(dir $@)
 	$(hide) $(MERGETAGS) -o $@ -m $(PRIVATE_MERGED_FILE) $(PRIVATE_SRC_FILES)
 
@@ -588,6 +595,10 @@
 # #################################################################
 ifneq ($(strip $(TARGET_NO_BOOTLOADER)),true)
   INSTALLED_BOOTLOADER_MODULE := $(PRODUCT_OUT)/bootloader
+  ifdef BOARD_PREBUILT_BOOTLOADER
+    $(eval $(call copy-one-file,$(BOARD_PREBUILT_BOOTLOADER),$(INSTALLED_BOOTLOADER_MODULE)))
+    $(call dist-for-goals,dist_files,$(INSTALLED_BOOTLOADER_MODULE))
+  endif # BOARD_PREBUILT_BOOTLOADER
   ifeq ($(strip $(TARGET_BOOTLOADER_IS_2ND)),true)
     INSTALLED_2NDBOOTLOADER_TARGET := $(PRODUCT_OUT)/2ndbootloader
   else
@@ -692,6 +703,14 @@
   BUILT_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
 endif
 
+# $1: boot image target
+# returns the kernel used to make the bootimage
+define bootimage-to-kernel
+  $(if $(BOARD_KERNEL_BINARIES),\
+    $(PRODUCT_OUT)/$(subst .img,,$(subst boot,kernel,$(notdir $(1)))),\
+    $(INSTALLED_KERNEL_TARGET))
+endef
+
 ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
   BOARD_KERNEL_BOOTIMAGE_PARTITION_SIZE := $(BOARD_BOOTIMAGE_PARTITION_SIZE)
 endif
@@ -704,8 +723,7 @@
 
 ifneq ($(strip $(TARGET_NO_KERNEL)),true)
 INTERNAL_BOOTIMAGE_ARGS := \
-	$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
-	--kernel $(INSTALLED_KERNEL_TARGET)
+	$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET))
 
 ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
 INTERNAL_BOOTIMAGE_ARGS += --ramdisk $(INSTALLED_RAMDISK_TARGET)
@@ -746,7 +764,7 @@
 endif
 
 INTERNAL_MKBOOTIMG_VERSION_ARGS := \
-    --os_version $(PLATFORM_VERSION) \
+    --os_version $(PLATFORM_VERSION_LAST_STABLE) \
     --os_patch_level $(PLATFORM_SECURITY_PATCH)
 
 # Define these only if we are building boot
@@ -755,74 +773,86 @@
 
 ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)
 $(error TARGET_BOOTIMAGE_USE_EXT2 is not supported anymore)
+endif # TARGET_BOOTIMAGE_USE_EXT2
 
-else ifeq (true,$(BOARD_AVB_ENABLE)) # TARGET_BOOTIMAGE_USE_EXT2 != true
+$(foreach b,$(INSTALLED_BOOTIMAGE_TARGET), $(eval $(call add-dependency,$(b),$(call bootimage-to-kernel,$(b)))))
+
+ifeq (true,$(BOARD_AVB_ENABLE))
+
+# $1: boot image target
+define build_boot_board_avb_enabled
+  $(MKBOOTIMG) --kernel $(call bootimage-to-kernel,$(1)) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(1)
+  $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE)))
+  $(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)
+endef
 
 $(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(AVBTOOL) $(INTERNAL_BOOTIMAGE_FILES) $(BOARD_AVB_BOOT_KEY_PATH)
 	$(call pretty,"Target boot image: $@")
-	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
-	$(hide) $(call assert-max-image-size,$@,$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE)))
-	$(hide) $(AVBTOOL) add_hash_footer \
-	  --image $@ \
-	  --partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \
-	  --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \
-	  $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
+	$(call build_boot_board_avb_enabled,$@)
 
 .PHONY: bootimage-nodeps
 bootimage-nodeps: $(MKBOOTIMG) $(AVBTOOL) $(BOARD_AVB_BOOT_KEY_PATH)
 	@echo "make $@: ignoring dependencies"
-	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
-	$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE)))
-	$(hide) $(AVBTOOL) add_hash_footer \
-	  --image $(INSTALLED_BOOTIMAGE_TARGET) \
-	  --partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \
-	  --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \
-	  $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
+	$(foreach b,$(INSTALLED_BOOTIMAGE_TARGET),$(call build_boot_board_avb_enabled,$(b)))
 
 else ifeq (true,$(PRODUCT_SUPPORTS_BOOT_SIGNER)) # BOARD_AVB_ENABLE != true
 
+# $1: boot image target
+define build_boot_supports_boot_signer
+  $(MKBOOTIMG) --kernel $(call bootimage-to-kernel,$(1)) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(1)
+  $(BOOT_SIGNER) /boot $@ $(PRODUCT_VERITY_SIGNING_KEY).pk8 $(PRODUCT_VERITY_SIGNING_KEY).x509.pem $(1)
+  $(call assert-max-image-size,$(1),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+endef
+
 $(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES) $(BOOT_SIGNER)
 	$(call pretty,"Target boot image: $@")
-	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
-	$(BOOT_SIGNER) /boot $@ $(PRODUCT_VERITY_SIGNING_KEY).pk8 $(PRODUCT_VERITY_SIGNING_KEY).x509.pem $@
-	$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+	$(call build_boot_supports_boot_signer,$@)
 
 .PHONY: bootimage-nodeps
 bootimage-nodeps: $(MKBOOTIMG) $(BOOT_SIGNER)
 	@echo "make $@: ignoring dependencies"
-	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
-	$(BOOT_SIGNER) /boot $(INSTALLED_BOOTIMAGE_TARGET) $(PRODUCT_VERITY_SIGNING_KEY).pk8 $(PRODUCT_VERITY_SIGNING_KEY).x509.pem $(INSTALLED_BOOTIMAGE_TARGET)
-	$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+	$(foreach b,$(INSTALLED_BOOTIMAGE_TARGET),$(call build_boot_supports_boot_signer,$(b)))
 
 else ifeq (true,$(PRODUCT_SUPPORTS_VBOOT)) # PRODUCT_SUPPORTS_BOOT_SIGNER != true
 
+# $1: boot image target
+define build_boot_supports_vboot
+  $(MKBOOTIMG) --kernel $(call bootimage-to-kernel,$(1)) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(1).unsigned
+  $(VBOOT_SIGNER) $(FUTILITY) $(1).unsigned $(PRODUCT_VBOOT_SIGNING_KEY).vbpubk $(PRODUCT_VBOOT_SIGNING_KEY).vbprivk $(PRODUCT_VBOOT_SIGNING_SUBKEY).vbprivk $(1).keyblock $(1)
+  $(call assert-max-image-size,$(1),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+endef
+
 $(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES) $(VBOOT_SIGNER) $(FUTILITY)
 	$(call pretty,"Target boot image: $@")
-	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@.unsigned
-	$(VBOOT_SIGNER) $(FUTILITY) $@.unsigned $(PRODUCT_VBOOT_SIGNING_KEY).vbpubk $(PRODUCT_VBOOT_SIGNING_KEY).vbprivk $(PRODUCT_VBOOT_SIGNING_SUBKEY).vbprivk $@.keyblock $@
-	$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+	$(call build_boot_supports_vboot,$@)
 
 .PHONY: bootimage-nodeps
 bootimage-nodeps: $(MKBOOTIMG) $(VBOOT_SIGNER) $(FUTILITY)
 	@echo "make $@: ignoring dependencies"
-	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET).unsigned
-	$(VBOOT_SIGNER) $(FUTILITY) $(INSTALLED_BOOTIMAGE_TARGET).unsigned $(PRODUCT_VBOOT_SIGNING_KEY).vbpubk $(PRODUCT_VBOOT_SIGNING_KEY).vbprivk $(PRODUCT_VBOOT_SIGNING_SUBKEY).vbprivk $(INSTALLED_BOOTIMAGE_TARGET).keyblock $(INSTALLED_BOOTIMAGE_TARGET)
-	$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+	$(foreach b,$(INSTALLED_BOOTIMAGE_TARGET),$(call build_boot_supports_vboot,$(b)))
 
 else # PRODUCT_SUPPORTS_VBOOT != true
 
+# $1: boot image target
+define build_boot_novboot
+  $(MKBOOTIMG) --kernel $(call bootimage-to-kernel,$(1)) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(1)
+  $(call assert-max-image-size,$1,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+endef
+
 $(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES)
 	$(call pretty,"Target boot image: $@")
-	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
-	$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+	$(call build_boot_novboot,$@)
 
 .PHONY: bootimage-nodeps
 bootimage-nodeps: $(MKBOOTIMG)
 	@echo "make $@: ignoring dependencies"
-	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
-	$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
+	$(foreach b,$(INSTALLED_BOOTIMAGE_TARGET),$(call build_boot_novboot,$(b)))
 
-endif # TARGET_BOOTIMAGE_USE_EXT2
+endif # BOARD_AVB_ENABLE
 endif # BUILDING_BOOT_IMAGE
 
 else # TARGET_NO_KERNEL == "true"
@@ -955,7 +985,6 @@
 tools_notice_file_html := $(HOST_OUT_INTERMEDIATES)/NOTICE.html
 kernel_notice_file := $(TARGET_OUT_NOTICE_FILES)/src/kernel.txt
 winpthreads_notice_file := $(TARGET_OUT_NOTICE_FILES)/src/winpthreads.txt
-pdk_fusion_notice_files := $(filter $(TARGET_OUT_NOTICE_FILES)/%, $(ALL_PDK_FUSION_FILES))
 
 # Some targets get included under $(PRODUCT_OUT) for debug symbols or other
 # reasons--not to be flashed onto any device. Targets under these directories
@@ -972,7 +1001,7 @@
 	        $(target_notice_file_html), \
 	        "Notices for files contained in the filesystem images in this directory:", \
 	        $(TARGET_OUT_NOTICE_FILES), \
-	        $(ALL_DEFAULT_INSTALLED_MODULES) $(kernel_notice_file) $(pdk_fusion_notice_files), \
+	        $(ALL_DEFAULT_INSTALLED_MODULES) $(kernel_notice_file), \
 	        $(exclude_target_dirs)))
 $(target_notice_file_html_gz): $(target_notice_file_html) | $(MINIGZIP)
 	$(hide) $(MINIGZIP) -9 < $< > $@
@@ -1016,7 +1045,7 @@
 # Notice files are copied to TARGET_OUT_NOTICE_FILES as a side-effect of their module
 # being built. A notice xml file must depend on all modules that could potentially
 # install a license file relevant to it.
-license_modules := $(ALL_DEFAULT_INSTALLED_MODULES) $(kernel_notice_file) $(pdk_fusion_notice_files)
+license_modules := $(ALL_DEFAULT_INSTALLED_MODULES) $(kernel_notice_file)
 # Only files copied to a system image need system image notices.
 license_modules := $(filter $(PRODUCT_OUT)/%,$(license_modules))
 # Phonys/fakes don't have notice files (though their deps might)
@@ -1025,6 +1054,8 @@
 license_modules := $(filter-out $(TARGET_OUT_TESTCASES)/%,$(license_modules))
 # filesystem images: system, vendor, product, system_ext, odm, vendor_dlkm, and odm_dlkm
 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))
@@ -1587,7 +1618,9 @@
 # SELinux files
 IGNORE_RECOVERY_SEPOLICY := $(patsubst $(TARGET_RECOVERY_OUT)/%,--exclude=/%,$(recovery_sepolicy))
 
-recovery_kernel := $(INSTALLED_KERNEL_TARGET) # same as a non-recovery system
+# if building multiple boot images from multiple kernels, use the first kernel listed
+# for the recovery image
+recovery_kernel := $(firstword $(INSTALLED_KERNEL_TARGET))
 recovery_ramdisk := $(PRODUCT_OUT)/ramdisk-recovery.img
 recovery_resources_common := bootable/recovery/res
 
@@ -1938,6 +1971,7 @@
 endif
 
 ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+$(foreach b,$(INSTALLED_BOOTIMAGE_TARGET), $(eval $(call add-dependency,$(b),$(call bootimage-to-kernel,$(b)))))
 $(INSTALLED_BOOTIMAGE_TARGET): $(recoveryimage-deps)
 	$(call pretty,"Target boot image from recovery: $@")
 	$(call build-recoveryimage-target, $@, $(PRODUCT_OUT)/$(subst .img,,$(subst boot,kernel,$(notdir $@))))
@@ -1956,7 +1990,7 @@
 .PHONY: recoveryimage-nodeps
 recoveryimage-nodeps:
 	@echo "make $@: ignoring dependencies"
-	$(call build-recoveryimage-target, $(INSTALLED_RECOVERYIMAGE_TARGET))
+	$(call build-recoveryimage-target, $(INSTALLED_RECOVERYIMAGE_TARGET), $(recovery_kernel))
 
 else # BUILDING_RECOVERY_IMAGE
 RECOVERY_RESOURCE_ZIP :=
@@ -2273,19 +2307,47 @@
 endif # TARGET_NO_KERNEL
 endif # BOARD_BUILD_SYSTEM_ROOT_IMAGE is not true
 
+# Creates a compatibility symlink between two partitions, e.g. /system/vendor to /vendor
+# $1: from location (e.g $(TARGET_OUT)/vendor)
+# $2: destination location (e.g. /vendor)
+# $3: partition image name (e.g. vendor.img)
+define create-partition-compat-symlink
+$(eval \
+$1:
+	@echo Symlink $(patsubst $(PRODUCT_OUT)/%,%,$1) to $2
+	mkdir -p $(dir $1)
+	if [ -d $1 ] && [ ! -h $1 ]; then \
+	  echo 'Non-symlink $1 detected!' 1>&2; \
+	  echo 'You cannot install files to $1 while building a separate $3!' 1>&2; \
+	  exit 1; \
+	fi
+	ln -sfn $2 $1
+)
+$1
+endef
+
+
 # -----------------------------------------------------------------
 # system image
-#
-# Remove overridden packages from $(ALL_PDK_FUSION_FILES)
-PDK_FUSION_SYSIMG_FILES := \
-    $(filter-out $(foreach p,$(overridden_packages),$(p) %/$(p).apk), \
-        $(ALL_PDK_FUSION_FILES))
 
 INTERNAL_SYSTEMIMAGE_FILES := $(sort $(filter $(TARGET_OUT)/%, \
     $(ALL_GENERATED_SOURCES) \
-    $(ALL_DEFAULT_INSTALLED_MODULES) \
-    $(PDK_FUSION_SYSIMG_FILES)) \
-    $(PDK_FUSION_SYMLINK_STAMP))
+    $(ALL_DEFAULT_INSTALLED_MODULES)))
+
+# Create symlink /system/vendor to /vendor if necessary.
+ifdef BOARD_USES_VENDORIMAGE
+  INTERNAL_SYSTEMIMAGE_FILES += $(call create-partition-compat-symlink,$(TARGET_OUT)/vendor,/vendor,vendor.img)
+endif
+
+# Create symlink /system/product to /product if necessary.
+ifdef BOARD_USES_PRODUCTIMAGE
+  INTERNAL_SYSTEMIMAGE_FILES += $(call create-partition-compat-symlink,$(TARGET_OUT)/product,/product,product.img)
+endif
+
+# Create symlink /system/system_ext to /system_ext if necessary.
+ifdef BOARD_USES_SYSTEM_EXTIMAGE
+  INTERNAL_SYSTEMIMAGE_FILES += $(call create-partition-compat-symlink,$(TARGET_OUT)/system_ext,/system_ext,system_ext.img)
+endif
 
 FULL_SYSTEMIMAGE_DEPS := $(INTERNAL_SYSTEMIMAGE_FILES) $(INTERNAL_USERIMAGES_DEPS)
 
@@ -2326,57 +2388,9 @@
     $(call intermediates-dir-for,PACKAGING,systemimage)
 BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img
 
-# Create symlink /system/vendor to /vendor if necessary.
-ifdef BOARD_USES_VENDORIMAGE
-define create-system-vendor-symlink
-$(hide) if [ -d $(TARGET_OUT)/vendor ] && [ ! -h $(TARGET_OUT)/vendor ]; then \
-  echo 'Non-symlink $(TARGET_OUT)/vendor detected!' 1>&2; \
-  echo 'You cannot install files to $(TARGET_OUT)/vendor while building a separate vendor.img!' 1>&2; \
-  exit 1; \
-fi
-$(hide) ln -sf /vendor $(TARGET_OUT)/vendor
-endef
-else
-define create-system-vendor-symlink
-endef
-endif
-
-# Create symlink /system/product to /product if necessary.
-ifdef BOARD_USES_PRODUCTIMAGE
-define create-system-product-symlink
-$(hide) if [ -d $(TARGET_OUT)/product ] && [ ! -h $(TARGET_OUT)/product ]; then \
-  echo 'Non-symlink $(TARGET_OUT)/product detected!' 1>&2; \
-  echo 'You cannot install files to $(TARGET_OUT)/product while building a separate product.img!' 1>&2; \
-  exit 1; \
-fi
-$(hide) ln -sf /product $(TARGET_OUT)/product
-endef
-else
-define create-system-product-symlink
-endef
-endif
-
-# Create symlink /system/system_ext to /system_ext if necessary.
-ifdef BOARD_USES_SYSTEM_EXTIMAGE
-define create-system-system_ext-symlink
-$(hide) if [ -d $(TARGET_OUT)/system_ext ] && [ ! -h $(TARGET_OUT)/system_ext ]; then \
-  echo 'Non-symlink $(TARGET_OUT)/system_ext detected!' 1>&2; \
-  echo 'You cannot install files to $(TARGET_OUT)/system_ext while building a separate system_ext.img!' 1>&2; \
-  exit 1; \
-fi
-$(hide) ln -sf /system_ext $(TARGET_OUT)/system_ext
-endef
-else
-define create-system-system_ext-symlink
-endef
-endif
-
 # $(1): output file
 define build-systemimage-target
   @echo "Target system fs image: $(1)"
-  $(call create-system-vendor-symlink)
-  $(call create-system-product-symlink)
-  $(call create-system-system_ext-symlink)
   @mkdir -p $(dir $(1)) $(systemimage_intermediates) && rm -rf $(systemimage_intermediates)/system_image_info.txt
   $(call generate-image-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt,system, \
       skip_fsck=true)
@@ -2419,11 +2433,11 @@
 $(RECOVERY_FROM_BOOT_PATCH): PRIVATE_DIFF_TOOL := $(diff_tool)
 $(RECOVERY_FROM_BOOT_PATCH): \
 	    $(INSTALLED_RECOVERYIMAGE_TARGET) \
-	    $(INSTALLED_BOOTIMAGE_TARGET) \
+	    $(firstword $(INSTALLED_BOOTIMAGE_TARGET)) \
 	    $(diff_tool)
 	@echo "Construct recovery from boot"
 	mkdir -p $(dir $@)
-	$(PRIVATE_DIFF_TOOL) $(INSTALLED_BOOTIMAGE_TARGET) $(INSTALLED_RECOVERYIMAGE_TARGET) $@
+	$(PRIVATE_DIFF_TOOL) $(firstword $(INSTALLED_BOOTIMAGE_TARGET)) $(INSTALLED_RECOVERYIMAGE_TARGET) $@
 else # $(BOARD_USES_FULL_RECOVERY_IMAGE) == true
 RECOVERY_FROM_BOOT_PATCH := $(INSTALLED_RECOVERYIMAGE_TARGET)
 endif # BOARD_USES_FULL_RECOVERY_IMAGE
@@ -2453,111 +2467,14 @@
 sync syncsys: $(INTERNAL_SYSTEMIMAGE_FILES)
 
 # -----------------------------------------------------------------
-## platform.zip: system, plus other files to be used in PDK fusion build,
-## in a zip file
-##
-## PDK_PLATFORM_ZIP_PRODUCT_BINARIES is used to store specified files to platform.zip.
-## The variable will be typically set from BoardConfig.mk.
-## Files under out dir will be rejected to prevent possible conflicts with other rules.
-ifneq (,$(BUILD_PLATFORM_ZIP))
-pdk_odex_javalibs := $(strip $(foreach m,$(DEXPREOPT.MODULES.JAVA_LIBRARIES),\
-  $(if $(filter $(DEXPREOPT.$(m).INSTALLED_STRIPPED),$(ALL_DEFAULT_INSTALLED_MODULES)),$(m))))
-pdk_odex_apps := $(strip $(foreach m,$(DEXPREOPT.MODULES.APPS),\
-  $(if $(filter $(DEXPREOPT.$(m).INSTALLED_STRIPPED),$(ALL_DEFAULT_INSTALLED_MODULES)),$(m))))
-pdk_classes_dex := $(strip \
-  $(foreach m,$(pdk_odex_javalibs),$(call intermediates-dir-for,JAVA_LIBRARIES,$(m),,COMMON)/javalib.jar) \
-  $(foreach m,$(pdk_odex_apps),$(call intermediates-dir-for,APPS,$(m))/package.apk))
-
-pdk_odex_config_mk := $(PRODUCT_OUT)/pdk_dexpreopt_config.mk
-$(pdk_odex_config_mk): PRIVATE_JAVA_LIBRARIES := $(pdk_odex_javalibs)
-$(pdk_odex_config_mk): PRIVATE_APPS := $(pdk_odex_apps)
-$(pdk_odex_config_mk) :
-	@echo "PDK odex config makefile: $@"
-	$(hide) mkdir -p $(dir $@)
-	$(hide) echo "# Auto-generated. Do not modify." > $@
-	$(hide) echo "PDK.DEXPREOPT.JAVA_LIBRARIES:=$(PRIVATE_JAVA_LIBRARIES)" >> $@
-	$(hide) echo "PDK.DEXPREOPT.APPS:=$(PRIVATE_APPS)" >> $@
-	$(foreach m,$(PRIVATE_JAVA_LIBRARIES),\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).SRC:=$(patsubst $(OUT_DIR)/%,%,$(call intermediates-dir-for,JAVA_LIBRARIES,$(m),,COMMON)/javalib.jar)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).DEX_PREOPT:=$(DEXPREOPT.$(m).DEX_PREOPT)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).MULTILIB:=$(DEXPREOPT.$(m).MULTILIB)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).DEX_PREOPT_FLAGS:=$(DEXPREOPT.$(m).DEX_PREOPT_FLAGS)" >> $@$(newline)\
-	  )
-	$(foreach m,$(PRIVATE_APPS),\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).SRC:=$(patsubst $(OUT_DIR)/%,%,$(call intermediates-dir-for,APPS,$(m))/package.apk)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).DEX_PREOPT:=$(DEXPREOPT.$(m).DEX_PREOPT)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).MULTILIB:=$(DEXPREOPT.$(m).MULTILIB)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).DEX_PREOPT_FLAGS:=$(DEXPREOPT.$(m).DEX_PREOPT_FLAGS)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).PRIVILEGED_MODULE:=$(DEXPREOPT.$(m).PRIVILEGED_MODULE)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).VENDOR_MODULE:=$(DEXPREOPT.$(m).VENDOR_MODULE)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).TARGET_ARCH:=$(DEXPREOPT.$(m).TARGET_ARCH)" >> $@$(newline)\
-	  $(hide) echo "PDK.DEXPREOPT.$(m).STRIPPED_SRC:=$(patsubst $(PRODUCT_OUT)/%,%,$(DEXPREOPT.$(m).INSTALLED_STRIPPED))" >> $@$(newline)\
-	  )
-
-PDK_PLATFORM_ZIP_PRODUCT_BINARIES := $(filter-out $(OUT_DIR)/%,$(PDK_PLATFORM_ZIP_PRODUCT_BINARIES))
-INSTALLED_PLATFORM_ZIP := $(PRODUCT_OUT)/platform.zip
-
-$(INSTALLED_PLATFORM_ZIP): PRIVATE_DEX_FILES := $(pdk_classes_dex)
-$(INSTALLED_PLATFORM_ZIP): PRIVATE_ODEX_CONFIG := $(pdk_odex_config_mk)
-$(INSTALLED_PLATFORM_ZIP) : $(SOONG_ZIP)
-# dependencies for the other partitions are defined below after their file lists
-# are known
-$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_SYSTEMIMAGE_FILES) $(pdk_classes_dex) $(pdk_odex_config_mk) $(API_FINGERPRINT)
-	$(call pretty,"Platform zip package: $(INSTALLED_PLATFORM_ZIP)")
-	rm -f $@ $@.lst
-	echo "-C $(PRODUCT_OUT)" >> $@.lst
-	echo "-D $(TARGET_OUT)" >> $@.lst
-	echo "-D $(TARGET_OUT_NOTICE_FILES)" >> $@.lst
-	echo "$(addprefix -f $(TARGET_OUT_UNSTRIPPED)/,$(PDK_SYMBOL_FILES_LIST))" >> $@.lst
-ifdef BUILDING_VENDOR_IMAGE
-	echo "-D $(TARGET_OUT_VENDOR)" >> $@.lst
-endif
-ifdef BUILDING_PRODUCT_IMAGE
-	echo "-D $(TARGET_OUT_PRODUCT)" >> $@.lst
-endif
-ifdef BUILDING_SYSTEM_EXT_IMAGE
-	echo "-D $(TARGET_OUT_SYSTEM_EXT)" >> $@.lst
-endif
-ifdef BUILDING_ODM_IMAGE
-	echo "-D $(TARGET_OUT_ODM)" >> $@.lst
-endif
-ifdef BUILDING_VENDOR_DLKM_IMAGE
-	echo "-D $(TARGET_OUT_VENDOR_DLKM)" >> $@.lst
-endif
-ifdef BUILDING_ODM_DLKM_IMAGE
-	echo "-D $(TARGET_OUT_ODM_DLKM)" >> $@.lst
-endif
-ifneq ($(PDK_PLATFORM_JAVA_ZIP_CONTENTS),)
-	echo "-C $(OUT_DIR)" >> $@.lst
-	for f in $(filter-out $(PRIVATE_DEX_FILES),$(addprefix -f $(OUT_DIR)/,$(PDK_PLATFORM_JAVA_ZIP_CONTENTS))); do \
-	  if [ -e $$f ]; then \
-	    echo "-f $$f"; \
-	  fi \
-	done >> $@.lst
-endif
-ifneq ($(PDK_PLATFORM_ZIP_PRODUCT_BINARIES),)
-        echo "-C . $(addprefix -f ,$(PDK_PLATFORM_ZIP_PRODUCT_BINARIES))" >> $@.lst
-endif
-	@# Add dex-preopt files and config.
-	$(if $(PRIVATE_DEX_FILES),\
-	  echo "-C $(OUT_DIR) $(addprefix -f ,$(PRIVATE_DEX_FILES))") >> $@.lst
-	echo "-C $(dir $(API_FINGERPRINT)) -f $(API_FINGERPRINT)" >> $@.lst
-	touch $(PRODUCT_OUT)/pdk.mk
-	echo "-C $(PRODUCT_OUT) -f $(PRIVATE_ODEX_CONFIG) -f $(PRODUCT_OUT)/pdk.mk" >> $@.lst
-	$(SOONG_ZIP) --ignore_missing_files -o $@ @$@.lst
-
+# Old PDK fusion targets
 .PHONY: platform
-platform: $(INSTALLED_PLATFORM_ZIP)
+platform:
+	echo "Warning: 'platform' is obsolete"
 
 .PHONY: platform-java
-platform-java: platform
-
-# Dist the platform.zip
-ifneq (,$(filter platform platform-java, $(MAKECMDGOALS)))
-$(call dist-for-goals, platform platform-java, $(INSTALLED_PLATFORM_ZIP))
-endif
-
-endif # BUILD_PLATFORM_ZIP
+platform-java:
+	echo "Warning: 'platform-java' is obsolete"
 
 # -----------------------------------------------------------------
 # data partition image
@@ -2691,9 +2608,7 @@
 
 INTERNAL_SYSTEMOTHERIMAGE_FILES := \
     $(filter $(TARGET_OUT_SYSTEM_OTHER)/%,\
-      $(ALL_DEFAULT_INSTALLED_MODULES)\
-      $(ALL_PDK_FUSION_FILES)) \
-    $(PDK_FUSION_SYMLINK_STAMP)
+      $(ALL_DEFAULT_INSTALLED_MODULES))
 
 # system_other dex files are installed as a side-effect of installing system image files
 INTERNAL_SYSTEMOTHERIMAGE_FILES += $(INTERNAL_SYSTEMIMAGE_FILES)
@@ -2756,36 +2671,12 @@
 ifdef BUILDING_VENDOR_IMAGE
 INTERNAL_VENDORIMAGE_FILES := \
     $(filter $(TARGET_OUT_VENDOR)/%,\
-      $(ALL_DEFAULT_INSTALLED_MODULES)\
-      $(ALL_PDK_FUSION_FILES)) \
-    $(PDK_FUSION_SYMLINK_STAMP)
+      $(ALL_DEFAULT_INSTALLED_MODULES))
 
-# platform.zip depends on $(INTERNAL_VENDORIMAGE_FILES).
-$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_VENDORIMAGE_FILES)
-
-INSTALLED_FILES_FILE_VENDOR := $(PRODUCT_OUT)/installed-files-vendor.txt
-INSTALLED_FILES_JSON_VENDOR := $(INSTALLED_FILES_FILE_VENDOR:.txt=.json)
-$(INSTALLED_FILES_FILE_VENDOR): .KATI_IMPLICIT_OUTPUTS := $(INSTALLED_FILES_JSON_VENDOR)
-$(INSTALLED_FILES_FILE_VENDOR) : $(INTERNAL_VENDORIMAGE_FILES) $(FILESLIST) $(FILESLIST_UTIL)
-	@echo Installed file list: $@
-	@mkdir -p $(dir $@)
-	@rm -f $@
-	$(hide) $(FILESLIST) $(TARGET_OUT_VENDOR) > $(@:.txt=.json)
-	$(hide) $(FILESLIST_UTIL) -c $(@:.txt=.json) > $@
 
 # Create symlink /vendor/odm to /odm if necessary.
 ifdef BOARD_USES_ODMIMAGE
-define create-vendor-odm-symlink
-$(hide) if [ -d $(TARGET_OUT_VENDOR)/odm ] && [ ! -h $(TARGET_OUT_VENDOR)/odm ]; then \
-  echo 'Non-symlink $(TARGET_OUT_VENDOR)/odm detected!' 1>&2; \
-  echo 'You cannot install files to $(TARGET_OUT_VENDOR)/odm while building a separate odm.img!' 1>&2; \
-  exit 1; \
-fi
-$(hide) ln -sf /odm $(TARGET_OUT_VENDOR)/odm
-endef
-else
-define create-vendor-odm-symlink
-endef
+  INTERNAL_VENDORIMAGE_FILES += $(call create-partition-compat-symlink,$(TARGET_OUT_VENDOR)/odm,/odm,odm.img)
 endif
 
 # Create symlinks for vendor_dlkm on devices with a vendor_dlkm partition:
@@ -2803,48 +2694,18 @@
 # The vendor DLKMs and other vendor_dlkm files must not be accessed using other paths because they
 # are not guaranteed to exist on all devices.
 ifdef BOARD_USES_VENDOR_DLKMIMAGE
-define create-vendor-vendor_dlkm-symlink
-$(hide) mkdir -p $(TARGET_OUT_VENDOR)/lib
-$(hide) if [ -d $(TARGET_OUT_VENDOR)/lib/modules ] && [ ! -h $(TARGET_OUT_VENDOR)/lib/modules ]; then \
-  echo 'Non-symlink $(TARGET_OUT_VENDOR)/lib/modules detected!' 1>&2; \
-  echo 'You cannot install files to $(TARGET_OUT_VENDOR)/lib/modules while building a separate vendor_dlkm.img!' 1>&2; \
-  exit 1; \
-fi
-$(hide) ln -sf /vendor_dlkm/lib/modules $(TARGET_OUT_VENDOR)/lib/modules
-endef
-else
-define create-vendor-vendor_dlkm-symlink
-endef
+  INTERNAL_VENDORIMAGE_FILES += $(call create-partition-compat-symlink,$(TARGET_OUT_VENDOR)/lib/modules,/vendor_dlkm/lib/modules,vendor_dlkm.img)
 endif
 
-# Create symlinks for odm_dlkm on devices with a odm_dlkm partition:
-# /odm/lib/modules -> /odm_dlkm/lib/modules
-#
-# On devices with a odm_dlkm partition,
-# - /odm/lib/modules is a symlink to a directory that stores odm DLKMs.
-# - /odm_dlkm/{etc,...} store other odm_dlkm files directly. The odm_dlkm partition is
-#   mounted at /odm_dlkm at runtime and the symlinks created in system/core/rootdir/Android.mk
-#   are hidden.
-# On devices without a odm_dlkm partition,
-# - /odm/lib/modules stores odm DLKMs directly.
-# - /odm_dlkm/{etc,...} are symlinks to directories that store other odm_dlkm files.
-#   See system/core/rootdir/Android.mk for a list of created symlinks.
-# The odm DLKMs and other odm_dlkm files must not be accessed using other paths because they
-# are not guaranteed to exist on all devices.
-ifdef BOARD_USES_ODM_DLKMIMAGE
-define create-odm-odm_dlkm-symlink
-$(hide) mkdir -p $(TARGET_OUT_ODM)/lib
-$(hide) if [ -d $(TARGET_OUT_ODM)/lib/modules ] && [ ! -h $(TARGET_OUT_ODM)/lib/modules ]; then \
-  echo 'Non-symlink $(TARGET_OUT_ODM)/lib/modules detected!' 1>&2; \
-  echo 'You cannot install files to $(TARGET_OUT_ODM)/lib/modules while building a separate odm_dlkm.img!' 1>&2; \
-  exit 1; \
-fi
-$(hide) ln -sf /odm_dlkm/lib/modules $(TARGET_OUT_ODM)/lib/modules
-endef
-else
-define create-odm-odm_dlkm-symlink
-endef
-endif
+INSTALLED_FILES_FILE_VENDOR := $(PRODUCT_OUT)/installed-files-vendor.txt
+INSTALLED_FILES_JSON_VENDOR := $(INSTALLED_FILES_FILE_VENDOR:.txt=.json)
+$(INSTALLED_FILES_FILE_VENDOR): .KATI_IMPLICIT_OUTPUTS := $(INSTALLED_FILES_JSON_VENDOR)
+$(INSTALLED_FILES_FILE_VENDOR) : $(INTERNAL_VENDORIMAGE_FILES) $(FILESLIST) $(FILESLIST_UTIL)
+	@echo Installed file list: $@
+	@mkdir -p $(dir $@)
+	@rm -f $@
+	$(hide) $(FILESLIST) $(TARGET_OUT_VENDOR) > $(@:.txt=.json)
+	$(hide) $(FILESLIST_UTIL) -c $(@:.txt=.json) > $@
 
 vendorimage_intermediates := \
     $(call intermediates-dir-for,PACKAGING,vendor)
@@ -2852,9 +2713,6 @@
 define build-vendorimage-target
   $(call pretty,"Target vendor fs image: $(INSTALLED_VENDORIMAGE_TARGET)")
   @mkdir -p $(TARGET_OUT_VENDOR)
-  $(call create-vendor-odm-symlink)
-  $(call create-vendor-vendor_dlkm-symlink)
-  $(call create-odm-odm_dlkm-symlink)
   @mkdir -p $(vendorimage_intermediates) && rm -rf $(vendorimage_intermediates)/vendor_image_info.txt
   $(call generate-image-prop-dictionary, $(vendorimage_intermediates)/vendor_image_info.txt,vendor,skip_fsck=true)
   PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \
@@ -2889,12 +2747,7 @@
 ifdef BUILDING_PRODUCT_IMAGE
 INTERNAL_PRODUCTIMAGE_FILES := \
     $(filter $(TARGET_OUT_PRODUCT)/%,\
-      $(ALL_DEFAULT_INSTALLED_MODULES)\
-      $(ALL_PDK_FUSION_FILES)) \
-    $(PDK_FUSION_SYMLINK_STAMP)
-
-# platform.zip depends on $(INTERNAL_PRODUCTIMAGE_FILES).
-$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_PRODUCTIMAGE_FILES)
+      $(ALL_DEFAULT_INSTALLED_MODULES))
 
 INSTALLED_FILES_FILE_PRODUCT := $(PRODUCT_OUT)/installed-files-product.txt
 INSTALLED_FILES_JSON_PRODUCT := $(INSTALLED_FILES_FILE_PRODUCT:.txt=.json)
@@ -2945,12 +2798,7 @@
 ifdef BUILDING_SYSTEM_EXT_IMAGE
 INTERNAL_SYSTEM_EXTIMAGE_FILES := \
     $(filter $(TARGET_OUT_SYSTEM_EXT)/%,\
-      $(ALL_DEFAULT_INSTALLED_MODULES)\
-      $(ALL_PDK_FUSION_FILES)) \
-    $(PDK_FUSION_SYMLINK_STAMP)
-
-# platform.zip depends on $(INTERNAL_SYSTEM_EXTIMAGE_FILES).
-$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_SYSTEM_EXTIMAGE_FILES)
+      $(ALL_DEFAULT_INSTALLED_MODULES))
 
 INSTALLED_FILES_FILE_SYSTEM_EXT := $(PRODUCT_OUT)/installed-files-system_ext.txt
 INSTALLED_FILES_JSON_SYSTEM_EXT := $(INSTALLED_FILES_FILE_SYSTEM_EXT:.txt=.json)
@@ -3003,11 +2851,25 @@
 ifdef BUILDING_ODM_IMAGE
 INTERNAL_ODMIMAGE_FILES := \
     $(filter $(TARGET_OUT_ODM)/%,\
-      $(ALL_DEFAULT_INSTALLED_MODULES)\
-      $(ALL_PDK_FUSION_FILES)) \
-    $(PDK_FUSION_SYMLINK_STAMP)
-# platform.zip depends on $(INTERNAL_ODMIMAGE_FILES).
-$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_ODMIMAGE_FILES)
+      $(ALL_DEFAULT_INSTALLED_MODULES))
+
+# Create symlinks for odm_dlkm on devices with a odm_dlkm partition:
+# /odm/lib/modules -> /odm_dlkm/lib/modules
+#
+# On devices with a odm_dlkm partition,
+# - /odm/lib/modules is a symlink to a directory that stores odm DLKMs.
+# - /odm_dlkm/{etc,...} store other odm_dlkm files directly. The odm_dlkm partition is
+#   mounted at /odm_dlkm at runtime and the symlinks created in system/core/rootdir/Android.mk
+#   are hidden.
+# On devices without a odm_dlkm partition,
+# - /odm/lib/modules stores odm DLKMs directly.
+# - /odm_dlkm/{etc,...} are symlinks to directories that store other odm_dlkm files.
+#   See system/core/rootdir/Android.mk for a list of created symlinks.
+# The odm DLKMs and other odm_dlkm files must not be accessed using other paths because they
+# are not guaranteed to exist on all devices.
+ifdef BOARD_USES_ODM_DLKMIMAGE
+  INTERNAL_ODMIMAGE_FILES += $(call create-partition-compat-symlink,$(TARGET_OUT_ODM)/lib/modules,/odm_dlkm/lib/modules,odm_dlkm.img)
+endif
 
 INSTALLED_FILES_FILE_ODM := $(PRODUCT_OUT)/installed-files-odm.txt
 INSTALLED_FILES_JSON_ODM := $(INSTALLED_FILES_FILE_ODM:.txt=.json)
@@ -3058,11 +2920,7 @@
 ifdef BUILDING_VENDOR_DLKM_IMAGE
 INTERNAL_VENDOR_DLKMIMAGE_FILES := \
     $(filter $(TARGET_OUT_VENDOR_DLKM)/%,\
-      $(ALL_DEFAULT_INSTALLED_MODULES)\
-      $(ALL_PDK_FUSION_FILES)) \
-    $(PDK_FUSION_SYMLINK_STAMP)
-# platform.zip depends on $(INTERNAL_VENDOR_DLKMIMAGE_FILES).
-$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_VENDOR_DLKMIMAGE_FILES)
+      $(ALL_DEFAULT_INSTALLED_MODULES))
 
 INSTALLED_FILES_FILE_VENDOR_DLKM := $(PRODUCT_OUT)/installed-files-vendor_dlkm.txt
 INSTALLED_FILES_JSON_VENDOR_DLKM := $(INSTALLED_FILES_FILE_VENDOR_DLKM:.txt=.json)
@@ -3113,11 +2971,7 @@
 ifdef BUILDING_ODM_DLKM_IMAGE
 INTERNAL_ODM_DLKMIMAGE_FILES := \
     $(filter $(TARGET_OUT_ODM_DLKM)/%,\
-      $(ALL_DEFAULT_INSTALLED_MODULES)\
-      $(ALL_PDK_FUSION_FILES)) \
-    $(PDK_FUSION_SYMLINK_STAMP)
-# platform.zip depends on $(INTERNAL_ODM_DLKMIMAGE_FILES).
-$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_ODM_DLKMIMAGE_FILES)
+      $(ALL_DEFAULT_INSTALLED_MODULES))
 
 INSTALLED_FILES_FILE_ODM_DLKM := $(PRODUCT_OUT)/installed-files-odm_dlkm.txt
 INSTALLED_FILES_JSON_ODM_DLKM := $(INSTALLED_FILES_FILE_ODM_DLKM:.txt=.json)
@@ -3289,22 +3143,22 @@
 
 BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS += \
     --prop com.android.build.system.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
-    --prop com.android.build.system.os_version:$(PLATFORM_VERSION) \
+    --prop com.android.build.system.os_version:$(PLATFORM_VERSION_LAST_STABLE) \
     --prop com.android.build.system.security_patch:$(PLATFORM_SECURITY_PATCH)
 
 BOARD_AVB_PRODUCT_ADD_HASHTREE_FOOTER_ARGS += \
     --prop com.android.build.product.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
-    --prop com.android.build.product.os_version:$(PLATFORM_VERSION) \
+    --prop com.android.build.product.os_version:$(PLATFORM_VERSION_LAST_STABLE) \
     --prop com.android.build.product.security_patch:$(PLATFORM_SECURITY_PATCH)
 
 BOARD_AVB_SYSTEM_EXT_ADD_HASHTREE_FOOTER_ARGS += \
     --prop com.android.build.system_ext.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
-    --prop com.android.build.system_ext.os_version:$(PLATFORM_VERSION) \
+    --prop com.android.build.system_ext.os_version:$(PLATFORM_VERSION_LAST_STABLE) \
     --prop com.android.build.system_ext.security_patch:$(PLATFORM_SECURITY_PATCH)
 
 BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS += \
     --prop com.android.build.boot.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
-    --prop com.android.build.boot.os_version:$(PLATFORM_VERSION)
+    --prop com.android.build.boot.os_version:$(PLATFORM_VERSION_LAST_STABLE)
 
 BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS += \
     --prop com.android.build.vendor_boot.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
@@ -3314,11 +3168,11 @@
 
 BOARD_AVB_VENDOR_ADD_HASHTREE_FOOTER_ARGS += \
     --prop com.android.build.vendor.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
-    --prop com.android.build.vendor.os_version:$(PLATFORM_VERSION)
+    --prop com.android.build.vendor.os_version:$(PLATFORM_VERSION_LAST_STABLE)
 
 BOARD_AVB_ODM_ADD_HASHTREE_FOOTER_ARGS += \
     --prop com.android.build.odm.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
-    --prop com.android.build.odm.os_version:$(PLATFORM_VERSION)
+    --prop com.android.build.odm.os_version:$(PLATFORM_VERSION_LAST_STABLE)
 
 BOARD_AVB_VENDOR_DLKM_ADD_HASHTREE_FOOTER_ARGS += \
     --prop com.android.build.vendor_dlkm.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
@@ -3937,9 +3791,6 @@
   ifeq ($(TARGET_PRODUCT),sdk)
     build_ota_package := false
   endif
-  ifeq ($(TARGET_BUILD_PDK),true)
-    build_ota_package := false
-  endif
   ifneq ($(PRODUCT_BUILD_GENERIC_OTA_PACKAGE),true)
     ifneq ($(filter generic%,$(TARGET_DEVICE)),)
       build_ota_package := false
@@ -4279,6 +4130,9 @@
 ifdef DEVICE_MANIFEST_FILE
 	$(hide) echo "vintf_include_empty_vendor_sku=true" >> $@
 endif
+ifeq ($(BOARD_BOOTLOADER_IN_UPDATE_PACKAGE),true)
+	$(hide) echo "bootloader_in_update_package=true" >> $@
+endif
 
 .PHONY: misc_info
 misc_info: $(INSTALLED_MISC_INFO_TARGET)
@@ -4427,34 +4281,98 @@
 # full system image deps, we speed up builds that do not build the system
 # image.
 ifdef BUILDING_SYSTEM_IMAGE
-$(BUILT_TARGET_FILES_PACKAGE): $(FULL_SYSTEMIMAGE_DEPS)
+  $(BUILT_TARGET_FILES_PACKAGE): $(FULL_SYSTEMIMAGE_DEPS)
+endif
+
+ifdef BUILDING_USERDATA_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_USERDATAIMAGE_FILES)
+endif
+
+ifdef BUILDING_SYSTEM_OTHER_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_SYSTEMOTHERIMAGE_FILES)
+endif
+
+ifdef BUILDING_VENDOR_BOOT_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_VENDOR_RAMDISK_FILES)
+endif
+
+ifdef BUILDING_RECOVERY_IMAGE
+  # TODO(b/30414428): Can't depend on INTERNAL_RECOVERYIMAGE_FILES alone like other
+  # BUILD_TARGET_FILES_PACKAGE dependencies because currently there're cp/rsync/rm
+  # commands in build-recoveryimage-target, which would touch the files under
+  # TARGET_RECOVERY_OUT and race with packaging target-files.zip.
+  ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+    $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_BOOTIMAGE_TARGET)
+  else
+    $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_RECOVERYIMAGE_TARGET)
+  endif
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_RECOVERYIMAGE_FILES)
+endif
+
+# Conditionally depend on the image files if the image is being built so the
+# target-files.zip rule doesn't wait on the image creation rule, or the image
+# if it is coming from a prebuilt.
+
+ifdef BUILDING_VENDOR_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_VENDORIMAGE_FILES)
+else ifdef BOARD_PREBUILT_VENDORIMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_VENDORIMAGE_TARGET)
+endif
+
+ifdef BUILDING_PRODUCT_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_PRODUCTIMAGE_FILES)
+else ifdef BOARD_PREBUILT_PRODUCTIMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_PRODUCTIMAGE_TARGET)
+endif
+
+ifdef BUILDING_SYSTEM_EXT_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_SYSTEM_EXTIMAGE_FILES)
+else ifdef BOARD_PREBUILT_SYSTEM_EXTIMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_SYSTEM_EXTIMAGE_TARGET)
+endif
+
+ifdef BUILDING_BOOT_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_RAMDISK_FILES)
+else ifdef BOARD_PREBUILT_BOOTIMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_BOOTIMAGE_TARGET)
+endif
+
+ifdef BUILDING_ODM_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_ODMIMAGE_FILES)
+else ifdef BOARD_PREBUILT_ODMIMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_ODMIMAGE_TARGET)
+endif
+
+ifdef BUILDING_VENDOR_DLKM_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_VENDOR_DLKMIMAGE_FILES)
+else ifdef BOARD_PREBUILT_VENDOR_DLKIMMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_VENDOR_DLKMIMAGE_TARGET)
+endif
+
+ifdef BUILDING_ODM_DLKM_IMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_ODM_DLKMIMAGE_FILES)
+else ifdef BOARD_ODM_VENDOR_DLKIMMAGE
+  $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_ODM_DLKMIMAGE_TARGET)
 endif
 
 ifeq ($(BUILD_QEMU_IMAGES),true)
-MK_VBMETA_BOOT_KERNEL_CMDLINE_SH := device/generic/goldfish/tools/mk_vbmeta_boot_params.sh
-$(BUILT_TARGET_FILES_PACKAGE): $(MK_VBMETA_BOOT_KERNEL_CMDLINE_SH)
+  MK_VBMETA_BOOT_KERNEL_CMDLINE_SH := device/generic/goldfish/tools/mk_vbmeta_boot_params.sh
+  $(BUILT_TARGET_FILES_PACKAGE): $(MK_VBMETA_BOOT_KERNEL_CMDLINE_SH)
+endif
+
+ifdef BOARD_PREBUILT_BOOTLOADER
+$(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_BOOTLOADER_MODULE)
+droidcore: $(INSTALLED_BOOTLOADER_MODULE)
 endif
 
 # Depending on the various images guarantees that the underlying
 # directories are up-to-date.
 $(BUILT_TARGET_FILES_PACKAGE): \
-	    $(INSTALLED_RAMDISK_TARGET) \
-	    $(INSTALLED_BOOTIMAGE_TARGET) \
-	    $(INSTALLED_VENDOR_BOOTIMAGE_TARGET) \
 	    $(INSTALLED_RADIOIMAGE_TARGET) \
 	    $(INSTALLED_RECOVERYIMAGE_TARGET) \
-	    $(INSTALLED_USERDATAIMAGE_TARGET) \
 	    $(INSTALLED_CACHEIMAGE_TARGET) \
-	    $(INSTALLED_VENDORIMAGE_TARGET) \
-	    $(INSTALLED_PRODUCTIMAGE_TARGET) \
-	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
-	    $(INSTALLED_VBMETAIMAGE_TARGET) \
-	    $(INSTALLED_ODMIMAGE_TARGET) \
-	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
-	    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
 	    $(INSTALLED_DTBOIMAGE_TARGET) \
 	    $(INSTALLED_CUSTOMIMAGES_TARGET) \
-	    $(INTERNAL_SYSTEMOTHERIMAGE_FILES) \
 	    $(INSTALLED_ANDROID_INFO_TXT_TARGET) \
 	    $(INSTALLED_KERNEL_TARGET) \
 	    $(INSTALLED_DTBIMAGE_TARGET) \
@@ -4482,12 +4400,6 @@
 	    $(BUILT_KERNEL_VERSION_FILE) \
 	    | $(ACP)
 	@echo "Package target files: $@"
-	$(call create-system-vendor-symlink)
-	$(call create-system-product-symlink)
-	$(call create-system-system_ext-symlink)
-	$(call create-vendor-odm-symlink)
-	$(call create-vendor-vendor_dlkm-symlink)
-	$(call create-odm-odm_dlkm-symlink)
 	$(hide) rm -rf $@ $@.list $(zip_root)
 	$(hide) mkdir -p $(dir $@) $(zip_root)
 ifneq (,$(INSTALLED_RECOVERYIMAGE_TARGET)$(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
@@ -4496,7 +4408,11 @@
 	$(hide) $(call package_files-copy-root, \
 	    $(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/$(PRIVATE_RECOVERY_OUT)/RAMDISK)
 ifdef INSTALLED_KERNEL_TARGET
+ifneq (,$(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
 	cp $(INSTALLED_KERNEL_TARGET) $(zip_root)/$(PRIVATE_RECOVERY_OUT)/
+else # BOARD_USES_RECOVERY_AS_BOOT not true
+	cp $(firstword $(INSTALLED_KERNEL_TARGET)) $(zip_root)/$(PRIVATE_RECOVERY_OUT)/kernel
+endif
 endif
 ifeq (truetrue,$(strip $(BUILDING_VENDOR_BOOT_IMAGE))$(strip $(AB_OTA_UPDATER)))
 	echo "$(GENERIC_KERNEL_CMDLINE)" > $(zip_root)/$(PRIVATE_RECOVERY_OUT)/cmdline
@@ -4526,7 +4442,7 @@
 ifdef BOARD_KERNEL_PAGESIZE
 	echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/$(PRIVATE_RECOVERY_OUT)/pagesize
 endif
-endif # INSTALLED_VENDOR_BOOTIMAGE_TARGET not defined
+endif # not (BUILDING_VENDOR_BOOT_IMAGE and AB_OTA_UPDATER)
 endif # INSTALLED_RECOVERYIMAGE_TARGET defined or BOARD_USES_RECOVERY_AS_BOOT is true
 	@# Components of the boot image
 	$(hide) mkdir -p $(zip_root)/BOOT
@@ -4540,7 +4456,7 @@
 	    $(TARGET_RAMDISK_OUT),$(zip_root)/BOOT/RAMDISK)
 endif
 ifdef INSTALLED_KERNEL_TARGET
-	$(hide) cp $(INSTALLED_KERNEL_TARGET) $(zip_root)/BOOT/kernel
+	$(hide) cp $(INSTALLED_KERNEL_TARGET) $(zip_root)/BOOT/
 endif
 ifndef INSTALLED_VENDOR_BOOTIMAGE_TARGET
 ifdef INSTALLED_2NDBOOTLOADER_TARGET
@@ -4716,14 +4632,22 @@
 	$(hide) mkdir -p $(zip_root)/IMAGES
 	$(hide) cp $(INSTALLED_ODMIMAGE_TARGET) $(zip_root)/IMAGES/
 endif
-ifdef BOARD_PREBUILT_VENDOR_DLKIMMAGE
+ifdef BOARD_PREBUILT_VENDOR_DLKMIMAGE
 	$(hide) mkdir -p $(zip_root)/IMAGES
-	$(hide) cp $(INSTALLED_VENDOR_DLKIMMAGE_TARGET) $(zip_root)/IMAGES/
+	$(hide) cp $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) $(zip_root)/IMAGES/
+endif
+ifdef BOARD_PREBUILT_ODM_DLKMIMAGE
+	$(hide) mkdir -p $(zip_root)/IMAGES
+	$(hide) cp $(INSTALLED_ODM_DLKMIMAGE_TARGET) $(zip_root)/IMAGES/
 endif
 ifdef BOARD_PREBUILT_DTBOIMAGE
 	$(hide) mkdir -p $(zip_root)/PREBUILT_IMAGES
 	$(hide) cp $(INSTALLED_DTBOIMAGE_TARGET) $(zip_root)/PREBUILT_IMAGES/
 endif # BOARD_PREBUILT_DTBOIMAGE
+ifdef BOARD_PREBUILT_BOOTLOADER
+	$(hide) mkdir -p $(zip_root)/IMAGES
+	$(hide) cp $(INSTALLED_BOOTLOADER_MODULE) $(zip_root)/IMAGES/
+endif
 ifneq ($(strip $(BOARD_CUSTOMIMAGES_PARTITION_LIST)),)
 	$(hide) mkdir -p $(zip_root)/PREBUILT_IMAGES
 	$(hide) $(foreach partition,$(BOARD_CUSTOMIMAGES_PARTITION_LIST), \
@@ -4802,9 +4726,7 @@
 .PHONY: target-files-package
 target-files-package: $(BUILT_TARGET_FILES_PACKAGE)
 
-ifneq ($(filter $(MAKECMDGOALS),target-files-package),)
 $(call dist-for-goals, target-files-package, $(BUILT_TARGET_FILES_PACKAGE))
-endif
 
 # -----------------------------------------------------------------
 # NDK Sysroot Package
@@ -4878,13 +4800,12 @@
 APPCOMPAT_ZIP := $(PRODUCT_OUT)/appcompat.zip
 # For apps_only build we'll establish the dependency later in build/make/core/main.mk.
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
-$(APPCOMPAT_ZIP): $(INSTALLED_SYSTEMIMAGE_TARGET) \
-	    $(INSTALLED_RAMDISK_TARGET) \
-	    $(INSTALLED_BOOTIMAGE_TARGET) \
-	    $(INSTALLED_USERDATAIMAGE_TARGET) \
-	    $(INSTALLED_VENDORIMAGE_TARGET) \
-	    $(INSTALLED_PRODUCTIMAGE_TARGET) \
-	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET)
+$(APPCOMPAT_ZIP): $(FULL_SYSTEMIMAGE_DEPS) \
+	    $(INTERNAL_RAMDISK_FILES) \
+	    $(INTERNAL_USERDATAIMAGE_FILES) \
+	    $(INTERNAL_VENDORIMAGE_FILES) \
+	    $(INTERNAL_PRODUCTIMAGE_FILES) \
+	    $(INTERNAL_SYSTEM_EXTIMAGE_FILES)
 endif
 $(APPCOMPAT_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,appcompat)/filelist
 $(APPCOMPAT_ZIP): $(SOONG_ZIP)
@@ -4907,16 +4828,15 @@
 SYMBOLS_ZIP := $(PRODUCT_OUT)/$(name).zip
 # For apps_only build we'll establish the dependency later in build/make/core/main.mk.
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
-$(SYMBOLS_ZIP): $(INSTALLED_SYSTEMIMAGE_TARGET) \
-	    $(INSTALLED_RAMDISK_TARGET) \
-	    $(INSTALLED_BOOTIMAGE_TARGET) \
-	    $(INSTALLED_USERDATAIMAGE_TARGET) \
-	    $(INSTALLED_VENDORIMAGE_TARGET) \
-	    $(INSTALLED_PRODUCTIMAGE_TARGET) \
-	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
-	    $(INSTALLED_ODMIMAGE_TARGET) \
-	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
-	    $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
+$(SYMBOLS_ZIP): $(FULL_SYSTEMIMAGE_DEPS) \
+	    $(INTERNAL_RAMDISK_FILES) \
+	    $(INTERNAL_USERDATAIMAGE_FILES) \
+	    $(INTERNAL_VENDORIMAGE_FILES) \
+	    $(INTERNAL_PRODUCTIMAGE_FILES) \
+	    $(INTERNAL_SYSTEM_EXTIMAGE_FILES) \
+	    $(INTERNAL_ODMIMAGE_FILES) \
+	    $(INTERNAL_VENDOR_DLKMIMAGE_FILES) \
+	    $(INTERNAL_ODM_DLKMIMAGE_FILES) \
 	    $(updater_dep)
 endif
 $(SYMBOLS_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,symbols)/filelist
@@ -4935,16 +4855,15 @@
 endif
 COVERAGE_ZIP := $(PRODUCT_OUT)/$(name).zip
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
-$(COVERAGE_ZIP): $(INSTALLED_SYSTEMIMAGE_TARGET) \
-	    $(INSTALLED_RAMDISK_TARGET) \
-	    $(INSTALLED_BOOTIMAGE_TARGET) \
-	    $(INSTALLED_USERDATAIMAGE_TARGET) \
-	    $(INSTALLED_VENDORIMAGE_TARGET) \
-	    $(INSTALLED_PRODUCTIMAGE_TARGET) \
-	    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
-	    $(INSTALLED_ODMIMAGE_TARGET) \
-	    $(INSTALLED_VENDOR_DLKMIMAGE_TARGET) \
-	    $(INSTALLED_ODM_DLKMIMAGE_TARGET)
+$(COVERAGE_ZIP): $(FULL_SYSTEMIMAGE_DEPS) \
+	    $(INTERNAL_RAMDISK_FILES) \
+	    $(INTERNAL_USERDATAIMAGE_FILES) \
+	    $(INTERNAL_VENDORIMAGE_FILES) \
+	    $(INTERNAL_PRODUCTIMAGE_FILES) \
+	    $(INTERNAL_SYSTEM_EXTIMAGE_FILES) \
+	    $(INTERNAL_ODMIMAGE_FILES) \
+	    $(INTERNAL_VENDOR_DLKMIMAGE_FILES) \
+	    $(INTERNAL_ODM_DLKMIMAGE_FILES)
 endif
 $(COVERAGE_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,coverage)/filelist
 $(COVERAGE_ZIP): $(SOONG_ZIP)
@@ -4964,7 +4883,7 @@
   $(PROFDATA_ZIP): $(SOONG_ZIP)
 	$(hide) $(SOONG_ZIP) -d -o $@ -C $(LLVM_PREBUILTS_BASE)/linux-x86/$(LLVM_PREBUILTS_VERSION) -f $(LLVM_PROFDATA) -f $(LIBCXX)
 
-  $(call dist-for-goals,droidcore,$(PROFDATA_ZIP))
+  $(call dist-for-goals,droidcore apps_only,$(PROFDATA_ZIP))
 endif
 
 # -----------------------------------------------------------------
@@ -4978,7 +4897,7 @@
 name := $(name)-apps-$(FILE_NAME_TAG)
 
 APPS_ZIP := $(PRODUCT_OUT)/$(name).zip
-$(APPS_ZIP): $(INSTALLED_SYSTEMIMAGE_TARGET)
+$(APPS_ZIP): $(FULL_SYSTEMIMAGE_DEPS)
 	@echo "Package apps: $@"
 	$(hide) rm -rf $@
 	$(hide) mkdir -p $(dir $@)
@@ -5013,6 +4932,32 @@
 # For apps_only build we'll establish the dependency later in build/make/core/main.mk.
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
 $(PROGUARD_DICT_ZIP): \
+    $(FULL_SYSTEMIMAGE_DEPS) \
+    $(INTERNAL_RAMDISK_FILES) \
+    $(INTERNAL_USERDATAIMAGE_FILES) \
+    $(INTERNAL_VENDORIMAGE_FILES) \
+    $(INTERNAL_PRODUCTIMAGE_FILES) \
+    $(INTERNAL_SYSTEM_EXTIMAGE_FILES) \
+    $(INTERNAL_ODMIMAGE_FILES) \
+    $(INTERNAL_VENDOR_DLKMIMAGE_FILES) \
+    $(INTERNAL_ODM_DLKMIMAGE_FILES) \
+    $(updater_dep)
+endif
+$(PROGUARD_DICT_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,proguard)/filelist
+$(PROGUARD_DICT_ZIP): $(SOONG_ZIP)
+	@echo "Packaging Proguard obfuscation dictionary files."
+	mkdir -p $(dir $@) $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS $(dir $(PRIVATE_LIST_FILE))
+	find $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS -name proguard_dictionary | \
+	    sed -e 's/\(.*\)\/proguard_dictionary/\0\n\1\/classes.jar/' > $(PRIVATE_LIST_FILE)
+	$(SOONG_ZIP) --ignore_missing_files -d -o $@ -C $(OUT_DIR)/.. -l $(PRIVATE_LIST_FILE)
+
+#------------------------------------------------------------------
+# A zip of Proguard usage files.
+#
+PROGUARD_USAGE_ZIP := $(PRODUCT_OUT)/$(TARGET_PRODUCT)-proguard-usage-$(FILE_NAME_TAG).zip
+# For apps_only build we'll establish the dependency later in build/make/core/main.mk.
+ifeq (,$(TARGET_BUILD_UNBUNDLED))
+$(PROGUARD_USAGE_ZIP): \
     $(INSTALLED_SYSTEMIMAGE_TARGET) \
     $(INSTALLED_RAMDISK_TARGET) \
     $(INSTALLED_BOOTIMAGE_TARGET) \
@@ -5025,14 +4970,12 @@
     $(INSTALLED_ODM_DLKMIMAGE_TARGET) \
     $(updater_dep)
 endif
-$(PROGUARD_DICT_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,proguard)/filelist
-$(PROGUARD_DICT_ZIP): $(SOONG_ZIP)
-	@echo "Packaging Proguard obfuscation dictionary files."
+$(PROGUARD_USAGE_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,proguard_usage)/filelist
+$(PROGUARD_USAGE_ZIP): $(MERGE_ZIPS)
+	@echo "Packaging Proguard usage files."
 	mkdir -p $(dir $@) $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS $(dir $(PRIVATE_LIST_FILE))
-	find $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS -name proguard_dictionary | \
-	    sed -e 's/\(.*\)\/proguard_dictionary/\0\n\1\/classes.jar/' > $(PRIVATE_LIST_FILE)
-	$(SOONG_ZIP) --ignore_missing_files -d -o $@ -C $(OUT_DIR)/.. -l $(PRIVATE_LIST_FILE)
-
+	find $(TARGET_OUT_COMMON_INTERMEDIATES)/APPS -name proguard_usage.zip > $(PRIVATE_LIST_FILE)
+	$(MERGE_ZIPS) $@ @$(PRIVATE_LIST_FILE)
 
 ifeq (true,$(PRODUCT_USE_DYNAMIC_PARTITIONS))
 
@@ -5311,13 +5254,6 @@
 	$(hide) zip -qjX $@ $(INTERNAL_EMULATOR_PACKAGE_FILES)
 
 endif
-# -----------------------------------------------------------------
-# Old PDK stuffs, retired
-# The pdk package (Platform Development Kit)
-
-#ifneq (,$(filter pdk,$(MAKECMDGOALS)))
-#  include development/pdk/Pdk.mk
-#endif
 
 
 # -----------------------------------------------------------------
@@ -5528,7 +5464,3 @@
 .PHONY: haiku
 haiku: $(SOONG_FUZZ_PACKAGING_ARCH_MODULES) $(ALL_FUZZ_TARGETS)
 $(call dist-for-goals,haiku,$(SOONG_FUZZ_PACKAGING_ARCH_MODULES))
-
-# -----------------------------------------------------------------
-# The makefile for haiku line coverage.
-include $(BUILD_SYSTEM)/line_coverage.mk
diff --git a/core/app_prebuilt_internal.mk b/core/app_prebuilt_internal.mk
index ab574b3..5767996 100644
--- a/core/app_prebuilt_internal.mk
+++ b/core/app_prebuilt_internal.mk
@@ -45,7 +45,7 @@
 # We skip it for unbundled app builds where we cannot build veridex.
 module_run_appcompat :=
 ifeq (true,$(non_system_module))
-ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))  # ! unbundled app build
+ifeq (,$(TARGET_BUILD_APPS))  # ! unbundled app build
 ifneq ($(UNSAFE_DISABLE_HIDDENAPI_FLAGS),true)
   module_run_appcompat := true
 endif
diff --git a/core/autogen_test_config.mk b/core/autogen_test_config.mk
index d4ca56f..137b118 100644
--- a/core/autogen_test_config.mk
+++ b/core/autogen_test_config.mk
@@ -22,6 +22,17 @@
 #   autogen_test_config_file: Path to the test config file generated.
 
 autogen_test_config_file := $(dir $(LOCAL_BUILT_MODULE))$(LOCAL_MODULE).config
+# TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base.
+autogen_test_install_base := /data/local/tmp
+# Automatically setup test root for native test.
+ifeq (true,$(is_native))
+  ifeq (true,$(LOCAL_VENDOR_MODULE))
+    autogen_test_install_base = /data/local/tests/vendor
+  endif
+  ifeq (true,$(LOCAL_USE_VNDK))
+    autogen_test_install_base = /data/local/tests/vendor
+  endif
+endif
 ifeq (true,$(is_native))
 ifeq ($(LOCAL_NATIVE_BENCHMARK),true)
 autogen_test_config_template := $(NATIVE_BENCHMARK_TEST_CONFIG_TEMPLATE)
@@ -33,10 +44,11 @@
   endif
 endif
 # Auto generating test config file for native test
+$(autogen_test_config_file): PRIVATE_TEST_INSTALL_BASE := $(autogen_test_install_base)
 $(autogen_test_config_file): PRIVATE_MODULE_NAME := $(LOCAL_MODULE)
 $(autogen_test_config_file) : $(autogen_test_config_template)
 	@echo "Auto generating test config $(notdir $@)"
-	$(hide) sed 's&{MODULE}&$(PRIVATE_MODULE_NAME)&g;s&{EXTRA_CONFIGS}&&g' $< > $@
+	$(hide) sed 's&{MODULE}&$(PRIVATE_MODULE_NAME)&g;s&{TEST_INSTALL_BASE}&$(PRIVATE_TEST_INSTALL_BASE)&g;s&{EXTRA_CONFIGS}&&g' $< > $@
 my_auto_generate_config := true
 else
 # Auto generating test config file for instrumentation test
diff --git a/core/base_rules.mk b/core/base_rules.mk
index 71c0d73..58be7a2 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -115,6 +115,7 @@
 
 include $(BUILD_SYSTEM)/local_vndk.mk
 include $(BUILD_SYSTEM)/local_systemsdk.mk
+include $(BUILD_SYSTEM)/local_current_sdk.mk
 
 my_module_tags := $(LOCAL_MODULE_TAGS)
 ifeq ($(my_host_cross),true)
@@ -487,7 +488,9 @@
 
 ifndef $(_local_path_target)
   $(_local_path_target) := true
-  $(eval $(call my_path_comp,$(_local_path),$(_local_path_target)))
+  ifneq (,$(findstring /,$(_local_path)))
+    $(eval $(call my_path_comp,$(_local_path),$(_local_path_target)))
+  endif
 endif
 
 _local_path :=
@@ -513,7 +516,11 @@
 $(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD := $(LOCAL_POST_INSTALL_CMD)
 $(LOCAL_INSTALLED_MODULE): $(LOCAL_BUILT_MODULE)
 	@echo "Install: $@"
+ifeq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
+	$(copy-file-or-link-to-new-target)
+else
 	$(copy-file-to-new-target)
+endif
 	$(PRIVATE_POST_INSTALL_CMD)
 endif
 
@@ -755,6 +762,13 @@
         $(test_config):$(dir)/$(LOCAL_MODULE).config)))
   endif
 
+  ifneq (,$(LOCAL_EXTRA_FULL_TEST_CONFIGS))
+    $(foreach test_config_file, $(LOCAL_EXTRA_FULL_TEST_CONFIGS), \
+      $(foreach suite, $(LOCAL_COMPATIBILITY_SUITE), \
+        $(eval my_compat_dist_config_$(suite) += $(foreach dir, $(call compatibility_suite_dirs,$(suite)), \
+          $(test_config_file):$(dir)/$(basename $(notdir $(test_config_file))).config))))
+  endif
+
   ifneq (,$(wildcard $(LOCAL_PATH)/DynamicConfig.xml))
     $(foreach suite, $(LOCAL_COMPATIBILITY_SUITE), \
       $(eval my_compat_dist_config_$(suite) += $(foreach dir, $(call compatibility_suite_dirs,$(suite)), \
@@ -971,6 +985,8 @@
 ALL_MODULES.$(my_register_name).MODULE_NAME := $(LOCAL_MODULE)
 ALL_MODULES.$(my_register_name).COMPATIBILITY_SUITES := $(LOCAL_COMPATIBILITY_SUITE)
 ALL_MODULES.$(my_register_name).TEST_CONFIG := $(test_config)
+ALL_MODULES.$(my_register_name).EXTRA_TEST_CONFIGS := $(LOCAL_EXTRA_FULL_TEST_CONFIGS)
+ALL_MODULES.$(my_register_name).TEST_MAINLINE_MODULES := $(LOCAL_TEST_MAINLINE_MODULES)
 test_config :=
 
 INSTALLABLE_FILES.$(LOCAL_INSTALLED_MODULE).MODULE := $(my_register_name)
diff --git a/core/binary.mk b/core/binary.mk
index 0b03f6a..be008e6 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -181,6 +181,8 @@
     my_ndk_api := $(call math_max,$(my_ndk_api),$(my_min_sdk_version))
   endif
 
+  my_ndk_crt_version := $(my_ndk_api)
+
   my_ndk_hist_api := $(my_ndk_api)
   ifeq ($(my_ndk_api),current)
     # The last API level supported by the old prebuilt NDKs.
diff --git a/core/board_config.mk b/core/board_config.mk
index 391e280..95d8af8 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -20,6 +20,7 @@
 # ###############################################################
 
 _board_strip_readonly_list := \
+  BOARD_BOOTLOADER_IN_UPDATE_PACKAGE \
   BOARD_EGL_CFG \
   BOARD_HAVE_BLUETOOTH \
   BOARD_INSTALLER_CMDLINE \
@@ -98,13 +99,14 @@
 
 _build_broken_var_list := \
   BUILD_BROKEN_DUP_RULES \
+  BUILD_BROKEN_DUP_SYSPROP \
   BUILD_BROKEN_ELF_PREBUILT_PRODUCT_COPY_FILES \
+  BUILD_BROKEN_MISSING_REQUIRED_MODULES \
   BUILD_BROKEN_OUTSIDE_INCLUDE_DIRS \
   BUILD_BROKEN_PREBUILT_ELF_FILES \
   BUILD_BROKEN_TREBLE_SYSPROP_NEVERALLOW \
   BUILD_BROKEN_USES_NETWORK \
   BUILD_BROKEN_VINTF_PRODUCT_COPY_FILES \
-  BUILD_BROKEN_DUP_SYSPROP \
 
 _build_broken_var_list += \
   $(foreach m,$(AVAILABLE_BUILD_MODULE_TYPES) \
@@ -288,7 +290,7 @@
 
 ###########################################
 # Now we can substitute with the real value of TARGET_COPY_OUT_DEBUG_RAMDISK
-ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+ifneq (,$(filter true,$(BOARD_USES_RECOVERY_AS_BOOT) $(BOARD_GKI_NONAB_COMPAT)))
 TARGET_COPY_OUT_DEBUG_RAMDISK := debug_ramdisk/first_stage_ramdisk
 TARGET_COPY_OUT_VENDOR_DEBUG_RAMDISK := vendor_debug_ramdisk/first_stage_ramdisk
 TARGET_COPY_OUT_TEST_HARNESS_RAMDISK := test_harness_ramdisk/first_stage_ramdisk
diff --git a/core/build-system.html b/core/build-system.html
index 9cd7b0b..b872909c 100644
--- a/core/build-system.html
+++ b/core/build-system.html
@@ -440,6 +440,33 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 </pre>
 
+<h3><a name="unbundled-build"/>Unbundled build</h3>
+<p>Unbundled build has several meanings by the context.
+Let me explain the meaning by the flags related to "unbundled build"</p>
+<h4>TARGET_BUILD_UNBUNDLED</h4>
+<p>The source tree might not have the full platform sources. It is always set if
+<code>TARGET_BUILD_APPS</code> or <code>TARGET_BUILD_UNBUNDLED_IMAGE</code> is set.</p>
+<h4>TARGET_BUILD_USE_PREBUILT_SDKS</h4>
+<p>It is an internal flag. If it is set, prebuilt SDKs are used, even if a module's
+<code>LOCAL_SDK_VERSION</code> is <code>current</code> (including <code>system_current</code>,
+<code>core_current</code>, and so on). If it is unset, build current SDKs,
+and use them as usual.</p>
+<h4>DISABLE_PREOPT</h4>
+<p>It is an internal flag as well. If it is set, dexpreopt is disabled.
+It is always set if <code>TARGET_BUILD_APPS</code> or <code>TARGET_BUILD_UNBUNDLED_IMAGE</code> is set,
+because dexpreopt tightly depends on the platform.</p>
+<h4>TARGET_BUILD_APPS</h4>
+<p>Build the apps that can be distributed outside the platform, so it turns on
+<code>TARGET_BUILD_UNBUNDLED</code> and <code>DISABLE_PREOPT</code>.
+Also, it turns on <code>TARGET_BUILD_USE_PREBUILT_SDKS</code>, unless
+<code>UNBUNDLED_BUILD_SDKS_FROM_SOURCE</code> is set.</p>
+<h4>TARGET_BUILD_UNBUNDLED_IMAGE</h4>
+<p>It is similar to <code>TARGET_BUILD_APPS</code>, but its target is an unbundled partition
+(such as the vendor partition). Accordingly, it sets <code>TARGET_BUILD_UNBUNDLED</code> and <code>DISABLE_PREOPT</code>.
+We can call the partition unbundled, because the partition can be distributed outside the platform.
+And also, it turns on <code>TARGET_BUILD_USE_PREBUILT_SDKS</code>, unless
+<code>UNBUNDLED_BUILD_SDKS_FROM_SOURCE</code> is set.</p>
+
 <h3><a name="platform-specific"/>Platform specific conditionals</h3>
 <p>Sometimes you need to set flags specifically for different platforms.  Here
 is a list of which values the different build-system defined variables will be
diff --git a/core/check_elf_file.mk b/core/check_elf_file.mk
index d54a5b7..b5be81f 100644
--- a/core/check_elf_file.mk
+++ b/core/check_elf_file.mk
@@ -14,12 +14,14 @@
 # - my_installed_module_stem
 # - my_prebuilt_src_file
 # - my_check_elf_file_shared_lib_files
+# - my_system_shared_libraries
 
 ifndef LOCAL_IS_HOST_MODULE
 ifneq ($(filter $(LOCAL_MODULE_CLASS),SHARED_LIBRARIES EXECUTABLES NATIVE_TESTS),)
 check_elf_files_stamp := $(intermediates)/check_elf_files.timestamp
 $(check_elf_files_stamp): PRIVATE_SONAME := $(if $(filter $(LOCAL_MODULE_CLASS),SHARED_LIBRARIES),$(my_installed_module_stem))
 $(check_elf_files_stamp): PRIVATE_ALLOW_UNDEFINED_SYMBOLS := $(LOCAL_ALLOW_UNDEFINED_SYMBOLS)
+$(check_elf_files_stamp): PRIVATE_SYSTEM_SHARED_LIBRARIES := $(my_system_shared_libraries)
 # PRIVATE_SHARED_LIBRARY_FILES are file paths to built shared libraries.
 # In addition to $(my_check_elf_file_shared_lib_files), some file paths are
 # added by `resolve-shared-libs-for-elf-file-check` from `core/main.mk`.
@@ -33,6 +35,7 @@
 	    --skip-unknown-elf-machine \
 	    $(if $(PRIVATE_SONAME),--soname $(PRIVATE_SONAME)) \
 	    $(foreach l,$(PRIVATE_SHARED_LIBRARY_FILES),--shared-lib $(l)) \
+	    $(foreach l,$(PRIVATE_SYSTEM_SHARED_LIBRARIES),--system-shared-lib $(l)) \
 	    $(if $(PRIVATE_ALLOW_UNDEFINED_SYMBOLS),--allow-undefined-symbols) \
 	    --llvm-readobj=$(LLVM_READOBJ) \
 	    $<
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 7f420a7..d515db3 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -98,6 +98,7 @@
 LOCAL_EXPORT_SDK_LIBRARIES:=
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS:=
 LOCAL_EXPORT_STATIC_LIBRARY_HEADERS:=
+LOCAL_EXTRA_FULL_TEST_CONFIGS:=
 LOCAL_EXTRACT_APK:=
 LOCAL_EXTRACT_DPI_APK:=
 LOCAL_FDO_SUPPORT:=
@@ -258,7 +259,6 @@
 LOCAL_SANITIZE_DIAG:=
 LOCAL_SANITIZE_RECOVER:=
 LOCAL_SANITIZE_NO_RECOVER:=
-LOCAL_SANITIZE_BLACKLIST :=
 LOCAL_SANITIZE_BLOCKLIST :=
 LOCAL_SDK_LIBRARIES :=
 LOCAL_SDK_RES_VERSION:=
@@ -276,6 +276,7 @@
 LOCAL_SOONG_LINK_TYPE :=
 LOCAL_SOONG_LINT_REPORTS :=
 LOCAL_SOONG_PROGUARD_DICT :=
+LOCAL_SOONG_PROGUARD_USAGE_ZIP :=
 LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=
 LOCAL_SOONG_DEVICE_RRO_DIRS :=
 LOCAL_SOONG_PRODUCT_RRO_DIRS :=
@@ -299,6 +300,7 @@
 LOCAL_TARGET_REQUIRED_MODULES:=
 LOCAL_TEST_CONFIG:=
 LOCAL_TEST_DATA:=
+LOCAL_TEST_MAINLINE_MODULES:=
 LOCAL_TEST_MODULE_TO_PROGUARD_WITH:=
 LOCAL_TIDY:=
 LOCAL_TIDY_CHECKS:=
diff --git a/core/combo/HOST_CROSS_linux_bionic-arm64.mk b/core/combo/HOST_CROSS_linux_bionic-arm64.mk
new file mode 100644
index 0000000..df6865f
--- /dev/null
+++ b/core/combo/HOST_CROSS_linux_bionic-arm64.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+# Configuration for builds hosted on linux_arm-arm64
+# Included by combo/select.mk
+
+define $(combo_var_prefix)transform-shared-lib-to-toc
+$(call _gen_toc_command_for_elf,$(1),$(2))
+endef
diff --git a/core/combo/arch/arm64/armv8-2a-dotprod.mk b/core/combo/arch/arm64/armv8-2a-dotprod.mk
new file mode 100644
index 0000000..c775cf7
--- /dev/null
+++ b/core/combo/arch/arm64/armv8-2a-dotprod.mk
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+# .mk file required to support build for the new armv8-2a-dotprod Arm64 arch
+# variant. The file just needs to be present but does not require to contain
+# anything
diff --git a/core/config.mk b/core/config.mk
index 1a0a418..be0b55c 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -154,6 +154,7 @@
 $(KATI_obsolete_var COVERAGE_PATHS,Use NATIVE_COVERAGE_PATHS instead)
 $(KATI_obsolete_var COVERAGE_EXCLUDE_PATHS,Use NATIVE_COVERAGE_EXCLUDE_PATHS instead)
 $(KATI_obsolete_var BOARD_VNDK_RUNTIME_DISABLE,VNDK-Lite is no longer supported.)
+$(KATI_obsolete_var LOCAL_SANITIZE_BLACKLIST,Use LOCAL_SANITIZE_BLOCKLIST instead.)
 
 # Used to force goals to build.  Only use for conditionally defined goals.
 .PHONY: FORCE
@@ -428,95 +429,12 @@
 endif
 endif
 
-# Set up PDK so we can use TARGET_BUILD_PDK to select prebuilt tools below
-.PHONY: pdk fusion
-pdk fusion: $(DEFAULT_GOAL)
-
-# What to build:
-# pdk fusion if:
-# 1) PDK_FUSION_PLATFORM_ZIP / PDK_FUSION_PLATFORM_DIR is passed in from the environment
-# or
-# 2) the platform.zip / pdk.mk exists in the default location
-# or
-# 3) fusion is a command line build goal,
-#    PDK_FUSION_PLATFORM_ZIP is needed anyway, then do we need the 'fusion' goal?
-# otherwise pdk only if:
-# 1) pdk is a command line build goal
-# or
-# 2) TARGET_BUILD_PDK is passed in from the environment
-
-# if PDK_FUSION_PLATFORM_ZIP or PDK_FUSION_PLATFORM_DIR is specified, do not override.
-ifeq (,$(strip $(PDK_FUSION_PLATFORM_ZIP)$(PDK_FUSION_PLATFORM_DIR)))
-  # Most PDK project paths should be using vendor/pdk/TARGET_DEVICE
-  # but some legacy ones (e.g. mini_armv7a_neon generic PDK) were setup
-  # with vendor/pdk/TARGET_PRODUCT.
-  # Others are set up with vendor/pdk/TARGET_DEVICE/TARGET_DEVICE-userdebug
-  _pdk_fusion_search_paths := \
-    vendor/pdk/$(TARGET_DEVICE)/$(TARGET_DEVICE)-$(TARGET_BUILD_VARIANT)/platform \
-    vendor/pdk/$(TARGET_DEVICE)/$(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT)/platform \
-    vendor/pdk/$(TARGET_DEVICE)/$(patsubst aosp_%,full_%,$(TARGET_PRODUCT))-$(TARGET_BUILD_VARIANT)/platform \
-    vendor/pdk/$(TARGET_PRODUCT)/$(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT)/platform \
-    vendor/pdk/$(TARGET_PRODUCT)/$(patsubst aosp_%,full_%,$(TARGET_PRODUCT))-$(TARGET_BUILD_VARIANT)/platform
-
-  _pdk_fusion_default_platform_zip := $(strip $(foreach p,$(_pdk_fusion_search_paths),$(wildcard $(p)/platform.zip)))
-  ifneq (,$(_pdk_fusion_default_platform_zip))
-    PDK_FUSION_PLATFORM_ZIP := $(word 1, $(_pdk_fusion_default_platform_zip))
-    _pdk_fusion_default_platform_zip :=
-  else
-    _pdk_fusion_default_platform_mk := $(strip $(foreach p,$(_pdk_fusion_search_paths),$(wildcard $(p)/pdk.mk)))
-    ifneq (,$(_pdk_fusion_default_platform_mk))
-      PDK_FUSION_PLATFORM_DIR := $(dir $(word 1,$(_pdk_fusion_default_platform_mk)))
-      _pdk_fusion_default_platform_mk :=
-    endif
-  endif # _pdk_fusion_default_platform_zip
-  _pdk_fusion_search_paths :=
-endif # !PDK_FUSION_PLATFORM_ZIP && !PDK_FUSION_PLATFORM_DIR
-
-ifneq (,$(PDK_FUSION_PLATFORM_ZIP))
-  ifneq (,$(PDK_FUSION_PLATFORM_DIR))
-    $(error Only one of PDK_FUSION_PLATFORM_ZIP or PDK_FUSION_PLATFORM_DIR may be specified)
-  endif
-endif
-
-ifneq (,$(filter pdk fusion, $(MAKECMDGOALS)))
-TARGET_BUILD_PDK := true
-ifneq (,$(filter fusion, $(MAKECMDGOALS)))
-ifeq (,$(strip $(PDK_FUSION_PLATFORM_ZIP)$(PDK_FUSION_PLATFORM_DIR)))
-  $(error Specify PDK_FUSION_PLATFORM_ZIP or PDK_FUSION_PLATFORM_DIR to do a PDK fusion.)
-endif
-endif  # fusion
-endif  # pdk or fusion
-
-ifdef PDK_FUSION_PLATFORM_ZIP
-TARGET_BUILD_PDK := true
-ifeq (,$(wildcard $(PDK_FUSION_PLATFORM_ZIP)))
-  ifneq (,$(wildcard $(patsubst %.zip,%,$(PDK_FUSION_PLATFORM_ZIP))/pdk.mk))
-    PDK_FUSION_PLATFORM_DIR := $(patsubst %.zip,%,$(PDK_FUSION_PLATFORM_ZIP))
-    PDK_FUSION_PLATFORM_ZIP :=
-  else
-    $(error Cannot find file $(PDK_FUSION_PLATFORM_ZIP).)
-  endif
-endif
-endif
-
-ifdef PDK_FUSION_PLATFORM_DIR
-TARGET_BUILD_PDK := true
-ifeq (,$(wildcard $(PDK_FUSION_PLATFORM_DIR)/pdk.mk))
-  $(error Cannot find file $(PDK_FUSION_PLATFORM_DIR)/pdk.mk.)
-endif
-endif
-
-BUILD_PLATFORM_ZIP := $(filter platform platform-java,$(MAKECMDGOALS))
-
 # ---------------------------------------------------------------
 # Whether we can expect a full build graph
 ALLOW_MISSING_DEPENDENCIES := $(filter true,$(ALLOW_MISSING_DEPENDENCIES))
 ifneq ($(TARGET_BUILD_APPS),)
 ALLOW_MISSING_DEPENDENCIES := true
 endif
-ifeq ($(TARGET_BUILD_PDK),true)
-ALLOW_MISSING_DEPENDENCIES := true
-endif
 ifeq ($(TARGET_BUILD_UNBUNDLED_IMAGE),true)
 ALLOW_MISSING_DEPENDENCIES := true
 endif
@@ -561,23 +479,23 @@
 #
 # Tools that are prebuilts for TARGET_BUILD_USE_PREBUILT_SDKS
 #
-ifeq (,$(TARGET_BUILD_USE_PREBUILT_SDKS)$(filter true,$(TARGET_BUILD_PDK)))
+ifeq (,$(TARGET_BUILD_USE_PREBUILT_SDKS))
   AAPT := $(HOST_OUT_EXECUTABLES)/aapt
   MAINDEXCLASSES := $(HOST_OUT_EXECUTABLES)/mainDexClasses
 
-else # TARGET_BUILD_USE_PREBUILT_SDKS || TARGET_BUILD_PDK
+else # TARGET_BUILD_USE_PREBUILT_SDKS
   AAPT := $(prebuilt_sdk_tools_bin)/aapt
   MAINDEXCLASSES := $(prebuilt_sdk_tools)/mainDexClasses
-endif # TARGET_BUILD_USE_PREBUILT_SDKS || TARGET_BUILD_PDK
+endif # TARGET_BUILD_USE_PREBUILT_SDKS
 
 ifeq (,$(TARGET_BUILD_USE_PREBUILT_SDKS))
-  # Use RenderScript prebuilts for unbundled builds but not PDK builds
+  # Use RenderScript prebuilts for unbundled builds
   LLVM_RS_CC := $(HOST_OUT_EXECUTABLES)/llvm-rs-cc
   BCC_COMPAT := $(HOST_OUT_EXECUTABLES)/bcc_compat
 else
   LLVM_RS_CC := $(prebuilt_sdk_tools_bin)/llvm-rs-cc
   BCC_COMPAT := $(prebuilt_sdk_tools_bin)/bcc_compat
-endif # TARGET_BUILD_PDK
+endif
 
 prebuilt_sdk_tools :=
 prebuilt_sdk_tools_bin :=
@@ -597,16 +515,8 @@
 # ---------------------------------------------------------------
 # Generic tools.
 
-LEX := $(prebuilt_build_tools_bin_noasan)/flex
-# The default PKGDATADIR built in the prebuilt bison is a relative path
-# prebuilts/build-tools/common/bison.
-# To run bison from elsewhere you need to set up enviromental variable
-# BISON_PKGDATADIR.
-BISON_PKGDATADIR := $(prebuilt_build_tools)/common/bison
-BISON := $(prebuilt_build_tools_bin_noasan)/bison
-YACC := $(BISON) -d
-BISON_DATA := $(wildcard $(BISON_PKGDATADIR)/* $(BISON_PKGDATADIR)/*/*)
-M4 :=$= $(prebuilt_build_tools_bin_noasan)/m4
+# These dependencies are now handled via dependencies on prebuilt_build_tool
+BISON_DATA :=$=
 
 YASM := prebuilts/misc/$(BUILD_OS)-$(HOST_PREBUILT_ARCH)/yasm/yasm
 
@@ -768,33 +678,22 @@
   PRODUCT_USE_VNDK := $(PRODUCT_FULL_TREBLE)
 endif
 
-# Define PRODUCT_PRODUCT_VNDK_VERSION if PRODUCT_USE_VNDK is true and
-# PRODUCT_SHIPPING_API_LEVEL is greater than 29.
-PRODUCT_USE_PRODUCT_VNDK := false
 ifeq ($(PRODUCT_USE_VNDK),true)
-  ifneq ($(PRODUCT_USE_PRODUCT_VNDK_OVERRIDE),)
-    PRODUCT_USE_PRODUCT_VNDK := $(PRODUCT_USE_PRODUCT_VNDK_OVERRIDE)
-  else ifeq ($(PRODUCT_SHIPPING_API_LEVEL),)
-    # No shipping level defined
-  else ifeq ($(call math_gt,$(PRODUCT_SHIPPING_API_LEVEL),29),true)
-    PRODUCT_USE_PRODUCT_VNDK := true
-  endif
-
   ifndef BOARD_VNDK_VERSION
     BOARD_VNDK_VERSION := current
   endif
-
-  ifeq ($(PRODUCT_USE_PRODUCT_VNDK),true)
-    ifndef PRODUCT_PRODUCT_VNDK_VERSION
-      PRODUCT_PRODUCT_VNDK_VERSION := current
-    endif
-  endif
 endif
 
 $(KATI_obsolete_var PRODUCT_USE_VNDK,Use BOARD_VNDK_VERSION instead)
 $(KATI_obsolete_var PRODUCT_USE_VNDK_OVERRIDE,Use BOARD_VNDK_VERSION instead)
-$(KATI_obsolete_var PRODUCT_USE_PRODUCT_VNDK,Use PRODUCT_PRODUCT_VNDK_VERSION instead)
-$(KATI_obsolete_var PRODUCT_USE_PRODUCT_VNDK_OVERRIDE,Use PRODUCT_PRODUCT_VNDK_VERSION instead)
+
+ifdef PRODUCT_PRODUCT_VNDK_VERSION
+  ifndef BOARD_VNDK_VERSION
+    # VNDK for product partition is not available unless BOARD_VNDK_VERSION
+    # defined.
+    $(error PRODUCT_PRODUCT_VNDK_VERSION cannot be defined without defining BOARD_VNDK_VERSION)
+  endif
+endif
 
 # Set BOARD_SYSTEMSDK_VERSIONS to the latest SystemSDK version starting from P-launching
 # devices if unset.
@@ -810,6 +709,16 @@
   endif
 endif
 
+ifndef BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES
+  BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES := current
+else
+  ifdef PRODUCT_SHIPPING_API_LEVEL
+    ifneq ($(call math_lt,$(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES),$(PRODUCT_SHIPPING_API_LEVEL)),)
+      $(error BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES ($(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES)) must be greater than or equal to PRODUCT_SHIPPING_API_LEVEL ($(PRODUCT_SHIPPING_API_LEVEL)))
+    endif
+  endif
+endif
+.KATI_READONLY := BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES
 
 ifdef PRODUCT_SHIPPING_API_LEVEL
   ifneq ($(call numbers_less_than,$(PRODUCT_SHIPPING_API_LEVEL),$(BOARD_SYSTEMSDK_VERSIONS)),)
@@ -859,7 +768,7 @@
 # is made which breaks compatibility with the previous platform sepolicy version,
 # not just on every increase in PLATFORM_SDK_VERSION.  The minor version should
 # be reset to 0 on every bump of the PLATFORM_SDK_VERSION.
-sepolicy_major_vers := 29
+sepolicy_major_vers := 30
 sepolicy_minor_vers := 0
 
 ifneq ($(sepolicy_major_vers), $(PLATFORM_SDK_VERSION))
diff --git a/core/config_sanitizers.mk b/core/config_sanitizers.mk
index 323bb36..eaab1b5 100644
--- a/core/config_sanitizers.mk
+++ b/core/config_sanitizers.mk
@@ -144,9 +144,6 @@
 
 # Support for local sanitize blacklist paths.
 ifneq ($(my_sanitize)$(my_global_sanitize),)
-  ifneq ($(LOCAL_SANITIZE_BLACKLIST),)
-    my_cflags += -fsanitize-blacklist=$(LOCAL_PATH)/$(LOCAL_SANITIZE_BLACKLIST)
-  endif
   ifneq ($(LOCAL_SANITIZE_BLOCKLIST),)
     my_cflags += -fsanitize-blacklist=$(LOCAL_PATH)/$(LOCAL_SANITIZE_BLOCKLIST)
   endif
diff --git a/core/definitions.mk b/core/definitions.mk
index 2bf1ba6..bfbeee3 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -110,6 +110,9 @@
 # All compatibility suites mentioned in LOCAL_COMPATIBILITY_SUITES
 ALL_COMPATIBILITY_SUITES :=
 
+# All compatibility suite files to dist.
+ALL_COMPATIBILITY_DIST_FILES :=
+
 # All LINK_TYPE entries
 ALL_LINK_TYPES :=
 
@@ -2551,6 +2554,18 @@
 $(hide) cp $< $@
 endef
 
+# The same as copy-file-to-new-target, but preserve symlinks. Symlinks are
+# converted to absolute to not break.
+define copy-file-or-link-to-new-target
+@mkdir -p $(dir $@)
+$(hide) rm -f $@
+$(hide) if [ -h $< ]; then \
+  ln -s $$(realpath $<) $@; \
+else \
+  cp $< $@; \
+fi
+endef
+
 # Copy a prebuilt file to a target location.
 define transform-prebuilt-to-target
 @echo "$($(PRIVATE_PREFIX)DISPLAY) Prebuilt: $(PRIVATE_MODULE) ($@)"
@@ -2563,6 +2578,13 @@
 $(copy-file-to-target-strip-comments)
 endef
 
+# Copy a prebuilt file to a target location, but preserve symlinks rather than
+# dereference them.
+define copy-or-link-prebuilt-to-target
+@echo "$($(PRIVATE_PREFIX)DISPLAY) Prebuilt: $(PRIVATE_MODULE) ($@)"
+$(copy-file-or-link-to-new-target)
+endef
+
 # Copy a list of files/directories to target location, with sub dir structure preserved.
 # For example $(HOST_OUT_EXECUTABLES)/aapt -> $(staging)/bin/aapt .
 # $(1): the source list of files/directories.
@@ -2812,6 +2834,7 @@
 # 2. Add all the files to each suite's dependent files list.
 # 3. Do the dependency addition to my_all_targets.
 # 4. Save the module name to COMPATIBILITY.$(suite).MODULES for each suite.
+# 5. Collect files to dist to ALL_COMPATIBILITY_DIST_FILES.
 # Requires for each suite: use my_compat_dist_config_$(suite) to define the test config.
 #    and use my_compat_dist_$(suite) to define the others.
 define create-suite-dependencies
@@ -2824,9 +2847,11 @@
     $$(foreach f,$$(my_compat_dist_$(suite)),$$(call word-colon,2,$$(f))) \
     $$(foreach f,$$(my_compat_dist_config_$(suite)),$$(call word-colon,2,$$(f))) \
     $$(my_compat_dist_test_data_$(suite))) \
+  $(eval ALL_COMPATIBILITY_DIST_FILES += $$(my_compat_dist_$(suite))) \
   $(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))))) \
+$(eval $(my_all_targets) : \
+  $(sort $(foreach suite,$(LOCAL_COMPATIBILITY_SUITE), \
+    $(foreach f,$(my_compat_dist_$(suite)), $(call word-colon,2,$(f))))) \
   $(call copy-many-xml-files-checked, \
     $(sort $(foreach suite,$(LOCAL_COMPATIBILITY_SUITE),$(my_compat_dist_config_$(suite))))))
 endef
@@ -3162,11 +3187,12 @@
 
 ###########################################################
 ## Find system_$(VER) in LOCAL_SDK_VERSION
+## note: system_server_* is excluded. It's a different API surface
 ##
 ## $(1): LOCAL_SDK_VERSION
 ###########################################################
 define has-system-sdk-version
-$(filter system_%,$(1))
+$(filter-out system_server_%,$(filter system_%,$(1)))
 endef
 
 ###########################################################
diff --git a/core/distdir.mk b/core/distdir.mk
index 5f40407..aad8ff3 100644
--- a/core/distdir.mk
+++ b/core/distdir.mk
@@ -28,7 +28,7 @@
 # certain files with certain goals.  When those goals are built
 # and "dist" is specified, the marked files will be copied to DIST_DIR.
 #
-# $(1): a list of goals  (e.g. droid, sdk, pdk, ndk). These must be PHONY
+# $(1): a list of goals  (e.g. droid, sdk, ndk). These must be PHONY
 # $(2): the dist files to add to those goals.  If the file contains ':',
 #       the text following the colon is the name that the file is copied
 #       to under the dist directory.  Subdirs are ok, and will be created
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 167fed9..a5571ae 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -148,15 +148,25 @@
 # BUILD_OS is the real host doing the build.
 BUILD_OS := $(HOST_OS)
 
-HOST_CROSS_OS :=
-# We can cross-build Windows binaries on Linux
+# We can do the cross-build only on Linux
 ifeq ($(HOST_OS),linux)
-ifeq ($(BUILD_HOST_static),)
-HOST_CROSS_OS := windows
-HOST_CROSS_ARCH := x86
-HOST_CROSS_2ND_ARCH := x86_64
-2ND_HOST_CROSS_IS_64_BIT := true
-endif
+  # Windows has been the default host_cross OS
+  ifeq (,$(filter-out windows,$(HOST_CROSS_OS)))
+    # We can only create static host binaries for Linux, so if static host
+    # binaries are requested, turn off Windows cross-builds.
+    ifeq ($(BUILD_HOST_static),)
+      HOST_CROSS_OS := windows
+      HOST_CROSS_ARCH := x86
+      HOST_CROSS_2ND_ARCH := x86_64
+      2ND_HOST_CROSS_IS_64_BIT := true
+    endif
+  else ifeq ($(HOST_CROSS_OS),linux_bionic)
+    ifeq (,$(HOST_CROSS_ARCH))
+      $(error HOST_CROSS_ARCH missing.)
+    endif
+  else
+    $(error Unsupported HOST_CROSS_OS $(HOST_CROSS_OS))
+  endif
 endif
 
 ifeq ($(HOST_OS),)
@@ -328,7 +338,7 @@
 HOST_OUT := $(HOST_OUT_ROOT)/$(HOST_OS)-$(HOST_PREBUILT_ARCH)
 SOONG_HOST_OUT := $(SOONG_OUT_DIR)/host/$(HOST_OS)-$(HOST_PREBUILT_ARCH)
 
-HOST_CROSS_OUT := $(HOST_OUT_ROOT)/windows-$(HOST_PREBUILT_ARCH)
+HOST_CROSS_OUT := $(HOST_OUT_ROOT)/$(HOST_CROSS_OS)-$(HOST_CROSS_ARCH)
 
 .KATI_READONLY := HOST_OUT SOONG_HOST_OUT HOST_CROSS_OUT
 
diff --git a/core/executable_internal.mk b/core/executable_internal.mk
index 32e56dd..c6a8faf 100644
--- a/core/executable_internal.mk
+++ b/core/executable_internal.mk
@@ -56,9 +56,9 @@
 my_target_crtend_o := $(SOONG_$(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJECT_crtend_android)
 endif
 ifneq ($(LOCAL_SDK_VERSION),)
-my_target_crtbegin_dynamic_o := $(wildcard $(my_ndk_sysroot_lib)/crtbegin_dynamic.o)
-my_target_crtbegin_static_o := $(wildcard $(my_ndk_sysroot_lib)/crtbegin_static.o)
-my_target_crtend_o := $(wildcard $(my_ndk_sysroot_lib)/crtend_android.o)
+my_target_crtbegin_dynamic_o := $(SOONG_$(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJECT_crtbegin_dynamic.sdk.$(my_ndk_crt_version))
+my_target_crtbegin_static_o := $(SOONG_$(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJECT_crtbegin_static.sdk.$(my_ndk_crt_version))
+my_target_crtend_o := $(SOONG_$(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJECT_crtend_android.sdk.$(my_ndk_crt_version))
 endif
 $(linked_module): PRIVATE_TARGET_LIBCRT_BUILTINS := $(my_target_libcrt_builtins)
 $(linked_module): PRIVATE_TARGET_LIBATOMIC := $(my_target_libatomic)
diff --git a/core/java.mk b/core/java.mk
index bb4593d..5fe8da5 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -4,17 +4,6 @@
 # LOCAL_MODULE_CLASS
 # all_res_assets
 
-ifeq ($(TARGET_BUILD_PDK),true)
-ifeq ($(TARGET_BUILD_PDK_JAVA_PLATFORM),)
-# LOCAL_SDK not defined or set to current
-ifeq ($(filter-out current,$(LOCAL_SDK_VERSION)),)
-ifneq ($(LOCAL_NO_STANDARD_LIBRARIES),true)
-LOCAL_SDK_VERSION := $(PDK_BUILD_SDK_VERSION)
-endif #!LOCAL_NO_STANDARD_LIBRARIES
-endif
-endif # !PDK_JAVA
-endif #PDK
-
 LOCAL_NO_STANDARD_LIBRARIES:=$(strip $(LOCAL_NO_STANDARD_LIBRARIES))
 LOCAL_SDK_VERSION:=$(strip $(LOCAL_SDK_VERSION))
 
diff --git a/core/line_coverage.mk b/core/line_coverage.mk
deleted file mode 100644
index 6bfbb8d..0000000
--- a/core/line_coverage.mk
+++ /dev/null
@@ -1,94 +0,0 @@
-# -----------------------------------------------------------------
-# Make target for line coverage. This target generates a zip file
-# called `line_coverage_profiles.zip` that contains a large set of
-# zip files one for each fuzz target/critical component. Each zip
-# file contains a set of profile files (*.gcno) that we will use
-# to generate line coverage reports. Furthermore, target compiles
-# all fuzz targets with line coverage instrumentation enabled and
-# packs them into another zip file called `line_coverage_profiles.zip`.
-#
-# To run the make target set the coverage related envvars first:
-# 	NATIVE_COVERAGE=true NATIVE_COVERAGE_PATHS=* make haiku-line-coverage
-# -----------------------------------------------------------------
-
-# TODO(b/148306195): Due this issue some fuzz targets cannot be built with
-# line coverage instrumentation. For now we just block them.
-blocked_fuzz_targets := libneuralnetworks_fuzzer
-
-fuzz_targets := $(ALL_FUZZ_TARGETS)
-fuzz_targets := $(filter-out $(blocked_fuzz_targets),$(fuzz_targets))
-
-
-# Android components that considered critical.
-# Please note that adding/Removing critical components is very rare.
-critical_components_static := \
-	lib-bt-packets \
-	libbt-stack \
-	libffi \
-	libhevcdec \
-	libhevcenc \
-	libmpeg2dec \
-	libosi \
-	libpdx \
-	libselinux \
-	libvold \
-	libyuv
-
-# Format is <module_name> or <module_name>:<apex_name>
-critical_components_shared := \
-	libaudioprocessing \
-	libbinder \
-	libbluetooth_gd \
-	libbrillo \
-	libcameraservice \
-	libcurl \
-	libhardware \
-	libinputflinger \
-	libopus \
-	libstagefright \
-	libvixl:com.android.art.debug
-
-# Use the intermediates directory to avoid installing libraries to the device.
-intermediates := $(call intermediates-dir-for,PACKAGING,haiku-line-coverage)
-
-
-# We want the profile files for all fuzz targets + critical components.
-line_coverage_profiles := $(intermediates)/line_coverage_profiles.zip
-
-critical_components_static_inputs := $(foreach lib,$(critical_components_static), \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,$(lib))/$(lib).a)
-
-critical_components_shared_inputs := $(foreach lib,$(critical_components_shared), \
-	$(eval filename := $(call word-colon,1,$(lib))) \
-	$(eval modulename := $(subst :,.,$(lib))) \
-	$(call intermediates-dir-for,SHARED_LIBRARIES,$(modulename))/$(filename).so)
-
-fuzz_target_inputs := $(foreach fuzz,$(fuzz_targets), \
-	$(call intermediates-dir-for,EXECUTABLES,$(fuzz))/$(fuzz))
-
-# When coverage is enabled (NATIVE_COVERAGE is set), make creates
-# a "coverage" directory and stores all profile (*.gcno) files in inside.
-# We need everything that is stored inside this directory.
-$(line_coverage_profiles): $(fuzz_target_inputs)
-$(line_coverage_profiles): $(critical_components_static_inputs)
-$(line_coverage_profiles): $(critical_components_shared_inputs)
-$(line_coverage_profiles): $(SOONG_ZIP)
-	$(SOONG_ZIP) -o $@ -D $(PRODUCT_OUT)/coverage
-
-
-# Zip all fuzz targets compiled with line coverage.
-line_coverage_fuzz_targets := $(intermediates)/line_coverage_fuzz_targets.zip
-
-$(line_coverage_fuzz_targets): $(fuzz_target_inputs)
-$(line_coverage_fuzz_targets): $(SOONG_ZIP)
-	$(SOONG_ZIP) -o $@ -j $(addprefix -f ,$(fuzz_target_inputs))
-
-
-.PHONY: haiku-line-coverage
-haiku-line-coverage: $(line_coverage_profiles) $(line_coverage_fuzz_targets)
-$(call dist-for-goals, haiku-line-coverage, \
-	$(line_coverage_profiles):line_coverage_profiles.zip \
-	$(line_coverage_fuzz_targets):line_coverage_fuzz_targets.zip)
-
-line_coverage_profiles :=
-line_coverage_fuzz_targets :=
diff --git a/core/local_current_sdk.mk b/core/local_current_sdk.mk
new file mode 100644
index 0000000..ea7da8a
--- /dev/null
+++ b/core/local_current_sdk.mk
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+ifdef BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES
+  ifneq (current,$(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES))
+    ifneq (,$(filter true,$(LOCAL_VENDOR_MODULE) $(LOCAL_ODM_MODULE) $(LOCAL_PROPRIETARY_MODULE)))
+      ifeq (current,$(LOCAL_SDK_VERSION))
+        LOCAL_SDK_VERSION := $(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES)
+      else ifeq (system_current,$(LOCAL_SDK_VERSION))
+        LOCAL_SDK_VERSION := system_$(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES)
+      endif
+    endif
+  endif
+endif
diff --git a/core/main.mk b/core/main.mk
index ab9962a..8c29045 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -33,6 +33,8 @@
 
 include $(SOONG_MAKEVARS_MK)
 
+YACC :=$= $(BISON) -d
+
 include $(BUILD_SYSTEM)/clang/config.mk
 
 # Write the build number to a file so it can be read back in
@@ -79,6 +81,8 @@
 -include test/mts/tools/build/config.mk
 # VTS-Core-specific config.
 -include test/vts/tools/vts-core-tradefed/build/config.mk
+# CSUITE-specific config.
+-include test/app_compat/csuite/tools/build/config.mk
 
 # Clean rules
 .PHONY: clean-dex-files
@@ -175,16 +179,8 @@
 endif
 
 # -----------------------------------------------------------------
-# Variable to check java support level inside PDK build.
-# Not necessary if the components is not in PDK.
-# not defined : not supported
-# "sdk" : sdk API only
-# "platform" : platform API supproted
-TARGET_BUILD_JAVA_SUPPORT_LEVEL := platform
-
-# -----------------------------------------------------------------
-# The pdk (Platform Development Kit) build
-include build/make/core/pdk_config.mk
+# PDK builds are no longer supported, this is always platform
+TARGET_BUILD_JAVA_SUPPORT_LEVEL :=$= platform
 
 # -----------------------------------------------------------------
 
@@ -425,7 +421,7 @@
 sdk_repo_goal := $(strip $(filter sdk_repo,$(MAKECMDGOALS)))
 MAKECMDGOALS := $(strip $(filter-out sdk_repo,$(MAKECMDGOALS)))
 
-ifneq ($(words $(sort $(filter-out $(INTERNAL_MODIFIER_TARGETS) checkbuild emulator_tests target-files-package,$(MAKECMDGOALS)))),1)
+ifneq ($(words $(sort $(filter-out $(INTERNAL_MODIFIER_TARGETS) checkbuild emulator_tests,$(MAKECMDGOALS)))),1)
 $(error The 'sdk' target may not be specified with any other targets)
 endif
 
@@ -516,11 +512,6 @@
 
 $(foreach mk,$(subdir_makefiles),$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] including $(mk) ...)$(eval include $(mk)))
 
-ifneq (,$(PDK_FUSION_PLATFORM_ZIP)$(PDK_FUSION_PLATFORM_DIR))
-# Bring in the PDK platform.zip modules.
-include $(BUILD_SYSTEM)/pdk_fusion_modules.mk
-endif # PDK_FUSION_PLATFORM_ZIP || PDK_FUSION_PLATFORM_DIR
-
 droid_targets : blueprint_tools
 
 endif # dont_bother
@@ -617,8 +608,8 @@
   $(eval modules_32 := $(patsubst %:32,%,$(filter %:32,$(2)))) \
   $(eval modules_64 := $(patsubst %:64,%,$(filter %:64,$(2)))) \
   $(eval modules_both := $(filter-out %:32 %:64,$(2))) \
-  $(eval ### For host cross modules, the primary arch is windows x86 and secondary is x86_64) \
-  $(if $(filter HOST_CROSS,$(1)), \
+  $(eval ### if 2ND_HOST_CROSS_IS_64_BIT, then primary/secondary are reversed for HOST_CROSS modules) \
+  $(if $(filter HOST_CROSS_true,$(1)_$(2ND_HOST_CROSS_IS_64_BIT)), \
     $(eval modules_1st_arch := $(modules_32)) \
     $(eval modules_2nd_arch := $(modules_64)), \
     $(eval modules_1st_arch := $(modules_64)) \
@@ -636,7 +627,6 @@
 )
 endef
 
-# TODO(b/7456955): error if a required module doesn't exist.
 # Resolve the required module names to 32-bit or 64-bit variant for:
 #   ALL_MODULES.<*>.REQUIRED_FROM_TARGET
 #   ALL_MODULES.<*>.REQUIRED_FROM_HOST
@@ -669,7 +659,8 @@
             $(if $(and $(module_is_native),$(required_is_shared_library_or_native_test)), \
               $(if $(ALL_MODULES.$(m).FOR_2ND_ARCH),$(r_i_2nd),$(r_i)), \
               $(r_i) $(r_i_2nd)))) \
-        $(eval ### TODO(b/7456955): error if r_m is empty / does not exist) \
+        $(eval r_m := $(foreach r_j,$(r_m),$(if $(ALL_MODULES.$(r_j).PATH),$(r_j)))) \
+        $(if $(r_m),,$(eval _nonexistent_required += $(1)$(comma)$(m)$(comma)$(1)$(comma)$(r_i))) \
         $(r_m))) \
     $(eval ALL_MODULES.$(m).REQUIRED_FROM_$(1) := $(sort $(r_r))) \
   ) \
@@ -692,18 +683,49 @@
     $(eval r_r := \
       $(foreach r_i,$(r), \
         $(eval r_m := $(call resolve-bitness-for-modules,$(1),$(r_i))) \
-        $(eval ### TODO(b/7456955): error if r_m is empty / does not exist) \
+        $(eval r_m := $(foreach r_j,$(r_m),$(if $(ALL_MODULES.$(r_j).PATH),$(r_j)))) \
+        $(if $(r_m),,$(eval _nonexistent_required += $(2)$(comma)$(m)$(comma)$(1)$(comma)$(r_i))) \
         $(r_m))) \
     $(eval ALL_MODULES.$(m).$(1)_REQUIRED_FROM_$(2) := $(sort $(r_r))) \
   ) \
 )
 endef
 
+_nonexistent_required :=
 $(call select-bitness-of-required-modules,TARGET)
 $(call select-bitness-of-required-modules,HOST)
 $(call select-bitness-of-required-modules,HOST_CROSS)
 $(call select-bitness-of-target-host-required-modules,TARGET,HOST)
 $(call select-bitness-of-target-host-required-modules,HOST,TARGET)
+_nonexistent_required := $(sort $(_nonexistent_required))
+
+check_missing_required_modules := true
+ifneq (,$(filter true,$(ALLOW_MISSING_DEPENDENCIES) $(BUILD_BROKEN_MISSING_REQUIRED_MODULES)))
+  check_missing_required_modules :=
+endif # ALLOW_MISSING_DEPENDENCIES == true || BUILD_BROKEN_MISSING_REQUIRED_MODULES == true
+
+# Some executables are skipped in ASAN SANITIZE_TARGET build, thus breaking their dependencies.
+ifneq (,$(filter address,$(SANITIZE_TARGET)))
+  check_missing_required_modules :=
+endif # SANITIZE_TARGET has ASAN
+
+# HOST OS darwin build is broken, disable this check for darwin for now.
+# TODO(b/162102724): Remove this when darwin host has no broken dependency.
+ifneq (,$(filter $(HOST_OS),darwin))
+  check_missing_required_modules :=
+endif # HOST_OS == darwin
+
+ifeq (true,$(check_missing_required_modules))
+ifneq (,$(_nonexistent_required))
+  $(warning Missing required dependencies:)
+  $(foreach r_i,$(_nonexistent_required), \
+    $(eval r := $(subst $(comma),$(space),$(r_i))) \
+    $(info $(word 1,$(r)) module $(word 2,$(r)) requires non-existent $(word 3,$(r)) module: $(word 4,$(r))) \
+  )
+  $(warning Set BUILD_BROKEN_MISSING_REQUIRED_MODULES := true to bypass this check if this is intentional)
+  $(error Build failed)
+endif # _nonexistent_required != empty
+endif # check_missing_required_modules == true
 
 define add-required-deps
 $(1): | $(2)
@@ -1386,6 +1408,10 @@
 test_files :=
 endif
 
+# Dedpulicate compatibility suite dist files across modules and packages before
+# copying them to their requested locations. Assign the eval result to an unused
+# var to prevent Make from trying to make a sense of it.
+_unused := $(call copy-many-files, $(sort $(ALL_COMPATIBILITY_DIST_FILES)))
 
 # Don't include any GNU General Public License shared objects or static
 # libraries in SDK images.  GPL executables (not static/dynamic libraries)
@@ -1613,6 +1639,10 @@
 # dist_files only for putting your library into the dist directory with a full build.
 .PHONY: dist_files
 
+ifeq ($(SOONG_COLLECT_JAVA_DEPS), true)
+  $(call dist-for-goals, dist_files, $(SOONG_OUT_DIR)/module_bp_java_deps.json)
+endif
+
 .PHONY: apps_only
 ifneq ($(TARGET_BUILD_APPS),)
   # If this build is just for apps, only build apps and not the full system by default.
@@ -1658,6 +1688,9 @@
   $(PROGUARD_DICT_ZIP) : $(apps_only_installed_files)
   $(call dist-for-goals,apps_only, $(PROGUARD_DICT_ZIP))
 
+  $(PROGUARD_USAGE_ZIP) : $(apps_only_installed_files)
+  $(call dist-for-goals,apps_only, $(PROGUARD_USAGE_ZIP))
+
   $(SYMBOLS_ZIP) : $(apps_only_installed_files)
   $(call dist-for-goals,apps_only, $(SYMBOLS_ZIP))
 
@@ -1686,6 +1719,7 @@
     $(BUILT_OTATOOLS_PACKAGE) \
     $(SYMBOLS_ZIP) \
     $(PROGUARD_DICT_ZIP) \
+    $(PROGUARD_USAGE_ZIP) \
     $(COVERAGE_ZIP) \
     $(APPCOMPAT_ZIP) \
     $(INSTALLED_FILES_FILE) \
@@ -1722,13 +1756,11 @@
     $(call dist-for-goals, droidcore, $(f)))
 
   ifneq ($(ANDROID_BUILD_EMBEDDED),true)
-  ifneq ($(TARGET_BUILD_PDK),true)
     $(call dist-for-goals, droidcore, \
       $(APPS_ZIP) \
       $(INTERNAL_EMULATOR_PACKAGE_TARGET) \
     )
   endif
-  endif
 
   $(call dist-for-goals, droidcore, \
     $(INSTALLED_FILES_FILE_ROOT) \
@@ -1768,9 +1800,11 @@
   # Put XML formatted API files in the dist dir.
   $(TARGET_OUT_COMMON_INTERMEDIATES)/api.xml: $(call java-lib-files,android_stubs_current) $(APICHECK)
   $(TARGET_OUT_COMMON_INTERMEDIATES)/system-api.xml: $(call java-lib-files,android_system_stubs_current) $(APICHECK)
+  $(TARGET_OUT_COMMON_INTERMEDIATES)/module-lib-api.xml: $(call java-lib-files,android_module_lib_stubs_current) $(APICHECK)
+  $(TARGET_OUT_COMMON_INTERMEDIATES)/system-server-api.xml: $(call java-lib-files,android_system_server_stubs_current) $(APICHECK)
   $(TARGET_OUT_COMMON_INTERMEDIATES)/test-api.xml: $(call java-lib-files,android_test_stubs_current) $(APICHECK)
 
-  api_xmls := $(addprefix $(TARGET_OUT_COMMON_INTERMEDIATES)/,api.xml system-api.xml test-api.xml)
+  api_xmls := $(addprefix $(TARGET_OUT_COMMON_INTERMEDIATES)/,api.xml system-api.xml module-lib-api.xml system-server-api.xml test-api.xml)
   $(api_xmls):
 	$(hide) echo "Converting API file to XML: $@"
 	$(hide) mkdir -p $(dir $@)
diff --git a/core/native_test_config_template.xml b/core/native_test_config_template.xml
index ef1818f..ea982cf 100644
--- a/core/native_test_config_template.xml
+++ b/core/native_test_config_template.xml
@@ -22,11 +22,11 @@
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}" />
+        <option name="push" value="{MODULE}->{TEST_INSTALL_BASE}/{MODULE}" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="native-test-device-path" value="{TEST_INSTALL_BASE}" />
         <option name="module-name" value="{MODULE}" />
     </test>
 </configuration>
diff --git a/core/ninja_config.mk b/core/ninja_config.mk
index 336048f..6fccacd 100644
--- a/core/ninja_config.mk
+++ b/core/ninja_config.mk
@@ -27,19 +27,14 @@
 	dicttool_aosp \
 	dump-products \
 	eng \
-	fusion \
 	oem_image \
 	online-system-api-sdk-docs \
-	pdk \
-	platform \
-	platform-java \
 	product-graph \
 	samplecode \
 	sdk \
 	sdk_addon \
 	sdk_repo \
 	stnod \
-	target-files-package \
 	test-art% \
 	user \
 	userdataimage \
diff --git a/core/package_internal.mk b/core/package_internal.mk
index b058891..a97e401 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -529,7 +529,7 @@
 # We skip it for unbundled app builds where we cannot build veridex.
 module_run_appcompat :=
 ifeq (true,$(non_system_module))
-ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))  # ! unbundled app build
+ifeq (,$(TARGET_BUILD_APPS))  # ! unbundled app build
 ifneq ($(UNSAFE_DISABLE_HIDDENAPI_FLAGS),true)
   module_run_appcompat := true
 endif
diff --git a/core/pdk_config.mk b/core/pdk_config.mk
deleted file mode 100644
index 922e0ef..0000000
--- a/core/pdk_config.mk
+++ /dev/null
@@ -1,190 +0,0 @@
-# This file defines the rule to fuse the platform.zip into the current PDK build.
-PDK_PLATFORM_JAVA_ZIP_JAVA_TARGET_LIB_DIR :=
-PDK_PLATFORM_JAVA_ZIP_JAVA_HOST_LIB_DIR := \
-	host/common/obj/JAVA_LIBRARIES/bouncycastle-host_intermediates \
-	host/common/obj/JAVA_LIBRARIES/compatibility-host-util_intermediates \
-	host/common/obj/JAVA_LIBRARIES/cts-tradefed-harness_intermediates \
-	host/common/obj/JAVA_LIBRARIES/hosttestlib_intermediates
-PDK_PLATFORM_JAVA_ZIP_CONTENTS :=
-
-ifneq (,$(filter platform-java, $(MAKECMDGOALS))$(PDK_FUSION_PLATFORM_ZIP)$(PDK_FUSION_PLATFORM_DIR))
-# additional items to add to platform.zip for platform-java build
-# For these dirs, add classes.jar and javalib.jar from the dir to platform.zip
-# all paths under out dir
-PDK_PLATFORM_JAVA_ZIP_JAVA_TARGET_LIB_DIR += \
-  target/common/obj/JAVA_LIBRARIES/android.test.runner_intermediates \
-  target/common/obj/JAVA_LIBRARIES/android-common_intermediates \
-  target/common/obj/JAVA_LIBRARIES/android-ex-camera2_intermediates \
-  target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates \
-  target/common/obj/JAVA_LIBRARIES/bouncycastle_intermediates \
-  target/common/obj/JAVA_LIBRARIES/conscrypt_intermediates \
-  target/common/obj/JAVA_LIBRARIES/core-oj_intermediates \
-  target/common/obj/JAVA_LIBRARIES/core-libart_intermediates \
-  target/common/obj/JAVA_LIBRARIES/core-icu4j_intermediates \
-  target/common/obj/JAVA_LIBRARIES/ext_intermediates \
-  target/common/obj/JAVA_LIBRARIES/framework-minus-apex_intermediates \
-  target/common/obj/JAVA_LIBRARIES/hwbinder_intermediates \
-  target/common/obj/JAVA_LIBRARIES/ims-common_intermediates \
-  target/common/obj/JAVA_LIBRARIES/okhttp_intermediates \
-  target/common/obj/JAVA_LIBRARIES/telephony-common_intermediates \
-  target/common/obj/JAVA_LIBRARIES/voip-common_intermediates \
-
-# not java libraries
-PDK_PLATFORM_JAVA_ZIP_CONTENTS += \
-	target/common/obj/APPS/framework-res_intermediates/package-export.apk \
-	target/common/obj/APPS/framework-res_intermediates/src/R.stamp
-endif # platform-java or FUSION build
-
-PDK_PLATFORM_JAVA_ZIP_JAVA_LIB_DIR := \
-	$(PDK_PLATFORM_JAVA_ZIP_JAVA_TARGET_LIB_DIR) \
-	$(PDK_PLATFORM_JAVA_ZIP_JAVA_HOST_LIB_DIR)
-
-PDK_PLATFORM_JAVA_ZIP_CONTENTS += $(foreach lib_dir,$(PDK_PLATFORM_JAVA_ZIP_JAVA_LIB_DIR),\
-    $(lib_dir)/classes.jar $(lib_dir)/classes-header.jar \
-    $(lib_dir)/javalib.jar  $(lib_dir)/classes*.dex \
-    $(lib_dir)/classes.dex.toc )
-
-# check and override java support level
-ifneq ($(TARGET_BUILD_PDK)$(PDK_FUSION_PLATFORM_ZIP)$(PDK_FUSION_PLATFORM_DIR),)
-  ifneq ($(wildcard external/proguard),)
-    TARGET_BUILD_JAVA_SUPPORT_LEVEL := sdk
-  else # no proguard
-    TARGET_BUILD_JAVA_SUPPORT_LEVEL :=
-  endif
-  # platform support is set after checking platform.zip
-endif # PDK
-
-ifneq (,$(PDK_FUSION_PLATFORM_DIR)$(PDK_FUSION_PLATFORM_ZIP))
-
-_pdk_fusion_intermediates :=
-_pdk_fusion_stamp :=
-_pdk_fusion_file_list :=
-_pdk_fusion_java_file_list :=
-PDK_FUSION_SYMLINK_STAMP :=
-
-ifdef PDK_FUSION_PLATFORM_DIR
-  _pdk_fusion_intermediates := $(PDK_FUSION_PLATFORM_DIR)
-  _pdk_fusion_file_list := $(sort \
-    $(shell cd $(PDK_FUSION_PLATFORM_DIR); find * -type f))
-  _pdk_fusion_java_file_list := $(filter target/common/%,$(_pdk_fusion_file_list))
-  _pdk_fusion_file_list := $(filter-out target/common/%,$(_pdk_fusion_file_list))
-
-  PDK_FUSION_SYMLINK_STAMP := $(call intermediates-dir-for, PACKAGING, pdk_fusion)/pdk_symlinks.stamp
-
-  symlink_list := $(sort \
-    $(shell cd $(PDK_FUSION_PLATFORM_DIR); find * -type l))
-$(PDK_FUSION_SYMLINK_STAMP): PRIVATE_SYMLINKS := $(foreach s,$(symlink_list),\
-    $(s):$(shell readlink $(PDK_FUSION_PLATFORM_DIR)/$(s)))
-$(PDK_FUSION_SYMLINK_STAMP):
-	$(foreach s,$(PRIVATE_SYMLINKS),\
-	  mkdir -p $(PRODUCT_OUT)/$(dir $(call word-colon,1,$(s))) && \
-	  ln -sf $(call word-colon,2,$(s)) $(PRODUCT_OUT)/$(call word-colon,1,$(s)) &&) true
-	touch $@
-
-  symlink_list :=
-endif # PDK_FUSION_PLATFORM_DIR
-
-ifdef PDK_FUSION_PLATFORM_ZIP
-  _pdk_fusion_intermediates := $(call intermediates-dir-for, PACKAGING, pdk_fusion)
-  _pdk_fusion_stamp := $(_pdk_fusion_intermediates)/pdk_fusion.stamp
-
-  _pdk_fusion_file_list := $(shell unzip -Z -1 $(PDK_FUSION_PLATFORM_ZIP) \
-      '*[^/]' -x 'target/common/*' 2>/dev/null)
-  _pdk_fusion_java_file_list := \
-      $(shell unzip -Z -1 $(PDK_FUSION_PLATFORM_ZIP) 'target/common/*' 2>/dev/null)
-  _pdk_fusion_files := $(addprefix $(_pdk_fusion_intermediates)/,\
-      $(_pdk_fusion_file_list) $(_pdk_fusion_java_file_list))
-
-$(_pdk_fusion_stamp) : $(PDK_FUSION_PLATFORM_ZIP)
-	@echo "Unzip $(dir $@) <- $<"
-	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)
-	$(hide) unzip -qo $< -d $(dir $@)
-	$(call split-long-arguments,-touch,$(_pdk_fusion_files))
-	$(hide) touch $@
-
-$(_pdk_fusion_files) : $(_pdk_fusion_stamp)
-endif # PDK_FUSION_PLATFORM_ZIP
-
-ifneq ($(_pdk_fusion_java_file_list),)
-  # This represents whether java build can use platform API or not
-  # This should not be used in Android.mk
-  TARGET_BUILD_PDK_JAVA_PLATFORM := true
-  ifneq ($(TARGET_BUILD_JAVA_SUPPORT_LEVEL),)
-    TARGET_BUILD_JAVA_SUPPORT_LEVEL := platform
-  endif
-endif
-
-# Implicit pattern rules to copy the fusion files to the system image directory.
-# Note that if there is already explicit rule in the build system to generate a file,
-# the pattern rule will be just ignored by make.
-# That's desired by us: we want only absent files from the platform zip package.
-# Copy with the last-modified time preserved, never follow symbolic links.
-$(PRODUCT_OUT)/% : $(_pdk_fusion_intermediates)/% $(_pdk_fusion_stamp)
-	@mkdir -p $(dir $@)
-	$(hide) rm -rf $@
-	$(hide) cp -fpPR $< $@
-
-# implicit rules for host java files
-$(HOST_COMMON_OUT_ROOT)/% : $(_pdk_fusion_intermediates)/host/common/% $(_pdk_fusion_stamp)
-	@mkdir -p $(dir $@)
-	$(hide) cp -fpPR $< $@
-
-ifeq (true,$(TARGET_BUILD_PDK_JAVA_PLATFORM))
-  PDK_FUSION_OUT_DIR := $(OUT_DIR)
-
-  define JAVA_dependency_template
-  $(call add-dependency,$(PDK_FUSION_OUT_DIR)/$(strip $(1)),\
-    $(foreach d,$(filter $(2),$(_pdk_fusion_java_file_list)),$(PDK_FUSION_OUT_DIR)/$(d)))
-  endef
-
-  # needs explicit dependency as package-export.apk is not explicitly pulled
-  $(eval $(call JAVA_dependency_template,\
-  target/common/obj/APPS/framework-res_intermediates/src/R.stamp,\
-  target/common/obj/APPS/framework-res_intermediates/package-export.apk))
-
-  # javalib.jar should pull classes.jar as classes.jar is not explicitly pulled.
-  $(foreach lib_dir,$(PDK_PLATFORM_JAVA_ZIP_JAVA_TARGET_LIB_DIR),\
-  $(eval $(call JAVA_dependency_template,$(lib_dir)/javalib.jar,\
-  $(lib_dir)/classes.jar)))
-
-# implicit rules for all other target files
-$(TARGET_COMMON_OUT_ROOT)/% : $(_pdk_fusion_intermediates)/target/common/% $(_pdk_fusion_stamp)
-	@mkdir -p $(dir $@)
-	$(hide) cp -fpPR $< $@
-endif # TARGET_BUILD_PDK_JAVA_PLATFORM
-
-ALL_PDK_FUSION_FILES := $(addprefix $(PRODUCT_OUT)/, $(_pdk_fusion_file_list))
-
-endif # PDK_FUSION_PLATFORM_ZIP || PDK_FUSION_PLATFORM_DIR
-
-ifeq ($(TARGET_BUILD_PDK),true)
-  $(info PDK TARGET_BUILD_JAVA_SUPPORT_LEVEL $(TARGET_BUILD_JAVA_SUPPORT_LEVEL))
-  ifeq ($(TARGET_BUILD_PDK_JAVA_PLATFORM),)
-    # SDK used for Java build under PDK
-    PDK_BUILD_SDK_VERSION := $(lastword $(TARGET_AVAILABLE_SDK_VERSIONS))
-    $(info PDK Build uses SDK $(PDK_BUILD_SDK_VERSION))
-  else # PDK_JAVA
-    $(info PDK Build uses the current platform API)
-  endif # PDK_JAVA
-endif # BUILD_PDK
-
-ifneq (,$(filter platform platform-java, $(MAKECMDGOALS))$(filter true,$(TARGET_BUILD_PDK)))
-  # files under $(PRODUCT_OUT)/symbols to help debugging.
-  # Source not included to PDK due to dependency issue, so provide symbols instead.
-
-  PDK_SYMBOL_FILES_LIST :=
-  ifeq ($(TARGET_IS_64_BIT),true)
-    PDK_SYMBOL_FILES_LIST += system/bin/app_process64
-    ifdef TARGET_2ND_ARCH
-      PDK_SYMBOL_FILES_LIST += system/bin/app_process32
-    endif
-  else
-    PDK_SYMBOL_FILES_LIST += system/bin/app_process32
-  endif
-
-  ifneq (,$(PDK_FUSION_PLATFORM_ZIP)$(PDK_FUSION_PLATFORM_DIR))
-    # symbols should be explicitly pulled for fusion build
-    $(foreach f,$(filter $(PDK_SYMBOL_FILES_LIST), $(_pdk_fusion_file_list)),\
-      $(eval $(call add-dependency,$(PRODUCT_OUT)/$(f),$(PRODUCT_OUT)/symbols/$(f))))
-  endif # PLATFORM_ZIP || PLATFORM_DIR
-endif # platform.zip/dir build or PDK
diff --git a/core/pdk_fusion_modules.mk b/core/pdk_fusion_modules.mk
deleted file mode 100644
index 235acf9..0000000
--- a/core/pdk_fusion_modules.mk
+++ /dev/null
@@ -1,86 +0,0 @@
-# Auto-generate module defitions from platform.zip.
-# We use these rules to rebuild .odex files of the .jar/.apk inside the platform.zip.
-#
-
-ifdef PDK_FUSION_PLATFORM_ZIP
-pdk_dexpreopt_config_mk := $(TARGET_OUT_INTERMEDIATES)/pdk_dexpreopt_config.mk
-
-$(shell rm -f $(pdk_dexpreopt_config_mk) && mkdir -p $(dir $(pdk_dexpreopt_config_mk)) && \
-        unzip -qo $(PDK_FUSION_PLATFORM_ZIP) -d $(dir $(pdk_dexpreopt_config_mk)) pdk_dexpreopt_config.mk 2>/dev/null)
-endif
-
-ifdef PDK_FUSION_PLATFORM_DIR
-pdk_dexpreopt_config_mk := $(PDK_FUSION_PLATFORM_DIR)/pdk_dexpreopt_config.mk
-endif
-
--include $(pdk_dexpreopt_config_mk)
-
-# Define a PDK prebuilt module that comes from platform.zip.
-# Must be called with $(eval)
-define prebuilt-pdk-java-module
-include $(CLEAR_VARS)
-LOCAL_MODULE:=$(1)
-LOCAL_MODULE_CLASS:=$(2)
-# Use LOCAL_PREBUILT_MODULE_FILE instead of LOCAL_SRC_FILES so we don't need to deal with LOCAL_PATH.
-LOCAL_PREBUILT_MODULE_FILE:=$(3)
-LOCAL_DEX_PREOPT:=$(4)
-LOCAL_MULTILIB:=$(5)
-LOCAL_DEX_PREOPT_FLAGS:=$(6)
-LOCAL_BUILT_MODULE_STEM:=$(7)
-LOCAL_MODULE_SUFFIX:=$(suffix $(7))
-LOCAL_PRIVILEGED_MODULE:=$(8)
-LOCAL_VENDOR_MODULE:=$(9)
-LOCAL_MODULE_TARGET_ARCH:=$(10)
-LOCAL_REPLACE_PREBUILT_APK_INSTALLED:=$(11)
-LOCAL_CERTIFICATE:=PRESIGNED
-include $(BUILD_PREBUILT)
-
-# The source prebuilts are extracted in the rule of _pdk_fusion_stamp.
-# Use a touch rule to establish the dependency.
-ifndef PDK_FUSION_PLATFORM_DIR
-$(3) $(11) : $(_pdk_fusion_stamp)
-	$(hide) if [ ! -f $$@ ]; then \
-	  echo 'Error: $$@ does not exist. Check your platform.zip.' 1>&2; \
-	  exit 1; \
-	fi
-	$(hide) touch $$@
-endif
-endef
-
-# We don't have a LOCAL_PATH for the auto-generated modules, so let it be the $(BUILD_SYSTEM).
-LOCAL_PATH := $(BUILD_SYSTEM)
-
-##### Java libraries.
-# Only set up rules for modules that aren't built from source.
-pdk_prebuilt_libraries := $(foreach l,$(PDK.DEXPREOPT.JAVA_LIBRARIES),\
-  $(if $(MODULE.TARGET.JAVA_LIBRARIES.$(l)),,$(l)))
-
-$(foreach l,$(pdk_prebuilt_libraries), $(eval \
-  $(call prebuilt-pdk-java-module,\
-    $(l),\
-    JAVA_LIBRARIES,\
-    $(_pdk_fusion_intermediates)/$(PDK.DEXPREOPT.$(l).SRC),\
-    $(PDK.DEXPREOPT.$(l).DEX_PREOPT),\
-    $(PDK.DEXPREOPT.$(l).MULTILIB),\
-    $(PDK.DEXPREOPT.$(l).DEX_PREOPT_FLAGS),\
-    javalib.jar,\
-    )))
-
-###### Apps.
-pdk_prebuilt_apps := $(foreach a,$(PDK.DEXPREOPT.APPS),\
-  $(if $(MODULE.TARGET.APPS.$(a)),,$(a)))
-
-$(foreach a,$(pdk_prebuilt_apps), $(eval \
-  $(call prebuilt-pdk-java-module,\
-    $(a),\
-    APPS,\
-    $(_pdk_fusion_intermediates)/$(PDK.DEXPREOPT.$(a).SRC),\
-    $(PDK.DEXPREOPT.$(a).DEX_PREOPT),\
-    $(PDK.DEXPREOPT.$(a).MULTILIB),\
-    $(PDK.DEXPREOPT.$(a).DEX_PREOPT_FLAGS),\
-    package.apk,\
-    $(PDK.DEXPREOPT.$(a).PRIVILEGED_MODULE),\
-    $(PDK.DEXPREOPT.$(a).VENDOR_MODULE),\
-    $(PDK.DEXPREOPT.$(a).TARGET_ARCH),\
-    $(_pdk_fusion_intermediates)/$(PDK.DEXPREOPT.$(a).STRIPPED_SRC),\
-    )))
diff --git a/core/product.mk b/core/product.mk
index 324010c..624501e 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -323,7 +323,7 @@
 
 # VNDK version of product partition. It can be 'current' if the product
 # partitions uses PLATFORM_VNDK_VERSION.
-_product_single_value_var += PRODUCT_PRODUCT_VNDK_VERSION
+_product_single_value_vars += PRODUCT_PRODUCT_VNDK_VERSION
 
 # Whether the list of allowed of actionable compatible properties should be disabled or not
 _product_single_value_vars += PRODUCT_ACTIONABLE_COMPATIBLE_PROPERTY_DISABLE
diff --git a/core/product_config.mk b/core/product_config.mk
index 38926c2..6170b5b 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -358,6 +358,12 @@
 $(KATI_obsolete_var OVERRIDE_PRODUCT_EXTRA_VNDK_VERSIONS \
     ,Use PRODUCT_EXTRA_VNDK_VERSIONS instead)
 
+# If build command defines OVERRIDE_PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE,
+# override PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE with it unless it is
+# defined as `false`. If the value is `false` clear
+# PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
+# OVERRIDE_PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE can be used for
+# testing only.
 ifdef OVERRIDE_PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
   ifeq (false,$(OVERRIDE_PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE))
     PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE :=
@@ -367,11 +373,35 @@
 else ifeq ($(PRODUCT_SHIPPING_API_LEVEL),)
   # No shipping level defined
 else ifeq ($(call math_gt,$(PRODUCT_SHIPPING_API_LEVEL),29),true)
+  # Enforce product interface if PRODUCT_SHIPPING_API_LEVEL is greater than 29.
   PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true
 endif
 
 $(KATI_obsolete_var OVERRIDE_PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE,Use PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE instead)
 
+# If build command defines PRODUCT_USE_PRODUCT_VNDK_OVERRIDE as `false`,
+# PRODUCT_PRODUCT_VNDK_VERSION will not be defined automatically.
+# PRODUCT_USE_PRODUCT_VNDK_OVERRIDE can be used for testing only.
+PRODUCT_USE_PRODUCT_VNDK := false
+ifneq ($(PRODUCT_USE_PRODUCT_VNDK_OVERRIDE),)
+  PRODUCT_USE_PRODUCT_VNDK := $(PRODUCT_USE_PRODUCT_VNDK_OVERRIDE)
+else ifeq ($(PRODUCT_SHIPPING_API_LEVEL),)
+  # No shipping level defined
+else ifeq ($(call math_gt,$(PRODUCT_SHIPPING_API_LEVEL),29),true)
+  # Enforce product interface for VNDK if PRODUCT_SHIPPING_API_LEVEL is greater
+  # than 29.
+  PRODUCT_USE_PRODUCT_VNDK := true
+endif
+
+ifeq ($(PRODUCT_USE_PRODUCT_VNDK),true)
+  ifndef PRODUCT_PRODUCT_VNDK_VERSION
+    PRODUCT_PRODUCT_VNDK_VERSION := current
+  endif
+endif
+
+$(KATI_obsolete_var PRODUCT_USE_PRODUCT_VNDK,Use PRODUCT_PRODUCT_VNDK_VERSION instead)
+$(KATI_obsolete_var PRODUCT_USE_PRODUCT_VNDK_OVERRIDE,Use PRODUCT_PRODUCT_VNDK_VERSION instead)
+
 define product-overrides-config
 $$(foreach rule,$$(PRODUCT_$(1)_OVERRIDES),\
     $$(if $$(filter 2,$$(words $$(subst :,$$(space),$$(rule)))),,\
diff --git a/core/rbe.mk b/core/rbe.mk
index 9ec8481..91606d4 100644
--- a/core/rbe.mk
+++ b/core/rbe.mk
@@ -19,45 +19,45 @@
   ifdef RBE_DIR
     rbe_dir := $(RBE_DIR)
   else
-    rbe_dir := $(HOME)/rbe
+    rbe_dir := prebuilts/remoteexecution-client/live/
   endif
 
   ifdef RBE_CXX_EXEC_STRATEGY
     cxx_rbe_exec_strategy := $(RBE_CXX_EXEC_STRATEGY)
   else
-    cxx_rbe_exec_strategy := "local"
+    cxx_rbe_exec_strategy := local
   endif
 
   ifdef RBE_CXX_COMPARE
     cxx_compare := $(RBE_CXX_COMPARE)
   else
-    cxx_compare := "false"
+    cxx_compare := false
   endif
 
   ifdef RBE_JAVAC_EXEC_STRATEGY
     javac_exec_strategy := $(RBE_JAVAC_EXEC_STRATEGY)
   else
-    javac_exec_strategy := "local"
+    javac_exec_strategy := remote_local_fallback
   endif
 
   ifdef RBE_R8_EXEC_STRATEGY
     r8_exec_strategy := $(RBE_R8_EXEC_STRATEGY)
   else
-    r8_exec_strategy := "local"
+    r8_exec_strategy := remote_local_fallback
   endif
 
   ifdef RBE_D8_EXEC_STRATEGY
     d8_exec_strategy := $(RBE_D8_EXEC_STRATEGY)
   else
-    d8_exec_strategy := "local"
+    d8_exec_strategy := remote_local_fallback
   endif
 
-  platform := "container-image=docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:582efb38f0c229ea39952fff9e132ccbe183e14869b39888010dacf56b360d62"
-  cxx_platform := $(platform)",Pool=default"
-  java_r8_d8_platform := $(platform)",Pool=java16"
+  platform := container-image=docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:582efb38f0c229ea39952fff9e132ccbe183e14869b39888010dacf56b360d62
+  cxx_platform := $(platform),Pool=default
+  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)" --compare="$(cxx_compare)"
+  RBE_CXX := --labels=type=compile,lang=cpp,compiler=clang --env_var_allowlist=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.
@@ -65,15 +65,15 @@
   CXX_WRAPPER := $(strip $(CXX_WRAPPER) $(RBE_WRAPPER) $(RBE_CXX))
 
   ifdef RBE_JAVAC
-    JAVAC_WRAPPER := $(strip $(JAVAC_WRAPPER) $(RBE_WRAPPER) --labels=type=compile,lang=java,compiler=javac --exec_strategy=$(javac_exec_strategy) --platform="$(java_r8_d8_platform)")
+    JAVAC_WRAPPER := $(strip $(JAVAC_WRAPPER) $(RBE_WRAPPER) --labels=type=compile,lang=java,compiler=javac --exec_strategy=$(javac_exec_strategy) --platform=$(java_r8_d8_platform))
   endif
 
   ifdef RBE_R8
-    R8_WRAPPER := $(strip $(RBE_WRAPPER) --labels=type=compile,compiler=r8 --exec_strategy=$(r8_exec_strategy) --platform="$(java_r8_d8_platform)" --inputs=out/soong/host/linux-x86/framework/r8-compat-proguard.jar,build/make/core/proguard_basic_keeps.flags --toolchain_inputs=prebuilts/jdk/jdk11/linux-x86/bin/java)
+    R8_WRAPPER := $(strip $(RBE_WRAPPER) --labels=type=compile,compiler=r8 --exec_strategy=$(r8_exec_strategy) --platform=$(java_r8_d8_platform) --inputs=out/soong/host/linux-x86/framework/r8-compat-proguard.jar,build/make/core/proguard_basic_keeps.flags --toolchain_inputs=prebuilts/jdk/jdk11/linux-x86/bin/java)
   endif
 
   ifdef RBE_D8
-    D8_WRAPPER := $(strip $(RBE_WRAPPER) --labels=type=compile,compiler=d8 --exec_strategy=$(d8_exec_strategy) --platform="$(java_r8_d8_platform)" --inputs=out/soong/host/linux-x86/framework/d8.jar --toolchain_inputs=prebuilts/jdk/jdk11/linux-x86/bin/java)
+    D8_WRAPPER := $(strip $(RBE_WRAPPER) --labels=type=compile,compiler=d8 --exec_strategy=$(d8_exec_strategy) --platform=$(java_r8_d8_platform) --inputs=out/soong/host/linux-x86/framework/d8.jar --toolchain_inputs=prebuilts/jdk/jdk11/linux-x86/bin/java)
   endif
 
   rbe_dir :=
diff --git a/core/sdk_font.mk b/core/sdk_font.mk
index 0259a9c..1742925 100644
--- a/core/sdk_font.mk
+++ b/core/sdk_font.mk
@@ -19,9 +19,9 @@
 
 # The font configuration files - system_fonts.xml, fallback_fonts.xml etc.
 sdk_font_config := $(sort $(wildcard frameworks/base/data/fonts/*.xml))
-sdk_font_config :=  $(addprefix $(SDK_FONT_TEMP)/, $(notdir $(sdk_font_config)))
+sdk_font_config :=  $(addprefix $(SDK_FONT_TEMP)/standard/, $(notdir $(sdk_font_config)))
 
-$(sdk_font_config): $(SDK_FONT_TEMP)/%.xml: \
+$(sdk_font_config): $(SDK_FONT_TEMP)/standard/%.xml: \
 			frameworks/base/data/fonts/%.xml
 	$(hide) mkdir -p $(dir $@)
 	$(hide) cp -vf $< $@
diff --git a/core/shared_library_internal.mk b/core/shared_library_internal.mk
index 219772a..12b7f44 100644
--- a/core/shared_library_internal.mk
+++ b/core/shared_library_internal.mk
@@ -51,8 +51,8 @@
 my_target_crtend_so_o := $(SOONG_$(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJECT_crtend_so)
 endif
 ifneq ($(LOCAL_SDK_VERSION),)
-my_target_crtbegin_so_o := $(wildcard $(my_ndk_sysroot_lib)/crtbegin_so.o)
-my_target_crtend_so_o := $(wildcard $(my_ndk_sysroot_lib)/crtend_so.o)
+my_target_crtbegin_so_o := $(SOONG_$(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJECT_crtbegin_so.sdk.$(my_ndk_crt_version))
+my_target_crtend_so_o := $(SOONG_$(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJECT_crtend_so.sdk.$(my_ndk_crt_version))
 endif
 $(linked_module): PRIVATE_TARGET_LIBCRT_BUILTINS := $(my_target_libcrt_builtins)
 $(linked_module): PRIVATE_TARGET_LIBATOMIC := $(my_target_libatomic)
diff --git a/core/soong_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index 46b16ac..50ac93a 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -7,6 +7,7 @@
 # LOCAL_SOONG_HEADER_JAR
 # LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR
 # LOCAL_SOONG_PROGUARD_DICT
+# LOCAL_SOONG_PROGUARD_USAGE
 # LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE
 # LOCAL_SOONG_RRO_DIRS
 # LOCAL_SOONG_JNI_LIBS_$(TARGET_ARCH)
@@ -52,7 +53,7 @@
 # We skip it for unbundled app builds where we cannot build veridex.
 module_run_appcompat :=
 ifeq (true,$(non_system_module))
-ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))  # ! unbundled app build
+ifeq (,$(TARGET_BUILD_APPS))  # ! unbundled app build
 ifneq ($(UNSAFE_DISABLE_HIDDENAPI_FLAGS),true)
   module_run_appcompat := true
 endif
@@ -85,6 +86,13 @@
     $(intermediates.COMMON)/proguard_dictionary)
 endif
 
+ifdef LOCAL_SOONG_PROGUARD_USAGE_ZIP
+  $(eval $(call copy-one-file,$(LOCAL_SOONG_PROGUARD_USAGE_ZIP),\
+    $(intermediates.COMMON)/proguard_usage.zip))
+  $(call add-dependency,$(LOCAL_BUILT_MODULE),\
+    $(intermediates.COMMON)/proguard_usage.zip)
+endif
+
 ifdef LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE
 resource_export_package := $(intermediates.COMMON)/package-export.apk
 resource_export_stamp := $(intermediates.COMMON)/src/R.stamp
diff --git a/core/soong_cc_prebuilt.mk b/core/soong_cc_prebuilt.mk
index c9b742a..770408c 100644
--- a/core/soong_cc_prebuilt.mk
+++ b/core/soong_cc_prebuilt.mk
@@ -91,6 +91,7 @@
 ifdef LOCAL_INSTALLED_MODULE
   ifneq ($(LOCAL_CHECK_ELF_FILES),)
     my_prebuilt_src_file := $(LOCAL_PREBUILT_MODULE_FILE)
+    my_system_shared_libraries := $(LOCAL_SYSTEM_SHARED_LIBRARIES)
     include $(BUILD_SYSTEM)/check_elf_file.mk
   endif
 endif
@@ -142,10 +143,21 @@
   $(LOCAL_BUILT_MODULE): $(same_vndk_variants_stamp)
 endif
 
+# Use copy-or-link-prebuilt-to-target for host executables and shared libraries,
+# to preserve symlinks to the source trees. They can then run directly from the
+# prebuilt directories where the linker can load their dependencies using
+# relative RUNPATHs.
 $(LOCAL_BUILT_MODULE): $(LOCAL_PREBUILT_MODULE_FILE)
+ifeq ($(LOCAL_IS_HOST_MODULE) $(if $(filter EXECUTABLES SHARED_LIBRARIES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),true,),true true)
+	$(copy-or-link-prebuilt-to-target)
+  ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
+	[ -x $@ ] || $(call echo-error,$@,Target of symlink is not executable)
+  endif
+else
 	$(transform-prebuilt-to-target)
-ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
+  ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
 	$(hide) chmod +x $@
+  endif
 endif
 
 ifndef LOCAL_IS_HOST_MODULE
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 9c4b509..ad2e816 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -42,7 +42,6 @@
 $(call add_json_bool, Unbundled_build,                   $(TARGET_BUILD_UNBUNDLED))
 $(call add_json_bool, Unbundled_build_apps,              $(TARGET_BUILD_APPS))
 $(call add_json_bool, Always_use_prebuilt_sdks,          $(TARGET_BUILD_USE_PREBUILT_SDKS))
-$(call add_json_bool, Pdk,                               $(filter true,$(TARGET_BUILD_PDK)))
 
 $(call add_json_bool, Debuggable,                        $(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 $(call add_json_bool, Eng,                               $(filter eng,$(TARGET_BUILD_VARIANT)))
@@ -211,6 +210,7 @@
 $(call end_json_map)
 
 $(call add_json_bool, EnforceProductPartitionInterface,  $(PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE))
+$(call add_json_str,  DeviceCurrentApiLevelForVendorModules,  $(BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES))
 
 $(call add_json_bool, InstallExtraFlattenedApexes, $(PRODUCT_INSTALL_EXTRA_FLATTENED_APEXES))
 
diff --git a/core/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index 05f700d..5444d96 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -58,6 +58,14 @@
     $(intermediates.COMMON)/proguard_dictionary)
 endif
 
+ifdef LOCAL_SOONG_PROGUARD_USAGE
+  $(eval $(call copy-one-file,$(LOCAL_SOONG_PROGUARD_USAGE_ZIP),\
+    $(intermediates.COMMON)/proguard_usage.zip))
+  $(call add-dependency,$(LOCAL_BUILT_MODULE),\
+    $(intermediates.COMMON)/proguard_usage.zip)
+endif
+
+
 ifdef LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE
   my_res_package := $(intermediates.COMMON)/package-res.apk
 
diff --git a/core/soong_rust_prebuilt.mk b/core/soong_rust_prebuilt.mk
index 804e37e..2f4c6e7 100644
--- a/core/soong_rust_prebuilt.mk
+++ b/core/soong_rust_prebuilt.mk
@@ -28,9 +28,9 @@
   $(call pretty-error,Unsupported LOCAL_MODULE_$(my_prefix)ARCH=$(LOCAL_MODULE_$(my_prefix)ARCH))
 endif
 
-# Don't install rlib/proc_macro libraries.
+# Don't install static/rlib/proc_macro libraries.
 ifndef LOCAL_UNINSTALLABLE_MODULE
-  ifneq ($(filter RLIB_LIBRARIES PROC_MACRO_LIBRARIES,$(LOCAL_MODULE_CLASS)),)
+  ifneq ($(filter STATIC_LIBRARIES RLIB_LIBRARIES PROC_MACRO_LIBRARIES,$(LOCAL_MODULE_CLASS)),)
     LOCAL_UNINSTALLABLE_MODULE := true
   endif
 endif
@@ -57,9 +57,16 @@
 endif
 
 $(LOCAL_BUILT_MODULE): $(LOCAL_PREBUILT_MODULE_FILE)
+ifeq ($(LOCAL_IS_HOST_MODULE) $(if $(filter EXECUTABLES SHARED_LIBRARIES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),true,),true true)
+	$(copy-or-link-prebuilt-to-target)
+  ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
+	[ -x $@ ] || $(call echo-error,$@,Target of symlink is not executable)
+  endif
+else
 	$(transform-prebuilt-to-target)
-ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
+  ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
 	$(hide) chmod +x $@
+  endif
 endif
 
 ifndef LOCAL_IS_HOST_MODULE
diff --git a/core/sysprop.mk b/core/sysprop.mk
index d01255f..73dbec7 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -300,7 +300,8 @@
 
 ifndef property_overrides_split_enabled
 _prop_vars_ += \
-    ADDITIONAL_VENDOR_PROPERTIES
+    ADDITIONAL_VENDOR_PROPERTIES \
+    PRODUCT_VENDOR_PROPERTIES
 endif
 
 _blacklist_names_ := \
diff --git a/core/tasks/art-host-tests.mk b/core/tasks/art-host-tests.mk
new file mode 100644
index 0000000..96e2c74
--- /dev/null
+++ b/core/tasks/art-host-tests.mk
@@ -0,0 +1,29 @@
+# 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.
+
+.PHONY: art-host-tests
+
+intermediates_dir := $(call intermediates-dir-for,PACKAGING,art-host-tests)
+art_host_tests_zip := $(PRODUCT_OUT)/art-host-tests.zip
+$(art_host_tests_zip) : $(COMPATIBILITY.art-host-tests.FILES) $(SOONG_ZIP)
+	echo $(sort $(COMPATIBILITY.art-host-tests.FILES)) | tr " " "\n" > $@.list
+	grep $(HOST_OUT_TESTCASES) $@.list > $@-host.list || true
+	grep $(TARGET_OUT_TESTCASES) $@.list > $@-target.list || true
+	$(hide) $(SOONG_ZIP) -d -o $@ -P host -C $(HOST_OUT) -l $@-host.list -P target -C $(PRODUCT_OUT) -l $@-target.list
+	rm -f $@.list $@-host.list $@-target.list
+
+art-host-tests: $(art_host_tests_zip)
+$(call dist-for-goals, art-host-tests, $(art_host_tests_zip))
+
+tests: art-host-tests
diff --git a/core/tasks/boot_jars_package_check.mk b/core/tasks/boot_jars_package_check.mk
index a17aaff..c9a8e27 100644
--- a/core/tasks/boot_jars_package_check.mk
+++ b/core/tasks/boot_jars_package_check.mk
@@ -17,7 +17,6 @@
 #
 
 ifneq ($(SKIP_BOOT_JARS_CHECK),true)
-ifneq ($(TARGET_BUILD_PDK),true)
 ifdef PRODUCT_BOOT_JARS
 
 intermediates := $(call intermediates-dir-for, PACKAGING, boot-jars-package-check,,COMMON)
@@ -61,5 +60,4 @@
 droidcore : check-boot-jars
 
 endif  # PRODUCT_BOOT_JARS
-endif  # TARGET_BUILD_PDK not true
 endif  # SKIP_BOOT_JARS_CHECK not true
diff --git a/core/tasks/check_boot_jars/package_allowed_list.txt b/core/tasks/check_boot_jars/package_allowed_list.txt
index 6240ffd..18ab427 100644
--- a/core/tasks/check_boot_jars/package_allowed_list.txt
+++ b/core/tasks/check_boot_jars/package_allowed_list.txt
@@ -122,8 +122,6 @@
 libcore\..*
 android\..*
 com\.android\..*
-
-
 ###################################################
 # android.test.base.jar
 junit\.extensions
@@ -241,6 +239,8 @@
 # Packages in the google namespace across all bootclasspath jars.
 com\.google\.android\..*
 com\.google\.vr\.platform.*
+com\.google\.i18n\.phonenumbers\..*
+com\.google\.i18n\.phonenumbers
 
 ###################################################
 # Packages used for Android in Chrome OS
diff --git a/core/tasks/csuite.mk b/core/tasks/csuite.mk
new file mode 100644
index 0000000..a8dba1d
--- /dev/null
+++ b/core/tasks/csuite.mk
@@ -0,0 +1,23 @@
+# Copyright (C) 2019 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.
+
+test_suite_name := csuite
+test_suite_tradefed := csuite-tradefed
+test_suite_readme := test/app_compat/csuite/README.md
+
+include $(BUILD_SYSTEM)/tasks/tools/compatibility.mk
+
+.PHONY: csuite
+csuite: $(compatibility_zip)
+$(call dist-for-goals, csuite, $(compatibility_zip))
diff --git a/core/tasks/module-info.mk b/core/tasks/module-info.mk
index f6cec15..cf32d65 100644
--- a/core/tasks/module-info.mk
+++ b/core/tasks/module-info.mk
@@ -14,11 +14,12 @@
 			'"compatibility_suites": [$(foreach w,$(sort $(ALL_MODULES.$(m).COMPATIBILITY_SUITES)),"$(w)", )], ' \
 			'"auto_test_config": [$(ALL_MODULES.$(m).auto_test_config)], ' \
 			'"module_name": "$(ALL_MODULES.$(m).MODULE_NAME)", ' \
-			'"test_config": [$(if $(ALL_MODULES.$(m).TEST_CONFIG),"$(ALL_MODULES.$(m).TEST_CONFIG)")], ' \
+			'"test_config": [$(foreach w,$(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS)),"$(w)", )], ' \
 			'"dependencies": [$(foreach w,$(sort $(ALL_DEPS.$(m).ALL_DEPS)),"$(w)", )], ' \
 			'"srcs": [$(foreach w,$(sort $(ALL_MODULES.$(m).SRCS)),"$(w)", )], ' \
 			'"srcjars": [$(foreach w,$(sort $(ALL_MODULES.$(m).SRCJARS)),"$(w)", )], ' \
 			'"classes_jar": [$(foreach w,$(sort $(ALL_MODULES.$(m).CLASSES_JAR)),"$(w)", )], ' \
+			'"test_mainline_modules": [$(foreach w,$(sort $(ALL_MODULES.$(m).TEST_MAINLINE_MODULES)),"$(w)", )], ' \
 			'},\n' \
 	 ) | sed -e 's/, *\]/]/g' -e 's/, *\}/ }/g' -e '$$s/,$$//' >> $@
 	$(hide) echo '}' >> $@
diff --git a/core/tasks/platform_availability_check.mk b/core/tasks/platform_availability_check.mk
index 043d130..7ce6b40 100644
--- a/core/tasks/platform_availability_check.mk
+++ b/core/tasks/platform_availability_check.mk
@@ -26,11 +26,31 @@
       $(if $(filter true,$(ALL_MODULES.$(m).NOT_AVAILABLE_FOR_PLATFORM)),\
         $(m))))))
 
-_violators_with_path := $(foreach m,$(sort $(_modules_not_available_for_platform)),\
+ifndef ALLOW_MISSING_DEPENDENCIES
+  _violators_with_path := $(foreach m,$(sort $(_modules_not_available_for_platform)),\
     $(m):$(word 1,$(ALL_MODULES.$(m).PATH))\
-)
+  )
 
-$(call maybe-print-list-and-error,$(_violators_with_path),\
+  $(call maybe-print-list-and-error,$(_violators_with_path),\
 Following modules are requested to be installed. But are not available \
 for platform because they do not have "//apex_available:platform" or \
 they depend on other modules that are not available for platform)
+
+else
+
+# Don't error out immediately when ALLOW_MISSING_DEPENDENCIES is set.
+# Instead, add a dependency on a rule that prints the error message.
+  define not_available_for_platform_rule
+    not_installable_file := $(patsubst $(OUT_DIR)/%,$(OUT_DIR)/NOT_AVAILABLE_FOR_PLATFORM/%,$(1)))
+    $(1): $$(not_installable_file)
+    $$(not_installable_file):
+	$(call echo-error,$(2),Module is requested to be installed but is not \
+available for platform because it does not have "//apex_available:platform" or \
+it depends on other modules that are not available for platform.)
+	exit 1
+  endef
+
+  $(foreach m,$(_modules_not_available_for_platform),\
+    $(foreach i,$(filter-out $(HOST_OUT)/%,$(ALL_MODULES.$(m).INSTALLED)),\
+      $(eval $(call not_available_for_platform_rule,$(i),$(m)))))
+endif
diff --git a/core/tasks/tools/compatibility.mk b/core/tasks/tools/compatibility.mk
index 93185af..f394b96 100644
--- a/core/tasks/tools/compatibility.mk
+++ b/core/tasks/tools/compatibility.mk
@@ -26,7 +26,8 @@
 # Output variables:
 #   compatibility_zip: the path to the output zip file.
 
-out_dir := $(HOST_OUT)/$(test_suite_name)/android-$(test_suite_name)
+test_suite_subdir := android-$(test_suite_name)
+out_dir := $(HOST_OUT)/$(test_suite_name)/$(test_suite_subdir)
 test_artifacts := $(COMPATIBILITY.$(test_suite_name).FILES)
 test_tools := $(HOST_OUT_JAVA_LIBRARIES)/hosttestlib.jar \
   $(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar \
@@ -44,10 +45,28 @@
 
 test_tools += $(test_suite_tools)
 
+# The JDK to package into the test suite zip file.  Always package the linux JDK.
+test_suite_jdk_dir := $(ANDROID_JAVA_HOME)/../linux-x86
+test_suite_jdk := $(call intermediates-dir-for,PACKAGING,$(test_suite_name)_jdk,HOST)/jdk.zip
+$(test_suite_jdk): PRIVATE_JDK_DIR := $(test_suite_jdk_dir)
+$(test_suite_jdk): PRIVATE_SUBDIR := $(test_suite_subdir)
+$(test_suite_jdk): $(shell find $(test_suite_jdk_dir) -type f | sort)
+$(test_suite_jdk): $(SOONG_ZIP)
+	$(SOONG_ZIP) -o $@ -P $(PRIVATE_SUBDIR)/jdk -C $(PRIVATE_JDK_DIR) -D $(PRIVATE_JDK_DIR)
+
 # Include host shared libraries
 host_shared_libs := $(call copy-many-files, $(COMPATIBILITY.$(test_suite_name).HOST_SHARED_LIBRARY.FILES))
 
-compatibility_zip_deps := $(test_artifacts) $(test_tools) $(test_suite_prebuilt_tools) $(test_suite_dynamic_config) $(SOONG_ZIP) $(host_shared_libs)
+compatibility_zip_deps := \
+  $(test_artifacts) \
+  $(test_tools) \
+  $(test_suite_prebuilt_tools) \
+  $(test_suite_dynamic_config) \
+  $(test_suite_jdk) \
+  $(MERGE_ZIPS) \
+  $(SOONG_ZIP) \
+  $(host_shared_libs) \
+
 compatibility_zip_resources := $(out_dir)/tools $(out_dir)/testcases
 
 # Test Suite NOTICE files
@@ -67,21 +86,24 @@
 endif
 
 compatibility_zip := $(out_dir).zip
-$(compatibility_zip): PRIVATE_NAME := android-$(test_suite_name)
 $(compatibility_zip): PRIVATE_OUT_DIR := $(out_dir)
 $(compatibility_zip): PRIVATE_TOOLS := $(test_tools) $(test_suite_prebuilt_tools)
 $(compatibility_zip): PRIVATE_SUITE_NAME := $(test_suite_name)
 $(compatibility_zip): PRIVATE_DYNAMIC_CONFIG := $(test_suite_dynamic_config)
 $(compatibility_zip): PRIVATE_RESOURCES := $(compatibility_zip_resources)
+$(compatibility_zip): PRIVATE_JDK := $(test_suite_jdk)
 $(compatibility_zip): $(compatibility_zip_deps) | $(ADB) $(ACP)
 # Make dir structure
-	$(hide) mkdir -p $(PRIVATE_OUT_DIR)/tools $(PRIVATE_OUT_DIR)/testcases
-	$(hide) echo $(BUILD_NUMBER_FROM_FILE) > $(PRIVATE_OUT_DIR)/tools/version.txt
+	mkdir -p $(PRIVATE_OUT_DIR)/tools $(PRIVATE_OUT_DIR)/testcases
+	rm -f $@ $@.tmp $@.jdk
+	echo $(BUILD_NUMBER_FROM_FILE) > $(PRIVATE_OUT_DIR)/tools/version.txt
 # Copy tools
-	$(hide) cp $(PRIVATE_TOOLS) $(PRIVATE_OUT_DIR)/tools
+	cp $(PRIVATE_TOOLS) $(PRIVATE_OUT_DIR)/tools
 	$(if $(PRIVATE_DYNAMIC_CONFIG),$(hide) cp $(PRIVATE_DYNAMIC_CONFIG) $(PRIVATE_OUT_DIR)/testcases/$(PRIVATE_SUITE_NAME).dynamic)
-	$(hide) find $(PRIVATE_RESOURCES) | sort >$@.list
-	$(hide) $(SOONG_ZIP) -d -o $@ -C $(dir $@) -l $@.list
+	find $(PRIVATE_RESOURCES) | sort >$@.list
+	$(SOONG_ZIP) -d -o $@.tmp -C $(dir $@) -l $@.list
+	$(MERGE_ZIPS) $@ $@.tmp $(PRIVATE_JDK)
+	rm -f $@.tmp
 
 # Reset all input variables
 test_suite_name :=
@@ -91,4 +113,6 @@
 test_suite_prebuilt_tools :=
 test_suite_tools :=
 include_test_suite_notice :=
+test_suite_jdk :=
+test_suite_jdk_dir :=
 host_shared_libs :=
diff --git a/core/tasks/tools/package-modules.mk b/core/tasks/tools/package-modules.mk
index 6cafa4a..2b43f0f 100644
--- a/core/tasks/tools/package-modules.mk
+++ b/core/tasks/tools/package-modules.mk
@@ -50,7 +50,7 @@
 ifeq ($(ALLOW_MISSING_DEPENDENCIES),true)
   # Ignore unknown installed files on partial builds
   my_missing_files =
-else ifeq ($(my_modules_strict),true)
+else ifneq ($(my_modules_strict),false)
   my_missing_files = $(shell $(call echo-error,$(my_makefile),$(my_package_name): Unknown installed file for module '$(1)'))$(eval my_missing_error := true)
 endif
 
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index c877e8b..b507ca9 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -84,40 +84,17 @@
 # generate the range of allowed SDK versions, so it must have an entry for every
 # unreleased API level targetable by this branch, not just those that are valid
 # lunch targets for this branch.
-PLATFORM_VERSION.RP1A := R
-PLATFORM_VERSION.SP1A := S
+
+# The last stable version name of the platform that was released.  During
+# development, this stays at that previous version, while the codename indicates
+# further work based on the previous version.
+PLATFORM_VERSION_LAST_STABLE := 11
+.KATI_READONLY := PLATFORM_VERSION_LAST_STABLE
 
 # These are the current development codenames, if the build is not a final
 # release build.  If this is a final release build, it is simply "REL".
-PLATFORM_VERSION_CODENAME.RP1A := R
 PLATFORM_VERSION_CODENAME.SP1A := S
 
-ifndef PLATFORM_VERSION
-  PLATFORM_VERSION := $(PLATFORM_VERSION.$(TARGET_PLATFORM_VERSION))
-  ifndef PLATFORM_VERSION
-    # PLATFORM_VERSION falls back to TARGET_PLATFORM_VERSION
-    PLATFORM_VERSION := $(TARGET_PLATFORM_VERSION)
-  endif
-endif
-.KATI_READONLY := PLATFORM_VERSION
-
-ifndef PLATFORM_SDK_VERSION
-  # This is the canonical definition of the SDK version, which defines
-  # the set of APIs and functionality available in the platform.  It
-  # is a single integer that increases monotonically as updates to
-  # the SDK are released.  It should only be incremented when the APIs for
-  # the new release are frozen (so that developers don't write apps against
-  # intermediate builds).  During development, this number remains at the
-  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
-  # the code-name of the new development work.
-
-  # When you increment the PLATFORM_SDK_VERSION please ensure you also
-  # clear out the following text file of all older PLATFORM_VERSION's:
-  # cts/tests/tests/os/assets/platform_versions.txt
-  PLATFORM_SDK_VERSION := 29
-endif
-.KATI_READONLY := PLATFORM_SDK_VERSION
-
 ifndef PLATFORM_VERSION_CODENAME
   PLATFORM_VERSION_CODENAME := $(PLATFORM_VERSION_CODENAME.$(TARGET_PLATFORM_VERSION))
   ifndef PLATFORM_VERSION_CODENAME
@@ -152,6 +129,32 @@
   PLATFORM_VERSION_CODENAME \
   PLATFORM_VERSION_ALL_CODENAMES
 
+ifndef PLATFORM_VERSION
+  ifeq (REL,$(PLATFORM_VERSION_CODENAME))
+      PLATFORM_VERSION := $(PLATFORM_VERSION_LAST_STABLE)
+  else
+      PLATFORM_VERSION := $(PLATFORM_VERSION_CODENAME)
+  endif
+endif
+.KATI_READONLY := PLATFORM_VERSION
+
+ifndef PLATFORM_SDK_VERSION
+  # This is the canonical definition of the SDK version, which defines
+  # the set of APIs and functionality available in the platform.  It
+  # is a single integer that increases monotonically as updates to
+  # the SDK are released.  It should only be incremented when the APIs for
+  # the new release are frozen (so that developers don't write apps against
+  # intermediate builds).  During development, this number remains at the
+  # SDK version the branch is based on and PLATFORM_VERSION_CODENAME holds
+  # the code-name of the new development work.
+
+  # When you increment the PLATFORM_SDK_VERSION please ensure you also
+  # clear out the following text file of all older PLATFORM_VERSION's:
+  # cts/tests/tests/os/assets/platform_versions.txt
+  PLATFORM_SDK_VERSION := 30
+endif
+.KATI_READONLY := PLATFORM_SDK_VERSION
+
 ifeq (REL,$(PLATFORM_VERSION_CODENAME))
   PLATFORM_PREVIEW_SDK_VERSION := 0
 else
@@ -237,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-08-05
+      PLATFORM_SECURITY_PATCH := 2020-09-05
 endif
 .KATI_READONLY := PLATFORM_SECURITY_PATCH
 
diff --git a/envsetup.sh b/envsetup.sh
index e981034..a3b07a7 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -34,6 +34,7 @@
 - gomod:      Go to the directory containing a module.
 - pathmod:    Get the directory containing a module.
 - refreshmod: Refresh list of modules for allmod/gomod/pathmod.
+- syswrite:   Remount partitions (e.g. system.img) as writable, rebooting if necessary.
 
 Environment options:
 - SANITIZE_HOST: Set to 'address' to use ASAN for all host modules.
@@ -355,7 +356,7 @@
 
 function addcompletions()
 {
-    local T dir f
+    local f=
 
     # Keep us from trying to run in something that's neither bash nor zsh.
     if [ -z "$BASH_VERSION" -a -z "$ZSH_VERSION" ]; then
@@ -857,6 +858,18 @@
     fi
 }
 
+# syswrite - disable verity, reboot if needed, and remount image
+#
+# Easy way to make system.img/etc writable
+function syswrite() {
+  adb wait-for-device && adb root || return 1
+  if [[ $(adb disable-verity | grep "reboot") ]]; then
+      echo "rebooting"
+      adb reboot && adb wait-for-device && adb root || return 1
+  fi
+  adb wait-for-device && adb remount || return 1
+}
+
 # coredump_setup - enable core dumps globally for any process
 #                  that has the core-file-size limit set correctly
 #
@@ -1613,6 +1626,41 @@
     done
 }
 
+function showcommands() {
+    local T=$(gettop)
+    if [[ -z "$TARGET_PRODUCT" ]]; then
+        >&2 echo "TARGET_PRODUCT not set. Run lunch."
+        return
+    fi
+    case $(uname -s) in
+        Darwin)
+            PREBUILT_NAME=darwin-x86
+            ;;
+        Linux)
+            PREBUILT_NAME=linux-x86
+            ;;
+        *)
+            >&2 echo Unknown host $(uname -s)
+            return
+            ;;
+    esac
+    if [[ -z "$OUT_DIR" ]]; then
+      if [[ -z "$OUT_DIR_COMMON_BASE" ]]; then
+        OUT_DIR=out
+      else
+        OUT_DIR=${OUT_DIR_COMMON_BASE}/${PWD##*/}
+      fi
+    fi
+    if [[ "$1" == "--regenerate" ]]; then
+      shift 1
+      NINJA_ARGS="-t commands $@" m
+    else
+      (cd $T && prebuilts/build-tools/$PREBUILT_NAME/bin/ninja \
+          -f $OUT_DIR/combined-${TARGET_PRODUCT}.ninja \
+          -t commands "$@")
+    fi
+}
+
 validate_current_shell
 source_vendorsetup
 addcompletions
diff --git a/rbesetup.sh b/rbesetup.sh
index f9317a3..0182bfd 100644
--- a/rbesetup.sh
+++ b/rbesetup.sh
@@ -1,4 +1,31 @@
-source build/envsetup.sh
+function _source_env_setup_script() {
+  local -r ENV_SETUP_SCRIPT="build/make/envsetup.sh"
+  local -r TOP_DIR=$(
+    while [[ ! -f "${ENV_SETUP_SCRIPT}" ]] && [[ "${PWD}" != "/" ]]; do
+      \cd ..
+    done
+    if [[ -f "${ENV_SETUP_SCRIPT}" ]]; then
+      echo "$(PWD= /bin/pwd -P)"
+    fi
+  )
+
+  local -r FULL_PATH_ENV_SETUP_SCRIPT="${TOP_DIR}/${ENV_SETUP_SCRIPT}"
+  if [[ ! -f "${FULL_PATH_ENV_SETUP_SCRIPT}" ]]; then
+    echo "ERROR: Unable to source ${ENV_SETUP_SCRIPT}"
+    return 1
+  fi
+
+  # Need to change directory to the repo root so vendor scripts can be sourced
+  # as well.
+  local -r CUR_DIR=$PWD
+  \cd "${TOP_DIR}"
+  source "${FULL_PATH_ENV_SETUP_SCRIPT}"
+  \cd "${CUR_DIR}"
+}
+
+# This function needs to run first as the remaining defining functions may be
+# using the envsetup.sh defined functions.
+_source_env_setup_script || return
 
 # This function prefixes the given command with appropriate variables needed
 # for the build to be executed with RBE.
@@ -28,9 +55,21 @@
 # ANDROID_ENABLE_METRICS_UPLOAD.
 function _export_metrics_uploader() {
   local uploader_path="$(gettop)/vendor/google/misc/metrics_uploader_prebuilt/metrics_uploader.sh"
-  if [ -x "${uploader_path}" ]; then
+  if [[ -x "${uploader_path}" ]]; then
     export ANDROID_ENABLE_METRICS_UPLOAD="${uploader_path}"
   fi
 }
 
+# This function sets RBE specific environment variables needed for the build to
+# executed by RBE. This file should be sourced once per checkout of Android code.
+function _set_rbe_vars() {
+  unset USE_GOMA
+  export USE_RBE="true"
+  export RBE_CXX_EXEC_STRATEGY="remote_local_fallback"
+  export RBE_JAVAC=1
+  export RBE_R8=1
+  export RBE_D8=1
+}
+
 _export_metrics_uploader
+_set_rbe_vars
diff --git a/target/board/BoardConfigGsiCommon.mk b/target/board/BoardConfigGsiCommon.mk
index 9d55f42..e34dc23 100644
--- a/target/board/BoardConfigGsiCommon.mk
+++ b/target/board/BoardConfigGsiCommon.mk
@@ -11,7 +11,9 @@
 # This flag is set by mainline but isn't desired for GSI.
 BOARD_USES_SYSTEM_OTHER_ODEX :=
 
-# system.img is always ext4 with sparse option
+# system.img is always ext4 and non-sparsed.
+TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
+
 # GSI also includes make_f2fs to support userdata parition in f2fs
 # for some devices
 TARGET_USERIMAGES_USE_F2FS := true
diff --git a/target/board/generic_64bitonly_x86_64/BoardConfig.mk b/target/board/generic_64bitonly_x86_64/BoardConfig.mk
new file mode 100644
index 0000000..71c4357
--- /dev/null
+++ b/target/board/generic_64bitonly_x86_64/BoardConfig.mk
@@ -0,0 +1,45 @@
+# 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
+
+# Keep the following for 32-bit native code support
+# There are a few native services still on 32-bit modes, e.g. media & audio.
+# Remove them in S.
+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/generic_64bitonly_x86_64/README.txt b/target/board/generic_64bitonly_x86_64/README.txt
new file mode 100644
index 0000000..dc7efd3
--- /dev/null
+++ b/target/board/generic_64bitonly_x86_64/README.txt
@@ -0,0 +1,7 @@
+The "generic_x86_64_app" product defines a non-hardware-specific IA target
+without a kernel or bootloader.
+
+It can be used to build the entire user-level system, and
+will work with the IA version of the emulator,
+
+This supports 64-bit apps only.
diff --git a/target/board/generic_64bitonly_x86_64/device.mk b/target/board/generic_64bitonly_x86_64/device.mk
new file mode 100644
index 0000000..bb49057
--- /dev/null
+++ b/target/board/generic_64bitonly_x86_64/device.mk
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+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/generic_64bitonly_x86_64/system.prop b/target/board/generic_64bitonly_x86_64/system.prop
new file mode 100644
index 0000000..ed9d173
--- /dev/null
+++ b/target/board/generic_64bitonly_x86_64/system.prop
@@ -0,0 +1,5 @@
+#
+# system.prop for generic sdk
+#
+
+rild.libpath=/vendor/lib64/libreference-ril.so
diff --git a/target/board/generic_arm64/BoardConfig.mk b/target/board/generic_arm64/BoardConfig.mk
index 22108fa..c45a8ab 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -58,20 +58,29 @@
 TARGET_NO_VENDOR_BOOT := true
 BOARD_USES_RECOVERY_AS_BOOT := true
 
+BOARD_KERNEL-4.19-GZ_BOOTIMAGE_PARTITION_SIZE := 47185920
 BOARD_KERNEL-5.4_BOOTIMAGE_PARTITION_SIZE := 67108864
+BOARD_KERNEL-5.4-ALLSYMS_BOOTIMAGE_PARTITION_SIZE := 67108864
 BOARD_KERNEL-5.4-GZ_BOOTIMAGE_PARTITION_SIZE := 47185920
+BOARD_KERNEL-5.4-GZ-ALLSYMS_BOOTIMAGE_PARTITION_SIZE := 47185920
 BOARD_KERNEL-5.4-LZ4_BOOTIMAGE_PARTITION_SIZE := 53477376
+BOARD_KERNEL-5.4-LZ4-ALLSYMS_BOOTIMAGE_PARTITION_SIZE := 53477376
 BOARD_KERNEL-MAINLINE_BOOTIMAGE_PARTITION_SIZE := 67108864
 BOARD_KERNEL-MAINLINE-GZ_BOOTIMAGE_PARTITION_SIZE := 47185920
 BOARD_KERNEL-MAINLINE-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 \
     kernel-mainline kernel-mainline-gz kernel-mainline-lz4
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+BOARD_KERNEL_BINARIES += kernel-5.4-allsyms kernel-5.4-gz-allsyms kernel-5.4-lz4-allsyms
+endif
+BOARD_KERNEL_MODULE_INTERFACE_VERSIONS := 5.4-android12-0
 
 # 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 d8d06cd..1585fbd 100644
--- a/target/board/generic_arm64/device.mk
+++ b/target/board/generic_arm64/device.mk
@@ -15,9 +15,17 @@
 #
 
 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 \
     kernel/prebuilts/mainline/arm64/kernel-mainline:kernel-mainline \
     kernel/prebuilts/mainline/arm64/kernel-mainline-gz:kernel-mainline-gz \
     kernel/prebuilts/mainline/arm64/kernel-mainline-lz4:kernel-mainline-lz4
+
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+PRODUCT_COPY_FILES += \
+    device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4:kernel-5.4-allsyms \
+    device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4-gz:kernel-5.4-gz-allsyms \
+    device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4-lz4:kernel-5.4-lz4-allsyms
+endif
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index 3949737..61a7583 100644
--- a/target/product/AndroidProducts.mk
+++ b/target/product/AndroidProducts.mk
@@ -43,6 +43,7 @@
 
 else
 PRODUCT_MAKEFILES := \
+    $(LOCAL_DIR)/aosp_64bitonly_x86_64.mk \
     $(LOCAL_DIR)/aosp_arm64_ab.mk \
     $(LOCAL_DIR)/aosp_arm64.mk \
     $(LOCAL_DIR)/aosp_arm_ab.mk \
@@ -55,12 +56,16 @@
     $(LOCAL_DIR)/full.mk \
     $(LOCAL_DIR)/full_x86.mk \
     $(LOCAL_DIR)/generic.mk \
+    $(LOCAL_DIR)/generic_system_arm64.mk \
+    $(LOCAL_DIR)/generic_system_x86.mk \
+    $(LOCAL_DIR)/generic_system_x86_64.mk \
+    $(LOCAL_DIR)/generic_system_x86_arm.mk \
     $(LOCAL_DIR)/generic_x86.mk \
     $(LOCAL_DIR)/gsi_arm64.mk \
     $(LOCAL_DIR)/mainline_system_arm64.mk \
     $(LOCAL_DIR)/mainline_system_x86.mk \
-    $(LOCAL_DIR)/mainline_system_x86_arm.mk \
     $(LOCAL_DIR)/mainline_system_x86_64.mk \
+    $(LOCAL_DIR)/mainline_system_x86_arm.mk \
     $(LOCAL_DIR)/sdk_arm64.mk \
     $(LOCAL_DIR)/sdk.mk \
     $(LOCAL_DIR)/sdk_phone_arm64.mk \
diff --git a/target/product/aosp_64bitonly_x86_64.mk b/target/product/aosp_64bitonly_x86_64.mk
new file mode 100644
index 0000000..4de4e0c
--- /dev/null
+++ b/target/product/aosp_64bitonly_x86_64.mk
@@ -0,0 +1,72 @@
+#
+# Copyright 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_USE_DYNAMIC_PARTITIONS := true
+
+# The system image of aosp_x86_64_app-userdebug is a GSI for the devices with:
+# - x86 64 bits user space
+# - 64 bits binder interface
+# - system-as-root
+# - VNDK enforcement
+# - compatible property override enabled
+
+# 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.
+
+# GSI for system/product & support 64-bit apps only
+$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit_only.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+
+# Enable mainline checking for excat this product name
+ifeq (aosp_64bitonly_x86_64,$(TARGET_PRODUCT))
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
+endif
+
+#
+# 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/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)
+
+#
+# Special settings for GSI releasing
+#
+ifeq (aosp_64bitonly_x86_64,$(TARGET_PRODUCT))
+$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_release.mk)
+endif
+
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
+    root/init.zygote64.rc
+
+# This build configuration supports 64-bit apps only
+PRODUCT_NAME := aosp_64bitonly_x86_64
+PRODUCT_DEVICE := generic_64bitonly_x86_64
+PRODUCT_BRAND := Android
+PRODUCT_MODEL := AOSP on x86_64 App
diff --git a/target/product/aosp_arm.mk b/target/product/aosp_arm.mk
index 0cec14b..90acc17 100644
--- a/target/product/aosp_arm.mk
+++ b/target/product/aosp_arm.mk
@@ -26,7 +26,7 @@
 #
 # All components inherited here go to system image
 #
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for excat this product name
 ifeq (aosp_arm,$(TARGET_PRODUCT))
diff --git a/target/product/aosp_arm64.mk b/target/product/aosp_arm64.mk
index 3254ccf..38f82a2 100644
--- a/target/product/aosp_arm64.mk
+++ b/target/product/aosp_arm64.mk
@@ -30,7 +30,7 @@
 # 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)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for excat this product name
 ifeq (aosp_arm64,$(TARGET_PRODUCT))
diff --git a/target/product/aosp_arm64_ab.mk b/target/product/aosp_arm64_ab.mk
index 0b2ae09..5510e1b 100644
--- a/target/product/aosp_arm64_ab.mk
+++ b/target/product/aosp_arm64_ab.mk
@@ -29,7 +29,7 @@
 # (The system image of Legacy GSI is not CSI)
 #
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for excat this product name
 ifeq (aosp_arm64_ab,$(TARGET_PRODUCT))
diff --git a/target/product/aosp_arm_ab.mk b/target/product/aosp_arm_ab.mk
index ec2e5d7..7e06044 100644
--- a/target/product/aosp_arm_ab.mk
+++ b/target/product/aosp_arm_ab.mk
@@ -28,7 +28,7 @@
 # All components inherited here go to system image
 # (The system image of Legacy GSI is not CSI)
 #
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for excat this product name
 ifeq (aosp_arm_ab,$(TARGET_PRODUCT))
diff --git a/target/product/aosp_product.mk b/target/product/aosp_product.mk
index a3da1c9..e396ad1 100644
--- a/target/product/aosp_product.mk
+++ b/target/product/aosp_product.mk
@@ -31,6 +31,7 @@
 PRODUCT_PACKAGES += \
     messaging \
     PhotoTable \
+    preinstalled-packages-platform-aosp-product.xml \
     WallpaperPicker \
 
 # Telephony:
diff --git a/target/product/aosp_x86.mk b/target/product/aosp_x86.mk
index 51b5daf..7db2c0f 100644
--- a/target/product/aosp_x86.mk
+++ b/target/product/aosp_x86.mk
@@ -26,7 +26,7 @@
 #
 # All components inherited here go to system image
 #
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for excat this product name
 ifeq (aosp_x86,$(TARGET_PRODUCT))
diff --git a/target/product/aosp_x86_64.mk b/target/product/aosp_x86_64.mk
index 9b26716..5d78264 100644
--- a/target/product/aosp_x86_64.mk
+++ b/target/product/aosp_x86_64.mk
@@ -32,7 +32,7 @@
 # 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)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for excat this product name
 ifeq (aosp_x86_64,$(TARGET_PRODUCT))
diff --git a/target/product/aosp_x86_64_ab.mk b/target/product/aosp_x86_64_ab.mk
index 578a254..c31545d 100644
--- a/target/product/aosp_x86_64_ab.mk
+++ b/target/product/aosp_x86_64_ab.mk
@@ -29,7 +29,7 @@
 # (The system image of Legacy GSI is not CSI)
 #
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for excat this product name
 ifeq (aosp_x86_64_ab,$(TARGET_PRODUCT))
diff --git a/target/product/aosp_x86_ab.mk b/target/product/aosp_x86_ab.mk
index 40c1d83..2f02dd1 100644
--- a/target/product/aosp_x86_ab.mk
+++ b/target/product/aosp_x86_ab.mk
@@ -29,7 +29,7 @@
 # (The system image of Legacy GSI is not CSI)
 #
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for excat this product name
 ifeq (aosp_x86_ab,$(TARGET_PRODUCT))
diff --git a/target/product/aosp_x86_arm.mk b/target/product/aosp_x86_arm.mk
index deba3d9..f96e068 100644
--- a/target/product/aosp_x86_arm.mk
+++ b/target/product/aosp_x86_arm.mk
@@ -19,7 +19,7 @@
 #
 # All components inherited here go to system image
 #
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking
 ifeq (aosp_x86_arm,$(TARGET_PRODUCT))
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index f6770fb..586c058 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -38,6 +38,7 @@
     bcc \
     blank_screen \
     blkid \
+    service-blobstore \
     bmgr \
     bootanimation \
     bootstat \
@@ -50,21 +51,27 @@
     charger \
     cmd \
     com.android.adbd \
-    com.android.apex.cts.shim.v1 \
     com.android.conscrypt \
     com.android.cronet \
+    com.android.extservices \
     com.android.i18n \
     com.android.ipsec \
     com.android.location.provider \
     com.android.media \
     com.android.media.swcodec \
+    com.android.mediaprovider \
+    com.android.os.statsd \
+    com.android.permission \
     com.android.resolv \
     com.android.neuralnetworks \
     com.android.sdkext \
     com.android.tethering \
     com.android.tzdata \
+    com.android.wifi \
     ContactsProvider \
     content \
+    CtsShimPrebuilt \
+    CtsShimPrivPrebuilt \
     debuggerd\
     device_config \
     dmctl \
@@ -75,7 +82,6 @@
     dumpsys \
     DynamicSystemInstallationService \
     e2fsck \
-    ExtServices \
     ExtShared \
     flags_health_check \
     framework-minus-apex \
@@ -94,7 +100,6 @@
     gpuservice \
     hid \
     hwservicemanager \
-    idmap \
     idmap2 \
     idmap2d \
     ime \
@@ -102,6 +107,7 @@
     incident \
     incidentd \
     incident_helper \
+    incident-helper-cmd \
     init.environ.rc \
     init_system \
     input \
@@ -111,7 +117,9 @@
     iptables \
     ip-up-vpn \
     javax.obex \
+    service-jobscheduler \
     keystore \
+    credstore \
     ld.mc \
     libaaudio \
     libamidi \
@@ -161,7 +169,6 @@
     libOpenMAXAL \
     libOpenSLES \
     libpdfium \
-    libpixelflinger \
     libpower \
     libpowermanager \
     libradio_metadata \
@@ -184,10 +191,10 @@
     libusbhost \
     libutils \
     libvulkan \
-    libwifi-service \
     libwilhelm \
     linker \
     linkerconfig \
+    llkd \
     lmkd \
     LocalTransport \
     locksettings \
@@ -196,13 +203,11 @@
     lpdump \
     lshal \
     mdnsd \
-    media \
     mediacodec.policy \
-    mediadrmserver \
     mediaextractor \
     mediametrics \
     media_profiles_V1_0.dtd \
-    MediaProvider \
+    MediaProviderLegacy \
     mediaserver \
     mke2fs \
     monkey \
@@ -215,12 +220,12 @@
     PackageInstaller \
     passwd_system \
     perfetto \
-    PermissionController \
     ping \
     ping6 \
     platform.xml \
     pm \
     pppd \
+    preinstalled-packages-platform.xml \
     privapp-permissions-platform.xml \
     racoon \
     recovery-persist \
@@ -245,7 +250,7 @@
     shell_and_utilities_system \
     sm \
     snapshotctl \
-    statsd \
+    SoundPicker \
     storaged \
     surfaceflinger \
     svc \
@@ -268,7 +273,7 @@
     WallpaperBackup \
     watchdogd \
     wificond \
-    wifi-service \
+    wifi.rc \
     wm \
 
 # VINTF data for system image
@@ -276,6 +281,12 @@
     system_manifest.xml \
     system_compatibility_matrix.xml \
 
+# HWASAN runtime for SANITIZE_TARGET=hwaddress builds
+ifneq (,$(filter hwaddress,$(SANITIZE_TARGET)))
+  PRODUCT_PACKAGES += \
+   libclang_rt.hwasan-aarch64-android.bootstrap
+endif
+
 # Host tools to install
 PRODUCT_HOST_PACKAGES += \
     BugReport \
@@ -324,12 +335,16 @@
     com.android.i18n:core-icu4j \
     telephony-common \
     voip-common \
-    ims-common \
+    ims-common
 
 PRODUCT_UPDATABLE_BOOT_JARS := \
     com.android.conscrypt:conscrypt \
     com.android.media:updatable-media \
+    com.android.mediaprovider:framework-mediaprovider \
+    com.android.os.statsd:framework-statsd \
+    com.android.permission:framework-permission \
     com.android.sdkext:framework-sdkextensions \
+    com.android.wifi:framework-wifi \
     com.android.tethering:framework-tethering
 
 PRODUCT_COPY_FILES += \
@@ -351,6 +366,9 @@
 PRODUCT_SYSTEM_PROPERTIES += ro.zygote?=zygote32
 
 PRODUCT_SYSTEM_PROPERTIES += debug.atrace.tags.enableflags=0
+PRODUCT_SYSTEM_PROPERTIES += persist.traced.enable=1
+
+PRODUCT_PROPERTY_OVERRIDES += ro.gfx.angle.supported=true
 
 # Packages included only for eng or userdebug builds, previously debug tagged
 PRODUCT_PACKAGES_DEBUG := \
diff --git a/target/product/base_vendor.mk b/target/product/base_vendor.mk
index b3368d6..b955841 100644
--- a/target/product/base_vendor.mk
+++ b/target/product/base_vendor.mk
@@ -40,7 +40,7 @@
 
 # Base modules and settings for the vendor partition.
 PRODUCT_PACKAGES += \
-    android.hardware.cas@1.1-service \
+    android.hardware.cas@1.2-service \
     android.hardware.media.omx@1.0-service \
     boringssl_self_test_vendor \
     dumpsys_vendor \
@@ -66,11 +66,11 @@
     passwd_vendor \
     selinux_policy_nonsystem \
     shell_and_utilities_vendor \
-    vndservice \
 
 # Base module when shipping api level is less than or equal to 29
 PRODUCT_PACKAGES_SHIPPING_API_LEVEL_29 += \
     android.hardware.configstore@1.1-service \
+    vndservice \
     vndservicemanager \
 
 # VINTF data for vendor image
diff --git a/target/product/emulated_storage.mk b/target/product/emulated_storage.mk
index 4c6c644..7d380d9 100644
--- a/target/product/emulated_storage.mk
+++ b/target/product/emulated_storage.mk
@@ -19,3 +19,5 @@
 
 PRODUCT_FS_CASEFOLD := 1
 PRODUCT_VENDOR_PROPERTIES += external_storage.casefold.enabled=1
+
+PRODUCT_VENDOR_PROPERTIES += external_storage.sdcardfs.enabled=0
diff --git a/target/product/emulator.mk b/target/product/emulator.mk
index 9dffc1a..36da1f7 100644
--- a/target/product/emulator.mk
+++ b/target/product/emulator.mk
@@ -50,12 +50,6 @@
 #PRODUCT_VENDOR_PROPERTIES += \
 #config.disable_location=true
 
-# Enable Perfetto traced
-# There is a stable property API for this prop so we can move it to /product.
-# https://android-review.googlesource.com/c/platform/system/libsysprop/+/952375
-PRODUCT_PRODUCT_PROPERTIES += \
-    persist.traced.enable=1
-
 # enable Google-specific location features,
 # like NetworkLocationProvider and LocationCollector
 PRODUCT_SYSTEM_EXT_PROPERTIES += \
diff --git a/target/product/emulator_vendor.mk b/target/product/emulator_vendor.mk
index bb679ec..89c3f3a 100644
--- a/target/product/emulator_vendor.mk
+++ b/target/product/emulator_vendor.mk
@@ -42,12 +42,6 @@
 #PRODUCT_VENDOR_PROPERTIES += \
 #config.disable_location=true
 
-# Enable Perfetto traced
-# There is a stable property API for this prop so we can move it to /product.
-# https://android-review.googlesource.com/c/platform/system/libsysprop/+/952375
-PRODUCT_PRODUCT_PROPERTIES += \
-    persist.traced.enable=1
-
 # enable Google-specific location features,
 # like NetworkLocationProvider and LocationCollector
 PRODUCT_SYSTEM_EXT_PROPERTIES += \
diff --git a/target/product/full_base.mk b/target/product/full_base.mk
index 64f61ff..a8e1e91 100644
--- a/target/product/full_base.mk
+++ b/target/product/full_base.mk
@@ -25,7 +25,8 @@
 
 PRODUCT_PACKAGES += \
     LiveWallpapersPicker \
-    PhotoTable
+    PhotoTable \
+    preinstalled-packages-platform-full-base.xml
 
 # Bluetooth:
 #   audio.a2dp.default is a system module. Generic system image includes
diff --git a/target/product/mainline_system.mk b/target/product/generic_system.mk
similarity index 94%
rename from target/product/mainline_system.mk
rename to target/product/generic_system.mk
index e3b3e7d..731a450 100644
--- a/target/product/mainline_system.mk
+++ b/target/product/generic_system.mk
@@ -34,14 +34,10 @@
     PartnerBookmarksProvider \
     PresencePolling \
     RcsService \
-    SafetyRegulatoryInfo \
     Stk \
     Tag \
     TimeZoneUpdater \
 
-# Binaries
-PRODUCT_PACKAGES += llkd
-
 # OTA support
 PRODUCT_PACKAGES += \
     recovery-refresh \
@@ -96,11 +92,6 @@
     libhidltransport \
     libhwbinder \
 
-# Camera service uses 'libdepthphoto' for adding dynamic depth
-# metadata inside depth jpegs.
-PRODUCT_PACKAGES += \
-    libdepthphoto \
-
 PRODUCT_PACKAGES_DEBUG += \
     avbctl \
     bootctl \
@@ -114,6 +105,11 @@
 PRODUCT_HOST_PACKAGES += \
     tinyplay
 
+# Enable configurable audio policy
+PRODUCT_PACKAGES += \
+    libaudiopolicyengineconfigurable \
+    libpolicy-subsystem
+
 # Include all zygote init scripts. "ro.zygote" will select one of them.
 PRODUCT_COPY_FILES += \
     system/core/rootdir/init.zygote32.rc:system/etc/init/hw/init.zygote32.rc \
@@ -128,11 +124,11 @@
 # TODO(b/150820813) Settings depends on static overlay, remove this after eliminating the dependency.
 PRODUCT_ENFORCE_RRO_EXEMPTED_TARGETS := Settings
 
-PRODUCT_NAME := mainline_system
+PRODUCT_NAME := generic_system
 PRODUCT_BRAND := generic
 
 # Define /system partition-specific product properties to identify that /system
-# partition is mainline_system.
+# partition is generic_system.
 PRODUCT_SYSTEM_NAME := mainline
 PRODUCT_SYSTEM_BRAND := Android
 PRODUCT_SYSTEM_MANUFACTURER := Android
diff --git a/target/product/generic_system_arm64.mk b/target/product/generic_system_arm64.mk
new file mode 100644
index 0000000..b8b12c3
--- /dev/null
+++ b/target/product/generic_system_arm64.mk
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+#
+# 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/generic_system.mk)
+$(call enforce-product-packages-exist,)
+
+# Enable mainline checking
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
+
+PRODUCT_BUILD_CACHE_IMAGE := false
+PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
+PRODUCT_BUILD_ODM_DLKM_IMAGE := false
+PRODUCT_BUILD_PRODUCT_IMAGE  := false
+PRODUCT_BUILD_RAMDISK_IMAGE := false
+PRODUCT_BUILD_SYSTEM_IMAGE := true
+PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
+PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
+PRODUCT_BUILD_USERDATA_IMAGE := false
+PRODUCT_BUILD_VENDOR_IMAGE := false
+
+PRODUCT_SHIPPING_API_LEVEL := 29
+
+# TODO(b/137033385): change this back to "all"
+PRODUCT_RESTRICT_VENDOR_FILES := owner
+
+PRODUCT_NAME := generic_system_arm64
+PRODUCT_DEVICE := mainline_arm64
+PRODUCT_BRAND := generic
diff --git a/target/product/generic_system_x86.mk b/target/product/generic_system_x86.mk
new file mode 100644
index 0000000..dddcb7e
--- /dev/null
+++ b/target/product/generic_system_x86.mk
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2019 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.
+#
+
+#
+# All components inherited here go to system image
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
+$(call enforce-product-packages-exist,)
+
+# Enable mainline checking
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
+
+PRODUCT_BUILD_CACHE_IMAGE := false
+PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
+PRODUCT_BUILD_ODM_DLKM_IMAGE := false
+PRODUCT_BUILD_PRODUCT_IMAGE  := false
+PRODUCT_BUILD_RAMDISK_IMAGE := false
+PRODUCT_BUILD_SYSTEM_IMAGE := true
+PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
+PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
+PRODUCT_BUILD_USERDATA_IMAGE := false
+PRODUCT_BUILD_VENDOR_IMAGE := false
+
+PRODUCT_SHIPPING_API_LEVEL := 29
+
+# TODO(b/137033385): change this back to "all"
+PRODUCT_RESTRICT_VENDOR_FILES := owner
+
+PRODUCT_NAME := generic_system_x86
+PRODUCT_DEVICE := mainline_x86
+PRODUCT_BRAND := generic
diff --git a/target/product/generic_system_x86_64.mk b/target/product/generic_system_x86_64.mk
new file mode 100644
index 0000000..1ca9678
--- /dev/null
+++ b/target/product/generic_system_x86_64.mk
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2019 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.
+#
+
+#
+# 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/generic_system.mk)
+$(call enforce-product-packages-exist,)
+
+# Enable mainline checking
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
+
+PRODUCT_BUILD_CACHE_IMAGE := false
+PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
+PRODUCT_BUILD_ODM_DLKM_IMAGE := false
+PRODUCT_BUILD_PRODUCT_IMAGE  := false
+PRODUCT_BUILD_RAMDISK_IMAGE := false
+PRODUCT_BUILD_SYSTEM_IMAGE := true
+PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
+PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
+PRODUCT_BUILD_USERDATA_IMAGE := false
+PRODUCT_BUILD_VENDOR_IMAGE := false
+
+PRODUCT_SHIPPING_API_LEVEL := 29
+
+PRODUCT_RESTRICT_VENDOR_FILES := all
+
+PRODUCT_NAME := generic_system_x86_64
+PRODUCT_DEVICE := mainline_x86_64
+PRODUCT_BRAND := generic
diff --git a/target/product/generic_system_x86_arm.mk b/target/product/generic_system_x86_arm.mk
new file mode 100644
index 0000000..a62fb9b
--- /dev/null
+++ b/target/product/generic_system_x86_arm.mk
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2019 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.
+#
+
+#
+# All components inherited here go to system image
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
+$(call enforce-product-packages-exist,)
+
+# Enable mainline checking
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
+
+PRODUCT_BUILD_CACHE_IMAGE := false
+PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
+PRODUCT_BUILD_ODM_DLKM_IMAGE := false
+PRODUCT_BUILD_PRODUCT_IMAGE  := false
+PRODUCT_BUILD_RAMDISK_IMAGE := false
+PRODUCT_BUILD_SYSTEM_IMAGE := true
+PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
+PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
+PRODUCT_BUILD_USERDATA_IMAGE := false
+PRODUCT_BUILD_VENDOR_IMAGE := false
+
+PRODUCT_SHIPPING_API_LEVEL := 29
+
+# TODO(b/137033385): change this back to "all"
+PRODUCT_RESTRICT_VENDOR_FILES := owner
+
+PRODUCT_NAME := generic_system_x86_arm
+PRODUCT_DEVICE := mainline_x86_arm
+PRODUCT_BRAND := generic
diff --git a/target/product/go_defaults_common.mk b/target/product/go_defaults_common.mk
index d324aa9..7f19615 100644
--- a/target/product/go_defaults_common.mk
+++ b/target/product/go_defaults_common.mk
@@ -20,7 +20,6 @@
 # Set lowram options and enable traced by default
 PRODUCT_VENDOR_PROPERTIES += \
      ro.config.low_ram=true \
-     persist.traced.enable=1 \
 
 # Speed profile services and wifi-service to reduce RAM and storage.
 PRODUCT_SYSTEM_SERVER_COMPILER_FILTER := speed-profile
@@ -40,6 +39,7 @@
 # Do not spin up a separate process for the network stack on go devices, use an in-process APK.
 PRODUCT_PACKAGES += InProcessNetworkStack
 PRODUCT_PACKAGES += CellBroadcastAppPlatform
+PRODUCT_PACKAGES += CellBroadcastServiceModulePlatform
 PRODUCT_PACKAGES += com.android.tethering.inprocess
 
 # Strip the local variable table and the local variable type table to reduce
diff --git a/target/product/gsi/30.txt b/target/product/gsi/30.txt
new file mode 100644
index 0000000..0589517
--- /dev/null
+++ b/target/product/gsi/30.txt
@@ -0,0 +1,309 @@
+LLNDK: libEGL.so
+LLNDK: libGLESv1_CM.so
+LLNDK: libGLESv2.so
+LLNDK: libGLESv3.so
+LLNDK: libRS.so
+LLNDK: libandroid_net.so
+LLNDK: libbinder_ndk.so
+LLNDK: libc.so
+LLNDK: libcgrouprc.so
+LLNDK: libdl.so
+LLNDK: libft2.so
+LLNDK: liblog.so
+LLNDK: libm.so
+LLNDK: libmediandk.so
+LLNDK: libnativewindow.so
+LLNDK: libneuralnetworks.so
+LLNDK: libselinux.so
+LLNDK: libsync.so
+LLNDK: libvndksupport.so
+LLNDK: libvulkan.so
+VNDK-SP: android.hardware.common-V1-ndk_platform.so
+VNDK-SP: android.hardware.graphics.common-V1-ndk_platform.so
+VNDK-SP: android.hardware.graphics.common@1.0.so
+VNDK-SP: android.hardware.graphics.common@1.1.so
+VNDK-SP: android.hardware.graphics.common@1.2.so
+VNDK-SP: android.hardware.graphics.mapper@2.0.so
+VNDK-SP: android.hardware.graphics.mapper@2.1.so
+VNDK-SP: android.hardware.graphics.mapper@3.0.so
+VNDK-SP: android.hardware.graphics.mapper@4.0.so
+VNDK-SP: android.hardware.renderscript@1.0.so
+VNDK-SP: android.hidl.memory.token@1.0.so
+VNDK-SP: android.hidl.memory@1.0-impl.so
+VNDK-SP: android.hidl.memory@1.0.so
+VNDK-SP: android.hidl.safe_union@1.0.so
+VNDK-SP: libRSCpuRef.so
+VNDK-SP: libRSDriver.so
+VNDK-SP: libRS_internal.so
+VNDK-SP: libbacktrace.so
+VNDK-SP: libbase.so
+VNDK-SP: libbcinfo.so
+VNDK-SP: libblas.so
+VNDK-SP: libc++.so
+VNDK-SP: libcompiler_rt.so
+VNDK-SP: libcutils.so
+VNDK-SP: libgralloctypes.so
+VNDK-SP: libhardware.so
+VNDK-SP: libhidlbase.so
+VNDK-SP: libhidlmemory.so
+VNDK-SP: libion.so
+VNDK-SP: libjsoncpp.so
+VNDK-SP: liblzma.so
+VNDK-SP: libprocessgroup.so
+VNDK-SP: libunwindstack.so
+VNDK-SP: libutils.so
+VNDK-SP: libutilscallstack.so
+VNDK-SP: libz.so
+VNDK-core: android.frameworks.automotive.display@1.0.so
+VNDK-core: android.frameworks.cameraservice.common@2.0.so
+VNDK-core: android.frameworks.cameraservice.device@2.0.so
+VNDK-core: android.frameworks.cameraservice.service@2.0.so
+VNDK-core: android.frameworks.cameraservice.service@2.1.so
+VNDK-core: android.frameworks.displayservice@1.0.so
+VNDK-core: android.frameworks.schedulerservice@1.0.so
+VNDK-core: android.frameworks.sensorservice@1.0.so
+VNDK-core: android.frameworks.stats@1.0.so
+VNDK-core: android.hardware.atrace@1.0.so
+VNDK-core: android.hardware.audio.common@2.0.so
+VNDK-core: android.hardware.audio.common@4.0.so
+VNDK-core: android.hardware.audio.common@5.0.so
+VNDK-core: android.hardware.audio.common@6.0.so
+VNDK-core: android.hardware.audio.effect@2.0.so
+VNDK-core: android.hardware.audio.effect@4.0.so
+VNDK-core: android.hardware.audio.effect@5.0.so
+VNDK-core: android.hardware.audio.effect@6.0.so
+VNDK-core: android.hardware.audio@2.0.so
+VNDK-core: android.hardware.audio@4.0.so
+VNDK-core: android.hardware.audio@5.0.so
+VNDK-core: android.hardware.audio@6.0.so
+VNDK-core: android.hardware.authsecret@1.0.so
+VNDK-core: android.hardware.automotive.audiocontrol@1.0.so
+VNDK-core: android.hardware.automotive.audiocontrol@2.0.so
+VNDK-core: android.hardware.automotive.can@1.0.so
+VNDK-core: android.hardware.automotive.evs@1.0.so
+VNDK-core: android.hardware.automotive.evs@1.1.so
+VNDK-core: android.hardware.automotive.occupant_awareness-V1-ndk_platform.so
+VNDK-core: android.hardware.automotive.sv@1.0.so
+VNDK-core: android.hardware.automotive.vehicle@2.0.so
+VNDK-core: android.hardware.biometrics.face@1.0.so
+VNDK-core: android.hardware.biometrics.fingerprint@2.1.so
+VNDK-core: android.hardware.biometrics.fingerprint@2.2.so
+VNDK-core: android.hardware.bluetooth.a2dp@1.0.so
+VNDK-core: android.hardware.bluetooth.audio@2.0.so
+VNDK-core: android.hardware.bluetooth@1.0.so
+VNDK-core: android.hardware.bluetooth@1.1.so
+VNDK-core: android.hardware.boot@1.0.so
+VNDK-core: android.hardware.boot@1.1.so
+VNDK-core: android.hardware.broadcastradio@1.0.so
+VNDK-core: android.hardware.broadcastradio@1.1.so
+VNDK-core: android.hardware.broadcastradio@2.0.so
+VNDK-core: android.hardware.camera.common@1.0.so
+VNDK-core: android.hardware.camera.device@1.0.so
+VNDK-core: android.hardware.camera.device@3.2.so
+VNDK-core: android.hardware.camera.device@3.3.so
+VNDK-core: android.hardware.camera.device@3.4.so
+VNDK-core: android.hardware.camera.device@3.5.so
+VNDK-core: android.hardware.camera.device@3.6.so
+VNDK-core: android.hardware.camera.metadata@3.2.so
+VNDK-core: android.hardware.camera.metadata@3.3.so
+VNDK-core: android.hardware.camera.metadata@3.4.so
+VNDK-core: android.hardware.camera.metadata@3.5.so
+VNDK-core: android.hardware.camera.provider@2.4.so
+VNDK-core: android.hardware.camera.provider@2.5.so
+VNDK-core: android.hardware.camera.provider@2.6.so
+VNDK-core: android.hardware.cas.native@1.0.so
+VNDK-core: android.hardware.cas@1.0.so
+VNDK-core: android.hardware.cas@1.1.so
+VNDK-core: android.hardware.cas@1.2.so
+VNDK-core: android.hardware.configstore-utils.so
+VNDK-core: android.hardware.configstore@1.0.so
+VNDK-core: android.hardware.configstore@1.1.so
+VNDK-core: android.hardware.confirmationui-support-lib.so
+VNDK-core: android.hardware.confirmationui@1.0.so
+VNDK-core: android.hardware.contexthub@1.0.so
+VNDK-core: android.hardware.contexthub@1.1.so
+VNDK-core: android.hardware.drm@1.0.so
+VNDK-core: android.hardware.drm@1.1.so
+VNDK-core: android.hardware.drm@1.2.so
+VNDK-core: android.hardware.drm@1.3.so
+VNDK-core: android.hardware.dumpstate@1.0.so
+VNDK-core: android.hardware.dumpstate@1.1.so
+VNDK-core: android.hardware.fastboot@1.0.so
+VNDK-core: android.hardware.gatekeeper@1.0.so
+VNDK-core: android.hardware.gnss.measurement_corrections@1.0.so
+VNDK-core: android.hardware.gnss.measurement_corrections@1.1.so
+VNDK-core: android.hardware.gnss.visibility_control@1.0.so
+VNDK-core: android.hardware.gnss@1.0.so
+VNDK-core: android.hardware.gnss@1.1.so
+VNDK-core: android.hardware.gnss@2.0.so
+VNDK-core: android.hardware.gnss@2.1.so
+VNDK-core: android.hardware.graphics.allocator@2.0.so
+VNDK-core: android.hardware.graphics.allocator@3.0.so
+VNDK-core: android.hardware.graphics.allocator@4.0.so
+VNDK-core: android.hardware.graphics.bufferqueue@1.0.so
+VNDK-core: android.hardware.graphics.bufferqueue@2.0.so
+VNDK-core: android.hardware.graphics.composer@2.1.so
+VNDK-core: android.hardware.graphics.composer@2.2.so
+VNDK-core: android.hardware.graphics.composer@2.3.so
+VNDK-core: android.hardware.graphics.composer@2.4.so
+VNDK-core: android.hardware.health.storage@1.0.so
+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-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-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
+VNDK-core: android.hardware.light-V1-ndk_platform.so
+VNDK-core: android.hardware.light@2.0.so
+VNDK-core: android.hardware.media.bufferpool@1.0.so
+VNDK-core: android.hardware.media.bufferpool@2.0.so
+VNDK-core: android.hardware.media.c2@1.0.so
+VNDK-core: android.hardware.media.c2@1.1.so
+VNDK-core: android.hardware.media.omx@1.0.so
+VNDK-core: android.hardware.media@1.0.so
+VNDK-core: android.hardware.memtrack@1.0.so
+VNDK-core: android.hardware.neuralnetworks@1.0.so
+VNDK-core: android.hardware.neuralnetworks@1.1.so
+VNDK-core: android.hardware.neuralnetworks@1.2.so
+VNDK-core: android.hardware.neuralnetworks@1.3.so
+VNDK-core: android.hardware.nfc@1.0.so
+VNDK-core: android.hardware.nfc@1.1.so
+VNDK-core: android.hardware.nfc@1.2.so
+VNDK-core: android.hardware.oemlock@1.0.so
+VNDK-core: android.hardware.power-V1-ndk_platform.so
+VNDK-core: android.hardware.power.stats@1.0.so
+VNDK-core: android.hardware.power@1.0.so
+VNDK-core: android.hardware.power@1.1.so
+VNDK-core: android.hardware.power@1.2.so
+VNDK-core: android.hardware.power@1.3.so
+VNDK-core: android.hardware.radio.config@1.0.so
+VNDK-core: android.hardware.radio.config@1.1.so
+VNDK-core: android.hardware.radio.config@1.2.so
+VNDK-core: android.hardware.radio.deprecated@1.0.so
+VNDK-core: android.hardware.radio@1.0.so
+VNDK-core: android.hardware.radio@1.1.so
+VNDK-core: android.hardware.radio@1.2.so
+VNDK-core: android.hardware.radio@1.3.so
+VNDK-core: android.hardware.radio@1.4.so
+VNDK-core: android.hardware.radio@1.5.so
+VNDK-core: android.hardware.rebootescrow-V1-ndk_platform.so
+VNDK-core: android.hardware.secure_element@1.0.so
+VNDK-core: android.hardware.secure_element@1.1.so
+VNDK-core: android.hardware.secure_element@1.2.so
+VNDK-core: android.hardware.sensors@1.0.so
+VNDK-core: android.hardware.sensors@2.0.so
+VNDK-core: android.hardware.sensors@2.1.so
+VNDK-core: android.hardware.soundtrigger@2.0-core.so
+VNDK-core: android.hardware.soundtrigger@2.0.so
+VNDK-core: android.hardware.soundtrigger@2.1.so
+VNDK-core: android.hardware.soundtrigger@2.2.so
+VNDK-core: android.hardware.soundtrigger@2.3.so
+VNDK-core: android.hardware.tetheroffload.config@1.0.so
+VNDK-core: android.hardware.tetheroffload.control@1.0.so
+VNDK-core: android.hardware.thermal@1.0.so
+VNDK-core: android.hardware.thermal@1.1.so
+VNDK-core: android.hardware.thermal@2.0.so
+VNDK-core: android.hardware.tv.cec@1.0.so
+VNDK-core: android.hardware.tv.cec@2.0.so
+VNDK-core: android.hardware.tv.input@1.0.so
+VNDK-core: android.hardware.tv.tuner@1.0.so
+VNDK-core: android.hardware.usb.gadget@1.0.so
+VNDK-core: android.hardware.usb.gadget@1.1.so
+VNDK-core: android.hardware.usb@1.0.so
+VNDK-core: android.hardware.usb@1.1.so
+VNDK-core: android.hardware.usb@1.2.so
+VNDK-core: android.hardware.vibrator-V1-ndk_platform.so
+VNDK-core: android.hardware.vibrator@1.0.so
+VNDK-core: android.hardware.vibrator@1.1.so
+VNDK-core: android.hardware.vibrator@1.2.so
+VNDK-core: android.hardware.vibrator@1.3.so
+VNDK-core: android.hardware.vr@1.0.so
+VNDK-core: android.hardware.weaver@1.0.so
+VNDK-core: android.hardware.wifi.hostapd@1.0.so
+VNDK-core: android.hardware.wifi.hostapd@1.1.so
+VNDK-core: android.hardware.wifi.hostapd@1.2.so
+VNDK-core: android.hardware.wifi.offload@1.0.so
+VNDK-core: android.hardware.wifi.supplicant@1.0.so
+VNDK-core: android.hardware.wifi.supplicant@1.1.so
+VNDK-core: android.hardware.wifi.supplicant@1.2.so
+VNDK-core: android.hardware.wifi.supplicant@1.3.so
+VNDK-core: android.hardware.wifi@1.0.so
+VNDK-core: android.hardware.wifi@1.1.so
+VNDK-core: android.hardware.wifi@1.2.so
+VNDK-core: android.hardware.wifi@1.3.so
+VNDK-core: android.hardware.wifi@1.4.so
+VNDK-core: android.hidl.allocator@1.0.so
+VNDK-core: android.hidl.memory.block@1.0.so
+VNDK-core: android.hidl.token@1.0-utils.so
+VNDK-core: android.hidl.token@1.0.so
+VNDK-core: android.system.net.netd@1.0.so
+VNDK-core: android.system.net.netd@1.1.so
+VNDK-core: android.system.suspend@1.0.so
+VNDK-core: android.system.wifi.keystore@1.0.so
+VNDK-core: libadf.so
+VNDK-core: libaudioroute.so
+VNDK-core: libaudioutils.so
+VNDK-core: libbinder.so
+VNDK-core: libbufferqueueconverter.so
+VNDK-core: libcamera_metadata.so
+VNDK-core: libcap.so
+VNDK-core: libcn-cbor.so
+VNDK-core: libcodec2.so
+VNDK-core: libcrypto.so
+VNDK-core: libcrypto_utils.so
+VNDK-core: libcurl.so
+VNDK-core: libdiskconfig.so
+VNDK-core: libdumpstateutil.so
+VNDK-core: libevent.so
+VNDK-core: libexif.so
+VNDK-core: libexpat.so
+VNDK-core: libfmq.so
+VNDK-core: libgatekeeper.so
+VNDK-core: libgui.so
+VNDK-core: libhardware_legacy.so
+VNDK-core: libhidlallocatorutils.so
+VNDK-core: libjpeg.so
+VNDK-core: libldacBT_abr.so
+VNDK-core: libldacBT_enc.so
+VNDK-core: liblz4.so
+VNDK-core: libmedia_helper.so
+VNDK-core: libmedia_omx.so
+VNDK-core: libmemtrack.so
+VNDK-core: libminijail.so
+VNDK-core: libmkbootimg_abi_check.so
+VNDK-core: libnetutils.so
+VNDK-core: libnl.so
+VNDK-core: libpcre2.so
+VNDK-core: libpiex.so
+VNDK-core: libpng.so
+VNDK-core: libpower.so
+VNDK-core: libprocinfo.so
+VNDK-core: libradio_metadata.so
+VNDK-core: libspeexresampler.so
+VNDK-core: libsqlite.so
+VNDK-core: libssl.so
+VNDK-core: libstagefright_bufferpool@2.0.so
+VNDK-core: libstagefright_bufferqueue_helper.so
+VNDK-core: libstagefright_foundation.so
+VNDK-core: libstagefright_omx.so
+VNDK-core: libstagefright_omx_utils.so
+VNDK-core: libstagefright_xmlparser.so
+VNDK-core: libsysutils.so
+VNDK-core: libtinyalsa.so
+VNDK-core: libtinyxml2.so
+VNDK-core: libui.so
+VNDK-core: libusbhost.so
+VNDK-core: libwifi-system-iface.so
+VNDK-core: libxml2.so
+VNDK-core: libyuv.so
+VNDK-core: libziparchive.so
+VNDK-private: libbacktrace.so
+VNDK-private: libblas.so
+VNDK-private: libcompiler_rt.so
+VNDK-private: libft2.so
+VNDK-private: libgui.so
diff --git a/target/product/gsi/Android.mk b/target/product/gsi/Android.mk
index 6775131..b4df5fe 100644
--- a/target/product/gsi/Android.mk
+++ b/target/product/gsi/Android.mk
@@ -31,10 +31,6 @@
 ifeq ($(TARGET_IS_64_BIT)|$(TARGET_2ND_ARCH),true|)
 # TODO(b/110429754) remove this condition when we support 64-bit-only device
 check-vndk-list: ;
-else ifeq ($(TARGET_BUILD_PDK),true)
-# b/118634643: don't check VNDK lib list when building PDK. Some libs (libandroid_net.so
-# and some render-script related ones) can't be built in PDK due to missing frameworks/base.
-check-vndk-list: ;
 else ifeq ($(TARGET_SKIP_CURRENT_VNDK),true)
 check-vndk-list: ;
 else ifeq ($(BOARD_VNDK_VERSION),)
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index 345faa4..baf1382 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -26,6 +26,7 @@
 VNDK-SP: android.hardware.graphics.mapper@2.0.so
 VNDK-SP: android.hardware.graphics.mapper@2.1.so
 VNDK-SP: android.hardware.graphics.mapper@3.0.so
+VNDK-SP: android.hardware.graphics.mapper@4.0.so
 VNDK-SP: android.hardware.renderscript@1.0.so
 VNDK-SP: android.hidl.memory.token@1.0.so
 VNDK-SP: android.hidl.memory@1.0-impl.so
@@ -41,6 +42,7 @@
 VNDK-SP: libc++.so
 VNDK-SP: libcompiler_rt.so
 VNDK-SP: libcutils.so
+VNDK-SP: libgralloctypes.so
 VNDK-SP: libhardware.so
 VNDK-SP: libhidlbase.so
 VNDK-SP: libhidlmemory.so
@@ -53,12 +55,14 @@
 VNDK-SP: libutilscallstack.so
 VNDK-SP: libz.so
 VNDK-core: android.hardware.audio.common@2.0.so
+VNDK-core: android.hardware.automotive.occupant_awareness-V1-ndk_platform.so
 VNDK-core: android.hardware.configstore-utils.so
 VNDK-core: android.hardware.configstore@1.0.so
 VNDK-core: android.hardware.configstore@1.1.so
 VNDK-core: android.hardware.confirmationui-support-lib.so
 VNDK-core: android.hardware.graphics.allocator@2.0.so
 VNDK-core: android.hardware.graphics.allocator@3.0.so
+VNDK-core: android.hardware.graphics.allocator@4.0.so
 VNDK-core: android.hardware.graphics.bufferqueue@1.0.so
 VNDK-core: android.hardware.graphics.bufferqueue@2.0.so
 VNDK-core: android.hardware.identity-V2-ndk_platform.so
@@ -69,6 +73,7 @@
 VNDK-core: android.hardware.media@1.0.so
 VNDK-core: android.hardware.memtrack@1.0.so
 VNDK-core: android.hardware.power-V1-ndk_platform.so
+VNDK-core: android.hardware.rebootescrow-V1-ndk_platform.so
 VNDK-core: android.hardware.soundtrigger@2.0-core.so
 VNDK-core: android.hardware.soundtrigger@2.0.so
 VNDK-core: android.hardware.vibrator-V1-ndk_platform.so
@@ -79,6 +84,7 @@
 VNDK-core: libaudioroute.so
 VNDK-core: libaudioutils.so
 VNDK-core: libbinder.so
+VNDK-core: libbufferqueueconverter.so
 VNDK-core: libcamera_metadata.so
 VNDK-core: libcap.so
 VNDK-core: libcn-cbor.so
diff --git a/target/product/gsi_arm64.mk b/target/product/gsi_arm64.mk
index adf7ca5..1043a85 100644
--- a/target/product/gsi_arm64.mk
+++ b/target/product/gsi_arm64.mk
@@ -18,7 +18,7 @@
 # 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)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index 46c956d..241b6ba 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -46,11 +46,16 @@
 # 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 \
     init.gsi.rc \
     init.vndk-nodef.rc \
 
-# Support additional P and Q VNDK packages
-PRODUCT_EXTRA_VNDK_VERSIONS := 28 29
+# Support additional P, Q and R VNDK packages
+PRODUCT_EXTRA_VNDK_VERSIONS := 28 29 30
diff --git a/target/product/handheld_product.mk b/target/product/handheld_product.mk
index e03c212..2199c57 100644
--- a/target/product/handheld_product.mk
+++ b/target/product/handheld_product.mk
@@ -31,6 +31,7 @@
     LatinIME \
     Music \
     OneTimeInitializer \
+    preinstalled-packages-platform-handheld-product.xml \
     QuickSearchBox \
     SettingsIntelligence \
     frameworks-base-overlays
diff --git a/target/product/handheld_system.mk b/target/product/handheld_system.mk
index e2c91b6..c2608c4 100644
--- a/target/product/handheld_system.mk
+++ b/target/product/handheld_system.mk
@@ -53,10 +53,9 @@
     librs_jni \
     ManagedProvisioning \
     MmsService \
-    MtpDocumentsProvider \
+    MtpService \
     MusicFX \
     NfcNci \
-    OsuLogin \
     PacProcessor \
     PrintRecommendationService \
     PrintSpooler \
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/mainline_system.mk b/target/product/mainline_system.mk
new file mode 120000
index 0000000..0b6eaf0
--- /dev/null
+++ b/target/product/mainline_system.mk
@@ -0,0 +1 @@
+generic_system.mk
\ No newline at end of file
diff --git a/target/product/mainline_system_arm64.mk b/target/product/mainline_system_arm64.mk
index a0c3e6d..5fa13ce 100644
--- a/target/product/mainline_system_arm64.mk
+++ b/target/product/mainline_system_arm64.mk
@@ -14,33 +14,10 @@
 # limitations under the License.
 #
 
-#
-# 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)
-$(call enforce-product-packages-exist,)
+# Do not modify this file. It's just alias of generic_system_arm64.mk
+# Will be removed when renaming from mainline_system to generic_system
+# complete
 
-# Enable mainline checking
-PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
-
-PRODUCT_BUILD_CACHE_IMAGE := false
-PRODUCT_BUILD_ODM_IMAGE := false
-PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
-PRODUCT_BUILD_ODM_DLKM_IMAGE := false
-PRODUCT_BUILD_PRODUCT_IMAGE  := false
-PRODUCT_BUILD_RAMDISK_IMAGE := false
-PRODUCT_BUILD_SYSTEM_IMAGE := true
-PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
-PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
-PRODUCT_BUILD_USERDATA_IMAGE := false
-PRODUCT_BUILD_VENDOR_IMAGE := false
-
-PRODUCT_SHIPPING_API_LEVEL := 29
-
-# TODO(b/137033385): change this back to "all"
-PRODUCT_RESTRICT_VENDOR_FILES := owner
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system_arm64.mk)
 
 PRODUCT_NAME := mainline_system_arm64
-PRODUCT_DEVICE := mainline_arm64
-PRODUCT_BRAND := generic
diff --git a/target/product/mainline_system_x86.mk b/target/product/mainline_system_x86.mk
index 3c4a867..3fb1963 100644
--- a/target/product/mainline_system_x86.mk
+++ b/target/product/mainline_system_x86.mk
@@ -14,32 +14,10 @@
 # limitations under the License.
 #
 
-#
-# All components inherited here go to system image
-#
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
-$(call enforce-product-packages-exist,)
+# Do not modify this file. It's just alias of generic_system_x86.mk
+# Will be removed when renaming from mainline_system to generic_system
+# complete
 
-# Enable mainline checking
-PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
-
-PRODUCT_BUILD_CACHE_IMAGE := false
-PRODUCT_BUILD_ODM_IMAGE := false
-PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
-PRODUCT_BUILD_ODM_DLKM_IMAGE := false
-PRODUCT_BUILD_PRODUCT_IMAGE  := false
-PRODUCT_BUILD_RAMDISK_IMAGE := false
-PRODUCT_BUILD_SYSTEM_IMAGE := true
-PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
-PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
-PRODUCT_BUILD_USERDATA_IMAGE := false
-PRODUCT_BUILD_VENDOR_IMAGE := false
-
-PRODUCT_SHIPPING_API_LEVEL := 29
-
-# TODO(b/137033385): change this back to "all"
-PRODUCT_RESTRICT_VENDOR_FILES := owner
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system_x86.mk)
 
 PRODUCT_NAME := mainline_system_x86
-PRODUCT_DEVICE := mainline_x86
-PRODUCT_BRAND := generic
diff --git a/target/product/mainline_system_x86_64.mk b/target/product/mainline_system_x86_64.mk
index 410c998..eab99c5 100644
--- a/target/product/mainline_system_x86_64.mk
+++ b/target/product/mainline_system_x86_64.mk
@@ -14,32 +14,10 @@
 # limitations under the License.
 #
 
-#
-# 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)
-$(call enforce-product-packages-exist,)
+# Do not modify this file. It's just alias of generic_system_x86_64.mk
+# Will be removed when renaming from mainline_system to generic_system
+# complete
 
-# Enable mainline checking
-PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
-
-PRODUCT_BUILD_CACHE_IMAGE := false
-PRODUCT_BUILD_ODM_IMAGE := false
-PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
-PRODUCT_BUILD_ODM_DLKM_IMAGE := false
-PRODUCT_BUILD_PRODUCT_IMAGE  := false
-PRODUCT_BUILD_RAMDISK_IMAGE := false
-PRODUCT_BUILD_SYSTEM_IMAGE := true
-PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
-PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
-PRODUCT_BUILD_USERDATA_IMAGE := false
-PRODUCT_BUILD_VENDOR_IMAGE := false
-
-PRODUCT_SHIPPING_API_LEVEL := 29
-
-PRODUCT_RESTRICT_VENDOR_FILES := all
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system_x86_64.mk)
 
 PRODUCT_NAME := mainline_system_x86_64
-PRODUCT_DEVICE := mainline_x86_64
-PRODUCT_BRAND := generic
diff --git a/target/product/mainline_system_x86_arm.mk b/target/product/mainline_system_x86_arm.mk
index 8c6611e..483fb58 100644
--- a/target/product/mainline_system_x86_arm.mk
+++ b/target/product/mainline_system_x86_arm.mk
@@ -14,32 +14,10 @@
 # limitations under the License.
 #
 
-#
-# All components inherited here go to system image
-#
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
-$(call enforce-product-packages-exist,)
+# Do not modify this file. It's just alias of generic_system_x86_arm.mk
+# Will be removed when renaming from mainline_system to generic_system
+# complete
 
-# Enable mainline checking
-PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
-
-PRODUCT_BUILD_CACHE_IMAGE := false
-PRODUCT_BUILD_ODM_IMAGE := false
-PRODUCT_BUILD_VENDOR_DLKM_IMAGE := false
-PRODUCT_BUILD_ODM_DLKM_IMAGE := false
-PRODUCT_BUILD_PRODUCT_IMAGE  := false
-PRODUCT_BUILD_RAMDISK_IMAGE := false
-PRODUCT_BUILD_SYSTEM_IMAGE := true
-PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
-PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
-PRODUCT_BUILD_USERDATA_IMAGE := false
-PRODUCT_BUILD_VENDOR_IMAGE := false
-
-PRODUCT_SHIPPING_API_LEVEL := 29
-
-# TODO(b/137033385): change this back to "all"
-PRODUCT_RESTRICT_VENDOR_FILES := owner
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system_x86_arm.mk)
 
 PRODUCT_NAME := mainline_system_x86_arm
-PRODUCT_DEVICE := mainline_x86_arm
-PRODUCT_BRAND := generic
diff --git a/target/product/media_system.mk b/target/product/media_system.mk
index 7a2dd73..1004dc5 100644
--- a/target/product/media_system.mk
+++ b/target/product/media_system.mk
@@ -52,12 +52,13 @@
 PRODUCT_SYSTEM_SERVER_JARS := \
     com.android.location.provider \
     services \
-    ethernet-service \
-    wifi-service \
+    ethernet-service
 
 # system server jars which are updated via apex modules.
 # The values should be of the format <apex name>:<jar name>
 PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS := \
+    com.android.permission:service-permission \
+    com.android.wifi:service-wifi \
     com.android.ipsec:android.net.ipsec.ike \
 
 PRODUCT_COPY_FILES += \
diff --git a/target/product/runtime_libart.mk b/target/product/runtime_libart.mk
index b96601d..7633abe 100644
--- a/target/product/runtime_libart.mk
+++ b/target/product/runtime_libart.mk
@@ -92,8 +92,4 @@
     dalvik.vm.minidebuginfo=true \
     dalvik.vm.dex2oat-minidebuginfo=true
 
-# Disable iorapd by default
-PRODUCT_SYSTEM_PROPERTIES += \
-    ro.iorapd.enable=false
-
 PRODUCT_USES_DEFAULT_ART_CONFIG := true
diff --git a/target/product/sdk_phone_arm64.mk b/target/product/sdk_phone_arm64.mk
index cefa288..761de05 100644
--- a/target/product/sdk_phone_arm64.mk
+++ b/target/product/sdk_phone_arm64.mk
@@ -30,7 +30,7 @@
 # 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)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 #
 # All components inherited here go to system_ext image
diff --git a/target/product/sdk_phone_armv7.mk b/target/product/sdk_phone_armv7.mk
index c4c5a38..5081a87 100644
--- a/target/product/sdk_phone_armv7.mk
+++ b/target/product/sdk_phone_armv7.mk
@@ -29,7 +29,7 @@
 #
 # All components inherited here go to system image
 #
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 #
 # All components inherited here go to system_ext image
diff --git a/target/product/sdk_phone_x86.mk b/target/product/sdk_phone_x86.mk
index bcee066..63671dc 100644
--- a/target/product/sdk_phone_x86.mk
+++ b/target/product/sdk_phone_x86.mk
@@ -24,7 +24,7 @@
 #
 # All components inherited here go to system image
 #
-$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for exact this product name
 ifeq (sdk_phone_x86,$(TARGET_PRODUCT))
diff --git a/target/product/sdk_phone_x86_64.mk b/target/product/sdk_phone_x86_64.mk
index 82bbee5..c5a6245 100644
--- a/target/product/sdk_phone_x86_64.mk
+++ b/target/product/sdk_phone_x86_64.mk
@@ -25,7 +25,7 @@
 # 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)
+$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_system.mk)
 
 # Enable mainline checking for exact this product name
 ifeq (sdk_phone_x86_64,$(TARGET_PRODUCT))
diff --git a/target/product/sysconfig/Android.bp b/target/product/sysconfig/Android.bp
new file mode 100644
index 0000000..5632d17
--- /dev/null
+++ b/target/product/sysconfig/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C} 2019 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.
+
+prebuilt_etc {
+    name: "preinstalled-packages-platform-aosp-product.xml",
+    product_specific: true,
+    sub_dir: "sysconfig",
+    src: "preinstalled-packages-platform-aosp-product.xml",
+}
+
+prebuilt_etc {
+    name: "preinstalled-packages-platform-full-base.xml",
+    sub_dir: "sysconfig",
+    src: "preinstalled-packages-platform-full-base.xml",
+}
+
+prebuilt_etc {
+    name: "preinstalled-packages-platform-handheld-product.xml",
+    product_specific: true,
+    sub_dir: "sysconfig",
+    src: "preinstalled-packages-platform-handheld-product.xml",
+}
\ No newline at end of file
diff --git a/target/product/sysconfig/preinstalled-packages-platform-aosp-product.xml b/target/product/sysconfig/preinstalled-packages-platform-aosp-product.xml
new file mode 100644
index 0000000..eec1326
--- /dev/null
+++ b/target/product/sysconfig/preinstalled-packages-platform-aosp-product.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<!-- System packages to preinstall on all devices with aosp_product, per user type.
+     Documentation at frameworks/base/data/etc/preinstalled-packages-platform.xml
+-->
+<config>
+    <install-in-user-type package="com.android.wallpaperpicker">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+</config>
diff --git a/target/product/sysconfig/preinstalled-packages-platform-full-base.xml b/target/product/sysconfig/preinstalled-packages-platform-full-base.xml
new file mode 100644
index 0000000..f601355
--- /dev/null
+++ b/target/product/sysconfig/preinstalled-packages-platform-full-base.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<!-- System packages to preinstall on all devices with full_base, per user type.
+     Documentation at frameworks/base/data/etc/preinstalled-packages-platform.xml
+-->
+<config>
+    <install-in-user-type package="com.android.wallpaper.livepicker">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+</config>
diff --git a/target/product/sysconfig/preinstalled-packages-platform-handheld-product.xml b/target/product/sysconfig/preinstalled-packages-platform-handheld-product.xml
new file mode 100644
index 0000000..a5d9ba2
--- /dev/null
+++ b/target/product/sysconfig/preinstalled-packages-platform-handheld-product.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<!-- System packages to preinstall on all devices with handheld_product, per user type.
+     Documentation at frameworks/base/data/etc/preinstalled-packages-platform.xml
+-->
+<config>
+    <install-in-user-type package="com.android.wallpapercropper">
+        <install-in user-type="FULL" />
+    </install-in-user-type>
+</config>
diff --git a/target/product/telephony_system.mk b/target/product/telephony_system.mk
index c306a04..ef48719 100644
--- a/target/product/telephony_system.mk
+++ b/target/product/telephony_system.mk
@@ -21,7 +21,7 @@
     ONS \
     CarrierDefaultApp \
     CallLogBackup \
-    CellBroadcastApp \
-    CellBroadcastServiceModule \
+    com.android.cellbroadcast \
+    CellBroadcastLegacyApp \
 
 PRODUCT_COPY_FILES := \
diff --git a/target/product/updatable_apex.mk b/target/product/updatable_apex.mk
index 2730f0e..c8dc8b0 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_VENDOR_PROPERTIES := ro.apex.updatable=true
   TARGET_FLATTEN_APEX := false
diff --git a/target/product/virtual_ab_ota_compression.mk b/target/product/virtual_ab_ota_compression.mk
new file mode 100644
index 0000000..c4849be
--- /dev/null
+++ b/target/product/virtual_ab_ota_compression.mk
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)
+
+PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.enabled=true
+
+PRODUCT_PACKAGES += snapuserd_ramdisk
diff --git a/target/product/virtual_ab_ota_retrofit_compression.mk b/target/product/virtual_ab_ota_retrofit_compression.mk
new file mode 100644
index 0000000..8059f75
--- /dev/null
+++ b/target/product/virtual_ab_ota_retrofit_compression.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
+
+PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.enabled=true
+
+PRODUCT_PACKAGES += snapuserd_ramdisk
+
diff --git a/tools/buildinfo.sh b/tools/buildinfo.sh
index 09d8f70..9bee115 100755
--- a/tools/buildinfo.sh
+++ b/tools/buildinfo.sh
@@ -11,7 +11,8 @@
 echo "ro.build.version.preview_sdk_fingerprint=$PLATFORM_PREVIEW_SDK_FINGERPRINT"
 echo "ro.build.version.codename=$PLATFORM_VERSION_CODENAME"
 echo "ro.build.version.all_codenames=$PLATFORM_VERSION_ALL_CODENAMES"
-echo "ro.build.version.release=$PLATFORM_VERSION"
+echo "ro.build.version.release=$PLATFORM_VERSION_LAST_STABLE"
+echo "ro.build.version.release_or_codename=$PLATFORM_VERSION"
 echo "ro.build.version.security_patch=$PLATFORM_SECURITY_PATCH"
 echo "ro.build.version.base_os=$PLATFORM_BASE_OS"
 echo "ro.build.version.min_supported_target_sdk=$PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION"
diff --git a/tools/check_elf_file.py b/tools/check_elf_file.py
index 372404b..1ff8e65 100755
--- a/tools/check_elf_file.py
+++ b/tools/check_elf_file.py
@@ -207,8 +207,8 @@
   def _parse_llvm_readobj(cls, elf_file_path, header, lines):
     """Parse the output of llvm-readobj."""
     lines_it = iter(lines)
-    imported, exported = cls._parse_dynamic_symbols(lines_it)
     dt_soname, dt_needed = cls._parse_dynamic_table(elf_file_path, lines_it)
+    imported, exported = cls._parse_dynamic_symbols(lines_it)
     return ELF(dt_soname, dt_needed, imported, exported, header)
 
 
@@ -397,7 +397,7 @@
       sys.exit(2)
 
 
-  def check_dt_needed(self):
+  def check_dt_needed(self, system_shared_lib_names):
     """Check whether all DT_NEEDED entries are specified in the build
     system."""
 
@@ -417,6 +417,11 @@
       dt_needed = sorted(set(self._file_under_test.dt_needed))
       modules = [re.sub('\\.so$', '', lib) for lib in dt_needed]
 
+      # Remove system shared libraries from the suggestion since they are added
+      # by default.
+      modules = [name for name in modules
+                 if name not in system_shared_lib_names]
+
       self._note()
       self._note('Fix suggestions:')
       self._note(
@@ -502,6 +507,11 @@
   parser.add_argument('--shared-lib', action='append', default=[],
                       help='Path to shared library dependencies')
 
+  # System Shared library names
+  parser.add_argument('--system-shared-lib', action='append', default=[],
+                      help='System shared libraries to be hidden from fix '
+                      'suggestions')
+
   # Check options
   parser.add_argument('--skip-bad-elf-magic', action='store_true',
                       help='Ignore the input file without the ELF magic word')
@@ -535,7 +545,7 @@
   if args.soname:
     checker.check_dt_soname(args.soname)
 
-  checker.check_dt_needed()
+  checker.check_dt_needed(args.system_shared_lib)
 
   if not args.allow_undefined_symbols:
     checker.check_symbols()
diff --git a/tools/extract_kernel.py b/tools/extract_kernel.py
index 92a647b..0046b38 100755
--- a/tools/extract_kernel.py
+++ b/tools/extract_kernel.py
@@ -40,7 +40,7 @@
 # LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
 LINUX_BANNER_PREFIX = b'Linux version '
 LINUX_BANNER_REGEX = LINUX_BANNER_PREFIX + \
-    r'(?P<release>(?P<version>[0-9]+[.][0-9]+[.][0-9]+).*) \(.*@.*\) \(.*\) .*\n'
+    r'(?P<release>(?P<version>[0-9]+[.][0-9]+[.][0-9]+).*) \(.*@.*\) \((?P<compiler>.*)\) .*\n'
 
 
 def get_from_release(input_bytes, start_idx, key):
@@ -82,6 +82,14 @@
   return dump_from_release(input_bytes, "version")
 
 
+def dump_compiler(input_bytes):
+  """
+  Dump kernel version, w.x.y, from input_bytes. Search for the string
+  "Linux version " and do pattern matching after it. See LINUX_BANNER_REGEX.
+  """
+  return dump_from_release(input_bytes, "compiler")
+
+
 def dump_release(input_bytes):
   """
   Dump kernel release, w.x.y-..., from input_bytes. Search for the string
@@ -208,6 +216,13 @@
                       nargs='?',
                       type=argparse.FileType('wb'),
                       const=sys.stdout)
+  parser.add_argument('--output-compiler',
+                      help='If specified, write the compiler information. Use stdout if no file '
+                           'is specified.',
+                      metavar='FILE',
+                      nargs='?',
+                      type=argparse.FileType('wb'),
+                      const=sys.stdout)
   parser.add_argument('--tools',
                       help='Decompression tools to use. If not specified, PATH '
                            'is searched.',
@@ -234,6 +249,10 @@
                       "kernel release in {}".format(args.input.name)):
     ret = 1
 
+  if not dump_to_file(args.output_compiler, dump_compiler, input_bytes,
+                      "kernel compiler in {}".format(args.input.name)):
+    ret = 1
+
   return ret
 
 
diff --git a/tools/fs_config/Android.mk b/tools/fs_config/Android.mk
index 41e8ca5..5fb68b8 100644
--- a/tools/fs_config/Android.mk
+++ b/tools/fs_config/Android.mk
@@ -24,7 +24,7 @@
 $(error Using $(TARGET_DEVICE_DIR)/android_filesystem_config.h is deprecated, please use TARGET_FS_CONFIG_GEN instead)
 endif
 
-system_android_filesystem_config := system/core/include/private/android_filesystem_config.h
+system_android_filesystem_config := system/core/libcutils/include/private/android_filesystem_config.h
 system_capability_header := bionic/libc/kernel/uapi/linux/capability.h
 
 # List of supported vendor, oem, odm, vendor_dlkm, odm_dlkm, product and system_ext Partitions
diff --git a/tools/fs_config/README b/tools/fs_config/README
deleted file mode 100644
index 21bdeb8..0000000
--- a/tools/fs_config/README
+++ /dev/null
@@ -1,137 +0,0 @@
- _____  _____  _____  _____  __  __  _____
-/  _  \/   __\/  _  \|  _  \/  \/  \/   __\
-|  _  <|   __||  _  ||  |  ||  \/  ||   __|
-\__|\_/\_____/\__|__/|_____/\__ \__/\_____/
-
-The fs_config_generator.py tool uses the platform android_filesystem_config.h and the
-TARGET_FS_CONFIG_GEN files to generate the fs_config_dirs and fs_config_files files for each
-partition, as well as passwd and group files, and the generated_oem_aid.h header.
-
-The fs_config_dirs and fs_config_files binary files are interpreted by the libcutils fs_config()
-function, along with the built-in defaults, to serve as overrides to complete the results. The
-Target files are used by filesystem and adb tools to ensure that the file and directory properties
-are preserved during runtime operations. The host files in the ${OUT} directory are used in the
-final stages when building the filesystem images to set the file and directory properties.
-
-See ./fs_config_generator.py fsconfig --help for how these files are generated.
-
-The passwd and group files are formatted as documented in man pages passwd(5) and group(5) and used
-by bionic for implementing getpwnam() and related functions.
-
-See ./fs_config_generator.py passwd --help and ./fs_config_generator.py group --help for how these
-files are generated.
-
-The generated_oem_aid.h creates identifiers for non-platform AIDs for developers wishing to use them
-in their native code.  To do so, include the oemaids_headers header library in the corresponding
-makefile and #include "generated_oem_aid.h" in the code wishing to use these identifiers.
-
-See ./fs_config_generator.py oemaid --help for how this file is generated.
-
-The parsing of the TARGET_FS_CONFIG_GEN files follows the Python ConfigParser specification, with
-the sections and fields as defined below. There are two types of sections, both sections require all
-options to be specified. The first section type is the "caps" section.
-
-The "caps" section follows the following syntax:
-
-[path]
-mode: Octal file mode
-user: AID_<user>
-group: AID_<group>
-caps: cap*
-
-Where:
-
-[path]
-  The filesystem path to configure. A path ending in / is considered a dir,
-  else its a file.
-
-mode:
-  A valid octal file mode of at least 3 digits. If 3 is specified, it is
-  prefixed with a 0, else mode is used as is.
-
-user:
-  Either the C define for a valid AID or the friendly name. For instance both
-  AID_RADIO and radio are acceptable. Note custom AIDs can be defined in the
-  AID section documented below.
-
-group:
-  Same as user.
-
-caps:
-  The name as declared in
-  system/core/include/private/android_filesystem_capability.h without the
-  leading CAP_. Mixed case is allowed. Caps can also be the raw:
-   * binary (0b0101)
-   * octal (0455)
-   * int (42)
-   * hex (0xFF)
-  For multiple caps, just separate by whitespace.
-
-It is an error to specify multiple sections with the same [path] in different
-files. Note that the same file may contain sections that override the previous
-section in Python versions <= 3.2. In Python 3.2 it's set to strict mode.
-
-
-The next section type is the "AID" section, for specifying OEM specific AIDS.
-
-The AID section follows the following syntax:
-
-[AID_<name>]
-value: <number>
-
-Where:
-
-[AID_<name>]
-  The <name> can contain characters in the set uppercase, numbers
-  and underscores.
-
-value:
-  A valid C style number string. Hex, octal, binary and decimal are supported.
-  See "caps" above for more details on number formatting.
-
-It is an error to specify multiple sections with the same [AID_<name>]. With
-the same constraints as [path] described above. It is also an error to specify
-multiple sections with the same value option. It is also an error to specify a
-value that is outside of the inclusive OEM ranges:
- * AID_OEM_RESERVED_START(2900) - AID_OEM_RESERVED_END(2999)
- * AID_OEM_RESERVED_2_START(5000) - AID_OEM_RESERVED_2_END(5999)
-
-as defined by system/core/include/private/android_filesystem_config.h.
-
-Ordering within the TARGET_FS_CONFIG_GEN files is not relevant. The paths for files are sorted
-like so within their respective array definition:
- * specified path before prefix match
- ** ie foo before f*
- * lexicographical less than before other
- ** ie boo before foo
-
-Given these paths:
-
-paths=['ac', 'a', 'acd', 'an', 'a*', 'aa', 'ac*']
-
-The sort order would be:
-paths=['a', 'aa', 'ac', 'acd', 'an', 'ac*', 'a*']
-
-Thus the fs_config tools will match on specified paths before attempting prefix, and match on the
-longest matching prefix.
-
-The declared AIDS are sorted in ascending numerical order based on the option "value". The string
-representation of value is preserved. Both choices were made for maximum readability of the generated
-file and to line up files. Sync lines are placed with the source file as comments in the generated
-header file.
-
-Unit Tests:
-
-From within the fs_config directory, unit tests can be executed like so:
-$ python -m unittest test_fs_config_generator.Tests
-.............
-----------------------------------------------------------------------
-Ran 13 tests in 0.004s
-
-OK
-
-One could also use nose if they would like:
-$ nose2
-
-To add new tests, simply add a test_<xxx> method to the test class. It will automatically
-get picked up and added to the test suite.
diff --git a/tools/fs_config/README.md b/tools/fs_config/README.md
new file mode 100644
index 0000000..bad5e10
--- /dev/null
+++ b/tools/fs_config/README.md
@@ -0,0 +1,84 @@
+# FS Config Generator
+
+The `fs_config_generator.py` tool uses the platform `android_filesystem_config.h` and the
+`TARGET_FS_CONFIG_GEN` files to generate the following:
+* `fs_config_dirs` and `fs_config_files` files for each partition
+* `passwd` and `group` files for each partition
+* The `generated_oem_aid.h` header
+
+## Outputs
+
+### `fs_config_dirs` and `fs_config_files`
+
+The `fs_config_dirs` and `fs_config_files` binary files are interpreted by the libcutils
+`fs_config()` function, along with the built-in defaults, to serve as overrides to complete the
+results. The Target files are used by filesystem and adb tools to ensure that the file and directory
+properties are preserved during runtime operations. The host files in the `$OUT` directory are used
+in the final stages when building the filesystem images to set the file and directory properties.
+
+See `./fs_config_generator.py fsconfig --help` for how these files are generated.
+
+### `passwd` and `group` files
+
+The `passwd` and `group` files are formatted as documented in man pages passwd(5) and group(5) and
+used by bionic for implementing `getpwnam()` and related functions.
+
+See `./fs_config_generator.py passwd --help` and `./fs_config_generator.py group --help` for how
+these files are generated.
+
+### The `generated_oem_aid.h` header
+
+The `generated_oem_aid.h` creates identifiers for non-platform AIDs for developers wishing to use
+them in their native code.  To do so, include the `oemaids_headers` header library in the
+corresponding makefile and `#include "generated_oem_aid.h"` in the code wishing to use these
+identifiers.
+
+See `./fs_config_generator.py oemaid --help` for how this file is generated.
+
+## Parsing
+
+See the documentation on [source.android.com](https://source.android.com/devices/tech/config/filesystem#configuring-aids) for details and examples.
+
+
+## Ordering
+
+Ordering within the `TARGET_FS_CONFIG_GEN` files is not relevant. The paths for files are sorted
+like so within their respective array definition:
+ * specified path before prefix match
+   * for example: foo before f*
+ * lexicographical less than before other
+   * for example: boo before foo
+
+Given these paths:
+
+    paths=['ac', 'a', 'acd', 'an', 'a*', 'aa', 'ac*']
+
+The sort order would be:
+
+    paths=['a', 'aa', 'ac', 'acd', 'an', 'ac*', 'a*']
+
+Thus the `fs_config` tools will match on specified paths before attempting prefix, and match on the
+longest matching prefix.
+
+The declared AIDs are sorted in ascending numerical order based on the option "value". The string
+representation of value is preserved. Both choices were made for maximum readability of the
+generated file and to line up files. Sync lines are placed with the source file as comments in the
+generated header file.
+
+## Unit Tests
+
+From within the `fs_config` directory, unit tests can be executed like so:
+
+    $ python -m unittest test_fs_config_generator.Tests
+    .............
+    ----------------------------------------------------------------------
+    Ran 13 tests in 0.004s
+
+    OK
+
+One could also use nose if they would like:
+
+    $ nose2
+
+To add new tests, simply add a `test_<xxx>` method to the test class. It will automatically
+get picked up and added to the test suite.
diff --git a/tools/fs_config/end_to_end_test/run_test.sh b/tools/fs_config/end_to_end_test/run_test.sh
index 7402276..b5a7e83 100755
--- a/tools/fs_config/end_to_end_test/run_test.sh
+++ b/tools/fs_config/end_to_end_test/run_test.sh
@@ -1,7 +1,7 @@
 cd $ANDROID_BUILD_TOP/build/make/tools/fs_config/end_to_end_test
 
 $ANDROID_BUILD_TOP/build/make/tools/fs_config/fs_config_generator.py fsconfig \
-  --aid-header $ANDROID_BUILD_TOP/system/core/include/private/android_filesystem_config.h \
+  --aid-header $ANDROID_BUILD_TOP/system/core/libcutils/include/private/android_filesystem_config.h \
   --capability-header $ANDROID_BUILD_TOP/bionic/libc/kernel/uapi/linux/capability.h \
   --partition system \
   --all-partitions vendor,product \
@@ -13,7 +13,7 @@
   echo 'Fail: Mismatch between system_fs_config_files and result_system_fs_config_files'
 
 $ANDROID_BUILD_TOP/build/make/tools/fs_config/fs_config_generator.py fsconfig \
-  --aid-header $ANDROID_BUILD_TOP/system/core/include/private/android_filesystem_config.h \
+  --aid-header $ANDROID_BUILD_TOP/system/core/libcutils/include/private/android_filesystem_config.h \
   --capability-header $ANDROID_BUILD_TOP/bionic/libc/kernel/uapi/linux/capability.h \
   --partition system \
   --all-partitions vendor,product \
@@ -25,7 +25,7 @@
   echo 'Fail: Mismatch between system_fs_config_dirs and result_system_fs_config_dirs'
 
 $ANDROID_BUILD_TOP/build/make/tools/fs_config/fs_config_generator.py fsconfig \
-  --aid-header $ANDROID_BUILD_TOP/system/core/include/private/android_filesystem_config.h \
+  --aid-header $ANDROID_BUILD_TOP/system/core/libcutils/include/private/android_filesystem_config.h \
   --capability-header $ANDROID_BUILD_TOP/bionic/libc/kernel/uapi/linux/capability.h \
   --partition vendor \
   --files \
@@ -36,7 +36,7 @@
   echo 'Fail: Mismatch between vendor_fs_config_files and result_vendor_fs_config_files'
 
 $ANDROID_BUILD_TOP/build/make/tools/fs_config/fs_config_generator.py fsconfig \
-  --aid-header $ANDROID_BUILD_TOP/system/core/include/private/android_filesystem_config.h \
+  --aid-header $ANDROID_BUILD_TOP/system/core/libcutils/include/private/android_filesystem_config.h \
   --capability-header $ANDROID_BUILD_TOP/bionic/libc/kernel/uapi/linux/capability.h \
   --partition vendor \
   --dirs \
@@ -47,7 +47,7 @@
   echo 'Fail: Mismatch between vendor_fs_config_dirs and result_vendor_fs_config_dirs'
 
 $ANDROID_BUILD_TOP/build/make/tools/fs_config/fs_config_generator.py fsconfig \
-  --aid-header $ANDROID_BUILD_TOP/system/core/include/private/android_filesystem_config.h \
+  --aid-header $ANDROID_BUILD_TOP/system/core/libcutils/include/private/android_filesystem_config.h \
   --capability-header $ANDROID_BUILD_TOP/bionic/libc/kernel/uapi/linux/capability.h \
   --partition product \
   --files \
@@ -58,7 +58,7 @@
   echo 'Fail: Mismatch between product_fs_config_files and result_product_fs_config_files'
 
 $ANDROID_BUILD_TOP/build/make/tools/fs_config/fs_config_generator.py fsconfig \
-  --aid-header $ANDROID_BUILD_TOP/system/core/include/private/android_filesystem_config.h \
+  --aid-header $ANDROID_BUILD_TOP/system/core/libcutils/include/private/android_filesystem_config.h \
   --capability-header $ANDROID_BUILD_TOP/bionic/libc/kernel/uapi/linux/capability.h \
   --partition product \
   --dirs \
diff --git a/tools/mk2bp_catalog.py b/tools/mk2bp_catalog.py
index 83abd62..c2afb9b 100755
--- a/tools/mk2bp_catalog.py
+++ b/tools/mk2bp_catalog.py
@@ -168,22 +168,24 @@
       return True
   return False
 
-def make_annotation_link(annotations, analysis, modules):
-  if analysis:
-    return "<a href='javascript:update_details(%d)'>%s</a>" % (
-      annotations.Add(analysis, modules),
-      len(analysis)
-    )
-  else:
-    return "";
-
-
 def is_clean(makefile):
   for analysis in makefile.analyses.values():
     if analysis:
       return False
   return True
 
+def clean_and_only_blocked_by_clean(soong, all_makefiles, makefile):
+  if not is_clean(makefile):
+    return False
+  modules = soong.reverse_makefiles[makefile.filename]
+  for module in modules:
+    for dep in soong.transitive_deps(module):
+      for filename in soong.makefiles.get(dep, []):
+        m = all_makefiles.get(filename)
+        if m and not is_clean(m):
+          return False
+  return True
+
 class Annotations(object):
   def __init__(self):
     self.entries = []
@@ -205,6 +207,7 @@
     self.makefiles = dict()
     self.reverse_makefiles = dict()
     self.installed = dict()
+    self.reverse_installed = dict()
     self.modules = set()
 
     for (module, module_type, problem, dependencies, makefiles, installed) in reader:
@@ -222,6 +225,29 @@
         self.reverse_makefiles.setdefault(f, []).append(module)
       for f in installed.strip().split(' '):
         self.installed[f] = module
+        self.reverse_installed.setdefault(module, []).append(f)
+
+  def transitive_deps(self, module):
+    results = set()
+    def traverse(module):
+      for dep in self.deps.get(module, []):
+        if not dep in results:
+          results.add(dep)
+          traverse(module)
+    traverse(module)
+    return results
+
+  def contains_unblocked_modules(self, filename):
+    for m in self.reverse_makefiles[filename]:
+      if len(self.deps[m]) == 0:
+        return True
+    return False
+
+  def contains_blocked_modules(self, filename):
+    for m in self.reverse_makefiles[filename]:
+      if len(self.deps[m]) > 0:
+        return True
+    return False
 
 def count_deps(depsdb, module, seen):
   """Based on the depsdb, count the number of transitive dependencies.
@@ -237,18 +263,6 @@
       count += 1 + count_deps(depsdb, dep, seen)
   return count
 
-def contains_unblocked_modules(soong, modules):
-  for m in modules:
-    if len(soong.deps[m]) == 0:
-      return True
-  return False
-
-def contains_blocked_modules(soong, modules):
-  for m in modules:
-    if len(soong.deps[m]) > 0:
-      return True
-  return False
-
 OTHER_PARTITON = "_other"
 HOST_PARTITON = "_host"
 
@@ -273,6 +287,27 @@
 def format_module_list(modules):
   return "".join(["<div>%s</div>" % format_module_link(m) for m in modules])
 
+def print_analysis_header(link, title):
+  print("""
+    <a name="%(link)s"></a>
+    <h2>%(title)s</h2>
+    <table>
+      <tr>
+        <th class="RowTitle">Directory</th>
+        <th class="Count">Total</th>
+        <th class="Count Clean">Easy</th>
+        <th class="Count Clean">Unblocked Clean</th>
+        <th class="Count Unblocked">Unblocked</th>
+        <th class="Count Blocked">Blocked</th>
+        <th class="Count Clean">Clean</th>
+  """ % {
+    "link": link,
+    "title": title
+  })
+  for analyzer in ANALYZERS:
+    print("""<th class="Count Warning">%s</th>""" % analyzer.title)
+  print("      </tr>")
+
 def main():
   parser = argparse.ArgumentParser(description="Info about remaining Android.mk files.")
   parser.add_argument("--device", type=str, required=True,
@@ -287,6 +322,9 @@
                       help="Equivalent of $OUT_DIR, which will also be checked if"
                         + " --out_dir is unset. If neither is set, default is"
                         + " 'out'.")
+  parser.add_argument("--mode", type=str,
+                      default="html",
+                      help="output format: csv or html")
 
   args = parser.parse_args()
 
@@ -297,14 +335,11 @@
     args.out_dir = args.out_dir[:-1]
 
   TARGET_DEVICE = args.device
-  HOST_OUT_ROOT = args.out_dir + "host"
+  global HOST_OUT_ROOT
+  HOST_OUT_ROOT = args.out_dir + "/host"
+  global PRODUCT_OUT
   PRODUCT_OUT = args.out_dir + "/target/product/%s" % TARGET_DEVICE
 
-  if args.title:
-    page_title = args.title
-  else:
-    page_title = "Remaining Android.mk files"
-
   # Read target information
   # TODO: Pull from configurable location. This is also slightly different because it's
   # only a single build, where as the tree scanning we do below is all Android.mk files.
@@ -312,580 +347,688 @@
       % PRODUCT_OUT, "r", errors="ignore") as csvfile:
     soong = SoongData(csv.reader(csvfile))
 
-  # Which modules are installed where
-  modules_by_partition = dict()
-  partitions = set()
-  for installed, module in soong.installed.items():
-    partition = get_partition_from_installed(HOST_OUT_ROOT, PRODUCT_OUT, installed)
-    modules_by_partition.setdefault(partition, []).append(module)
-    partitions.add(partition)
+  # Read the makefiles
+  all_makefiles = dict()
+  for filename, modules in soong.reverse_makefiles.items():
+    if filename.startswith(args.out_dir + "/"):
+      continue
+    all_makefiles[filename] = Makefile(filename)
 
-  print("""
-  <html>
-    <head>
-      <title>%(page_title)s</title>
-      <style type="text/css">
-        body, table {
-          font-family: Roboto, sans-serif;
-          font-size: 9pt;
-        }
-        body {
-          margin: 0;
-          padding: 0;
-          display: flex;
-          flex-direction: column;
-          height: 100vh;
-        }
-        #container {
-          flex: 1;
-          display: flex;
-          flex-direction: row;
-          overflow: hidden;
-        }
-        #tables {
-          padding: 0 20px 0 20px;
-          overflow: scroll;
-          flex: 2 2 600px;
-        }
-        #details {
-          display: none;
-          overflow: scroll;
-          flex: 1 1 650px;
-          padding: 0 20px 0 20px;
-        }
-        h1 {
-          margin: 16px 0 16px 20px;
-        }
-        h2 {
-          margin: 12px 0 4px 0;
-        }
-        .DirName {
-          text-align: left;
-          width: 200px;
-          min-width: 200px;
-        }
-        .Count {
-          text-align: center;
-          width: 60px;
-          min-width: 60px;
-          max-width: 60px;
-        }
-        th.Clean,
-        th.Unblocked {
-          background-color: #1e8e3e;
-        }
-        th.Blocked {
-          background-color: #d93025;
-        }
-        th.Warning {
-          background-color: #e8710a;
-        }
-        th {
-          background-color: #1a73e8;
-          color: white;
-          font-weight: bold;
-        }
-        td.Unblocked {
-          background-color: #81c995;
-        }
-        td.Blocked {
-          background-color: #f28b82;
-        }
-        td, th {
-          padding: 2px 4px;
-          border-right: 2px solid white;
-        }
-        tr.AospDir td {
-          background-color: #e6f4ea;
-          border-right-color: #e6f4ea;
-        }
-        tr.GoogleDir td {
-          background-color: #e8f0fe;
-          border-right-color: #e8f0fe;
-        }
-        tr.PartnerDir td {
-          background-color: #fce8e6;
-          border-right-color: #fce8e6;
-        }
-        table {
-          border-spacing: 0;
-          border-collapse: collapse;
-        }
-        div.Makefile {
-          margin: 12px 0 0 0;
-        }
-        div.Makefile:first {
-          margin-top: 0;
-        }
-        div.FileModules {
-          padding: 4px 0 0 20px;
-        }
-        td.LineNo {
-          vertical-align: baseline;
-          padding: 6px 0 0 20px;
-          width: 50px;
-          vertical-align: baseline;
-        }
-        td.LineText {
-          vertical-align: baseline;
-          font-family: monospace;
-          padding: 6px 0 0 0;
-        }
-        a.CsLink {
-          font-family: monospace;
-        }
-        div.Help {
-          width: 550px;
-        }
-        table.HelpColumns tr {
-          border-bottom: 2px solid white;
-        }
-        .ModuleName {
-          vertical-align: baseline;
-          padding: 6px 0 0 20px;
-          width: 275px;
-        }
-        .ModuleDeps {
-          vertical-align: baseline;
-          padding: 6px 0 0 0;
-        }
-        table#Modules td {
-          vertical-align: baseline;
-        }
-        tr.Alt {
-          background-color: #ececec;
-        }
-        tr.Alt td {
-          border-right-color: #ececec;
-        }
-        .AnalysisCol {
-          width: 300px;
-          padding: 2px;
-          line-height: 21px;
-        }
-        .Analysis {
-          color: white;
-          font-weight: bold;
-          background-color: #e8710a;
-          border-radius: 6px;
-          margin: 4px;
-          padding: 2px 6px;
-          white-space: nowrap;
-        }
-        .Nav {
-          margin: 4px 0 16px 20px;
-        }
-        .NavSpacer {
-          display: inline-block;
-          width: 6px;
-        }
-        .ModuleDetails {
-          margin-top: 20px;
-        }
-        .ModuleDetails td {
-          vertical-align: baseline;
-        }
-      </style>
-    </head>
-    <body>
-      <h1>%(page_title)s</h1>
-      <div class="Nav">
-        <a href='#help'>Help</a>
-        <span class='NavSpacer'></span><span class='NavSpacer'> </span>
-        Partitions:
-  """ % {
-    "page_title": page_title,
-  })
-  for partition in sorted(partitions):
-    print("<a href='#partition_%s'>%s</a><span class='NavSpacer'></span>" % (partition, partition))
+  if args.mode == "html":
+    HtmlProcessor(args=args, soong=soong, all_makefiles=all_makefiles).execute()
+  elif args.mode == "csv":
+    CsvProcessor(args=args, soong=soong, all_makefiles=all_makefiles).execute()
 
-  print("""
-        <span class='NavSpacer'></span><span class='NavSpacer'> </span>
-      </div>
-      <div id="container">
-        <div id="tables">
-        <a name="help"></a>
-        <div class="Help">
-          <p>
-          This page analyzes the remaining Android.mk files in the Android Source tree.
-          <p>
-          The modules are first broken down by which of the device filesystem partitions
-          they are installed to. This also includes host tools and testcases which don't
-          actually reside in their own partition but convenitely group together.
-          <p>
-          The makefiles for each partition are further are grouped into a set of directories
-          aritrarily picked to break down the problem size by owners.
-          <ul style="width: 300px">
-            <li style="background-color: #e6f4ea">AOSP directories are colored green.</li>
-            <li style="background-color: #e8f0fe">Google directories are colored blue.</li>
-            <li style="background-color: #fce8e6">Other partner directories are colored red.</li>
-          </ul>
-          Each of the makefiles are scanned for issues that are likely to come up during
-          conversion to soong.  Clicking the number in each cell shows additional information,
-          including the line that triggered the warning.
-          <p>
-          <table class="HelpColumns">
-            <tr>
-              <th>Total</th>
-              <td>The total number of makefiles in this each directory.</td>
-            </tr>
-            <tr>
-              <th class="Unblocked">Unblocked</th>
-              <td>Makefiles containing one or more modules that don't have any
-                  additional dependencies pending before conversion.</td>
-            </tr>
-            <tr>
-              <th class="Blocked">Blocked</th>
-              <td>Makefiles containiong one or more modules which <i>do</i> have
-                  additional prerequesite depenedencies that are not yet converted.</td>
-            </tr>
-            <tr>
-              <th class="Clean">Clean</th>
-              <td>The number of makefiles that have none of the following warnings.</td>
-            </tr>
-            <tr>
-              <th class="Warning">ifeq / ifneq</th>
-              <td>Makefiles that use <code>ifeq</code> or <code>ifneq</code>. i.e.
-              conditionals.</td>
-            </tr>
-            <tr>
-              <th class="Warning">Wacky Includes</th>
-              <td>Makefiles that <code>include</code> files other than the standard build-system
-                  defined template and macros.</td>
-            </tr>
-            <tr>
-              <th class="Warning">Calls base_rules</th>
-              <td>Makefiles that include base_rules.mk directly.</td>
-            </tr>
-            <tr>
-              <th class="Warning">Calls define</th>
-              <td>Makefiles that define their own macros. Some of these are easy to convert
-                  to soong <code>defaults</code>, but others are complex.</td>
-            </tr>
-            <tr>
-              <th class="Warning">Has ../</th>
-              <td>Makefiles containing the string "../" outside of a comment. These likely
-                  access files outside their directories.</td>
-            </tr>
-            <tr>
-              <th class="Warning">dist-for-goals</th>
-              <td>Makefiles that call <code>dist-for-goals</code> directly.</td>
-            </tr>
-            <tr>
-              <th class="Warning">.PHONY</th>
-              <td>Makefiles that declare .PHONY targets.</td>
-            </tr>
-            <tr>
-              <th class="Warning">renderscript</th>
-              <td>Makefiles defining targets that depend on <code>.rscript</code> source files.</td>
-            </tr>
-            <tr>
-              <th class="Warning">vts src</th>
-              <td>Makefiles defining targets that depend on <code>.vts</code> source files.</td>
-            </tr>
-            <tr>
-              <th class="Warning">COPY_HEADERS</th>
-              <td>Makefiles using LOCAL_COPY_HEADERS.</td>
-            </tr>
-          </table>
-          <p>
-          Following the list of directories is a list of the modules that are installed on
-          each partition. Potential issues from their makefiles are listed, as well as the
-          total number of dependencies (both blocking that module and blocked by that module)
-          and the list of direct dependencies.  Note: The number is the number of all transitive
-          dependencies and the list of modules is only the direct dependencies.
-        </div>
-  """)
+class HtmlProcessor(object):
+  def __init__(self, args, soong, all_makefiles):
+    self.args = args
+    self.soong = soong
+    self.all_makefiles = all_makefiles
+    self.annotations = Annotations()
 
-  annotations = Annotations()
+  def execute(self):
+    if self.args.title:
+      page_title = self.args.title
+    else:
+      page_title = "Remaining Android.mk files"
 
-  # For each partition
-  makefiles_for_partitions = dict()
-  for partition in sorted(partitions):
-    modules = modules_by_partition[partition]
-
-    makefiles = set(itertools.chain.from_iterable(
-        [soong.makefiles[module] for module in modules]))
-
-    # Read makefiles
-    summary = Summary()
-    for filename in makefiles:
-      if not filename.startswith(args.out_dir + "/"):
-        summary.Add(Makefile(filename))
-
-    # Categorize directories by who is responsible
-    aosp_dirs = []
-    google_dirs = []
-    partner_dirs = []
-    for dirname in sorted(summary.directories.keys()):
-      if is_aosp(dirname):
-        aosp_dirs.append(dirname)
-      elif is_google(dirname):
-        google_dirs.append(dirname)
-      else:
-        partner_dirs.append(dirname)
+    # Which modules are installed where
+    modules_by_partition = dict()
+    partitions = set()
+    for installed, module in self.soong.installed.items():
+      partition = get_partition_from_installed(HOST_OUT_ROOT, PRODUCT_OUT, installed)
+      modules_by_partition.setdefault(partition, []).append(module)
+      partitions.add(partition)
 
     print("""
-      <a name="partition_%(partition)s"></a>
-      <h2>%(partition)s</h2>
-      <table>
-        <tr>
-          <th class="DirName">Directory</th>
-          <th class="Count">Total</th>
-          <th class="Count Unblocked">Unblocked</th>
-          <th class="Count Blocked">Blocked</th>
-          <th class="Count Clean">Clean</th>
+    <html>
+      <head>
+        <title>%(page_title)s</title>
+        <style type="text/css">
+          body, table {
+            font-family: Roboto, sans-serif;
+            font-size: 9pt;
+          }
+          body {
+            margin: 0;
+            padding: 0;
+            display: flex;
+            flex-direction: column;
+            height: 100vh;
+          }
+          #container {
+            flex: 1;
+            display: flex;
+            flex-direction: row;
+            overflow: hidden;
+          }
+          #tables {
+            padding: 0 20px 40px 20px;
+            overflow: scroll;
+            flex: 2 2 600px;
+          }
+          #details {
+            display: none;
+            overflow: scroll;
+            flex: 1 1 650px;
+            padding: 0 20px 0 20px;
+          }
+          h1 {
+            margin: 16px 0 16px 20px;
+          }
+          h2 {
+            margin: 12px 0 4px 0;
+          }
+          .RowTitle {
+            text-align: left;
+            width: 200px;
+            min-width: 200px;
+          }
+          .Count {
+            text-align: center;
+            width: 60px;
+            min-width: 60px;
+            max-width: 60px;
+          }
+          th.Clean,
+          th.Unblocked {
+            background-color: #1e8e3e;
+          }
+          th.Blocked {
+            background-color: #d93025;
+          }
+          th.Warning {
+            background-color: #e8710a;
+          }
+          th {
+            background-color: #1a73e8;
+            color: white;
+            font-weight: bold;
+          }
+          td.Unblocked {
+            background-color: #81c995;
+          }
+          td.Blocked {
+            background-color: #f28b82;
+          }
+          td, th {
+            padding: 2px 4px;
+            border-right: 2px solid white;
+          }
+          tr.TotalRow td {
+            background-color: white;
+            border-right-color: white;
+          }
+          tr.AospDir td {
+            background-color: #e6f4ea;
+            border-right-color: #e6f4ea;
+          }
+          tr.GoogleDir td {
+            background-color: #e8f0fe;
+            border-right-color: #e8f0fe;
+          }
+          tr.PartnerDir td {
+            background-color: #fce8e6;
+            border-right-color: #fce8e6;
+          }
+          table {
+            border-spacing: 0;
+            border-collapse: collapse;
+          }
+          div.Makefile {
+            margin: 12px 0 0 0;
+          }
+          div.Makefile:first {
+            margin-top: 0;
+          }
+          div.FileModules {
+            padding: 4px 0 0 20px;
+          }
+          td.LineNo {
+            vertical-align: baseline;
+            padding: 6px 0 0 20px;
+            width: 50px;
+            vertical-align: baseline;
+          }
+          td.LineText {
+            vertical-align: baseline;
+            font-family: monospace;
+            padding: 6px 0 0 0;
+          }
+          a.CsLink {
+            font-family: monospace;
+          }
+          div.Help {
+            width: 550px;
+          }
+          table.HelpColumns tr {
+            border-bottom: 2px solid white;
+          }
+          .ModuleName {
+            vertical-align: baseline;
+            padding: 6px 0 0 20px;
+            width: 275px;
+          }
+          .ModuleDeps {
+            vertical-align: baseline;
+            padding: 6px 0 0 0;
+          }
+          table#Modules td {
+            vertical-align: baseline;
+          }
+          tr.Alt {
+            background-color: #ececec;
+          }
+          tr.Alt td {
+            border-right-color: #ececec;
+          }
+          .AnalysisCol {
+            width: 300px;
+            padding: 2px;
+            line-height: 21px;
+          }
+          .Analysis {
+            color: white;
+            font-weight: bold;
+            background-color: #e8710a;
+            border-radius: 6px;
+            margin: 4px;
+            padding: 2px 6px;
+            white-space: nowrap;
+          }
+          .Nav {
+            margin: 4px 0 16px 20px;
+          }
+          .NavSpacer {
+            display: inline-block;
+            width: 6px;
+          }
+          .ModuleDetails {
+            margin-top: 20px;
+          }
+          .ModuleDetails td {
+            vertical-align: baseline;
+          }
+        </style>
+      </head>
+      <body>
+        <h1>%(page_title)s</h1>
+        <div class="Nav">
+          <a href='#help'>Help</a>
+          <span class='NavSpacer'></span><span class='NavSpacer'> </span>
+          Partitions:
     """ % {
-      "partition": partition
+      "page_title": page_title,
     })
+    for partition in sorted(partitions):
+      print("<a href='#partition_%s'>%s</a><span class='NavSpacer'></span>" % (partition, partition))
 
-    for analyzer in ANALYZERS:
-      print("""<th class="Count Warning">%s</th>""" % analyzer.title)
-
-    print("      </tr>")
-    for dirgroup, rowclass in [(aosp_dirs, "AospDir"),
-                               (google_dirs, "GoogleDir"),
-                               (partner_dirs, "PartnerDir"),]:
-      for dirname in dirgroup:
-        makefiles = summary.directories[dirname]
-
-        all_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles]
-        clean_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
-            if is_clean(makefile)]
-        unblocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
-            if contains_unblocked_modules(soong,
-              soong.reverse_makefiles[makefile.filename])]
-        blocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
-            if contains_blocked_modules(soong,
-              soong.reverse_makefiles[makefile.filename])]
-
-        print("""
-          <tr class="%(rowclass)s">
-            <td class="DirName">%(dirname)s</td>
-            <td class="Count">%(makefiles)s</td>
-            <td class="Count">%(unblocked)s</td>
-            <td class="Count">%(blocked)s</td>
-            <td class="Count">%(clean)s</td>
-        """ % {
-          "rowclass": rowclass,
-          "dirname": dirname,
-          "makefiles": make_annotation_link(annotations, all_makefiles, modules),
-          "unblocked": make_annotation_link(annotations, unblocked_makefiles, modules),
-          "blocked": make_annotation_link(annotations, blocked_makefiles, modules),
-          "clean": make_annotation_link(annotations, clean_makefiles, modules),
-        })
-        for analyzer in ANALYZERS:
-          analyses = [m.analyses.get(analyzer) for m in makefiles if m.analyses.get(analyzer)]
-          print("""<td class="Count">%s</td>"""
-              % make_annotation_link(annotations, analyses, modules))
-
-        print("      </tr>")
     print("""
-      </table>
+          <span class='NavSpacer'></span><span class='NavSpacer'> </span>
+          <a href='#summary'>Overall Summary</a>
+        </div>
+        <div id="container">
+          <div id="tables">
+          <a name="help"></a>
+          <div class="Help">
+            <p>
+            This page analyzes the remaining Android.mk files in the Android Source tree.
+            <p>
+            The modules are first broken down by which of the device filesystem partitions
+            they are installed to. This also includes host tools and testcases which don't
+            actually reside in their own partition but convenitely group together.
+            <p>
+            The makefiles for each partition are further are grouped into a set of directories
+            aritrarily picked to break down the problem size by owners.
+            <ul style="width: 300px">
+              <li style="background-color: #e6f4ea">AOSP directories are colored green.</li>
+              <li style="background-color: #e8f0fe">Google directories are colored blue.</li>
+              <li style="background-color: #fce8e6">Other partner directories are colored red.</li>
+            </ul>
+            Each of the makefiles are scanned for issues that are likely to come up during
+            conversion to soong.  Clicking the number in each cell shows additional information,
+            including the line that triggered the warning.
+            <p>
+            <table class="HelpColumns">
+              <tr>
+                <th>Total</th>
+                <td>The total number of makefiles in this each directory.</td>
+              </tr>
+              <tr>
+                <th class="Clean">Easy</th>
+                <td>The number of makefiles that have no warnings themselves, and also
+                    none of their dependencies have warnings either.</td>
+              </tr>
+              <tr>
+                <th class="Clean">Unblocked Clean</th>
+                <td>The number of makefiles that are both Unblocked and Clean.</td>
+              </tr>
+
+              <tr>
+                <th class="Unblocked">Unblocked</th>
+                <td>Makefiles containing one or more modules that don't have any
+                    additional dependencies pending before conversion.</td>
+              </tr>
+              <tr>
+                <th class="Blocked">Blocked</th>
+                <td>Makefiles containiong one or more modules which <i>do</i> have
+                    additional prerequesite depenedencies that are not yet converted.</td>
+              </tr>
+              <tr>
+                <th class="Clean">Clean</th>
+                <td>The number of makefiles that have none of the following warnings.</td>
+              </tr>
+              <tr>
+                <th class="Warning">ifeq / ifneq</th>
+                <td>Makefiles that use <code>ifeq</code> or <code>ifneq</code>. i.e.
+                conditionals.</td>
+              </tr>
+              <tr>
+                <th class="Warning">Wacky Includes</th>
+                <td>Makefiles that <code>include</code> files other than the standard build-system
+                    defined template and macros.</td>
+              </tr>
+              <tr>
+                <th class="Warning">Calls base_rules</th>
+                <td>Makefiles that include base_rules.mk directly.</td>
+              </tr>
+              <tr>
+                <th class="Warning">Calls define</th>
+                <td>Makefiles that define their own macros. Some of these are easy to convert
+                    to soong <code>defaults</code>, but others are complex.</td>
+              </tr>
+              <tr>
+                <th class="Warning">Has ../</th>
+                <td>Makefiles containing the string "../" outside of a comment. These likely
+                    access files outside their directories.</td>
+              </tr>
+              <tr>
+                <th class="Warning">dist-for-goals</th>
+                <td>Makefiles that call <code>dist-for-goals</code> directly.</td>
+              </tr>
+              <tr>
+                <th class="Warning">.PHONY</th>
+                <td>Makefiles that declare .PHONY targets.</td>
+              </tr>
+              <tr>
+                <th class="Warning">renderscript</th>
+                <td>Makefiles defining targets that depend on <code>.rscript</code> source files.</td>
+              </tr>
+              <tr>
+                <th class="Warning">vts src</th>
+                <td>Makefiles defining targets that depend on <code>.vts</code> source files.</td>
+              </tr>
+              <tr>
+                <th class="Warning">COPY_HEADERS</th>
+                <td>Makefiles using LOCAL_COPY_HEADERS.</td>
+              </tr>
+            </table>
+            <p>
+            Following the list of directories is a list of the modules that are installed on
+            each partition. Potential issues from their makefiles are listed, as well as the
+            total number of dependencies (both blocking that module and blocked by that module)
+            and the list of direct dependencies.  Note: The number is the number of all transitive
+            dependencies and the list of modules is only the direct dependencies.
+          </div>
     """)
 
-    module_details = [(count_deps(soong.deps, m, []), -count_deps(soong.reverse_deps, m, []), m)
-               for m in modules]
-    module_details.sort()
-    module_details = [m[2] for m in module_details]
-    print("""
-      <table class="ModuleDetails">""")
-    print("<tr>")
-    print("  <th>Module Name</th>")
-    print("  <th>Issues</th>")
-    print("  <th colspan='2'>Blocked By</th>")
-    print("  <th colspan='2'>Blocking</th>")
-    print("</tr>")
-    altRow = True
-    for module in module_details:
-      analyses = set()
-      for filename in soong.makefiles[module]:
-        makefile = summary.makefiles.get(filename)
+    overall_summary = Summary()
+
+    # For each partition
+    for partition in sorted(partitions):
+      modules = modules_by_partition[partition]
+
+      makefiles = set(itertools.chain.from_iterable(
+          [self.soong.makefiles[module] for module in modules]))
+
+      # Read makefiles
+      summary = Summary()
+      for filename in makefiles:
+        makefile = self.all_makefiles.get(filename)
         if makefile:
-          for analyzer, analysis in makefile.analyses.items():
-            if analysis:
-              analyses.add(analyzer.title)
+          summary.Add(makefile)
+          overall_summary.Add(makefile)
 
-      altRow = not altRow
-      print("<tr class='%s'>" % ("Alt" if altRow else "",))
-      print("  <td><a name='module_%s'></a>%s</td>" % (module, module))
-      print("  <td class='AnalysisCol'>%s</td>" % " ".join(["<span class='Analysis'>%s</span>" % title
-          for title in analyses]))
-      print("  <td>%s</td>" % count_deps(soong.deps, module, []))
-      print("  <td>%s</td>" % format_module_list(soong.deps.get(module, [])))
-      print("  <td>%s</td>" % count_deps(soong.reverse_deps, module, []))
-      print("  <td>%s</td>" % format_module_list(soong.reverse_deps.get(module, [])))
+      # Categorize directories by who is responsible
+      aosp_dirs = []
+      google_dirs = []
+      partner_dirs = []
+      for dirname in sorted(summary.directories.keys()):
+        if is_aosp(dirname):
+          aosp_dirs.append(dirname)
+        elif is_google(dirname):
+          google_dirs.append(dirname)
+        else:
+          partner_dirs.append(dirname)
+
+      print_analysis_header("partition_" + partition, partition)
+
+      for dirgroup, rowclass in [(aosp_dirs, "AospDir"),
+                                 (google_dirs, "GoogleDir"),
+                                 (partner_dirs, "PartnerDir"),]:
+        for dirname in dirgroup:
+          self.print_analysis_row(summary, modules,
+                               dirname, rowclass, summary.directories[dirname])
+
+      self.print_analysis_row(summary, modules,
+                           "Total", "TotalRow",
+                           set(itertools.chain.from_iterable(summary.directories.values())))
+      print("""
+        </table>
+      """)
+
+      module_details = [(count_deps(self.soong.deps, m, []),
+                         -count_deps(self.soong.reverse_deps, m, []), m)
+                 for m in modules]
+      module_details.sort()
+      module_details = [m[2] for m in module_details]
+      print("""
+        <table class="ModuleDetails">""")
+      print("<tr>")
+      print("  <th>Module Name</th>")
+      print("  <th>Issues</th>")
+      print("  <th colspan='2'>Blocked By</th>")
+      print("  <th colspan='2'>Blocking</th>")
       print("</tr>")
-    print("""</table>""")
+      altRow = True
+      for module in module_details:
+        analyses = set()
+        for filename in self.soong.makefiles[module]:
+          makefile = summary.makefiles.get(filename)
+          if makefile:
+            for analyzer, analysis in makefile.analyses.items():
+              if analysis:
+                analyses.add(analyzer.title)
 
-  print("""
-    <script type="text/javascript">
-    function close_details() {
-      document.getElementById('details').style.display = 'none';
-    }
+        altRow = not altRow
+        print("<tr class='%s'>" % ("Alt" if altRow else "",))
+        print("  <td><a name='module_%s'></a>%s</td>" % (module, module))
+        print("  <td class='AnalysisCol'>%s</td>" % " ".join(["<span class='Analysis'>%s</span>" % title
+            for title in analyses]))
+        print("  <td>%s</td>" % count_deps(self.soong.deps, module, []))
+        print("  <td>%s</td>" % format_module_list(self.soong.deps.get(module, [])))
+        print("  <td>%s</td>" % count_deps(self.soong.reverse_deps, module, []))
+        print("  <td>%s</td>" % format_module_list(self.soong.reverse_deps.get(module, [])))
+        print("</tr>")
+      print("""</table>""")
 
-    class LineMatch {
-      constructor(lineno, text) {
-        this.lineno = lineno;
-        this.text = text;
-      }
-    }
+    print_analysis_header("summary", "Overall Summary")
 
-    class Analysis {
-      constructor(filename, modules, line_matches) {
-        this.filename = filename;
-        this.modules = modules;
-        this.line_matches = line_matches;
-      }
-    }
+    modules = [module for installed, module in self.soong.installed.items()]
+    self.print_analysis_row(overall_summary, modules,
+                         "All Makefiles", "TotalRow",
+                         set(itertools.chain.from_iterable(overall_summary.directories.values())))
+    print("""
+        </table>
+    """)
 
-    class Module {
-      constructor(deps) {
-        this.deps = deps;
-      }
-    }
-
-    function make_module_link(module) {
-      var a = document.createElement('a');
-      a.className = 'ModuleLink';
-      a.innerText = module;
-      a.href = '#module_' + module;
-      return a;
-    }
-
-    function update_details(id) {
-      document.getElementById('details').style.display = 'block';
-
-      var analyses = ANALYSIS[id];
-
-      var details = document.getElementById("details_data");
-      while (details.firstChild) {
-          details.removeChild(details.firstChild);
+    print("""
+      <script type="text/javascript">
+      function close_details() {
+        document.getElementById('details').style.display = 'none';
       }
 
-      for (var i=0; i<analyses.length; i++) {
-        var analysis = analyses[i];
+      class LineMatch {
+        constructor(lineno, text) {
+          this.lineno = lineno;
+          this.text = text;
+        }
+      }
 
-        var makefileDiv = document.createElement('div');
-        makefileDiv.className = 'Makefile';
-        details.appendChild(makefileDiv);
+      class Analysis {
+        constructor(filename, modules, line_matches) {
+          this.filename = filename;
+          this.modules = modules;
+          this.line_matches = line_matches;
+        }
+      }
 
-        var fileA = document.createElement('a');
-        makefileDiv.appendChild(fileA);
-        fileA.className = 'CsLink';
-        fileA.href = '%(codesearch)s' + analysis.filename;
-        fileA.innerText = analysis.filename;
-        fileA.target = "_blank";
+      class Module {
+        constructor(deps) {
+          this.deps = deps;
+        }
+      }
 
-        if (analysis.modules.length > 0) {
-          var moduleTable = document.createElement('table');
-          details.appendChild(moduleTable);
+      function make_module_link(module) {
+        var a = document.createElement('a');
+        a.className = 'ModuleLink';
+        a.innerText = module;
+        a.href = '#module_' + module;
+        return a;
+      }
 
-          for (var j=0; j<analysis.modules.length; j++) {
-            var moduleRow = document.createElement('tr');
-            moduleTable.appendChild(moduleRow);
+      function update_details(id) {
+        document.getElementById('details').style.display = 'block';
 
-            var moduleNameCell = document.createElement('td');
-            moduleRow.appendChild(moduleNameCell);
-            moduleNameCell.className = 'ModuleName';
-            moduleNameCell.appendChild(make_module_link(analysis.modules[j]));
+        var analyses = ANALYSIS[id];
 
-            var moduleData = MODULE_DATA[analysis.modules[j]];
-            console.log(moduleData);
+        var details = document.getElementById("details_data");
+        while (details.firstChild) {
+            details.removeChild(details.firstChild);
+        }
 
-            var depCell = document.createElement('td');
-            moduleRow.appendChild(depCell);
+        for (var i=0; i<analyses.length; i++) {
+          var analysis = analyses[i];
 
-            if (moduleData.deps.length == 0) {
-              depCell.className = 'ModuleDeps Unblocked';
-              depCell.innerText = 'UNBLOCKED';
-            } else {
-              depCell.className = 'ModuleDeps Blocked';
+          var makefileDiv = document.createElement('div');
+          makefileDiv.className = 'Makefile';
+          details.appendChild(makefileDiv);
 
-              for (var k=0; k<moduleData.deps.length; k++) {
-                depCell.appendChild(make_module_link(moduleData.deps[k]));
-                depCell.appendChild(document.createElement('br'));
+          var fileA = document.createElement('a');
+          makefileDiv.appendChild(fileA);
+          fileA.className = 'CsLink';
+          fileA.href = '%(codesearch)s' + analysis.filename;
+          fileA.innerText = analysis.filename;
+          fileA.target = "_blank";
+
+          if (analysis.modules.length > 0) {
+            var moduleTable = document.createElement('table');
+            details.appendChild(moduleTable);
+
+            for (var j=0; j<analysis.modules.length; j++) {
+              var moduleRow = document.createElement('tr');
+              moduleTable.appendChild(moduleRow);
+
+              var moduleNameCell = document.createElement('td');
+              moduleRow.appendChild(moduleNameCell);
+              moduleNameCell.className = 'ModuleName';
+              moduleNameCell.appendChild(make_module_link(analysis.modules[j]));
+
+              var moduleData = MODULE_DATA[analysis.modules[j]];
+              console.log(moduleData);
+
+              var depCell = document.createElement('td');
+              moduleRow.appendChild(depCell);
+
+              if (moduleData.deps.length == 0) {
+                depCell.className = 'ModuleDeps Unblocked';
+                depCell.innerText = 'UNBLOCKED';
+              } else {
+                depCell.className = 'ModuleDeps Blocked';
+
+                for (var k=0; k<moduleData.deps.length; k++) {
+                  depCell.appendChild(make_module_link(moduleData.deps[k]));
+                  depCell.appendChild(document.createElement('br'));
+                }
               }
             }
           }
-        }
 
-        if (analysis.line_matches.length > 0) {
-          var lineTable = document.createElement('table');
-          details.appendChild(lineTable);
+          if (analysis.line_matches.length > 0) {
+            var lineTable = document.createElement('table');
+            details.appendChild(lineTable);
 
-          for (var j=0; j<analysis.line_matches.length; j++) {
-            var line_match = analysis.line_matches[j];
+            for (var j=0; j<analysis.line_matches.length; j++) {
+              var line_match = analysis.line_matches[j];
 
-            var lineRow = document.createElement('tr');
-            lineTable.appendChild(lineRow);
+              var lineRow = document.createElement('tr');
+              lineTable.appendChild(lineRow);
 
-            var linenoCell = document.createElement('td');
-            lineRow.appendChild(linenoCell);
-            linenoCell.className = 'LineNo';
+              var linenoCell = document.createElement('td');
+              lineRow.appendChild(linenoCell);
+              linenoCell.className = 'LineNo';
 
-            var linenoA = document.createElement('a');
-            linenoCell.appendChild(linenoA);
-            linenoA.className = 'CsLink';
-            linenoA.href = '%(codesearch)s' + analysis.filename
-                + ';l=' + line_match.lineno;
-            linenoA.innerText = line_match.lineno;
-            linenoA.target = "_blank";
+              var linenoA = document.createElement('a');
+              linenoCell.appendChild(linenoA);
+              linenoA.className = 'CsLink';
+              linenoA.href = '%(codesearch)s' + analysis.filename
+                  + ';l=' + line_match.lineno;
+              linenoA.innerText = line_match.lineno;
+              linenoA.target = "_blank";
 
-            var textCell = document.createElement('td');
-            lineRow.appendChild(textCell);
-            textCell.className = 'LineText';
-            textCell.innerText = line_match.text;
+              var textCell = document.createElement('td');
+              lineRow.appendChild(textCell);
+              textCell.className = 'LineText';
+              textCell.innerText = line_match.text;
+            }
           }
         }
       }
-    }
 
-    var ANALYSIS = [
-    """ % {
-        "codesearch": args.codesearch,
-    })
-  for entry, mods in annotations.entries:
-    print("  [")
-    for analysis in entry:
-      print("    new Analysis('%(filename)s', %(modules)s, [%(line_matches)s])," % {
-        "filename": analysis.filename,
-        #"modules": json.dumps([m for m in mods if m in filename in soong.makefiles[m]]),
-        "modules": json.dumps(
-            [m for m in soong.reverse_makefiles[analysis.filename] if m in mods]),
-        "line_matches": ", ".join([
-            "new LineMatch(%d, %s)" % (lineno, json.dumps(text))
-            for lineno, text in analysis.line_matches]),
+      var ANALYSIS = [
+      """ % {
+          "codesearch": self.args.codesearch,
       })
-    print("  ],")
-  print("""
-    ];
-    var MODULE_DATA = {
-  """)
-  for module in soong.modules:
-    print("      '%(name)s': new Module(%(deps)s)," % {
-      "name": module,
-      "deps": json.dumps(soong.deps[module]),
-    })
-  print("""
-    };
-    </script>
+    for entry, mods in self.annotations.entries:
+      print("  [")
+      for analysis in entry:
+        print("    new Analysis('%(filename)s', %(modules)s, [%(line_matches)s])," % {
+          "filename": analysis.filename,
+          #"modules": json.dumps([m for m in mods if m in filename in self.soong.makefiles[m]]),
+          "modules": json.dumps(
+              [m for m in self.soong.reverse_makefiles[analysis.filename] if m in mods]),
+          "line_matches": ", ".join([
+              "new LineMatch(%d, %s)" % (lineno, json.dumps(text))
+              for lineno, text in analysis.line_matches]),
+        })
+      print("  ],")
+    print("""
+      ];
+      var MODULE_DATA = {
+    """)
+    for module in self.soong.modules:
+      print("      '%(name)s': new Module(%(deps)s)," % {
+        "name": module,
+        "deps": json.dumps(self.soong.deps[module]),
+      })
+    print("""
+      };
+      </script>
 
-  """)
+    """)
 
-  print("""
-      </div> <!-- id=tables -->
-      <div id="details">
-        <div style="text-align: right;">
-          <a href="javascript:close_details();">
-            <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
-          </a>
+    print("""
+        </div> <!-- id=tables -->
+        <div id="details">
+          <div style="text-align: right;">
+            <a href="javascript:close_details();">
+              <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
+            </a>
+          </div>
+          <div id="details_data"></div>
         </div>
-        <div id="details_data"></div>
-      </div>
-    </body>
-  </html>
-  """)
+      </body>
+    </html>
+    """)
+
+  def traverse_ready_makefiles(self, summary, makefiles):
+    return [Analysis(makefile.filename, []) for makefile in makefiles
+        if clean_and_only_blocked_by_clean(self.soong, self.all_makefiles, makefile)]
+
+  def print_analysis_row(self, summary, modules, rowtitle, rowclass, makefiles):
+    all_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles]
+    clean_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+        if is_clean(makefile)]
+    easy_makefiles = self.traverse_ready_makefiles(summary, makefiles)
+    unblocked_clean_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+        if (self.soong.contains_unblocked_modules(makefile.filename)
+            and is_clean(makefile))]
+    unblocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+        if self.soong.contains_unblocked_modules(makefile.filename)]
+    blocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+        if self.soong.contains_blocked_modules(makefile.filename)]
+
+    print("""
+      <tr class="%(rowclass)s">
+        <td class="RowTitle">%(rowtitle)s</td>
+        <td class="Count">%(makefiles)s</td>
+        <td class="Count">%(easy)s</td>
+        <td class="Count">%(unblocked_clean)s</td>
+        <td class="Count">%(unblocked)s</td>
+        <td class="Count">%(blocked)s</td>
+        <td class="Count">%(clean)s</td>
+    """ % {
+      "rowclass": rowclass,
+      "rowtitle": rowtitle,
+      "makefiles": self.make_annotation_link(all_makefiles, modules),
+      "unblocked": self.make_annotation_link(unblocked_makefiles, modules),
+      "blocked": self.make_annotation_link(blocked_makefiles, modules),
+      "clean": self.make_annotation_link(clean_makefiles, modules),
+      "unblocked_clean": self.make_annotation_link(unblocked_clean_makefiles, modules),
+      "easy": self.make_annotation_link(easy_makefiles, modules),
+    })
+
+    for analyzer in ANALYZERS:
+      analyses = [m.analyses.get(analyzer) for m in makefiles if m.analyses.get(analyzer)]
+      print("""<td class="Count">%s</td>"""
+          % self.make_annotation_link(analyses, modules))
+
+    print("      </tr>")
+
+  def make_annotation_link(self, analysis, modules):
+    if analysis:
+      return "<a href='javascript:update_details(%d)'>%s</a>" % (
+        self.annotations.Add(analysis, modules),
+        len(analysis)
+      )
+    else:
+      return "";
+
+class CsvProcessor(object):
+  def __init__(self, args, soong, all_makefiles):
+    self.args = args
+    self.soong = soong
+    self.all_makefiles = all_makefiles
+
+  def execute(self):
+    csvout = csv.writer(sys.stdout)
+
+    # Title row
+    row = ["Filename", "Module", "Partitions", "Easy", "Unblocked Clean", "Unblocked",
+           "Blocked", "Clean"]
+    for analyzer in ANALYZERS:
+      row.append(analyzer.title)
+    csvout.writerow(row)
+
+    # Makefile & module data
+    for filename in sorted(self.all_makefiles.keys()):
+      makefile = self.all_makefiles[filename]
+      for module in self.soong.reverse_makefiles[filename]:
+        row = [filename, module]
+        # Partitions
+        row.append(";".join(sorted(set([get_partition_from_installed(HOST_OUT_ROOT, PRODUCT_OUT,
+                                         installed)
+                                        for installed
+                                        in self.soong.reverse_installed.get(module, [])]))))
+        # Easy
+        row.append(1
+            if clean_and_only_blocked_by_clean(self.soong, self.all_makefiles, makefile)
+            else "")
+        # Unblocked Clean
+        row.append(1
+            if (self.soong.contains_unblocked_modules(makefile.filename) and is_clean(makefile))
+            else "")
+        # Unblocked
+        row.append(1 if self.soong.contains_unblocked_modules(makefile.filename) else "")
+        # Blocked
+        row.append(1 if self.soong.contains_blocked_modules(makefile.filename) else "")
+        # Clean
+        row.append(1 if is_clean(makefile) else "")
+        # Analysis
+        for analyzer in ANALYZERS:
+          row.append(1 if makefile.analyses.get(analyzer) else "")
+        # Write results
+        csvout.writerow(row)
 
 if __name__ == "__main__":
   main()
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index 11f92ab..45e0514 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -49,6 +49,7 @@
     required: [
         "blk_alloc_to_base_fs",
         "e2fsck",
+        "mkuserimg_mke2fs",
         "simg2img",
         "tune2fs",
     ],
@@ -88,14 +89,35 @@
     ],
 }
 
+python_library_host {
+    name: "ota_metadata_proto",
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: true,
+        },
+    },
+    srcs: [
+       "ota_metadata.proto",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+}
+
 python_defaults {
     name: "releasetools_ota_from_target_files_defaults",
     srcs: [
         "edify_generator.py",
+        "non_ab_ota.py",
         "ota_from_target_files.py",
+        "ota_utils.py",
         "target_files_diff.py",
     ],
     libs: [
+        "ota_metadata_proto",
         "releasetools_check_target_files_vintf",
         "releasetools_common",
         "releasetools_verity_utils",
@@ -104,6 +126,12 @@
         "brillo_update_payload",
         "checkvintf",
     ],
+    target: {
+        darwin: {
+            // required module "brillo_update_payload" is disabled on darwin
+            enabled: false,
+        },
+    },
 }
 
 //
@@ -244,7 +272,9 @@
         "bsdiff",
         "imgdiff",
         "minigzip",
+        "lz4",
         "mkbootfs",
+        "signapk",
     ],
 }
 
@@ -297,6 +327,12 @@
     required: [
         "delta_generator",
     ],
+    target: {
+        darwin: {
+            // required module "delta_generator" is disabled on darwin
+            enabled: false,
+        },
+    },
 }
 
 python_binary_host {
@@ -369,6 +405,12 @@
     required: [
         "checkvintf",
     ],
+    target: {
+        darwin: {
+            // libs dep "releasetools_ota_from_target_files" is disabled on darwin
+            enabled: false,
+        },
+    },
 }
 
 python_binary_host {
@@ -466,6 +508,12 @@
     data: [
         "testdata/**/*",
     ],
+    target: {
+        darwin: {
+            // libs dep "releasetools_ota_from_target_files" is disabled on darwin
+            enabled: false,
+        },
+    },
 }
 
 python_test_host {
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index a1f8e31..eb041ec 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -739,6 +739,18 @@
   common.ZipClose(output_zip)
 
 
+def HasPartition(partition_name):
+  """Determines if the target files archive should build a given partition."""
+
+  return ((os.path.isdir(
+      os.path.join(OPTIONS.input_tmp, partition_name.upper())) and
+           OPTIONS.info_dict.get(
+               "building_{}_image".format(partition_name)) == "true") or
+          os.path.exists(
+              os.path.join(OPTIONS.input_tmp, "IMAGES",
+                           "{}.img".format(partition_name))))
+
+
 def AddImagesToTargetFiles(filename):
   """Creates and adds images (boot/recovery/system/...) to a target_files.zip.
 
@@ -767,49 +779,16 @@
   has_boot = OPTIONS.info_dict.get("no_boot") != "true"
   has_vendor_boot = OPTIONS.info_dict.get("vendor_boot") == "true"
 
-  # {vendor,odm,product,system_ext,vendor_dlkm,odm_dlkm}.img
-  # are unlike system.img or
-  # system_other.img, because it could be built from source, or  dropped into
-  # target_files.zip as a prebuilt blob. We consider either of them as
-  # {vendor,product,system_ext}.img being available, which could be
-  # used when generating vbmeta.img for AVB.
-  has_vendor = ((os.path.isdir(os.path.join(OPTIONS.input_tmp, "VENDOR")) and
-                 OPTIONS.info_dict.get("building_vendor_image") == "true") or
-                os.path.exists(
-                    os.path.join(OPTIONS.input_tmp, "IMAGES", "vendor.img")))
-  has_odm = ((os.path.isdir(os.path.join(OPTIONS.input_tmp, "ODM")) and
-              OPTIONS.info_dict.get("building_odm_image") == "true") or
-             os.path.exists(
-                 os.path.join(OPTIONS.input_tmp, "IMAGES", "odm.img")))
-  has_vendor_dlkm = ((os.path.isdir(os.path.join(OPTIONS.input_tmp,
-                                                 "VENDOR_DLKM")) and
-                      OPTIONS.info_dict.get("building_vendor_dlkm_image")
-                      == "true") or
-                     os.path.exists(
-                         os.path.join(OPTIONS.input_tmp, "IMAGES",
-                                      "vendor_dlkm.img")))
-  has_odm_dlkm = ((os.path.isdir(os.path.join(OPTIONS.input_tmp,
-                                              "ODM_DLKM")) and
-                   OPTIONS.info_dict.get("building_odm_dlkm_image")
-                   == "true") or
-                  os.path.exists(os.path.join(OPTIONS.input_tmp, "IMAGES",
-                                              "odm_dlkm.img")))
-  has_product = ((os.path.isdir(os.path.join(OPTIONS.input_tmp, "PRODUCT")) and
-                  OPTIONS.info_dict.get("building_product_image") == "true") or
-                 os.path.exists(
-                     os.path.join(OPTIONS.input_tmp, "IMAGES", "product.img")))
-  has_system_ext = (
-      (os.path.isdir(os.path.join(OPTIONS.input_tmp, "SYSTEM_EXT")) and
-       OPTIONS.info_dict.get("building_system_ext_image") == "true") or
-      os.path.exists(
-          os.path.join(OPTIONS.input_tmp, "IMAGES", "system_ext.img")))
-  has_system = (
-      os.path.isdir(os.path.join(OPTIONS.input_tmp, "SYSTEM")) and
-      OPTIONS.info_dict.get("building_system_image") == "true")
-
-  has_system_other = (
-      os.path.isdir(os.path.join(OPTIONS.input_tmp, "SYSTEM_OTHER")) and
-      OPTIONS.info_dict.get("building_system_other_image") == "true")
+  # {vendor,odm,product,system_ext,vendor_dlkm,odm_dlkm, system, system_other}.img
+  # can be built from source, or  dropped into target_files.zip as a prebuilt blob.
+  has_vendor = HasPartition("vendor")
+  has_odm = HasPartition("odm")
+  has_vendor_dlkm = HasPartition("vendor_dlkm")
+  has_odm_dlkm = HasPartition("odm_dlkm")
+  has_product = HasPartition("product")
+  has_system_ext = HasPartition("system_ext")
+  has_system = HasPartition("system")
+  has_system_other = HasPartition("system_other")
   has_userdata = OPTIONS.info_dict.get("building_userdata_image") == "true"
   has_cache = OPTIONS.info_dict.get("building_cache_image") == "true"
 
diff --git a/tools/releasetools/apex_utils.py b/tools/releasetools/apex_utils.py
index afebc40..8783f25 100644
--- a/tools/releasetools/apex_utils.py
+++ b/tools/releasetools/apex_utils.py
@@ -51,6 +51,8 @@
     self.apex_path = apex_path
     self.key_passwords = key_passwords
     self.codename_to_api_level_map = codename_to_api_level_map
+    self.debugfs_path = os.path.join(
+        OPTIONS.search_path, "bin", "debugfs_static")
 
   def ProcessApexFile(self, apk_keys, payload_key, signing_args=None):
     """Scans and signs the apk files and repack the apex
@@ -61,7 +63,13 @@
     Returns:
       The repacked apex file containing the signed apk files.
     """
-    list_cmd = ['deapexer', 'list', self.apex_path]
+    if not os.path.exists(self.debugfs_path):
+      raise ApexSigningError(
+          "Couldn't find location of debugfs_static: " +
+          "Path {} does not exist. ".format(debugfs_path) +
+          "Make sure bin/debugfs_static can be found in -p <path>")
+    list_cmd = ['deapexer', '--debugfs_path',
+                self.debugfs_path, 'list', self.apex_path]
     entries_names = common.RunAndCheckOutput(list_cmd).split()
     apk_entries = [name for name in entries_names if name.endswith('.apk')]
 
@@ -91,8 +99,14 @@
 
   def ExtractApexPayloadAndSignApks(self, apk_entries, apk_keys):
     """Extracts the payload image and signs the containing apk files."""
+    if not os.path.exists(self.debugfs_path):
+      raise ApexSigningError(
+          "Couldn't find location of debugfs_static: " +
+          "Path {} does not exist. ".format(debugfs_path) +
+          "Make sure bin/debugfs_static can be found in -p <path>")
     payload_dir = common.MakeTempDir()
-    extract_cmd = ['deapexer', 'extract', self.apex_path, payload_dir]
+    extract_cmd = ['deapexer', '--debugfs_path',
+                   self.debugfs_path, 'extract', self.apex_path, payload_dir]
     common.RunAndCheckOutput(extract_cmd)
 
     has_signed_apk = False
@@ -149,7 +163,8 @@
     # Add quote to the signing_args as we will pass
     # --signing_args "--signing_helper_with_files=%path" to apexer
     if signing_args:
-      generate_image_cmd.extend(['--signing_args', '"{}"'.format(signing_args)])
+      generate_image_cmd.extend(
+          ['--signing_args', '"{}"'.format(signing_args)])
 
     # optional arguments for apex repacking
     manifest_json = os.path.join(apex_dir, 'apex_manifest.json')
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
index ef66112..0edefac 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -220,6 +220,52 @@
 
   raise ValueError('{} is not a valid directory or zip file'.format(inp))
 
+def CheckVintfIfTrebleEnabled(target_files, target_info):
+  """Checks compatibility info of the input target files.
+
+  Metadata used for compatibility verification is retrieved from target_zip.
+
+  Compatibility should only be checked for devices that have enabled
+  Treble support.
+
+  Args:
+    target_files: Path to zip file containing the source files to be included
+        for OTA. Can also be the path to extracted directory.
+    target_info: The BuildInfo instance that holds the target build info.
+  """
+
+  # Will only proceed if the target has enabled the Treble support (as well as
+  # having a /vendor partition).
+  if not HasTrebleEnabled(target_files, target_info):
+    return
+
+  # Skip adding the compatibility package as a workaround for b/114240221. The
+  # compatibility will always fail on devices without qualified kernels.
+  if OPTIONS.skip_compatibility_check:
+    return
+
+  if not CheckVintf(target_files, target_info):
+    raise RuntimeError("VINTF compatibility check failed")
+
+def HasTrebleEnabled(target_files, target_info):
+  def HasVendorPartition(target_files):
+    if os.path.isdir(target_files):
+      return os.path.isdir(os.path.join(target_files, "VENDOR"))
+    if zipfile.is_zipfile(target_files):
+      return HasPartition(zipfile.ZipFile(target_files), "vendor")
+    raise ValueError("Unknown target_files argument")
+
+  return (HasVendorPartition(target_files) and
+          target_info.GetBuildProp("ro.treble.enabled") == "true")
+
+
+def HasPartition(target_files_zip, partition):
+  try:
+    target_files_zip.getinfo(partition.upper() + "/")
+    return True
+  except KeyError:
+    return False
+
 
 def main(argv):
   args = common.ParseOptions(argv, __doc__)
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 1846a67..c77d8c6 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -118,7 +118,7 @@
 AVB_VBMETA_PARTITIONS = ('vbmeta_system', 'vbmeta_vendor')
 
 # Partitions that should have their care_map added to META/care_map.pb
-PARTITIONS_WITH_CARE_MAP = (
+PARTITIONS_WITH_CARE_MAP = [
     'system',
     'vendor',
     'product',
@@ -126,7 +126,7 @@
     'odm',
     'vendor_dlkm',
     'odm_dlkm',
-)
+]
 
 
 class ErrorCode(object):
@@ -729,10 +729,14 @@
       fingerprint = build_info.GetPartitionFingerprint(partition)
       if fingerprint:
         d["avb_{}_salt".format(partition)] = sha256(fingerprint.encode()).hexdigest()
-
+  try:
+    d["ab_partitions"] = read_helper("META/ab_partitions.txt").split("\n")
+  except KeyError:
+    logger.warning("Can't find META/ab_partitions.txt")
   return d
 
 
+
 def LoadListFromFile(file_path):
   with open(file_path) as f:
     return f.read().splitlines()
@@ -1227,7 +1231,7 @@
     cmd = ["mkbootfs", os.path.join(sourcedir, "RAMDISK")]
   p1 = Run(cmd, stdout=subprocess.PIPE)
   if lz4_ramdisks:
-    p2 = Run(["lz4", "-l", "-12" , "--favor-decSpeed"], stdin=p1.stdout,
+    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())
@@ -3176,8 +3180,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/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
index ab38d0d..5409194 100755
--- a/tools/releasetools/img_from_target_files.py
+++ b/tools/releasetools/img_from_target_files.py
@@ -58,6 +58,7 @@
 OPTIONS.additional_entries = []
 OPTIONS.bootable_only = False
 OPTIONS.put_super = None
+OPTIONS.put_bootloader = None
 OPTIONS.dynamic_partition_list = None
 OPTIONS.super_device_list = None
 OPTIONS.retrofit_dap = None
@@ -75,6 +76,7 @@
     info = OPTIONS.info_dict = common.LoadInfoDict(input_zip)
 
   OPTIONS.put_super = info.get('super_image_in_update_package') == 'true'
+  OPTIONS.put_bootloader = info.get('bootloader_in_update_package') == 'true'
   OPTIONS.dynamic_partition_list = info.get('dynamic_partition_list',
                                             '').strip().split()
   OPTIONS.super_device_list = info.get('super_block_devices',
@@ -122,9 +124,11 @@
 
   for image_path in [name for name in namelist if name.startswith('IMAGES/')]:
     image = os.path.basename(image_path)
-    if OPTIONS.bootable_only and image not in ('boot.img', 'recovery.img'):
+    if OPTIONS.bootable_only and image not in('boot.img', 'recovery.img', 'bootloader'):
       continue
-    if not image.endswith('.img'):
+    if not image.endswith('.img') and image != 'bootloader':
+      continue
+    if image == 'bootloader' and not OPTIONS.put_bootloader:
       continue
     # Filter out super_empty and the images that are already in super partition.
     if OPTIONS.put_super:
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index 45532f5..bfd2f90 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -197,8 +197,6 @@
     'PREBUILT_IMAGES/*',
     'RADIO/*',
     'VENDOR/*',
-    'VENDOR_DLKM/*',
-    'ODM_DLKM/*',
 )
 
 # VENDOR_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
diff --git a/tools/releasetools/non_ab_ota.py b/tools/releasetools/non_ab_ota.py
new file mode 100644
index 0000000..471ef25
--- /dev/null
+++ b/tools/releasetools/non_ab_ota.py
@@ -0,0 +1,684 @@
+# 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.
+
+import collections
+import logging
+import os
+import zipfile
+
+import common
+import edify_generator
+import verity_utils
+from check_target_files_vintf import CheckVintfIfTrebleEnabled, HasPartition
+from common import OPTIONS
+from ota_utils import UNZIP_PATTERN, FinalizeMetadata, GetPackageMetadata, PropertyFiles
+
+logger = logging.getLogger(__name__)
+
+
+def GetBlockDifferences(target_zip, source_zip, target_info, source_info,
+                        device_specific):
+  """Returns a ordered dict of block differences with partition name as key."""
+
+  def GetIncrementalBlockDifferenceForPartition(name):
+    if not HasPartition(source_zip, name):
+      raise RuntimeError(
+          "can't generate incremental that adds {}".format(name))
+
+    partition_src = common.GetUserImage(name, OPTIONS.source_tmp, source_zip,
+                                        info_dict=source_info,
+                                        allow_shared_blocks=allow_shared_blocks)
+
+    hashtree_info_generator = verity_utils.CreateHashtreeInfoGenerator(
+        name, 4096, target_info)
+    partition_tgt = common.GetUserImage(name, OPTIONS.target_tmp, target_zip,
+                                        info_dict=target_info,
+                                        allow_shared_blocks=allow_shared_blocks,
+                                        hashtree_info_generator=hashtree_info_generator)
+
+    # Check the first block of the source system partition for remount R/W only
+    # if the filesystem is ext4.
+    partition_source_info = source_info["fstab"]["/" + name]
+    check_first_block = partition_source_info.fs_type == "ext4"
+    # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
+    # in zip formats. However with squashfs, a) all files are compressed in LZ4;
+    # b) the blocks listed in block map may not contain all the bytes for a
+    # given file (because they're rounded to be 4K-aligned).
+    partition_target_info = target_info["fstab"]["/" + name]
+    disable_imgdiff = (partition_source_info.fs_type == "squashfs" or
+                       partition_target_info.fs_type == "squashfs")
+    return common.BlockDifference(name, partition_tgt, partition_src,
+                                  check_first_block,
+                                  version=blockimgdiff_version,
+                                  disable_imgdiff=disable_imgdiff)
+
+  if source_zip:
+    # See notes in common.GetUserImage()
+    allow_shared_blocks = (source_info.get('ext4_share_dup_blocks') == "true" or
+                           target_info.get('ext4_share_dup_blocks') == "true")
+    blockimgdiff_version = max(
+        int(i) for i in target_info.get(
+            "blockimgdiff_versions", "1").split(","))
+    assert blockimgdiff_version >= 3
+
+  block_diff_dict = collections.OrderedDict()
+  partition_names = ["system", "vendor", "product", "odm", "system_ext",
+                     "vendor_dlkm", "odm_dlkm"]
+  for partition in partition_names:
+    if not HasPartition(target_zip, partition):
+      continue
+    # Full OTA update.
+    if not source_zip:
+      tgt = common.GetUserImage(partition, OPTIONS.input_tmp, target_zip,
+                                info_dict=target_info,
+                                reset_file_map=True)
+      block_diff_dict[partition] = common.BlockDifference(partition, tgt,
+                                                          src=None)
+    # Incremental OTA update.
+    else:
+      block_diff_dict[partition] = GetIncrementalBlockDifferenceForPartition(
+          partition)
+  assert "system" in block_diff_dict
+
+  # Get the block diffs from the device specific script. If there is a
+  # duplicate block diff for a partition, ignore the diff in the generic script
+  # and use the one in the device specific script instead.
+  if source_zip:
+    device_specific_diffs = device_specific.IncrementalOTA_GetBlockDifferences()
+    function_name = "IncrementalOTA_GetBlockDifferences"
+  else:
+    device_specific_diffs = device_specific.FullOTA_GetBlockDifferences()
+    function_name = "FullOTA_GetBlockDifferences"
+
+  if device_specific_diffs:
+    assert all(isinstance(diff, common.BlockDifference)
+               for diff in device_specific_diffs), \
+        "{} is not returning a list of BlockDifference objects".format(
+            function_name)
+    for diff in device_specific_diffs:
+      if diff.partition in block_diff_dict:
+        logger.warning("Duplicate block difference found. Device specific block"
+                       " diff for partition '%s' overrides the one in generic"
+                       " script.", diff.partition)
+      block_diff_dict[diff.partition] = diff
+
+  return block_diff_dict
+
+
+def WriteFullOTAPackage(input_zip, output_file):
+  target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
+
+  # We don't know what version it will be installed on top of. We expect the API
+  # just won't change very often. Similarly for fstab, it might have changed in
+  # the target build.
+  target_api_version = target_info["recovery_api_version"]
+  script = edify_generator.EdifyGenerator(target_api_version, target_info)
+
+  if target_info.oem_props and not OPTIONS.oem_no_mount:
+    target_info.WriteMountOemScript(script)
+
+  metadata = GetPackageMetadata(target_info)
+
+  if not OPTIONS.no_signing:
+    staging_file = common.MakeTempFile(suffix='.zip')
+  else:
+    staging_file = output_file
+
+  output_zip = zipfile.ZipFile(
+      staging_file, "w", compression=zipfile.ZIP_DEFLATED)
+
+  device_specific = common.DeviceSpecificParams(
+      input_zip=input_zip,
+      input_version=target_api_version,
+      output_zip=output_zip,
+      script=script,
+      input_tmp=OPTIONS.input_tmp,
+      metadata=metadata,
+      info_dict=OPTIONS.info_dict)
+
+  assert HasRecoveryPatch(input_zip, info_dict=OPTIONS.info_dict)
+
+  # Assertions (e.g. downgrade check, device properties check).
+  ts = target_info.GetBuildProp("ro.build.date.utc")
+  ts_text = target_info.GetBuildProp("ro.build.date")
+  script.AssertOlderBuild(ts, ts_text)
+
+  target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
+  device_specific.FullOTA_Assertions()
+
+  block_diff_dict = GetBlockDifferences(target_zip=input_zip, source_zip=None,
+                                        target_info=target_info,
+                                        source_info=None,
+                                        device_specific=device_specific)
+
+  # Two-step package strategy (in chronological order, which is *not*
+  # the order in which the generated script has things):
+  #
+  # if stage is not "2/3" or "3/3":
+  #    write recovery image to boot partition
+  #    set stage to "2/3"
+  #    reboot to boot partition and restart recovery
+  # else if stage is "2/3":
+  #    write recovery image to recovery partition
+  #    set stage to "3/3"
+  #    reboot to recovery partition and restart recovery
+  # else:
+  #    (stage must be "3/3")
+  #    set stage to ""
+  #    do normal full package installation:
+  #       wipe and install system, boot image, etc.
+  #       set up system to update recovery partition on first boot
+  #    complete script normally
+  #    (allow recovery to mark itself finished and reboot)
+
+  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
+                                         OPTIONS.input_tmp, "RECOVERY")
+  if OPTIONS.two_step:
+    if not target_info.get("multistage_support"):
+      assert False, "two-step packages not supported by this build"
+    fs = target_info["fstab"]["/misc"]
+    assert fs.fs_type.upper() == "EMMC", \
+        "two-step packages only supported on devices with EMMC /misc partitions"
+    bcb_dev = {"bcb_dev": fs.device}
+    common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
+    script.AppendExtra("""
+if get_stage("%(bcb_dev)s") == "2/3" then
+""" % bcb_dev)
+
+    # Stage 2/3: Write recovery image to /recovery (currently running /boot).
+    script.Comment("Stage 2/3")
+    script.WriteRawImage("/recovery", "recovery.img")
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "3/3");
+reboot_now("%(bcb_dev)s", "recovery");
+else if get_stage("%(bcb_dev)s") == "3/3" then
+""" % bcb_dev)
+
+    # Stage 3/3: Make changes.
+    script.Comment("Stage 3/3")
+
+  # Dump fingerprints
+  script.Print("Target: {}".format(target_info.fingerprint))
+
+  device_specific.FullOTA_InstallBegin()
+
+  # All other partitions as well as the data wipe use 10% of the progress, and
+  # the update of the system partition takes the remaining progress.
+  system_progress = 0.9 - (len(block_diff_dict) - 1) * 0.1
+  if OPTIONS.wipe_user_data:
+    system_progress -= 0.1
+  progress_dict = {partition: 0.1 for partition in block_diff_dict}
+  progress_dict["system"] = system_progress
+
+  if target_info.get('use_dynamic_partitions') == "true":
+    # Use empty source_info_dict to indicate that all partitions / groups must
+    # be re-added.
+    dynamic_partitions_diff = common.DynamicPartitionsDifference(
+        info_dict=OPTIONS.info_dict,
+        block_diffs=block_diff_dict.values(),
+        progress_dict=progress_dict)
+    dynamic_partitions_diff.WriteScript(script, output_zip,
+                                        write_verify_script=OPTIONS.verify)
+  else:
+    for block_diff in block_diff_dict.values():
+      block_diff.WriteScript(script, output_zip,
+                             progress=progress_dict.get(block_diff.partition),
+                             write_verify_script=OPTIONS.verify)
+
+  CheckVintfIfTrebleEnabled(OPTIONS.input_tmp, target_info)
+
+  boot_img = common.GetBootableImage(
+      "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
+  common.CheckSize(boot_img.data, "boot.img", target_info)
+  common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
+
+  script.WriteRawImage("/boot", "boot.img")
+
+  script.ShowProgress(0.1, 10)
+  device_specific.FullOTA_InstallEnd()
+
+  if OPTIONS.extra_script is not None:
+    script.AppendExtra(OPTIONS.extra_script)
+
+  script.UnmountAll()
+
+  if OPTIONS.wipe_user_data:
+    script.ShowProgress(0.1, 10)
+    script.FormatPartition("/data")
+
+  if OPTIONS.two_step:
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "");
+""" % bcb_dev)
+    script.AppendExtra("else\n")
+
+    # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
+    script.Comment("Stage 1/3")
+    _WriteRecoveryImageToBoot(script, output_zip)
+
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "2/3");
+reboot_now("%(bcb_dev)s", "");
+endif;
+endif;
+""" % bcb_dev)
+
+  script.SetProgress(1)
+  script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
+  metadata.required_cache = script.required_cache
+
+  # We haven't written the metadata entry, which will be done in
+  # FinalizeMetadata.
+  common.ZipClose(output_zip)
+
+  needed_property_files = (
+      NonAbOtaPropertyFiles(),
+  )
+  FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
+
+
+def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_file):
+  target_info = common.BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
+  source_info = common.BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)
+
+  target_api_version = target_info["recovery_api_version"]
+  source_api_version = source_info["recovery_api_version"]
+  if source_api_version == 0:
+    logger.warning(
+        "Generating edify script for a source that can't install it.")
+
+  script = edify_generator.EdifyGenerator(
+      source_api_version, target_info, fstab=source_info["fstab"])
+
+  if target_info.oem_props or source_info.oem_props:
+    if not OPTIONS.oem_no_mount:
+      source_info.WriteMountOemScript(script)
+
+  metadata = GetPackageMetadata(target_info, source_info)
+
+  if not OPTIONS.no_signing:
+    staging_file = common.MakeTempFile(suffix='.zip')
+  else:
+    staging_file = output_file
+
+  output_zip = zipfile.ZipFile(
+      staging_file, "w", compression=zipfile.ZIP_DEFLATED)
+
+  device_specific = common.DeviceSpecificParams(
+      source_zip=source_zip,
+      source_version=source_api_version,
+      source_tmp=OPTIONS.source_tmp,
+      target_zip=target_zip,
+      target_version=target_api_version,
+      target_tmp=OPTIONS.target_tmp,
+      output_zip=output_zip,
+      script=script,
+      metadata=metadata,
+      info_dict=source_info)
+
+  source_boot = common.GetBootableImage(
+      "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", source_info)
+  target_boot = common.GetBootableImage(
+      "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT", target_info)
+  updating_boot = (not OPTIONS.two_step and
+                   (source_boot.data != target_boot.data))
+
+  target_recovery = common.GetBootableImage(
+      "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
+
+  block_diff_dict = GetBlockDifferences(target_zip=target_zip,
+                                        source_zip=source_zip,
+                                        target_info=target_info,
+                                        source_info=source_info,
+                                        device_specific=device_specific)
+
+  CheckVintfIfTrebleEnabled(OPTIONS.target_tmp, target_info)
+
+  # Assertions (e.g. device properties check).
+  target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
+  device_specific.IncrementalOTA_Assertions()
+
+  # Two-step incremental package strategy (in chronological order,
+  # which is *not* the order in which the generated script has
+  # things):
+  #
+  # if stage is not "2/3" or "3/3":
+  #    do verification on current system
+  #    write recovery image to boot partition
+  #    set stage to "2/3"
+  #    reboot to boot partition and restart recovery
+  # else if stage is "2/3":
+  #    write recovery image to recovery partition
+  #    set stage to "3/3"
+  #    reboot to recovery partition and restart recovery
+  # else:
+  #    (stage must be "3/3")
+  #    perform update:
+  #       patch system files, etc.
+  #       force full install of new boot image
+  #       set up system to update recovery partition on first boot
+  #    complete script normally
+  #    (allow recovery to mark itself finished and reboot)
+
+  if OPTIONS.two_step:
+    if not source_info.get("multistage_support"):
+      assert False, "two-step packages not supported by this build"
+    fs = source_info["fstab"]["/misc"]
+    assert fs.fs_type.upper() == "EMMC", \
+        "two-step packages only supported on devices with EMMC /misc partitions"
+    bcb_dev = {"bcb_dev": fs.device}
+    common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
+    script.AppendExtra("""
+if get_stage("%(bcb_dev)s") == "2/3" then
+""" % bcb_dev)
+
+    # Stage 2/3: Write recovery image to /recovery (currently running /boot).
+    script.Comment("Stage 2/3")
+    script.AppendExtra("sleep(20);\n")
+    script.WriteRawImage("/recovery", "recovery.img")
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "3/3");
+reboot_now("%(bcb_dev)s", "recovery");
+else if get_stage("%(bcb_dev)s") != "3/3" then
+""" % bcb_dev)
+
+    # Stage 1/3: (a) Verify the current system.
+    script.Comment("Stage 1/3")
+
+  # Dump fingerprints
+  script.Print("Source: {}".format(source_info.fingerprint))
+  script.Print("Target: {}".format(target_info.fingerprint))
+
+  script.Print("Verifying current system...")
+
+  device_specific.IncrementalOTA_VerifyBegin()
+
+  WriteFingerprintAssertion(script, target_info, source_info)
+
+  # Check the required cache size (i.e. stashed blocks).
+  required_cache_sizes = [diff.required_cache for diff in
+                          block_diff_dict.values()]
+  if updating_boot:
+    boot_type, boot_device_expr = common.GetTypeAndDeviceExpr("/boot",
+                                                              source_info)
+    d = common.Difference(target_boot, source_boot)
+    _, _, d = d.ComputePatch()
+    if d is None:
+      include_full_boot = True
+      common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
+    else:
+      include_full_boot = False
+
+      logger.info(
+          "boot      target: %d  source: %d  diff: %d", target_boot.size,
+          source_boot.size, len(d))
+
+      common.ZipWriteStr(output_zip, "boot.img.p", d)
+
+      target_expr = 'concat("{}:",{},":{}:{}")'.format(
+          boot_type, boot_device_expr, target_boot.size, target_boot.sha1)
+      source_expr = 'concat("{}:",{},":{}:{}")'.format(
+          boot_type, boot_device_expr, source_boot.size, source_boot.sha1)
+      script.PatchPartitionExprCheck(target_expr, source_expr)
+
+      required_cache_sizes.append(target_boot.size)
+
+  if required_cache_sizes:
+    script.CacheFreeSpaceCheck(max(required_cache_sizes))
+
+  # Verify the existing partitions.
+  for diff in block_diff_dict.values():
+    diff.WriteVerifyScript(script, touched_blocks_only=True)
+
+  device_specific.IncrementalOTA_VerifyEnd()
+
+  if OPTIONS.two_step:
+    # Stage 1/3: (b) Write recovery image to /boot.
+    _WriteRecoveryImageToBoot(script, output_zip)
+
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "2/3");
+reboot_now("%(bcb_dev)s", "");
+else
+""" % bcb_dev)
+
+    # Stage 3/3: Make changes.
+    script.Comment("Stage 3/3")
+
+  script.Comment("---- start making changes here ----")
+
+  device_specific.IncrementalOTA_InstallBegin()
+
+  progress_dict = {partition: 0.1 for partition in block_diff_dict}
+  progress_dict["system"] = 1 - len(block_diff_dict) * 0.1
+
+  if OPTIONS.source_info_dict.get("use_dynamic_partitions") == "true":
+    if OPTIONS.target_info_dict.get("use_dynamic_partitions") != "true":
+      raise RuntimeError(
+          "can't generate incremental that disables dynamic partitions")
+    dynamic_partitions_diff = common.DynamicPartitionsDifference(
+        info_dict=OPTIONS.target_info_dict,
+        source_info_dict=OPTIONS.source_info_dict,
+        block_diffs=block_diff_dict.values(),
+        progress_dict=progress_dict)
+    dynamic_partitions_diff.WriteScript(
+        script, output_zip, write_verify_script=OPTIONS.verify)
+  else:
+    for block_diff in block_diff_dict.values():
+      block_diff.WriteScript(script, output_zip,
+                             progress=progress_dict.get(block_diff.partition),
+                             write_verify_script=OPTIONS.verify)
+
+  if OPTIONS.two_step:
+    common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
+    script.WriteRawImage("/boot", "boot.img")
+    logger.info("writing full boot image (forced by two-step mode)")
+
+  if not OPTIONS.two_step:
+    if updating_boot:
+      if include_full_boot:
+        logger.info("boot image changed; including full.")
+        script.Print("Installing boot image...")
+        script.WriteRawImage("/boot", "boot.img")
+      else:
+        # Produce the boot image by applying a patch to the current
+        # contents of the boot partition, and write it back to the
+        # partition.
+        logger.info("boot image changed; including patch.")
+        script.Print("Patching boot image...")
+        script.ShowProgress(0.1, 10)
+        target_expr = 'concat("{}:",{},":{}:{}")'.format(
+            boot_type, boot_device_expr, target_boot.size, target_boot.sha1)
+        source_expr = 'concat("{}:",{},":{}:{}")'.format(
+            boot_type, boot_device_expr, source_boot.size, source_boot.sha1)
+        script.PatchPartitionExpr(target_expr, source_expr, '"boot.img.p"')
+    else:
+      logger.info("boot image unchanged; skipping.")
+
+  # Do device-specific installation (eg, write radio image).
+  device_specific.IncrementalOTA_InstallEnd()
+
+  if OPTIONS.extra_script is not None:
+    script.AppendExtra(OPTIONS.extra_script)
+
+  if OPTIONS.wipe_user_data:
+    script.Print("Erasing user data...")
+    script.FormatPartition("/data")
+
+  if OPTIONS.two_step:
+    script.AppendExtra("""
+set_stage("%(bcb_dev)s", "");
+endif;
+endif;
+""" % bcb_dev)
+
+  script.SetProgress(1)
+  # For downgrade OTAs, we prefer to use the update-binary in the source
+  # build that is actually newer than the one in the target build.
+  if OPTIONS.downgrade:
+    script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
+  else:
+    script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
+  metadata.required_cache = script.required_cache
+
+  # We haven't written the metadata entry yet, which will be handled in
+  # FinalizeMetadata().
+  common.ZipClose(output_zip)
+
+  # Sign the generated zip package unless no_signing is specified.
+  needed_property_files = (
+      NonAbOtaPropertyFiles(),
+  )
+  FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
+
+
+def GenerateNonAbOtaPackage(target_file, output_file, source_file=None):
+  """Generates a non-A/B OTA package."""
+  # Check the loaded info dicts first.
+  if OPTIONS.info_dict.get("no_recovery") == "true":
+    raise common.ExternalError(
+        "--- target build has specified no recovery ---")
+
+  # Non-A/B OTAs rely on /cache partition to store temporary files.
+  cache_size = OPTIONS.info_dict.get("cache_size")
+  if cache_size is None:
+    logger.warning("--- can't determine the cache partition size ---")
+  OPTIONS.cache_size = cache_size
+
+  if OPTIONS.extra_script is not None:
+    with open(OPTIONS.extra_script) as fp:
+      OPTIONS.extra_script = fp.read()
+
+  if OPTIONS.extracted_input is not None:
+    OPTIONS.input_tmp = OPTIONS.extracted_input
+  else:
+    logger.info("unzipping target target-files...")
+    OPTIONS.input_tmp = common.UnzipTemp(target_file, UNZIP_PATTERN)
+  OPTIONS.target_tmp = OPTIONS.input_tmp
+
+  # If the caller explicitly specified the device-specific extensions path via
+  # -s / --device_specific, use that. Otherwise, use META/releasetools.py if it
+  # is present in the target target_files. Otherwise, take the path of the file
+  # from 'tool_extensions' in the info dict and look for that in the local
+  # filesystem, relative to the current directory.
+  if OPTIONS.device_specific is None:
+    from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
+    if os.path.exists(from_input):
+      logger.info("(using device-specific extensions from target_files)")
+      OPTIONS.device_specific = from_input
+    else:
+      OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions")
+
+  if OPTIONS.device_specific is not None:
+    OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
+
+  # Generate a full OTA.
+  if source_file is None:
+    with zipfile.ZipFile(target_file) as input_zip:
+      WriteFullOTAPackage(
+          input_zip,
+          output_file)
+
+  # Generate an incremental OTA.
+  else:
+    logger.info("unzipping source target-files...")
+    OPTIONS.source_tmp = common.UnzipTemp(
+        OPTIONS.incremental_source, UNZIP_PATTERN)
+    with zipfile.ZipFile(target_file) as input_zip, \
+            zipfile.ZipFile(source_file) as source_zip:
+      WriteBlockIncrementalOTAPackage(
+          input_zip,
+          source_zip,
+          output_file)
+
+
+def WriteFingerprintAssertion(script, target_info, source_info):
+  source_oem_props = source_info.oem_props
+  target_oem_props = target_info.oem_props
+
+  if source_oem_props is None and target_oem_props is None:
+    script.AssertSomeFingerprint(
+        source_info.fingerprint, target_info.fingerprint)
+  elif source_oem_props is not None and target_oem_props is not None:
+    script.AssertSomeThumbprint(
+        target_info.GetBuildProp("ro.build.thumbprint"),
+        source_info.GetBuildProp("ro.build.thumbprint"))
+  elif source_oem_props is None and target_oem_props is not None:
+    script.AssertFingerprintOrThumbprint(
+        source_info.fingerprint,
+        target_info.GetBuildProp("ro.build.thumbprint"))
+  else:
+    script.AssertFingerprintOrThumbprint(
+        target_info.fingerprint,
+        source_info.GetBuildProp("ro.build.thumbprint"))
+
+
+class NonAbOtaPropertyFiles(PropertyFiles):
+  """The property-files for non-A/B OTA.
+
+  For non-A/B OTA, the property-files string contains the info for METADATA
+  entry, with which a system updater can be fetched the package metadata prior
+  to downloading the entire package.
+  """
+
+  def __init__(self):
+    super(NonAbOtaPropertyFiles, self).__init__()
+    self.name = 'ota-property-files'
+
+
+def _WriteRecoveryImageToBoot(script, output_zip):
+  """Find and write recovery image to /boot in two-step OTA.
+
+  In two-step OTAs, we write recovery image to /boot as the first step so that
+  we can reboot to there and install a new recovery image to /recovery.
+  A special "recovery-two-step.img" will be preferred, which encodes the correct
+  path of "/boot". Otherwise the device may show "device is corrupt" message
+  when booting into /boot.
+
+  Fall back to using the regular recovery.img if the two-step recovery image
+  doesn't exist. Note that rebuilding the special image at this point may be
+  infeasible, because we don't have the desired boot signer and keys when
+  calling ota_from_target_files.py.
+  """
+
+  recovery_two_step_img_name = "recovery-two-step.img"
+  recovery_two_step_img_path = os.path.join(
+      OPTIONS.input_tmp, "OTA", recovery_two_step_img_name)
+  if os.path.exists(recovery_two_step_img_path):
+    common.ZipWrite(
+        output_zip,
+        recovery_two_step_img_path,
+        arcname=recovery_two_step_img_name)
+    logger.info(
+        "two-step package: using %s in stage 1/3", recovery_two_step_img_name)
+    script.WriteRawImage("/boot", recovery_two_step_img_name)
+  else:
+    logger.info("two-step package: using recovery.img in stage 1/3")
+    # The "recovery.img" entry has been written into package earlier.
+    script.WriteRawImage("/boot", "recovery.img")
+
+
+def HasRecoveryPatch(target_files_zip, info_dict):
+  board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true"
+
+  if board_uses_vendorimage:
+    target_files_dir = "VENDOR"
+  else:
+    target_files_dir = "SYSTEM/vendor"
+
+  patch = "%s/recovery-from-boot.p" % target_files_dir
+  img = "%s/etc/recovery.img" % target_files_dir
+
+  namelist = target_files_zip.namelist()
+  return patch in namelist or img in namelist
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index b70044e..2833397 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -206,9 +206,6 @@
 
 from __future__ import print_function
 
-import collections
-import copy
-import itertools
 import logging
 import multiprocessing
 import os.path
@@ -218,12 +215,13 @@
 import sys
 import zipfile
 
-import check_target_files_vintf
 import common
-import edify_generator
+import ota_utils
 import target_files_diff
-import verity_utils
-
+from check_target_files_vintf import CheckVintfIfTrebleEnabled
+from non_ab_ota import GenerateNonAbOtaPackage
+from ota_utils import (UNZIP_PATTERN, FinalizeMetadata, GetPackageMetadata,
+                       PropertyFiles)
 
 if sys.hexversion < 0x02070000:
   print("Python 2.7 or newer is required.", file=sys.stderr)
@@ -231,20 +229,16 @@
 
 logger = logging.getLogger(__name__)
 
-OPTIONS = common.OPTIONS
-OPTIONS.package_key = None
-OPTIONS.incremental_source = None
+OPTIONS = ota_utils.OPTIONS
 OPTIONS.verify = False
 OPTIONS.patch_threshold = 0.95
 OPTIONS.wipe_user_data = False
-OPTIONS.downgrade = False
 OPTIONS.extra_script = None
 OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
 if OPTIONS.worker_threads == 0:
   OPTIONS.worker_threads = 1
 OPTIONS.two_step = False
 OPTIONS.include_secondary = False
-OPTIONS.no_signing = False
 OPTIONS.block_based = True
 OPTIONS.updater_binary = None
 OPTIONS.oem_dicts = None
@@ -260,21 +254,15 @@
 OPTIONS.payload_signer_args = []
 OPTIONS.payload_signer_maximum_signature_size = None
 OPTIONS.extracted_input = None
-OPTIONS.key_passwords = []
 OPTIONS.skip_postinstall = False
-OPTIONS.retrofit_dynamic_partitions = False
 OPTIONS.skip_compatibility_check = False
-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'
 POSTINSTALL_CONFIG = 'META/postinstall_config.txt'
 DYNAMIC_PARTITION_INFO = 'META/dynamic_partitions_info.txt'
 AB_PARTITIONS = 'META/ab_partitions.txt'
-UNZIP_PATTERN = ['IMAGES/*', 'META/*', 'OTA/*', 'RADIO/*']
+
 # Files to be unzipped for target diffing purpose.
 TARGET_DIFFING_UNZIP_PATTERN = ['BOOT', 'RECOVERY', 'SYSTEM/*', 'VENDOR/*',
                                 'PRODUCT/*', 'SYSTEM_EXT/*', 'ODM/*',
@@ -488,13 +476,6 @@
                     compress_type=zipfile.ZIP_STORED)
 
 
-def SignOutput(temp_zip_name, output_zip_name):
-  pw = OPTIONS.key_passwords[OPTIONS.package_key]
-
-  common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
-                  whole_file=True)
-
-
 def _LoadOemDicts(oem_source):
   """Returns the list of loaded OEM properties dict."""
   if not oem_source:
@@ -507,658 +488,6 @@
   return oem_dicts
 
 
-def _WriteRecoveryImageToBoot(script, output_zip):
-  """Find and write recovery image to /boot in two-step OTA.
-
-  In two-step OTAs, we write recovery image to /boot as the first step so that
-  we can reboot to there and install a new recovery image to /recovery.
-  A special "recovery-two-step.img" will be preferred, which encodes the correct
-  path of "/boot". Otherwise the device may show "device is corrupt" message
-  when booting into /boot.
-
-  Fall back to using the regular recovery.img if the two-step recovery image
-  doesn't exist. Note that rebuilding the special image at this point may be
-  infeasible, because we don't have the desired boot signer and keys when
-  calling ota_from_target_files.py.
-  """
-
-  recovery_two_step_img_name = "recovery-two-step.img"
-  recovery_two_step_img_path = os.path.join(
-      OPTIONS.input_tmp, "OTA", recovery_two_step_img_name)
-  if os.path.exists(recovery_two_step_img_path):
-    common.ZipWrite(
-        output_zip,
-        recovery_two_step_img_path,
-        arcname=recovery_two_step_img_name)
-    logger.info(
-        "two-step package: using %s in stage 1/3", recovery_two_step_img_name)
-    script.WriteRawImage("/boot", recovery_two_step_img_name)
-  else:
-    logger.info("two-step package: using recovery.img in stage 1/3")
-    # The "recovery.img" entry has been written into package earlier.
-    script.WriteRawImage("/boot", "recovery.img")
-
-
-def HasRecoveryPatch(target_files_zip, info_dict):
-  board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true"
-
-  if board_uses_vendorimage:
-    target_files_dir = "VENDOR"
-  else:
-    target_files_dir = "SYSTEM/vendor"
-
-  patch = "%s/recovery-from-boot.p" % target_files_dir
-  img = "%s/etc/recovery.img" % target_files_dir
-
-  namelist = target_files_zip.namelist()
-  return patch in namelist or img in namelist
-
-
-def HasPartition(target_files_zip, partition):
-  try:
-    target_files_zip.getinfo(partition.upper() + "/")
-    return True
-  except KeyError:
-    return False
-
-
-def HasTrebleEnabled(target_files, target_info):
-  def HasVendorPartition(target_files):
-    if os.path.isdir(target_files):
-      return os.path.isdir(os.path.join(target_files, "VENDOR"))
-    if zipfile.is_zipfile(target_files):
-      return HasPartition(zipfile.ZipFile(target_files), "vendor")
-    raise ValueError("Unknown target_files argument")
-
-  return (HasVendorPartition(target_files) and
-          target_info.GetBuildProp("ro.treble.enabled") == "true")
-
-
-def WriteFingerprintAssertion(script, target_info, source_info):
-  source_oem_props = source_info.oem_props
-  target_oem_props = target_info.oem_props
-
-  if source_oem_props is None and target_oem_props is None:
-    script.AssertSomeFingerprint(
-        source_info.fingerprint, target_info.fingerprint)
-  elif source_oem_props is not None and target_oem_props is not None:
-    script.AssertSomeThumbprint(
-        target_info.GetBuildProp("ro.build.thumbprint"),
-        source_info.GetBuildProp("ro.build.thumbprint"))
-  elif source_oem_props is None and target_oem_props is not None:
-    script.AssertFingerprintOrThumbprint(
-        source_info.fingerprint,
-        target_info.GetBuildProp("ro.build.thumbprint"))
-  else:
-    script.AssertFingerprintOrThumbprint(
-        target_info.fingerprint,
-        source_info.GetBuildProp("ro.build.thumbprint"))
-
-
-def CheckVintfIfTrebleEnabled(target_files, target_info):
-  """Checks compatibility info of the input target files.
-
-  Metadata used for compatibility verification is retrieved from target_zip.
-
-  Compatibility should only be checked for devices that have enabled
-  Treble support.
-
-  Args:
-    target_files: Path to zip file containing the source files to be included
-        for OTA. Can also be the path to extracted directory.
-    target_info: The BuildInfo instance that holds the target build info.
-  """
-
-  # Will only proceed if the target has enabled the Treble support (as well as
-  # having a /vendor partition).
-  if not HasTrebleEnabled(target_files, target_info):
-    return
-
-  # Skip adding the compatibility package as a workaround for b/114240221. The
-  # compatibility will always fail on devices without qualified kernels.
-  if OPTIONS.skip_compatibility_check:
-    return
-
-  if not check_target_files_vintf.CheckVintf(target_files, target_info):
-    raise RuntimeError("VINTF compatibility check failed")
-
-
-def GetBlockDifferences(target_zip, source_zip, target_info, source_info,
-                        device_specific):
-  """Returns a ordered dict of block differences with partition name as key."""
-
-  def GetIncrementalBlockDifferenceForPartition(name):
-    if not HasPartition(source_zip, name):
-      raise RuntimeError(
-          "can't generate incremental that adds {}".format(name))
-
-    partition_src = common.GetUserImage(name, OPTIONS.source_tmp, source_zip,
-                                        info_dict=source_info,
-                                        allow_shared_blocks=allow_shared_blocks)
-
-    hashtree_info_generator = verity_utils.CreateHashtreeInfoGenerator(
-        name, 4096, target_info)
-    partition_tgt = common.GetUserImage(name, OPTIONS.target_tmp, target_zip,
-                                        info_dict=target_info,
-                                        allow_shared_blocks=allow_shared_blocks,
-                                        hashtree_info_generator=hashtree_info_generator)
-
-    # Check the first block of the source system partition for remount R/W only
-    # if the filesystem is ext4.
-    partition_source_info = source_info["fstab"]["/" + name]
-    check_first_block = partition_source_info.fs_type == "ext4"
-    # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
-    # in zip formats. However with squashfs, a) all files are compressed in LZ4;
-    # b) the blocks listed in block map may not contain all the bytes for a
-    # given file (because they're rounded to be 4K-aligned).
-    partition_target_info = target_info["fstab"]["/" + name]
-    disable_imgdiff = (partition_source_info.fs_type == "squashfs" or
-                       partition_target_info.fs_type == "squashfs")
-    return common.BlockDifference(name, partition_tgt, partition_src,
-                                  check_first_block,
-                                  version=blockimgdiff_version,
-                                  disable_imgdiff=disable_imgdiff)
-
-  if source_zip:
-    # See notes in common.GetUserImage()
-    allow_shared_blocks = (source_info.get('ext4_share_dup_blocks') == "true" or
-                           target_info.get('ext4_share_dup_blocks') == "true")
-    blockimgdiff_version = max(
-        int(i) for i in target_info.get(
-            "blockimgdiff_versions", "1").split(","))
-    assert blockimgdiff_version >= 3
-
-  block_diff_dict = collections.OrderedDict()
-  partition_names = ["system", "vendor", "product", "odm", "system_ext",
-                     "vendor_dlkm", "odm_dlkm"]
-  for partition in partition_names:
-    if not HasPartition(target_zip, partition):
-      continue
-    # Full OTA update.
-    if not source_zip:
-      tgt = common.GetUserImage(partition, OPTIONS.input_tmp, target_zip,
-                                info_dict=target_info,
-                                reset_file_map=True)
-      block_diff_dict[partition] = common.BlockDifference(partition, tgt,
-                                                          src=None)
-    # Incremental OTA update.
-    else:
-      block_diff_dict[partition] = GetIncrementalBlockDifferenceForPartition(
-          partition)
-  assert "system" in block_diff_dict
-
-  # Get the block diffs from the device specific script. If there is a
-  # duplicate block diff for a partition, ignore the diff in the generic script
-  # and use the one in the device specific script instead.
-  if source_zip:
-    device_specific_diffs = device_specific.IncrementalOTA_GetBlockDifferences()
-    function_name = "IncrementalOTA_GetBlockDifferences"
-  else:
-    device_specific_diffs = device_specific.FullOTA_GetBlockDifferences()
-    function_name = "FullOTA_GetBlockDifferences"
-
-  if device_specific_diffs:
-    assert all(isinstance(diff, common.BlockDifference)
-               for diff in device_specific_diffs), \
-        "{} is not returning a list of BlockDifference objects".format(
-            function_name)
-    for diff in device_specific_diffs:
-      if diff.partition in block_diff_dict:
-        logger.warning("Duplicate block difference found. Device specific block"
-                       " diff for partition '%s' overrides the one in generic"
-                       " script.", diff.partition)
-      block_diff_dict[diff.partition] = diff
-
-  return block_diff_dict
-
-
-def WriteFullOTAPackage(input_zip, output_file):
-  target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
-
-  # We don't know what version it will be installed on top of. We expect the API
-  # just won't change very often. Similarly for fstab, it might have changed in
-  # the target build.
-  target_api_version = target_info["recovery_api_version"]
-  script = edify_generator.EdifyGenerator(target_api_version, target_info)
-
-  if target_info.oem_props and not OPTIONS.oem_no_mount:
-    target_info.WriteMountOemScript(script)
-
-  metadata = GetPackageMetadata(target_info)
-
-  if not OPTIONS.no_signing:
-    staging_file = common.MakeTempFile(suffix='.zip')
-  else:
-    staging_file = output_file
-
-  output_zip = zipfile.ZipFile(
-      staging_file, "w", compression=zipfile.ZIP_DEFLATED)
-
-  device_specific = common.DeviceSpecificParams(
-      input_zip=input_zip,
-      input_version=target_api_version,
-      output_zip=output_zip,
-      script=script,
-      input_tmp=OPTIONS.input_tmp,
-      metadata=metadata,
-      info_dict=OPTIONS.info_dict)
-
-  assert HasRecoveryPatch(input_zip, info_dict=OPTIONS.info_dict)
-
-  # Assertions (e.g. downgrade check, device properties check).
-  ts = target_info.GetBuildProp("ro.build.date.utc")
-  ts_text = target_info.GetBuildProp("ro.build.date")
-  script.AssertOlderBuild(ts, ts_text)
-
-  target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
-  device_specific.FullOTA_Assertions()
-
-  block_diff_dict = GetBlockDifferences(target_zip=input_zip, source_zip=None,
-                                        target_info=target_info,
-                                        source_info=None,
-                                        device_specific=device_specific)
-
-  # Two-step package strategy (in chronological order, which is *not*
-  # the order in which the generated script has things):
-  #
-  # if stage is not "2/3" or "3/3":
-  #    write recovery image to boot partition
-  #    set stage to "2/3"
-  #    reboot to boot partition and restart recovery
-  # else if stage is "2/3":
-  #    write recovery image to recovery partition
-  #    set stage to "3/3"
-  #    reboot to recovery partition and restart recovery
-  # else:
-  #    (stage must be "3/3")
-  #    set stage to ""
-  #    do normal full package installation:
-  #       wipe and install system, boot image, etc.
-  #       set up system to update recovery partition on first boot
-  #    complete script normally
-  #    (allow recovery to mark itself finished and reboot)
-
-  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
-                                         OPTIONS.input_tmp, "RECOVERY")
-  if OPTIONS.two_step:
-    if not target_info.get("multistage_support"):
-      assert False, "two-step packages not supported by this build"
-    fs = target_info["fstab"]["/misc"]
-    assert fs.fs_type.upper() == "EMMC", \
-        "two-step packages only supported on devices with EMMC /misc partitions"
-    bcb_dev = {"bcb_dev": fs.device}
-    common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
-    script.AppendExtra("""
-if get_stage("%(bcb_dev)s") == "2/3" then
-""" % bcb_dev)
-
-    # Stage 2/3: Write recovery image to /recovery (currently running /boot).
-    script.Comment("Stage 2/3")
-    script.WriteRawImage("/recovery", "recovery.img")
-    script.AppendExtra("""
-set_stage("%(bcb_dev)s", "3/3");
-reboot_now("%(bcb_dev)s", "recovery");
-else if get_stage("%(bcb_dev)s") == "3/3" then
-""" % bcb_dev)
-
-    # Stage 3/3: Make changes.
-    script.Comment("Stage 3/3")
-
-  # Dump fingerprints
-  script.Print("Target: {}".format(target_info.fingerprint))
-
-  device_specific.FullOTA_InstallBegin()
-
-  # All other partitions as well as the data wipe use 10% of the progress, and
-  # the update of the system partition takes the remaining progress.
-  system_progress = 0.9 - (len(block_diff_dict) - 1) * 0.1
-  if OPTIONS.wipe_user_data:
-    system_progress -= 0.1
-  progress_dict = {partition: 0.1 for partition in block_diff_dict}
-  progress_dict["system"] = system_progress
-
-  if target_info.get('use_dynamic_partitions') == "true":
-    # Use empty source_info_dict to indicate that all partitions / groups must
-    # be re-added.
-    dynamic_partitions_diff = common.DynamicPartitionsDifference(
-        info_dict=OPTIONS.info_dict,
-        block_diffs=block_diff_dict.values(),
-        progress_dict=progress_dict)
-    dynamic_partitions_diff.WriteScript(script, output_zip,
-                                        write_verify_script=OPTIONS.verify)
-  else:
-    for block_diff in block_diff_dict.values():
-      block_diff.WriteScript(script, output_zip,
-                             progress=progress_dict.get(block_diff.partition),
-                             write_verify_script=OPTIONS.verify)
-
-  CheckVintfIfTrebleEnabled(OPTIONS.input_tmp, target_info)
-
-  boot_img = common.GetBootableImage(
-      "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
-  common.CheckSize(boot_img.data, "boot.img", target_info)
-  common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
-
-  script.WriteRawImage("/boot", "boot.img")
-
-  script.ShowProgress(0.1, 10)
-  device_specific.FullOTA_InstallEnd()
-
-  if OPTIONS.extra_script is not None:
-    script.AppendExtra(OPTIONS.extra_script)
-
-  script.UnmountAll()
-
-  if OPTIONS.wipe_user_data:
-    script.ShowProgress(0.1, 10)
-    script.FormatPartition("/data")
-
-  if OPTIONS.two_step:
-    script.AppendExtra("""
-set_stage("%(bcb_dev)s", "");
-""" % bcb_dev)
-    script.AppendExtra("else\n")
-
-    # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
-    script.Comment("Stage 1/3")
-    _WriteRecoveryImageToBoot(script, output_zip)
-
-    script.AppendExtra("""
-set_stage("%(bcb_dev)s", "2/3");
-reboot_now("%(bcb_dev)s", "");
-endif;
-endif;
-""" % bcb_dev)
-
-  script.SetProgress(1)
-  script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
-  metadata["ota-required-cache"] = str(script.required_cache)
-
-  # We haven't written the metadata entry, which will be done in
-  # FinalizeMetadata.
-  common.ZipClose(output_zip)
-
-  needed_property_files = (
-      NonAbOtaPropertyFiles(),
-  )
-  FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
-
-
-def WriteMetadata(metadata, output):
-  """Writes the metadata to the zip archive or a file.
-
-  Args:
-    metadata: The metadata dict for the package.
-    output: A ZipFile object or a string of the output file path.
-  """
-
-  value = "".join(["%s=%s\n" % kv for kv in sorted(metadata.items())])
-  if isinstance(output, zipfile.ZipFile):
-    common.ZipWriteStr(output, METADATA_NAME, value,
-                       compress_type=zipfile.ZIP_STORED)
-    return
-
-  with open(output, 'w') as f:
-    f.write(value)
-
-
-def HandleDowngradeMetadata(metadata, target_info, source_info):
-  # Only incremental OTAs are allowed to reach here.
-  assert OPTIONS.incremental_source is not None
-
-  post_timestamp = target_info.GetBuildProp("ro.build.date.utc")
-  pre_timestamp = source_info.GetBuildProp("ro.build.date.utc")
-  is_downgrade = int(post_timestamp) < int(pre_timestamp)
-
-  if OPTIONS.downgrade:
-    if not is_downgrade:
-      raise RuntimeError(
-          "--downgrade or --override_timestamp specified but no downgrade "
-          "detected: pre: %s, post: %s" % (pre_timestamp, post_timestamp))
-    metadata["ota-downgrade"] = "yes"
-  else:
-    if is_downgrade:
-      raise RuntimeError(
-          "Downgrade detected based on timestamp check: pre: %s, post: %s. "
-          "Need to specify --override_timestamp OR --downgrade to allow "
-          "building the incremental." % (pre_timestamp, post_timestamp))
-
-
-def GetPackageMetadata(target_info, source_info=None):
-  """Generates and returns the metadata dict.
-
-  It generates a dict() that contains the info to be written into an OTA
-  package (META-INF/com/android/metadata). It also handles the detection of
-  downgrade / data wipe based on the global options.
-
-  Args:
-    target_info: The BuildInfo instance that holds the target build info.
-    source_info: The BuildInfo instance that holds the source build info, or
-        None if generating full OTA.
-
-  Returns:
-    A dict to be written into package metadata entry.
-  """
-  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': separator.join(sorted(post_build_fingerprints)),
-      'post-build-incremental': target_info.GetBuildProp(
-          'ro.build.version.incremental'),
-      'post-sdk-level': target_info.GetBuildProp(
-          'ro.build.version.sdk'),
-      'post-security-patch-level': target_info.GetBuildProp(
-          'ro.build.version.security_patch'),
-  }
-
-  if target_info.is_ab and not OPTIONS.force_non_ab:
-    metadata['ota-type'] = 'AB'
-    metadata['ota-required-cache'] = '0'
-  else:
-    metadata['ota-type'] = 'BLOCK'
-
-  if OPTIONS.wipe_user_data:
-    metadata['ota-wipe'] = 'yes'
-
-  if OPTIONS.retrofit_dynamic_partitions:
-    metadata['ota-retrofit-dynamic-partitions'] = 'yes'
-
-  is_incremental = source_info is not None
-  if is_incremental:
-    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'] = separator.join(sorted(pre_build_devices))
-  else:
-    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')
-
-  # Detect downgrades and set up downgrade flags accordingly.
-  if is_incremental:
-    HandleDowngradeMetadata(metadata, target_info, source_info)
-
-  return metadata
-
-
-class PropertyFiles(object):
-  """A class that computes the property-files string for an OTA package.
-
-  A property-files string is a comma-separated string that contains the
-  offset/size info for an OTA package. The entries, which must be ZIP_STORED,
-  can be fetched directly with the package URL along with the offset/size info.
-  These strings can be used for streaming A/B OTAs, or allowing an updater to
-  download package metadata entry directly, without paying the cost of
-  downloading entire package.
-
-  Computing the final property-files string requires two passes. Because doing
-  the whole package signing (with signapk.jar) will possibly reorder the ZIP
-  entries, which may in turn invalidate earlier computed ZIP entry offset/size
-  values.
-
-  This class provides functions to be called for each pass. The general flow is
-  as follows.
-
-    property_files = PropertyFiles()
-    # The first pass, which writes placeholders before doing initial signing.
-    property_files.Compute()
-    SignOutput()
-
-    # The second pass, by replacing the placeholders with actual data.
-    property_files.Finalize()
-    SignOutput()
-
-  And the caller can additionally verify the final result.
-
-    property_files.Verify()
-  """
-
-  def __init__(self):
-    self.name = None
-    self.required = ()
-    self.optional = ()
-
-  def Compute(self, input_zip):
-    """Computes and returns a property-files string with placeholders.
-
-    We reserve extra space for the offset and size of the metadata entry itself,
-    although we don't know the final values until the package gets signed.
-
-    Args:
-      input_zip: The input ZIP file.
-
-    Returns:
-      A string with placeholders for the metadata offset/size info, e.g.
-      "payload.bin:679:343,payload_properties.txt:378:45,metadata:        ".
-    """
-    return self.GetPropertyFilesString(input_zip, reserve_space=True)
-
-  class InsufficientSpaceException(Exception):
-    pass
-
-  def Finalize(self, input_zip, reserved_length):
-    """Finalizes a property-files string with actual METADATA offset/size info.
-
-    The input ZIP file has been signed, with the ZIP entries in the desired
-    place (signapk.jar will possibly reorder the ZIP entries). Now we compute
-    the ZIP entry offsets and construct the property-files string with actual
-    data. Note that during this process, we must pad the property-files string
-    to the reserved length, so that the METADATA entry size remains the same.
-    Otherwise the entries' offsets and sizes may change again.
-
-    Args:
-      input_zip: The input ZIP file.
-      reserved_length: The reserved length of the property-files string during
-          the call to Compute(). The final string must be no more than this
-          size.
-
-    Returns:
-      A property-files string including the metadata offset/size info, e.g.
-      "payload.bin:679:343,payload_properties.txt:378:45,metadata:69:379  ".
-
-    Raises:
-      InsufficientSpaceException: If the reserved length is insufficient to hold
-          the final string.
-    """
-    result = self.GetPropertyFilesString(input_zip, reserve_space=False)
-    if len(result) > reserved_length:
-      raise self.InsufficientSpaceException(
-          'Insufficient reserved space: reserved={}, actual={}'.format(
-              reserved_length, len(result)))
-
-    result += ' ' * (reserved_length - len(result))
-    return result
-
-  def Verify(self, input_zip, expected):
-    """Verifies the input ZIP file contains the expected property-files string.
-
-    Args:
-      input_zip: The input ZIP file.
-      expected: The property-files string that's computed from Finalize().
-
-    Raises:
-      AssertionError: On finding a mismatch.
-    """
-    actual = self.GetPropertyFilesString(input_zip)
-    assert actual == expected, \
-        "Mismatching streaming metadata: {} vs {}.".format(actual, expected)
-
-  def GetPropertyFilesString(self, zip_file, reserve_space=False):
-    """
-    Constructs the property-files string per request.
-
-    Args:
-      zip_file: The input ZIP file.
-      reserved_length: The reserved length of the property-files string.
-
-    Returns:
-      A property-files string including the metadata offset/size info, e.g.
-      "payload.bin:679:343,payload_properties.txt:378:45,metadata:     ".
-    """
-
-    def ComputeEntryOffsetSize(name):
-      """Computes the zip entry offset and size."""
-      info = zip_file.getinfo(name)
-      offset = info.header_offset
-      offset += zipfile.sizeFileHeader
-      offset += len(info.extra) + len(info.filename)
-      size = info.file_size
-      return '%s:%d:%d' % (os.path.basename(name), offset, size)
-
-    tokens = []
-    tokens.extend(self._GetPrecomputed(zip_file))
-    for entry in self.required:
-      tokens.append(ComputeEntryOffsetSize(entry))
-    for entry in self.optional:
-      if entry in zip_file.namelist():
-        tokens.append(ComputeEntryOffsetSize(entry))
-
-    # 'META-INF/com/android/metadata' is required. We don't know its actual
-    # offset and length (as well as the values for other entries). So we reserve
-    # 15-byte as a placeholder ('offset:length'), which is sufficient to cover
-    # the space for metadata entry. Because 'offset' allows a max of 10-digit
-    # (i.e. ~9 GiB), with a max of 4-digit for the length. Note that all the
-    # reserved space serves the metadata entry only.
-    if reserve_space:
-      tokens.append('metadata:' + ' ' * 15)
-    else:
-      tokens.append(ComputeEntryOffsetSize(METADATA_NAME))
-
-    return ','.join(tokens)
-
-  def _GetPrecomputed(self, input_zip):
-    """Computes the additional tokens to be included into the property-files.
-
-    This applies to tokens without actual ZIP entries, such as
-    payload_metadadata.bin. We want to expose the offset/size to updaters, so
-    that they can download the payload metadata directly with the info.
-
-    Args:
-      input_zip: The input zip file.
-
-    Returns:
-      A list of strings (tokens) to be added to the property-files string.
-    """
-    # pylint: disable=no-self-use
-    # pylint: disable=unused-argument
-    return []
-
-
 class StreamingPropertyFiles(PropertyFiles):
   """A subclass for computing the property-files for streaming A/B OTAs."""
 
@@ -1264,362 +593,6 @@
     return (payload_offset, metadata_total)
 
 
-class NonAbOtaPropertyFiles(PropertyFiles):
-  """The property-files for non-A/B OTA.
-
-  For non-A/B OTA, the property-files string contains the info for METADATA
-  entry, with which a system updater can be fetched the package metadata prior
-  to downloading the entire package.
-  """
-
-  def __init__(self):
-    super(NonAbOtaPropertyFiles, self).__init__()
-    self.name = 'ota-property-files'
-
-
-def FinalizeMetadata(metadata, input_file, output_file, needed_property_files):
-  """Finalizes the metadata and signs an A/B OTA package.
-
-  In order to stream an A/B OTA package, we need 'ota-streaming-property-files'
-  that contains the offsets and sizes for the ZIP entries. An example
-  property-files string is as follows.
-
-    "payload.bin:679:343,payload_properties.txt:378:45,metadata:69:379"
-
-  OTA server can pass down this string, in addition to the package URL, to the
-  system update client. System update client can then fetch individual ZIP
-  entries (ZIP_STORED) directly at the given offset of the URL.
-
-  Args:
-    metadata: The metadata dict for the package.
-    input_file: The input ZIP filename that doesn't contain the package METADATA
-        entry yet.
-    output_file: The final output ZIP filename.
-    needed_property_files: The list of PropertyFiles' to be generated.
-  """
-
-  def ComputeAllPropertyFiles(input_file, needed_property_files):
-    # Write the current metadata entry with placeholders.
-    with zipfile.ZipFile(input_file) as input_zip:
-      for property_files in needed_property_files:
-        metadata[property_files.name] = property_files.Compute(input_zip)
-      namelist = input_zip.namelist()
-
-    if METADATA_NAME in namelist:
-      common.ZipDelete(input_file, METADATA_NAME)
-    output_zip = zipfile.ZipFile(input_file, 'a')
-    WriteMetadata(metadata, output_zip)
-    common.ZipClose(output_zip)
-
-    if OPTIONS.no_signing:
-      return input_file
-
-    prelim_signing = common.MakeTempFile(suffix='.zip')
-    SignOutput(input_file, prelim_signing)
-    return prelim_signing
-
-  def FinalizeAllPropertyFiles(prelim_signing, needed_property_files):
-    with zipfile.ZipFile(prelim_signing) as prelim_signing_zip:
-      for property_files in needed_property_files:
-        metadata[property_files.name] = property_files.Finalize(
-            prelim_signing_zip, len(metadata[property_files.name]))
-
-  # SignOutput(), which in turn calls signapk.jar, will possibly reorder the ZIP
-  # entries, as well as padding the entry headers. We do a preliminary signing
-  # (with an incomplete metadata entry) to allow that to happen. Then compute
-  # the ZIP entry offsets, write back the final metadata and do the final
-  # signing.
-  prelim_signing = ComputeAllPropertyFiles(input_file, needed_property_files)
-  try:
-    FinalizeAllPropertyFiles(prelim_signing, needed_property_files)
-  except PropertyFiles.InsufficientSpaceException:
-    # Even with the preliminary signing, the entry orders may change
-    # dramatically, which leads to insufficiently reserved space during the
-    # first call to ComputeAllPropertyFiles(). In that case, we redo all the
-    # preliminary signing works, based on the already ordered ZIP entries, to
-    # address the issue.
-    prelim_signing = ComputeAllPropertyFiles(
-        prelim_signing, needed_property_files)
-    FinalizeAllPropertyFiles(prelim_signing, needed_property_files)
-
-  # Replace the METADATA entry.
-  common.ZipDelete(prelim_signing, METADATA_NAME)
-  output_zip = zipfile.ZipFile(prelim_signing, 'a')
-  WriteMetadata(metadata, output_zip)
-  common.ZipClose(output_zip)
-
-  # Re-sign the package after updating the metadata entry.
-  if OPTIONS.no_signing:
-    output_file = prelim_signing
-  else:
-    SignOutput(prelim_signing, output_file)
-
-  # Reopen the final signed zip to double check the streaming metadata.
-  with zipfile.ZipFile(output_file) as output_zip:
-    for property_files in needed_property_files:
-      property_files.Verify(output_zip, metadata[property_files.name].strip())
-
-  # If requested, dump the metadata to a separate file.
-  output_metadata_path = OPTIONS.output_metadata_path
-  if output_metadata_path:
-    WriteMetadata(metadata, output_metadata_path)
-
-
-def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_file):
-  target_info = common.BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
-  source_info = common.BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)
-
-  target_api_version = target_info["recovery_api_version"]
-  source_api_version = source_info["recovery_api_version"]
-  if source_api_version == 0:
-    logger.warning(
-        "Generating edify script for a source that can't install it.")
-
-  script = edify_generator.EdifyGenerator(
-      source_api_version, target_info, fstab=source_info["fstab"])
-
-  if target_info.oem_props or source_info.oem_props:
-    if not OPTIONS.oem_no_mount:
-      source_info.WriteMountOemScript(script)
-
-  metadata = GetPackageMetadata(target_info, source_info)
-
-  if not OPTIONS.no_signing:
-    staging_file = common.MakeTempFile(suffix='.zip')
-  else:
-    staging_file = output_file
-
-  output_zip = zipfile.ZipFile(
-      staging_file, "w", compression=zipfile.ZIP_DEFLATED)
-
-  device_specific = common.DeviceSpecificParams(
-      source_zip=source_zip,
-      source_version=source_api_version,
-      source_tmp=OPTIONS.source_tmp,
-      target_zip=target_zip,
-      target_version=target_api_version,
-      target_tmp=OPTIONS.target_tmp,
-      output_zip=output_zip,
-      script=script,
-      metadata=metadata,
-      info_dict=source_info)
-
-  source_boot = common.GetBootableImage(
-      "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", source_info)
-  target_boot = common.GetBootableImage(
-      "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT", target_info)
-  updating_boot = (not OPTIONS.two_step and
-                   (source_boot.data != target_boot.data))
-
-  target_recovery = common.GetBootableImage(
-      "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
-
-  block_diff_dict = GetBlockDifferences(target_zip=target_zip,
-                                        source_zip=source_zip,
-                                        target_info=target_info,
-                                        source_info=source_info,
-                                        device_specific=device_specific)
-
-  CheckVintfIfTrebleEnabled(OPTIONS.target_tmp, target_info)
-
-  # Assertions (e.g. device properties check).
-  target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
-  device_specific.IncrementalOTA_Assertions()
-
-  # Two-step incremental package strategy (in chronological order,
-  # which is *not* the order in which the generated script has
-  # things):
-  #
-  # if stage is not "2/3" or "3/3":
-  #    do verification on current system
-  #    write recovery image to boot partition
-  #    set stage to "2/3"
-  #    reboot to boot partition and restart recovery
-  # else if stage is "2/3":
-  #    write recovery image to recovery partition
-  #    set stage to "3/3"
-  #    reboot to recovery partition and restart recovery
-  # else:
-  #    (stage must be "3/3")
-  #    perform update:
-  #       patch system files, etc.
-  #       force full install of new boot image
-  #       set up system to update recovery partition on first boot
-  #    complete script normally
-  #    (allow recovery to mark itself finished and reboot)
-
-  if OPTIONS.two_step:
-    if not source_info.get("multistage_support"):
-      assert False, "two-step packages not supported by this build"
-    fs = source_info["fstab"]["/misc"]
-    assert fs.fs_type.upper() == "EMMC", \
-        "two-step packages only supported on devices with EMMC /misc partitions"
-    bcb_dev = {"bcb_dev": fs.device}
-    common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
-    script.AppendExtra("""
-if get_stage("%(bcb_dev)s") == "2/3" then
-""" % bcb_dev)
-
-    # Stage 2/3: Write recovery image to /recovery (currently running /boot).
-    script.Comment("Stage 2/3")
-    script.AppendExtra("sleep(20);\n")
-    script.WriteRawImage("/recovery", "recovery.img")
-    script.AppendExtra("""
-set_stage("%(bcb_dev)s", "3/3");
-reboot_now("%(bcb_dev)s", "recovery");
-else if get_stage("%(bcb_dev)s") != "3/3" then
-""" % bcb_dev)
-
-    # Stage 1/3: (a) Verify the current system.
-    script.Comment("Stage 1/3")
-
-  # Dump fingerprints
-  script.Print("Source: {}".format(source_info.fingerprint))
-  script.Print("Target: {}".format(target_info.fingerprint))
-
-  script.Print("Verifying current system...")
-
-  device_specific.IncrementalOTA_VerifyBegin()
-
-  WriteFingerprintAssertion(script, target_info, source_info)
-
-  # Check the required cache size (i.e. stashed blocks).
-  required_cache_sizes = [diff.required_cache for diff in
-                          block_diff_dict.values()]
-  if updating_boot:
-    boot_type, boot_device_expr = common.GetTypeAndDeviceExpr("/boot",
-                                                              source_info)
-    d = common.Difference(target_boot, source_boot)
-    _, _, d = d.ComputePatch()
-    if d is None:
-      include_full_boot = True
-      common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
-    else:
-      include_full_boot = False
-
-      logger.info(
-          "boot      target: %d  source: %d  diff: %d", target_boot.size,
-          source_boot.size, len(d))
-
-      common.ZipWriteStr(output_zip, "boot.img.p", d)
-
-      target_expr = 'concat("{}:",{},":{}:{}")'.format(
-          boot_type, boot_device_expr, target_boot.size, target_boot.sha1)
-      source_expr = 'concat("{}:",{},":{}:{}")'.format(
-          boot_type, boot_device_expr, source_boot.size, source_boot.sha1)
-      script.PatchPartitionExprCheck(target_expr, source_expr)
-
-      required_cache_sizes.append(target_boot.size)
-
-  if required_cache_sizes:
-    script.CacheFreeSpaceCheck(max(required_cache_sizes))
-
-  # Verify the existing partitions.
-  for diff in block_diff_dict.values():
-    diff.WriteVerifyScript(script, touched_blocks_only=True)
-
-  device_specific.IncrementalOTA_VerifyEnd()
-
-  if OPTIONS.two_step:
-    # Stage 1/3: (b) Write recovery image to /boot.
-    _WriteRecoveryImageToBoot(script, output_zip)
-
-    script.AppendExtra("""
-set_stage("%(bcb_dev)s", "2/3");
-reboot_now("%(bcb_dev)s", "");
-else
-""" % bcb_dev)
-
-    # Stage 3/3: Make changes.
-    script.Comment("Stage 3/3")
-
-  script.Comment("---- start making changes here ----")
-
-  device_specific.IncrementalOTA_InstallBegin()
-
-  progress_dict = {partition: 0.1 for partition in block_diff_dict}
-  progress_dict["system"] = 1 - len(block_diff_dict) * 0.1
-
-  if OPTIONS.source_info_dict.get("use_dynamic_partitions") == "true":
-    if OPTIONS.target_info_dict.get("use_dynamic_partitions") != "true":
-      raise RuntimeError(
-          "can't generate incremental that disables dynamic partitions")
-    dynamic_partitions_diff = common.DynamicPartitionsDifference(
-        info_dict=OPTIONS.target_info_dict,
-        source_info_dict=OPTIONS.source_info_dict,
-        block_diffs=block_diff_dict.values(),
-        progress_dict=progress_dict)
-    dynamic_partitions_diff.WriteScript(
-        script, output_zip, write_verify_script=OPTIONS.verify)
-  else:
-    for block_diff in block_diff_dict.values():
-      block_diff.WriteScript(script, output_zip,
-                             progress=progress_dict.get(block_diff.partition),
-                             write_verify_script=OPTIONS.verify)
-
-  if OPTIONS.two_step:
-    common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
-    script.WriteRawImage("/boot", "boot.img")
-    logger.info("writing full boot image (forced by two-step mode)")
-
-  if not OPTIONS.two_step:
-    if updating_boot:
-      if include_full_boot:
-        logger.info("boot image changed; including full.")
-        script.Print("Installing boot image...")
-        script.WriteRawImage("/boot", "boot.img")
-      else:
-        # Produce the boot image by applying a patch to the current
-        # contents of the boot partition, and write it back to the
-        # partition.
-        logger.info("boot image changed; including patch.")
-        script.Print("Patching boot image...")
-        script.ShowProgress(0.1, 10)
-        target_expr = 'concat("{}:",{},":{}:{}")'.format(
-            boot_type, boot_device_expr, target_boot.size, target_boot.sha1)
-        source_expr = 'concat("{}:",{},":{}:{}")'.format(
-            boot_type, boot_device_expr, source_boot.size, source_boot.sha1)
-        script.PatchPartitionExpr(target_expr, source_expr, '"boot.img.p"')
-    else:
-      logger.info("boot image unchanged; skipping.")
-
-  # Do device-specific installation (eg, write radio image).
-  device_specific.IncrementalOTA_InstallEnd()
-
-  if OPTIONS.extra_script is not None:
-    script.AppendExtra(OPTIONS.extra_script)
-
-  if OPTIONS.wipe_user_data:
-    script.Print("Erasing user data...")
-    script.FormatPartition("/data")
-
-  if OPTIONS.two_step:
-    script.AppendExtra("""
-set_stage("%(bcb_dev)s", "");
-endif;
-endif;
-""" % bcb_dev)
-
-  script.SetProgress(1)
-  # For downgrade OTAs, we prefer to use the update-binary in the source
-  # build that is actually newer than the one in the target build.
-  if OPTIONS.downgrade:
-    script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
-  else:
-    script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
-  metadata["ota-required-cache"] = str(script.required_cache)
-
-  # We haven't written the metadata entry yet, which will be handled in
-  # FinalizeMetadata().
-  common.ZipClose(output_zip)
-
-  # Sign the generated zip package unless no_signing is specified.
-  needed_property_files = (
-      NonAbOtaPropertyFiles(),
-  )
-  FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
-
-
 def GetTargetFilesZipForSecondaryImages(input_file, skip_postinstall=False):
   """Returns a target-files.zip file for generating secondary payload.
 
@@ -1805,7 +778,7 @@
   with open(new_ab_partitions, 'w') as f:
     for partition in ab_partitions:
       if (partition in dynamic_partition_list and
-          partition not in super_block_devices):
+              partition not in super_block_devices):
         logger.info("Dropping %s from ab_partitions.txt", partition)
         continue
       f.write(partition + "\n")
@@ -1852,31 +825,49 @@
                                compression=zipfile.ZIP_DEFLATED)
 
   if source_file is not None:
+    assert "ab_partitions" in OPTIONS.source_info_dict, \
+        "META/ab_partitions.txt is required for ab_update."
+    assert "ab_partitions" in OPTIONS.target_info_dict, \
+        "META/ab_partitions.txt is required for ab_update."
     target_info = common.BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
     source_info = common.BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)
   else:
+    assert "ab_partitions" in OPTIONS.info_dict, \
+        "META/ab_partitions.txt is required for ab_update."
     target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
     source_info = None
 
-  # Metadata to comply with Android OTA package format.
-  metadata = GetPackageMetadata(target_info, source_info)
-
   if OPTIONS.retrofit_dynamic_partitions:
     target_file = GetTargetFilesZipForRetrofitDynamicPartitions(
         target_file, target_info.get("super_block_devices").strip().split(),
         target_info.get("dynamic_partition_list").strip().split())
   elif OPTIONS.skip_postinstall:
     target_file = GetTargetFilesZipWithoutPostinstallConfig(target_file)
+  # Target_file may have been modified, reparse ab_partitions
+  with zipfile.ZipFile(target_file, allowZip64=True) as zfp:
+    target_info.info_dict['ab_partitions'] = zfp.read(
+        AB_PARTITIONS).strip().split("\n")
 
+  # Metadata to comply with Android OTA package format.
+  metadata = GetPackageMetadata(target_info, source_info)
   # Generate payload.
   payload = Payload()
 
+  partition_timestamps = []
   # Enforce a max timestamp this payload can be applied on top of.
   if OPTIONS.downgrade:
     max_timestamp = source_info.GetBuildProp("ro.build.date.utc")
   else:
-    max_timestamp = metadata["post-timestamp"]
+    max_timestamp = str(metadata.postcondition.timestamp)
+    partition_timestamps = [
+        part.partition_name + ":" + part.version
+        for part in metadata.postcondition.partition_state]
   additional_args = ["--max_timestamp", max_timestamp]
+  if partition_timestamps:
+    additional_args.extend(
+        ["--partition_timestamps", ",".join(
+            partition_timestamps)]
+    )
 
   payload.Generate(target_file, source_file, additional_args)
 
@@ -1904,7 +895,7 @@
   # into A/B OTA package.
   target_zip = zipfile.ZipFile(target_file, "r")
   if (target_info.get("verity") == "true" or
-      target_info.get("avb_enable") == "true"):
+          target_info.get("avb_enable") == "true"):
     care_map_list = [x for x in ["care_map.pb", "care_map.txt"] if
                      "META/" + x in target_zip.namelist()]
 
@@ -1938,104 +929,6 @@
   FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
 
 
-def GenerateNonAbOtaPackage(target_file, output_file, source_file=None):
-  """Generates a non-A/B OTA package."""
-  # Check the loaded info dicts first.
-  if OPTIONS.info_dict.get("no_recovery") == "true":
-    raise common.ExternalError(
-        "--- target build has specified no recovery ---")
-
-  # Non-A/B OTAs rely on /cache partition to store temporary files.
-  cache_size = OPTIONS.info_dict.get("cache_size")
-  if cache_size is None:
-    logger.warning("--- can't determine the cache partition size ---")
-  OPTIONS.cache_size = cache_size
-
-  if OPTIONS.extra_script is not None:
-    with open(OPTIONS.extra_script) as fp:
-      OPTIONS.extra_script = fp.read()
-
-  if OPTIONS.extracted_input is not None:
-    OPTIONS.input_tmp = OPTIONS.extracted_input
-  else:
-    logger.info("unzipping target target-files...")
-    OPTIONS.input_tmp = common.UnzipTemp(target_file, UNZIP_PATTERN)
-  OPTIONS.target_tmp = OPTIONS.input_tmp
-
-  # If the caller explicitly specified the device-specific extensions path via
-  # -s / --device_specific, use that. Otherwise, use META/releasetools.py if it
-  # is present in the target target_files. Otherwise, take the path of the file
-  # from 'tool_extensions' in the info dict and look for that in the local
-  # filesystem, relative to the current directory.
-  if OPTIONS.device_specific is None:
-    from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
-    if os.path.exists(from_input):
-      logger.info("(using device-specific extensions from target_files)")
-      OPTIONS.device_specific = from_input
-    else:
-      OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions")
-
-  if OPTIONS.device_specific is not None:
-    OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
-
-  # Generate a full OTA.
-  if source_file is None:
-    with zipfile.ZipFile(target_file) as input_zip:
-      WriteFullOTAPackage(
-          input_zip,
-          output_file)
-
-  # Generate an incremental OTA.
-  else:
-    logger.info("unzipping source target-files...")
-    OPTIONS.source_tmp = common.UnzipTemp(
-        OPTIONS.incremental_source, UNZIP_PATTERN)
-    with zipfile.ZipFile(target_file) as input_zip, \
-            zipfile.ZipFile(source_file) as source_zip:
-      WriteBlockIncrementalOTAPackage(
-          input_zip,
-          source_zip,
-          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):
@@ -2198,7 +1091,7 @@
   # use_dynamic_partitions but target build does.
   if (OPTIONS.source_info_dict and
       OPTIONS.source_info_dict.get("use_dynamic_partitions") != "true" and
-      OPTIONS.target_info_dict.get("use_dynamic_partitions") == "true"):
+          OPTIONS.target_info_dict.get("use_dynamic_partitions") == "true"):
     if OPTIONS.target_info_dict.get("dynamic_partition_retrofit") != "true":
       raise common.ExternalError(
           "Expect to generate incremental OTA for retrofitting dynamic "
diff --git a/tools/releasetools/ota_metadata.proto b/tools/releasetools/ota_metadata.proto
new file mode 100644
index 0000000..20d3091
--- /dev/null
+++ b/tools/releasetools/ota_metadata.proto
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+// If you change this file,
+// Please update ota_metadata_pb2.py by executing
+// protoc ota_metadata.proto --python_out $ANDROID_BUILD_TOP/build/tools/releasetools
+
+
+syntax = "proto3";
+
+package build.tools.releasetools;
+option optimize_for = LITE_RUNTIME;
+
+// The build information of a particular partition on the device.
+message PartitionState {
+  string partition_name = 1;
+  repeated string device = 2;
+  repeated string build = 3;
+  // The version string of the partition. It's usually timestamp if present.
+  // One known exception is the boot image, who uses the kmi version, e.g.
+  // 5.4.42-android12-0
+  string version = 4;
+
+  // TODO(xunchang), revisit other necessary fields, e.g. security_patch_level.
+}
+
+// The build information on the device. The bytes of the running images are thus
+// inferred from the device state. For more information of the meaning of each
+// subfield, check
+// https://source.android.com/compatibility/android-cdd#3_2_2_build_parameters
+message DeviceState {
+  // device name. i.e. ro.product.device; if the field has multiple values, it
+  // means the ota package supports multiple devices. This usually happens when
+  // we use the same image to support multiple skus.
+  repeated string device = 1;
+  // device fingerprint. Up to R build, the value reads from
+  // ro.build.fingerprint.
+  repeated string build = 2;
+  // A value that specify a version of the android build.
+  string build_incremental = 3;
+  // The timestamp when the build is generated.
+  int64 timestamp = 4;
+  // The version of the currently-executing Android system.
+  string sdk_level = 5;
+  // A value indicating the security patch level of a build.
+  string security_patch_level = 6;
+
+  // The detailed state of each partition. For partial updates or devices with
+  // mixed build of partitions, some of the above fields may left empty. And the
+  // client will rely on the information of specific partitions to target the
+  // update.
+  repeated PartitionState partition_state = 7;
+}
+
+// The metadata of an OTA package. It contains the information of the package
+// and prerequisite to install the update correctly.
+message OtaMetadata {
+  enum OtaType {
+    UNKNOWN = 0;
+    AB = 1;
+    BLOCK = 2;
+    BRICK = 3;
+  };
+  OtaType type = 1;
+  // True if we need to wipe after the update.
+  bool wipe = 2;
+  // True if the timestamp of the post build is older than the pre build.
+  bool downgrade = 3;
+  // A map of name:content of property files, e.g. ota-property-files.
+  map<string, string> property_files = 4;
+
+  // The required device state in order to install the package.
+  DeviceState precondition = 5;
+  // The expected device state after the update.
+  DeviceState postcondition = 6;
+
+  // True if the ota that updates a device to support dynamic partitions, where
+  // the source build doesn't support it.
+  bool retrofit_dynamic_partitions = 7;
+  // The required size of the cache partition, only valid for non-A/B update.
+  int64 required_cache = 8;
+}
diff --git a/tools/releasetools/ota_metadata_pb2.py b/tools/releasetools/ota_metadata_pb2.py
new file mode 100644
index 0000000..ff2b2c5
--- /dev/null
+++ b/tools/releasetools/ota_metadata_pb2.py
@@ -0,0 +1,343 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: ota_metadata.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='ota_metadata.proto',
+  package='build.tools.releasetools',
+  syntax='proto3',
+  serialized_options=b'H\003',
+  serialized_pb=b'\n\x12ota_metadata.proto\x12\x18\x62uild.tools.releasetools\"X\n\x0ePartitionState\x12\x16\n\x0epartition_name\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65vice\x18\x02 \x03(\t\x12\r\n\x05\x62uild\x18\x03 \x03(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\"\xce\x01\n\x0b\x44\x65viceState\x12\x0e\n\x06\x64\x65vice\x18\x01 \x03(\t\x12\r\n\x05\x62uild\x18\x02 \x03(\t\x12\x19\n\x11\x62uild_incremental\x18\x03 \x01(\t\x12\x11\n\ttimestamp\x18\x04 \x01(\x03\x12\x11\n\tsdk_level\x18\x05 \x01(\t\x12\x1c\n\x14security_patch_level\x18\x06 \x01(\t\x12\x41\n\x0fpartition_state\x18\x07 \x03(\x0b\x32(.build.tools.releasetools.PartitionState\"\xe1\x03\n\x0bOtaMetadata\x12;\n\x04type\x18\x01 \x01(\x0e\x32-.build.tools.releasetools.OtaMetadata.OtaType\x12\x0c\n\x04wipe\x18\x02 \x01(\x08\x12\x11\n\tdowngrade\x18\x03 \x01(\x08\x12P\n\x0eproperty_files\x18\x04 \x03(\x0b\x32\x38.build.tools.releasetools.OtaMetadata.PropertyFilesEntry\x12;\n\x0cprecondition\x18\x05 \x01(\x0b\x32%.build.tools.releasetools.DeviceState\x12<\n\rpostcondition\x18\x06 \x01(\x0b\x32%.build.tools.releasetools.DeviceState\x12#\n\x1bretrofit_dynamic_partitions\x18\x07 \x01(\x08\x12\x16\n\x0erequired_cache\x18\x08 \x01(\x03\x1a\x34\n\x12PropertyFilesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"4\n\x07OtaType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x06\n\x02\x41\x42\x10\x01\x12\t\n\x05\x42LOCK\x10\x02\x12\t\n\x05\x42RICK\x10\x03\x42\x02H\x03\x62\x06proto3'
+)
+
+
+
+_OTAMETADATA_OTATYPE = _descriptor.EnumDescriptor(
+  name='OtaType',
+  full_name='build.tools.releasetools.OtaMetadata.OtaType',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='AB', index=1, number=1,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='BLOCK', index=2, number=2,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='BRICK', index=3, number=3,
+      serialized_options=None,
+      type=None),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=777,
+  serialized_end=829,
+)
+_sym_db.RegisterEnumDescriptor(_OTAMETADATA_OTATYPE)
+
+
+_PARTITIONSTATE = _descriptor.Descriptor(
+  name='PartitionState',
+  full_name='build.tools.releasetools.PartitionState',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='partition_name', full_name='build.tools.releasetools.PartitionState.partition_name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='device', full_name='build.tools.releasetools.PartitionState.device', index=1,
+      number=2, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='build', full_name='build.tools.releasetools.PartitionState.build', index=2,
+      number=3, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='version', full_name='build.tools.releasetools.PartitionState.version', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=48,
+  serialized_end=136,
+)
+
+
+_DEVICESTATE = _descriptor.Descriptor(
+  name='DeviceState',
+  full_name='build.tools.releasetools.DeviceState',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='device', full_name='build.tools.releasetools.DeviceState.device', index=0,
+      number=1, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='build', full_name='build.tools.releasetools.DeviceState.build', index=1,
+      number=2, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='build_incremental', full_name='build.tools.releasetools.DeviceState.build_incremental', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='timestamp', full_name='build.tools.releasetools.DeviceState.timestamp', index=3,
+      number=4, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='sdk_level', full_name='build.tools.releasetools.DeviceState.sdk_level', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='security_patch_level', full_name='build.tools.releasetools.DeviceState.security_patch_level', index=5,
+      number=6, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='partition_state', full_name='build.tools.releasetools.DeviceState.partition_state', index=6,
+      number=7, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=139,
+  serialized_end=345,
+)
+
+
+_OTAMETADATA_PROPERTYFILESENTRY = _descriptor.Descriptor(
+  name='PropertyFilesEntry',
+  full_name='build.tools.releasetools.OtaMetadata.PropertyFilesEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='build.tools.releasetools.OtaMetadata.PropertyFilesEntry.key', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='build.tools.releasetools.OtaMetadata.PropertyFilesEntry.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=723,
+  serialized_end=775,
+)
+
+_OTAMETADATA = _descriptor.Descriptor(
+  name='OtaMetadata',
+  full_name='build.tools.releasetools.OtaMetadata',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='type', full_name='build.tools.releasetools.OtaMetadata.type', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='wipe', full_name='build.tools.releasetools.OtaMetadata.wipe', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='downgrade', full_name='build.tools.releasetools.OtaMetadata.downgrade', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='property_files', full_name='build.tools.releasetools.OtaMetadata.property_files', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='precondition', full_name='build.tools.releasetools.OtaMetadata.precondition', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='postcondition', full_name='build.tools.releasetools.OtaMetadata.postcondition', index=5,
+      number=6, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='retrofit_dynamic_partitions', full_name='build.tools.releasetools.OtaMetadata.retrofit_dynamic_partitions', index=6,
+      number=7, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='required_cache', full_name='build.tools.releasetools.OtaMetadata.required_cache', index=7,
+      number=8, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[_OTAMETADATA_PROPERTYFILESENTRY, ],
+  enum_types=[
+    _OTAMETADATA_OTATYPE,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=348,
+  serialized_end=829,
+)
+
+_DEVICESTATE.fields_by_name['partition_state'].message_type = _PARTITIONSTATE
+_OTAMETADATA_PROPERTYFILESENTRY.containing_type = _OTAMETADATA
+_OTAMETADATA.fields_by_name['type'].enum_type = _OTAMETADATA_OTATYPE
+_OTAMETADATA.fields_by_name['property_files'].message_type = _OTAMETADATA_PROPERTYFILESENTRY
+_OTAMETADATA.fields_by_name['precondition'].message_type = _DEVICESTATE
+_OTAMETADATA.fields_by_name['postcondition'].message_type = _DEVICESTATE
+_OTAMETADATA_OTATYPE.containing_type = _OTAMETADATA
+DESCRIPTOR.message_types_by_name['PartitionState'] = _PARTITIONSTATE
+DESCRIPTOR.message_types_by_name['DeviceState'] = _DEVICESTATE
+DESCRIPTOR.message_types_by_name['OtaMetadata'] = _OTAMETADATA
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+PartitionState = _reflection.GeneratedProtocolMessageType('PartitionState', (_message.Message,), {
+  'DESCRIPTOR' : _PARTITIONSTATE,
+  '__module__' : 'ota_metadata_pb2'
+  # @@protoc_insertion_point(class_scope:build.tools.releasetools.PartitionState)
+  })
+_sym_db.RegisterMessage(PartitionState)
+
+DeviceState = _reflection.GeneratedProtocolMessageType('DeviceState', (_message.Message,), {
+  'DESCRIPTOR' : _DEVICESTATE,
+  '__module__' : 'ota_metadata_pb2'
+  # @@protoc_insertion_point(class_scope:build.tools.releasetools.DeviceState)
+  })
+_sym_db.RegisterMessage(DeviceState)
+
+OtaMetadata = _reflection.GeneratedProtocolMessageType('OtaMetadata', (_message.Message,), {
+
+  'PropertyFilesEntry' : _reflection.GeneratedProtocolMessageType('PropertyFilesEntry', (_message.Message,), {
+    'DESCRIPTOR' : _OTAMETADATA_PROPERTYFILESENTRY,
+    '__module__' : 'ota_metadata_pb2'
+    # @@protoc_insertion_point(class_scope:build.tools.releasetools.OtaMetadata.PropertyFilesEntry)
+    })
+  ,
+  'DESCRIPTOR' : _OTAMETADATA,
+  '__module__' : 'ota_metadata_pb2'
+  # @@protoc_insertion_point(class_scope:build.tools.releasetools.OtaMetadata)
+  })
+_sym_db.RegisterMessage(OtaMetadata)
+_sym_db.RegisterMessage(OtaMetadata.PropertyFilesEntry)
+
+
+DESCRIPTOR._options = None
+_OTAMETADATA_PROPERTYFILESENTRY._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
new file mode 100644
index 0000000..d444d41
--- /dev/null
+++ b/tools/releasetools/ota_utils.py
@@ -0,0 +1,563 @@
+# 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.
+
+import copy
+import itertools
+import os
+import zipfile
+
+import ota_metadata_pb2
+from common import (ZipDelete, ZipClose, OPTIONS, MakeTempFile,
+                    ZipWriteStr, BuildInfo, LoadDictionaryFromFile,
+                    SignFile, PARTITIONS_WITH_CARE_MAP, PartitionBuildProps)
+
+
+OPTIONS.no_signing = False
+OPTIONS.force_non_ab = False
+OPTIONS.wipe_user_data = False
+OPTIONS.downgrade = False
+OPTIONS.key_passwords = {}
+OPTIONS.package_key = None
+OPTIONS.incremental_source = None
+OPTIONS.retrofit_dynamic_partitions = False
+OPTIONS.output_metadata_path = None
+OPTIONS.boot_variable_file = None
+
+METADATA_NAME = 'META-INF/com/android/metadata'
+METADATA_PROTO_NAME = 'META-INF/com/android/metadata.pb'
+UNZIP_PATTERN = ['IMAGES/*', 'META/*', 'OTA/*', 'RADIO/*']
+
+
+def FinalizeMetadata(metadata, input_file, output_file, needed_property_files):
+  """Finalizes the metadata and signs an A/B OTA package.
+
+  In order to stream an A/B OTA package, we need 'ota-streaming-property-files'
+  that contains the offsets and sizes for the ZIP entries. An example
+  property-files string is as follows.
+
+    "payload.bin:679:343,payload_properties.txt:378:45,metadata:69:379"
+
+  OTA server can pass down this string, in addition to the package URL, to the
+  system update client. System update client can then fetch individual ZIP
+  entries (ZIP_STORED) directly at the given offset of the URL.
+
+  Args:
+    metadata: The metadata dict for the package.
+    input_file: The input ZIP filename that doesn't contain the package METADATA
+        entry yet.
+    output_file: The final output ZIP filename.
+    needed_property_files: The list of PropertyFiles' to be generated.
+  """
+
+  def ComputeAllPropertyFiles(input_file, needed_property_files):
+    # Write the current metadata entry with placeholders.
+    with zipfile.ZipFile(input_file) as input_zip:
+      for property_files in needed_property_files:
+        metadata.property_files[property_files.name] = property_files.Compute(
+            input_zip)
+      namelist = input_zip.namelist()
+
+    if METADATA_NAME in namelist or METADATA_PROTO_NAME in namelist:
+      ZipDelete(input_file, [METADATA_NAME, METADATA_PROTO_NAME])
+    output_zip = zipfile.ZipFile(input_file, 'a')
+    WriteMetadata(metadata, output_zip)
+    ZipClose(output_zip)
+
+    if OPTIONS.no_signing:
+      return input_file
+
+    prelim_signing = MakeTempFile(suffix='.zip')
+    SignOutput(input_file, prelim_signing)
+    return prelim_signing
+
+  def FinalizeAllPropertyFiles(prelim_signing, needed_property_files):
+    with zipfile.ZipFile(prelim_signing) as prelim_signing_zip:
+      for property_files in needed_property_files:
+        metadata.property_files[property_files.name] = property_files.Finalize(
+            prelim_signing_zip,
+            len(metadata.property_files[property_files.name]))
+
+  # SignOutput(), which in turn calls signapk.jar, will possibly reorder the ZIP
+  # entries, as well as padding the entry headers. We do a preliminary signing
+  # (with an incomplete metadata entry) to allow that to happen. Then compute
+  # the ZIP entry offsets, write back the final metadata and do the final
+  # signing.
+  prelim_signing = ComputeAllPropertyFiles(input_file, needed_property_files)
+  try:
+    FinalizeAllPropertyFiles(prelim_signing, needed_property_files)
+  except PropertyFiles.InsufficientSpaceException:
+    # Even with the preliminary signing, the entry orders may change
+    # dramatically, which leads to insufficiently reserved space during the
+    # first call to ComputeAllPropertyFiles(). In that case, we redo all the
+    # preliminary signing works, based on the already ordered ZIP entries, to
+    # address the issue.
+    prelim_signing = ComputeAllPropertyFiles(
+        prelim_signing, needed_property_files)
+    FinalizeAllPropertyFiles(prelim_signing, needed_property_files)
+
+  # Replace the METADATA entry.
+  ZipDelete(prelim_signing, [METADATA_NAME, METADATA_PROTO_NAME])
+  output_zip = zipfile.ZipFile(prelim_signing, 'a')
+  WriteMetadata(metadata, output_zip)
+  ZipClose(output_zip)
+
+  # Re-sign the package after updating the metadata entry.
+  if OPTIONS.no_signing:
+    output_file = prelim_signing
+  else:
+    SignOutput(prelim_signing, output_file)
+
+  # Reopen the final signed zip to double check the streaming metadata.
+  with zipfile.ZipFile(output_file) as output_zip:
+    for property_files in needed_property_files:
+      property_files.Verify(
+          output_zip, metadata.property_files[property_files.name].strip())
+
+  # If requested, dump the metadata to a separate file.
+  output_metadata_path = OPTIONS.output_metadata_path
+  if output_metadata_path:
+    WriteMetadata(metadata, output_metadata_path)
+
+
+def WriteMetadata(metadata_proto, output):
+  """Writes the metadata to the zip archive or a file.
+
+  Args:
+    metadata_proto: The metadata protobuf for the package.
+    output: A ZipFile object or a string of the output file path. If a string
+      path is given, the metadata in the protobuf format will be written to
+      {output}.pb, e.g. ota_metadata.pb
+  """
+
+  metadata_dict = BuildLegacyOtaMetadata(metadata_proto)
+  legacy_metadata = "".join(["%s=%s\n" % kv for kv in
+                             sorted(metadata_dict.items())])
+  if isinstance(output, zipfile.ZipFile):
+    ZipWriteStr(output, METADATA_PROTO_NAME, metadata_proto.SerializeToString(),
+                compress_type=zipfile.ZIP_STORED)
+    ZipWriteStr(output, METADATA_NAME, legacy_metadata,
+                compress_type=zipfile.ZIP_STORED)
+    return
+
+  with open('{}.pb'.format(output), 'w') as f:
+    f.write(metadata_proto.SerializeToString())
+  with open(output, 'w') as f:
+    f.write(legacy_metadata)
+
+
+def UpdateDeviceState(device_state, build_info, boot_variable_values,
+                      is_post_build):
+  """Update the fields of the DeviceState proto with build info."""
+
+  def UpdatePartitionStates(partition_states):
+    """Update the per-partition state according to its build.prop"""
+    if not build_info.is_ab:
+      return
+    build_info_set = ComputeRuntimeBuildInfos(build_info,
+                                              boot_variable_values)
+    assert "ab_partitions" in build_info.info_dict,\
+      "ab_partitions property required for ab update."
+    ab_partitions = set(build_info.info_dict.get("ab_partitions"))
+
+    # delta_generator will error out on unused timestamps,
+    # so only generate timestamps for dynamic partitions
+    # used in OTA update.
+    for partition in sorted(set(PARTITIONS_WITH_CARE_MAP) & ab_partitions):
+      partition_prop = build_info.info_dict.get(
+          '{}.build.prop'.format(partition))
+      # Skip if the partition is missing, or it doesn't have a build.prop
+      if not partition_prop or not partition_prop.build_props:
+        continue
+
+      partition_state = partition_states.add()
+      partition_state.partition_name = partition
+      # Update the partition's runtime device names and fingerprints
+      partition_devices = set()
+      partition_fingerprints = set()
+      for runtime_build_info in build_info_set:
+        partition_devices.add(
+            runtime_build_info.GetPartitionBuildProp('ro.product.device',
+                                                     partition))
+        partition_fingerprints.add(
+            runtime_build_info.GetPartitionFingerprint(partition))
+
+      partition_state.device.extend(sorted(partition_devices))
+      partition_state.build.extend(sorted(partition_fingerprints))
+
+      # TODO(xunchang) set the boot image's version with kmi. Note the boot
+      # image doesn't have a file map.
+      partition_state.version = build_info.GetPartitionBuildProp(
+          'ro.build.date.utc', partition)
+
+  # TODO(xunchang), we can save a call to ComputeRuntimeBuildInfos.
+  build_devices, build_fingerprints = \
+      CalculateRuntimeDevicesAndFingerprints(build_info, boot_variable_values)
+  device_state.device.extend(sorted(build_devices))
+  device_state.build.extend(sorted(build_fingerprints))
+  device_state.build_incremental = build_info.GetBuildProp(
+      'ro.build.version.incremental')
+
+  UpdatePartitionStates(device_state.partition_state)
+
+  if is_post_build:
+    device_state.sdk_level = build_info.GetBuildProp(
+        'ro.build.version.sdk')
+    device_state.security_patch_level = build_info.GetBuildProp(
+        'ro.build.version.security_patch')
+    # Use the actual post-timestamp, even for a downgrade case.
+    device_state.timestamp = int(build_info.GetBuildProp('ro.build.date.utc'))
+
+
+def GetPackageMetadata(target_info, source_info=None):
+  """Generates and returns the metadata proto.
+
+  It generates a ota_metadata protobuf that contains the info to be written
+  into an OTA package (META-INF/com/android/metadata.pb). It also handles the
+  detection of downgrade / data wipe based on the global options.
+
+  Args:
+    target_info: The BuildInfo instance that holds the target build info.
+    source_info: The BuildInfo instance that holds the source build info, or
+        None if generating full OTA.
+
+  Returns:
+    A protobuf to be written into package metadata entry.
+  """
+  assert isinstance(target_info, BuildInfo)
+  assert source_info is None or isinstance(source_info, BuildInfo)
+
+  boot_variable_values = {}
+  if OPTIONS.boot_variable_file:
+    d = LoadDictionaryFromFile(OPTIONS.boot_variable_file)
+    for key, values in d.items():
+      boot_variable_values[key] = [val.strip() for val in values.split(',')]
+
+  metadata_proto = ota_metadata_pb2.OtaMetadata()
+  # TODO(xunchang) some fields, e.g. post-device isn't necessary. We can
+  # consider skipping them if they aren't used by clients.
+  UpdateDeviceState(metadata_proto.postcondition, target_info,
+                    boot_variable_values, True)
+
+  if target_info.is_ab and not OPTIONS.force_non_ab:
+    metadata_proto.type = ota_metadata_pb2.OtaMetadata.AB
+    metadata_proto.required_cache = 0
+  else:
+    metadata_proto.type = ota_metadata_pb2.OtaMetadata.BLOCK
+    # cache requirement will be updated by the non-A/B codes.
+
+  if OPTIONS.wipe_user_data:
+    metadata_proto.wipe = True
+
+  if OPTIONS.retrofit_dynamic_partitions:
+    metadata_proto.retrofit_dynamic_partitions = True
+
+  is_incremental = source_info is not None
+  if is_incremental:
+    UpdateDeviceState(metadata_proto.precondition, source_info,
+                      boot_variable_values, False)
+  else:
+    metadata_proto.precondition.device.extend(
+        metadata_proto.postcondition.device)
+
+  # Detect downgrades and set up downgrade flags accordingly.
+  if is_incremental:
+    HandleDowngradeMetadata(metadata_proto, target_info, source_info)
+
+  return metadata_proto
+
+
+def BuildLegacyOtaMetadata(metadata_proto):
+  """Converts the metadata proto to a legacy metadata dict.
+
+  This metadata dict is used to build the legacy metadata text file for
+  backward compatibility. We won't add new keys to the legacy metadata format.
+  If new information is needed, we should add it as a new field in OtaMetadata
+  proto definition.
+  """
+
+  separator = '|'
+
+  metadata_dict = {}
+  if metadata_proto.type == ota_metadata_pb2.OtaMetadata.AB:
+    metadata_dict['ota-type'] = 'AB'
+  elif metadata_proto.type == ota_metadata_pb2.OtaMetadata.BLOCK:
+    metadata_dict['ota-type'] = 'BLOCK'
+  if metadata_proto.wipe:
+    metadata_dict['ota-wipe'] = 'yes'
+  if metadata_proto.retrofit_dynamic_partitions:
+    metadata_dict['ota-retrofit-dynamic-partitions'] = 'yes'
+  if metadata_proto.downgrade:
+    metadata_dict['ota-downgrade'] = 'yes'
+
+  metadata_dict['ota-required-cache'] = str(metadata_proto.required_cache)
+
+  post_build = metadata_proto.postcondition
+  metadata_dict['post-build'] = separator.join(post_build.build)
+  metadata_dict['post-build-incremental'] = post_build.build_incremental
+  metadata_dict['post-sdk-level'] = post_build.sdk_level
+  metadata_dict['post-security-patch-level'] = post_build.security_patch_level
+  metadata_dict['post-timestamp'] = str(post_build.timestamp)
+
+  pre_build = metadata_proto.precondition
+  metadata_dict['pre-device'] = separator.join(pre_build.device)
+  # incremental updates
+  if len(pre_build.build) != 0:
+    metadata_dict['pre-build'] = separator.join(pre_build.build)
+    metadata_dict['pre-build-incremental'] = pre_build.build_incremental
+
+  metadata_dict.update(metadata_proto.property_files)
+
+  return metadata_dict
+
+
+def HandleDowngradeMetadata(metadata_proto, target_info, source_info):
+  # Only incremental OTAs are allowed to reach here.
+  assert OPTIONS.incremental_source is not None
+
+  post_timestamp = target_info.GetBuildProp("ro.build.date.utc")
+  pre_timestamp = source_info.GetBuildProp("ro.build.date.utc")
+  is_downgrade = int(post_timestamp) < int(pre_timestamp)
+
+  if OPTIONS.downgrade:
+    if not is_downgrade:
+      raise RuntimeError(
+          "--downgrade or --override_timestamp specified but no downgrade "
+          "detected: pre: %s, post: %s" % (pre_timestamp, post_timestamp))
+    metadata_proto.downgrade = True
+  else:
+    if is_downgrade:
+      raise RuntimeError(
+          "Downgrade detected based on timestamp check: pre: %s, post: %s. "
+          "Need to specify --override_timestamp OR --downgrade to allow "
+          "building the incremental." % (pre_timestamp, post_timestamp))
+
+
+def ComputeRuntimeBuildInfos(default_build_info, boot_variable_values):
+  """Returns a set of build info objects that may exist during runtime."""
+
+  build_info_set = {default_build_info}
+  if not boot_variable_values:
+    return build_info_set
+
+  # 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(default_build_info.info_dict)
+    for partition in 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] = \
+              PartitionBuildProps.FromInputFile(input_zip, partition,
+                                                placeholder_values)
+      else:
+        info_dict[partition_prop_key] = \
+            PartitionBuildProps.FromInputFile(input_file, partition,
+                                              placeholder_values)
+    info_dict["build.prop"] = info_dict["system.build.prop"]
+    build_info_set.add(BuildInfo(info_dict, default_build_info.oem_dicts))
+
+  return build_info_set
+
+
+def CalculateRuntimeDevicesAndFingerprints(default_build_info,
+                                           boot_variable_values):
+  """Returns a tuple of sets for runtime devices and fingerprints"""
+
+  device_names = set()
+  fingerprints = set()
+  build_info_set = ComputeRuntimeBuildInfos(default_build_info,
+                                            boot_variable_values)
+  for runtime_build_info in build_info_set:
+    device_names.add(runtime_build_info.device)
+    fingerprints.add(runtime_build_info.fingerprint)
+  return device_names, fingerprints
+
+
+class PropertyFiles(object):
+  """A class that computes the property-files string for an OTA package.
+
+  A property-files string is a comma-separated string that contains the
+  offset/size info for an OTA package. The entries, which must be ZIP_STORED,
+  can be fetched directly with the package URL along with the offset/size info.
+  These strings can be used for streaming A/B OTAs, or allowing an updater to
+  download package metadata entry directly, without paying the cost of
+  downloading entire package.
+
+  Computing the final property-files string requires two passes. Because doing
+  the whole package signing (with signapk.jar) will possibly reorder the ZIP
+  entries, which may in turn invalidate earlier computed ZIP entry offset/size
+  values.
+
+  This class provides functions to be called for each pass. The general flow is
+  as follows.
+
+    property_files = PropertyFiles()
+    # The first pass, which writes placeholders before doing initial signing.
+    property_files.Compute()
+    SignOutput()
+
+    # The second pass, by replacing the placeholders with actual data.
+    property_files.Finalize()
+    SignOutput()
+
+  And the caller can additionally verify the final result.
+
+    property_files.Verify()
+  """
+
+  def __init__(self):
+    self.name = None
+    self.required = ()
+    self.optional = ()
+
+  def Compute(self, input_zip):
+    """Computes and returns a property-files string with placeholders.
+
+    We reserve extra space for the offset and size of the metadata entry itself,
+    although we don't know the final values until the package gets signed.
+
+    Args:
+      input_zip: The input ZIP file.
+
+    Returns:
+      A string with placeholders for the metadata offset/size info, e.g.
+      "payload.bin:679:343,payload_properties.txt:378:45,metadata:        ".
+    """
+    return self.GetPropertyFilesString(input_zip, reserve_space=True)
+
+  class InsufficientSpaceException(Exception):
+    pass
+
+  def Finalize(self, input_zip, reserved_length):
+    """Finalizes a property-files string with actual METADATA offset/size info.
+
+    The input ZIP file has been signed, with the ZIP entries in the desired
+    place (signapk.jar will possibly reorder the ZIP entries). Now we compute
+    the ZIP entry offsets and construct the property-files string with actual
+    data. Note that during this process, we must pad the property-files string
+    to the reserved length, so that the METADATA entry size remains the same.
+    Otherwise the entries' offsets and sizes may change again.
+
+    Args:
+      input_zip: The input ZIP file.
+      reserved_length: The reserved length of the property-files string during
+          the call to Compute(). The final string must be no more than this
+          size.
+
+    Returns:
+      A property-files string including the metadata offset/size info, e.g.
+      "payload.bin:679:343,payload_properties.txt:378:45,metadata:69:379  ".
+
+    Raises:
+      InsufficientSpaceException: If the reserved length is insufficient to hold
+          the final string.
+    """
+    result = self.GetPropertyFilesString(input_zip, reserve_space=False)
+    if len(result) > reserved_length:
+      raise self.InsufficientSpaceException(
+          'Insufficient reserved space: reserved={}, actual={}'.format(
+              reserved_length, len(result)))
+
+    result += ' ' * (reserved_length - len(result))
+    return result
+
+  def Verify(self, input_zip, expected):
+    """Verifies the input ZIP file contains the expected property-files string.
+
+    Args:
+      input_zip: The input ZIP file.
+      expected: The property-files string that's computed from Finalize().
+
+    Raises:
+      AssertionError: On finding a mismatch.
+    """
+    actual = self.GetPropertyFilesString(input_zip)
+    assert actual == expected, \
+        "Mismatching streaming metadata: {} vs {}.".format(actual, expected)
+
+  def GetPropertyFilesString(self, zip_file, reserve_space=False):
+    """
+    Constructs the property-files string per request.
+
+    Args:
+      zip_file: The input ZIP file.
+      reserved_length: The reserved length of the property-files string.
+
+    Returns:
+      A property-files string including the metadata offset/size info, e.g.
+      "payload.bin:679:343,payload_properties.txt:378:45,metadata:     ".
+    """
+
+    def ComputeEntryOffsetSize(name):
+      """Computes the zip entry offset and size."""
+      info = zip_file.getinfo(name)
+      offset = info.header_offset
+      offset += zipfile.sizeFileHeader
+      offset += len(info.extra) + len(info.filename)
+      size = info.file_size
+      return '%s:%d:%d' % (os.path.basename(name), offset, size)
+
+    tokens = []
+    tokens.extend(self._GetPrecomputed(zip_file))
+    for entry in self.required:
+      tokens.append(ComputeEntryOffsetSize(entry))
+    for entry in self.optional:
+      if entry in zip_file.namelist():
+        tokens.append(ComputeEntryOffsetSize(entry))
+
+    # 'META-INF/com/android/metadata' is required. We don't know its actual
+    # offset and length (as well as the values for other entries). So we reserve
+    # 15-byte as a placeholder ('offset:length'), which is sufficient to cover
+    # the space for metadata entry. Because 'offset' allows a max of 10-digit
+    # (i.e. ~9 GiB), with a max of 4-digit for the length. Note that all the
+    # reserved space serves the metadata entry only.
+    if reserve_space:
+      tokens.append('metadata:' + ' ' * 15)
+      tokens.append('metadata.pb:' + ' ' * 15)
+    else:
+      tokens.append(ComputeEntryOffsetSize(METADATA_NAME))
+      tokens.append(ComputeEntryOffsetSize(METADATA_PROTO_NAME))
+
+    return ','.join(tokens)
+
+  def _GetPrecomputed(self, input_zip):
+    """Computes the additional tokens to be included into the property-files.
+
+    This applies to tokens without actual ZIP entries, such as
+    payload_metadata.bin. We want to expose the offset/size to updaters, so
+    that they can download the payload metadata directly with the info.
+
+    Args:
+      input_zip: The input zip file.
+
+    Returns:
+      A list of strings (tokens) to be added to the property-files string.
+    """
+    # pylint: disable=no-self-use
+    # pylint: disable=unused-argument
+    return []
+
+
+def SignOutput(temp_zip_name, output_zip_name):
+  pw = OPTIONS.key_passwords[OPTIONS.package_key]
+
+  SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
+           whole_file=True)
diff --git a/tools/releasetools/test_apex_utils.py b/tools/releasetools/test_apex_utils.py
index 7b4a4b0..339ddc7 100644
--- a/tools/releasetools/test_apex_utils.py
+++ b/tools/releasetools/test_apex_utils.py
@@ -160,7 +160,7 @@
 
     self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
     apex_file = signer.ProcessApexFile(apk_keys, self.payload_key)
-    package_name_extract_cmd = ['aapt', 'dump', 'badging', apex_file]
+    package_name_extract_cmd = ['aapt2', 'dump', 'badging', apex_file]
     output = common.RunAndCheckOutput(package_name_extract_cmd)
     for line in output.splitlines():
       # Sample output from aapt: "package: name='com.google.android.wifi'
diff --git a/tools/releasetools/test_non_ab_ota.py b/tools/releasetools/test_non_ab_ota.py
new file mode 100644
index 0000000..5207e2f
--- /dev/null
+++ b/tools/releasetools/test_non_ab_ota.py
@@ -0,0 +1,172 @@
+#
+# 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.
+#
+
+import copy
+import zipfile
+
+import common
+import test_utils
+
+from non_ab_ota import NonAbOtaPropertyFiles, WriteFingerprintAssertion
+from test_utils import PropertyFilesTestCase
+
+
+class NonAbOtaPropertyFilesTest(PropertyFilesTestCase):
+  """Additional validity checks specialized for NonAbOtaPropertyFiles."""
+  def setUp(self):
+     common.OPTIONS.no_signing = False
+  def test_init(self):
+    property_files = NonAbOtaPropertyFiles()
+    self.assertEqual('ota-property-files', property_files.name)
+    self.assertEqual((), property_files.required)
+    self.assertEqual((), property_files.optional)
+
+  def test_Compute(self):
+    entries = ()
+    zip_file = self.construct_zip_package(entries)
+    property_files = NonAbOtaPropertyFiles()
+    with zipfile.ZipFile(zip_file) as zip_fp:
+      property_files_string = property_files.Compute(zip_fp)
+
+    tokens = self._parse_property_files_string(property_files_string)
+    self.assertEqual(2, len(tokens))
+    self._verify_entries(zip_file, tokens, entries)
+
+  def test_Finalize(self):
+    entries = [
+        'META-INF/com/android/metadata',
+        'META-INF/com/android/metadata.pb',
+    ]
+    zip_file = self.construct_zip_package(entries)
+    property_files = NonAbOtaPropertyFiles()
+    with zipfile.ZipFile(zip_file) as zip_fp:
+      raw_metadata = property_files.GetPropertyFilesString(
+          zip_fp, reserve_space=False)
+      property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
+    tokens = self._parse_property_files_string(property_files_string)
+
+    self.assertEqual(2, len(tokens))
+    # 'META-INF/com/android/metadata' will be key'd as 'metadata'.
+    entries[0] = 'metadata'
+    entries[1] = 'metadata.pb'
+    self._verify_entries(zip_file, tokens, entries)
+
+  def test_Verify(self):
+    entries = (
+        'META-INF/com/android/metadata',
+        'META-INF/com/android/metadata.pb',
+    )
+    zip_file = self.construct_zip_package(entries)
+    property_files = NonAbOtaPropertyFiles()
+    with zipfile.ZipFile(zip_file) as zip_fp:
+      raw_metadata = property_files.GetPropertyFilesString(
+          zip_fp, reserve_space=False)
+
+      property_files.Verify(zip_fp, raw_metadata)
+
+class NonAbOTATest(test_utils.ReleaseToolsTestCase):
+  TEST_TARGET_INFO_DICT = {
+      '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_INFO_DICT_USES_OEM_PROPS = {
+      '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': 'brand2',
+          'ro.product.device': 'device2',
+      },
+      {
+          'ro.product.brand': 'brand3',
+          'ro.product.device': 'device3',
+      },
+  ]
+  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'].build_props['ro.build.fingerprint'] = (
+        'source-build-fingerprint')
+    source_info = common.BuildInfo(source_info_dict, None)
+
+    script_writer = test_utils.MockScriptWriter()
+    WriteFingerprintAssertion(script_writer, target_info, source_info)
+    self.assertEqual(
+        [('AssertSomeFingerprint', 'source-build-fingerprint',
+          'build-fingerprint-target')],
+        script_writer.lines)
+
+  def test_WriteFingerprintAssertion_with_source_oem_props(self):
+    target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
+    source_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
+                                   self.TEST_OEM_DICTS)
+
+    script_writer = test_utils.MockScriptWriter()
+    WriteFingerprintAssertion(script_writer, target_info, source_info)
+    self.assertEqual(
+        [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
+          'build-thumbprint')],
+        script_writer.lines)
+
+  def test_WriteFingerprintAssertion_with_target_oem_props(self):
+    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
+                                   self.TEST_OEM_DICTS)
+    source_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
+
+    script_writer = test_utils.MockScriptWriter()
+    WriteFingerprintAssertion(script_writer, target_info, source_info)
+    self.assertEqual(
+        [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
+          'build-thumbprint')],
+        script_writer.lines)
+
+  def test_WriteFingerprintAssertion_with_both_oem_props(self):
+    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'].build_props['ro.build.thumbprint'] = (
+        'source-build-thumbprint')
+    source_info = common.BuildInfo(source_info_dict, self.TEST_OEM_DICTS)
+
+    script_writer = test_utils.MockScriptWriter()
+    WriteFingerprintAssertion(script_writer, target_info, source_info)
+    self.assertEqual(
+        [('AssertSomeThumbprint', 'build-thumbprint',
+          'source-build-thumbprint')],
+        script_writer.lines)
diff --git a/tools/releasetools/test_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index 07b2e05..84cd4c8 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -20,14 +20,18 @@
 import zipfile
 
 import common
+import ota_metadata_pb2
 import test_utils
+from ota_utils import (
+    BuildLegacyOtaMetadata, CalculateRuntimeDevicesAndFingerprints,
+    FinalizeMetadata, GetPackageMetadata, PropertyFiles)
 from ota_from_target_files import (
-    _LoadOemDicts, AbOtaPropertyFiles, FinalizeMetadata,
-    GetPackageMetadata, GetTargetFilesZipForSecondaryImages,
-    GetTargetFilesZipWithoutPostinstallConfig, NonAbOtaPropertyFiles,
-    Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
-    StreamingPropertyFiles, WriteFingerprintAssertion,
-    CalculateRuntimeDevicesAndFingerprints)
+    _LoadOemDicts, AbOtaPropertyFiles,
+    GetTargetFilesZipForSecondaryImages,
+    GetTargetFilesZipWithoutPostinstallConfig,
+    Payload, PayloadSigner, POSTINSTALL_CONFIG,
+    StreamingPropertyFiles, AB_PARTITIONS)
+from test_utils import PropertyFilesTestCase
 
 
 def construct_target_files(secondary=False):
@@ -142,28 +146,13 @@
       ),
       'vendor.build.prop': common.PartitionBuildProps.FromDictionary(
           'vendor', {
-               'ro.vendor.build.fingerprint': 'vendor-build-fingerprint'}
+              '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': 'brand2',
-          'ro.product.device': 'device2',
-      },
-      {
-          'ro.product.brand': 'brand3',
-          'ro.product.device': 'device3',
-      },
-  ]
-
   def setUp(self):
     self.testdata_dir = test_utils.get_testdata_dir()
     self.assertTrue(os.path.exists(self.testdata_dir))
@@ -177,63 +166,71 @@
     common.OPTIONS.no_signing = False
     common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
     common.OPTIONS.key_passwords = {
-        common.OPTIONS.package_key : None,
+        common.OPTIONS.package_key: None,
     }
 
     common.OPTIONS.search_path = test_utils.get_search_path()
 
+  @staticmethod
+  def GetLegacyOtaMetadata(target_info, source_info=None):
+    metadata_proto = GetPackageMetadata(target_info, source_info)
+    return BuildLegacyOtaMetadata(metadata_proto)
+
   def test_GetPackageMetadata_abOta_full(self):
     target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
     target_info_dict['ab_update'] = 'true'
+    target_info_dict['ab_partitions'] = []
     target_info = common.BuildInfo(target_info_dict, None)
-    metadata = GetPackageMetadata(target_info)
+    metadata = self.GetLegacyOtaMetadata(target_info)
     self.assertDictEqual(
         {
-            'ota-type' : 'AB',
-            'ota-required-cache' : '0',
-            'post-build' : 'build-fingerprint-target',
-            'post-build-incremental' : 'build-version-incremental-target',
-            'post-sdk-level' : '27',
-            'post-security-patch-level' : '2017-12-01',
-            'post-timestamp' : '1500000000',
-            'pre-device' : 'product-device',
+            'ota-type': 'AB',
+            'ota-required-cache': '0',
+            'post-build': 'build-fingerprint-target',
+            'post-build-incremental': 'build-version-incremental-target',
+            'post-sdk-level': '27',
+            'post-security-patch-level': '2017-12-01',
+            'post-timestamp': '1500000000',
+            'pre-device': 'product-device',
         },
         metadata)
 
   def test_GetPackageMetadata_abOta_incremental(self):
     target_info_dict = copy.deepcopy(self.TEST_TARGET_INFO_DICT)
     target_info_dict['ab_update'] = 'true'
+    target_info_dict['ab_partitions'] = []
     target_info = common.BuildInfo(target_info_dict, None)
     source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
     common.OPTIONS.incremental_source = ''
-    metadata = GetPackageMetadata(target_info, source_info)
+    metadata = self.GetLegacyOtaMetadata(target_info, source_info)
     self.assertDictEqual(
         {
-            'ota-type' : 'AB',
-            'ota-required-cache' : '0',
-            'post-build' : 'build-fingerprint-target',
-            'post-build-incremental' : 'build-version-incremental-target',
-            'post-sdk-level' : '27',
-            'post-security-patch-level' : '2017-12-01',
-            'post-timestamp' : '1500000000',
-            'pre-device' : 'product-device',
-            'pre-build' : 'build-fingerprint-source',
-            'pre-build-incremental' : 'build-version-incremental-source',
+            'ota-type': 'AB',
+            'ota-required-cache': '0',
+            'post-build': 'build-fingerprint-target',
+            'post-build-incremental': 'build-version-incremental-target',
+            'post-sdk-level': '27',
+            'post-security-patch-level': '2017-12-01',
+            'post-timestamp': '1500000000',
+            'pre-device': 'product-device',
+            'pre-build': 'build-fingerprint-source',
+            'pre-build-incremental': 'build-version-incremental-source',
         },
         metadata)
 
   def test_GetPackageMetadata_nonAbOta_full(self):
     target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
-    metadata = GetPackageMetadata(target_info)
+    metadata = self.GetLegacyOtaMetadata(target_info)
     self.assertDictEqual(
         {
-            'ota-type' : 'BLOCK',
-            'post-build' : 'build-fingerprint-target',
-            'post-build-incremental' : 'build-version-incremental-target',
-            'post-sdk-level' : '27',
-            'post-security-patch-level' : '2017-12-01',
-            'post-timestamp' : '1500000000',
-            'pre-device' : 'product-device',
+            'ota-type': 'BLOCK',
+            'ota-required-cache': '0',
+            'post-build': 'build-fingerprint-target',
+            'post-build-incremental': 'build-version-incremental-target',
+            'post-sdk-level': '27',
+            'post-security-patch-level': '2017-12-01',
+            'post-timestamp': '1500000000',
+            'pre-device': 'product-device',
         },
         metadata)
 
@@ -241,52 +238,55 @@
     target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
     source_info = common.BuildInfo(self.TEST_SOURCE_INFO_DICT, None)
     common.OPTIONS.incremental_source = ''
-    metadata = GetPackageMetadata(target_info, source_info)
+    metadata = self.GetLegacyOtaMetadata(target_info, source_info)
     self.assertDictEqual(
         {
-            'ota-type' : 'BLOCK',
-            'post-build' : 'build-fingerprint-target',
-            'post-build-incremental' : 'build-version-incremental-target',
-            'post-sdk-level' : '27',
-            'post-security-patch-level' : '2017-12-01',
-            'post-timestamp' : '1500000000',
-            'pre-device' : 'product-device',
-            'pre-build' : 'build-fingerprint-source',
-            'pre-build-incremental' : 'build-version-incremental-source',
+            'ota-type': 'BLOCK',
+            'ota-required-cache': '0',
+            'post-build': 'build-fingerprint-target',
+            'post-build-incremental': 'build-version-incremental-target',
+            'post-sdk-level': '27',
+            'post-security-patch-level': '2017-12-01',
+            'post-timestamp': '1500000000',
+            'pre-device': 'product-device',
+            'pre-build': 'build-fingerprint-source',
+            'pre-build-incremental': 'build-version-incremental-source',
         },
         metadata)
 
   def test_GetPackageMetadata_wipe(self):
     target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
     common.OPTIONS.wipe_user_data = True
-    metadata = GetPackageMetadata(target_info)
+    metadata = self.GetLegacyOtaMetadata(target_info)
     self.assertDictEqual(
         {
-            'ota-type' : 'BLOCK',
-            'ota-wipe' : 'yes',
-            'post-build' : 'build-fingerprint-target',
-            'post-build-incremental' : 'build-version-incremental-target',
-            'post-sdk-level' : '27',
-            'post-security-patch-level' : '2017-12-01',
-            'post-timestamp' : '1500000000',
-            'pre-device' : 'product-device',
+            'ota-type': 'BLOCK',
+            'ota-required-cache': '0',
+            'ota-wipe': 'yes',
+            'post-build': 'build-fingerprint-target',
+            'post-build-incremental': 'build-version-incremental-target',
+            'post-sdk-level': '27',
+            'post-security-patch-level': '2017-12-01',
+            'post-timestamp': '1500000000',
+            'pre-device': 'product-device',
         },
         metadata)
 
   def test_GetPackageMetadata_retrofitDynamicPartitions(self):
     target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
     common.OPTIONS.retrofit_dynamic_partitions = True
-    metadata = GetPackageMetadata(target_info)
+    metadata = self.GetLegacyOtaMetadata(target_info)
     self.assertDictEqual(
         {
-            'ota-retrofit-dynamic-partitions' : 'yes',
-            'ota-type' : 'BLOCK',
-            'post-build' : 'build-fingerprint-target',
-            'post-build-incremental' : 'build-version-incremental-target',
-            'post-sdk-level' : '27',
-            'post-security-patch-level' : '2017-12-01',
-            'post-timestamp' : '1500000000',
-            'pre-device' : 'product-device',
+            'ota-retrofit-dynamic-partitions': 'yes',
+            'ota-type': 'BLOCK',
+            'ota-required-cache': '0',
+            'post-build': 'build-fingerprint-target',
+            'post-build-incremental': 'build-version-incremental-target',
+            'post-sdk-level': '27',
+            'post-security-patch-level': '2017-12-01',
+            'post-timestamp': '1500000000',
+            'pre-device': 'product-device',
         },
         metadata)
 
@@ -306,7 +306,7 @@
     target_info = common.BuildInfo(target_info_dict, None)
     source_info = common.BuildInfo(source_info_dict, None)
     common.OPTIONS.incremental_source = ''
-    self.assertRaises(RuntimeError, GetPackageMetadata, target_info,
+    self.assertRaises(RuntimeError, self.GetLegacyOtaMetadata, target_info,
                       source_info)
 
   def test_GetPackageMetadata_downgrade(self):
@@ -320,20 +320,22 @@
     common.OPTIONS.incremental_source = ''
     common.OPTIONS.downgrade = True
     common.OPTIONS.wipe_user_data = True
-    metadata = GetPackageMetadata(target_info, source_info)
+    metadata = self.GetLegacyOtaMetadata(target_info, source_info)
+
     self.assertDictEqual(
         {
-            'ota-downgrade' : 'yes',
-            'ota-type' : 'BLOCK',
-            'ota-wipe' : 'yes',
-            'post-build' : 'build-fingerprint-target',
-            'post-build-incremental' : 'build-version-incremental-target',
-            'post-sdk-level' : '27',
-            'post-security-patch-level' : '2017-12-01',
-            'post-timestamp' : '1400000000',
-            'pre-device' : 'product-device',
-            'pre-build' : 'build-fingerprint-source',
-            'pre-build-incremental' : 'build-version-incremental-source',
+            'ota-downgrade': 'yes',
+            'ota-type': 'BLOCK',
+            'ota-required-cache': '0',
+            'ota-wipe': 'yes',
+            'post-build': 'build-fingerprint-target',
+            'post-build-incremental': 'build-version-incremental-target',
+            'post-sdk-level': '27',
+            'post-security-patch-level': '2017-12-01',
+            'post-timestamp': '1400000000',
+            'pre-device': 'product-device',
+            'pre-build': 'build-fingerprint-source',
+            'pre-build-incremental': 'build-version-incremental-source',
         },
         metadata)
 
@@ -477,13 +479,13 @@
             'A' * 1024 * 1024 * 1024,
             zipfile.ZIP_STORED)
 
-    metadata = {}
+    metadata = ota_metadata_pb2.OtaMetadata()
     output_file = common.MakeTempFile(suffix='.zip')
     needed_property_files = (
         TestPropertyFiles(),
     )
     FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
-    self.assertIn('ota-test-property-files', metadata)
+    self.assertIn('ota-test-property-files', metadata.property_files)
 
   @test_utils.SkipIfExternalToolsUnavailable()
   def test_FinalizeMetadata(self):
@@ -521,66 +523,13 @@
           'A' * 1024 * 1024,
           zipfile.ZIP_STORED)
 
-    metadata = {}
+    metadata = ota_metadata_pb2.OtaMetadata()
     needed_property_files = (
         TestPropertyFiles(),
     )
     output_file = common.MakeTempFile(suffix='.zip')
     FinalizeMetadata(metadata, zip_file, output_file, needed_property_files)
-    self.assertIn('ota-test-property-files', metadata)
-
-  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'].build_props['ro.build.fingerprint'] = (
-        'source-build-fingerprint')
-    source_info = common.BuildInfo(source_info_dict, None)
-
-    script_writer = test_utils.MockScriptWriter()
-    WriteFingerprintAssertion(script_writer, target_info, source_info)
-    self.assertEqual(
-        [('AssertSomeFingerprint', 'source-build-fingerprint',
-          'build-fingerprint-target')],
-        script_writer.lines)
-
-  def test_WriteFingerprintAssertion_with_source_oem_props(self):
-    target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
-    source_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
-                                   self.TEST_OEM_DICTS)
-
-    script_writer = test_utils.MockScriptWriter()
-    WriteFingerprintAssertion(script_writer, target_info, source_info)
-    self.assertEqual(
-        [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
-          'build-thumbprint')],
-        script_writer.lines)
-
-  def test_WriteFingerprintAssertion_with_target_oem_props(self):
-    target_info = common.BuildInfo(self.TEST_INFO_DICT_USES_OEM_PROPS,
-                                   self.TEST_OEM_DICTS)
-    source_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None)
-
-    script_writer = test_utils.MockScriptWriter()
-    WriteFingerprintAssertion(script_writer, target_info, source_info)
-    self.assertEqual(
-        [('AssertFingerprintOrThumbprint', 'build-fingerprint-target',
-          'build-thumbprint')],
-        script_writer.lines)
-
-  def test_WriteFingerprintAssertion_with_both_oem_props(self):
-    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'].build_props['ro.build.thumbprint'] = (
-        'source-build-thumbprint')
-    source_info = common.BuildInfo(source_info_dict, self.TEST_OEM_DICTS)
-
-    script_writer = test_utils.MockScriptWriter()
-    WriteFingerprintAssertion(script_writer, target_info, source_info)
-    self.assertEqual(
-        [('AssertSomeThumbprint', 'build-thumbprint',
-          'source-build-thumbprint')],
-        script_writer.lines)
+    self.assertIn('ota-test-property-files', metadata.property_files)
 
 
 class TestPropertyFiles(PropertyFiles):
@@ -599,40 +548,7 @@
     )
 
 
-class PropertyFilesTest(test_utils.ReleaseToolsTestCase):
-
-  def setUp(self):
-    common.OPTIONS.no_signing = False
-
-  @staticmethod
-  def construct_zip_package(entries):
-    zip_file = common.MakeTempFile(suffix='.zip')
-    with zipfile.ZipFile(zip_file, 'w') as zip_fp:
-      for entry in entries:
-        zip_fp.writestr(
-            entry,
-            entry.replace('.', '-').upper(),
-            zipfile.ZIP_STORED)
-    return zip_file
-
-  @staticmethod
-  def _parse_property_files_string(data):
-    result = {}
-    for token in data.split(','):
-      name, info = token.split(':', 1)
-      result[name] = info
-    return result
-
-  def _verify_entries(self, input_file, tokens, entries):
-    for entry in entries:
-      offset, size = map(int, tokens[entry].split(':'))
-      with open(input_file, 'rb') as input_fp:
-        input_fp.seek(offset)
-        if entry == 'metadata':
-          expected = b'META-INF/COM/ANDROID/METADATA'
-        else:
-          expected = entry.replace('.', '-').upper().encode()
-        self.assertEqual(expected, input_fp.read(size))
+class PropertyFilesTest(PropertyFilesTestCase):
 
   @test_utils.SkipIfExternalToolsUnavailable()
   def test_Compute(self):
@@ -646,7 +562,7 @@
       property_files_string = property_files.Compute(zip_fp)
 
     tokens = self._parse_property_files_string(property_files_string)
-    self.assertEqual(3, len(tokens))
+    self.assertEqual(4, len(tokens))
     self._verify_entries(zip_file, tokens, entries)
 
   def test_Compute_withOptionalEntries(self):
@@ -662,7 +578,7 @@
       property_files_string = property_files.Compute(zip_fp)
 
     tokens = self._parse_property_files_string(property_files_string)
-    self.assertEqual(5, len(tokens))
+    self.assertEqual(6, len(tokens))
     self._verify_entries(zip_file, tokens, entries)
 
   def test_Compute_missingRequiredEntry(self):
@@ -680,6 +596,7 @@
         'required-entry1',
         'required-entry2',
         'META-INF/com/android/metadata',
+        'META-INF/com/android/metadata.pb',
     ]
     zip_file = self.construct_zip_package(entries)
     property_files = TestPropertyFiles()
@@ -689,10 +606,11 @@
       streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
     tokens = self._parse_property_files_string(streaming_metadata)
 
-    self.assertEqual(3, len(tokens))
+    self.assertEqual(4, len(tokens))
     # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
     # streaming metadata.
     entries[2] = 'metadata'
+    entries[3] = 'metadata.pb'
     self._verify_entries(zip_file, tokens, entries)
 
   @test_utils.SkipIfExternalToolsUnavailable()
@@ -703,6 +621,7 @@
         'optional-entry1',
         'optional-entry2',
         'META-INF/com/android/metadata',
+        'META-INF/com/android/metadata.pb',
     )
     zip_file = self.construct_zip_package(entries)
     property_files = TestPropertyFiles()
@@ -737,6 +656,7 @@
         'optional-entry1',
         'optional-entry2',
         'META-INF/com/android/metadata',
+        'META-INF/com/android/metadata.pb',
     )
     zip_file = self.construct_zip_package(entries)
     property_files = TestPropertyFiles()
@@ -753,7 +673,7 @@
           AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
 
 
-class StreamingPropertyFilesTest(PropertyFilesTest):
+class StreamingPropertyFilesTest(PropertyFilesTestCase):
   """Additional validity checks specialized for StreamingPropertyFiles."""
 
   def test_init(self):
@@ -786,7 +706,7 @@
       property_files_string = property_files.Compute(zip_fp)
 
     tokens = self._parse_property_files_string(property_files_string)
-    self.assertEqual(5, len(tokens))
+    self.assertEqual(6, len(tokens))
     self._verify_entries(zip_file, tokens, entries)
 
   def test_Finalize(self):
@@ -796,6 +716,7 @@
         'care_map.txt',
         'compatibility.zip',
         'META-INF/com/android/metadata',
+        'META-INF/com/android/metadata.pb',
     ]
     zip_file = self.construct_zip_package(entries)
     property_files = StreamingPropertyFiles()
@@ -805,10 +726,11 @@
       streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
     tokens = self._parse_property_files_string(streaming_metadata)
 
-    self.assertEqual(5, len(tokens))
+    self.assertEqual(6, len(tokens))
     # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
     # streaming metadata.
     entries[4] = 'metadata'
+    entries[5] = 'metadata.pb'
     self._verify_entries(zip_file, tokens, entries)
 
   def test_Verify(self):
@@ -818,6 +740,7 @@
         'care_map.txt',
         'compatibility.zip',
         'META-INF/com/android/metadata',
+        'META-INF/com/android/metadata.pb',
     )
     zip_file = self.construct_zip_package(entries)
     property_files = StreamingPropertyFiles()
@@ -834,7 +757,7 @@
           AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
 
 
-class AbOtaPropertyFilesTest(PropertyFilesTest):
+class AbOtaPropertyFilesTest(PropertyFilesTestCase):
   """Additional validity checks specialized for AbOtaPropertyFiles."""
 
   # The size for payload and metadata signature size.
@@ -849,7 +772,7 @@
     common.OPTIONS.payload_signer_args = None
     common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
     common.OPTIONS.key_passwords = {
-        common.OPTIONS.package_key : None,
+        common.OPTIONS.package_key: None,
     }
 
   def test_init(self):
@@ -954,6 +877,7 @@
       # Put META-INF/com/android/metadata if needed.
       if with_metadata:
         entries.append('META-INF/com/android/metadata')
+        entries.append('META-INF/com/android/metadata.pb')
 
       for entry in entries:
         zip_fp.writestr(
@@ -969,9 +893,9 @@
       property_files_string = property_files.Compute(zip_fp)
 
     tokens = self._parse_property_files_string(property_files_string)
-    # "6" indcludes the four entries above, one metadata entry, and one entry
+    # "7" indcludes the four entries above, two metadata entries, and one entry
     # for payload-metadata.bin.
-    self.assertEqual(6, len(tokens))
+    self.assertEqual(7, len(tokens))
     self._verify_entries(
         zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
 
@@ -982,12 +906,13 @@
     with zipfile.ZipFile(zip_file, 'r') as zip_fp:
       raw_metadata = property_files.GetPropertyFilesString(
           zip_fp, reserve_space=False)
-      property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
+      property_files_string = property_files.Finalize(
+          zip_fp, len(raw_metadata))
 
     tokens = self._parse_property_files_string(property_files_string)
-    # "6" indcludes the four entries above, one metadata entry, and one entry
+    # "7" includes the four entries above, two metadata entries, and one entry
     # for payload-metadata.bin.
-    self.assertEqual(6, len(tokens))
+    self.assertEqual(7, len(tokens))
     self._verify_entries(
         zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
 
@@ -1002,56 +927,6 @@
       property_files.Verify(zip_fp, raw_metadata)
 
 
-class NonAbOtaPropertyFilesTest(PropertyFilesTest):
-  """Additional validity checks specialized for NonAbOtaPropertyFiles."""
-
-  def test_init(self):
-    property_files = NonAbOtaPropertyFiles()
-    self.assertEqual('ota-property-files', property_files.name)
-    self.assertEqual((), property_files.required)
-    self.assertEqual((), property_files.optional)
-
-  def test_Compute(self):
-    entries = ()
-    zip_file = self.construct_zip_package(entries)
-    property_files = NonAbOtaPropertyFiles()
-    with zipfile.ZipFile(zip_file) as zip_fp:
-      property_files_string = property_files.Compute(zip_fp)
-
-    tokens = self._parse_property_files_string(property_files_string)
-    self.assertEqual(1, len(tokens))
-    self._verify_entries(zip_file, tokens, entries)
-
-  def test_Finalize(self):
-    entries = [
-        'META-INF/com/android/metadata',
-    ]
-    zip_file = self.construct_zip_package(entries)
-    property_files = NonAbOtaPropertyFiles()
-    with zipfile.ZipFile(zip_file) as zip_fp:
-      raw_metadata = property_files.GetPropertyFilesString(
-          zip_fp, reserve_space=False)
-      property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
-    tokens = self._parse_property_files_string(property_files_string)
-
-    self.assertEqual(1, len(tokens))
-    # 'META-INF/com/android/metadata' will be key'd as 'metadata'.
-    entries[0] = 'metadata'
-    self._verify_entries(zip_file, tokens, entries)
-
-  def test_Verify(self):
-    entries = (
-        'META-INF/com/android/metadata',
-    )
-    zip_file = self.construct_zip_package(entries)
-    property_files = NonAbOtaPropertyFiles()
-    with zipfile.ZipFile(zip_file) as zip_fp:
-      raw_metadata = property_files.GetPropertyFilesString(
-          zip_fp, reserve_space=False)
-
-      property_files.Verify(zip_fp, raw_metadata)
-
-
 class PayloadSignerTest(test_utils.ReleaseToolsTestCase):
 
   SIGFILE = 'sigfile.bin'
@@ -1065,7 +940,7 @@
     common.OPTIONS.payload_signer_args = []
     common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
     common.OPTIONS.key_passwords = {
-        common.OPTIONS.package_key : None,
+        common.OPTIONS.package_key: None,
     }
 
   def _assertFilesEqual(self, file1, file2):
@@ -1083,7 +958,7 @@
     common.OPTIONS.package_key = os.path.join(
         self.testdata_dir, 'testkey_with_passwd')
     common.OPTIONS.key_passwords = {
-        common.OPTIONS.package_key : 'foo',
+        common.OPTIONS.package_key: 'foo',
     }
     payload_signer = PayloadSigner()
     self.assertEqual('openssl', payload_signer.signer)
@@ -1160,7 +1035,7 @@
     common.OPTIONS.payload_signer_args = None
     common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
     common.OPTIONS.key_passwords = {
-        common.OPTIONS.package_key : None,
+        common.OPTIONS.package_key: None,
     }
 
   @staticmethod
@@ -1315,8 +1190,8 @@
       # Then assert these entries are stored.
       for entry_info in verify_zip.infolist():
         if entry_info.filename not in (
-            Payload.SECONDARY_PAYLOAD_BIN,
-            Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
+                Payload.SECONDARY_PAYLOAD_BIN,
+                Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT):
           continue
         self.assertEqual(zipfile.ZIP_STORED, entry_info.compress_type)
 
@@ -1326,6 +1201,7 @@
       'recovery_api_version=3',
       'fstab_version=2',
       'recovery_as_boot=true',
+      'ab_update=true',
   ]
 
   BUILD_PROP = [
@@ -1336,10 +1212,29 @@
       'ro.build.tags=build-tags',
       'ro.build.version.sdk=30',
       'ro.build.version.security_patch=2020',
-      'ro.build.date.utc=12345678'
+      'ro.build.date.utc=12345678',
+      '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.version.sdk=30',
+      'ro.system.build.version.security_patch=2020',
+      'ro.system.build.date.utc=12345678',
+      'ro.product.system.brand=generic',
+      'ro.product.system.name=generic',
+      'ro.product.system.device=generic',
   ]
 
   VENDOR_BUILD_PROP = [
+      'ro.vendor.build.version.release=version-release',
+      'ro.vendor.build.id=build-id',
+      'ro.vendor.build.version.incremental=version-incremental',
+      'ro.vendor.build.type=build-type',
+      'ro.vendor.build.tags=build-tags',
+      'ro.vendor.build.version.sdk=30',
+      'ro.vendor.build.version.security_patch=2020',
+      'ro.vendor.build.date.utc=12345678',
       'ro.product.vendor.brand=vendor-product-brand',
       'ro.product.vendor.name=vendor-product-name',
       'ro.product.vendor.device=vendor-product-device'
@@ -1468,6 +1363,7 @@
         'ro.product.vendor.name=vendor-product-std',
         'VENDOR/etc/build_pro.prop':
         'ro.product.vendor.name=vendor-product-pro',
+        AB_PARTITIONS: '\n'.join(['system', 'vendor']),
     }, self.test_dir)
 
     common.OPTIONS.boot_variable_file = common.MakeTempFile()
@@ -1475,8 +1371,8 @@
       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'])
+    metadata_dict = BuildLegacyOtaMetadata(GetPackageMetadata(build_info))
+    self.assertEqual('vendor-product-device', metadata_dict['pre-device'])
     fingerprints = [
         self.constructFingerprint(
             'vendor-product-brand/vendor-product-name/vendor-product-device'),
@@ -1485,7 +1381,33 @@
         self.constructFingerprint(
             'vendor-product-brand/vendor-product-std/vendor-product-device'),
     ]
-    self.assertEqual('|'.join(fingerprints), metadata['post-build'])
+    self.assertEqual('|'.join(fingerprints), metadata_dict['post-build'])
+
+  def CheckMetadataEqual(self, metadata_dict, metadata_proto):
+    post_build = metadata_proto.postcondition
+    self.assertEqual('|'.join(post_build.build),
+                     metadata_dict['post-build'])
+    self.assertEqual(post_build.build_incremental,
+                     metadata_dict['post-build-incremental'])
+    self.assertEqual(post_build.sdk_level,
+                     metadata_dict['post-sdk-level'])
+    self.assertEqual(post_build.security_patch_level,
+                     metadata_dict['post-security-patch-level'])
+
+    if metadata_proto.type == ota_metadata_pb2.OtaMetadata.AB:
+      ota_type = 'AB'
+    elif metadata_proto.type == ota_metadata_pb2.OtaMetadata.BLOCK:
+      ota_type = 'BLOCK'
+    else:
+      ota_type = ''
+    self.assertEqual(ota_type, metadata_dict['ota-type'])
+    self.assertEqual(metadata_proto.wipe,
+                     metadata_dict.get('ota-wipe') == 'yes')
+    self.assertEqual(metadata_proto.required_cache,
+                     int(metadata_dict.get('ota-required-cache', 0)))
+    self.assertEqual(metadata_proto.retrofit_dynamic_partitions,
+                     metadata_dict.get(
+                         'ota-retrofit-dynamic-partitions') == 'yes')
 
   def test_GetPackageMetadata_incremental_package(self):
     vendor_build_prop = copy.deepcopy(self.VENDOR_BUILD_PROP)
@@ -1493,6 +1415,8 @@
         'import /vendor/etc/build_${ro.boot.sku_name}.prop',
     ])
     self.writeFiles({
+        'META/misc_info.txt': '\n'.join(self.MISC_INFO),
+        'META/ab_partitions.txt': '\n'.join(['system', 'vendor', 'product']),
         'SYSTEM/build.prop': '\n'.join(self.BUILD_PROP),
         'VENDOR/build.prop': '\n'.join(vendor_build_prop),
         'VENDOR/etc/build_std.prop':
@@ -1514,10 +1438,22 @@
         'ro.build.tags=build-tags',
         'ro.build.version.sdk=29',
         'ro.build.version.security_patch=2020',
-        'ro.build.date.utc=12340000'
+        'ro.build.date.utc=12340000',
+        'ro.system.build.version.release=source-version-release',
+        'ro.system.build.id=source-build-id',
+        'ro.system.build.version.incremental=source-version-incremental',
+        'ro.system.build.type=build-type',
+        'ro.system.build.tags=build-tags',
+        'ro.system.build.version.sdk=29',
+        'ro.system.build.version.security_patch=2020',
+        'ro.system.build.date.utc=12340000',
+        'ro.product.system.brand=generic',
+        'ro.product.system.name=generic',
+        'ro.product.system.device=generic',
     ]
     self.writeFiles({
         'META/misc_info.txt': '\n'.join(self.MISC_INFO),
+        'META/ab_partitions.txt': '\n'.join(['system', 'vendor', 'product']),
         'SYSTEM/build.prop': '\n'.join(source_build_prop),
         'VENDOR/build.prop': '\n'.join(vendor_build_prop),
         'VENDOR/etc/build_std.prop':
@@ -1530,21 +1466,22 @@
     target_info = common.BuildInfo(common.LoadInfoDict(self.test_dir))
     source_info = common.BuildInfo(common.LoadInfoDict(source_dir))
 
-    metadata = GetPackageMetadata(target_info, source_info)
+    metadata_proto = GetPackageMetadata(target_info, source_info)
+    metadata_dict = BuildLegacyOtaMetadata(metadata_proto)
     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'
+        metadata_dict['pre-device'])
+    source_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),
+        '{}'.format(source_suffix),
         'vendor-product-brand/vendor-product-name/vendor-device-std'
-        '{}'.format(suffix),
+        '{}'.format(source_suffix),
         'vendor-product-brand/vendor-product-name/vendor-product-device'
-        '{}'.format(suffix),
+        '{}'.format(source_suffix),
     ]
-    self.assertEqual('|'.join(pre_fingerprints), metadata['pre-build'])
+    self.assertEqual('|'.join(pre_fingerprints), metadata_dict['pre-build'])
 
     post_fingerprints = [
         self.constructFingerprint(
@@ -1554,4 +1491,31 @@
         self.constructFingerprint(
             'vendor-product-brand/vendor-product-name/vendor-product-device'),
     ]
-    self.assertEqual('|'.join(post_fingerprints), metadata['post-build'])
+    self.assertEqual('|'.join(post_fingerprints), metadata_dict['post-build'])
+
+    self.CheckMetadataEqual(metadata_dict, metadata_proto)
+
+    pre_partition_states = metadata_proto.precondition.partition_state
+    self.assertEqual(2, len(pre_partition_states))
+    self.assertEqual('system', pre_partition_states[0].partition_name)
+    self.assertEqual(['generic'], pre_partition_states[0].device)
+    self.assertEqual(['generic/generic/generic{}'.format(source_suffix)],
+                     pre_partition_states[0].build)
+
+    self.assertEqual('vendor', pre_partition_states[1].partition_name)
+    self.assertEqual(['vendor-device-pro', 'vendor-device-std',
+                      'vendor-product-device'], pre_partition_states[1].device)
+    vendor_fingerprints = post_fingerprints
+    self.assertEqual(vendor_fingerprints, pre_partition_states[1].build)
+
+    post_partition_states = metadata_proto.postcondition.partition_state
+    self.assertEqual(2, len(post_partition_states))
+    self.assertEqual('system', post_partition_states[0].partition_name)
+    self.assertEqual(['generic'], post_partition_states[0].device)
+    self.assertEqual([self.constructFingerprint('generic/generic/generic')],
+                     post_partition_states[0].build)
+
+    self.assertEqual('vendor', post_partition_states[1].partition_name)
+    self.assertEqual(['vendor-device-pro', 'vendor-device-std',
+                      'vendor-product-device'], post_partition_states[1].device)
+    self.assertEqual(vendor_fingerprints, post_partition_states[1].build)
diff --git a/tools/releasetools/test_utils.py b/tools/releasetools/test_utils.py
index e999757..7b7f22a 100755
--- a/tools/releasetools/test_utils.py
+++ b/tools/releasetools/test_utils.py
@@ -22,9 +22,11 @@
 import logging
 import os
 import os.path
+import re
 import struct
 import sys
 import unittest
+import zipfile
 
 import common
 
@@ -192,9 +194,57 @@
   def tearDown(self):
     common.Cleanup()
 
+class PropertyFilesTestCase(ReleaseToolsTestCase):
+
+  @staticmethod
+  def construct_zip_package(entries):
+    zip_file = common.MakeTempFile(suffix='.zip')
+    with zipfile.ZipFile(zip_file, 'w') as zip_fp:
+      for entry in entries:
+        zip_fp.writestr(
+            entry,
+            entry.replace('.', '-').upper(),
+            zipfile.ZIP_STORED)
+    return zip_file
+
+  @staticmethod
+  def _parse_property_files_string(data):
+    result = {}
+    for token in data.split(','):
+      name, info = token.split(':', 1)
+      result[name] = info
+    return result
+
+  def setUp(self):
+    common.OPTIONS.no_signing = False
+
+  def _verify_entries(self, input_file, tokens, entries):
+    for entry in entries:
+      offset, size = map(int, tokens[entry].split(':'))
+      with open(input_file, 'rb') as input_fp:
+        input_fp.seek(offset)
+        if entry == 'metadata':
+          expected = b'META-INF/COM/ANDROID/METADATA'
+        elif entry == 'metadata.pb':
+          expected = b'META-INF/COM/ANDROID/METADATA-PB'
+        else:
+          expected = entry.replace('.', '-').upper().encode()
+        self.assertEqual(expected, input_fp.read(size))
+
 
 if __name__ == '__main__':
-  testsuite = unittest.TestLoader().discover(
-      os.path.dirname(os.path.realpath(__file__)))
+  # We only want to run tests from the top level directory. Unfortunately the
+  # pattern option of unittest.discover, internally using fnmatch, doesn't
+  # provide a good API to filter the test files based on directory. So we do an
+  # os walk and load them manually.
+  test_modules = []
+  base_path = os.path.dirname(os.path.realpath(__file__))
+  for dirpath, _, files in os.walk(base_path):
+    for fn in files:
+      if dirpath == base_path and re.match('test_.*\\.py$', fn):
+        test_modules.append(fn[:-3])
+
+  test_suite = unittest.TestLoader().loadTestsFromNames(test_modules)
+
   # atest needs a verbosity level of >= 2 to correctly parse the result.
-  unittest.TextTestRunner(verbosity=2).run(testsuite)
+  unittest.TextTestRunner(verbosity=2).run(test_suite)
diff --git a/tools/signapk/src/com/android/signapk/SignApk.java b/tools/signapk/src/com/android/signapk/SignApk.java
index 95ef05f..7e5c8fc 100644
--- a/tools/signapk/src/com/android/signapk/SignApk.java
+++ b/tools/signapk/src/com/android/signapk/SignApk.java
@@ -41,6 +41,7 @@
 import com.android.apksig.apk.ApkUtils;
 import com.android.apksig.apk.MinSdkVersionException;
 import com.android.apksig.util.DataSink;
+import com.android.apksig.util.DataSource;
 import com.android.apksig.util.DataSources;
 import com.android.apksig.zip.ZipFormatException;
 
@@ -57,6 +58,7 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.RandomAccessFile;
 import java.lang.reflect.Constructor;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -1021,9 +1023,10 @@
                            "[-providerClass <className>] " +
                            "[--min-sdk-version <n>] " +
                            "[--disable-v2] " +
+                           "[--enable-v4] " +
                            "publickey.x509[.pem] privatekey.pk8 " +
                            "[publickey2.x509[.pem] privatekey2.pk8 ...] " +
-                           "input.jar output.jar");
+                           "input.jar output.jar [output-v4-file]");
         System.exit(2);
     }
 
@@ -1043,6 +1046,7 @@
         int alignment = 4;
         Integer minSdkVersionOverride = null;
         boolean signUsingApkSignatureSchemeV2 = true;
+        boolean signUsingApkSignatureSchemeV4 = false;
         SigningCertificateLineage certLineage = null;
 
         int argstart = 0;
@@ -1071,6 +1075,9 @@
             } else if ("--disable-v2".equals(args[argstart])) {
                 signUsingApkSignatureSchemeV2 = false;
                 ++argstart;
+            } else if ("--enable-v4".equals(args[argstart])) {
+                signUsingApkSignatureSchemeV4 = true;
+                ++argstart;
             } else if ("--lineage".equals(args[argstart])) {
                 File lineageFile = new File(args[++argstart]);
                 try {
@@ -1085,8 +1092,14 @@
             }
         }
 
-        if ((args.length - argstart) % 2 == 1) usage();
-        int numKeys = ((args.length - argstart) / 2) - 1;
+        int numArgsExcludeV4FilePath;
+        if (signUsingApkSignatureSchemeV4) {
+            numArgsExcludeV4FilePath = args.length - 1;
+        } else {
+            numArgsExcludeV4FilePath = args.length;
+        }
+        if ((numArgsExcludeV4FilePath - argstart) % 2 == 1) usage();
+        int numKeys = ((numArgsExcludeV4FilePath - argstart) / 2) - 1;
         if (signWholeFile && numKeys > 1) {
             System.err.println("Only one key may be used with -w.");
             System.exit(2);
@@ -1094,8 +1107,12 @@
 
         loadProviderIfNecessary(providerClass);
 
-        String inputFilename = args[args.length-2];
-        String outputFilename = args[args.length-1];
+        String inputFilename = args[numArgsExcludeV4FilePath - 2];
+        String outputFilename = args[numArgsExcludeV4FilePath - 1];
+        String outputV4Filename = "";
+        if (signUsingApkSignatureSchemeV4) {
+            outputV4Filename = args[args.length - 1];
+        }
 
         JarFile inputJar = null;
         FileOutputStream outputFile = null;
@@ -1233,6 +1250,13 @@
                     outputFile.close();
                     outputFile = null;
                     apkSigner.outputDone();
+
+                    if (signUsingApkSignatureSchemeV4) {
+                        final DataSource outputApkIn = DataSources.asDataSource(
+                                new RandomAccessFile(new File(outputFilename), "r"));
+                        final File outputV4File =  new File(outputV4Filename);
+                        apkSigner.signV4(outputApkIn, outputV4File, false /* ignore failures */);
+                    }
                 }
 
                 return;
diff --git a/tools/warn/android_project_list.py b/tools/warn/android_project_list.py
index 4726fa2..1010b24 100644
--- a/tools/warn/android_project_list.py
+++ b/tools/warn/android_project_list.py
@@ -102,6 +102,7 @@
     create_pattern('ndk'),
     # match vendor/unbungled_google/packages before other packages
     create_pattern('unbundled_google'),
+    create_pattern('packages/providers/MediaProvider'),
     create_pattern('packages'),
     create_pattern('pdk'),
     create_pattern('prebuilts'),
diff --git a/tools/warn/cpp_warn_patterns.py b/tools/warn/cpp_warn_patterns.py
index 65ce73a..e8783bc 100644
--- a/tools/warn/cpp_warn_patterns.py
+++ b/tools/warn/cpp_warn_patterns.py
@@ -155,6 +155,7 @@
            [r".*: warning: unknown attribute '.+'"]),
     medium('Attribute ignored',
            [r".*: warning: '_*packed_*' attribute ignored",
+            r".*: warning: .* not supported .*Wignored-attributes",
             r".*: warning: attribute declaration must precede definition .+ignored-attributes"]),
     medium('Visibility problem',
            [r".*: warning: declaration of '.+' will not be visible outside of this function"]),
@@ -251,6 +252,8 @@
            [r".*: warning: taking address of temporary"]),
     medium('Taking address of packed member',
            [r".*: warning: taking address of packed member"]),
+    medium('Pack alignment value is modified',
+           [r".*: warning: .*#pragma pack alignment value is modified.*Wpragma-pack.*"]),
     medium('Possible broken line continuation',
            [r".*: warning: backslash and newline separated by space"]),
     medium('Undefined variable template',
@@ -332,7 +335,7 @@
              [r".*: warning: extra tokens at end of #endif directive"]),
     medium('Comparison between different enums',
            [r".*: warning: comparison between '.+' and '.+'.+Wenum-compare",
-            r".*: warning: comparison of .* enumeration types .*-Wenum-compare-switch"]),
+            r".*: warning: comparison of .* enumeration types .*-Wenum-compare.*"]),
     medium('Conversion may change value',
            [r".*: warning: converting negative value '.+' to '.+'",
             r".*: warning: conversion to '.+' .+ may (alter|change)"]),
@@ -396,6 +399,8 @@
          r".*: warning: absolute value function '.+' given .+ which may cause truncation .+Wabsolute-value"]),
     low('Using C++11 extensions',
         [r".*: warning: 'auto' type specifier is a C\+\+11 extension"]),
+    low('Using C++17 extensions',
+        [r".*: warning: .* a C\+\+17 extension .+Wc\+\+17-extensions"]),
     low('Refers to implicitly defined namespace',
         [r".*: warning: using directive refers to implicitly-defined namespace .+"]),
     low('Invalid pp token',
@@ -437,8 +442,10 @@
            [r".*: warning: unannotated fall-through between switch labels.+Wimplicit-fallthrough"]),
     medium('Invalid partial specialization',
            [r".*: warning: class template partial specialization.+Winvalid-partial-specialization"]),
-    medium('Overlapping compatisons',
+    medium('Overlapping comparisons',
            [r".*: warning: overlapping comparisons.+Wtautological-overlap-compare"]),
+    medium('bitwise comparison',
+           [r".*: warning: bitwise comparison.+Wtautological-bitwise-compare"]),
     medium('int in bool context',
            [r".*: warning: converting.+to a boolean.+Wint-in-bool-context"]),
     medium('bitwise conditional parentheses',
diff --git a/tools/warn/java_warn_patterns.py b/tools/warn/java_warn_patterns.py
index 17e3864..ac1ed5d 100644
--- a/tools/warn/java_warn_patterns.py
+++ b/tools/warn/java_warn_patterns.py
@@ -486,6 +486,7 @@
                 [r'.*\.java:.*: warning: \[static\] static method should be qualified']),
     medium('AbstractInner'),
     medium('BothPackageInfoAndHtml'),
+    medium('BuilderSetStyle'),
     medium('CallbackName'),
     medium('ExecutorRegistration'),
     medium('HiddenTypeParameter'),
@@ -493,9 +494,11 @@
     medium('ListenerLast'),
     medium('MinMaxConstant'),
     medium('MissingBuildMethod'),
+    medium('MissingGetterMatchingBuilder'),
     medium('NoByteOrShort'),
     medium('OverlappingConstants'),
     medium('SetterReturnsThis'),
+    medium('StaticFinalBuilder'),
     medium('StreamFiles'),
     medium('Typo'),
     medium('UseIcu'),
diff --git a/tools/warn/other_warn_patterns.py b/tools/warn/other_warn_patterns.py
index 318c3d4..8df5b87 100644
--- a/tools/warn/other_warn_patterns.py
+++ b/tools/warn/other_warn_patterns.py
@@ -143,6 +143,8 @@
     # Yacc warnings
     yacc('deprecate directive',
          [r".*\.yy?:.*: warning: deprecated directive: "]),
+    yacc('reduce/reduce conflicts',
+         [r".*\.yy?: warning: .+ reduce/reduce conflicts "]),
     yacc('shift/reduce conflicts',
          [r".*\.yy?: warning: .+ shift/reduce conflicts "]),
     {'category': 'yacc', 'severity': Severity.SKIP,