Merge "Add extra variables to soong.variables" into main
diff --git a/core/Makefile b/core/Makefile
index 74c6834..099df47 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -5949,6 +5949,20 @@
   fi
 endef
 
+# This is the same as the non-hermetic version, but also accepts a list of files in the directory
+# to copy. It will only copy those files. This is so that we don't copy extra files that could've
+# been built in the staging directories by prior builds.
+# $(1): Directory to copy
+# $(2): Location to copy it to
+# $(3): A list of files in the $(1) directory, only these files will be copied
+define package_files-copy-root-hermetic
+  $(if $(BUILD_BROKEN_INCORRECT_PARTITION_IMAGES),
+    $(call package_files-copy-root,$(1),$(2)),
+    $(foreach f,$(filter $(strip $(1))/%,$(3)), \
+      mkdir -p $(strip $(2))/$(dir $(patsubst $(strip $(1))/%,%,$(f)))$(newline) \
+      $(ACP) -d $(f) $(strip $(2))/$(patsubst $(strip $(1))/%,%,$(f))$(newline)))
+endef
+
 built_ota_tools :=
 
 # We can't build static executables when SANITIZE_TARGET=address
@@ -6298,7 +6312,7 @@
 	    $(BUILT_KERNEL_VERSION_FILE) \
 	    | $(ACP)
 	@echo "Building target files: $@"
-	$(hide) rm -rf $@ $@.list $(zip_root)
+	$(hide) rm -rf $@ $(zip_root)
 	$(hide) mkdir -p $(dir $@) $(zip_root)
 ifneq (,$(INSTALLED_RECOVERYIMAGE_TARGET)$(filter true,$(BOARD_USES_RECOVERY_AS_BOOT))$(filter true,$(BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT)))
 	@# Components of the recovery image
@@ -6425,8 +6439,8 @@
 endif # INSTALLED_VENDOR_BOOTIMAGE_TARGET
 ifdef BUILDING_SYSTEM_IMAGE
 	@# Contents of the system image
-	$(hide) $(call package_files-copy-root, \
-	    $(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM,$(FULL_SYSTEMIMAGE_DEPS))
 else ifdef INSTALLED_BUILD_PROP_TARGET
 	@# Copy the system build.prop even if not building a system image
 	@# because add_img_to_target_files may need it to build other partition
@@ -6436,48 +6450,48 @@
 endif
 ifdef BUILDING_USERDATA_IMAGE
 	@# Contents of the data image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_DATA),$(zip_root)/DATA)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_DATA),$(zip_root)/DATA,$(INSTALLED_USERDATAIMAGE_TARGET_DEPS))
 endif
 ifdef BUILDING_VENDOR_IMAGE
 	@# Contents of the vendor image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_VENDOR),$(zip_root)/VENDOR)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_VENDOR),$(zip_root)/VENDOR,$(INTERNAL_VENDORIMAGE_FILES))
 endif
 ifdef BUILDING_PRODUCT_IMAGE
 	@# Contents of the product image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_PRODUCT),$(zip_root)/PRODUCT)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_PRODUCT),$(zip_root)/PRODUCT,$(INTERNAL_PRODUCTIMAGE_FILES))
 endif
 ifdef BUILDING_SYSTEM_EXT_IMAGE
 	@# Contents of the system_ext image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_SYSTEM_EXT),$(zip_root)/SYSTEM_EXT)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_SYSTEM_EXT),$(zip_root)/SYSTEM_EXT,$(INTERNAL_SYSTEM_EXTIMAGE_FILES))
 endif
 ifdef BUILDING_ODM_IMAGE
 	@# Contents of the odm image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_ODM),$(zip_root)/ODM)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_ODM),$(zip_root)/ODM,$(INTERNAL_ODMIMAGE_FILES))
 endif
 ifdef BUILDING_VENDOR_DLKM_IMAGE
 	@# Contents of the vendor_dlkm image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_VENDOR_DLKM),$(zip_root)/VENDOR_DLKM)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_VENDOR_DLKM),$(zip_root)/VENDOR_DLKM,$(INTERNAL_VENDOR_DLKMIMAGE_FILES))
 endif
 ifdef BUILDING_ODM_DLKM_IMAGE
 	@# Contents of the odm_dlkm image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_ODM_DLKM),$(zip_root)/ODM_DLKM)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_ODM_DLKM),$(zip_root)/ODM_DLKM,$(INTERNAL_ODM_DLKMIMAGE_FILES))
 endif
 ifdef BUILDING_SYSTEM_DLKM_IMAGE
 	@# Contents of the system_dlkm image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_SYSTEM_DLKM),$(zip_root)/SYSTEM_DLKM)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_SYSTEM_DLKM),$(zip_root)/SYSTEM_DLKM,$(INTERNAL_SYSTEM_DLKMIMAGE_FILES))
 endif
 ifdef BUILDING_SYSTEM_OTHER_IMAGE
 	@# Contents of the system_other image
-	$(hide) $(call package_files-copy-root, \
-	    $(TARGET_OUT_SYSTEM_OTHER),$(zip_root)/SYSTEM_OTHER)
+	$(hide) $(call package_files-copy-root-hermetic, \
+	    $(TARGET_OUT_SYSTEM_OTHER),$(zip_root)/SYSTEM_OTHER,$(INTERNAL_SYSTEMOTHERIMAGE_FILES))
 endif
 	@# Extra contents of the OTA package
 	$(hide) mkdir -p $(zip_root)/OTA
@@ -6566,7 +6580,8 @@
 endif
 ifeq ($(BREAKPAD_GENERATE_SYMBOLS),true)
 	@# If breakpad symbols have been generated, add them to the zip.
-	$(hide) cp -R $(TARGET_OUT_BREAKPAD) $(zip_root)/BREAKPAD
+	$(call package_files-copy-root, \
+	    $(TARGET_OUT_BREAKPAD),$(zip_root)/BREAKPAD)
 endif
 ifdef BOARD_PREBUILT_VENDORIMAGE
 	$(hide) mkdir -p $(zip_root)/IMAGES
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index fd915b5..6d64f97 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -111,6 +111,7 @@
 # default.
 INDIVIDUALLY_TOGGLEABLE_PREBUILT_MODULES := \
   btservices \
+  devicelock \
   permission \
   rkpd \
   uwb \
@@ -162,6 +163,8 @@
 $(call add_soong_config_var_value,ANDROID,release_avf_enable_remote_attestation,$(RELEASE_AVF_ENABLE_REMOTE_ATTESTATION))
 $(call add_soong_config_var_value,ANDROID,release_avf_enable_vendor_modules,$(RELEASE_AVF_ENABLE_VENDOR_MODULES))
 
+$(call add_soong_config_var_value,ANDROID,release_binder_death_recipient_weak_from_jni,$(RELEASE_BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI))
+
 # Enable system_server optimizations by default unless explicitly set or if
 # there may be dependent runtime jars.
 # TODO(b/240588226): Remove the off-by-default exceptions after handling
diff --git a/core/combo/HOST_darwin-x86_64.mk b/core/combo/HOST_darwin.mk
similarity index 97%
rename from core/combo/HOST_darwin-x86_64.mk
rename to core/combo/HOST_darwin.mk
index dac3bbf..11063e6 100644
--- a/core/combo/HOST_darwin-x86_64.mk
+++ b/core/combo/HOST_darwin.mk
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-# Configuration for Darwin (Mac OS X) on x86_64.
+# Configuration for Darwin (Mac OS X).
 # Included by combo/select.mk
 
 define $(combo_var_prefix)transform-shared-lib-to-toc
diff --git a/core/combo/HOST_linux-x86_64.mk b/core/combo/HOST_linux-x86_64.mk
deleted file mode 100644
index 845733f..0000000
--- a/core/combo/HOST_linux-x86_64.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2006 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.
-#
-
-# Configuration for builds hosted on linux-x86_64.
-# Included by combo/select.mk
-
-define $(combo_var_prefix)transform-shared-lib-to-toc
-$(call _gen_toc_command_for_elf,$(1),$(2))
-endef
diff --git a/core/combo/HOST_linux-x86.mk b/core/combo/HOST_linux.mk
similarity index 94%
rename from core/combo/HOST_linux-x86.mk
rename to core/combo/HOST_linux.mk
index 3f4ec0a..bfdd3eb 100644
--- a/core/combo/HOST_linux-x86.mk
+++ b/core/combo/HOST_linux.mk
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-# Configuration for builds hosted on linux-x86.
+# Configuration for builds hosted on linux.
 # Included by combo/select.mk
 
 define $(combo_var_prefix)transform-shared-lib-to-toc
diff --git a/core/combo/select.mk b/core/combo/select.mk
index 9c7e69e..a836ed8 100644
--- a/core/combo/select.mk
+++ b/core/combo/select.mk
@@ -21,8 +21,12 @@
 #	combo_2nd_arch_prefix -- it's defined if this is loaded for the 2nd arch.
 #
 
-# Build a target string like "linux-arm" or "darwin-x86".
-combo_os_arch := $($(combo_target)OS)-$($(combo_target)$(combo_2nd_arch_prefix)ARCH)
+ifeq ($(combo_target),HOST_)
+  combo_os_arch := $(HOST_OS)
+else
+  # Build a target string like "linux-arm" or "darwin-x86".
+  combo_os_arch := $($(combo_target)OS)-$($(combo_target)$(combo_2nd_arch_prefix)ARCH)
+endif
 
 combo_var_prefix := $(combo_2nd_arch_prefix)$(combo_target)
 
diff --git a/core/main.mk b/core/main.mk
index e697d04..7c25862 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -220,7 +220,7 @@
 # property_overrides_split_enabled is true. Otherwise it will be installed in
 # /system/build.prop
 ifdef BOARD_VNDK_VERSION
-  ifneq ($(KEEP_VNDK),false)
+  ifeq ($(KEEP_VNDK),true)
   ifeq ($(BOARD_VNDK_VERSION),current)
     ADDITIONAL_VENDOR_PROPERTIES := ro.vndk.version=$(PLATFORM_VNDK_VERSION)
   else
@@ -339,7 +339,7 @@
 # modules. It uses the version in PRODUCT_PRODUCT_VNDK_VERSION. If the value
 # is "current", use PLATFORM_VNDK_VERSION.
 ifdef PRODUCT_PRODUCT_VNDK_VERSION
-ifneq ($(KEEP_VNDK),false)
+ifeq ($(KEEP_VNDK),true)
 ifeq ($(PRODUCT_PRODUCT_VNDK_VERSION),current)
 ADDITIONAL_PRODUCT_PROPERTIES += ro.product.vndk.version=$(PLATFORM_VNDK_VERSION)
 else
diff --git a/core/product.mk b/core/product.mk
index c268f4d..ca65948 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -445,6 +445,8 @@
 
 _product_list_vars += PRODUCT_AFDO_PROFILES
 
+_product_single_value_vars += PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API
+
 .KATI_READONLY := _product_single_value_vars _product_list_vars
 _product_var_list :=$= $(_product_single_value_vars) $(_product_list_vars)
 
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 844f4bd..b172ec2 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -379,6 +379,8 @@
   $(call add_json_bool, BoardAvbEnable, $(filter true,$(BOARD_AVB_ENABLE)))
 $(call end_json_map)
 
+$(call add_json_bool, NextReleaseHideFlaggedApi, $(filter true,$(PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API)))
+
 $(call json_end)
 
 $(file >$(SOONG_VARIABLES).tmp,$(json_contents))
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index f8dbafd..29e4ecd 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -235,6 +235,7 @@
     pm \
     pppd \
     preinstalled-packages-platform.xml \
+    printflags \
     privapp-permissions-platform.xml \
     prng_seeder \
     racoon \
diff --git a/target/product/mainline_sdk.mk b/target/product/mainline_sdk.mk
index 343aed6..0ea72cc 100644
--- a/target/product/mainline_sdk.mk
+++ b/target/product/mainline_sdk.mk
@@ -16,3 +16,5 @@
 PRODUCT_NAME := mainline_sdk
 PRODUCT_BRAND := Android
 PRODUCT_DEVICE := mainline_sdk
+
+PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API := true
diff --git a/target/product/sdk_arm64.mk b/target/product/sdk_arm64.mk
index 497f673..3eb9304 100644
--- a/target/product/sdk_arm64.mk
+++ b/target/product/sdk_arm64.mk
@@ -22,3 +22,5 @@
 PRODUCT_NAME := sdk_arm64
 PRODUCT_BRAND := Android
 PRODUCT_DEVICE := mainline_arm64
+
+PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API := true
diff --git a/target/product/sdk_phone_arm64.mk b/target/product/sdk_phone_arm64.mk
index 3f81615..c16c403 100644
--- a/target/product/sdk_phone_arm64.mk
+++ b/target/product/sdk_phone_arm64.mk
@@ -63,4 +63,4 @@
 # library name, so the check fails.
 PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true
 
-
+PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API := true
diff --git a/target/product/sdk_phone_armv7.mk b/target/product/sdk_phone_armv7.mk
index 48a0e3b..293b1ea 100644
--- a/target/product/sdk_phone_armv7.mk
+++ b/target/product/sdk_phone_armv7.mk
@@ -62,3 +62,5 @@
 # RadioConfigLib), which makes it impossible to translate their module names to
 # library name, so the check fails.
 PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true
+
+PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API := true
diff --git a/target/product/sdk_phone_x86.mk b/target/product/sdk_phone_x86.mk
index 0f8b508..90cd8d5 100644
--- a/target/product/sdk_phone_x86.mk
+++ b/target/product/sdk_phone_x86.mk
@@ -57,3 +57,5 @@
 # RadioConfigLib), which makes it impossible to translate their module names to
 # library name, so the check fails.
 PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true
+
+PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API := true
diff --git a/target/product/sdk_phone_x86_64.mk b/target/product/sdk_phone_x86_64.mk
index f5d9028..b2e14a5 100644
--- a/target/product/sdk_phone_x86_64.mk
+++ b/target/product/sdk_phone_x86_64.mk
@@ -58,3 +58,5 @@
 # RadioConfigLib), which makes it impossible to translate their module names to
 # library name, so the check fails.
 PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true
+
+PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API := true
diff --git a/target/product/sdk_x86.mk b/target/product/sdk_x86.mk
index 843321f..a6e3bcd 100644
--- a/target/product/sdk_x86.mk
+++ b/target/product/sdk_x86.mk
@@ -22,3 +22,5 @@
 PRODUCT_NAME := sdk_x86_64
 PRODUCT_BRAND := Android
 PRODUCT_DEVICE := mainline_x86
+
+PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API := true
diff --git a/target/product/sdk_x86_64.mk b/target/product/sdk_x86_64.mk
index c1caf7e..af73007 100644
--- a/target/product/sdk_x86_64.mk
+++ b/target/product/sdk_x86_64.mk
@@ -25,3 +25,5 @@
 PRODUCT_NAME := sdk_x86_64
 PRODUCT_BRAND := Android
 PRODUCT_DEVICE := mainline_x86_64
+
+PRODUCT_NEXT_RELEASE_HIDE_FLAGGED_API := true
diff --git a/tools/aconfig/printflags/Android.bp b/tools/aconfig/printflags/Android.bp
index 5d73d96..da18cdc 100644
--- a/tools/aconfig/printflags/Android.bp
+++ b/tools/aconfig/printflags/Android.bp
@@ -2,8 +2,8 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-rust_binary {
-    name: "printflags",
+rust_defaults {
+    name: "printflags.defaults",
     edition: "2021",
     clippy_lints: "android",
     lints: "android",
@@ -12,5 +12,16 @@
         "libaconfig_protos",
         "libanyhow",
         "libprotobuf",
+        "libregex",
     ],
 }
+
+rust_binary {
+    name: "printflags",
+    defaults: ["printflags.defaults"],
+}
+
+rust_test_host {
+    name: "printflags.test",
+    defaults: ["printflags.defaults"],
+}
diff --git a/tools/aconfig/printflags/src/main.rs b/tools/aconfig/printflags/src/main.rs
index a9f7c03..88fdea9 100644
--- a/tools/aconfig/printflags/src/main.rs
+++ b/tools/aconfig/printflags/src/main.rs
@@ -16,12 +16,43 @@
 
 //! `printflags` is a device binary to print feature flags.
 
+use aconfig_protos::aconfig::Flag_state as State;
 use aconfig_protos::aconfig::Parsed_flags as ProtoParsedFlags;
-use anyhow::Result;
+use anyhow::{bail, Result};
+use regex::Regex;
 use std::collections::HashMap;
-use std::fs;
+use std::process::Command;
+use std::{fs, str};
+
+fn parse_device_config(raw: &str) -> HashMap<String, String> {
+    let mut flags = HashMap::new();
+    let regex = Regex::new(r"(?m)^([[[:alnum:]]_]+/[[[:alnum:]]_\.]+)=(true|false)$").unwrap();
+    for capture in regex.captures_iter(raw) {
+        let key = capture.get(1).unwrap().as_str().to_string();
+        let value = match capture.get(2).unwrap().as_str() {
+            "true" => format!("{:?} (device_config)", State::ENABLED),
+            "false" => format!("{:?} (device_config)", State::DISABLED),
+            _ => panic!(),
+        };
+        flags.insert(key, value);
+    }
+    flags
+}
 
 fn main() -> Result<()> {
+    // read device_config
+    let output = Command::new("/system/bin/device_config").arg("list").output()?;
+    if !output.status.success() {
+        let reason = match output.status.code() {
+            Some(code) => format!("exit code {}", code),
+            None => "terminated by signal".to_string(),
+        };
+        bail!("failed to execute device_config: {}", reason);
+    }
+    let dc_stdout = str::from_utf8(&output.stdout)?;
+    let device_config_flags = parse_device_config(dc_stdout);
+
+    // read aconfig_flags.pb files
     let mut flags: HashMap<String, Vec<String>> = HashMap::new();
     for partition in ["system", "system_ext", "product", "vendor"] {
         let path = format!("/{}/etc/aconfig_flags.pb", partition);
@@ -31,15 +62,49 @@
         };
         let parsed_flags: ProtoParsedFlags = protobuf::Message::parse_from_bytes(&bytes)?;
         for flag in parsed_flags.parsed_flag {
-            let key = format!("{}.{}", flag.package(), flag.name());
+            let key = format!("{}/{}.{}", flag.namespace(), flag.package(), flag.name());
             let value = format!("{:?} + {:?} ({})", flag.permission(), flag.state(), partition);
             flags.entry(key).or_default().push(value);
         }
     }
-    for (key, value) in flags {
-        // TODO: if the flag is READ_WRITE (for any partition), call "device_config get" to obtain
-        // the flag's current state, and append value to the output
-        println!("{}: {}", key, value.join(", "));
+
+    // print flags
+    for (key, mut value) in flags {
+        let (_, package_and_name) = key.split_once('/').unwrap();
+        if let Some(dc_value) = device_config_flags.get(&key) {
+            value.push(dc_value.to_string());
+        }
+        println!("{}: {}", package_and_name, value.join(", "));
     }
+
     Ok(())
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_foo() {
+        let input = r#"
+namespace_one/com.foo.bar.flag_one=true
+namespace_one/com.foo.bar.flag_two=false
+random_noise;
+namespace_two/android.flag_one=true
+namespace_two/android.flag_two=nonsense
+"#;
+        let expected = HashMap::from([
+            (
+                "namespace_one/com.foo.bar.flag_one".to_string(),
+                "ENABLED (device_config)".to_string(),
+            ),
+            (
+                "namespace_one/com.foo.bar.flag_two".to_string(),
+                "DISABLED (device_config)".to_string(),
+            ),
+            ("namespace_two/android.flag_one".to_string(), "ENABLED (device_config)".to_string()),
+        ]);
+        let actual = parse_device_config(input);
+        assert_eq!(expected, actual);
+    }
+}
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 4bcb8fc..a3daca5 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -450,6 +450,11 @@
     return system_prop and system_prop.GetProp("ro.build.version.release") == "11"
 
   @property
+  def is_release_key(self):
+    system_prop = self.info_dict.get("build.prop")
+    return system_prop and system_prop.GetProp("ro.build.tags") == "release-key"
+
+  @property
   def vabc_compression_param(self):
     return self.get("virtual_ab_compression_method", "")
 
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 56ec929..d4420c9 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -728,47 +728,33 @@
   return input_file
 
 
-def GetTargetFilesZipForCustomImagesUpdates(input_file, custom_images):
+def GetTargetFilesZipForCustomImagesUpdates(input_file, custom_images: dict):
   """Returns a target-files.zip for custom partitions update.
 
   This function modifies ab_partitions list with the desired custom partitions
   and puts the custom images into the target target-files.zip.
 
   Args:
-    input_file: The input target-files.zip filename.
+    input_file: The input target-files extracted directory
     custom_images: A map of custom partitions and custom images.
 
   Returns:
-    The filename of a target-files.zip which has renamed the custom images in
-    the IMAGES/ to their partition names.
+    The extracted dir of a target-files.zip which has renamed the custom images
+    in the IMAGES/ to their partition names.
   """
+  for custom_image in custom_images.values():
+    if not os.path.exists(os.path.join(input_file, "IMAGES", custom_image)):
+      raise ValueError("Specified custom image {} not found in target files {}, available images are {}",
+                       custom_image, input_file, os.listdir(os.path.join(input_file, "IMAGES")))
 
-  # First pass: use zip2zip to copy the target files contents, excluding
-  # the "custom" images that will be replaced.
-  target_file = common.MakeTempFile(prefix="targetfiles-", suffix=".zip")
-  cmd = ['zip2zip', '-i', input_file, '-o', target_file]
-
-  images = {}
   for custom_partition, custom_image in custom_images.items():
     default_custom_image = '{}.img'.format(custom_partition)
     if default_custom_image != custom_image:
-      src = 'IMAGES/' + custom_image
-      dst = 'IMAGES/' + default_custom_image
-      cmd.extend(['-x', dst])
-      images[dst] = src
+      src = os.path.join(input_file, 'IMAGES', custom_image)
+      dst = os.path.join(input_file, 'IMAGES', default_custom_image)
+      os.rename(src, dst)
 
-  common.RunAndCheckOutput(cmd)
-
-  # Second pass: write {custom_image}.img as {custom_partition}.img.
-  with zipfile.ZipFile(input_file, allowZip64=True) as input_zip:
-    with zipfile.ZipFile(target_file, 'a', allowZip64=True) as output_zip:
-      for dst, src in images.items():
-        data = input_zip.read(src)
-        logger.info("Update custom partition '%s'", dst)
-        common.ZipWriteStr(output_zip, dst, data)
-      output_zip.close()
-
-  return target_file
+  return input_file
 
 
 def GeneratePartitionTimestampFlags(partition_state):
@@ -845,6 +831,10 @@
   """Generates an Android OTA package that has A/B update payload."""
   # If input target_files are directories, create a copy so that we can modify
   # them directly
+  target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
+  if OPTIONS.disable_vabc and target_info.is_release_key:
+    raise ValueError("Disabling VABC on release-key builds is not supported.")
+
   target_file = ExtractOrCopyTargetFiles(target_file)
   if source_file is not None:
     source_file = ExtractOrCopyTargetFiles(source_file)
@@ -888,7 +878,6 @@
   else:
     assert "ab_partitions" in OPTIONS.info_dict, \
         "META/ab_partitions.txt is required for ab_update."
-    target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
     source_info = None
     if target_info.vabc_compression_param:
       minimum_api_level_required = VABC_COMPRESSION_PARAM_SUPPORT[
@@ -1238,7 +1227,7 @@
       if len(words) == 2:
         if not words[1].isdigit():
           raise ValueError("Cannot parse value %r for option $COMPRESSION_LEVEL - only "
-                         "integers are allowed." % words[1])
+                           "integers are allowed." % words[1])
     elif o == "--security_patch_level":
       OPTIONS.security_patch_level = a
     elif o in ("--max_threads"):
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
index 9b3367e..5c70223 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -755,12 +755,10 @@
 
 
 def LocatePartitionPath(target_files_dir: str, partition: str, allow_empty):
-  path = os.path.join(target_files_dir, "RADIO", partition + ".img")
-  if os.path.exists(path):
-    return path
-  path = os.path.join(target_files_dir, "IMAGES", partition + ".img")
-  if os.path.exists(path):
-    return path
+  for subdir in TARGET_FILES_IMAGES_SUBDIR:
+    path = os.path.join(target_files_dir, subdir, partition + ".img")
+    if os.path.exists(path):
+      return path
   if allow_empty:
     return ""
   raise common.ExternalError(
@@ -773,12 +771,10 @@
 
 
 def LocatePartitionMap(target_files_dir: str, partition: str):
-  path = os.path.join(target_files_dir, "RADIO", partition + ".map")
-  if os.path.exists(path):
-    return path
-  path = os.path.join(target_files_dir, "IMAGES", partition + ".map")
-  if os.path.exists(path):
-    return path
+  for subdir in TARGET_FILES_IMAGES_SUBDIR:
+    path = os.path.join(target_files_dir, subdir, partition + ".map")
+    if os.path.exists(path):
+      return path
   return ""
 
 
@@ -1061,7 +1057,7 @@
     if common.IsSparseImage(src):
       return common.UnsparseImage(src, dst)
     else:
-      return os.link(src, dst)
+      return os.symlink(os.path.realpath(src), dst)
 
   for subdir in TARGET_FILES_IMAGES_SUBDIR:
     if not os.path.exists(os.path.join(input_dir, subdir)):