diff options
51 files changed, 1976 insertions, 744 deletions
diff --git a/android/apex.go b/android/apex.go index 87599051a..c0acada13 100644 --- a/android/apex.go +++ b/android/apex.go @@ -16,6 +16,7 @@ package android import ( "fmt" + "slices" "sort" "strconv" "strings" @@ -108,7 +109,7 @@ func (i ApexInfo) AddJSONData(d *map[string]interface{}) { // are configured to have the same alias variation named apex29. Whether platform APIs is allowed // or not also matters; if two APEXes don't have the same allowance, they get different names and // thus wouldn't be merged. -func (i ApexInfo) mergedName(ctx PathContext) string { +func (i ApexInfo) mergedName() string { name := "apex" + strconv.Itoa(i.MinSdkVersion.FinalOrFutureInt()) return name } @@ -543,17 +544,10 @@ func AvailableToSameApexes(mod1, mod2 ApexModule) bool { return true } -type byApexName []ApexInfo - -func (a byApexName) Len() int { return len(a) } -func (a byApexName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byApexName) Less(i, j int) bool { return a[i].ApexVariationName < a[j].ApexVariationName } - // mergeApexVariations deduplicates apex variations that would build identically into a common // variation. It returns the reduced list of variations and a list of aliases from the original // variation names to the new variation names. -func mergeApexVariations(ctx PathContext, apexInfos []ApexInfo) (merged []ApexInfo, aliases [][2]string) { - sort.Sort(byApexName(apexInfos)) +func mergeApexVariations(apexInfos []ApexInfo) (merged []ApexInfo, aliases [][2]string) { seen := make(map[string]int) for _, apexInfo := range apexInfos { // If this is for a prebuilt apex then use the actual name of the apex variation to prevent this @@ -567,7 +561,7 @@ func mergeApexVariations(ctx PathContext, apexInfos []ApexInfo) (merged []ApexIn // this one into it, otherwise create a new merged ApexInfo from this one and save it away so // other ApexInfo instances can be merged into it. variantName := apexInfo.ApexVariationName - mergedName := apexInfo.mergedName(ctx) + mergedName := apexInfo.mergedName() if index, exists := seen[mergedName]; exists { // Variants having the same mergedName are deduped merged[index].InApexVariants = append(merged[index].InApexVariants, variantName) @@ -606,18 +600,20 @@ func CreateApexVariations(mctx BottomUpMutatorContext, module ApexModule) []Modu // TODO(jiyong): is this the right place? base.checkApexAvailableProperty(mctx) - var apexInfos []ApexInfo - var aliases [][2]string - if !mctx.Module().(ApexModule).UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { - apexInfos, aliases = mergeApexVariations(mctx, base.apexInfos) - } else { - apexInfos = base.apexInfos - } + apexInfos := base.apexInfos // base.apexInfos is only needed to propagate the list of apexes from apexInfoMutator to // apexMutator. It is no longer accurate after mergeApexVariations, and won't be copied to // all but the first created variant. Clear it so it doesn't accidentally get used later. base.apexInfos = nil - sort.Sort(byApexName(apexInfos)) + + slices.SortFunc(apexInfos, func(a, b ApexInfo) int { + return strings.Compare(a.ApexVariationName, b.ApexVariationName) + }) + + var aliases [][2]string + if !mctx.Module().(ApexModule).UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { + apexInfos, aliases = mergeApexVariations(apexInfos) + } var inApex ApexMembership for _, a := range apexInfos { diff --git a/android/apex_test.go b/android/apex_test.go index ddc730d05..347bf7d98 100644 --- a/android/apex_test.go +++ b/android/apex_test.go @@ -33,10 +33,22 @@ func Test_mergeApexVariations(t *testing.T) { { name: "single", in: []ApexInfo{ - {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "foo", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantMerged: []ApexInfo{ - {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "apex10000", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantAliases: [][2]string{ {"foo", "apex10000"}, @@ -45,98 +57,231 @@ func Test_mergeApexVariations(t *testing.T) { { name: "merge", in: []ApexInfo{ - {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, - {"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "foo", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, + { + ApexVariationName: "bar", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"bar"}, + InApexModules: []string{"bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantMerged: []ApexInfo{ - {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false, nil}}, + { + ApexVariationName: "apex10000", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo", "bar"}, + InApexModules: []string{"foo", "bar"}, + }}, wantAliases: [][2]string{ - {"bar", "apex10000"}, {"foo", "apex10000"}, + {"bar", "apex10000"}, }, }, { name: "don't merge version", in: []ApexInfo{ - {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, - {"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "foo", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, + { + ApexVariationName: "bar", + MinSdkVersion: uncheckedFinalApiLevel(30), + InApexVariants: []string{"bar"}, + InApexModules: []string{"bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantMerged: []ApexInfo{ - {"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil}, - {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "apex10000", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, + { + ApexVariationName: "apex30", + MinSdkVersion: uncheckedFinalApiLevel(30), + InApexVariants: []string{"bar"}, + InApexModules: []string{"bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantAliases: [][2]string{ - {"bar", "apex30"}, {"foo", "apex10000"}, + {"bar", "apex30"}, }, }, { name: "merge updatable", in: []ApexInfo{ - {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, - {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "foo", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, + { + ApexVariationName: "bar", + MinSdkVersion: FutureApiLevel, + Updatable: true, + InApexVariants: []string{"bar"}, + InApexModules: []string{"bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantMerged: []ApexInfo{ - {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "apex10000", + MinSdkVersion: FutureApiLevel, + Updatable: true, + InApexVariants: []string{"foo", "bar"}, + InApexModules: []string{"foo", "bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantAliases: [][2]string{ - {"bar", "apex10000"}, {"foo", "apex10000"}, + {"bar", "apex10000"}, }, }, { name: "don't merge when for prebuilt_apex", in: []ApexInfo{ - {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, - {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "foo", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, + { + ApexVariationName: "bar", + MinSdkVersion: FutureApiLevel, + Updatable: true, + InApexVariants: []string{"bar"}, + InApexModules: []string{"bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, // This one should not be merged in with the others because it is for // a prebuilt_apex. - {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil}, + { + ApexVariationName: "baz", + MinSdkVersion: FutureApiLevel, + Updatable: true, + InApexVariants: []string{"baz"}, + InApexModules: []string{"baz"}, + ForPrebuiltApex: ForPrebuiltApex, + }, }, wantMerged: []ApexInfo{ - {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil}, - {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil}, + { + ApexVariationName: "apex10000", + MinSdkVersion: FutureApiLevel, + Updatable: true, + InApexVariants: []string{"foo", "bar"}, + InApexModules: []string{"foo", "bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, + { + ApexVariationName: "baz", + MinSdkVersion: FutureApiLevel, + Updatable: true, + InApexVariants: []string{"baz"}, + InApexModules: []string{"baz"}, + ForPrebuiltApex: ForPrebuiltApex, + }, }, wantAliases: [][2]string{ - {"bar", "apex10000"}, {"foo", "apex10000"}, + {"bar", "apex10000"}, }, }, { name: "merge different UsePlatformApis but don't allow using platform api", in: []ApexInfo{ - {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, - {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "foo", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, + { + ApexVariationName: "bar", + MinSdkVersion: FutureApiLevel, + UsePlatformApis: true, + InApexVariants: []string{"bar"}, + InApexModules: []string{"bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantMerged: []ApexInfo{ - {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "apex10000", + MinSdkVersion: FutureApiLevel, + InApexVariants: []string{"foo", "bar"}, + InApexModules: []string{"foo", "bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantAliases: [][2]string{ - {"bar", "apex10000"}, {"foo", "apex10000"}, + {"bar", "apex10000"}, }, }, { name: "merge same UsePlatformApis and allow using platform api", in: []ApexInfo{ - {"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil}, - {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "foo", + MinSdkVersion: FutureApiLevel, + UsePlatformApis: true, + InApexVariants: []string{"foo"}, + InApexModules: []string{"foo"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, + { + ApexVariationName: "bar", + MinSdkVersion: FutureApiLevel, + UsePlatformApis: true, + InApexVariants: []string{"bar"}, + InApexModules: []string{"bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantMerged: []ApexInfo{ - {"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil}, + { + ApexVariationName: "apex10000", + MinSdkVersion: FutureApiLevel, + UsePlatformApis: true, + InApexVariants: []string{"foo", "bar"}, + InApexModules: []string{"foo", "bar"}, + ForPrebuiltApex: NotForPrebuiltApex, + }, }, wantAliases: [][2]string{ - {"bar", "apex10000"}, {"foo", "apex10000"}, + {"bar", "apex10000"}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - config := TestConfig(t.TempDir(), nil, "", nil) - ctx := &configErrorWrapper{config: config} - gotMerged, gotAliases := mergeApexVariations(ctx, tt.in) + gotMerged, gotAliases := mergeApexVariations(tt.in) if !reflect.DeepEqual(gotMerged, tt.wantMerged) { t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged) } diff --git a/android/base_module_context.go b/android/base_module_context.go index c4922f4bc..c5fe58578 100644 --- a/android/base_module_context.go +++ b/android/base_module_context.go @@ -20,7 +20,7 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/parser" + "github.com/google/blueprint/proptools" ) // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns @@ -219,7 +219,7 @@ type BaseModuleContext interface { // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context // can be used to evaluate the final value of Configurable properties. - EvaluateConfiguration(parser.SelectType, string, string) (string, bool) + EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue } type baseModuleContext struct { @@ -577,6 +577,6 @@ func (b *baseModuleContext) GetPathString(skipFirst bool) string { return sb.String() } -func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) { - return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(ty, property, condition) +func (m *baseModuleContext) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue { + return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(condition, property) } diff --git a/android/config.go b/android/config.go index 11bd81b89..75d135fc0 100644 --- a/android/config.go +++ b/android/config.go @@ -949,7 +949,11 @@ func (c *config) PlatformPreviewSdkVersion() string { } func (c *config) PlatformMinSupportedTargetSdkVersion() string { - return String(c.productVariables.Platform_min_supported_target_sdk_version) + var val, ok = c.productVariables.BuildFlags["RELEASE_PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION"] + if !ok { + return "" + } + return val } func (c *config) PlatformBaseOS() string { diff --git a/android/module.go b/android/module.go index 89c4ddde9..5fe379c8a 100644 --- a/android/module.go +++ b/android/module.go @@ -29,7 +29,6 @@ import ( "android/soong/bazel" "github.com/google/blueprint" - "github.com/google/blueprint/parser" "github.com/google/blueprint/proptools" ) @@ -1043,12 +1042,12 @@ func (m *ModuleBase) baseDepsMutator(ctx BottomUpMutatorContext) { pv := ctx.Config().productVariables fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil if fullManifest { - m.addRequiredDeps(ctx) + addRequiredDeps(ctx) } } // addRequiredDeps adds required, target_required, and host_required as dependencies. -func (m *ModuleBase) addRequiredDeps(ctx BottomUpMutatorContext) { +func addRequiredDeps(ctx BottomUpMutatorContext) { addDep := func(target Target, depName string) { if !ctx.OtherModuleExists(depName) { if ctx.Config().AllowMissingDependencies() { @@ -1061,9 +1060,9 @@ func (m *ModuleBase) addRequiredDeps(ctx BottomUpMutatorContext) { // in build/make/core/main.mk. // TODO(jiyong): the Make-side does this only when the required module is a shared // library or a native test. - bothInAndroid := m.Device() && target.Os.Class == Device - nativeArch := InList(m.Arch().ArchType.Multilib, []string{"lib32", "lib64"}) - sameBitness := m.Arch().ArchType.Multilib == target.Arch.ArchType.Multilib + bothInAndroid := ctx.Device() && target.Os.Class == Device + nativeArch := InList(ctx.Arch().ArchType.Multilib, []string{"lib32", "lib64"}) + sameBitness := ctx.Arch().ArchType.Multilib == target.Arch.ArchType.Multilib if bothInAndroid && nativeArch && !sameBitness { return } @@ -1082,31 +1081,31 @@ func (m *ModuleBase) addRequiredDeps(ctx BottomUpMutatorContext) { hostTargets = append(hostTargets, ctx.Config().Targets[ctx.Config().BuildOS]...) hostTargets = append(hostTargets, ctx.Config().BuildOSCommonTarget) - if m.Device() { - for _, depName := range m.RequiredModuleNames() { + if ctx.Device() { + for _, depName := range ctx.Module().RequiredModuleNames() { for _, target := range deviceTargets { addDep(target, depName) } } - for _, depName := range m.HostRequiredModuleNames() { + for _, depName := range ctx.Module().HostRequiredModuleNames() { for _, target := range hostTargets { addDep(target, depName) } } } - if m.Host() { - for _, depName := range m.RequiredModuleNames() { + if ctx.Host() { + for _, depName := range ctx.Module().RequiredModuleNames() { for _, target := range hostTargets { // When a host module requires another host module, don't make a // dependency if they have different OSes (i.e. hostcross). - if m.Target().HostCross != target.HostCross { + if ctx.Target().HostCross != target.HostCross { continue } addDep(target, depName) } } - for _, depName := range m.TargetRequiredModuleNames() { + for _, depName := range ctx.Module().TargetRequiredModuleNames() { for _, target := range deviceTargets { addDep(target, depName) } @@ -2140,41 +2139,82 @@ func (e configurationEvalutor) PropertyErrorf(property string, fmt string, args e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args) } -func (e configurationEvalutor) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) { +func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue { ctx := e.ctx m := e.m - switch ty { - case parser.SelectTypeReleaseVariable: - if v, ok := ctx.Config().productVariables.BuildFlags[condition]; ok { - return v, true + switch condition.FunctionName { + case "release_variable": + if len(condition.Args) != 1 { + ctx.OtherModulePropertyErrorf(m, property, "release_variable requires 1 argument, found %d", len(condition.Args)) + return proptools.ConfigurableValueUndefined() + } + if v, ok := ctx.Config().productVariables.BuildFlags[condition.Args[0]]; ok { + return proptools.ConfigurableValueString(v) } - return "", false - case parser.SelectTypeProductVariable: + return proptools.ConfigurableValueUndefined() + case "product_variable": // TODO(b/323382414): Might add these on a case-by-case basis ctx.OtherModulePropertyErrorf(m, property, "TODO(b/323382414): Product variables are not yet supported in selects") - return "", false - case parser.SelectTypeSoongConfigVariable: - parts := strings.Split(condition, ":") - namespace := parts[0] - variable := parts[1] + return proptools.ConfigurableValueUndefined() + case "soong_config_variable": + if len(condition.Args) != 2 { + ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", len(condition.Args)) + return proptools.ConfigurableValueUndefined() + } + namespace := condition.Args[0] + variable := condition.Args[1] if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok { if v, ok := n[variable]; ok { - return v, true + return proptools.ConfigurableValueString(v) } } - return "", false - case parser.SelectTypeVariant: - if condition == "arch" { - if !m.base().ArchReady() { - ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran") - return "", false + return proptools.ConfigurableValueUndefined() + case "arch": + if len(condition.Args) != 0 { + ctx.OtherModulePropertyErrorf(m, property, "arch requires no arguments, found %d", len(condition.Args)) + return proptools.ConfigurableValueUndefined() + } + if !m.base().ArchReady() { + ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran") + return proptools.ConfigurableValueUndefined() + } + return proptools.ConfigurableValueString(m.base().Arch().ArchType.Name) + case "os": + if len(condition.Args) != 0 { + ctx.OtherModulePropertyErrorf(m, property, "os requires no arguments, found %d", len(condition.Args)) + return proptools.ConfigurableValueUndefined() + } + // the arch mutator runs after the os mutator, we can just use this to enforce that os is ready. + if !m.base().ArchReady() { + ctx.OtherModulePropertyErrorf(m, property, "A select on os was attempted before the arch mutator ran (arch runs after os, we use it to lazily detect that os is ready)") + return proptools.ConfigurableValueUndefined() + } + return proptools.ConfigurableValueString(m.base().Os().Name) + case "boolean_var_for_testing": + // We currently don't have any other boolean variables (we should add support for typing + // the soong config variables), so add this fake one for testing the boolean select + // functionality. + if len(condition.Args) != 0 { + ctx.OtherModulePropertyErrorf(m, property, "boolean_var_for_testing requires 0 arguments, found %d", len(condition.Args)) + return proptools.ConfigurableValueUndefined() + } + + if n, ok := ctx.Config().productVariables.VendorVars["boolean_var"]; ok { + if v, ok := n["for_testing"]; ok { + switch v { + case "true": + return proptools.ConfigurableValueBool(true) + case "false": + return proptools.ConfigurableValueBool(false) + default: + ctx.OtherModulePropertyErrorf(m, property, "testing:my_boolean_var can only be true or false, found %q", v) + } } - return m.base().Arch().ArchType.Name, true } - ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition) - return "", false + return proptools.ConfigurableValueUndefined() default: - panic("Should be unreachable") + ctx.OtherModulePropertyErrorf(m, property, "Unknown select condition %s", condition.FunctionName) + return proptools.ConfigurableValueUndefined() } } diff --git a/android/mutator.go b/android/mutator.go index 0ff4f48ea..75ba65048 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -391,6 +391,7 @@ func (x *registerMutatorsContext) BottomUpBlueprint(name string, m blueprint.Bot type IncomingTransitionContext interface { ArchModuleContext + ModuleProviderContext // Module returns the target of the dependency edge for which the transition // is being computed @@ -404,6 +405,7 @@ type IncomingTransitionContext interface { type OutgoingTransitionContext interface { ArchModuleContext + ModuleProviderContext // Module returns the target of the dependency edge for which the transition // is being computed @@ -505,6 +507,7 @@ type TransitionMutator interface { type androidTransitionMutator struct { finalPhase bool mutator TransitionMutator + name string } func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string { @@ -537,6 +540,10 @@ func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig { return DeviceConfig{c.bp.Config().(Config).deviceConfig} } +func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) { + return c.bp.Provider(provider) +} + func (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string { if m, ok := bpctx.Module().(Module); ok { ctx := outgoingTransitionContextPool.Get().(*outgoingTransitionContextImpl) @@ -568,6 +575,10 @@ func (c *incomingTransitionContextImpl) DeviceConfig() DeviceConfig { return DeviceConfig{c.bp.Config().(Config).deviceConfig} } +func (c *incomingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) { + return c.bp.Provider(provider) +} + func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string { if m, ok := bpctx.Module().(Module); ok { ctx := incomingTransitionContextPool.Get().(*incomingTransitionContextImpl) @@ -586,6 +597,9 @@ func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, if am, ok := ctx.Module().(Module); ok { mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase) defer bottomUpMutatorContextPool.Put(mctx) + base := am.base() + base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name) + base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation) a.mutator.Mutate(mctx, variation) } } @@ -594,6 +608,7 @@ func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) { atm := &androidTransitionMutator{ finalPhase: x.finalPhase, mutator: m, + name: name, } mutator := &mutator{ name: name, diff --git a/android/paths.go b/android/paths.go index a40f48274..2b33f67ce 100644 --- a/android/paths.go +++ b/android/paths.go @@ -673,7 +673,8 @@ func PathsAndMissingDepsRelativeToModuleSourceDir(input SourceInput) (Paths, []s expandedSrcFiles = append(expandedSrcFiles, srcFiles...) } - return expandedSrcFiles, append(missingDeps, missingExcludeDeps...) + // TODO: b/334169722 - Replace with an error instead of implicitly removing duplicates. + return FirstUniquePaths(expandedSrcFiles), append(missingDeps, missingExcludeDeps...) } type missingDependencyError struct { diff --git a/android/selects_test.go b/android/selects_test.go index e59b3e65d..f912ce626 100644 --- a/android/selects_test.go +++ b/android/selects_test.go @@ -269,11 +269,11 @@ func TestSelects(t *testing.T) { }, }, { - name: "Select on variant", + name: "Select on arch", bp: ` my_module_type { name: "foo", - my_string: select(variant("arch"), { + my_string: select(arch(), { "x86": "my_x86", "x86_64": "my_x86_64", "arm": "my_arm", @@ -287,6 +287,22 @@ func TestSelects(t *testing.T) { }, }, { + name: "Select on os", + bp: ` + my_module_type { + name: "foo", + my_string: select(os(), { + "android": "my_android", + "linux": "my_linux", + default: "my_default", + }), + } + `, + provider: selectsTestProvider{ + my_string: proptools.StringPtr("my_android"), + }, + }, + { name: "Unset value", bp: ` my_module_type { @@ -327,8 +343,10 @@ func TestSelects(t *testing.T) { my_module_type { name: "foo", my_string: select(soong_config_variable("my_namespace", "my_variable"), { + "foo": "bar", default: unset, }) + select(soong_config_variable("my_namespace", "my_variable2"), { + "baz": "qux", default: unset, }) } @@ -341,6 +359,7 @@ func TestSelects(t *testing.T) { my_module_type { name: "foo", my_string: select(soong_config_variable("my_namespace", "my_variable"), { + "foo": "bar", default: unset, }) + select(soong_config_variable("my_namespace", "my_variable2"), { default: "a", @@ -414,6 +433,169 @@ func TestSelects(t *testing.T) { replacing_string_list: &[]string{"b1"}, }, }, + { + name: "Multi-condition string 1", + bp: ` + my_module_type { + name: "foo", + my_string: select(( + soong_config_variable("my_namespace", "my_variable"), + soong_config_variable("my_namespace", "my_variable2"), + ), { + ("a", "b"): "a+b", + ("a", default): "a+default", + (default, default): "default", + }), + } + `, + vendorVars: map[string]map[string]string{ + "my_namespace": { + "my_variable": "a", + "my_variable2": "b", + }, + }, + provider: selectsTestProvider{ + my_string: proptools.StringPtr("a+b"), + }, + }, + { + name: "Multi-condition string 2", + bp: ` + my_module_type { + name: "foo", + my_string: select(( + soong_config_variable("my_namespace", "my_variable"), + soong_config_variable("my_namespace", "my_variable2"), + ), { + ("a", "b"): "a+b", + ("a", default): "a+default", + (default, default): "default", + }), + } + `, + vendorVars: map[string]map[string]string{ + "my_namespace": { + "my_variable": "a", + "my_variable2": "c", + }, + }, + provider: selectsTestProvider{ + my_string: proptools.StringPtr("a+default"), + }, + }, + { + name: "Multi-condition string 3", + bp: ` + my_module_type { + name: "foo", + my_string: select(( + soong_config_variable("my_namespace", "my_variable"), + soong_config_variable("my_namespace", "my_variable2"), + ), { + ("a", "b"): "a+b", + ("a", default): "a+default", + (default, default): "default", + }), + } + `, + vendorVars: map[string]map[string]string{ + "my_namespace": { + "my_variable": "c", + "my_variable2": "b", + }, + }, + provider: selectsTestProvider{ + my_string: proptools.StringPtr("default"), + }, + }, + { + name: "Select on boolean", + bp: ` + my_module_type { + name: "foo", + my_string: select(boolean_var_for_testing(), { + true: "t", + false: "f", + }), + } + `, + vendorVars: map[string]map[string]string{ + "boolean_var": { + "for_testing": "true", + }, + }, + provider: selectsTestProvider{ + my_string: proptools.StringPtr("t"), + }, + }, + { + name: "Select on boolean false", + bp: ` + my_module_type { + name: "foo", + my_string: select(boolean_var_for_testing(), { + true: "t", + false: "f", + }), + } + `, + vendorVars: map[string]map[string]string{ + "boolean_var": { + "for_testing": "false", + }, + }, + provider: selectsTestProvider{ + my_string: proptools.StringPtr("f"), + }, + }, + { + name: "Select on boolean undefined", + bp: ` + my_module_type { + name: "foo", + my_string: select(boolean_var_for_testing(), { + true: "t", + false: "f", + }), + } + `, + expectedError: "foo", + }, + { + name: "Select on boolean undefined with default", + bp: ` + my_module_type { + name: "foo", + my_string: select(boolean_var_for_testing(), { + true: "t", + false: "f", + default: "default", + }), + } + `, + provider: selectsTestProvider{ + my_string: proptools.StringPtr("default"), + }, + }, + { + name: "Mismatched condition types", + bp: ` + my_module_type { + name: "foo", + my_string: select(boolean_var_for_testing(), { + "true": "t", + "false": "f", + default: "default", + }), + } + `, + vendorVars: map[string]map[string]string{ + "boolean_var": { + "for_testing": "false", + }, + }, + expectedError: "Expected all branches of a select on condition boolean_var_for_testing\\(\\) to have type bool, found string", + }, } for _, tc := range testCases { diff --git a/android/util.go b/android/util.go index 363b31ce5..698a85650 100644 --- a/android/util.go +++ b/android/util.go @@ -524,22 +524,27 @@ func SplitFileExt(name string) (string, string, string) { return root, suffix, ext } -// ShardPaths takes a Paths, and returns a slice of Paths where each one has at most shardSize paths. -func ShardPaths(paths Paths, shardSize int) []Paths { - if len(paths) == 0 { +func shard[T ~[]E, E any](toShard T, shardSize int) []T { + if len(toShard) == 0 { return nil } - ret := make([]Paths, 0, (len(paths)+shardSize-1)/shardSize) - for len(paths) > shardSize { - ret = append(ret, paths[0:shardSize]) - paths = paths[shardSize:] + + ret := make([]T, 0, (len(toShard)+shardSize-1)/shardSize) + for len(toShard) > shardSize { + ret = append(ret, toShard[0:shardSize]) + toShard = toShard[shardSize:] } - if len(paths) > 0 { - ret = append(ret, paths) + if len(toShard) > 0 { + ret = append(ret, toShard) } return ret } +// ShardPaths takes a Paths, and returns a slice of Paths where each one has at most shardSize paths. +func ShardPaths(paths Paths, shardSize int) []Paths { + return shard(paths, shardSize) +} + // ShardString takes a string and returns a slice of strings where the length of each one is // at most shardSize. func ShardString(s string, shardSize int) []string { @@ -560,18 +565,7 @@ func ShardString(s string, shardSize int) []string { // ShardStrings takes a slice of strings, and returns a slice of slices of strings where each one has at most shardSize // elements. func ShardStrings(s []string, shardSize int) [][]string { - if len(s) == 0 { - return nil - } - ret := make([][]string, 0, (len(s)+shardSize-1)/shardSize) - for len(s) > shardSize { - ret = append(ret, s[0:shardSize]) - s = s[shardSize:] - } - if len(s) > 0 { - ret = append(ret, s) - } - return ret + return shard(s, shardSize) } // CheckDuplicate checks if there are duplicates in given string list. diff --git a/android/variable.go b/android/variable.go index b0afd5b9b..0040d836d 100644 --- a/android/variable.go +++ b/android/variable.go @@ -139,6 +139,8 @@ type variableProperties struct { Srcs []string Exclude_srcs []string Cmd *string + + Deps []string } // eng is true for -eng builds, and can be used to turn on additional heavyweight debugging @@ -199,23 +201,22 @@ type ProductVariables struct { BuildThumbprintFile *string `json:",omitempty"` DisplayBuildNumber *bool `json:",omitempty"` - Platform_display_version_name *string `json:",omitempty"` - Platform_version_name *string `json:",omitempty"` - Platform_sdk_version *int `json:",omitempty"` - Platform_sdk_codename *string `json:",omitempty"` - Platform_sdk_version_or_codename *string `json:",omitempty"` - Platform_sdk_final *bool `json:",omitempty"` - Platform_sdk_extension_version *int `json:",omitempty"` - Platform_base_sdk_extension_version *int `json:",omitempty"` - Platform_version_active_codenames []string `json:",omitempty"` - Platform_version_all_preview_codenames []string `json:",omitempty"` - Platform_systemsdk_versions []string `json:",omitempty"` - Platform_security_patch *string `json:",omitempty"` - Platform_preview_sdk_version *string `json:",omitempty"` - Platform_min_supported_target_sdk_version *string `json:",omitempty"` - Platform_base_os *string `json:",omitempty"` - Platform_version_last_stable *string `json:",omitempty"` - Platform_version_known_codenames *string `json:",omitempty"` + Platform_display_version_name *string `json:",omitempty"` + Platform_version_name *string `json:",omitempty"` + Platform_sdk_version *int `json:",omitempty"` + Platform_sdk_codename *string `json:",omitempty"` + Platform_sdk_version_or_codename *string `json:",omitempty"` + Platform_sdk_final *bool `json:",omitempty"` + Platform_sdk_extension_version *int `json:",omitempty"` + Platform_base_sdk_extension_version *int `json:",omitempty"` + Platform_version_active_codenames []string `json:",omitempty"` + Platform_version_all_preview_codenames []string `json:",omitempty"` + Platform_systemsdk_versions []string `json:",omitempty"` + Platform_security_patch *string `json:",omitempty"` + Platform_preview_sdk_version *string `json:",omitempty"` + Platform_base_os *string `json:",omitempty"` + Platform_version_last_stable *string `json:",omitempty"` + Platform_version_known_codenames *string `json:",omitempty"` DeviceName *string `json:",omitempty"` DeviceProduct *string `json:",omitempty"` diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go index 672e852d4..b5b49b1ab 100644 --- a/bpfix/bpfix/bpfix_test.go +++ b/bpfix/bpfix/bpfix_test.go @@ -19,6 +19,7 @@ package bpfix import ( "bytes" "fmt" + "os" "reflect" "strings" "testing" @@ -2215,3 +2216,9 @@ func TestRemoveResourceAndAssetsIfDefault(t *testing.T) { }) } } + +func TestMain(m *testing.M) { + // Skip checking Android.mk path with cleaning "ANDROID_BUILD_TOP" + os.Setenv("ANDROID_BUILD_TOP", "") + os.Exit(m.Run()) +} diff --git a/cc/Android.bp b/cc/Android.bp index 8c86eb706..5ba94270b 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -91,6 +91,7 @@ bootstrap_go_package { "afdo_test.go", "binary_test.go", "cc_test.go", + "cc_test_only_property_test.go", "compiler_test.go", "gen_test.go", "genrule_test.go", @@ -845,6 +845,7 @@ type Module struct { VendorProperties VendorProperties Properties BaseProperties + sourceProperties android.SourceProperties // initialize before calling Init hod android.HostOrDeviceSupported @@ -1262,6 +1263,10 @@ func (c *Module) Init() android.Module { for _, feature := range c.features { c.AddProperties(feature.props()...) } + // Allow test-only on libraries that are not cc_test_library + if c.library != nil && !c.testLibrary() { + c.AddProperties(&c.sourceProperties) + } android.InitAndroidArchModule(c, c.hod, c.multilib) android.InitApexModule(c) @@ -1990,6 +1995,20 @@ func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { } func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { + ctx := moduleContextFromAndroidModuleContext(actx, c) + + // If Test_only is set on a module in bp file, respect the setting, otherwise + // see if is a known test module type. + testOnly := c.testModule || c.testLibrary() + if c.sourceProperties.Test_only != nil { + testOnly = Bool(c.sourceProperties.Test_only) + } + // Keep before any early returns. + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: testOnly, + TopLevelTarget: c.testModule, + }) + // Handle the case of a test module split by `test_per_src` mutator. // // The `test_per_src` mutator adds an extra variation named "", depending on all the other @@ -2008,8 +2027,6 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { c.makeLinkType = GetMakeLinkType(actx, c) - ctx := moduleContextFromAndroidModuleContext(actx, c) - deps := c.depsToPaths(ctx) if ctx.Failed() { return @@ -2135,6 +2152,7 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if c.testModule { android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } + android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()}) android.CollectDependencyAconfigFiles(ctx, &c.mergedAconfigFiles) @@ -3308,10 +3326,10 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library. // Re-exported shared library headers must be included as well since they can help us with type information // about template instantiations (instantiated from their headers). - // -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version - // scripts. c.sabi.Properties.ReexportedIncludes = append( c.sabi.Properties.ReexportedIncludes, depExporterInfo.IncludeDirs.Strings()...) + c.sabi.Properties.ReexportedSystemIncludes = append( + c.sabi.Properties.ReexportedSystemIncludes, depExporterInfo.SystemIncludeDirs.Strings()...) } makeLibName := MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName()) + libDepTag.makeSuffix @@ -3382,6 +3400,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if c.sabi != nil { c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes) + c.sabi.Properties.ReexportedSystemIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedSystemIncludes) } return depPaths diff --git a/cc/cc_test.go b/cc/cc_test.go index d4955c615..3d75bf5a6 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -958,6 +958,7 @@ func TestLlndkLibrary(t *testing.T) { cc_library_headers { name: "libexternal_llndk_headers", export_include_dirs: ["include_llndk"], + export_system_include_dirs: ["include_system_llndk"], llndk: { symbol_file: "libllndk.map.txt", }, @@ -973,6 +974,17 @@ func TestLlndkLibrary(t *testing.T) { }, export_include_dirs: ["include"], } + + cc_library { + name: "libllndk_with_system_headers", + llndk: { + symbol_file: "libllndk.map.txt", + export_llndk_headers: ["libexternal_llndk_headers"], + export_headers_as_system: true, + }, + export_include_dirs: ["include"], + export_system_include_dirs: ["include_system"], + } `) actual := result.ModuleVariantsForTests("libllndk") for i := 0; i < len(actual); i++ { @@ -990,20 +1002,26 @@ func TestLlndkLibrary(t *testing.T) { params := result.ModuleForTests("libllndk", "android_vendor_arm_armv7-a-neon_shared").Description("generate stub") android.AssertSame(t, "use Vendor API level for default stubs", "202404", params.Args["apiLevel"]) - checkExportedIncludeDirs := func(module, variant string, expectedDirs ...string) { + checkExportedIncludeDirs := func(module, variant string, expectedSystemDirs []string, expectedDirs ...string) { t.Helper() m := result.ModuleForTests(module, variant).Module() f, _ := android.SingletonModuleProvider(result, m, FlagExporterInfoProvider) android.AssertPathsRelativeToTopEquals(t, "exported include dirs for "+module+"["+variant+"]", expectedDirs, f.IncludeDirs) + android.AssertPathsRelativeToTopEquals(t, "exported include dirs for "+module+"["+variant+"]", + expectedSystemDirs, f.SystemIncludeDirs) } - checkExportedIncludeDirs("libllndk", coreVariant, "include") - checkExportedIncludeDirs("libllndk", vendorVariant, "include") - checkExportedIncludeDirs("libllndk_with_external_headers", coreVariant, "include") - checkExportedIncludeDirs("libllndk_with_external_headers", vendorVariant, "include_llndk") - checkExportedIncludeDirs("libllndk_with_override_headers", coreVariant, "include") - checkExportedIncludeDirs("libllndk_with_override_headers", vendorVariant, "include_llndk") + checkExportedIncludeDirs("libllndk", coreVariant, nil, "include") + checkExportedIncludeDirs("libllndk", vendorVariant, nil, "include") + checkExportedIncludeDirs("libllndk_with_external_headers", coreVariant, nil, "include") + checkExportedIncludeDirs("libllndk_with_external_headers", vendorVariant, + []string{"include_system_llndk"}, "include_llndk") + checkExportedIncludeDirs("libllndk_with_override_headers", coreVariant, nil, "include") + checkExportedIncludeDirs("libllndk_with_override_headers", vendorVariant, nil, "include_llndk") + checkExportedIncludeDirs("libllndk_with_system_headers", coreVariant, []string{"include_system"}, "include") + checkExportedIncludeDirs("libllndk_with_system_headers", vendorVariant, + []string{"include_system", "include", "include_system_llndk"}, "include_llndk") checkAbiLinkerIncludeDirs := func(module string) { t.Helper() @@ -1016,12 +1034,14 @@ func TestLlndkLibrary(t *testing.T) { } vendorModule := result.ModuleForTests(module, vendorVariant).Module() vendorInfo, _ := android.SingletonModuleProvider(result, vendorModule, FlagExporterInfoProvider) + vendorDirs := android.Concat(vendorInfo.IncludeDirs, vendorInfo.SystemIncludeDirs) android.AssertStringEquals(t, module+" has different exported include dirs for vendor variant and ABI check", - android.JoinPathsWithPrefix(vendorInfo.IncludeDirs, "-I"), abiCheckFlags) + android.JoinPathsWithPrefix(vendorDirs, "-I"), abiCheckFlags) } checkAbiLinkerIncludeDirs("libllndk") checkAbiLinkerIncludeDirs("libllndk_with_override_headers") checkAbiLinkerIncludeDirs("libllndk_with_external_headers") + checkAbiLinkerIncludeDirs("libllndk_with_system_headers") } func TestLlndkHeaders(t *testing.T) { diff --git a/cc/cc_test_only_property_test.go b/cc/cc_test_only_property_test.go new file mode 100644 index 000000000..c14f34ecb --- /dev/null +++ b/cc/cc_test_only_property_test.go @@ -0,0 +1,219 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cc + +import ( + "android/soong/android" + "android/soong/android/team_proto" + "log" + "strings" + "testing" + + "github.com/google/blueprint" + "google.golang.org/protobuf/proto" +) + +func TestTestOnlyProvider(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForCcTest, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("cc_test_host", TestHostFactory) + }), + ).RunTestWithBp(t, ` + // These should be test-only + cc_fuzz { name: "cc-fuzz" } + cc_test { name: "cc-test", gtest:false } + cc_benchmark { name: "cc-benchmark" } + cc_library { name: "cc-library-forced", + test_only: true } + cc_test_library {name: "cc-test-library", gtest: false} + cc_test_host {name: "cc-test-host", gtest: false} + + // These should not be. + cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] } + cc_library { name: "cc_library" } + cc_library { name: "cc_library_false", test_only: false } + cc_library_static { name: "cc_static" } + cc_library_shared { name: "cc_library_shared" } + + cc_object { name: "cc-object" } + `) + + // Visit all modules and ensure only the ones that should + // marked as test-only are marked as test-only. + + actualTestOnly := []string{} + ctx.VisitAllModules(func(m blueprint.Module) { + if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok { + if provider.TestOnly { + actualTestOnly = append(actualTestOnly, m.Name()) + } + } + }) + expectedTestOnlyModules := []string{ + "cc-test", + "cc-library-forced", + "cc-fuzz", + "cc-benchmark", + "cc-test-library", + "cc-test-host", + } + + notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTestOnly) + if notEqual { + t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right) + } +} + +func TestTestOnlyValueWithTestPerSrcProp(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForCcTest, + ).RunTestWithBp(t, ` + // These should be test-only + cc_test { name: "cc-test", + gtest: false, + test_per_src: true, + srcs: ["foo_test.cpp"], + test_options: { unit_test: false, }, + } + `) + + // Ensure all variation of test-per-src tests are marked test-only. + ctx.VisitAllModules(func(m blueprint.Module) { + testOnly := false + if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok { + if provider.TestOnly { + testOnly = true + } + } + if module, ok := m.(*Module); ok { + if testModule, ok := module.installer.(*testBinary); ok { + if !testOnly && *testModule.Properties.Test_per_src { + t.Errorf("%v is not test-only but should be", m) + } + } + } + }) +} + +func TestTestOnlyInTeamsProto(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + android.PrepareForTestWithTeamBuildComponents, + prepareForCcTest, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterParallelSingletonType("all_teams", android.AllTeamsFactory) + ctx.RegisterModuleType("cc_test_host", TestHostFactory) + + }), + ).RunTestWithBp(t, ` + package { default_team: "someteam"} + + // These should be test-only + cc_fuzz { name: "cc-fuzz" } + cc_test { name: "cc-test", gtest:false } + cc_benchmark { name: "cc-benchmark" } + cc_library { name: "cc-library-forced", + test_only: true } + cc_test_library {name: "cc-test-library", gtest: false} + cc_test_host {name: "cc-test-host", gtest: false} + + // These should not be. + cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] } + cc_library { name: "cc_library" } + cc_library_static { name: "cc_static" } + cc_library_shared { name: "cc_library_shared" } + + cc_object { name: "cc-object" } + team { + name: "someteam", + trendy_team_id: "cool_team", + } + `) + + var teams *team_proto.AllTeams + teams = getTeamProtoOutput(t, ctx) + + // map of module name -> trendy team name. + actualTrueModules := []string{} + for _, teamProto := range teams.Teams { + if Bool(teamProto.TestOnly) { + actualTrueModules = append(actualTrueModules, teamProto.GetTargetName()) + } + } + expectedTestOnlyModules := []string{ + "cc-test", + "cc-library-forced", + "cc-fuzz", + "cc-benchmark", + "cc-test-library", + "cc-test-host", + } + + notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTrueModules) + if notEqual { + t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right) + } +} + +// Don't allow setting test-only on things that are always tests or never tests. +func TestInvalidTestOnlyTargets(t *testing.T) { + testCases := []string{ + ` cc_test { name: "cc-test", test_only: true, gtest: false, srcs: ["foo.cc"], } `, + ` cc_binary { name: "cc-binary", test_only: true, srcs: ["foo.cc"], } `, + ` cc_test_library {name: "cc-test-library", test_only: true, gtest: false} `, + ` cc_test_host {name: "cc-test-host", test_only: true, gtest: false} `, + ` cc_defaults {name: "cc-defaults", test_only: true} `, + } + + for i, bp := range testCases { + ctx := android.GroupFixturePreparers( + prepareForCcTest, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("cc_test_host", TestHostFactory) + })). + ExtendWithErrorHandler(android.FixtureIgnoreErrors). + RunTestWithBp(t, bp) + if len(ctx.Errs) == 0 { + t.Errorf("Expected err setting test_only in testcase #%d", i) + } + if len(ctx.Errs) > 1 { + t.Errorf("Too many errs: [%s] %v", bp, ctx.Errs) + } + + if len(ctx.Errs) == 1 { + if !strings.Contains(ctx.Errs[0].Error(), "unrecognized property \"test_only\"") { + t.Errorf("ERR: %s bad bp: %s", ctx.Errs[0], bp) + } + } + } +} + +func getTeamProtoOutput(t *testing.T, ctx *android.TestResult) *team_proto.AllTeams { + teams := new(team_proto.AllTeams) + config := ctx.SingletonForTests("all_teams") + allOutputs := config.AllOutputs() + + protoPath := allOutputs[0] + + out := config.MaybeOutput(protoPath) + outProto := []byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, out)) + if err := proto.Unmarshal(outProto, teams); err != nil { + log.Fatalln("Failed to parse teams proto:", err) + } + return teams +} diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go index 380f20a7e..beb68e19d 100644 --- a/cc/config/arm64_device.go +++ b/cc/config/arm64_device.go @@ -101,7 +101,9 @@ func init() { pctx.VariableFunc("Arm64Cflags", func(ctx android.PackageVarContext) string { flags := arm64Cflags - if !ctx.Config().NoBionicPageSizeMacro() { + if ctx.Config().NoBionicPageSizeMacro() { + flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO") + } else { flags = append(flags, "-D__BIONIC_DEPRECATED_PAGE_SIZE_MACRO") } return strings.Join(flags, " ") diff --git a/cc/config/global.go b/cc/config/global.go index 08fcb91fa..16b5e0938 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -144,6 +144,9 @@ var ( // Make paths in deps files relative. "-no-canonical-prefixes", + + // http://b/315250603 temporarily disabled + "-Wno-error=format", } commonGlobalConlyflags = []string{} @@ -254,8 +257,6 @@ var ( "-Werror=fortify-source", // http://b/315246135 temporarily disabled "-Wno-unused-variable", - // http://b/315250603 temporarily disabled - "-Wno-error=format", // Disabled because it produces many false positives. http://b/323050926 "-Wno-missing-field-initializers", // http://b/323050889 diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go index f88358aa9..5aa2a7e3b 100644 --- a/cc/config/x86_64_device.go +++ b/cc/config/x86_64_device.go @@ -110,7 +110,9 @@ func init() { // Clang cflags pctx.VariableFunc("X86_64Cflags", func(ctx android.PackageVarContext) string { flags := x86_64Cflags - if !ctx.Config().NoBionicPageSizeMacro() { + if ctx.Config().NoBionicPageSizeMacro() { + flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO") + } else { flags = append(flags, "-D__BIONIC_DEPRECATED_PAGE_SIZE_MACRO") } return strings.Join(flags, " ") diff --git a/cc/library.go b/cc/library.go index d9754df99..5b2480906 100644 --- a/cc/library.go +++ b/cc/library.go @@ -294,6 +294,10 @@ func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths { return android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs) } +func (f *flagExporter) exportedSystemIncludes(ctx ModuleContext) android.Paths { + return android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs) +} + // exportIncludes registers the include directories and system include directories to be exported // transitively to modules depending on this module. func (f *flagExporter) exportIncludes(ctx ModuleContext) { @@ -1204,12 +1208,22 @@ func (library *libraryDecorator) coverageOutputFilePath() android.OptionalPath { func (library *libraryDecorator) exportedIncludeDirsForAbiCheck(ctx ModuleContext) []string { exportIncludeDirs := library.flagExporter.exportedIncludes(ctx).Strings() exportIncludeDirs = append(exportIncludeDirs, library.sabi.Properties.ReexportedIncludes...) - return exportIncludeDirs + exportSystemIncludeDirs := library.flagExporter.exportedSystemIncludes(ctx).Strings() + exportSystemIncludeDirs = append(exportSystemIncludeDirs, library.sabi.Properties.ReexportedSystemIncludes...) + // The ABI checker does not distinguish normal and system headers. + return append(exportIncludeDirs, exportSystemIncludeDirs...) } func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, deps PathDeps) []string { + var includeDirs, systemIncludeDirs []string + // The ABI checker does not need the preprocess which adds macro guards to function declarations. - includeDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings() + preprocessedDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings() + if Bool(library.Properties.Llndk.Export_headers_as_system) { + systemIncludeDirs = append(systemIncludeDirs, preprocessedDirs...) + } else { + includeDirs = append(includeDirs, preprocessedDirs...) + } if library.Properties.Llndk.Override_export_include_dirs != nil { includeDirs = append(includeDirs, android.PathsForModuleSrc( @@ -1220,7 +1234,8 @@ func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, // LLNDK does not reexport the implementation's dependencies, such as export_header_libs. } - systemIncludeDirs := []string{} + systemIncludeDirs = append(systemIncludeDirs, + library.flagExporter.exportedSystemIncludes(ctx).Strings()...) if Bool(library.Properties.Llndk.Export_headers_as_system) { systemIncludeDirs = append(systemIncludeDirs, includeDirs...) includeDirs = nil diff --git a/cc/sabi.go b/cc/sabi.go index af2672634..ef43c8daf 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -92,7 +92,8 @@ type SAbiProperties struct { // Include directories that may contain ABI information exported by a library. // These directories are passed to the header-abi-dumper. - ReexportedIncludes []string `blueprint:"mutated"` + ReexportedIncludes []string `blueprint:"mutated"` + ReexportedSystemIncludes []string `blueprint:"mutated"` } type sabi struct { diff --git a/cmd/release_config/Android.bp b/cmd/release_config/Android.bp deleted file mode 100644 index 7f627ffb7..000000000 --- a/cmd/release_config/Android.bp +++ /dev/null @@ -1,30 +0,0 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -bootstrap_go_package { - name: "release-config", - pkgPath: "android/soong/cmd/release_config", - deps: [ - "golang-protobuf-encoding-prototext", - "golang-protobuf-reflect-protoreflect", - "golang-protobuf-runtime-protoimpl", - "soong-cmd-release-config-proto", - ], - srcs: [ - "main.go", - ], -} - -bootstrap_go_package { - name: "soong-cmd-release-config-proto", - pkgPath: "android/soong/cmd/release_config/release_config_proto", - deps: [ - "golang-protobuf-reflect-protoreflect", - "golang-protobuf-runtime-protoimpl", - ], - srcs: [ - "release_config_proto/build_flags_out.pb.go", - "release_config_proto/build_flags_src.pb.go", - ], -} diff --git a/cmd/release_config/release_config/Android.bp b/cmd/release_config/release_config/Android.bp new file mode 100644 index 000000000..3c7382637 --- /dev/null +++ b/cmd/release_config/release_config/Android.bp @@ -0,0 +1,18 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-cmd-release_config-release_config", + pkgPath: "android/soong/cmd/release_config/release_config", + deps: [ + "golang-protobuf-encoding-prototext", + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + "soong-cmd-release_config-proto", + "soong-cmd-release_config-lib", + ], + srcs: [ + "main.go", + ], +} diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go new file mode 100644 index 000000000..076abfaaf --- /dev/null +++ b/cmd/release_config/release_config/main.go @@ -0,0 +1,57 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "flag" + "os" + + rc_lib "android/soong/cmd/release_config/release_config_lib" +) + +func main() { + var top string + var releaseConfigMapPaths rc_lib.StringList + var targetRelease string + var outputDir string + var err error + var configs *rc_lib.ReleaseConfigs + + flag.StringVar(&top, "top", ".", "path to top of workspace") + flag.Var(&releaseConfigMapPaths, "map", "path to a release_config_map.textproto. may be repeated") + flag.StringVar(&targetRelease, "release", "trunk_staging", "TARGET_RELEASE for this build") + flag.StringVar(&outputDir, "out_dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created") + flag.Parse() + + if err = os.Chdir(top); err != nil { + panic(err) + } + configs, err = rc_lib.ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease) + if err != nil { + panic(err) + } + err = os.MkdirAll(outputDir, 0775) + if err != nil { + panic(err) + } + err = configs.DumpMakefile(outputDir, targetRelease) + if err != nil { + panic(err) + } + err = configs.DumpArtifact(outputDir) + if err != nil { + panic(err) + } +} diff --git a/cmd/release_config/release_config_lib/Android.bp b/cmd/release_config/release_config_lib/Android.bp new file mode 100644 index 000000000..601194c93 --- /dev/null +++ b/cmd/release_config/release_config_lib/Android.bp @@ -0,0 +1,36 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-cmd-release_config-lib", + pkgPath: "android/soong/release_config/release_config_lib", + deps: [ + "golang-protobuf-encoding-prototext", + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + "soong-cmd-release_config-proto", + ], + srcs: [ + "flag_artifact.go", + "flag_declaration.go", + "flag_value.go", + "release_config.go", + "release_configs.go", + "util.go", + ], +} diff --git a/cmd/release_config/release_config_lib/flag_artifact.go b/cmd/release_config/release_config_lib/flag_artifact.go new file mode 100644 index 000000000..51673a5ec --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_artifact.go @@ -0,0 +1,89 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "fmt" + + "android/soong/cmd/release_config/release_config_proto" + + "google.golang.org/protobuf/proto" +) + +type FlagArtifact struct { + FlagDeclaration *release_config_proto.FlagDeclaration + + // The index of the config directory where this flag was declared. + // Flag values cannot be set in a location with a lower index. + DeclarationIndex int + + Traces []*release_config_proto.Tracepoint + + // Assigned value + Value *release_config_proto.Value +} + +// Key is flag name. +type FlagArtifacts map[string]*FlagArtifact + +func (src *FlagArtifact) Clone() *FlagArtifact { + value := &release_config_proto.Value{} + proto.Merge(value, src.Value) + return &FlagArtifact{ + FlagDeclaration: src.FlagDeclaration, + Traces: src.Traces, + Value: value, + } +} + +func (src FlagArtifacts) Clone() (dst FlagArtifacts) { + if dst == nil { + dst = make(FlagArtifacts) + } + for k, v := range src { + dst[k] = v.Clone() + } + return +} + +func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error { + name := *flagValue.proto.Name + fa.Traces = append(fa.Traces, &release_config_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value}) + if fa.Value.GetObsolete() { + return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces) + } + switch val := flagValue.proto.Value.Val.(type) { + case *release_config_proto.Value_StringValue: + fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_StringValue{val.StringValue}} + case *release_config_proto.Value_BoolValue: + fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_BoolValue{val.BoolValue}} + case *release_config_proto.Value_Obsolete: + if !val.Obsolete { + return fmt.Errorf("%s: Cannot set obsolete=false. Trace=%v", name, fa.Traces) + } + fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_Obsolete{true}} + default: + return fmt.Errorf("Invalid type for flag_value: %T. Trace=%v", val, fa.Traces) + } + return nil +} + +func (fa *FlagArtifact) Marshal() (*release_config_proto.FlagArtifact, error) { + return &release_config_proto.FlagArtifact{ + FlagDeclaration: fa.FlagDeclaration, + Value: fa.Value, + Traces: fa.Traces, + }, nil +} diff --git a/cmd/release_config/release_config_lib/flag_declaration.go b/cmd/release_config/release_config_lib/flag_declaration.go new file mode 100644 index 000000000..d5cc41845 --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_declaration.go @@ -0,0 +1,27 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "android/soong/cmd/release_config/release_config_proto" +) + +func FlagDeclarationFactory(protoPath string) (fd *release_config_proto.FlagDeclaration) { + fd = &release_config_proto.FlagDeclaration{} + if protoPath != "" { + LoadTextproto(protoPath, fd) + } + return fd +} diff --git a/cmd/release_config/release_config_lib/flag_value.go b/cmd/release_config/release_config_lib/flag_value.go new file mode 100644 index 000000000..138e8f8d3 --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_value.go @@ -0,0 +1,56 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "android/soong/cmd/release_config/release_config_proto" +) + +type FlagValue struct { + // The path providing this value. + path string + + // Protobuf + proto release_config_proto.FlagValue +} + +func FlagValueFactory(protoPath string) (fv *FlagValue) { + fv = &FlagValue{path: protoPath} + if protoPath != "" { + LoadTextproto(protoPath, &fv.proto) + } + return fv +} + +func MarshalValue(value *release_config_proto.Value) string { + switch val := value.Val.(type) { + case *release_config_proto.Value_UnspecifiedValue: + // Value was never set. + return "" + case *release_config_proto.Value_StringValue: + return val.StringValue + case *release_config_proto.Value_BoolValue: + if val.BoolValue { + return "true" + } + // False ==> empty string + return "" + case *release_config_proto.Value_Obsolete: + return " #OBSOLETE" + default: + // Flagged as error elsewhere, so return empty string here. + return "" + } +} diff --git a/cmd/release_config/release_config_lib/flag_value_test.go b/cmd/release_config/release_config_lib/flag_value_test.go new file mode 100644 index 000000000..aaa4cafeb --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_value_test.go @@ -0,0 +1,67 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "os" + "path/filepath" + "testing" + + rc_proto "android/soong/cmd/release_config/release_config_proto" + + "google.golang.org/protobuf/proto" +) + +type testCaseFlagValue struct { + protoPath string + name string + data []byte + expected rc_proto.FlagValue + err error +} + +func (tc testCaseFlagValue) assertProtoEqual(t *testing.T, expected, actual proto.Message) { + if !proto.Equal(expected, actual) { + t.Errorf("Expected %q found %q", expected, actual) + } +} + +func TestFlagValue(t *testing.T) { + testCases := []testCaseFlagValue{ + { + name: "stringVal", + protoPath: "build/release/flag_values/test/RELEASE_FOO.textproto", + data: []byte(`name: "RELEASE_FOO" value {string_value: "BAR"}`), + expected: rc_proto.FlagValue{ + Name: proto.String("RELEASE_FOO"), + Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{"BAR"}}, + }, + err: nil, + }, + } + for _, tc := range testCases { + var err error + tempdir := t.TempDir() + path := filepath.Join(tempdir, tc.protoPath) + if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil { + t.Fatal(err) + } + if err = os.WriteFile(path, tc.data, 0644); err != nil { + t.Fatal(err) + } + actual := FlagValueFactory(path) + tc.assertProtoEqual(t, &tc.expected, &actual.proto) + } +} diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go new file mode 100644 index 000000000..3110dae81 --- /dev/null +++ b/cmd/release_config/release_config_lib/release_config.go @@ -0,0 +1,154 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "fmt" + + "android/soong/cmd/release_config/release_config_proto" + + "google.golang.org/protobuf/proto" +) + +// One directory's contribution to the a release config. +type ReleaseConfigContribution struct { + // Paths to files providing this config. + path string + + // The index of the config directory where this release config + // contribution was declared. + // Flag values cannot be set in a location with a lower index. + DeclarationIndex int + + // Protobufs relevant to the config. + proto release_config_proto.ReleaseConfig + + FlagValues []*FlagValue +} + +// A generated release config. +type ReleaseConfig struct { + // the Name of the release config + Name string + + // The index of the config directory where this release config was + // first declared. + // Flag values cannot be set in a location with a lower index. + DeclarationIndex int + + // What contributes to this config. + Contributions []*ReleaseConfigContribution + + // Aliases for this release + OtherNames []string + + // The names of release configs that we inherit + InheritNames []string + + // Unmarshalled flag artifacts + FlagArtifacts FlagArtifacts + + // Generated release config + ReleaseConfigArtifact *release_config_proto.ReleaseConfigArtifact + + // We have begun compiling this release config. + compileInProgress bool +} + +func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) { + return &ReleaseConfig{Name: name, DeclarationIndex: index} +} + +func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error { + if config.ReleaseConfigArtifact != nil { + return nil + } + if config.compileInProgress { + return fmt.Errorf("Loop detected for release config %s", config.Name) + } + config.compileInProgress = true + + // Generate any configs we need to inherit. This will detect loops in + // the config. + contributionsToApply := []*ReleaseConfigContribution{} + myInherits := []string{} + myInheritsSet := make(map[string]bool) + for _, inherit := range config.InheritNames { + if _, ok := myInheritsSet[inherit]; ok { + continue + } + myInherits = append(myInherits, inherit) + myInheritsSet[inherit] = true + iConfig, err := configs.GetReleaseConfig(inherit) + if err != nil { + return err + } + iConfig.GenerateReleaseConfig(configs) + contributionsToApply = append(contributionsToApply, iConfig.Contributions...) + } + contributionsToApply = append(contributionsToApply, config.Contributions...) + + myAconfigValueSets := []string{} + myFlags := configs.FlagArtifacts.Clone() + myDirsMap := make(map[int]bool) + for _, contrib := range contributionsToApply { + myAconfigValueSets = append(myAconfigValueSets, contrib.proto.AconfigValueSets...) + myDirsMap[contrib.DeclarationIndex] = true + for _, value := range contrib.FlagValues { + fa, ok := myFlags[*value.proto.Name] + if !ok { + return fmt.Errorf("Setting value for undefined flag %s in %s\n", *value.proto.Name, value.path) + } + myDirsMap[fa.DeclarationIndex] = true + if fa.DeclarationIndex > contrib.DeclarationIndex { + // Setting location is to the left of declaration. + return fmt.Errorf("Setting value for flag %s not allowed in %s\n", *value.proto.Name, value.path) + } + if err := fa.UpdateValue(*value); err != nil { + return err + } + } + } + + directories := []string{} + for idx, confDir := range configs.ConfigDirs { + if _, ok := myDirsMap[idx]; ok { + directories = append(directories, confDir) + } + } + + config.FlagArtifacts = myFlags + config.ReleaseConfigArtifact = &release_config_proto.ReleaseConfigArtifact{ + Name: proto.String(config.Name), + OtherNames: config.OtherNames, + FlagArtifacts: func() []*release_config_proto.FlagArtifact { + ret := []*release_config_proto.FlagArtifact{} + for _, flag := range myFlags { + ret = append(ret, &release_config_proto.FlagArtifact{ + FlagDeclaration: flag.FlagDeclaration, + Traces: flag.Traces, + Value: flag.Value, + }) + } + return ret + }(), + AconfigValueSets: myAconfigValueSets, + Inherits: myInherits, + Directories: directories, + } + + config.compileInProgress = false + return nil +} diff --git a/cmd/release_config/main.go b/cmd/release_config/release_config_lib/release_configs.go index 3bb6b3dfe..74fdc005f 100644 --- a/cmd/release_config/main.go +++ b/cmd/release_config/release_config_lib/release_configs.go @@ -12,12 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package main +package release_config_lib import ( "cmp" "encoding/json" - "flag" "fmt" "io/fs" "os" @@ -31,105 +30,6 @@ import ( "google.golang.org/protobuf/proto" ) -var verboseFlag bool - -type StringList []string - -func (l *StringList) Set(v string) error { - *l = append(*l, v) - return nil -} - -func (l *StringList) String() string { - return fmt.Sprintf("%v", *l) -} - -var releaseConfigMapPaths StringList - -func DumpProtos(outDir string, message proto.Message) error { - basePath := filepath.Join(outDir, "all_release_configs") - writer := func(suffix string, marshal func() ([]byte, error)) error { - data, err := marshal() - if err != nil { - return err - } - return os.WriteFile(fmt.Sprintf("%s.%s", basePath, suffix), data, 0644) - } - err := writer("textproto", func() ([]byte, error) { return prototext.MarshalOptions{Multiline: true}.Marshal(message) }) - if err != nil { - return err - } - - err = writer("pb", func() ([]byte, error) { return proto.Marshal(message) }) - if err != nil { - return err - } - - return writer("json", func() ([]byte, error) { return json.MarshalIndent(message, "", " ") }) -} - -func LoadTextproto(path string, message proto.Message) error { - data, err := os.ReadFile(path) - if err != nil { - return err - } - ret := prototext.Unmarshal(data, message) - if verboseFlag { - debug, _ := prototext.Marshal(message) - fmt.Printf("%s: %s\n", path, debug) - } - return ret -} - -func WalkTextprotoFiles(root string, subdir string, Func fs.WalkDirFunc) error { - path := filepath.Join(root, subdir) - if _, err := os.Stat(path); err != nil { - // Missing subdirs are not an error. - return nil - } - return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if strings.HasSuffix(d.Name(), ".textproto") && d.Type().IsRegular() { - return Func(path, d, err) - } - return nil - }) -} - -type FlagValue struct { - // The path providing this value. - path string - - // Protobuf - proto release_config_proto.FlagValue -} - -func FlagValueFactory(protoPath string) (fv *FlagValue) { - fv = &FlagValue{path: protoPath} - if protoPath != "" { - LoadTextproto(protoPath, &fv.proto) - } - return fv -} - -// One directory's contribution to the a release config. -type ReleaseConfigContribution struct { - // Paths to files providing this config. - path string - - // The index of the config directory where this release config - // contribution was declared. - // Flag values cannot be set in a location with a lower index. - DeclarationIndex int - - // Protobufs relevant to the config. - proto release_config_proto.ReleaseConfig - - FlagValues []*FlagValue -} - // A single release_config_map.textproto and its associated data. // Used primarily for debugging. type ReleaseConfigMap struct { @@ -143,51 +43,6 @@ type ReleaseConfigMap struct { FlagDeclarations []release_config_proto.FlagDeclaration } -// A generated release config. -type ReleaseConfig struct { - // the Name of the release config - Name string - - // The index of the config directory where this release config was - // first declared. - // Flag values cannot be set in a location with a lower index. - DeclarationIndex int - - // What contributes to this config. - Contributions []*ReleaseConfigContribution - - // Aliases for this release - OtherNames []string - - // The names of release configs that we inherit - InheritNames []string - - // Unmarshalled flag artifacts - FlagArtifacts FlagArtifacts - - // Generated release config - ReleaseConfigArtifact *release_config_proto.ReleaseConfigArtifact - - // We have begun compiling this release config. - compileInProgress bool -} - -type FlagArtifact struct { - FlagDeclaration *release_config_proto.FlagDeclaration - - // The index of the config directory where this flag was declared. - // Flag values cannot be set in a location with a lower index. - DeclarationIndex int - - Traces []*release_config_proto.Tracepoint - - // Assigned value - Value *release_config_proto.Value -} - -// Key is flag name. -type FlagArtifacts map[string]*FlagArtifact - type ReleaseConfigDirMap map[string]int // The generated release configs. @@ -215,28 +70,27 @@ type ReleaseConfigs struct { ConfigDirIndexes ReleaseConfigDirMap } -func (src *FlagArtifact) Clone() *FlagArtifact { - value := &release_config_proto.Value{} - proto.Merge(value, src.Value) - return &FlagArtifact{ - FlagDeclaration: src.FlagDeclaration, - Traces: src.Traces, - Value: value, +func (configs *ReleaseConfigs) DumpArtifact(outDir string) error { + message := &configs.Artifact + basePath := filepath.Join(outDir, "all_release_configs") + writer := func(suffix string, marshal func() ([]byte, error)) error { + data, err := marshal() + if err != nil { + return err + } + return os.WriteFile(fmt.Sprintf("%s.%s", basePath, suffix), data, 0644) } -} - -func (src FlagArtifacts) Clone() (dst FlagArtifacts) { - if dst == nil { - dst = make(FlagArtifacts) + err := writer("textproto", func() ([]byte, error) { return prototext.MarshalOptions{Multiline: true}.Marshal(message) }) + if err != nil { + return err } - for k, v := range src { - dst[k] = v.Clone() + + err = writer("pb", func() ([]byte, error) { return proto.Marshal(message) }) + if err != nil { + return err } - return -} -func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) { - return &ReleaseConfig{Name: name, DeclarationIndex: index} + return writer("json", func() ([]byte, error) { return json.MarshalIndent(message, "", " ") }) } func ReleaseConfigsFactory() (c *ReleaseConfigs) { @@ -260,19 +114,8 @@ func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) { return m } -func FlagDeclarationFactory(protoPath string) (fd *release_config_proto.FlagDeclaration) { - fd = &release_config_proto.FlagDeclaration{} - if protoPath != "" { - LoadTextproto(protoPath, fd) - } - return fd -} - func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error { m := ReleaseConfigMapFactory(path) - if m.proto.Origin == nil || *m.proto.Origin == "" { - return fmt.Errorf("Release config map %s lacks origin", path) - } if m.proto.DefaultContainer == nil { return fmt.Errorf("Release config map %s lacks default_container", path) } @@ -296,13 +139,13 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex if flagDeclaration.Container == nil { flagDeclaration.Container = m.proto.DefaultContainer } - // TODO: drop flag_declaration.origin from the proto. - if flagDeclaration.Origin == nil { - flagDeclaration.Origin = m.proto.Origin + // TODO: once we have namespaces initialized, we can throw an error here. + if flagDeclaration.Namespace == nil { + flagDeclaration.Namespace = proto.String("android_UNKNOWN") } - // There is always a default value. + // If the input didn't specify a value, create one (== UnspecifiedValue). if flagDeclaration.Value == nil { - flagDeclaration.Value = &release_config_proto.Value{Val: &release_config_proto.Value_UnspecifiedValue{true}} + flagDeclaration.Value = &release_config_proto.Value{Val: &release_config_proto.Value_UnspecifiedValue{false}} } m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration) name := *flagDeclaration.Name @@ -414,7 +257,7 @@ func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error addVar(name, "VALUE", value) addVar(name, "DECLARED_IN", *flag.Traces[0].Source) addVar(name, "SET_IN", *flag.Traces[len(flag.Traces)-1].Source) - addVar(name, "ORIGIN", *decl.Origin) + addVar(name, "NAMESPACE", *decl.Namespace) } pNames := []string{} for k, _ := range partitions { @@ -493,172 +336,14 @@ func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) erro return nil } -func MarshalValue(value *release_config_proto.Value) string { - switch val := value.Val.(type) { - case *release_config_proto.Value_UnspecifiedValue: - // Value was never set. - return "" - case *release_config_proto.Value_StringValue: - return val.StringValue - case *release_config_proto.Value_BoolValue: - if val.BoolValue { - return "true" - } - // False ==> empty string - return "" - case *release_config_proto.Value_Obsolete: - return " #OBSOLETE" - default: - // Flagged as error elsewhere, so return empty string here. - return "" - } -} - -func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error { - name := *flagValue.proto.Name - fa.Traces = append(fa.Traces, &release_config_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value}) - if fa.Value.GetObsolete() { - return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces) - } - switch val := flagValue.proto.Value.Val.(type) { - case *release_config_proto.Value_StringValue: - fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_StringValue{val.StringValue}} - case *release_config_proto.Value_BoolValue: - fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_BoolValue{val.BoolValue}} - case *release_config_proto.Value_Obsolete: - if !val.Obsolete { - return fmt.Errorf("%s: Cannot set obsolete=false. Trace=%v", name, fa.Traces) - } - fa.Value = &release_config_proto.Value{Val: &release_config_proto.Value_Obsolete{true}} - default: - return fmt.Errorf("Invalid type for flag_value: %T. Trace=%v", val, fa.Traces) - } - return nil -} - -func (fa *FlagArtifact) Marshal() (*release_config_proto.FlagArtifact, error) { - return &release_config_proto.FlagArtifact{ - FlagDeclaration: fa.FlagDeclaration, - Value: fa.Value, - Traces: fa.Traces, - }, nil -} - -func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error { - if config.ReleaseConfigArtifact != nil { - return nil - } - if config.compileInProgress { - return fmt.Errorf("Loop detected for release config %s", config.Name) - } - config.compileInProgress = true - - // Generate any configs we need to inherit. This will detect loops in - // the config. - contributionsToApply := []*ReleaseConfigContribution{} - myInherits := []string{} - myInheritsSet := make(map[string]bool) - for _, inherit := range config.InheritNames { - if _, ok := myInheritsSet[inherit]; ok { - continue - } - myInherits = append(myInherits, inherit) - myInheritsSet[inherit] = true - iConfig, err := configs.GetReleaseConfig(inherit) - if err != nil { - return err - } - iConfig.GenerateReleaseConfig(configs) - contributionsToApply = append(contributionsToApply, iConfig.Contributions...) - } - contributionsToApply = append(contributionsToApply, config.Contributions...) - - myAconfigValueSets := []string{} - myFlags := configs.FlagArtifacts.Clone() - myDirsMap := make(map[int]bool) - for _, contrib := range contributionsToApply { - myAconfigValueSets = append(myAconfigValueSets, contrib.proto.AconfigValueSets...) - myDirsMap[contrib.DeclarationIndex] = true - for _, value := range contrib.FlagValues { - fa, ok := myFlags[*value.proto.Name] - if !ok { - return fmt.Errorf("Setting value for undefined flag %s in %s\n", *value.proto.Name, value.path) - } - myDirsMap[fa.DeclarationIndex] = true - if fa.DeclarationIndex > contrib.DeclarationIndex { - // Setting location is to the left of declaration. - return fmt.Errorf("Setting value for flag %s not allowed in %s\n", *value.proto.Name, value.path) - } - if err := fa.UpdateValue(*value); err != nil { - return err - } - } - } - - directories := []string{} - for idx, confDir := range configs.ConfigDirs { - if _, ok := myDirsMap[idx]; ok { - directories = append(directories, confDir) - } - } - - config.FlagArtifacts = myFlags - config.ReleaseConfigArtifact = &release_config_proto.ReleaseConfigArtifact{ - Name: proto.String(config.Name), - OtherNames: config.OtherNames, - FlagArtifacts: func() []*release_config_proto.FlagArtifact { - ret := []*release_config_proto.FlagArtifact{} - for _, flag := range myFlags { - ret = append(ret, &release_config_proto.FlagArtifact{ - FlagDeclaration: flag.FlagDeclaration, - Traces: flag.Traces, - Value: flag.Value, - }) - } - return ret - }(), - AconfigValueSets: myAconfigValueSets, - Inherits: myInherits, - Directories: directories, - } - - config.compileInProgress = false - return nil -} - -func main() { - var targetRelease string - var outputDir string - - outEnv := os.Getenv("OUT_DIR") - if outEnv == "" { - outEnv = "out" - } - defaultOutputDir := filepath.Join(outEnv, "soong", "release-config") - var defaultMapPaths StringList - defaultLocations := StringList{ - "build/release/release_config_map.textproto", - "vendor/google_shared/build/release/release_config_map.textproto", - "vendor/google/release/release_config_map.textproto", - } - for _, path := range defaultLocations { - if _, err := os.Stat(path); err == nil { - defaultMapPaths = append(defaultMapPaths, path) - } - } - prodMaps := os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS") - if prodMaps != "" { - defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...) - } - - flag.BoolVar(&verboseFlag, "debug", false, "print debugging information") - flag.Var(&releaseConfigMapPaths, "map", "path to a release_config_map.textproto. may be repeated") - flag.StringVar(&targetRelease, "release", "trunk_staging", "TARGET_RELEASE for this build") - flag.StringVar(&outputDir, "out_dir", defaultOutputDir, "basepath for the output. Multiple formats are created") - flag.Parse() +func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string) (*ReleaseConfigs, error) { + var err error if len(releaseConfigMapPaths) == 0 { - releaseConfigMapPaths = defaultMapPaths + releaseConfigMapPaths = GetDefaultMapPaths() + if len(releaseConfigMapPaths) == 0 { + return nil, fmt.Errorf("No maps found") + } fmt.Printf("No --map argument provided. Using: --map %s\n", strings.Join(releaseConfigMapPaths, " --map ")) } @@ -668,24 +353,13 @@ func main() { configDir := filepath.Dir(releaseConfigMapPath) configs.ConfigDirIndexes[configDir] = idx configs.ConfigDirs = append(configs.ConfigDirs, configDir) - err := configs.LoadReleaseConfigMap(releaseConfigMapPath, idx) + err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx) if err != nil { - panic(err) + return nil, err } } // Now that we have all of the release config maps, can meld them and generate the artifacts. - err := configs.GenerateReleaseConfigs(targetRelease) - if err != nil { - panic(err) - } - err = os.MkdirAll(outputDir, 0775) - if err != nil { - panic(err) - } - err = configs.DumpMakefile(outputDir, targetRelease) - if err != nil { - panic(err) - } - DumpProtos(outputDir, &configs.Artifact) + err = configs.GenerateReleaseConfigs(targetRelease) + return configs, err } diff --git a/cmd/release_config/release_config_lib/util.go b/cmd/release_config/release_config_lib/util.go new file mode 100644 index 000000000..c59deb337 --- /dev/null +++ b/cmd/release_config/release_config_lib/util.go @@ -0,0 +1,90 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" + + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" +) + +type StringList []string + +func (l *StringList) Set(v string) error { + *l = append(*l, v) + return nil +} + +func (l *StringList) String() string { + return fmt.Sprintf("%v", *l) +} + +func LoadTextproto(path string, message proto.Message) error { + data, err := os.ReadFile(path) + if err != nil { + return err + } + ret := prototext.Unmarshal(data, message) + return ret +} + +func WalkTextprotoFiles(root string, subdir string, Func fs.WalkDirFunc) error { + path := filepath.Join(root, subdir) + if _, err := os.Stat(path); err != nil { + // Missing subdirs are not an error. + return nil + } + return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if strings.HasSuffix(d.Name(), ".textproto") && d.Type().IsRegular() { + return Func(path, d, err) + } + return nil + }) +} + +func GetDefaultOutDir() string { + outEnv := os.Getenv("OUT_DIR") + if outEnv == "" { + outEnv = "out" + } + return filepath.Join(outEnv, "soong", "release-config") +} + +func GetDefaultMapPaths() StringList { + var defaultMapPaths StringList + defaultLocations := StringList{ + "build/release/release_config_map.textproto", + "vendor/google_shared/build/release/release_config_map.textproto", + "vendor/google/release/release_config_map.textproto", + } + for _, path := range defaultLocations { + if _, err := os.Stat(path); err == nil { + defaultMapPaths = append(defaultMapPaths, path) + } + } + prodMaps := os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS") + if prodMaps != "" { + defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...) + } + return defaultMapPaths +} diff --git a/cmd/release_config/release_config_proto/Android.bp b/cmd/release_config/release_config_proto/Android.bp index a8660c753..5a6aeab54 100644 --- a/cmd/release_config/release_config_proto/Android.bp +++ b/cmd/release_config/release_config_proto/Android.bp @@ -17,7 +17,7 @@ package { } bootstrap_go_package { - name: "soong-release_config_proto", + name: "soong-cmd-release_config-proto", pkgPath: "android/soong/release_config/release_config_proto", deps: [ "golang-protobuf-reflect-protoreflect", diff --git a/cmd/release_config/release_config_proto/build_flags_src.pb.go b/cmd/release_config/release_config_proto/build_flags_src.pb.go index 0f2c30b76..ccf3b3f14 100644 --- a/cmd/release_config/release_config_proto/build_flags_src.pb.go +++ b/cmd/release_config/release_config_proto/build_flags_src.pb.go @@ -287,6 +287,9 @@ type FlagDeclaration struct { // The name of the flag. // See # name for format detail Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Namespace the flag belongs to (required) + // See # namespace for format detail + Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` // Text description of the flag's purpose. Description *string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` // Value for the flag @@ -296,9 +299,6 @@ type FlagDeclaration struct { // The container for this flag. This overrides any default container given // in the release_config_map message. Container *Container `protobuf:"varint,206,opt,name=container,enum=android.release_config_proto.Container" json:"container,omitempty"` - // Temporarily allow origin at the flag declaration level while we - // move flags to their own locations. - Origin *string `protobuf:"bytes,208,opt,name=origin" json:"origin,omitempty"` } func (x *FlagDeclaration) Reset() { @@ -340,6 +340,13 @@ func (x *FlagDeclaration) GetName() string { return "" } +func (x *FlagDeclaration) GetNamespace() string { + if x != nil && x.Namespace != nil { + return *x.Namespace + } + return "" +} + func (x *FlagDeclaration) GetDescription() string { if x != nil && x.Description != nil { return *x.Description @@ -368,13 +375,6 @@ func (x *FlagDeclaration) GetContainer() Container { return Container_UNSPECIFIED_container } -func (x *FlagDeclaration) GetOrigin() string { - if x != nil && x.Origin != nil { - return *x.Origin - } - return "" -} - type FlagValue struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -568,8 +568,6 @@ type ReleaseConfigMap struct { // Any aliases. Aliases []*ReleaseAlias `protobuf:"bytes,1,rep,name=aliases" json:"aliases,omitempty"` - // The origin for flags declared here. - Origin *string `protobuf:"bytes,2,opt,name=origin" json:"origin,omitempty"` // The default container for flags declared here. DefaultContainer *Container `protobuf:"varint,3,opt,name=default_container,json=defaultContainer,enum=android.release_config_proto.Container" json:"default_container,omitempty"` } @@ -613,13 +611,6 @@ func (x *ReleaseConfigMap) GetAliases() []*ReleaseAlias { return nil } -func (x *ReleaseConfigMap) GetOrigin() string { - if x != nil && x.Origin != nil { - return *x.Origin - } - return "" -} - func (x *ReleaseConfigMap) GetDefaultContainer() Container { if x != nil && x.DefaultContainer != nil { return *x.DefaultContainer @@ -643,71 +634,70 @@ var file_build_flags_src_proto_rawDesc = []byte{ 0x6c, 0x75, 0x65, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x08, 0x6f, 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x18, 0xcb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x62, - 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0xb8, 0x02, + 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0xbd, 0x02, 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, - 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x18, 0xcd, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, - 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, - 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x46, 0x0a, 0x09, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0xce, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, - 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x12, 0x17, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0xd0, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, - 0x4a, 0x06, 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x5c, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x67, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6e, 0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, - 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x53, 0x65, 0x74, 0x73, 0x22, 0x3b, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x22, 0xc9, 0x01, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x12, 0x45, 0x0a, 0x07, 0x61, 0x6c, - 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0xcd, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x08, 0x77, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x46, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x18, 0xce, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, - 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, 0x54, 0x0a, 0x11, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, + 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4a, + 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x06, 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x5c, 0x0a, + 0x0a, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6e, 0x0a, 0x0e, 0x72, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x2c, 0x0a, + 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, + 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, 0x74, 0x73, 0x22, 0x3b, 0x0a, 0x0d, 0x72, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xb1, 0x01, 0x0a, 0x12, 0x72, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x12, + 0x45, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, + 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x54, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x27, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x10, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2a, 0x4a, 0x0a, 0x08, + 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c, + 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, + 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x2a, 0x64, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x10, 0x00, + 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x4f, + 0x44, 0x55, 0x43, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, + 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x5f, 0x45, 0x58, 0x54, + 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x56, 0x45, 0x4e, 0x44, 0x4f, 0x52, 0x10, 0x05, 0x42, 0x33, + 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x10, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2a, - 0x4a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, - 0x6c, 0x6f, 0x77, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10, - 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x10, 0x02, 0x12, - 0x0a, 0x0a, 0x06, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x2a, 0x64, 0x0a, 0x09, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, - 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x59, 0x53, - 0x54, 0x45, 0x4d, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x5f, - 0x45, 0x58, 0x54, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x56, 0x45, 0x4e, 0x44, 0x4f, 0x52, 0x10, - 0x05, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, - 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x6f, 0x74, 0x6f, } var ( diff --git a/cmd/release_config/release_config_proto/build_flags_src.proto b/cmd/release_config/release_config_proto/build_flags_src.proto index 0662716d5..85015248e 100644 --- a/cmd/release_config/release_config_proto/build_flags_src.proto +++ b/cmd/release_config/release_config_proto/build_flags_src.proto @@ -26,6 +26,11 @@ option go_package = "android/soong/release_config/release_config_proto"; // RELEASE_MY_PACKAGE_FLAG is a valid name, while MY_PACKAGE_FLAG, and // RELEASE_MY_PACKAGE__FLAG are invalid. // +// # namespace: namespace the flag belongs to +// +// format: a lowercase string in snake_case format, no consecutive underscores, and no leading +// digit. For example android_bar_system +// // # package: package to which the flag belongs // // format: lowercase strings in snake_case format, delimited by dots, no @@ -77,6 +82,10 @@ message flag_declaration { // See # name for format detail optional string name = 1; + // Namespace the flag belongs to (required) + // See # namespace for format detail + optional string namespace = 2; + // Text description of the flag's purpose. optional string description = 3; @@ -96,12 +105,6 @@ message flag_declaration { // The package associated with this flag. // (when Gantry is ready for it) optional string package = 207; reserved 207; - - // Temporarily allow origin at the flag declaration level while we - // move flags to their own locations. - optional string origin = 208; - - // TODO: do we want to include "first used in" (= ap2a)? } message flag_value { @@ -141,9 +144,6 @@ message release_config_map { // Any aliases. repeated release_alias aliases = 1; - // The origin for flags declared here. - optional string origin = 2; - // The default container for flags declared here. optional container default_container = 3; diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go index 57c7ae851..af1d33da6 100644 --- a/dexpreopt/class_loader_context.go +++ b/dexpreopt/class_loader_context.go @@ -323,6 +323,7 @@ func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathCont } else if clc.Host == hostPath && clc.Device == devicePath { // Ok, the same library with the same paths. Don't re-add it, but don't raise an error // either, as the same library may be reachable via different transitional dependencies. + clc.Optional = clc.Optional && optional return nil } else { // Fail, as someone is trying to add the same library with different paths. This likely diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index f4ecad46c..3a5071d34 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -84,12 +84,21 @@ func TestFileSystemDeps(t *testing.T) { cc_library { name: "libbar", required: ["libbaz"], + target: { + platform: { + required: ["lib_platform_only"], + }, + }, } cc_library { name: "libbaz", } + cc_library { + name: "lib_platform_only", + } + phony { name: "phony", required: [ @@ -120,6 +129,7 @@ func TestFileSystemDeps(t *testing.T) { "lib64/libbar.so", "lib64/libbaz.so", "lib64/libquz.so", + "lib64/lib_platform_only.so", "etc/bpf/bpf.o", } for _, e := range expected { diff --git a/java/aar.go b/java/aar.go index fef0d8c58..f8955ce90 100644 --- a/java/aar.go +++ b/java/aar.go @@ -356,12 +356,13 @@ type aaptBuildActionOptions struct { forceNonFinalResourceIDs bool extraLinkFlags []string aconfigTextFiles android.Paths + usesLibrary *usesLibrary } func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptions) { staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedExportPackages, libFlags := - aaptLibs(ctx, opts.sdkContext, opts.classLoaderContexts) + aaptLibs(ctx, opts.sdkContext, opts.classLoaderContexts, opts.usesLibrary) // Exclude any libraries from the supplied list. opts.classLoaderContexts = opts.classLoaderContexts.ExcludeLibs(opts.excludedLibs) @@ -703,7 +704,8 @@ func (t transitiveAarDeps) assets() android.Paths { } // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths -func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) ( +func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, + classLoaderContexts dexpreopt.ClassLoaderContextMap, usesLibrary *usesLibrary) ( staticResourcesNodes, sharedResourcesNodes *android.DepSet[*resourcesNode], staticRRODirs *android.DepSet[rroDir], staticManifests *android.DepSet[android.Path], sharedLibs android.Paths, flags []string) { @@ -753,6 +755,9 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoa } addCLCFromDep(ctx, module, classLoaderContexts) + if usesLibrary != nil { + addMissingOptionalUsesLibsFromDep(ctx, module, usesLibrary) + } }) // AAPT2 overlays are in lowest to highest priority order, the topological order will be reversed later. @@ -805,12 +810,12 @@ func (a *AndroidLibrary) OutputFiles(tag string) (android.Paths, error) { var _ AndroidLibraryDependency = (*AndroidLibrary)(nil) func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { + a.usesLibrary.deps(ctx, false) a.Module.deps(ctx) sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) if sdkDep.hasFrameworkLibs() { a.aapt.deps(ctx, sdkDep) } - a.usesLibrary.deps(ctx, false) for _, aconfig_declaration := range a.aaptProperties.Flags_packages { ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration) @@ -829,6 +834,7 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) classLoaderContexts: a.classLoaderContexts, enforceDefaultTargetSdkVersion: false, aconfigTextFiles: getAconfigFilePaths(ctx), + usesLibrary: &a.usesLibrary, }, ) @@ -922,7 +928,8 @@ func AndroidLibraryFactory() android.Module { module.Module.addHostAndDeviceProperties() module.AddProperties( &module.aaptProperties, - &module.androidLibraryProperties) + &module.androidLibraryProperties, + &module.sourceProperties) module.androidLibraryProperties.BuildAAR = true module.Module.linter.library = true @@ -978,6 +985,7 @@ type AARImport struct { headerJarFile android.WritablePath implementationJarFile android.WritablePath + implementationAndResourcesJarFile android.WritablePath proguardFlags android.WritablePath exportPackage android.WritablePath transitiveAaptResourcePackagesFile android.Path @@ -1013,7 +1021,7 @@ func (a *AARImport) OutputFiles(tag string) (android.Paths, error) { case ".aar": return []android.Path{a.aarPath}, nil case "": - return []android.Path{a.implementationJarFile}, nil + return []android.Path{a.implementationAndResourcesJarFile}, nil default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } @@ -1155,8 +1163,9 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { TransformJetifier(ctx, a.aarPath.(android.WritablePath), inputFile) } + jarName := ctx.ModuleName() + ".jar" extractedAARDir := android.PathForModuleOut(ctx, "aar") - classpathFile := extractedAARDir.Join(ctx, ctx.ModuleName()+".jar") + classpathFile := extractedAARDir.Join(ctx, jarName) a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml") a.rTxt = extractedAARDir.Join(ctx, "R.txt") a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip") @@ -1212,7 +1221,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { linkDeps = append(linkDeps, a.manifest) staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags := - aaptLibs(ctx, android.SdkContext(a), nil) + aaptLibs(ctx, android.SdkContext(a), nil, nil) _ = sharedResourcesNodesDepSet _ = staticRRODirsDepSet @@ -1272,6 +1281,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { var staticJars android.Paths var staticHeaderJars android.Paths + var staticResourceJars android.Paths ctx.VisitDirectDeps(func(module android.Module) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { tag := ctx.OtherModuleDependencyTag(module) @@ -1279,26 +1289,49 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { case staticLibTag: staticJars = append(staticJars, dep.ImplementationJars...) staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...) + staticResourceJars = append(staticResourceJars, dep.ResourceJars...) } } addCLCFromDep(ctx, module, a.classLoaderContexts) + addMissingOptionalUsesLibsFromDep(ctx, module, &a.usesLibrary) }) var implementationJarFile android.OutputPath if len(staticJars) > 0 { combineJars := append(android.Paths{classpathFile}, staticJars...) - implementationJarFile = android.PathForModuleOut(ctx, "combined", ctx.ModuleName()+".jar").OutputPath + implementationJarFile = android.PathForModuleOut(ctx, "combined", jarName).OutputPath TransformJarsToJar(ctx, implementationJarFile, "combine", combineJars, android.OptionalPath{}, false, nil, nil) } else { implementationJarFile = classpathFile } + var resourceJarFile android.Path + if len(staticResourceJars) > 1 { + combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName) + TransformJarsToJar(ctx, combinedJar, "for resources", staticResourceJars, android.OptionalPath{}, + false, nil, nil) + resourceJarFile = combinedJar + } else if len(staticResourceJars) == 1 { + resourceJarFile = staticResourceJars[0] + } + + // merge implementation jar with resources if necessary + implementationAndResourcesJar := implementationJarFile + if resourceJarFile != nil { + jars := android.Paths{resourceJarFile, implementationAndResourcesJar} + combinedJar := android.PathForModuleOut(ctx, "withres", jarName).OutputPath + TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{}, + false, nil, nil) + implementationAndResourcesJar = combinedJar + } + + a.implementationJarFile = implementationJarFile // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource - a.implementationJarFile = implementationJarFile.WithoutRel() + a.implementationAndResourcesJarFile = implementationAndResourcesJar.WithoutRel() if len(staticHeaderJars) > 0 { combineJars := append(android.Paths{classpathFile}, staticHeaderJars...) - a.headerJarFile = android.PathForModuleOut(ctx, "turbine-combined", ctx.ModuleName()+".jar") + a.headerJarFile = android.PathForModuleOut(ctx, "turbine-combined", jarName) TransformJarsToJar(ctx, a.headerJarFile, "combine header jars", combineJars, android.OptionalPath{}, false, nil, nil) } else { a.headerJarFile = classpathFile @@ -1306,9 +1339,10 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { android.SetProvider(ctx, JavaInfoProvider, JavaInfo{ HeaderJars: android.PathsIfNonNil(a.headerJarFile), + ResourceJars: android.PathsIfNonNil(resourceJarFile), TransitiveLibsHeaderJars: a.transitiveLibsHeaderJars, TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars, - ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationJarFile), + ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile), ImplementationJars: android.PathsIfNonNil(a.implementationJarFile), StubsLinkType: Implementation, // TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts @@ -1346,7 +1380,7 @@ func (a *AARImport) HeaderJars() android.Paths { } func (a *AARImport) ImplementationAndResourcesJars() android.Paths { - return android.Paths{a.implementationJarFile} + return android.Paths{a.implementationAndResourcesJarFile} } func (a *AARImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { @@ -1378,6 +1412,12 @@ func (a *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, var _ android.PrebuiltInterface = (*AARImport)(nil) +func (a *AARImport) UsesLibrary() *usesLibrary { + return &a.usesLibrary +} + +var _ ModuleWithUsesLibrary = (*AARImport)(nil) + // android_library_import imports an `.aar` file into the build graph as if it was built with android_library. // // This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of diff --git a/java/aar_test.go b/java/aar_test.go index 3361bf929..d6dbe3c25 100644 --- a/java/aar_test.go +++ b/java/aar_test.go @@ -136,18 +136,19 @@ func TestAndroidLibraryOutputFilesRel(t *testing.T) { android_library { name: "foo", srcs: ["a.java"], + java_resources: ["foo.txt"], } android_library_import { name: "bar", - aars: ["bar.aar"], + aars: ["bar_prebuilt.aar"], } android_library_import { name: "baz", - aars: ["baz.aar"], - static_libs: ["bar"], + aars: ["baz_prebuilt.aar"], + static_libs: ["foo", "bar"], } `) @@ -160,11 +161,11 @@ func TestAndroidLibraryOutputFilesRel(t *testing.T) { bazOutputPath := android.OutputFileForModule(android.PathContext(nil), baz.Module(), "") android.AssertPathRelativeToTopEquals(t, "foo output path", - "out/soong/.intermediates/foo/android_common/javac/foo.jar", fooOutputPath) + "out/soong/.intermediates/foo/android_common/withres/foo.jar", fooOutputPath) android.AssertPathRelativeToTopEquals(t, "bar output path", "out/soong/.intermediates/bar/android_common/aar/bar.jar", barOutputPath) android.AssertPathRelativeToTopEquals(t, "baz output path", - "out/soong/.intermediates/baz/android_common/combined/baz.jar", bazOutputPath) + "out/soong/.intermediates/baz/android_common/withres/baz.jar", bazOutputPath) android.AssertStringEquals(t, "foo relative output path", "foo.jar", fooOutputPath.Rel()) diff --git a/java/app.go b/java/app.go index 7b2577538..50d1a2f43 100755..100644 --- a/java/app.go +++ b/java/app.go @@ -249,13 +249,13 @@ func (c Certificate) AndroidMkString() string { } func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { - a.Module.deps(ctx) - if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion(ctx).Specified() { ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared") } sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) + a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs()) + a.Module.deps(ctx) if sdkDep.hasFrameworkLibs() { a.aapt.deps(ctx, sdkDep) } @@ -285,9 +285,6 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { } ctx.AddFarVariationDependencies(variation, jniLibTag, a.appProperties.Jni_libs...) } - - a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs()) - for _, aconfig_declaration := range a.aaptProperties.Flags_packages { ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration) } @@ -329,6 +326,10 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon a.aapt.manifestValues.applicationId = *applicationId } a.generateAndroidBuildActions(ctx) + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + }) + } func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -530,6 +531,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { forceNonFinalResourceIDs: nonFinalIds, extraLinkFlags: aaptLinkFlags, aconfigTextFiles: getAconfigFilePaths(ctx), + usesLibrary: &a.usesLibrary, }, ) @@ -811,18 +813,10 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries. a.usesLibrary.freezeEnforceUsesLibraries() - // Add implicit SDK libraries to <uses-library> list. - requiredUsesLibs, optionalUsesLibs := a.classLoaderContexts.UsesLibs() - for _, usesLib := range requiredUsesLibs { - a.usesLibrary.addLib(usesLib, false) - } - for _, usesLib := range optionalUsesLibs { - a.usesLibrary.addLib(usesLib, true) - } - // Check that the <uses-library> list is coherent with the manifest. if a.usesLibrary.enforceUsesLibraries() { - manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile) + manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest( + ctx, a.mergedManifestFile, &a.classLoaderContexts) apkDeps = append(apkDeps, manifestCheckFile) } @@ -1191,7 +1185,8 @@ func AndroidAppFactory() android.Module { module.AddProperties( &module.aaptProperties, &module.appProperties, - &module.overridableAppProperties) + &module.overridableAppProperties, + &module.Library.sourceProperties) module.usesLibrary.enforce = true @@ -1340,6 +1335,11 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { TestSuites: a.testProperties.Test_suites, IsHost: false, }) + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + TopLevelTarget: true, + }) + } func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path { @@ -1532,9 +1532,13 @@ type OverrideAndroidTest struct { android.OverrideModuleBase } -func (i *OverrideAndroidTest) GenerateAndroidBuildActions(_ android.ModuleContext) { +func (i *OverrideAndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { // All the overrides happen in the base module. // TODO(jungjw): Check the base module type. + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + TopLevelTarget: true, + }) } // override_android_test is used to create an android_app module based on another android_test by overriding @@ -1582,6 +1586,9 @@ type UsesLibraryProperties struct { // provide the android.test.base statically and use jarjar to rename them so they do not collide // with the classes provided by the android.test.base library. Exclude_uses_libs []string + + // The module names of optional uses-library libraries that are missing from the source tree. + Missing_optional_uses_libs []string `blueprint:"mutated"` } // usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the @@ -1598,20 +1605,11 @@ type usesLibrary struct { shouldDisableDexpreopt bool } -func (u *usesLibrary) addLib(lib string, optional bool) { - if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) { - if optional { - u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib) - } else { - u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib) - } - } -} - func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps bool) { if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() { ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs...) - ctx.AddVariationDependencies(nil, usesLibOptTag, u.presentOptionalUsesLibs(ctx)...) + presentOptionalUsesLibs := u.presentOptionalUsesLibs(ctx) + ctx.AddVariationDependencies(nil, usesLibOptTag, presentOptionalUsesLibs...) // Only add these extra dependencies if the module is an app that depends on framework // libs. This avoids creating a cyclic dependency: // e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res. @@ -1622,6 +1620,8 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps boo ctx.AddVariationDependencies(nil, usesLibCompat28OptTag, dexpreopt.OptionalCompatUsesLibs28...) ctx.AddVariationDependencies(nil, usesLibCompat30OptTag, dexpreopt.OptionalCompatUsesLibs30...) } + _, diff, _ := android.ListSetDifference(u.usesLibraryProperties.Optional_uses_libs, presentOptionalUsesLibs) + u.usesLibraryProperties.Missing_optional_uses_libs = diff } else { ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.usesLibraryProperties.Uses_libs...) ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.presentOptionalUsesLibs(ctx)...) @@ -1640,15 +1640,6 @@ func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []s return optionalUsesLibs } -// Helper function to replace string in a list. -func replaceInList(list []string, oldstr, newstr string) { - for i, str := range list { - if str == oldstr { - list[i] = newstr - } - } -} - // Returns a map of module names of shared library dependencies to the paths to their dex jars on // host and on device. func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext) dexpreopt.ClassLoaderContextMap { @@ -1690,11 +1681,6 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext libName := dep if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil { libName = *ulib.ProvidesUsesLib() - // Replace module name with library name in `uses_libs`/`optional_uses_libs` in - // order to pass verify_uses_libraries check (which compares these properties - // against library names written in the manifest). - replaceInList(u.usesLibraryProperties.Uses_libs, dep, libName) - replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName) } clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional, lib.DexJarBuildPath(ctx).PathOrNil(), lib.DexJarInstallPath(), @@ -1728,7 +1714,7 @@ func (u *usesLibrary) freezeEnforceUsesLibraries() { // an APK with the manifest embedded in it (manifest_check will know which one it is by the file // extension: APKs are supposed to end with '.apk'). func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile android.Path, - outputFile android.WritablePath) android.Path { + outputFile android.WritablePath, classLoaderContexts *dexpreopt.ClassLoaderContextMap) android.Path { statusFile := dexpreopt.UsesLibrariesStatusFile(ctx) @@ -1756,27 +1742,37 @@ func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile a cmd.Flag("--enforce-uses-libraries-relax") } - for _, lib := range u.usesLibraryProperties.Uses_libs { + requiredUsesLibs, optionalUsesLibs := classLoaderContexts.UsesLibs() + for _, lib := range requiredUsesLibs { cmd.FlagWithArg("--uses-library ", lib) } - - for _, lib := range u.usesLibraryProperties.Optional_uses_libs { + for _, lib := range optionalUsesLibs { cmd.FlagWithArg("--optional-uses-library ", lib) } + // Also add missing optional uses libs, as the manifest check expects them. + // Note that what we add here are the module names of those missing libs, not library names, while + // the manifest check actually expects library names. However, the case where a library is missing + // and the module name != the library name is too rare for us to handle. + for _, lib := range u.usesLibraryProperties.Missing_optional_uses_libs { + cmd.FlagWithArg("--missing-optional-uses-library ", lib) + } + rule.Build("verify_uses_libraries", "verify <uses-library>") return outputFile } // verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against // the build system and returns the path to a copy of the manifest. -func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path { +func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path, + classLoaderContexts *dexpreopt.ClassLoaderContextMap) android.Path { outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml") - return u.verifyUsesLibraries(ctx, manifest, outputFile) + return u.verifyUsesLibraries(ctx, manifest, outputFile, classLoaderContexts) } // verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the build // system and returns the path to a copy of the APK. -func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) { - u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file +func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path, + classLoaderContexts *dexpreopt.ClassLoaderContextMap) { + u.verifyUsesLibraries(ctx, apk, nil, classLoaderContexts) // for APKs manifest_check does not write output file } diff --git a/java/app_import.go b/java/app_import.go index 7387e168c..bb07c423a 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -355,7 +355,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext } if a.usesLibrary.enforceUsesLibraries() { - a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk) + a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk, &a.dexpreopter.classLoaderContexts) } a.dexpreopter.dexpreopt(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), jnisUncompressed) @@ -611,6 +611,12 @@ func createArchDpiVariantGroupType(archNames []string, dpiNames []string) reflec return return_struct } +func (a *AndroidAppImport) UsesLibrary() *usesLibrary { + return &a.usesLibrary +} + +var _ ModuleWithUsesLibrary = (*AndroidAppImport)(nil) + // android_app_import imports a prebuilt apk with additional processing specified in the module. // DPI-specific apk source files can be specified using dpi_variants. Example: // diff --git a/java/app_test.go b/java/app_test.go index 8262777b2..eab40e7da 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -3244,7 +3244,10 @@ func TestUsesLibraries(t *testing.T) { name: "static-y", srcs: ["a.java"], uses_libs: ["runtime-required-y"], - optional_uses_libs: ["runtime-optional-y"], + optional_uses_libs: [ + "runtime-optional-y", + "missing-lib-a", + ], sdk_version: "current", } @@ -3280,7 +3283,7 @@ func TestUsesLibraries(t *testing.T) { sdk_version: "current", optional_uses_libs: [ "bar", - "baz", + "missing-lib-b", ], } @@ -3295,7 +3298,7 @@ func TestUsesLibraries(t *testing.T) { ], optional_uses_libs: [ "bar", - "baz", + "missing-lib-b", ], } ` @@ -3317,10 +3320,10 @@ func TestUsesLibraries(t *testing.T) { // propagated from dependencies. actualManifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"] expectManifestFixerArgs := `--extract-native-libs=true ` + - `--uses-library qux ` + - `--uses-library quuz ` + `--uses-library foo ` + `--uses-library com.non.sdk.lib ` + + `--uses-library qux ` + + `--uses-library quuz ` + `--uses-library runtime-library ` + `--uses-library runtime-required-x ` + `--uses-library runtime-required-y ` + @@ -3339,9 +3342,10 @@ func TestUsesLibraries(t *testing.T) { `--uses-library runtime-required-x ` + `--uses-library runtime-required-y ` + `--optional-uses-library bar ` + - `--optional-uses-library baz ` + `--optional-uses-library runtime-optional-x ` + - `--optional-uses-library runtime-optional-y ` + `--optional-uses-library runtime-optional-y ` + + `--missing-optional-uses-library missing-lib-b ` + + `--missing-optional-uses-library missing-lib-a` android.AssertStringDoesContain(t, "verify cmd args", verifyCmd, verifyArgs) // Test that all libraries are verified for an APK (library order matters). @@ -3350,7 +3354,7 @@ func TestUsesLibraries(t *testing.T) { `--uses-library com.non.sdk.lib ` + `--uses-library android.test.runner ` + `--optional-uses-library bar ` + - `--optional-uses-library baz ` + `--missing-optional-uses-library missing-lib-b ` android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs) // Test that necessary args are passed for constructing CLC in Ninja phase. @@ -4432,6 +4436,44 @@ func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) { android.AssertBoolEquals(t, "dexpreopt should be disabled if optional_uses_libs does not have an implementation", true, dexpreopt == nil) } +func TestTestOnlyApp(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + ).RunTestWithBp(t, ` + // These should be test-only + android_test { + name: "android-test", + } + android_test_helper_app { + name: "helper-app", + } + override_android_test { + name: "override-test", + base: "android-app", + } + // And these should not be + android_app { + name: "android-app", + srcs: ["b.java"], + sdk_version: "current", + } + `) + + expectedTestOnly := []string{ + "android-test", + "helper-app", + "override-test", + } + + expectedTopLevel := []string{ + "android-test", + "override-test", + } + + assertTestOnlyAndTopLevel(t, ctx, expectedTestOnly, expectedTopLevel) +} + func TestAppStem(t *testing.T) { ctx := testApp(t, ` android_app { diff --git a/java/base.go b/java/base.go index 391ba8355..938ac5e82 100644 --- a/java/base.go +++ b/java/base.go @@ -435,6 +435,7 @@ type Module struct { deviceProperties DeviceProperties overridableProperties OverridableProperties + sourceProperties android.SourceProperties // jar file containing header classes including static library dependencies, suitable for // inserting into the bootclasspath/classpath of another compile @@ -842,9 +843,11 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { if dep != nil { if component, ok := dep.(SdkLibraryComponentDependency); ok { if lib := component.OptionalSdkLibraryImplementation(); lib != nil { - // Add library as optional if it's one of the optional compatibility libs. + // Add library as optional if it's one of the optional compatibility libs or it's + // explicitly listed in the optional_uses_libs property. tag := usesLibReqTag - if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) { + if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) || + android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs) { tag = usesLibOptTag } ctx.AddVariationDependencies(nil, tag, *lib) @@ -2386,6 +2389,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } addCLCFromDep(ctx, module, j.classLoaderContexts) + addMissingOptionalUsesLibsFromDep(ctx, module, &j.usesLibrary) }) return deps @@ -2719,3 +2723,13 @@ type ModuleWithStem interface { } var _ ModuleWithStem = (*Module)(nil) + +type ModuleWithUsesLibrary interface { + UsesLibrary() *usesLibrary +} + +func (j *Module) UsesLibrary() *usesLibrary { + return &j.usesLibrary +} + +var _ ModuleWithUsesLibrary = (*Module)(nil) diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go index 3413da03d..6ccc5c1b1 100644 --- a/java/device_host_converter_test.go +++ b/java/device_host_converter_test.go @@ -16,7 +16,7 @@ package java import ( "android/soong/android" - "reflect" + "slices" "strings" "testing" ) @@ -84,7 +84,7 @@ func TestDeviceForHost(t *testing.T) { deviceImportCombined.Output, } - if !reflect.DeepEqual(combined.Inputs, expectedInputs) { + if !slices.Equal(combined.Inputs.Strings(), expectedInputs.Strings()) { t.Errorf("expected host_module combined inputs:\n%q\ngot:\n%q", expectedInputs, combined.Inputs) } @@ -95,7 +95,7 @@ func TestDeviceForHost(t *testing.T) { deviceRes.Output, } - if !reflect.DeepEqual(resCombined.Inputs, expectedInputs) { + if !slices.Equal(resCombined.Inputs.Strings(), expectedInputs.Strings()) { t.Errorf("expected host_module res combined inputs:\n%q\ngot:\n%q", expectedInputs, resCombined.Inputs) } @@ -165,7 +165,7 @@ func TestHostForDevice(t *testing.T) { hostImportCombined.Output, } - if !reflect.DeepEqual(combined.Inputs, expectedInputs) { + if !slices.Equal(combined.Inputs.Strings(), expectedInputs.Strings()) { t.Errorf("expected device_module combined inputs:\n%q\ngot:\n%q", expectedInputs, combined.Inputs) } @@ -176,7 +176,7 @@ func TestHostForDevice(t *testing.T) { hostRes.Output, } - if !reflect.DeepEqual(resCombined.Inputs, expectedInputs) { + if !slices.Equal(resCombined.Inputs.Strings(), expectedInputs.Strings()) { t.Errorf("expected device_module res combined inputs:\n%q\ngot:\n%q", expectedInputs, resCombined.Inputs) } diff --git a/java/fuzz.go b/java/fuzz.go index dc4c6bec5..fb31ce794 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -64,6 +64,8 @@ func JavaFuzzFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) + module.Module.sourceProperties.Top_level_test_target = true android.AddLoadHook(module, func(ctx android.LoadHookContext) { disableLinuxBionic := struct { diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index e4beb5e55..ae587eac3 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -1478,13 +1478,3 @@ func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module andro } return bootDexJar.Path() } - -// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules. -func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule { - encodedDexJarsByModuleName := bootDexJarByModule{} - for _, module := range contents { - path := retrieveEncodedBootDexJarFromModule(ctx, module) - encodedDexJarsByModuleName.addPath(module, path) - } - return encodedDexJarsByModuleName -} diff --git a/java/java.go b/java/java.go index 188723060..2834c5f0c 100644 --- a/java/java.go +++ b/java/java.go @@ -964,11 +964,16 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...) } + + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: Bool(j.sourceProperties.Test_only), + TopLevelTarget: j.sourceProperties.Top_level_test_target, + }) } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { - j.deps(ctx) j.usesLibrary.deps(ctx, false) + j.deps(ctx) } const ( @@ -1129,6 +1134,7 @@ func LibraryFactory() android.Module { module := &Library{} module.addHostAndDeviceProperties() + module.AddProperties(&module.sourceProperties) module.initModuleAndImport(module) @@ -1610,6 +1616,8 @@ func TestFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) + module.Module.sourceProperties.Top_level_test_target = true InitJavaModule(module, android.HostAndDeviceSupported) return module @@ -1625,6 +1633,7 @@ func TestHelperLibraryFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) InitJavaModule(module, android.HostAndDeviceSupported) return module @@ -1680,6 +1689,8 @@ func InitTestHost(th *TestHost, installable *bool, testSuites []string, autoGenC th.properties.Installable = installable th.testProperties.Auto_gen_config = autoGenConfig th.testProperties.Test_suites = testSuites + th.sourceProperties.Test_only = proptools.BoolPtr(true) + th.sourceProperties.Top_level_test_target = true } // @@ -1805,7 +1816,7 @@ func BinaryFactory() android.Module { module := &Binary{} module.addHostAndDeviceProperties() - module.AddProperties(&module.binaryProperties) + module.AddProperties(&module.binaryProperties, &module.sourceProperties) module.Module.properties.Installable = proptools.BoolPtr(true) @@ -2570,7 +2581,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { // header jar for this module. reuseImplementationJarAsHeaderJar := slices.Equal(staticJars, staticHeaderJars) - var headerOutputFile android.WritablePath + var headerOutputFile android.ModuleOutPath if reuseImplementationJarAsHeaderJar { headerOutputFile = outputFile } else { @@ -2593,8 +2604,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { headerOutputFile = outputFile } } - j.combinedHeaderFile = headerOutputFile - j.combinedImplementationFile = outputFile + + // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource. + // Also strip the relative path from the header output file so that the reuseImplementationJarAsHeaderJar check + // in a module that depends on this module considers them equal. + j.combinedHeaderFile = headerOutputFile.WithoutRel() + j.combinedImplementationFile = outputFile.WithoutRel() j.maybeInstall(ctx, jarName, outputFile) @@ -3153,13 +3168,35 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, // <uses_library> and should not be added to CLC, but the transitive <uses-library> dependencies // from its CLC should be added to the current CLC. if sdkLib != nil { - clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, false, + optional := false + if module, ok := ctx.Module().(ModuleWithUsesLibrary); ok { + if android.InList(*sdkLib, module.UsesLibrary().usesLibraryProperties.Optional_uses_libs) { + optional = true + } + } + clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, optional, dep.DexJarBuildPath(ctx).PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts()) } else { clcMap.AddContextMap(dep.ClassLoaderContexts(), depName) } } +func addMissingOptionalUsesLibsFromDep(ctx android.ModuleContext, depModule android.Module, + usesLibrary *usesLibrary) { + + dep, ok := depModule.(ModuleWithUsesLibrary) + if !ok { + return + } + + for _, lib := range dep.UsesLibrary().usesLibraryProperties.Missing_optional_uses_libs { + if !android.InList(lib, usesLibrary.usesLibraryProperties.Missing_optional_uses_libs) { + usesLibrary.usesLibraryProperties.Missing_optional_uses_libs = + append(usesLibrary.usesLibraryProperties.Missing_optional_uses_libs, lib) + } + } +} + type JavaApiContributionImport struct { JavaApiContribution diff --git a/java/java_test.go b/java/java_test.go index 2676aa558..a1192bb5f 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2838,6 +2838,99 @@ func TestApiLibraryAconfigDeclarations(t *testing.T) { android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt") } +func TestTestOnly(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + ).RunTestWithBp(t, ` + // These should be test-only + java_library { + name: "lib1-test-only", + srcs: ["a.java"], + test_only: true, + } + java_test { + name: "java-test", + } + java_test_host { + name: "java-test-host", + } + java_test_helper_library { + name: "helper-library", + } + java_binary { + name: "java-data-binary", + srcs: ["foo.java"], + main_class: "foo.bar.jb", + test_only: true, + } + + // These are NOT + java_library { + name: "lib2-app", + srcs: ["b.java"], + } + java_import { + name: "bar", + jars: ["bar.jar"], + } + java_binary { + name: "java-binary", + srcs: ["foo.java"], + main_class: "foo.bar.jb", + } + `) + + expectedTestOnlyModules := []string{ + "lib1-test-only", + "java-test", + "java-test-host", + "helper-library", + "java-data-binary", + } + expectedTopLevelTests := []string{ + "java-test", + "java-test-host", + } + assertTestOnlyAndTopLevel(t, ctx, expectedTestOnlyModules, expectedTopLevelTests) +} + +// Don't allow setting test-only on things that are always tests or never tests. +func TestInvalidTestOnlyTargets(t *testing.T) { + testCases := []string{ + ` java_test { name: "java-test", test_only: true, srcs: ["foo.java"], } `, + ` java_test_host { name: "java-test-host", test_only: true, srcs: ["foo.java"], } `, + ` java_test_import { name: "java-test-import", test_only: true, } `, + ` java_api_library { name: "java-api-library", test_only: true, } `, + ` java_test_helper_library { name: "test-help-lib", test_only: true, } `, + ` java_defaults { name: "java-defaults", test_only: true, } `, + } + + for i, bp := range testCases { + android.GroupFixturePreparers(prepareForJavaTest). + ExtendWithErrorHandler( + expectOneError("unrecognized property \"test_only\"", + fmt.Sprintf("testcase: %d", i))). + RunTestWithBp(t, bp) + } +} + +// Expect exactly one that matches 'expected'. +// Append 'msg' to the Errorf that printed. +func expectOneError(expected string, msg string) android.FixtureErrorHandler { + return android.FixtureCustomErrorHandler(func(t *testing.T, result *android.TestResult) { + t.Helper() + if len(result.Errs) != 1 { + t.Errorf("Expected exactly one error, but found: %d when setting test_only on: %s", len(result.Errs), msg) + return + } + actualErrMsg := result.Errs[0].Error() + if !strings.Contains(actualErrMsg, expected) { + t.Errorf("Different error than expected. Received: [%v] on %s expected: %s", actualErrMsg, msg, expected) + } + }) +} + func TestJavaLibHostWithStem(t *testing.T) { ctx, _ := testJava(t, ` java_library_host { @@ -2872,3 +2965,79 @@ func TestJavaLibWithStem(t *testing.T) { t.Errorf("Module output does not contain expected jar %s", "foo-new.jar") } } + +func TestJavaLibraryOutputFilesRel(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + } + + java_import { + name: "bar", + jars: ["bar.aar"], + + } + + java_import { + name: "baz", + jars: ["baz.aar"], + static_libs: ["bar"], + } + `) + + foo := result.ModuleForTests("foo", "android_common") + bar := result.ModuleForTests("bar", "android_common") + baz := result.ModuleForTests("baz", "android_common") + + fooOutputPath := android.OutputFileForModule(android.PathContext(nil), foo.Module(), "") + barOutputPath := android.OutputFileForModule(android.PathContext(nil), bar.Module(), "") + bazOutputPath := android.OutputFileForModule(android.PathContext(nil), baz.Module(), "") + + android.AssertPathRelativeToTopEquals(t, "foo output path", + "out/soong/.intermediates/foo/android_common/javac/foo.jar", fooOutputPath) + android.AssertPathRelativeToTopEquals(t, "bar output path", + "out/soong/.intermediates/bar/android_common/combined/bar.jar", barOutputPath) + android.AssertPathRelativeToTopEquals(t, "baz output path", + "out/soong/.intermediates/baz/android_common/combined/baz.jar", bazOutputPath) + + android.AssertStringEquals(t, "foo relative output path", + "foo.jar", fooOutputPath.Rel()) + android.AssertStringEquals(t, "bar relative output path", + "bar.jar", barOutputPath.Rel()) + android.AssertStringEquals(t, "baz relative output path", + "baz.jar", bazOutputPath.Rel()) +} + +func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTestOnly []string, expectedTopLevel []string) { + t.Helper() + actualTrueModules := []string{} + actualTopLevelTests := []string{} + addActuals := func(m blueprint.Module, key blueprint.ProviderKey[android.TestModuleInformation]) { + if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, key); ok { + if provider.TestOnly { + actualTrueModules = append(actualTrueModules, m.Name()) + } + if provider.TopLevelTarget { + actualTopLevelTests = append(actualTopLevelTests, m.Name()) + } + } + } + + ctx.VisitAllModules(func(m blueprint.Module) { + addActuals(m, android.TestOnlyProviderKey) + + }) + + notEqual, left, right := android.ListSetDifference(expectedTestOnly, actualTrueModules) + if notEqual { + t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right) + } + + notEqual, left, right = android.ListSetDifference(expectedTopLevel, actualTopLevelTests) + if notEqual { + t.Errorf("top-level: Expected but not found: %v, Found but not expected: %v", left, right) + } +} diff --git a/partner/androidmk/androidmk_test.go b/partner/androidmk/androidmk_test.go index 6bae836d9..3ace7502d 100644 --- a/partner/androidmk/androidmk_test.go +++ b/partner/androidmk/androidmk_test.go @@ -54,6 +54,9 @@ cc_library_shared { } func TestEndToEnd(t *testing.T) { + // Skip checking Android.mk path with cleaning "ANDROID_BUILD_TOP" + t.Setenv("ANDROID_BUILD_TOP", "") + for i, test := range testCases { expected, err := bpfix.Reformat(test.expected) if err != nil { diff --git a/rust/builder.go b/rust/builder.go index 2f5e12aa5..4f45e33c1 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -61,7 +61,7 @@ var ( // Use the metadata output as it has the smallest footprint. "--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " + "$rustcFlags $clippyFlags" + - " && grep \"^$out:\" $out.d.raw > $out.d", + " && grep ^$out: $out.d.raw > $out.d", CommandDeps: []string{"$clippyCmd"}, Deps: blueprint.DepsGCC, Depfile: "$out.d", diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py index c33b104bd..b10125994 100755 --- a/scripts/manifest_check.py +++ b/scripts/manifest_check.py @@ -52,6 +52,14 @@ def parse_args(): 'required:false' ) parser.add_argument( + '--missing-optional-uses-library', + dest='missing_optional_uses_libraries', + action='append', + help='specify uses-library entries missing from the build system with ' + 'required:false', + default=[] + ) + parser.add_argument( '--enforce-uses-libraries', dest='enforce_uses_libraries', action='store_true', @@ -91,7 +99,7 @@ C_OFF = "\033[0m" C_BOLD = "\033[1m" -def enforce_uses_libraries(manifest, required, optional, relax, is_apk, path): +def enforce_uses_libraries(manifest, required, optional, missing_optional, relax, is_apk, path): """Verify that the <uses-library> tags in the manifest match those provided by the build system. @@ -119,7 +127,12 @@ def enforce_uses_libraries(manifest, required, optional, relax, is_apk, path): required = trim_namespace_parts(required) optional = trim_namespace_parts(optional) - if manifest_required == required and manifest_optional == optional: + existing_manifest_optional = [ + lib for lib in manifest_optional if lib not in missing_optional] + + # The order of the existing libraries matter, while the order of the missing + # ones doesn't. + if manifest_required == required and existing_manifest_optional == optional: return None #pylint: disable=line-too-long @@ -129,6 +142,7 @@ def enforce_uses_libraries(manifest, required, optional, relax, is_apk, path): '\t- required libraries in build system: %s[%s]%s\n' % (C_RED, ', '.join(required), C_OFF), '\t vs. in the manifest: %s[%s]%s\n' % (C_RED, ', '.join(manifest_required), C_OFF), '\t- optional libraries in build system: %s[%s]%s\n' % (C_RED, ', '.join(optional), C_OFF), + '\t and missing ones in build system: %s[%s]%s\n' % (C_RED, ', '.join(missing_optional), C_OFF), '\t vs. in the manifest: %s[%s]%s\n' % (C_RED, ', '.join(manifest_optional), C_OFF), '\t- tags in the manifest (%s):\n' % path, '\t\t%s\n' % '\t\t'.join(tags), @@ -340,11 +354,14 @@ def main(): if args.enforce_uses_libraries: # Load dexpreopt.config files and build a mapping from module - # names to library names. This is necessary because build system - # addresses libraries by their module name (`uses_libs`, - # `optional_uses_libs`, `LOCAL_USES_LIBRARIES`, - # `LOCAL_OPTIONAL_LIBRARY_NAMES` all contain module names), while - # the manifest addresses libraries by their name. + # names to library names. This is for Make only and it's necessary + # because Make passes module names from `LOCAL_USES_LIBRARIES`, + # `LOCAL_OPTIONAL_LIBRARY_NAMES`, while the manifest addresses + # libraries by their name. Soong doesn't use it and doesn't need it + # because it converts the module names to the library names and + # passes the library names. There is no need to translate missing + # optional libs because they are missing and therefore there is no + # mapping for them. mod_to_lib = load_dexpreopt_configs(args.dexpreopt_configs) required = translate_libnames(args.uses_libraries, mod_to_lib) optional = translate_libnames(args.optional_uses_libraries, @@ -354,8 +371,8 @@ def main(): # those in the manifest. Raise an exception on mismatch, unless the # script was passed a special parameter to suppress exceptions. errmsg = enforce_uses_libraries(manifest, required, optional, - args.enforce_uses_libraries_relax, - is_apk, args.input) + args.missing_optional_uses_libraries, + args.enforce_uses_libraries_relax, is_apk, args.input) # Create a status file that is empty on success, or contains an # error message on failure. When exceptions are suppressed, diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py index 3be7a30bf..8003b3e19 100755 --- a/scripts/manifest_check_test.py +++ b/scripts/manifest_check_test.py @@ -44,15 +44,17 @@ def required_apk(value): class EnforceUsesLibrariesTest(unittest.TestCase): """Unit tests for add_extract_native_libs function.""" - def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[]): #pylint: disable=dangerous-default-value + def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[], + missing_optional_uses_libraries=[]): #pylint: disable=dangerous-default-value doc = minidom.parseString(xml) try: relax = False manifest_check.enforce_uses_libraries( - doc, uses_libraries, optional_uses_libraries, relax, False, - 'path/to/X/AndroidManifest.xml') + doc, uses_libraries, optional_uses_libraries, missing_optional_uses_libraries, + relax, False, 'path/to/X/AndroidManifest.xml') manifest_check.enforce_uses_libraries(apk, uses_libraries, optional_uses_libraries, + missing_optional_uses_libraries, relax, True, 'path/to/X/X.apk') return True @@ -102,6 +104,15 @@ class EnforceUsesLibrariesTest(unittest.TestCase): matches = self.run_test(xml, apk, optional_uses_libraries=['foo']) self.assertFalse(matches) + def test_expected_missing_optional_uses_library(self): + xml = self.xml_tmpl % ( + uses_library_xml('foo') + uses_library_xml('missing') + uses_library_xml('bar')) + apk = self.apk_tmpl % ( + uses_library_apk('foo') + uses_library_apk('missing') + uses_library_apk('bar')) + matches = self.run_test(xml, apk, optional_uses_libraries=['foo', 'bar'], + missing_optional_uses_libraries=['missing']) + self.assertFalse(matches) + def test_missing_uses_library(self): xml = self.xml_tmpl % ('') apk = self.apk_tmpl % ('') |