Merge "Change how we set ro.product.first_api_level."
diff --git a/core/Makefile b/core/Makefile
index 9314b94..0d47e63 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -892,7 +892,12 @@
 # $1: boot image file name
 # $2: boot image variant (boot, boot-debug, boot-test-harness)
 define get-bootimage-partition-size
-  $(BOARD_$(call to-upper,$(subst .img,,$(subst $(2),kernel,$(notdir $(1)))))_BOOTIMAGE_PARTITION_SIZE)
+$(BOARD_$(call to-upper,$(subst .img,,$(subst $(2),kernel,$(notdir $(1)))))_BOOTIMAGE_PARTITION_SIZE)
+endef
+
+# $1: partition size
+define get-partition-size-argument
+  $(if $(1),--partition_size $(1),--dynamic_partition_size)
 endef
 
 ifneq ($(strip $(TARGET_NO_KERNEL)),true)
@@ -1024,7 +1029,7 @@
   $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(call get-bootimage-partition-size,$(1),boot)))
   $(AVBTOOL) add_hash_footer \
           --image $(1) \
-          --partition_size $(call get-bootimage-partition-size,$(1),boot) \
+          $(call get-partition-size-argument,$(call get-bootimage-partition-size,$(1),boot)) \
           --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \
           $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
 endef
@@ -1107,7 +1112,7 @@
 	cp $(INTERNAL_PREBUILT_BOOTIMAGE) $@
 	$(AVBTOOL) add_hash_footer \
 	    --image $@ \
-	    --partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \
+	    $(call get-partition-size-argument,$(BOARD_BOOTIMAGE_PARTITION_SIZE)) \
 	    --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \
 	    $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
 else
@@ -1145,7 +1150,7 @@
 	$(call assert-max-image-size,$@,$(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE))
 	$(AVBTOOL) add_hash_footer \
            --image $@ \
-	   --partition_size $(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE) \
+	   $(call get-partition-size-argument,$(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE)) \
 	   --partition_name init_boot $(INTERNAL_AVB_INIT_BOOT_SIGNING_ARGS) \
 	   $(BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS)
 else
@@ -1166,7 +1171,7 @@
 	cp $(INTERNAL_PREBUILT_INIT_BOOT_IMAGE) $@
 	$(AVBTOOL) add_hash_footer \
 	    --image $@ \
-	    --partition_size $(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE) \
+	    $(call get-partition-size-argument,$(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE)) \
 	    --partition_name boot $(INTERNAL_AVB_INIT_BOOT_SIGNING_ARGS) \
 	    $(BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS)
 else
@@ -1294,7 +1299,7 @@
 	$(call assert-max-image-size,$@,$(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE))
 	$(AVBTOOL) add_hash_footer \
            --image $@ \
-	   --partition_size $(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE) \
+	   $(call get-partition-size-argument,$(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE)) \
 	   --partition_name vendor_boot $(INTERNAL_AVB_VENDOR_BOOT_SIGNING_ARGS) \
 	   $(BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS)
 else
@@ -2395,8 +2400,8 @@
     $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE))))
   $(if $(filter true,$(BOARD_AVB_ENABLE)), \
     $(if $(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)), \
-      $(AVBTOOL) add_hash_footer --image $(1) --partition_size $(call get-bootimage-partition-size,$(1),boot) --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS),\
-      $(AVBTOOL) add_hash_footer --image $(1) --partition_size $(BOARD_RECOVERYIMAGE_PARTITION_SIZE) --partition_name recovery $(INTERNAL_AVB_RECOVERY_SIGNING_ARGS) $(BOARD_AVB_RECOVERY_ADD_HASH_FOOTER_ARGS)))
+      $(AVBTOOL) add_hash_footer --image $(1) $(call get-partition-size-argument,$(call get-bootimage-partition-size,$(1),boot)) --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS),\
+      $(AVBTOOL) add_hash_footer --image $(1) $(call get-partition-size-argument,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE)) --partition_name recovery $(INTERNAL_AVB_RECOVERY_SIGNING_ARGS) $(BOARD_AVB_RECOVERY_ADD_HASH_FOOTER_ARGS)))
 endef
 
 recoveryimage-deps := $(MKBOOTIMG) $(recovery_ramdisk) $(recovery_kernel)
@@ -2562,7 +2567,7 @@
 $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(call get-bootimage-partition-size,$(1),$(2))))
 $(AVBTOOL) add_hash_footer \
   --image $(1) \
-  --partition_size $(call get-bootimage-partition-size,$(1),$(2))\
+  $(call get-partition-size-argument,$(call get-bootimage-partition-size,$(1),$(2)))\
   --partition_name boot $(INTERNAL_AVB_BOOT_TEST_SIGNING_ARGS) \
   $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
 $(call assert-max-image-size,$(1),$(call get-bootimage-partition-size,$(1),$(2)))
@@ -2650,7 +2655,7 @@
 $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE)))
 $(AVBTOOL) add_hash_footer \
   --image $(1) \
-  --partition_size $(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE) \
+  $(call get-partition-size-argument,$(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE)) \
   --partition_name vendor_boot $(INTERNAL_AVB_VENDOR_BOOT_TEST_SIGNING_ARGS) \
   $(BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS)
 $(call assert-max-image-size,$(1),$(BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE))
@@ -3680,7 +3685,7 @@
 	cp $(BOARD_PREBUILT_DTBOIMAGE) $@
 	$(AVBTOOL) add_hash_footer \
 	    --image $@ \
-	    --partition_size $(BOARD_DTBOIMG_PARTITION_SIZE) \
+	    $(call get-partition-size-argument,$(BOARD_DTBOIMG_PARTITION_SIZE)) \
 	    --partition_name dtbo $(INTERNAL_AVB_DTBO_SIGNING_ARGS) \
 	    $(BOARD_AVB_DTBO_ADD_HASH_FOOTER_ARGS)
 else
@@ -3707,7 +3712,7 @@
 	cp $< $@
 	$(AVBTOOL) add_hash_footer \
 	    --image $@ \
-	    --partition_size $(BOARD_PVMFWIMAGE_PARTITION_SIZE) \
+	    $(call get-partition-size-argument,$(BOARD_PVMFWIMAGE_PARTITION_SIZE)) \
 	    --partition_name pvmfw $(INTERNAL_AVB_PVMFW_SIGNING_ARGS) \
 	    $(BOARD_AVB_PVMFW_ADD_HASH_FOOTER_ARGS)
 else
@@ -3749,7 +3754,7 @@
           --image $(3) \
           --key $(BOARD_AVB_$(call to-upper,$(2))_KEY_PATH) \
           --algorithm $(BOARD_AVB_$(call to-upper,$(2))_ALGORITHM) \
-          --partition_size $(BOARD_AVB_$(call to-upper,$(2))_PARTITION_SIZE) \
+          $(call get-partition-size-argument,$(BOARD_AVB_$(call to-upper,$(2))_PARTITION_SIZE)) \
           --partition_name $(2) \
           $(INTERNAL_AVB_CUSTOMIMAGES_SIGNING_ARGS) \
           $(BOARD_AVB_$(call to-upper,$(2))_ADD_HASHTREE_FOOTER_ARGS)
@@ -3838,8 +3843,7 @@
     --prop com.android.build.system_ext.security_patch:$(PLATFORM_SECURITY_PATCH)
 
 BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS += \
-    --prop com.android.build.boot.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
-    --prop com.android.build.boot.os_version:$(PLATFORM_VERSION_LAST_STABLE)
+    --prop com.android.build.boot.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE)
 
 BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS += \
     --prop com.android.build.init_boot.fingerprint:$(BUILD_FINGERPRINT_FROM_FILE) \
@@ -3880,6 +3884,14 @@
 # The following vendor- and odm-specific images needs explicit SPL set per board.
 # TODO(b/210875415) Is this security_patch property used? Should it be removed from
 # boot.img when there is no platform ramdisk included in it?
+ifdef BOOT_OS_VERSION
+BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS += \
+    --prop com.android.build.boot.os_version:$(BOOT_OS_VERSION)
+else
+BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS += \
+    --prop com.android.build.boot.os_version:$(PLATFORM_VERSION_LAST_STABLE)
+endif
+
 ifdef BOOT_SECURITY_PATCH
 BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS += \
     --prop com.android.build.boot.security_patch:$(BOOT_SECURITY_PATCH)
@@ -5563,7 +5575,7 @@
 	$(hide) cp $(TOPDIR)system/update_engine/update_engine.conf $(zip_root)/META/update_engine_config.txt
 	$(hide) cp $(TOPDIR)external/zucchini/version_info.h $(zip_root)/META/zucchini_config.txt
 	$(hide) cp $(HOST_OUT_SHARED_LIBRARIES)/liblz4.so $(zip_root)/META/liblz4.so
-	$(hide) for part in $(strip $(AB_OTA_PARTITIONS)); do \
+	$(hide) for part in $(sort $(AB_OTA_PARTITIONS)); do \
 	  echo "$${part}" >> $(zip_root)/META/ab_partitions.txt; \
 	done
 	$(hide) for conf in $(strip $(AB_OTA_POSTINSTALL_CONFIG)); do \
diff --git a/core/base_rules.mk b/core/base_rules.mk
index f497ddf..c554c80 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -996,6 +996,11 @@
         $(call word-colon,2,$(f))))
 endif
 
+ifdef LOCAL_TEST_DATA_BINS
+  ALL_MODULES.$(my_register_name).TEST_DATA_BINS := \
+    $(ALL_MODULES.$(my_register_name).TEST_DATA_BINS) $(LOCAL_TEST_DATA_BINS)
+endif
+
 ##########################################################################
 ## When compiling against the VNDK, add the .vendor or .product suffix to
 ## required modules.
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 7152934..57f9ef8 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -318,6 +318,7 @@
 LOCAL_TARGET_REQUIRED_MODULES:=
 LOCAL_TEST_CONFIG:=
 LOCAL_TEST_DATA:=
+LOCAL_TEST_DATA_BINS:=
 LOCAL_TEST_MAINLINE_MODULES:=
 LOCAL_TEST_MODULE_TO_PROGUARD_WITH:=
 LOCAL_TIDY:=
diff --git a/core/combo/select.mk b/core/combo/select.mk
index 7617558..9c7e69e 100644
--- a/core/combo/select.mk
+++ b/core/combo/select.mk
@@ -35,7 +35,7 @@
   ,HOST_CROSS builds are not supported in Make)
 else
 
-$(combo_var_prefix)GLOBAL_ARFLAGS := crsPD -format=gnu
+$(combo_var_prefix)GLOBAL_ARFLAGS := crsPD --format=gnu
 
 $(combo_var_prefix)STATIC_LIB_SUFFIX := .a
 
diff --git a/core/main.mk b/core/main.mk
index 47666c1..d5dc49f 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -343,7 +343,7 @@
 ADDITIONAL_PRODUCT_PROPERTIES += ro.build.characteristics=$(TARGET_AAPT_CHARACTERISTICS)
 
 ifeq ($(AB_OTA_UPDATER),true)
-ADDITIONAL_PRODUCT_PROPERTIES += ro.product.ab_ota_partitions=$(subst $(space),$(comma),$(strip $(AB_OTA_PARTITIONS)))
+ADDITIONAL_PRODUCT_PROPERTIES += ro.product.ab_ota_partitions=$(subst $(space),$(comma),$(sort $(AB_OTA_PARTITIONS)))
 endif
 
 # -----------------------------------------------------------------
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 7f9dbe5..355cd3e 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -28,6 +28,7 @@
 $(call add_json_str,  Platform_sdk_codename,             $(PLATFORM_VERSION_CODENAME))
 $(call add_json_bool, Platform_sdk_final,                $(filter REL,$(PLATFORM_VERSION_CODENAME)))
 $(call add_json_val,  Platform_sdk_extension_version,    $(PLATFORM_SDK_EXTENSION_VERSION))
+$(call add_json_val,  Platform_base_sdk_extension_version, $(PLATFORM_BASE_SDK_EXTENSION_VERSION))
 $(call add_json_csv,  Platform_version_active_codenames, $(PLATFORM_VERSION_ALL_CODENAMES))
 $(call add_json_str,  Platform_security_patch,           $(PLATFORM_SECURITY_PATCH))
 $(call add_json_str,  Platform_preview_sdk_version,      $(PLATFORM_PREVIEW_SDK_VERSION))
@@ -206,6 +207,8 @@
 $(call add_json_list, SystemExtPrivateSepolicyDirs,      $(SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS) $(BOARD_PLAT_PRIVATE_SEPOLICY_DIR))
 $(call add_json_list, BoardSepolicyM4Defs,               $(BOARD_SEPOLICY_M4DEFS))
 $(call add_json_str,  BoardSepolicyVers,                 $(BOARD_SEPOLICY_VERS))
+$(call add_json_str,  SystemExtSepolicyPrebuiltApiDir,   $(BOARD_SYSTEM_EXT_PREBUILT_DIR))
+$(call add_json_str,  ProductSepolicyPrebuiltApiDir,     $(BOARD_PRODUCT_PREBUILT_DIR))
 
 $(call add_json_str,  PlatformSepolicyVersion,           $(PLATFORM_SEPOLICY_VERSION))
 $(call add_json_str,  TotSepolicyVersion,                $(TOT_SEPOLICY_VERSION))
diff --git a/core/tasks/module-info.mk b/core/tasks/module-info.mk
index 9acf6e8..e5ddb1a 100644
--- a/core/tasks/module-info.mk
+++ b/core/tasks/module-info.mk
@@ -26,6 +26,7 @@
 			'"is_unit_test": "$(ALL_MODULES.$(m).IS_UNIT_TEST)", ' \
 			'"data": [$(foreach w,$(sort $(ALL_MODULES.$(m).TEST_DATA)),"$(w)", )], ' \
 			'"runtime_dependencies": [$(foreach w,$(sort $(ALL_MODULES.$(m).LOCAL_RUNTIME_LIBRARIES)),"$(w)", )], ' \
+			'"data_dependencies": [$(foreach w,$(sort $(ALL_MODULES.$(m).TEST_DATA_BINS)),"$(w)", )], ' \
 			'},\n' \
 	 ) | sed -e 's/, *\]/]/g' -e 's/, *\}/ }/g' -e '$$s/,$$//' >> $@
 	$(hide) echo '}' >> $@
diff --git a/target/board/ndk/BoardConfig.mk b/target/board/ndk/BoardConfig.mk
new file mode 100644
index 0000000..da8b5f3
--- /dev/null
+++ b/target/board/ndk/BoardConfig.mk
@@ -0,0 +1,21 @@
+# Copyright (C) 2022 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_SUITE := ndk
+TARGET_USES_64_BIT_BINDER := true
+
+MALLOC_SVELTE := true
+
+USE_SAFESTACK := false
diff --git a/target/board/ndk/README.md b/target/board/ndk/README.md
new file mode 100644
index 0000000..d8f3a16
--- /dev/null
+++ b/target/board/ndk/README.md
@@ -0,0 +1,2 @@
+This device is suitable for a soong-only build that builds for all the architectures
+needed for the ndk.
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index 7d9d90e..ee702e5 100644
--- a/target/product/AndroidProducts.mk
+++ b/target/product/AndroidProducts.mk
@@ -61,6 +61,7 @@
     $(LOCAL_DIR)/mainline_system_x86.mk \
     $(LOCAL_DIR)/mainline_system_x86_64.mk \
     $(LOCAL_DIR)/mainline_system_x86_arm.mk \
+    $(LOCAL_DIR)/ndk.mk \
     $(LOCAL_DIR)/sdk_arm64.mk \
     $(LOCAL_DIR)/sdk.mk \
     $(LOCAL_DIR)/sdk_phone_arm64.mk \
diff --git a/target/product/core_no_zygote.mk b/target/product/core_no_zygote.mk
new file mode 100644
index 0000000..205a897
--- /dev/null
+++ b/target/product/core_no_zygote.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2022 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.
+#
+
+# Inherit from this product for devices that do not include a zygote using:
+# $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit_only.mk)
+# The inheritance for this must come before the inheritance chain that leads
+# to core_minimal.mk.
+
+# Copy the no-zygote startup script
+PRODUCT_COPY_FILES += system/core/rootdir/init.no_zygote.rc:system/etc/init/hw/init.no_zygote.rc
+
+# Set the zygote property to select the no-zygote script.
+# This line must be parsed before the one in core_minimal.mk
+PRODUCT_VENDOR_PROPERTIES += ro.zygote=no_zygote
+
+TARGET_SUPPORTS_32_BIT_APPS := false
+TARGET_SUPPORTS_64_BIT_APPS := false
diff --git a/target/product/ndk.mk b/target/product/ndk.mk
new file mode 100644
index 0000000..1dfd0db
--- /dev/null
+++ b/target/product/ndk.mk
@@ -0,0 +1,21 @@
+# Copyright (C) 2022 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.
+#
+
+# This device is suitable for soong-only build that builds for all the architectures
+# needed for the ndk. It is not going to work for normal `lunch <foo> && m` workflows.
+
+PRODUCT_NAME := ndk
+PRODUCT_BRAND := Android
+PRODUCT_DEVICE := ndk
diff --git a/target/product/virtual_ab_ota/compression.mk b/target/product/virtual_ab_ota/compression.mk
index d5bd2a5..88c58b8 100644
--- a/target/product/virtual_ab_ota/compression.mk
+++ b/target/product/virtual_ab_ota/compression.mk
@@ -18,7 +18,6 @@
 
 PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.enabled=true
 PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true
-PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.io_uring.enabled=true
 PRODUCT_VIRTUAL_AB_COMPRESSION := true
 PRODUCT_PACKAGES += \
     snapuserd.vendor_ramdisk \
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index 7b2c290..25483f3 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -558,6 +558,7 @@
 
 python_binary_host {
     name: "fsverity_manifest_generator",
+    defaults: ["releasetools_binary_defaults"],
     srcs: [
         "fsverity_manifest_generator.py",
     ],
@@ -574,6 +575,7 @@
 
 python_binary_host {
     name: "fsverity_metadata_generator",
+    defaults: ["releasetools_binary_defaults"],
     srcs: [
         "fsverity_metadata_generator.py",
     ],
diff --git a/tools/releasetools/apex_utils.py b/tools/releasetools/apex_utils.py
index 2a39f65..69d6c13 100644
--- a/tools/releasetools/apex_utils.py
+++ b/tools/releasetools/apex_utils.py
@@ -54,7 +54,7 @@
 class ApexApkSigner(object):
   """Class to sign the apk files and other files in an apex payload image and repack the apex"""
 
-  def __init__(self, apex_path, key_passwords, codename_to_api_level_map, avbtool=None, sign_tool=None):
+  def __init__(self, apex_path, key_passwords, codename_to_api_level_map, avbtool=None, sign_tool=None, fsverity_tool=None):
     self.apex_path = apex_path
     if not key_passwords:
       self.key_passwords = dict()
@@ -65,8 +65,9 @@
         OPTIONS.search_path, "bin", "debugfs_static")
     self.avbtool = avbtool if avbtool else "avbtool"
     self.sign_tool = sign_tool
+    self.fsverity_tool = fsverity_tool if fsverity_tool else "fsverity"
 
-  def ProcessApexFile(self, apk_keys, payload_key, signing_args=None):
+  def ProcessApexFile(self, apk_keys, payload_key, signing_args=None, is_sepolicy=False, sepolicy_key=None, sepolicy_cert=None):
     """Scans and signs the payload files and repack the apex
 
     Args:
@@ -84,10 +85,14 @@
                 self.debugfs_path, 'list', self.apex_path]
     entries_names = common.RunAndCheckOutput(list_cmd).split()
     apk_entries = [name for name in entries_names if name.endswith('.apk')]
+    sepolicy_entries = []
+    if is_sepolicy:
+      sepolicy_entries = [name for name in entries_names if
+          name.startswith('./etc/SEPolicy') and name.endswith('.zip')]
 
     # No need to sign and repack, return the original apex path.
-    if not apk_entries and self.sign_tool is None:
-      logger.info('No apk file to sign in %s', self.apex_path)
+    if not apk_entries and not sepolicy_entries and self.sign_tool is None:
+      logger.info('No payload (apk or zip) file to sign in %s', self.apex_path)
       return self.apex_path
 
     for entry in apk_entries:
@@ -101,15 +106,16 @@
         logger.warning('Apk path does not contain the intended directory name:'
                        ' %s', entry)
 
-    payload_dir, has_signed_content = self.ExtractApexPayloadAndSignContents(
-        apk_entries, apk_keys, payload_key, signing_args)
+    payload_dir, has_signed_content = self.ExtractApexPayloadAndSignContents(apk_entries,
+        apk_keys, payload_key, sepolicy_entries, sepolicy_key, sepolicy_cert, signing_args)
     if not has_signed_content:
       logger.info('No contents has been signed in %s', self.apex_path)
       return self.apex_path
 
     return self.RepackApexPayload(payload_dir, payload_key, signing_args)
 
-  def ExtractApexPayloadAndSignContents(self, apk_entries, apk_keys, payload_key, signing_args):
+  def ExtractApexPayloadAndSignContents(self, apk_entries, apk_keys, payload_key,
+  sepolicy_entries, sepolicy_key, sepolicy_cert, signing_args):
     """Extracts the payload image and signs the containing apk files."""
     if not os.path.exists(self.debugfs_path):
       raise ApexSigningError(
@@ -141,6 +147,11 @@
           codename_to_api_level_map=self.codename_to_api_level_map)
       has_signed_content = True
 
+    for entry in sepolicy_entries:
+      sepolicy_key = sepolicy_key if sepolicy_key else payload_key
+      self.SignSePolicy(payload_dir, entry, sepolicy_key, sepolicy_cert)
+      has_signed_content = True
+
     if self.sign_tool:
       logger.info('Signing payload contents in apex %s with %s', self.apex_path, self.sign_tool)
       # Pass avbtool to the custom signing tool
@@ -154,6 +165,36 @@
 
     return payload_dir, has_signed_content
 
+  def SignSePolicy(self, payload_dir, sepolicy_zip, sepolicy_key, sepolicy_cert):
+    sepolicy_sig = sepolicy_zip + '.sig'
+    sepolicy_fsv_sig = sepolicy_zip + '.fsv_sig'
+
+    policy_zip_path = os.path.join(payload_dir, sepolicy_zip)
+    sig_out_path = os.path.join(payload_dir, sepolicy_sig)
+    sig_old = sig_out_path + '.old'
+    if os.path.exists(sig_out_path):
+      os.rename(sig_out_path, sig_old)
+    sign_cmd = ['openssl', 'dgst', '-sign', sepolicy_key, '-keyform', 'PEM', '-sha256',
+        '-out', sig_out_path, '-binary', policy_zip_path]
+    common.RunAndCheckOutput(sign_cmd)
+    if os.path.exists(sig_old):
+      os.remove(sig_old)
+
+    if not sepolicy_cert:
+      logger.info('No cert provided for SEPolicy, skipping fsverity sign')
+      return
+
+    fsv_sig_out_path = os.path.join(payload_dir, sepolicy_fsv_sig)
+    fsv_sig_old = fsv_sig_out_path + '.old'
+    if os.path.exists(fsv_sig_out_path):
+      os.rename(fsv_sig_out_path, fsv_sig_old)
+
+    fsverity_cmd = [self.fsverity_tool, 'sign', policy_zip_path, fsv_sig_out_path,
+        '--key=' + sepolicy_key, '--cert=' + sepolicy_cert]
+    common.RunAndCheckOutput(fsverity_cmd)
+    if os.path.exists(fsv_sig_old):
+      os.remove(fsv_sig_old)
+
   def RepackApexPayload(self, payload_dir, payload_key, signing_args=None):
     """Rebuilds the apex file with the updated payload directory."""
     apex_dir = common.MakeTempDir()
@@ -324,7 +365,9 @@
 
 def SignUncompressedApex(avbtool, apex_file, payload_key, container_key,
                          container_pw, apk_keys, codename_to_api_level_map,
-                         no_hashtree, signing_args=None, sign_tool=None):
+                         no_hashtree, signing_args=None, sign_tool=None,
+                         is_sepolicy=False, sepolicy_key=None, sepolicy_cert=None,
+                         fsverity_tool=None):
   """Signs the current uncompressed APEX with the given payload/container keys.
 
   Args:
@@ -337,6 +380,10 @@
     no_hashtree: Don't include hashtree in the signed APEX.
     signing_args: Additional args to be passed to the payload signer.
     sign_tool: A tool to sign the contents of the APEX.
+    is_sepolicy: Indicates if the apex is a sepolicy.apex
+    sepolicy_key: Key to sign a sepolicy zip.
+    sepolicy_cert: Cert to sign a sepolicy zip.
+    fsverity_tool: fsverity path to sign sepolicy zip.
 
   Returns:
     The path to the signed APEX file.
@@ -345,8 +392,9 @@
   # the apex file after signing.
   apk_signer = ApexApkSigner(apex_file, container_pw,
                              codename_to_api_level_map,
-                             avbtool, sign_tool)
-  apex_file = apk_signer.ProcessApexFile(apk_keys, payload_key, signing_args)
+                             avbtool, sign_tool, fsverity_tool)
+  apex_file = apk_signer.ProcessApexFile(
+      apk_keys, payload_key, signing_args, is_sepolicy, sepolicy_key, sepolicy_cert)
 
   # 2a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
   # payload_key.
@@ -400,7 +448,9 @@
 
 def SignCompressedApex(avbtool, apex_file, payload_key, container_key,
                        container_pw, apk_keys, codename_to_api_level_map,
-                       no_hashtree, signing_args=None, sign_tool=None):
+                       no_hashtree, signing_args=None, sign_tool=None,
+                       is_sepolicy=False, sepolicy_key=None, sepolicy_cert=None,
+                       fsverity_tool=None):
   """Signs the current compressed APEX with the given payload/container keys.
 
   Args:
@@ -412,6 +462,10 @@
     codename_to_api_level_map: A dict that maps from codename to API level.
     no_hashtree: Don't include hashtree in the signed APEX.
     signing_args: Additional args to be passed to the payload signer.
+    is_sepolicy: Indicates if the apex is a sepolicy.apex
+    sepolicy_key: Key to sign a sepolicy zip.
+    sepolicy_cert: Cert to sign a sepolicy zip.
+    fsverity_tool: fsverity path to sign sepolicy zip.
 
   Returns:
     The path to the signed APEX file.
@@ -438,7 +492,11 @@
       codename_to_api_level_map,
       no_hashtree,
       signing_args,
-      sign_tool)
+      sign_tool,
+      is_sepolicy,
+      sepolicy_key,
+      sepolicy_cert,
+      fsverity_tool)
 
   # 3. Compress signed original apex.
   compressed_apex_file = common.MakeTempFile(prefix='apex-container-',
@@ -466,7 +524,8 @@
 
 def SignApex(avbtool, apex_data, payload_key, container_key, container_pw,
              apk_keys, codename_to_api_level_map,
-             no_hashtree, signing_args=None, sign_tool=None):
+             no_hashtree, signing_args=None, sign_tool=None,
+             is_sepolicy=False, sepolicy_key=None, sepolicy_cert=None, fsverity_tool=None):
   """Signs the current APEX with the given payload/container keys.
 
   Args:
@@ -478,6 +537,9 @@
     codename_to_api_level_map: A dict that maps from codename to API level.
     no_hashtree: Don't include hashtree in the signed APEX.
     signing_args: Additional args to be passed to the payload signer.
+    sepolicy_key: Key to sign a sepolicy zip.
+    sepolicy_cert: Cert to sign a sepolicy zip.
+    fsverity_tool: fsverity path to sign sepolicy zip.
 
   Returns:
     The path to the signed APEX file.
@@ -503,7 +565,11 @@
           no_hashtree=no_hashtree,
           apk_keys=apk_keys,
           signing_args=signing_args,
-          sign_tool=sign_tool)
+          sign_tool=sign_tool,
+          is_sepolicy=is_sepolicy,
+          sepolicy_key=sepolicy_key,
+          sepolicy_cert=sepolicy_cert,
+          fsverity_tool=fsverity_tool)
     elif apex_type == 'COMPRESSED':
       return SignCompressedApex(
           avbtool,
@@ -515,7 +581,11 @@
           no_hashtree=no_hashtree,
           apk_keys=apk_keys,
           signing_args=signing_args,
-          sign_tool=sign_tool)
+          sign_tool=sign_tool,
+          is_sepolicy=is_sepolicy,
+          sepolicy_key=sepolicy_key,
+          sepolicy_cert=sepolicy_cert,
+          fsverity_tool=fsverity_tool)
     else:
       # TODO(b/172912232): support signing compressed apex
       raise ApexInfoError('Unsupported apex type {}'.format(apex_type))
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 4b5846d..dbd2c6f 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -705,7 +705,7 @@
       if mount_point not in allowed_partitions:
           continue
 
-    if mount_point == "system_other":
+    if (mount_point == "system_other") and (dest_prop != "partition_size"):
       # Propagate system properties to system_other. They'll get overridden
       # after as needed.
       copy_prop(src_prop.format("system"), dest_prop)
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
index 6fc79d2..876e399 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -164,7 +164,7 @@
   """
   def PathToPatterns(path):
     if path[-1] == '/':
-      path += '*'
+      path += '**'
 
     # Loop over all the entries in DIR_SEARCH_PATHS and find one where the key
     # is a prefix of path. In order to get find the correct prefix, sort the
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 60a9265..107fad1 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1026,7 +1026,8 @@
 
     import_path = tokens[1]
     if not re.match(r'^/{}/.*\.prop$'.format(self.partition), import_path):
-      raise ValueError('Unrecognized import path {}'.format(line))
+      logger.warn('Unrecognized import path {}'.format(line))
+      return {}
 
     # We only recognize a subset of import statement that the init process
     # supports. And we can loose the restriction based on how the dynamic
@@ -2245,8 +2246,8 @@
   stdoutdata, stderrdata = proc.communicate()
   if proc.returncode != 0:
     raise ExternalError(
-        "Failed to obtain minSdkVersion: aapt2 return code {}:\n{}\n{}".format(
-            proc.returncode, stdoutdata, stderrdata))
+        "Failed to obtain minSdkVersion for {}: aapt2 return code {}:\n{}\n{}".format(
+            apk_name, proc.returncode, stdoutdata, stderrdata))
 
   for line in stdoutdata.split("\n"):
     # Looking for lines such as sdkVersion:'23' or sdkVersion:'M'.
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index da5e93f..1318e37 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -72,7 +72,8 @@
       files package and saves it at this path.
 
   --rebuild_recovery
-      Deprecated; does nothing.
+      Copy the recovery image used by non-A/B devices, used when
+      regenerating vendor images with --rebuild-sepolicy.
 
   --allow-duplicate-apkapex-keys
       If provided, duplicate APK/APEX keys are ignored and the value from the
@@ -127,7 +128,7 @@
 import sparse_img
 import verity_utils
 
-from common import AddCareMapForAbOta, ExternalError, PARTITIONS_WITH_CARE_MAP
+from common import ExternalError
 
 logger = logging.getLogger(__name__)
 
@@ -145,7 +146,6 @@
 OPTIONS.output_ota = None
 OPTIONS.output_img = None
 OPTIONS.output_super_empty = None
-# TODO(b/132730255): Remove this option.
 OPTIONS.rebuild_recovery = False
 # TODO(b/150582573): Remove this option.
 OPTIONS.allow_duplicate_apkapex_keys = False
@@ -826,10 +826,6 @@
         image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
         OPTIONS.info_dict[image_size_prop] = image_size
 
-  AddCareMapForAbOta(
-      os.path.join(output_target_files_dir, 'META', 'care_map.pb'),
-      PARTITIONS_WITH_CARE_MAP, partition_image_map)
-
 
 def process_special_cases(temp_dir, framework_meta, vendor_meta,
                           output_target_files_temp_dir,
@@ -843,11 +839,12 @@
 
   Args:
     temp_dir: Location containing an 'output' directory where target files have
-      been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES, etc.
+      been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES,
+      etc.
     framework_meta: The name of a directory containing the special items
       extracted from the framework target files package.
-    vendor_meta: The name of a directory containing the special items
-      extracted from the vendor target files package.
+    vendor_meta: The name of a directory containing the special items extracted
+      from the vendor target files package.
     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.
@@ -858,9 +855,7 @@
       partitions. Used to filter apexkeys.txt and apkcerts.txt.
     vendor_partition_set: Partitions that are considered vendor partitions. Used
       to filter apexkeys.txt and apkcerts.txt.
-
-    The following are only used if dexpreopt is applied:
-
+  Args used if dexpreopt is applied:
     framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
     framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
     vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
@@ -915,14 +910,14 @@
 
 
 def process_dexopt(temp_dir, framework_meta, vendor_meta,
-                   output_target_files_temp_dir,
-                   framework_dexpreopt_tools, framework_dexpreopt_config,
-                   vendor_dexpreopt_config):
+                   output_target_files_temp_dir, framework_dexpreopt_tools,
+                   framework_dexpreopt_config, vendor_dexpreopt_config):
   """If needed, generates dexopt files for vendor apps.
 
   Args:
     temp_dir: Location containing an 'output' directory where target files have
-      been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES, etc.
+      been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES,
+      etc.
     framework_meta: The name of a directory containing the special items
       extracted from the framework target files package.
     vendor_meta: The name of a directory containing the special items extracted
@@ -940,8 +935,7 @@
       os.path.join(vendor_meta, *misc_info_path))
 
   if (vendor_misc_info_dict.get('building_with_vsdk') != 'true' or
-      framework_dexpreopt_tools is None or
-      framework_dexpreopt_config is None or
+      framework_dexpreopt_tools is None or framework_dexpreopt_config is None or
       vendor_dexpreopt_config is None):
     return
 
@@ -984,8 +978,10 @@
   #                 package.vdex
   #                 package.odex
   dexpreopt_tools_files_temp_dir = os.path.join(temp_dir, 'tools')
-  dexpreopt_framework_config_files_temp_dir = os.path.join(temp_dir, 'system_config')
-  dexpreopt_vendor_config_files_temp_dir = os.path.join(temp_dir, 'vendor_config')
+  dexpreopt_framework_config_files_temp_dir = os.path.join(
+      temp_dir, 'system_config')
+  dexpreopt_vendor_config_files_temp_dir = os.path.join(temp_dir,
+                                                        'vendor_config')
 
   extract_items(
       target_files=OPTIONS.framework_dexpreopt_tools,
@@ -1000,10 +996,12 @@
       target_files_temp_dir=dexpreopt_vendor_config_files_temp_dir,
       extract_item_list=('*',))
 
-  os.symlink(os.path.join(output_target_files_temp_dir, "SYSTEM"),
-             os.path.join(temp_dir, "system"))
-  os.symlink(os.path.join(output_target_files_temp_dir, "VENDOR"),
-             os.path.join(temp_dir, "vendor"))
+  os.symlink(
+      os.path.join(output_target_files_temp_dir, 'SYSTEM'),
+      os.path.join(temp_dir, 'system'))
+  os.symlink(
+      os.path.join(output_target_files_temp_dir, 'VENDOR'),
+      os.path.join(temp_dir, 'vendor'))
 
   # The directory structure for flatteded APEXes is:
   #
@@ -1026,7 +1024,7 @@
   #         com.android.appsearch.apex
   #         com.android.art.apex
   #         ...
-  apex_root = os.path.join(output_target_files_temp_dir, "SYSTEM", "apex")
+  apex_root = os.path.join(output_target_files_temp_dir, 'SYSTEM', 'apex')
   framework_misc_info_dict = common.LoadDictionaryFromFile(
       os.path.join(framework_meta, *misc_info_path))
 
@@ -1094,13 +1092,14 @@
     dex_img = 'VENDOR'
     # Open vendor_filesystem_config to append the items generated by dexopt.
     vendor_file_system_config = open(
-        os.path.join(temp_dir, 'output', 'META', 'vendor_filesystem_config.txt'),
-        'a')
+        os.path.join(temp_dir, 'output', 'META',
+                     'vendor_filesystem_config.txt'), 'a')
 
   # Dexpreopt vendor apps.
   dexpreopt_config_suffix = '_dexpreopt.config'
-  for config in glob.glob(os.path.join(
-      dexpreopt_vendor_config_files_temp_dir, '*' + dexpreopt_config_suffix)):
+  for config in glob.glob(
+      os.path.join(dexpreopt_vendor_config_files_temp_dir,
+                   '*' + dexpreopt_config_suffix)):
     app = os.path.basename(config)[:-len(dexpreopt_config_suffix)]
     logging.info('dexpreopt config: %s %s', config, app)
 
@@ -1110,8 +1109,9 @@
       apk_dir = 'priv-app'
       apk_path = os.path.join(temp_dir, 'vendor', apk_dir, app, app + '.apk')
       if not os.path.exists(apk_path):
-        logging.warning('skipping dexpreopt for %s, no apk found in vendor/app '
-                        'or vendor/priv-app', app)
+        logging.warning(
+            'skipping dexpreopt for %s, no apk found in vendor/app '
+            'or vendor/priv-app', app)
         continue
 
     # Generate dexpreopting script. Note 'out_dir' is not the output directory
@@ -1121,10 +1121,11 @@
     command = [
         os.path.join(dexpreopt_tools_files_temp_dir, 'dexpreopt_gen'),
         '-global',
-        os.path.join(dexpreopt_framework_config_files_temp_dir, 'dexpreopt.config'),
+        os.path.join(dexpreopt_framework_config_files_temp_dir,
+                     'dexpreopt.config'),
         '-global_soong',
-        os.path.join(
-            dexpreopt_framework_config_files_temp_dir, 'dexpreopt_soong.config'),
+        os.path.join(dexpreopt_framework_config_files_temp_dir,
+                     'dexpreopt_soong.config'),
         '-module',
         config,
         '-dexpreopt_script',
@@ -1137,13 +1138,13 @@
     ]
 
     # Run the command from temp_dir so all tool paths are its descendants.
-    logging.info("running %s", command)
-    subprocess.check_call(command, cwd = temp_dir)
+    logging.info('running %s', command)
+    subprocess.check_call(command, cwd=temp_dir)
 
     # Call the generated script.
     command = ['sh', 'dexpreopt_app.sh', apk_path]
-    logging.info("running %s", command)
-    subprocess.check_call(command, cwd = temp_dir)
+    logging.info('running %s', command)
+    subprocess.check_call(command, cwd=temp_dir)
 
     # Output files are in:
     #
@@ -1171,14 +1172,17 @@
     # TODO(b/188179859): Support for other architectures.
     arch = 'arm64'
 
-    dex_destination = os.path.join(temp_dir, 'output', dex_img, apk_dir, app, 'oat', arch)
+    dex_destination = os.path.join(temp_dir, 'output', dex_img, apk_dir, app,
+                                   'oat', arch)
     os.makedirs(dex_destination)
-    dex2oat_path = os.path.join(
-        temp_dir, 'out', 'dex2oat_result', 'vendor', apk_dir, app, 'oat', arch)
-    shutil.copy(os.path.join(dex2oat_path, 'package.vdex'),
-                os.path.join(dex_destination, app + '.vdex'))
-    shutil.copy(os.path.join(dex2oat_path, 'package.odex'),
-                os.path.join(dex_destination, app + '.odex'))
+    dex2oat_path = os.path.join(temp_dir, 'out', 'dex2oat_result', 'vendor',
+                                apk_dir, app, 'oat', arch)
+    shutil.copy(
+        os.path.join(dex2oat_path, 'package.vdex'),
+        os.path.join(dex_destination, app + '.vdex'))
+    shutil.copy(
+        os.path.join(dex2oat_path, 'package.odex'),
+        os.path.join(dex_destination, app + '.odex'))
 
     # Append entries to vendor_file_system_config.txt, such as:
     #
@@ -1192,8 +1196,10 @@
       vendor_file_system_config.writelines([
           vendor_app_prefix + ' 0 2000 755 ' + selabel + '\n',
           vendor_app_prefix + '/' + arch + ' 0 2000 755 ' + selabel + '\n',
-          vendor_app_prefix + '/' + arch + '/' + app + '.odex 0 0 644 ' + selabel + '\n',
-          vendor_app_prefix + '/' + arch + '/' + app + '.vdex 0 0 644 ' + selabel + '\n',
+          vendor_app_prefix + '/' + arch + '/' + app + '.odex 0 0 644 ' +
+          selabel + '\n',
+          vendor_app_prefix + '/' + arch + '/' + app + '.vdex 0 0 644 ' +
+          selabel + '\n',
       ])
 
   if not use_system_other_odex:
@@ -1202,7 +1208,8 @@
     # TODO(b/188179859): Rebuilding a vendor image in GRF mode (e.g., T(framework)
     #                    and S(vendor) may require logic similar to that in
     #                    rebuild_image_with_sepolicy.
-    vendor_img = os.path.join(output_target_files_temp_dir, 'IMAGES', 'vendor.img')
+    vendor_img = os.path.join(output_target_files_temp_dir, 'IMAGES',
+                              'vendor.img')
     if os.path.exists(vendor_img):
       logging.info('Deleting %s', vendor_img)
       os.remove(vendor_img)
@@ -1210,9 +1217,8 @@
 
 def create_merged_package(temp_dir, framework_target_files, framework_item_list,
                           vendor_target_files, vendor_item_list,
-                          framework_misc_info_keys, rebuild_recovery,
-                          framework_dexpreopt_tools, framework_dexpreopt_config,
-                          vendor_dexpreopt_config):
+                          framework_misc_info_keys, framework_dexpreopt_tools,
+                          framework_dexpreopt_config, vendor_dexpreopt_config):
   """Merges two target files packages into one target files structure.
 
   Args:
@@ -1234,11 +1240,7 @@
     framework_misc_info_keys: A list of keys to obtain from the framework
       instance of META/misc_info.txt. The remaining keys should come 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.
-
-    The following are only used if dexpreopt is applied:
-
+  Args used if dexpreopt is applied:
     framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
     framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
     vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
@@ -1297,7 +1299,7 @@
   Args:
     target_files_dir: Path to merged temp directory.
     rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
-      devices and write it to the system image.
+      devices and write it to the vendor image.
   """
 
   # Regenerate IMAGES in the target directory.
@@ -1306,7 +1308,6 @@
       '--verbose',
       '--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)
@@ -1315,6 +1316,7 @@
 
 
 def rebuild_image_with_sepolicy(target_files_dir,
+                                rebuild_recovery,
                                 vendor_otatools=None,
                                 vendor_target_files=None):
   """Rebuilds odm.img or vendor.img to include merged sepolicy files.
@@ -1323,6 +1325,8 @@
 
   Args:
     target_files_dir: Path to the extracted merged target-files package.
+    rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
+      devices and use it when regenerating the vendor images.
     vendor_otatools: If not None, path to an otatools.zip from the vendor build
       that is used when recompiling the image.
     vendor_target_files: Expected if vendor_otatools is not None. Path to the
@@ -1333,6 +1337,7 @@
       os.path.join(target_files_dir, 'IMAGES/odm.img')):
     partition = 'odm'
   partition_img = '{}.img'.format(partition)
+  partition_map = '{}.map'.format(partition)
 
   logger.info('Recompiling %s using the merged sepolicy files.', partition_img)
 
@@ -1396,8 +1401,10 @@
         os.path.join(vendor_otatools_dir, 'bin', 'add_img_to_target_files'),
         '--verbose',
         '--add_missing',
-        vendor_target_files_dir,
     ]
+    if rebuild_recovery:
+      rebuild_partition_command.append('--rebuild_recovery')
+    rebuild_partition_command.append(vendor_target_files_dir)
     logger.info('Recompiling %s: %s', partition_img,
                 ' '.join(rebuild_partition_command))
     common.RunAndCheckOutput(rebuild_partition_command, verbose=True)
@@ -1408,6 +1415,23 @@
     shutil.move(
         os.path.join(vendor_target_files_dir, 'IMAGES', partition_img),
         os.path.join(target_files_dir, 'IMAGES', partition_img))
+    shutil.move(
+        os.path.join(vendor_target_files_dir, 'IMAGES', partition_map),
+        os.path.join(target_files_dir, 'IMAGES', partition_map))
+
+    def copy_recovery_file(filename):
+      for subdir in ('VENDOR', 'SYSTEM/vendor'):
+        source = os.path.join(vendor_target_files_dir, subdir, filename)
+        if os.path.exists(source):
+          dest = os.path.join(target_files_dir, subdir, filename)
+          shutil.copy(source, dest)
+          return
+      logger.info('Skipping copy_recovery_file for %s, file not found',
+                  filename)
+
+    if rebuild_recovery:
+      copy_recovery_file('etc/recovery.img')
+      copy_recovery_file('bin/install-recovery.sh')
 
 
 def generate_super_empty_image(target_dir, output_super_empty):
@@ -1531,13 +1555,11 @@
     output_super_empty: If provided, creates a super_empty.img file from the
       merged target files package and saves it at this path.
     rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
-      devices and write it to the system image.
+      devices and use it when regenerating the vendor images.
     vendor_otatools: Path to an otatools zip used for recompiling vendor images.
     rebuild_sepolicy: If true, rebuild odm.img (if target uses ODM) or
       vendor.img using a merged precompiled_sepolicy file.
-
-    The following are only used if dexpreopt is applied:
-
+  Args used if dexpreopt is applied:
     framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
     framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
     vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
@@ -1549,7 +1571,7 @@
   output_target_files_temp_dir = create_merged_package(
       temp_dir, framework_target_files, framework_item_list,
       vendor_target_files, vendor_item_list, framework_misc_info_keys,
-      rebuild_recovery, framework_dexpreopt_tools, framework_dexpreopt_config,
+      framework_dexpreopt_tools, framework_dexpreopt_config,
       vendor_dexpreopt_config)
 
   if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
@@ -1600,8 +1622,8 @@
   common.RunAndCheckOutput(split_sepolicy_cmd)
   # Include the compiled policy in an image if requested.
   if rebuild_sepolicy:
-    rebuild_image_with_sepolicy(output_target_files_temp_dir, vendor_otatools,
-                                vendor_target_files)
+    rebuild_image_with_sepolicy(output_target_files_temp_dir, rebuild_recovery,
+                                vendor_otatools, vendor_target_files)
 
   # Run validation checks on the pre-installed APEX files.
   validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
@@ -1715,7 +1737,7 @@
       OPTIONS.output_img = a
     elif o == '--output-super-empty':
       OPTIONS.output_super_empty = a
-    elif o == '--rebuild_recovery':  # TODO(b/132730255): Warn
+    elif o == '--rebuild_recovery':
       OPTIONS.rebuild_recovery = True
     elif o == '--allow-duplicate-apkapex-keys':
       OPTIONS.allow_duplicate_apkapex_keys = True
@@ -1770,7 +1792,8 @@
   if (args or OPTIONS.framework_target_files is None or
       OPTIONS.vendor_target_files is None or
       (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
-      (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
+      (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None) or
+      (OPTIONS.rebuild_recovery and not OPTIONS.rebuild_sepolicy)):
     common.Usage(__doc__)
     sys.exit(1)
 
@@ -1820,7 +1843,8 @@
           rebuild_sepolicy=OPTIONS.rebuild_sepolicy,
           framework_dexpreopt_tools=OPTIONS.framework_dexpreopt_tools,
           framework_dexpreopt_config=OPTIONS.framework_dexpreopt_config,
-          vendor_dexpreopt_config=OPTIONS.vendor_dexpreopt_config), OPTIONS.keep_tmp)
+          vendor_dexpreopt_config=OPTIONS.vendor_dexpreopt_config),
+      OPTIONS.keep_tmp)
 
 
 if __name__ == '__main__':
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
index 6896f83..5d403dc 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -569,7 +569,8 @@
       tokens.append('metadata.pb:' + ' ' * 15)
     else:
       tokens.append(ComputeEntryOffsetSize(METADATA_NAME))
-      tokens.append(ComputeEntryOffsetSize(METADATA_PROTO_NAME))
+      if METADATA_PROTO_NAME in zip_file.namelist():
+          tokens.append(ComputeEntryOffsetSize(METADATA_PROTO_NAME))
 
     return ','.join(tokens)
 
diff --git a/tools/releasetools/sign_apex.py b/tools/releasetools/sign_apex.py
index 66f5e05..01ee80b 100755
--- a/tools/releasetools/sign_apex.py
+++ b/tools/releasetools/sign_apex.py
@@ -42,6 +42,15 @@
 
   --sign_tool <sign_tool>
       Optional flag that specifies a custom signing tool for the contents of the apex.
+
+  --sepolicy_key <key>
+      Optional flag that specifies the sepolicy signing key, defaults to payload_key.
+
+  --sepolicy_cert <cert>
+      Optional flag that specifies the sepolicy signing cert.
+
+  --fsverity_tool <path>
+      Optional flag that specifies the path to fsverity tool to sign SEPolicy, defaults to fsverity.
 """
 
 import logging
@@ -55,7 +64,8 @@
 
 
 def SignApexFile(avbtool, apex_file, payload_key, container_key, no_hashtree,
-                 apk_keys=None, signing_args=None, codename_to_api_level_map=None, sign_tool=None):
+                 apk_keys=None, signing_args=None, codename_to_api_level_map=None, sign_tool=None,
+                 sepolicy_key=None, sepolicy_cert=None, fsverity_tool=None):
   """Signs the given apex file."""
   with open(apex_file, 'rb') as input_fp:
     apex_data = input_fp.read()
@@ -70,7 +80,11 @@
       no_hashtree=no_hashtree,
       apk_keys=apk_keys,
       signing_args=signing_args,
-      sign_tool=sign_tool)
+      sign_tool=sign_tool,
+      is_sepolicy=apex_file.endswith("sepolicy.apex"),
+      sepolicy_key=sepolicy_key,
+      sepolicy_cert=sepolicy_cert,
+      fsverity_tool=fsverity_tool)
 
 
 def main(argv):
@@ -106,6 +120,12 @@
         options['extra_apks'].update({n: key})
     elif o == '--sign_tool':
       options['sign_tool'] = a
+    elif o == '--sepolicy_key':
+      options['sepolicy_key'] = a
+    elif o == '--sepolicy_cert':
+      options['sepolicy_cert'] = a
+    elif o == '--fsverity_tool':
+      options['fsverity_tool'] = a
     else:
       return False
     return True
@@ -121,6 +141,9 @@
           'payload_key=',
           'extra_apks=',
           'sign_tool=',
+          'sepolicy_key=',
+          'sepolicy_cert=',
+          'fsverity_tool='
       ],
       extra_option_handler=option_handler)
 
@@ -141,7 +164,10 @@
       signing_args=options.get('payload_extra_args'),
       codename_to_api_level_map=options.get(
           'codename_to_api_level_map', {}),
-      sign_tool=options.get('sign_tool', None))
+      sign_tool=options.get('sign_tool', None),
+      sepolicy_key=options.get('sepolicy_key', None),
+      sepolicy_cert=options.get('sepolicy_cert', None),
+      fsverity_tool=options.get('fsverity_tool', None))
   shutil.copyfile(signed_apex, args[1])
   logger.info("done.")
 
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index adba866..e06f4e6 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -1244,6 +1244,7 @@
   logger.info("Building vendor partitions using vendor otatools.")
   vendor_tempdir = common.UnzipTemp(output_zip_path, [
       "META/*",
+      "SYSTEM/build.prop",
   ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
 
   # Disable various partitions that build based on misc_info fields.
@@ -1266,9 +1267,25 @@
     for key in sorted(vendor_misc_info):
       output.write("{}={}\n".format(key, vendor_misc_info[key]))
 
+  # Disable system partition by a placeholder of IMAGES/system.img,
+  # instead of removing SYSTEM folder.
+  # Because SYSTEM/build.prop is still needed for:
+  #   add_img_to_target_files.CreateImage ->
+  #   common.BuildInfo ->
+  #   common.BuildInfo.CalculateFingerprint
+  vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
+  if not os.path.exists(vendor_images_path):
+    os.makedirs(vendor_images_path)
+  with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
+    pass
+
   # Disable care_map.pb as not all ab_partitions are available when
   # vendor otatools regenerates vendor images.
-  os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
+  if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
+    os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
+  # Disable RADIO images
+  if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
+    os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
 
   # Build vendor images using vendor otatools.
   vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
@@ -1276,6 +1293,7 @@
   cmd = [
       os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
       "--is_signing",
+      "--add_missing",
       "--verbose",
       vendor_tempdir,
   ]
diff --git a/tools/releasetools/test_sign_apex.py b/tools/releasetools/test_sign_apex.py
index 8470f20..c344e22 100644
--- a/tools/releasetools/test_sign_apex.py
+++ b/tools/releasetools/test_sign_apex.py
@@ -71,3 +71,21 @@
         False,
         codename_to_api_level_map={'S': 31, 'Tiramisu' : 32})
     self.assertTrue(os.path.exists(signed_apex))
+
+  @test_utils.SkipIfExternalToolsUnavailable()
+  def test_SignApexWithSepolicy(self):
+    test_apex = os.path.join(self.testdata_dir, 'sepolicy.apex')
+    payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
+    container_key = os.path.join(self.testdata_dir, 'testkey')
+    sepolicy_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
+    sepolicy_cert = os.path.join(self.testdata_dir, 'testkey.x509.pem')
+    signed_test_apex = sign_apex.SignApexFile(
+        'avbtool',
+        test_apex,
+        payload_key,
+        container_key,
+        False,
+        None,
+        sepolicy_key=sepolicy_key,
+        sepolicy_cert=sepolicy_cert)
+    self.assertTrue(os.path.exists(signed_test_apex))
diff --git a/tools/releasetools/testdata/sepolicy.apex b/tools/releasetools/testdata/sepolicy.apex
new file mode 100644
index 0000000..f7d267d
--- /dev/null
+++ b/tools/releasetools/testdata/sepolicy.apex
Binary files differ