Merge "Fix zsh compatibility issue in build/envsetup.sh"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index ddee654..4e06d80 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -673,6 +673,11 @@
 $(call add-clean-step, rm -rf $(HOST_OUT)/fuzz/*)
 $(call add-clean-step, rm -rf $(SOONG_OUT_DIR)/host/*/fuzz/*)
 
+# Change file layout of system_other
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system_other)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/apex)
+
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/core/Makefile b/core/Makefile
index 951761c..c9b478e 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1924,7 +1924,8 @@
 ifeq (,$(filter true, $(BOARD_USES_FULL_RECOVERY_IMAGE) $(BOARD_USES_RECOVERY_AS_BOOT) \
   $(BOARD_BUILD_SYSTEM_ROOT_IMAGE) $(BOARD_INCLUDE_RECOVERY_DTBO) $(BOARD_INCLUDE_RECOVERY_ACPIO)))
 # Named '.dat' so we don't attempt to use imgdiff for patching it.
-RECOVERY_RESOURCE_ZIP := $(TARGET_OUT)/etc/recovery-resource.dat
+RECOVERY_RESOURCE_ZIP := $(TARGET_OUT_VENDOR)/etc/recovery-resource.dat
+ALL_DEFAULT_INSTALLED_MODULES += $(RECOVERY_RESOURCE_ZIP)
 else
 RECOVERY_RESOURCE_ZIP :=
 endif
@@ -2294,8 +2295,7 @@
 INTERNAL_SYSTEMIMAGE_FILES := $(sort $(filter $(TARGET_OUT)/%, \
     $(ALL_GENERATED_SOURCES) \
     $(ALL_DEFAULT_INSTALLED_MODULES) \
-    $(PDK_FUSION_SYSIMG_FILES) \
-    $(RECOVERY_RESOURCE_ZIP)) \
+    $(PDK_FUSION_SYSIMG_FILES)) \
     $(PDK_FUSION_SYMLINK_STAMP))
 
 FULL_SYSTEMIMAGE_DEPS := $(INTERNAL_SYSTEMIMAGE_FILES) $(INTERNAL_USERIMAGES_DEPS)
@@ -3893,6 +3893,9 @@
 ifeq ($(BOARD_USES_FULL_RECOVERY_IMAGE),true)
 	$(hide) echo "full_recovery_image=true" >> $@
 endif
+ifdef BOARD_USES_VENDORIMAGE
+	$(hide) echo "board_uses_vendorimage=true" >> $@
+endif
 ifeq ($(BOARD_AVB_ENABLE),true)
 	$(hide) echo "avb_enable=true" >> $@
 	$(hide) echo "avb_vbmeta_key_path=$(BOARD_AVB_KEY_PATH)" >> $@
@@ -4032,6 +4035,18 @@
     $(BUILT_TARGET_FILES_PACKAGE): $(TARGET_OUT_OEM)/$(OSRELEASED_DIRECTORY)/product_version
     $(BUILT_TARGET_FILES_PACKAGE): $(TARGET_OUT_ETC)/$(OSRELEASED_DIRECTORY)/system_version
   endif
+
+  # Not checking in board_config.mk, since AB_OTA_PARTITIONS may be updated in Android.mk (e.g. to
+  # additionally include radio or bootloader partitions).
+  ifeq ($(AB_OTA_PARTITIONS),)
+    $(error AB_OTA_PARTITIONS must be defined when using AB_OTA_UPDATER)
+  endif
+endif
+
+ifneq ($(AB_OTA_PARTITIONS),)
+  ifneq ($(AB_OTA_UPDATER),true)
+    $(error AB_OTA_UPDATER must be true when defining AB_OTA_PARTITIONS)
+  endif
 endif
 
 # Run fs_config while creating the target files package
@@ -4299,10 +4314,8 @@
 	  $(zip_root)/META/$(notdir $(PRODUCT_ODM_BASE_FS_PATH))
 endif
 ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
-ifdef BUILDING_SYSTEM_IMAGE
 	$(hide) PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH MKBOOTIMG=$(MKBOOTIMG) \
 	    $(MAKE_RECOVERY_PATCH) $(zip_root) $(zip_root)
-endif # BUILDING_SYSTEM_IMAGE
 endif
 ifeq ($(AB_OTA_UPDATER),true)
 	@# When using the A/B updater, include the updater config files in the zip.
diff --git a/core/board_config.mk b/core/board_config.mk
index 242012f..3127c19 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -86,6 +86,7 @@
 
 _build_broken_var_list := \
   BUILD_BROKEN_DUP_RULES \
+  BUILD_BROKEN_PREBUILT_ELF_FILES \
   BUILD_BROKEN_USES_NETWORK \
 
 _build_broken_var_list += \
@@ -583,8 +584,16 @@
 # APEXes are by default flattened, i.e. non-updatable.
 # It can be unflattened (and updatable) by inheriting from
 # updatable_apex.mk
-ifeq (,$(TARGET_FLATTEN_APEX))
-TARGET_FLATTEN_APEX := true
+#
+# APEX flattening can also be forcibly enabled (resp. disabled) by
+# setting OVERRIDE_TARGET_FLATTEN_APEX to true (resp. false), e.g. by
+# setting the OVERRIDE_TARGET_FLATTEN_APEX environment variable.
+ifdef OVERRIDE_TARGET_FLATTEN_APEX
+  TARGET_FLATTEN_APEX := $(OVERRIDE_TARGET_FLATTEN_APEX)
+else
+  ifeq (,$(TARGET_FLATTEN_APEX))
+    TARGET_FLATTEN_APEX := true
+  endif
 endif
 
 ifeq (,$(TARGET_BUILD_APPS))
diff --git a/core/check_elf_file.mk b/core/check_elf_file.mk
index 0faaadd..7a5de67 100644
--- a/core/check_elf_file.mk
+++ b/core/check_elf_file.mk
@@ -38,12 +38,18 @@
 	    $<
 	$(hide) touch $@
 
-ifneq ($(PRODUCT_CHECK_ELF_FILES)$(CHECK_ELF_FILES),)
 ifneq ($(strip $(LOCAL_CHECK_ELF_FILES)),false)
+ifneq ($(strip $(BUILD_BROKEN_PREBUILT_ELF_FILES)),true)
+# TODO(b/141176116): Remove the PRODUCT_CHECK_ELF_FILES condition below and
+# cover `make droid` targets after everything goes well with `make checkbuild`
+# targets.
+ifneq ($(PRODUCT_CHECK_ELF_FILES)$(CHECK_ELF_FILES),)
 $(LOCAL_BUILT_MODULE): $(check_elf_files_stamp)
-check-elf-files: $(check_elf_files_stamp)
-endif  # LOCAL_CHECK_ELF_FILES
 endif  # PRODUCT_CHECK_ELF_FILES or CHECK_ELF_FILES
 
+check-elf-files: $(check_elf_files_stamp)
+endif  # BUILD_BROKEN_PREBUILT_ELF_FILES
+endif  # LOCAL_CHECK_ELF_FILES
+
 endif  # SHARED_LIBRARIES, EXECUTABLES, NATIVE_TESTS
 endif  # !LOCAL_IS_HOST_MODULE
diff --git a/core/cxx_stl_setup.mk b/core/cxx_stl_setup.mk
index 8e4a46c..95b1090 100644
--- a/core/cxx_stl_setup.mk
+++ b/core/cxx_stl_setup.mk
@@ -33,12 +33,6 @@
     endif
 endif
 
-# Yes, this is actually what the clang driver does.
-linux_dynamic_gcclibs := -lgcc_s -lgcc -lc -lgcc_s -lgcc
-linux_static_gcclibs := -Wl,--start-group -lgcc -lgcc_eh -lc -Wl,--end-group
-darwin_dynamic_gcclibs := -lc -lSystem
-darwin_static_gcclibs := NO_STATIC_HOST_BINARIES_ON_DARWIN
-
 my_link_type := dynamic
 ifdef LOCAL_IS_HOST_MODULE
     ifneq (,$(BUILD_HOST_static))
@@ -79,8 +73,7 @@
 
     ifdef LOCAL_IS_HOST_MODULE
         my_cppflags += -nostdinc++
-        my_ldflags += -nodefaultlibs
-        my_cxx_ldlibs += $($($(my_prefix)OS)_$(my_link_type)_gcclibs)
+        my_ldflags += -nostdlib++
     else
         my_static_libraries += libc++demangle
         ifeq (arm,$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH))
@@ -99,8 +92,7 @@
 else ifeq ($(my_cxx_stl),none)
     ifdef LOCAL_IS_HOST_MODULE
         my_cppflags += -nostdinc++
-        my_ldflags += -nodefaultlibs
-        my_cxx_ldlibs += $($($(my_prefix)OS)_$(my_link_type)_gcclibs)
+        my_ldflags += -nostdlib++
     endif
 else
     $(error $(LOCAL_PATH): $(LOCAL_MODULE): $(my_cxx_stl) is not a supported STL.)
diff --git a/core/main.mk b/core/main.mk
index d2cc47b..fa203ca 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -193,17 +193,7 @@
 # The pdk (Platform Development Kit) build
 include build/make/core/pdk_config.mk
 
-#
 # -----------------------------------------------------------------
-# Enable dynamic linker warnings for userdebug, eng and non-REL builds
-ifneq ($(TARGET_BUILD_VARIANT),user)
-  ADDITIONAL_BUILD_PROPERTIES += ro.bionic.ld.warning=1
-else
-# Enable it for user builds as long as they are not final.
-ifneq ($(PLATFORM_VERSION_CODENAME),REL)
-  ADDITIONAL_BUILD_PROPERTIES += ro.bionic.ld.warning=1
-endif
-endif
 
 ADDITIONAL_BUILD_PROPERTIES += ro.treble.enabled=${PRODUCT_FULL_TREBLE}
 
diff --git a/core/soong_cc_prebuilt.mk b/core/soong_cc_prebuilt.mk
index 09eb419..9e3f0d3 100644
--- a/core/soong_cc_prebuilt.mk
+++ b/core/soong_cc_prebuilt.mk
@@ -136,7 +136,7 @@
 
 ifndef LOCAL_IS_HOST_MODULE
   ifdef LOCAL_SOONG_UNSTRIPPED_BINARY
-    ifneq ($(LOCAL_VNDK_DEPEND_ON_CORE_VARIANT),true)
+    ifneq ($(LOCAL_UNINSTALLABLE_MODULE),true)
       my_symbol_path := $(if $(LOCAL_SOONG_SYMBOL_PATH),$(LOCAL_SOONG_SYMBOL_PATH),$(my_module_path))
       # Store a copy with symbols for symbolic debugging
       my_unstripped_path := $(TARGET_OUT_UNSTRIPPED)/$(patsubst $(PRODUCT_OUT)/%,%,$(my_symbol_path))
diff --git a/envsetup.sh b/envsetup.sh
index 3d5d361..f0c6b9b 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -580,7 +580,7 @@
 
     local i=1
     local choice
-    for choice in $choices
+    for choice in $(echo $choices)
     do
         echo "     $i. $choice"
         i=$(($i+1))
diff --git a/target/board/mainline_arm64/BoardConfig.mk b/target/board/mainline_arm64/BoardConfig.mk
index 70505f4..7cb2609 100644
--- a/target/board/mainline_arm64/BoardConfig.mk
+++ b/target/board/mainline_arm64/BoardConfig.mk
@@ -32,5 +32,11 @@
 AB_OTA_UPDATER := true
 AB_OTA_PARTITIONS := system
 
-BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
 BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
+
+# Mainline devices support apex
+# TODO: move this to BoardConfigMainlineCommon. Currently, GSI wants flattened
+#       apexes, but emulator wants .apex files, preventing this.
+TARGET_FLATTEN_APEX := false
diff --git a/target/board/mainline_x86/BoardConfig.mk b/target/board/mainline_x86/BoardConfig.mk
new file mode 100644
index 0000000..a20d17c
--- /dev/null
+++ b/target/board/mainline_x86/BoardConfig.mk
@@ -0,0 +1,35 @@
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+TARGET_ARCH := x86
+TARGET_ARCH_VARIANT := x86
+TARGET_CPU_ABI := x86
+
+include build/make/target/board/BoardConfigMainlineCommon.mk
+
+TARGET_NO_KERNEL := true
+
+# Build generic A/B format system-only OTA.
+AB_OTA_UPDATER := true
+AB_OTA_PARTITIONS := system
+
+BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
+
+# Mainline devices support apex
+# TODO: move this to product makefile and use updatable_apex.mk
+TARGET_FLATTEN_APEX := false
diff --git a/target/board/mainline_x86_arm/BoardConfig.mk b/target/board/mainline_x86_arm/BoardConfig.mk
new file mode 100644
index 0000000..6b282c2
--- /dev/null
+++ b/target/board/mainline_x86_arm/BoardConfig.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+TARGET_ARCH := x86
+TARGET_ARCH_VARIANT := x86
+TARGET_CPU_ABI := x86
+
+TARGET_NATIVE_BRIDGE_ARCH := arm
+TARGET_NATIVE_BRIDGE_ARCH_VARIANT := armv7-a-neon
+TARGET_NATIVE_BRIDGE_CPU_VARIANT := generic
+TARGET_NATIVE_BRIDGE_ABI := armeabi-v7a armeabi
+
+include build/make/target/board/BoardConfigMainlineCommon.mk
+
+TARGET_NO_KERNEL := true
+
+# Build generic A/B format system-only OTA.
+AB_OTA_UPDATER := true
+AB_OTA_PARTITIONS := system
+
+BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := ext4
+BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
+
+# Mainline devices support apex
+# TODO: move this to product makefile and use updatable_apex.mk
+TARGET_FLATTEN_APEX := false
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index 174916d..ca4ed2c 100644
--- a/target/product/AndroidProducts.mk
+++ b/target/product/AndroidProducts.mk
@@ -55,6 +55,8 @@
     $(LOCAL_DIR)/gsi_arm64.mk \
     $(LOCAL_DIR)/mainline_arm64.mk \
     $(LOCAL_DIR)/mainline_system_arm64.mk \
+    $(LOCAL_DIR)/mainline_system_x86.mk \
+    $(LOCAL_DIR)/mainline_system_x86_arm.mk \
     $(LOCAL_DIR)/sdk_arm64.mk \
     $(LOCAL_DIR)/sdk.mk \
     $(LOCAL_DIR)/sdk_phone_arm64.mk \
diff --git a/target/product/aosp_product.mk b/target/product/aosp_product.mk
index 8c87983..aefad82 100644
--- a/target/product/aosp_product.mk
+++ b/target/product/aosp_product.mk
@@ -21,21 +21,6 @@
 # Default AOSP sounds
 $(call inherit-product-if-exists, frameworks/base/data/sounds/AllAudio.mk)
 
-# TODO(b/133643923): Clean up the mainline whitelist
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
-    system/app/messaging/messaging.apk \
-    system/app/messaging/oat/% \
-    system/app/WAPPushManager/WAPPushManager.apk \
-    system/app/WAPPushManager/oat/% \
-    system/bin/healthd \
-    system/etc/init/healthd.rc \
-    system/etc/vintf/manifest/manifest_healthd.xml \
-    system/lib/libframesequence.so \
-    system/lib/libgiftranscode.so \
-    system/lib64/libframesequence.so \
-    system/lib64/libgiftranscode.so \
-
-
 # Additional settings used in all AOSP builds
 PRODUCT_PRODUCT_PROPERTIES += \
     ro.config.ringtone=Ring_Synth_04.ogg \
diff --git a/target/product/base_product.mk b/target/product/base_product.mk
index 749d2c2..2ed550c 100644
--- a/target/product/base_product.mk
+++ b/target/product/base_product.mk
@@ -17,7 +17,6 @@
 # Base modules and settings for the product partition.
 PRODUCT_PACKAGES += \
     group_product \
-    healthd \
     ModuleMetadata \
     passwd_product \
     product_compatibility_matrix.xml \
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index ec373db..f49218a 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -29,7 +29,6 @@
     android.test.mock \
     android.test.runner \
     apexd \
-    applypatch \
     appops \
     app_process \
     appwidget \
@@ -49,6 +48,7 @@
     cgroups.json \
     charger \
     cmd \
+    com.android.apex.cts.shim.v1_prebuilt \
     com.android.conscrypt \
     com.android.i18n \
     com.android.location.provider \
diff --git a/target/product/base_vendor.mk b/target/product/base_vendor.mk
index 9d79e0f..1657e71 100644
--- a/target/product/base_vendor.mk
+++ b/target/product/base_vendor.mk
@@ -75,3 +75,8 @@
 # VINTF data for vendor image
 PRODUCT_PACKAGES += \
     device_compatibility_matrix.xml \
+
+# Packages to update the recovery partition, which will be installed on
+# /vendor. TODO(b/141648565): Don't install these unless they're needed.
+PRODUCT_PACKAGES += \
+    applypatch
diff --git a/target/product/mainline_system.mk b/target/product/mainline_system.mk
index 43bc45f..b8f2838 100644
--- a/target/product/mainline_system.mk
+++ b/target/product/mainline_system.mk
@@ -105,8 +105,7 @@
 # Enable dynamic partition size
 PRODUCT_USE_DYNAMIC_PARTITION_SIZE := true
 
-PRODUCT_PACKAGES += \
-    com.android.apex.cts.shim.v1_prebuilt
+PRODUCT_ENFORCE_RRO_TARGETS := *
 
 PRODUCT_NAME := mainline_system
 PRODUCT_BRAND := generic
diff --git a/target/product/mainline_system_x86.mk b/target/product/mainline_system_x86.mk
new file mode 100644
index 0000000..ac33068
--- /dev/null
+++ b/target/product/mainline_system_x86.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# All components inherited here go to system image
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call enforce-product-packages-exist,)
+
+# Enable mainline checking
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
+
+PRODUCT_BUILD_CACHE_IMAGE := false
+PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_PRODUCT_IMAGE  := false
+PRODUCT_BUILD_RAMDISK_IMAGE := false
+PRODUCT_BUILD_SYSTEM_IMAGE := true
+PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
+PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
+PRODUCT_BUILD_USERDATA_IMAGE := false
+PRODUCT_BUILD_VENDOR_IMAGE := false
+
+PRODUCT_NAME := mainline_system_x86
+PRODUCT_DEVICE := mainline_x86
+PRODUCT_BRAND := generic
+PRODUCT_SHIPPING_API_LEVEL := 28
+PRODUCT_RESTRICT_VENDOR_FILES := all
diff --git a/target/product/mainline_system_x86_arm.mk b/target/product/mainline_system_x86_arm.mk
new file mode 100644
index 0000000..0ed86cc
--- /dev/null
+++ b/target/product/mainline_system_x86_arm.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# All components inherited here go to system image
+#
+$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk)
+$(call enforce-product-packages-exist,)
+
+# Enable mainline checking
+PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := true
+
+PRODUCT_BUILD_CACHE_IMAGE := false
+PRODUCT_BUILD_ODM_IMAGE := false
+PRODUCT_BUILD_PRODUCT_IMAGE  := false
+PRODUCT_BUILD_RAMDISK_IMAGE := false
+PRODUCT_BUILD_SYSTEM_IMAGE := true
+PRODUCT_BUILD_SYSTEM_EXT_IMAGE := false
+PRODUCT_BUILD_SYSTEM_OTHER_IMAGE := false
+PRODUCT_BUILD_USERDATA_IMAGE := false
+PRODUCT_BUILD_VENDOR_IMAGE := false
+
+PRODUCT_NAME := mainline_system_x86_arm
+PRODUCT_DEVICE := mainline_x86_arm
+PRODUCT_BRAND := generic
+PRODUCT_SHIPPING_API_LEVEL := 28
+PRODUCT_RESTRICT_VENDOR_FILES := all
diff --git a/target/product/updatable_apex.mk b/target/product/updatable_apex.mk
index a9f4baf..bdaf545 100644
--- a/target/product/updatable_apex.mk
+++ b/target/product/updatable_apex.mk
@@ -16,5 +16,7 @@
 
 # Inherit this when the target needs to support updating APEXes
 
-PRODUCT_PROPERTY_OVERRIDES := ro.apex.updatable=true
-TARGET_FLATTEN_APEX := false
+ifneq ($(OVERRIDE_TARGET_FLATTEN_APEX),true)
+  PRODUCT_PROPERTY_OVERRIDES := ro.apex.updatable=true
+  TARGET_FLATTEN_APEX := false
+endif
diff --git a/tools/releasetools/OWNERS b/tools/releasetools/OWNERS
index 766adb4..a8295d4 100644
--- a/tools/releasetools/OWNERS
+++ b/tools/releasetools/OWNERS
@@ -1,2 +1,3 @@
-tbao@google.com
+nhdo@google.com
 xunchang@google.com
+zhaojiac@google.com
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index a5816bc..4ba8643 100755
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -165,9 +165,12 @@
       else:
         common.ZipWrite(output_zip, output_file, arc_name)
 
-  if (OPTIONS.rebuild_recovery and recovery_img is not None and
-      boot_img is not None):
-    logger.info("Building new recovery patch")
+  board_uses_vendorimage = OPTIONS.info_dict.get(
+      "board_uses_vendorimage") == "true"
+
+  if (OPTIONS.rebuild_recovery and not board_uses_vendorimage and
+      recovery_img is not None and boot_img is not None):
+    logger.info("Building new recovery patch on system at system/vendor")
     common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img,
                              boot_img, info_dict=OPTIONS.info_dict)
 
@@ -190,7 +193,7 @@
   CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system_other", img)
 
 
-def AddVendor(output_zip):
+def AddVendor(output_zip, recovery_img=None, boot_img=None):
   """Turn the contents of VENDOR into a vendor image and store in it
   output_zip."""
 
@@ -199,6 +202,27 @@
     logger.info("vendor.img already exists; no need to rebuild...")
     return img.name
 
+  def output_sink(fn, data):
+    ofile = open(os.path.join(OPTIONS.input_tmp, "VENDOR", fn), "w")
+    ofile.write(data)
+    ofile.close()
+
+    if output_zip:
+      arc_name = "VENDOR/" + fn
+      if arc_name in output_zip.namelist():
+        OPTIONS.replace_updated_files_list.append(arc_name)
+      else:
+        common.ZipWrite(output_zip, ofile.name, arc_name)
+
+  board_uses_vendorimage = OPTIONS.info_dict.get(
+      "board_uses_vendorimage") == "true"
+
+  if (OPTIONS.rebuild_recovery and board_uses_vendorimage and
+      recovery_img is not None and boot_img is not None):
+    logger.info("Building new recovery patch on vendor")
+    common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img,
+                             boot_img, info_dict=OPTIONS.info_dict)
+
   block_list = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor.map")
   CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "vendor", img,
               block_list=block_list)
@@ -293,11 +317,6 @@
   logger.info("creating %s.img...", what)
 
   image_props = build_image.ImagePropFromGlobalDict(info_dict, what)
-  fstab = info_dict["fstab"]
-  mount_point = "/" + what
-  if fstab and mount_point in fstab:
-    image_props["fs_type"] = fstab[mount_point].fs_type
-
   image_props["timestamp"] = FIXED_FILE_TIMESTAMP
 
   if what == "system":
@@ -382,9 +401,6 @@
   else:
     user_dir = common.MakeTempDir()
 
-  fstab = OPTIONS.info_dict["fstab"]
-  if fstab:
-    image_props["fs_type"] = fstab["/data"].fs_type
   build_image.BuildImage(user_dir, image_props, img.name)
 
   common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
@@ -471,10 +487,6 @@
   image_props["timestamp"] = FIXED_FILE_TIMESTAMP
 
   user_dir = common.MakeTempDir()
-
-  fstab = OPTIONS.info_dict["fstab"]
-  if fstab:
-    image_props["fs_type"] = fstab["/cache"].fs_type
   build_image.BuildImage(user_dir, image_props, img.name)
 
   common.CheckSize(img.name, "cache.img", OPTIONS.info_dict)
@@ -781,7 +793,8 @@
 
   if has_vendor:
     banner("vendor")
-    partitions['vendor'] = AddVendor(output_zip)
+    partitions['vendor'] = AddVendor(
+        output_zip, recovery_img=recovery_image, boot_img=boot_image)
 
   if has_product:
     banner("product")
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 974d4b0..37c03ab 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -393,37 +393,8 @@
   makeint("boot_size")
   makeint("fstab_version")
 
-  # We changed recovery.fstab path in Q, from ../RAMDISK/etc/recovery.fstab to
-  # ../RAMDISK/system/etc/recovery.fstab. LoadInfoDict() has to handle both
-  # cases, since it may load the info_dict from an old build (e.g. when
-  # generating incremental OTAs from that build).
-  system_root_image = d.get("system_root_image") == "true"
-  if d.get("no_recovery") != "true":
-    recovery_fstab_path = "RECOVERY/RAMDISK/system/etc/recovery.fstab"
-    if isinstance(input_file, zipfile.ZipFile):
-      if recovery_fstab_path not in input_file.namelist():
-        recovery_fstab_path = "RECOVERY/RAMDISK/etc/recovery.fstab"
-    else:
-      path = os.path.join(input_file, *recovery_fstab_path.split("/"))
-      if not os.path.exists(path):
-        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") == "true":
-    recovery_fstab_path = "BOOT/RAMDISK/system/etc/recovery.fstab"
-    if isinstance(input_file, zipfile.ZipFile):
-      if recovery_fstab_path not in input_file.namelist():
-        recovery_fstab_path = "BOOT/RAMDISK/etc/recovery.fstab"
-    else:
-      path = os.path.join(input_file, *recovery_fstab_path.split("/"))
-      if not os.path.exists(path):
-        recovery_fstab_path = "BOOT/RAMDISK/etc/recovery.fstab"
-    d["fstab"] = LoadRecoveryFSTab(
-        read_helper, d["fstab_version"], recovery_fstab_path, system_root_image)
-
-  else:
-    d["fstab"] = None
+  # Load recovery fstab if applicable.
+  d["fstab"] = _FindAndLoadRecoveryFstab(d, input_file, read_helper)
 
   # Tries to load the build props for all partitions with care_map, including
   # system and vendor.
@@ -549,6 +520,47 @@
   return d
 
 
+def _FindAndLoadRecoveryFstab(info_dict, input_file, read_helper):
+  """Finds the path to recovery fstab and loads its contents."""
+  # recovery fstab is only meaningful when installing an update via recovery
+  # (i.e. non-A/B OTA). Skip loading fstab if device used A/B OTA.
+  if info_dict.get('ab_update') == 'true':
+    return None
+
+  # We changed recovery.fstab path in Q, from ../RAMDISK/etc/recovery.fstab to
+  # ../RAMDISK/system/etc/recovery.fstab. This function has to handle both
+  # cases, since it may load the info_dict from an old build (e.g. when
+  # generating incremental OTAs from that build).
+  system_root_image = info_dict.get('system_root_image') == 'true'
+  if info_dict.get('no_recovery') != 'true':
+    recovery_fstab_path = 'RECOVERY/RAMDISK/system/etc/recovery.fstab'
+    if isinstance(input_file, zipfile.ZipFile):
+      if recovery_fstab_path not in input_file.namelist():
+        recovery_fstab_path = 'RECOVERY/RAMDISK/etc/recovery.fstab'
+    else:
+      path = os.path.join(input_file, *recovery_fstab_path.split('/'))
+      if not os.path.exists(path):
+        recovery_fstab_path = 'RECOVERY/RAMDISK/etc/recovery.fstab'
+    return LoadRecoveryFSTab(
+        read_helper, info_dict['fstab_version'], recovery_fstab_path,
+        system_root_image)
+
+  if info_dict.get('recovery_as_boot') == 'true':
+    recovery_fstab_path = 'BOOT/RAMDISK/system/etc/recovery.fstab'
+    if isinstance(input_file, zipfile.ZipFile):
+      if recovery_fstab_path not in input_file.namelist():
+        recovery_fstab_path = 'BOOT/RAMDISK/etc/recovery.fstab'
+    else:
+      path = os.path.join(input_file, *recovery_fstab_path.split('/'))
+      if not os.path.exists(path):
+        recovery_fstab_path = 'BOOT/RAMDISK/etc/recovery.fstab'
+    return LoadRecoveryFSTab(
+        read_helper, info_dict['fstab_version'], recovery_fstab_path,
+        system_root_image)
+
+  return None
+
+
 def DumpInfoDict(d):
   for k, v in sorted(d.items()):
     logger.info("%-25s = (%s) %s", k, type(v).__name__, v)
@@ -629,7 +641,7 @@
     cmd.extend(["--salt", avb_salt])
 
 
-def GetAvbPartitionArg(partition, image, info_dict = None):
+def GetAvbPartitionArg(partition, image, info_dict=None):
   """Returns the VBMeta arguments for partition.
 
   It sets up the VBMeta argument by including the partition descriptor from the
@@ -2535,13 +2547,25 @@
     info_dict = OPTIONS.info_dict
 
   full_recovery_image = info_dict.get("full_recovery_image") == "true"
+  board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true"
+
+  if board_uses_vendorimage:
+    # In this case, the output sink is rooted at VENDOR
+    recovery_img_path = "etc/recovery.img"
+    recovery_resource_dat_path = "VENDOR/etc/recovery-resource.dat"
+    sh_dir = "bin"
+  else:
+    # In this case the output sink is rooted at SYSTEM
+    recovery_img_path = "vendor/etc/recovery.img"
+    recovery_resource_dat_path = "SYSTEM/vendor/etc/recovery-resource.dat"
+    sh_dir = "vendor/bin"
 
   if full_recovery_image:
-    output_sink("etc/recovery.img", recovery_img.data)
+    output_sink(recovery_img_path, recovery_img.data)
 
   else:
     system_root_image = info_dict.get("system_root_image") == "true"
-    path = os.path.join(input_dir, "SYSTEM", "etc", "recovery-resource.dat")
+    path = os.path.join(input_dir, recovery_resource_dat_path)
     # With system-root-image, boot and recovery images will have mismatching
     # entries (only recovery has the ramdisk entry) (Bug: 72731506). Use bsdiff
     # to handle such a case.
@@ -2554,7 +2578,7 @@
       if os.path.exists(path):
         diff_program.append("-b")
         diff_program.append(path)
-        bonus_args = "--bonus /system/etc/recovery-resource.dat"
+        bonus_args = "--bonus /vendor/etc/recovery-resource.dat"
       else:
         bonus_args = ""
 
@@ -2571,10 +2595,16 @@
     return
 
   if full_recovery_image:
-    sh = """#!/system/bin/sh
+
+    # Note that we use /vendor to refer to the recovery resources. This will
+    # work for a separate vendor partition mounted at /vendor or a
+    # /system/vendor subdirectory on the system partition, for which init will
+    # create a symlink from /vendor to /system/vendor.
+
+    sh = """#!/vendor/bin/sh
 if ! applypatch --check %(type)s:%(device)s:%(size)d:%(sha1)s; then
   applypatch \\
-          --flash /system/etc/recovery.img \\
+          --flash /vendor/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"
@@ -2586,10 +2616,10 @@
        'sha1': recovery_img.sha1,
        'size': recovery_img.size}
   else:
-    sh = """#!/system/bin/sh
+    sh = """#!/vendor/bin/sh
 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 \\
+          --patch /vendor/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" || \\
@@ -2607,9 +2637,9 @@
        'recovery_device': recovery_device,
        'bonus_args': bonus_args}
 
-  # The install script location moved from /system/etc to /system/bin
-  # in the L release.
-  sh_location = "bin/install-recovery.sh"
+  # The install script location moved from /system/etc to /system/bin in the L
+  # release. In the R release it is in VENDOR/bin or SYSTEM/vendor/bin.
+  sh_location = os.path.join(sh_dir, "install-recovery.sh")
 
   logger.info("putting script in %s", sh_location)
 
diff --git a/tools/releasetools/make_recovery_patch.py b/tools/releasetools/make_recovery_patch.py
index 725b355..1497d69 100644
--- a/tools/releasetools/make_recovery_patch.py
+++ b/tools/releasetools/make_recovery_patch.py
@@ -47,8 +47,17 @@
   if not recovery_img or not boot_img:
     sys.exit(0)
 
+  board_uses_vendorimage = OPTIONS.info_dict.get(
+      "board_uses_vendorimage") == "true"
+
+  if board_uses_vendorimage:
+    target_files_dir = "VENDOR"
+  else:
+    target_files_dir = "SYSTEM"
+
   def output_sink(fn, data):
-    with open(os.path.join(output_dir, "SYSTEM", *fn.split("/")), "wb") as f:
+    with open(os.path.join(output_dir, target_files_dir,
+                           *fn.split("/")), "wb") as f:
       f.write(data)
 
   common.MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img)
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index ba70986..544f996 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -68,8 +68,7 @@
       files package and saves it at this path.
 
   --rebuild_recovery
-      Rebuild the recovery patch used by non-A/B devices and write it to the
-      system image.
+      Deprecated; does nothing.
 
   --keep-tmp
       Keep tempoary files for debugging purposes.
@@ -106,6 +105,7 @@
 OPTIONS.output_ota = None
 OPTIONS.output_img = None
 OPTIONS.output_super_empty = None
+# TODO(b/132730255): Remove this option.
 OPTIONS.rebuild_recovery = False
 OPTIONS.keep_tmp = False
 
@@ -372,32 +372,6 @@
   write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
 
 
-def append_recovery_to_filesystem_config(output_target_files_temp_dir):
-  """Performs special processing for META/filesystem_config.txt.
-
-  This function appends recovery information to META/filesystem_config.txt so
-  that recovery patch regeneration will succeed.
-
-  Args:
-    output_target_files_temp_dir: The name of a directory that will be used to
-      create the output target files package after all the special cases are
-      processed. We find filesystem_config.txt here.
-  """
-
-  filesystem_config_txt = os.path.join(output_target_files_temp_dir, 'META',
-                                       'filesystem_config.txt')
-
-  with open(filesystem_config_txt, 'a') as f:
-    # TODO(bpeckham) this data is hard coded. It should be generated
-    # programmatically.
-    f.write('system/bin/install-recovery.sh 0 0 750 '
-            'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
-    f.write('system/recovery-from-boot.p 0 0 644 '
-            'selabel=u:object_r:system_file:s0 capabilities=0x0\n')
-    f.write('system/etc/recovery.img 0 0 440 '
-            'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
-
-
 def process_misc_info_txt(framework_target_files_temp_dir,
                           vendor_target_files_temp_dir,
                           output_target_files_temp_dir,
@@ -594,7 +568,7 @@
 def process_special_cases(framework_target_files_temp_dir,
                           vendor_target_files_temp_dir,
                           output_target_files_temp_dir,
-                          framework_misc_info_keys, rebuild_recovery):
+                          framework_misc_info_keys):
   """Performs special-case processing for certain target files items.
 
   Certain files in the output target files package require special-case
@@ -611,8 +585,6 @@
     framework_misc_info_keys: A list of keys to obtain from the framework
       instance of META/misc_info.txt. The remaining keys from the vendor
       instance.
-    rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
-      devices and write it to the system image.
   """
 
   if 'ab_update' in framework_misc_info_keys:
@@ -621,10 +593,6 @@
         vendor_target_files_temp_dir=vendor_target_files_temp_dir,
         output_target_files_temp_dir=output_target_files_temp_dir)
 
-  if rebuild_recovery:
-    append_recovery_to_filesystem_config(
-        output_target_files_temp_dir=output_target_files_temp_dir)
-
   copy_file_contexts(
       framework_target_files_dir=framework_target_files_temp_dir,
       vendor_target_files_dir=vendor_target_files_temp_dir,
@@ -757,8 +725,7 @@
       framework_target_files_temp_dir=framework_target_files_temp_dir,
       vendor_target_files_temp_dir=vendor_target_files_temp_dir,
       output_target_files_temp_dir=output_target_files_temp_dir,
-      framework_misc_info_keys=framework_misc_info_keys,
-      rebuild_recovery=rebuild_recovery)
+      framework_misc_info_keys=framework_misc_info_keys)
 
   return output_target_files_temp_dir
 
@@ -779,6 +746,7 @@
 
   add_img_args = ['--verbose']
   add_img_args.append('--add_missing')
+  # TODO(b/132730255): Remove this if statement.
   if rebuild_recovery:
     add_img_args.append('--rebuild_recovery')
   add_img_args.append(target_files_dir)
@@ -1016,7 +984,7 @@
       OPTIONS.output_img = a
     elif o == '--output-super-empty':
       OPTIONS.output_super_empty = a
-    elif o == '--rebuild_recovery':
+    elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
       OPTIONS.rebuild_recovery = True
     elif o == '--keep-tmp':
       OPTIONS.keep_tmp = True
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index de947f3..3fc3c22 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -731,10 +731,19 @@
     script.WriteRawImage("/boot", "recovery.img")
 
 
-def HasRecoveryPatch(target_files_zip):
+def HasRecoveryPatch(target_files_zip, info_dict):
+  board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true"
+
+  if board_uses_vendorimage:
+    target_files_dir = "VENDOR"
+  else:
+    target_files_dir = "SYSTEM/vendor"
+
+  patch = "%s/recovery-from-boot.p" % target_files_dir
+  img = "%s/etc/recovery.img" %target_files_dir
+
   namelist = [name for name in target_files_zip.namelist()]
-  return ("SYSTEM/recovery-from-boot.p" in namelist or
-          "SYSTEM/etc/recovery.img" in namelist)
+  return (patch in namelist or img in namelist)
 
 
 def HasPartition(target_files_zip, partition):
@@ -925,7 +934,7 @@
       metadata=metadata,
       info_dict=OPTIONS.info_dict)
 
-  assert HasRecoveryPatch(input_zip)
+  assert HasRecoveryPatch(input_zip, info_dict=OPTIONS.info_dict)
 
   # Assertions (e.g. downgrade check, device properties check).
   ts = target_info.GetBuildProp("ro.build.date.utc")
diff --git a/tools/releasetools/sparse_img.py b/tools/releasetools/sparse_img.py
index 3367896..a249081 100644
--- a/tools/releasetools/sparse_img.py
+++ b/tools/releasetools/sparse_img.py
@@ -249,8 +249,9 @@
 
     with open(fn) as f:
       for line in f:
-        fn, ranges = line.split(None, 1)
-        ranges = rangelib.RangeSet.parse(ranges)
+        fn, ranges_text = line.rstrip().split(None, 1)
+        ranges = rangelib.RangeSet.parse(ranges_text)
+        ranges.extra['text_str'] = ranges_text
 
         if allow_shared_blocks:
           # Find the shared blocks that have been claimed by others. If so, tag
@@ -261,9 +262,6 @@
             if not non_shared:
               continue
 
-            # There shouldn't anything in the extra dict yet.
-            assert not ranges.extra, "Non-empty RangeSet.extra"
-
             # Put the non-shared RangeSet as the value in the block map, which
             # has a copy of the original RangeSet.
             non_shared.extra['uses_shared_blocks'] = ranges
diff --git a/tools/releasetools/test_check_target_files_vintf.py b/tools/releasetools/test_check_target_files_vintf.py
index a1328c2..79f9018 100644
--- a/tools/releasetools/test_check_target_files_vintf.py
+++ b/tools/releasetools/test_check_target_files_vintf.py
@@ -78,6 +78,8 @@
     for root, _, files in os.walk(test_delta_dir):
       rel_root = os.path.relpath(root, test_delta_dir)
       for f in files:
+        if not f.endswith('.xml'):
+          continue
         output_file = os.path.join(test_dir, rel_root, f)
         with open(os.path.join(root, f)) as inp:
           write_string_to_file(inp.read(), output_file)
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index ceb023f..cc59cba 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -749,10 +749,12 @@
     self.assertNotIn(
         'incomplete', sparse_image.file_map['/system/file2'].extra)
 
-    # All other entries should look normal without any tags.
+    # '/system/file1' will only contain one field -- a copy of the input text.
+    self.assertEqual(1, len(sparse_image.file_map['/system/file1'].extra))
+
+    # Meta entries should not have any extra tag.
     self.assertFalse(sparse_image.file_map['__COPY'].extra)
     self.assertFalse(sparse_image.file_map['__NONZERO-0'].extra)
-    self.assertFalse(sparse_image.file_map['/system/file1'].extra)
 
   @test_utils.SkipIfExternalToolsUnavailable()
   def test_GetSparseImage_incompleteRanges(self):
@@ -775,7 +777,9 @@
     with zipfile.ZipFile(target_files, 'r') as input_zip:
       sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
 
-    self.assertFalse(sparse_image.file_map['/system/file1'].extra)
+    self.assertEqual(
+        '1-5 9-10',
+        sparse_image.file_map['/system/file1'].extra['text_str'])
     self.assertTrue(sparse_image.file_map['/system/file2'].extra['incomplete'])
 
   @test_utils.SkipIfExternalToolsUnavailable()
@@ -801,7 +805,9 @@
     with zipfile.ZipFile(target_files, 'r') as input_zip:
       sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
 
-    self.assertFalse(sparse_image.file_map['//system/file1'].extra)
+    self.assertEqual(
+        '1-5 9-10',
+        sparse_image.file_map['//system/file1'].extra['text_str'])
     self.assertTrue(sparse_image.file_map['//system/file2'].extra['incomplete'])
     self.assertTrue(
         sparse_image.file_map['/system/app/file3'].extra['incomplete'])
@@ -826,7 +832,9 @@
     with zipfile.ZipFile(target_files, 'r') as input_zip:
       sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
 
-    self.assertFalse(sparse_image.file_map['//system/file1'].extra)
+    self.assertEqual(
+        '1-5 9-10',
+        sparse_image.file_map['//system/file1'].extra['text_str'])
     self.assertTrue(sparse_image.file_map['//init.rc'].extra['incomplete'])
 
   @test_utils.SkipIfExternalToolsUnavailable()
diff --git a/tools/releasetools/test_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index 9825a5e..f7d59da 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -596,7 +596,7 @@
 
     with zipfile.ZipFile(target_file) as verify_zip:
       namelist = verify_zip.namelist()
-      ab_partitions = verify_zip.read('META/ab_partitions.txt')
+      ab_partitions = verify_zip.read('META/ab_partitions.txt').decode()
 
     self.assertIn('META/ab_partitions.txt', namelist)
     self.assertIn('IMAGES/system.img', namelist)
@@ -676,9 +676,9 @@
 
     with zipfile.ZipFile(target_file) as verify_zip:
       namelist = verify_zip.namelist()
-      updated_misc_info = verify_zip.read('META/misc_info.txt')
+      updated_misc_info = verify_zip.read('META/misc_info.txt').decode()
       updated_dynamic_partitions_info = verify_zip.read(
-          'META/dynamic_partitions_info.txt')
+          'META/dynamic_partitions_info.txt').decode()
 
     self.assertIn('META/ab_partitions.txt', namelist)
     self.assertIn('IMAGES/system.img', namelist)
diff --git a/tools/releasetools/test_validate_target_files.py b/tools/releasetools/test_validate_target_files.py
index 9c816eb..6504515 100644
--- a/tools/releasetools/test_validate_target_files.py
+++ b/tools/releasetools/test_validate_target_files.py
@@ -238,14 +238,14 @@
     system_root = os.path.join(input_tmp, "SYSTEM")
     os.mkdir(system_root)
 
-    # Write the test file that contain multiple blocks of zeros, and these
-    # zero blocks will be omitted by kernel. And the test files will occupy one
-    # block range each in the final system image.
+    # Write test files that contain multiple blocks of zeros, and these zero
+    # blocks will be omitted by kernel. Each test file will occupy one block in
+    # the final system image.
     with open(os.path.join(system_root, 'a'), 'w') as f:
-      f.write("aaa")
+      f.write('aaa')
       f.write('\0' * 4096 * 3)
     with open(os.path.join(system_root, 'b'), 'w') as f:
-      f.write("bbb")
+      f.write('bbb')
       f.write('\0' * 4096 * 3)
 
     raw_file_map = os.path.join(input_tmp, 'IMAGES', 'raw_system.map')
@@ -254,7 +254,7 @@
     # Parse the generated file map and update the block ranges for each file.
     file_map_list = {}
     image_ranges = RangeSet()
-    with open(raw_file_map, 'r') as f:
+    with open(raw_file_map) as f:
       for line in f.readlines():
         info = line.split()
         self.assertEqual(2, len(info))
@@ -265,7 +265,7 @@
     mock_shared_block = RangeSet("10-20").subtract(image_ranges).first(1)
     with open(os.path.join(input_tmp, 'IMAGES', 'system.map'), 'w') as f:
       for key in sorted(file_map_list.keys()):
-        line = "{} {}\n".format(
+        line = '{} {}\n'.format(
             key, file_map_list[key].union(mock_shared_block))
         f.write(line)
 
@@ -277,9 +277,55 @@
       for name in all_entries:
         input_zip.write(os.path.join(input_tmp, name), arcname=name)
 
-    input_zip = zipfile.ZipFile(input_file, 'r')
-    info_dict = {'extfs_sparse_flag': '-s'}
-
     # Expect the validation to pass and both files are skipped due to
     # 'incomplete' block range.
-    ValidateFileConsistency(input_zip, input_tmp, info_dict)
+    with zipfile.ZipFile(input_file) as input_zip:
+      info_dict = {'extfs_sparse_flag': '-s'}
+      ValidateFileConsistency(input_zip, input_tmp, info_dict)
+
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_ValidateFileConsistency_nonMonotonicRanges(self):
+    input_tmp = common.MakeTempDir()
+    os.mkdir(os.path.join(input_tmp, 'IMAGES'))
+    system_image = os.path.join(input_tmp, 'IMAGES', 'system.img')
+    system_root = os.path.join(input_tmp, "SYSTEM")
+    os.mkdir(system_root)
+
+    # Write the test file that contain three blocks of 'a', 'b', 'c'.
+    with open(os.path.join(system_root, 'abc'), 'w') as f:
+      f.write('a' * 4096 + 'b' * 4096 + 'c' * 4096)
+    raw_file_map = os.path.join(input_tmp, 'IMAGES', 'raw_system.map')
+    self._generate_system_image(system_image, system_root, raw_file_map)
+
+    # Parse the generated file map and manipulate the block ranges of 'abc' to
+    # be 'cba'.
+    file_map_list = {}
+    with open(raw_file_map) as f:
+      for line in f.readlines():
+        info = line.split()
+        self.assertEqual(2, len(info))
+        ranges = RangeSet(info[1])
+        self.assertTrue(ranges.monotonic)
+        blocks = reversed(list(ranges.next_item()))
+        file_map_list[info[0]] = ' '.join([str(block) for block in blocks])
+
+    # Update the contents of 'abc' to be 'cba'.
+    with open(os.path.join(system_root, 'abc'), 'w') as f:
+      f.write('c' * 4096 + 'b' * 4096 + 'a' * 4096)
+
+    # Update the system.map.
+    with open(os.path.join(input_tmp, 'IMAGES', 'system.map'), 'w') as f:
+      for key in sorted(file_map_list.keys()):
+        f.write('{} {}\n'.format(key, file_map_list[key]))
+
+    # Get the target zip file.
+    input_file = common.MakeTempFile()
+    all_entries = ['SYSTEM/', 'SYSTEM/abc', 'IMAGES/',
+                   'IMAGES/system.map', 'IMAGES/system.img']
+    with zipfile.ZipFile(input_file, 'w') as input_zip:
+      for name in all_entries:
+        input_zip.write(os.path.join(input_tmp, name), arcname=name)
+
+    with zipfile.ZipFile(input_file) as input_zip:
+      info_dict = {'extfs_sparse_flag': '-s'}
+      ValidateFileConsistency(input_zip, input_tmp, info_dict)
diff --git a/tools/releasetools/validate_target_files.py b/tools/releasetools/validate_target_files.py
index c299a48..383ef7b 100755
--- a/tools/releasetools/validate_target_files.py
+++ b/tools/releasetools/validate_target_files.py
@@ -36,20 +36,21 @@
 import os.path
 import re
 import zipfile
+from hashlib import sha1
 
 import common
+import rangelib
 
 
 def _ReadFile(file_name, unpacked_name, round_up=False):
   """Constructs and returns a File object. Rounds up its size if needed."""
-
   assert os.path.exists(unpacked_name)
   with open(unpacked_name, 'rb') as f:
     file_data = f.read()
   file_size = len(file_data)
   if round_up:
     file_size_rounded_up = common.RoundUpTo4K(file_size)
-    file_data += '\0' * (file_size_rounded_up - file_size)
+    file_data += b'\0' * (file_size_rounded_up - file_size)
   return common.File(file_name, file_data)
 
 
@@ -96,13 +97,15 @@
         logging.warning('Skipping %s that has incomplete block list', entry)
         continue
 
-      # TODO(b/79951650): Handle files with non-monotonic ranges.
+      # If the file has non-monotonic ranges, read each range in order.
       if not file_ranges.monotonic:
-        logging.warning(
-            'Skipping %s that has non-monotonic ranges: %s', entry, file_ranges)
-        continue
-
-      blocks_sha1 = image.RangeSha1(file_ranges)
+        h = sha1()
+        for file_range in file_ranges.extra['text_str'].split(' '):
+          for data in image.ReadRangeSet(rangelib.RangeSet(file_range)):
+            h.update(data)
+        blocks_sha1 = h.hexdigest()
+      else:
+        blocks_sha1 = image.RangeSha1(file_ranges)
 
       # The filename under unpacked directory, such as SYSTEM/bin/sh.
       unpacked_name = os.path.join(
@@ -138,7 +141,7 @@
   1. full recovery:
   ...
   if ! applypatch --check type:device:size:sha1; then
-    applypatch --flash /system/etc/recovery.img \\
+    applypatch --flash /vendor/etc/recovery.img \\
         type:device:size:sha1 && \\
   ...
 
@@ -146,18 +149,26 @@
   ...
   if ! applypatch --check type:recovery_device:recovery_size:recovery_sha1; then
     applypatch [--bonus bonus_args] \\
-        --patch /system/recovery-from-boot.p \\
+        --patch /vendor/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
+  For full recovery, we want to calculate the SHA-1 of /vendor/etc/recovery.img
   and compare it against the one embedded in the script. While for recovery
   from boot, we want to check the SHA-1 for both recovery.img and boot.img
   under IMAGES/.
   """
 
-  script_path = 'SYSTEM/bin/install-recovery.sh'
+  board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true"
+
+  if board_uses_vendorimage:
+    script_path = 'VENDOR/bin/install-recovery.sh'
+    recovery_img = 'VENDOR/etc/recovery.img'
+  else:
+    script_path = 'SYSTEM/vendor/bin/install-recovery.sh'
+    recovery_img = 'SYSTEM/vendor/etc/recovery.img'
+
   if not os.path.exists(os.path.join(input_tmp, script_path)):
     logging.info('%s does not exist in input_tmp', script_path)
     return
@@ -188,7 +199,7 @@
     # 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)
+        input_tmp, 'recovery.img', recovery_img, recovery_sha1)
   else:
     assert len(lines) == 11, "Invalid line count: {}".format(lines)