summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/apex.go32
-rw-r--r--android/apex_test.go209
-rw-r--r--android/base_module_context.go8
-rw-r--r--android/config.go6
-rw-r--r--android/module.go112
-rw-r--r--android/mutator.go15
-rw-r--r--android/paths.go3
-rw-r--r--android/selects_test.go186
-rw-r--r--android/util.go36
-rw-r--r--android/variable.go35
-rw-r--r--bpfix/bpfix/bpfix_test.go7
-rw-r--r--cc/Android.bp1
-rw-r--r--cc/cc.go27
-rw-r--r--cc/cc_test.go36
-rw-r--r--cc/cc_test_only_property_test.go219
-rw-r--r--cc/config/arm64_device.go4
-rw-r--r--cc/config/global.go5
-rw-r--r--cc/config/x86_64_device.go4
-rw-r--r--cc/library.go21
-rw-r--r--cc/sabi.go3
-rw-r--r--cmd/release_config/Android.bp30
-rw-r--r--cmd/release_config/release_config/Android.bp18
-rw-r--r--cmd/release_config/release_config/main.go57
-rw-r--r--cmd/release_config/release_config_lib/Android.bp36
-rw-r--r--cmd/release_config/release_config_lib/flag_artifact.go89
-rw-r--r--cmd/release_config/release_config_lib/flag_declaration.go27
-rw-r--r--cmd/release_config/release_config_lib/flag_value.go56
-rw-r--r--cmd/release_config/release_config_lib/flag_value_test.go67
-rw-r--r--cmd/release_config/release_config_lib/release_config.go154
-rw-r--r--cmd/release_config/release_config_lib/release_configs.go (renamed from cmd/release_config/main.go)394
-rw-r--r--cmd/release_config/release_config_lib/util.go90
-rw-r--r--cmd/release_config/release_config_proto/Android.bp2
-rw-r--r--cmd/release_config/release_config_proto/build_flags_src.pb.go150
-rw-r--r--cmd/release_config/release_config_proto/build_flags_src.proto18
-rw-r--r--dexpreopt/class_loader_context.go1
-rw-r--r--filesystem/filesystem_test.go10
-rw-r--r--java/aar.go64
-rw-r--r--java/aar_test.go11
-rw-r--r--[-rwxr-xr-x]java/app.go96
-rw-r--r--java/app_import.go8
-rw-r--r--java/app_test.go58
-rw-r--r--java/base.go18
-rw-r--r--java/device_host_converter_test.go10
-rw-r--r--java/fuzz.go2
-rw-r--r--java/hiddenapi_modular.go10
-rw-r--r--java/java.go49
-rw-r--r--java/java_test.go169
-rw-r--r--partner/androidmk/androidmk_test.go3
-rw-r--r--rust/builder.go2
-rwxr-xr-xscripts/manifest_check.py35
-rwxr-xr-xscripts/manifest_check_test.py17
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",
diff --git a/cc/cc.go b/cc/cc.go
index 69ecc78fd..e3954d7a8 100644
--- a/cc/cc.go
+++ b/cc/cc.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 % ('')