Use per-app package list to avoid unnecessary dexpreopt.

Starting from aosp/2594905, dexpreopt depends on
`$PRODUCT_OUT/product_packages.txt`. When PRODUCT_PACKAGES changes,
dexpreopt has to rerun for all apps. This is not ideal.

After this change, dexpreopt uses a per-app product_packages.txt that is
filtered by the app's dependencies, and it uses `rsync --checksum` to
prevent the file's mtime from being changed if the contents don't change.
This avoids unnecessary dexpreopt reruns.

Bug: 288218403
Test: m
Test: Change PRODUCT_PACKAGES and see no dexpreopt reruns.
Change-Id: I5788a9ee987dfd0abfd7d91cbcef748452290004
This commit is contained in:
Jiakai Zhang
2023-06-26 16:47:38 +01:00
parent a41c679fe1
commit 51b2a8b5eb
5 changed files with 60 additions and 24 deletions

View File

@@ -16,6 +16,7 @@ package java
import (
"path/filepath"
"sort"
"strings"
"android/soong/android"
@@ -390,11 +391,37 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
// "product_packages.txt" is generated by `build/make/core/Makefile`.
// 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.
productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", "product_packages.txt")
appProductPackagesStaging := appProductPackages.ReplaceExtension(ctx, "txt.tmp")
clcNames, _ := dexpreopt.ComputeClassLoaderContextDependencies(dexpreoptConfig.ClassLoaderContexts)
sort.Strings(clcNames) // The order needs to be deterministic.
productPackagesRule := android.NewRuleBuilder(pctx, ctx)
if len(clcNames) > 0 {
productPackagesRule.Command().
Text("grep -F -x").
FlagForEachArg("-e ", clcNames).
Input(productPackages).
FlagWithOutput("> ", appProductPackagesStaging).
Text("|| true")
} else {
productPackagesRule.Command().
Text("rm -f").Output(appProductPackagesStaging).
Text("&&").
Text("touch").Output(appProductPackagesStaging)
}
productPackagesRule.Command().
Text("rsync --checksum").
Input(appProductPackagesStaging).
Output(appProductPackages)
productPackagesRule.Restat().Build("product_packages", "dexpreopt product_packages")
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
ctx, globalSoong, global, dexpreoptConfig, productPackages)
ctx, globalSoong, global, dexpreoptConfig, appProductPackages)
if err != nil {
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
return