summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Inseob Kim <inseob@google.com> 2023-11-17 06:47:43 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2023-11-17 06:47:43 +0000
commit550a615b4d86e42ae4a10cb6fafc541c33376802 (patch)
tree05b749978bfdc14285ffecaead1d6f461cf97129
parent688b94c3d26f841e2915f1648300f9a1269ddc4f (diff)
parent6b52e7aabe870ff7e271af156edefbea0a650617 (diff)
Merge "Add support for auto-generated characteristics RRO" into main am: b5d713f2cb am: 99913d4e59 am: 6b52e7aabe
Original change: https://android-review.googlesource.com/c/platform/build/soong/+/2817177 Change-Id: I7bca74e210529ae6c2fbcb7746e06b7d4a493e8c Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--java/aapt2.go28
-rw-r--r--java/aar.go11
-rw-r--r--java/androidmk.go5
-rwxr-xr-xjava/app.go74
4 files changed, 111 insertions, 7 deletions
diff --git a/java/aapt2.go b/java/aapt2.go
index aa0eb7f44..89f1f70c0 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -25,17 +25,23 @@ import (
"android/soong/android"
)
+func isPathValueResource(res android.Path) bool {
+ subDir := filepath.Dir(res.String())
+ subDir, lastDir := filepath.Split(subDir)
+ return strings.HasPrefix(lastDir, "values")
+}
+
// Convert input resource file path to output file path.
// values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat;
// For other resource file, just replace the last "/" with "_" and add .flat extension.
func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath {
name := res.Base()
- subDir := filepath.Dir(res.String())
- subDir, lastDir := filepath.Split(subDir)
- if strings.HasPrefix(lastDir, "values") {
+ if isPathValueResource(res) {
name = strings.TrimSuffix(name, ".xml") + ".arsc"
}
+ subDir := filepath.Dir(res.String())
+ subDir, lastDir := filepath.Split(subDir)
name = lastDir + "_" + name + ".flat"
return android.PathForModuleOut(ctx, "aapt2", subDir, name)
}
@@ -63,7 +69,21 @@ var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile",
// aapt2Compile compiles resources and puts the results in the requested directory.
func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths,
- flags []string) android.WritablePaths {
+ flags []string, productToFilter string) android.WritablePaths {
+ if productToFilter != "" && productToFilter != "default" {
+ // --filter-product leaves only product-specific resources. Product-specific resources only exist
+ // in value resources (values/*.xml), so filter value resource files only. Ignore other types of
+ // resources as they don't need to be in product characteristics RRO (and they will cause aapt2
+ // compile errors)
+ filteredPaths := android.Paths{}
+ for _, path := range paths {
+ if isPathValueResource(path) {
+ filteredPaths = append(filteredPaths, path)
+ }
+ }
+ paths = filteredPaths
+ flags = append([]string{"--filter-product " + productToFilter}, flags...)
+ }
// Shard the input paths so that they can be processed in parallel. If we shard them into too
// small chunks, the additional cost of spinning up aapt2 outweighs the performance gain. The
diff --git a/java/aar.go b/java/aar.go
index c5e6710c0..d58e14557 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -102,6 +102,9 @@ type aaptProperties struct {
// true if RRO is enforced for any of the dependent modules
RROEnforcedForDependent bool `blueprint:"mutated"`
+
+ // Filter only specified product and ignore other products
+ Filter_product *string `blueprint:"mutated"`
}
type aapt struct {
@@ -162,6 +165,10 @@ func (a *aapt) useResourceProcessorBusyBox() bool {
return BoolDefault(a.aaptProperties.Use_resource_processor, false)
}
+func (a *aapt) filterProduct() string {
+ return String(a.aaptProperties.Filter_product)
+}
+
func (a *aapt) ExportPackage() android.Path {
return a.exportPackage
}
@@ -434,7 +441,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio
var compiledResDirs []android.Paths
for _, dir := range resDirs {
a.resourceFiles = append(a.resourceFiles, dir.files...)
- compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths())
+ compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags, a.filterProduct()).Paths())
}
for i, zip := range resZips {
@@ -493,7 +500,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio
}
for _, dir := range overlayDirs {
- compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths()...)
+ compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags, a.filterProduct()).Paths()...)
}
var splitPackages android.WritablePaths
diff --git a/java/androidmk.go b/java/androidmk.go
index 97b303dfb..84f78c89b 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -343,10 +343,15 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
Disabled: true,
}}
}
+ var required []string
+ if proptools.Bool(app.appProperties.Generate_product_characteristics_rro) {
+ required = []string{app.productCharacteristicsRROPackageName()}
+ }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "APPS",
OutputFile: android.OptionalPathForPath(app.outputFile),
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+ Required: required,
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
// App module names can be overridden.
diff --git a/java/app.go b/java/app.go
index 41848ce0b..9b7f4c46c 100755
--- a/java/app.go
+++ b/java/app.go
@@ -131,6 +131,16 @@ type appProperties struct {
// Specifies the file that contains the allowlist for this app.
Privapp_allowlist *string `android:"path"`
+
+ // If set, create an RRO package which contains only resources having PRODUCT_CHARACTERISTICS
+ // and install the RRO package to /product partition, instead of passing --product argument
+ // to aapt2. Default is false.
+ // Setting this will make this APK identical to all targets, regardless of
+ // PRODUCT_CHARACTERISTICS.
+ Generate_product_characteristics_rro *bool
+
+ ProductCharacteristicsRROPackageName *string `blueprint:"mutated"`
+ ProductCharacteristicsRROManifestModuleName *string `blueprint:"mutated"`
}
// android_app properties that can be overridden by override_android_app
@@ -455,8 +465,9 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
aaptLinkFlags := []string{}
// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
+ autogenerateRRO := proptools.Bool(a.appProperties.Generate_product_characteristics_rro)
hasProduct := android.PrefixInList(a.aaptProperties.Aaptflags, "--product")
- if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
+ if !autogenerateRRO && !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
}
@@ -1057,6 +1068,8 @@ func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) {
}
case ".export-package.apk":
return []android.Path{a.exportPackage}, nil
+ case ".manifest.xml":
+ return []android.Path{a.aapt.manifestPath}, nil
}
return a.Library.OutputFiles(tag)
}
@@ -1086,6 +1099,14 @@ func (a *AndroidApp) IDEInfo(dpInfo *android.IdeInfo) {
a.aapt.IDEInfo(dpInfo)
}
+func (a *AndroidApp) productCharacteristicsRROPackageName() string {
+ return proptools.String(a.appProperties.ProductCharacteristicsRROPackageName)
+}
+
+func (a *AndroidApp) productCharacteristicsRROManifestModuleName() string {
+ return proptools.String(a.appProperties.ProductCharacteristicsRROManifestModuleName)
+}
+
// android_app compiles sources and Android resources into an Android application package `.apk` file.
func AndroidAppFactory() android.Module {
module := &AndroidApp{}
@@ -1112,6 +1133,57 @@ func AndroidAppFactory() android.Module {
android.InitApexModule(module)
android.InitBazelModule(module)
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ a := ctx.Module().(*AndroidApp)
+
+ characteristics := ctx.Config().ProductAAPTCharacteristics()
+ if characteristics == "default" || characteristics == "" {
+ module.appProperties.Generate_product_characteristics_rro = nil
+ // no need to create RRO
+ return
+ }
+
+ if !proptools.Bool(module.appProperties.Generate_product_characteristics_rro) {
+ return
+ }
+
+ rroPackageName := a.Name() + "__" + strings.ReplaceAll(characteristics, ",", "_") + "__auto_generated_characteristics_rro"
+ rroManifestName := rroPackageName + "_manifest"
+
+ a.appProperties.ProductCharacteristicsRROPackageName = proptools.StringPtr(rroPackageName)
+ a.appProperties.ProductCharacteristicsRROManifestModuleName = proptools.StringPtr(rroManifestName)
+
+ rroManifestProperties := struct {
+ Name *string
+ Tools []string
+ Out []string
+ Srcs []string
+ Cmd *string
+ }{
+ Name: proptools.StringPtr(rroManifestName),
+ Tools: []string{"characteristics_rro_generator"},
+ Out: []string{"AndroidManifest.xml"},
+ Srcs: []string{":" + a.Name() + "{.manifest.xml}"},
+ Cmd: proptools.StringPtr("$(location characteristics_rro_generator) $(in) $(out)"),
+ }
+ ctx.CreateModule(genrule.GenRuleFactory, &rroManifestProperties)
+
+ rroProperties := struct {
+ Name *string
+ Filter_product *string
+ Aaptflags []string
+ Manifest *string
+ Resource_dirs []string
+ }{
+ Name: proptools.StringPtr(rroPackageName),
+ Filter_product: proptools.StringPtr(characteristics),
+ Aaptflags: []string{"--auto-add-overlay"},
+ Manifest: proptools.StringPtr(":" + rroManifestName),
+ Resource_dirs: a.aaptProperties.Resource_dirs,
+ }
+ ctx.CreateModule(RuntimeResourceOverlayFactory, &rroProperties)
+ })
+
return module
}