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

Commit d2021e3f authored by LaMont Jones's avatar LaMont Jones Committed by Gerrit Code Review
Browse files

Merge "Add RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS" into main

parents 60333154 21d04d99
Loading
Loading
Loading
Loading
+109 −49
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
package aconfig

import (
	"path/filepath"
	"slices"
	"strings"

	"android/soong/android"
@@ -22,6 +24,11 @@ import (
	"github.com/google/blueprint"
)

type AconfigReleaseConfigValue struct {
	ReleaseConfig string
	Values        []string `blueprint:"mutated"`
}

type DeclarationsModule struct {
	android.ModuleBase
	android.DefaultableModuleBase
@@ -34,8 +41,10 @@ type DeclarationsModule struct {
		// Release config flag package
		Package string

		// Values from TARGET_RELEASE / RELEASE_ACONFIG_VALUE_SETS
		Values []string `blueprint:"mutated"`
		// Values for release configs / RELEASE_ACONFIG_VALUE_SETS
		// The current release config is `ReleaseConfig: ""`, others
		// are from RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS.
		ReleaseConfigValues []AconfigReleaseConfigValue

		// Container(system/vendor/apex) that this module belongs to
		Container string
@@ -57,6 +66,10 @@ func DeclarationsFactory() android.Module {

type implicitValuesTagType struct {
	blueprint.BaseDependencyTag

	// The release config name for these values.
	// Empty string for the actual current release config.
	ReleaseConfig string
}

var implicitValuesTag = implicitValuesTagType{}
@@ -81,6 +94,11 @@ func (module *DeclarationsModule) DepsMutator(ctx android.BottomUpMutatorContext
	if len(valuesFromConfig) > 0 {
		ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig...)
	}
	for rcName, valueSets := range ctx.Config().ReleaseAconfigExtraReleaseConfigsValueSets() {
		if len(valueSets) > 0 {
			ctx.AddDependency(ctx.Module(), implicitValuesTagType{ReleaseConfig: rcName}, valueSets...)
		}
	}
}

func joinAndPrefix(prefix string, values []string) string {
@@ -101,33 +119,72 @@ func optionalVariable(prefix string, value string) string {
	return sb.String()
}

// Assemble the actual filename.
// If `rcName` is not empty, then insert "-{rcName}" into the path before the
// file extension.
func assembleFileName(rcName, path string) string {
	if rcName == "" {
		return path
	}
	dir, file := filepath.Split(path)
	rcName = "-" + rcName
	ext := filepath.Ext(file)
	base := file[:len(file)-len(ext)]
	return dir + base + rcName + ext
}

func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
	valuesFiles := make([]android.Path, 0)
	// Determine which release configs we are processing.
	//
	// We always process the current release config (empty string).
	// We may have been told to also create artifacts for some others.
	configs := append([]string{""}, ctx.Config().ReleaseAconfigExtraReleaseConfigs()...)
	slices.Sort(configs)

	values := make(map[string][]string)
	valuesFiles := make(map[string][]android.Path, 0)
	providerData := android.AconfigReleaseDeclarationsProviderData{}
	ctx.VisitDirectDeps(func(dep android.Module) {
		if depData, ok := android.OtherModuleProvider(ctx, dep, valueSetProviderKey); ok {
			depTag := ctx.OtherModuleDependencyTag(dep)
			for _, config := range configs {
				tag := implicitValuesTagType{ReleaseConfig: config}
				if depTag == tag {
					paths, ok := depData.AvailablePackages[module.properties.Package]
					if ok {
				valuesFiles = append(valuesFiles, paths...)
						valuesFiles[config] = append(valuesFiles[config], paths...)
						for _, path := range paths {
					module.properties.Values = append(module.properties.Values, path.String())
							values[config] = append(values[config], path.String())
						}
					}
				}
			}
		}
	})
	for _, config := range configs {
		module.properties.ReleaseConfigValues = append(module.properties.ReleaseConfigValues, AconfigReleaseConfigValue{
			ReleaseConfig: config,
			Values:        values[config],
		})

		// Intermediate format
		declarationFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
	intermediateCacheFilePath := android.PathForModuleOut(ctx, "intermediate.pb")
	defaultPermission := ctx.Config().ReleaseAconfigFlagDefaultPermission()
		intermediateCacheFilePath := android.PathForModuleOut(ctx, assembleFileName(config, "intermediate.pb"))
		var defaultPermission string
		defaultPermission = ctx.Config().ReleaseAconfigFlagDefaultPermission()
		if config != "" {
			if confPerm, ok := ctx.Config().GetBuildFlag("RELEASE_ACONFIG_FLAG_DEFAULT_PERMISSION_" + config); ok {
				defaultPermission = confPerm
			}
		}
		inputFiles := make([]android.Path, len(declarationFiles))
		copy(inputFiles, declarationFiles)
	inputFiles = append(inputFiles, valuesFiles...)
		inputFiles = append(inputFiles, valuesFiles[config]...)
		args := map[string]string{
			"release_version":    ctx.Config().ReleaseVersion(),
			"package":            module.properties.Package,
			"declarations":       android.JoinPathsWithPrefix(declarationFiles, "--declarations "),
		"values":             joinAndPrefix(" --values ", module.properties.Values),
			"values":             joinAndPrefix(" --values ", values[config]),
			"default-permission": optionalVariable(" --default-permission ", defaultPermission),
		}
		if len(module.properties.Container) > 0 {
@@ -141,7 +198,7 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module
			Args:        args,
		})

	intermediateDumpFilePath := android.PathForModuleOut(ctx, "intermediate.txt")
		intermediateDumpFilePath := android.PathForModuleOut(ctx, assembleFileName(config, "intermediate.txt"))
		ctx.Build(pctx, android.BuildParams{
			Rule:        aconfigTextRule,
			Output:      intermediateDumpFilePath,
@@ -149,11 +206,14 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module
			Description: "aconfig_text",
		})

	android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, android.AconfigDeclarationsProviderData{
		providerData[config] = android.AconfigDeclarationsProviderData{
			Package:                     module.properties.Package,
			Container:                   module.properties.Container,
			Exportable:                  module.properties.Exportable,
			IntermediateCacheOutputPath: intermediateCacheFilePath,
			IntermediateDumpOutputPath:  intermediateDumpFilePath,
	})
		}
	}
	android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, providerData[""])
	android.SetProvider(ctx, android.AconfigReleaseDeclarationsProviderKey, providerData)
}
+93 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
package aconfig

import (
	"slices"
	"strings"
	"testing"

@@ -134,3 +135,95 @@ func TestMandatoryProperties(t *testing.T) {
		})
	}
}

func TestAssembleFileName(t *testing.T) {
	testCases := []struct {
		name          string
		releaseConfig string
		path          string
		expectedValue string
	}{
		{
			name:          "active release config",
			path:          "file.path",
			expectedValue: "file.path",
		},
		{
			name:          "release config FOO",
			releaseConfig: "FOO",
			path:          "file.path",
			expectedValue: "file-FOO.path",
		},
	}
	for _, test := range testCases {
		actualValue := assembleFileName(test.releaseConfig, test.path)
		if actualValue != test.expectedValue {
			t.Errorf("Expected %q found %q", test.expectedValue, actualValue)
		}
	}
}

func TestGenerateAndroidBuildActions(t *testing.T) {
	testCases := []struct {
		name         string
		buildFlags   map[string]string
		bp           string
		errorHandler android.FixtureErrorHandler
	}{
		{
			name: "generate extra",
			buildFlags: map[string]string{
				"RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS": "config2",
				"RELEASE_ACONFIG_VALUE_SETS":            "aconfig_value_set-config1",
				"RELEASE_ACONFIG_VALUE_SETS_config2":    "aconfig_value_set-config2",
			},
			bp: `
				aconfig_declarations {
					name: "module_name",
					package: "com.example.package",
					container: "com.android.foo",
					srcs: [
						"foo.aconfig",
						"bar.aconfig",
					],
				}
				aconfig_value_set {
					name: "aconfig_value_set-config1",
					values: []
				}
				aconfig_value_set {
					name: "aconfig_value_set-config2",
					values: []
				}
			`,
		},
	}
	for _, test := range testCases {
		fixture := PrepareForTest(t, addBuildFlagsForTest(test.buildFlags))
		if test.errorHandler != nil {
			fixture = fixture.ExtendWithErrorHandler(test.errorHandler)
		}
		result := fixture.RunTestWithBp(t, test.bp)
		module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule)
		depData, _ := android.SingletonModuleProvider(result, module, android.AconfigReleaseDeclarationsProviderKey)
		expectedKeys := []string{""}
		for _, rc := range strings.Split(test.buildFlags["RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS"], " ") {
			expectedKeys = append(expectedKeys, rc)
		}
		slices.Sort(expectedKeys)
		actualKeys := []string{}
		for rc := range depData {
			actualKeys = append(actualKeys, rc)
		}
		slices.Sort(actualKeys)
		android.AssertStringEquals(t, "provider keys", strings.Join(expectedKeys, " "), strings.Join(actualKeys, " "))
		for _, rc := range actualKeys {
			if !strings.HasSuffix(depData[rc].IntermediateCacheOutputPath.String(), assembleFileName(rc, "/intermediate.pb")) {
				t.Errorf("Incorrect intermediates proto path in provider for release config %s: %s", rc, depData[rc].IntermediateCacheOutputPath.String())
			}
			if !strings.HasSuffix(depData[rc].IntermediateDumpOutputPath.String(), assembleFileName(rc, "/intermediate.txt")) {
				t.Errorf("Incorrect intermediates text path in provider for release config %s: %s", rc, depData[rc].IntermediateDumpOutputPath.String())
			}
		}
	}
}
+71 −50
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package aconfig
import (
	"android/soong/android"
	"fmt"
	"slices"
)

// A singleton module that collects all of the aconfig flags declared in the
@@ -27,25 +28,39 @@ import (
// ones that are relevant to the product currently being built, so that that infra
// doesn't need to pull from multiple builds and merge them.
func AllAconfigDeclarationsFactory() android.Singleton {
	return &allAconfigDeclarationsSingleton{}
	return &allAconfigDeclarationsSingleton{releaseMap: make(map[string]allAconfigReleaseDeclarationsSingleton)}
}

type allAconfigDeclarationsSingleton struct {
type allAconfigReleaseDeclarationsSingleton struct {
	intermediateBinaryProtoPath android.OutputPath
	intermediateTextProtoPath   android.OutputPath
}

type allAconfigDeclarationsSingleton struct {
	releaseMap map[string]allAconfigReleaseDeclarationsSingleton
}

func (this *allAconfigDeclarationsSingleton) sortedConfigNames() []string {
	var names []string
	for k := range this.releaseMap {
		names = append(names, k)
	}
	slices.Sort(names)
	return names
}

func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
	for _, rcName := range append([]string{""}, ctx.Config().ReleaseAconfigExtraReleaseConfigs()...) {
		// Find all of the aconfig_declarations modules
		var packages = make(map[string]int)
		var cacheFiles android.Paths
		ctx.VisitAllModules(func(module android.Module) {
		decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
			decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigReleaseDeclarationsProviderKey)
			if !ok {
				return
			}
		cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
		packages[decl.Package]++
			cacheFiles = append(cacheFiles, decl[rcName].IntermediateCacheOutputPath)
			packages[decl[rcName].Package]++
		})

		var numOffendingPkg = 0
@@ -61,36 +76,42 @@ func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.Si
		}

		// Generate build action for aconfig (binary proto output)
	this.intermediateBinaryProtoPath = android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
		paths := allAconfigReleaseDeclarationsSingleton{
			intermediateBinaryProtoPath: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.pb")),
			intermediateTextProtoPath:   android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.textproto")),
		}
		this.releaseMap[rcName] = paths
		ctx.Build(pctx, android.BuildParams{
			Rule:        AllDeclarationsRule,
			Inputs:      cacheFiles,
		Output:      this.intermediateBinaryProtoPath,
			Output:      this.releaseMap[rcName].intermediateBinaryProtoPath,
			Description: "all_aconfig_declarations",
			Args: map[string]string{
				"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
			},
		})
	ctx.Phony("all_aconfig_declarations", this.intermediateBinaryProtoPath)
		ctx.Phony("all_aconfig_declarations", this.releaseMap[rcName].intermediateBinaryProtoPath)

		// Generate build action for aconfig (text proto output)
	this.intermediateTextProtoPath = android.PathForIntermediates(ctx, "all_aconfig_declarations.textproto")
		ctx.Build(pctx, android.BuildParams{
			Rule:        AllDeclarationsRuleTextProto,
			Inputs:      cacheFiles,
		Output:      this.intermediateTextProtoPath,
			Output:      this.releaseMap[rcName].intermediateTextProtoPath,
			Description: "all_aconfig_declarations_textproto",
			Args: map[string]string{
				"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
			},
		})
	ctx.Phony("all_aconfig_declarations_textproto", this.intermediateTextProtoPath)
		ctx.Phony("all_aconfig_declarations_textproto", this.releaseMap[rcName].intermediateTextProtoPath)
	}
}

func (this *allAconfigDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
	ctx.DistForGoal("droid", this.intermediateBinaryProtoPath)
	for _, rcName := range this.sortedConfigNames() {
		ctx.DistForGoal("droid", this.releaseMap[rcName].intermediateBinaryProtoPath)
		for _, goal := range []string{"docs", "droid", "sdk"} {
		ctx.DistForGoalWithFilename(goal, this.intermediateBinaryProtoPath, "flags.pb")
		ctx.DistForGoalWithFilename(goal, this.intermediateTextProtoPath, "flags.textproto")
			ctx.DistForGoalWithFilename(goal, this.releaseMap[rcName].intermediateBinaryProtoPath, assembleFileName(rcName, "flags.pb"))
			ctx.DistForGoalWithFilename(goal, this.releaseMap[rcName].intermediateTextProtoPath, assembleFileName(rcName, "flags.textproto"))
		}
	}
}
+19 −1
Original line number Diff line number Diff line
@@ -23,7 +23,25 @@ import (
var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)

func runTest(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
	return android.GroupFixturePreparers(PrepareForTestWithAconfigBuildComponents).
	return PrepareForTest(t).
		ExtendWithErrorHandler(errorHandler).
		RunTestWithBp(t, bp)
}

func PrepareForTest(t *testing.T, preparers ...android.FixturePreparer) android.FixturePreparer {
	preparers = append([]android.FixturePreparer{PrepareForTestWithAconfigBuildComponents}, preparers...)
	return android.GroupFixturePreparers(preparers...)
}

func addBuildFlagsForTest(buildFlags map[string]string) android.FixturePreparer {
	return android.GroupFixturePreparers(
		android.FixtureModifyProductVariables(func(vars android.FixtureProductVariables) {
			if vars.BuildFlags == nil {
				vars.BuildFlags = make(map[string]string)
			}
			for k, v := range buildFlags {
				vars.BuildFlags[k] = v
			}
		}),
	)
}
+6 −0
Original line number Diff line number Diff line
@@ -43,6 +43,10 @@ type AconfigDeclarationsProviderData struct {

var AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]()

type AconfigReleaseDeclarationsProviderData map[string]AconfigDeclarationsProviderData

var AconfigReleaseDeclarationsProviderKey = blueprint.NewProvider[AconfigReleaseDeclarationsProviderData]()

type ModeInfo struct {
	Container string
	Mode      string
@@ -112,6 +116,8 @@ func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
		if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok {
			mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath)
		}
		// If we were generating on-device artifacts for other release configs, we would need to add code here to propagate
		// those artifacts as well.  See also b/298444886.
		if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok {
			for container, v := range dep.AconfigFiles {
				mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
Loading