Merge "Clean up merge_target_files"
diff --git a/Changes.md b/Changes.md
index 1ab005f..5edb1d8 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,35 @@
 # Build System Changes for Android.mk Writers
 
+## Genrule starts disallowing directory inputs
+
+To better specify the inputs to the build, we are restricting use of directories
+as inputs to genrules.
+
+To fix existing uses, change inputs to specify the inputs and update the command
+accordingly. For example:
+
+```
+genrule: {
+    name: "foo",
+    srcs: ["bar"],
+    cmd: "cp $(location bar)/*.xml $(gendir)",
+    ...
+}
+```
+
+would become
+
+```
+genrule: {
+    name: "foo",
+    srcs: ["bar/*.xml"],
+    cmd: "cp $(in) $(gendir)",
+    ...
+}
+
+`BUILD_BROKEN_INPUT_DIR_MODULES` can be used to allowlist specific directories
+with genrules that have input directories.
+
 ## Dexpreopt starts enforcing `<uses-library>` checks (for Java modules)
 
 In order to construct correct class loader context for dexpreopt, build system
diff --git a/core/Makefile b/core/Makefile
index 37e6477..f7b55e6 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -906,11 +906,9 @@
 
 INTERNAL_INIT_BOOT_IMAGE_ARGS :=
 
-INTERNAL_BOOT_HAS_RAMDISK :=
 ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
   ifneq ($(BUILDING_INIT_BOOT_IMAGE),true)
     INTERNAL_BOOTIMAGE_ARGS += --ramdisk $(INSTALLED_RAMDISK_TARGET)
-    INTERNAL_BOOT_HAS_RAMDISK := true
   else
     INTERNAL_INIT_BOOT_IMAGE_ARGS += --ramdisk $(INSTALLED_RAMDISK_TARGET)
   endif
@@ -973,7 +971,6 @@
 
 INTERNAL_GKI_CERTIFICATE_ARGS :=
 INTERNAL_GKI_CERTIFICATE_DEPS :=
-INTERNAL_GENERIC_RAMDISK_BOOT_SIGNATURE :=
 ifdef BOARD_GKI_SIGNING_KEY_PATH
   ifndef BOARD_GKI_SIGNING_ALGORITHM
     $(error BOARD_GKI_SIGNING_ALGORITHM should be defined with BOARD_GKI_SIGNING_KEY_PATH)
@@ -994,13 +991,6 @@
     $(BOARD_GKI_SIGNING_KEY_PATH) \
     $(AVBTOOL)
 
-  ifdef INSTALLED_RAMDISK_TARGET
-    INTERNAL_GENERIC_RAMDISK_BOOT_SIGNATURE := \
-      $(call intermediates-dir-for,PACKAGING,generic_ramdisk)/boot_signature
-
-    $(INTERNAL_GENERIC_RAMDISK_BOOT_SIGNATURE): $(INSTALLED_RAMDISK_TARGET) $(INTERNAL_GKI_CERTIFICATE_DEPS)
-	$(call generate_generic_boot_image_certificate,$(INSTALLED_RAMDISK_TARGET),$@,generic_ramdisk,$(BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS))
-  endif
 endif
 
 # Define these only if we are building boot
@@ -1018,14 +1008,16 @@
 # $1: boot image target
 define build_boot_board_avb_enabled
   $(eval kernel := $(call bootimage-to-kernel,$(1)))
+  $(MKBOOTIMG) --kernel $(kernel) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(1)
   $(if $(BOARD_GKI_SIGNING_KEY_PATH), \
+    $(eval boot_signature := $(call intermediates-dir-for,PACKAGING,generic_boot)/$(notdir $(1)).boot_signature) \
     $(eval kernel_signature := $(call intermediates-dir-for,PACKAGING,generic_kernel)/$(notdir $(kernel)).boot_signature) \
+    $(call generate_generic_boot_image_certificate,$(1),$(boot_signature),boot,$(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)) $(newline) \
     $(call generate_generic_boot_image_certificate,$(kernel),$(kernel_signature),generic_kernel,$(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)) $(newline) \
-    $(if $(INTERNAL_BOOT_HAS_RAMDISK), \
-      cat $(INTERNAL_GENERIC_RAMDISK_BOOT_SIGNATURE) >> $(kernel_signature) $(newline)))
-  $(MKBOOTIMG) --kernel $(kernel) $(INTERNAL_BOOTIMAGE_ARGS) \
-    $(if $(BOARD_GKI_SIGNING_KEY_PATH),--boot_signature "$(kernel_signature)",$(INTERNAL_MKBOOTIMG_VERSION_ARGS)) \
-    $(BOARD_MKBOOTIMG_ARGS) --output $(1)
+    cat $(kernel_signature) >> $(boot_signature) $(newline) \
+    $(call assert-max-image-size,$(boot_signature),16 << 10) $(newline) \
+    truncate -s $$(( 16 << 10 )) $(boot_signature) $(newline) \
+    cat "$(boot_signature)" >> $(1))
   $(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) \
@@ -1034,9 +1026,6 @@
           $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
 endef
 
-ifdef INTERNAL_BOOT_HAS_RAMDISK
-$(INSTALLED_BOOTIMAGE_TARGET): $(INTERNAL_GENERIC_RAMDISK_BOOT_SIGNATURE)
-endif
 $(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(AVBTOOL) $(INTERNAL_BOOTIMAGE_FILES) $(BOARD_AVB_BOOT_KEY_PATH) $(INTERNAL_GKI_CERTIFICATE_DEPS)
 	$(call pretty,"Target boot image: $@")
 	$(call build_boot_board_avb_enabled,$@)
@@ -1141,12 +1130,9 @@
 endif
 
 ifeq ($(BOARD_AVB_ENABLE),true)
-$(INSTALLED_INIT_BOOT_IMAGE_TARGET): $(INTERNAL_GENERIC_RAMDISK_BOOT_SIGNATURE)
 $(INSTALLED_INIT_BOOT_IMAGE_TARGET): $(AVBTOOL) $(BOARD_AVB_INIT_BOOT_KEY_PATH)
 	$(call pretty,"Target init_boot image: $@")
-	$(MKBOOTIMG) $(INTERNAL_INIT_BOOT_IMAGE_ARGS) \
-	  $(if $(BOARD_GKI_SIGNING_KEY_PATH),--boot_signature "$(INTERNAL_GENERIC_RAMDISK_BOOT_SIGNATURE)",$(INTERNAL_MKBOOTIMG_VERSION_ARGS)) \
-	  $(BOARD_MKBOOTIMG_INIT_ARGS) --output "$@"
+	$(MKBOOTIMG) $(INTERNAL_INIT_BOOT_IMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_INIT_ARGS) --output "$@"
 	$(call assert-max-image-size,$@,$(BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE))
 	$(AVBTOOL) add_hash_footer \
            --image $@ \
@@ -3930,13 +3916,6 @@
     --prop com.android.build.pvmfw.security_patch:$(PVMFW_SECURITY_PATCH)
 endif
 
-# For upgrading devices without a init_boot partition, the init_boot footer args
-# should fallback to boot partition footer.
-ifndef INSTALLED_INIT_BOOT_IMAGE_TARGET
-BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS += \
-    $(BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS)
-endif
-
 BOOT_FOOTER_ARGS := BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS
 INIT_BOOT_FOOTER_ARGS := BOARD_AVB_INIT_BOOT_ADD_HASH_FOOTER_ARGS
 VENDOR_BOOT_FOOTER_ARGS := BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS
diff --git a/core/board_config.mk b/core/board_config.mk
index 405fea6..97b258d 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -174,6 +174,7 @@
   BUILD_BROKEN_DUP_SYSPROP \
   BUILD_BROKEN_ELF_PREBUILT_PRODUCT_COPY_FILES \
   BUILD_BROKEN_ENFORCE_SYSPROP_OWNER \
+  BUILD_BROKEN_INPUT_DIR_MODULES \
   BUILD_BROKEN_MISSING_REQUIRED_MODULES \
   BUILD_BROKEN_OUTSIDE_INCLUDE_DIRS \
   BUILD_BROKEN_PREBUILT_ELF_FILES \
diff --git a/core/product-graph.mk b/core/product-graph.mk
index d425b22..6d51db1 100644
--- a/core/product-graph.mk
+++ b/core/product-graph.mk
@@ -14,13 +14,10 @@
 # limitations under the License.
 #
 
-# the foreach and the if remove the single space entries that creep in because of the evals
+# the sort also acts as a strip to remove the single space entries that creep in because of the evals
 define gather-all-products
-$(sort $(foreach p, \
-	$(eval _all_products_visited := )
-  $(call all-products-inner, $(PARENT_PRODUCT_FILES)) \
-	, $(if $(strip $(p)),$(strip $(p)),)) \
-)
+$(eval _all_products_visited := )\
+$(sort $(call all-products-inner, $(PARENT_PRODUCT_FILES)))
 endef
 
 define all-products-inner
@@ -72,7 +69,7 @@
 $(hide) echo \"$(1)\" [ \
 label=\"$(dir $(1))\\n$(notdir $(1))\\n\\n$(subst $(close_parenthesis),,$(subst $(open_parethesis),,$(call get-product-var,$(1),PRODUCT_MODEL)))\\n$(call get-product-var,$(1),PRODUCT_DEVICE)\" \
 style=\"filled\" fillcolor=\"$(strip $(call node-color,$(1)))\" \
-colorscheme=\"svg\" fontcolor=\"darkblue\" href=\"products/$(1).html\" \
+colorscheme=\"svg\" fontcolor=\"darkblue\" \
 ] >> $(2)
 
 endef
@@ -95,66 +92,7 @@
 	false
 endif
 
-# Evaluates to the name of the product file
-# $(1) product file
-define product-debug-filename
-$(OUT_DIR)/products/$(strip $(1)).html
-endef
-
-# Makes a rule for the product debug info
-# $(1) product file
-define transform-product-debug
-$(OUT_DIR)/products/$(strip $(1)).txt: $(this_makefile)
-	@echo Product debug info file: $$@
-	$(hide) rm -f $$@
-	$(hide) mkdir -p $$(dir $$@)
-	$(hide) echo 'FILE=$(strip $(1))' >> $$@
-	$(hide) echo 'PRODUCT_NAME=$(call get-product-var,$(1),PRODUCT_NAME)' >> $$@
-	$(hide) echo 'PRODUCT_MODEL=$(call get-product-var,$(1),PRODUCT_MODEL)' >> $$@
-	$(hide) echo 'PRODUCT_LOCALES=$(call get-product-var,$(1),PRODUCT_LOCALES)' >> $$@
-	$(hide) echo 'PRODUCT_AAPT_CONFIG=$(call get-product-var,$(1),PRODUCT_AAPT_CONFIG)' >> $$@
-	$(hide) echo 'PRODUCT_AAPT_PREF_CONFIG=$(call get-product-var,$(1),PRODUCT_AAPT_PREF_CONFIG)' >> $$@
-	$(hide) echo 'PRODUCT_PACKAGES=$(call get-product-var,$(1),PRODUCT_PACKAGES)' >> $$@
-	$(hide) echo 'PRODUCT_DEVICE=$(call get-product-var,$(1),PRODUCT_DEVICE)' >> $$@
-	$(hide) echo 'PRODUCT_MANUFACTURER=$(call get-product-var,$(1),PRODUCT_MANUFACTURER)' >> $$@
-	$(hide) echo 'PRODUCT_PROPERTY_OVERRIDES=$(call get-product-var,$(1),PRODUCT_PROPERTY_OVERRIDES)' >> $$@
-	$(hide) echo 'PRODUCT_DEFAULT_PROPERTY_OVERRIDES=$(call get-product-var,$(1),PRODUCT_DEFAULT_PROPERTY_OVERRIDES)' >> $$@
-	$(hide) echo 'PRODUCT_SYSTEM_DEFAULT_PROPERTIES=$(call get-product-var,$(1),PRODUCT_SYSTEM_DEFAULT_PROPERTIES)' >> $$@
-	$(hide) echo 'PRODUCT_PRODUCT_PROPERTIES=$(call get-product-var,$(1),PRODUCT_PRODUCT_PROPERTIES)' >> $$@
-	$(hide) echo 'PRODUCT_SYSTEM_EXT_PROPERTIES=$(call get-product-var,$(1),PRODUCT_SYSTEM_EXT_PROPERTIES)' >> $$@
-	$(hide) echo 'PRODUCT_ODM_PROPERTIES=$(call get-product-var,$(1),PRODUCT_ODM_PROPERTIES)' >> $$@
-	$(hide) echo 'PRODUCT_CHARACTERISTICS=$(call get-product-var,$(1),PRODUCT_CHARACTERISTICS)' >> $$@
-	$(hide) echo 'PRODUCT_COPY_FILES=$(call get-product-var,$(1),PRODUCT_COPY_FILES)' >> $$@
-	$(hide) echo 'PRODUCT_OTA_PUBLIC_KEYS=$(call get-product-var,$(1),PRODUCT_OTA_PUBLIC_KEYS)' >> $$@
-	$(hide) echo 'PRODUCT_EXTRA_OTA_KEYS=$(call get-product-var,$(1),PRODUCT_EXTRA_OTA_KEYS)' >> $$@
-	$(hide) echo 'PRODUCT_EXTRA_RECOVERY_KEYS=$(call get-product-var,$(1),PRODUCT_EXTRA_RECOVERY_KEYS)' >> $$@
-	$(hide) echo 'PRODUCT_PACKAGE_OVERLAYS=$(call get-product-var,$(1),PRODUCT_PACKAGE_OVERLAYS)' >> $$@
-	$(hide) echo 'DEVICE_PACKAGE_OVERLAYS=$(call get-product-var,$(1),DEVICE_PACKAGE_OVERLAYS)' >> $$@
-	$(hide) echo 'PRODUCT_SDK_ADDON_NAME=$(call get-product-var,$(1),PRODUCT_SDK_ADDON_NAME)' >> $$@
-	$(hide) echo 'PRODUCT_SDK_ADDON_COPY_FILES=$(call get-product-var,$(1),PRODUCT_SDK_ADDON_COPY_FILES)' >> $$@
-	$(hide) echo 'PRODUCT_SDK_ADDON_COPY_MODULES=$(call get-product-var,$(1),PRODUCT_SDK_ADDON_COPY_MODULES)' >> $$@
-	$(hide) echo 'PRODUCT_SDK_ADDON_DOC_MODULES=$(call get-product-var,$(1),PRODUCT_SDK_ADDON_DOC_MODULES)' >> $$@
-	$(hide) echo 'PRODUCT_DEFAULT_WIFI_CHANNELS=$(call get-product-var,$(1),PRODUCT_DEFAULT_WIFI_CHANNELS)' >> $$@
-	$(hide) echo 'PRODUCT_DEFAULT_DEV_CERTIFICATE=$(call get-product-var,$(1),PRODUCT_DEFAULT_DEV_CERTIFICATE)' >> $$@
-	$(hide) echo 'PRODUCT_MAINLINE_SEPOLICY_DEV_CERTIFICATES=$(call get-product-var,$(1),PRODUCT_MAINLINE_SEPOLICY_DEV_CERTIFICATES)' >> $$@
-	$(hide) echo 'PRODUCT_RESTRICT_VENDOR_FILES=$(call get-product-var,$(1),PRODUCT_RESTRICT_VENDOR_FILES)' >> $$@
-	$(hide) echo 'PRODUCT_VENDOR_KERNEL_HEADERS=$(call get-product-var,$(1),PRODUCT_VENDOR_KERNEL_HEADERS)' >> $$@
-
-$(call product-debug-filename, $(p)): \
-			$(OUT_DIR)/products/$(strip $(1)).txt \
-			build/make/tools/product_debug.py \
-			$(this_makefile)
-	@echo Product debug html file: $$@
-	$(hide) mkdir -p $$(dir $$@)
-	$(hide) cat $$< | build/make/tools/product_debug.py > $$@
-endef
-
 ifeq (,$(RBC_PRODUCT_CONFIG)$(RBC_NO_PRODUCT_GRAPH)$(RBC_BOARD_CONFIG))
-product_debug_files:=
-$(foreach p,$(all_products), \
-			$(eval $(call transform-product-debug, $(p))) \
-			$(eval product_debug_files += $(call product-debug-filename, $(p))) \
-   )
 
 .PHONY: product-graph
 product-graph: $(products_graph)
diff --git a/core/product_config.mk b/core/product_config.mk
index 15935ea..1deb39b 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -112,8 +112,7 @@
 
 # Return empty unless the board is QCOM
 define is-vendor-board-qcom
-$(if $(strip $(TARGET_BOARD_PLATFORM) $(QCOM_BOARD_PLATFORMS)),\
-  $(filter $(TARGET_BOARD_PLATFORM),$(QCOM_BOARD_PLATFORMS)),\
+$(if $(strip $(TARGET_BOARD_PLATFORM) $(QCOM_BOARD_PLATFORMS)),$(filter $(TARGET_BOARD_PLATFORM),$(QCOM_BOARD_PLATFORMS)),\
   $(error both TARGET_BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) and QCOM_BOARD_PLATFORMS=$(QCOM_BOARD_PLATFORMS)))
 endef
 
diff --git a/core/product_config.rbc b/core/product_config.rbc
index 2820695..469b0f7 100644
--- a/core/product_config.rbc
+++ b/core/product_config.rbc
@@ -165,10 +165,10 @@
         pcm(globals, handle)
 
         # Now we know everything about this PCM, record it in 'configs'.
-        children = __h_inherited_modules(handle)
+        children = handle.inherited_modules
         if _options.trace_modules:
             print("#   ", "    ".join(children.keys()))
-        configs[name] = (pcm, __h_cfg(handle), children.keys(), False)
+        configs[name] = (pcm, handle.cfg, children.keys(), False)
         pcm_count = pcm_count + 1
 
         if len(children) == 0:
@@ -235,7 +235,7 @@
     input_variables_init(globals_base, h_base)
     input_variables_init(globals, h)
     board_config_init(globals, h)
-    return (globals, _dictionary_difference(h[0], h_base[0]), globals_base)
+    return (globals, _dictionary_difference(h.cfg, h_base.cfg), globals_base)
 
 
 def _substitute_inherited(configs, pcm_name, cfg):
@@ -392,11 +392,11 @@
 #   default value list (initially empty, modified by inheriting)
 def __h_new():
     """Constructs a handle which is passed to PCM."""
-    return (dict(), dict(), list())
-
-def __h_inherited_modules(handle):
-    """Returns PCM's inherited modules dict."""
-    return handle[1]
+    return struct(
+        cfg = dict(),
+        inherited_modules = dict(),
+        default_list_value = list()
+    )
 
 def __h_cfg(handle):
     """Returns PCM's product configuration attributes dict.
@@ -404,7 +404,7 @@
     This function is also exported as rblf.cfg, and every PCM
     calls it at the beginning.
     """
-    return handle[0]
+    return handle.cfg
 
 def _setdefault(handle, attr):
     """If attribute has not been set, assigns default value to it.
@@ -413,9 +413,9 @@
     Only list attributes are initialized this way. The default
     value is kept in the PCM's handle. Calling inherit() updates it.
     """
-    cfg = handle[0]
+    cfg = handle.cfg
     if cfg.get(attr) == None:
-        cfg[attr] = list(handle[2])
+        cfg[attr] = list(handle.default_list_value)
     return cfg[attr]
 
 def _inherit(handle, pcm_name, pcm):
@@ -424,12 +424,11 @@
     This function is exported as rblf.inherit, PCM calls it when
     a module is inherited.
     """
-    cfg, inherited, default_lv = handle
-    inherited[pcm_name] = pcm
-    default_lv.append(_indirect(pcm_name))
+    handle.inherited_modules[pcm_name] = pcm
+    handle.default_list_value.append(_indirect(pcm_name))
 
     # Add inherited module reference to all configuration values
-    for attr, val in cfg.items():
+    for attr, val in handle.cfg.items():
         if type(val) == "list":
             val.append(_indirect(pcm_name))
 
@@ -467,6 +466,13 @@
     #TODO(asmundak)
     pass
 
+def _add_product_dex_preopt_module_config(handle, modules, config):
+    """Equivalent to add-product-dex-preopt-module-config from build/make/core/product.mk."""
+    modules = __words(modules)
+    config = _mkstrip(config).replace(" ", "|@SP@|")
+    _setdefault(handle, "PRODUCT_DEX_PREOPT_MODULE_CONFIGS")
+    handle.cfg["PRODUCT_DEX_PREOPT_MODULE_CONFIGS"] += [m + "=" + config for m in modules]
+
 def _file_wildcard_exists(file_pattern):
     """Return True if there are files matching given bash pattern."""
     return len(rblf_wildcard(file_pattern)) > 0
@@ -719,6 +725,7 @@
     soong_config_set = _soong_config_set,
     soong_config_get = _soong_config_get,
     abspath = _abspath,
+    add_product_dex_preopt_module_config = _add_product_dex_preopt_module_config,
     addprefix = _addprefix,
     addsuffix = _addsuffix,
     board_platform_in = _board_platform_in,
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 355cd3e..c24df60 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -270,6 +270,7 @@
 $(call add_json_bool, BuildBrokenEnforceSyspropOwner,     $(filter true,$(BUILD_BROKEN_ENFORCE_SYSPROP_OWNER)))
 $(call add_json_bool, BuildBrokenTrebleSyspropNeverallow, $(filter true,$(BUILD_BROKEN_TREBLE_SYSPROP_NEVERALLOW)))
 $(call add_json_bool, BuildBrokenVendorPropertyNamespace, $(filter true,$(BUILD_BROKEN_VENDOR_PROPERTY_NAMESPACE)))
+$(call add_json_list, BuildBrokenInputDirModules, $(BUILD_BROKEN_INPUT_DIR_MODULES))
 
 $(call add_json_bool, BuildDebugfsRestrictionsEnabled, $(filter true,$(PRODUCT_SET_DEBUGFS_RESTRICTIONS)))
 
diff --git a/core/sysprop.mk b/core/sysprop.mk
index 9febe11..43b8953 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -262,6 +262,7 @@
 	        BOARD_BUILD_SYSTEM_ROOT_IMAGE="$(BOARD_BUILD_SYSTEM_ROOT_IMAGE)" \
 	        BOARD_USE_VBMETA_DIGTEST_IN_FINGERPRINT="$(BOARD_USE_VBMETA_DIGTEST_IN_FINGERPRINT)" \
 	        PLATFORM_VERSION="$(PLATFORM_VERSION)" \
+	        PLATFORM_DISPLAY_VERSION="$(PLATFORM_DISPLAY_VERSION)" \
 	        PLATFORM_VERSION_LAST_STABLE="$(PLATFORM_VERSION_LAST_STABLE)" \
 	        PLATFORM_SECURITY_PATCH="$(PLATFORM_SECURITY_PATCH)" \
 	        PLATFORM_BASE_OS="$(PLATFORM_BASE_OS)" \
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 8ee21c8..f19e841 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -19,6 +19,7 @@
 #
 # Guarantees that the following are defined:
 #     PLATFORM_VERSION
+#     PLATFORM_DISPLAY_VERSION
 #     PLATFORM_SDK_VERSION
 #     PLATFORM_VERSION_CODENAME
 #     DEFAULT_APP_TARGET_SDK
@@ -54,6 +55,11 @@
 # release build.  If this is a final release build, it is simply "REL".
 PLATFORM_VERSION_CODENAME.TP1A := Tiramisu
 
+# This is the user-visible version.  In a final release build it should
+# be empty to use PLATFORM_VERSION as the user-visible version.  For
+# a preview release it can be set to a user-friendly value like `12 Preview 1`
+PLATFORM_DISPLAY_VERSION :=
+
 ifndef PLATFORM_SDK_VERSION
   # This is the canonical definition of the SDK version, which defines
   # the set of APIs and functionality available in the platform.  It
diff --git a/core/version_util.mk b/core/version_util.mk
index 2633640..3a0d4b5 100644
--- a/core/version_util.mk
+++ b/core/version_util.mk
@@ -108,6 +108,10 @@
 endif
 .KATI_READONLY := PLATFORM_VERSION
 
+ifndef PLATFORM_DISPLAY_VERSION
+  PLATFORM_DISPLAY_VERSION := $(PLATFORM_VERSION)
+endif
+.KATI_READONLY := PLATFORM_DISPLAY_VERSION
 
 ifeq (REL,$(PLATFORM_VERSION_CODENAME))
   PLATFORM_PREVIEW_SDK_VERSION := 0
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index 3223002..851a2cb 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -63,7 +63,7 @@
     com.android.scheduling:framework-scheduling \
     com.android.sdkext:framework-sdkextensions \
     com.android.tethering:framework-connectivity \
-    com.android.tethering:framework-connectivity-tiramisu \
+    com.android.tethering:framework-connectivity-t \
     com.android.tethering:framework-tethering \
     com.android.wifi:framework-wifi
 
diff --git a/target/product/virtual_ab_ota/compression.mk b/target/product/virtual_ab_ota/compression.mk
index 88c58b8..d5bd2a5 100644
--- a/target/product/virtual_ab_ota/compression.mk
+++ b/target/product/virtual_ab_ota/compression.mk
@@ -18,6 +18,7 @@
 
 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/buildinfo.sh b/tools/buildinfo.sh
index 20c96de..536a381 100755
--- a/tools/buildinfo.sh
+++ b/tools/buildinfo.sh
@@ -19,6 +19,7 @@
 echo "ro.build.version.known_codenames=$PLATFORM_VERSION_KNOWN_CODENAMES"
 echo "ro.build.version.release=$PLATFORM_VERSION_LAST_STABLE"
 echo "ro.build.version.release_or_codename=$PLATFORM_VERSION"
+echo "ro.build.version.release_or_preview_display=$PLATFORM_DISPLAY_VERSION"
 echo "ro.build.version.security_patch=$PLATFORM_SECURITY_PATCH"
 echo "ro.build.version.base_os=$PLATFORM_BASE_OS"
 echo "ro.build.version.min_supported_target_sdk=$PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION"
diff --git a/tools/product_debug.py b/tools/product_debug.py
deleted file mode 100755
index ff2657c..0000000
--- a/tools/product_debug.py
+++ /dev/null
@@ -1,159 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2012 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.
-
-import os
-import re
-import sys
-
-def break_lines(key, val):
-  # these don't get split
-  if key in ("PRODUCT_MODEL"):
-    return (key,val)
-  return (key, "\n".join(val.split()))
-
-def split_line(line):
-  words = line.split("=", 1)
-  if len(words) == 1:
-    return (words[0], "")
-  else:
-    return (words[0], words[1])
-
-def sort_lines(text):
-  lines = text.split()
-  lines.sort()
-  return "\n".join(lines)
-
-def parse_variables(lines):
-  return [split_line(line) for line in lines if line.strip()]
-
-def render_variables(variables):
-  variables = dict(variables)
-  del variables["FILE"]
-  variables = list(variables.iteritems())
-  variables.sort(lambda a, b: cmp(a[0], b[0]))
-  return ("<table id='variables'>"
-      + "\n".join([ "<tr><th>%(key)s</th><td>%(val)s</td></tr>" % { "key": key, "val": val }
-        for key,val in variables])
-      +"</table>")
-
-def linkify_inherit(variables, text, func_name):
-  groups = re.split("(\\$\\(call " + func_name + ",.*\\))", text)
-  result = ""
-  for i in range(0,len(groups)/2):
-    i = i * 2
-    result = result + groups[i]
-    s = groups[i+1]
-    href = s.split(",", 1)[1].strip()[:-1]
-    href = href.replace("$(SRC_TARGET_DIR)", "build/target")
-    href = ("../" * variables["FILE"].count("/")) + href + ".html"
-    result = result + "<a href=\"%s\">%s</a>" % (href,s)
-  result = result + groups[-1]
-  return result
-
-def render_original(variables, text):
-  text = linkify_inherit(variables, text, "inherit-product")
-  text = linkify_inherit(variables, text, "inherit-product-if-exists")
-  return text
-
-def read_file(fn):
-  f = file(fn)
-  text = f.read()
-  f.close()
-  return text
-
-def main(argv):
-  # read the variables
-  lines = sys.stdin.readlines()
-  variables = parse_variables(lines)
-
-  # format the variables
-  variables = [break_lines(key,val) for key,val in variables]
-
-  # now it's a dict
-  variables = dict(variables)
-
-  sorted_vars = (
-      "PRODUCT_COPY_FILES",
-      "PRODUCT_PACKAGES",
-      "PRODUCT_LOCALES",
-      "PRODUCT_PROPERTY_OVERRIDES",
-    )
-
-  for key in sorted_vars:
-    variables[key] = sort_lines(variables[key])
-
-  # the original file
-  original = read_file(variables["FILE"])
-
-  # formatting
-  values = dict(variables)
-  values.update({
-    "variables": render_variables(variables),
-    "original": render_original(variables, original),
-  })
-  print """<html>
-
-
-<head>
-  <title>%(FILE)s</title>
-  <style type="text/css">
-    body {
-      font-family: Helvetica, Arial, sans-serif;
-      padding-bottom: 20px;
-    }
-    #variables {
-      border-collapse: collapse;
-    }
-    #variables th, #variables td {
-      vertical-align: top;
-      text-align: left;
-      border-top: 1px solid #c5cdde;
-      border-bottom: 1px solid #c5cdde;
-      padding: 2px 10px 2px 10px;
-    }
-    #variables th {
-      font-size: 10pt;
-      background-color: #e2ecff
-    }
-    #variables td {
-      background-color: #ebf2ff;
-      white-space: pre;
-      font-size: 10pt;
-    }
-    #original {
-      background-color: #ebf2ff;
-      border-top: 1px solid #c5cdde;
-      border-bottom: 1px solid #c5cdde;
-      padding: 2px 10px 2px 10px;
-      white-space: pre;
-      font-size: 10pt;
-    }
-  </style>
-</head>
-<body>
-<h1>%(FILE)s</h1>
-<a href="#Original">Original</a>
-<a href="#Variables">Variables</a>
-<h2><a name="Original"></a>Original</h2>
-<div id="original">%(original)s</div>
-<h2><a name="Variables"></a>Variables</h2>
-%(variables)s
-</body>
-</html>
-""" % values
-
-if __name__ == "__main__":
-  main(sys.argv)
diff --git a/tools/releasetools/OWNERS b/tools/releasetools/OWNERS
index 5827046..4ceb6ff 100644
--- a/tools/releasetools/OWNERS
+++ b/tools/releasetools/OWNERS
@@ -2,5 +2,5 @@
 nhdo@google.com
 zhangkelvin@google.com
 
-per-file merge_*.py = danielnorman@google.com
+per-file *merge_*.py = danielnorman@google.com, jgalmes@google.com, rseymour@google.com
 
diff --git a/tools/releasetools/apex_utils.py b/tools/releasetools/apex_utils.py
index 69d6c13..3f13a4a 100644
--- a/tools/releasetools/apex_utils.py
+++ b/tools/releasetools/apex_utils.py
@@ -214,7 +214,7 @@
       if os.path.isfile(path):
         os.remove(path)
       elif os.path.isdir(path):
-        shutil.rmtree(path)
+        shutil.rmtree(path, ignore_errors=True)
 
     # TODO(xunchang) the signing process can be improved by using
     # '--unsigned_payload_only'. But we need to parse the vbmeta earlier for
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 107fad1..9feb8af 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1405,7 +1405,7 @@
           "gki_signing_algorithm" in OPTIONS.info_dict)
 
 
-def _GenerateGkiCertificate(image, image_name, partition_name):
+def _GenerateGkiCertificate(image, image_name):
   key_path = OPTIONS.info_dict.get("gki_signing_key_path")
   algorithm = OPTIONS.info_dict.get("gki_signing_algorithm")
 
@@ -1434,8 +1434,7 @@
   if signature_args:
     cmd.extend(["--additional_avb_args", signature_args])
 
-  args = OPTIONS.info_dict.get(
-      "avb_" + partition_name + "_add_hash_footer_args", "")
+  args = OPTIONS.info_dict.get("avb_boot_add_hash_footer_args", "")
   args = args.strip()
   if args:
     cmd.extend(["--additional_avb_args", args])
@@ -1628,27 +1627,9 @@
   if args and args.strip():
     cmd.extend(shlex.split(args))
 
-  boot_signature = None
-  if _HasGkiCertificationArgs():
-    # Certify GKI images.
-    boot_signature_bytes = b''
-    if kernel_path is not None:
-      boot_signature_bytes += _GenerateGkiCertificate(
-          kernel_path, "generic_kernel", "boot")
-    if has_ramdisk:
-      boot_signature_bytes += _GenerateGkiCertificate(
-          ramdisk_img.name, "generic_ramdisk", "init_boot")
-
-    if len(boot_signature_bytes) > 0:
-      boot_signature = tempfile.NamedTemporaryFile()
-      boot_signature.write(boot_signature_bytes)
-      boot_signature.flush()
-      cmd.extend(["--boot_signature", boot_signature.name])
-  else:
-    # Certified GKI boot/init_boot image mustn't set 'mkbootimg_version_args'.
-    args = info_dict.get("mkbootimg_version_args")
-    if args and args.strip():
-      cmd.extend(shlex.split(args))
+  args = info_dict.get("mkbootimg_version_args")
+  if args and args.strip():
+    cmd.extend(shlex.split(args))
 
   if has_ramdisk:
     cmd.extend(["--ramdisk", ramdisk_img.name])
@@ -1670,6 +1651,29 @@
 
   RunAndCheckOutput(cmd)
 
+  if _HasGkiCertificationArgs():
+    if not os.path.exists(img.name):
+      raise ValueError("Cannot find GKI boot.img")
+    if kernel_path is None or not os.path.exists(kernel_path):
+      raise ValueError("Cannot find GKI kernel.img")
+
+    # Certify GKI images.
+    boot_signature_bytes = b''
+    boot_signature_bytes += _GenerateGkiCertificate(img.name, "boot")
+    boot_signature_bytes += _GenerateGkiCertificate(
+        kernel_path, "generic_kernel")
+
+    BOOT_SIGNATURE_SIZE = 16 * 1024
+    if len(boot_signature_bytes) > BOOT_SIGNATURE_SIZE:
+      raise ValueError(
+          f"GKI boot_signature size must be <= {BOOT_SIGNATURE_SIZE}")
+    boot_signature_bytes += (
+        b'\0' * (BOOT_SIGNATURE_SIZE - len(boot_signature_bytes)))
+    assert len(boot_signature_bytes) == BOOT_SIGNATURE_SIZE
+
+    with open(img.name, 'ab') as f:
+      f.write(boot_signature_bytes)
+
   if (info_dict.get("boot_signer") == "true" and
           info_dict.get("verity_key")):
     # Hard-code the path as "/boot" for two-step special recovery image (which
@@ -1730,9 +1734,6 @@
     ramdisk_img.close()
   img.close()
 
-  if boot_signature is not None:
-    boot_signature.close()
-
   return data
 
 
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index 7dd365f..f973263 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -1642,7 +1642,7 @@
     }
     test_file = tempfile.NamedTemporaryFile()
     self.assertRaises(common.ExternalError, common._GenerateGkiCertificate,
-                      test_file.name, 'generic_kernel', 'boot')
+                      test_file.name, 'generic_kernel')
 
   def test_GenerateGkiCertificate_SearchKeyPathNotFound(self):
     pubkey = 'no_testkey_gki.pem'
@@ -1662,7 +1662,7 @@
     }
     test_file = tempfile.NamedTemporaryFile()
     self.assertRaises(common.ExternalError, common._GenerateGkiCertificate,
-                      test_file.name, 'generic_kernel', 'boot')
+                      test_file.name, 'generic_kernel')
 
 class InstallRecoveryScriptFormatTest(test_utils.ReleaseToolsTestCase):
   """Checks the format of install-recovery.sh.