Merge "Include charger.recovery for recovery."
diff --git a/Changes.md b/Changes.md
index 35b8944..1fadcef 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,35 @@
 # Build System Changes for Android.mk Writers
 
+## `PRODUCT_HOST_PACKAGES` split from `PRODUCT_PACKAGES` {#PRODUCT_HOST_PACKAGES}
+
+Previously, adding a module to `PRODUCT_PACKAGES` that supported both the host
+and the target (`host_supported` in Android.bp; two modules with the same name
+in Android.mk) would cause both to be built and installed. In many cases you
+only want either the host or target versions to be built/installed by default,
+and would be over-building with both. So `PRODUCT_PACKAGES` will be changing to
+just affect target modules, while `PRODUCT_HOST_PACKAGES` is being added for
+host modules.
+
+Functional differences between `PRODUCT_PACKAGES` and `PRODUCT_HOST_PACKAGES`:
+
+* `PRODUCT_HOST_PACKAGES` does not have `_ENG`/`_DEBUG` variants, as that's a
+  property of the target, not the host.
+* `PRODUCT_HOST_PACKAGES` does not support `LOCAL_MODULE_OVERRIDES`.
+* `PRODUCT_HOST_PACKAGES` requires listed modules to exist, and be host
+  modules. (Unless `ALLOW_MISSING_DEPENDENCIES` is set)
+
+This is still an active migration, so currently it still uses
+`PRODUCT_PACKAGES` to make installation decisions, but verifies that if we used
+`PRODUCT_HOST_PACKAGES`, it would trigger installation for all of the same host
+packages. This check ignores shared libraries, as those are not normally
+necessary in `PRODUCT_*PACKAGES`, and tended to be over-built (especially the
+32-bit variants).
+
+Future changes will switch installation decisions to `PRODUCT_HOST_PACKAGES`
+for host modules, error when there's a host-only module in `PRODUCT_PACKAGES`,
+and do some further cleanup where `LOCAL_REQUIRED_MODULES` are still merged
+between host and target modules with the same name.
+
 ## `*.c.arm` / `*.cpp.arm` deprecation  {#file_arm}
 
 In Android.mk files, you used to be able to change LOCAL_ARM_MODE for each
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 21034ad..51139ed 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -603,6 +603,13 @@
 
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib*)
 
+# Clean up old testcase files
+$(call add-clean-step, rm -rf $(TARGET_OUT_TESTCASES)/*)
+$(call add-clean-step, rm -rf $(HOST_OUT_TESTCASES)/*)
+$(call add-clean-step, rm -rf $(HOST_CROSS_OUT_TESTCASES)/*)
+$(call add-clean-step, rm -rf $(TARGET_OUT_DATA)/*)
+$(call add-clean-step, rm -rf $(HOST_OUT)/vts/*)
+$(call add-clean-step, rm -rf $(HOST_OUT)/framework/vts-tradefed.jar)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/core/Makefile b/core/Makefile
index 44f01ba..8a73f4e 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1556,13 +1556,11 @@
     $(TARGET_RECOVERY_ROOT_OUT)/plat_file_contexts \
     $(TARGET_RECOVERY_ROOT_OUT)/vendor_file_contexts \
     $(TARGET_RECOVERY_ROOT_OUT)/plat_property_contexts \
-    $(TARGET_RECOVERY_ROOT_OUT)/vendor_property_contexts
-
-ifdef BOARD_ODM_SEPOLICY_DIRS
-recovery_sepolicy += \
+    $(TARGET_RECOVERY_ROOT_OUT)/vendor_property_contexts \
     $(TARGET_RECOVERY_ROOT_OUT)/odm_file_contexts \
-    $(TARGET_RECOVERY_ROOT_OUT)/odm_property_contexts
-endif
+    $(TARGET_RECOVERY_ROOT_OUT)/odm_property_contexts \
+    $(TARGET_RECOVERY_ROOT_OUT)/product_file_contexts \
+    $(TARGET_RECOVERY_ROOT_OUT)/product_property_contexts
 
 # Passed into rsync from non-recovery root to recovery root, to avoid overwriting recovery-specific
 # SELinux files
diff --git a/core/android_manifest.mk b/core/android_manifest.mk
index efa6ae6..931b1b1 100644
--- a/core/android_manifest.mk
+++ b/core/android_manifest.mk
@@ -36,7 +36,7 @@
   fixed_android_manifest := $(intermediates.COMMON)/manifest/AndroidManifest.xml.fixed
 
   $(full_android_manifest): PRIVATE_LIBS_MANIFESTS := $(my_full_libs_manifest_files)
-  $(full_android_manifest): $(ANDROID_MANIFEST_MERGER_DEPS)
+  $(full_android_manifest): $(ANDROID_MANIFEST_MERGER)
   $(full_android_manifest) : $(fixed_android_manifest) $(my_full_libs_manifest_files)
 	@echo "Merge android manifest files: $@ <-- $< $(PRIVATE_LIBS_MANIFESTS)"
 	@mkdir -p $(dir $@)
diff --git a/core/base_rules.mk b/core/base_rules.mk
index 2fbf524..b2bbe46 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -242,6 +242,33 @@
   partition_tag := $(if $(call should-install-to-system,$(my_module_tags)),,_DATA)
 endif
 endif
+# For test modules that lack a suite tag, set null-suite as the default.
+# We only support adding a default suite to native tests, native benchmarks, and instrumentation tests.
+# This is because they are the only tests we currently auto-generate test configs for.
+ifndef LOCAL_COMPATIBILITY_SUITE
+  ifneq ($(filter NATIVE_TESTS NATIVE_BENCHMARK, $(LOCAL_MODULE_CLASS)),)
+    LOCAL_COMPATIBILITY_SUITE := null-suite
+  endif
+  ifneq ($(filter APPS, $(LOCAL_MODULE_CLASS)),)
+    ifneq ($(filter $(my_module_tags),tests),)
+      LOCAL_COMPATIBILITY_SUITE := null-suite
+    endif
+  endif
+endif
+
+use_testcase_folder :=
+ifdef ENABLE_DEFAULT_TEST_LOCATION
+  ifeq ($(my_module_path),)
+    ifneq ($(LOCAL_MODULE),$(filter $(LOCAL_MODULE),$(DEFAULT_DATA_OUT_MODULES)))
+      ifdef LOCAL_COMPATIBILITY_SUITE
+        ifneq (true, $(LOCAL_IS_HOST_MODULE))
+          use_testcase_folder := true
+        endif
+      endif
+    endif
+  endif
+endif
+
 ifeq ($(my_module_path),)
   install_path_var := $(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)OUT$(partition_tag)_$(LOCAL_MODULE_CLASS)
   ifeq (true,$(LOCAL_PRIVILEGED_MODULE))
@@ -249,6 +276,16 @@
   endif
 
   my_module_path := $($(install_path_var))
+
+  # If use_testcase_folder be set, and LOCAL_MODULE_PATH not set,
+  # overwrite the default path under testcase.
+  ifeq ($(use_testcase_folder),true)
+    arch_dir := $($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)
+    testcase_folder := $($(my_prefix)OUT_TESTCASES)/$(LOCAL_MODULE)/$(arch_dir)
+    my_module_path := $(testcase_folder)
+    arch_dir :=
+  endif
+
   ifeq ($(strip $(my_module_path)),)
     $(error $(LOCAL_PATH): unhandled install path "$(install_path_var) for $(LOCAL_MODULE)")
   endif
@@ -324,7 +361,9 @@
   # Neither do Runtime Resource Overlay apks, which contain just the overlaid resources.
   else ifeq ($(LOCAL_IS_RUNTIME_RESOURCE_OVERLAY),true)
   else
-    my_module_path := $(my_module_path)/$(LOCAL_MODULE)
+    ifneq ($(use_testcase_folder),true)
+      my_module_path := $(my_module_path)/$(LOCAL_MODULE)
+    endif
   endif
   endif
   LOCAL_INSTALLED_MODULE := $(my_module_path)/$(my_installed_module_stem)
@@ -429,12 +468,23 @@
 my_init_rc_installed :=
 my_init_rc_pairs :=
 my_installed_symlinks :=
+my_default_test_module :=
+ifeq ($(use_testcase_folder),true)
+arch_dir := $($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)
+my_default_test_module := $($(my_prefix)OUT_TESTCASES)/$(LOCAL_MODULE)/$(arch_dir)/$(my_installed_module_stem)
+arch_dir :=
+endif
+
 ifneq (true,$(LOCAL_UNINSTALLABLE_MODULE))
+ifneq ($(LOCAL_INSTALLED_MODULE),$(my_default_test_module))
+# Install into the testcase folder
+$(LOCAL_INSTALLED_MODULE) : $(my_default_test_module)
 $(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD := $(LOCAL_POST_INSTALL_CMD)
 $(LOCAL_INSTALLED_MODULE): $(LOCAL_BUILT_MODULE)
 	@echo "Install: $@"
 	$(copy-file-to-new-target)
 	$(PRIVATE_POST_INSTALL_CMD)
+endif
 
 ifndef LOCAL_IS_HOST_MODULE
 # Rule to install the module's companion init.rc.
@@ -544,20 +594,6 @@
 endif
 endif
 
-# For test modules that lack a suite tag, set null-suite as the default.
-# We only support adding a default suite to native tests, native benchmarks, and instrumentation tests.
-# This is because they are the only tests we currently auto-generate test configs for.
-ifndef LOCAL_COMPATIBILITY_SUITE
-ifneq ($(filter NATIVE_TESTS NATIVE_BENCHMARK, $(LOCAL_MODULE_CLASS)),)
-LOCAL_COMPATIBILITY_SUITE := null-suite
-endif
-ifneq ($(filter APPS, $(LOCAL_MODULE_CLASS)),)
-ifneq ($(filter $(my_module_tags),tests),)
-LOCAL_COMPATIBILITY_SUITE := null-suite
-endif
-endif
-endif
-
 ###########################################################
 ## Compatibility suite files.
 ###########################################################
@@ -575,9 +611,15 @@
 ifdef LOCAL_MULTILIB
   multi_arch := true
 endif
+
 ifdef multi_arch
+arch_dir := /$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)
+else
+ifeq ($(use_testcase_folder),true)
   arch_dir := /$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)
 endif
+endif
+
 multi_arch :=
 
 # The module itself.
@@ -671,6 +713,17 @@
 endif
 
 
+ifeq ($(use_testcase_folder),true)
+ifneq ($(my_test_data_file_pairs),)
+$(foreach pair, $(my_test_data_file_pairs), \
+  $(eval parts := $(subst :,$(space),$(pair))) \
+  $(eval src_path := $(word 1,$(parts))) \
+  $(eval file := $(word 2,$(parts))) \
+  $(foreach suite, $(LOCAL_COMPATIBILITY_SUITE), \
+    $(eval my_compat_dist_$(suite) += $(foreach dir, $(call compatibility_suite_dirs,$(suite),$(arch_dir)), \
+      $(call filter-copy-pair,$(src_path),$(call append-path,$(dir),$(file)),$(my_installed_test_data))))))
+endif
+else
 ifneq ($(my_test_data_file_pairs),)
 $(foreach pair, $(my_test_data_file_pairs), \
   $(eval parts := $(subst :,$(space),$(pair))) \
@@ -680,6 +733,9 @@
     $(eval my_compat_dist_$(suite) += $(foreach dir, $(call compatibility_suite_dirs,$(suite),$(arch_dir)), \
       $(src_path):$(call append-path,$(dir),$(file))))))
 endif
+endif
+
+
 
 arch_dir :=
 is_native :=
diff --git a/core/config.mk b/core/config.mk
index 242558e..0bc460e 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -1174,4 +1174,12 @@
 include $(BUILD_SYSTEM)/soong_config.mk
 endif
 
+# If ENABLE_DEFAULT_TEST_LOCATION is true, move default install path from
+# $(my_prefix)OUT_DATA to $(my_prefix)OUT_TESTCASES
+ENABLE_DEFAULT_TEST_LOCATION := true
+-include external/linux-kselftest/android/kselftest_test_list.mk
+-include external/ltp/android/ltp_package_list.mk
+DEFAULT_DATA_OUT_MODULES := ltp $(ltp_packages) $(kselftest_modules)
+.KATI_READONLY := ENABLE_DEFAULT_TEST_LOCATION DEFAULT_DATA_OUT_MODULES
+
 include $(BUILD_SYSTEM)/dumpvar.mk
diff --git a/core/definitions.mk b/core/definitions.mk
index c46a873..e880fa5 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2478,6 +2478,25 @@
 	$$(align-package)
 endef
 
+# Create copy pair for compatibility suite
+# Filter out $(LOCAL_INSTALLED_MODULE) to prevent overriding target
+# $(1): source path
+# $(2): destination path
+# The format of copy pair is src:dst
+define compat-copy-pair
+$(if $(filter-out $(2), $(LOCAL_INSTALLED_MODULE)), $(1):$(2))
+endef
+
+# Create copy pair for $(1) $(2)
+# If $(2) is substring of $(3) do nothing.
+# $(1): source path
+# $(2): destination path
+# $(3): filter-out target
+# The format of copy pair is src:dst
+define filter-copy-pair
+$(if $(findstring $(2), $(3)),,$(1):$(2))
+endef
+
 # Copies many files.
 # $(1): The files to copy.  Each entry is a ':' separated src:dst pair
 # $(2): An optional directory to prepend to the destination
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index 3d02cdc..85ddbfa 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -117,6 +117,10 @@
 
 my_dexpreopt_archs :=
 my_dexpreopt_images :=
+my_dexpreopt_infix := boot
+ifeq (true, $(DEXPREOPT_USE_APEX_IMAGE))
+  my_dexpreopt_infix := apex
+endif
 
 ifdef LOCAL_DEX_PREOPT
   ifeq (,$(filter PRESIGNED,$(LOCAL_CERTIFICATE)))
@@ -150,13 +154,13 @@
     # #################################################
     # Odex for the 1st arch
     my_dexpreopt_archs += $(TARGET_ARCH)
-    my_dexpreopt_images += $(DEXPREOPT_IMAGE_boot_$(TARGET_ARCH))
+    my_dexpreopt_images += $(DEXPREOPT_IMAGE_$(my_dexpreopt_infix)_$(TARGET_ARCH))
     # Odex for the 2nd arch
     ifdef TARGET_2ND_ARCH
       ifneq ($(TARGET_TRANSLATE_2ND_ARCH),true)
         ifneq (first,$(my_module_multilib))
           my_dexpreopt_archs += $(TARGET_2ND_ARCH)
-          my_dexpreopt_images += $(DEXPREOPT_IMAGE_boot_$(TARGET_2ND_ARCH))
+          my_dexpreopt_images += $(DEXPREOPT_IMAGE_$(my_dexpreopt_infix)_$(TARGET_2ND_ARCH))
         endif  # my_module_multilib is not first.
       endif  # TARGET_TRANSLATE_2ND_ARCH not true
     endif  # TARGET_2ND_ARCH
@@ -166,13 +170,15 @@
     # Save the module multilib since setup_one_odex modifies it.
     my_2nd_arch_prefix := $(LOCAL_2ND_ARCH_VAR_PREFIX)
     my_dexpreopt_archs += $(TARGET_$(my_2nd_arch_prefix)ARCH)
-    my_dexpreopt_images += $(DEXPREOPT_IMAGE_boot_$(TARGET_$(my_2nd_arch_prefix)ARCH))
+    my_dexpreopt_images += \
+        $(DEXPREOPT_IMAGE_$(my_dexpreopt_infix)_$(TARGET_$(my_2nd_arch_prefix)ARCH))
     ifdef TARGET_2ND_ARCH
       ifeq ($(my_module_multilib),both)
         # The non-preferred arch
         my_2nd_arch_prefix := $(if $(LOCAL_2ND_ARCH_VAR_PREFIX),,$(TARGET_2ND_ARCH_VAR_PREFIX))
         my_dexpreopt_archs += $(TARGET_$(my_2nd_arch_prefix)ARCH)
-        my_dexpreopt_images += $(DEXPREOPT_IMAGE_boot_$(TARGET_$(my_2nd_arch_prefix)ARCH))
+        my_dexpreopt_images += \
+            $(DEXPREOPT_IMAGE_$(my_dexpreopt_infix)_$(TARGET_$(my_2nd_arch_prefix)ARCH))
       endif  # LOCAL_MULTILIB is both
     endif  # TARGET_2ND_ARCH
   endif  # LOCAL_MODULE_CLASS
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 506ec4d..1704daf 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -523,6 +523,11 @@
   $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_APPS_PRIVILEGED \
   $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_TESTCASES
 
+MODULE_CLASS_APPS := app
+MODULE_CLASS_EXECUTABLES := bin
+MODULE_CLASS_JAVA_LIBRARIES := framework
+MODULE_CLASS_NATIVE_TESTS := nativetest
+MODULE_CLASS_METRIC_TESTS := benchmarktest
 TARGET_OUT_DATA := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_DATA)
 TARGET_OUT_DATA_EXECUTABLES := $(TARGET_OUT_EXECUTABLES)
 TARGET_OUT_DATA_SHARED_LIBRARIES := $(TARGET_OUT_SHARED_LIBRARIES)
@@ -542,6 +547,7 @@
 TARGET_OUT_VENDOR_NATIVE_TESTS := $(TARGET_OUT_DATA)/nativetest$(TARGET_VENDOR_TEST_SUFFIX)
 TARGET_OUT_VENDOR_METRIC_TESTS := $(TARGET_OUT_DATA)/benchmarktest$(TARGET_VENDOR_TEST_SUFFIX)
 endif
+MODULE_CLASS_FAKE := fake_packages
 TARGET_OUT_DATA_FAKE := $(TARGET_OUT_DATA)/fake_packages
 .KATI_READONLY := \
   TARGET_OUT_DATA \
@@ -556,7 +562,13 @@
   TARGET_OUT_DATA_METRIC_TESTS \
   TARGET_OUT_VENDOR_NATIVE_TESTS \
   TARGET_OUT_VENDOR_METRIC_TESTS \
-  TARGET_OUT_DATA_FAKE
+  TARGET_OUT_DATA_FAKE \
+  MODULE_CLASS_APPS \
+  MODULE_CLASS_EXECUTABLES \
+  MODULE_CLASS_JAVA_LIBRARIES \
+  MODULE_CLASS_NATIVE_TESTS \
+  MODULE_CLASS_METRIC_TESTS \
+  MODULE_CLASS_FAKE
 
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_EXECUTABLES := $(TARGET_OUT_DATA_EXECUTABLES)
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_SHARED_LIBRARIES := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_SHARED_LIBRARIES)
diff --git a/core/main.mk b/core/main.mk
index 8b43867..5d97027 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -568,6 +568,22 @@
 endef
 endif  # TARGET_TRANSLATE_2ND_ARCH
 
+# TODO: we can probably check to see if these modules are actually host
+# modules
+define get-host-32-bit-modules
+$(sort $(foreach m,$(1),\
+  $(if $(ALL_MODULES.$(m)$(HOST_2ND_ARCH_MODULE_SUFFIX).CLASS),\
+    $(m)$(HOST_2ND_ARCH_MODULE_SUFFIX))))
+endef
+# Get a list of corresponding 32-bit module names, if one exists;
+# otherwise return the original module name
+define get-host-32-bit-modules-if-we-can
+$(sort $(foreach m,$(1),\
+  $(if $(ALL_MODULES.$(m)$(HOST_2ND_ARCH_MODULE_SUFFIX).CLASS),\
+    $(m)$(HOST_2ND_ARCH_MODULE_SUFFIX),\
+    $(m))))
+endef
+
 # If a module is for a cross host os, the required modules must be for
 # that OS too.
 # If a module is built for 32-bit, the required modules must be 32-bit too;
@@ -1015,6 +1031,16 @@
   $(call expand-required-modules,$(1),$(_erm_new_modules),$(_erm_all_overrides)))
 endef
 
+# Same as expand-required-modules above, but does not handle module overrides, as
+# we don't intend to support them on the host.
+define expand-required-host-modules
+$(eval _erm_req := $(foreach m,$(2),$(ALL_MODULES.$(m).REQUIRED))) \
+$(eval _erm_new_modules := $(sort $(filter-out $($(1)),$(_erm_req)))) \
+$(eval $(1) += $(_erm_new_modules)) \
+$(if $(_erm_new_modules),\
+  $(call expand-required-host-modules,$(1),$(_erm_new_modules)))
+endef
+
 # Transforms paths relative to PRODUCT_OUT to absolute paths.
 # $(1): list of relative paths
 # $(2): optional suffix to append to paths
@@ -1080,6 +1106,23 @@
     $(foreach cf,$(PRODUCTS.$(_mk).PRODUCT_COPY_FILES),$(call word-colon,2,$(cf))))
 endef
 
+# Similar to product-installed-files above, but handles PRODUCT_HOST_PACKAGES instead
+# This does support the :32 / :64 syntax, but does not support module overrides.
+define host-installed-files
+  $(eval _hif_modules := $(PRODUCTS.$(strip $(1)).PRODUCT_HOST_PACKAGES)) \
+  $(eval ### Resolve the :32 :64 module name) \
+  $(eval _hif_modules_32 := $(patsubst %:32,%,$(filter %:32, $(_hif_modules)))) \
+  $(eval _hif_modules_64 := $(patsubst %:64,%,$(filter %:64, $(_hif_modules)))) \
+  $(eval _hif_modules_rest := $(filter-out %:32 %:64,$(_hif_modules))) \
+  $(eval _hif_modules := $(call get-host-32-bit-modules-if-we-can, $(_hif_modules_32))) \
+  $(eval _hif_modules += $(_hif_modules_64)) \
+  $(eval ### For the rest we add both) \
+  $(eval _hif_modules += $(call get-host-32-bit-modules, $(_hif_modules_rest))) \
+  $(eval _hif_modules += $(_hif_modules_rest)) \
+  $(call expand-required-host-modules,_hif_modules,$(_hif_modules)) \
+  $(filter $(HOST_OUT_ROOT)/%,$(call module-installed-files, $(_hif_modules)))
+endef
+
 # Fails the build if the given list is non-empty, and prints it entries (stripping PRODUCT_OUT).
 # $(1): list of files to print
 # $(2): heading to print on failure
@@ -1107,10 +1150,42 @@
 endif
 
 ifdef FULL_BUILD
-  product_FILES := $(call product-installed-files, $(INTERNAL_PRODUCT))
+  # Check to ensure that all modules in PRODUCT_HOST_PACKAGES exist
+  #
+  # Many host modules are Linux-only, so skip this check on Mac. If we ever have Mac-only modules,
+  # maybe it would make sense to have PRODUCT_HOST_PACKAGES_LINUX/_DARWIN?
+  ifneq ($(HOST_OS),darwin)
+    ifneq (true,$(ALLOW_MISSING_DEPENDENCIES))
+      _modules := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_HOST_PACKAGES)
+      _nonexistant_modules := $(foreach m,$(_modules),\
+        $(if $(filter FAKE,$(ALL_MODULES.$(m).CLASS))$(filter $(HOST_OUT_ROOT)/%,$(ALL_MODULES.$(m).INSTALLED)),,$(m)))
+      $(call maybe-print-list-and-error,$(_nonexistant_modules),\
+        $(INTERNAL_PRODUCT) includes non-existant modules in PRODUCT_HOST_PACKAGES)
+    endif
+  endif
+
+  product_host_FILES := $(call host-installed-files,$(INTERNAL_PRODUCT))
+  product_target_FILES := $(call product-installed-files, $(INTERNAL_PRODUCT))
   # WARNING: The product_MODULES variable is depended on by external files.
   product_MODULES := $(_pif_modules)
 
+  # Verify that PRODUCT_HOST_PACKAGES is complete
+  # This is a temporary requirement during migration
+  # Ignore libraries, since they shouldn't need to be in PRODUCT_PACKAGES for the most part anyway.
+  host_files_in_target_FILES := $(filter-out \
+    $(HOST_OUT_SHARED_LIBRARIES)/% \
+    $($(HOST_2ND_ARCH_VAR_PREFIX)HOST_OUT_SHARED_LIBRARIES)/%,\
+      $(filter $(HOST_OUT_ROOT)/%,$(product_target_FILES)))
+  ifneq (,$(filter-out $(product_host_FILES),$(host_files_in_target_FILES)))
+    packages := $(foreach f,$(filter-out $(product_host_FILES),$(host_files_in_target_FILES)), \
+      $(or $(INSTALLABLE_FILES.$(f).MODULE),$(f)))
+    $(warning Missing modules from PRODUCT_HOST_PACKAGES)
+    $(warning See $(CHANGES_URL)#PRODUCT_HOST_PACKAGES for more information)
+    $(foreach f,$(sort $(packages)),$(warning _ $(f)))
+    $(error stop)
+  endif
+  host_files_in_target_FILES :=
+
   # Verify the artifact path requirements made by included products.
   is_asan := $(if $(filter address,$(SANITIZE_TARGET)),true)
   ifneq (true,$(or $(is_asan),$(DISABLE_ARTIFACT_PATH_REQUIREMENTS)))
@@ -1153,7 +1228,7 @@
     $(eval unused_whitelist := $(filter-out $(files),$(whitelist_patterns))) \
     $(call maybe-print-list-and-error,$(unused_whitelist),$(makefile) includes redundant whitelist entries in its artifact path requirement.) \
     $(eval ### Optionally verify that nothing else produces files inside this artifact path requirement.) \
-    $(eval extra_files := $(filter-out $(files) $(HOST_OUT)/%,$(product_FILES))) \
+    $(eval extra_files := $(filter-out $(files) $(HOST_OUT)/%,$(product_target_FILES))) \
     $(eval files_in_requirement := $(filter $(path_patterns),$(extra_files))) \
     $(eval all_offending_files += $(files_in_requirement)) \
     $(eval whitelist := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST)) \
@@ -1178,14 +1253,16 @@
   # a subset of the module makefiles.  Don't try to build any modules
   # requested by the product, because we probably won't have rules
   # to build them.
-  product_FILES :=
+  product_target_FILES :=
+  product_host_FILES :=
 endif
 
 # TODO: Remove the 3 places in the tree that use ALL_DEFAULT_INSTALLED_MODULES
 # and get rid of it from this list.
 modules_to_install := $(sort \
     $(ALL_DEFAULT_INSTALLED_MODULES) \
-    $(product_FILES) \
+    $(product_target_FILES) \
+    $(product_host_FILES) \
     $(call get-tagged-modules,$(tags_to_install)) \
     $(CUSTOM_MODULES) \
   )
@@ -1591,8 +1668,8 @@
 
 .PHONY: dump-files
 dump-files:
-	$(info product_FILES for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):)
-	$(foreach p,$(sort $(product_FILES)),$(info :   $(p)))
+	$(info product_target_FILES for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):)
+	$(foreach p,$(sort $(product_target_FILES)),$(info :   $(p)))
 	@echo Successfully dumped product file list
 
 .PHONY: nothing
diff --git a/core/native_benchmark.mk b/core/native_benchmark.mk
index e73bcad..4750649 100644
--- a/core/native_benchmark.mk
+++ b/core/native_benchmark.mk
@@ -6,8 +6,10 @@
 
 LOCAL_STATIC_LIBRARIES += libgoogle-benchmark
 
+ifndef ENABLE_DEFAULT_TEST_LOCATION
 LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_METRIC_TESTS)/$(LOCAL_MODULE)
 LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_METRIC_TESTS)/$(LOCAL_MODULE)
+endif
 
 ifndef LOCAL_MULTILIB
 ifndef LOCAL_32_BIT_ONLY
diff --git a/core/ninja_config.mk b/core/ninja_config.mk
index 684ab9f..e9e89c3 100644
--- a/core/ninja_config.mk
+++ b/core/ninja_config.mk
@@ -50,7 +50,6 @@
 	user \
 	userdataimage \
 	userdebug \
-	valgrind-test-art% \
 	vts \
 	win_sdk \
 	winsdk-tools
diff --git a/core/package_internal.mk b/core/package_internal.mk
index 9043710..3be4635 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -768,10 +768,17 @@
 
 ifdef LOCAL_COMPATIBILITY_SUITE
 
+ifndef ENABLE_DEFAULT_TEST_LOCATION
 $(foreach suite, $(LOCAL_COMPATIBILITY_SUITE), \
   $(eval my_compat_dist_$(suite) := $(foreach dir, $(call compatibility_suite_dirs,$(suite)), \
     $(foreach s,$(my_split_suffixes),\
       $(intermediates)/package_$(s).apk:$(dir)/$(LOCAL_MODULE)_$(s).apk))))
+else
+$(foreach suite, $(LOCAL_COMPATIBILITY_SUITE), \
+  $(eval my_compat_dist_$(suite) := $(foreach dir, $(call compatibility_suite_dirs,$(suite)), \
+    $(foreach s,$(my_split_suffixes),\
+      $(call compat-copy-pair,$(intermediates)/package_$(s).apk,$(dir)/$(LOCAL_MODULE)_$(s).apk)))))
+endif
 
 $(call create-suite-dependencies)
 
diff --git a/core/product.mk b/core/product.mk
index fba2ed3..a367a6b 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -117,6 +117,7 @@
     PRODUCT_AAPT_CONFIG \
     PRODUCT_AAPT_PREF_CONFIG \
     PRODUCT_AAPT_PREBUILT_DPI \
+    PRODUCT_HOST_PACKAGES \
     PRODUCT_PACKAGES \
     PRODUCT_PACKAGES_DEBUG \
     PRODUCT_PACKAGES_DEBUG_ASAN \
diff --git a/core/target_test_internal.mk b/core/target_test_internal.mk
index b5c3a7c..1ed1195 100644
--- a/core/target_test_internal.mk
+++ b/core/target_test_internal.mk
@@ -29,6 +29,15 @@
 $(error $(LOCAL_PATH): Do not set LOCAL_MODULE_PATH_64 when building test $(LOCAL_MODULE))
 endif
 
+use_testcase_folder := false
+ifdef ENABLE_DEFAULT_TEST_LOCATION
+  ifneq ($(LOCAL_MODULE),$(filter $(LOCAL_MODULE),$(DEFAULT_DATA_OUT_MODULES)))
+    use_testcase_folder := true
+  endif
+endif
+
+ifneq ($(use_testcase_folder),true)
 ifndef LOCAL_MODULE_RELATIVE_PATH
 LOCAL_MODULE_RELATIVE_PATH := $(LOCAL_MODULE)
 endif
+endif
diff --git a/core/tasks/tools/package-modules.mk b/core/tasks/tools/package-modules.mk
index 629a9b2..82b4c6a 100644
--- a/core/tasks/tools/package-modules.mk
+++ b/core/tasks/tools/package-modules.mk
@@ -40,6 +40,8 @@
     $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).PICKUP_FILES)))\
   $(eval _built_files := $(strip $(ALL_MODULES.$(m).BUILT_INSTALLED)\
     $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).BUILT_INSTALLED)))\
+  $(eval _module_class_folder := $($(strip MODULE_CLASS_$(word 1, $(strip $(ALL_MODULES.$(m).CLASS)\
+    $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).CLASS))))))\
   $(if $(_pickup_files)$(_built_files),,\
     $(call my_missing_files,$(m)))\
   $(eval my_pickup_files += $(_pickup_files))\
@@ -49,9 +51,15 @@
     $(if $(filter $(TARGET_OUT_ROOT)/%,$(ins)),\
       $(eval bui := $(word 1,$(bui_ins)))\
       $(eval my_built_modules += $(bui))\
+      $(if $(filter $(_module_class_folder), nativetest benchmarktest),\
+        $(eval module_class_folder_stem := $(_module_class_folder)$(findstring 64, $(patsubst $(PRODUCT_OUT)/%,%,$(ins)))),\
+        $(eval module_class_folder_stem := $(_module_class_folder)))\
       $(eval my_copy_dest := $(patsubst data/%,DATA/%,\
-                               $(patsubst system/%,DATA/%,\
-                                 $(patsubst $(PRODUCT_OUT)/%,%,$(ins)))))\
+                               $(patsubst testcases/%,DATA/$(module_class_folder_stem)/%,\
+                                 $(patsubst testcases/$(m)/$(TARGET_ARCH)/%,DATA/$(module_class_folder_stem)/$(m)/%,\
+                                   $(patsubst testcases/$(m)/$(TARGET_2ND_ARCH)/%,DATA/$(module_class_folder_stem)/$(m)/%,\
+                                     $(patsubst system/%,DATA/%,\
+                                       $(patsubst $(PRODUCT_OUT)/%,%,$(ins))))))))\
       $(eval my_copy_pairs += $(bui):$(my_staging_dir)/$(my_copy_dest)))\
   ))
 
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 835d9fe..6923698 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -252,7 +252,7 @@
     #  It must be of the form "YYYY-MM-DD" on production devices.
     #  It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
     #  If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
-      PLATFORM_SECURITY_PATCH := 2019-02-05
+      PLATFORM_SECURITY_PATCH := 2019-03-05
 endif
 .KATI_READONLY := PLATFORM_SECURITY_PATCH
 
diff --git a/target/board/generic_x86/device.mk b/target/board/generic_x86/device.mk
index a31058d..83cbd54 100644
--- a/target/board/generic_x86/device.mk
+++ b/target/board/generic_x86/device.mk
@@ -22,3 +22,7 @@
 PRODUCT_PACKAGES += \
 	bios.bin \
 	vgabios-cirrus.bin \
+
+PRODUCT_HOST_PACKAGES += \
+	bios.bin \
+	vgabios-cirrus.bin \
diff --git a/target/board/generic_x86_64/device.mk b/target/board/generic_x86_64/device.mk
index a31058d..83cbd54 100755
--- a/target/board/generic_x86_64/device.mk
+++ b/target/board/generic_x86_64/device.mk
@@ -22,3 +22,7 @@
 PRODUCT_PACKAGES += \
 	bios.bin \
 	vgabios-cirrus.bin \
+
+PRODUCT_HOST_PACKAGES += \
+	bios.bin \
+	vgabios-cirrus.bin \
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index f8ff22f..83a84f7 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -277,6 +277,42 @@
     framework_manifest.xml \
     system_compatibility_matrix.xml \
 
+# Host tools to install
+PRODUCT_HOST_PACKAGES += \
+    BugReport \
+    adb \
+    adbd \
+    atest \
+    bcc \
+    bit \
+    e2fsck \
+    fastboot \
+    flags_health_check \
+    icu-data_host_runtime_apex \
+    incident_report \
+    ld.mc \
+    lpdump \
+    mdnsd \
+    minigzip \
+    mke2fs \
+    resize2fs \
+    selinux_policy_system \
+    sgdisk \
+    shell_and_utilities_system \
+    sqlite3 \
+    tinyplay \
+    tune2fs \
+    tzdatacheck \
+    unwind_info \
+    unwind_reg_info \
+    unwind_symbols \
+    viewcompiler \
+    tzdata_host \
+    tzdata_host_runtime_apex \
+    tzlookup.xml_host_runtime_apex \
+    tz_version_host \
+    tz_version_host_runtime_apex \
+
 ifeq ($(TARGET_CORE_JARS),)
 $(error TARGET_CORE_JARS is empty; cannot initialize PRODUCT_BOOT_JARS variable)
 endif
diff --git a/target/product/base_vendor.mk b/target/product/base_vendor.mk
index 6ea7292..bf01957 100644
--- a/target/product/base_vendor.mk
+++ b/target/product/base_vendor.mk
@@ -27,6 +27,16 @@
     shell_and_utilities_recovery \
     watchdogd.recovery \
 
+# These had been pulled in via init_second_stage.recovery, but may not be needed.
+PRODUCT_HOST_PACKAGES += \
+    e2fsdroid \
+    mke2fs \
+    sload_f2fs \
+    make_f2fs \
+
+PRODUCT_HOST_PACKAGES += \
+    icu-data_host_runtime_apex
+
 # Base modules and settings for the vendor partition.
 PRODUCT_PACKAGES += \
     android.hardware.cas@1.0-service \
diff --git a/target/product/full_x86.mk b/target/product/full_x86.mk
index a76b07c..17ca398 100644
--- a/target/product/full_x86.mk
+++ b/target/product/full_x86.mk
@@ -36,6 +36,10 @@
 	bios.bin \
 	vgabios-cirrus.bin \
 
+PRODUCT_HOST_PACKAGES += \
+	bios.bin \
+	vgabios-cirrus.bin \
+
 # Enable dynamic partition size
 PRODUCT_USE_DYNAMIC_PARTITION_SIZE := true
 
diff --git a/target/product/go_defaults_common.mk b/target/product/go_defaults_common.mk
index e35bf30..7042f6d 100644
--- a/target/product/go_defaults_common.mk
+++ b/target/product/go_defaults_common.mk
@@ -61,9 +61,8 @@
 # Do not generate libartd.
 PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD := false
 
-# Do not spin up a separate process for the network stack on go devices, use an in-process lib.
-PRODUCT_PACKAGES += NetworkStackLib
-PRODUCT_SYSTEM_SERVER_JARS += NetworkStackLib
+# Do not spin up a separate process for the network stack on go devices, use an in-process APK.
+PRODUCT_PACKAGES += InProcessNetworkStack
 
 # Strip the local variable table and the local variable type table to reduce
 # the size of the system image. This has no bearing on stack traces, but will
diff --git a/target/product/gsi_common.mk b/target/product/gsi_common.mk
index e87309b..fb0478d 100644
--- a/target/product/gsi_common.mk
+++ b/target/product/gsi_common.mk
@@ -24,12 +24,12 @@
 $(call inherit-product-if-exists, frameworks/base/data/sounds/AllAudio.mk)
 
 # Additional settings used in all AOSP builds
-PRODUCT_PROPERTY_OVERRIDES := \
+PRODUCT_PROPERTY_OVERRIDES += \
     ro.config.ringtone=Ring_Synth_04.ogg \
     ro.config.notification_sound=pixiedust.ogg
 
 # The mainline checking whitelist, should be clean up
-PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST := \
+PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
     system/app/messaging/messaging.apk \
     system/app/PhotoTable/PhotoTable.apk \
     system/app/WAPPushManager/WAPPushManager.apk \
diff --git a/target/product/mainline_system.mk b/target/product/mainline_system.mk
index 22d1626..0ddc3db 100644
--- a/target/product/mainline_system.mk
+++ b/target/product/mainline_system.mk
@@ -92,6 +92,9 @@
     tinypcminfo \
     update_engine_client \
 
+PRODUCT_HOST_PACKAGES += \
+    tinyplay
+
 # Enable stats logging in LMKD
 TARGET_LMKD_STATS_LOG := true
 PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
diff --git a/target/product/media_system.mk b/target/product/media_system.mk
index 65ee073..2ba7005 100644
--- a/target/product/media_system.mk
+++ b/target/product/media_system.mk
@@ -60,6 +60,8 @@
     StatementService \
     vndk_snapshot_package \
 
+PRODUCT_HOST_PACKAGES += \
+    fsck.f2fs \
 
 PRODUCT_COPY_FILES += \
     frameworks/native/data/etc/android.software.webview.xml:system/etc/permissions/android.software.webview.xml
diff --git a/target/product/runtime_libart.mk b/target/product/runtime_libart.mk
index fa35d43..412d8cf 100644
--- a/target/product/runtime_libart.mk
+++ b/target/product/runtime_libart.mk
@@ -40,6 +40,7 @@
 
 # Android Runtime APEX module.
 PRODUCT_PACKAGES += com.android.runtime
+PRODUCT_HOST_PACKAGES += com.android.runtime
 
 # Certificates.
 PRODUCT_PACKAGES += \
diff --git a/tools/checkowners.py b/tools/checkowners.py
index 7f03968..d6853d8 100755
--- a/tools/checkowners.py
+++ b/tools/checkowners.py
@@ -52,12 +52,13 @@
   noparent = 'set +noparent'
   email = '([^@ ]+@[^ @]+|\\*)'
   emails = '(%s( *, *%s)*)' % (email, email)
-  directive = '(%s|%s)' % (emails, noparent)
+  file_directive = 'file: *([^ :]+ *: *)?[^ ]+'
+  directive = '(%s|%s|%s)' % (emails, noparent, file_directive)
   glob = '[a-zA-Z0-9_\\.\\-\\*\\?]+'
   globs = '(%s( *, *%s)*)' % (glob, glob)
   perfile = 'per-file +' + globs + ' *= *' + directive
   include = 'include +([^ :]+ *: *)?[^ ]+'
-  pats = '(|%s|%s|%s|%s)$' % (noparent, email, perfile, include)
+  pats = '(|%s|%s|%s|%s|%s)$' % (noparent, email, perfile, include, file_directive)
   patterns = re.compile(pats)
   address_pattern = re.compile('([^@ ]+@[^ @]+)')
   perfile_pattern = re.compile('per-file +.*=(.*)')
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index cfa81e1..9cda0bd 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -46,9 +46,15 @@
 
 class Options(object):
   def __init__(self):
+    base_out_path = os.getenv('OUT_DIR_COMMON_BASE')
+    if base_out_path is None:
+      base_search_path = "out"
+    else:
+      base_search_path = os.path.join(base_out_path, os.path.basename(os.getcwd()))
+
     platform_search_path = {
-        "linux2": "out/host/linux-x86",
-        "darwin": "out/host/darwin-x86",
+        "linux2": os.path.join(base_search_path, "host/linux-x86"),
+        "darwin": os.path.join(base_search_path, "host/darwin-x86"),
     }
 
     self.search_path = platform_search_path.get(sys.platform)
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index 2645829..5014516 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -25,10 +25,22 @@
       The input target files package containing system bits. This is a zip
       archive.
 
+  --system-item-list system-item-list-file
+      The optional path to a newline-separated config file that replaces the
+      contents of default_system_item_list if provided.
+
+  --system-misc-info-keys system-misc-info-keys-file
+      The optional path to a newline-separated config file that replaces the
+      contents of default_system_misc_info_keys if provided.
+
   --other-target-files other-target-files-zip-archive
       The input target files package containing other bits. This is a zip
       archive.
 
+  --other-item-list other-item-list-file
+      The optional path to a newline-separated config file that replaces the
+      contents of default_other_item_list if provided.
+
   --output-target-files output-target-files-package
       The output merged target files package. Also a zip archive.
 """
@@ -48,16 +60,19 @@
 OPTIONS = common.OPTIONS
 OPTIONS.verbose = True
 OPTIONS.system_target_files = None
+OPTIONS.system_item_list = None
+OPTIONS.system_misc_info_keys = None
 OPTIONS.other_target_files = None
+OPTIONS.other_item_list = None
 OPTIONS.output_target_files = None
 OPTIONS.keep_tmp = False
 
-# system_extract_as_is_item_list is a list of items to extract from the partial
+# default_system_item_list is a list of items to extract from the partial
 # system target files package as is, meaning these items will land in the
 # output target files package exactly as they appear in the input partial
 # system target files package.
 
-system_extract_as_is_item_list = [
+default_system_item_list = [
     'META/apkcerts.txt',
     'META/filesystem_config.txt',
     'META/root_filesystem_config.txt',
@@ -78,10 +93,10 @@
     'META/*',
 ]
 
-# system_misc_info_keys is a list of keys to obtain from the system instance of
+# default_system_misc_info_keys is a list of keys to obtain from the system instance of
 # META/misc_info.txt. The remaining keys from the other instance.
 
-system_misc_info_keys = [
+default_system_misc_info_keys = [
     'avb_system_hashtree_enable',
     'avb_system_add_hashtree_footer_args',
     'avb_system_key_path',
@@ -98,12 +113,12 @@
     'system_size',
 ]
 
-# other_extract_as_is_item_list is a list of items to extract from the partial
+# default_other_item_list is a list of items to extract from the partial
 # other target files package as is, meaning these items will land in the output
 # target files package exactly as they appear in the input partial other target
 # files package.
 
-other_extract_as_is_item_list = [
+default_other_item_list = [
     'META/boot_filesystem_config.txt',
     'META/otakeys.txt',
     'META/releasetools.py',
@@ -119,7 +134,7 @@
     'VENDOR/*',
 ]
 
-# other_extract_for_merge_item_list is a list of items to extract from the
+# other_extract_special_item_list is a list of items to extract from the
 # partial other target files package that need some special processing, such as
 # some sort of combination with items from the partial system target files
 # package.
@@ -172,6 +187,18 @@
       filtered_extract_item_list)
 
 
+def read_config_list(config_file_path):
+  """Reads a config file into a list of strings.
+
+  Expects the file to be newline-separated.
+
+  Args:
+    config_file_path: The path to the config file to open and read.
+  """
+  with open(config_file_path) as config_file:
+    return config_file.read().splitlines()
+
+
 def process_ab_partitions_txt(
     system_target_files_temp_dir,
     other_target_files_temp_dir,
@@ -223,7 +250,8 @@
 def process_misc_info_txt(
     system_target_files_temp_dir,
     other_target_files_temp_dir,
-    output_target_files_temp_dir):
+    output_target_files_temp_dir,
+    system_misc_info_keys):
   """Perform special processing for META/misc_info.txt
 
   This function merges the contents of the META/misc_info.txt files from the
@@ -242,6 +270,9 @@
     output_target_files_temp_dir: The name of a directory that will be used
     to create the output target files package after all the special cases
     are processed.
+
+    system_misc_info_keys: A list of keys to obtain from the system instance
+    of META/misc_info.txt. The remaining keys from the other instance.
   """
 
   def read_helper(d):
@@ -258,8 +289,7 @@
       read_helper(other_target_files_temp_dir))
 
   # Replace certain values in merged_info_dict with values from
-  # system_info_dict. TODO(b/124467065): This should be more flexible than
-  # using the hard-coded system_misc_info_keys.
+  # system_info_dict.
 
   for key in system_misc_info_keys:
     merged_info_dict[key] = system_info_dict[key]
@@ -355,7 +385,8 @@
     temp_dir,
     system_target_files_temp_dir,
     other_target_files_temp_dir,
-    output_target_files_temp_dir):
+    output_target_files_temp_dir,
+    system_misc_info_keys):
   """Perform special-case processing for certain target files items.
 
   Certain files in the output target files package require special-case
@@ -374,6 +405,9 @@
     output_target_files_temp_dir: The name of a directory that will be used
     to create the output target files package after all the special cases
     are processed.
+
+    system_misc_info_keys: A list of keys to obtain from the system instance
+    of META/misc_info.txt. The remaining keys from the other instance.
   """
 
   process_ab_partitions_txt(
@@ -384,7 +418,8 @@
   process_misc_info_txt(
       system_target_files_temp_dir=system_target_files_temp_dir,
       other_target_files_temp_dir=other_target_files_temp_dir,
-      output_target_files_temp_dir=output_target_files_temp_dir)
+      output_target_files_temp_dir=output_target_files_temp_dir,
+      system_misc_info_keys=system_misc_info_keys)
 
   process_file_contexts_bin(
       temp_dir=temp_dir,
@@ -394,7 +429,10 @@
 def merge_target_files(
     temp_dir,
     system_target_files,
+    system_item_list,
+    system_misc_info_keys,
     other_target_files,
+    other_item_list,
     output_target_files):
   """Merge two target files packages together.
 
@@ -410,13 +448,32 @@
     system_target_files: The name of the zip archive containing the system
     partial target files package.
 
+    system_item_list: The list of items to extract from the partial system
+    target files package as is, meaning these items will land in the output
+    target files package exactly as they appear in the input partial system
+    target files package.
+
+    system_misc_info_keys: The list of keys to obtain from the system instance
+    of META/misc_info.txt. The remaining keys from the other instance.
+
     other_target_files: The name of the zip archive containing the other
     partial target files package.
 
+    other_item_list: The list of items to extract from the partial other
+    target files package as is, meaning these items will land in the output
+    target files package exactly as they appear in the input partial other
+    target files package.
+
     output_target_files: The name of the output zip archive target files
     package created by merging system and other.
   """
 
+  logger.info(
+      'starting: merge system %s and other %s into output %s',
+      system_target_files,
+      other_target_files,
+      output_target_files)
+
   # Create directory names that we'll use when we extract files from system,
   # and other, and for zipping the final output.
 
@@ -431,7 +488,7 @@
   extract_items(
       target_files=system_target_files,
       target_files_temp_dir=output_target_files_temp_dir,
-      extract_item_list=system_extract_as_is_item_list)
+      extract_item_list=system_item_list)
 
   # Extract "as is" items from the input other partial target files package. We
   # extract them directly into the output temporary directory since the items
@@ -440,7 +497,7 @@
   extract_items(
       target_files=other_target_files,
       target_files_temp_dir=output_target_files_temp_dir,
-      extract_item_list=other_extract_as_is_item_list)
+      extract_item_list=other_item_list)
 
   # Extract "special" items from the input system partial target files package.
   # We extract these items to different directory since they require special
@@ -469,7 +526,8 @@
       temp_dir=temp_dir,
       system_target_files_temp_dir=system_target_files_temp_dir,
       other_target_files_temp_dir=other_target_files_temp_dir,
-      output_target_files_temp_dir=output_target_files_temp_dir)
+      output_target_files_temp_dir=output_target_files_temp_dir,
+      system_misc_info_keys=system_misc_info_keys)
 
   # Regenerate IMAGES in the temporary directory.
 
@@ -520,25 +578,15 @@
   common.RunAndWait(command, verbose=True)
 
 
-def merge_target_files_with_temp_dir(
-    system_target_files,
-    other_target_files,
-    output_target_files,
-    keep_tmp):
+def call_func_with_temp_dir(func, keep_tmp):
   """Manage the creation and cleanup of the temporary directory.
 
-  This function wraps merge_target_files after first creating a temporary
+  This function calls the given function after first creating a temporary
   directory. It also cleans up the temporary directory.
 
   Args:
-    system_target_files: The name of the zip archive containing the system
-    partial target files package.
-
-    other_target_files: The name of the zip archive containing the other
-    partial target files package.
-
-    output_target_files: The name of the output zip archive target files
-    package created by merging system and other.
+    func: The function to call. Should accept one parameter, the path to
+    the temporary directory.
 
     keep_tmp: Keep the temporary directory after processing is complete.
   """
@@ -547,20 +595,10 @@
   # we use when we extract items from the input target files packages, and also
   # a scratch directory that we use for temporary files.
 
-  logger.info(
-      'starting: merge system %s and other %s into output %s',
-      system_target_files,
-      other_target_files,
-      output_target_files)
-
   temp_dir = common.MakeTempDir(prefix='merge_target_files_')
 
   try:
-    merge_target_files(
-        temp_dir=temp_dir,
-        system_target_files=system_target_files,
-        other_target_files=other_target_files,
-        output_target_files=output_target_files)
+    func(temp_dir)
   except:
     raise
   finally:
@@ -573,7 +611,7 @@
 def main():
   """The main function.
 
-  Process command line arguments, then call merge_target_files_with_temp_dir to
+  Process command line arguments, then call merge_target_files to
   perform the heavy lifting.
   """
 
@@ -582,8 +620,14 @@
   def option_handler(o, a):
     if o == '--system-target-files':
       OPTIONS.system_target_files = a
+    elif o == '--system-item-list':
+      OPTIONS.system_item_list = a
+    elif o == '--system-misc-info-keys':
+      OPTIONS.system_misc_info_keys = a
     elif o == '--other-target-files':
       OPTIONS.other_target_files = a
+    elif o == '--other-item-list':
+      OPTIONS.other_item_list = a
     elif o == '--output-target-files':
       OPTIONS.output_target_files = a
     elif o == '--keep_tmp':
@@ -596,7 +640,10 @@
       sys.argv[1:], __doc__,
       extra_long_opts=[
           'system-target-files=',
+          'system-item-list=',
+          'system-misc-info-keys=',
           'other-target-files=',
+          'other-item-list=',
           'output-target-files=',
           "keep_tmp",
       ],
@@ -609,11 +656,31 @@
     common.Usage(__doc__)
     sys.exit(1)
 
-  merge_target_files_with_temp_dir(
-      system_target_files=OPTIONS.system_target_files,
-      other_target_files=OPTIONS.other_target_files,
-      output_target_files=OPTIONS.output_target_files,
-      keep_tmp=OPTIONS.keep_tmp)
+  if OPTIONS.system_item_list:
+    system_item_list = read_config_list(OPTIONS.system_item_list)
+  else:
+    system_item_list = default_system_item_list
+
+  if OPTIONS.system_misc_info_keys:
+    system_misc_info_keys = read_config_list(OPTIONS.system_misc_info_keys)
+  else:
+    system_misc_info_keys = default_system_misc_info_keys
+
+  if OPTIONS.other_item_list:
+    other_item_list = read_config_list(OPTIONS.other_item_list)
+  else:
+    other_item_list = default_other_item_list
+
+  call_func_with_temp_dir(
+      lambda temp_dir: merge_target_files(
+          temp_dir=temp_dir,
+          system_target_files=OPTIONS.system_target_files,
+          system_item_list=system_item_list,
+          system_misc_info_keys=system_misc_info_keys,
+          other_target_files=OPTIONS.other_target_files,
+          other_item_list=other_item_list,
+          output_target_files=OPTIONS.output_target_files),
+      OPTIONS.keep_tmp)
 
 
 if __name__ == '__main__':
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index fa9e2e9..fe40936 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -235,8 +235,9 @@
 METADATA_NAME = 'META-INF/com/android/metadata'
 POSTINSTALL_CONFIG = 'META/postinstall_config.txt'
 DYNAMIC_PARTITION_INFO = 'META/dynamic_partitions_info.txt'
+AB_PARTITIONS = 'META/ab_partitions.txt'
 UNZIP_PATTERN = ['IMAGES/*', 'META/*']
-SUPER_SPLIT_PATTERN = ['OTA/super_*.img']
+RETROFIT_DAP_UNZIP_PATTERN = ['OTA/super_*.img', AB_PARTITIONS]
 
 
 class BuildInfo(object):
@@ -1060,6 +1061,9 @@
   if OPTIONS.wipe_user_data:
     metadata['ota-wipe'] = 'yes'
 
+  if OPTIONS.retrofit_dynamic_partitions:
+    metadata['ota-retrofit-dynamic-partitions'] = 'yes'
+
   is_incremental = source_info is not None
   if is_incremental:
     metadata['pre-build'] = source_info.fingerprint
@@ -1852,7 +1856,8 @@
 
 
 def GetTargetFilesZipForRetrofitDynamicPartitions(input_file,
-                                                  super_block_devices):
+                                                  super_block_devices,
+                                                  dynamic_partition_list):
   """Returns a target-files.zip for retrofitting dynamic partitions.
 
   This allows brillo_update_payload to generate an OTA based on the exact
@@ -1861,6 +1866,7 @@
   Args:
     input_file: The input target-files.zip filename.
     super_block_devices: The list of super block devices
+    dynamic_partition_list: The list of dynamic partitions
 
   Returns:
     The filename of target-files.zip with *.img replaced with super_*.img for
@@ -1877,8 +1883,34 @@
   with zipfile.ZipFile(input_file, 'r') as input_zip:
     namelist = input_zip.namelist()
 
+  input_tmp = common.UnzipTemp(input_file, RETROFIT_DAP_UNZIP_PATTERN)
+
+  # Remove partitions from META/ab_partitions.txt that is in
+  # dynamic_partition_list but not in super_block_devices so that
+  # brillo_update_payload won't generate update for those logical partitions.
+  ab_partitions_file = os.path.join(input_tmp, *AB_PARTITIONS.split('/'))
+  with open(ab_partitions_file) as f:
+    ab_partitions_lines = f.readlines()
+    ab_partitions = [line.strip() for line in ab_partitions_lines]
+  # Assert that all super_block_devices are in ab_partitions
+  super_device_not_updated = [partition for partition in super_block_devices
+                              if partition not in ab_partitions]
+  assert not super_device_not_updated, \
+      "{} is in super_block_devices but not in {}".format(
+          super_device_not_updated, AB_PARTITIONS)
+  # ab_partitions -= (dynamic_partition_list - super_block_devices)
+  new_ab_partitions = common.MakeTempFile(prefix="ab_partitions", suffix=".txt")
+  with open(new_ab_partitions, 'w') as f:
+    for partition in ab_partitions:
+      if (partition in dynamic_partition_list and
+          partition not in super_block_devices):
+          logger.info("Dropping %s from ab_partitions.txt", partition)
+          continue
+      f.write(partition + "\n")
+  to_delete = [AB_PARTITIONS]
+
   # Always skip postinstall for a retrofit update.
-  to_delete = [POSTINSTALL_CONFIG]
+  to_delete += [POSTINSTALL_CONFIG]
 
   # Delete dynamic_partitions_info.txt so that brillo_update_payload thinks this
   # is a regular update on devices without dynamic partitions support.
@@ -1890,7 +1922,6 @@
 
   common.ZipDelete(target_file, to_delete)
 
-  input_tmp = common.UnzipTemp(input_file, SUPER_SPLIT_PATTERN)
   target_zip = zipfile.ZipFile(target_file, 'a', allowZip64=True)
 
   # Write super_{foo}.img as {foo}.img.
@@ -1900,6 +1931,9 @@
     unzipped_file = os.path.join(input_tmp, *src.split('/'))
     common.ZipWrite(target_zip, unzipped_file, arcname=dst)
 
+  # Write new ab_partitions.txt file
+  common.ZipWrite(target_zip, new_ab_partitions, arcname=AB_PARTITIONS)
+
   common.ZipClose(target_zip)
 
   return target_file
@@ -1928,7 +1962,8 @@
 
   if OPTIONS.retrofit_dynamic_partitions:
     target_file = GetTargetFilesZipForRetrofitDynamicPartitions(
-        target_file, target_info.get("super_block_devices").strip().split())
+        target_file, target_info.get("super_block_devices").strip().split(),
+        target_info.get("dynamic_partition_list").strip().split())
   elif OPTIONS.skip_postinstall:
     target_file = GetTargetFilesZipWithoutPostinstallConfig(target_file)
 
diff --git a/tools/releasetools/test_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index 44703db..c2da907 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -415,6 +415,7 @@
     # Reset the global options as in ota_from_target_files.py.
     common.OPTIONS.incremental_source = None
     common.OPTIONS.downgrade = False
+    common.OPTIONS.retrofit_dynamic_partitions = False
     common.OPTIONS.timestamp = False
     common.OPTIONS.wipe_user_data = False
     common.OPTIONS.no_signing = False
@@ -517,6 +518,23 @@
         },
         metadata)
 
+  def test_GetPackageMetadata_retrofitDynamicPartitions(self):
+    target_info = BuildInfo(self.TEST_TARGET_INFO_DICT, None)
+    common.OPTIONS.retrofit_dynamic_partitions = True
+    metadata = GetPackageMetadata(target_info)
+    self.assertDictEqual(
+        {
+            'ota-retrofit-dynamic-partitions' : 'yes',
+            'ota-type' : 'BLOCK',
+            'post-build' : 'build-fingerprint-target',
+            'post-build-incremental' : 'build-version-incremental-target',
+            'post-sdk-level' : '27',
+            'post-security-patch-level' : '2017-12-01',
+            'post-timestamp' : '1500000000',
+            'pre-device' : 'product-device',
+        },
+        metadata)
+
   @staticmethod
   def _test_GetPackageMetadata_swapBuildTimestamps(target_info, source_info):
     (target_info['build.prop']['ro.build.date.utc'],