Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5d713f2 authored by Inseob Kim's avatar Inseob Kim Committed by Gerrit Code Review
Browse files

Merge "Add support for auto-generated characteristics RRO" into main

parents 88d5104c 34dc4cd7
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -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
+9 −2
Original line number Diff line number Diff line
@@ -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
}
@@ -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 {
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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.
+73 −1
Original line number Diff line number Diff line
@@ -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
}