Merge "Make more Treble make variables read only."
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 1e64c4f..bd605ec 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -4,6 +4,7 @@
 
 # '',true
 LOCAL_32_BIT_ONLY:=
+LOCAL_AAPT2_ONLY:=
 LOCAL_AAPT_FLAGS:=
 LOCAL_AAPT_INCLUDE_ALL_RESOURCES:=
 LOCAL_ADDITIONAL_CERTIFICATES:=
diff --git a/core/config.mk b/core/config.mk
index 9515fac..bebc186 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -536,14 +536,14 @@
   ZIPALIGN := $(HOST_OUT_EXECUTABLES)/zipalign
 
 else # TARGET_BUILD_APPS || TARGET_BUILD_PDK
-  AIDL := $(prebuilt_sdk_tools_bin)/aidl
+  AIDL := $(prebuilt_build_tools_bin)/aidl
   AAPT := $(prebuilt_sdk_tools_bin)/aapt
   AAPT2 := $(prebuilt_sdk_tools_bin)/aapt2
   DESUGAR := $(prebuilt_build_tools_jars)/desugar.jar
   MAINDEXCLASSES := $(prebuilt_sdk_tools)/mainDexClasses
   SIGNAPK_JAR := $(prebuilt_sdk_tools)/lib/signapk$(COMMON_JAVA_PACKAGE_SUFFIX)
   SIGNAPK_JNI_LIBRARY_PATH := $(prebuilt_sdk_tools)/$(HOST_OS)/lib64
-  ZIPALIGN := $(prebuilt_sdk_tools_bin)/zipalign
+  ZIPALIGN := $(prebuilt_build_tools_bin)/zipalign
 endif # TARGET_BUILD_APPS || TARGET_BUILD_PDK
 
 R8_COMPAT_PROGUARD := $(HOST_OUT_EXECUTABLES)/r8-compat-proguard
diff --git a/core/droiddoc.mk b/core/droiddoc.mk
index d66b688..2bac984 100644
--- a/core/droiddoc.mk
+++ b/core/droiddoc.mk
@@ -91,8 +91,11 @@
 $(full_target): PRIVATE_SOURCE_PATH := $(call normalize-path-list,$(LOCAL_DROIDDOC_SOURCE_PATH))
 $(full_target): PRIVATE_JAVA_FILES := $(filter %.java,$(full_src_files))
 $(full_target): PRIVATE_JAVA_FILES += $(addprefix $($(my_prefix)OUT_COMMON_INTERMEDIATES)/, $(filter %.java,$(LOCAL_INTERMEDIATE_SOURCES)))
+$(full_target): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
 $(full_target): PRIVATE_SOURCE_INTERMEDIATES_DIR := $(intermediates.COMMON)/src
+$(full_target): PRIVATE_SRCJAR_INTERMEDIATES_DIR := $(intermediates.COMMON)/srcjars
 $(full_target): PRIVATE_SRC_LIST_FILE := $(intermediates.COMMON)/droiddoc-src-list
+$(full_target): PRIVATE_SRCJAR_LIST_FILE := $(intermediates.COMMON)/droiddoc-srcjar-list
 
 ifneq ($(strip $(LOCAL_ADDITIONAL_JAVA_DIR)),)
 $(full_target): PRIVATE_ADDITIONAL_JAVA_DIR := $(LOCAL_ADDITIONAL_JAVA_DIR)
@@ -173,17 +176,21 @@
         $(droiddoc) \
         $(html_dir_files) \
         $(full_java_libs) \
+        $(EXTRACT_SRCJARS) \
+        $(LOCAL_SRCJARS) \
         $(LOCAL_ADDITIONAL_DEPENDENCIES)
 	@echo Docs droiddoc: $(PRIVATE_OUT_DIR)
 	$(hide) mkdir -p $(dir $@)
-	$(addprefix $(hide) rm -rf ,$(PRIVATE_STUB_OUT_DIR))
+	$(hide) rm -rf $(PRIVATE_STUB_OUT_DIR) $(PRIVATE_SRCJAR_INTERMEDIATES_DIR)
 	$(call prepare-doc-source-list,$(PRIVATE_SRC_LIST_FILE),$(PRIVATE_JAVA_FILES), \
 			$(PRIVATE_SOURCE_INTERMEDIATES_DIR) $(PRIVATE_ADDITIONAL_JAVA_DIR))
+	$(EXTRACT_SRCJARS) $(PRIVATE_SRCJAR_INTERMEDIATES_DIR) $(PRIVATE_SRCJAR_LIST_FILE) $(PRIVATE_SRCJARS)
 	$(hide) ( \
 		$(JAVADOC) \
                 -encoding UTF-8 \
                 -source 1.8 \
                 \@$(PRIVATE_SRC_LIST_FILE) \
+                \@$(PRIVATE_SRCJAR_LIST_FILE) \
                 -J-Xmx1600m \
                 -J-XX:-OmitStackTraceInFastThrow \
                 -XDignore.symbol.file \
@@ -223,17 +230,19 @@
 # For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
 $(full_target): PRIVATE_BOOTCLASSPATH_ARG := $(addprefix -bootclasspath ,$(PRIVATE_BOOTCLASSPATH))
 endif
-
-$(full_target): $(full_src_files) $(full_java_libs)
+$(full_target): $(full_src_files) $(full_java_libs) $(EXTRACT_SRCJARS) $(LOCAL_SRCJARS) $(LOCAL_ADDITIONAL_DEPENDENCIES)
 	@echo Docs javadoc: $(PRIVATE_OUT_DIR)
 	@mkdir -p $(dir $@)
+	rm -rf $(PRIVATE_SRCJAR_INTERMEDIATES_DIR)
 	$(call prepare-doc-source-list,$(PRIVATE_SRC_LIST_FILE),$(PRIVATE_JAVA_FILES), \
 			$(PRIVATE_SOURCE_INTERMEDIATES_DIR) $(PRIVATE_ADDITIONAL_JAVA_DIR))
+	$(EXTRACT_SRCJARS) $(PRIVATE_SRCJAR_INTERMEDIATES_DIR) $(PRIVATE_SRCJAR_LIST_FILE) $(PRIVATE_SRCJARS)
 	$(hide) ( \
 		$(JAVADOC) \
                 -encoding UTF-8 \
                 $(PRIVATE_DROIDDOC_OPTIONS) \
                 \@$(PRIVATE_SRC_LIST_FILE) \
+                \@$(PRIVATE_SRCJAR_LIST_FILE) \
                 -J-Xmx1024m \
                 -XDignore.symbol.file \
                 -Xdoclint:none \
diff --git a/core/java_common.mk b/core/java_common.mk
index 6ae1415..4dd0de6 100644
--- a/core/java_common.mk
+++ b/core/java_common.mk
@@ -414,7 +414,14 @@
 my_allowed_types := java:sdk java:system java:platform
 endif
 
-my_link_deps := $(addprefix JAVA_LIBRARIES:,$(LOCAL_STATIC_JAVA_LIBRARIES))
+ifdef LOCAL_AAPT2_ONLY
+my_link_type += aapt2_only
+endif
+ifdef LOCAL_USE_AAPT2
+my_allowed_types += aapt2_only
+endif
+
+my_link_deps := $(addprefix JAVA_LIBRARIES:,$(LOCAL_STATIC_JAVA_LIBRARIES) $(LOCAL_JAVA_LIBRARIES))
 my_link_deps += $(addprefix APPS:,$(apk_libraries))
 
 my_2nd_arch_prefix := $(LOCAL_2ND_ARCH_VAR_PREFIX)
diff --git a/core/package_internal.mk b/core/package_internal.mk
index 9bf173f..9f99c7a 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -146,6 +146,10 @@
 need_compile_asset := true
 endif
 
+ifdef LOCAL_AAPT2_ONLY
+LOCAL_USE_AAPT2 := true
+endif
+
 my_res_package :=
 ifdef LOCAL_USE_AAPT2
 # In aapt2 the last takes precedence.
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index 48e410b..3fec8d9 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -547,6 +547,10 @@
 $(common_javalib_jar) : $(common_classes_jar)
 	$(transform-prebuilt-to-target)
 
+ifdef LOCAL_AAPT2_ONLY
+LOCAL_USE_AAPT2 := true
+endif
+
 ifdef LOCAL_USE_AAPT2
 ifneq ($(my_src_aar),)
 LOCAL_SDK_RES_VERSION:=$(strip $(LOCAL_SDK_RES_VERSION))
diff --git a/core/static_java_library.mk b/core/static_java_library.mk
index 69cf955..5ffb88d 100644
--- a/core/static_java_library.mk
+++ b/core/static_java_library.mk
@@ -28,6 +28,10 @@
 
 my_res_package :=
 
+ifdef LOCAL_AAPT2_ONLY
+LOCAL_USE_AAPT2 := true
+endif
+
 # Hack to build static Java library with Android resource
 # See bug 5714516
 all_resources :=
diff --git a/core/tasks/collect_gpl_sources.mk b/core/tasks/collect_gpl_sources.mk
index 30ba62b..70f0afe 100644
--- a/core/tasks/collect_gpl_sources.mk
+++ b/core/tasks/collect_gpl_sources.mk
@@ -12,20 +12,22 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-gpl_source_tgz := $(call intermediates-dir-for,PACKAGING,gpl_source,HOST,COMMON)/gpl_source.tgz
+ifdef dist_goal
+
+# The rule below doesn't have dependenices on the files that it copies,
+# so manually generate directly into the DIST_DIR directory that is always
+# wiped between dist builds.
+gpl_source_tgz := $(DIST_DIR)/gpl_source.tgz
 
 # FORCE since we can't know whether any of the sources changed
 $(gpl_source_tgz): PRIVATE_PATHS := $(sort $(patsubst %/, %, $(dir $(ALL_GPL_MODULE_LICENSE_FILES))))
-$(gpl_source_tgz) : $(ALL_GPL_MODULE_LICENSE_FILES) FORCE
+$(gpl_source_tgz) : $(ALL_GPL_MODULE_LICENSE_FILES)
 	@echo Package gpl sources: $@
-	@rm -rf $(dir $@) && mkdir -p $(dir $@)
 	$(hide) tar cfz $@ --exclude ".git*" $(PRIVATE_PATHS)
 
-
-.PHONY: gpl_source_tgz
-gpl_source_tgz : $(gpl_source_tgz)
-
 # Dist the tgz only if we are doing a full build
 ifeq (,$(TARGET_BUILD_APPS))
-$(call dist-for-goals, droidcore, $(gpl_source_tgz))
+droidcore: $(gpl_source_tgz)
 endif
+
+endif # dist_goal
diff --git a/core/tasks/vndk.mk b/core/tasks/vndk.mk
new file mode 100644
index 0000000..d824a41
--- /dev/null
+++ b/core/tasks/vndk.mk
@@ -0,0 +1,124 @@
+# Copyright (C) 2017 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.
+
+current_makefile := $(lastword $(MAKEFILE_LIST))
+
+# BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
+ifeq ($(BOARD_VNDK_VERSION),current)
+
+# Returns arch-specific libclang_rt.ubsan* library name.
+# Because VNDK_CORE_LIBRARIES includes all arch variants for libclang_rt.ubsan*
+# libs, the arch-specific libs are selected separately.
+#
+# Args:
+#   $(1): if not empty, evaluates for TARGET_2ND_ARCH
+define clang-ubsan-vndk-core
+  $(eval prefix := $(if $(1),2ND_,))
+  $(addsuffix .vendor,$($(addprefix $(prefix),UBSAN_RUNTIME_LIBRARY)))
+endef
+
+# Args:
+#   $(1): list of lib names without '.so' suffix (e.g., libX.vendor)
+#   $(2): if not empty, evaluates for TARGET_2ND_ARCH
+define paths-of-intermediates
+  $(strip \
+    $(foreach lib,$(1), \
+      $(call append-path,$(call intermediates-dir-for,SHARED_LIBRARIES,$(lib),,,$(2)),$(lib).so)))
+endef
+
+vndk_core_libs := $(addsuffix .vendor,$(filter-out libclang_rt.ubsan%,$(VNDK_CORE_LIBRARIES)))
+vndk_sp_libs := $(addsuffix .vendor,$(VNDK_SAMEPROCESS_LIBRARIES))
+vndk_snapshot_dependencies := \
+  $(vndk_core_libs) \
+  $(vndk_sp_libs)
+
+# If in the future libclang_rt.ubsan* is removed from the VNDK-core list,
+# need to update the related logic in this file.
+ifeq (,$(filter libclang_rt.ubsan%,$(VNDK_CORE_LIBRARIES)))
+  $(error libclang_rt.ubsan* is no longer a VNDK-core library.)
+endif
+
+# for TARGET_ARCH
+clang_ubsan_vndk_core_$(TARGET_ARCH) := $(call clang-ubsan-vndk-core)
+vndk_snapshot_dependencies += \
+  $(clang_ubsan_vndk_core_$(TARGET_ARCH))
+
+ifdef TARGET_2ND_ARCH
+clang_ubsan_vndk_core_$(TARGET_2ND_ARCH) := $(call clang-ubsan-vndk-core,true)
+vndk_snapshot_dependencies += \
+  $(clang_ubsan_vndk_core_$(TARGET_2ND_ARCH))
+endif
+
+vndk_snapshot_zip := $(PRODUCT_OUT)/android-vndk-$(TARGET_ARCH).zip
+vndk_snapshot_out := $(call intermediates-dir-for,PACKAGING,vndk-snapshot)
+$(vndk_snapshot_zip): PRIVATE_VNDK_SNAPSHOT_OUT := $(vndk_snapshot_out)
+
+$(vndk_snapshot_zip): PRIVATE_VNDK_CORE_OUT_$(TARGET_ARCH) := \
+  $(vndk_snapshot_out)/arch-$(TARGET_ARCH)/shared/vndk-core
+$(vndk_snapshot_zip): PRIVATE_VNDK_CORE_INTERMEDIATES_$(TARGET_ARCH) := \
+  $(call paths-of-intermediates,$(vndk_core_libs) $(clang_ubsan_vndk_core_$(TARGET_ARCH)))
+$(vndk_snapshot_zip): PRIVATE_VNDK_SP_OUT_$(TARGET_ARCH) := \
+  $(vndk_snapshot_out)/arch-$(TARGET_ARCH)/shared/vndk-sp
+$(vndk_snapshot_zip): PRIVATE_VNDK_SP_INTERMEDIATES_$(TARGET_ARCH) := \
+  $(call paths-of-intermediates,$(vndk_sp_libs))
+
+ifdef TARGET_2ND_ARCH
+$(vndk_snapshot_zip): PRIVATE_VNDK_CORE_OUT_$(TARGET_2ND_ARCH) := \
+  $(vndk_snapshot_out)/arch-$(TARGET_2ND_ARCH)/shared/vndk-core
+$(vndk_snapshot_zip): PRIVATE_VNDK_CORE_INTERMEDIATES_$(TARGET_2ND_ARCH) := \
+  $(call paths-of-intermediates,$(vndk_core_libs) $(clang_ubsan_vndk_core_$(TARGET_2ND_ARCH)),true)
+$(vndk_snapshot_zip): PRIVATE_VNDK_SP_OUT_$(TARGET_2ND_ARCH) := \
+  $(vndk_snapshot_out)/arch-$(TARGET_2ND_ARCH)/shared/vndk-sp
+$(vndk_snapshot_zip): PRIVATE_VNDK_SP_INTERMEDIATES_$(TARGET_2ND_ARCH) := \
+  $(call paths-of-intermediates,$(vndk_sp_libs),true)
+endif
+
+# Args
+#   $(1): destination directory
+#   $(2): list of libs to copy
+$(vndk_snapshot_zip): private-copy-vndk-intermediates = \
+	@mkdir -p $(1); \
+	$(foreach lib,$(2),cp -p $(lib) $(call append-path,$(1),$(subst .vendor,,$(notdir $(lib))));)
+
+$(vndk_snapshot_zip): $(vndk_snapshot_dependencies) $(SOONG_ZIP)
+	@echo 'Generating VNDK snapshot: $@'
+	@rm -f $@
+	@rm -rf $(PRIVATE_VNDK_SNAPSHOT_OUT)
+	@mkdir -p $(PRIVATE_VNDK_SNAPSHOT_OUT)
+	$(call private-copy-vndk-intermediates, \
+		$(PRIVATE_VNDK_CORE_OUT_$(TARGET_ARCH)),$(PRIVATE_VNDK_CORE_INTERMEDIATES_$(TARGET_ARCH)))
+	$(call private-copy-vndk-intermediates, \
+		$(PRIVATE_VNDK_SP_OUT_$(TARGET_ARCH)),$(PRIVATE_VNDK_SP_INTERMEDIATES_$(TARGET_ARCH)))
+ifdef TARGET_2ND_ARCH
+	$(call private-copy-vndk-intermediates, \
+		$(PRIVATE_VNDK_CORE_OUT_$(TARGET_2ND_ARCH)),$(PRIVATE_VNDK_CORE_INTERMEDIATES_$(TARGET_2ND_ARCH)))
+	$(call private-copy-vndk-intermediates, \
+		$(PRIVATE_VNDK_SP_OUT_$(TARGET_2ND_ARCH)),$(PRIVATE_VNDK_SP_INTERMEDIATES_$(TARGET_2ND_ARCH)))
+endif
+	$(hide) $(SOONG_ZIP) -o $@ -P vndk-snapshot -C $(PRIVATE_VNDK_SNAPSHOT_OUT) \
+	-D $(PRIVATE_VNDK_SNAPSHOT_OUT)
+
+.PHONY: vndk
+vndk: $(vndk_snapshot_zip)
+
+$(call dist-for-goals, vndk, $(vndk_snapshot_zip))
+
+else # BOARD_VNDK_VERSION is NOT set to 'current'
+
+.PHONY: vndk
+vndk:
+	$(call echo-error,$(current_makefile),CANNOT generate VNDK snapshot. BOARD_VNDK_VERSION must be set to 'current'.)
+	exit 1
+
+endif # BOARD_VNDK_VERSION
diff --git a/tools/java-event-log-tags.py b/tools/java-event-log-tags.py
index f364751..37cd712 100755
--- a/tools/java-event-log-tags.py
+++ b/tools/java-event-log-tags.py
@@ -51,30 +51,37 @@
     print >> sys.stderr, "unhandled option %s" % (o,)
     sys.exit(1)
 
-if len(args) != 2:
-  print "need exactly two input files, not %d" % (len(args),)
+if len(args) != 1 and len(args) != 2:
+  print "need one or two input files, not %d" % (len(args),)
   print __doc__
   sys.exit(1)
 
 fn = args[0]
 tagfile = event_log_tags.TagFile(fn)
 
-# Load the merged tag file (which should have numbers assigned for all
-# tags.  Use the numbers from the merged file to fill in any missing
-# numbers from the input file.
-merged_fn = args[1]
-merged_tagfile = event_log_tags.TagFile(merged_fn)
-merged_by_name = dict([(t.tagname, t) for t in merged_tagfile.tags])
-for t in tagfile.tags:
-  if t.tagnum is None:
-    if t.tagname in merged_by_name:
-      t.tagnum = merged_by_name[t.tagname].tagnum
-    else:
-      # We're building something that's not being included in the
-      # product, so its tags don't appear in the merged file.  Assign
-      # them all an arbitrary number so we can emit the java and
-      # compile the (unused) package.
-      t.tagnum = 999999
+if len(args) > 1:
+  # Load the merged tag file (which should have numbers assigned for all
+  # tags.  Use the numbers from the merged file to fill in any missing
+  # numbers from the input file.
+  merged_fn = args[1]
+  merged_tagfile = event_log_tags.TagFile(merged_fn)
+  merged_by_name = dict([(t.tagname, t) for t in merged_tagfile.tags])
+  for t in tagfile.tags:
+    if t.tagnum is None:
+      if t.tagname in merged_by_name:
+        t.tagnum = merged_by_name[t.tagname].tagnum
+      else:
+        # We're building something that's not being included in the
+        # product, so its tags don't appear in the merged file.  Assign
+        # them all an arbitrary number so we can emit the java and
+        # compile the (unused) package.
+        t.tagnum = 999999
+else:
+  # Not using the merged tag file, so all tags must have manually assigned
+  # numbers
+  for t in tagfile.tags:
+    if t.tagnum is None:
+      tagfilef.AddError("tag \"%s\" has no number" % (tagname,), tag.linenum)
 
 if "java_package" not in tagfile.options:
   tagfile.AddError("java_package option not specified", linenum=0)
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index d31a297..5698356 100755
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -350,6 +350,10 @@
               dtbo_img_path, prefix="IMAGES/"):
   """Create a VBMeta image and store it in output_zip."""
   img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "vbmeta.img")
+  if os.path.exists(img.input_name):
+    print("vbmeta.img already exists in %s; not rebuilding..." % (prefix,))
+    return img.input_name
+
   avbtool = os.getenv('AVBTOOL') or OPTIONS.info_dict["avb_avbtool"]
   cmd = [avbtool, "make_vbmeta_image", "--output", img.name]
   common.AppendAVBSigningArgs(cmd, "vbmeta")
@@ -529,53 +533,43 @@
   def banner(s):
     print("\n\n++++ " + s + " ++++\n\n")
 
-  prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
-  boot_image = None
-  if os.path.exists(prebuilt_path):
-    banner("boot")
-    print("boot.img already exists in IMAGES/, no need to rebuild...")
-    if OPTIONS.rebuild_recovery:
-      boot_image = common.GetBootableImage(
-          "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
-  else:
-    banner("boot")
-    boot_image = common.GetBootableImage(
-        "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
-    if boot_image:
+  banner("boot")
+  # common.GetBootableImage() returns the image directly if present.
+  boot_image = common.GetBootableImage(
+      "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
+  # boot.img may be unavailable in some targets (e.g. aosp_arm64).
+  if boot_image:
+    boot_img_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img")
+    if not os.path.exists(boot_img_path):
+      boot_image.WriteToDir(OPTIONS.input_tmp)
       if output_zip:
         boot_image.AddToZip(output_zip)
-      else:
-        boot_image.WriteToDir(OPTIONS.input_tmp)
 
   recovery_image = None
   if has_recovery:
     banner("recovery")
-    prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "recovery.img")
-    if os.path.exists(prebuilt_path):
-      print("recovery.img already exists in IMAGES/, no need to rebuild...")
-      if OPTIONS.rebuild_recovery:
-        recovery_image = common.GetBootableImage(
-            "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp,
-            "RECOVERY")
-    else:
-      recovery_image = common.GetBootableImage(
-          "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
-      if recovery_image:
-        if output_zip:
-          recovery_image.AddToZip(output_zip)
-        else:
-          recovery_image.WriteToDir(OPTIONS.input_tmp)
+    recovery_image = common.GetBootableImage(
+        "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
+    assert recovery_image, "Failed to create recovery.img."
+    recovery_img_path = os.path.join(
+        OPTIONS.input_tmp, "IMAGES", "recovery.img")
+    if not os.path.exists(recovery_img_path):
+      recovery_image.WriteToDir(OPTIONS.input_tmp)
+      if output_zip:
+        recovery_image.AddToZip(output_zip)
 
       banner("recovery (two-step image)")
       # The special recovery.img for two-step package use.
       recovery_two_step_image = common.GetBootableImage(
           "IMAGES/recovery-two-step.img", "recovery-two-step.img",
           OPTIONS.input_tmp, "RECOVERY", two_step_image=True)
-      if recovery_two_step_image:
+      assert recovery_two_step_image, "Failed to create recovery-two-step.img."
+      recovery_two_step_image_path = os.path.join(
+          OPTIONS.input_tmp, "IMAGES", "recovery-two-step.img")
+      if not os.path.exists(recovery_two_step_image_path):
+        recovery_two_step_image.WriteToDir(OPTIONS.input_tmp)
         if output_zip:
           recovery_two_step_image.AddToZip(output_zip)
-        else:
-          recovery_two_step_image.WriteToDir(OPTIONS.input_tmp)
 
   banner("system")
   system_img_path = AddSystem(
@@ -604,9 +598,8 @@
 
   if OPTIONS.info_dict.get("avb_enable") == "true":
     banner("vbmeta")
-    boot_contents = boot_image.WriteToTemp()
-    AddVBMeta(output_zip, boot_contents.name, system_img_path,
-              vendor_img_path, dtbo_img_path)
+    AddVBMeta(output_zip, boot_img_path, system_img_path, vendor_img_path,
+              dtbo_img_path)
 
   # For devices using A/B update, copy over images from RADIO/ and/or
   # VENDOR_IMAGES/ to IMAGES/ and make sure we have all the needed