Merge "Move android_library resource handling to Bazel's ResourceProcessorBusyBox" into main
This commit is contained in:
240
java/aar.go
240
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),
|
||||
|
Reference in New Issue
Block a user