Introduce module type to autogenerate RROS
At ToT, soong emits metadata to make (LOCAL_SOONG_PRODUCT_RRO_DIRS and
LOCAL_SOONG_DEVICE_RRO_DIRS), and make uses this metadata to build and
install apks that are intalled in /vendor or /product. This CL ports
this logic to soong using a new module type. The module type will have a
dependency on the base module (e.g. SystemUI). This dependency edge will
be used to get information such as
- rroDirsDepSet
- manifest (to get package_name)
To reduce code duplication, `aaptBuildActions` has been extended to
accept a manifest and rroDirs parameter.
This should be a no op for now. The followup work includes
- Autogenerating these module in the load hook of android_app and
override_android_app
- Including the autogenerated modules in kati built img files
- Including the autogenerated modules in soong built img files
Test: go test ./java
Bug: 375277835
Change-Id: Icd34f59eb751ba60db3c265acada946e20db5f26
diff --git a/java/aar.go b/java/aar.go
index b5cdde3..e0e642e 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -417,6 +417,25 @@
extraLinkFlags []string
aconfigTextFiles android.Paths
usesLibrary *usesLibrary
+ // If rroDirs is provided, it will be used to generate package-res.apk
+ rroDirs *android.Paths
+ // If manifestForAapt is not nil, it will be used for aapt instead of the default source manifest.
+ manifestForAapt android.Path
+}
+
+func filterRRO(rroDirsDepSet depset.DepSet[rroDir], filter overlayType) android.Paths {
+ var paths android.Paths
+ seen := make(map[android.Path]bool)
+ for _, d := range rroDirsDepSet.ToList() {
+ if d.overlayType == filter {
+ if seen[d.path] {
+ continue
+ }
+ seen[d.path] = true
+ paths = append(paths, d.path)
+ }
+ }
+ return paths
}
func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptions) {
@@ -428,10 +447,15 @@
opts.classLoaderContexts = opts.classLoaderContexts.ExcludeLibs(opts.excludedLibs)
// App manifest file
- manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
- manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
+ var manifestFilePath android.Path
+ if opts.manifestForAapt != nil {
+ manifestFilePath = opts.manifestForAapt
+ } else {
+ manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+ manifestFilePath = android.PathForModuleSrc(ctx, manifestFile)
+ }
- manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{
+ manifestPath := ManifestFixer(ctx, manifestFilePath, ManifestFixerParams{
SdkContext: opts.sdkContext,
ClassLoaderContexts: opts.classLoaderContexts,
IsLibrary: a.isLibrary,
@@ -472,6 +496,10 @@
compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, opts.sdkContext, manifestPath)
+ a.rroDirsDepSet = depset.NewBuilder[rroDir](depset.TOPOLOGICAL).
+ Direct(rroDirs...).
+ Transitive(staticRRODirsDepSet).Build()
+
linkFlags = append(linkFlags, libFlags...)
linkDeps = append(linkDeps, sharedExportPackages...)
linkDeps = append(linkDeps, staticDeps.resPackages()...)
@@ -565,6 +593,11 @@
compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...)
}
+ var compiledRro, compiledRroOverlay android.Paths
+ if opts.rroDirs != nil {
+ compiledRro, compiledRroOverlay = a.compileResInDir(ctx, *opts.rroDirs, compileFlags, opts.aconfigTextFiles)
+ }
+
var splitPackages android.WritablePaths
var splits []split
@@ -591,10 +624,20 @@
if !a.isLibrary {
transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets())
}
- aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
- linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages,
- opts.aconfigTextFiles)
- ctx.CheckbuildFile(packageRes)
+ if opts.rroDirs == nil { // link resources and overlay
+ aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
+ linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages,
+ opts.aconfigTextFiles)
+ ctx.CheckbuildFile(packageRes)
+ } else { // link autogenerated rro
+ if len(compiledRro) == 0 {
+ return
+ }
+ aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
+ linkFlags, linkDeps, compiledRro, compiledRroOverlay, nil, nil,
+ opts.aconfigTextFiles)
+ ctx.CheckbuildFile(packageRes)
+ }
// Extract assets from the resource package output so that they can be used later in aapt2link
// for modules that depend on this one.
@@ -652,15 +695,46 @@
usedResourceProcessor: a.useResourceProcessorBusyBox(ctx),
}).
Transitive(staticResourcesNodesDepSet).Build()
- a.rroDirsDepSet = depset.NewBuilder[rroDir](depset.TOPOLOGICAL).
- Direct(rroDirs...).
- Transitive(staticRRODirsDepSet).Build()
a.manifestsDepSet = depset.NewBuilder[android.Path](depset.TOPOLOGICAL).
Direct(a.manifestPath).
DirectSlice(additionalManifests).
Transitive(staticManifestsDepSet).Build()
}
+// comileResInDir finds the resource files in dirs by globbing and then compiles them using aapt2
+// returns the file paths of compiled resources
+// dirs[0] is used as compileRes
+// dirs[1:] is used as compileOverlay
+func (a *aapt) compileResInDir(ctx android.ModuleContext, dirs android.Paths, compileFlags []string, aconfig android.Paths) (android.Paths, android.Paths) {
+ filesInDir := func(dir android.Path) android.Paths {
+ files, err := ctx.GlobWithDeps(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
+ if err != nil {
+ ctx.ModuleErrorf("failed to glob overlay resource dir %q: %s", dir, err.Error())
+ return nil
+ }
+ var filePaths android.Paths
+ for _, file := range files {
+ if strings.HasSuffix(file, "/") {
+ continue // ignore directories
+ }
+ filePaths = append(filePaths, android.PathForSource(ctx, file))
+ }
+ return filePaths
+ }
+
+ var compiledRes, compiledOverlay android.Paths
+ if len(dirs) == 0 {
+ return nil, nil
+ }
+ compiledRes = append(compiledRes, aapt2Compile(ctx, dirs[0], filesInDir(dirs[0]), compileFlags, a.filterProduct(), aconfig).Paths()...)
+ if len(dirs) > 0 {
+ for _, dir := range dirs[1:] {
+ compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir, filesInDir(dir), compileFlags, a.filterProduct(), aconfig).Paths()...)
+ }
+ }
+ return compiledRes, compiledOverlay
+}
+
var resourceProcessorBusyBox = pctx.AndroidStaticRule("resourceProcessorBusyBox",
blueprint.RuleParams{
Command: "${config.JavaCmd} -cp ${config.ResourceProcessorBusyBox} " +
@@ -805,7 +879,7 @@
switch depTag {
case instrumentationForTag:
// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
- case sdkLibTag, libTag:
+ case sdkLibTag, libTag, rroDepTag:
if exportPackage != nil {
sharedResourcesNodeDepSets = append(sharedResourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
sharedLibs = append(sharedLibs, exportPackage)