summaryrefslogtreecommitdiff
path: root/java/aar.go
diff options
context:
space:
mode:
Diffstat (limited to 'java/aar.go')
-rw-r--r--java/aar.go241
1 files changed, 196 insertions, 45 deletions
diff --git a/java/aar.go b/java/aar.go
index c9e08e2b5..180e1d726 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -88,28 +88,40 @@ type aaptProperties struct {
// do not include AndroidManifest from dependent libraries
Dont_merge_manifests *bool
+ // If use_resource_processor is set, use Bazel's resource processor instead of aapt2 to generate R.class files.
+ // The resource processor produces more optimal R.class files that only list resources in the package of the
+ // library that provided them, as opposed to aapt2 which produces R.java files for every package containing
+ // every resource. Using the resource processor can provide significant build time speedups, but requires
+ // fixing the module to use the correct package to reference each resource, and to avoid having any other
+ // libraries in the tree that use the same package name. Defaults to false, but will default to true in the
+ // future.
+ Use_resource_processor *bool
+
// true if RRO is enforced for any of the dependent modules
RROEnforcedForDependent bool `blueprint:"mutated"`
}
type aapt struct {
- aaptSrcJar android.Path
- exportPackage android.Path
- manifestPath android.Path
- proguardOptionsFile android.Path
- rTxt android.Path
- extraAaptPackagesFile android.Path
- mergedManifestFile android.Path
- noticeFile android.OptionalPath
- assetPackage android.OptionalPath
- isLibrary bool
- defaultManifestVersion string
- useEmbeddedNativeLibs bool
- useEmbeddedDex bool
- usesNonSdkApis bool
- hasNoCode bool
- LoggingParent string
- resourceFiles android.Paths
+ aaptSrcJar android.Path
+ transitiveAaptRJars android.Paths
+ transitiveAaptResourcePackages android.Paths
+ exportPackage android.Path
+ manifestPath android.Path
+ proguardOptionsFile android.Path
+ rTxt android.Path
+ rJar android.Path
+ extraAaptPackagesFile android.Path
+ mergedManifestFile android.Path
+ noticeFile android.OptionalPath
+ assetPackage android.OptionalPath
+ isLibrary bool
+ defaultManifestVersion string
+ useEmbeddedNativeLibs bool
+ useEmbeddedDex bool
+ usesNonSdkApis bool
+ hasNoCode bool
+ LoggingParent string
+ resourceFiles android.Paths
splitNames []string
splits []split
@@ -139,6 +151,10 @@ func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) {
}
}
+func (a *aapt) useResourceProcessorBusyBox() bool {
+ return BoolDefault(a.aaptProperties.Use_resource_processor, false)
+}
+
func (a *aapt) ExportPackage() android.Path {
return a.exportPackage
}
@@ -175,8 +191,6 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte
// Flags specified in Android.bp
linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
- linkFlags = append(linkFlags, "--no-static-lib-packages")
-
// Find implicit or explicit asset and resource dirs
assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
@@ -348,6 +362,19 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
linkFlags = append(linkFlags, "--static-lib")
}
+ if a.isLibrary && a.useResourceProcessorBusyBox() {
+ // When building an android_library using ResourceProcessorBusyBox the resources are merged into
+ // package-res.apk with --merge-only, but --no-static-lib-packages is not used so that R.txt only
+ // contains resources from this library.
+ linkFlags = append(linkFlags, "--merge-only")
+ } else {
+ // When building and app or when building an android_library without ResourceProcessorBusyBox
+ // --no-static-lib-packages is used to put all the resources into the app. If ResourceProcessorBusyBox
+ // is used then the app's R.txt will be post-processed along with the R.txt files from dependencies to
+ // sort resources into the right packages in R.class.
+ linkFlags = append(linkFlags, "--no-static-lib-packages")
+ }
+
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")
@@ -355,6 +382,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
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 compiledResDirs []android.Paths
for _, dir := range resDirs {
@@ -374,7 +402,23 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
// of transitiveStaticLibs.
transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
- compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
+ if a.isLibrary && a.useResourceProcessorBusyBox() {
+ // When building an android_library with ResourceProcessorBusyBox enabled treat static library dependencies
+ // as imports. The resources from dependencies will not be merged into this module's package-res.apk, and
+ // instead modules depending on this module will reference package-res.apk from all transitive static
+ // dependencies.
+ for _, staticDep := range staticDeps {
+ linkDeps = append(linkDeps, staticDep.resPackage)
+ linkFlags = append(linkFlags, "-I "+staticDep.resPackage.String())
+ if staticDep.usedResourceProcessor {
+ transitiveRJars = append(transitiveRJars, staticDep.rJar)
+ }
+ }
+ } else {
+ // When building an app or building a library without ResourceProcessorBusyBox enabled all static
+ // dependencies are compiled into this module's package-res.apk as overlays.
+ compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
+ }
if len(transitiveStaticLibs) > 0 {
// If we are using static android libraries, every source file becomes an overlay.
@@ -437,7 +481,16 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
a.assetPackage = android.OptionalPathForPath(assets)
}
+ if a.useResourceProcessorBusyBox() {
+ rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
+ resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary)
+ transitiveRJars = append(transitiveRJars, rJar)
+ a.rJar = rJar
+ }
+
a.aaptSrcJar = srcJar
+ a.transitiveAaptRJars = transitiveRJars
+ a.transitiveAaptResourcePackages = staticDeps.resPackages()
a.exportPackage = packageRes
a.manifestPath = manifestPath
a.proguardOptionsFile = proguardOptionsFile
@@ -449,7 +502,11 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
resPackage: a.exportPackage,
manifest: a.manifestPath,
additionalManifests: additionalManifests,
+ rTxt: a.rTxt,
+ rJar: a.rJar,
assets: a.assetPackage,
+
+ usedResourceProcessor: a.useResourceProcessorBusyBox(),
}).
Transitive(staticResourcesNodesDepSet).Build()
a.rroDirsDepSet = android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL).
@@ -461,34 +518,93 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
Transitive(staticManifestsDepSet).Build()
}
+var resourceProcessorBusyBox = pctx.AndroidStaticRule("resourceProcessorBusyBox",
+ blueprint.RuleParams{
+ Command: "${config.JavaCmd} -cp ${config.ResourceProcessorBusyBox} " +
+ "com.google.devtools.build.android.ResourceProcessorBusyBox --tool=GENERATE_BINARY_R -- @${out}.args && " +
+ "if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out}; fi",
+ CommandDeps: []string{"${config.ResourceProcessorBusyBox}"},
+ Rspfile: "${out}.args",
+ RspfileContent: "--primaryRTxt ${rTxt} --primaryManifest ${manifest} --classJarOutput ${out}.tmp ${args}",
+ Restat: true,
+ }, "rTxt", "manifest", "args")
+
+// resourceProcessorBusyBoxGenerateBinaryR converts the R.txt file produced by aapt2 into R.class files
+// using Bazel's ResourceProcessorBusyBox tool, which is faster than compiling the R.java files and
+// supports producing classes for static dependencies that only include resources from that dependency.
+func resourceProcessorBusyBoxGenerateBinaryR(ctx android.ModuleContext, rTxt, manifest android.Path,
+ rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool) {
+
+ var args []string
+ var deps android.Paths
+
+ if !isLibrary {
+ // When compiling an app, pass all R.txt and AndroidManifest.xml from transitive static library dependencies
+ // to ResourceProcessorBusyBox so that it can regenerate R.class files with the final resource IDs for each
+ // package.
+ args, deps = transitiveDeps.resourceProcessorDeps()
+ } else {
+ // When compiling a library don't pass any dependencies as it only needs to generate an R.class file for this
+ // library. Pass --finalFields=false so that the R.class file contains non-final fields so they don't get
+ // inlined into the library before the final IDs are assigned during app compilation.
+ args = append(args, "--finalFields=false")
+ }
+
+ deps = append(deps, rTxt, manifest)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: resourceProcessorBusyBox,
+ Output: rJar,
+ Implicits: deps,
+ Description: "ResourceProcessorBusyBox",
+ Args: map[string]string{
+ "rTxt": rTxt.String(),
+ "manifest": manifest.String(),
+ "args": strings.Join(args, " "),
+ },
+ })
+}
+
type resourcesNode struct {
resPackage android.Path
manifest android.Path
additionalManifests android.Paths
+ rTxt android.Path
+ rJar android.Path
assets android.OptionalPath
+
+ usedResourceProcessor bool
}
type transitiveAarDeps []*resourcesNode
func (t transitiveAarDeps) resPackages() android.Paths {
- var paths android.Paths
+ paths := make(android.Paths, 0, len(t))
for _, dep := range t {
paths = append(paths, dep.resPackage)
}
- return android.FirstUniquePaths(paths)
+ return paths
}
func (t transitiveAarDeps) manifests() android.Paths {
- var paths android.Paths
+ paths := make(android.Paths, 0, len(t))
for _, dep := range t {
paths = append(paths, dep.manifest)
paths = append(paths, dep.additionalManifests...)
}
- return android.FirstUniquePaths(paths)
+ return paths
+}
+
+func (t transitiveAarDeps) resourceProcessorDeps() (args []string, deps android.Paths) {
+ for _, dep := range t {
+ args = append(args, "--library="+dep.rTxt.String()+","+dep.manifest.String())
+ deps = append(deps, dep.rTxt, dep.manifest)
+ }
+ return args, deps
}
func (t transitiveAarDeps) assets() android.Paths {
- var paths android.Paths
+ paths := make(android.Paths, 0, len(t))
for _, dep := range t {
if dep.assets.Valid() {
paths = append(paths, dep.assets.Path())
@@ -613,9 +729,12 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
- ctx.CheckbuildFile(a.proguardOptionsFile)
- ctx.CheckbuildFile(a.exportPackage)
- ctx.CheckbuildFile(a.aaptSrcJar)
+ ctx.CheckbuildFile(a.aapt.proguardOptionsFile)
+ ctx.CheckbuildFile(a.aapt.exportPackage)
+ ctx.CheckbuildFile(a.aapt.aaptSrcJar)
+ if a.useResourceProcessorBusyBox() {
+ ctx.CheckbuildFile(a.aapt.rJar)
+ }
// apps manifests are handled by aapt, don't let Module see them
a.properties.Manifest = nil
@@ -627,7 +746,22 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
a.proguardOptionsFile)
- a.Module.compile(ctx, a.aaptSrcJar)
+ var extraSrcJars android.Paths
+ var extraCombinedJars android.Paths
+ var extraClasspathJars android.Paths
+ if a.useResourceProcessorBusyBox() {
+ // When building a library with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox for this
+ // library and each of the transitive static android_library dependencies has already created an
+ // R.class file for the appropriate package. Add all of those R.class files to the classpath.
+ extraClasspathJars = a.transitiveAaptRJars
+ } else {
+ // When building a library without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
+ // R.java files for the library's package and the packages from all transitive static android_library
+ // dependencies. Compile the srcjar alongside the rest of the sources.
+ extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
+ }
+
+ a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar")
var res android.Paths
@@ -729,12 +863,15 @@ type AARImport struct {
properties AARImportProperties
- classpathFile android.WritablePath
- proguardFlags android.WritablePath
- exportPackage android.WritablePath
- extraAaptPackagesFile android.WritablePath
- manifest android.WritablePath
- assetsPackage android.WritablePath
+ classpathFile android.WritablePath
+ proguardFlags android.WritablePath
+ exportPackage android.WritablePath
+ transitiveAaptResourcePackages android.Paths
+ extraAaptPackagesFile android.WritablePath
+ manifest android.WritablePath
+ assetsPackage android.WritablePath
+ rTxt android.WritablePath
+ rJar android.WritablePath
resourcesNodesDepSet *android.DepSet[*resourcesNode]
manifestsDepSet *android.DepSet[android.Path]
@@ -903,12 +1040,13 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
+ aarRTxt := extractedAARDir.Join(ctx, "R.txt")
a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
ctx.Build(pctx, android.BuildParams{
Rule: unzipAAR,
Input: a.aarPath,
- Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage},
+ Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, aarRTxt},
Description: "unzip AAR",
Args: map[string]string{
"outDir": extractedAARDir.String(),
@@ -928,14 +1066,14 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// 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")
+ a.rTxt = android.PathForModuleOut(ctx, "R.txt")
a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages")
var linkDeps android.Paths
linkFlags := []string{
"--static-lib",
- "--no-static-lib-packages",
+ "--merge-only",
"--auto-add-overlay",
}
@@ -948,25 +1086,35 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
_ = staticRRODirsDepSet
staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
- // AAPT2 overlays are in lowest to highest priority order, reverse the topological order
- // of transitiveStaticLibs.
- transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
-
linkDeps = append(linkDeps, sharedLibs...)
- linkDeps = append(linkDeps, transitiveStaticLibs...)
+ linkDeps = append(linkDeps, staticDeps.resPackages()...)
linkFlags = append(linkFlags, libFlags...)
- overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
+ overlayRes := android.Paths{flata}
+
+ // Treat static library dependencies of static libraries as imports.
+ transitiveStaticLibs := staticDeps.resPackages()
+ linkDeps = append(linkDeps, transitiveStaticLibs...)
+ for _, staticLib := range transitiveStaticLibs {
+ linkFlags = append(linkFlags, "-I "+staticLib.String())
+ }
transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
- aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
+ aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, a.rTxt, a.extraAaptPackagesFile,
linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
+ a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar")
+ resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true)
+
resourcesNodesDepSetBuilder := android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL)
resourcesNodesDepSetBuilder.Direct(&resourcesNode{
resPackage: a.exportPackage,
manifest: a.manifest,
+ rTxt: a.rTxt,
+ rJar: a.rJar,
assets: android.OptionalPathForPath(a.assetsPackage),
+
+ usedResourceProcessor: true,
})
resourcesNodesDepSetBuilder.Transitive(staticResourcesNodesDepSet)
a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build()
@@ -981,6 +1129,8 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
_ = staticManifestsDepSet
a.manifestsDepSet = manifestDepSetBuilder.Build()
+ a.transitiveAaptResourcePackages = staticDeps.resPackages()
+
a.collectTransitiveHeaderJars(ctx)
ctx.SetProvider(JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(a.classpathFile),
@@ -988,6 +1138,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
ImplementationJars: android.PathsIfNonNil(a.classpathFile),
+ // TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
})
if proptools.Bool(a.properties.Extract_jni) {