Move android_library resource handling to Bazel's ResourceProcessorBusyBox

The R.Java files generated by aapt2 link --no-static-lib-packages
cause scaling problems by combining all resources into every package
listed in a dependencies' AndroidManifest.xml file.  For SystemUI-core
this results in 74 R.java files, each with 76k lines, and takes 20
seconds to compile in javac.

Both AGP and Bazel have workarounds for this that avoid using the
R.java files generated by aapt2, instead generating more efficient
R.class files directly based on the R.txt file.

Bazel uses the ResourceProcessorBusyBox tool that is already present
in our tree to process the resources.  Reuse the same tool in Soong
to create the R.jar.

The more efficient R.class files require modifiying source files
that use incorrect packages to refer to resources.

Ignore-AOSP-First: merge conflict
Bug: 284023594
Test: TestAndroidResourceProcessor
Change-Id: I026073b40dabcfdb10e5d7a52e9348205b0e9a66
This commit is contained in:
Colin Cross
2023-06-20 22:40:02 -07:00
parent 2c5ed9e9ec
commit 039d8dfb67
7 changed files with 486 additions and 62 deletions

View File

@@ -88,16 +88,28 @@ 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
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
@@ -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,7 +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")
linkFlags = append(linkFlags, "--enable-compact-entries")
// Find implicit or explicit asset and resource dirs
@@ -349,6 +364,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")
@@ -356,6 +384,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 {
@@ -375,7 +404,23 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
// of transitiveStaticLibs.
transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
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.
@@ -438,7 +483,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
@@ -450,7 +504,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).
@@ -462,34 +520,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())
@@ -614,9 +731,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
@@ -628,7 +748,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
@@ -733,9 +868,12 @@ type AARImport struct {
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]
@@ -904,12 +1042,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(),
@@ -929,14 +1068,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",
}
@@ -949,25 +1088,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()
@@ -982,6 +1131,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),

View File

@@ -265,6 +265,7 @@ func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile)
entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage)
entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackages)
entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
@@ -508,6 +509,7 @@ func (a *AndroidLibrary) AndroidMkEntries() []android.AndroidMkEntries {
}
entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage)
entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", a.transitiveAaptResourcePackages)
entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", a.extraAaptPackagesFile)
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile)
entries.AddStrings("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.exportedProguardFlagFiles.Strings()...)

View File

@@ -521,7 +521,23 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
a.dexpreopter.preventInstall = a.appProperties.PreventInstall
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
var extraSrcJars android.Paths
var extraClasspathJars android.Paths
var extraCombinedJars android.Paths
if a.useResourceProcessorBusyBox() {
// When building an app with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox has already
// created R.class files that provide IDs for resources in busybox/R.jar. Pass that file in the
// classpath when compiling everything else, and add it to the final classes jar.
extraClasspathJars = android.Paths{a.aapt.rJar}
extraCombinedJars = android.Paths{a.aapt.rJar}
} else {
// When building an app without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
// R.java files for the app'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)
}
return a.dexJarFile.PathOrNil()

View File

@@ -723,6 +723,9 @@ func TestAppJavaResources(t *testing.T) {
func TestAndroidResourceProcessor(t *testing.T) {
testCases := []struct {
name string
appUsesRP bool
directLibUsesRP bool
transitiveLibUsesRP bool
dontVerifyApp bool
appResources []string
@@ -759,7 +762,12 @@ func TestAndroidResourceProcessor(t *testing.T) {
transitiveImportImports []string
}{
{
// Test with all modules set to use_resource_processor: false (except android_library_import modules,
// which always use resource processor).
name: "legacy",
appUsesRP: false,
directLibUsesRP: false,
transitiveLibUsesRP: false,
appResources: nil,
appOverlays: []string{
@@ -771,7 +779,6 @@ func TestAndroidResourceProcessor(t *testing.T) {
"out/soong/.intermediates/direct_import/android_common/package-res.apk",
"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
},
appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
appClasspath: []string{
@@ -792,7 +799,6 @@ func TestAndroidResourceProcessor(t *testing.T) {
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
},
directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
directClasspath: []string{
@@ -814,18 +820,256 @@ func TestAndroidResourceProcessor(t *testing.T) {
transitiveCombined: nil,
directImportResources: nil,
directImportOverlays: []string{
"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata",
directImportOverlays: []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
directImportImports: []string{
"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
},
directImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
transitiveImportResources: nil,
transitiveImportOverlays: []string{
"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata",
transitiveImportOverlays: []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"},
transitiveImportImports: []string{
"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
},
transitiveImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
},
{
// Test with all modules set to use_resource_processor: true.
name: "resource_processor",
appUsesRP: true,
directLibUsesRP: true,
transitiveLibUsesRP: true,
appResources: nil,
appOverlays: []string{
"out/soong/.intermediates/transitive/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/direct/android_common/package-res.apk",
"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/direct_import/android_common/package-res.apk",
"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
},
appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
appSrcJars: nil,
appClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
"out/soong/.intermediates/app/android_common/busybox/R.jar",
"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
appCombined: []string{
"out/soong/.intermediates/app/android_common/busybox/R.jar",
"out/soong/.intermediates/app/android_common/javac/app.jar",
"out/soong/.intermediates/direct/android_common/combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
directResources: nil,
directOverlays: []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"},
directImports: []string{
"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/transitive/android_common/package-res.apk",
},
directSrcJars: nil,
directClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
"out/soong/.intermediates/direct/android_common/busybox/R.jar",
"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
},
directCombined: []string{
"out/soong/.intermediates/direct/android_common/javac/direct.jar",
"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
},
transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
transitiveOverlays: nil,
transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
transitiveSrcJars: nil,
transitiveClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
},
transitiveCombined: nil,
directImportResources: nil,
directImportOverlays: []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
directImportImports: []string{
"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
},
transitiveImportResources: nil,
transitiveImportOverlays: []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"},
transitiveImportImports: []string{
"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
},
}, {
// Test an app building with resource processor enabled but with dependencies built without
// resource processor.
name: "app_resource_processor",
appUsesRP: true,
directLibUsesRP: false,
transitiveLibUsesRP: false,
appResources: nil,
appOverlays: []string{
"out/soong/.intermediates/transitive/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/direct/android_common/package-res.apk",
"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/direct_import/android_common/package-res.apk",
"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
},
appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
appSrcJars: nil,
appClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
// R.jar has to come before direct.jar
"out/soong/.intermediates/app/android_common/busybox/R.jar",
"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
appCombined: []string{
"out/soong/.intermediates/app/android_common/busybox/R.jar",
"out/soong/.intermediates/app/android_common/javac/app.jar",
"out/soong/.intermediates/direct/android_common/combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
dontVerifyDirect: true,
dontVerifyTransitive: true,
dontVerifyDirectImport: true,
dontVerifyTransitiveImport: true,
},
{
// Test an app building without resource processor enabled but with a dependency built with
// resource processor.
name: "app_dependency_lib_resource_processor",
appUsesRP: false,
directLibUsesRP: true,
transitiveLibUsesRP: false,
appOverlays: []string{
"out/soong/.intermediates/transitive/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/direct/android_common/package-res.apk",
"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/direct_import/android_common/package-res.apk",
"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
},
appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
appClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
appCombined: []string{
"out/soong/.intermediates/app/android_common/javac/app.jar",
"out/soong/.intermediates/direct/android_common/combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
directResources: nil,
directOverlays: []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"},
directImports: []string{
"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/transitive/android_common/package-res.apk",
},
directSrcJars: nil,
directClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
"out/soong/.intermediates/direct/android_common/busybox/R.jar",
"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
},
directCombined: []string{
"out/soong/.intermediates/direct/android_common/javac/direct.jar",
"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
},
dontVerifyTransitive: true,
dontVerifyDirectImport: true,
dontVerifyTransitiveImport: true,
},
{
// Test a library building without resource processor enabled but with a dependency built with
// resource processor.
name: "lib_dependency_lib_resource_processor",
appUsesRP: false,
directLibUsesRP: false,
transitiveLibUsesRP: true,
appOverlays: []string{
"out/soong/.intermediates/transitive/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/direct/android_common/package-res.apk",
"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/direct_import/android_common/package-res.apk",
"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
},
appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
appClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
appCombined: []string{
"out/soong/.intermediates/app/android_common/javac/app.jar",
"out/soong/.intermediates/direct/android_common/combined/direct.jar",
"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
},
directResources: nil,
directOverlays: []string{
"out/soong/.intermediates/transitive/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
},
directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
directClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
},
directCombined: []string{
"out/soong/.intermediates/direct/android_common/javac/direct.jar",
"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
},
transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
transitiveOverlays: nil,
transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
transitiveSrcJars: nil,
transitiveClasspath: []string{
"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
},
transitiveCombined: nil,
dontVerifyDirectImport: true,
dontVerifyTransitiveImport: true,
},
}
@@ -839,6 +1083,7 @@ func TestAndroidResourceProcessor(t *testing.T) {
resource_dirs: ["app/res"],
manifest: "app/AndroidManifest.xml",
static_libs: ["direct", "direct_import"],
use_resource_processor: %v,
}
android_library {
@@ -848,6 +1093,7 @@ func TestAndroidResourceProcessor(t *testing.T) {
resource_dirs: ["direct/res"],
manifest: "direct/AndroidManifest.xml",
static_libs: ["transitive", "transitive_import"],
use_resource_processor: %v,
}
android_library {
@@ -856,6 +1102,7 @@ func TestAndroidResourceProcessor(t *testing.T) {
srcs: ["transitive/transitive.java"],
resource_dirs: ["transitive/res"],
manifest: "transitive/AndroidManifest.xml",
use_resource_processor: %v,
}
android_library_import {
@@ -883,7 +1130,7 @@ func TestAndroidResourceProcessor(t *testing.T) {
sdk_version: "current",
aars: ["transitive_import_dep.aar"],
}
`)
`, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP)
fs := android.MockFS{
"app/res/values/strings.xml": nil,

View File

@@ -1057,7 +1057,7 @@ func (module *Module) addGeneratedSrcJars(path android.Path) {
module.properties.Generated_srcjars = append(module.properties.Generated_srcjars, path)
}
func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
deps := j.collectDeps(ctx)
@@ -1095,9 +1095,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...)
if aaptSrcJar != nil {
srcJars = append(srcJars, aaptSrcJar)
}
srcJars = append(srcJars, extraSrcJars...)
srcJars = append(srcJars, j.properties.Generated_srcjars...)
srcFiles = srcFiles.FilterOutByExt(".srcjar")
@@ -1140,6 +1138,11 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
var kotlinJars android.Paths
var kotlinHeaderJars android.Paths
// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
// any dependencies so that it can override any non-final R classes from dependencies with the
// final R classes from the app.
flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...)
if srcFiles.HasExt(".kt") {
// When using kotlin sources turbine is used to generate annotation processor sources,
// including for annotation processors that generate API, so we can use turbine for
@@ -1233,8 +1236,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
// allow for the use of annotation processors that do function correctly
// with sharding enabled. See: b/77284273.
}
extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, kotlinHeaderJars)
j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
if ctx.Failed() {
return
}
@@ -1385,6 +1389,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
jars = append(jars, servicesJar)
}
jars = append(android.CopyOf(extraCombinedJars), jars...)
// Combine the classes built from sources, any manifests, and any static libraries into
// classes.jar. If there is only one input jar this step will be skipped.
var outputFile android.OutputPath

View File

@@ -148,6 +148,8 @@ func init() {
pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar")
pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file")
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")

View File

@@ -692,7 +692,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
j.classLoaderContexts = j.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
}
j.compile(ctx, nil)
j.compile(ctx, nil, nil, nil)
// Collect the module directory for IDE info in java/jdeps.go.
j.modulePaths = append(j.modulePaths, ctx.ModuleDir())