Merge "Add virtual A/B compression product."
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 e099a72..37ff378 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
@@ -584,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
@@ -749,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
@@ -1036,6 +1051,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))
@@ -2286,6 +2303,26 @@
 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
 
@@ -2293,6 +2330,21 @@
     $(ALL_GENERATED_SOURCES) \
     $(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)
 
 # ASAN libraries in the system image - add dependency.
@@ -2332,57 +2384,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)
@@ -2665,29 +2669,10 @@
     $(filter $(TARGET_OUT_VENDOR)/%,\
       $(ALL_DEFAULT_INSTALLED_MODULES))
 
-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:
@@ -2705,48 +2690,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)
@@ -2754,9 +2709,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 \
@@ -2897,6 +2849,24 @@
     $(filter $(TARGET_OUT_ODM)/%,\
       $(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)
 $(INSTALLED_FILES_FILE_ODM): .KATI_IMPLICIT_OUTPUTS := $(INSTALLED_FILES_JSON_ODM)
@@ -3169,22 +3139,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) \
@@ -3194,11 +3164,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) \
@@ -4156,6 +4126,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)
@@ -4304,34 +4277,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) \
@@ -4359,12 +4396,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)))
@@ -4407,7 +4438,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
@@ -4597,14 +4628,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), \
@@ -4683,9 +4722,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
@@ -4759,13 +4796,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)
@@ -4788,16 +4824,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
@@ -4816,16 +4851,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)
@@ -4845,7 +4879,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
 
 # -----------------------------------------------------------------
@@ -4859,7 +4893,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 $@)
@@ -4894,16 +4928,15 @@
 # For apps_only build we'll establish the dependency later in build/make/core/main.mk.
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
 $(PROGUARD_DICT_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) \
+    $(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
@@ -5427,7 +5460,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/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 7397470..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)
@@ -515,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
 
@@ -761,7 +766,7 @@
     $(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)/$(notdir $(test_config_file))))))
+          $(test_config_file):$(dir)/$(basename $(notdir $(test_config_file))).config))))
   endif
 
   ifneq (,$(wildcard $(LOCAL_PATH)/DynamicConfig.xml))
@@ -981,6 +986,7 @@
 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/board_config.mk b/core/board_config.mk
index 12b26c6..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 \
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 9c29974..d515db3 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -300,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 57296d8..be0b55c 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -678,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.
@@ -720,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)),)
@@ -769,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/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/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/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 bf07b49..ebec885 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -81,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
@@ -419,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
 
@@ -606,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)) \
@@ -1406,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)
@@ -1790,9 +1796,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 4d1009f..6fccacd 100644
--- a/core/ninja_config.mk
+++ b/core/ninja_config.mk
@@ -35,7 +35,6 @@
 	sdk_addon \
 	sdk_repo \
 	stnod \
-	target-files-package \
 	test-art% \
 	user \
 	userdataimage \
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 5e55cfb..91606d4 100644
--- a/core/rbe.mk
+++ b/core/rbe.mk
@@ -57,7 +57,7 @@
   java_r8_d8_platform := $(platform),Pool=java16
 
   RBE_WRAPPER := $(rbe_dir)/rewrapper
-  RBE_CXX := --labels=type=compile,lang=cpp,compiler=clang --env_var_whitelist=PWD --exec_strategy=$(cxx_rbe_exec_strategy) --platform=$(cxx_platform) --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.
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/soong_cc_prebuilt.mk b/core/soong_cc_prebuilt.mk
index c9b742a..a0315a5 100644
--- a/core/soong_cc_prebuilt.mk
+++ b/core/soong_cc_prebuilt.mk
@@ -142,8 +142,16 @@
   $(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)
+else
 	$(transform-prebuilt-to-target)
+endif
 ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
 	$(hide) chmod +x $@
 endif
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 4731250..ad2e816 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -210,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_rust_prebuilt.mk b/core/soong_rust_prebuilt.mk
index 804e37e..b54f300 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,7 +57,11 @@
 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)
+else
 	$(transform-prebuilt-to-target)
+endif
 ifneq ($(filter EXECUTABLES NATIVE_TESTS,$(LOCAL_MODULE_CLASS)),)
 	$(hide) chmod +x $@
 endif
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 d9aebed..cf32d65 100644
--- a/core/tasks/module-info.mk
+++ b/core/tasks/module-info.mk
@@ -19,6 +19,7 @@
 			'"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..f252ff5 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,$(ALL_MODULES.$(m).INSTALLED),\
+      $(eval $(call not_available_for_platform_rule,$(i),$(m)))))
+endif
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..b836e54 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.
@@ -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 adcf081..724ad7d 100644
--- a/rbesetup.sh
+++ b/rbesetup.sh
@@ -36,6 +36,7 @@
 # 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
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 c20c782..c45a8ab 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -58,6 +58,7 @@
 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
@@ -74,7 +75,7 @@
 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
diff --git a/target/board/generic_arm64/device.mk b/target/board/generic_arm64/device.mk
index dfa146a..1585fbd 100644
--- a/target/board/generic_arm64/device.mk
+++ b/target/board/generic_arm64/device.mk
@@ -15,6 +15,7 @@
 #
 
 PRODUCT_COPY_FILES += \
+    kernel/prebuilts/4.19/arm64/Image.gz:kernel-4.19-gz \
     device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4:kernel-5.4 \
     device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4-gz:kernel-5.4-gz \
     device/google/cuttlefish_kernel/5.4-arm64/kernel-5.4-lz4:kernel-5.4-lz4 \
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index 8c069ba..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 \
diff --git a/target/product/aosp_64bitonly_x86_64.mk b/target/product/aosp_64bitonly_x86_64.mk
new file mode 100644
index 0000000..4de4e0c8
--- /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_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/base_system.mk b/target/product/base_system.mk
index f6770fb..b97d98d 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
@@ -324,12 +329,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 +360,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 47c4e23..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 \
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/generic_system.mk b/target/product/generic_system.mk
index bf74c4a..731a450 100644
--- a/target/product/generic_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 \
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/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_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/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..1bd2af7 100644
--- a/target/product/runtime_libart.mk
+++ b/target/product/runtime_libart.mk
@@ -92,8 +92,8 @@
     dalvik.vm.minidebuginfo=true \
     dalvik.vm.dex2oat-minidebuginfo=true
 
-# Disable iorapd by default
+# Enable iorapd by default
 PRODUCT_SYSTEM_PROPERTIES += \
-    ro.iorapd.enable=false
+    ro.iorapd.enable=true
 
 PRODUCT_USES_DEFAULT_ART_CONFIG := true
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/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..ee8efd50 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)
 
 
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..bad5e104
--- /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 21134b6..45e0514 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -89,16 +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",
-        "ota_from_target_files.py",
         "non_ab_ota.py",
-        "target_files_diff.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",
@@ -253,7 +272,9 @@
         "bsdiff",
         "imgdiff",
         "minigzip",
+        "lz4",
         "mkbootfs",
+        "signapk",
     ],
 }
 
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 56785d6..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()
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/non_ab_ota.py b/tools/releasetools/non_ab_ota.py
index 3a87957..471ef25 100644
--- a/tools/releasetools/non_ab_ota.py
+++ b/tools/releasetools/non_ab_ota.py
@@ -276,7 +276,7 @@
 
   script.SetProgress(1)
   script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
-  metadata["ota-required-cache"] = str(script.required_cache)
+  metadata.required_cache = script.required_cache
 
   # We haven't written the metadata entry, which will be done in
   # FinalizeMetadata.
@@ -530,7 +530,7 @@
     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)
+  metadata.required_cache = script.required_cache
 
   # We haven't written the metadata entry yet, which will be handled in
   # FinalizeMetadata().
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 962adc1..2833397 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -778,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")
@@ -825,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)
 
@@ -877,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()]
 
@@ -1073,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
index 4bb2b61..d444d41 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -17,6 +17,7 @@
 import os
 import zipfile
 
+import ota_metadata_pb2
 from common import (ZipDelete, ZipClose, OPTIONS, MakeTempFile,
                     ZipWriteStr, BuildInfo, LoadDictionaryFromFile,
                     SignFile, PARTITIONS_WITH_CARE_MAP, PartitionBuildProps)
@@ -34,6 +35,7 @@
 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/*']
 
 
@@ -62,11 +64,12 @@
     # 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)
+        metadata.property_files[property_files.name] = property_files.Compute(
+            input_zip)
       namelist = input_zip.namelist()
 
-    if METADATA_NAME in namelist:
-      ZipDelete(input_file, METADATA_NAME)
+    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)
@@ -81,8 +84,9 @@
   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]))
+        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
@@ -103,7 +107,7 @@
     FinalizeAllPropertyFiles(prelim_signing, needed_property_files)
 
   # Replace the METADATA entry.
-  ZipDelete(prelim_signing, METADATA_NAME)
+  ZipDelete(prelim_signing, [METADATA_NAME, METADATA_PROTO_NAME])
   output_zip = zipfile.ZipFile(prelim_signing, 'a')
   WriteMetadata(metadata, output_zip)
   ZipClose(output_zip)
@@ -117,7 +121,8 @@
   # 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())
+      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
@@ -125,30 +130,101 @@
     WriteMetadata(metadata, output_metadata_path)
 
 
-def WriteMetadata(metadata, output):
+def WriteMetadata(metadata_proto, 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.
+    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
   """
 
-  value = "".join(["%s=%s\n" % kv for kv in sorted(metadata.items())])
+  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_NAME, value,
+    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(value)
+    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 dict.
+  """Generates and returns the metadata proto.
 
-  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.
+  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.
@@ -156,66 +232,96 @@
         None if generating full OTA.
 
   Returns:
-    A dict to be written into package metadata entry.
+    A protobuf to be written into package metadata entry.
   """
   assert isinstance(target_info, BuildInfo)
   assert source_info is None or isinstance(source_info, BuildInfo)
 
-  separator = '|'
-
   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(',')]
 
-  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'),
-  }
+  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['ota-type'] = 'AB'
-    metadata['ota-required-cache'] = '0'
+    metadata_proto.type = ota_metadata_pb2.OtaMetadata.AB
+    metadata_proto.required_cache = 0
   else:
-    metadata['ota-type'] = 'BLOCK'
+    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['ota-wipe'] = 'yes'
+    metadata_proto.wipe = True
 
   if OPTIONS.retrofit_dynamic_partitions:
-    metadata['ota-retrofit-dynamic-partitions'] = 'yes'
+    metadata_proto.retrofit_dynamic_partitions = True
 
   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))
+    UpdateDeviceState(metadata_proto.precondition, source_info,
+                      boot_variable_values, False)
   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')
+    metadata_proto.precondition.device.extend(
+        metadata_proto.postcondition.device)
 
   # Detect downgrades and set up downgrade flags accordingly.
   if is_incremental:
-    HandleDowngradeMetadata(metadata, target_info, source_info)
+    HandleDowngradeMetadata(metadata_proto, target_info, source_info)
 
-  return metadata
+  return metadata_proto
 
 
-def HandleDowngradeMetadata(metadata, target_info, source_info):
+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
 
@@ -228,7 +334,7 @@
       raise RuntimeError(
           "--downgrade or --override_timestamp specified but no downgrade "
           "detected: pre: %s, post: %s" % (pre_timestamp, post_timestamp))
-    metadata["ota-downgrade"] = "yes"
+    metadata_proto.downgrade = True
   else:
     if is_downgrade:
       raise RuntimeError(
@@ -237,14 +343,12 @@
           "building the incremental." % (pre_timestamp, post_timestamp))
 
 
-def CalculateRuntimeDevicesAndFingerprints(build_info, boot_variable_values):
-  """Returns a tuple of sets for runtime devices and fingerprints"""
+def ComputeRuntimeBuildInfos(default_build_info, boot_variable_values):
+  """Returns a set of build info objects that may exist during runtime."""
 
-  device_names = {build_info.device}
-  fingerprints = {build_info.fingerprint}
-
+  build_info_set = {default_build_info}
   if not boot_variable_values:
-    return device_names, fingerprints
+    return build_info_set
 
   # Calculate all possible combinations of the values for the boot variables.
   keys = boot_variable_values.keys()
@@ -254,7 +358,7 @@
   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)
+    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
@@ -268,10 +372,22 @@
             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))
 
-    new_build_info = BuildInfo(info_dict, build_info.oem_dicts)
-    device_names.add(new_build_info.device)
-    fingerprints.add(new_build_info.fingerprint)
+  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
 
 
@@ -415,8 +531,10 @@
     # 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)
 
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
index ee1b411..5207e2f 100644
--- a/tools/releasetools/test_non_ab_ota.py
+++ b/tools/releasetools/test_non_ab_ota.py
@@ -42,12 +42,13 @@
       property_files_string = property_files.Compute(zip_fp)
 
     tokens = self._parse_property_files_string(property_files_string)
-    self.assertEqual(1, len(tokens))
+    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()
@@ -57,14 +58,16 @@
       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))
+    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()
diff --git a/tools/releasetools/test_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index 52aa487..84cd4c8 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -20,17 +20,20 @@
 import zipfile
 
 import common
+import ota_metadata_pb2
 import test_utils
-from ota_utils import CalculateRuntimeDevicesAndFingerprints
+from ota_utils import (
+    BuildLegacyOtaMetadata, CalculateRuntimeDevicesAndFingerprints,
+    FinalizeMetadata, GetPackageMetadata, PropertyFiles)
 from ota_from_target_files import (
-    _LoadOemDicts, AbOtaPropertyFiles, FinalizeMetadata,
-    GetPackageMetadata, GetTargetFilesZipForSecondaryImages,
+    _LoadOemDicts, AbOtaPropertyFiles,
+    GetTargetFilesZipForSecondaryImages,
     GetTargetFilesZipWithoutPostinstallConfig,
-    Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
-    StreamingPropertyFiles)
-from non_ab_ota import NonAbOtaPropertyFiles
+    Payload, PayloadSigner, POSTINSTALL_CONFIG,
+    StreamingPropertyFiles, AB_PARTITIONS)
 from test_utils import PropertyFilesTestCase
 
+
 def construct_target_files(secondary=False):
   """Returns a target-files.zip file for generating OTA packages."""
   target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
@@ -143,14 +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',
   }
 
-
   def setUp(self):
     self.testdata_dir = test_utils.get_testdata_dir()
     self.assertTrue(os.path.exists(self.testdata_dir))
@@ -164,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)
 
@@ -228,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)
 
@@ -293,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):
@@ -307,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)
 
@@ -464,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):
@@ -508,13 +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)
+    self.assertIn('ota-test-property-files', metadata.property_files)
 
 
 class TestPropertyFiles(PropertyFiles):
@@ -532,8 +547,8 @@
         'optional-entry2',
     )
 
-class PropertyFilesTest(PropertyFilesTestCase):
 
+class PropertyFilesTest(PropertyFilesTestCase):
 
   @test_utils.SkipIfExternalToolsUnavailable()
   def test_Compute(self):
@@ -547,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):
@@ -563,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):
@@ -581,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()
@@ -590,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()
@@ -604,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()
@@ -638,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()
@@ -687,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):
@@ -697,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()
@@ -706,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):
@@ -719,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()
@@ -750,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):
@@ -855,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(
@@ -870,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'))
 
@@ -883,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'))
 
@@ -916,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):
@@ -934,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)
@@ -1011,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
@@ -1166,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)
 
@@ -1177,6 +1201,7 @@
       'recovery_api_version=3',
       'fstab_version=2',
       'recovery_as_boot=true',
+      'ab_update=true',
   ]
 
   BUILD_PROP = [
@@ -1187,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'
@@ -1319,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()
@@ -1326,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'),
@@ -1336,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)
@@ -1344,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':
@@ -1365,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':
@@ -1381,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(
@@ -1405,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 65092d8..7b7f22a 100755
--- a/tools/releasetools/test_utils.py
+++ b/tools/releasetools/test_utils.py
@@ -22,6 +22,7 @@
 import logging
 import os
 import os.path
+import re
 import struct
 import sys
 import unittest
@@ -224,13 +225,26 @@
         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,