From f3b7bada56c306da91008324957da7e537e2da99 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 2 Aug 2023 15:49:00 -0700 Subject: [PATCH] Don't generate aapt2 srcjars when using resource processor When using resource processor the R.class files are generated directly, and the R.java files generated by aapt2 are unused. These files can huge, reaching 500 MB for some modules and 76 GB across all modules for a checkbuild on internal main. They will be deleted after zipping into srcjars after Ie5143e1e4b36ca1f4e45b001d79aca5379063517, but we can skip generating them completely for modules where resource processor is used. Bug: 284023594 Bug: 294285775 Test: m checkbuild Change-Id: If5e3fd1d25c6c7860898776ecdd392be8850c17c --- java/aapt2.go | 76 ++++++++++++++++++++++++++++++++++----------------- java/aar.go | 23 ++++++++++------ java/app.go | 8 +++++- 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/java/aapt2.go b/java/aapt2.go index 4cff8a720..3bb70b53f 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -146,21 +146,25 @@ func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link", blueprint.RuleParams{ - Command: `rm -rf $genDir && ` + - `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` + - `--output-text-symbols ${rTxt} $inFlags && ` + - `${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir &&` + - `${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages ' && ` + - `rm -rf $genDir`, + Command: `$preamble` + + `${config.Aapt2Cmd} link -o $out $flags --proguard $proguardOptions ` + + `--output-text-symbols ${rTxt} $inFlags` + + `$postamble`, CommandDeps: []string{ "${config.Aapt2Cmd}", "${config.SoongZipCmd}", - "${config.ExtractJarPackagesCmd}", }, Restat: true, }, - "flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt", "extraPackages") + "flags", "inFlags", "proguardOptions", "rTxt", "extraPackages", "preamble", "postamble") + +var aapt2ExtractExtraPackagesRule = pctx.AndroidStaticRule("aapt2ExtractExtraPackages", + blueprint.RuleParams{ + Command: `${config.ExtractJarPackagesCmd} -i $in -o $out --prefix '--extra-packages '`, + CommandDeps: []string{"${config.ExtractJarPackagesCmd}"}, + Restat: true, + }) var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile", blueprint.RuleParams{ @@ -176,12 +180,10 @@ var mergeAssetsRule = pctx.AndroidStaticRule("mergeAssets", }) func aapt2Link(ctx android.ModuleContext, - packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath, + packageRes, genJar, proguardOptions, rTxt android.WritablePath, flags []string, deps android.Paths, compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) { - genDir := android.PathForModuleGen(ctx, "aapt2", "R") - var inFlags []string if len(compiledRes) > 0 { @@ -218,7 +220,7 @@ func aapt2Link(ctx android.ModuleContext, } // Set auxiliary outputs as implicit outputs to establish correct dependency chains. - implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages) + implicitOutputs := append(splitPackages, proguardOptions, rTxt) linkOutput := packageRes // AAPT2 ignores assets in overlays. Merge them after linking. @@ -233,25 +235,49 @@ func aapt2Link(ctx android.ModuleContext, }) } + // Note the absence of splitPackages. The caller is supposed to compose and provide --split flag + // values via the flags parameter when it wants to split outputs. + // TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably + // tidy. + args := map[string]string{ + "flags": strings.Join(flags, " "), + "inFlags": strings.Join(inFlags, " "), + "proguardOptions": proguardOptions.String(), + "rTxt": rTxt.String(), + } + + if genJar != nil { + // Generating java source files from aapt2 was requested, use aapt2LinkAndGenRule and pass it + // genJar and genDir args. + genDir := android.PathForModuleGen(ctx, "aapt2", "R") + ctx.Variable(pctx, "aapt2GenDir", genDir.String()) + ctx.Variable(pctx, "aapt2GenJar", genJar.String()) + implicitOutputs = append(implicitOutputs, genJar) + args["preamble"] = `rm -rf $aapt2GenDir && ` + args["postamble"] = `&& ${config.SoongZipCmd} -write_if_changed -jar -o $aapt2GenJar -C $aapt2GenDir -D $aapt2GenDir && ` + + `rm -rf $aapt2GenDir` + args["flags"] += " --java $aapt2GenDir" + } + ctx.Build(pctx, android.BuildParams{ Rule: aapt2LinkRule, Description: "aapt2 link", Implicits: deps, Output: linkOutput, ImplicitOutputs: implicitOutputs, - // Note the absence of splitPackages. The caller is supposed to compose and provide --split flag - // values via the flags parameter when it wants to split outputs. - // TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably - // tidy. - Args: map[string]string{ - "flags": strings.Join(flags, " "), - "inFlags": strings.Join(inFlags, " "), - "proguardOptions": proguardOptions.String(), - "genDir": genDir.String(), - "genJar": genJar.String(), - "rTxt": rTxt.String(), - "extraPackages": extraPackages.String(), - }, + Args: args, + }) +} + +// aapt2ExtractExtraPackages takes a srcjar generated by aapt2 or a classes jar generated by ResourceProcessorBusyBox +// and converts it to a text file containing a list of --extra_package arguments for passing to Make modules so they +// correctly generate R.java entries for packages provided by transitive dependencies. +func aapt2ExtractExtraPackages(ctx android.ModuleContext, out android.WritablePath, in android.Path) { + ctx.Build(pctx, android.BuildParams{ + Rule: aapt2ExtractExtraPackagesRule, + Description: "aapt2 extract extra packages", + Input: in, + Output: out, }) } diff --git a/java/aar.go b/java/aar.go index 180e1d726..d1a7ed774 100644 --- a/java/aar.go +++ b/java/aar.go @@ -376,13 +376,12 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon } packageRes := android.PathForModuleOut(ctx, "package-res.apk") - // the subdir "android" is required to be filtered by package names - srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar") proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") rTxt := android.PathForModuleOut(ctx, "R.txt") // This file isn't used by Soong, but is generated for exporting extraPackages := android.PathForModuleOut(ctx, "extra_packages") var transitiveRJars android.Paths + var srcJar android.WritablePath var compiledResDirs []android.Paths for _, dir := range resDirs { @@ -459,15 +458,19 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon }) } + if !a.useResourceProcessorBusyBox() { + // the subdir "android" is required to be filtered by package names + srcJar = android.PathForModuleGen(ctx, "android", "R.srcjar") + } + // No need to specify assets from dependencies to aapt2Link for libraries, all transitive assets will be // provided to the final app aapt2Link step. var transitiveAssets android.Paths if !a.isLibrary { transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets()) } - aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages, + aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages) - // Extract assets from the resource package output so that they can be used later in aapt2link // for modules that depend on this one. if android.PrefixInList(linkFlags, "-A ") { @@ -484,8 +487,11 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon if a.useResourceProcessorBusyBox() { rJar := android.PathForModuleOut(ctx, "busybox/R.jar") resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary) + aapt2ExtractExtraPackages(ctx, extraPackages, rJar) transitiveRJars = append(transitiveRJars, rJar) a.rJar = rJar + } else { + aapt2ExtractExtraPackages(ctx, extraPackages, srcJar) } a.aaptSrcJar = srcJar @@ -731,9 +737,10 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.CheckbuildFile(a.aapt.proguardOptionsFile) ctx.CheckbuildFile(a.aapt.exportPackage) - ctx.CheckbuildFile(a.aapt.aaptSrcJar) if a.useResourceProcessorBusyBox() { ctx.CheckbuildFile(a.aapt.rJar) + } else { + ctx.CheckbuildFile(a.aapt.aaptSrcJar) } // apps manifests are handled by aapt, don't let Module see them @@ -1063,8 +1070,6 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { aapt2CompileZip(ctx, flata, a.aarPath, "res", compileFlags) a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk") - // the subdir "android" is required to be filtered by package names - srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar") proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") a.rTxt = android.PathForModuleOut(ctx, "R.txt") a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages") @@ -1100,12 +1105,14 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { } transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets()) - aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, a.rTxt, a.extraAaptPackagesFile, + aapt2Link(ctx, a.exportPackage, nil, proguardOptionsFile, a.rTxt, linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil) a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar") resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true) + aapt2ExtractExtraPackages(ctx, a.extraAaptPackagesFile, a.rJar) + resourcesNodesDepSetBuilder := android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL) resourcesNodesDepSetBuilder.Direct(&resourcesNode{ resPackage: a.exportPackage, diff --git a/java/app.go b/java/app.go index 224bc8867..2baef8db1 100755 --- a/java/app.go +++ b/java/app.go @@ -1022,7 +1022,13 @@ func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) { case ".aapt.proguardOptionsFile": return []android.Path{a.proguardOptionsFile}, nil case ".aapt.srcjar": - return []android.Path{a.aaptSrcJar}, nil + if a.aaptSrcJar != nil { + return []android.Path{a.aaptSrcJar}, nil + } + case ".aapt.jar": + if a.rJar != nil { + return []android.Path{a.rJar}, nil + } case ".export-package.apk": return []android.Path{a.exportPackage}, nil }