Merge "Revert "Mount generic ramdisk as readwrite.""
diff --git a/core/Makefile b/core/Makefile
index 91b9616..f788abd 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -3746,7 +3746,7 @@
 $(BUILT_KERNEL_CONFIGS_FILE): $(EXTRACT_KERNEL) $(firstword $(INSTALLED_KERNEL_TARGET))
 	$< --tools $(PRIVATE_DECOMPRESS_TOOLS) --input $(firstword $(INSTALLED_KERNEL_TARGET)) \
 	  --output-configs $@ \
-	  --output-version $(BUILT_KERNEL_VERSION_FILE)
+	  --output-release $(BUILT_KERNEL_VERSION_FILE)
 
 my_decompress_tools :=
 
@@ -3755,7 +3755,7 @@
 
 endif # INSTALLED_KERNEL_TARGET
 
-check_vintf_compatible_args += --kernel $$(cat $(BUILT_KERNEL_VERSION_FILE)):$(BUILT_KERNEL_CONFIGS_FILE)
+check_vintf_compatible_args += --kernel $(BUILT_KERNEL_VERSION_FILE):$(BUILT_KERNEL_CONFIGS_FILE)
 check_vintf_compatible_deps += $(BUILT_KERNEL_CONFIGS_FILE) $(BUILT_KERNEL_VERSION_FILE)
 
 endif # PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS
@@ -4140,6 +4140,9 @@
 	$(hide) echo "board_uses_vendorimage=true" >> $@
 endif
 ifeq ($(BOARD_AVB_ENABLE),true)
+ifeq ($(BUILDING_VBMETA_IMAGE),true)
+	$(hide) echo "avb_building_vbmeta_image=true" >> $@
+endif # BUILDING_VBMETA_IMAGE
 	$(hide) echo "avb_enable=true" >> $@
 	$(hide) echo "avb_vbmeta_key_path=$(BOARD_AVB_KEY_PATH)" >> $@
 	$(hide) echo "avb_vbmeta_algorithm=$(BOARD_AVB_ALGORITHM)" >> $@
@@ -4239,6 +4242,9 @@
 ifeq ($(BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE),true)
 	$(hide) echo "exclude_kernel_from_recovery_image=true" >> $@
 endif
+ifneq ($(BOARD_PARTIAL_OTA_UPDATE_PARTITIONS_LIST),)
+	$(hide) echo "partial_ota_update_partitions_list=$(BOARD_PARTIAL_OTA_UPDATE_PARTITIONS_LIST)" >> $@
+endif
 
 .PHONY: misc_info
 misc_info: $(INSTALLED_MISC_INFO_TARGET)
@@ -4442,7 +4448,8 @@
 
 ifdef BUILDING_BOOT_IMAGE
   $(BUILT_TARGET_FILES_PACKAGE): $(INTERNAL_RAMDISK_FILES)
-else ifdef INTERNAL_PREBUILT_BOOTIMAGE
+endif
+ifneq (,$(INTERNAL_PREBUILT_BOOTIMAGE) $(filter true,$(BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES)))
   $(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_BOOTIMAGE_TARGET)
 endif
 
@@ -4741,10 +4748,12 @@
 	$(hide) mkdir -p $(zip_root)/IMAGES
 	$(hide) cp $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) $(zip_root)/IMAGES/
 endif
-ifdef INTERNAL_PREBUILT_BOOTIMAGE
+ifneq (,$(INTERNAL_PREBUILT_BOOTIMAGE) $(filter true,$(BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES)))
+ifdef INSTALLED_BOOTIMAGE_TARGET
 	$(hide) mkdir -p $(zip_root)/IMAGES
 	$(hide) cp $(INSTALLED_BOOTIMAGE_TARGET) $(zip_root)/IMAGES/
-endif
+endif # INSTALLED_BOOTIMAGE_TARGET
+endif # INTERNAL_PREBUILT_BOOTIMAGE != "" || BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES == true
 ifdef BOARD_PREBUILT_ODMIMAGE
 	$(hide) mkdir -p $(zip_root)/IMAGES
 	$(hide) cp $(INSTALLED_ODMIMAGE_TARGET) $(zip_root)/IMAGES/
diff --git a/core/board_config.mk b/core/board_config.mk
index 457b3bf..bc52345 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -107,11 +107,14 @@
 #   recovery resources are built to vendor_boot.
 # - BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT controls whether GSI AVB keys are
 #   built to vendor_boot.
+# - BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES controls whether boot images in $OUT are added
+#   to target files package directly.
 _board_strip_readonly_list += \
   BOARD_USES_GENERIC_KERNEL_IMAGE \
   BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE \
   BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT \
   BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT \
+  BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES \
 
 _build_broken_var_list := \
   BUILD_BROKEN_DUP_RULES \
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index 799b623..c31d4e8 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -189,20 +189,42 @@
   my_filtered_optional_uses_libraries := $(filter-out $(INTERNAL_PLATFORM_MISSING_USES_LIBRARIES), \
     $(LOCAL_OPTIONAL_USES_LIBRARIES))
 
-  # dexpreopt needs the paths to the dex jars of these libraries in order to
-  # construct class loader context for dex2oat.
-  my_extra_dexpreopt_libs := \
-    org.apache.http.legacy \
+  # compatibility libraries are added to class loader context of an app only if
+  # targetSdkVersion in the app's manifest is lower than the given SDK version
+
+  my_dexpreopt_libs_compat_28 := \
+    org.apache.http.legacy
+
+  my_dexpreopt_libs_compat_29 := \
     android.hidl.base-V1.0-java \
-    android.hidl.manager-V1.0-java \
+    android.hidl.manager-V1.0-java
+
+  my_dexpreopt_libs_compat_30 := \
     android.test.base \
+    android.test.mock
+
+  my_dexpreopt_libs_compat := \
+    $(my_dexpreopt_libs_compat_28) \
+    $(my_dexpreopt_libs_compat_29) \
+    $(my_dexpreopt_libs_compat_30)
 
   my_dexpreopt_libs := $(sort \
     $(LOCAL_USES_LIBRARIES) \
     $(my_filtered_optional_uses_libraries) \
-    $(my_extra_dexpreopt_libs) \
   )
 
+  # 1: SDK version
+  # 2: list of libraries
+  add_json_class_loader_context = \
+    $(call add_json_map, $(1)) \
+    $(foreach lib, $(2),\
+      $(call add_json_map, $(lib)) \
+      $(eval file := $(filter %/$(lib).jar, $(call module-installed-files,$(lib)))) \
+      $(call add_json_str, Host,       $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib),,COMMON)/javalib.jar) \
+      $(call add_json_str, Device,     $(call install-path-to-on-device-path,$(file))) \
+      $(call end_json_map)) \
+    $(call end_json_map)
+
   # Record dex-preopt config.
   DEXPREOPT.$(LOCAL_MODULE).DEX_PREOPT := $(LOCAL_DEX_PREOPT)
   DEXPREOPT.$(LOCAL_MODULE).MULTILIB := $(LOCAL_MULTILIB)
@@ -230,15 +252,11 @@
   $(call add_json_str,  ProfileClassListing,            $(if $(my_process_profile),$(LOCAL_DEX_PREOPT_PROFILE)))
   $(call add_json_bool, ProfileIsTextListing,           $(my_profile_is_text_listing))
   $(call add_json_bool, EnforceUsesLibraries,           $(LOCAL_ENFORCE_USES_LIBRARIES))
-  $(call add_json_list, OptionalUsesLibraries,          $(my_filtered_optional_uses_libraries))
-  $(call add_json_list, UsesLibraries,                  $(LOCAL_USES_LIBRARIES))
-  $(call add_json_map,  LibraryPaths)
-  $(foreach lib,$(my_dexpreopt_libs),\
-    $(call add_json_map, $(lib)) \
-    $(eval file := $(filter %/$(lib).jar, $(call module-installed-files,$(lib)))) \
-    $(call add_json_str, Host,   $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib),,COMMON)/javalib.jar) \
-    $(call add_json_str, Device, $(call install-path-to-on-device-path,$(file))) \
-    $(call end_json_map))
+  $(call add_json_map,  ClassLoaderContexts)
+  $(call add_json_class_loader_context, any, $(my_dexpreopt_libs))
+  $(call add_json_class_loader_context,  28, $(my_dexpreopt_libs_compat_28))
+  $(call add_json_class_loader_context,  29, $(my_dexpreopt_libs_compat_29))
+  $(call add_json_class_loader_context,  30, $(my_dexpreopt_libs_compat_30))
   $(call end_json_map)
   $(call add_json_list, Archs,                          $(my_dexpreopt_archs))
   $(call add_json_list, DexPreoptImages,                $(my_dexpreopt_images))
@@ -280,7 +298,7 @@
   my_dexpreopt_deps := $(my_dex_jar)
   my_dexpreopt_deps += $(if $(my_process_profile),$(LOCAL_DEX_PREOPT_PROFILE))
   my_dexpreopt_deps += \
-    $(foreach lib, $(my_dexpreopt_libs), \
+    $(foreach lib, $(my_dexpreopt_libs) $(my_dexpreopt_libs_compat), \
       $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib),,COMMON)/javalib.jar)
   my_dexpreopt_deps += $(my_dexpreopt_images_deps)
   my_dexpreopt_deps += $(DEXPREOPT_BOOTCLASSPATH_DEX_FILES)
diff --git a/core/main.mk b/core/main.mk
index 8728792..9b19761 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -748,7 +748,7 @@
     $(eval r := $(call module-installed-files,$(r))) \
     $(eval h_m := $(filter $(HOST_OUT)/%, $(ALL_MODULES.$(m).INSTALLED))) \
     $(eval h_r := $(filter $(HOST_OUT)/%, $(r))) \
-    $(eval h_m := $(filter-out $(h_r), $(h_m))) \
+    $(eval h_r := $(filter-out $(h_m), $(h_r))) \
     $(if $(h_m), $(eval $(call add-required-deps, $(h_m),$(h_r)))) \
   ) \
 )
@@ -764,7 +764,7 @@
     $(eval r := $(call module-installed-files,$(r))) \
     $(eval hc_m := $(filter $(HOST_CROSS_OUT)/%, $(ALL_MODULES.$(m).INSTALLED))) \
     $(eval hc_r := $(filter $(HOST_CROSS_OUT)/%, $(r))) \
-    $(eval hc_m := $(filter-out $(hc_r), $(hc_m))) \
+    $(eval hc_r := $(filter-out $(hc_m), $(hc_r))) \
     $(if $(hc_m), $(eval $(call add-required-deps, $(hc_m),$(hc_r)))) \
   ) \
 )
@@ -780,7 +780,7 @@
     $(eval r := $(call module-installed-files,$(r))) \
     $(eval t_m := $(filter $(TARGET_OUT_ROOT)/%, $(ALL_MODULES.$(m).INSTALLED))) \
     $(eval t_r := $(filter $(TARGET_OUT_ROOT)/%, $(r))) \
-    $(eval t_m := $(filter-out $(t_r), $(t_m))) \
+    $(eval t_r := $(filter-out $(t_m), $(t_r))) \
     $(if $(t_m), $(eval $(call add-required-deps, $(t_m),$(t_r)))) \
   ) \
 )
@@ -807,7 +807,6 @@
     )\
     $(eval req_files := $(strip $(req_files)))\
     $(eval mod_files := $(filter $(HOST_OUT)/%, $(call module-installed-files,$(m)))) \
-    $(eval mod_files := $(filter-out $(req_files),$(mod_files)))\
     $(if $(mod_files),\
       $(eval $(call add-required-deps, $(mod_files),$(req_files))) \
     )\
@@ -836,7 +835,6 @@
     )\
     $(eval req_files := $(strip $(req_files)))\
     $(eval mod_files := $(filter $(TARGET_OUT_ROOT)/%, $(call module-installed-files,$(m))))\
-    $(eval mod_files := $(filter-out $(req_files),$(mod_files)))\
     $(if $(mod_files),\
       $(eval $(call add-required-deps, $(mod_files),$(req_files))) \
     )\
diff --git a/core/sysprop.mk b/core/sysprop.mk
index fdefced..1c66281 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -68,7 +68,9 @@
 #       emitted to the output
 # $(4): list of variable names each of which contains name=value pairs
 # $(5): optional list of prop names to force remove from the output. Properties from both
-#       $(3) and (4) are affected.
+#       $(3) and (4) are affected
+# $(6): optional list of files to append at the end. The content of each file is emitted
+#       to the output
 define build-properties
 ALL_DEFAULT_INSTALLED_MODULES += $(2)
 
@@ -90,7 +92,7 @@
     $(eval _option := --allow-dup)\
 )
 
-$(2): $(POST_PROCESS_PROPS) $(INTERNAL_BUILD_ID_MAKEFILE) $(API_FINGERPRINT) $(3)
+$(2): $(POST_PROCESS_PROPS) $(INTERNAL_BUILD_ID_MAKEFILE) $(API_FINGERPRINT) $(3) $(6)
 	$(hide) echo Building $$@
 	$(hide) mkdir -p $$(dir $$@)
 	$(hide) rm -f $$@ && touch $$@
@@ -113,6 +115,10 @@
 	    )\
 	)
 	$(hide) $(POST_PROCESS_PROPS) $$(_option) $$@ $(5)
+	$(hide) $(foreach file,$(strip $(6)),\
+	    if [ -f "$(file)" ]; then\
+	        cat $(file) >> $$@;\
+	    fi;)
 	$(hide) echo "# end of file" >> $$@
 endef
 
@@ -265,19 +271,6 @@
 	        TARGET_CPU_ABI2="$(TARGET_CPU_ABI2)" \
 	        bash $(BUILDINFO_SH) > $@
 
-ifneq ($(PRODUCT_OEM_PROPERTIES),)
-import_oem_prop := $(call intermediates-dir-for,ETC,system_build_prop)/oem.prop
-
-$(import_oem_prop):
-	$(hide) echo "#" >> $@; \
-	        echo "# PRODUCT_OEM_PROPERTIES" >> $@; \
-	        echo "#" >> $@;
-	$(hide) $(foreach prop,$(PRODUCT_OEM_PROPERTIES), \
-	    echo "import /oem/oem.prop $(prop)" >> $@;)
-else
-import_oem_prop :=
-endif
-
 ifdef TARGET_SYSTEM_PROP
 system_prop_file := $(TARGET_SYSTEM_PROP)
 else
@@ -285,7 +278,6 @@
 endif
 
 _prop_files_ := \
-  $(import_oem_prop) \
   $(gen_from_buildinfo_sh) \
   $(system_prop_file)
 
@@ -311,9 +303,13 @@
 
 INSTALLED_BUILD_PROP_TARGET := $(TARGET_OUT)/build.prop
 
-$(eval $(call build-properties,system,$(INSTALLED_BUILD_PROP_TARGET),\
-$(_prop_files_),$(_prop_vars_),\
-$(_blacklist_names_)))
+$(eval $(call build-properties,\
+    system,\
+    $(INSTALLED_BUILD_PROP_TARGET),\
+    $(_prop_files_),\
+    $(_prop_vars_),\
+    $(_blacklist_names_),\
+    $(empty)))
 
 # -----------------------------------------------------------------
 # vendor/build.prop
@@ -349,7 +345,8 @@
     $(INSTALLED_VENDOR_BUILD_PROP_TARGET),\
     $(_prop_files_),\
     $(_prop_vars_),\
-    $(PRODUCT_VENDOR_PROPERTY_BLACKLIST)))
+    $(PRODUCT_VENDOR_PROPERTY_BLACKLIST),\
+    $(empty)))
 
 # -----------------------------------------------------------------
 # product/etc/build.prop
@@ -366,12 +363,29 @@
     PRODUCT_PRODUCT_PROPERTIES
 
 INSTALLED_PRODUCT_BUILD_PROP_TARGET := $(TARGET_OUT_PRODUCT)/etc/build.prop
+
+ifdef PRODUCT_OEM_PROPERTIES
+import_oem_prop := $(call intermediates-dir-for,ETC,import_oem_prop)/oem.prop
+
+$(import_oem_prop):
+	$(hide) echo "####################################" >> $@; \
+	        echo "# PRODUCT_OEM_PROPERTIES" >> $@; \
+	        echo "####################################" >> $@;
+	$(hide) $(foreach prop,$(PRODUCT_OEM_PROPERTIES), \
+	    echo "import /oem/oem.prop $(prop)" >> $@;)
+
+_footers_ := $(import_oem_prop)
+else
+_footers_ :=
+endif
+
 $(eval $(call build-properties,\
     product,\
     $(INSTALLED_PRODUCT_BUILD_PROP_TARGET),\
     $(_prop_files_),\
     $(_prop_vars_),\
-    $(empty)))
+    $(empty),\
+    $(_footers_)))
 
 # ----------------------------------------------------------------
 # odm/etc/build.prop
@@ -392,6 +406,7 @@
     $(INSTALLED_ODM_BUILD_PROP_TARGET),\
     $(_prop_files),\
     $(_prop_vars_),\
+    $(empty),\
     $(empty)))
 
 # ----------------------------------------------------------------
@@ -401,7 +416,11 @@
 INSTALLED_VENDOR_DLKM_BUILD_PROP_TARGET := $(TARGET_OUT_VENDOR_DLKM)/etc/build.prop
 $(eval $(call build-properties,\
     vendor_dlkm,\
-    $(INSTALLED_VENDOR_DLKM_BUILD_PROP_TARGET)))
+    $(INSTALLED_VENDOR_DLKM_BUILD_PROP_TARGET),\
+    $(empty),\
+    $(empty),\
+    $(empty),\
+    $(empty)))
 
 # ----------------------------------------------------------------
 # odm_dlkm/etc/build.prop
@@ -410,7 +429,11 @@
 INSTALLED_ODM_DLKM_BUILD_PROP_TARGET := $(TARGET_OUT_ODM_DLKM)/etc/build.prop
 $(eval $(call build-properties,\
     odm_dlkm,\
-    $(INSTALLED_ODM_DLKM_BUILD_PROP_TARGET)))
+    $(INSTALLED_ODM_DLKM_BUILD_PROP_TARGET),\
+    $(empty),\
+    $(empty),\
+    $(empty),\
+    $(empty)))
 
 # -----------------------------------------------------------------
 # system_ext/etc/build.prop
@@ -429,6 +452,7 @@
     $(INSTALLED_SYSTEM_EXT_BUILD_PROP_TARGET),\
     $(_prop_files_),\
     $(_prop_vars_),\
+    $(empty),\
     $(empty)))
 
 # ----------------------------------------------------------------
@@ -439,4 +463,8 @@
 INSTALLED_RAMDISK_BUILD_PROP_TARGET := $(TARGET_RAMDISK_OUT)/$(RAMDISK_BUILD_PROP_REL_PATH)
 $(eval $(call build-properties,\
     bootimage,\
-    $(INSTALLED_RAMDISK_BUILD_PROP_TARGET)))
+    $(INSTALLED_RAMDISK_BUILD_PROP_TARGET),\
+    $(empty),\
+    $(empty),\
+    $(empty),\
+    $(empty)))
diff --git a/target/board/generic_arm64/BoardConfig.mk b/target/board/generic_arm64/BoardConfig.mk
index 3d3eb2e..414e032 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -82,6 +82,9 @@
 TARGET_NO_KERNEL := false
 BOARD_USES_GENERIC_KERNEL_IMAGE := true
 BOARD_KERNEL_MODULE_INTERFACE_VERSIONS := 5.4-android12-0
+# Copy boot image in $OUT to target files. This is defined for targets where
+# the installed GKI APEXes are built from source.
+BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES := true
 
 # No vendor_boot
 BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT :=
diff --git a/target/board/generic_arm64/README.txt b/target/board/generic_arm64/README.txt
index 21c71d7..8711a14 100644
--- a/target/board/generic_arm64/README.txt
+++ b/target/board/generic_arm64/README.txt
@@ -1,5 +1,7 @@
 The "generic_arm64" product defines a non-hardware-specific arm64 target
-without a kernel or bootloader.
+without a bootloader.
+
+It is also the target to build the generic kernel image (GKI).
 
 It is not a product "base class"; no other products inherit
 from it or use it in any way.
diff --git a/target/board/generic_arm64/sepolicy/OWNERS b/target/board/generic_arm64/sepolicy/OWNERS
index ff29677..6dc2b86 100644
--- a/target/board/generic_arm64/sepolicy/OWNERS
+++ b/target/board/generic_arm64/sepolicy/OWNERS
@@ -1,8 +1 @@
-alanstokes@google.com
-bowgotsai@google.com
-jbires@google.com
-jeffv@google.com
-jgalenson@google.com
-sspatil@google.com
-tomcherry@google.com
-trong@google.com
+include platform/system/sepolicy:/OWNERS
diff --git a/target/board/mainline_arm64/sepolicy/OWNERS b/target/board/mainline_arm64/sepolicy/OWNERS
index ff29677..6dc2b86 100644
--- a/target/board/mainline_arm64/sepolicy/OWNERS
+++ b/target/board/mainline_arm64/sepolicy/OWNERS
@@ -1,8 +1 @@
-alanstokes@google.com
-bowgotsai@google.com
-jbires@google.com
-jeffv@google.com
-jgalenson@google.com
-sspatil@google.com
-tomcherry@google.com
-trong@google.com
+include platform/system/sepolicy:/OWNERS
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index f057958..c17398b 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -43,6 +43,7 @@
 VNDK-SP: libc++.so
 VNDK-SP: libcompiler_rt.so
 VNDK-SP: libcutils.so
+VNDK-SP: libdmabufheap.so
 VNDK-SP: libgralloctypes.so
 VNDK-SP: libhardware.so
 VNDK-SP: libhidlbase.so
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index eb041ec..d836d65 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -959,8 +959,9 @@
           if item not in vbmeta_vendor.split()]
       vbmeta_partitions.append("vbmeta_vendor")
 
-    banner("vbmeta")
-    AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)
+    if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
+      banner("vbmeta")
+      AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)
 
   if OPTIONS.info_dict.get("use_dynamic_partitions") == "true":
     banner("super_empty")
diff --git a/tools/releasetools/check_target_files_vintf.py b/tools/releasetools/check_target_files_vintf.py
index 3c2406c..a2ddfe7 100755
--- a/tools/releasetools/check_target_files_vintf.py
+++ b/tools/releasetools/check_target_files_vintf.py
@@ -100,10 +100,7 @@
                 'PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS is not set')
     return []
 
-  with open(version_path) as f:
-    version = f.read().strip()
-
-  return ['--kernel', '{}:{}'.format(version, config_path)]
+  return ['--kernel', '{}:{}'.format(version_path, config_path)]
 
 
 def CheckVintfFromExtractedTargetFiles(input_tmp, info_dict=None):
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 9a57c8a..ce36508 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -217,10 +217,13 @@
 
 import logging
 import multiprocessing
+import os
 import os.path
+import re
 import shlex
 import shutil
 import struct
+import subprocess
 import sys
 import zipfile
 
@@ -955,6 +958,63 @@
       for part in partition_state]
   return ["--partition_timestamps", ",".join(partition_timestamps)]
 
+def GeneratePartitionTimestampFlagsDowngrade(pre_partition_state, post_partition_state):
+  assert pre_partition_state is not None
+  partition_timestamps = {}
+  for part in pre_partition_state:
+    partition_timestamps[part.partition_name] = part.version
+  for part in post_partition_state:
+    partition_timestamps[part.partition_name] = \
+      max(part.version, partition_timestamps[part.partition_name])
+  return [
+    "--partition_timestamps",
+    ",".join([key + ":" + val for (key, val) in partition_timestamps.items()])
+    ]
+
+def IsSparseImage(filepath):
+  with open(filepath, 'rb') as fp:
+    # Magic for android sparse image format
+    # https://source.android.com/devices/bootloader/images
+    return fp.read(4) == b'\x3A\xFF\x26\xED'
+
+def SupportsMainlineGkiUpdates(target_file):
+  """Return True if the build supports MainlineGKIUpdates.
+
+  This function scans the product.img file in IMAGES/ directory for
+  pattern |*/apex/com.android.gki.*.apex|. If there are files
+  matching this pattern, conclude that build supports mainline
+  GKI and return True
+
+  Args:
+    target_file: Path to a target_file.zip, or an extracted directory
+  Return:
+    True if thisb uild supports Mainline GKI Updates.
+  """
+  if target_file is None:
+    return False
+  if os.path.isfile(target_file):
+    target_file = common.UnzipTemp(target_file, ["IMAGES/product.img"])
+  if not os.path.isdir(target_file):
+    assert os.path.isdir(target_file), \
+        "{} must be a path to zip archive or dir containing extracted"\
+        " target_files".format(target_file)
+  image_file = os.path.join(target_file, "IMAGES", "product.img")
+
+  if not os.path.isfile(image_file):
+    return False
+
+  if IsSparseImage(image_file):
+    # Unsparse the image
+    tmp_img = common.MakeTempFile(suffix=".img")
+    subprocess.check_output(["simg2img", image_file, tmp_img])
+    image_file = tmp_img
+
+  cmd = ["debugfs_static", "-R", "ls -p /apex", image_file]
+  output = subprocess.check_output(cmd).decode()
+
+  pattern = re.compile(r"com\.android\.gki\..*\.apex")
+  return pattern.search(output) is not None
+
 def GenerateAbOtaPackage(target_file, output_file, source_file=None):
   """Generates an Android OTA package that has A/B update payload."""
   # Stage the output zip package for package signing.
@@ -1015,6 +1075,10 @@
   # Enforce a max timestamp this payload can be applied on top of.
   if OPTIONS.downgrade:
     max_timestamp = source_info.GetBuildProp("ro.build.date.utc")
+    partition_timestamps_flags = GeneratePartitionTimestampFlagsDowngrade(
+      metadata.precondition.partition_state,
+      metadata.postcondition.partition_state
+      )
   else:
     max_timestamp = str(metadata.postcondition.timestamp)
     partition_timestamps_flags = GeneratePartitionTimestampFlags(
@@ -1022,6 +1086,10 @@
 
   additional_args += ["--max_timestamp", max_timestamp]
 
+  if SupportsMainlineGkiUpdates(source_file):
+    logger.info("Detected build with mainline GKI, include full boot image.")
+    additional_args.extend(["--full_boot", "true"])
+
   payload.Generate(
       target_file,
       source_file,
@@ -1043,15 +1111,9 @@
     secondary_target_file = GetTargetFilesZipForSecondaryImages(
         target_file, OPTIONS.skip_postinstall)
     secondary_payload = Payload(secondary=True)
-    assert not OPTIONS.downgrade
-    partition_timestamps_flags = GeneratePartitionTimestampFlags(
-      [part
-       for part in metadata.postcondition.partition_state
-       if part.partition_name not in SECONDARY_PAYLOAD_SKIPPED_IMAGES]
-    )
     secondary_payload.Generate(secondary_target_file,
                                additional_args=["--max_timestamp",
-                               max_timestamp]+partition_timestamps_flags)
+                               max_timestamp])
     secondary_payload.Sign(payload_signer)
     secondary_payload.WriteToZip(output_zip)
 
@@ -1226,15 +1288,6 @@
 
   common.InitLogging()
 
-  if OPTIONS.downgrade:
-    # We should only allow downgrading incrementals (as opposed to full).
-    # Otherwise the device may go back from arbitrary build with this full
-    # OTA package.
-    if OPTIONS.incremental_source is None:
-      raise ValueError("Cannot generate downgradable full OTAs")
-    if OPTIONS.partial:
-      raise ValueError("Cannot generate downgradable partial OTAs")
-
   # Load the build info dicts from the zip directly or the extracted input
   # directory. We don't need to unzip the entire target-files zips, because they
   # won't be needed for A/B OTAs (brillo_update_payload does that on its own).
@@ -1247,6 +1300,14 @@
   else:
     OPTIONS.info_dict = ParseInfoDict(args[0])
 
+  if OPTIONS.downgrade:
+    # We should only allow downgrading incrementals (as opposed to full).
+    # Otherwise the device may go back from arbitrary build with this full
+    # OTA package.
+    if OPTIONS.incremental_source is None:
+      raise ValueError("Cannot generate downgradable full OTAs")
+
+
   # TODO(xunchang) for retrofit and partial updates, maybe we should rebuild the
   # target-file and reload the info_dict. So the info will be consistent with
   # the modified target-file.
@@ -1254,6 +1315,7 @@
   logger.info("--- target info ---")
   common.DumpInfoDict(OPTIONS.info_dict)
 
+
   # Load the source build dict if applicable.
   if OPTIONS.incremental_source is not None:
     OPTIONS.target_info_dict = OPTIONS.info_dict
@@ -1262,6 +1324,17 @@
     logger.info("--- source info ---")
     common.DumpInfoDict(OPTIONS.source_info_dict)
 
+  if OPTIONS.partial:
+    OPTIONS.info_dict['ab_partitions'] = \
+      list(
+        set(OPTIONS.info_dict['ab_partitions']) & set(OPTIONS.partial)
+        )
+    if OPTIONS.source_info_dict:
+      OPTIONS.source_info_dict['ab_partitions'] = \
+        list(
+          set(OPTIONS.source_info_dict['ab_partitions']) & set(OPTIONS.partial)
+          )
+
   # Load OEM dicts if provided.
   OPTIONS.oem_dicts = _LoadOemDicts(OPTIONS.oem_source)
 
diff --git a/tools/zipalign/Android.bp b/tools/zipalign/Android.bp
index d88ee74..135cd76 100644
--- a/tools/zipalign/Android.bp
+++ b/tools/zipalign/Android.bp
@@ -63,6 +63,8 @@
         "libgmock",
     ],
     data: [
+         "tests/data/diffOrders.zip",
+         "tests/data/holes.zip",
          "tests/data/unaligned.zip",
     ],
     defaults: ["zipalign_defaults"],
diff --git a/tools/zipalign/ZipAlign.cpp b/tools/zipalign/ZipAlign.cpp
index 1851ac5..08f67ff 100644
--- a/tools/zipalign/ZipAlign.cpp
+++ b/tools/zipalign/ZipAlign.cpp
@@ -47,7 +47,6 @@
 {
     int numEntries = pZin->getNumEntries();
     ZipEntry* pEntry;
-    int bias = 0;
     status_t status;
 
     for (int i = 0; i < numEntries; i++) {
@@ -68,30 +67,20 @@
 
             if (zopfli) {
                 status = pZout->addRecompress(pZin, pEntry, &pNewEntry);
-                bias += pNewEntry->getCompressedLen() - pEntry->getCompressedLen();
             } else {
                 status = pZout->add(pZin, pEntry, padding, &pNewEntry);
             }
         } else {
             const int alignTo = getAlignment(pageAlignSharedLibs, alignment, pEntry);
 
-            /*
-             * Copy the entry, adjusting as required.  We assume that the
-             * file position in the new file will be equal to the file
-             * position in the original.
-             */
-            off_t newOffset = pEntry->getFileOffset() + bias;
-            padding = (alignTo - (newOffset % alignTo)) % alignTo;
-
             //printf("--- %s: orig at %ld(+%d) len=%ld, adding pad=%d\n",
             //    pEntry->getFileName(), (long) pEntry->getFileOffset(),
             //    bias, (long) pEntry->getUncompressedLen(), padding);
-            status = pZout->add(pZin, pEntry, padding, &pNewEntry);
+            status = pZout->add(pZin, pEntry, alignTo, &pNewEntry);
         }
 
         if (status != OK)
             return 1;
-        bias += padding;
         //printf(" added '%s' at %ld (pad=%d)\n",
         //    pNewEntry->getFileName(), (long) pNewEntry->getFileOffset(),
         //    padding);
diff --git a/tools/zipalign/ZipFile.cpp b/tools/zipalign/ZipFile.cpp
index 29d1bc6..9938a06 100644
--- a/tools/zipalign/ZipFile.cpp
+++ b/tools/zipalign/ZipFile.cpp
@@ -503,6 +503,32 @@
 }
 
 /*
+ * Based on the current position in the output zip, assess where the entry
+ * payload will end up if written as-is. If alignment is not satisfactory,
+ * add some padding in the extra field.
+ *
+ */
+status_t ZipFile::alignEntry(android::ZipEntry* pEntry, uint32_t alignTo){
+    if (alignTo == 0 || alignTo == 1)
+        return OK;
+
+    // Calculate where the entry payload offset will end up if we were to write
+    // it as-is.
+    uint64_t expectedPayloadOffset = ftell(mZipFp) +
+        android::ZipEntry::LocalFileHeader::kLFHLen +
+        pEntry->mLFH.mFileNameLength +
+        pEntry->mLFH.mExtraFieldLength;
+
+    // If the alignment is not what was requested, add some padding in the extra
+    // so the payload ends up where is requested.
+    uint64_t alignDiff = alignTo - (expectedPayloadOffset % alignTo);
+    if (alignDiff == 0)
+        return OK;
+
+    return pEntry->addPadding(alignDiff);
+}
+
+/*
  * Add an entry by copying it from another zip file.  If "padding" is
  * nonzero, the specified number of bytes will be added to the "extra"
  * field in the header.
@@ -510,7 +536,7 @@
  * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
  */
 status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
-    int padding, ZipEntry** ppEntry)
+    int alignTo, ZipEntry** ppEntry)
 {
     ZipEntry* pEntry = NULL;
     status_t result;
@@ -537,11 +563,10 @@
     result = pEntry->initFromExternal(pSourceEntry);
     if (result != OK)
         goto bail;
-    if (padding != 0) {
-        result = pEntry->addPadding(padding);
-        if (result != OK)
-            goto bail;
-    }
+
+    result = alignEntry(pEntry, alignTo);
+    if (result != OK)
+      goto bail;
 
     /*
      * From here on out, failures are more interesting.
diff --git a/tools/zipalign/ZipFile.h b/tools/zipalign/ZipFile.h
index 11d20c5..854f981 100644
--- a/tools/zipalign/ZipFile.h
+++ b/tools/zipalign/ZipFile.h
@@ -102,14 +102,14 @@
     }
 
     /*
-     * Add an entry by copying it from another zip file.  If "padding" is
-     * nonzero, the specified number of bytes will be added to the "extra"
-     * field in the header.
+     * Add an entry by copying it from another zip file.  If "alignment" is
+     * nonzero, an appropriate number of bytes will be added to the "extra"
+     * field in the header so the entry payload is aligned.
      *
      * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
      */
     status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
-        int padding, ZipEntry** ppEntry);
+        int alignment, ZipEntry** ppEntry);
 
     /*
      * Add an entry by copying it from another zip file, recompressing with
@@ -163,6 +163,8 @@
     ZipFile(const ZipFile& src);
     ZipFile& operator=(const ZipFile& src);
 
+    status_t alignEntry(android::ZipEntry* pEntry, uint32_t alignTo);
+
     class EndOfCentralDir {
     public:
         EndOfCentralDir(void) :
diff --git a/tools/zipalign/tests/data/diffOrders.zip b/tools/zipalign/tests/data/diffOrders.zip
new file mode 100644
index 0000000..8f512ed
--- /dev/null
+++ b/tools/zipalign/tests/data/diffOrders.zip
Binary files differ
diff --git a/tools/zipalign/tests/data/holes.zip b/tools/zipalign/tests/data/holes.zip
new file mode 100644
index 0000000..c88f891
--- /dev/null
+++ b/tools/zipalign/tests/data/holes.zip
Binary files differ
diff --git a/tools/zipalign/tests/src/align_test.cpp b/tools/zipalign/tests/src/align_test.cpp
index 073a156..c79e791 100644
--- a/tools/zipalign/tests/src/align_test.cpp
+++ b/tools/zipalign/tests/src/align_test.cpp
@@ -19,6 +19,35 @@
   const std::string src = GetTestPath("unaligned.zip");
   const std::string dst = GetTestPath("unaligned_out.zip");
 
-  int result = process(src.c_str(), dst.c_str(), 4, true, false, 4096);
-  ASSERT_EQ(0, result);
+  int processed = process(src.c_str(), dst.c_str(), 4, true, false, 4096);
+  ASSERT_EQ(0, processed);
+
+  int verified = verify(dst.c_str(), 4, true, false);
+  ASSERT_EQ(0, verified);
+}
+
+// Align a zip featuring a hole at the beginning. The
+// hole in the archive is a delete entry in the Central
+// Directory.
+TEST(Align, Holes) {
+  const std::string src = GetTestPath("holes.zip");
+  const std::string dst = GetTestPath("holes_out.zip");
+
+  int processed = process(src.c_str(), dst.c_str(), 4, true, false, 4096);
+  ASSERT_EQ(0, processed);
+
+  int verified = verify(dst.c_str(), 4, false, true);
+  ASSERT_EQ(0, verified);
+}
+
+// Align a zip where LFH order and CD entries differ.
+TEST(Align, DifferenteOrders) {
+  const std::string src = GetTestPath("diffOrders.zip");
+  const std::string dst = GetTestPath("diffOrders_out.zip");
+
+  int processed = process(src.c_str(), dst.c_str(), 4, true, false, 4096);
+  ASSERT_EQ(0, processed);
+
+  int verified = verify(dst.c_str(), 4, false, true);
+  ASSERT_EQ(0, verified);
 }