Merge "Skip building boot-(test-harness|debug).img if not needed"
diff --git a/core/Makefile b/core/Makefile
index 3eb20aa..4b2a331 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1601,6 +1601,18 @@
 
 endif # PRODUCT_USE_DYNAMIC_PARTITIONS
 
+# $(1) the partition variable component (eg SYSTEM)
+# $(2) the partition prefix in properties (eg system)
+# $(3) the image prop file
+# $(4) optional "other" size
+define add-sparse-flags-to-image-props
+$(eval _size := $(BOARD_$(1)IMAGE_PARTITION_SIZE))
+$(eval _reserved := $(BOARD_$(1)IMAGE_PARTITION_RESERVED_SIZE))
+$(eval _headroom := $(PRODUCT_$(1)_HEADROOM))
+$(if $(or $(_size), $(_reserved), $(_headroom), $(4)),,
+    $(hide) echo "$(2)_disable_sparse=true" >> $(3))
+endef
+
 # $(1): the path of the output dictionary file
 # $(2): a subset of "system vendor cache userdata product system_ext oem odm vendor_dlkm odm_dlkm"
 # $(3): additional "key=value" pairs to append to the dictionary file.
@@ -1621,11 +1633,14 @@
     $(if $(PRODUCT_SYSTEM_BASE_FS_PATH),$(hide) echo "system_base_fs_file=$(PRODUCT_SYSTEM_BASE_FS_PATH)" >> $(1))
     $(if $(PRODUCT_SYSTEM_HEADROOM),$(hide) echo "system_headroom=$(PRODUCT_SYSTEM_HEADROOM)" >> $(1))
     $(if $(BOARD_SYSTEMIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "system_reserved_size=$(BOARD_SYSTEMIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(call add-sparse-flags-to-image-props,SYSTEM,system,$(1))
     $(hide) echo "system_selinux_fc=$(SELINUX_FC)" >> $(1)
     $(hide) echo "building_system_image=$(BUILDING_SYSTEM_IMAGE)" >> $(1)
 )
 $(if $(filter $(2),system_other),\
     $(hide) echo "building_system_other_image=$(BUILDING_SYSTEM_OTHER_IMAGE)" >> $(1)
+    $(if $(INTERNAL_SYSTEM_OTHER_PARTITION_SIZE),,
+        $(hide) echo "system_other_disable_sparse=true" >> $(1))
 )
 $(if $(filter $(2),userdata),\
     $(if $(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "userdata_fs_type=$(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
@@ -1656,6 +1671,7 @@
     $(if $(BOARD_VENDORIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "vendor_squashfs_disable_4k_align=$(BOARD_VENDORIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
     $(if $(PRODUCT_VENDOR_BASE_FS_PATH),$(hide) echo "vendor_base_fs_file=$(PRODUCT_VENDOR_BASE_FS_PATH)" >> $(1))
     $(if $(BOARD_VENDORIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "vendor_reserved_size=$(BOARD_VENDORIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(call add-sparse-flags-to-image-props,VENDOR,vendor,$(1))
     $(hide) echo "vendor_selinux_fc=$(SELINUX_FC)" >> $(1)
     $(hide) echo "building_vendor_image=$(BUILDING_VENDOR_IMAGE)" >> $(1)
 )
@@ -1673,6 +1689,7 @@
     $(if $(BOARD_PRODUCTIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "product_squashfs_disable_4k_align=$(BOARD_PRODUCTIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
     $(if $(PRODUCT_PRODUCT_BASE_FS_PATH),$(hide) echo "product_base_fs_file=$(PRODUCT_PRODUCT_BASE_FS_PATH)" >> $(1))
     $(if $(BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "product_reserved_size=$(BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(call add-sparse-flags-to-image-props,PRODUCT,product,$(1))
     $(hide) echo "product_selinux_fc=$(SELINUX_FC)" >> $(1)
     $(hide) echo "building_product_image=$(BUILDING_PRODUCT_IMAGE)" >> $(1)
 )
@@ -1689,6 +1706,7 @@
     $(if $(BOARD_SYSTEM_EXTIMAGE_SQUASHFS_BLOCK_SIZE),$(hide) echo "system_ext_squashfs_block_size=$(BOARD_SYSTEM_EXTIMAGE_SQUASHFS_BLOCK_SIZE)" >> $(1))
     $(if $(BOARD_SYSTEM_EXTIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "system_ext_squashfs_disable_4k_align=$(BOARD_SYSTEM_EXTIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
     $(if $(BOARD_SYSTEM_EXTIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "system_ext_reserved_size=$(BOARD_SYSTEM_EXTIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(call add-sparse-flags-to-image-props,SYSTEM_EXT,system_ext,$(1))
     $(hide) echo "system_ext_selinux_fc=$(SELINUX_FC)" >> $(1)
     $(hide) echo "building_system_ext_image=$(BUILDING_SYSTEM_EXT_IMAGE)" >> $(1)
 )
@@ -1704,6 +1722,7 @@
     $(if $(BOARD_ODMIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "odm_squashfs_disable_4k_align=$(BOARD_ODMIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
     $(if $(PRODUCT_ODM_BASE_FS_PATH),$(hide) echo "odm_base_fs_file=$(PRODUCT_ODM_BASE_FS_PATH)" >> $(1))
     $(if $(BOARD_ODMIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "odm_reserved_size=$(BOARD_ODMIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(call add-sparse-flags-to-image-props,ODM,odm,$(1))
     $(hide) echo "odm_selinux_fc=$(SELINUX_FC)" >> $(1)
     $(hide) echo "building_odm_image=$(BUILDING_ODM_IMAGE)" >> $(1)
 )
@@ -1720,6 +1739,7 @@
     $(if $(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_BLOCK_SIZE),$(hide) echo "vendor_dlkm_squashfs_block_size=$(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_BLOCK_SIZE)" >> $(1))
     $(if $(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "vendor_dlkm_squashfs_disable_4k_align=$(BOARD_VENDOR_DLKMIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
     $(if $(BOARD_VENDOR_DLKMIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "vendor_dlkm_reserved_size=$(BOARD_VENDOR_DLKMIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(call add-sparse-flags-to-image-props,VENDOR_DLKM,vendor_dlkm,$(1))
     $(hide) echo "vendor_dlkm_selinux_fc=$(SELINUX_FC)" >> $(1)
     $(hide) echo "building_vendor_dlkm_image=$(BUILDING_VENDOR_DLKM_IMAGE)" >> $(1)
 )
@@ -1734,6 +1754,7 @@
     $(if $(BOARD_ODM_DLKMIMAGE_SQUASHFS_BLOCK_SIZE),$(hide) echo "odm_dlkm_squashfs_block_size=$(BOARD_ODM_DLKMIMAGE_SQUASHFS_BLOCK_SIZE)" >> $(1))
     $(if $(BOARD_ODM_DLKMIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "odm_dlkm_squashfs_disable_4k_align=$(BOARD_ODM_DLKMIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1))
     $(if $(BOARD_ODM_DLKMIMAGE_PARTITION_RESERVED_SIZE),$(hide) echo "odm_dlkm_reserved_size=$(BOARD_ODM_DLKMIMAGE_PARTITION_RESERVED_SIZE)" >> $(1))
+    $(call add-sparse-flags-to-image-props,ODM_DLKM,odm_dlkm,$(1))
     $(hide) echo "odm_dlkm_selinux_fc=$(SELINUX_FC)" >> $(1)
     $(hide) echo "building_odm_dlkm_image=$(BUILDING_ODM_DLKM_IMAGE)" >> $(1)
 )
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index fe97047..2197eb9 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -36,7 +36,9 @@
   $(call add_soong_config_namespace,art_module)
   SOONG_CONFIG_art_module += source_build
 endif
-ifneq (,$(findstring .android.art,$(TARGET_BUILD_APPS)))
+ifneq (,$(SOONG_CONFIG_art_module_source_build))
+  # Keep an explicit setting.
+else ifneq (,$(findstring .android.art,$(TARGET_BUILD_APPS)))
   # Build ART modules from source if they are listed in TARGET_BUILD_APPS.
   SOONG_CONFIG_art_module_source_build := true
 else ifeq (,$(filter-out modules_% mainline_modules_%,$(TARGET_PRODUCT)))
diff --git a/core/host_java_library.mk b/core/host_java_library.mk
index 0f95202..07797c8 100644
--- a/core/host_java_library.mk
+++ b/core/host_java_library.mk
@@ -131,3 +131,8 @@
 ifeq ($(TURBINE_ENABLED),false)
 $(eval $(call copy-one-file,$(LOCAL_FULL_CLASSES_JACOCO_JAR),$(full_classes_header_jar)))
 endif
+
+#######################################
+# Capture deps added after base_rules.mk
+include $(BUILD_NOTICE_FILE)
+#######################################
diff --git a/core/main.mk b/core/main.mk
index e1cfead..6b8080c 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1670,8 +1670,7 @@
     $(INSTALLED_FILES_JSON_ROOT) \
     $(INSTALLED_FILES_FILE_RECOVERY) \
     $(INSTALLED_FILES_JSON_RECOVERY) \
-    $(INSTALLED_ANDROID_INFO_TXT_TARGET) \
-    soong_docs
+    $(INSTALLED_ANDROID_INFO_TXT_TARGET)
 
 # The droidcore target depends on the droidcore-unbundled subset and any other
 # targets for a non-unbundled (full source) full system build.
diff --git a/core/soong_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index 82fb413..eeac9aa 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -254,3 +254,8 @@
 endif
 
 SOONG_ALREADY_CONV += $(LOCAL_MODULE)
+
+#######################################
+# Capture deps added after base_rules.mk
+include $(BUILD_NOTICE_FILE)
+#######################################
diff --git a/core/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index 1ebbf14..1b93be2 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -206,3 +206,8 @@
 		$(hide) touch $@)
 
 SOONG_ALREADY_CONV += $(LOCAL_MODULE)
+
+#######################################
+# Capture deps added after base_rules.mk
+include $(BUILD_NOTICE_FILE)
+#######################################
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index a358005..c8fa49f 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -247,7 +247,7 @@
     #  It must be of the form "YYYY-MM-DD" on production devices.
     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
-      PLATFORM_SECURITY_PATCH := 2021-08-05
+      PLATFORM_SECURITY_PATCH := 2021-09-05
 endif
 .KATI_READONLY := PLATFORM_SECURITY_PATCH
 
diff --git a/envsetup.sh b/envsetup.sh
index 6085f7a..d70e815 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -1707,7 +1707,7 @@
 function b()
 (
     # Generate BUILD, bzl files into the synthetic Bazel workspace (out/soong/workspace).
-    _trigger_build "all-modules" nothing GENERATE_BAZEL_FILES=true USE_BAZEL_ANALYSIS= || return 1
+    _trigger_build "all-modules" bp2build USE_BAZEL_ANALYSIS= || return 1
     # Then, run Bazel using the synthetic workspace as the --package_path.
     if [[ -z "$@" ]]; then
         # If there are no args, show help.
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index 6f4b7f1..755d85e 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -93,6 +93,8 @@
 VNDK-core: android.hardware.power-V1-ndk_platform.so
 VNDK-core: android.hardware.power.stats-V1-ndk.so
 VNDK-core: android.hardware.power.stats-V1-ndk_platform.so
+VNDK-core: android.hardware.radio-V1-ndk.so
+VNDK-core: android.hardware.radio-V1-ndk_platform.so
 VNDK-core: android.hardware.rebootescrow-V1-ndk.so
 VNDK-core: android.hardware.rebootescrow-V1-ndk_platform.so
 VNDK-core: android.hardware.security.keymint-V1-ndk.so
@@ -107,6 +109,8 @@
 VNDK-core: android.hardware.vibrator-V1-ndk_platform.so
 VNDK-core: android.hardware.weaver-V1-ndk.so
 VNDK-core: android.hardware.weaver-V1-ndk_platform.so
+VNDK-core: android.hardware.wifi.hostapd-V1-ndk.so
+VNDK-core: android.hardware.wifi.hostapd-V1-ndk_platform.so
 VNDK-core: android.hidl.token@1.0-utils.so
 VNDK-core: android.hidl.token@1.0.so
 VNDK-core: android.system.keystore2-V1-ndk.so
diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk
index d924d0b..bd7c4ab 100644
--- a/target/product/gsi_release.mk
+++ b/target/product/gsi_release.mk
@@ -74,3 +74,7 @@
 
 # Always build modules from source
 MODULE_BUILD_FROM_SOURCE := true
+
+# Additional settings used in all GSI builds
+PRODUCT_PRODUCT_PROPERTIES += \
+    ro.crypto.metadata_init_delete_all_keys.enabled=false \
diff --git a/tools/check_elf_file.py b/tools/check_elf_file.py
index 1ff8e65..045cb1d 100755
--- a/tools/check_elf_file.py
+++ b/tools/check_elf_file.py
@@ -195,10 +195,12 @@
   @classmethod
   def _read_llvm_readobj(cls, elf_file_path, header, llvm_readobj):
     """Run llvm-readobj and parse the output."""
-    proc = subprocess.Popen(
-      [llvm_readobj, '-dynamic-table', '-dyn-symbols', elf_file_path],
-      stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    cmd = [llvm_readobj, '--dynamic-table', '--dyn-symbols', elf_file_path]
+    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     out, _ = proc.communicate()
+    rc = proc.returncode
+    if rc != 0:
+      raise subprocess.CalledProcessError(rc, cmd, out)
     lines = out.splitlines()
     return cls._parse_llvm_readobj(elf_file_path, header, lines)
 
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index f3b58f8..5275087 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -42,6 +42,10 @@
   --is_signing
       Skip building & adding the images for "userdata" and "cache" if we
       are signing the target files.
+
+  --skip_list <partitions>
+      Optional comma-separated list of partitions to skip when
+      processing the zipfile.
 """
 
 from __future__ import print_function
@@ -78,6 +82,7 @@
 OPTIONS.replace_verity_public_key = False
 OPTIONS.replace_verity_private_key = False
 OPTIONS.is_signing = False
+OPTIONS.skip_list = []
 
 # Use a fixed timestamp (01/01/2009 00:00:00 UTC) for files when packaging
 # images. (b/24377993, b/80600931)
@@ -589,7 +594,7 @@
     AssertionError: If it can't find an image.
   """
   for partition in ab_partitions:
-    img_name = partition.strip() + ".img"
+    img_name = partition + ".img"
 
     # Assert that the image is present under IMAGES/ now.
     if output_zip:
@@ -796,7 +801,7 @@
     logger.info("\n\n++++ %s  ++++\n\n", s)
 
   boot_image = None
-  if has_boot:
+  if has_boot and "boot" not in OPTIONS.skip_list:
     banner("boot")
     boot_images = OPTIONS.info_dict.get("boot_images")
     if boot_images is None:
@@ -817,7 +822,7 @@
           if output_zip:
             boot_image.AddToZip(output_zip)
 
-  if has_vendor_boot:
+  if has_vendor_boot and "vendor_boot" not in OPTIONS.skip_list:
     banner("vendor_boot")
     vendor_boot_image = common.GetVendorBootImage(
         "IMAGES/vendor_boot.img", "vendor_boot.img", OPTIONS.input_tmp,
@@ -831,7 +836,7 @@
           vendor_boot_image.AddToZip(output_zip)
 
   recovery_image = None
-  if has_recovery:
+  if has_recovery and "recovery" not in OPTIONS.skip_list:
     banner("recovery")
     recovery_image = common.GetBootableImage(
         "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
@@ -856,59 +861,39 @@
         if output_zip:
           recovery_two_step_image.AddToZip(output_zip)
 
-  if has_system:
-    banner("system")
-    partitions['system'] = AddSystem(
-        output_zip, recovery_img=recovery_image, boot_img=boot_image)
+  def add_partition(call):
+    partition, has_partition, add_func, add_args = call
+    if has_partition and partition not in OPTIONS.skip_list:
+      banner(partition)
+      partitions[partition] = add_func(output_zip, *add_args)
 
-  if has_vendor:
-    banner("vendor")
-    partitions['vendor'] = AddVendor(
-        output_zip, recovery_img=recovery_image, boot_img=boot_image)
-
-  if has_product:
-    banner("product")
-    partitions['product'] = AddProduct(output_zip)
-
-  if has_system_ext:
-    banner("system_ext")
-    partitions['system_ext'] = AddSystemExt(output_zip)
-
-  if has_odm:
-    banner("odm")
-    partitions['odm'] = AddOdm(output_zip)
-
-  if has_vendor_dlkm:
-    banner("vendor_dlkm")
-    partitions['vendor_dlkm'] = AddVendorDlkm(output_zip)
-
-  if has_odm_dlkm:
-    banner("odm_dlkm")
-    partitions['odm_dlkm'] = AddOdmDlkm(output_zip)
-
-  if has_system_other:
-    banner("system_other")
-    AddSystemOther(output_zip)
+  add_partition_calls = (
+      ("system", has_system, AddSystem, [recovery_image, boot_image]),
+      ("vendor", has_vendor, AddVendor, [recovery_image, boot_image]),
+      ("product", has_product, AddProduct, []),
+      ("system_ext", has_system_ext, AddSystemExt, []),
+      ("odm", has_odm, AddOdm, []),
+      ("vendor_dlkm", has_vendor_dlkm, AddVendorDlkm, []),
+      ("odm_dlkm", has_odm_dlkm, AddOdmDlkm, []),
+      ("system_other", has_system_other, AddSystemOther, []),
+  )
+  for call in add_partition_calls:
+    add_partition(call)
 
   AddApexInfo(output_zip)
 
   if not OPTIONS.is_signing:
-    banner("userdata")
-    AddUserdata(output_zip)
-    banner("cache")
-    AddCache(output_zip)
+    add_partition(("userdata", True, AddUserdata, []))
+    add_partition(("cache", True, AddUserdata, []))
 
   if OPTIONS.info_dict.get("board_bpt_enable") == "true":
     banner("partition-table")
     AddPartitionTable(output_zip)
 
-  if OPTIONS.info_dict.get("has_dtbo") == "true":
-    banner("dtbo")
-    partitions['dtbo'] = AddDtbo(output_zip)
-
-  if OPTIONS.info_dict.get("has_pvmfw") == "true":
-    banner("pvmfw")
-    partitions['pvmfw'] = AddPvmfw(output_zip)
+  add_partition(
+      ("dtbo", OPTIONS.info_dict.get("has_dtbo") == "true", AddDtbo, []))
+  add_partition(
+      ("pvmfw", OPTIONS.info_dict.get("has_pvmfw") == "true", AddPvmfw, []))
 
   # Custom images.
   custom_partitions = OPTIONS.info_dict.get(
@@ -926,7 +911,7 @@
     vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(custom_partitions)
 
     vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
-    if vbmeta_system:
+    if vbmeta_system and "vbmeta_system" not in OPTIONS.skip_list:
       banner("vbmeta_system")
       partitions["vbmeta_system"] = AddVBMeta(
           output_zip, partitions, "vbmeta_system", vbmeta_system.split())
@@ -936,7 +921,7 @@
       vbmeta_partitions.append("vbmeta_system")
 
     vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip()
-    if vbmeta_vendor:
+    if vbmeta_vendor and "vbmeta_vendor" not in OPTIONS.skip_list:
       banner("vbmeta_vendor")
       partitions["vbmeta_vendor"] = AddVBMeta(
           output_zip, partitions, "vbmeta_vendor", vbmeta_vendor.split())
@@ -945,16 +930,20 @@
           if item not in vbmeta_vendor.split()]
       vbmeta_partitions.append("vbmeta_vendor")
 
-    if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
+    if OPTIONS.info_dict.get("avb_building_vbmeta_image"
+                            ) == "true" and "vbmeta" not in OPTIONS.skip_list:
       banner("vbmeta")
       AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)
 
   if OPTIONS.info_dict.get("use_dynamic_partitions") == "true":
-    if OPTIONS.info_dict.get("build_super_empty_partition") == "true":
+    if OPTIONS.info_dict.get(
+        "build_super_empty_partition"
+    ) == "true" and "super_empty" not in OPTIONS.skip_list:
       banner("super_empty")
       AddSuperEmpty(output_zip)
 
-  if OPTIONS.info_dict.get("build_super_partition") == "true":
+  if OPTIONS.info_dict.get(
+      "build_super_partition") == "true" and "super" not in OPTIONS.skip_list:
     if OPTIONS.info_dict.get(
         "build_retrofit_dynamic_partitions_ota_package") == "true":
       banner("super split images")
@@ -965,17 +954,20 @@
                                    "ab_partitions.txt")
   if os.path.exists(ab_partitions_txt):
     with open(ab_partitions_txt) as f:
-      ab_partitions = f.readlines()
+      ab_partitions = f.read().splitlines()
 
-    # For devices using A/B update, make sure we have all the needed images
-    # ready under IMAGES/ or RADIO/.
-    CheckAbOtaImages(output_zip, ab_partitions)
+    # Skip care_map generation if any A/B partitions are in the skip list,
+    # since this file cannot be generated without those partitions.
+    if not set(ab_partitions).intersection(set(OPTIONS.skip_list)):
+      # For devices using A/B update, make sure we have all the needed images
+      # ready under IMAGES/ or RADIO/.
+      CheckAbOtaImages(output_zip, ab_partitions)
 
-    # Generate care_map.pb for ab_partitions, then write this file to
-    # target_files package.
-    output_care_map = os.path.join(OPTIONS.input_tmp, "META", "care_map.pb")
-    AddCareMapForAbOta(output_zip if output_zip else output_care_map,
-                       ab_partitions, partitions)
+      # Generate care_map.pb for ab_partitions, then write this file to
+      # target_files package.
+      output_care_map = os.path.join(OPTIONS.input_tmp, "META", "care_map.pb")
+      AddCareMapForAbOta(output_zip if output_zip else output_care_map,
+                         ab_partitions, partitions)
 
   # Radio images that need to be packed into IMAGES/, and product-img.zip.
   pack_radioimages_txt = os.path.join(
@@ -984,7 +976,8 @@
     with open(pack_radioimages_txt) as f:
       AddPackRadioImages(output_zip, f.readlines())
 
-  AddVbmetaDigest(output_zip)
+  if "vbmeta" not in OPTIONS.skip_list:
+    AddVbmetaDigest(output_zip)
 
   if output_zip:
     common.ZipClose(output_zip)
@@ -1005,6 +998,8 @@
       OPTIONS.replace_verity_public_key = (True, a)
     elif o == "--is_signing":
       OPTIONS.is_signing = True
+    elif o == "--skip_list":
+      OPTIONS.skip_list = a.split(',')
     else:
       return False
     return True
@@ -1014,7 +1009,7 @@
       extra_long_opts=["add_missing", "rebuild_recovery",
                        "replace_verity_public_key=",
                        "replace_verity_private_key=",
-                       "is_signing"],
+                       "is_signing","skip_list="],
       extra_option_handler=option_handler)
 
   if len(args) != 1:
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index f2ba321..1fe468e 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -256,9 +256,11 @@
   needs_casefold = prop_dict.get("needs_casefold", 0)
   needs_compress = prop_dict.get("needs_compress", 0)
 
+  disable_sparse = "disable_sparse" in prop_dict
+
   if fs_type.startswith("ext"):
     build_command = [prop_dict["ext_mkuserimg"]]
-    if "extfs_sparse_flag" in prop_dict:
+    if "extfs_sparse_flag" in prop_dict and not disable_sparse:
       build_command.append(prop_dict["extfs_sparse_flag"])
       run_e2fsck = True
     build_command.extend([in_dir, out_file, fs_type,
@@ -303,7 +305,7 @@
   elif fs_type.startswith("erofs"):
     build_command = ["mkerofsimage.sh"]
     build_command.extend([in_dir, out_file])
-    if "erofs_sparse_flag" in prop_dict:
+    if "erofs_sparse_flag" in prop_dict and not disable_sparse:
       build_command.extend([prop_dict["erofs_sparse_flag"]])
     build_command.extend(["-m", prop_dict["mount_point"]])
     if target_out:
@@ -319,7 +321,7 @@
   elif fs_type.startswith("squash"):
     build_command = ["mksquashfsimage.sh"]
     build_command.extend([in_dir, out_file])
-    if "squashfs_sparse_flag" in prop_dict:
+    if "squashfs_sparse_flag" in prop_dict and not disable_sparse:
       build_command.extend([prop_dict["squashfs_sparse_flag"]])
     build_command.extend(["-m", prop_dict["mount_point"]])
     if target_out:
@@ -341,7 +343,7 @@
   elif fs_type.startswith("f2fs"):
     build_command = ["mkf2fsuserimg.sh"]
     build_command.extend([out_file, prop_dict["image_size"]])
-    if "f2fs_sparse_flag" in prop_dict:
+    if "f2fs_sparse_flag" in prop_dict and not disable_sparse:
       build_command.extend([prop_dict["f2fs_sparse_flag"]])
     if fs_config:
       build_command.extend(["-C", fs_config])
@@ -448,17 +450,20 @@
   # or None if not applicable.
   verity_image_builder = verity_utils.CreateVerityImageBuilder(prop_dict)
 
+  disable_sparse = "disable_sparse" in prop_dict
+  mkfs_output = None
   if (prop_dict.get("use_dynamic_partition_size") == "true" and
       "partition_size" not in prop_dict):
     # If partition_size is not defined, use output of `du' + reserved_size.
     # For compressed file system, it's better to use the compressed size to avoid wasting space.
     if fs_type.startswith("erofs"):
-      tmp_dict = prop_dict.copy()
-      if "erofs_sparse_flag" in tmp_dict:
-        tmp_dict.pop("erofs_sparse_flag")
-      BuildImageMkfs(in_dir, tmp_dict, out_file, target_out, fs_config)
-      size = GetDiskUsage(out_file)
-      os.remove(out_file)
+      mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
+      if "erofs_sparse_flag" in prop_dict and not disable_sparse:
+        image_path = UnsparseImage(out_file, replace=False)
+        size = GetDiskUsage(image_path)
+        os.remove(image_path)
+      else:
+        size = GetDiskUsage(out_file)
     else:
       size = GetDiskUsage(in_dir)
     logger.info(
@@ -481,7 +486,7 @@
           size // BYTES_IN_MB, prop_dict["extfs_inode_count"])
       BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
       sparse_image = False
-      if "extfs_sparse_flag" in prop_dict:
+      if "extfs_sparse_flag" in prop_dict and not disable_sparse:
         sparse_image = True
       fs_dict = GetFilesystemCharacteristics(fs_type, out_file, sparse_image)
       os.remove(out_file)
@@ -525,7 +530,7 @@
       prop_dict["image_size"] = str(size)
       BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
       sparse_image = False
-      if "f2fs_sparse_flag" in prop_dict:
+      if "f2fs_sparse_flag" in prop_dict and not disable_sparse:
         sparse_image = True
       fs_dict = GetFilesystemCharacteristics(fs_type, out_file, sparse_image)
       os.remove(out_file)
@@ -546,7 +551,8 @@
     max_image_size = verity_image_builder.CalculateMaxImageSize()
     prop_dict["image_size"] = str(max_image_size)
 
-  mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
+  if not mkfs_output:
+    mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
 
   # Check if there's enough headroom space available for ext4 image.
   if "partition_headroom" in prop_dict and fs_type.startswith("ext4"):
@@ -642,6 +648,7 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("system_reserved_size", "partition_reserved_size")
     copy_prop("system_selinux_fc", "selinux_fc")
+    copy_prop("system_disable_sparse", "disable_sparse")
   elif mount_point == "system_other":
     # We inherit the selinux policies of /system since we contain some of its
     # files.
@@ -668,6 +675,7 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("system_reserved_size", "partition_reserved_size")
     copy_prop("system_selinux_fc", "selinux_fc")
+    copy_prop("system_disable_sparse", "disable_sparse")
   elif mount_point == "data":
     # Copy the generic fs type first, override with specific one if available.
     copy_prop("fs_type", "fs_type")
@@ -708,6 +716,7 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("vendor_reserved_size", "partition_reserved_size")
     copy_prop("vendor_selinux_fc", "selinux_fc")
+    copy_prop("vendor_disable_sparse", "disable_sparse")
   elif mount_point == "product":
     copy_prop("avb_product_hashtree_enable", "avb_hashtree_enable")
     copy_prop("avb_product_add_hashtree_footer_args",
@@ -733,6 +742,7 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("product_reserved_size", "partition_reserved_size")
     copy_prop("product_selinux_fc", "selinux_fc")
+    copy_prop("product_disable_sparse", "disable_sparse")
   elif mount_point == "system_ext":
     copy_prop("avb_system_ext_hashtree_enable", "avb_hashtree_enable")
     copy_prop("avb_system_ext_add_hashtree_footer_args",
@@ -760,6 +770,7 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("system_ext_reserved_size", "partition_reserved_size")
     copy_prop("system_ext_selinux_fc", "selinux_fc")
+    copy_prop("system_ext_disable_sparse", "disable_sparse")
   elif mount_point == "odm":
     copy_prop("avb_odm_hashtree_enable", "avb_hashtree_enable")
     copy_prop("avb_odm_add_hashtree_footer_args",
@@ -783,6 +794,7 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("odm_reserved_size", "partition_reserved_size")
     copy_prop("odm_selinux_fc", "selinux_fc")
+    copy_prop("odm_disable_sparse", "disable_sparse")
   elif mount_point == "vendor_dlkm":
     copy_prop("avb_vendor_dlkm_hashtree_enable", "avb_hashtree_enable")
     copy_prop("avb_vendor_dlkm_add_hashtree_footer_args",
@@ -808,6 +820,7 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("vendor_dlkm_reserved_size", "partition_reserved_size")
     copy_prop("vendor_dlkm_selinux_fc", "selinux_fc")
+    copy_prop("vendor_dlkm_disable_sparse", "disable_sparse")
   elif mount_point == "odm_dlkm":
     copy_prop("avb_odm_dlkm_hashtree_enable", "avb_hashtree_enable")
     copy_prop("avb_odm_dlkm_add_hashtree_footer_args",
@@ -831,6 +844,7 @@
       d["extfs_rsv_pct"] = "0"
     copy_prop("odm_dlkm_reserved_size", "partition_reserved_size")
     copy_prop("odm_dlkm_selinux_fc", "selinux_fc")
+    copy_prop("odm_dlkm_disable_sparse", "disable_sparse")
   elif mount_point == "oem":
     copy_prop("fs_type", "fs_type")
     copy_prop("oem_size", "partition_size")
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index f30e382..c6800e8 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1983,6 +1983,8 @@
     info_dict = LoadInfoDict(input_zip)
 
   is_sparse = info_dict.get("extfs_sparse_flag")
+  if info_dict.get(which + "_disable_sparse"):
+    is_sparse = False
 
   # When target uses 'BOARD_EXT4_SHARE_DUP_BLOCKS := true', images may contain
   # shared blocks (i.e. some blocks will show up in multiple files' block
@@ -3851,12 +3853,14 @@
   if not image_size:
     return None
 
+  disable_sparse = OPTIONS.info_dict.get(which + "_disable_sparse")
+
   image_blocks = int(image_size) // 4096 - 1
   assert image_blocks > 0, "blocks for {} must be positive".format(which)
 
   # For sparse images, we will only check the blocks that are listed in the care
   # map, i.e. the ones with meaningful data.
-  if "extfs_sparse_flag" in OPTIONS.info_dict:
+  if "extfs_sparse_flag" in OPTIONS.info_dict and not disable_sparse:
     simg = sparse_img.SparseImage(imgname)
     care_map_ranges = simg.care_map.intersect(
         rangelib.RangeSet("0-{}".format(image_blocks)))
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 40da34d..4eb2f0c 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -225,6 +225,8 @@
   --enable_vabc_xor
       Enable the VABC xor feature. Will reduce space requirements for OTA
 
+  --force_minor_version
+      Override the update_engine minor version for delta generation.
 """
 
 from __future__ import print_function
@@ -291,6 +293,7 @@
 OPTIONS.spl_downgrade = False
 OPTIONS.vabc_downgrade = False
 OPTIONS.enable_vabc_xor = True
+OPTIONS.force_minor_version = None
 
 POSTINSTALL_CONFIG = 'META/postinstall_config.txt'
 DYNAMIC_PARTITION_INFO = 'META/dynamic_partitions_info.txt'
@@ -1144,6 +1147,8 @@
     additional_args += ["--disable_vabc", "true"]
   if OPTIONS.enable_vabc_xor:
     additional_args += ["--enable_vabc_xor", "true"]
+  if OPTIONS.force_minor_version:
+    additional_args += ["--force_minor_version", OPTIONS.force_minor_version]
   additional_args += ["--max_timestamp", max_timestamp]
 
   if SupportsMainlineGkiUpdates(source_file):
@@ -1317,6 +1322,8 @@
       OPTIONS.vabc_downgrade = True
     elif o == "--enable_vabc_xor":
       OPTIONS.enable_vabc_xor = a.lower() != "false"
+    elif o == "--force_minor_version":
+      OPTIONS.force_minor_version = a
     else:
       return False
     return True
@@ -1362,6 +1369,7 @@
                                  "spl_downgrade",
                                  "vabc_downgrade",
                                  "enable_vabc_xor=",
+                                 "force_minor_version=",
                              ], extra_option_handler=option_handler)
 
   if len(args) != 2:
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index 0842af9..47703bb 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -189,6 +189,8 @@
 OPTIONS.gki_signing_algorithm = None
 OPTIONS.gki_signing_extra_args = None
 OPTIONS.android_jar_path = None
+OPTIONS.vendor_partitions = []
+OPTIONS.vendor_otatools = None
 
 
 AVB_FOOTER_ARGS_BY_PARTITION = {
@@ -1289,6 +1291,10 @@
       OPTIONS.gki_signing_algorithm = a
     elif o == "--gki_signing_extra_args":
       OPTIONS.gki_signing_extra_args = a
+    elif o == "--vendor_otatools":
+      OPTIONS.vendor_otatools = a
+    elif o == "--vendor_partitions":
+      OPTIONS.vendor_partitions = a.split(",")
     else:
       return False
     return True
@@ -1339,6 +1345,8 @@
           "gki_signing_key=",
           "gki_signing_algorithm=",
           "gki_signing_extra_args=",
+          "vendor_partitions=",
+          "vendor_otatools=",
       ],
       extra_option_handler=option_handler)
 
@@ -1385,7 +1393,12 @@
   common.ZipClose(output_zip)
 
   # Skip building userdata.img and cache.img when signing the target files.
-  new_args = ["--is_signing"]
+  new_args = ["--is_signing", "--verbose"]
+  if OPTIONS.vendor_partitions:
+    new_args += [
+        "--skip_list",
+        ','.join(OPTIONS.vendor_partitions),
+    ]
   # add_img_to_target_files builds the system image from scratch, so the
   # recovery patch is guaranteed to be regenerated there.
   if OPTIONS.rebuild_recovery:
@@ -1393,6 +1406,19 @@
   new_args.append(args[1])
   add_img_to_target_files.main(new_args)
 
+  # Rebuild the vendor partitions using vendor_otatools.
+  # TODO(b/192253131): Remove the need for image compilation with vendor_otatools
+  if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
+    vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
+    common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
+    cmd = [
+        os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
+        "--verbose",
+        "--add_missing",
+        args[1],
+    ]
+    common.RunAndCheckOutput(cmd, verbose=True)
+
   print("done.")