Merge "Generate unstripped .oat files in the symbols directory."
diff --git a/core/Makefile b/core/Makefile
index 33b697c..a248f5e 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -39,7 +39,6 @@
                 $(if $(filter init%rc,$(notdir $(_dest)))$(filter %/etc/init,$(dir $(_dest))),\
                     $(eval $(call copy-init-script-file-checked,$(_src),$(_fulldest))),\
                     $(eval $(call copy-one-file,$(_src),$(_fulldest)))))) \
-        $(eval ALL_DEFAULT_INSTALLED_MODULES += $(_fulldest)) \
         $(eval unique_product_copy_files_destinations += $(_dest))))
 
 # Dump a list of overriden (and ignored PRODUCT_COPY_FILES entries)
@@ -467,6 +466,34 @@
 # ----------------------------------------------------------------
 
 # -----------------------------------------------------------------
+# product-services build.prop
+INSTALLED_PRODUCT_SERVICES_BUILD_PROP_TARGET := $(TARGET_OUT_PRODUCT_SERVICES)/build.prop
+ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_PRODUCT_SERVICES_BUILD_PROP_TARGET)
+
+FINAL_PRODUCT_SERVICES_PROPERTIES += \
+    $(call collapse-pairs, $(PRODUCT_PRODUCT_SERVICES_PROPERTIES))
+FINAL_PRODUCT_SERVICES_PROPERTIES := $(call uniq-pairs-by-first-component, \
+    $(FINAL_PRODUCT_SERVICES_PROPERTIES),=)
+
+$(INSTALLED_PRODUCT_SERVICES_BUILD_PROP_TARGET):
+	@echo Target product-services buildinfo: $@
+	@mkdir -p $(dir $@)
+	$(hide) echo > $@
+ifdef BOARD_USES_PRODUCT_SERVICESIMAGE
+	$(hide) echo ro.productservices.build.date=`$(DATE_FROM_FILE)`>>$@
+	$(hide) echo ro.productservices.build.date.utc=`$(DATE_FROM_FILE) +%s`>>$@
+	$(hide) echo ro.productservices.build.fingerprint="$(BUILD_FINGERPRINT_FROM_FILE)">>$@
+endif  # BOARD_USES_PRODUCT_SERVICESIMAGE
+	$(hide) echo "#" >> $@; \
+	        echo "# ADDITIONAL PRODUCT_SERVICES PROPERTIES" >> $@; \
+	        echo "#" >> $@;
+	$(hide) $(foreach line,$(FINAL_PRODUCT_SERVICES_PROPERTIES), \
+		echo "$(line)" >> $@;)
+	$(hide) build/make/tools/post_process_props.py $@
+
+# ----------------------------------------------------------------
+
+# -----------------------------------------------------------------
 # sdk-build.prop
 #
 # There are certain things in build.prop that we don't want to
@@ -1101,7 +1128,7 @@
 ifneq (true,$(TARGET_USERIMAGES_SPARSE_SQUASHFS_DISABLED))
   INTERNAL_USERIMAGES_SPARSE_SQUASHFS_FLAG := -s
 endif
-ifneq ($(filter $(BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE) $(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE) $(BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE),squashfs),)
+ifneq ($(filter $(BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE) $(BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE) $(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE) $(BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE),squashfs),)
 INTERNAL_USERIMAGES_DEPS += $(MAKE_SQUASHFS) $(MKSQUASHFSUSERIMG) $(IMG2SIMG)
 endif
 
@@ -1135,7 +1162,7 @@
 endif # USE_LOGICAL_PARTITIONS
 
 # $(1): the path of the output dictionary file
-# $(2): a subset of "system vendor cache userdata product oem"
+# $(2): a subset of "system vendor cache userdata product productservices oem"
 # $(3): additional "key=value" pairs to append to the dictionary file.
 define generate-image-prop-dictionary
 $(if $(filter $(2),system),\
@@ -1184,6 +1211,19 @@
     $(if $(BOARD_PRODUCTIMAGE_SQUASHFS_BLOCK_SIZE),$(hide) echo "product_squashfs_block_size=$(BOARD_PRODUCTIMAGE_SQUASHFS_BLOCK_SIZE)" >> $(1))
     $(if $(BOARD_PRODUCTIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "product_squashfs_disable_4k_align=$(BOARD_PRODUCTIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
     $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_BASE_FS_PATH),$(hide) echo "product_base_fs_file=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_BASE_FS_PATH)" >> $(1))
+    $(if $(BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "product_reserved_size=$(BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+)
+$(if $(filter $(2),productservices),\
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "productservices_fs_type=$(BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_EXTFS_INODE_COUNT),$(hide) echo "productservices_extfs_inode_count=$(BOARD_PRODUCT_SERVICESIMAGE_EXTFS_INODE_COUNT)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_EXTFS_RSV_PCT),$(hide) echo "productservices_extfs_rsv_pct=$(BOARD_PRODUCT_SERVICESIMAGE_EXTFS_RSV_PCT)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_PARTITION_SIZE),$(hide) echo "productservices_size=$(BOARD_PRODUCT_SERVICESIMAGE_PARTITION_SIZE)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_JOURNAL_SIZE),$(hide) echo "productservices_journal_size=$(BOARD_PRODUCT_SERVICESIMAGE_JOURNAL_SIZE)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_SQUASHFS_COMPRESSOR),$(hide) echo "productservices_squashfs_compressor=$(BOARD_PRODUCT_SERVICESIMAGE_SQUASHFS_COMPRESSOR)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_SQUASHFS_COMPRESSOR_OPT),$(hide) echo "productservices_squashfs_compressor_opt=$(BOARD_PRODUCT_SERVICESIMAGE_SQUASHFS_COMPRESSOR_OPT)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_SQUASHFS_BLOCK_SIZE),$(hide) echo "productservices_squashfs_block_size=$(BOARD_PRODUCT_SERVICESIMAGE_SQUASHFS_BLOCK_SIZE)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "productservices_squashfs_disable_4k_align=$(BOARD_PRODUCT_SERVICESIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
+    $(if $(BOARD_PRODUCT_SERVICESIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "productservices_reserved_size=$(BOARD_PRODUCT_SERVICESIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
 )
 $(if $(filter $(2),oem),\
     $(if $(BOARD_OEMIMAGE_PARTITION_SIZE),$(hide) echo "oem_size=$(BOARD_OEMIMAGE_PARTITION_SIZE)" >> $(1))
@@ -1208,6 +1248,7 @@
 $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION),$(hide) echo "system_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION)" >> $(1))
 $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION),$(hide) echo "vendor_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION)" >> $(1))
 $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_VERITY_PARTITION),$(hide) echo "product_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_VERITY_PARTITION)" >> $(1))
+$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_SERVICES_VERITY_PARTITION),$(hide) echo "productservices_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_SERVICES_VERITY_PARTITION)" >> $(1))
 $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT),$(hide) echo "vboot=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT)" >> $(1))
 $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT),$(hide) echo "vboot_key=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VBOOT_SIGNING_KEY)" >> $(1))
 $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT),$(hide) echo "vboot_subkey=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VBOOT_SIGNING_SUBKEY)" >> $(1))
@@ -1235,11 +1276,16 @@
         $(hide) echo "avb_product_key_path=$(BOARD_AVB_PRODUCT_KEY_PATH)" >> $(1)
         $(hide) echo "avb_product_algorithm=$(BOARD_AVB_PRODUCT_ALGORITHM)" >> $(1)
         $(hide) echo "avb_product_rollback_index_location=$(BOARD_AVB_PRODUCT_ROLLBACK_INDEX_LOCATION)" >> $(1)))
+$(if $(BOARD_AVB_ENABLE),\
+    $(if $(BOARD_AVB_PRODUCT_SERVICES_KEY_PATH),\
+        $(hide) echo "avb_productservices_key_path=$(BOARD_AVB_PRODUCT_SERVICES_KEY_PATH)" >> $(1)
+        $(hide) echo "avb_productservices_algorithm=$(BOARD_AVB_PRODUCT_SERVICES_ALGORITHM)" >> $(1)
+        $(hide) echo "avb_productservices_rollback_index_location=$(BOARD_AVB_PRODUCT_SERVICES_ROLLBACK_INDEX_LOCATION)" >> $(1)))
 $(if $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)),\
     $(hide) echo "recovery_as_boot=true" >> $(1))
 $(if $(filter true,$(BOARD_BUILD_SYSTEM_ROOT_IMAGE)),\
     $(hide) echo "system_root_image=true" >> $(1)
-    $(hide) echo "ramdisk_dir=$(TARGET_ROOT_OUT)" >> $(1))
+    $(hide) echo "root_dir=$(TARGET_ROOT_OUT)" >> $(1))
 $(if $(USE_LOGICAL_PARTITIONS),$(hide) echo "use_logical_partitions=true" >> $(1))
 $(if $(3),$(hide) $(foreach kv,$(3),echo "$(kv)" >> $(1);))
 endef
@@ -1247,7 +1293,7 @@
 # $(1): the path of the output dictionary file
 # $(2): additional "key=value" pairs to append to the dictionary file.
 define generate-userimage-prop-dictionary
-$(call generate-image-prop-dictionary,$(1),system vendor cache userdata product oem,$(2))
+$(call generate-image-prop-dictionary,$(1),system vendor cache userdata product productservices oem,$(2))
 endef
 
 # $(1): the path of the input dictionary file, where each line has the format key=value
@@ -1309,6 +1355,9 @@
 ifdef BOARD_USES_PRODUCTIMAGE
 recovery_build_props += $(INSTALLED_PRODUCT_BUILD_PROP_TARGET)
 endif
+ifdef BOARD_USES_PRODUCT_SERVICESIMAGE
+recovery_build_props += $(INSTALLED_PRODUCT_SERVICES_BUILD_PROP_TARGET)
+endif
 recovery_resources_common := $(call include-path-for, recovery)/res
 
 # Set recovery_density to the density bucket of the device.
@@ -1647,11 +1696,27 @@
 endef
 endif
 
+# Create symlink /system/product-services to /product-services if necessary.
+ifdef BOARD_USES_PRODUCT_SERVICESIMAGE
+define create-system-productservices-symlink
+$(hide) if [ -d $(TARGET_OUT)/product-services ] && [ ! -h $(TARGET_OUT)/product-services ]; then \
+  echo 'Non-symlink $(TARGET_OUT)/product-services detected!' 1>&2; \
+  echo 'You cannot install files to $(TARGET_OUT)/product-services while building a separate product-services.img!' 1>&2; \
+  exit 1; \
+fi
+$(hide) ln -sf /product-services $(TARGET_OUT)/product-services
+endef
+else
+define create-system-productservices-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-productservices-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)
@@ -1731,6 +1796,7 @@
   $(call pretty,"Target system fs tarball: $(INSTALLED_SYSTEMTARBALL_TARGET)")
   $(call create-system-vendor-symlink)
   $(call create-system-product-symlink)
+  $(call create-system-productservices-symlink)
   $(MKTARBALL) $(FS_GET_STATS) \
     $(PRODUCT_OUT) system $(PRIVATE_SYSTEM_TAR) \
     $(INSTALLED_SYSTEMTARBALL_TARGET) $(TARGET_OUT)
@@ -1815,6 +1881,10 @@
 	$(hide) cd $(dir $@) && zip -qryX $(notdir $@) \
 		$(TARGET_COPY_OUT_PRODUCT)
 endif
+ifdef BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE
+	$(hide) cd $(dir $@) && zip -qryX $(notdir $@) \
+		$(TARGET_COPY_OUT_PRODUCT_SERVICES)
+endif
 ifneq ($(PDK_PLATFORM_JAVA_ZIP_CONTENTS),)
 	$(hide) cd $(OUT_DIR) && zip -qryX $(patsubst $(OUT_DIR)/%,%,$@) $(PDK_PLATFORM_JAVA_ZIP_CONTENTS)
 endif
@@ -2196,8 +2266,11 @@
   $(call generate-image-prop-dictionary, $(productimage_intermediates)/product_image_info.txt,product,skip_fsck=true)
   $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
       ./build/tools/releasetools/build_image.py \
-      $(TARGET_OUT_PRODUCT) $(productimage_intermediates)/product_image_info.txt $(INSTALLED_PRODUCTIMAGE_TARGET) $(TARGET_OUT)
-  $(hide) $(call assert-max-image-size,$(INSTALLED_PRODUCTIMAGE_TARGET),$(BOARD_PRODUCTIMAGE_PARTITION_SIZE))
+      $(TARGET_OUT_PRODUCT) $(productimage_intermediates)/product_image_info.txt $(INSTALLED_PRODUCTIMAGE_TARGET) $(TARGET_OUT) \
+      $(productimage_intermediates)/generated_product_image_info.txt
+  $(hide) $(call assert-max-image-size,$(INSTALLED_PRODUCTIMAGE_TARGET),\
+      $(call read-image-prop-dictionary,\
+          $(productimage_intermediates)/generated_product_image_info.txt,product_size))
 endef
 
 # We just build this directly to the install location.
@@ -2217,6 +2290,61 @@
 endif
 
 # -----------------------------------------------------------------
+# product-services partition image
+ifdef BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE
+INTERNAL_PRODUCT_SERVICESIMAGE_FILES := \
+    $(filter $(TARGET_OUT_PRODUCT_SERVICES)/%,\
+      $(ALL_DEFAULT_INSTALLED_MODULES)\
+      $(ALL_PDK_FUSION_FILES)) \
+    $(PDK_FUSION_SYMLINK_STAMP)
+
+# platform.zip depends on $(INTERNAL_PRODUCT_SERVICESIMAGE_FILES).
+$(INSTALLED_PLATFORM_ZIP) : $(INTERNAL_PRODUCT_SERVICESIMAGE_FILES)
+
+INSTALLED_FILES_FILE_PRODUCT_SERVICES := $(PRODUCT_OUT)/installed-files-productservices.txt
+INSTALLED_FILES_JSON_PRODUCT_SERVICES := $(INSTALLED_FILES_FILE_PRODUCT_SERVICES:.txt=.json)
+$(INSTALLED_FILES_FILE_PRODUCT_SERVICES): .KATI_IMPLICIT_OUTPUTS := $(INSTALLED_FILES_JSON_PRODUCT_SERVICES)
+$(INSTALLED_FILES_FILE_PRODUCT_SERVICES) : $(INTERNAL_PRODUCT_SERVICESIMAGE_FILES) $(FILESLIST)
+	@echo Installed file list: $@
+	@mkdir -p $(dir $@)
+	@rm -f $@
+	$(hide) $(FILESLIST) $(TARGET_OUT_PRODUCT_SERVICES) > $(@:.txt=.json)
+	$(hide) build/tools/fileslist_util.py -c $(@:.txt=.json) > $@
+
+productservicesimage_intermediates := \
+    $(call intermediates-dir-for,PACKAGING,productservices)
+BUILT_PRODUCT_SERVICESIMAGE_TARGET := $(PRODUCT_OUT)/product-services.img
+define build-productservicesimage-target
+  $(call pretty,"Target product-services fs image: $(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET)")
+  @mkdir -p $(TARGET_OUT_PRODUCT_SERVICES)
+  @mkdir -p $(productservicesimage_intermediates) && rm -rf $(productservicesimage_intermediates)/productservices_image_info.txt
+  $(call generate-userimage-prop-dictionary, $(productservicesimage_intermediates)/productservices_image_info.txt, skip_fsck=true)
+  $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
+      ./build/tools/releasetools/build_image.py \
+      $(TARGET_OUT_PRODUCT_SERVICES) $(productservicesimage_intermediates)/productservices_image_info.txt $(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET) $(TARGET_OUT) \
+      $(productservicesimage_intermediates)/generated_productservices_image_info.txt
+  $(hide) $(call assert-max-image-size,$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET),\
+      $(call read-image-prop-dictionary,\
+          $(productservicesimage_intermediates)/generated_productservices_image_info.txt,productservices_size))
+endef
+
+# We just build this directly to the install location.
+INSTALLED_PRODUCT_SERVICESIMAGE_TARGET := $(BUILT_PRODUCT_SERVICESIMAGE_TARGET)
+$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET): $(INTERNAL_USERIMAGES_DEPS) $(INTERNAL_PRODUCT_SERVICESIMAGE_FILES) $(INSTALLED_FILES_FILE_PRODUCT_SERVICES) $(BUILD_IMAGE_SRCS)
+	$(build-productservicesimage-target)
+
+.PHONY: productservicesimage-nodeps psnod
+productservicesimage-nodeps psnod: | $(INTERNAL_USERIMAGES_DEPS)
+	$(build-productservicesimage-target)
+
+sync: $(INTERNAL_PRODUCT_SERVICESIMAGE_FILES)
+
+else ifdef BOARD_PREBUILT_PRODUCT_SERVICESIMAGE
+INSTALLED_PRODUCT_SERVICESIMAGE_TARGET := $(PRODUCT_OUT)/product-services.img
+$(eval $(call copy-one-file,$(BOARD_PREBUILT_PRODUCT_SERVICESIMAGE),$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET)))
+endif
+
+# -----------------------------------------------------------------
 # dtbo image
 ifdef BOARD_PREBUILT_DTBOIMAGE
 INSTALLED_DTBOIMAGE_TARGET := $(PRODUCT_OUT)/dtbo.img
@@ -2260,6 +2388,7 @@
 VENDOR_FOOTER_ARGS := BOARD_AVB_VENDOR_ADD_HASHTREE_FOOTER_ARGS
 RECOVERY_FOOTER_ARGS := BOARD_AVB_RECOVERY_ADD_HASH_FOOTER_ARGS
 PRODUCT_FOOTER_ARGS := BOARD_AVB_PRODUCT_ADD_HASHTREE_FOOTER_ARGS
+PRODUCT_SERVICES_FOOTER_ARGS := BOARD_AVB_PRODUCT_SERVICES_ADD_HASHTREE_FOOTER_ARGS
 
 # Check and set required build variables for a chain partition.
 # $(1): the partition to enable AVB chain, e.g., BOOT or SYSTEM.
@@ -2377,6 +2506,9 @@
   $(if $(BOARD_AVB_PRODUCT_KEY_PATH),\
     $(hide) $(AVBTOOL) extract_public_key --key $(BOARD_AVB_PRODUCT_KEY_PATH) \
       --output $(1)/product.avbpubkey)
+  $(if $(BOARD_AVB_PRODUCT_SERVICES_KEY_PATH),\
+    $(hide) $(AVBTOOL) extract_public_key --key $(BOARD_AVB_PRODUCT_SERVICES_KEY_PATH) \
+      --output $(1)/product-services.avbpubkey)
   $(if $(BOARD_AVB_DTBO_KEY_PATH),\
     $(hide) $(AVBTOOL) extract_public_key --key $(BOARD_AVB_DTBO_KEY_PATH) \
       --output $(1)/dtbo.avbpubkey)
@@ -2404,6 +2536,7 @@
 		$(INSTALLED_SYSTEMIMAGE) \
 		$(INSTALLED_VENDORIMAGE_TARGET) \
 		$(INSTALLED_PRODUCTIMAGE_TARGET) \
+		$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET) \
 		$(INSTALLED_DTBOIMAGE_TARGET) \
 		$(INSTALLED_RECOVERYIMAGE_TARGET) \
 		$(BOARD_AVB_KEY_PATH)
@@ -2424,6 +2557,60 @@
 endif # BOARD_AVB_ENABLE
 
 # -----------------------------------------------------------------
+# Check image sizes <= size of super partition
+
+ifeq (,$(TARGET_BUILD_APPS))
+# Do not check for apps-only build
+
+ifeq (true,$(USE_LOGICAL_PARTITIONS))
+ifdef BOARD_SUPER_PARTITION_SIZE
+ifdef BOARD_SUPER_PARTITION_PARTITION_LIST
+
+droid_targets: check_android_partition_sizes
+
+.PHONY: check_android_partition_sizes
+
+# BOARD_SUPER_PARTITION_PARTITION_LIST: a list of the following tokens
+valid_super_partition_list := system vendor product productservices
+ifneq (,$(filter-out $(valid_super_partition_list),$(BOARD_SUPER_PARTITION_PARTITION_LIST)))
+$(error BOARD_SUPER_PARTITION_PARTITION_LIST contains invalid partition name. \
+        Valid names are $(valid_super_partition_list).)
+endif
+valid_super_partition_list :=
+
+# Add image dependencies so that generated_*_image_info.txt are written before checking.
+ifneq (,$(filter system,$(BOARD_SUPER_PARTITION_PARTITION_LIST)))
+check_android_partition_sizes: $(BUILT_SYSTEMIMAGE)
+endif
+ifneq (,$(filter vendor,$(BOARD_SUPER_PARTITION_PARTITION_LIST)))
+check_android_partition_sizes: $(INSTALLED_VENDORIMAGE_TARGET)
+endif
+ifneq (,$(filter product,$(BOARD_SUPER_PARTITION_PARTITION_LIST)))
+check_android_partition_sizes: $(INSTALLED_PRODUCTIMAGE_TARGET)
+endif
+ifneq (,$(filter productservices,$(BOARD_SUPER_PARTITION_PARTITION_LIST)))
+check_android_partition_sizes: $(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET)
+endif
+
+check_android_partition_sizes:
+	partition_size_list="$(foreach p,$(BOARD_SUPER_PARTITION_PARTITION_LIST),$(call read-image-prop-dictionary,$($(p)image_intermediates)/generated_$(p)_image_info.txt,$(p)_size))"; \
+	sum_sizes_expr=$$(sed -e 's/ /+/g' <<< "$${partition_size_list}"); \
+	if [ $$(( $${sum_sizes_expr} )) -gt $(BOARD_SUPER_PARTITION_SIZE) ]; then \
+		echo 'The sum of sizes of all logical partitions is larger than BOARD_SUPER_PARTITION_SIZE.'; \
+		echo $${sum_sizes_expr} '==' $$(( $${sum_sizes_expr} )) '>' $(BOARD_SUPER_PARTITION_SIZE); \
+		exit 1; \
+	else \
+		echo 'The sum of sizes of all logical partitions is within BOARD_SUPER_PARTITION_SIZE:' \
+		    $${sum_sizes_expr} '==' $$(( $${sum_sizes_expr} )) '<=' $(BOARD_SUPER_PARTITION_SIZE); \
+	fi
+
+endif # BOARD_SUPER_PARTITION_PARTITION_LIST
+endif # BOARD_SUPER_PARTITION_SIZE
+endif # USE_LOGICAL_PARTITIONS
+
+endif # TARGET_BUILD_APPS
+
+# -----------------------------------------------------------------
 # bring in the installer image generation defines if necessary
 ifeq ($(TARGET_USE_DISKINSTALLER),true)
 include bootable/diskinstaller/config.mk
@@ -2665,6 +2852,7 @@
 		$(INSTALLED_CACHEIMAGE_TARGET) \
 		$(INSTALLED_VENDORIMAGE_TARGET) \
 		$(INSTALLED_PRODUCTIMAGE_TARGET) \
+		$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET) \
 		$(INSTALLED_VBMETAIMAGE_TARGET) \
 		$(INSTALLED_DTBOIMAGE_TARGET) \
 		$(INTERNAL_SYSTEMOTHERIMAGE_FILES) \
@@ -2674,6 +2862,7 @@
 		$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_BASE_FS_PATH) \
 		$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_BASE_FS_PATH) \
 		$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_BASE_FS_PATH) \
+		$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_SERVICES_BASE_FS_PATH) \
 		$(SELINUX_FC) \
 		$(APKCERTS_FILE) \
 		$(SOONG_ZIP) \
@@ -2689,6 +2878,7 @@
 	@echo "Package target files: $@"
 	$(call create-system-vendor-symlink)
 	$(call create-system-product-symlink)
+	$(call create-system-productservices-symlink)
 	$(hide) rm -rf $@ $@.list $(zip_root)
 	$(hide) mkdir -p $(dir $@) $(zip_root)
 ifneq (,$(INSTALLED_RECOVERYIMAGE_TARGET)$(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
@@ -2762,6 +2952,11 @@
 	$(hide) $(call package_files-copy-root, \
 		$(TARGET_OUT_PRODUCT),$(zip_root)/PRODUCT)
 endif
+ifdef BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE
+	@# Contents of the product-services image
+	$(hide) $(call package_files-copy-root, \
+		$(TARGET_OUT_PRODUCT_SERVICES),$(zip_root)/PRODUCT_SERVICES)
+endif
 ifdef INSTALLED_SYSTEMOTHERIMAGE_TARGET
 	@# Contents of the system_other image
 	$(hide) $(call package_files-copy-root, \
@@ -2833,6 +3028,10 @@
 	$(hide) cp $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_BASE_FS_PATH) \
 	  $(zip_root)/META/$(notdir $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_BASE_FS_PATH))
 endif
+ifneq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_SERVICES_BASE_FS_PATH),)
+	$(hide) cp $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_SERVICES_BASE_FS_PATH) \
+	  $(zip_root)/META/$(notdir $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_SERVICES_BASE_FS_PATH))
+endif
 ifneq ($(strip $(SANITIZE_TARGET)),)
 	# We need to create userdata.img with real data because the instrumented libraries are in userdata.img.
 	$(hide) echo "userdata_img_with_data=true" >> $(zip_root)/META/misc_info.txt
@@ -2909,6 +3108,10 @@
 	$(hide) mkdir -p $(zip_root)/IMAGES
 	$(hide) cp $(INSTALLED_PRODUCTIMAGE_TARGET) $(zip_root)/IMAGES/
 endif
+ifdef BOARD_PREBUILT_PRODUCT_SERVICESIMAGE
+	$(hide) mkdir -p $(zip_root)/IMAGES
+	$(hide) cp $(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET) $(zip_root)/IMAGES/
+endif
 ifdef BOARD_PREBUILT_BOOTIMAGE
 	$(hide) mkdir -p $(zip_root)/IMAGES
 	$(hide) cp $(INSTALLED_BOOTIMAGE_TARGET) $(zip_root)/IMAGES/
@@ -2942,6 +3145,9 @@
 ifdef BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE
 	$(hide) $(call fs_config,$(zip_root)/PRODUCT,product/) > $(zip_root)/META/product_filesystem_config.txt
 endif
+ifdef BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE
+	$(hide) $(call fs_config,$(zip_root)/PRODUCT_SERVICES,product-services/) > $(zip_root)/META/productservices_filesystem_config.txt
+endif
 ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
 	@# When using BOARD_BUILD_SYSTEM_ROOT_IMAGE, ROOT always contains the files for the root under
 	@# normal boot. BOOT/RAMDISK exists only if additionally using BOARD_USES_RECOVERY_AS_BOOT.
@@ -3049,6 +3255,27 @@
 updatepackage: $(INTERNAL_UPDATE_PACKAGE_TARGET)
 
 # -----------------------------------------------------------------
+# A zip of the appcompat directory containing logs
+APPCOMPAT_ZIP := $(PRODUCT_OUT)/appcompat.zip
+# For apps_only build we'll establish the dependency later in build/make/core/main.mk.
+ifndef TARGET_BUILD_APPS
+$(APPCOMPAT_ZIP): $(INSTALLED_SYSTEMIMAGE) \
+		$(INSTALLED_BOOTIMAGE_TARGET) \
+		$(INSTALLED_USERDATAIMAGE_TARGET) \
+		$(INSTALLED_VENDORIMAGE_TARGET) \
+		$(INSTALLED_PRODUCTIMAGE_TARGET) \
+		$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET)
+endif
+$(APPCOMPAT_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,appcompat)/filelist
+$(APPCOMPAT_ZIP): $(SOONG_ZIP)
+	@echo "appcompat logs: $@"
+	$(hide) rm -rf $@ $(PRIVATE_LIST_FILE)
+	$(hide) mkdir -p $(dir $@) $(PRODUCT_OUT)/appcompat $(dir $(PRIVATE_LIST_FILE))
+	$(hide) find $(PRODUCT_OUT)/appcompat | sort >$(PRIVATE_LIST_FILE)
+	$(hide) $(SOONG_ZIP) -d -o $@ -C $(PRODUCT_OUT)/appcompat -l $(PRIVATE_LIST_FILE)
+
+
+# -----------------------------------------------------------------
 # A zip of the symbols directory.  Keep the full paths to make it
 # more obvious where these files came from.
 #
@@ -3066,6 +3293,7 @@
 		$(INSTALLED_USERDATAIMAGE_TARGET) \
 		$(INSTALLED_VENDORIMAGE_TARGET) \
 		$(INSTALLED_PRODUCTIMAGE_TARGET) \
+		$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET) \
 		$(updater_dep)
 endif
 $(SYMBOLS_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,symbols)/filelist
@@ -3089,7 +3317,8 @@
 		$(INSTALLED_BOOTIMAGE_TARGET) \
 		$(INSTALLED_USERDATAIMAGE_TARGET) \
 		$(INSTALLED_VENDORIMAGE_TARGET) \
-		$(INSTALLED_PRODUCTIMAGE_TARGET)
+		$(INSTALLED_PRODUCTIMAGE_TARGET) \
+		$(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET)
 endif
 $(COVERAGE_ZIP): PRIVATE_LIST_FILE := $(call intermediates-dir-for,PACKAGING,coverage)/filelist
 $(COVERAGE_ZIP): $(SOONG_ZIP)
@@ -3198,6 +3427,15 @@
 productimage: $(INSTALLED_QEMU_PRODUCTIMAGE)
 droidcore: $(INSTALLED_QEMU_PRODUCTIMAGE)
 endif
+ifeq ($(BOARD_USES_PRODUCT_SERVICESIMAGE),true)
+INSTALLED_QEMU_PRODUCT_SERVICESIMAGE := $(PRODUCT_OUT)/product-services-qemu.img
+$(INSTALLED_QEMU_PRODUCT_SERVICESIMAGE): $(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET) $(MK_QEMU_IMAGE_SH) $(SGDISK_HOST)
+	@echo Create product-services-qemu.img
+	(export SGDISK=$(SGDISK_HOST); $(MK_QEMU_IMAGE_SH) ${PRODUCT_OUT}/product-services.img)
+
+productservicesimage: $(INSTALLED_QEMU_PRODUCT_SERVICESIMAGE)
+droidcore: $(INSTALLED_QEMU_PRODUCT_SERVICESIMAGE)
+endif
 endif
 # -----------------------------------------------------------------
 # The emulator package
@@ -3261,6 +3499,7 @@
 	$(ALL_DEFAULT_INSTALLED_MODULES) \
 	$(INSTALLED_RAMDISK_TARGET) \
 	$(ALL_DOCS) \
+	$(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/metalava-api-stubs-docs_annotations.zip \
 	$(ALL_SDK_FILES)
 endif
 
@@ -3293,6 +3532,7 @@
 	$(OUT_DOCS)/offline-sdk-timestamp \
 	$(SYMBOLS_ZIP) \
 	$(COVERAGE_ZIP) \
+	$(APPCOMPAT_ZIP) \
 	$(INSTALLED_SYSTEMIMAGE) \
 	$(INSTALLED_QEMU_SYSTEMIMAGE) \
 	$(INSTALLED_QEMU_VENDORIMAGE) \
diff --git a/core/base_rules.mk b/core/base_rules.mk
index f59df3f..744740f 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -75,6 +75,8 @@
 LOCAL_ODM_MODULE := true
 else ifneq ($(filter $(TARGET_OUT_PRODUCT)/%,$(_path)),)
 LOCAL_PRODUCT_MODULE := true
+else ifneq ($(filter $(TARGET_OUT_PRODUCT_SERVICES)/%,$(_path)),)
+LOCAL_PRODUCT_SERVICES_MODULE := true
 endif
 _path :=
 
@@ -205,6 +207,8 @@
   partition_tag := _ODM
 else ifeq (true,$(LOCAL_PRODUCT_MODULE))
   partition_tag := _PRODUCT
+else ifeq (true,$(LOCAL_PRODUCT_SERVICES_MODULE))
+  partition_tag := _PRODUCT_SERVICES
 else ifeq (NATIVE_TESTS,$(LOCAL_MODULE_CLASS))
   partition_tag := _DATA
 else
@@ -352,6 +356,7 @@
 ## make clean- targets
 ###########################################################
 cleantarget := clean-$(my_register_name)
+.PHONY: $(cleantarget)
 $(cleantarget) : PRIVATE_MODULE := $(my_register_name)
 $(cleantarget) : PRIVATE_CLEAN_FILES := \
     $(LOCAL_BUILT_MODULE) \
diff --git a/core/clang/TARGET_x86_64.mk b/core/clang/TARGET_x86_64.mk
index 0d3ee3f..3161f84 100644
--- a/core/clang/TARGET_x86_64.mk
+++ b/core/clang/TARGET_x86_64.mk
@@ -3,3 +3,6 @@
 RS_COMPAT_TRIPLE := x86_64-linux-android
 
 TARGET_LIBPROFILE_RT := $(LLVM_RTLIB_PATH)/libclang_rt.profile-x86_64-android.a
+
+# Address sanitizer clang config
+ADDRESS_SANITIZER_LINKER := /system/bin/linker_asan64
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 5051ef7..e7116a5 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -207,6 +207,7 @@
 LOCAL_PRIVILEGED_MODULE:=
 # '',full,custom,disabled,obfuscation,optimization
 LOCAL_PRODUCT_MODULE:=
+LOCAL_PRODUCT_SERVICES_MODULE:=
 LOCAL_PROGUARD_ENABLED:=
 LOCAL_PROGUARD_FLAG_FILES:=
 LOCAL_PROGUARD_FLAGS:=
@@ -252,6 +253,7 @@
 LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES :=
 LOCAL_DROIDDOC_STUBS_SRCJAR :=
 LOCAL_DROIDDOC_DOC_ZIP :=
+LOCAL_DROIDDOC_ANNOTATIONS_ZIP :=
 # '',true
 LOCAL_SOURCE_FILES_ALL_GENERATED:=
 LOCAL_SRC_FILES:=
diff --git a/core/config.mk b/core/config.mk
index df73c56..33f1b7b 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -719,6 +719,7 @@
 DEXDUMP := $(HOST_OUT_EXECUTABLES)/dexdump2$(BUILD_EXECUTABLE_SUFFIX)
 PROFMAN := $(HOST_OUT_EXECUTABLES)/profman
 HIDDENAPI := $(HOST_OUT_EXECUTABLES)/hiddenapi
+CLASS2GREYLIST := $(HOST_OUT_EXECUTABLES)/class2greylist
 
 FINDBUGS_DIR := external/owasp/sanitizer/tools/findbugs/bin
 FINDBUGS := $(FINDBUGS_DIR)/findbugs
@@ -901,7 +902,8 @@
 # A list of SEPolicy versions, besides PLATFORM_SEPOLICY_VERSION, that the framework supports.
 PLATFORM_SEPOLICY_COMPAT_VERSIONS := \
     26.0 \
-    27.0
+    27.0 \
+    28.0 \
 
 .KATI_READONLY := \
     PLATFORM_SEPOLICY_COMPAT_VERSIONS \
@@ -930,6 +932,20 @@
 endif
 endif
 
+ifneq ($(BOARD_PRODUCTIMAGE_PARTITION_SIZE),)
+ifneq ($(BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE),)
+$(error Should not define BOARD_PRODUCTIMAGE_PARTITION_SIZE and \
+    BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE together)
+endif
+endif
+
+ifneq ($(BOARD_PRODUCT_SERVICESIMAGE_PARTITION_SIZE),)
+ifneq ($(BOARD_PRODUCT_SERVICESIMAGE_PARTITION_RESERVED_SIZE),)
+$(error Should not define BOARD_PRODUCT_SERVICESIMAGE_PARTITION_SIZE and \
+    BOARD_PRODUCT_SERVICESIMAGE_PARTITION_RESERVED_SIZE together)
+endif
+endif
+
 endif # USE_LOGICAL_PARTITIONS
 
 # ###############################################################
@@ -1088,6 +1104,7 @@
     bptimage-nodeps \
     vnod vendorimage-nodeps \
     pnod productimage-nodeps \
+    psnod productservicesimage-nodeps \
     systemotherimage-nodeps \
     ramdisk-nodeps \
     bootimage-nodeps \
diff --git a/core/definitions.mk b/core/definitions.mk
index df5aa67..4341c62 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2557,6 +2557,17 @@
   mv $@.compressed $@;
 endef
 
+ifeq ($(HOST_OS),linux)
+# Runs appcompat and store logs in $(PRODUCT_OUT)/appcompat
+define run-appcompat
+$(hide) \
+  mkdir -p $(PRODUCT_OUT)/appcompat; \
+  art/tools/veridex/appcompat.sh --dex-file=$@ 2>&1 > $(PRODUCT_OUT)/appcompat/$(PRIVATE_MODULE).log;
+endef
+else
+run-appcompat =
+endif
+
 # Remove dynamic timestamps from packages
 #
 define remove-timestamps-from-package
@@ -2855,6 +2866,16 @@
     PRIVATE_DEX_INPUTS := $$(PRIVATE_DEX_INPUTS) $(1)
 endef
 
+# Generate a greylist.txt from a classes.jar
+define hiddenapi-generate-greylist-txt
+$(2): $(1) $(CLASS2GREYLIST)
+	$(CLASS2GREYLIST) $(1) > $(2)
+
+$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): $(2)
+$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): \
+    PRIVATE_GREYLIST_INPUTS := $$(PRIVATE_GREYLIST_INPUTS) $(2)
+endef
+
 # File names for intermediate dex files of `hiddenapi-copy-soong-jar`.
 hiddenapi-soong-input-dex = $(dir $(1))/hiddenapi/dex-input/classes.dex
 hiddenapi-soong-output-dex = $(dir $(1))/hiddenapi/dex-output/classes.dex
@@ -3552,10 +3573,12 @@
 ###########################################################
 ## Verify module name meets character requirements:
 ##   a-z A-Z 0-9
-##   _.+-=,@~
+##   _.+-,@~
 ##
 ## This is a subset of bazel's target name restrictions:
 ##   https://docs.bazel.build/versions/master/build-ref.html#name
+##
+## Kati has problems with '=': https://github.com/google/kati/issues/138
 ###########################################################
 define verify-module-name
 $(if $(filter-out $(LOCAL_MODULE),$(subst /,,$(LOCAL_MODULE))), \
@@ -3564,14 +3587,14 @@
   $(call pretty-error,Invalid characters in module name: $(call _invalid-name-chars,$(LOCAL_MODULE))))
 endef
 define _invalid-name-chars
-$(subst _,,$(subst .,,$(subst +,,$(subst -,,$(subst =,,$(subst $(comma),,$(subst @,,$(subst ~,,$(subst 0,,$(subst 1,,$(subst 2,,$(subst 3,,$(subst 4,,$(subst 5,,$(subst 6,,$(subst 7,,$(subst 8,,$(subst 9,,$(subst a,,$(subst b,,$(subst c,,$(subst d,,$(subst e,,$(subst f,,$(subst g,,$(subst h,,$(subst i,,$(subst j,,$(subst k,,$(subst l,,$(subst m,,$(subst n,,$(subst o,,$(subst p,,$(subst q,,$(subst r,,$(subst s,,$(subst t,,$(subst u,,$(subst v,,$(subst w,,$(subst x,,$(subst y,,$(subst z,,$(call to-lower,$(1))))))))))))))))))))))))))))))))))))))))))))))
+$(subst _,,$(subst .,,$(subst +,,$(subst -,,$(subst $(comma),,$(subst @,,$(subst ~,,$(subst 0,,$(subst 1,,$(subst 2,,$(subst 3,,$(subst 4,,$(subst 5,,$(subst 6,,$(subst 7,,$(subst 8,,$(subst 9,,$(subst a,,$(subst b,,$(subst c,,$(subst d,,$(subst e,,$(subst f,,$(subst g,,$(subst h,,$(subst i,,$(subst j,,$(subst k,,$(subst l,,$(subst m,,$(subst n,,$(subst o,,$(subst p,,$(subst q,,$(subst r,,$(subst s,,$(subst t,,$(subst u,,$(subst v,,$(subst w,,$(subst x,,$(subst y,,$(subst z,,$(call to-lower,$(1)))))))))))))))))))))))))))))))))))))))))))))
 endef
 .KATI_READONLY := verify-module-name _invalid-name-chars
 
 ###########################################################
 ## Verify module stem meets character requirements:
 ##   a-z A-Z 0-9
-##   _.+-=,@~
+##   _.+-,@~
 ##
 ## This is a subset of bazel's target name restrictions:
 ##   https://docs.bazel.build/versions/master/build-ref.html#name
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index 3585026..208647e 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -34,6 +34,14 @@
         else # LOCAL_APK_LIBRARIES not empty
           LOCAL_DEX_PREOPT := nostripping
         endif # LOCAL_APK_LIBRARIES not empty
+      else
+        # Default to nostripping for non system preopt (enables preopt).
+        # Don't strip in case the oat/vdex version in system ROM doesn't match the one in other
+        # partitions. It needs to be able to fall back to the APK for that case.
+        # Also only enable preopt for non tests.
+        ifeq (,$(filter $(LOCAL_MODULE_TAGS),tests))
+          LOCAL_DEX_PREOPT := nostripping
+        endif
       endif # Installed to system.img.
     endif # LOCAL_DEX_PREOPT undefined
   endif # TARGET_BUILD_APPS empty
@@ -204,6 +212,11 @@
 endif
 endif
 
+# Only preopt primary arch for translated arch since there is only an image there.
+ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
+my_module_multilib := first
+endif
+
 # #################################################
 # Odex for the 1st arch
 my_2nd_arch_prefix :=
@@ -222,9 +235,12 @@
 else  # must be APPS
 # The preferred arch
 my_2nd_arch_prefix := $(LOCAL_2ND_ARCH_VAR_PREFIX)
+# Save the module multilib since setup_one_odex modifies it.
+saved_my_module_multilib := $(my_module_multilib)
 include $(BUILD_SYSTEM)/setup_one_odex.mk
+my_module_multilib := $(saved_my_module_multilib)
 ifdef TARGET_2ND_ARCH
-ifeq ($(LOCAL_MULTILIB),both)
+ifeq ($(my_module_multilib),both)
 # The non-preferred arch
 my_2nd_arch_prefix := $(if $(LOCAL_2ND_ARCH_VAR_PREFIX),,$(TARGET_2ND_ARCH_VAR_PREFIX))
 include $(BUILD_SYSTEM)/setup_one_odex.mk
diff --git a/core/droiddoc.mk b/core/droiddoc.mk
index deaee56..5425e31 100644
--- a/core/droiddoc.mk
+++ b/core/droiddoc.mk
@@ -287,6 +287,7 @@
 	$(hide) ( F=$$(pwd)/$@ ; cd $(PRIVATE_DOCS_DIR) && zip -rqX $$F * )
 
 $(LOCAL_MODULE)-docs.zip : $(out_zip)
+.PHONY: $(LOCAL_MODULE)-docs.zip
 
 $(call dist-for-goals,docs,$(out_zip))
 
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 2f37767..d8469da 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -180,6 +180,7 @@
 TARGET_COPY_OUT_OEM := oem
 TARGET_COPY_OUT_ODM := odm
 TARGET_COPY_OUT_PRODUCT := product
+TARGET_COPY_OUT_PRODUCT_SERVICES := product-services
 TARGET_COPY_OUT_ROOT := root
 TARGET_COPY_OUT_RECOVERY := recovery
 
@@ -210,6 +211,17 @@
 TARGET_COPY_OUT_PRODUCT := $(_product_path_placeholder)
 ###########################################
 
+###########################################
+# Define TARGET_COPY_OUT_PRODUCT_SERVICES to a placeholder, for at this point
+# we don't know if the device wants to build a separate product-services.img
+# or just build product stuff into system.img.
+# A device can set up TARGET_COPY_OUT_PRODUCT_SERVICES to "product-services" in its
+# BoardConfig.mk.
+# We'll substitute with the real value after loading BoardConfig.mk.
+_productservices_path_placeholder := ||PRODUCTSERVICES-PATH-PH||
+TARGET_COPY_OUT_PRODUCT_SERVICES := $(_productservices_path_placeholder)
+###########################################
+
 #################################################################
 # Set up minimal BOOTCLASSPATH list of jars to build/execute
 # java code with dalvikvm/art.
@@ -342,6 +354,28 @@
 endif
 
 ###########################################
+# Now we can substitute with the real value of TARGET_COPY_OUT_PRODUCT_SERVICES
+ifeq ($(TARGET_COPY_OUT_PRODUCT_SERVICES),$(_productservices_path_placeholder))
+TARGET_COPY_OUT_PRODUCT_SERVICES := system/product-services
+else ifeq ($(filter product-services system/product-services,$(TARGET_COPY_OUT_PRODUCT_SERVICES)),)
+$(error TARGET_COPY_OUT_PRODUCT_SERVICES must be either 'product-services' or 'system/product-services', seeing '$(TARGET_COPY_OUT_PRODUCT_SERVICES)'.)
+endif
+PRODUCT_SERVICES_COPY_FILES := $(subst $(_productservices_path_placeholder),$(TARGET_COPY_OUT_PRODUCT_SERVICES),$(PRODUCT_SERVICES_COPY_FILES))
+
+BOARD_USES_PRODUCT_SERVICESIMAGE :=
+ifdef BOARD_PREBUILT_PRODUCT_SERVICESIMAGE
+BOARD_USES_PRODUCT_SERVICESIMAGE := true
+endif
+ifdef BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE
+BOARD_USES_PRODUCT_SERVICESIMAGE := true
+endif
+ifeq ($(TARGET_COPY_OUT_PRODUCT_SERVICES),product-services)
+BOARD_USES_PRODUCT_SERVICESIMAGE := true
+else ifdef BOARD_USES_PRODUCT_SERVICESIMAGE
+$(error TARGET_COPY_OUT_PRODUCT_SERVICES must be set to 'product-services' to use a product-services image)
+endif
+
+###########################################
 # Ensure that only TARGET_RECOVERY_UPDATER_LIBS *or* AB_OTA_UPDATER is set.
 TARGET_RECOVERY_UPDATER_LIBS ?=
 AB_OTA_UPDATER ?=
@@ -880,6 +914,39 @@
   $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_PRODUCT_APPS \
   $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_PRODUCT_APPS_PRIVILEGED
 
+TARGET_OUT_PRODUCT_SERVICES := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_PRODUCT_SERVICES)
+ifneq ($(filter address,$(SANITIZE_TARGET)),)
+target_out_productservices_shared_libraries_base := $(PRODUCT_SERVICES_OUT)/$(TARGET_COPY_OUT_ASAN)/product-services
+ifeq ($(SANITIZE_LITE),true)
+# When using SANITIZE_LITE, APKs must not be packaged with sanitized libraries, as they will not
+# work with unsanitized app_process. For simplicity, generate APKs into /data/asan/.
+target_out_productservices_app_base := $(PRODUCT_SERVICES_OUT)/$(TARGET_COPY_OUT_ASAN)/product-services
+else
+target_out_productservices_app_base := $(TARGET_OUT_PRODUCT_SERVICES)
+endif
+else
+target_out_productservices_shared_libraries_base := $(TARGET_OUT_PRODUCT_SERVICES)
+target_out_productservices_app_base := $(TARGET_OUT_PRODUCT_SERVICES)
+endif
+
+ifeq ($(TARGET_IS_64_BIT),true)
+TARGET_OUT_PRODUCT_SERVICES_SHARED_LIBRARIES := $(target_out_productservices_shared_libraries_base)/lib64
+else
+TARGET_OUT_PRODUCT_SERVICES_SHARED_LIBRARIES := $(target_out_productservices_shared_libraries_base)/lib
+endif
+TARGET_OUT_PRODUCT_SERVICES_JAVA_LIBRARIES:= $(TARGET_OUT_PRODUCT_SERVICES)/framework
+TARGET_OUT_PRODUCT_SERVICES_APPS := $(target_out_productservices_app_base)/app
+TARGET_OUT_PRODUCT_SERVICES_APPS_PRIVILEGED := $(target_out_productservices_app_base)/priv-app
+TARGET_OUT_PRODUCT_SERVICES_ETC := $(TARGET_OUT_PRODUCT_SERVICES)/etc
+
+ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_PRODUCT_SERVICES_SHARED_LIBRARIES := $(target_out_productservices_shared_libraries_base)/lib/$(TARGET_2ND_ARCH)
+else
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_PRODUCT_SERVICES_SHARED_LIBRARIES := $(target_out_productservices_shared_libraries_base)/lib
+endif
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_PRODUCT_SERVICES_APPS := $(TARGET_OUT_PRODUCT_SERVICES_APPS)
+$(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_PRODUCT_SERVICES_APPS_PRIVILEGED := $(TARGET_OUT_PRODUCT_SERVICES_APPS_PRIVILEGED)
+
 TARGET_OUT_BREAKPAD := $(PRODUCT_OUT)/breakpad
 .KATI_READONLY := TARGET_OUT_BREAKPAD
 
diff --git a/core/host_java_library.mk b/core/host_java_library.mk
index db24542..2aed61e 100644
--- a/core/host_java_library.mk
+++ b/core/host_java_library.mk
@@ -93,6 +93,7 @@
 
 javac-check : $(full_classes_compiled_jar)
 javac-check-$(LOCAL_MODULE) : $(full_classes_compiled_jar)
+.PHONY: javac-check-$(LOCAL_MODULE)
 
 $(full_classes_combined_jar): $(full_classes_compiled_jar) \
                               $(jar_manifest_file) \
diff --git a/core/java.mk b/core/java.mk
index 78b492d..a094ecd 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -79,6 +79,7 @@
 built_dex_hiddenapi := $(intermediates.COMMON)/dex-hiddenapi/classes.dex
 full_classes_stubs_jar := $(intermediates.COMMON)/stubs.jar
 java_source_list_file := $(intermediates.COMMON)/java-source-list
+greylist_txt := $(intermediates.COMMON)/greylist.txt
 
 
 ifeq ($(LOCAL_MODULE_CLASS)$(LOCAL_SRC_FILES)$(LOCAL_STATIC_JAVA_LIBRARIES)$(LOCAL_SOURCE_FILES_ALL_GENERATED),APPS)
@@ -308,6 +309,7 @@
 
 javac-check : $(full_classes_compiled_jar)
 javac-check-$(LOCAL_MODULE) : $(full_classes_compiled_jar)
+.PHONY: javac-check-$(LOCAL_MODULE)
 
 $(full_classes_combined_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
 $(full_classes_combined_jar): $(full_classes_compiled_jar) \
@@ -544,6 +546,13 @@
 endif
 
 ifneq ($(filter $(LOCAL_MODULE),$(PRODUCT_BOOT_JARS)),) # is_boot_jar
+  # Derive API greylist from the classes jar.
+  # We use full_classes_proguard_jar here, as that is what is converted to dex
+  # later on. The difference is academic currently, as we don't proguard any
+  # bootclasspath code at the moment. If we were to do that, we should add keep
+  # rules for all members with the @UnsupportedAppUsage annotation.
+  $(eval $(call hiddenapi-generate-greylist-txt,$(full_classes_proguard_jar),$(greylist_txt)))
+  LOCAL_INTERMEDIATE_TARGETS += $(greylist_txt)
   $(eval $(call hiddenapi-copy-dex-files,$(built_dex_intermediate),$(built_dex_hiddenapi)))
   built_dex_copy_from := $(built_dex_hiddenapi)
 else # !is_boot_jar
@@ -576,6 +585,7 @@
 findbugs_html := $(PRODUCT_OUT)/findbugs/$(LOCAL_MODULE).html
 $(findbugs_html) : PRIVATE_XML_FILE := $(findbugs_xml)
 $(LOCAL_MODULE)-findbugs : $(findbugs_html)
+.PHONY: $(LOCAL_MODULE)-findbugs
 $(findbugs_html) : $(findbugs_xml)
 	@mkdir -p $(dir $@)
 	@echo ConvertXmlToText: $@
diff --git a/core/main.mk b/core/main.mk
index b057465..a991d88 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -901,7 +901,18 @@
   $(call expand-required-modules,$(1),$(_erm_new_modules)))
 endef
 
-# Determines the files a particular product installs.
+# Transforms paths relative to PRODUCT_OUT to absolute paths.
+# $(1): list of relative paths
+# $(2): optional suffix to append to paths
+define resolve-product-relative-paths
+  $(subst $(_vendor_path_placeholder),$(TARGET_COPY_OUT_VENDOR),\
+    $(subst $(_product_path_placeholder),$(TARGET_COPY_OUT_PRODUCT),\
+      $(foreach p,$(1),$(call append-path,$(PRODUCT_OUT),$(p)$(2)))))
+endef
+
+# Lists most of the files a particular product installs, including:
+# - PRODUCT_PACKAGES, and their LOCAL_REQUIRED_MODULES
+# - PRODUCT_COPY_FILES
 # The base list of modules to build for this product is specified
 # by the appropriate product definition file, which was included
 # by product_config.mk.
@@ -915,7 +926,8 @@
 #   32-bit variant, if it exits. See the select-bitness-of-required-modules definition.
 # $(1): product makefile
 define product-installed-files
-  $(eval _pif_modules := $(PRODUCTS.$(strip $(1)).PRODUCT_PACKAGES)) \
+  $(eval _mk := $(strip $(1))) \
+  $(eval _pif_modules := $(PRODUCTS.$(_mk).PRODUCT_PACKAGES)) \
   $(if $(BOARD_VNDK_VERSION),$(eval _pif_modules += vndk_package)) \
   $(eval ### Filter out the overridden packages and executables before doing expansion) \
   $(eval _pif_overrides := $(foreach p, $(_pif_modules), $(PACKAGES.$(p).OVERRIDES))) \
@@ -932,7 +944,9 @@
   $(eval _pif_modules += $(call get-32-bit-modules, $(_pif_modules_rest))) \
   $(eval _pif_modules += $(_pif_modules_rest)) \
   $(call expand-required-modules,_pif_modules,$(_pif_modules)) \
-  $(call module-installed-files, $(_pif_modules))
+  $(call module-installed-files, $(_pif_modules)) \
+  $(call resolve-product-relative-paths,\
+    $(foreach cf,$(PRODUCTS.$(_mk).PRODUCT_COPY_FILES),$(call word-colon,2,$(cf))))
 endef
 
 # Fails the build if the given list is non-empty, and prints it entries (stripping PRODUCT_OUT).
@@ -963,6 +977,39 @@
 
 ifdef FULL_BUILD
   product_FILES := $(call product-installed-files, $(INTERNAL_PRODUCT))
+
+  # Verify the artifact path requirements made by included products.
+  all_offending_files :=
+  $(foreach makefile,$(ARTIFACT_PATH_REQUIREMENT_PRODUCTS),\
+    $(eval requirements := $(PRODUCTS.$(makefile).ARTIFACT_PATH_REQUIREMENTS)) \
+    $(eval ### Verify that the product only produces files inside its path requirements.) \
+    $(eval whitelist := $(PRODUCTS.$(makefile).ARTIFACT_PATH_WHITELIST)) \
+    $(eval path_patterns := $(call resolve-product-relative-paths,$(requirements),%)) \
+    $(eval whitelist_patterns := $(call resolve-product-relative-paths,$(whitelist))) \
+    $(eval files := $(call product-installed-files, $(makefile))) \
+    $(eval files := $(filter-out $(TARGET_OUT_FAKE)/% $(HOST_OUT)/%,$(files))) \
+    $(eval # RROs become REQUIRED by the source module, but are always placed on the vendor partition.) \
+    $(eval files := $(filter-out %__auto_generated_rro.apk,$(files))) \
+    $(eval offending_files := $(filter-out $(path_patterns) $(whitelist_patterns),$(files))) \
+    $(call maybe-print-list-and-error,$(offending_files),$(makefile) produces files outside its artifact path requirement.) \
+    $(eval unused_whitelist := $(filter-out $(files),$(whitelist_patterns))) \
+    $(call maybe-print-list-and-error,$(unused_whitelist),$(makefile) includes redundant whitelist entries in its artifact path requirement.) \
+    $(eval ### Optionally verify that nothing else produces files inside this artifact path requirement.) \
+    $(eval extra_files := $(filter-out $(files) $(HOST_OUT)/%,$(product_FILES))) \
+    $(eval files_in_requirement := $(filter $(path_patterns),$(extra_files))) \
+    $(eval all_offending_files += $(files_in_requirement)) \
+    $(eval whitelist := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST)) \
+    $(eval whitelist_patterns := $(call resolve-product-relative-paths,$(whitelist))) \
+    $(eval offending_files := $(filter-out $(whitelist_patterns),$(files_in_requirement))) \
+    $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS),\
+      $(call maybe-print-list-and-error,$(offending_files),$(INTERNAL_PRODUCT) produces files inside $(makefile)s artifact path requirement.) \
+      $(eval unused_whitelist := $(filter-out $(extra_files),$(whitelist_patterns))) \
+      $(call maybe-print-list-and-error,$(unused_whitelist),$(INTERNAL_PRODUCT) includes redundant artifact path requirement whitelist entries.) \
+    ) \
+  )
+$(PRODUCT_OUT)/offending_artifacts.txt:
+	rm -f $@
+	$(foreach f,$(sort $(all_offending_files)),echo $(f) >> $@;)
 else
   # We're not doing a full build, and are probably only including
   # a subset of the module makefiles.  Don't try to build any modules
@@ -971,43 +1018,6 @@
   product_FILES :=
 endif
 
-# Transforms paths relative to PRODUCT_OUT to absolute paths.
-# $(1): list of relative paths
-# $(2): optional suffix to append to paths
-define resolve-product-relative-paths
-  $(subst $(_vendor_path_placeholder),$(TARGET_COPY_OUT_VENDOR),\
-    $(subst $(_product_path_placeholder),$(TARGET_COPY_OUT_PRODUCT),\
-      $(foreach p,$(1),$(PRODUCT_OUT)/$(p)$(2))))
-endef
-
-# Verify the artifact path requirements made by included products.
-$(foreach makefile,$(ARTIFACT_PATH_REQUIREMENT_PRODUCTS),\
-  $(eval requirements := $(PRODUCTS.$(makefile).ARTIFACT_PATH_REQUIREMENTS)) \
-  $(eval ### Verify that the product only produces files inside its path requirements.) \
-  $(eval whitelist := $(PRODUCTS.$(makefile).ARTIFACT_PATH_WHITELIST)) \
-  $(eval path_patterns := $(call resolve-product-relative-paths,$(requirements),%)) \
-  $(eval whitelist_patterns := $(call resolve-product-relative-paths,$(whitelist))) \
-  $(eval files := $(call product-installed-files, $(makefile))) \
-  $(eval files += $(foreach cf,$(PRODUCTS.$(makefile).PRODUCT_COPY_FILES),\
-    $(call append-path,$(PRODUCT_OUT),$(call word-colon,2,$(cf))))) \
-  $(eval files := $(filter-out $(TARGET_OUT_FAKE)/% $(HOST_OUT)/%,$(files))) \
-  $(eval offending_files := $(filter-out $(path_patterns) $(whitelist_patterns),$(files))) \
-  $(call maybe-print-list-and-error,$(offending_files),$(makefile) produces files outside its artifact path requirement.) \
-  $(eval unused_whitelist := $(filter-out $(files),$(whitelist_patterns))) \
-  $(call maybe-print-list-and-error,$(unused_whitelist),$(makefile) includes redundant whitelist entries in its artifact path requirement.) \
-  $(eval ### Optionally verify that nothing else produces files inside this artifact path requirement.) \
-  $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS),\
-    $(eval extra_files := $(filter-out $(files) $(HOST_OUT)/%,$(product_FILES))) \
-    $(eval whitelist := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST)) \
-    $(eval whitelist_patterns := $(call resolve-product-relative-paths,$(whitelist))) \
-    $(eval files_in_requirement := $(filter $(path_patterns),$(extra_files))) \
-    $(eval offending_files := $(filter-out $(whitelist_patterns),$(files_in_requirement))) \
-    $(call maybe-print-list-and-error,$(offending_files),$(INTERNAL_PRODUCT) produces files inside $(makefile)s artifact path requirement.) \
-    $(eval unused_whitelist := $(filter-out $(extra_files),$(whitelist_patterns))) \
-    $(call maybe-print-list-and-error,$(unused_whitelist),$(INTERNAL_PRODUCT) includes redundant artifact path requirement whitelist entries.) \
-  ) \
-)
-
 ifeq (0,1)
   $(info product_FILES for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):)
   $(foreach p,$(product_FILES),$(info :   $(p)))
@@ -1174,6 +1184,9 @@
 .PHONY: productimage
 productimage: $(INSTALLED_PRODUCTIMAGE_TARGET)
 
+.PHONY: productservicesimage
+productservicesimage: $(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET)
+
 .PHONY: systemotherimage
 systemotherimage: $(INSTALLED_SYSTEMOTHERIMAGE_TARGET)
 
@@ -1205,6 +1218,8 @@
     $(INSTALLED_FILES_JSON_VENDOR) \
     $(INSTALLED_FILES_FILE_PRODUCT) \
     $(INSTALLED_FILES_JSON_PRODUCT) \
+    $(INSTALLED_FILES_FILE_PRODUCT_SERVICES) \
+    $(INSTALLED_FILES_JSON_PRODUCT_SERVICES) \
     $(INSTALLED_FILES_FILE_SYSTEMOTHER) \
     $(INSTALLED_FILES_JSON_SYSTEMOTHER) \
     soong_docs
@@ -1248,6 +1263,9 @@
   $(COVERAGE_ZIP) : $(apps_only_installed_files)
   $(call dist-for-goals,apps_only, $(COVERAGE_ZIP))
 
+  $(APPCOMPAT_ZIP) : $(apps_only_installed_files)
+  $(call dist-for-goals,apps_only, $(APPCOMPAT_ZIP))
+
 .PHONY: apps_only
 apps_only: $(unbundled_build_modules)
 
@@ -1269,12 +1287,15 @@
     $(BUILT_OTATOOLS_PACKAGE) \
     $(SYMBOLS_ZIP) \
     $(COVERAGE_ZIP) \
+    $(APPCOMPAT_ZIP) \
     $(INSTALLED_FILES_FILE) \
     $(INSTALLED_FILES_JSON) \
     $(INSTALLED_FILES_FILE_VENDOR) \
     $(INSTALLED_FILES_JSON_VENDOR) \
     $(INSTALLED_FILES_FILE_PRODUCT) \
     $(INSTALLED_FILES_JSON_PRODUCT) \
+    $(INSTALLED_FILES_FILE_PRODUCT_SERVICES) \
+    $(INSTALLED_FILES_JSON_PRODUCT_SERVICES) \
     $(INSTALLED_FILES_FILE_SYSTEMOTHER) \
     $(INSTALLED_FILES_JSON_SYSTEMOTHER) \
     $(INSTALLED_BUILD_PROP_TARGET) \
@@ -1322,26 +1343,6 @@
 # Building a full system-- the default is to build droidcore
 droid_targets: droidcore dist_files
 
-ifdef USE_LOGICAL_PARTITIONS
-ifdef BOARD_SUPER_PARTITION_SIZE
-ifdef BOARD_SUPER_PARTITION_PARTITION_LIST
-
-droid_targets: check_android_partition_sizes
-
-.PHONY: check_android_partition_sizes
-check_android_partition_sizes: partition_size_list=$(foreach p,$(BOARD_SUPER_PARTITION_PARTITION_LIST),$(BOARD_$(call to-upper,$(p))IMAGE_PARTITION_SIZE))
-check_android_partition_sizes: sum_sizes_expr=$(subst $(space),+,$(partition_size_list))
-check_android_partition_sizes:
-	if [ $$(( $(sum_sizes_expr) )) -gt $(BOARD_SUPER_PARTITION_SIZE) ]; then \
-		echo The sum of sizes of all logical partitions is larger than BOARD_SUPER_PARTITION_SIZE.; \
-		echo $(sum_sizes_expr) == $$(( $(sum_sizes_expr) )) '>' $(BOARD_SUPER_PARTITION_SIZE); \
-		exit 1; \
-	fi
-
-endif # BOARD_SUPER_PARTITION_PARTITION_LIST
-endif # BOARD_SUPER_PARTITION_SIZE
-endif # USE_LOGICAL_PARTITIONS
-
 endif # TARGET_BUILD_APPS
 
 .PHONY: docs
@@ -1354,13 +1355,15 @@
     $(ALL_SDK_TARGETS) \
     $(SYMBOLS_ZIP) \
     $(COVERAGE_ZIP) \
+    $(APPCOMPAT_ZIP) \
     $(INSTALLED_BUILD_PROP_TARGET) \
 )
 
 # umbrella targets to assit engineers in verifying builds
 .PHONY: java native target host java-host java-target native-host native-target \
         java-host-tests java-target-tests native-host-tests native-target-tests \
-        java-tests native-tests host-tests target-tests tests java-dex
+        java-tests native-tests host-tests target-tests tests java-dex \
+        native-host-cross
 # some synonyms
 .PHONY: host-java target-java host-native target-native \
         target-java-tests target-native-tests
diff --git a/core/package_internal.mk b/core/package_internal.mk
index 637a135..be87bb2 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -118,6 +118,8 @@
         enforce_rro_enabled :=
       else ifeq (true,$(LOCAL_PRODUCT_MODULE))
         enforce_rro_enabled :=
+      else ifeq (true,$(LOCAL_PRODUCT_SERVICES_MODULE))
+        enforce_rro_enabled :=
       endif
     else ifeq ($(filter $(TARGET_OUT)/%,$(LOCAL_MODULE_PATH)),)
       enforce_rro_enabled :=
@@ -590,6 +592,10 @@
 endif
 endif
 
+ifdef LOCAL_PRODUCT_MODULE
+$(LOCAL_BUILT_MODULE) : $(call intermediates-dir-for,PACKAGING,veridex,HOST)/veridex.zip
+endif
+
 $(LOCAL_BUILT_MODULE): PRIVATE_DONT_DELETE_JAR_DIRS := $(LOCAL_DONT_DELETE_JAR_DIRS)
 $(LOCAL_BUILT_MODULE): PRIVATE_RESOURCE_INTERMEDIATES_DIR := $(intermediates.COMMON)/resources
 $(LOCAL_BUILT_MODULE): PRIVATE_FULL_CLASSES_JAR := $(full_classes_jar)
@@ -630,6 +636,10 @@
 	@# No need to align, sign-package below will do it.
 	$(uncompress-dexs)
 endif
+# Run appcompat before stripping the classes.dex file.
+ifdef LOCAL_PRODUCT_MODULE
+	$(run-appcompat)
+endif  # LOCAL_PRODUCT_MODULE
 ifdef LOCAL_DEX_PREOPT
 ifneq ($(BUILD_PLATFORM_ZIP),)
 	@# Keep a copy of apk with classes.dex unstripped
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index 94c2dcd..2e6cb22 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -376,6 +376,10 @@
 $(built_module) : $(MINIGZIP)
 endif
 
+ifdef LOCAL_PRODUCT_MODULE
+$(built_module) : $(call intermediates-dir-for,PACKAGING,veridex,HOST)/veridex.zip
+endif
+
 $(built_module) : $(my_prebuilt_src_file) | $(ZIPALIGN) $(SIGNAPK_JAR)
 	$(transform-prebuilt-to-target)
 	$(uncompress-shared-libs)
@@ -390,6 +394,10 @@
 endif  # LOCAL_DEX_PREOPT
 ifneq ($(LOCAL_CERTIFICATE),PRESIGNED)
 	@# Only strip out files if we can re-sign the package.
+# Run appcompat before stripping the classes.dex file.
+ifdef LOCAL_PRODUCT_MODULE
+	$(run-appcompat)
+endif  # LOCAL_PRODUCT_MODULE
 ifdef LOCAL_DEX_PREOPT
 ifneq (nostripping,$(LOCAL_DEX_PREOPT))
 	$(call dexpreopt-remove-classes.dex,$@)
diff --git a/core/product-graph.mk b/core/product-graph.mk
index 4133bd9..696aabf 100644
--- a/core/product-graph.mk
+++ b/core/product-graph.mk
@@ -105,6 +105,7 @@
 	$(hide) echo 'PRODUCT_DEFAULT_PROPERTY_OVERRIDES=$$(PRODUCTS.$(strip $(1)).PRODUCT_DEFAULT_PROPERTY_OVERRIDES)' >> $$@
 	$(hide) echo 'PRODUCT_SYSTEM_DEFAULT_PROPERTIES=$$(PRODUCTS.$(strip $(1)).PRODUCT_SYSTEM_DEFAULT_PROPERTIES)' >> $$@
 	$(hide) echo 'PRODUCT_PRODUCT_PROPERTIES=$$(PRODUCTS.$(strip $(1)).PRODUCT_PRODUCT_PROPERTIES)' >> $$@
+	$(hide) echo 'PRODUCT_PRODUCT_SERVICES_PROPERTIES=$$(PRODUCTS.$(strip $(1)).PRODUCT_PRODUCT_SERVICES_PROPERTIES)' >> $$@
 	$(hide) echo 'PRODUCT_CHARACTERISTICS=$$(PRODUCTS.$(strip $(1)).PRODUCT_CHARACTERISTICS)' >> $$@
 	$(hide) echo 'PRODUCT_COPY_FILES=$$(PRODUCTS.$(strip $(1)).PRODUCT_COPY_FILES)' >> $$@
 	$(hide) echo 'PRODUCT_OTA_PUBLIC_KEYS=$$(PRODUCTS.$(strip $(1)).PRODUCT_OTA_PUBLIC_KEYS)' >> $$@
@@ -144,3 +145,4 @@
 	dot -Tsvg -Nshape=box -o $@ $<
 
 product-graph: $(products_pdf) $(products_svg)
+.PHONY: product-graph
diff --git a/core/product.mk b/core/product.mk
index 51b376a..ff2e7e7 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -128,6 +128,7 @@
     PRODUCT_PROPERTY_OVERRIDES \
     PRODUCT_DEFAULT_PROPERTY_OVERRIDES \
     PRODUCT_PRODUCT_PROPERTIES \
+    PRODUCT_PRODUCT_SERVICES_PROPERTIES \
     PRODUCT_CHARACTERISTICS \
     PRODUCT_COPY_FILES \
     PRODUCT_OTA_PUBLIC_KEYS \
@@ -167,6 +168,7 @@
     PRODUCT_SYSTEM_VERITY_PARTITION \
     PRODUCT_VENDOR_VERITY_PARTITION \
     PRODUCT_PRODUCT_VERITY_PARTITION \
+    PRODUCT_PRODUCT_SERVICES_VERITY_PARTITION \
     PRODUCT_SYSTEM_SERVER_DEBUG_INFO \
     PRODUCT_OTHER_JAVA_DEBUG_INFO \
     PRODUCT_DEX_PREOPT_MODULE_CONFIGS \
@@ -182,6 +184,7 @@
     PRODUCT_SYSTEM_BASE_FS_PATH \
     PRODUCT_VENDOR_BASE_FS_PATH \
     PRODUCT_PRODUCT_BASE_FS_PATH \
+    PRODUCT_PRODUCT_SERVICES_BASE_FS_PATH \
     PRODUCT_SHIPPING_API_LEVEL \
     VENDOR_PRODUCT_RESTRICT_VENDOR_FILES \
     VENDOR_EXCEPTION_MODULES \
@@ -378,6 +381,8 @@
 	BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE \
 	BOARD_PRODUCTIMAGE_PARTITION_SIZE \
 	BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE \
+	BOARD_PRODUCT_SERVICESIMAGE_PARTITION_SIZE \
+	BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE \
 	BOARD_INSTALLER_CMDLINE \
 
 
@@ -390,6 +395,8 @@
 _product_stash_var_list += \
 	BOARD_SYSTEMIMAGE_PARTITION_RESERVED_SIZE \
 	BOARD_VENDORIMAGE_PARTITION_RESERVED_SIZE \
+	BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE \
+	BOARD_PRODUCT_SERVICESIMAGE_PARTITION_RESERVED_SIZE \
 	BOARD_SUPER_PARTITION_SIZE \
 	BOARD_SUPER_PARTITION_PARTITION_LIST \
 
diff --git a/core/product_config.mk b/core/product_config.mk
index 8425b09..325dc64 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -373,6 +373,14 @@
     $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_PROPERTIES))
 .KATI_READONLY := PRODUCT_PRODUCT_PROPERTIES
 
+
+# A list of property assignments, like "key = value", with zero or more
+# whitespace characters on either side of the '='.
+# used for adding properties to build.prop of product partition
+PRODUCT_PRODUCT_SERVICES_PROPERTIES := \
+    $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PRODUCT_SERVICES_PROPERTIES))
+.KATI_READONLY := PRODUCT_PRODUCT_SERVICES_PROPERTIES
+
 # Should we use the default resources or add any product specific overlays
 PRODUCT_PACKAGE_OVERLAYS := \
     $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGE_OVERLAYS))
diff --git a/core/soong_config.mk b/core/soong_config.mk
index f75e263..914b7f9 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -133,6 +133,7 @@
 $(call add_json_str,  VendorPath,                        $(TARGET_COPY_OUT_VENDOR))
 $(call add_json_str,  OdmPath,                           $(TARGET_COPY_OUT_ODM))
 $(call add_json_str,  ProductPath,                       $(TARGET_COPY_OUT_PRODUCT))
+$(call add_json_str,  ProductServicesPath,               $(TARGET_COPY_OUT_PRODUCT_SERVICES))
 $(call add_json_bool, MinimizeJavaDebugInfo,             $(filter true,$(PRODUCT_MINIMIZE_JAVA_DEBUG_INFO)))
 
 $(call add_json_bool, UseGoma,                           $(filter-out false,$(USE_GOMA)))
diff --git a/core/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index ef71107..44b4f5c 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -19,6 +19,7 @@
 full_classes_pre_proguard_jar := $(intermediates.COMMON)/classes-pre-proguard.jar
 full_classes_header_jar := $(intermediates.COMMON)/classes-header.jar
 common_javalib.jar := $(intermediates.COMMON)/javalib.jar
+greylist_txt := $(intermediates.COMMON)/greylist.txt
 
 $(eval $(call copy-one-file,$(LOCAL_PREBUILT_MODULE_FILE),$(full_classes_jar)))
 $(eval $(call copy-one-file,$(LOCAL_PREBUILT_MODULE_FILE),$(full_classes_pre_proguard_jar)))
@@ -33,6 +34,10 @@
 $(call dist-for-goals,docs,$(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip)
 endif
 
+ifdef LOCAL_DROIDDOC_ANNOTATIONS_ZIP
+$(eval $(call copy-one-file,$(LOCAL_DROIDDOC_ANNOTATIONS_ZIP),$(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/$(LOCAL_MODULE)_annotations.zip))
+endif
+
 ifdef LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR
   $(eval $(call copy-one-file,$(LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR),\
     $(intermediates.COMMON)/jacoco-report-classes.jar))
@@ -82,6 +87,11 @@
   ifneq ($(LOCAL_UNINSTALLABLE_MODULE),true)
     ifndef LOCAL_IS_HOST_MODULE
       ifneq ($(filter $(LOCAL_MODULE),$(PRODUCT_BOOT_JARS)),)  # is_boot_jar
+        # Derive greylist from classes.jar.
+        # We use full_classes_jar here, which is the post-proguard jar (on the basis that we also
+        # have a full_classes_pre_proguard_jar). This is consistent with the equivalent code in
+        # java.mk.
+        $(eval $(call hiddenapi-generate-greylist-txt,$(full_classes_jar),$(greylist_txt)))
         $(eval $(call hiddenapi-copy-soong-jar,$(LOCAL_SOONG_DEX_JAR),$(common_javalib.jar)))
       else # !is_boot_jar
         $(eval $(call copy-one-file,$(LOCAL_SOONG_DEX_JAR),$(common_javalib.jar)))
@@ -131,6 +141,7 @@
 
 javac-check : $(full_classes_jar)
 javac-check-$(LOCAL_MODULE) : $(full_classes_jar)
+.PHONY: javac-check-$(LOCAL_MODULE)
 
 ifndef LOCAL_IS_HOST_MODULE
 ifeq ($(LOCAL_SDK_VERSION),system_current)
diff --git a/core/tasks/vndk.mk b/core/tasks/vndk.mk
index ba48df7..1bde7a6 100644
--- a/core/tasks/vndk.mk
+++ b/core/tasks/vndk.mk
@@ -145,8 +145,10 @@
 # vndk_snapshot_zip
 vndk_snapshot_variant := $(vndk_snapshot_out)/$(TARGET_ARCH)
 binder :=
-ifneq ($(TARGET_USES_64_BIT_BINDER), true)
-  binder := binder32
+ifneq ($(TARGET_IS_64_BIT), true)
+  ifneq ($(TARGET_USES_64_BIT_BINDER), true)
+    binder := binder32
+  endif
 endif
 vndk_lib_dir := $(subst $(space),/,$(strip $(vndk_snapshot_variant) $(binder) arch-$(TARGET_ARCH)-$(TARGET_ARCH_VARIANT)))
 vndk_lib_dir_2nd := $(subst $(space),/,$(strip $(vndk_snapshot_variant) $(binder) arch-$(TARGET_2ND_ARCH)-$(TARGET_2ND_ARCH_VARIANT)))
diff --git a/envsetup.sh b/envsetup.sh
index 12168e1..5894144 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -48,12 +48,12 @@
 {
     local T=$(gettop)
     # Grep out the variable names from the script.
-    cached_vars=`cat $T/build/envsetup.sh | tr '()' '  ' | awk '{for(i=1;i<=NF;i++) if($i~/get_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`
-    cached_abs_vars=`cat $T/build/envsetup.sh | tr '()' '  ' | awk '{for(i=1;i<=NF;i++) if($i~/get_abs_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`
+    cached_vars=(`cat $T/build/envsetup.sh | tr '()' '  ' | awk '{for(i=1;i<=NF;i++) if($i~/get_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`)
+    cached_abs_vars=(`cat $T/build/envsetup.sh | tr '()' '  ' | awk '{for(i=1;i<=NF;i++) if($i~/get_abs_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`)
     # Call the build system to dump the "<val>=<value>" pairs as a shell script.
     build_dicts_script=`\builtin cd $T; build/soong/soong_ui.bash --dumpvars-mode \
-                        --vars="$cached_vars" \
-                        --abs-vars="$cached_abs_vars" \
+                        --vars="${cached_vars[*]}" \
+                        --abs-vars="${cached_abs_vars[*]}" \
                         --var-prefix=var_cache_ \
                         --abs-var-prefix=abs_var_cache_`
     local ret=$?
@@ -317,11 +317,11 @@
 
 # Takes a command name, and check if it's in ENVSETUP_NO_COMPLETION or not.
 function should_add_completion() {
-    local cmd="$1"
+    local cmd="$(basename $1| sed 's/_completion//' |sed 's/\.\(.*\)*sh$//')"
     case :"$ENVSETUP_NO_COMPLETION": in
-    *:"$cmd":*)
-        return 1
-        ;;
+        *:"$cmd":*)
+            return 1
+            ;;
     esac
     return 0
 }
@@ -330,22 +330,27 @@
 {
     local T dir f
 
-    # Keep us from trying to run in something that isn't bash.
-    if [ -z "${BASH_VERSION}" ]; then
+    # Keep us from trying to run in something that's neither bash nor zsh.
+    if [ -z "$BASH_VERSION" -a -z "$ZSH_VERSION" ]; then
         return
     fi
 
     # Keep us from trying to run in bash that's too old.
-    if [ ${BASH_VERSINFO[0]} -lt 3 ]; then
+    if [ -n "$BASH_VERSION" -a ${BASH_VERSINFO[0]} -lt 3 ]; then
         return
     fi
 
+    local completion_files=(
+      system/core/adb/adb.bash
+      system/core/fastboot/fastboot.bash
+      tools/tradefederation/core/atest/atest_completion.sh
+    )
     # Completion can be disabled selectively to allow users to use non-standard completion.
     # e.g.
     # ENVSETUP_NO_COMPLETION=adb # -> disable adb completion
     # ENVSETUP_NO_COMPLETION=adb:bit # -> disable adb and bit completion
-    for f in system/core/adb/adb.bash system/core/fastboot/fastboot.bash; do
-        if [ -f "$f" ] && should_add_completion $(basename "$f" .bash) ; then
+    for f in ${completion_files[*]}; do
+        if [ -f "$f" ] && should_add_completion "$f"; then
             . $f
         fi
     done
@@ -353,6 +358,7 @@
     if should_add_completion bit ; then
         complete -C "bit --tab" bit
     fi
+    complete -F _lunch lunch
 }
 
 function choosetype()
@@ -646,7 +652,6 @@
     COMPREPLY=( $(compgen -W "${COMMON_LUNCH_CHOICES_CACHE}" -- ${cur}) )
     return 0
 }
-complete -F _lunch lunch
 
 # Configures the build to build unbundled apps.
 # Run tapas with one or more app names (from LOCAL_PACKAGE_NAME)
@@ -1562,24 +1567,37 @@
     "$(gettop)"/tools/tradefederation/core/atest/atest.py "$@"
 }
 
-if [ "x$SHELL" != "x/bin/bash" ]; then
-    case `ps -o command -p $$` in
+# Zsh needs bashcompinit called to support bash-style completion.
+function add_zsh_completion() {
+    autoload -U compinit && compinit
+    autoload -U bashcompinit && bashcompinit
+}
+
+function validate_current_shell() {
+    local current_sh="$(ps -o command -p $$)"
+    case "$current_sh" in
         *bash*)
+            function check_type() { type -t "$1"; }
             ;;
+        *zsh*)
+            function check_type() { type "$1"; }
+            add_zsh_completion ;;
         *)
-            echo "WARNING: Only bash is supported, use of other shell would lead to erroneous results"
+            echo -e "WARNING: Only bash and zsh are supported.\nUse of other shell would lead to erroneous results."
             ;;
     esac
-fi
+}
 
 # Execute the contents of any vendorsetup.sh files we can find.
-for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
-         `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
-         `test -d product && find -L product -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort`
-do
-    echo "including $f"
-    . $f
-done
-unset f
+function source_vendorsetup() {
+    for dir in device vendor product; do
+        for f in $(test -d $dir && \
+            find -L $dir -maxdepth 4 -name 'vendorsetup.sh' 2>/dev/null | sort); do
+            echo "including $f"; . $f
+        done
+    done
+}
 
+validate_current_shell
+source_vendorsetup
 addcompletions
diff --git a/help.sh b/help.sh
index c143542..ad22253 100755
--- a/help.sh
+++ b/help.sh
@@ -40,6 +40,8 @@
                             Stands for "Vendor, NO Dependencies"
     pnod                    Quickly rebuild the product image from built packages
                             Stands for "Product, NO Dependencies"
+    psnod                   Quickly rebuild the product-services image from built packages
+                            Stands for "ProductServices, NO Dependencies"
 
 
 So, for example, you could run:
diff --git a/target/board/BoardConfigEmuCommon.mk b/target/board/BoardConfigEmuCommon.mk
index 1d58eab..e8a562a 100644
--- a/target/board/BoardConfigEmuCommon.mk
+++ b/target/board/BoardConfigEmuCommon.mk
@@ -11,9 +11,6 @@
 BOARD_USES_GENERIC_AUDIO := true
 TARGET_BOOTLOADER_BOARD_NAME := goldfish_$(TARGET_ARCH)
 
-TARGET_USES_64_BIT_BINDER := true
-TARGET_USES_MKE2FS := true
-
 # no hardware camera
 USE_CAMERA_STUB := true
 
@@ -29,22 +26,14 @@
 USE_OPENGL_RENDERER := true
 
 TARGET_COPY_OUT_VENDOR := vendor
+
 # ~100 MB vendor image. Please adjust system image / vendor image sizes
 # when finalizing them.
 BOARD_VENDORIMAGE_PARTITION_SIZE := 100000000
 BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_FLASH_BLOCK_SIZE := 512
-TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
 DEVICE_MATRIX_FILE   := device/generic/goldfish/compatibility_matrix.xml
 
-# Android generic system image always create metadata partition
-BOARD_USES_METADATA_PARTITION := true
-
-# Set this to create /cache mount point for non-A/B devices that mounts /cache.
-# The partition size doesn't matter, just to make build pass.
-BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
-BOARD_CACHEIMAGE_PARTITION_SIZE := 16777216
-
 BOARD_SEPOLICY_DIRS += device/generic/goldfish/sepolicy/common
 BOARD_PROPERTY_OVERRIDES_SPLIT_ENABLED := true
 
diff --git a/target/board/BoardConfigGsiCommon.mk b/target/board/BoardConfigGsiCommon.mk
index 237cd28..24614de 100644
--- a/target/board/BoardConfigGsiCommon.mk
+++ b/target/board/BoardConfigGsiCommon.mk
@@ -3,6 +3,13 @@
 # Common compile-time definitions for GSI
 #
 
+# system.img is always ext4 with sparse option
+TARGET_USERIMAGES_USE_EXT4 := true
+# TODO(b/63790380): emulator doesn't support sparse yet
+#TARGET_USERIMAGES_SPARSE_EXT_DISABLED := false
+TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
+TARGET_USES_MKE2FS := true
+
 # Android Verified Boot (AVB):
 #   Builds a special vbmeta.img that disables AVB verification.
 #   Otherwise, AVB will prevent the device from booting the generic system.img.
@@ -20,9 +27,20 @@
 endif
 BOARD_VNDK_VERSION := current
 
-# Pi GSI supports system-as-root
+# system-as-root is mandatory from Android P
 TARGET_NO_RECOVERY := true
 BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
 
+# 64 bits binder interface is mandatory from Android P
+TARGET_USES_64_BIT_BINDER := true
+
+# Android generic system image always create metadata partition
+BOARD_USES_METADATA_PARTITION := true
+
+# Set this to create /cache mount point for non-A/B devices that mounts /cache.
+# The partition size doesn't matter, just to make build pass.
+BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_CACHEIMAGE_PARTITION_SIZE := 16777216
+
 # Audio: must using XML format for Treblized devices
 USE_XML_AUDIO_POLICY_CONF := 1
diff --git a/target/board/generic/BoardConfig.mk b/target/board/generic/BoardConfig.mk
index 38d294b..8113ae3 100644
--- a/target/board/generic/BoardConfig.mk
+++ b/target/board/generic/BoardConfig.mk
@@ -48,7 +48,6 @@
 include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
 
-TARGET_USERIMAGES_USE_EXT4 := true
 # Partition size is default 1.5GB (1536MB) for 64 bits projects
 BOARD_SYSTEMIMAGE_PARTITION_SIZE := 1610612736
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
diff --git a/target/board/generic_arm64/BoardConfig.mk b/target/board/generic_arm64/BoardConfig.mk
index 88f89de..ad6d229 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -55,7 +55,6 @@
 include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
 
-TARGET_USERIMAGES_USE_EXT4 := true
 # Partition size is default 1.5GB (1536MB) for 64 bits projects
 BOARD_SYSTEMIMAGE_PARTITION_SIZE := 1610612736
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
@@ -63,9 +62,10 @@
 # Emulator system image is going to be used as GSI and some vendor still hasn't
 # cleaned up all device specific directories under root!
 
-# TODO(jiyong) These might be SoC specific.
-BOARD_ROOT_EXTRA_FOLDERS += firmware firmware/radio persist
+# TODO(b/111434759, b/111287060) SoC specific hacks
 BOARD_ROOT_EXTRA_SYMLINKS := /vendor/lib/dsp:/dsp
+BOARD_ROOT_EXTRA_SYMLINKS += /mnt/vendor/persist:/persist
+BOARD_ROOT_EXTRA_SYMLINKS += /vendor/firmware_mnt:/firmware
 
 # TODO(b/36764215): remove this setting when the generic system image
 # no longer has QCOM-specific directories under /.
diff --git a/target/board/generic_x86/BoardConfig.mk b/target/board/generic_x86/BoardConfig.mk
index 9a45188..c8ba2cf 100644
--- a/target/board/generic_x86/BoardConfig.mk
+++ b/target/board/generic_x86/BoardConfig.mk
@@ -23,6 +23,5 @@
 include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
 
-TARGET_USERIMAGES_USE_EXT4 := true
 BOARD_SYSTEMIMAGE_PARTITION_SIZE := 2684354560
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
diff --git a/target/board/generic_x86_64/BoardConfig.mk b/target/board/generic_x86_64/BoardConfig.mk
index a24263d..1bae7f8 100755
--- a/target/board/generic_x86_64/BoardConfig.mk
+++ b/target/board/generic_x86_64/BoardConfig.mk
@@ -27,6 +27,5 @@
 include build/make/target/board/BoardConfigEmuCommon.mk
 include build/make/target/board/BoardConfigGsiCommon.mk
 
-TARGET_USERIMAGES_USE_EXT4 := true
 BOARD_SYSTEMIMAGE_PARTITION_SIZE := 2684354560 # 2.5 GB
 BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800
diff --git a/target/product/aosp_arm.mk b/target/product/aosp_arm.mk
index 8c8f407..a052b3a 100644
--- a/target/product/aosp_arm.mk
+++ b/target/product/aosp_arm.mk
@@ -14,6 +14,13 @@
 # limitations under the License.
 #
 
+# The system image of aosp_arm-userdebug is a GSI for the devices with:
+# - ARM 32 bits user space
+# - 64 bits binder interface
+# - system-as-root
+# - VNDK enforcement
+# - compatible property override enabled
+
 PRODUCT_PROPERTY_OVERRIDES += \
 	rild.libpath=/vendor/lib/libreference-ril.so
 
@@ -27,6 +34,13 @@
 
 include $(SRC_TARGET_DIR)/product/full.mk
 
+# Enable A/B update
+AB_OTA_UPDATER := true
+AB_OTA_PARTITIONS := system
+PRODUCT_PACKAGES += \
+    update_engine \
+    update_verifier
+
 # Needed by Pi newly launched device to pass VtsTrebleSysProp on GSI
 PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE := true
 
diff --git a/target/product/aosp_arm64.mk b/target/product/aosp_arm64.mk
index aeff3f0..efbc300 100644
--- a/target/product/aosp_arm64.mk
+++ b/target/product/aosp_arm64.mk
@@ -14,6 +14,13 @@
 # limitations under the License.
 #
 
+# The system image of aosp_arm64-userdebug is a GSI for the devices with:
+# - ARM 64 bits user space
+# - 64 bits binder interface
+# - system-as-root
+# - VNDK enforcement
+# - compatible property override enabled
+
 PRODUCT_PROPERTY_OVERRIDES += \
 	rild.libpath=/vendor/lib64/libreference-ril.so
 
@@ -44,6 +51,13 @@
 
 include $(SRC_TARGET_DIR)/product/emulator.mk
 
+# Enable A/B update
+AB_OTA_UPDATER := true
+AB_OTA_PARTITIONS := system
+PRODUCT_PACKAGES += \
+    update_engine \
+    update_verifier
+
 # Needed by Pi newly launched device to pass VtsTrebleSysProp on GSI
 PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE := true
 
diff --git a/target/product/aosp_arm64_ab.mk b/target/product/aosp_arm64_ab.mk
index c96cb91..d389c74 100644
--- a/target/product/aosp_arm64_ab.mk
+++ b/target/product/aosp_arm64_ab.mk
@@ -19,8 +19,14 @@
 # on the generic system image, place them in build/make/target/board/
 # treble_system.prop.
 
+# aosp_arm64_ab-userdebug is a Legacy GSI for the devices with:
+# - ARM 64 bits user space
+# - 64 bits binder interface
+# - system-as-root
+
 include build/make/target/product/treble_common_64.mk
 
+# Enable A/B update
 AB_OTA_UPDATER := true
 AB_OTA_PARTITIONS := system
 PRODUCT_PACKAGES += \
diff --git a/target/product/aosp_arm_ab.mk b/target/product/aosp_arm_ab.mk
index 98b2f99..5845d3b 100644
--- a/target/product/aosp_arm_ab.mk
+++ b/target/product/aosp_arm_ab.mk
@@ -19,8 +19,14 @@
 # on the generic system image, place them in build/make/target/board/
 # treble_system.prop.
 
+# aosp_arm_ab-userdebug is a Legacy GSI for the devices with:
+# - ARM 32 bits user space
+# - 32 bits binder interface
+# - system-as-root
+
 include build/make/target/product/treble_common_32.mk
 
+# Enable A/B update
 AB_OTA_UPDATER := true
 AB_OTA_PARTITIONS := system
 PRODUCT_PACKAGES += \
diff --git a/target/product/aosp_x86.mk b/target/product/aosp_x86.mk
index b044149..7929a3e 100644
--- a/target/product/aosp_x86.mk
+++ b/target/product/aosp_x86.mk
@@ -14,6 +14,13 @@
 # limitations under the License.
 #
 
+# The system image of aosp_x86-userdebug is a GSI for the devices with:
+# - x86 32 bits user space
+# - 64 bits binder interface
+# - system-as-root
+# - VNDK enforcement
+# - compatible property override enabled
+
 PRODUCT_PROPERTY_OVERRIDES += \
 	rild.libpath=/vendor/lib/libreference-ril.so
 
@@ -28,6 +35,13 @@
 
 include $(SRC_TARGET_DIR)/product/full_x86.mk
 
+# Enable A/B update
+AB_OTA_UPDATER := true
+AB_OTA_PARTITIONS := system
+PRODUCT_PACKAGES += \
+    update_engine \
+    update_verifier
+
 # Needed by Pi newly launched device to pass VtsTrebleSysProp on GSI
 PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE := true
 
diff --git a/target/product/aosp_x86_64.mk b/target/product/aosp_x86_64.mk
index 4d2589e..5a934a9 100644
--- a/target/product/aosp_x86_64.mk
+++ b/target/product/aosp_x86_64.mk
@@ -14,6 +14,13 @@
 # limitations under the License.
 #
 
+# The system image of aosp_x86_64-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
+
 PRODUCT_PROPERTY_OVERRIDES += \
 	rild.libpath=/vendor/lib64/libreference-ril.so
 
@@ -41,6 +48,13 @@
 
 include $(SRC_TARGET_DIR)/product/emulator.mk
 
+# Enable A/B update
+AB_OTA_UPDATER := true
+AB_OTA_PARTITIONS := system
+PRODUCT_PACKAGES += \
+    update_engine \
+    update_verifier
+
 # Needed by Pi newly launched device to pass VtsTrebleSysProp on GSI
 PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE := true
 
diff --git a/target/product/aosp_x86_64_ab.mk b/target/product/aosp_x86_64_ab.mk
index 4590dc5..d9163d7 100644
--- a/target/product/aosp_x86_64_ab.mk
+++ b/target/product/aosp_x86_64_ab.mk
@@ -19,8 +19,14 @@
 # on the generic system image, place them in build/make/target/board/
 # treble_system.prop.
 
+# aosp_x86_64_ab-userdebug is a Legacy GSI for the devices with:
+# - x86 64 bits user space
+# - 64 bits binder interface
+# - system-as-root
+
 include build/make/target/product/treble_common_64.mk
 
+# Enable A/B update
 AB_OTA_UPDATER := true
 AB_OTA_PARTITIONS := system
 PRODUCT_PACKAGES += \
diff --git a/target/product/aosp_x86_ab.mk b/target/product/aosp_x86_ab.mk
index 404a4da..4fff3d1 100644
--- a/target/product/aosp_x86_ab.mk
+++ b/target/product/aosp_x86_ab.mk
@@ -19,8 +19,14 @@
 # on the generic system image, place them in build/make/target/board/
 # treble_system.prop.
 
+# aosp_x86_ab-userdebug is a Legacy GSI for the devices with:
+# - x86 32 bits user space
+# - 32 bits binder interface
+# - system-as-root
+
 include build/make/target/product/treble_common_32.mk
 
+# Enable A/B update
 AB_OTA_UPDATER := true
 AB_OTA_PARTITIONS := system
 PRODUCT_PACKAGES += \
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 8b3f857..3311e3d 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -290,7 +290,10 @@
     procrank \
     showmap \
     sqlite3 \
-    strace
+    strace \
+    unwind_info \
+    unwind_reg_info \
+    unwind_symbols \
 
 # The set of packages whose code can be loaded by the system server.
 PRODUCT_SYSTEM_SERVER_APPS += \
diff --git a/target/product/mainline_arm64.mk b/target/product/mainline_arm64.mk
index 2dcca88..4c18dd3 100644
--- a/target/product/mainline_arm64.mk
+++ b/target/product/mainline_arm64.mk
@@ -24,4 +24,6 @@
 PRODUCT_SHIPPING_API_LEVEL := 28
 
 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST := system/etc/seccomp_policy/mediacodec.policy
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST := \
+    root/init.zygote64_32.rc \
+    system/etc/seccomp_policy/mediacodec.policy \
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 8ac039f..6a97182 100755
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -74,7 +74,7 @@
 
 
 # Partitions that should have their care_map added to META/care_map.txt.
-PARTITIONS_WITH_CARE_MAP = ('system', 'vendor', 'product')
+PARTITIONS_WITH_CARE_MAP = ('system', 'vendor', 'product', 'product-services')
 
 
 class OutputFile(object):
@@ -196,6 +196,24 @@
   return img.name
 
 
+def AddProductServices(output_zip):
+  """Turn the contents of PRODUCT_SERVICES into a product-services image and
+  store it in output_zip."""
+
+  img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES",
+                   "product-services.img")
+  if os.path.exists(img.input_name):
+    print("product-services.img already exists; no need to rebuild...")
+    return img.input_name
+
+  block_list = OutputFile(
+      output_zip, OPTIONS.input_tmp, "IMAGES", "product-services.map")
+  CreateImage(
+      OPTIONS.input_tmp, OPTIONS.info_dict, "product-services", img,
+      block_list=block_list)
+  return img.name
+
+
 def AddDtbo(output_zip):
   """Adds the DTBO image.
 
@@ -340,29 +358,26 @@
   img.Write()
 
 
-def AppendVBMetaArgsForPartition(cmd, partition, img_path, public_key_dir):
-  if not img_path:
-    return
+def AppendVBMetaArgsForPartition(cmd, partition, image):
+  """Appends the VBMeta arguments for partition.
 
+  It sets up the VBMeta argument by including the partition descriptor from the
+  given 'image', or by configuring the partition as a chained partition.
+
+  Args:
+    cmd: A list of command args that will be used to generate the vbmeta image.
+        The argument for the partition will be appended to the list.
+    partition: The name of the partition (e.g. "system").
+    image: The path to the partition image.
+  """
   # Check if chain partition is used.
   key_path = OPTIONS.info_dict.get("avb_" + partition + "_key_path")
   if key_path:
-    # extract public key in AVB format to be included in vbmeta.img
-    avbtool = os.getenv('AVBTOOL') or OPTIONS.info_dict["avb_avbtool"]
-    public_key_path = os.path.join(public_key_dir, "%s.avbpubkey" % partition)
-    p = common.Run([avbtool, "extract_public_key", "--key", key_path,
-                    "--output", public_key_path],
-                   stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    p.communicate()
-    assert p.returncode == 0, \
-        "avbtool extract_public_key fail for partition: %r" % partition
-
-    rollback_index_location = OPTIONS.info_dict[
-        "avb_" + partition + "_rollback_index_location"]
-    cmd.extend(["--chain_partition", "%s:%s:%s" % (
-        partition, rollback_index_location, public_key_path)])
+    chained_partition_arg = common.GetAvbChainedPartitionArg(
+        partition, OPTIONS.info_dict)
+    cmd.extend(["--chain_partition", chained_partition_arg])
   else:
-    cmd.extend(["--include_descriptors_from_image", img_path])
+    cmd.extend(["--include_descriptors_from_image", image])
 
 
 def AddVBMeta(output_zip, partitions):
@@ -371,8 +386,8 @@
   Args:
     output_zip: The output zip file, which needs to be already open.
     partitions: A dict that's keyed by partition names with image paths as
-        values. Only valid partition names are accepted, which include 'boot',
-        'recovery', 'system', 'vendor', 'dtbo'.
+        values. Only valid partition names are accepted, as listed in
+        common.AVB_PARTITIONS.
   """
   img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vbmeta.img")
   if os.path.exists(img.input_name):
@@ -383,13 +398,12 @@
   cmd = [avbtool, "make_vbmeta_image", "--output", img.name]
   common.AppendAVBSigningArgs(cmd, "vbmeta")
 
-  public_key_dir = common.MakeTempDir(prefix="avbpubkey-")
   for partition, path in partitions.items():
-    assert partition in common.AVB_PARTITIONS, 'Unknown partition: %s' % (
-        partition,)
-    assert os.path.exists(path), 'Failed to find %s for partition %s' % (
-        path, partition)
-    AppendVBMetaArgsForPartition(cmd, partition, path, public_key_dir)
+    assert partition in common.AVB_PARTITIONS, \
+        'Unknown partition: {}'.format(partition)
+    assert os.path.exists(path), \
+        'Failed to find {} for {}'.format(path, partition)
+    AppendVBMetaArgsForPartition(cmd, partition, path)
 
   args = OPTIONS.info_dict.get("avb_vbmeta_args")
   if args and args.strip():
@@ -628,16 +642,22 @@
 
   has_recovery = OPTIONS.info_dict.get("no_recovery") != "true"
 
-  # {vendor,product}.img is unlike system.img or system_other.img. Because it
-  # could be built from source, or dropped into target_files.zip as a prebuilt
-  # blob. We consider either of them as {vendor,product}.img being available,
-  # which could be used when generating vbmeta.img for AVB.
+  # {vendor,product,product-services}.img are unlike system.img or
+  # system_other.img. Because it could be built from source, or dropped into
+  # target_files.zip as a prebuilt blob. We consider either of them as
+  # {vendor,product,product-services}.img being available, which could be
+  # used when generating vbmeta.img for AVB.
   has_vendor = (os.path.isdir(os.path.join(OPTIONS.input_tmp, "VENDOR")) or
                 os.path.exists(os.path.join(OPTIONS.input_tmp, "IMAGES",
                                             "vendor.img")))
   has_product = (os.path.isdir(os.path.join(OPTIONS.input_tmp, "PRODUCT")) or
                  os.path.exists(os.path.join(OPTIONS.input_tmp, "IMAGES",
                                              "product.img")))
+  has_productservices = (os.path.isdir(os.path.join(OPTIONS.input_tmp,
+                                                    "PRODUCTSERVICES")) or
+                         os.path.exists(os.path.join(OPTIONS.input_tmp,
+                                                     "IMAGES",
+                                                     "product-services.img")))
   has_system_other = os.path.isdir(os.path.join(OPTIONS.input_tmp,
                                                 "SYSTEM_OTHER"))
 
@@ -714,6 +734,10 @@
     banner("product")
     partitions['product'] = AddProduct(output_zip)
 
+  if has_productservices:
+    banner("product-services")
+    partitions['product-services'] = AddProductServices(output_zip)
+
   if has_system_other:
     banner("system_other")
     AddSystemOther(output_zip)
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
index e82e66a..c7d93d3 100644
--- a/tools/releasetools/blockimgdiff.py
+++ b/tools/releasetools/blockimgdiff.py
@@ -163,7 +163,7 @@
 
   def RangeSha1(self, ranges):
     h = sha1()
-    for data in self._GetRangeData(ranges):
+    for data in self._GetRangeData(ranges): # pylint: disable=not-an-iterable
       h.update(data)
     return h.hexdigest()
 
@@ -177,7 +177,7 @@
       return sha1(self.data).hexdigest()
 
   def WriteRangeDataToFd(self, ranges, fd):
-    for data in self._GetRangeData(ranges):
+    for data in self._GetRangeData(ranges): # pylint: disable=not-an-iterable
       fd.write(data)
 
 
@@ -320,46 +320,45 @@
       print(''.join(['  {}\n'.format(name) for name in values]))
 
 
-# BlockImageDiff works on two image objects.  An image object is
-# anything that provides the following attributes:
-#
-#    blocksize: the size in bytes of a block, currently must be 4096.
-#
-#    total_blocks: the total size of the partition/image, in blocks.
-#
-#    care_map: a RangeSet containing which blocks (in the range [0,
-#      total_blocks) we actually care about; i.e. which blocks contain
-#      data.
-#
-#    file_map: a dict that partitions the blocks contained in care_map
-#      into smaller domains that are useful for doing diffs on.
-#      (Typically a domain is a file, and the key in file_map is the
-#      pathname.)
-#
-#    clobbered_blocks: a RangeSet containing which blocks contain data
-#      but may be altered by the FS. They need to be excluded when
-#      verifying the partition integrity.
-#
-#    ReadRangeSet(): a function that takes a RangeSet and returns the
-#      data contained in the image blocks of that RangeSet.  The data
-#      is returned as a list or tuple of strings; concatenating the
-#      elements together should produce the requested data.
-#      Implementations are free to break up the data into list/tuple
-#      elements in any way that is convenient.
-#
-#    RangeSha1(): a function that returns (as a hex string) the SHA-1
-#      hash of all the data in the specified range.
-#
-#    TotalSha1(): a function that returns (as a hex string) the SHA-1
-#      hash of all the data in the image (ie, all the blocks in the
-#      care_map minus clobbered_blocks, or including the clobbered
-#      blocks if include_clobbered_blocks is True).
-#
-# When creating a BlockImageDiff, the src image may be None, in which
-# case the list of transfers produced will never read from the
-# original image.
-
 class BlockImageDiff(object):
+  """Generates the diff of two block image objects.
+
+  BlockImageDiff works on two image objects. An image object is anything that
+  provides the following attributes:
+
+     blocksize: the size in bytes of a block, currently must be 4096.
+
+     total_blocks: the total size of the partition/image, in blocks.
+
+     care_map: a RangeSet containing which blocks (in the range [0,
+       total_blocks) we actually care about; i.e. which blocks contain data.
+
+     file_map: a dict that partitions the blocks contained in care_map into
+         smaller domains that are useful for doing diffs on. (Typically a domain
+         is a file, and the key in file_map is the pathname.)
+
+     clobbered_blocks: a RangeSet containing which blocks contain data but may
+         be altered by the FS. They need to be excluded when verifying the
+         partition integrity.
+
+     ReadRangeSet(): a function that takes a RangeSet and returns the data
+         contained in the image blocks of that RangeSet. The data is returned as
+         a list or tuple of strings; concatenating the elements together should
+         produce the requested data. Implementations are free to break up the
+         data into list/tuple elements in any way that is convenient.
+
+     RangeSha1(): a function that returns (as a hex string) the SHA-1 hash of
+         all the data in the specified range.
+
+     TotalSha1(): a function that returns (as a hex string) the SHA-1 hash of
+         all the data in the image (ie, all the blocks in the care_map minus
+         clobbered_blocks, or including the clobbered blocks if
+         include_clobbered_blocks is True).
+
+  When creating a BlockImageDiff, the src image may be None, in which case the
+  list of transfers produced will never read from the original image.
+  """
+
   def __init__(self, tgt, src=None, threads=None, version=4,
                disable_imgdiff=False):
     if threads is None:
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 8e20859..fc3eb2c 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -483,7 +483,7 @@
     True iff the image is built successfully.
   """
   # system_root_image=true: build a system.img that combines the contents of
-  # /system and the ramdisk, and can be mounted at the root of the file system.
+  # /system and root, which should be mounted at the root of the file system.
   origin_in = in_dir
   fs_config = prop_dict.get("fs_config")
   if (prop_dict.get("system_root_image") == "true" and
@@ -492,12 +492,12 @@
     # Change the mount point to "/".
     prop_dict["mount_point"] = "/"
     if fs_config:
-      # We need to merge the fs_config files of system and ramdisk.
-      merged_fs_config = common.MakeTempFile(prefix="root_fs_config",
+      # We need to merge the fs_config files of system and root.
+      merged_fs_config = common.MakeTempFile(prefix="merged_fs_config",
                                              suffix=".txt")
       with open(merged_fs_config, "w") as fw:
-        if "ramdisk_fs_config" in prop_dict:
-          with open(prop_dict["ramdisk_fs_config"]) as fr:
+        if "root_fs_config" in prop_dict:
+          with open(prop_dict["root_fs_config"]) as fr:
             fw.writelines(fr.readlines())
         with open(fs_config) as fr:
           fw.writelines(fr.readlines())
@@ -645,10 +645,10 @@
 
   if in_dir != origin_in:
     # Construct a staging directory of the root file system.
-    ramdisk_dir = prop_dict.get("ramdisk_dir")
-    if ramdisk_dir:
+    root_dir = prop_dict.get("root_dir")
+    if root_dir:
       shutil.rmtree(in_dir)
-      shutil.copytree(ramdisk_dir, in_dir, symlinks=True)
+      shutil.copytree(root_dir, in_dir, symlinks=True)
     staging_system = os.path.join(in_dir, "system")
     shutil.rmtree(staging_system, ignore_errors=True)
     shutil.copytree(origin_in, staging_system, symlinks=True)
@@ -790,8 +790,8 @@
       d["journal_size"] = "0"
     copy_prop("system_verity_block_device", "verity_block_device")
     copy_prop("system_root_image", "system_root_image")
-    copy_prop("ramdisk_dir", "ramdisk_dir")
-    copy_prop("ramdisk_fs_config", "ramdisk_fs_config")
+    copy_prop("root_dir", "root_dir")
+    copy_prop("root_fs_config", "root_fs_config")
     copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
     copy_prop("system_squashfs_compressor", "squashfs_compressor")
     copy_prop("system_squashfs_compressor_opt", "squashfs_compressor_opt")
@@ -875,6 +875,29 @@
     copy_prop("product_extfs_inode_count", "extfs_inode_count")
     if not copy_prop("product_extfs_rsv_pct", "extfs_rsv_pct"):
       d["extfs_rsv_pct"] = "0"
+    copy_prop("product_reserved_size", "partition_reserved_size")
+  elif mount_point == "product-services":
+    copy_prop("avb_productservices_hashtree_enable", "avb_hashtree_enable")
+    copy_prop("avb_productservices_add_hashtree_footer_args",
+              "avb_add_hashtree_footer_args")
+    copy_prop("avb_productservices_key_path", "avb_key_path")
+    copy_prop("avb_productservices_algorithm", "avb_algorithm")
+    copy_prop("productservices_fs_type", "fs_type")
+    copy_prop("productservices_size", "partition_size")
+    if not copy_prop("productservices_journal_size", "journal_size"):
+      d["journal_size"] = "0"
+    copy_prop("productservices_verity_block_device", "verity_block_device")
+    copy_prop("productservices_squashfs_compressor", "squashfs_compressor")
+    copy_prop("productservices_squashfs_compressor_opt",
+              "squashfs_compressor_opt")
+    copy_prop("productservices_squashfs_block_size", "squashfs_block_size")
+    copy_prop("productservices_squashfs_disable_4k_align",
+              "squashfs_disable_4k_align")
+    copy_prop("productservices_base_fs_file", "base_fs_file")
+    copy_prop("productservices_extfs_inode_count", "extfs_inode_count")
+    if not copy_prop("productservices_extfs_rsv_pct", "extfs_rsv_pct"):
+      d["extfs_rsv_pct"] = "0"
+    copy_prop("productservices_reserved_size", "partition_reserved_size")
   elif mount_point == "oem":
     copy_prop("fs_type", "fs_type")
     copy_prop("oem_size", "partition_size")
@@ -914,6 +937,10 @@
     copy_prop("partition_size", "system_size")
   elif mount_point == "vendor":
     copy_prop("partition_size", "vendor_size")
+  elif mount_point == "product":
+    copy_prop("partition_size", "product_size")
+  elif mount_point == "product-services":
+    copy_prop("partition_size", "productservices_size")
   return d
 
 
@@ -955,6 +982,8 @@
       mount_point = "oem"
     elif image_filename == "product.img":
       mount_point = "product"
+    elif image_filename == "product-services.img":
+      mount_point = "product-services"
     else:
       print("error: unknown image file name ", image_filename, file=sys.stderr)
       sys.exit(1)
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 364d6ac..c10e57c 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -44,7 +44,7 @@
         "darwin": "out/host/darwin-x86",
     }
 
-    self.search_path = platform_search_path.get(sys.platform, None)
+    self.search_path = platform_search_path.get(sys.platform)
     self.signapk_path = "framework/signapk.jar"  # Relative to search_path
     self.signapk_shared_library_path = "lib64"   # Relative to search_path
     self.extra_signapk_args = []
@@ -78,7 +78,8 @@
 
 
 # The partitions allowed to be signed by AVB (Android verified boot 2.0).
-AVB_PARTITIONS = ('boot', 'recovery', 'system', 'vendor', 'product', 'dtbo')
+AVB_PARTITIONS = ('boot', 'recovery', 'system', 'vendor', 'product',
+                  'product-services', 'dtbo')
 
 
 class ErrorCode(object):
@@ -195,10 +196,10 @@
     if fc_config:
       d["selinux_fc"] = fc_config
 
-    # Similarly we need to redirect "ramdisk_dir" and "ramdisk_fs_config".
+    # Similarly we need to redirect "root_dir" and "root_fs_config".
     if d.get("system_root_image") == "true":
-      d["ramdisk_dir"] = os.path.join(input_dir, "ROOT")
-      d["ramdisk_fs_config"] = os.path.join(
+      d["root_dir"] = os.path.join(input_dir, "ROOT")
+      d["root_fs_config"] = os.path.join(
           input_dir, "META", "root_filesystem_config.txt")
 
     # Redirect {system,vendor}_base_fs_file.
@@ -236,15 +237,15 @@
   makeint("boot_size")
   makeint("fstab_version")
 
-  system_root_image = d.get("system_root_image", None) == "true"
-  if d.get("no_recovery", None) != "true":
+  system_root_image = d.get("system_root_image") == "true"
+  if d.get("no_recovery") != "true":
     recovery_fstab_path = "RECOVERY/RAMDISK/etc/recovery.fstab"
-    d["fstab"] = LoadRecoveryFSTab(read_helper, d["fstab_version"],
-        recovery_fstab_path, system_root_image)
-  elif d.get("recovery_as_boot", None) == "true":
+    d["fstab"] = LoadRecoveryFSTab(
+        read_helper, d["fstab_version"], recovery_fstab_path, system_root_image)
+  elif d.get("recovery_as_boot") == "true":
     recovery_fstab_path = "BOOT/RAMDISK/etc/recovery.fstab"
-    d["fstab"] = LoadRecoveryFSTab(read_helper, d["fstab_version"],
-        recovery_fstab_path, system_root_image)
+    d["fstab"] = LoadRecoveryFSTab(
+        read_helper, d["fstab_version"], recovery_fstab_path, system_root_image)
   else:
     d["fstab"] = None
 
@@ -370,6 +371,40 @@
     cmd.extend(["--salt", avb_salt])
 
 
+def GetAvbChainedPartitionArg(partition, info_dict, key=None):
+  """Constructs and returns the arg to build or verify a chained partition.
+
+  Args:
+    partition: The partition name.
+    info_dict: The info dict to look up the key info and rollback index
+        location.
+    key: The key to be used for building or verifying the partition. Defaults to
+        the key listed in info_dict.
+
+  Returns:
+    A string of form "partition:rollback_index_location:key" that can be used to
+    build or verify vbmeta image.
+
+  Raises:
+    AssertionError: When it fails to extract the public key with avbtool.
+  """
+  if key is None:
+    key = info_dict["avb_" + partition + "_key_path"]
+  avbtool = os.getenv('AVBTOOL') or info_dict["avb_avbtool"]
+  pubkey_path = MakeTempFile(prefix="avb-", suffix=".pubkey")
+  proc = Run(
+      [avbtool, "extract_public_key", "--key", key, "--output", pubkey_path],
+      stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+  stdoutdata, _ = proc.communicate()
+  assert proc.returncode == 0, \
+      "Failed to extract pubkey for {}:\n{}".format(
+          partition, stdoutdata)
+
+  rollback_index_location = info_dict[
+      "avb_" + partition + "_rollback_index_location"]
+  return "{}:{}:{}".format(partition, rollback_index_location, pubkey_path)
+
+
 def _BuildBootableImage(sourcedir, fs_config_file, info_dict=None,
                         has_ramdisk=False, two_step_image=False):
   """Build a bootable image from the specified sourcedir.
@@ -440,11 +475,11 @@
     cmd.append("--pagesize")
     cmd.append(open(fn).read().rstrip("\n"))
 
-  args = info_dict.get("mkbootimg_args", None)
+  args = info_dict.get("mkbootimg_args")
   if args and args.strip():
     cmd.extend(shlex.split(args))
 
-  args = info_dict.get("mkbootimg_version_args", None)
+  args = info_dict.get("mkbootimg_version_args")
   if args and args.strip():
     cmd.extend(shlex.split(args))
 
@@ -452,7 +487,7 @@
     cmd.extend(["--ramdisk", ramdisk_img.name])
 
   img_unsigned = None
-  if info_dict.get("vboot", None):
+  if info_dict.get("vboot"):
     img_unsigned = tempfile.NamedTemporaryFile()
     cmd.extend(["--output", img_unsigned.name])
   else:
@@ -470,8 +505,8 @@
   p.communicate()
   assert p.returncode == 0, "mkbootimg of %s image failed" % (partition_name,)
 
-  if (info_dict.get("boot_signer", None) == "true" and
-      info_dict.get("verity_key", None)):
+  if (info_dict.get("boot_signer") == "true" and
+      info_dict.get("verity_key")):
     # Hard-code the path as "/boot" for two-step special recovery image (which
     # will be loaded into /boot during the two-step OTA).
     if two_step_image:
@@ -488,7 +523,7 @@
     assert p.returncode == 0, "boot_signer of %s image failed" % path
 
   # Sign the image if vboot is non-empty.
-  elif info_dict.get("vboot", None):
+  elif info_dict.get("vboot"):
     path = "/" + partition_name
     img_keyblock = tempfile.NamedTemporaryFile()
     # We have switched from the prebuilt futility binary to using the tool
@@ -577,9 +612,9 @@
 
 
 def Gunzip(in_filename, out_filename):
-  """Gunzip the given gzip compressed file to a given output file.
-  """
-  with gzip.open(in_filename, "rb") as in_file, open(out_filename, "wb") as out_file:
+  """Gunzips the given gzip compressed file to a given output file."""
+  with gzip.open(in_filename, "rb") as in_file, \
+       open(out_filename, "wb") as out_file:
     shutil.copyfileobj(in_file, out_file)
 
 
@@ -733,7 +768,7 @@
   devnull.close()
 
   key_passwords.update(PasswordManager().GetPasswords(need_passwords))
-  key_passwords.update(dict.fromkeys(no_passwords, None))
+  key_passwords.update(dict.fromkeys(no_passwords))
   return key_passwords
 
 
@@ -798,8 +833,7 @@
 
 
 def SignFile(input_name, output_name, key, password, min_api_level=None,
-    codename_to_api_level_map=dict(),
-    whole_file=False):
+             codename_to_api_level_map=None, whole_file=False):
   """Sign the input_name zip/jar/apk, producing output_name.  Use the
   given key and password (the latter may be None if the key does not
   have a password.
@@ -815,6 +849,8 @@
   codename_to_api_level_map is needed to translate the codename which may be
   encountered as the APK's minSdkVersion.
   """
+  if codename_to_api_level_map is None:
+    codename_to_api_level_map = {}
 
   java_library_path = os.path.join(
       OPTIONS.search_path, OPTIONS.signapk_shared_library_path)
@@ -876,7 +912,7 @@
     device = p.device
     if "/" in device:
       device = device[device.rfind("/")+1:]
-    limit = info_dict.get(device + "_size", None)
+    limit = info_dict.get(device + "_size")
   if not fs_type or not limit:
     return
 
@@ -1106,8 +1142,8 @@
 
 class PasswordManager(object):
   def __init__(self):
-    self.editor = os.getenv("EDITOR", None)
-    self.pwfile = os.getenv("ANDROID_PW_FILE", None)
+    self.editor = os.getenv("EDITOR")
+    self.pwfile = os.getenv("ANDROID_PW_FILE")
 
   def GetPasswords(self, items):
     """Get passwords corresponding to each string in 'items',
@@ -1357,7 +1393,7 @@
     module does not define the function, return the value of the
     'default' kwarg (which itself defaults to None)."""
     if self.module is None or not hasattr(self.module, function_name):
-      return kwargs.get("default", None)
+      return kwargs.get("default")
     return getattr(self.module, function_name)(*((self,) + args), **kwargs)
 
   def FullOTA_Assertions(self):
@@ -1407,8 +1443,9 @@
   def VerifyOTA_Assertions(self):
     return self._DoCall("VerifyOTA_Assertions")
 
+
 class File(object):
-  def __init__(self, name, data, compress_size = None):
+  def __init__(self, name, data, compress_size=None):
     self.name = name
     self.data = data
     self.size = len(data)
@@ -1435,6 +1472,7 @@
   def AddToZip(self, z, compression=None):
     ZipWriteStr(z, self.name, self.data, compress_type=compression)
 
+
 DIFF_PROGRAM_BY_EXT = {
     ".gz" : "imgdiff",
     ".zip" : ["imgdiff", "-z"],
@@ -1443,6 +1481,7 @@
     ".img" : "imgdiff",
     }
 
+
 class Difference(object):
   def __init__(self, tf, sf, diff_program=None):
     self.tf = tf
@@ -1510,9 +1549,11 @@
 
 
   def GetPatch(self):
-    """Return a tuple (target_file, source_file, patch_data).
+    """Returns a tuple of (target_file, source_file, patch_data).
+
     patch_data may be None if ComputePatch hasn't been called, or if
-    computing the patch failed."""
+    computing the patch failed.
+    """
     return self.tf, self.sf, self.patch
 
 
@@ -1544,7 +1585,8 @@
         else:
           name = "%s (%s)" % (tf.name, sf.name)
         if patch is None:
-          print("patching failed!                                  %s" % (name,))
+          print(
+              "patching failed!                                  %s" % (name,))
         else:
           print("%8.2f sec %8d / %8d bytes (%6.2f%%) %s" % (
               dur, len(patch), tf.size, 100.0 * len(patch) / tf.size, name))
@@ -1597,7 +1639,8 @@
   def required_cache(self):
     return self._required_cache
 
-  def WriteScript(self, script, output_zip, progress=None):
+  def WriteScript(self, script, output_zip, progress=None,
+                  write_verify_script=False):
     if not self.src:
       # write the output unconditionally
       script.Print("Patching %s image unconditionally..." % (self.partition,))
@@ -1607,7 +1650,8 @@
     if progress:
       script.ShowProgress(progress, 0)
     self._WriteUpdate(script, output_zip)
-    if OPTIONS.verify:
+
+    if write_verify_script:
       self._WritePostInstallVerifyScript(script)
 
   def WriteStrictVerifyScript(self, script):
@@ -1621,12 +1665,12 @@
     script.Print("Verifying %s..." % (partition,))
     ranges = self.tgt.care_map
     ranges_str = ranges.to_string_raw()
-    script.AppendExtra('range_sha1("%s", "%s") == "%s" && '
-                       'ui_print("    Verified.") || '
-                       'ui_print("\\"%s\\" has unexpected contents.");' % (
-                       self.device, ranges_str,
-                       self.tgt.TotalSha1(include_clobbered_blocks=True),
-                       self.device))
+    script.AppendExtra(
+        'range_sha1("%s", "%s") == "%s" && ui_print("    Verified.") || '
+        'ui_print("\\"%s\\" has unexpected contents.");' % (
+            self.device, ranges_str,
+            self.tgt.TotalSha1(include_clobbered_blocks=True),
+            self.device))
     script.AppendExtra("")
 
   def WriteVerifyScript(self, script, touched_blocks_only=False):
@@ -1650,12 +1694,12 @@
         return
 
       ranges_str = ranges.to_string_raw()
-      script.AppendExtra(('if (range_sha1("%s", "%s") == "%s" || '
-                          'block_image_verify("%s", '
-                          'package_extract_file("%s.transfer.list"), '
-                          '"%s.new.dat", "%s.patch.dat")) then') % (
-                          self.device, ranges_str, expected_sha1,
-                          self.device, partition, partition, partition))
+      script.AppendExtra(
+          'if (range_sha1("%s", "%s") == "%s" || block_image_verify("%s", '
+          'package_extract_file("%s.transfer.list"), "%s.new.dat", '
+          '"%s.patch.dat")) then' % (
+              self.device, ranges_str, expected_sha1,
+              self.device, partition, partition, partition))
       script.Print('Verified %s image...' % (partition,))
       script.AppendExtra('else')
 
@@ -1705,17 +1749,19 @@
     # Unlike pre-install verification, clobbered_blocks should not be ignored.
     ranges = self.tgt.care_map
     ranges_str = ranges.to_string_raw()
-    script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % (
-                       self.device, ranges_str,
-                       self.tgt.TotalSha1(include_clobbered_blocks=True)))
+    script.AppendExtra(
+        'if range_sha1("%s", "%s") == "%s" then' % (
+            self.device, ranges_str,
+            self.tgt.TotalSha1(include_clobbered_blocks=True)))
 
     # Bug: 20881595
     # Verify that extended blocks are really zeroed out.
     if self.tgt.extended:
       ranges_str = self.tgt.extended.to_string_raw()
-      script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % (
-                         self.device, ranges_str,
-                         self._HashZeroBlocks(self.tgt.extended.size())))
+      script.AppendExtra(
+          'if range_sha1("%s", "%s") == "%s" then' % (
+              self.device, ranges_str,
+              self._HashZeroBlocks(self.tgt.extended.size())))
       script.Print('Verified the updated %s image.' % (partition,))
       if partition == "system":
         code = ErrorCode.SYSTEM_NONZERO_CONTENTS
@@ -1745,9 +1791,9 @@
              '{}.transfer.list'.format(self.path),
              '{}.transfer.list'.format(self.partition))
 
-    # For full OTA, compress the new.dat with brotli with quality 6 to reduce its size. Quailty 9
-    # almost triples the compression time but doesn't further reduce the size too much.
-    # For a typical 1.8G system.new.dat
+    # For full OTA, compress the new.dat with brotli with quality 6 to reduce
+    # its size. Quailty 9 almost triples the compression time but doesn't
+    # further reduce the size too much. For a typical 1.8G system.new.dat
     #                       zip  | brotli(quality 6)  | brotli(quality 9)
     #   compressed_size:    942M | 869M (~8% reduced) | 854M
     #   compression_time:   75s  | 265s               | 719s
@@ -1812,6 +1858,7 @@
 
 DataImage = blockimgdiff.DataImage
 
+
 # map recovery.fstab's fs_types to mount/format "partition types"
 PARTITION_TYPES = {
     "ext4": "EMMC",
@@ -1820,6 +1867,7 @@
     "squashfs": "EMMC"
 }
 
+
 def GetTypeAndDevice(mount_point, info):
   fstab = info["fstab"]
   if fstab:
@@ -1914,7 +1962,7 @@
       if os.path.exists(path):
         diff_program.append("-b")
         diff_program.append(path)
-        bonus_args = "-b /system/etc/recovery-resource.dat"
+        bonus_args = "--bonus /system/etc/recovery-resource.dat"
       else:
         bonus_args = ""
 
@@ -1932,8 +1980,12 @@
 
   if full_recovery_image:
     sh = """#!/system/bin/sh
-if ! applypatch -c %(type)s:%(device)s:%(size)d:%(sha1)s; then
-  applypatch /system/etc/recovery.img %(type)s:%(device)s %(sha1)s %(size)d && log -t recovery "Installing new recovery image: succeeded" || log -t recovery "Installing new recovery image: failed"
+if ! applypatch --check %(type)s:%(device)s:%(size)d:%(sha1)s; then
+  applypatch \\
+          --flash /system/etc/recovery.img \\
+          --target %(type)s:%(device)s:%(size)d:%(sha1)s && \\
+      log -t recovery "Installing new recovery image: succeeded" || \\
+      log -t recovery "Installing new recovery image: failed"
 else
   log -t recovery "Recovery image already installed"
 fi
@@ -1943,8 +1995,13 @@
        'size': recovery_img.size}
   else:
     sh = """#!/system/bin/sh
-if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
-  applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p && log -t recovery "Installing new recovery image: succeeded" || log -t recovery "Installing new recovery image: failed"
+if ! applypatch --check %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
+  applypatch %(bonus_args)s \\
+          --patch /system/recovery-from-boot.p \\
+          --source %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s \\
+          --target %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s && \\
+      log -t recovery "Installing new recovery image: succeeded" || \\
+      log -t recovery "Installing new recovery image: failed"
 else
   log -t recovery "Recovery image already installed"
 fi
diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py
index 5c3533e..3595a9e 100644
--- a/tools/releasetools/edify_generator.py
+++ b/tools/releasetools/edify_generator.py
@@ -132,8 +132,8 @@
     self.script.append(
         ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || '
          'abort("E%d: Can\'t install this package (%s) over newer '
-         'build (" + getprop("ro.build.date") + ").");') % (timestamp,
-             common.ErrorCode.OLDER_BUILD, timestamp_text))
+         'build (" + getprop("ro.build.date") + ").");') % (
+             timestamp, common.ErrorCode.OLDER_BUILD, timestamp_text))
 
   def AssertDevice(self, device):
     """Assert that the device identifier is the given string."""
@@ -260,8 +260,8 @@
       cmd.append(',\0%s,\0package_extract_file("%s")' % patchpairs[i:i+2])
     cmd.append(') ||\n    abort("E%d: Failed to apply patch to %s");' % (
         common.ErrorCode.APPLY_PATCH_FAILURE, srcfile))
-    cmd = "".join(cmd)
-    self.script.append(self.WordWrap(cmd))
+    cmd_str = "".join(cmd)
+    self.script.append(self.WordWrap(cmd_str))
 
   def WriteRawImage(self, mount_point, fn, mapfn=None):
     """Write the given package file into the partition for the given
diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
index e6e8c9f..01ff149 100755
--- a/tools/releasetools/img_from_target_files.py
+++ b/tools/releasetools/img_from_target_files.py
@@ -28,17 +28,17 @@
 
 from __future__ import print_function
 
+import os
+import shutil
 import sys
+import zipfile
+
+import common
 
 if sys.hexversion < 0x02070000:
   print("Python 2.7 or newer is required.", file=sys.stderr)
   sys.exit(1)
 
-import os
-import shutil
-import zipfile
-
-import common
 
 OPTIONS = common.OPTIONS
 
@@ -51,11 +51,12 @@
 
 
 def main(argv):
-  bootable_only = [False]
+  # This allows modifying the value from inner function.
+  bootable_only_array = [False]
 
   def option_handler(o, _):
     if o in ("-z", "--bootable_zip"):
-      bootable_only[0] = True
+      bootable_only_array[0] = True
     else:
       return False
     return True
@@ -65,7 +66,7 @@
                              extra_long_opts=["bootable_zip"],
                              extra_option_handler=option_handler)
 
-  bootable_only = bootable_only[0]
+  bootable_only = bootable_only_array[0]
 
   if len(args) != 2:
     common.Usage(__doc__)
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 26d4187..8cfe4c3 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -697,17 +697,11 @@
   if not HasTrebleEnabled(target_zip, target_info):
     return
 
-  # We don't support OEM thumbprint in Treble world (which calculates
-  # fingerprints in a different way as shown in CalculateFingerprint()).
-  assert not target_info.oem_props
-
   # Full OTA carries the info for system/vendor both.
   if source_info is None:
     AddCompatibilityArchive(True, True)
     return
 
-  assert not source_info.oem_props
-
   source_fp = source_info.fingerprint
   target_fp = target_info.fingerprint
   system_updated = source_fp != target_fp
@@ -833,7 +827,8 @@
                                      allow_shared_blocks)
   system_tgt.ResetFileMap()
   system_diff = common.BlockDifference("system", system_tgt, src=None)
-  system_diff.WriteScript(script, output_zip)
+  system_diff.WriteScript(script, output_zip,
+                          write_verify_script=OPTIONS.verify)
 
   boot_img = common.GetBootableImage(
       "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
@@ -845,7 +840,8 @@
                                        allow_shared_blocks)
     vendor_tgt.ResetFileMap()
     vendor_diff = common.BlockDifference("vendor", vendor_tgt)
-    vendor_diff.WriteScript(script, output_zip)
+    vendor_diff.WriteScript(script, output_zip,
+                            write_verify_script=OPTIONS.verify)
 
   AddCompatibilityArchiveIfTrebleEnabled(input_zip, output_zip, target_info)
 
@@ -1565,10 +1561,12 @@
   device_specific.IncrementalOTA_InstallBegin()
 
   system_diff.WriteScript(script, output_zip,
-                          progress=0.8 if vendor_diff else 0.9)
+                          progress=0.8 if vendor_diff else 0.9,
+                          write_verify_script=OPTIONS.verify)
 
   if vendor_diff:
-    vendor_diff.WriteScript(script, output_zip, progress=0.1)
+    vendor_diff.WriteScript(script, output_zip, progress=0.1,
+                            write_verify_script=OPTIONS.verify)
 
   if OPTIONS.two_step:
     common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
diff --git a/tools/releasetools/pylintrc b/tools/releasetools/pylintrc
index 7b3405c..2a30742 100644
--- a/tools/releasetools/pylintrc
+++ b/tools/releasetools/pylintrc
@@ -62,7 +62,7 @@
 # --enable=similarities". If you want to run only the classes checker, but have
 # no Warning level messages displayed, use"--disable=all --enable=classes
 # --disable=W"
-disable=invalid-name,missing-docstring,too-many-branches,too-many-locals,too-many-arguments,too-many-statements,duplicate-code,too-few-public-methods,too-many-instance-attributes,too-many-lines,too-many-public-methods,locally-disabled,fixme
+disable=invalid-name,missing-docstring,too-many-branches,too-many-locals,too-many-arguments,too-many-statements,duplicate-code,too-few-public-methods,too-many-instance-attributes,too-many-lines,too-many-public-methods,locally-disabled,fixme,not-callable
 
 
 [REPORTS]
diff --git a/tools/releasetools/test_add_img_to_target_files.py b/tools/releasetools/test_add_img_to_target_files.py
index a9c7f7c..3f2e5ea 100644
--- a/tools/releasetools/test_add_img_to_target_files.py
+++ b/tools/releasetools/test_add_img_to_target_files.py
@@ -22,7 +22,8 @@
 import common
 import test_utils
 from add_img_to_target_files import (
-    AddCareMapTxtForAbOta, AddPackRadioImages, CheckAbOtaImages, GetCareMap)
+    AddCareMapTxtForAbOta, AddPackRadioImages, AppendVBMetaArgsForPartition,
+    CheckAbOtaImages, GetCareMap)
 from rangelib import RangeSet
 
 
@@ -264,6 +265,31 @@
     # The existing entry should be scheduled to be replaced.
     self.assertIn('META/care_map.txt', OPTIONS.replace_updated_files_list)
 
+  def test_AppendVBMetaArgsForPartition(self):
+    OPTIONS.info_dict = {}
+    cmd = []
+    AppendVBMetaArgsForPartition(cmd, 'system', '/path/to/system.img')
+    self.assertEqual(
+        ['--include_descriptors_from_image', '/path/to/system.img'], cmd)
+
+  def test_AppendVBMetaArgsForPartition_vendorAsChainedPartition(self):
+    testdata_dir = test_utils.get_testdata_dir()
+    pubkey = os.path.join(testdata_dir, 'testkey.pubkey.pem')
+    OPTIONS.info_dict = {
+        'avb_avbtool': 'avbtool',
+        'avb_vendor_key_path': pubkey,
+        'avb_vendor_rollback_index_location': 5,
+    }
+    cmd = []
+    AppendVBMetaArgsForPartition(cmd, 'vendor', '/path/to/vendor.img')
+    self.assertEqual(2, len(cmd))
+    self.assertEqual('--chain_partition', cmd[0])
+    chained_partition_args = cmd[1].split(':')
+    self.assertEqual(3, len(chained_partition_args))
+    self.assertEqual('vendor', chained_partition_args[0])
+    self.assertEqual('5', chained_partition_args[1])
+    self.assertTrue(os.path.exists(chained_partition_args[2]))
+
   def test_GetCareMap(self):
     sparse_image = test_utils.construct_sparse_image([
         (0xCAC1, 6),
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index 1c75d19..2a28db4 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -524,6 +524,9 @@
 
 class CommonUtilsTest(unittest.TestCase):
 
+  def setUp(self):
+    self.testdata_dir = test_utils.get_testdata_dir()
+
   def tearDown(self):
     common.Cleanup()
 
@@ -730,6 +733,56 @@
           AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
           False)
 
+  def test_GetAvbChainedPartitionArg(self):
+    pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
+    info_dict = {
+        'avb_avbtool': 'avbtool',
+        'avb_system_key_path': pubkey,
+        'avb_system_rollback_index_location': 2,
+    }
+    args = common.GetAvbChainedPartitionArg('system', info_dict).split(':')
+    self.assertEqual(3, len(args))
+    self.assertEqual('system', args[0])
+    self.assertEqual('2', args[1])
+    self.assertTrue(os.path.exists(args[2]))
+
+  def test_GetAvbChainedPartitionArg_withPrivateKey(self):
+    key = os.path.join(self.testdata_dir, 'testkey.key')
+    info_dict = {
+        'avb_avbtool': 'avbtool',
+        'avb_product_key_path': key,
+        'avb_product_rollback_index_location': 2,
+    }
+    args = common.GetAvbChainedPartitionArg('product', info_dict).split(':')
+    self.assertEqual(3, len(args))
+    self.assertEqual('product', args[0])
+    self.assertEqual('2', args[1])
+    self.assertTrue(os.path.exists(args[2]))
+
+  def test_GetAvbChainedPartitionArg_withSpecifiedKey(self):
+    info_dict = {
+        'avb_avbtool': 'avbtool',
+        'avb_system_key_path': 'does-not-exist',
+        'avb_system_rollback_index_location': 2,
+    }
+    pubkey = os.path.join(self.testdata_dir, 'testkey.pubkey.pem')
+    args = common.GetAvbChainedPartitionArg(
+        'system', info_dict, pubkey).split(':')
+    self.assertEqual(3, len(args))
+    self.assertEqual('system', args[0])
+    self.assertEqual('2', args[1])
+    self.assertTrue(os.path.exists(args[2]))
+
+  def test_GetAvbChainedPartitionArg_invalidKey(self):
+    pubkey = os.path.join(self.testdata_dir, 'testkey_with_passwd.x509.pem')
+    info_dict = {
+        'avb_avbtool': 'avbtool',
+        'avb_system_key_path': pubkey,
+        'avb_system_rollback_index_location': 2,
+    }
+    self.assertRaises(
+        AssertionError, common.GetAvbChainedPartitionArg, 'system', info_dict)
+
 
 class InstallRecoveryScriptFormatTest(unittest.TestCase):
   """Checks the format of install-recovery.sh.
diff --git a/tools/releasetools/testdata/testkey.key b/tools/releasetools/testdata/testkey.key
new file mode 100644
index 0000000..3a84607
--- /dev/null
+++ b/tools/releasetools/testdata/testkey.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+O/I7YvBaCZA3
+KrvP7ErTh6DS3cAvjLY2GkAA7NWcXIICsVwWMtMZAMO+Rtk/o3XY7r53Amg8ue2e
+b0D5Wc8gUVEeDQdRZJscz5CTwmC/b/YBWQBSPknWv23hf7ZYjR5HMk/XlmOfrylA
+oaZzJyKvLSBu+Zi9cvZlSZObnoOYR8JQJEhjYgYn8JwycV4i1VTQvEqxXkyW3kE7
+RW/8JXgRqI4vDIKehm5SFi2jt0eU7/ju/8f3OGQkLng4DV2QPfwQ+A7kad+EYVI1
+dBGYkNNesWB3o75A7jJQ1fyVg/XQzOKZSki1lrTm3rw0AOrBiXdPudbO+4L2vgip
+kPI9/bVNAgMBAAECggEABGjBSY0Wgw+7rvunlL8mUNbQ7HJFVRTO2FwtZZgXr2MZ
+hFR2DPGqoOa6ortjp6zzO071TS7aGaY5krWDbQQe3+Hinm6w37sUOUu6TyJvOaCv
+tAJLFpzo+zg+pL5gDJdgv0e0QAv1TSszKpNUl1Ct5h+Go+vXFXUHrvtQl4fKBwqA
+efxcd3R4z3p/3Cl2ZYIRz9I7UXUZZYwJE7bDNDz3aFZ1jUoELGmhe1O5w0hJY1q6
+PxuOM9bL60yDn0vu0eiCjaPlHeHyGe9pQ1aQLEuwQz9zpWC01dWPVkLmny7HDygC
+VBsdg8MNlzJQ1WV2en11BH72IqZ59U8pD0xEB7a4BQKBgQDxenfXyYZw4AKcaJlP
+ncJmsx/wcgEvWNxiI4etArXES4VIyP2OlSw+q9JbOOpaSk8TJP5PNfUkgTbC4B2y
+gh/AobJP5b7Wn5LrsHc3GY6CzF1i8T4xXQRxnaKWE86SOmZQlEmyCnpyCmfFVuaR
+E8p8CPW/gQLhpxSlQdGZ0bYLiwKBgQDJrJRDdyaI/Isusog/OwKHVGBU6CmRa5tM
+gx+GIlxheqhuDqnBkr0h1kL20Zi80JeG7vKWr+dwfqkEarfdTe+juwlIuQ3MEuXL
+AbsKNuaU1naOqOLm9rjZgRtR7oNLVH5AbkKMaJz1zM6YiMl54FEDX7ZVY8b6q1Kz
+YXT3sGi9hwKBgBsNa0ujagpPLjuzhCllNRgoTRW0z+kr/VSJQnPhb9eT1lS3H6DP
+mWtT+Hb7w1VmKcGtTUg2dUYnq6jdTrZm2YPNGZrV1DFbIyyAUnq7xDlnB7dD64HA
+N/U6gbJqeaPsIvY4BqGJhvorrEBxYdcy7mZC4rUXkOkSvL9exkqDMe/NAoGARaHU
+v0aQg5PO6pyx9kMFqHw1lptiXtdsk4pihAmxI+cZ6IYfjrp/mwNDs7zCo87RwsEV
++Xlay7iv2tqOCVczerDFj9p1LRUJSoKadfhmvNUfsjoVvfFJ+a9eI3fa1VOjE9P+
+HkSwjR3d50Sza+VLk4Kkje8ZcMtejpkDrdG3GFkCgYBXHqciwlFn5nMPFRe8v426
+6YBiUtzCQCZxDtMeeZYCJslFfjrqPXNUcU/flxWwaikjFsLJEtl7aT3Hpdi5I7T8
+yCYkUWqAAh7twEYTOeG6v/tEa/PmsBjZXPD2zkCp76EQmv3gbvsH4F/nA55gT/GR
+2in6XS/4rHBvjn5gF6MFyg==
+-----END PRIVATE KEY-----
diff --git a/tools/releasetools/validate_target_files.py b/tools/releasetools/validate_target_files.py
index 886de26..09f800f 100755
--- a/tools/releasetools/validate_target_files.py
+++ b/tools/releasetools/validate_target_files.py
@@ -131,14 +131,18 @@
 
   1. full recovery:
   ...
-  if ! applypatch -c type:device:size:SHA-1; then
-  applypatch /system/etc/recovery.img type:device sha1 size && ...
+  if ! applypatch --check type:device:size:sha1; then
+    applypatch --flash /system/etc/recovery.img \\
+        type:device:size:sha1 && \\
   ...
 
   2. recovery from boot:
   ...
-  applypatch [-b bonus_args] boot_info recovery_info recovery_sha1 \
-  recovery_size patch_info && ...
+  if ! applypatch --check type:recovery_device:recovery_size:recovery_sha1; then
+    applypatch [--bonus bonus_args] \\
+        --patch /system/recovery-from-boot.p \\
+        --source type:boot_device:boot_size:boot_sha1 \\
+        --target type:recovery_device:recovery_size:recovery_sha1 && \\
   ...
 
   For full recovery, we want to calculate the SHA-1 of /system/etc/recovery.img
@@ -155,44 +159,63 @@
   logging.info('Checking %s', script_path)
   with open(os.path.join(input_tmp, script_path), 'r') as script:
     lines = script.read().strip().split('\n')
-  assert len(lines) >= 6
-  check_cmd = re.search(r'if ! applypatch -c \w+:.+:\w+:(\w+);',
+  assert len(lines) >= 10
+  check_cmd = re.search(r'if ! applypatch --check (\w+:.+:\w+:\w+);',
                         lines[1].strip())
-  expected_recovery_check_sha1 = check_cmd.group(1)
-  patch_cmd = re.search(r'(applypatch.+)&&', lines[2].strip())
-  applypatch_argv = patch_cmd.group(1).strip().split()
+  check_partition = check_cmd.group(1)
+  assert len(check_partition.split(':')) == 4
 
   full_recovery_image = info_dict.get("full_recovery_image") == "true"
   if full_recovery_image:
-    assert len(applypatch_argv) == 5
-    # Check we have the same expected SHA-1 of recovery.img in both check mode
-    # and patch mode.
-    expected_recovery_sha1 = applypatch_argv[3].strip()
-    assert expected_recovery_check_sha1 == expected_recovery_sha1
-    ValidateFileAgainstSha1(input_tmp, 'recovery.img',
-                            'SYSTEM/etc/recovery.img', expected_recovery_sha1)
-  else:
-    # We're patching boot.img to get recovery.img where bonus_args is optional
-    if applypatch_argv[1] == "-b":
-      assert len(applypatch_argv) == 8
-      boot_info_index = 3
-    else:
-      assert len(applypatch_argv) == 6
-      boot_info_index = 1
+    assert len(lines) == 10, "Invalid line count: {}".format(lines)
 
-    # boot_info: boot_type:boot_device:boot_size:boot_sha1
-    boot_info = applypatch_argv[boot_info_index].strip().split(':')
-    assert len(boot_info) == 4
+    # Expect something like "EMMC:/dev/block/recovery:28:5f9c..62e3".
+    target = re.search(r'--target (.+) &&', lines[4].strip())
+    assert target is not None, \
+        "Failed to parse target line \"{}\"".format(lines[4])
+    flash_partition = target.group(1)
+
+    # Check we have the same recovery target in the check and flash commands.
+    assert check_partition == flash_partition, \
+        "Mismatching targets: {} vs {}".format(check_partition, flash_partition)
+
+    # Validate the SHA-1 of the recovery image.
+    recovery_sha1 = flash_partition.split(':')[3]
+    ValidateFileAgainstSha1(
+        input_tmp, 'recovery.img', 'SYSTEM/etc/recovery.img', recovery_sha1)
+  else:
+    assert len(lines) == 11, "Invalid line count: {}".format(lines)
+
+    # --source boot_type:boot_device:boot_size:boot_sha1
+    source = re.search(r'--source (\w+:.+:\w+:\w+) \\', lines[4].strip())
+    assert source is not None, \
+        "Failed to parse source line \"{}\"".format(lines[4])
+
+    source_partition = source.group(1)
+    source_info = source_partition.split(':')
+    assert len(source_info) == 4, \
+        "Invalid source partition: {}".format(source_partition)
     ValidateFileAgainstSha1(input_tmp, file_name='boot.img',
                             file_path='IMAGES/boot.img',
-                            expected_sha1=boot_info[3])
+                            expected_sha1=source_info[3])
 
-    recovery_sha1_index = boot_info_index + 2
-    expected_recovery_sha1 = applypatch_argv[recovery_sha1_index]
-    assert expected_recovery_check_sha1 == expected_recovery_sha1
+    # --target recovery_type:recovery_device:recovery_size:recovery_sha1
+    target = re.search(r'--target (\w+:.+:\w+:\w+) && \\', lines[5].strip())
+    assert target is not None, \
+        "Failed to parse target line \"{}\"".format(lines[5])
+    target_partition = target.group(1)
+
+    # Check we have the same recovery target in the check and patch commands.
+    assert check_partition == target_partition, \
+        "Mismatching targets: {} vs {}".format(
+            check_partition, target_partition)
+
+    recovery_info = target_partition.split(':')
+    assert len(recovery_info) == 4, \
+        "Invalid target partition: {}".format(target_partition)
     ValidateFileAgainstSha1(input_tmp, file_name='recovery.img',
                             file_path='IMAGES/recovery.img',
-                            expected_sha1=expected_recovery_sha1)
+                            expected_sha1=recovery_info[3])
 
   logging.info('Done checking %s', script_path)
 
@@ -292,9 +315,19 @@
     key = options['verity_key']
     if key is None:
       key = info_dict['avb_vbmeta_key_path']
+
     # avbtool verifies all the images that have descriptors listed in vbmeta.
     image = os.path.join(input_tmp, 'IMAGES', 'vbmeta.img')
     cmd = ['avbtool', 'verify_image', '--image', image, '--key', key]
+
+    # Append the args for chained partitions if any.
+    for partition in common.AVB_PARTITIONS:
+      key_name = 'avb_' + partition + '_key_path'
+      if info_dict.get(key_name) is not None:
+        chained_partition_arg = common.GetAvbChainedPartitionArg(
+            partition, info_dict, options[key_name])
+        cmd.extend(["--expected_chain_partition", chained_partition_arg])
+
     proc = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     stdoutdata, _ = proc.communicate()
     assert proc.returncode == 0, \
@@ -316,8 +349,13 @@
   parser.add_argument(
       '--verity_key',
       help='the verity public key to verify the bootable images (Verified '
-           'Boot 1.0), or the vbmeta image (Verified Boot 2.0), where '
+           'Boot 1.0), or the vbmeta image (Verified Boot 2.0, aka AVB), where '
            'applicable')
+  for partition in common.AVB_PARTITIONS:
+    parser.add_argument(
+        '--avb_' + partition + '_key_path',
+        help='the public or private key in PEM format to verify AVB chained '
+             'partition of {}'.format(partition))
   parser.add_argument(
       '--verity_key_mincrypt',
       help='the verity public key in mincrypt format to verify the system '
diff --git a/tools/warn.py b/tools/warn.py
index 89f4778..4596307 100755
--- a/tools/warn.py
+++ b/tools/warn.py
@@ -75,6 +75,7 @@
 #   emit_js_data():
 
 import argparse
+import cgi
 import csv
 import multiprocessing
 import os
@@ -3149,6 +3150,14 @@
   print '];'
 
 
+# Emit a JavaScript const string array for HTML.
+def emit_const_html_string_array(name, array):
+  print 'const ' + name + ' = ['
+  for s in array:
+    print '"' + cgi.escape(strip_escape_string(s)) + '",'
+  print '];'
+
+
 # Emit a JavaScript const object array.
 def emit_const_object_array(name, array):
   print 'const ' + name + ' = ['
@@ -3167,11 +3176,11 @@
   emit_const_string_array('ProjectNames', project_names)
   emit_const_int_array('WarnPatternsSeverity',
                        [w['severity'] for w in warn_patterns])
-  emit_const_string_array('WarnPatternsDescription',
-                          [w['description'] for w in warn_patterns])
-  emit_const_string_array('WarnPatternsOption',
-                          [w['option'] for w in warn_patterns])
-  emit_const_string_array('WarningMessages', warning_messages)
+  emit_const_html_string_array('WarnPatternsDescription',
+                               [w['description'] for w in warn_patterns])
+  emit_const_html_string_array('WarnPatternsOption',
+                               [w['option'] for w in warn_patterns])
+  emit_const_html_string_array('WarningMessages', warning_messages)
   emit_const_object_array('Warnings', warning_records)
 
 draw_table_javascript = """