Loading java/aapt2.go +24 −4 Original line number Diff line number Diff line Loading @@ -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) } Loading Loading @@ -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 Loading java/aar.go +9 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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 } Loading Loading @@ -432,7 +439,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 { Loading Loading @@ -491,7 +498,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 Loading java/androidmk.go +5 −0 Original line number Diff line number Diff line Loading @@ -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. Loading java/app.go +73 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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()) } Loading Loading @@ -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) } Loading Loading @@ -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{} Loading @@ -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 } Loading Loading
java/aapt2.go +24 −4 Original line number Diff line number Diff line Loading @@ -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) } Loading Loading @@ -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 Loading
java/aar.go +9 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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 } Loading Loading @@ -432,7 +439,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 { Loading Loading @@ -491,7 +498,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 Loading
java/androidmk.go +5 −0 Original line number Diff line number Diff line Loading @@ -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. Loading
java/app.go +73 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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()) } Loading Loading @@ -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) } Loading Loading @@ -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{} Loading @@ -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 } Loading