Merge "Add support for /product-services partition"
diff --git a/Usage.txt b/Usage.txt
index 004210b..558329b 100644
--- a/Usage.txt
+++ b/Usage.txt
@@ -29,7 +29,7 @@
   An alternative to setting $TARGET_PRODUCT and $TARGET_BUILD_VARIANT,
   which you may see in build servers, is to execute:
 
-    make PRODUCT-<product>-<variant>
+    m PRODUCT-<product>-<variant>
 
 
   A target may be a file path. For example, out/host/linux-x86/bin/adb .
@@ -46,6 +46,17 @@
     files named Android.bp
       these files are defined in Blueprint syntax
 
+  During a build, a few log files are generated in ${OUT} (or ${DIST_DIR}/logs
+    for dist builds):
+
+    verbose.log.gz
+      every command run, along with its outputs. This is similar to the
+      previous `m showcommands` option.
+    error.log
+      list of actions that failed during the build, and their outputs.
+    soong.log
+      verbose debug information from soong_ui
+
   For now, the full (extremely large) compiled list of targets can be found
     (after running the build once), split among these two files:
 
@@ -57,8 +68,6 @@
     tool here.
 
 Targets that adjust an existing build:
-  showcommands              Display the individual commands run to implement
-                            the build
   dist                      Copy into ${DIST_DIR} the portion of the build
                             that must be distributed
 
@@ -71,7 +80,7 @@
   Variables can either be set in the surrounding shell environment or can be
     passed as command-line arguments. For example:
       export I_AM_A_SHELL_VAR=1
-      I_AM_ANOTHER_SHELL_VAR=2 make droid I_AM_A_MAKE_VAR=3
+      I_AM_ANOTHER_SHELL_VAR=2 m droid I_AM_A_MAKE_VAR=3
   Here are some common variables and their meanings:
     TARGET_PRODUCT          The <product> to build # as described above
     TARGET_BUILD_VARIANT    The <variant> to build # as described above
diff --git a/core/android_manifest.mk b/core/android_manifest.mk
index 3af81ff..517379a 100644
--- a/core/android_manifest.mk
+++ b/core/android_manifest.mk
@@ -47,7 +47,7 @@
 ifneq (,$(strip $(my_full_libs_manifest_files)))
 
 $(full_android_manifest): PRIVATE_LIBS_MANIFESTS := $(my_full_libs_manifest_files)
-$(full_android_manifest): $(ANDROID_MANIFEST_MERGER_CLASSPATH)
+$(full_android_manifest): $(ANDROID_MANIFEST_MERGER_DEPS)
 $(full_android_manifest) : $(main_android_manifest) $(my_full_libs_manifest_files)
 	@echo "Merge android manifest files: $@ <-- $< $(PRIVATE_LIBS_MANIFESTS)"
 	@mkdir -p $(dir $@)
diff --git a/core/build-system.html b/core/build-system.html
index 3d86e24..3a11a47 100644
--- a/core/build-system.html
+++ b/core/build-system.html
@@ -147,12 +147,6 @@
 .c, .cpp, .h, .java, java libraries, etc., should all work without intervention
 in the Android.mk file.</p>
 
-<h3>Hiding command lines</h3>
-<p>The default of the build system will be to hide the command lines being
-executed for make steps.  It will be possible to override this by specifying
-the showcommands pseudo-target, and possibly by setting an environment
-variable.</p>
-
 <h3>Wildcard source files</h3>
 <p>Wildcarding source file will be discouraged.  It may be useful in some
 scenarios.  The default <code>$(wildcard *)</code> will not work due to the
@@ -326,19 +320,6 @@
 directory inside the current combo directory.  This is especially useful on the
 simulator and emulator, where the persistent data remains present between 
 builds.</li>
-<li><b>showcommands</b> - <code>showcommands</code> is a modifier target
-which causes the build system to show the actual command lines for the build
-steps, instead of the brief descriptions.  Most people don't like seeing the
-actual commands, because they're quite long and hard to read, but if you need
-to for debugging purposes, you can add <code>showcommands</code> to the list
-of targets you build.  For example <code>make showcommands</code> will build
-the default android configuration, and <code>make runtime showcommands</code>
-will build just the runtime, and targets that it depends on, while displaying
-the full command lines.  Please note that there are a couple places where the
-commands aren't shown here.  These are considered bugs, and should be fixed,
-but they're often hard to track down.  Please let
-<a href="mailto:android-build-team">android-build-team</a> know if you find
-any.</li>
 <li><b>LOCAL_MODULE</b> - Anything you specify as a <code>LOCAL_MODULE</code>
 in an Android.mk is made into a pseudotarget.  For example, <code>make
 runtime</code> might be shorthand for <code>make
diff --git a/core/config.mk b/core/config.mk
index 94ae1d8..f7a8176 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -723,19 +723,6 @@
 FINDBUGS_DIR := external/owasp/sanitizer/tools/findbugs/bin
 FINDBUGS := $(FINDBUGS_DIR)/findbugs
 
-# Tool to merge AndroidManifest.xmls
-ANDROID_MANIFEST_MERGER_CLASSPATH := \
-    prebuilts/gradle-plugin/com/android/tools/build/manifest-merger/26.1.0/manifest-merger-26.1.0.jar \
-    prebuilts/gradle-plugin/com/android/tools/common/26.1.0/common-26.1.0.jar \
-    prebuilts/gradle-plugin/com/android/tools/sdk-common/26.1.0/sdk-common-26.1.0.jar \
-    prebuilts/gradle-plugin/com/android/tools/sdklib/26.1.0/sdklib-26.1.0.jar \
-    prebuilts/gradle-plugin/org/jetbrains/kotlin/kotlin-runtime/1.0.5/kotlin-runtime-1.0.5.jar \
-    prebuilts/gradle-plugin/org/jetbrains/kotlin/kotlin-stdlib/1.1.3/kotlin-stdlib-1.1.3.jar \
-    prebuilts/misc/common/guava/guava-21.0.jar
-ANDROID_MANIFEST_MERGER := $(JAVA) \
-    -classpath $(subst $(space),:,$(strip $(ANDROID_MANIFEST_MERGER_CLASSPATH))) \
-    com.android.manifmerger.Merger
-
 COLUMN:= column
 
 USE_OPENJDK9 := true
@@ -914,7 +901,8 @@
 # A list of SEPolicy versions, besides PLATFORM_SEPOLICY_VERSION, that the framework supports.
 PLATFORM_SEPOLICY_COMPAT_VERSIONS := \
     26.0 \
-    27.0
+    27.0 \
+    28.0 \
 
 .KATI_READONLY := \
     PLATFORM_SEPOLICY_COMPAT_VERSIONS \
@@ -1049,6 +1037,8 @@
 TARGET_SDK_VERSIONS_WITHOUT_JAVA_18_SUPPORT := $(call numbers_less_than,24,$(TARGET_AVAILABLE_SDK_VERSIONS))
 TARGET_SDK_VERSIONS_WITHOUT_JAVA_19_SUPPORT := $(call numbers_less_than,27,$(TARGET_AVAILABLE_SDK_VERSIONS))
 
+INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/hiddenapi-public-list.txt
+INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/hiddenapi-private-list.txt
 INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/hiddenapi-light-greylist.txt
 INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/hiddenapi-dark-greylist.txt
 INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/hiddenapi-blacklist.txt
diff --git a/core/definitions.mk b/core/definitions.mk
index 8d7e3ff..7108e09 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2557,6 +2557,17 @@
   mv $@.compressed $@;
 endef
 
+ifeq ($(HOST_OS),linux)
+# Runs appcompat and store logs in $(PRODUCT_OUT)/appcompat
+define run-appcompat
+$(hide) \
+  mkdir -p $(PRODUCT_OUT)/appcompat; \
+  art/tools/veridex/appcompat.sh --dex-file=$@ 2>&1 > $(PRODUCT_OUT)/appcompat/$(PRIVATE_MODULE).log;
+endef
+else
+run-appcompat =
+endif
+
 # Remove dynamic timestamps from packages
 #
 define remove-timestamps-from-package
@@ -2837,6 +2848,7 @@
 endef
 
 # Copy dex files, invoking $(HIDDENAPI) on them in the process.
+# Also make the source dex file an input of the hiddenapi singleton rule in dex_preopt.mk.
 define hiddenapi-copy-dex-files
 $(2): $(1) $(HIDDENAPI) $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
       $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
@@ -2848,6 +2860,10 @@
 	    --light-greylist=$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
 	    --dark-greylist=$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) \
 	    --blacklist=$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
+
+$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST): $(1)
+$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST): \
+    PRIVATE_DEX_INPUTS := $$(PRIVATE_DEX_INPUTS) $(1)
 endef
 
 # File names for intermediate dex files of `hiddenapi-copy-soong-jar`.
@@ -3547,10 +3563,12 @@
 ###########################################################
 ## Verify module name meets character requirements:
 ##   a-z A-Z 0-9
-##   _.+-=,@~
+##   _.+-,@~
 ##
 ## This is a subset of bazel's target name restrictions:
 ##   https://docs.bazel.build/versions/master/build-ref.html#name
+##
+## Kati has problems with '=': https://github.com/google/kati/issues/138
 ###########################################################
 define verify-module-name
 $(if $(filter-out $(LOCAL_MODULE),$(subst /,,$(LOCAL_MODULE))), \
@@ -3559,14 +3577,14 @@
   $(call pretty-error,Invalid characters in module name: $(call _invalid-name-chars,$(LOCAL_MODULE))))
 endef
 define _invalid-name-chars
-$(subst _,,$(subst .,,$(subst +,,$(subst -,,$(subst =,,$(subst $(comma),,$(subst @,,$(subst ~,,$(subst 0,,$(subst 1,,$(subst 2,,$(subst 3,,$(subst 4,,$(subst 5,,$(subst 6,,$(subst 7,,$(subst 8,,$(subst 9,,$(subst a,,$(subst b,,$(subst c,,$(subst d,,$(subst e,,$(subst f,,$(subst g,,$(subst h,,$(subst i,,$(subst j,,$(subst k,,$(subst l,,$(subst m,,$(subst n,,$(subst o,,$(subst p,,$(subst q,,$(subst r,,$(subst s,,$(subst t,,$(subst u,,$(subst v,,$(subst w,,$(subst x,,$(subst y,,$(subst z,,$(call to-lower,$(1))))))))))))))))))))))))))))))))))))))))))))))
+$(subst _,,$(subst .,,$(subst +,,$(subst -,,$(subst $(comma),,$(subst @,,$(subst ~,,$(subst 0,,$(subst 1,,$(subst 2,,$(subst 3,,$(subst 4,,$(subst 5,,$(subst 6,,$(subst 7,,$(subst 8,,$(subst 9,,$(subst a,,$(subst b,,$(subst c,,$(subst d,,$(subst e,,$(subst f,,$(subst g,,$(subst h,,$(subst i,,$(subst j,,$(subst k,,$(subst l,,$(subst m,,$(subst n,,$(subst o,,$(subst p,,$(subst q,,$(subst r,,$(subst s,,$(subst t,,$(subst u,,$(subst v,,$(subst w,,$(subst x,,$(subst y,,$(subst z,,$(call to-lower,$(1)))))))))))))))))))))))))))))))))))))))))))))
 endef
 .KATI_READONLY := verify-module-name _invalid-name-chars
 
 ###########################################################
 ## Verify module stem meets character requirements:
 ##   a-z A-Z 0-9
-##   _.+-=,@~
+##   _.+-,@~
 ##
 ## This is a subset of bazel's target name restrictions:
 ##   https://docs.bazel.build/versions/master/build-ref.html#name
diff --git a/core/dex_preopt.mk b/core/dex_preopt.mk
index de830d4..6be6c17 100644
--- a/core/dex_preopt.mk
+++ b/core/dex_preopt.mk
@@ -89,3 +89,36 @@
 ifdef TARGET_2ND_ARCH
 $(TARGET_2ND_ARCH_VAR_PREFIX)DEXPREOPT_ONE_FILE_DEPENDENCY_BUILT_BOOT_PREOPT := $($(TARGET_2ND_ARCH_VAR_PREFIX)DEFAULT_DEX_PREOPT_BUILT_IMAGE_FILENAME)
 endif  # TARGET_2ND_ARCH
+
+# === hiddenapi rules ===
+
+hiddenapi_stubs_jar = $(call intermediates-dir-for,JAVA_LIBRARIES,$(1),,COMMON)/javalib.jar
+
+# Public API stubs
+HIDDENAPI_STUBS := \
+    $(call hiddenapi_stubs_jar,android_stubs_current) \
+    $(call hiddenapi_stubs_jar,android.test.base.stubs) \
+    $(call hiddenapi_stubs_jar,android.test.mock.stubs) \
+    $(call hiddenapi_stubs_jar,android.test.runner.stubs)
+
+# System API stubs
+HIDDENAPI_STUBS += \
+    $(call hiddenapi_stubs_jar,android_system_stubs_current)
+
+# Test API stubs
+HIDDENAPI_STUBS += \
+    $(call hiddenapi_stubs_jar,android_test_stubs_current)
+
+# Singleton rule which applies $(HIDDENAPI) on all boot class path dex files.
+# Inputs are filled with `hiddenapi-copy-dex-files` rules.
+$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST): \
+    PRIVATE_HIDDENAPI_STUBS := $(HIDDENAPI_STUBS)
+$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST): \
+    .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST)
+$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST): $(HIDDENAPI) $(HIDDENAPI_STUBS)
+	for INPUT_DEX in $(PRIVATE_DEX_INPUTS); do \
+		find `dirname $${INPUT_DEX}` -maxdepth 1 -name "classes*.dex"; \
+	done | sort | sed 's/^/--boot-dex=/' | xargs $(HIDDENAPI) list \
+	    $(addprefix --stub-dex=,$(PRIVATE_HIDDENAPI_STUBS)) \
+	    --out-public=$(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
+	    --out-private=$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST)
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index 3585026..208647e 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -34,6 +34,14 @@
         else # LOCAL_APK_LIBRARIES not empty
           LOCAL_DEX_PREOPT := nostripping
         endif # LOCAL_APK_LIBRARIES not empty
+      else
+        # Default to nostripping for non system preopt (enables preopt).
+        # Don't strip in case the oat/vdex version in system ROM doesn't match the one in other
+        # partitions. It needs to be able to fall back to the APK for that case.
+        # Also only enable preopt for non tests.
+        ifeq (,$(filter $(LOCAL_MODULE_TAGS),tests))
+          LOCAL_DEX_PREOPT := nostripping
+        endif
       endif # Installed to system.img.
     endif # LOCAL_DEX_PREOPT undefined
   endif # TARGET_BUILD_APPS empty
@@ -204,6 +212,11 @@
 endif
 endif
 
+# Only preopt primary arch for translated arch since there is only an image there.
+ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
+my_module_multilib := first
+endif
+
 # #################################################
 # Odex for the 1st arch
 my_2nd_arch_prefix :=
@@ -222,9 +235,12 @@
 else  # must be APPS
 # The preferred arch
 my_2nd_arch_prefix := $(LOCAL_2ND_ARCH_VAR_PREFIX)
+# Save the module multilib since setup_one_odex modifies it.
+saved_my_module_multilib := $(my_module_multilib)
 include $(BUILD_SYSTEM)/setup_one_odex.mk
+my_module_multilib := $(saved_my_module_multilib)
 ifdef TARGET_2ND_ARCH
-ifeq ($(LOCAL_MULTILIB),both)
+ifeq ($(my_module_multilib),both)
 # The non-preferred arch
 my_2nd_arch_prefix := $(if $(LOCAL_2ND_ARCH_VAR_PREFIX),,$(TARGET_2ND_ARCH_VAR_PREFIX))
 include $(BUILD_SYSTEM)/setup_one_odex.mk
diff --git a/core/main.mk b/core/main.mk
index 9f01b31..cc64d2d 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -26,6 +26,8 @@
 
 else # KATI
 
+$(info [1/1] initializing build system ...)
+
 # Absolute path of the present working direcotry.
 # This overrides the shell variable $PWD, which does not necessarily points to
 # the top of the source tree, for example when "make -C" is used in m/mm/mmm.
@@ -405,6 +407,8 @@
 ENFORCE_RRO_SOURCES :=
 endif
 
+subdir_makefiles_inc := .
+
 ifneq ($(ONE_SHOT_MAKEFILE),)
 # We've probably been invoked by the "mm" shell function
 # with a subdirectory's makefile.
@@ -449,7 +453,7 @@
 #
 
 subdir_makefiles := $(SOONG_ANDROID_MK) $(file <$(OUT_DIR)/.module_paths/Android.mk.list)
-subdir_makefiles_total := $(words $(subdir_makefiles))
+subdir_makefiles_total := $(words int $(subdir_makefiles) post finish)
 .KATI_READONLY := subdir_makefiles_total
 
 $(foreach mk,$(subdir_makefiles),$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] including $(mk) ...)$(eval include $(mk)))
@@ -465,6 +469,12 @@
 
 endif # ONE_SHOT_MAKEFILE
 
+ifndef subdir_makefiles_total
+subdir_makefiles_total := $(words init post finish)
+endif
+
+$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] finishing build rules ...)
+
 # -------------------------------------------------------------------
 # All module makefiles have been included at this point.
 # -------------------------------------------------------------------
@@ -981,6 +991,8 @@
   $(eval files += $(foreach cf,$(PRODUCTS.$(makefile).PRODUCT_COPY_FILES),\
     $(call append-path,$(PRODUCT_OUT),$(call word-colon,2,$(cf))))) \
   $(eval files := $(filter-out $(TARGET_OUT_FAKE)/% $(HOST_OUT)/%,$(files))) \
+  $(eval # RROs become REQUIRED by the source module, but are always placed on the vendor partition.) \
+  $(eval files := $(filter-out %__auto_generated_rro.apk,$(files))) \
   $(eval offending_files := $(filter-out $(path_patterns) $(whitelist_patterns),$(files))) \
   $(call maybe-print-list-and-error,$(offending_files),$(makefile) produces files outside its artifact path requirement.) \
   $(eval unused_whitelist := $(filter-out $(files),$(whitelist_patterns))) \
@@ -1412,4 +1424,6 @@
 ndk: $(SOONG_OUT_DIR)/ndk.timestamp
 .PHONY: ndk
 
+$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] writing build rules ...)
+
 endif # KATI
diff --git a/core/package_internal.mk b/core/package_internal.mk
index 7d5a0ae..be87bb2 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -592,6 +592,10 @@
 endif
 endif
 
+ifdef LOCAL_PRODUCT_MODULE
+$(LOCAL_BUILT_MODULE) : $(call intermediates-dir-for,PACKAGING,veridex,HOST)/veridex.zip
+endif
+
 $(LOCAL_BUILT_MODULE): PRIVATE_DONT_DELETE_JAR_DIRS := $(LOCAL_DONT_DELETE_JAR_DIRS)
 $(LOCAL_BUILT_MODULE): PRIVATE_RESOURCE_INTERMEDIATES_DIR := $(intermediates.COMMON)/resources
 $(LOCAL_BUILT_MODULE): PRIVATE_FULL_CLASSES_JAR := $(full_classes_jar)
@@ -632,6 +636,10 @@
 	@# No need to align, sign-package below will do it.
 	$(uncompress-dexs)
 endif
+# Run appcompat before stripping the classes.dex file.
+ifdef LOCAL_PRODUCT_MODULE
+	$(run-appcompat)
+endif  # LOCAL_PRODUCT_MODULE
 ifdef LOCAL_DEX_PREOPT
 ifneq ($(BUILD_PLATFORM_ZIP),)
 	@# Keep a copy of apk with classes.dex unstripped
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index c635ca5..2e6cb22 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -376,6 +376,10 @@
 $(built_module) : $(MINIGZIP)
 endif
 
+ifdef LOCAL_PRODUCT_MODULE
+$(built_module) : $(call intermediates-dir-for,PACKAGING,veridex,HOST)/veridex.zip
+endif
+
 $(built_module) : $(my_prebuilt_src_file) | $(ZIPALIGN) $(SIGNAPK_JAR)
 	$(transform-prebuilt-to-target)
 	$(uncompress-shared-libs)
@@ -390,6 +394,10 @@
 endif  # LOCAL_DEX_PREOPT
 ifneq ($(LOCAL_CERTIFICATE),PRESIGNED)
 	@# Only strip out files if we can re-sign the package.
+# Run appcompat before stripping the classes.dex file.
+ifdef LOCAL_PRODUCT_MODULE
+	$(run-appcompat)
+endif  # LOCAL_PRODUCT_MODULE
 ifdef LOCAL_DEX_PREOPT
 ifneq (nostripping,$(LOCAL_DEX_PREOPT))
 	$(call dexpreopt-remove-classes.dex,$@)
@@ -667,7 +675,7 @@
 $(my_exported_sdk_libs_file):
 	@echo "Export SDK libs $@"
 	$(hide) mkdir -p $(dir $@) && rm -f $@
-	$(if $(PRIATE_EXPORTED_SDK_LIBS),\
+	$(if $(PRIVATE_EXPORTED_SDK_LIBS),\
 		$(hide) echo $(PRIVATE_EXPORTED_SDK_LIBS) | tr ' ' '\n' > $@,\
 		$(hide) touch $@)
 
diff --git a/target/board/generic_arm64/BoardConfig.mk b/target/board/generic_arm64/BoardConfig.mk
index 88f89de..caf0cee 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -63,9 +63,10 @@
 # Emulator system image is going to be used as GSI and some vendor still hasn't
 # cleaned up all device specific directories under root!
 
-# TODO(jiyong) These might be SoC specific.
-BOARD_ROOT_EXTRA_FOLDERS += firmware firmware/radio persist
+# TODO(b/111434759, b/111287060) SoC specific hacks
 BOARD_ROOT_EXTRA_SYMLINKS := /vendor/lib/dsp:/dsp
+BOARD_ROOT_EXTRA_SYMLINKS += /mnt/vendor/persist:/persist
+BOARD_ROOT_EXTRA_SYMLINKS += /vendor/firmware_mnt:/firmware
 
 # TODO(b/36764215): remove this setting when the generic system image
 # no longer has QCOM-specific directories under /.
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 83c53b6..8b3f857 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -245,9 +245,8 @@
     wifi-service \
     wm \
 
-# VINTF data
+# VINTF data for system image
 PRODUCT_PACKAGES += \
-    device_manifest.xml \
     framework_manifest.xml \
     framework_compatibility_matrix.xml \
 
diff --git a/target/product/base_vendor.mk b/target/product/base_vendor.mk
index 681def2..9542a0e 100644
--- a/target/product/base_vendor.mk
+++ b/target/product/base_vendor.mk
@@ -27,7 +27,6 @@
     android.hardware.cas@1.0-service \
     android.hardware.configstore@1.0-service \
     android.hardware.media.omx@1.0-service \
-    device_compatibility_matrix.xml \
     fs_config_files_nonsystem \
     fs_config_dirs_nonsystem \
     gralloc.default \
@@ -48,3 +47,8 @@
     shell_and_utilities_vendor \
     vndservice \
     vndservicemanager \
+
+# VINTF data for vendor image
+PRODUCT_PACKAGES += \
+    device_manifest.xml \
+    device_compatibility_matrix.xml \
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
index 24c5b2d..e82e66a 100644
--- a/tools/releasetools/blockimgdiff.py
+++ b/tools/releasetools/blockimgdiff.py
@@ -270,7 +270,6 @@
   USED_IMGDIFF_LARGE_APK = "Large APK files split and diff'd with imgdiff"
 
   # Reasons for not applying imgdiff on APKs.
-  SKIPPED_TRIMMED = "Not used imgdiff due to trimmed RangeSet"
   SKIPPED_NONMONOTONIC = "Not used imgdiff due to having non-monotonic ranges"
   SKIPPED_SHARED_BLOCKS = "Not used imgdiff due to using shared blocks"
   SKIPPED_INCOMPLETE = "Not used imgdiff due to incomplete RangeSet"
@@ -279,7 +278,6 @@
   REASONS = (
       USED_IMGDIFF,
       USED_IMGDIFF_LARGE_APK,
-      SKIPPED_TRIMMED,
       SKIPPED_NONMONOTONIC,
       SKIPPED_SHARED_BLOCKS,
       SKIPPED_INCOMPLETE,
@@ -449,10 +447,6 @@
       self.imgdiff_stats.Log(name, ImgdiffStats.SKIPPED_INCOMPLETE)
       return False
 
-    if tgt_ranges.extra.get('trimmed') or src_ranges.extra.get('trimmed'):
-      self.imgdiff_stats.Log(name, ImgdiffStats.SKIPPED_TRIMMED)
-      return False
-
     reason = (ImgdiffStats.USED_IMGDIFF_LARGE_APK if large_apk
               else ImgdiffStats.USED_IMGDIFF)
     self.imgdiff_stats.Log(name, reason)
@@ -836,14 +830,10 @@
                   str(xf.tgt_ranges), str(xf.src_ranges)))
           else:
             if xf.patch:
-              # We have already generated the patch with imgdiff. Check if the
-              # transfer is intact.
+              # We have already generated the patch with imgdiff, while
+              # splitting large APKs (i.e. in FindTransfers()).
               assert not self.disable_imgdiff
               imgdiff = True
-              if (xf.src_ranges.extra.get('trimmed') or
-                  xf.tgt_ranges.extra.get('trimmed')):
-                imgdiff = False
-                xf.patch = None
             else:
               imgdiff = self.CanUseImgdiff(
                   xf.tgt_name, xf.tgt_ranges, xf.src_ranges)
@@ -1045,42 +1035,6 @@
     for i, xf in enumerate(L):
       xf.order = i
 
-  def RemoveBackwardEdges(self):
-    print("Removing backward edges...")
-    in_order = 0
-    out_of_order = 0
-    lost_source = 0
-
-    for xf in self.transfers:
-      lost = 0
-      size = xf.src_ranges.size()
-      for u in xf.goes_before:
-        # xf should go before u
-        if xf.order < u.order:
-          # it does, hurray!
-          in_order += 1
-        else:
-          # it doesn't, boo.  trim the blocks that u writes from xf's
-          # source, so that xf can go after u.
-          out_of_order += 1
-          assert xf.src_ranges.overlaps(u.tgt_ranges)
-          xf.src_ranges = xf.src_ranges.subtract(u.tgt_ranges)
-          xf.src_ranges.extra['trimmed'] = True
-
-      if xf.style == "diff" and not xf.src_ranges:
-        # nothing left to diff from; treat as new data
-        xf.style = "new"
-
-      lost = size - xf.src_ranges.size()
-      lost_source += lost
-
-    print(("  %d/%d dependencies (%.2f%%) were violated; "
-           "%d source blocks removed.") %
-          (out_of_order, in_order + out_of_order,
-           (out_of_order * 100.0 / (in_order + out_of_order))
-           if (in_order + out_of_order) else 0.0,
-           lost_source))
-
   def ReverseBackwardEdges(self):
     """Reverse unsatisfying edges and compute pairs of stashed blocks.
 
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index e7d8154..3dbffc7 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -655,12 +655,25 @@
   # if they contain all zeros. We can't reconstruct such a file from its block
   # list. Tag such entries accordingly. (Bug: 65213616)
   for entry in image.file_map:
-    # "/system/framework/am.jar" => "SYSTEM/framework/am.jar".
-    arcname = string.replace(entry, which, which.upper(), 1)[1:]
     # Skip artificial names, such as "__ZERO", "__NONZERO-1".
-    if arcname not in input_zip.namelist():
+    if not entry.startswith('/'):
       continue
 
+    # "/system/framework/am.jar" => "SYSTEM/framework/am.jar". Note that when
+    # using system_root_image, the filename listed in system.map may contain an
+    # additional leading slash (i.e. "//system/framework/am.jar"). Using lstrip
+    # to get consistent results.
+    arcname = string.replace(entry, which, which.upper(), 1).lstrip('/')
+
+    # Special handling another case with system_root_image, where files not
+    # under /system (e.g. "/sbin/charger") are packed under ROOT/ in a
+    # target_files.zip.
+    if which == 'system' and not arcname.startswith('SYSTEM'):
+      arcname = 'ROOT/' + arcname
+
+    assert arcname in input_zip.namelist(), \
+        "Failed to find the ZIP entry for {}".format(entry)
+
     info = input_zip.getinfo(arcname)
     ranges = image.file_map[entry]
 
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 0e25c7e..b9c410f 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -697,17 +697,11 @@
   if not HasTrebleEnabled(target_zip, target_info):
     return
 
-  # We don't support OEM thumbprint in Treble world (which calculates
-  # fingerprints in a different way as shown in CalculateFingerprint()).
-  assert not target_info.oem_props
-
   # Full OTA carries the info for system/vendor both.
   if source_info is None:
     AddCompatibilityArchive(True, True)
     return
 
-  assert not source_info.oem_props
-
   source_fp = source_info.fingerprint
   target_fp = target_info.fingerprint
   system_updated = source_fp != target_fp
@@ -1657,9 +1651,15 @@
   target_file = common.MakeTempFile(prefix="targetfiles-", suffix=".zip")
   target_zip = zipfile.ZipFile(target_file, 'w', allowZip64=True)
 
-  input_tmp = common.UnzipTemp(input_file, UNZIP_PATTERN)
   with zipfile.ZipFile(input_file, 'r') as input_zip:
     infolist = input_zip.infolist()
+    namelist = input_zip.namelist()
+
+  # Additionally unzip 'RADIO/*' if exists.
+  unzip_pattern = UNZIP_PATTERN[:]
+  if any([entry.startswith('RADIO/') for entry in namelist]):
+    unzip_pattern.append('RADIO/*')
+  input_tmp = common.UnzipTemp(input_file, unzip_pattern)
 
   for info in infolist:
     unzipped_file = os.path.join(input_tmp, *info.filename.split('/'))
@@ -1675,7 +1675,7 @@
     elif skip_postinstall and info.filename == POSTINSTALL_CONFIG:
       pass
 
-    elif info.filename.startswith(('META/', 'IMAGES/')):
+    elif info.filename.startswith(('META/', 'IMAGES/', 'RADIO/')):
       common.ZipWrite(target_zip, unzipped_file, arcname=info.filename)
 
   common.ZipClose(target_zip)
diff --git a/tools/releasetools/test_blockimgdiff.py b/tools/releasetools/test_blockimgdiff.py
index ceada18..124b4d5 100644
--- a/tools/releasetools/test_blockimgdiff.py
+++ b/tools/releasetools/test_blockimgdiff.py
@@ -203,8 +203,8 @@
 
     self.assertDictEqual(
         {
-            ImgdiffStats.USED_IMGDIFF : {"/system/app/app1.apk"},
-            ImgdiffStats.USED_IMGDIFF_LARGE_APK : {"/vendor/app/app2.apk"},
+            ImgdiffStats.USED_IMGDIFF: {"/system/app/app1.apk"},
+            ImgdiffStats.USED_IMGDIFF_LARGE_APK: {"/vendor/app/app2.apk"},
         },
         block_image_diff.imgdiff_stats.stats)
 
@@ -229,13 +229,6 @@
             "/system/app/app2.apk", RangeSet("10-15"),
             RangeSet("15-20 30 10-14")))
 
-    # At least one of the ranges has been modified.
-    src_ranges = RangeSet("0-5")
-    src_ranges.extra['trimmed'] = True
-    self.assertFalse(
-        block_image_diff.CanUseImgdiff(
-            "/vendor/app/app3.apk", RangeSet("10-15"), src_ranges))
-
     # At least one of the ranges is incomplete.
     src_ranges = RangeSet("0-5")
     src_ranges.extra['incomplete'] = True
@@ -246,8 +239,7 @@
     # The stats are correctly logged.
     self.assertDictEqual(
         {
-            ImgdiffStats.SKIPPED_NONMONOTONIC : {'/system/app/app2.apk'},
-            ImgdiffStats.SKIPPED_TRIMMED : {'/vendor/app/app3.apk'},
+            ImgdiffStats.SKIPPED_NONMONOTONIC: {'/system/app/app2.apk'},
             ImgdiffStats.SKIPPED_INCOMPLETE: {'/vendor/app/app4.apk'},
         },
         block_image_diff.imgdiff_stats.stats)
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index f211b03..1c75d19 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -662,6 +662,74 @@
     self.assertFalse(sparse_image.file_map['/system/file1'].extra)
     self.assertTrue(sparse_image.file_map['/system/file2'].extra['incomplete'])
 
+  def test_GetSparseImage_systemRootImage_filenameWithExtraLeadingSlash(self):
+    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
+    with zipfile.ZipFile(target_files, 'w') as target_files_zip:
+      target_files_zip.write(
+          test_utils.construct_sparse_image([(0xCAC2, 16)]),
+          arcname='IMAGES/system.img')
+      target_files_zip.writestr(
+          'IMAGES/system.map',
+          '\n'.join([
+              '//system/file1 1-5 9-10',
+              '//system/file2 11-12',
+              '/system/app/file3 13-15']))
+      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
+      # '/system/file2' has less blocks listed (2) than actual (3).
+      target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3))
+      # '/system/app/file3' has less blocks listed (3) than actual (4).
+      target_files_zip.writestr('SYSTEM/app/file3', os.urandom(4096 * 4))
+
+    tempdir = common.UnzipTemp(target_files)
+    with zipfile.ZipFile(target_files, 'r') as input_zip:
+      sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
+
+    self.assertFalse(sparse_image.file_map['//system/file1'].extra)
+    self.assertTrue(sparse_image.file_map['//system/file2'].extra['incomplete'])
+    self.assertTrue(
+        sparse_image.file_map['/system/app/file3'].extra['incomplete'])
+
+  def test_GetSparseImage_systemRootImage_nonSystemFiles(self):
+    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
+    with zipfile.ZipFile(target_files, 'w') as target_files_zip:
+      target_files_zip.write(
+          test_utils.construct_sparse_image([(0xCAC2, 16)]),
+          arcname='IMAGES/system.img')
+      target_files_zip.writestr(
+          'IMAGES/system.map',
+          '\n'.join([
+              '//system/file1 1-5 9-10',
+              '//init.rc 13-15']))
+      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
+      # '/init.rc' has less blocks listed (3) than actual (4).
+      target_files_zip.writestr('ROOT/init.rc', os.urandom(4096 * 4))
+
+    tempdir = common.UnzipTemp(target_files)
+    with zipfile.ZipFile(target_files, 'r') as input_zip:
+      sparse_image = common.GetSparseImage('system', tempdir, input_zip, False)
+
+    self.assertFalse(sparse_image.file_map['//system/file1'].extra)
+    self.assertTrue(sparse_image.file_map['//init.rc'].extra['incomplete'])
+
+  def test_GetSparseImage_fileNotFound(self):
+    target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip')
+    with zipfile.ZipFile(target_files, 'w') as target_files_zip:
+      target_files_zip.write(
+          test_utils.construct_sparse_image([(0xCAC2, 16)]),
+          arcname='IMAGES/system.img')
+      target_files_zip.writestr(
+          'IMAGES/system.map',
+          '\n'.join([
+              '//system/file1 1-5 9-10',
+              '//system/file2 11-12']))
+      target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7))
+
+    tempdir = common.UnzipTemp(target_files)
+    with zipfile.ZipFile(target_files, 'r') as input_zip:
+      self.assertRaises(
+          AssertionError, common.GetSparseImage, 'system', tempdir, input_zip,
+          False)
+
 
 class InstallRecoveryScriptFormatTest(unittest.TestCase):
   """Checks the format of install-recovery.sh.
diff --git a/tools/releasetools/test_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index 7c34b7e..c8e6750 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -566,6 +566,8 @@
     self.assertIn('IMAGES/boot.img', namelist)
     self.assertIn('IMAGES/system.img', namelist)
     self.assertIn('IMAGES/vendor.img', namelist)
+    self.assertIn('RADIO/bootloader.img', namelist)
+    self.assertIn('RADIO/modem.img', namelist)
     self.assertIn(POSTINSTALL_CONFIG, namelist)
 
     self.assertNotIn('IMAGES/system_other.img', namelist)
@@ -583,11 +585,33 @@
     self.assertIn('IMAGES/boot.img', namelist)
     self.assertIn('IMAGES/system.img', namelist)
     self.assertIn('IMAGES/vendor.img', namelist)
+    self.assertIn('RADIO/bootloader.img', namelist)
+    self.assertIn('RADIO/modem.img', namelist)
 
     self.assertNotIn('IMAGES/system_other.img', namelist)
     self.assertNotIn('IMAGES/system.map', namelist)
     self.assertNotIn(POSTINSTALL_CONFIG, namelist)
 
+  def test_GetTargetFilesZipForSecondaryImages_withoutRadioImages(self):
+    input_file = construct_target_files(secondary=True)
+    common.ZipDelete(input_file, 'RADIO/bootloader.img')
+    common.ZipDelete(input_file, 'RADIO/modem.img')
+    target_file = GetTargetFilesZipForSecondaryImages(input_file)
+
+    with zipfile.ZipFile(target_file) as verify_zip:
+      namelist = verify_zip.namelist()
+
+    self.assertIn('META/ab_partitions.txt', namelist)
+    self.assertIn('IMAGES/boot.img', namelist)
+    self.assertIn('IMAGES/system.img', namelist)
+    self.assertIn('IMAGES/vendor.img', namelist)
+    self.assertIn(POSTINSTALL_CONFIG, namelist)
+
+    self.assertNotIn('IMAGES/system_other.img', namelist)
+    self.assertNotIn('IMAGES/system.map', namelist)
+    self.assertNotIn('RADIO/bootloader.img', namelist)
+    self.assertNotIn('RADIO/modem.img', namelist)
+
   def test_GetTargetFilesZipWithoutPostinstallConfig(self):
     input_file = construct_target_files()
     target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)