Use per-app package list to avoid unnecessary dexpreopt.

Similar to aosp/2637193, but for apps defined in Makefile.

Bug: 288218403
Test: m
Test: Change PRODUCT_PACKAGES and see no dexpreopt reruns.
Change-Id: If0ecbb2d210a780c56ea506bb8d3363e1bd91f58
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index bdd47a8..288f81f 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -152,6 +152,9 @@
   $(LOCAL_USES_LIBRARIES) \
   $(my_filtered_optional_uses_libraries)
 
+# The order needs to be deterministic.
+my_dexpreopt_libs_all := $(sort $(my_dexpreopt_libs) $(my_dexpreopt_libs_compat))
+
 # Module dexpreopt.config depends on dexpreopt.config files of each
 # <uses-library> dependency, because these libraries may be processed after
 # the current module by Make (there's no topological order), so the dependency
@@ -442,6 +445,28 @@
 	  @cp $(PRIVATE_BUILT_MODULE) $@
   endif
 
+  # The root "product_packages.txt" is generated by `build/make/core/Makefile`. It contains a list
+  # of all packages that are installed on the device. We use `grep` to filter the list by the app's
+  # dependencies to create a per-app list, and use `rsync --checksum` to prevent the file's mtime
+  # from being changed if the contents don't change. This avoids unnecessary dexpreopt reruns.
+  my_dexpreopt_product_packages := $(intermediates)/product_packages.txt
+  .KATI_RESTAT: $(my_dexpreopt_product_packages)
+  $(my_dexpreopt_product_packages): PRIVATE_MODULE := $(LOCAL_MODULE)
+  $(my_dexpreopt_product_packages): PRIVATE_LIBS := $(my_dexpreopt_libs_all)
+  $(my_dexpreopt_product_packages): PRIVATE_STAGING := $(my_dexpreopt_product_packages).tmp
+  $(my_dexpreopt_product_packages): $(PRODUCT_OUT)/product_packages.txt
+	@echo "$(PRIVATE_MODULE) dexpreopt product_packages"
+  ifneq (,$(my_dexpreopt_libs_all))
+		grep -F -x \
+			$(addprefix -e ,$(PRIVATE_LIBS)) \
+			$(PRODUCT_OUT)/product_packages.txt \
+			> $(PRIVATE_STAGING) \
+			|| true
+  else
+		rm -f $(PRIVATE_STAGING) && touch $(PRIVATE_STAGING)
+  endif
+	rsync --checksum $(PRIVATE_STAGING) $@
+
   my_dexpreopt_script := $(intermediates)/dexpreopt.sh
   my_dexpreopt_zip := $(intermediates)/dexpreopt.zip
   DEXPREOPT.$(LOCAL_MODULE).POST_INSTALLED_DEXPREOPT_ZIP := $(my_dexpreopt_zip)
@@ -450,9 +475,10 @@
   $(my_dexpreopt_script): PRIVATE_GLOBAL_SOONG_CONFIG := $(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE)
   $(my_dexpreopt_script): PRIVATE_GLOBAL_CONFIG := $(DEX_PREOPT_CONFIG_FOR_MAKE)
   $(my_dexpreopt_script): PRIVATE_MODULE_CONFIG := $(my_dexpreopt_config)
+  $(my_dexpreopt_script): PRIVATE_PRODUCT_PACKAGES := $(my_dexpreopt_product_packages)
   $(my_dexpreopt_script): $(DEXPREOPT_GEN)
   $(my_dexpreopt_script): $(my_dexpreopt_jar_copy)
-  $(my_dexpreopt_script): $(my_dexpreopt_config) $(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE) $(DEX_PREOPT_CONFIG_FOR_MAKE)
+  $(my_dexpreopt_script): $(my_dexpreopt_config) $(DEX_PREOPT_SOONG_CONFIG_FOR_MAKE) $(DEX_PREOPT_CONFIG_FOR_MAKE) $(my_dexpreopt_product_packages)
 	@echo "$(PRIVATE_MODULE) dexpreopt gen"
 	$(DEXPREOPT_GEN) \
 	-global_soong $(PRIVATE_GLOBAL_SOONG_CONFIG) \
@@ -460,12 +486,12 @@
 	-module $(PRIVATE_MODULE_CONFIG) \
 	-dexpreopt_script $@ \
 	-out_dir $(OUT_DIR) \
-	-product_packages $(PRODUCT_OUT)/product_packages.txt
+	-product_packages $(PRIVATE_PRODUCT_PACKAGES)
 
   my_dexpreopt_deps := $(my_dex_jar)
   my_dexpreopt_deps += $(if $(my_process_profile),$(LOCAL_DEX_PREOPT_PROFILE))
   my_dexpreopt_deps += \
-    $(foreach lib, $(my_dexpreopt_libs) $(my_dexpreopt_libs_compat), \
+    $(foreach lib, $(my_dexpreopt_libs_all), \
       $(call intermediates-dir-for,JAVA_LIBRARIES,$(lib),,COMMON)/javalib.jar)
   my_dexpreopt_deps += $(my_dexpreopt_images_deps)
   my_dexpreopt_deps += $(DEXPREOPT_BOOTCLASSPATH_DEX_FILES)
@@ -501,8 +527,11 @@
   $(my_all_targets): $(my_dexpreopt_zip)
 
   my_dexpreopt_config :=
+  my_dexpreopt_product_packages :=
   my_dexpreopt_script :=
   my_dexpreopt_zip :=
   my_dexpreopt_config_for_postprocessing :=
 endif # LOCAL_DEX_PREOPT
 endif # my_create_dexpreopt_config
+
+my_dexpreopt_libs_all :=