Merge "Add support for auto-generated characteristics RRO" into main am: b5d713f2cb
am: 99913d4e59
Original change: https://android-review.googlesource.com/c/platform/build/soong/+/2817177 Change-Id: Iafa0e65932058e0e0f0644b4aa42e7e6f803d95b Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -25,17 +25,23 @@ import (
|
|||||||
"android/soong/android"
|
"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.
|
// Convert input resource file path to output file path.
|
||||||
// values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat;
|
// values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat;
|
||||||
// For other resource file, just replace the last "/" with "_" and add .flat extension.
|
// For other resource file, just replace the last "/" with "_" and add .flat extension.
|
||||||
func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath {
|
func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath {
|
||||||
|
|
||||||
name := res.Base()
|
name := res.Base()
|
||||||
subDir := filepath.Dir(res.String())
|
if isPathValueResource(res) {
|
||||||
subDir, lastDir := filepath.Split(subDir)
|
|
||||||
if strings.HasPrefix(lastDir, "values") {
|
|
||||||
name = strings.TrimSuffix(name, ".xml") + ".arsc"
|
name = strings.TrimSuffix(name, ".xml") + ".arsc"
|
||||||
}
|
}
|
||||||
|
subDir := filepath.Dir(res.String())
|
||||||
|
subDir, lastDir := filepath.Split(subDir)
|
||||||
name = lastDir + "_" + name + ".flat"
|
name = lastDir + "_" + name + ".flat"
|
||||||
return android.PathForModuleOut(ctx, "aapt2", subDir, name)
|
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.
|
// aapt2Compile compiles resources and puts the results in the requested directory.
|
||||||
func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths,
|
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
|
// 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
|
// small chunks, the additional cost of spinning up aapt2 outweighs the performance gain. The
|
||||||
|
11
java/aar.go
11
java/aar.go
@@ -102,6 +102,9 @@ type aaptProperties struct {
|
|||||||
|
|
||||||
// true if RRO is enforced for any of the dependent modules
|
// true if RRO is enforced for any of the dependent modules
|
||||||
RROEnforcedForDependent bool `blueprint:"mutated"`
|
RROEnforcedForDependent bool `blueprint:"mutated"`
|
||||||
|
|
||||||
|
// Filter only specified product and ignore other products
|
||||||
|
Filter_product *string `blueprint:"mutated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type aapt struct {
|
type aapt struct {
|
||||||
@@ -162,6 +165,10 @@ func (a *aapt) useResourceProcessorBusyBox() bool {
|
|||||||
return BoolDefault(a.aaptProperties.Use_resource_processor, false)
|
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 {
|
func (a *aapt) ExportPackage() android.Path {
|
||||||
return a.exportPackage
|
return a.exportPackage
|
||||||
}
|
}
|
||||||
@@ -432,7 +439,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio
|
|||||||
var compiledResDirs []android.Paths
|
var compiledResDirs []android.Paths
|
||||||
for _, dir := range resDirs {
|
for _, dir := range resDirs {
|
||||||
a.resourceFiles = append(a.resourceFiles, dir.files...)
|
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 {
|
for i, zip := range resZips {
|
||||||
@@ -491,7 +498,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, dir := range overlayDirs {
|
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
|
var splitPackages android.WritablePaths
|
||||||
|
@@ -343,10 +343,15 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
|
|||||||
Disabled: true,
|
Disabled: true,
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
var required []string
|
||||||
|
if proptools.Bool(app.appProperties.Generate_product_characteristics_rro) {
|
||||||
|
required = []string{app.productCharacteristicsRROPackageName()}
|
||||||
|
}
|
||||||
return []android.AndroidMkEntries{android.AndroidMkEntries{
|
return []android.AndroidMkEntries{android.AndroidMkEntries{
|
||||||
Class: "APPS",
|
Class: "APPS",
|
||||||
OutputFile: android.OptionalPathForPath(app.outputFile),
|
OutputFile: android.OptionalPathForPath(app.outputFile),
|
||||||
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
|
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
|
||||||
|
Required: required,
|
||||||
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
||||||
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
||||||
// App module names can be overridden.
|
// App module names can be overridden.
|
||||||
|
74
java/app.go
74
java/app.go
@@ -131,6 +131,16 @@ type appProperties struct {
|
|||||||
|
|
||||||
// Specifies the file that contains the allowlist for this app.
|
// Specifies the file that contains the allowlist for this app.
|
||||||
Privapp_allowlist *string `android:"path"`
|
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
|
// android_app properties that can be overridden by override_android_app
|
||||||
@@ -455,8 +465,9 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
|
|||||||
aaptLinkFlags := []string{}
|
aaptLinkFlags := []string{}
|
||||||
|
|
||||||
// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
|
// 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")
|
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())
|
aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1057,6 +1068,8 @@ func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) {
|
|||||||
}
|
}
|
||||||
case ".export-package.apk":
|
case ".export-package.apk":
|
||||||
return []android.Path{a.exportPackage}, nil
|
return []android.Path{a.exportPackage}, nil
|
||||||
|
case ".manifest.xml":
|
||||||
|
return []android.Path{a.aapt.manifestPath}, nil
|
||||||
}
|
}
|
||||||
return a.Library.OutputFiles(tag)
|
return a.Library.OutputFiles(tag)
|
||||||
}
|
}
|
||||||
@@ -1086,6 +1099,14 @@ func (a *AndroidApp) IDEInfo(dpInfo *android.IdeInfo) {
|
|||||||
a.aapt.IDEInfo(dpInfo)
|
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.
|
// android_app compiles sources and Android resources into an Android application package `.apk` file.
|
||||||
func AndroidAppFactory() android.Module {
|
func AndroidAppFactory() android.Module {
|
||||||
module := &AndroidApp{}
|
module := &AndroidApp{}
|
||||||
@@ -1112,6 +1133,57 @@ func AndroidAppFactory() android.Module {
|
|||||||
android.InitApexModule(module)
|
android.InitApexModule(module)
|
||||||
android.InitBazelModule(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
|
return module
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user