diff options
143 files changed, 3508 insertions, 2677 deletions
diff --git a/.gitignore b/.gitignore index 5d2bc0d05..89de74ee1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ *.iml *.ipr *.iws - +*.swp +/.vscode diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 317f5c434..e8cad7d7b 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -4,3 +4,4 @@ bpfmt = true [Hook Scripts] do_not_use_DO_NOT_MERGE = ${REPO_ROOT}/build/soong/scripts/check_do_not_merge.sh ${PREUPLOAD_COMMIT} +aosp_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "." @@ -449,6 +449,7 @@ soong_config_module_type { config_namespace: "acme", variables: ["board"], bool_variables: ["feature"], + list_variables: ["impl"], value_variables: ["width"], properties: ["cflags", "srcs"], } @@ -460,24 +461,40 @@ soong_config_string_variable { ``` This example describes a new `acme_cc_defaults` module type that extends the -`cc_defaults` module type, with three additional conditionals based on -variables `board`, `feature` and `width`, which can affect properties `cflags` -and `srcs`. Additionally, each conditional will contain a `conditions_default` -property can affect `cflags` and `srcs` in the following conditions: - -* bool variable (e.g. `feature`): the variable is unspecified or not set to a true value +`cc_defaults` module type, with four additional conditionals based on variables +`board`, `feature`, `impl` and `width` which can affect properties `cflags` and +`srcs`. The four types of soong variables control properties in the following +ways. + +* bool variable (e.g. `feature`): Properties are applied if set to `true`. +* list variable (e.g. `impl`): (lists of strings properties only) Properties are + applied for each value in the list, using `%s` substitution. For example, if + the property is `["%s.cpp", "%s.h"]` and the list value is `foo bar`, + the result is `["foo.cpp", "foo.h", "bar.cpp", "bar.h"]`. +* value variable (e.g. `width`): (strings or lists of strings) The value are + directly substituted into properties using `%s`. +* string variable (e.g. `board`): Properties are applied only if they match the + variable's value. + +Additionally, each conditional containing a `conditions_default` property can +affect `cflags` and `srcs` in the following conditions: + +* bool variable (e.g. `feature`): the variable is unspecified or not set to + `true` +* list variable (e.g. `impl`): the variable is unspecified * value variable (e.g. `width`): the variable is unspecified -* string variable (e.g. `board`): the variable is unspecified or the variable is set to a string unused in the -given module. For example, with `board`, if the `board` -conditional contains the properties `soc_a` and `conditions_default`, when -board=soc_b, the `cflags` and `srcs` values under `conditions_default` will be -used. To specify that no properties should be amended for `soc_b`, you can set -`soc_b: {},`. +* string variable (e.g. `board`): the variable is unspecified or the variable is + set to a string unused in the given module. For example, with `board`, if the + `board` conditional contains the properties `soc_a` and `conditions_default`, + when `board` is `soc_b`, the `cflags` and `srcs` values under + `conditions_default` is used. To specify that no properties should be amended + for `soc_b`, you can set `soc_b: {},`. The values of the variables can be set from a product's `BoardConfig.mk` file: ``` $(call soong_config_set,acme,board,soc_a) $(call soong_config_set,acme,feature,true) +$(call soong_config_set,acme,impl,foo.cpp bar.cpp) $(call soong_config_set,acme,width,200) ``` @@ -519,6 +536,12 @@ acme_cc_defaults { cflags: ["-DWIDTH=DEFAULT"], }, }, + impl: { + srcs: ["impl/%s"], + conditions_default: { + srcs: ["impl/default.cpp"], + }, + }, }, } @@ -530,7 +553,8 @@ cc_library { ``` With the `BoardConfig.mk` snippet above, `libacme_foo` would build with -`cflags: "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200"`. +`cflags: "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200"` and +`srcs: ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"]`. Alternatively, with `DefaultBoardConfig.mk`: @@ -539,12 +563,14 @@ SOONG_CONFIG_NAMESPACES += acme SOONG_CONFIG_acme += \ board \ feature \ + impl \ width \ SOONG_CONFIG_acme_feature := false ``` -then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"`. +then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"` +and `srcs: ["*.cpp", "impl/default.cpp"]`. Alternatively, with `DefaultBoardConfig.mk`: @@ -553,13 +579,15 @@ SOONG_CONFIG_NAMESPACES += acme SOONG_CONFIG_acme += \ board \ feature \ + impl \ width \ SOONG_CONFIG_acme_board := soc_c +SOONG_CONFIG_acme_impl := baz ``` then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT --DFEATURE_DEFAULT -DSIZE=DEFAULT"`. +-DFEATURE_DEFAULT -DSIZE=DEFAULT"` and `srcs: ["*.cpp", "impl/baz.cpp"]`. `soong_config_module_type` modules will work best when used to wrap defaults modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced diff --git a/TEST_MAPPING b/TEST_MAPPING index 9f386ca49..6eabd7c14 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -3,5 +3,14 @@ { "path": "packages/modules/SdkExtensions" } + ], + + "postsubmit": [ + { + "name": "MicrodroidHostTestCases" + }, + { + "name": "MicrodroidTestApp" + } ] } diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go index d29e3122d..71a64dddc 100644 --- a/aconfig/aconfig_declarations.go +++ b/aconfig/aconfig_declarations.go @@ -73,8 +73,9 @@ func (module *DeclarationsModule) DepsMutator(ctx android.BottomUpMutatorContext if len(module.properties.Package) == 0 { ctx.PropertyErrorf("package", "missing package property") } - // TODO(b/311155208): Add mandatory check for container after all pre-existing - // ones are changed. + if len(module.properties.Container) == 0 { + ctx.PropertyErrorf("container", "missing container property") + } // Add a dependency on the aconfig_value_sets defined in // RELEASE_ACONFIG_VALUE_SETS, and add any aconfig_values that diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go index 5201fedb1..c37274c71 100644 --- a/aconfig/aconfig_declarations_test.go +++ b/aconfig/aconfig_declarations_test.go @@ -88,19 +88,49 @@ func TestAconfigDeclarationsWithContainer(t *testing.T) { android.AssertStringEquals(t, "rule must contain container", rule.Args["container"], "--container com.android.foo") } -func TestAconfigDeclarationsWithoutContainer(t *testing.T) { - bp := ` - aconfig_declarations { - name: "module_name", - package: "com.example.package", - srcs: [ - "foo.aconfig", - ], - } - ` - result := runTest(t, android.FixtureExpectsNoErrors, bp) - - module := result.ModuleForTests("module_name", "") - rule := module.Rule("aconfig") - android.AssertIntEquals(t, "rule must not contain container", len(rule.Args["container"]), 0) +func TestMandatoryProperties(t *testing.T) { + testCases := []struct { + name string + expectedError string + bp string + }{ + { + name: "Srcs missing from aconfig_declarations", + bp: ` + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + container: "otherapex", + }`, + expectedError: `missing source files`, + }, + { + name: "Package missing from aconfig_declarations", + bp: ` + aconfig_declarations { + name: "my_aconfig_declarations_foo", + container: "otherapex", + srcs: ["foo.aconfig"], + }`, + expectedError: `missing package property`, + }, + { + name: "Container missing from aconfig_declarations", + bp: ` + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + srcs: ["foo.aconfig"], + }`, + expectedError: `missing container property`, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + errorHandler := android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError) + android.GroupFixturePreparers(PrepareForTestWithAconfigBuildComponents). + ExtendWithErrorHandler(errorHandler). + RunTestWithBp(t, test.bp) + }) + } } diff --git a/aconfig/codegen/aconfig_declarations_group_test.go b/aconfig/codegen/aconfig_declarations_group_test.go index ec7cea383..c69d21ffd 100644 --- a/aconfig/codegen/aconfig_declarations_group_test.go +++ b/aconfig/codegen/aconfig_declarations_group_test.go @@ -15,9 +15,10 @@ package codegen import ( + "testing" + "android/soong/android" "android/soong/java" - "testing" ) func TestAconfigDeclarationsGroup(t *testing.T) { @@ -28,6 +29,7 @@ func TestAconfigDeclarationsGroup(t *testing.T) { aconfig_declarations { name: "foo-aconfig", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } @@ -39,6 +41,7 @@ func TestAconfigDeclarationsGroup(t *testing.T) { aconfig_declarations { name: "bar-aconfig", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go index 80e492620..ec0a6b6cd 100644 --- a/aconfig/codegen/cc_aconfig_library.go +++ b/aconfig/codegen/cc_aconfig_library.go @@ -22,6 +22,7 @@ import ( "github.com/google/blueprint/proptools" "fmt" + "strconv" "strings" ) @@ -33,6 +34,10 @@ var ccDeclarationsTag = ccDeclarationsTagType{} const baseLibDep = "server_configurable_flags" +const libBaseDep = "libbase" +const libLogDep = "liblog" +const libAconfigStorageReadApiCcDep = "libaconfig_storage_read_api_cc" + type CcAconfigLibraryProperties struct { // name of the aconfig_declarations module to generate a library for Aconfig_declarations string @@ -82,7 +87,14 @@ func (this *CcAconfigLibraryCallbacks) GeneratorDeps(ctx cc.DepsContext, deps cc // Add a dependency for the aconfig flags base library if it is not forced read only if mode != "force-read-only" { deps.SharedLibs = append(deps.SharedLibs, baseLibDep) + } + + // TODO: after storage migration is over, don't add these in force-read-only-mode. + deps.SharedLibs = append(deps.SharedLibs, libAconfigStorageReadApiCcDep) + deps.SharedLibs = append(deps.SharedLibs, libBaseDep) + deps.SharedLibs = append(deps.SharedLibs, libLogDep) + // TODO: It'd be really nice if we could reexport this library and not make everyone do it. return deps @@ -144,6 +156,7 @@ func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContex Args: map[string]string{ "gendir": this.generatedDir.String(), "mode": mode, + "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorageCc()), }, }) diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go index 05449bc6c..d01d13b61 100644 --- a/aconfig/codegen/cc_aconfig_library_test.go +++ b/aconfig/codegen/cc_aconfig_library_test.go @@ -50,6 +50,7 @@ func testCCCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) { aconfig_declarations { name: "my_aconfig_declarations", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } @@ -58,6 +59,26 @@ func testCCCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) { srcs: ["server_configurable_flags.cc"], } + cc_library { + name: "libbase", + srcs: ["libbase.cc"], + } + + cc_library { + name: "liblog", + srcs: ["liblog.cc"], + } + + cc_library { + name: "libaconfig_storage_read_api_cc", + srcs: ["libaconfig_storage_read_api_cc.cc"], + } + + cc_library { + name: "libaconfig_storage_protos_cc", + srcs: ["libaconfig_storage_protos_cc.cc"], + } + cc_aconfig_library { name: "my_cc_aconfig_library", aconfig_declarations: "my_aconfig_declarations", @@ -92,6 +113,7 @@ func testIncorrectCCCodegenModeHelper(t *testing.T, bpMode string, err string) { aconfig_declarations { name: "my_aconfig_declarations", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } @@ -100,6 +122,27 @@ func testIncorrectCCCodegenModeHelper(t *testing.T, bpMode string, err string) { srcs: ["server_configurable_flags.cc"], } + cc_library { + name: "libbase", + srcs: ["libbase.cc"], + } + + cc_library { + name: "liblog", + srcs: ["liblog.cc"], + } + + cc_library { + name: "libaconfig_storage_read_api_cc", + srcs: ["libaconfig_storage_read_api_cc.cc"], + } + + cc_library { + name: "libaconfig_storage_protos_cc", + srcs: ["libaconfig_storage_protos_cc.cc"], + } + + cc_aconfig_library { name: "my_cc_aconfig_library", aconfig_declarations: "my_aconfig_declarations", @@ -126,6 +169,7 @@ func TestAndroidMkCcLibrary(t *testing.T) { aconfig_declarations { name: "my_aconfig_declarations_bar", package: "com.example.package", + container: "com.android.foo", srcs: ["bar.aconfig"], } @@ -152,6 +196,30 @@ func TestAndroidMkCcLibrary(t *testing.T) { srcs: ["server_configurable_flags.cc"], vendor_available: true, } + + cc_library { + name: "libbase", + srcs: ["libbase.cc"], + vendor_available: true, + } + + cc_library { + name: "liblog", + srcs: ["liblog.cc"], + vendor_available: true, + } + + cc_library { + name: "libaconfig_storage_read_api_cc", + srcs: ["libaconfig_storage_read_api_cc.cc"], + vendor_available: true, + } + + cc_library { + name: "libaconfig_storage_protos_cc", + srcs: ["libaconfig_storage_protos_cc.cc"], + vendor_available: true, + } ` result := android.GroupFixturePreparers( PrepareForTestWithAconfigBuildComponents, @@ -176,6 +244,7 @@ func TestForceReadOnly(t *testing.T) { aconfig_declarations { name: "my_aconfig_declarations", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } @@ -184,6 +253,22 @@ func TestForceReadOnly(t *testing.T) { aconfig_declarations: "my_aconfig_declarations", mode: "force-read-only", } + + + cc_library { + name: "libbase", + srcs: ["libbase.cc"], + } + + cc_library { + name: "liblog", + srcs: ["liblog.cc"], + } + + cc_library { + name: "libaconfig_storage_read_api_cc", + srcs: ["libaconfig_storage_read_api_cc.cc"], + } `)) module := result.ModuleForTests("my_cc_aconfig_library", "android_arm64_armv8-a_shared").Module() diff --git a/aconfig/codegen/init.go b/aconfig/codegen/init.go index 73a89514d..6182e14d4 100644 --- a/aconfig/codegen/init.go +++ b/aconfig/codegen/init.go @@ -49,11 +49,12 @@ var ( ` && ${aconfig} create-cpp-lib` + ` --mode ${mode}` + ` --cache ${in}` + - ` --out ${gendir}`, + ` --out ${gendir}` + + ` --allow-instrumentation ${debug}`, CommandDeps: []string{ "$aconfig", }, - }, "gendir", "mode") + }, "gendir", "mode", "debug") // For rust_aconfig_library: Generate Rust library rustRule = pctx.AndroidStaticRule("rust_aconfig_library", diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go index a46ce5245..9f42e21de 100644 --- a/aconfig/codegen/java_aconfig_library.go +++ b/aconfig/codegen/java_aconfig_library.go @@ -115,6 +115,7 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuild module.AddJarJarRenameRule(declarations.Package+".Flags", "") module.AddJarJarRenameRule(declarations.Package+".FeatureFlags", "") module.AddJarJarRenameRule(declarations.Package+".FeatureFlagsImpl", "") + module.AddJarJarRenameRule(declarations.Package+".CustomFeatureFlags", "") module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "") } diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go index de45b5cc3..87b54a47f 100644 --- a/aconfig/codegen/java_aconfig_library_test.go +++ b/aconfig/codegen/java_aconfig_library_test.go @@ -35,6 +35,7 @@ func runJavaAndroidMkTest(t *testing.T, bp string) { aconfig_declarations { name: "my_aconfig_declarations_foo", package: "com.example.package.foo", + container: "system", srcs: ["foo.aconfig"], } @@ -46,6 +47,7 @@ func runJavaAndroidMkTest(t *testing.T, bp string) { aconfig_declarations { name: "my_aconfig_declarations_bar", package: "com.example.package.bar", + container: "system", srcs: ["bar.aconfig"], } @@ -60,7 +62,7 @@ func runJavaAndroidMkTest(t *testing.T, bp string) { entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0] makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"] - android.EnsureListContainsSuffix(t, makeVar, "android_common/aconfig_merged.pb") + android.EnsureListContainsSuffix(t, makeVar, "android_common/system/aconfig_merged.pb") } func TestAndroidMkJavaLibrary(t *testing.T) { @@ -175,6 +177,7 @@ func testCodegenMode(t *testing.T, bpMode string, ruleMode string) { aconfig_declarations { name: "my_aconfig_declarations", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], exportable: true, } @@ -200,6 +203,7 @@ func testCodegenModeWithError(t *testing.T, bpMode string, err string) { aconfig_declarations { name: "my_aconfig_declarations", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } @@ -234,3 +238,52 @@ func TestForceReadOnlyMode(t *testing.T) { func TestUnsupportedMode(t *testing.T) { testCodegenModeWithError(t, "mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode") } + +func TestMkEntriesMatchedContainer(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + java.PrepareForTestWithJavaDefaultModules). + ExtendWithErrorHandler(android.FixtureExpectsNoErrors). + RunTestWithBp(t, ` + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package.foo", + container: "system", + srcs: ["foo.aconfig"], + } + + java_aconfig_library { + name: "my_java_aconfig_library_foo", + aconfig_declarations: "my_aconfig_declarations_foo", + } + + aconfig_declarations { + name: "my_aconfig_declarations_bar", + package: "com.example.package.bar", + container: "system_ext", + srcs: ["bar.aconfig"], + } + + java_aconfig_library { + name: "my_java_aconfig_library_bar", + aconfig_declarations: "my_aconfig_declarations_bar", + } + + java_library { + name: "my_module", + srcs: [ + "src/foo.java", + ], + static_libs: [ + "my_java_aconfig_library_foo", + "my_java_aconfig_library_bar", + ], + platform_apis: true, + } + `) + + module := result.ModuleForTests("my_module", "android_common").Module() + entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0] + makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"] + android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb") +} diff --git a/aconfig/codegen/rust_aconfig_library_test.go b/aconfig/codegen/rust_aconfig_library_test.go index fe28f9441..523b464c0 100644 --- a/aconfig/codegen/rust_aconfig_library_test.go +++ b/aconfig/codegen/rust_aconfig_library_test.go @@ -46,6 +46,7 @@ func TestRustAconfigLibrary(t *testing.T) { aconfig_declarations { name: "my_aconfig_declarations", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } @@ -131,6 +132,7 @@ func testRustCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) { aconfig_declarations { name: "my_aconfig_declarations", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } rust_aconfig_library { @@ -193,6 +195,7 @@ func testIncorrectRustCodegenModeHelper(t *testing.T, bpMode string, err string) aconfig_declarations { name: "my_aconfig_declarations", package: "com.example.package", + container: "com.android.foo", srcs: ["foo.aconfig"], } rust_aconfig_library { diff --git a/android/Android.bp b/android/Android.bp index 4c59592c8..9ce8cdcd2 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -41,6 +41,7 @@ bootstrap_go_package { "buildinfo_prop.go", "config.go", "test_config.go", + "configurable_properties.go", "configured_jars.go", "csuite_config.go", "deapexer.go", @@ -60,6 +61,7 @@ bootstrap_go_package { "license_metadata.go", "license_sdk_member.go", "licenses.go", + "logtags.go", "makevars.go", "metrics.go", "module.go", @@ -138,6 +140,7 @@ bootstrap_go_package { "selects_test.go", "singleton_module_test.go", "soong_config_modules_test.go", + "test_suites_test.go", "util_test.go", "variable_test.go", "visibility_test.go", diff --git a/android/androidmk.go b/android/androidmk.go index 07f7c58d0..66f42f97c 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -36,6 +36,7 @@ import ( "github.com/google/blueprint" "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/pathtools" + "github.com/google/blueprint/proptools" ) func init() { @@ -541,6 +542,11 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint a.SetPath("LOCAL_SOONG_INSTALLED_MODULE", base.katiInstalls[len(base.katiInstalls)-1].to) a.SetString("LOCAL_SOONG_INSTALL_PAIRS", base.katiInstalls.BuiltInstalled()) a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", base.katiSymlinks.InstallPaths().Paths()) + } else { + // Soong may not have generated the install rule also when `no_full_install: true`. + // Mark this module as uninstallable in order to prevent Make from creating an + // install rule there. + a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install)) } if len(base.testData) > 0 { @@ -849,7 +855,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs * mod blueprint.Module, provider AndroidMkDataProvider) error { amod := mod.(Module).base() - if shouldSkipAndroidMkProcessing(amod) { + if shouldSkipAndroidMkProcessing(ctx, amod) { return nil } @@ -939,7 +945,7 @@ func WriteAndroidMkData(w io.Writer, data AndroidMkData) { func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, mod blueprint.Module, provider AndroidMkEntriesProvider) error { - if shouldSkipAndroidMkProcessing(mod.(Module).base()) { + if shouldSkipAndroidMkProcessing(ctx, mod.(Module).base()) { return nil } @@ -961,11 +967,11 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleIn return nil } -func ShouldSkipAndroidMkProcessing(module Module) bool { - return shouldSkipAndroidMkProcessing(module.base()) +func ShouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module Module) bool { + return shouldSkipAndroidMkProcessing(ctx, module.base()) } -func shouldSkipAndroidMkProcessing(module *ModuleBase) bool { +func shouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module *ModuleBase) bool { if !module.commonProperties.NamespaceExportedToMake { // TODO(jeffrygaston) do we want to validate that there are no modules being // exported to Kati that depend on this module? @@ -984,7 +990,7 @@ func shouldSkipAndroidMkProcessing(module *ModuleBase) bool { return true } - return !module.Enabled() || + return !module.Enabled(ctx) || module.commonProperties.HideFromMake || // Make does not understand LinuxBionic module.Os() == LinuxBionic || diff --git a/android/apex.go b/android/apex.go index c0acada13..dc0aeed17 100644 --- a/android/apex.go +++ b/android/apex.go @@ -90,7 +90,13 @@ type ApexInfo struct { TestApexes []string } -var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex") +// AllApexInfo holds the ApexInfo of all apexes that include this module. +type AllApexInfo struct { + ApexInfos []ApexInfo +} + +var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex_mutate") +var AllApexInfoProvider = blueprint.NewMutatorProvider[*AllApexInfo]("apex_info") func (i ApexInfo) AddJSONData(d *map[string]interface{}) { (*d)["Apex"] = map[string]interface{}{ @@ -586,75 +592,131 @@ func mergeApexVariations(apexInfos []ApexInfo) (merged []ApexInfo, aliases [][2] return merged, aliases } -// CreateApexVariations mutates a given module into multiple apex variants each of which is for an -// apexBundle (and/or the platform) where the module is part of. -func CreateApexVariations(mctx BottomUpMutatorContext, module ApexModule) []Module { +// IncomingApexTransition is called by apexTransitionMutator.IncomingTransition on modules that can be in apexes. +// The incomingVariation can be either the name of an apex if the dependency is coming directly from an apex +// module, or it can be the name of an apex variation (e.g. apex10000) if it is coming from another module that +// is in the apex. +func IncomingApexTransition(ctx IncomingTransitionContext, incomingVariation string) string { + module := ctx.Module().(ApexModule) base := module.apexModuleBase() - // Shortcut - if len(base.apexInfos) == 0 { - return nil + var apexInfos []ApexInfo + if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok { + apexInfos = allApexInfos.ApexInfos } - // Do some validity checks. - // TODO(jiyong): is this the right place? - base.checkApexAvailableProperty(mctx) - - 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 + // Dependencies from platform variations go to the platform variation. + if incomingVariation == "" { + return "" + } - slices.SortFunc(apexInfos, func(a, b ApexInfo) int { - return strings.Compare(a.ApexVariationName, b.ApexVariationName) - }) + // If this module has no apex variations the use the platform variation. + if len(apexInfos) == 0 { + return "" + } + // Convert the list of apex infos into from the AllApexInfoProvider into the merged list + // of apex variations and the aliases from apex names to apex variations. var aliases [][2]string - if !mctx.Module().(ApexModule).UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { + if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { apexInfos, aliases = mergeApexVariations(apexInfos) } + // Check if the incoming variation matches an apex name, and if so use the corresponding + // apex variation. + aliasIndex := slices.IndexFunc(aliases, func(alias [2]string) bool { + return alias[0] == incomingVariation + }) + if aliasIndex >= 0 { + return aliases[aliasIndex][1] + } + + // Check if the incoming variation matches an apex variation. + apexIndex := slices.IndexFunc(apexInfos, func(info ApexInfo) bool { + return info.ApexVariationName == incomingVariation + }) + if apexIndex >= 0 { + return incomingVariation + } + + return "" +} + +func MutateApexTransition(ctx BaseModuleContext, variation string) { + module := ctx.Module().(ApexModule) + base := module.apexModuleBase() + platformVariation := variation == "" + + var apexInfos []ApexInfo + if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok { + apexInfos = allApexInfos.ApexInfos + } + + // Shortcut + if len(apexInfos) == 0 { + return + } + + // Do some validity checks. + // TODO(jiyong): is this the right place? + base.checkApexAvailableProperty(ctx) + + if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { + apexInfos, _ = mergeApexVariations(apexInfos) + } + var inApex ApexMembership for _, a := range apexInfos { for _, apexContents := range a.ApexContents { - inApex = inApex.merge(apexContents.contents[mctx.ModuleName()]) + inApex = inApex.merge(apexContents.contents[ctx.ModuleName()]) } } base.ApexProperties.InAnyApex = true base.ApexProperties.DirectlyInAnyApex = inApex == directlyInApex - defaultVariation := "" - mctx.SetDefaultDependencyVariation(&defaultVariation) - - variations := []string{defaultVariation} - testApexes := []string{} - for _, a := range apexInfos { - variations = append(variations, a.ApexVariationName) - testApexes = append(testApexes, a.TestApexes...) + if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) { + // Do not install the module for platform, but still allow it to output + // uninstallable AndroidMk entries in certain cases when they have side + // effects. TODO(jiyong): move this routine to somewhere else + module.MakeUninstallable() } - modules := mctx.CreateVariations(variations...) - for i, mod := range modules { - platformVariation := i == 0 - if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) { - // Do not install the module for platform, but still allow it to output - // uninstallable AndroidMk entries in certain cases when they have side - // effects. TODO(jiyong): move this routine to somewhere else - mod.MakeUninstallable() - } - if !platformVariation { - mctx.SetVariationProvider(mod, ApexInfoProvider, apexInfos[i-1]) + if !platformVariation { + var thisApexInfo ApexInfo + + apexIndex := slices.IndexFunc(apexInfos, func(info ApexInfo) bool { + return info.ApexVariationName == variation + }) + if apexIndex >= 0 { + thisApexInfo = apexInfos[apexIndex] + } else { + panic(fmt.Errorf("failed to find apexInfo for incoming variation %q", variation)) } - // Set the value of TestApexes in every single apex variant. - // This allows each apex variant to be aware of the test apexes in the user provided apex_available. - mod.(ApexModule).apexModuleBase().ApexProperties.TestApexes = testApexes + + SetProvider(ctx, ApexInfoProvider, thisApexInfo) } - for _, alias := range aliases { - mctx.CreateAliasVariation(alias[0], alias[1]) + // Set the value of TestApexes in every single apex variant. + // This allows each apex variant to be aware of the test apexes in the user provided apex_available. + var testApexes []string + for _, a := range apexInfos { + testApexes = append(testApexes, a.TestApexes...) } + base.ApexProperties.TestApexes = testApexes - return modules +} + +func ApexInfoMutator(ctx TopDownMutatorContext, module ApexModule) { + base := module.apexModuleBase() + if len(base.apexInfos) > 0 { + apexInfos := slices.Clone(base.apexInfos) + slices.SortFunc(apexInfos, func(a, b ApexInfo) int { + return strings.Compare(a.ApexVariationName, b.ApexVariationName) + }) + SetProvider(ctx, AllApexInfoProvider, &AllApexInfo{apexInfos}) + // base.apexInfos is only needed to propagate the list of apexes from the apex module to its + // contents within apexInfoMutator. Clear it so it doesn't accidentally get used later. + base.apexInfos = nil + } } // UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies that are @@ -665,13 +727,16 @@ func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModul // InApexVariants list in common. It is used instead of DepIsInSameApex because it needs to // determine if the dep is in the same APEX due to being directly included, not only if it // is included _because_ it is a dependency. - anyInSameApex := func(a, b []ApexInfo) bool { - collectApexes := func(infos []ApexInfo) []string { - var ret []string - for _, info := range infos { - ret = append(ret, info.InApexVariants...) + anyInSameApex := func(a, b ApexModule) bool { + collectApexes := func(m ApexModule) []string { + if allApexInfo, ok := OtherModuleProvider(mctx, m, AllApexInfoProvider); ok { + var ret []string + for _, info := range allApexInfo.ApexInfos { + ret = append(ret, info.InApexVariants...) + } + return ret } - return ret + return nil } aApexes := collectApexes(a) @@ -689,7 +754,7 @@ func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModul // If any of the dependencies requires unique apex variations, so does this module. mctx.VisitDirectDeps(func(dep Module) { if depApexModule, ok := dep.(ApexModule); ok { - if anyInSameApex(depApexModule.apexModuleBase().apexInfos, am.apexModuleBase().apexInfos) && + if anyInSameApex(depApexModule, am) && (depApexModule.UniqueApexVariations() || depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) { am.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps = true diff --git a/android/apex_contributions.go b/android/apex_contributions.go index 03e32d6fa..91549e5d8 100644 --- a/android/apex_contributions.go +++ b/android/apex_contributions.go @@ -15,8 +15,6 @@ package android import ( - "strings" - "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -115,15 +113,6 @@ func (a *allApexContributions) DepsMutator(ctx BottomUpMutatorContext) { func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleContext) { addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) { for _, content := range m.Contents() { - // Coverage builds for TARGET_RELEASE=foo should always build from source, - // even if TARGET_RELEASE=foo uses prebuilt mainline modules. - // This is necessary because the checked-in prebuilts were generated with - // instrumentation turned off. - // - // Skip any prebuilt contents in coverage builds - if strings.HasPrefix(content, "prebuilt_") && (ctx.Config().JavaCoverageEnabled() || ctx.DeviceConfig().NativeCoverageEnabled()) { - continue - } if !ctx.OtherModuleExists(content) && !ctx.Config().AllowMissingDependencies() { ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name()) } diff --git a/android/arch.go b/android/arch.go index 27ce4d464..e0c6908c1 100644 --- a/android/arch.go +++ b/android/arch.go @@ -16,16 +16,11 @@ package android import ( "encoding" - "encoding/json" "fmt" "reflect" "runtime" - "sort" "strings" - "android/soong/bazel" - "android/soong/starlark_fmt" - "github.com/google/blueprint" "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" @@ -491,7 +486,7 @@ func osMutator(bpctx blueprint.BottomUpMutatorContext) { // dependencies on OsType variants that are explicitly disabled in their // properties. The CommonOS variant will still depend on disabled variants // if they are disabled afterwards, e.g. in archMutator if - if module.Enabled() { + if module.Enabled(mctx) { mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module) } } @@ -516,7 +511,7 @@ func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module { var variants []Module mctx.VisitDirectDeps(func(m Module) { if mctx.OtherModuleDependencyTag(m) == commonOsToOsSpecificVariantTag { - if m.Enabled() { + if m.Enabled(mctx) { variants = append(variants, m) } } @@ -980,12 +975,18 @@ func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.S panic(fmt.Errorf("unexpected tag format %q", field.Tag)) } // these tags don't need to be present in the runtime generated struct type. - values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path", "replace_instead_of_append"}) + // However replace_instead_of_append does, because it's read by the blueprint + // property extending util functions, which can operate on these generated arch + // property structs. + values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"}) if len(values) > 0 { - panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name)) + if values[0] != "replace_instead_of_append" || len(values) > 1 { + panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name)) + } + field.Tag = `android:"replace_instead_of_append"` + } else { + field.Tag = `` } - - field.Tag = `` return true, field } return false, field @@ -1899,428 +1900,8 @@ func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([] return buildTargets, nil } -func (m *ModuleBase) getArchPropertySet(propertySet interface{}, archType ArchType) interface{} { - archString := archType.Field - for i := range m.archProperties { - if m.archProperties[i] == nil { - // Skip over nil properties - continue - } - - // Not archProperties are usable; this function looks for properties of a very specific - // form, and ignores the rest. - for _, archProperty := range m.archProperties[i] { - // archPropValue is a property struct, we are looking for the form: - // `arch: { arm: { key: value, ... }}` - archPropValue := reflect.ValueOf(archProperty).Elem() - - // Unwrap src so that it should looks like a pointer to `arm: { key: value, ... }` - src := archPropValue.FieldByName("Arch").Elem() - - // Step into non-nil pointers to structs in the src value. - if src.Kind() == reflect.Ptr { - if src.IsNil() { - continue - } - src = src.Elem() - } - - // Find the requested field (e.g. arm, x86) in the src struct. - src = src.FieldByName(archString) - - // We only care about structs. - if !src.IsValid() || src.Kind() != reflect.Struct { - continue - } - - // If the value of the field is a struct then step into the - // BlueprintEmbed field. The special "BlueprintEmbed" name is - // used by createArchPropTypeDesc to embed the arch properties - // in the parent struct, so the src arch prop should be in this - // field. - // - // See createArchPropTypeDesc for more details on how Arch-specific - // module properties are processed from the nested props and written - // into the module's archProperties. - src = src.FieldByName("BlueprintEmbed") - - // Clone the destination prop, since we want a unique prop struct per arch. - propertySetClone := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface() - - // Copy the located property struct into the cloned destination property struct. - err := proptools.ExtendMatchingProperties([]interface{}{propertySetClone}, src.Interface(), nil, proptools.OrderReplace) - if err != nil { - // This is fine, it just means the src struct doesn't match the type of propertySet. - continue - } - - return propertySetClone - } - } - // No property set was found specific to the given arch, so return an empty - // property set. - return reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface() -} - -// getMultilibPropertySet returns a property set struct matching the type of -// `propertySet`, containing multilib-specific module properties for the given architecture. -// If no multilib-specific properties exist for the given architecture, returns an empty property -// set matching `propertySet`'s type. -func (m *ModuleBase) getMultilibPropertySet(propertySet interface{}, archType ArchType) interface{} { - // archType.Multilib is lowercase (for example, lib32) but property struct field is - // capitalized, such as Lib32, so use strings.Title to capitalize it. - multiLibString := strings.Title(archType.Multilib) - - for i := range m.archProperties { - if m.archProperties[i] == nil { - // Skip over nil properties - continue - } - - // Not archProperties are usable; this function looks for properties of a very specific - // form, and ignores the rest. - for _, archProperties := range m.archProperties[i] { - // archPropValue is a property struct, we are looking for the form: - // `multilib: { lib32: { key: value, ... }}` - archPropValue := reflect.ValueOf(archProperties).Elem() - - // Unwrap src so that it should looks like a pointer to `lib32: { key: value, ... }` - src := archPropValue.FieldByName("Multilib").Elem() - - // Step into non-nil pointers to structs in the src value. - if src.Kind() == reflect.Ptr { - if src.IsNil() { - // Ignore nil pointers. - continue - } - src = src.Elem() - } - - // Find the requested field (e.g. lib32) in the src struct. - src = src.FieldByName(multiLibString) - - // We only care about valid struct pointers. - if !src.IsValid() || src.Kind() != reflect.Ptr || src.Elem().Kind() != reflect.Struct { - continue - } - - // Get the zero value for the requested property set. - propertySetClone := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface() - - // Copy the located property struct into the "zero" property set struct. - err := proptools.ExtendMatchingProperties([]interface{}{propertySetClone}, src.Interface(), nil, proptools.OrderReplace) - - if err != nil { - // This is fine, it just means the src struct doesn't match. - continue - } - - return propertySetClone - } - } - - // There were no multilib properties specifically matching the given archtype. - // Return zeroed value. - return reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface() -} - // ArchVariantContext defines the limited context necessary to retrieve arch_variant properties. type ArchVariantContext interface { ModuleErrorf(fmt string, args ...interface{}) PropertyErrorf(property, fmt string, args ...interface{}) } - -// ArchVariantProperties represents a map of arch-variant config strings to a property interface{}. -type ArchVariantProperties map[string]interface{} - -// ConfigurationAxisToArchVariantProperties represents a map of bazel.ConfigurationAxis to -// ArchVariantProperties, such that each independent arch-variant axis maps to the -// configs/properties for that axis. -type ConfigurationAxisToArchVariantProperties map[bazel.ConfigurationAxis]ArchVariantProperties - -// GetArchVariantProperties returns a ConfigurationAxisToArchVariantProperties where the -// arch-variant properties correspond to the values of the properties of the 'propertySet' struct -// that are specific to that axis/configuration. Each axis is independent, containing -// non-overlapping configs that correspond to the various "arch-variant" support, at this time: -// -// arches (including multilib) -// oses -// arch+os combinations -// -// For example, passing a struct { Foo bool, Bar string } will return an interface{} that can be -// type asserted back into the same struct, containing the config-specific property value specified -// by the module if defined. -// -// Arch-specific properties may come from an arch stanza or a multilib stanza; properties -// in these stanzas are combined. -// For example: `arch: { x86: { Foo: ["bar"] } }, multilib: { lib32: {` Foo: ["baz"] } }` -// will result in `Foo: ["bar", "baz"]` being returned for architecture x86, if the given -// propertyset contains `Foo []string`. -func (m *ModuleBase) GetArchVariantProperties(ctx ArchVariantContext, propertySet interface{}) ConfigurationAxisToArchVariantProperties { - // Return value of the arch types to the prop values for that arch. - axisToProps := ConfigurationAxisToArchVariantProperties{} - - // Nothing to do for non-arch-specific modules. - if !m.ArchSpecific() { - return axisToProps - } - - dstType := reflect.ValueOf(propertySet).Type() - var archProperties []interface{} - - // First find the property set in the module that corresponds to the requested - // one. m.archProperties[i] corresponds to m.GetProperties()[i]. - for i, generalProp := range m.GetProperties() { - srcType := reflect.ValueOf(generalProp).Type() - if srcType == dstType { - archProperties = m.archProperties[i] - axisToProps[bazel.NoConfigAxis] = ArchVariantProperties{"": generalProp} - break - } - } - - if archProperties == nil { - // This module does not have the property set requested - return axisToProps - } - - archToProp := ArchVariantProperties{} - // For each arch type (x86, arm64, etc.) - for _, arch := range ArchTypeList() { - // Arch properties are sometimes sharded (see createArchPropTypeDesc() ). - // Iterate over every shard and extract a struct with the same type as the - // input one that contains the data specific to that arch. - propertyStructs := make([]reflect.Value, 0) - archFeaturePropertyStructs := make(map[string][]reflect.Value, 0) - for _, archProperty := range archProperties { - archTypeStruct, ok := getArchTypeStruct(ctx, archProperty, arch) - if ok { - propertyStructs = append(propertyStructs, archTypeStruct) - - // For each feature this arch supports (arm: neon, x86: ssse3, sse4, ...) - for _, feature := range archFeatures[arch] { - prefix := "arch." + arch.Name + "." + feature - if featureProperties, ok := getChildPropertyStruct(ctx, archTypeStruct, feature, prefix); ok { - archFeaturePropertyStructs[feature] = append(archFeaturePropertyStructs[feature], featureProperties) - } - } - } - multilibStruct, ok := getMultilibStruct(ctx, archProperty, arch) - if ok { - propertyStructs = append(propertyStructs, multilibStruct) - } - } - - archToProp[arch.Name] = mergeStructs(ctx, propertyStructs, propertySet) - - // In soong, if multiple features match the current configuration, they're - // all used. In bazel, we have to have unambiguous select() statements, so - // we can't have two features that are both active in the same select(). - // One alternative is to split out each feature into a separate select(), - // but then it's difficult to support exclude_srcs, which may need to - // exclude things from the regular arch select() statement if a certain - // feature is active. Instead, keep the features in the same select - // statement as the arches, but emit the power set of all possible - // combinations of features, so that bazel can match the most precise one. - allFeatures := make([]string, 0, len(archFeaturePropertyStructs)) - for feature := range archFeaturePropertyStructs { - allFeatures = append(allFeatures, feature) - } - for _, features := range bazel.PowerSetWithoutEmptySet(allFeatures) { - sort.Strings(features) - propsForCurrentFeatureSet := make([]reflect.Value, 0) - propsForCurrentFeatureSet = append(propsForCurrentFeatureSet, propertyStructs...) - for _, feature := range features { - propsForCurrentFeatureSet = append(propsForCurrentFeatureSet, archFeaturePropertyStructs[feature]...) - } - archToProp[arch.Name+"-"+strings.Join(features, "-")] = - mergeStructs(ctx, propsForCurrentFeatureSet, propertySet) - } - } - axisToProps[bazel.ArchConfigurationAxis] = archToProp - - osToProp := ArchVariantProperties{} - archOsToProp := ArchVariantProperties{} - - linuxStructs := getTargetStructs(ctx, archProperties, "Linux") - bionicStructs := getTargetStructs(ctx, archProperties, "Bionic") - hostStructs := getTargetStructs(ctx, archProperties, "Host") - hostLinuxStructs := getTargetStructs(ctx, archProperties, "Host_linux") - hostNotWindowsStructs := getTargetStructs(ctx, archProperties, "Not_windows") - - // For android, linux, ... - for _, os := range osTypeList { - if os == CommonOS { - // It looks like this OS value is not used in Blueprint files - continue - } - osStructs := make([]reflect.Value, 0) - - osSpecificStructs := getTargetStructs(ctx, archProperties, os.Field) - if os.Class == Host { - osStructs = append(osStructs, hostStructs...) - } - if os.Linux() { - osStructs = append(osStructs, linuxStructs...) - } - if os.Bionic() { - osStructs = append(osStructs, bionicStructs...) - } - if os.Linux() && os.Class == Host { - osStructs = append(osStructs, hostLinuxStructs...) - } - - if os == LinuxMusl { - osStructs = append(osStructs, getTargetStructs(ctx, archProperties, "Musl")...) - } - if os == Linux { - osStructs = append(osStructs, getTargetStructs(ctx, archProperties, "Glibc")...) - } - - osStructs = append(osStructs, osSpecificStructs...) - - if os.Class == Host && os != Windows { - osStructs = append(osStructs, hostNotWindowsStructs...) - } - osToProp[os.Name] = mergeStructs(ctx, osStructs, propertySet) - - // For arm, x86, ... - for _, arch := range osArchTypeMap[os] { - osArchStructs := make([]reflect.Value, 0) - - // Auto-combine with Linux_ and Bionic_ targets. This potentially results in - // repetition and select() bloat, but use of Linux_* and Bionic_* targets is rare. - // TODO(b/201423152): Look into cleanup. - if os.Linux() { - targetField := "Linux_" + arch.Name - targetStructs := getTargetStructs(ctx, archProperties, targetField) - osArchStructs = append(osArchStructs, targetStructs...) - } - if os.Bionic() { - targetField := "Bionic_" + arch.Name - targetStructs := getTargetStructs(ctx, archProperties, targetField) - osArchStructs = append(osArchStructs, targetStructs...) - } - if os == LinuxMusl { - targetField := "Musl_" + arch.Name - targetStructs := getTargetStructs(ctx, archProperties, targetField) - osArchStructs = append(osArchStructs, targetStructs...) - } - if os == Linux { - targetField := "Glibc_" + arch.Name - targetStructs := getTargetStructs(ctx, archProperties, targetField) - osArchStructs = append(osArchStructs, targetStructs...) - } - - targetField := GetCompoundTargetField(os, arch) - targetName := fmt.Sprintf("%s_%s", os.Name, arch.Name) - targetStructs := getTargetStructs(ctx, archProperties, targetField) - osArchStructs = append(osArchStructs, targetStructs...) - - archOsToProp[targetName] = mergeStructs(ctx, osArchStructs, propertySet) - } - } - - axisToProps[bazel.OsConfigurationAxis] = osToProp - axisToProps[bazel.OsArchConfigurationAxis] = archOsToProp - return axisToProps -} - -// Returns a struct matching the propertySet interface, containing properties specific to the targetName -// For example, given these arguments: -// -// propertySet = BaseCompilerProperties -// targetName = "android_arm" -// -// And given this Android.bp fragment: -// -// target: -// android_arm: { -// srcs: ["foo.c"], -// } -// android_arm64: { -// srcs: ["bar.c"], -// } -// } -// -// This would return a BaseCompilerProperties with BaseCompilerProperties.Srcs = ["foo.c"] -func getTargetStructs(ctx ArchVariantContext, archProperties []interface{}, targetName string) []reflect.Value { - var propertyStructs []reflect.Value - for _, archProperty := range archProperties { - archPropValues := reflect.ValueOf(archProperty).Elem() - targetProp := archPropValues.FieldByName("Target").Elem() - targetStruct, ok := getChildPropertyStruct(ctx, targetProp, targetName, targetName) - if ok { - propertyStructs = append(propertyStructs, targetStruct) - } else { - return []reflect.Value{} - } - } - - return propertyStructs -} - -func mergeStructs(ctx ArchVariantContext, propertyStructs []reflect.Value, propertySet interface{}) interface{} { - // Create a new instance of the requested property set - value := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface() - - // Merge all the structs together - for _, propertyStruct := range propertyStructs { - mergePropertyStruct(ctx, value, propertyStruct) - } - - return value -} - -func printArchTypeStarlarkDict(dict map[ArchType][]string) string { - valDict := make(map[string]string, len(dict)) - for k, v := range dict { - valDict[k.String()] = starlark_fmt.PrintStringList(v, 1) - } - return starlark_fmt.PrintDict(valDict, 0) -} - -func printArchTypeNestedStarlarkDict(dict map[ArchType]map[string][]string) string { - valDict := make(map[string]string, len(dict)) - for k, v := range dict { - valDict[k.String()] = starlark_fmt.PrintStringListDict(v, 1) - } - return starlark_fmt.PrintDict(valDict, 0) -} - -func printArchConfigList(arches []archConfig) string { - jsonOut, err := json.MarshalIndent(arches, "", starlark_fmt.Indention(1)) - if err != nil { - panic(fmt.Errorf("Error converting arch configs %#v to json: %q", arches, err)) - } - return fmt.Sprintf("json.decode('''%s''')", string(jsonOut)) -} - -func StarlarkArchConfigurations() string { - return fmt.Sprintf(` -_arch_to_variants = %s - -_arch_to_cpu_variants = %s - -_arch_to_features = %s - -_android_arch_feature_for_arch_variant = %s - -_aml_arches = %s - -_ndk_arches = %s - -arch_to_variants = _arch_to_variants -arch_to_cpu_variants = _arch_to_cpu_variants -arch_to_features = _arch_to_features -android_arch_feature_for_arch_variants = _android_arch_feature_for_arch_variant -aml_arches = _aml_arches -ndk_arches = _ndk_arches -`, printArchTypeStarlarkDict(archVariants), - printArchTypeStarlarkDict(cpuVariants), - printArchTypeStarlarkDict(archFeatures), - printArchTypeNestedStarlarkDict(androidArchFeatureMap), - printArchConfigList(getAmlAbisConfig()), - printArchConfigList(getNdkAbisConfig()), - ) -} diff --git a/android/arch_test.go b/android/arch_test.go index 5021a67af..f0a58a90b 100644 --- a/android/arch_test.go +++ b/android/arch_test.go @@ -423,7 +423,7 @@ func TestArchMutator(t *testing.T) { variants := ctx.ModuleVariantsForTests(name) for _, variant := range variants { m := ctx.ModuleForTests(name, variant) - if m.Module().Enabled() { + if m.Module().Enabled(PanickingConfigAndErrorContext(ctx)) { ret = append(ret, variant) } } @@ -533,7 +533,7 @@ func TestArchMutatorNativeBridge(t *testing.T) { variants := ctx.ModuleVariantsForTests(name) for _, variant := range variants { m := ctx.ModuleForTests(name, variant) - if m.Module().Enabled() { + if m.Module().Enabled(PanickingConfigAndErrorContext(ctx)) { ret = append(ret, variant) } } diff --git a/android/base_module_context.go b/android/base_module_context.go index 2dc1fd7c6..550600052 100644 --- a/android/base_module_context.go +++ b/android/base_module_context.go @@ -325,7 +325,7 @@ func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag b return nil } - if !aModule.Enabled() { + if !aModule.Enabled(b) { if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) { if b.Config().AllowMissingDependencies() { b.AddMissingDependencies([]string{b.OtherModuleName(aModule)}) diff --git a/android/config.go b/android/config.go index 75d135fc0..f6711e61f 100644 --- a/android/config.go +++ b/android/config.go @@ -229,6 +229,11 @@ func (c Config) ReleaseNdkAbiMonitored() bool { return c.config.productVariables.GetBuildFlagBool("RELEASE_NDK_ABI_MONITORED") } +// Enable read flag from new storage, for C/C++ +func (c Config) ReleaseReadFromNewStorageCc() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_READ_FROM_NEW_STORAGE_CC") +} + func (c Config) ReleaseHiddenApiExportableStubs() bool { return c.config.productVariables.GetBuildFlagBool("RELEASE_HIDDEN_API_EXPORTABLE_STUBS") || Bool(c.config.productVariables.HiddenapiExportableStubs) @@ -813,12 +818,12 @@ func (c *config) GetenvWithDefault(key string, defaultValue string) string { } func (c *config) IsEnvTrue(key string) bool { - value := c.Getenv(key) + value := strings.ToLower(c.Getenv(key)) return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" } func (c *config) IsEnvFalse(key string) bool { - value := c.Getenv(key) + value := strings.ToLower(c.Getenv(key)) return value == "0" || value == "n" || value == "no" || value == "off" || value == "false" } @@ -2099,6 +2104,7 @@ var ( "RELEASE_APEX_CONTRIBUTIONS_IPSEC", "RELEASE_APEX_CONTRIBUTIONS_MEDIA", "RELEASE_APEX_CONTRIBUTIONS_MEDIAPROVIDER", + "RELEASE_APEX_CONTRIBUTIONS_MODULE_METADATA", "RELEASE_APEX_CONTRIBUTIONS_NETWORKSTACKGOOGLE", "RELEASE_APEX_CONTRIBUTIONS_NEURALNETWORKS", "RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION", diff --git a/android/configurable_properties.go b/android/configurable_properties.go new file mode 100644 index 000000000..dad42fa1d --- /dev/null +++ b/android/configurable_properties.go @@ -0,0 +1,28 @@ +package android + +import "github.com/google/blueprint/proptools" + +// CreateSelectOsToBool is a utility function that makes it easy to create a +// Configurable property value that maps from os to a bool. Use an empty string +// to indicate a "default" case. +func CreateSelectOsToBool(cases map[string]*bool) proptools.Configurable[bool] { + var resultCases []proptools.ConfigurableCase[bool] + for pattern, value := range cases { + if pattern == "" { + resultCases = append(resultCases, proptools.NewConfigurableCase( + []proptools.ConfigurablePattern{proptools.NewDefaultConfigurablePattern()}, + value, + )) + } else { + resultCases = append(resultCases, proptools.NewConfigurableCase( + []proptools.ConfigurablePattern{proptools.NewStringConfigurablePattern(pattern)}, + value, + )) + } + } + + return proptools.NewConfigurable( + []proptools.ConfigurableCondition{proptools.NewConfigurableCondition("os", nil)}, + resultCases, + ) +} diff --git a/android/early_module_context.go b/android/early_module_context.go index cf1b5fcab..23f4c90a2 100644 --- a/android/early_module_context.go +++ b/android/early_module_context.go @@ -173,5 +173,5 @@ func (e *earlyModuleContext) Namespace() *Namespace { } func (e *earlyModuleContext) OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) { - e.EarlyModuleContext.OtherModulePropertyErrorf(module, property, fmt, args) + e.EarlyModuleContext.OtherModulePropertyErrorf(module, property, fmt, args...) } diff --git a/android/gen_notice.go b/android/gen_notice.go index 1acc638e8..6815f6467 100644 --- a/android/gen_notice.go +++ b/android/gen_notice.go @@ -62,7 +62,7 @@ func (s *genNoticeBuildRules) GenerateBuildActions(ctx SingletonContext) { if mod == nil { continue } - if !mod.Enabled() { // don't depend on variants without build rules + if !mod.Enabled(ctx) { // don't depend on variants without build rules continue } modules = append(modules, mod) diff --git a/android/license_metadata.go b/android/license_metadata.go index eabb1b170..3fea02909 100644 --- a/android/license_metadata.go +++ b/android/license_metadata.go @@ -36,7 +36,7 @@ var ( func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) { base := ctx.Module().base() - if !base.Enabled() { + if !base.Enabled(ctx) { return } @@ -69,7 +69,7 @@ func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) { if dep == nil { return } - if !dep.Enabled() { + if !dep.Enabled(ctx) { return } @@ -195,7 +195,7 @@ func isContainerFromFileExtensions(installPaths InstallPaths, builtPaths Paths) for _, path := range paths { switch path.Ext() { - case ".zip", ".tar", ".tgz", ".tar.gz", ".img", ".srcszip", ".apex": + case ".zip", ".tar", ".tgz", ".tar.gz", ".img", ".srcszip", ".apex", ".capex": return true } } diff --git a/android/logtags.go b/android/logtags.go new file mode 100644 index 000000000..d11cccf4f --- /dev/null +++ b/android/logtags.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 android + +import "github.com/google/blueprint" + +func init() { + RegisterParallelSingletonType("logtags", LogtagsSingleton) +} + +type LogtagsInfo struct { + Logtags Paths +} + +var LogtagsProviderKey = blueprint.NewProvider[*LogtagsInfo]() + +func LogtagsSingleton() Singleton { + return &logtagsSingleton{} +} + +type logtagsSingleton struct{} + +func MergedLogtagsPath(ctx PathContext) OutputPath { + return PathForIntermediates(ctx, "all-event-log-tags.txt") +} + +func (l *logtagsSingleton) GenerateBuildActions(ctx SingletonContext) { + var allLogtags Paths + ctx.VisitAllModules(func(module Module) { + if !module.ExportedToMake() { + return + } + if logtagsInfo, ok := SingletonModuleProvider(ctx, module, LogtagsProviderKey); ok { + allLogtags = append(allLogtags, logtagsInfo.Logtags...) + } + }) + + builder := NewRuleBuilder(pctx, ctx) + builder.Command(). + BuiltTool("merge-event-log-tags"). + FlagWithOutput("-o ", MergedLogtagsPath(ctx)). + Inputs(SortedUniquePaths(allLogtags)) + builder.Build("all-event-log-tags.txt", "merge logtags") +} diff --git a/android/makevars.go b/android/makevars.go index 4039e7edb..e73645fdc 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -98,6 +98,7 @@ type MakeVarsContext interface { BlueprintFile(module blueprint.Module) string ModuleErrorf(module blueprint.Module, format string, args ...interface{}) + OtherModulePropertyErrorf(module Module, property, format string, args ...interface{}) Errorf(format string, args ...interface{}) VisitAllModules(visit func(Module)) @@ -265,7 +266,7 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { } ctx.VisitAllModules(func(m Module) { - if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled() { + if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled(ctx) { mctx := &makeVarsContext{ SingletonContext: ctx, } diff --git a/android/module.go b/android/module.go index 5fe379c8a..40a591007 100644 --- a/android/module.go +++ b/android/module.go @@ -60,7 +60,7 @@ type Module interface { base() *ModuleBase Disable() - Enabled() bool + Enabled(ctx ConfigAndErrorContext) bool Target() Target MultiTargets() []Target @@ -287,7 +287,7 @@ type commonProperties struct { // but are not usually required (e.g. superceded by a prebuilt) should not be // disabled as that will prevent them from being built by the checkbuild target // and so prevent early detection of changes that have broken those modules. - Enabled *bool `android:"arch_variant"` + Enabled proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"` // Controls the visibility of this module to other modules. Allowable values are one or more of // these formats: @@ -484,6 +484,11 @@ type commonProperties struct { // Set by osMutator. CommonOSVariant bool `blueprint:"mutated"` + // When set to true, this module is not installed to the full install path (ex: under + // out/target/product/<name>/<partition>). It can be installed only to the packaging + // modules like android_filesystem. + No_full_install *bool + // When HideFromMake is set to true, no entry for this variant will be emitted in the // generated Android.mk file. HideFromMake bool `blueprint:"mutated"` @@ -1392,14 +1397,11 @@ func (m *ModuleBase) PartitionTag(config DeviceConfig) string { return partition } -func (m *ModuleBase) Enabled() bool { +func (m *ModuleBase) Enabled(ctx ConfigAndErrorContext) bool { if m.commonProperties.ForcedDisabled { return false } - if m.commonProperties.Enabled == nil { - return !m.Os().DefaultDisabled - } - return *m.commonProperties.Enabled + return m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled) } func (m *ModuleBase) Disable() { @@ -1643,7 +1645,7 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { // not be created if the module is not exported to make. // Those could depend on the build target and fail to compile // for the current build target. - if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(a) { + if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, a) { allCheckbuildFiles = append(allCheckbuildFiles, a.checkbuildFiles...) } }) @@ -1835,7 +1837,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) checkDistProperties(ctx, fmt.Sprintf("dists[%d]", i), &m.distProperties.Dists[i]) } - if m.Enabled() { + if m.Enabled(ctx) { // ensure all direct android.Module deps are enabled ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) { if m, ok := bm.(Module); ok { @@ -2136,19 +2138,19 @@ func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools. } func (e configurationEvalutor) PropertyErrorf(property string, fmt string, args ...interface{}) { - e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args) + e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args...) } func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue { ctx := e.ctx m := e.m - switch condition.FunctionName { + 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)) + if condition.NumArgs() != 1 { + ctx.OtherModulePropertyErrorf(m, property, "release_variable requires 1 argument, found %d", condition.NumArgs()) return proptools.ConfigurableValueUndefined() } - if v, ok := ctx.Config().productVariables.BuildFlags[condition.Args[0]]; ok { + if v, ok := ctx.Config().productVariables.BuildFlags[condition.Arg(0)]; ok { return proptools.ConfigurableValueString(v) } return proptools.ConfigurableValueUndefined() @@ -2157,12 +2159,12 @@ func (e configurationEvalutor) EvaluateConfiguration(condition proptools.Configu ctx.OtherModulePropertyErrorf(m, property, "TODO(b/323382414): Product variables are not yet supported in selects") 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)) + if condition.NumArgs() != 2 { + ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", condition.NumArgs()) return proptools.ConfigurableValueUndefined() } - namespace := condition.Args[0] - variable := condition.Args[1] + namespace := condition.Arg(0) + variable := condition.Arg(1) if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok { if v, ok := n[variable]; ok { return proptools.ConfigurableValueString(v) @@ -2170,8 +2172,8 @@ func (e configurationEvalutor) EvaluateConfiguration(condition proptools.Configu } return proptools.ConfigurableValueUndefined() case "arch": - if len(condition.Args) != 0 { - ctx.OtherModulePropertyErrorf(m, property, "arch requires no arguments, found %d", len(condition.Args)) + if condition.NumArgs() != 0 { + ctx.OtherModulePropertyErrorf(m, property, "arch requires no arguments, found %d", condition.NumArgs()) return proptools.ConfigurableValueUndefined() } if !m.base().ArchReady() { @@ -2180,8 +2182,8 @@ func (e configurationEvalutor) EvaluateConfiguration(condition proptools.Configu } 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)) + if condition.NumArgs() != 0 { + ctx.OtherModulePropertyErrorf(m, property, "os requires no arguments, found %d", condition.NumArgs()) return proptools.ConfigurableValueUndefined() } // the arch mutator runs after the os mutator, we can just use this to enforce that os is ready. @@ -2194,8 +2196,8 @@ func (e configurationEvalutor) EvaluateConfiguration(condition proptools.Configu // 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)) + if condition.NumArgs() != 0 { + ctx.OtherModulePropertyErrorf(m, property, "boolean_var_for_testing requires 0 arguments, found %d", condition.NumArgs()) return proptools.ConfigurableValueUndefined() } @@ -2535,7 +2537,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { } osDeps := map[osAndCross]Paths{} ctx.VisitAllModules(func(module Module) { - if module.Enabled() { + if module.Enabled(ctx) { key := osAndCross{os: module.Target().Os, hostCross: module.Target().HostCross} osDeps[key] = append(osDeps[key], module.base().checkbuildFiles...) } diff --git a/android/module_context.go b/android/module_context.go index d3e2770cb..605d3baeb 100644 --- a/android/module_context.go +++ b/android/module_context.go @@ -444,6 +444,21 @@ func (m *moduleContext) skipInstall() bool { return false } +// Tells whether this module is installed to the full install path (ex: +// out/target/product/<name>/<partition>) or not. If this returns false, the install build rule is +// not created and this module can only be installed to packaging modules like android_filesystem. +func (m *moduleContext) requiresFullInstall() bool { + if m.skipInstall() { + return false + } + + if proptools.Bool(m.module.base().commonProperties.No_full_install) { + return false + } + + return true +} + func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath { return m.installFile(installPath, name, srcPath, deps, false, true, nil) @@ -476,6 +491,7 @@ func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, e executable: executable, effectiveLicenseFiles: &licenseFiles, partition: fullInstallPath.partition, + skipInstall: m.skipInstall(), } m.packagingSpecs = append(m.packagingSpecs, spec) return spec @@ -489,7 +505,7 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false) } - if !m.skipInstall() { + if m.requiresFullInstall() { deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList())...) deps = append(deps, m.module.base().installedInitRcPaths...) deps = append(deps, m.module.base().installedVintfFragmentsPaths...) @@ -562,7 +578,7 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src if err != nil { panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err)) } - if !m.skipInstall() { + if m.requiresFullInstall() { if m.Config().KatiEnabled() { // When creating the symlink rule in Soong but embedding in Make, write the rule to a @@ -599,6 +615,7 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src symlinkTarget: relPath, executable: false, partition: fullInstallPath.partition, + skipInstall: m.skipInstall(), }) return fullInstallPath @@ -610,7 +627,7 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str fullInstallPath := installPath.Join(m, name) m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true) - if !m.skipInstall() { + if m.requiresFullInstall() { if m.Config().KatiEnabled() { // When creating the symlink rule in Soong but embedding in Make, write the rule to a // makefile instead of directly to the ninja file so that main.mk can add the @@ -640,6 +657,7 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str symlinkTarget: absPath, executable: false, partition: fullInstallPath.partition, + skipInstall: m.skipInstall(), }) return fullInstallPath diff --git a/android/mutator.go b/android/mutator.go index 75ba65048..440b9060f 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -293,15 +293,14 @@ type BottomUpMutatorContext interface { // WalkDeps, etc. AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module) - // ReplaceDependencies replaces all dependencies on the identical variant of the module with the - // specified name with the current variant of this module. Replacements don't take effect until - // after the mutator pass is finished. + // ReplaceDependencies finds all the variants of the module with the specified name, then + // replaces all dependencies onto those variants with the current variant of this module. + // Replacements don't take effect until after the mutator pass is finished. ReplaceDependencies(string) - // ReplaceDependencies replaces all dependencies on the identical variant of the module with the - // specified name with the current variant of this module as long as the supplied predicate returns - // true. - // + // ReplaceDependenciesIf finds all the variants of the module with the specified name, then + // replaces all dependencies onto those variants with the current variant of this module + // as long as the supplied predicate returns true. // Replacements don't take effect until after the mutator pass is finished. ReplaceDependenciesIf(string, blueprint.ReplaceDependencyPredicate) @@ -595,11 +594,16 @@ func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTr func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) { if am, ok := ctx.Module().(Module); ok { + if variation != "" { + // TODO: this should really be checking whether the TransitionMutator affected this module, not + // the empty variant, but TransitionMutator has no concept of skipping a module. + base := am.base() + base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name) + base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation) + } + 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) } } @@ -674,13 +678,11 @@ func RegisterComponentsMutator(ctx RegisterMutatorsContext) { // on component modules to be added so that they can depend directly on a prebuilt // module. func componentDepsMutator(ctx BottomUpMutatorContext) { - if m := ctx.Module(); m.Enabled() { - m.ComponentDepsMutator(ctx) - } + ctx.Module().ComponentDepsMutator(ctx) } func depsMutator(ctx BottomUpMutatorContext) { - if m := ctx.Module(); m.Enabled() { + if m := ctx.Module(); m.Enabled(ctx) { m.base().baseDepsMutator(ctx) m.DepsMutator(ctx) } diff --git a/android/override_module.go b/android/override_module.go index 1341f537c..55f384f1f 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -28,6 +28,7 @@ package android // module based on it. import ( + "fmt" "sort" "sync" @@ -120,7 +121,7 @@ type OverridableModule interface { addOverride(o OverrideModule) getOverrides() []OverrideModule - override(ctx BaseModuleContext, m Module, o OverrideModule) + override(ctx BaseModuleContext, bm OverridableModule, o OverrideModule) GetOverriddenBy() string GetOverriddenByModuleDir() string @@ -191,15 +192,14 @@ func (b *OverridableModuleBase) setOverridesProperty(overridesProperty *[]string } // Overrides a base module with the given OverrideModule. -func (b *OverridableModuleBase) override(ctx BaseModuleContext, m Module, o OverrideModule) { - +func (b *OverridableModuleBase) override(ctx BaseModuleContext, bm OverridableModule, o OverrideModule) { for _, p := range b.overridableProperties { for _, op := range o.getOverridingProperties() { if proptools.TypeEqual(p, op) { err := proptools.ExtendProperties(p, op, nil, proptools.OrderReplace) if err != nil { if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { - ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + ctx.OtherModulePropertyErrorf(bm, propertyErr.Property, "%s", propertyErr.Err.Error()) } else { panic(err) } @@ -210,7 +210,7 @@ func (b *OverridableModuleBase) override(ctx BaseModuleContext, m Module, o Over // Adds the base module to the overrides property, if exists, of the overriding module. See the // comment on OverridableModuleBase.overridesProperty for details. if b.overridesProperty != nil { - *b.overridesProperty = append(*b.overridesProperty, ctx.ModuleName()) + *b.overridesProperty = append(*b.overridesProperty, ctx.OtherModuleName(bm)) } b.overridableModuleProperties.OverriddenBy = o.Name() b.overridableModuleProperties.OverriddenByModuleDir = o.ModuleDir() @@ -235,7 +235,7 @@ func (b *OverridableModuleBase) OverridablePropertiesDepsMutator(ctx BottomUpMut // to keep them in this order and not put any order mutators between them. func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) { ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel() - ctx.BottomUp("perform_override", performOverrideMutator).Parallel() + ctx.Transition("override", &overrideTransitionMutator{}) // overridableModuleDepsMutator calls OverridablePropertiesDepsMutator so that overridable modules can // add deps from overridable properties. ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel() @@ -262,18 +262,6 @@ func overrideModuleDepsMutator(ctx BottomUpMutatorContext) { ctx.PropertyErrorf("base", "%q is not a valid module name", base) return } - // See if there's a prebuilt module that overrides this override module with prefer flag, - // in which case we call HideFromMake on the corresponding variant later. - ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) { - prebuilt := GetEmbeddedPrebuilt(dep) - if prebuilt == nil { - panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name()) - } - if prebuilt.UsePrebuilt() { - module.setOverriddenByPrebuilt(dep) - return - } - }) baseModule := ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base)[0] if o, ok := baseModule.(OverridableModule); ok { overrideModule := ctx.Module().(OverrideModule) @@ -285,11 +273,13 @@ func overrideModuleDepsMutator(ctx BottomUpMutatorContext) { // Now, goes through all overridable modules, finds all modules overriding them, creates a local // variant for each of them, and performs the actual overriding operation by calling override(). -func performOverrideMutator(ctx BottomUpMutatorContext) { +type overrideTransitionMutator struct{} + +func (overrideTransitionMutator) Split(ctx BaseModuleContext) []string { if b, ok := ctx.Module().(OverridableModule); ok { overrides := b.getOverrides() if len(overrides) == 0 { - return + return []string{""} } variants := make([]string, len(overrides)+1) // The first variant is for the original, non-overridden, base module. @@ -297,32 +287,74 @@ func performOverrideMutator(ctx BottomUpMutatorContext) { for i, o := range overrides { variants[i+1] = o.(Module).Name() } - mods := ctx.CreateLocalVariations(variants...) - // Make the original variation the default one to depend on if no other override module variant - // is specified. - ctx.AliasVariation(variants[0]) - for i, o := range overrides { - mods[i+1].(OverridableModule).override(ctx, mods[i+1], o) - if prebuilt := o.getOverriddenByPrebuilt(); prebuilt != nil { - // The overriding module itself, too, is overridden by a prebuilt. - // Perform the same check for replacement - checkInvariantsForSourceAndPrebuilt(ctx, mods[i+1], prebuilt) - // Copy the flag and hide it in make - mods[i+1].ReplacedByPrebuilt() - } - } + return variants } else if o, ok := ctx.Module().(OverrideModule); ok { // Create a variant of the overriding module with its own name. This matches the above local // variant name rule for overridden modules, and thus allows ReplaceDependencies to match the // two. - ctx.CreateLocalVariations(o.Name()) - // To allow dependencies to be added without having to know the above variation. - ctx.AliasVariation(o.Name()) + return []string{o.Name()} + } + + return []string{""} +} + +func (overrideTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string { + if o, ok := ctx.Module().(OverrideModule); ok { + if ctx.DepTag() == overrideBaseDepTag { + return o.Name() + } + } + + // Variations are always local and shouldn't affect the variant used for dependencies + return "" +} + +func (overrideTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string { + if _, ok := ctx.Module().(OverridableModule); ok { + return incomingVariation + } else if o, ok := ctx.Module().(OverrideModule); ok { + // To allow dependencies to be added without having to know the variation. + return o.Name() + } + + return "" +} + +func (overrideTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) { + if o, ok := ctx.Module().(OverrideModule); ok { + overridableDeps := ctx.GetDirectDepsWithTag(overrideBaseDepTag) + if len(overridableDeps) > 1 { + panic(fmt.Errorf("expected a single dependency with overrideBaseDepTag, found %q", overridableDeps)) + } else if len(overridableDeps) == 1 { + b := overridableDeps[0].(OverridableModule) + b.override(ctx, b, o) + + checkPrebuiltReplacesOverride(ctx, b) + } + } +} + +func checkPrebuiltReplacesOverride(ctx BottomUpMutatorContext, b OverridableModule) { + // See if there's a prebuilt module that overrides this override module with prefer flag, + // in which case we call HideFromMake on the corresponding variant later. + prebuiltDeps := ctx.GetDirectDepsWithTag(PrebuiltDepTag) + for _, prebuiltDep := range prebuiltDeps { + prebuilt := GetEmbeddedPrebuilt(prebuiltDep) + if prebuilt == nil { + panic("PrebuiltDepTag leads to a non-prebuilt module " + prebuiltDep.Name()) + } + if prebuilt.UsePrebuilt() { + // The overriding module itself, too, is overridden by a prebuilt. + // Perform the same check for replacement + checkInvariantsForSourceAndPrebuilt(ctx, b, prebuiltDep) + // Copy the flag and hide it in make + b.ReplacedByPrebuilt() + } } } func overridableModuleDepsMutator(ctx BottomUpMutatorContext) { - if b, ok := ctx.Module().(OverridableModule); ok && b.Enabled() { + if b, ok := ctx.Module().(OverridableModule); ok && b.Enabled(ctx) { b.OverridablePropertiesDepsMutator(ctx) } } diff --git a/android/packaging.go b/android/packaging.go index a8fb28d30..fe61da1e9 100644 --- a/android/packaging.go +++ b/android/packaging.go @@ -43,6 +43,30 @@ type PackagingSpec struct { effectiveLicenseFiles *Paths partition string + + // Whether this packaging spec represents an installation of the srcPath (i.e. this struct + // is created via InstallFile or InstallSymlink) or a simple packaging (i.e. created via + // PackageFile). + skipInstall bool +} + +func (p *PackagingSpec) Equals(other *PackagingSpec) bool { + if other == nil { + return false + } + if p.relPathInPackage != other.relPathInPackage { + return false + } + if p.srcPath != other.srcPath || p.symlinkTarget != other.symlinkTarget { + return false + } + if p.executable != other.executable { + return false + } + if p.partition != other.partition { + return false + } + return true } // Get file name of installed package @@ -74,6 +98,10 @@ func (p *PackagingSpec) Partition() string { return p.partition } +func (p *PackagingSpec) SkipInstall() bool { + return p.skipInstall +} + type PackageModule interface { Module packagingBase() *PackagingBase @@ -234,9 +262,15 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter continue } } - if _, ok := m[ps.relPathInPackage]; !ok { - m[ps.relPathInPackage] = ps + dstPath := ps.relPathInPackage + if existingPs, ok := m[dstPath]; ok { + if !existingPs.Equals(&ps) { + ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps) + } + continue } + + m[dstPath] = ps } }) return m diff --git a/android/paths.go b/android/paths.go index 2b33f67ce..8d92aa4a9 100644 --- a/android/paths.go +++ b/android/paths.go @@ -60,6 +60,7 @@ type EarlyModulePathContext interface { ModuleDir() string ModuleErrorf(fmt string, args ...interface{}) + OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{}) } var _ EarlyModulePathContext = ModuleContext(nil) @@ -277,6 +278,7 @@ type WritablePath interface { type genPathProvider interface { genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath + genPathWithExtAndTrimExt(ctx ModuleOutPathContext, subdir, ext string, trimExt string) ModuleGenPath } type objPathProvider interface { objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath @@ -295,6 +297,16 @@ func GenPathWithExt(ctx ModuleOutPathContext, subdir string, p Path, ext string) return PathForModuleGen(ctx) } +// GenPathWithExtAndTrimExt derives a new file path in ctx's generated sources directory +// from the current path, but with the new extension and trim the suffix. +func GenPathWithExtAndTrimExt(ctx ModuleOutPathContext, subdir string, p Path, ext string, trimExt string) ModuleGenPath { + if path, ok := p.(genPathProvider); ok { + return path.genPathWithExtAndTrimExt(ctx, subdir, ext, trimExt) + } + ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p) + return PathForModuleGen(ctx) +} + // ObjPathWithExt derives a new file path in ctx's object directory from the // current path, but with the new extension. func ObjPathWithExt(ctx ModuleOutPathContext, subdir string, p Path, ext string) ModuleObjPath { @@ -550,7 +562,7 @@ func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag if module == nil { return nil, missingDependencyError{[]string{moduleName}} } - if aModule, ok := module.(Module); ok && !aModule.Enabled() { + if aModule, ok := module.(Module); ok && !aModule.Enabled(ctx) { return nil, missingDependencyError{[]string{moduleName}} } if outProducer, ok := module.(OutputFileProducer); ok { @@ -1507,6 +1519,17 @@ func (p SourcePath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) } +func (p SourcePath) genPathWithExtAndTrimExt(ctx ModuleOutPathContext, subdir, ext string, trimExt string) ModuleGenPath { + // If Trim_extension being set, force append Output_extension without replace original extension. + if trimExt != "" { + if ext != "" { + return PathForModuleGen(ctx, subdir, strings.TrimSuffix(p.path, trimExt)+"."+ext) + } + return PathForModuleGen(ctx, subdir, strings.TrimSuffix(p.path, trimExt)) + } + return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) +} + func (p SourcePath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath { return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) } @@ -1594,6 +1617,17 @@ func (p ModuleGenPath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext stri return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) } +func (p ModuleGenPath) genPathWithExtAndTrimExt(ctx ModuleOutPathContext, subdir, ext string, trimExt string) ModuleGenPath { + // If Trim_extension being set, force append Output_extension without replace original extension. + if trimExt != "" { + if ext != "" { + return PathForModuleGen(ctx, subdir, strings.TrimSuffix(p.path, trimExt)+"."+ext) + } + return PathForModuleGen(ctx, subdir, strings.TrimSuffix(p.path, trimExt)) + } + return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) +} + func (p ModuleGenPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath { return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) } diff --git a/android/prebuilt.go b/android/prebuilt.go index 794ddcc2f..51b86a56f 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -275,7 +275,7 @@ func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface srcPropertyName := proptools.PropertyNameForField(srcField) srcsSupplier := func(ctx BaseModuleContext, _ Module) []string { - if !module.Enabled() { + if !module.Enabled(ctx) { return nil } value := srcPropsValue.FieldByIndex(srcFieldIndex) @@ -425,7 +425,7 @@ func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) { m := ctx.Module() // If this module is a prebuilt, is enabled and has not been renamed to source then add a // dependency onto the source if it is present. - if p := GetEmbeddedPrebuilt(m); p != nil && m.Enabled() && !p.properties.PrebuiltRenamedToSource { + if p := GetEmbeddedPrebuilt(m); p != nil && m.Enabled(ctx) && !p.properties.PrebuiltRenamedToSource { bmn, _ := m.(baseModuleName) name := bmn.BaseModuleName() if ctx.OtherModuleReverseDependencyVariantExists(name) { @@ -702,15 +702,10 @@ func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt M } // If source is not available or is disabled then always use the prebuilt. - if source == nil || !source.Enabled() { + if source == nil || !source.Enabled(ctx) { return true } - // If the use_source_config_var property is set then it overrides the prefer property setting. - if configVar := p.properties.Use_source_config_var; configVar != nil { - return !ctx.Config().VendorConfig(proptools.String(configVar.Config_namespace)).Bool(proptools.String(configVar.Var_name)) - } - // TODO: use p.Properties.Name and ctx.ModuleDir to override preference return Bool(p.properties.Prefer) } diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index 2241b0815..d775ac356 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -295,158 +295,6 @@ func TestPrebuilts(t *testing.T) { }`, prebuilt: []OsType{Android, buildOS}, }, - { - name: "prebuilt use_source_config_var={acme, use_source} - no var specified", - modules: ` - source { - name: "bar", - } - - prebuilt { - name: "bar", - use_source_config_var: {config_namespace: "acme", var_name: "use_source"}, - srcs: ["prebuilt_file"], - }`, - // When use_source_env is specified then it will use the prebuilt by default if the environment - // variable is not set. - prebuilt: []OsType{Android, buildOS}, - }, - { - name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=false", - modules: ` - source { - name: "bar", - } - - prebuilt { - name: "bar", - use_source_config_var: {config_namespace: "acme", var_name: "use_source"}, - srcs: ["prebuilt_file"], - }`, - preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) { - variables.VendorVars = map[string]map[string]string{ - "acme": { - "use_source": "false", - }, - } - }), - // Setting the environment variable named in use_source_env to false will cause the prebuilt to - // be used. - prebuilt: []OsType{Android, buildOS}, - }, - { - name: "apex_contributions supersedes any source preferred via use_source_config_var", - modules: ` - source { - name: "bar", - } - - prebuilt { - name: "bar", - use_source_config_var: {config_namespace: "acme", var_name: "use_source"}, - srcs: ["prebuilt_file"], - } - apex_contributions { - name: "my_mainline_module_contribution", - api_domain: "apexfoo", - // this metadata module contains prebuilt - contents: ["prebuilt_bar"], - } - all_apex_contributions { - name: "all_apex_contributions", - } - `, - preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) { - variables.VendorVars = map[string]map[string]string{ - "acme": { - "use_source": "true", - }, - } - variables.BuildFlags = map[string]string{ - "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contribution", - } - }), - // use_source_config_var indicates that source should be used - // but this is superseded by `my_mainline_module_contribution` - prebuilt: []OsType{Android, buildOS}, - }, - { - name: "apex_contributions supersedes any prebuilt preferred via use_source_config_var", - modules: ` - source { - name: "bar", - } - - prebuilt { - name: "bar", - use_source_config_var: {config_namespace: "acme", var_name: "use_source"}, - srcs: ["prebuilt_file"], - } - apex_contributions { - name: "my_mainline_module_contribution", - api_domain: "apexfoo", - // this metadata module contains source - contents: ["bar"], - } - all_apex_contributions { - name: "all_apex_contributions", - } - `, - preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) { - variables.VendorVars = map[string]map[string]string{ - "acme": { - "use_source": "false", - }, - } - variables.BuildFlags = map[string]string{ - "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contribution", - } - }), - // use_source_config_var indicates that prebuilt should be used - // but this is superseded by `my_mainline_module_contribution` - prebuilt: nil, - }, - { - name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true", - modules: ` - source { - name: "bar", - } - - prebuilt { - name: "bar", - use_source_config_var: {config_namespace: "acme", var_name: "use_source"}, - srcs: ["prebuilt_file"], - }`, - preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) { - variables.VendorVars = map[string]map[string]string{ - "acme": { - "use_source": "true", - }, - } - }), - // Setting the environment variable named in use_source_env to true will cause the source to be - // used. - prebuilt: nil, - }, - { - name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true, no source", - modules: ` - prebuilt { - name: "bar", - use_source_config_var: {config_namespace: "acme", var_name: "use_source"}, - srcs: ["prebuilt_file"], - }`, - preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) { - variables.VendorVars = map[string]map[string]string{ - "acme": { - "use_source": "true", - }, - } - }), - // Although the environment variable says to use source there is no source available. - prebuilt: []OsType{Android, buildOS}, - }, } fs := MockFS{ @@ -503,7 +351,7 @@ func TestPrebuilts(t *testing.T) { } }) - moduleIsDisabled := !foo.Module().Enabled() + moduleIsDisabled := !foo.Module().Enabled(PanickingConfigAndErrorContext(result.TestContext)) deps := foo.Module().(*sourceModule).deps if moduleIsDisabled { if len(deps) > 0 { @@ -762,45 +610,3 @@ func TestPrebuiltErrorCannotListBothSourceAndPrebuiltInContributions(t *testing. } `, selectMainlineModuleContritbutions) } - -// Test that apex_contributions of prebuilt modules are ignored in coverage builds -func TestSourceIsSelectedInCoverageBuilds(t *testing.T) { - prebuiltMainlineContributions := GroupFixturePreparers( - FixtureModifyProductVariables(func(variables FixtureProductVariables) { - variables.BuildFlags = map[string]string{ - "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_prebuilt_apex_contributions", - } - }), - FixtureMergeEnv(map[string]string{ - "EMMA_INSTRUMENT_FRAMEWORK": "true", - }), - ) - bp := ` - source { - name: "foo", - } - prebuilt { - name: "foo", - srcs: ["prebuilt_file"], - } - apex_contributions { - name: "my_prebuilt_apex_contributions", - api_domain: "my_mainline_module", - contents: [ - "prebuilt_foo", - ], - } - all_apex_contributions { - name: "all_apex_contributions", - } - ` - ctx := GroupFixturePreparers( - PrepareForTestWithArchMutator, - PrepareForTestWithPrebuilts, - FixtureRegisterWithContext(registerTestPrebuiltModules), - prebuiltMainlineContributions).RunTestWithBp(t, bp) - source := ctx.ModuleForTests("foo", "android_common").Module() - AssertBoolEquals(t, "Source should be preferred in coverage builds", true, !source.IsHideFromMake()) - prebuilt := ctx.ModuleForTests("prebuilt_foo", "android_common").Module() - AssertBoolEquals(t, "Prebuilt should not be preferred in coverage builds", false, !prebuilt.IsHideFromMake()) -} diff --git a/android/register.go b/android/register.go index d00c15fd0..aeb3b4c1b 100644 --- a/android/register.go +++ b/android/register.go @@ -16,8 +16,9 @@ package android import ( "fmt" - "github.com/google/blueprint" "reflect" + + "github.com/google/blueprint" ) // A sortable component is one whose registration order affects the order in which it is executed diff --git a/android/selects_test.go b/android/selects_test.go index f912ce626..d9499a500 100644 --- a/android/selects_test.go +++ b/android/selects_test.go @@ -28,6 +28,7 @@ func TestSelects(t *testing.T) { name string bp string provider selectsTestProvider + providers map[string]selectsTestProvider vendorVars map[string]map[string]string expectedError string }{ @@ -411,6 +412,42 @@ func TestSelects(t *testing.T) { }, }, { + name: "defaults applied to multiple modules", + bp: ` + my_module_type { + name: "foo2", + defaults: ["bar"], + my_string_list: select(soong_config_variable("my_namespace", "my_variable"), { + "a": ["a1"], + default: ["b1"], + }), + } + my_module_type { + name: "foo", + defaults: ["bar"], + my_string_list: select(soong_config_variable("my_namespace", "my_variable"), { + "a": ["a1"], + default: ["b1"], + }), + } + my_defaults { + name: "bar", + my_string_list: select(soong_config_variable("my_namespace", "my_variable2"), { + "a": ["a2"], + default: ["b2"], + }), + } + `, + providers: map[string]selectsTestProvider{ + "foo": { + my_string_list: &[]string{"b2", "b1"}, + }, + "foo2": { + my_string_list: &[]string{"b2", "b1"}, + }, + }, + }, + { name: "Replacing string list", bp: ` my_module_type { @@ -596,6 +633,61 @@ func TestSelects(t *testing.T) { }, expectedError: "Expected all branches of a select on condition boolean_var_for_testing\\(\\) to have type bool, found string", }, + { + name: "Assigning select to nonconfigurable bool", + bp: ` + my_module_type { + name: "foo", + my_nonconfigurable_bool: select(arch(), { + "x86_64": true, + default: false, + }), + } + `, + expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_bool"`, + }, + { + name: "Assigning select to nonconfigurable string", + bp: ` + my_module_type { + name: "foo", + my_nonconfigurable_string: select(arch(), { + "x86_64": "x86!", + default: "unknown!", + }), + } + `, + expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string"`, + }, + { + name: "Assigning appended selects to nonconfigurable string", + bp: ` + my_module_type { + name: "foo", + my_nonconfigurable_string: select(arch(), { + "x86_64": "x86!", + default: "unknown!", + }) + select(os(), { + "darwin": "_darwin!", + default: "unknown!", + }), + } + `, + expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string"`, + }, + { + name: "Assigning select to nonconfigurable string list", + bp: ` + my_module_type { + name: "foo", + my_nonconfigurable_string_list: select(arch(), { + "x86_64": ["foo", "bar"], + default: ["baz", "qux"], + }), + } + `, + expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string_list"`, + }, } for _, tc := range testCases { @@ -617,10 +709,19 @@ func TestSelects(t *testing.T) { result := fixtures.RunTestWithBp(t, tc.bp) if tc.expectedError == "" { - m := result.ModuleForTests("foo", "android_arm64_armv8-a") - p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey) - if !reflect.DeepEqual(p, tc.provider) { - t.Errorf("Expected:\n %q\ngot:\n %q", tc.provider.String(), p.String()) + if len(tc.providers) == 0 { + tc.providers = map[string]selectsTestProvider{ + "foo": tc.provider, + } + } + + for moduleName := range tc.providers { + expected := tc.providers[moduleName] + m := result.ModuleForTests(moduleName, "android_arm64_armv8-a") + p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey) + if !reflect.DeepEqual(p, expected) { + t.Errorf("Expected:\n %q\ngot:\n %q", expected.String(), p.String()) + } } } }) @@ -628,11 +729,14 @@ func TestSelects(t *testing.T) { } type selectsTestProvider struct { - my_bool *bool - my_string *string - my_string_list *[]string - my_paths *[]string - replacing_string_list *[]string + my_bool *bool + my_string *string + my_string_list *[]string + my_paths *[]string + replacing_string_list *[]string + my_nonconfigurable_bool *bool + my_nonconfigurable_string *string + my_nonconfigurable_string_list []string } func (p *selectsTestProvider) String() string { @@ -644,23 +748,42 @@ func (p *selectsTestProvider) String() string { if p.my_string != nil { myStringStr = *p.my_string } + myNonconfigurableStringStr := "nil" + if p.my_string != nil { + myNonconfigurableStringStr = *p.my_nonconfigurable_string + } return fmt.Sprintf(`selectsTestProvider { my_bool: %v, my_string: %s, my_string_list: %s, my_paths: %s, replacing_string_list %s, -}`, myBoolStr, myStringStr, p.my_string_list, p.my_paths, p.replacing_string_list) + my_nonconfigurable_bool: %v, + my_nonconfigurable_string: %s, + my_nonconfigurable_string_list: %s, +}`, + myBoolStr, + myStringStr, + p.my_string_list, + p.my_paths, + p.replacing_string_list, + p.my_nonconfigurable_bool, + myNonconfigurableStringStr, + p.my_nonconfigurable_string_list, + ) } var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]() type selectsMockModuleProperties struct { - My_bool proptools.Configurable[bool] - My_string proptools.Configurable[string] - My_string_list proptools.Configurable[[]string] - My_paths proptools.Configurable[[]string] `android:"path"` - Replacing_string_list proptools.Configurable[[]string] `android:"replace_instead_of_append,arch_variant"` + My_bool proptools.Configurable[bool] + My_string proptools.Configurable[string] + My_string_list proptools.Configurable[[]string] + My_paths proptools.Configurable[[]string] `android:"path"` + Replacing_string_list proptools.Configurable[[]string] `android:"replace_instead_of_append,arch_variant"` + My_nonconfigurable_bool *bool + My_nonconfigurable_string *string + My_nonconfigurable_string_list []string } type selectsMockModule struct { @@ -671,11 +794,14 @@ type selectsMockModule struct { func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) { SetProvider(ctx, selectsTestProviderKey, selectsTestProvider{ - my_bool: p.properties.My_bool.Get(ctx), - my_string: p.properties.My_string.Get(ctx), - my_string_list: p.properties.My_string_list.Get(ctx), - my_paths: p.properties.My_paths.Get(ctx), - replacing_string_list: p.properties.Replacing_string_list.Get(ctx), + my_bool: p.properties.My_bool.Get(ctx), + my_string: p.properties.My_string.Get(ctx), + my_string_list: p.properties.My_string_list.Get(ctx), + my_paths: p.properties.My_paths.Get(ctx), + replacing_string_list: p.properties.Replacing_string_list.Get(ctx), + my_nonconfigurable_bool: p.properties.My_nonconfigurable_bool, + my_nonconfigurable_string: p.properties.My_nonconfigurable_string, + my_nonconfigurable_string_list: p.properties.My_nonconfigurable_string_list, }) } diff --git a/android/singleton.go b/android/singleton.go index 76df1ebba..d364384e2 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -284,5 +284,5 @@ func (s *singletonContextAdaptor) moduleProvider(module blueprint.Module, provid } func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) { - s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args) + s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args...) } diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go index 90b49eb19..38db92995 100644 --- a/android/soong_config_modules.go +++ b/android/soong_config_modules.go @@ -64,6 +64,7 @@ type soongConfigModuleTypeImportProperties struct { // specified in `conditions_default` will only be used under the following conditions: // bool variable: the variable is unspecified or not set to a true value // value variable: the variable is unspecified +// list variable: the variable is unspecified // string variable: the variable is unspecified or the variable is set to a string unused in the // given module. For example, string variable `test` takes values: "a" and "b", // if the module contains a property `a` and `conditions_default`, when test=b, @@ -104,6 +105,12 @@ type soongConfigModuleTypeImportProperties struct { // cflags: ["-DWIDTH=DEFAULT"], // }, // }, +// impl: { +// srcs: ["impl/%s"], +// conditions_default: { +// srcs: ["impl/default.cpp"], +// }, +// }, // }, // } // @@ -122,6 +129,7 @@ type soongConfigModuleTypeImportProperties struct { // variables: ["board"], // bool_variables: ["feature"], // value_variables: ["width"], +// list_variables: ["impl"], // properties: ["cflags", "srcs"], // } // @@ -135,8 +143,10 @@ type soongConfigModuleTypeImportProperties struct { // $(call add_soong_config_var_value, acme, board, soc_a) // $(call add_soong_config_var_value, acme, feature, true) // $(call add_soong_config_var_value, acme, width, 200) +// $(call add_soong_config_var_value, acme, impl, foo.cpp bar.cpp) // -// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200". +// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200" and srcs +// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"]. // // Alternatively, if acme BoardConfig.mk file contained: // @@ -148,7 +158,9 @@ type soongConfigModuleTypeImportProperties struct { // SOONG_CONFIG_acme_feature := false // // Then libacme_foo would build with cflags: -// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT". +// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT" +// and with srcs: +// ["*.cpp", "impl/default.cpp"]. // // Similarly, if acme BoardConfig.mk file contained: // @@ -158,9 +170,13 @@ type soongConfigModuleTypeImportProperties struct { // feature \ // // SOONG_CONFIG_acme_board := soc_c +// SOONG_CONFIG_acme_impl := foo.cpp bar.cpp // // Then libacme_foo would build with cflags: -// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT". +// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT" +// and with srcs: +// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"]. +// func SoongConfigModuleTypeImportFactory() Module { module := &soongConfigModuleTypeImport{} @@ -201,6 +217,7 @@ type soongConfigModuleTypeModule struct { // // bool variable: the variable is unspecified or not set to a true value // value variable: the variable is unspecified +// list variable: the variable is unspecified // string variable: the variable is unspecified or the variable is set to a string unused in the // given module. For example, string variable `test` takes values: "a" and "b", // if the module contains a property `a` and `conditions_default`, when test=b, @@ -209,56 +226,63 @@ type soongConfigModuleTypeModule struct { // // For example, an Android.bp file could have: // -// soong_config_module_type { -// name: "acme_cc_defaults", -// module_type: "cc_defaults", -// config_namespace: "acme", -// variables: ["board"], -// bool_variables: ["feature"], -// value_variables: ["width"], -// properties: ["cflags", "srcs"], -// } -// -// soong_config_string_variable { -// name: "board", -// values: ["soc_a", "soc_b"], -// } -// -// acme_cc_defaults { -// name: "acme_defaults", -// cflags: ["-DGENERIC"], -// soong_config_variables: { -// board: { -// soc_a: { -// cflags: ["-DSOC_A"], -// }, -// soc_b: { -// cflags: ["-DSOC_B"], -// }, -// conditions_default: { -// cflags: ["-DSOC_DEFAULT"], -// }, +// soong_config_module_type { +// name: "acme_cc_defaults", +// module_type: "cc_defaults", +// config_namespace: "acme", +// variables: ["board"], +// bool_variables: ["feature"], +// value_variables: ["width"], +// list_variables: ["impl"], +// properties: ["cflags", "srcs"], +// } +// +// soong_config_string_variable { +// name: "board", +// values: ["soc_a", "soc_b"], +// } +// +// acme_cc_defaults { +// name: "acme_defaults", +// cflags: ["-DGENERIC"], +// soong_config_variables: { +// board: { +// soc_a: { +// cflags: ["-DSOC_A"], +// }, +// soc_b: { +// cflags: ["-DSOC_B"], // }, -// feature: { -// cflags: ["-DFEATURE"], -// conditions_default: { -// cflags: ["-DFEATURE_DEFAULT"], -// }, +// conditions_default: { +// cflags: ["-DSOC_DEFAULT"], // }, -// width: { -// cflags: ["-DWIDTH=%s"], -// conditions_default: { -// cflags: ["-DWIDTH=DEFAULT"], -// }, +// }, +// feature: { +// cflags: ["-DFEATURE"], +// conditions_default: { +// cflags: ["-DFEATURE_DEFAULT"], +// }, +// }, +// width: { +// cflags: ["-DWIDTH=%s"], +// conditions_default: { +// cflags: ["-DWIDTH=DEFAULT"], +// }, +// }, +// impl: { +// srcs: ["impl/%s"], +// conditions_default: { +// srcs: ["impl/default.cpp"], // }, // }, -// } +// }, +// } // -// cc_library { -// name: "libacme_foo", -// defaults: ["acme_defaults"], -// srcs: ["*.cpp"], -// } +// cc_library { +// name: "libacme_foo", +// defaults: ["acme_defaults"], +// srcs: ["*.cpp"], +// } // // If an acme BoardConfig.mk file contained: // @@ -270,8 +294,10 @@ type soongConfigModuleTypeModule struct { // SOONG_CONFIG_acme_board := soc_a // SOONG_CONFIG_acme_feature := true // SOONG_CONFIG_acme_width := 200 +// SOONG_CONFIG_acme_impl := foo.cpp bar.cpp // -// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE". +// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE" and srcs +// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"]. func SoongConfigModuleTypeFactory() Module { module := &soongConfigModuleTypeModule{} diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go index c78b72669..c910974f6 100644 --- a/android/soongconfig/modules.go +++ b/android/soongconfig/modules.go @@ -117,6 +117,10 @@ type ModuleTypeProperties struct { // inserted into the properties with %s substitution. Value_variables []string + // the list of SOONG_CONFIG list variables that this module type will read. Each value will be + // inserted into the properties with %s substitution. + List_variables []string + // the list of properties that this module type will extend. Properties []string } @@ -468,6 +472,18 @@ func newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) { }) } + for _, name := range props.List_variables { + if err := checkVariableName(name); err != nil { + return nil, []error{fmt.Errorf("list_variables %s", err)} + } + + mt.Variables = append(mt.Variables, &listVariable{ + baseVariable: baseVariable{ + variable: name, + }, + }) + } + return mt, nil } @@ -730,6 +746,90 @@ func (s *valueVariable) printfIntoPropertyRecursive(fieldName []string, propStru return nil } +// Struct to allow conditions set based on a list variable, supporting string substitution. +type listVariable struct { + baseVariable +} + +func (s *listVariable) variableValuesType() reflect.Type { + return emptyInterfaceType +} + +// initializeProperties initializes a property to zero value of typ with an additional conditions +// default field. +func (s *listVariable) initializeProperties(v reflect.Value, typ reflect.Type) { + initializePropertiesWithDefault(v, typ) +} + +// PropertiesToApply returns an interface{} value based on initializeProperties to be applied to +// the module. If the variable was not set, conditions_default interface will be returned; +// otherwise, the interface in values, without conditions_default will be returned with all +// appropriate string substitutions based on variable being set. +func (s *listVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) { + // If this variable was not referenced in the module, there are no properties to apply. + if !values.IsValid() || values.Elem().IsZero() { + return nil, nil + } + if !config.IsSet(s.variable) { + return conditionsDefaultField(values.Elem().Elem()).Interface(), nil + } + configValues := strings.Split(config.String(s.variable), " ") + + values = removeDefault(values) + propStruct := values.Elem() + if !propStruct.IsValid() { + return nil, nil + } + if err := s.printfIntoPropertyRecursive(nil, propStruct, configValues); err != nil { + return nil, err + } + + return values.Interface(), nil +} + +func (s *listVariable) printfIntoPropertyRecursive(fieldName []string, propStruct reflect.Value, configValues []string) error { + for i := 0; i < propStruct.NumField(); i++ { + field := propStruct.Field(i) + kind := field.Kind() + if kind == reflect.Ptr { + if field.IsNil() { + continue + } + field = field.Elem() + kind = field.Kind() + } + switch kind { + case reflect.Slice: + elemType := field.Type().Elem() + newLen := field.Len() * len(configValues) + newField := reflect.MakeSlice(field.Type(), 0, newLen) + for j := 0; j < field.Len(); j++ { + for _, configValue := range configValues { + res := reflect.Indirect(reflect.New(elemType)) + res.Set(field.Index(j)) + err := printfIntoProperty(res, configValue) + if err != nil { + fieldName = append(fieldName, propStruct.Type().Field(i).Name) + return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err) + } + newField = reflect.Append(newField, res) + } + } + field.Set(newField) + case reflect.Struct: + fieldName = append(fieldName, propStruct.Type().Field(i).Name) + if err := s.printfIntoPropertyRecursive(fieldName, field, configValues); err != nil { + return err + } + fieldName = fieldName[:len(fieldName)-1] + default: + fieldName = append(fieldName, propStruct.Type().Field(i).Name) + return fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, strings.Join(fieldName, "."), kind) + } + } + return nil +} + func printfIntoProperty(propertyValue reflect.Value, configValue string) error { s := propertyValue.String() @@ -739,7 +839,7 @@ func printfIntoProperty(propertyValue reflect.Value, configValue string) error { } if count > 1 { - return fmt.Errorf("value variable properties only support a single '%%'") + return fmt.Errorf("list/value variable properties only support a single '%%'") } if !strings.Contains(s, "%s") { diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go index 1da0b49ad..d76794ca5 100644 --- a/android/soongconfig/modules_test.go +++ b/android/soongconfig/modules_test.go @@ -291,11 +291,13 @@ func Test_createAffectablePropertiesType(t *testing.T) { type properties struct { A *string B bool + C []string } -type boolVarProps struct { +type varProps struct { A *string B bool + C []string Conditions_default *properties } @@ -311,6 +313,19 @@ type valueSoongConfigVars struct { My_value_var interface{} } +type listProperties struct { + C []string +} + +type listVarProps struct { + C []string + Conditions_default *listProperties +} + +type listSoongConfigVars struct { + List_var interface{} +} + func Test_PropertiesToApply_Bool(t *testing.T) { mt, _ := newModuleType(&ModuleTypeProperties{ Module_type: "foo", @@ -330,7 +345,7 @@ func Test_PropertiesToApply_Bool(t *testing.T) { Soong_config_variables boolSoongConfigVars }{ Soong_config_variables: boolSoongConfigVars{ - Bool_var: &boolVarProps{ + Bool_var: &varProps{ A: boolVarPositive.A, B: boolVarPositive.B, Conditions_default: conditionsDefault, @@ -373,6 +388,59 @@ func Test_PropertiesToApply_Bool(t *testing.T) { } } +func Test_PropertiesToApply_List(t *testing.T) { + mt, _ := newModuleType(&ModuleTypeProperties{ + Module_type: "foo", + Config_namespace: "bar", + List_variables: []string{"my_list_var"}, + Properties: []string{"c"}, + }) + conditionsDefault := &listProperties{ + C: []string{"default"}, + } + actualProps := &struct { + Soong_config_variables listSoongConfigVars + }{ + Soong_config_variables: listSoongConfigVars{ + List_var: &listVarProps{ + C: []string{"A=%s", "B=%s"}, + Conditions_default: conditionsDefault, + }, + }, + } + props := reflect.ValueOf(actualProps) + + testCases := []struct { + name string + config SoongConfig + wantProps []interface{} + }{ + { + name: "no_vendor_config", + config: Config(map[string]string{}), + wantProps: []interface{}{conditionsDefault}, + }, + { + name: "value_var_set", + config: Config(map[string]string{"my_list_var": "hello there"}), + wantProps: []interface{}{&listProperties{ + C: []string{"A=hello", "A=there", "B=hello", "B=there"}, + }}, + }, + } + + for _, tc := range testCases { + gotProps, err := PropertiesToApply(mt, props, tc.config) + if err != nil { + t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err) + } + + if !reflect.DeepEqual(gotProps, tc.wantProps) { + t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps) + } + } +} + func Test_PropertiesToApply_Value(t *testing.T) { mt, _ := newModuleType(&ModuleTypeProperties{ Module_type: "foo", @@ -388,7 +456,7 @@ func Test_PropertiesToApply_Value(t *testing.T) { Soong_config_variables valueSoongConfigVars }{ Soong_config_variables: valueSoongConfigVars{ - My_value_var: &boolVarProps{ + My_value_var: &varProps{ A: proptools.StringPtr("A=%s"), B: true, Conditions_default: conditionsDefault, @@ -524,7 +592,7 @@ func Test_PropertiesToApply_String_Error(t *testing.T) { Soong_config_variables stringSoongConfigVars }{ Soong_config_variables: stringSoongConfigVars{ - String_var: &boolVarProps{ + String_var: &varProps{ A: stringVarPositive.A, B: stringVarPositive.B, Conditions_default: conditionsDefault, diff --git a/android/test_suites.go b/android/test_suites.go index adcc15a6e..ff75f26bb 100644 --- a/android/test_suites.go +++ b/android/test_suites.go @@ -14,6 +14,11 @@ package android +import ( + "path/filepath" + "strings" +) + func init() { RegisterParallelSingletonType("testsuites", testSuiteFilesFactory) } @@ -23,8 +28,8 @@ func testSuiteFilesFactory() Singleton { } type testSuiteFiles struct { - robolectric WritablePath - ravenwood WritablePath + robolectric []Path + ravenwood []Path } type TestSuiteModule interface { @@ -48,53 +53,107 @@ func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) { }) t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"]) - ctx.Phony("robolectric-tests", t.robolectric) + ctx.Phony("robolectric-tests", t.robolectric...) t.ravenwood = ravenwoodTestSuite(ctx, files["ravenwood-tests"]) - ctx.Phony("ravenwood-tests", t.ravenwood) + ctx.Phony("ravenwood-tests", t.ravenwood...) } func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) { - ctx.DistForGoal("robolectric-tests", t.robolectric) - ctx.DistForGoal("ravenwood-tests", t.ravenwood) + ctx.DistForGoal("robolectric-tests", t.robolectric...) + ctx.DistForGoal("ravenwood-tests", t.ravenwood...) } -func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath { +func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) []Path { var installedPaths InstallPaths for _, module := range SortedKeys(files) { installedPaths = append(installedPaths, files[module]...) } - testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases") - outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip") + outputFile := pathForPackaging(ctx, "robolectric-tests.zip") rule := NewRuleBuilder(pctx, ctx) rule.Command().BuiltTool("soong_zip"). FlagWithOutput("-o ", outputFile). FlagWithArg("-P ", "host/testcases"). - FlagWithArg("-C ", testCasesDir.String()). + FlagWithArg("-C ", pathForTestCases(ctx).String()). FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()). + Flag("-sha256") // necessary to save cas_uploader's time + + testList := buildTestList(ctx, "robolectric-tests_list", installedPaths) + testListZipOutputFile := pathForPackaging(ctx, "robolectric-tests_list.zip") + + rule.Command().BuiltTool("soong_zip"). + FlagWithOutput("-o ", testListZipOutputFile). + FlagWithArg("-C ", pathForPackaging(ctx).String()). + FlagWithInput("-f ", testList). Flag("-sha256") + rule.Build("robolectric_tests_zip", "robolectric-tests.zip") - return outputFile + return []Path{outputFile, testListZipOutputFile} } -func ravenwoodTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath { +func ravenwoodTestSuite(ctx SingletonContext, files map[string]InstallPaths) []Path { var installedPaths InstallPaths for _, module := range SortedKeys(files) { installedPaths = append(installedPaths, files[module]...) } - testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases") - outputFile := PathForOutput(ctx, "packaging", "ravenwood-tests.zip") + outputFile := pathForPackaging(ctx, "ravenwood-tests.zip") rule := NewRuleBuilder(pctx, ctx) rule.Command().BuiltTool("soong_zip"). FlagWithOutput("-o ", outputFile). FlagWithArg("-P ", "host/testcases"). - FlagWithArg("-C ", testCasesDir.String()). + FlagWithArg("-C ", pathForTestCases(ctx).String()). FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()). + Flag("-sha256") // necessary to save cas_uploader's time + + testList := buildTestList(ctx, "ravenwood-tests_list", installedPaths) + testListZipOutputFile := pathForPackaging(ctx, "ravenwood-tests_list.zip") + + rule.Command().BuiltTool("soong_zip"). + FlagWithOutput("-o ", testListZipOutputFile). + FlagWithArg("-C ", pathForPackaging(ctx).String()). + FlagWithInput("-f ", testList). Flag("-sha256") + rule.Build("ravenwood_tests_zip", "ravenwood-tests.zip") + return []Path{outputFile, testListZipOutputFile} +} + +func buildTestList(ctx SingletonContext, listFile string, installedPaths InstallPaths) Path { + buf := &strings.Builder{} + for _, p := range installedPaths { + if p.Ext() != ".config" { + continue + } + pc, err := toTestListPath(p.String(), pathForTestCases(ctx).String(), "host/testcases") + if err != nil { + ctx.Errorf("Failed to convert path: %s, %v", p.String(), err) + continue + } + buf.WriteString(pc) + buf.WriteString("\n") + } + outputFile := pathForPackaging(ctx, listFile) + WriteFileRuleVerbatim(ctx, outputFile, buf.String()) return outputFile } + +func toTestListPath(path, relativeRoot, prefix string) (string, error) { + dest, err := filepath.Rel(relativeRoot, path) + if err != nil { + return "", err + } + return filepath.Join(prefix, dest), nil +} + +func pathForPackaging(ctx PathContext, pathComponents ...string) OutputPath { + pathComponents = append([]string{"packaging"}, pathComponents...) + return PathForOutput(ctx, pathComponents...) +} + +func pathForTestCases(ctx PathContext) InstallPath { + return pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases") +} diff --git a/android/test_suites_test.go b/android/test_suites_test.go new file mode 100644 index 000000000..db9a34d11 --- /dev/null +++ b/android/test_suites_test.go @@ -0,0 +1,117 @@ +// 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 android + +import ( + "path/filepath" + "testing" +) + +func TestBuildTestList(t *testing.T) { + t.Parallel() + ctx := GroupFixturePreparers( + prepareForFakeTestSuite, + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterParallelSingletonType("testsuites", testSuiteFilesFactory) + }), + ).RunTestWithBp(t, ` + fake_module { + name: "module1", + outputs: [ + "Test1/Test1.config", + "Test1/Test1.apk", + ], + test_suites: ["ravenwood-tests"], + } + fake_module { + name: "module2", + outputs: [ + "Test2/Test21/Test21.config", + "Test2/Test21/Test21.apk", + ], + test_suites: ["ravenwood-tests", "robolectric-tests"], + } + fake_module { + name: "module_without_config", + outputs: [ + "BadTest/BadTest.jar", + ], + test_suites: ["robolectric-tests"], + } + `) + + config := ctx.SingletonForTests("testsuites") + allOutputs := config.AllOutputs() + + wantContents := map[string]string{ + "robolectric-tests.zip": "", + "robolectric-tests_list.zip": "", + "robolectric-tests_list": `host/testcases/Test2/Test21/Test21.config +`, + "ravenwood-tests.zip": "", + "ravenwood-tests_list.zip": "", + "ravenwood-tests_list": `host/testcases/Test1/Test1.config +host/testcases/Test2/Test21/Test21.config +`, + } + for _, output := range allOutputs { + want, ok := wantContents[filepath.Base(output)] + if !ok { + t.Errorf("unexpected output: %q", output) + continue + } + + got := "" + if want != "" { + got = ContentFromFileRuleForTests(t, ctx.TestContext, config.MaybeOutput(output)) + } + + if want != got { + t.Errorf("want %q, got %q", want, got) + } + } +} + +type fake_module struct { + ModuleBase + props struct { + Outputs []string + Test_suites []string + } +} + +func fakeTestSuiteFactory() Module { + module := &fake_module{} + base := module.base() + module.AddProperties(&base.nameProperties, &module.props) + InitAndroidModule(module) + return module +} + +var prepareForFakeTestSuite = GroupFixturePreparers( + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("fake_module", fakeTestSuiteFactory) + }), +) + +func (f *fake_module) GenerateAndroidBuildActions(ctx ModuleContext) { + for _, output := range f.props.Outputs { + ctx.InstallFile(pathForTestCases(ctx), output, nil) + } +} + +func (f *fake_module) TestSuites() []string { + return f.props.Test_suites +} diff --git a/android/testing.go b/android/testing.go index a67624a3f..6518f4a53 100644 --- a/android/testing.go +++ b/android/testing.go @@ -1287,3 +1287,21 @@ func EnsureListContainsSuffix(t *testing.T, result []string, expected string) { t.Errorf("%q is not found in %v", expected, result) } } + +type panickingConfigAndErrorContext struct { + ctx *TestContext +} + +func (ctx *panickingConfigAndErrorContext) OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{}) { + panic(ctx.ctx.PropertyErrorf(module, property, fmt, args...).Error()) +} + +func (ctx *panickingConfigAndErrorContext) Config() Config { + return ctx.ctx.Config() +} + +func PanickingConfigAndErrorContext(ctx *TestContext) ConfigAndErrorContext { + return &panickingConfigAndErrorContext{ + ctx: ctx, + } +} diff --git a/android/variable.go b/android/variable.go index 0040d836d..419bd61de 100644 --- a/android/variable.go +++ b/android/variable.go @@ -20,8 +20,6 @@ import ( "runtime" "strings" - "android/soong/bazel" - "github.com/google/blueprint/proptools" ) @@ -60,16 +58,16 @@ type variableProperties struct { // unbundled_build is a catch-all property to annotate modules that don't build in one or // more unbundled branches, usually due to dependencies missing from the manifest. Unbundled_build struct { - Enabled *bool `android:"arch_variant"` + Enabled proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"` } `android:"arch_variant"` // similar to `Unbundled_build`, but `Always_use_prebuilt_sdks` means that it uses prebuilt // sdk specifically. Always_use_prebuilt_sdks struct { - Enabled *bool `android:"arch_variant"` + Enabled proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"` } `android:"arch_variant"` - Malloc_not_svelte struct { + Malloc_low_memory struct { Cflags []string `android:"arch_variant"` Shared_libs []string `android:"arch_variant"` Whole_static_libs []string `android:"arch_variant"` @@ -280,7 +278,7 @@ type ProductVariables struct { Unbundled_build_image *bool `json:",omitempty"` Always_use_prebuilt_sdks *bool `json:",omitempty"` Skip_boot_jars_check *bool `json:",omitempty"` - Malloc_not_svelte *bool `json:",omitempty"` + Malloc_low_memory *bool `json:",omitempty"` Malloc_zero_contents *bool `json:",omitempty"` Malloc_pattern_fill_contents *bool `json:",omitempty"` Safestack *bool `json:",omitempty"` @@ -492,10 +490,6 @@ type ProductVariables struct { CheckVendorSeappViolations *bool `json:",omitempty"` - // PartitionVarsForBazelMigrationOnlyDoNotUse are extra variables that are used to define the - // partition images. They should not be read from soong modules. - PartitionVarsForBazelMigrationOnlyDoNotUse PartitionVariables `json:",omitempty"` - BuildFlags map[string]string `json:",omitempty"` BuildFromSourceStub *bool `json:",omitempty"` @@ -618,7 +612,7 @@ func (v *ProductVariables) SetDefaultConfig() { AAPTCharacteristics: stringPtr("nosdcard"), AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"}, - Malloc_not_svelte: boolPtr(true), + Malloc_low_memory: boolPtr(false), Malloc_zero_contents: boolPtr(true), Malloc_pattern_fill_contents: boolPtr(false), Safestack: boolPtr(false), @@ -644,387 +638,6 @@ func (this *ProductVariables) GetBuildFlagBool(flag string) bool { return val == "true" } -// ProductConfigContext requires the access to the Module to get product config properties. -type ProductConfigContext interface { - Module() Module -} - -// ProductConfigOrSoongConfigProperty represents either a soong config variable + its value -// or a product config variable. You can get both a ConfigurationAxis and a SelectKey from it -// for use in bazel attributes. ProductVariableProperties() will return a map from properties -> -// this interface -> property structs for use in bp2build converters -type ProductConfigOrSoongConfigProperty interface { - // Name of the product variable or soong config variable - Name() string - // AlwaysEmit returns true for soong config variables but false for product variables. This - // is intended to indicate if we need to always emit empty lists in the select statements. - AlwaysEmit() bool - // ConfigurationAxis returns the bazel.ConfigurationAxis that represents this variable. The - // configuration axis will change depending on the variable and whether it's arch/os variant - // as well. - ConfigurationAxis() bazel.ConfigurationAxis - // SelectKey returns a string that represents the key of a select branch, however, it is not - // actually the real label written out to the build file. - // this.ConfigurationAxis().SelectKey(this.SelectKey()) will give the actual label. - SelectKey() string -} - -// ProductConfigProperty represents a product config variable, and if it is arch-variant or not. -type ProductConfigProperty struct { - // The name of the product variable, e.g. "safestack", "malloc_not_svelte", - // "board" - name string - - arch string -} - -func (p ProductConfigProperty) Name() string { - return p.name -} - -func (p ProductConfigProperty) AlwaysEmit() bool { - return false -} - -func (p ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis { - return bazel.ProductVariableConfigurationAxis(p.arch != "", p.name+"__"+p.arch) -} - -func (p ProductConfigProperty) SelectKey() string { - if p.arch == "" { - return strings.ToLower(p.name) - } else { - return strings.ToLower(p.name + "-" + p.arch) - } -} - -// SoongConfigProperty represents a soong config variable, its value if it's a string variable, -// and if it's dependent on the OS or not -type SoongConfigProperty struct { - name string - namespace string - // Can be an empty string for bool/value soong config variables - value string - // If there is a target: field inside a soong config property struct, the os that it selects - // on will be represented here. - os string -} - -func (p SoongConfigProperty) Name() string { - return p.name -} - -func (p SoongConfigProperty) AlwaysEmit() bool { - return true -} - -func (p SoongConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis { - return bazel.ProductVariableConfigurationAxis(false, p.namespace+"__"+p.name+"__"+p.os) -} - -// SelectKey returns the literal string that represents this variable in a BUILD -// select statement. -func (p SoongConfigProperty) SelectKey() string { - // p.value being conditions_default can happen with or without a desired os. When not using - // an os, we want to emit literally just //conditions:default in the select statement, but - // when using an os, we want to emit namespace__name__conditions_default__os, so that - // the branch is only taken if the variable is not set, and we're on the desired os. - // ConfigurationAxis#SelectKey will map the conditions_default result of this function to - // //conditions:default. - if p.value == bazel.ConditionsDefaultConfigKey && p.os == "" { - return bazel.ConditionsDefaultConfigKey - } - - parts := []string{p.namespace, p.name} - if p.value != "" && p.value != bazel.ConditionsDefaultSelectKey { - parts = append(parts, p.value) - } - if p.os != "" { - parts = append(parts, p.os) - } - - // e.g. acme__feature1, android__board__soc_a, my_namespace__my_variables__my_value__my_os - return strings.ToLower(strings.Join(parts, "__")) -} - -// ProductConfigProperties is a map of maps to group property values according -// their property name and the product config variable they're set under. -// -// The outer map key is the name of the property, like "cflags". -// -// The inner map key is a ProductConfigProperty, which is a struct of product -// variable name, namespace, and the "full configuration" of the product -// variable. -// -// e.g. product variable name: board, namespace: acme, full config: vendor_chip_foo -// -// The value of the map is the interface{} representing the value of the -// property, like ["-DDEFINES"] for cflags. -type ProductConfigProperties map[string]map[ProductConfigOrSoongConfigProperty]interface{} - -func (p *ProductConfigProperties) AddProductConfigProperty( - propertyName, productVariableName, arch string, propertyValue interface{}) { - - productConfigProp := ProductConfigProperty{ - name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board - arch: arch, // e.g. "", x86, arm64 - } - - p.AddEitherProperty(propertyName, productConfigProp, propertyValue) -} - -func (p *ProductConfigProperties) AddSoongConfigProperty( - propertyName, namespace, variableName, value, os string, propertyValue interface{}) { - - soongConfigProp := SoongConfigProperty{ - namespace: namespace, - name: variableName, // e.g. size, feature1, feature2, FEATURE3, board - value: value, - os: os, // e.g. android, linux_x86 - } - - p.AddEitherProperty(propertyName, soongConfigProp, propertyValue) -} - -func (p *ProductConfigProperties) AddEitherProperty( - propertyName string, key ProductConfigOrSoongConfigProperty, propertyValue interface{}) { - if (*p)[propertyName] == nil { - (*p)[propertyName] = make(map[ProductConfigOrSoongConfigProperty]interface{}) - } - - if existing, ok := (*p)[propertyName][key]; ok { - switch dst := existing.(type) { - case []string: - src, ok := propertyValue.([]string) - if !ok { - panic("Conflicting types") - } - dst = append(dst, src...) - (*p)[propertyName][key] = dst - default: - if existing != propertyValue { - panic(fmt.Errorf("TODO: handle merging value %#v", existing)) - } - } - } else { - (*p)[propertyName][key] = propertyValue - } -} - -// maybeExtractConfigVarProp attempts to read this value as a config var struct -// wrapped by interfaces and ptrs. If it's not the right type, the second return -// value is false. -func maybeExtractConfigVarProp(v reflect.Value) (reflect.Value, bool) { - if v.Kind() == reflect.Interface { - // The conditions_default value can be either - // 1) an ptr to an interface of a struct (bool config variables and product variables) - // 2) an interface of 1) (config variables with nested structs, like string vars) - v = v.Elem() - } - if v.Kind() != reflect.Ptr { - return v, false - } - v = reflect.Indirect(v) - if v.Kind() == reflect.Interface { - // Extract the struct from the interface - v = v.Elem() - } - - if !v.IsValid() { - return v, false - } - - if v.Kind() != reflect.Struct { - return v, false - } - return v, true -} - -func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(variableValues reflect.Value, arch string) { - // Example of product_variables: - // - // product_variables: { - // malloc_not_svelte: { - // shared_libs: ["malloc_not_svelte_shared_lib"], - // whole_static_libs: ["malloc_not_svelte_whole_static_lib"], - // exclude_static_libs: [ - // "malloc_not_svelte_static_lib_excludes", - // "malloc_not_svelte_whole_static_lib_excludes", - // ], - // }, - // }, - - for i := 0; i < variableValues.NumField(); i++ { - // e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc. - productVariableName := variableValues.Type().Field(i).Name - - variableValue := variableValues.Field(i) - // Check if any properties were set for the module - if variableValue.IsZero() { - // e.g. feature1: {}, malloc_not_svelte: {} - continue - } - - for j := 0; j < variableValue.NumField(); j++ { - property := variableValue.Field(j) - // e.g. Asflags, Cflags, Enabled, etc. - propertyName := variableValue.Type().Field(j).Name - if property.Kind() != reflect.Interface { - productConfigProperties.AddProductConfigProperty(propertyName, productVariableName, arch, property.Interface()) - } - } - } - -} - -func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties(namespace string, soongConfigVariablesStruct reflect.Value) error { - // - // Example of soong_config_variables: - // - // soong_config_variables: { - // feature1: { - // conditions_default: { - // ... - // }, - // cflags: ... - // }, - // feature2: { - // cflags: ... - // conditions_default: { - // ... - // }, - // }, - // board: { - // soc_a: { - // ... - // }, - // soc_b: { - // ... - // }, - // soc_c: {}, - // conditions_default: { - // ... - // }, - // }, - // } - for i := 0; i < soongConfigVariablesStruct.NumField(); i++ { - // e.g. feature1, feature2, board - variableName := soongConfigVariablesStruct.Type().Field(i).Name - variableStruct := soongConfigVariablesStruct.Field(i) - // Check if any properties were set for the module - if variableStruct.IsZero() { - // e.g. feature1: {} - continue - } - - // Unlike product variables, config variables require a few more - // indirections to extract the struct from the reflect.Value. - if v, ok := maybeExtractConfigVarProp(variableStruct); ok { - variableStruct = v - } else if !v.IsValid() { - // Skip invalid variables which may not used, else leads to panic - continue - } - - for j := 0; j < variableStruct.NumField(); j++ { - propertyOrStruct := variableStruct.Field(j) - // propertyOrValueName can either be: - // - A property, like: Asflags, Cflags, Enabled, etc. - // - A soong config string variable's value, like soc_a, soc_b, soc_c in the example above - // - "conditions_default" - propertyOrValueName := variableStruct.Type().Field(j).Name - - // If the property wasn't set, no need to pass it along - if propertyOrStruct.IsZero() { - continue - } - - if v, ok := maybeExtractConfigVarProp(propertyOrStruct); ok { - // The field is a struct, which is used by: - // 1) soong_config_string_variables - // - // soc_a: { - // cflags: ..., - // } - // - // soc_b: { - // cflags: ..., - // } - // - // 2) conditions_default structs for all soong config variable types. - // - // conditions_default: { - // cflags: ..., - // static_libs: ... - // } - // - // This means that propertyOrValueName is either conditions_default, or a soong - // config string variable's value. - field := v - // Iterate over fields of this struct prop. - for k := 0; k < field.NumField(); k++ { - // For product variables, zero values are irrelevant; however, for soong config variables, - // empty values are relevant because there can also be a conditions default which is not - // applied for empty variables. - if field.Field(k).IsZero() && namespace == "" { - continue - } - - propertyName := field.Type().Field(k).Name - if propertyName == "Target" { - productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), field.Field(k)) - } else if propertyName == "Arch" || propertyName == "Multilib" { - return fmt.Errorf("Arch/Multilib are not currently supported in soong config variable structs") - } else { - productConfigProperties.AddSoongConfigProperty(propertyName, namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), "", field.Field(k).Interface()) - } - } - } else if propertyOrStruct.Kind() != reflect.Interface { - // If not an interface, then this is not a conditions_default or - // a struct prop. That is, this is a bool/value config variable. - if propertyOrValueName == "Target" { - productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, "", propertyOrStruct) - } else if propertyOrValueName == "Arch" || propertyOrValueName == "Multilib" { - return fmt.Errorf("Arch/Multilib are not currently supported in soong config variable structs") - } else { - productConfigProperties.AddSoongConfigProperty(propertyOrValueName, namespace, variableName, "", "", propertyOrStruct.Interface()) - } - } - } - } - return nil -} - -func (productConfigProperties *ProductConfigProperties) AddSoongConfigPropertiesFromTargetStruct(namespace, soongConfigVariableName string, soongConfigVariableValue string, targetStruct reflect.Value) { - // targetStruct will be a struct with fields like "android", "host", "arm", "x86", - // "android_arm", etc. The values of each of those fields will be a regular property struct. - for i := 0; i < targetStruct.NumField(); i++ { - targetFieldName := targetStruct.Type().Field(i).Name - archOrOsSpecificStruct := targetStruct.Field(i) - for j := 0; j < archOrOsSpecificStruct.NumField(); j++ { - property := archOrOsSpecificStruct.Field(j) - // e.g. Asflags, Cflags, Enabled, etc. - propertyName := archOrOsSpecificStruct.Type().Field(j).Name - - if targetFieldName == "Android" { - productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, "android", property.Interface()) - } else if targetFieldName == "Host" { - for _, os := range osTypeList { - if os.Class == Host { - productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, os.Name, property.Interface()) - } - } - } else if !archOrOsSpecificStruct.IsZero() { - // One problem with supporting additional fields is that if multiple branches of - // "target" overlap, we don't want them to be in the same select statement (aka - // configuration axis). "android" and "host" are disjoint, so it's ok that we only - // have 2 axes right now. (soongConfigVariables and soongConfigVariablesPlusOs) - panic("TODO: support other target types in soong config variable structs: " + targetFieldName) - } - } - } -} - func VariableMutator(mctx BottomUpMutatorContext) { var module Module var ok bool diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go index 9d61e1cf9..8a8bb2eaa 100644 --- a/androidmk/androidmk/android.go +++ b/androidmk/androidmk/android.go @@ -151,7 +151,7 @@ func init() { "LOCAL_CLANG_CFLAGS": "clang_cflags", "LOCAL_YACCFLAGS": "yacc.flags", "LOCAL_SANITIZE_RECOVER": "sanitize.recover", - "LOCAL_LOGTAGS_FILES": "logtags", + "LOCAL_SOONG_LOGTAGS_FILES": "logtags", "LOCAL_EXPORT_HEADER_LIBRARY_HEADERS": "export_header_lib_headers", "LOCAL_EXPORT_SHARED_LIBRARY_HEADERS": "export_shared_lib_headers", "LOCAL_EXPORT_STATIC_LIBRARY_HEADERS": "export_static_lib_headers", diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go index 3e44f0b1b..726041c60 100644 --- a/apex/aconfig_test.go +++ b/apex/aconfig_test.go @@ -162,6 +162,21 @@ func TestValidationAcrossContainersExportedPass(t *testing.T) { name: "server_configurable_flags", srcs: ["server_configurable_flags.cc"], } + cc_library { + name: "libbase", + srcs: ["libbase.cc"], + apex_available: [ + "myapex", + ], + } + cc_library { + name: "libaconfig_storage_read_api_cc", + srcs: ["libaconfig_storage_read_api_cc.cc"], + } + cc_library { + name: "libaconfig_storage_protos_cc", + srcs: ["libaconfig_storage_protos_cc.cc"], + } aconfig_declarations { name: "my_aconfig_declarations_bar", package: "com.example.package", @@ -410,6 +425,21 @@ func TestValidationAcrossContainersNotExportedFail(t *testing.T) { name: "server_configurable_flags", srcs: ["server_configurable_flags.cc"], } + cc_library { + name: "libbase", + srcs: ["libbase.cc"], + apex_available: [ + "myapex", + ], + } + cc_library { + name: "libaconfig_storage_read_api_cc", + srcs: ["libaconfig_storage_read_api_cc.cc"], + } + cc_library { + name: "libaconfig_storage_protos_cc", + srcs: ["libaconfig_storage_protos_cc.cc"], + } aconfig_declarations { name: "my_aconfig_declarations_foo", package: "com.example.package", @@ -460,6 +490,21 @@ func TestValidationAcrossContainersNotExportedFail(t *testing.T) { name: "server_configurable_flags", srcs: ["server_configurable_flags.cc"], } + cc_library { + name: "libbase", + srcs: ["libbase.cc"], + apex_available: [ + "myapex", + ], + } + cc_library { + name: "libaconfig_storage_read_api_cc", + srcs: ["libaconfig_storage_read_api_cc.cc"], + } + cc_library { + name: "libaconfig_storage_protos_cc", + srcs: ["libaconfig_storage_protos_cc.cc"], + } aconfig_declarations { name: "my_aconfig_declarations_foo", package: "com.example.package", diff --git a/apex/apex.go b/apex/apex.go index 2e7fbf6ac..40eb712ab 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -73,7 +73,7 @@ func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { // Run mark_platform_availability before the apexMutator as the apexMutator needs to know whether // it should create a platform variant. ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel() - ctx.BottomUp("apex", apexMutator).Parallel() + ctx.Transition("apex", &apexTransitionMutator{}) ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel() ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel() // Register after apex_info mutator so that it can use ApexVariationName @@ -1077,20 +1077,24 @@ type ApexInfoMutator interface { // specific variant to modules that support the ApexInfoMutator. // It also propagates updatable=true to apps of updatable apexes func apexInfoMutator(mctx android.TopDownMutatorContext) { - if !mctx.Module().Enabled() { + if !mctx.Module().Enabled(mctx) { return } if a, ok := mctx.Module().(ApexInfoMutator); ok { a.ApexInfoMutator(mctx) } + + if am, ok := mctx.Module().(android.ApexModule); ok { + android.ApexInfoMutator(mctx, am) + } enforceAppUpdatability(mctx) } // apexStrictUpdatibilityLintMutator propagates strict_updatability_linting to transitive deps of a mainline module // This check is enforced for updatable modules func apexStrictUpdatibilityLintMutator(mctx android.TopDownMutatorContext) { - if !mctx.Module().Enabled() { + if !mctx.Module().Enabled(mctx) { return } if apex, ok := mctx.Module().(*apexBundle); ok && apex.checkStrictUpdatabilityLinting() { @@ -1117,7 +1121,7 @@ func apexStrictUpdatibilityLintMutator(mctx android.TopDownMutatorContext) { // enforceAppUpdatability propagates updatable=true to apps of updatable apexes func enforceAppUpdatability(mctx android.TopDownMutatorContext) { - if !mctx.Module().Enabled() { + if !mctx.Module().Enabled(mctx) { return } if apex, ok := mctx.Module().(*apexBundle); ok && apex.Updatable() { @@ -1195,7 +1199,7 @@ func (a *apexBundle) checkStrictUpdatabilityLinting() bool { // unique apex variations for this module. See android/apex.go for more about unique apex variant. // TODO(jiyong): move this to android/apex.go? func apexUniqueVariationsMutator(mctx android.BottomUpMutatorContext) { - if !mctx.Module().Enabled() { + if !mctx.Module().Enabled(mctx) { return } if am, ok := mctx.Module().(android.ApexModule); ok { @@ -1207,7 +1211,7 @@ func apexUniqueVariationsMutator(mctx android.BottomUpMutatorContext) { // the apex in order to retrieve its contents later. // TODO(jiyong): move this to android/apex.go? func apexTestForDepsMutator(mctx android.BottomUpMutatorContext) { - if !mctx.Module().Enabled() { + if !mctx.Module().Enabled(mctx) { return } if am, ok := mctx.Module().(android.ApexModule); ok { @@ -1222,7 +1226,7 @@ func apexTestForDepsMutator(mctx android.BottomUpMutatorContext) { // TODO(jiyong): move this to android/apex.go? func apexTestForMutator(mctx android.BottomUpMutatorContext) { - if !mctx.Module().Enabled() { + if !mctx.Module().Enabled(mctx) { return } if _, ok := mctx.Module().(android.ApexModule); ok { @@ -1284,40 +1288,41 @@ func markPlatformAvailability(mctx android.BottomUpMutatorContext) { } } -// apexMutator visits each module and creates apex variations if the module was marked in the -// previous run of apexInfoMutator. -func apexMutator(mctx android.BottomUpMutatorContext) { - if !mctx.Module().Enabled() { - return - } - - // This is the usual path. - if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { - android.CreateApexVariations(mctx, am) - return - } +type apexTransitionMutator struct{} +func (a *apexTransitionMutator) Split(ctx android.BaseModuleContext) []string { // apexBundle itself is mutated so that it and its dependencies have the same apex variant. - // Note that a default variation "" is also created as an alias, and the default dependency - // variation is set to the default variation. This is to allow an apex to depend on another - // module which is outside of the apex. This is because the dependent module is not mutated - // for this apex variant. - createApexVariation := func(apexBundleName string) { - defaultVariation := "" - mctx.SetDefaultDependencyVariation(&defaultVariation) - mctx.CreateVariations(apexBundleName) - mctx.CreateAliasVariation(defaultVariation, apexBundleName) - } - - if ai, ok := mctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) { - createApexVariation(ai.ApexVariationName()) - } else if o, ok := mctx.Module().(*OverrideApex); ok { + if ai, ok := ctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) { + return []string{ai.ApexVariationName()} + } else if o, ok := ctx.Module().(*OverrideApex); ok { apexBundleName := o.GetOverriddenModuleName() if apexBundleName == "" { - mctx.ModuleErrorf("base property is not set") - return + ctx.ModuleErrorf("base property is not set") } - createApexVariation(apexBundleName) + return []string{apexBundleName} + } + return []string{""} +} + +func (a *apexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + return sourceVariation +} + +func (a *apexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { + return android.IncomingApexTransition(ctx, incomingVariation) + } else if ai, ok := ctx.Module().(ApexInfoMutator); ok { + return ai.ApexVariationName() + } else if o, ok := ctx.Module().(*OverrideApex); ok { + return o.GetOverriddenModuleName() + } + + return "" +} + +func (a *apexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { + android.MutateApexTransition(ctx, variation) } } @@ -1335,7 +1340,7 @@ func apexModuleTypeRequiresVariant(module ApexInfoMutator) bool { // See android.UpdateDirectlyInAnyApex // TODO(jiyong): move this to android/apex.go? func apexDirectlyInAnyMutator(mctx android.BottomUpMutatorContext) { - if !mctx.Module().Enabled() { + if !mctx.Module().Enabled(mctx) { return } if am, ok := mctx.Module().(android.ApexModule); ok { @@ -1969,7 +1974,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok { return false } - if mod, ok := child.(android.Module); ok && !mod.Enabled() { + if mod, ok := child.(android.Module); ok && !mod.Enabled(ctx) { return false } depName := ctx.OtherModuleName(child) diff --git a/apex/apex_test.go b/apex/apex_test.go index 0825ab974..9a5c2b49b 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -3671,34 +3671,13 @@ func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleN func vndkLibrariesTxtFiles(vers ...string) (result string) { for _, v := range vers { - if v == "current" { - for _, txt := range []string{"vndkcore", "vndksp", "vndkprivate", "vndkproduct"} { - result += ` - ` + txt + `_libraries_txt { - name: "` + txt + `.libraries.txt", - insert_vndk_version: true, - } - ` - } + for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate", "vndkproduct"} { result += ` - llndk_libraries_txt { - name: "llndk.libraries.txt", - } - llndk_libraries_txt_for_apex { - name: "llndk.libraries.txt.apex", - stem: "llndk.libraries.txt", - insert_vndk_version: true, - } - ` - } else { - for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate", "vndkproduct"} { - result += ` prebuilt_etc { name: "` + txt + `.libraries.` + v + `.txt", src: "dummy.txt", } ` - } } } return @@ -5622,8 +5601,21 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { compile_dex: true, } ` + // This test disables libbar, which causes the ComponentDepsMutator to add + // deps on libbar.stubs and other sub-modules that don't exist. We can + // enable AllowMissingDependencies to work around that, but enabling that + // causes extra checks for missing source files to dex_bootjars, so add those + // to the mock fs as well. + preparer2 := android.GroupFixturePreparers( + preparer, + android.PrepareForTestWithAllowMissingDependencies, + android.FixtureMergeMockFs(map[string][]byte{ + "build/soong/scripts/check_boot_jars/package_allowed_list.txt": nil, + "frameworks/base/config/boot-profile.txt": nil, + }), + ) - ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) + ctx := testDexpreoptWithApexes(t, bp, "", preparer2, fragment) checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") @@ -9241,7 +9233,7 @@ func TestPrebuiltStubLibDep(t *testing.T) { continue } mod := ctx.ModuleForTests(modName, variant).Module().(*cc.Module) - if !mod.Enabled() || mod.IsHideFromMake() { + if !mod.Enabled(android.PanickingConfigAndErrorContext(ctx)) || mod.IsHideFromMake() { continue } for _, ent := range android.AndroidMkEntriesForTest(t, ctx, mod) { @@ -10691,6 +10683,21 @@ func TestAconfigFilesJavaAndCcDeps(t *testing.T) { name: "server_configurable_flags", srcs: ["server_configurable_flags.cc"], } + cc_library { + name: "libbase", + srcs: ["libbase.cc"], + apex_available: [ + "myapex", + ], + } + cc_library { + name: "libaconfig_storage_read_api_cc", + srcs: ["libaconfig_storage_read_api_cc.cc"], + } + cc_library { + name: "libaconfig_storage_protos_cc", + srcs: ["libaconfig_storage_protos_cc.cc"], + } `) mod := ctx.ModuleForTests("myapex", "android_common_myapex") @@ -11413,6 +11420,7 @@ func TestAconfifDeclarationsValidation(t *testing.T) { aconfig_declarations { name: "%[1]s", package: "com.example.package", + container: "system", srcs: [ "%[1]s.aconfig", ], diff --git a/bin/build-flag b/bin/build-flag new file mode 100755 index 000000000..dc404bc97 --- /dev/null +++ b/bin/build-flag @@ -0,0 +1,28 @@ +#!/bin/bash -eu +# +# Copyright 2017 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. + +source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh +require_top + +# Save the current PWD for use in soong_ui +export ORIGINAL_PWD=${PWD} +export TOP=$(gettop) +source ${TOP}/build/soong/scripts/microfactory.bash + +soong_build_go build-flag android/soong/cmd/release_config/build_flag + +cd ${TOP} +exec "$(getoutdir)/build-flag" "$@" diff --git a/cc/Android.bp b/cc/Android.bp index 5ba94270b..9ce89330e 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -96,7 +96,6 @@ bootstrap_go_package { "gen_test.go", "genrule_test.go", "library_headers_test.go", - "library_stub_test.go", "library_test.go", "lto_test.go", "ndk_test.go", diff --git a/cc/androidmk.go b/cc/androidmk.go index ef2636625..df356df0e 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -88,7 +88,7 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { if len(c.Properties.Logtags) > 0 { - entries.AddStrings("LOCAL_LOGTAGS_FILES", c.Properties.Logtags...) + entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", c.logtagsPaths.Strings()...) } // Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make // world, even if it is an empty list. In the Make world, @@ -119,16 +119,15 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { } else if c.InProduct() { entries.SetBool("LOCAL_IN_PRODUCT", true) } - if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake { - // Make the SDK variant uninstallable so that there are not two rules to install - // to the same location. - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) + if c.Properties.SdkAndPlatformVariantVisibleToMake { // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite // dependencies to the .sdk suffix when building a module that uses the SDK. entries.SetString("SOONG_SDK_VARIANT_MODULES", "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))") } android.SetAconfigFileMkEntries(c.AndroidModuleBase(), entries, c.mergedAconfigFiles) + + entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", c.IsSkipInstall()) }, }, ExtraFooters: []android.AndroidMkExtraFootersFunc{ diff --git a/cc/builder.go b/cc/builder.go index 845176e09..e255cbebb 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -608,6 +608,10 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs ccCmd = "clang++" moduleFlags = cppflags moduleToolingFlags = toolingCppflags + case ".rs": + // A source provider (e.g. rust_bindgen) may provide both rs and c files. + // Ignore the rs files. + continue case ".h", ".hpp": ctx.PropertyErrorf("srcs", "Header file %s is not supported, instead use export_include_dirs or local_include_dirs.", srcFile) continue @@ -855,8 +859,8 @@ func transformObjToDynamicBinary(ctx android.ModuleContext, // into a single .ldump sAbi dump file func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path, baseName string, exportedIncludeDirs []string, symbolFile android.OptionalPath, - excludedSymbolVersions, excludedSymbolTags []string, - api string) android.Path { + excludedSymbolVersions, excludedSymbolTags, includedSymbolTags []string, + api string, isLlndk bool) android.Path { outputFile := android.PathForModuleOut(ctx, baseName+".lsdump") @@ -874,6 +878,12 @@ func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path for _, tag := range excludedSymbolTags { symbolFilterStr += " --exclude-symbol-tag " + tag } + for _, tag := range includedSymbolTags { + symbolFilterStr += " --include-symbol-tag " + tag + } + if isLlndk { + symbolFilterStr += " --symbol-tag-policy MatchTagOnly" + } apiLevelsJson := android.GetApiLevelsJson(ctx) implicits = append(implicits, apiLevelsJson) symbolFilterStr += " --api-map " + apiLevelsJson.String() @@ -50,6 +50,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("sdk", sdkMutator).Parallel() ctx.BottomUp("vndk", VndkMutator).Parallel() + ctx.BottomUp("llndk", llndkMutator).Parallel() ctx.BottomUp("link", LinkageMutator).Parallel() ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel() ctx.BottomUp("version", versionMutator).Parallel() @@ -319,7 +320,7 @@ type BaseProperties struct { // *.logtags files, to combine together in order to generate the /system/etc/event-log-tags // file - Logtags []string + Logtags []string `android:"path"` // Make this module available when building for ramdisk. // On device without a dedicated recovery partition, the module is only @@ -908,6 +909,8 @@ type Module struct { // Aconfig files for all transitive deps. Also exposed via TransitiveDeclarationsInfo mergedAconfigFiles map[string]android.Paths + + logtagsPaths android.Paths } func (c *Module) AddJSONData(d *map[string]interface{}) { @@ -1997,6 +2000,11 @@ func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { ctx := moduleContextFromAndroidModuleContext(actx, c) + c.logtagsPaths = android.PathsForModuleSrc(actx, c.Properties.Logtags) + android.SetProvider(ctx, android.LogtagsProviderKey, &android.LogtagsInfo{ + Logtags: c.logtagsPaths, + }) + // 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() @@ -2508,7 +2516,7 @@ func (c *Module) shouldUseApiSurface() bool { } func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { - if !c.Enabled() { + if !c.Enabled(actx) { return } @@ -2756,7 +2764,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } func BeginMutator(ctx android.BottomUpMutatorContext) { - if c, ok := ctx.Module().(*Module); ok && c.Enabled() { + if c, ok := ctx.Module().(*Module); ok && c.Enabled(ctx) { c.beginMutator(ctx) } } diff --git a/cc/compiler.go b/cc/compiler.go index 9a961cfb9..a1b329e2c 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -141,6 +141,19 @@ type BaseCompilerProperties struct { Flags []string } + // Populated by aidl_interface CPP backend to let other modules (e.g. cc_cmake_snapshot) + // access actual source files and not generated cpp intermediary sources. + AidlInterface struct { + // list of aidl_interface sources + Sources []string `blueprint:"mutated"` + + // AIDL backend language (e.g. "cpp", "ndk") + Lang string `blueprint:"mutated"` + + // list of flags passed to AIDL generator + Flags []string `blueprint:"mutated"` + } `blueprint:"mutated"` + Renderscript struct { // list of directories that will be added to the llvm-rs-cc include paths Include_dirs []string diff --git a/cc/fuzz.go b/cc/fuzz.go index 2436f33d2..b3e663962 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -433,7 +433,7 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) return } // Discard non-fuzz targets. - if ok := fuzz.IsValid(ccModule.FuzzModuleStruct()); !ok { + if ok := fuzz.IsValid(ctx, ccModule.FuzzModuleStruct()); !ok { return } diff --git a/cc/library.go b/cc/library.go index 5b2480906..12ecc131a 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1249,16 +1249,29 @@ func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, func (library *libraryDecorator) linkLlndkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string, - excludeSymbolVersions, excludeSymbolTags []string) android.Path { + excludeSymbolVersions, excludeSymbolTags []string, + vendorApiLevel string) android.Path { // NDK symbols in version 34 are LLNDK symbols. Those in version 35 are not. - // TODO(b/314010764): Add parameters to read LLNDK symbols from the symbol file. return transformDumpToLinkedDump(ctx, sAbiDumpFiles, soFile, libFileName+".llndk", library.llndkIncludeDirsForAbiCheck(ctx, deps), android.OptionalPathForModuleSrc(ctx, library.Properties.Llndk.Symbol_file), append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...), append([]string{"platform-only"}, excludeSymbolTags...), - "34") + []string{"llndk=" + vendorApiLevel}, "34", true /* isLlndk */) +} + +func (library *libraryDecorator) linkApexSAbiDumpFiles(ctx ModuleContext, + deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string, + excludeSymbolVersions, excludeSymbolTags []string, + sdkVersion string) android.Path { + return transformDumpToLinkedDump(ctx, + sAbiDumpFiles, soFile, libFileName+".apex", + library.exportedIncludeDirsForAbiCheck(ctx), + android.OptionalPathForModuleSrc(ctx, library.Properties.Stubs.Symbol_file), + append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...), + append([]string{"platform-only"}, excludeSymbolTags...), + []string{"apex", "systemapi"}, sdkVersion, false /* isLlndk */) } func getRefAbiDumpFile(ctx android.ModuleInstallPathContext, @@ -1276,21 +1289,21 @@ func getRefAbiDumpFile(ctx android.ModuleInstallPathContext, } // Return the previous and current SDK versions for cross-version ABI diff. -func crossVersionAbiDiffSdkVersions(ctx ModuleContext, dumpDir string) (string, string) { +func crossVersionAbiDiffSdkVersions(ctx ModuleContext, dumpDir string) (int, int) { sdkVersionInt := ctx.Config().PlatformSdkVersion().FinalInt() - sdkVersionStr := ctx.Config().PlatformSdkVersion().String() if ctx.Config().PlatformSdkFinal() { - return strconv.Itoa(sdkVersionInt - 1), sdkVersionStr + return sdkVersionInt - 1, sdkVersionInt } else { // The platform SDK version can be upgraded before finalization while the corresponding abi dumps hasn't // been generated. Thus the Cross-Version Check chooses PLATFORM_SDK_VERION - 1 as previous version. // This situation could be identified by checking the existence of the PLATFORM_SDK_VERION dump directory. - versionedDumpDir := android.ExistentPathForSource(ctx, dumpDir, sdkVersionStr) + versionedDumpDir := android.ExistentPathForSource(ctx, + dumpDir, ctx.Config().PlatformSdkVersion().String()) if versionedDumpDir.Valid() { - return sdkVersionStr, strconv.Itoa(sdkVersionInt + 1) + return sdkVersionInt, sdkVersionInt + 1 } else { - return strconv.Itoa(sdkVersionInt - 1), sdkVersionStr + return sdkVersionInt - 1, sdkVersionInt } } } @@ -1309,7 +1322,7 @@ func currRefAbiDumpSdkVersion(ctx ModuleContext) string { // sourceAbiDiff registers a build statement to compare linked sAbi dump files (.lsdump). func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, sourceDump, referenceDump android.Path, - baseName, nameExt string, isLlndkOrNdk, allowExtensions bool, + baseName, nameExt string, isLlndk, allowExtensions bool, sourceVersion, errorMessage string) { extraFlags := []string{"-target-version", sourceVersion} @@ -1321,7 +1334,7 @@ func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, "-allow-unreferenced-changes", "-allow-unreferenced-elf-symbol-changes") } - if isLlndkOrNdk { + if isLlndk { extraFlags = append(extraFlags, "-consider-opaque-types-different") } if allowExtensions { @@ -1337,23 +1350,23 @@ func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, func (library *libraryDecorator) crossVersionAbiDiff(ctx android.ModuleContext, sourceDump, referenceDump android.Path, - baseName string, isLlndkOrNdk bool, sourceVersion, prevVersion string) { + baseName string, isLlndk bool, sourceVersion, prevVersion string) { errorMessage := "error: Please follow https://android.googlesource.com/platform/development/+/main/vndk/tools/header-checker/README.md#configure-cross_version-abi-check to resolve the ABI difference between your source code and version " + prevVersion + "." library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, prevVersion, - isLlndkOrNdk, true /* allowExtensions */, sourceVersion, errorMessage) + isLlndk, true /* allowExtensions */, sourceVersion, errorMessage) } func (library *libraryDecorator) sameVersionAbiDiff(ctx android.ModuleContext, sourceDump, referenceDump android.Path, - baseName, nameExt string, isLlndkOrNdk bool) { + baseName, nameExt string, isLlndk bool) { libName := strings.TrimSuffix(baseName, filepath.Ext(baseName)) errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, nameExt, - isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage) + isLlndk, false /* allowExtensions */, "current", errorMessage) } func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, @@ -1368,7 +1381,7 @@ func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, } library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, nameExt, - false /* isLlndkOrNdk */, false /* allowExtensions */, "current", errorMessage) + false /* isLlndk */, false /* allowExtensions */, "current", errorMessage) } func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, objs Objects, fileName string, soFile android.Path) { @@ -1385,20 +1398,30 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathD android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)), headerAbiChecker.Exclude_symbol_versions, headerAbiChecker.Exclude_symbol_tags, - currSdkVersion) + []string{} /* includeSymbolTags */, currSdkVersion, false /* isLlndk */) - var llndkDump android.Path + var llndkDump, apexVariantDump android.Path tags := classifySourceAbiDump(ctx) for _, tag := range tags { - if tag == llndkLsdumpTag { + if tag == llndkLsdumpTag && currVendorVersion != "" { if llndkDump == nil { // TODO(b/323447559): Evaluate if replacing sAbiDumpFiles with implDump is faster llndkDump = library.linkLlndkSAbiDumpFiles(ctx, deps, objs.sAbiDumpFiles, soFile, fileName, headerAbiChecker.Exclude_symbol_versions, - headerAbiChecker.Exclude_symbol_tags) + headerAbiChecker.Exclude_symbol_tags, + currVendorVersion) } addLsdumpPath(string(tag) + ":" + llndkDump.String()) + } else if tag == apexLsdumpTag { + if apexVariantDump == nil { + apexVariantDump = library.linkApexSAbiDumpFiles(ctx, + deps, objs.sAbiDumpFiles, soFile, fileName, + headerAbiChecker.Exclude_symbol_versions, + headerAbiChecker.Exclude_symbol_tags, + currSdkVersion) + } + addLsdumpPath(string(tag) + ":" + apexVariantDump.String()) } else { addLsdumpPath(string(tag) + ":" + implDump.String()) } @@ -1412,11 +1435,13 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathD } dumpDir := filepath.Join("prebuilts", "abi-dumps", dumpDirName) isLlndk := (tag == llndkLsdumpTag) - isNdk := (tag == ndkLsdumpTag) + isApex := (tag == apexLsdumpTag) binderBitness := ctx.DeviceConfig().BinderBitness() nameExt := "" if isLlndk { nameExt = "llndk" + } else if isApex { + nameExt = "apex" } // Check against the previous version. var prevVersion, currVersion string @@ -1430,13 +1455,19 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathD sourceDump = llndkDump } } else { - prevVersion, currVersion = crossVersionAbiDiffSdkVersions(ctx, dumpDir) + prevVersionInt, currVersionInt := crossVersionAbiDiffSdkVersions(ctx, dumpDir) + prevVersion = strconv.Itoa(prevVersionInt) + currVersion = strconv.Itoa(currVersionInt) + // APEX dumps are generated by different rules after trunk stable. + if isApex && prevVersionInt > 34 { + sourceDump = apexVariantDump + } } prevDumpDir := filepath.Join(dumpDir, prevVersion, binderBitness) prevDumpFile := getRefAbiDumpFile(ctx, prevDumpDir, fileName) if prevDumpFile.Valid() { library.crossVersionAbiDiff(ctx, sourceDump, prevDumpFile.Path(), - fileName, isLlndk || isNdk, currVersion, nameExt+prevVersion) + fileName, isLlndk, currVersion, nameExt+prevVersion) } // Check against the current version. sourceDump = implDump @@ -1447,12 +1478,16 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathD } } else { currVersion = currSdkVersion + if isApex && (!ctx.Config().PlatformSdkFinal() || + ctx.Config().PlatformSdkVersion().FinalInt() > 34) { + sourceDump = apexVariantDump + } } currDumpDir := filepath.Join(dumpDir, currVersion, binderBitness) currDumpFile := getRefAbiDumpFile(ctx, currDumpDir, fileName) if currDumpFile.Valid() { library.sameVersionAbiDiff(ctx, sourceDump, currDumpFile.Path(), - fileName, nameExt, isLlndk || isNdk) + fileName, nameExt, isLlndk) } } // Check against the opt-in reference dumps. diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go deleted file mode 100644 index 4df0a4186..000000000 --- a/cc/library_stub_test.go +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright 2021 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 ( - _ "fmt" - _ "sort" - - "testing" - - "android/soong/android" - - "github.com/google/blueprint" -) - -func hasDirectDependency(t *testing.T, ctx *android.TestResult, from android.Module, to android.Module) bool { - t.Helper() - var found bool - ctx.VisitDirectDeps(from, func(dep blueprint.Module) { - if dep == to { - found = true - } - }) - return found -} - -func TestApiLibraryReplacesExistingModule(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - shared_libs: ["libbar"], - vendor_available: true, - } - - cc_library { - name: "libbar", - } - - cc_api_library { - name: "libbar", - vendor_available: true, - src: "libbar.so", - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() - libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module() - libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "original library should be linked with non-stub variant", true, hasDirectDependency(t, ctx, libfoo, libbar)) - android.AssertBoolEquals(t, "Stub library from API surface should be not linked with non-stub variant", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport)) - - libfooVendor := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_shared").Module() - libbarApiImportVendor := ctx.ModuleForTests("libbar.apiimport", "android_vendor_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfooVendor, libbar)) - android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfooVendor, libbarApiImportVendor)) -} - -func TestApiLibraryDoNotRequireOriginalModule(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - shared_libs: ["libbar"], - vendor: true, - } - - cc_api_library { - name: "libbar", - src: "libbar.so", - vendor_available: true, - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - libfoo := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_shared").Module() - libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport)) -} - -func TestApiLibraryShouldNotReplaceWithoutApiImport(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - shared_libs: ["libbar"], - vendor_available: true, - } - - cc_library { - name: "libbar", - vendor_available: true, - } - - cc_api_library { - name: "libbar", - src: "libbar.so", - vendor_available: true, - } - - api_imports { - name: "api_imports", - shared_libs: [], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - libfoo := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_shared").Module() - libbar := ctx.ModuleForTests("libbar", "android_vendor_arm64_armv8-a_shared").Module() - libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "original library should be linked", true, hasDirectDependency(t, ctx, libfoo, libbar)) - android.AssertBoolEquals(t, "Stub library from API surface should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport)) -} - -func TestExportDirFromStubLibrary(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - export_include_dirs: ["source_include_dir"], - export_system_include_dirs: ["source_system_include_dir"], - vendor_available: true, - } - cc_api_library { - name: "libfoo", - export_include_dirs: ["stub_include_dir"], - export_system_include_dirs: ["stub_system_include_dir"], - vendor_available: true, - src: "libfoo.so", - } - api_imports { - name: "api_imports", - shared_libs: [ - "libfoo", - ], - header_libs: [], - } - // vendor binary - cc_binary { - name: "vendorbin", - vendor: true, - srcs: ["vendor.cc"], - shared_libs: ["libfoo"], - } - ` - ctx := prepareForCcTest.RunTestWithBp(t, bp) - vendorCFlags := ctx.ModuleForTests("vendorbin", "android_vendor_arm64_armv8-a").Rule("cc").Args["cFlags"] - android.AssertStringDoesContain(t, "Vendor binary should compile using headers provided by stub", vendorCFlags, "-Istub_include_dir") - android.AssertStringDoesNotContain(t, "Vendor binary should not compile using headers of source", vendorCFlags, "-Isource_include_dir") - android.AssertStringDoesContain(t, "Vendor binary should compile using system headers provided by stub", vendorCFlags, "-isystem stub_system_include_dir") - android.AssertStringDoesNotContain(t, "Vendor binary should not compile using system headers of source", vendorCFlags, "-isystem source_system_include_dir") - - vendorImplicits := ctx.ModuleForTests("vendorbin", "android_vendor_arm64_armv8-a").Rule("cc").OrderOnly.Strings() - // Building the stub.so file first assembles its .h files in multi-tree out. - // These header files are required for compiling the other API domain (vendor in this case) - android.AssertStringListContains(t, "Vendor binary compilation should have an implicit dep on the stub .so file", vendorImplicits, "libfoo.so") -} - -func TestApiLibraryWithLlndkVariant(t *testing.T) { - bp := ` - cc_binary { - name: "binfoo", - vendor: true, - srcs: ["binfoo.cc"], - shared_libs: ["libbar"], - } - - cc_api_library { - name: "libbar", - // TODO(b/244244438) Remove src property once all variants are implemented. - src: "libbar.so", - vendor_available: true, - variants: [ - "llndk", - ], - } - - cc_api_variant { - name: "libbar", - variant: "llndk", - src: "libbar_llndk.so", - export_include_dirs: ["libbar_llndk_include"] - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - header_libs: [], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - binfoo := ctx.ModuleForTests("binfoo", "android_vendor_arm64_armv8-a").Module() - libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor_arm64_armv8-a_shared").Module() - libbarApiVariant := ctx.ModuleForTests("libbar.llndk.apiimport", "android_vendor_arm64_armv8-a").Module() - - android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, binfoo, libbarApiImport)) - android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant)) - - binFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor_arm64_armv8-a").Rule("ld").Args["libFlags"] - android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", binFooLibFlags, "libbar.llndk.apiimport.so") - - binFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor_arm64_armv8-a").Rule("cc").Args["cFlags"] - android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", binFooCFlags, "-Ilibbar_llndk_include") -} - -func TestApiLibraryWithNdkVariant(t *testing.T) { - bp := ` - cc_binary { - name: "binfoo", - sdk_version: "29", - srcs: ["binfoo.cc"], - shared_libs: ["libbar"], - stl: "c++_shared", - } - - cc_binary { - name: "binbaz", - sdk_version: "30", - srcs: ["binbaz.cc"], - shared_libs: ["libbar"], - stl: "c++_shared", - } - - cc_binary { - name: "binqux", - srcs: ["binfoo.cc"], - shared_libs: ["libbar"], - } - - cc_library { - name: "libbar", - srcs: ["libbar.cc"], - } - - cc_api_library { - name: "libbar", - // TODO(b/244244438) Remove src property once all variants are implemented. - src: "libbar.so", - variants: [ - "ndk.29", - "ndk.30", - "ndk.current", - ], - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "29", - src: "libbar_ndk_29.so", - export_include_dirs: ["libbar_ndk_29_include"] - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "30", - src: "libbar_ndk_30.so", - export_include_dirs: ["libbar_ndk_30_include"] - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "current", - src: "libbar_ndk_current.so", - export_include_dirs: ["libbar_ndk_current_include"] - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - header_libs: [], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module() - libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module() - libbarApiVariantv29 := ctx.ModuleForTests("libbar.ndk.29.apiimport", "android_arm64_armv8-a_sdk").Module() - libbarApiImportv30 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_30").Module() - libbarApiVariantv30 := ctx.ModuleForTests("libbar.ndk.30.apiimport", "android_arm64_armv8-a_sdk").Module() - - android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29)) - android.AssertBoolEquals(t, "Stub library variant from API surface should be linked with target version", true, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv29)) - android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportv30)) - android.AssertBoolEquals(t, "Stub library variant from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv30)) - - binbaz := ctx.ModuleForTests("binbaz", "android_arm64_armv8-a_sdk").Module() - - android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportv30)) - android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29)) - - binFooLibFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("ld").Args["libFlags"] - android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar.ndk.29.apiimport.so") - - binFooCFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("cc").Args["cFlags"] - android.AssertStringDoesContain(t, "Binary using sdk should include headers from the NDK variant source", binFooCFlags, "-Ilibbar_ndk_29_include") - - binQux := ctx.ModuleForTests("binqux", "android_arm64_armv8-a").Module() - android.AssertBoolEquals(t, "NDK Stub library from API surface should not be linked with nonSdk binary", false, - (hasDirectDependency(t, ctx, binQux, libbarApiImportv30) || hasDirectDependency(t, ctx, binQux, libbarApiImportv29))) -} - -func TestApiLibraryWithMultipleVariants(t *testing.T) { - bp := ` - cc_binary { - name: "binfoo", - sdk_version: "29", - srcs: ["binfoo.cc"], - shared_libs: ["libbar"], - stl: "c++_shared", - } - - cc_binary { - name: "binbaz", - vendor: true, - srcs: ["binbaz.cc"], - shared_libs: ["libbar"], - } - - cc_library { - name: "libbar", - srcs: ["libbar.cc"], - } - - cc_api_library { - name: "libbar", - // TODO(b/244244438) Remove src property once all variants are implemented. - src: "libbar.so", - vendor_available: true, - variants: [ - "llndk", - "ndk.29", - "ndk.30", - "ndk.current", - "apex.29", - "apex.30", - "apex.current", - ], - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "29", - src: "libbar_ndk_29.so", - export_include_dirs: ["libbar_ndk_29_include"] - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "30", - src: "libbar_ndk_30.so", - export_include_dirs: ["libbar_ndk_30_include"] - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "current", - src: "libbar_ndk_current.so", - export_include_dirs: ["libbar_ndk_current_include"] - } - - cc_api_variant { - name: "libbar", - variant: "apex", - version: "29", - src: "libbar_apex_29.so", - export_include_dirs: ["libbar_apex_29_include"] - } - - cc_api_variant { - name: "libbar", - variant: "apex", - version: "30", - src: "libbar_apex_30.so", - export_include_dirs: ["libbar_apex_30_include"] - } - - cc_api_variant { - name: "libbar", - variant: "apex", - version: "current", - src: "libbar_apex_current.so", - export_include_dirs: ["libbar_apex_current_include"] - } - - cc_api_variant { - name: "libbar", - variant: "llndk", - src: "libbar_llndk.so", - export_include_dirs: ["libbar_llndk_include"] - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - apex_shared_libs: [ - "libbar", - ], - } - ` - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module() - libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module() - libbarApiImportLlndk := ctx.ModuleForTests("libbar.apiimport", "android_vendor_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "Binary using SDK should be linked with API library from NDK variant", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29)) - android.AssertBoolEquals(t, "Binary using SDK should not be linked with API library from LLNDK variant", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportLlndk)) - - binbaz := ctx.ModuleForTests("binbaz", "android_vendor_arm64_armv8-a").Module() - - android.AssertBoolEquals(t, "Vendor binary should be linked with API library from LLNDK variant", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportLlndk)) - android.AssertBoolEquals(t, "Vendor binary should not be linked with API library from NDK variant", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29)) - -} diff --git a/cc/linker.go b/cc/linker.go index 9686697c8..56a68b2ce 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -330,6 +330,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs) deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Target.Vendor.Header_libs...) deps.HeaderLibs = removeListFromList(deps.HeaderLibs, linker.Properties.Target.Vendor.Exclude_header_libs) + deps.ReexportHeaderLibHeaders = removeListFromList(deps.ReexportHeaderLibHeaders, linker.Properties.Target.Vendor.Exclude_header_libs) deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor.Exclude_static_libs) deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs) deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor.Exclude_runtime_libs) @@ -342,6 +343,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Product.Static_libs...) deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Product.Exclude_static_libs) deps.HeaderLibs = removeListFromList(deps.HeaderLibs, linker.Properties.Target.Product.Exclude_header_libs) + deps.ReexportHeaderLibHeaders = removeListFromList(deps.ReexportHeaderLibHeaders, linker.Properties.Target.Product.Exclude_header_libs) deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Product.Exclude_static_libs) deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Product.Exclude_static_libs) deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Product.Exclude_runtime_libs) diff --git a/cc/llndk_library.go b/cc/llndk_library.go index 9e727a10b..5b86c6478 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -16,12 +16,12 @@ package cc import ( "android/soong/android" + "android/soong/etc" "strings" ) var ( llndkLibrarySuffix = ".llndk" - llndkHeadersSuffix = ".llndk" ) // Holds properties to describe a stub shared library based on the provided version file. @@ -78,3 +78,143 @@ func makeLlndkVars(ctx android.MakeVarsContext) { ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " ")) } + +func init() { + RegisterLlndkLibraryTxtType(android.InitRegistrationContext) +} + +func RegisterLlndkLibraryTxtType(ctx android.RegistrationContext) { + ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory) +} + +type llndkLibrariesTxtModule struct { + android.SingletonModuleBase + + outputFile android.OutputPath + moduleNames []string + fileNames []string +} + +var _ etc.PrebuiltEtcModule = &llndkLibrariesTxtModule{} +var _ android.OutputFileProducer = &llndkLibrariesTxtModule{} + +// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries +// generated by Soong but can be referenced by other modules. +// For example, apex_vndk can depend on these files as prebuilt. +// Make uses LLNDK_LIBRARIES to determine which libraries to install. +// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN. +// Therefore, by removing the library here, we cause it to only be installed if libc +// depends on it. +func llndkLibrariesTxtFactory() android.SingletonModule { + m := &llndkLibrariesTxtModule{} + android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) + return m +} + +func (txt *llndkLibrariesTxtModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + filename := txt.Name() + + txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath + + installPath := android.PathForModuleInstall(ctx, "etc") + ctx.InstallFile(installPath, filename, txt.outputFile) +} + +func (txt *llndkLibrariesTxtModule) GenerateSingletonBuildActions(ctx android.SingletonContext) { + if txt.outputFile.String() == "" { + // Skip if target file path is empty + return + } + + ctx.VisitAllModules(func(m android.Module) { + if c, ok := m.(*Module); ok && c.VendorProperties.IsLLNDK && !c.Header() && !c.IsVndkPrebuiltLibrary() { + filename, err := getVndkFileName(c) + if err != nil { + ctx.ModuleErrorf(m, "%s", err) + } + + if !strings.HasPrefix(ctx.ModuleName(m), "libclang_rt.hwasan") { + txt.moduleNames = append(txt.moduleNames, ctx.ModuleName(m)) + } + txt.fileNames = append(txt.fileNames, filename) + } + }) + txt.moduleNames = android.SortedUniqueStrings(txt.moduleNames) + txt.fileNames = android.SortedUniqueStrings(txt.fileNames) + + android.WriteFileRule(ctx, txt.outputFile, strings.Join(txt.fileNames, "\n")) +} + +func (txt *llndkLibrariesTxtModule) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{{ + Class: "ETC", + OutputFile: android.OptionalPathForPath(txt.outputFile), + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base()) + }, + }, + }} +} + +func (txt *llndkLibrariesTxtModule) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict("LLNDK_LIBRARIES", strings.Join(txt.moduleNames, " ")) +} + +// PrebuiltEtcModule interface +func (txt *llndkLibrariesTxtModule) OutputFile() android.OutputPath { + return txt.outputFile +} + +// PrebuiltEtcModule interface +func (txt *llndkLibrariesTxtModule) BaseDir() string { + return "etc" +} + +// PrebuiltEtcModule interface +func (txt *llndkLibrariesTxtModule) SubDir() string { + return "" +} + +func (txt *llndkLibrariesTxtModule) OutputFiles(tag string) (android.Paths, error) { + return android.Paths{txt.outputFile}, nil +} + +func llndkMutator(mctx android.BottomUpMutatorContext) { + m, ok := mctx.Module().(*Module) + if !ok { + return + } + + if shouldSkipLlndkMutator(mctx, m) { + return + } + + lib, isLib := m.linker.(*libraryDecorator) + prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker) + + if m.InVendorOrProduct() && isLib && lib.hasLLNDKStubs() { + m.VendorProperties.IsLLNDK = true + } + if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() { + m.VendorProperties.IsLLNDK = true + } + + if m.IsVndkPrebuiltLibrary() && !m.IsVndk() { + m.VendorProperties.IsLLNDK = true + } +} + +// Check for modules that mustn't be LLNDK +func shouldSkipLlndkMutator(mctx android.BottomUpMutatorContext, m *Module) bool { + if !m.Enabled(mctx) { + return true + } + if !m.Device() { + return true + } + if m.Target().NativeBridge == android.NativeBridgeEnabled { + return true + } + return false +} diff --git a/cc/makevars.go b/cc/makevars.go index 9251d6a49..51bcbf090 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -279,7 +279,7 @@ func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, sanitizerLibs := android.SortedStringValues(sanitizerVariables) var sanitizerLibStems []string ctx.VisitAllModules(func(m android.Module) { - if !m.Enabled() { + if !m.Enabled(ctx) { return } diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go index 86166dcbb..5beeab1ee 100644 --- a/cc/ndk_abi.go +++ b/cc/ndk_abi.go @@ -40,7 +40,7 @@ type ndkAbiDumpSingleton struct{} func (n *ndkAbiDumpSingleton) GenerateBuildActions(ctx android.SingletonContext) { var depPaths android.Paths ctx.VisitAllModules(func(module android.Module) { - if !module.Enabled() { + if !module.Enabled(ctx) { return } @@ -78,7 +78,7 @@ type ndkAbiDiffSingleton struct{} func (n *ndkAbiDiffSingleton) GenerateBuildActions(ctx android.SingletonContext) { var depPaths android.Paths ctx.VisitAllModules(func(module android.Module) { - if m, ok := module.(android.Module); ok && !m.Enabled() { + if m, ok := module.(android.Module); ok && !m.Enabled(ctx) { return } diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 25231fdf5..f32606814 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -148,7 +148,7 @@ func ndkLibraryVersions(ctx android.BaseMutatorContext, from android.ApiLevel) [ } func (this *stubDecorator) stubsVersions(ctx android.BaseMutatorContext) []string { - if !ctx.Module().Enabled() { + if !ctx.Module().Enabled(ctx) { return nil } if ctx.Target().NativeBridge == android.NativeBridgeEnabled { diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index e815172ae..3c48f6881 100644 --- a/cc/ndk_sysroot.go +++ b/cc/ndk_sysroot.go @@ -150,7 +150,7 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { var installPaths android.Paths var licensePaths android.Paths ctx.VisitAllModules(func(module android.Module) { - if m, ok := module.(android.Module); ok && !m.Enabled() { + if m, ok := module.(android.Module); ok && !m.Enabled(ctx) { return } diff --git a/cc/prebuilt.go b/cc/prebuilt.go index cbb5d58db..e9f790f73 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -177,7 +177,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, implicits = append(implicits, importLibOutputFile) ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, + Rule: android.CpExecutable, Description: "prebuilt import library", Input: importLibSrc, Output: importLibOutputFile, @@ -188,7 +188,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, } ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, + Rule: android.CpExecutable, Description: "prebuilt shared library", Implicits: implicits, Input: in, diff --git a/cc/sabi.go b/cc/sabi.go index ef43c8daf..edd9cfe80 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -29,8 +29,8 @@ var ( type lsdumpTag string const ( + apexLsdumpTag lsdumpTag = "APEX" llndkLsdumpTag lsdumpTag = "LLNDK" - ndkLsdumpTag lsdumpTag = "NDK" platformLsdumpTag lsdumpTag = "PLATFORM" productLsdumpTag lsdumpTag = "PRODUCT" vendorLsdumpTag lsdumpTag = "VENDOR" @@ -39,8 +39,8 @@ const ( // Return the prebuilt ABI dump directory for a tag; an empty string for an opt-in dump. func (tag *lsdumpTag) dirName() string { switch *tag { - case ndkLsdumpTag: - return "ndk" + case apexLsdumpTag: + return "platform" case llndkLsdumpTag: return "vndk" case platformLsdumpTag: @@ -134,11 +134,10 @@ func classifySourceAbiDump(ctx android.BaseModuleContext) []lsdumpTag { if m.isImplementationForLLNDKPublic() { result = append(result, llndkLsdumpTag) } - // Return NDK if the library is both NDK and APEX. - // TODO(b/309880485): Split NDK and APEX ABI. - if m.IsNdk(ctx.Config()) { - result = append(result, ndkLsdumpTag) - } else if m.library.hasStubsVariants() || headerAbiChecker.enabled() { + // APEX and opt-in platform dumps are placed in the same directory. + if m.library.hasStubsVariants() { + result = append(result, apexLsdumpTag) + } else if headerAbiChecker.enabled() { result = append(result, platformLsdumpTag) } } else if headerAbiChecker.enabled() { diff --git a/cc/sanitize.go b/cc/sanitize.go index db046ec58..1a94729c6 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -55,7 +55,6 @@ var ( // higher number of "optimized out" stack variables. // b/112437883. "-instcombine-lower-dbg-declare=0", - "-hwasan-use-after-scope=1", "-dom-tree-reachability-max-bbs-to-explore=128", } @@ -82,7 +81,8 @@ var ( "-fno-sanitize-recover=integer,undefined"} hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512", "export_memory_stats=0", "max_malloc_fill_size=131072", "malloc_fill_byte=0"} - memtagStackCommonFlags = []string{"-march=armv8-a+memtag", "-mllvm", "-dom-tree-reachability-max-bbs-to-explore=128"} + memtagStackCommonFlags = []string{"-march=armv8-a+memtag"} + memtagStackLlvmFlags = []string{"-dom-tree-reachability-max-bbs-to-explore=128"} hostOnlySanitizeFlags = []string{"-fno-sanitize-recover=all"} deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all"} @@ -176,11 +176,11 @@ func (t SanitizerType) name() string { func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) { switch t { - case cfi, Hwasan, Asan, tsan, Fuzzer, scs: + case cfi, Hwasan, Asan, tsan, Fuzzer, scs, Memtag_stack: sanitizer := &sanitizerSplitMutator{t} ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator) ctx.Transition(t.variationName(), sanitizer) - case Memtag_heap, Memtag_stack, Memtag_globals, intOverflow: + case Memtag_heap, Memtag_globals, intOverflow: // do nothing default: panic(fmt.Errorf("unknown SanitizerType %d", t)) @@ -407,6 +407,7 @@ func init() { android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider) android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider) + android.RegisterMakeVarsProvider(pctx, memtagStackMakeVarsProvider) } func (sanitize *sanitize) props() []interface{} { @@ -683,10 +684,14 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Diag.Cfi = nil } - // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. - // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary. - if (ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { - s.Hwaddress = nil + if ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery() { + // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. + // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary. + if !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { + s.Hwaddress = nil + } + // Memtag stack in ramdisk makes pKVM unhappy. + s.Memtag_stack = nil } if ctx.staticBinary() { @@ -858,7 +863,7 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...) flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...) - flags.CFlagsDeps = append(flags.CFlagsDeps, android.PathForSource(ctx, cfiBlocklistPath + "/" + cfiBlocklistFilename)) + flags.CFlagsDeps = append(flags.CFlagsDeps, android.PathForSource(ctx, cfiBlocklistPath+"/"+cfiBlocklistFilename)) if Bool(s.Properties.Sanitize.Config.Cfi_assembly_support) { flags.Local.CFlags = append(flags.Local.CFlags, cfiAssemblySupportFlag) } @@ -879,6 +884,13 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.Local.CFlags = append(flags.Local.CFlags, memtagStackCommonFlags...) flags.Local.AsFlags = append(flags.Local.AsFlags, memtagStackCommonFlags...) flags.Local.LdFlags = append(flags.Local.LdFlags, memtagStackCommonFlags...) + + for _, flag := range memtagStackLlvmFlags { + flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag) + } + for _, flag := range memtagStackLlvmFlags { + flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag) + } } if (Bool(sanProps.Memtag_heap) || Bool(sanProps.Memtag_stack) || Bool(sanProps.Memtag_globals)) && ctx.binary() { @@ -1303,6 +1315,8 @@ func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, vari hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name()) } else if s.sanitizer == cfi { cfiStaticLibs(mctx.Config()).add(c, c.Module().Name()) + } else if s.sanitizer == Memtag_stack { + memtagStackStaticLibs(mctx.Config()).add(c, c.Module().Name()); } } } else if c.IsSanitizerEnabled(s.sanitizer) { @@ -1371,7 +1385,7 @@ func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { // Add the dependency to the runtime library for each of the sanitizer variants func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { - if !c.Enabled() { + if !c.Enabled(mctx) { return } var sanitizers []string @@ -1552,7 +1566,7 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { addStaticDeps(config.BuiltinsRuntimeLibrary(toolchain), true) } - if runtimeSharedLibrary != "" && (toolchain.Bionic() || toolchain.Musl() || c.sanitize.Properties.UbsanRuntimeDep) { + if runtimeSharedLibrary != "" && (toolchain.Bionic() || toolchain.Musl()) { // UBSan is supported on non-bionic linux host builds as well // Adding dependency to the runtime library. We are using *FarVariation* @@ -1715,6 +1729,14 @@ func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap { }).(*sanitizerStaticLibsMap) } +var memtagStackStaticLibsKey = android.NewOnceKey("memtagStackStaticLibs") + +func memtagStackStaticLibs(config android.Config) *sanitizerStaticLibsMap { + return config.Once(memtagStackStaticLibsKey, func() interface{} { + return newSanitizerStaticLibsMap(Memtag_stack) + }).(*sanitizerStaticLibsMap) +} + func enableMinimalRuntime(sanitize *sanitize) bool { if sanitize.isSanitizerEnabled(Asan) { return false @@ -1761,3 +1783,7 @@ func cfiMakeVarsProvider(ctx android.MakeVarsContext) { func hwasanMakeVarsProvider(ctx android.MakeVarsContext) { hwasanStaticLibs(ctx.Config()).exportToMake(ctx) } + +func memtagStackMakeVarsProvider(ctx android.MakeVarsContext) { + memtagStackStaticLibs(ctx.Config()).exportToMake(ctx) +} @@ -49,45 +49,19 @@ func sdkMutator(ctx android.BottomUpMutatorContext) { modules[1].(*Module).Properties.IsSdkVariant = true if ctx.Config().UnbundledBuildApps() { - // For an unbundled apps build, hide the platform variant from Make. + // For an unbundled apps build, hide the platform variant from Make + // so that other Make modules don't link against it, but against the + // SDK variant. modules[0].(*Module).Properties.HideFromMake = true - modules[0].(*Module).Properties.PreventInstall = true } else { // For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when // exposed to Make. modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true - modules[1].(*Module).Properties.PreventInstall = true } + // SDK variant never gets installed because the variant is to be embedded in + // APKs, not to be installed to the platform. + modules[1].(*Module).Properties.PreventInstall = true ctx.AliasVariation("") - } else if isCcModule && ccModule.isImportedApiLibrary() { - apiLibrary, _ := ccModule.linker.(*apiLibraryDecorator) - if apiLibrary.hasNDKStubs() && ccModule.canUseSdk() { - variations := []string{"sdk"} - if apiLibrary.hasApexStubs() { - variations = append(variations, "") - } - // Handle cc_api_library module with NDK stubs and variants only which can use SDK - modules := ctx.CreateVariations(variations...) - // Mark the SDK variant. - modules[0].(*Module).Properties.IsSdkVariant = true - if ctx.Config().UnbundledBuildApps() { - if apiLibrary.hasApexStubs() { - // For an unbundled apps build, hide the platform variant from Make. - modules[1].(*Module).Properties.HideFromMake = true - } - modules[1].(*Module).Properties.PreventInstall = true - } else { - // For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when - // exposed to Make. - modules[0].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true - // SDK variant is not supposed to be installed - modules[0].(*Module).Properties.PreventInstall = true - } - } else { - ccModule.Properties.Sdk_version = nil - ctx.CreateVariations("") - ctx.AliasVariation("") - } } else { if isCcModule { // Clear the sdk_version property for modules that don't have an SDK variant so diff --git a/cc/testing.go b/cc/testing.go index 20c435aca..4b4e866d4 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -554,6 +554,7 @@ var PrepareForTestWithCcBuildComponents = android.GroupFixturePreparers( ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) RegisterVndkLibraryTxtTypes(ctx) + RegisterLlndkLibraryTxtType(ctx) }), // Additional files needed in tests that disallow non-existent source files. @@ -570,17 +571,17 @@ var PrepareForTestWithCcDefaultModules = android.GroupFixturePreparers( // Additional files needed in tests that disallow non-existent source. android.MockFS{ - "defaults/cc/common/libc.map.txt": nil, - "defaults/cc/common/libdl.map.txt": nil, - "defaults/cc/common/libft2.map.txt": nil, - "defaults/cc/common/libm.map.txt": nil, - "defaults/cc/common/ndk_libc++_shared": nil, - "defaults/cc/common/crtbegin_so.c": nil, - "defaults/cc/common/crtbegin.c": nil, - "defaults/cc/common/crtend_so.c": nil, - "defaults/cc/common/crtend.c": nil, - "defaults/cc/common/crtbrand.c": nil, - "external/compiler-rt/lib/cfi/cfi_blocklist.txt": nil, + "defaults/cc/common/libc.map.txt": nil, + "defaults/cc/common/libdl.map.txt": nil, + "defaults/cc/common/libft2.map.txt": nil, + "defaults/cc/common/libm.map.txt": nil, + "defaults/cc/common/ndk_libc++_shared": nil, + "defaults/cc/common/crtbegin_so.c": nil, + "defaults/cc/common/crtbegin.c": nil, + "defaults/cc/common/crtend_so.c": nil, + "defaults/cc/common/crtend.c": nil, + "defaults/cc/common/crtbrand.c": nil, + "external/compiler-rt/lib/cfi/cfi_blocklist.txt": nil, "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil, "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a": nil, @@ -702,6 +703,7 @@ func CreateTestContext(config android.Config) *android.TestContext { ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) RegisterVndkLibraryTxtTypes(ctx) + RegisterLlndkLibraryTxtType(ctx) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) android.RegisterPrebuiltMutators(ctx) diff --git a/cc/tidy.go b/cc/tidy.go index 76ac7d583..ec1e8a206 100644 --- a/cc/tidy.go +++ b/cc/tidy.go @@ -220,7 +220,7 @@ func collectTidyObjModuleTargets(ctx android.SingletonContext, module android.Mo // (1) Collect all obj/tidy files into OS-specific groups. ctx.VisitAllModuleVariants(module, func(variant android.Module) { - if ctx.Config().KatiEnabled() && android.ShouldSkipAndroidMkProcessing(variant) { + if ctx.Config().KatiEnabled() && android.ShouldSkipAndroidMkProcessing(ctx, variant) { return } if m, ok := variant.(*Module); ok { diff --git a/cc/vndk.go b/cc/vndk.go index 14b44b643..548992d37 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -219,7 +219,6 @@ func vndkIsVndkDepAllowed(from *vndkdep, to *vndkdep) error { type moduleListerFunc func(ctx android.SingletonContext) (moduleNames, fileNames []string) var ( - llndkLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsLLNDK && !m.Header() }) vndkSPLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKSP }) vndkCoreLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKCore }) vndkPrivateLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKPrivate }) @@ -323,8 +322,8 @@ func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) { } // Check for modules that mustn't be VNDK -func shouldSkipVndkMutator(m *Module) bool { - if !m.Enabled() { +func shouldSkipVndkMutator(ctx android.ConfigAndErrorContext, m *Module) bool { + if !m.Enabled(ctx) { return true } if !m.Device() { @@ -339,7 +338,7 @@ func shouldSkipVndkMutator(m *Module) bool { } func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool { - if shouldSkipVndkMutator(m) { + if shouldSkipVndkMutator(mctx, m) { return false } @@ -370,7 +369,7 @@ func VndkMutator(mctx android.BottomUpMutatorContext) { return } - if shouldSkipVndkMutator(m) { + if shouldSkipVndkMutator(mctx, m) { return } @@ -378,19 +377,12 @@ func VndkMutator(mctx android.BottomUpMutatorContext) { prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker) if m.InVendorOrProduct() && isLib && lib.hasLLNDKStubs() { - m.VendorProperties.IsLLNDK = true m.VendorProperties.IsVNDKPrivate = Bool(lib.Properties.Llndk.Private) } if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() { - m.VendorProperties.IsLLNDK = true m.VendorProperties.IsVNDKPrivate = Bool(prebuiltLib.Properties.Llndk.Private) } - if m.IsVndkPrebuiltLibrary() && !m.IsVndk() { - m.VendorProperties.IsLLNDK = true - // TODO(b/280697209): copy "llndk.private" flag to vndk_prebuilt_shared - } - if (isLib && lib.buildShared()) || (isPrebuiltLib && prebuiltLib.buildShared()) { if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() { processVndkLibrary(mctx, m) @@ -404,8 +396,6 @@ func init() { } func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) { - ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory) - ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt_for_apex", llndkLibrariesTxtApexOnlyFactory) ctx.RegisterParallelSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory) ctx.RegisterParallelSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory) ctx.RegisterParallelSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory) @@ -435,25 +425,6 @@ type VndkLibrariesTxtProperties struct { var _ etc.PrebuiltEtcModule = &vndkLibrariesTxt{} var _ android.OutputFileProducer = &vndkLibrariesTxt{} -// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries -// generated by Soong. -// Make uses LLNDK_LIBRARIES to determine which libraries to install. -// HWASAN is only part of the LLNDK in builds in which libc depends on HWASAN. -// Therefore, by removing the library here, we cause it to only be installed if libc -// depends on it. -func llndkLibrariesTxtFactory() android.SingletonModule { - return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan") -} - -// llndk_libraries_txt_for_apex is a singleton module that provide the same LLNDK libraries list -// with the llndk_libraries_txt, but skips setting make variable LLNDK_LIBRARIES. So, it must not -// be used without installing llndk_libraries_txt singleton. -// We include llndk_libraries_txt by default to install the llndk.libraries.txt file to system/etc. -// This singleton module is to install the llndk.libraries.<ver>.txt file to vndk apex. -func llndkLibrariesTxtApexOnlyFactory() android.SingletonModule { - return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "", "libclang_rt.hwasan") -} - // vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries // generated by Soong but can be referenced by other modules. // For example, apex_vndk can depend on these files as prebuilt. @@ -577,6 +548,7 @@ func (txt *vndkLibrariesTxt) SubDir() string { func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) { return android.Paths{txt.outputFile}, nil } + func getVndkFileName(m *Module) (string, error) { if library, ok := m.linker.(*libraryDecorator); ok { return library.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil diff --git a/cmd/release_config/build_flag/main.go b/cmd/release_config/build_flag/main.go index 6f909af86..cc2b57a27 100644 --- a/cmd/release_config/build_flag/main.go +++ b/cmd/release_config/build_flag/main.go @@ -1,10 +1,12 @@ package main import ( + "cmp" "flag" "fmt" "os" "path/filepath" + "slices" "strings" rc_lib "android/soong/cmd/release_config/release_config_lib" @@ -36,6 +38,16 @@ type Flags struct { // Disable warning messages quiet bool + + // Show all release configs + allReleases bool + + // Call get_build_var PRODUCT_RELEASE_CONFIG_MAPS to get the + // product-specific map directories. + useGetBuildVar bool + + // Panic on errors. + debug bool } type CommandFunc func(*rc_lib.ReleaseConfigs, Flags, string, []string) error @@ -60,6 +72,14 @@ func GetMapDir(path string) (string, error) { return "", fmt.Errorf("Could not determine directory from %s", path) } +func MarshalFlagDefaultValue(config *rc_lib.ReleaseConfig, name string) (ret string, err error) { + fa, ok := config.FlagArtifacts[name] + if !ok { + return "", fmt.Errorf("%s not found in %s", name, config.Name) + } + return rc_lib.MarshalValue(fa.Traces[0].Value), nil +} + func MarshalFlagValue(config *rc_lib.ReleaseConfig, name string) (ret string, err error) { fa, ok := config.FlagArtifacts[name] if !ok { @@ -68,19 +88,41 @@ func MarshalFlagValue(config *rc_lib.ReleaseConfig, name string) (ret string, er return rc_lib.MarshalValue(fa.Value), nil } +// Returns a list of ReleaseConfig objects for which to process flags. func GetReleaseArgs(configs *rc_lib.ReleaseConfigs, commonFlags Flags) ([]*rc_lib.ReleaseConfig, error) { var all bool - relFlags := flag.NewFlagSet("set", flag.ExitOnError) - relFlags.BoolVar(&all, "all", false, "Display all flags") + relFlags := flag.NewFlagSet("releaseFlags", flag.ExitOnError) + relFlags.BoolVar(&all, "all", false, "Display all releases") relFlags.Parse(commonFlags.targetReleases) var ret []*rc_lib.ReleaseConfig - if all { + if all || commonFlags.allReleases { + sortMap := map[string]int{ + "trunk_staging": 0, + "trunk_food": 10, + "trunk": 20, + // Anything not listed above, uses this for key 1 in the sort. + "-default": 100, + } + for _, config := range configs.ReleaseConfigs { ret = append(ret, config) } + slices.SortFunc(ret, func(a, b *rc_lib.ReleaseConfig) int { + mapValue := func(v *rc_lib.ReleaseConfig) int { + if v, ok := sortMap[v.Name]; ok { + return v + } + return sortMap["-default"] + } + if n := cmp.Compare(mapValue(a), mapValue(b)); n != 0 { + return n + } + return cmp.Compare(a.Name, b.Name) + }) return ret, nil } for _, arg := range relFlags.Args() { + // Return releases in the order that they were given. config, err := configs.GetReleaseConfig(arg) if err != nil { return nil, err @@ -92,12 +134,17 @@ func GetReleaseArgs(configs *rc_lib.ReleaseConfigs, commonFlags Flags) ([]*rc_li func GetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, args []string) error { isTrace := cmd == "trace" + isSet := cmd == "set" + var all bool - getFlags := flag.NewFlagSet("set", flag.ExitOnError) + getFlags := flag.NewFlagSet("get", flag.ExitOnError) getFlags.BoolVar(&all, "all", false, "Display all flags") getFlags.Parse(args) args = getFlags.Args() + if isSet { + commonFlags.allReleases = true + } releaseConfigList, err := GetReleaseArgs(configs, commonFlags) if err != nil { return err @@ -113,21 +160,72 @@ func GetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, a } } - showName := len(releaseConfigList) > 1 || len(args) > 1 - for _, config := range releaseConfigList { - var configName string - if len(releaseConfigList) > 1 { - configName = fmt.Sprintf("%s.", config.Name) - } + var maxVariableNameLen, maxReleaseNameLen int + var releaseNameFormat, variableNameFormat string + valueFormat := "%s" + showReleaseName := len(releaseConfigList) > 1 + showVariableName := len(args) > 1 + if showVariableName { for _, arg := range args { - val, err := MarshalFlagValue(config, arg) - if err != nil { - return err + maxVariableNameLen = max(len(arg), maxVariableNameLen) + } + variableNameFormat = fmt.Sprintf("%%-%ds ", maxVariableNameLen) + valueFormat = "'%s'" + } + if showReleaseName { + for _, config := range releaseConfigList { + maxReleaseNameLen = max(len(config.Name), maxReleaseNameLen) + } + releaseNameFormat = fmt.Sprintf("%%-%ds ", maxReleaseNameLen) + valueFormat = "'%s'" + } + + outputOneLine := func(variable, release, value, valueFormat string) { + var outStr string + if showVariableName { + outStr += fmt.Sprintf(variableNameFormat, variable) + } + if showReleaseName { + outStr += fmt.Sprintf(releaseNameFormat, release) + } + outStr += fmt.Sprintf(valueFormat, value) + fmt.Println(outStr) + } + + for _, arg := range args { + if _, ok := configs.FlagArtifacts[arg]; !ok { + return fmt.Errorf("%s is not a defined build flag", arg) + } + } + + for _, arg := range args { + for _, config := range releaseConfigList { + if isSet { + // If this is from the set command, format the output as: + // <default> "" + // trunk_staging "" + // trunk "" + // + // ap1a "" + // ... + switch { + case config.Name == "trunk_staging": + defaultValue, err := MarshalFlagDefaultValue(config, arg) + if err != nil { + return err + } + outputOneLine(arg, "<default>", defaultValue, valueFormat) + case config.AconfigFlagsOnly: + continue + case config.Name == "trunk": + fmt.Println() + } } - if showName { - fmt.Printf("%s%s=%s\n", configName, arg, val) + val, err := MarshalFlagValue(config, arg) + if err == nil { + outputOneLine(arg, config.Name, val, valueFormat) } else { - fmt.Printf("%s\n", val) + outputOneLine(arg, config.Name, "REDACTED", "%s") } if isTrace { for _, trace := range config.FlagArtifacts[arg].Traces { @@ -160,12 +258,15 @@ func SetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, a if err != nil { return err } + if release.AconfigFlagsOnly { + return fmt.Errorf("%s does not allow build flag overrides", targetRelease) + } flagArtifact, ok := release.FlagArtifacts[name] if !ok { return fmt.Errorf("Unknown build flag %s", name) } if valueDir == "" { - mapDir, err := GetMapDir(*flagArtifact.Traces[len(flagArtifact.Traces)-1].Source) + mapDir, err := configs.GetFlagValueDirectory(release, flagArtifact) if err != nil { return err } @@ -177,53 +278,79 @@ func SetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, a Value: rc_lib.UnmarshalValue(value), } flagPath := filepath.Join(valueDir, "flag_values", targetRelease, fmt.Sprintf("%s.textproto", name)) - return rc_lib.WriteMessage(flagPath, flagValue) + err = rc_lib.WriteMessage(flagPath, flagValue) + if err != nil { + return err + } + + // Reload the release configs. + configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, commonFlags.targetReleases[0], commonFlags.useGetBuildVar) + if err != nil { + return err + } + err = GetCommand(configs, commonFlags, cmd, args[0:1]) + if err != nil { + return err + } + fmt.Printf("Updated: %s\n", flagPath) + return nil } func main() { - var err error var commonFlags Flags var configs *rc_lib.ReleaseConfigs + topDir, err := rc_lib.GetTopDir() - outEnv := os.Getenv("OUT_DIR") - if outEnv == "" { - outEnv = "out" - } // Handle the common arguments - flag.StringVar(&commonFlags.top, "top", ".", "path to top of workspace") + flag.StringVar(&commonFlags.top, "top", topDir, "path to top of workspace") flag.BoolVar(&commonFlags.quiet, "quiet", false, "disable warning messages") flag.Var(&commonFlags.maps, "map", "path to a release_config_map.textproto. may be repeated") - flag.StringVar(&commonFlags.outDir, "out_dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created") + flag.StringVar(&commonFlags.outDir, "out-dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created") flag.Var(&commonFlags.targetReleases, "release", "TARGET_RELEASE for this build") + flag.BoolVar(&commonFlags.allReleases, "all-releases", false, "operate on all releases. (Ignored for set command)") + flag.BoolVar(&commonFlags.useGetBuildVar, "use-get-build-var", true, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS to get needed maps") + flag.BoolVar(&commonFlags.debug, "debug", false, "turn on debugging output for errors") flag.Parse() + errorExit := func(err error) { + if commonFlags.debug { + panic(err) + } + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } + if commonFlags.quiet { rc_lib.DisableWarnings() } if len(commonFlags.targetReleases) == 0 { - commonFlags.targetReleases = rc_lib.StringList{"trunk_staging"} + release, ok := os.LookupEnv("TARGET_RELEASE") + if ok { + commonFlags.targetReleases = rc_lib.StringList{release} + } else { + commonFlags.targetReleases = rc_lib.StringList{"trunk_staging"} + } } if err = os.Chdir(commonFlags.top); err != nil { - panic(err) + errorExit(err) } // Get the current state of flagging. relName := commonFlags.targetReleases[0] if relName == "--all" || relName == "-all" { - // If the users said `--release --all`, grab trunk staging for simplicity. - relName = "trunk_staging" + commonFlags.allReleases = true } - configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, relName) + configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, relName, commonFlags.useGetBuildVar) if err != nil { - panic(err) + errorExit(err) } if cmd, ok := commandMap[flag.Arg(0)]; ok { args := flag.Args() if err = cmd(configs, commonFlags, args[0], args[1:]); err != nil { - panic(err) + errorExit(err) } } } diff --git a/cmd/release_config/crunch_flags/main.go b/cmd/release_config/crunch_flags/main.go index 616674bc5..4d763c8d7 100644 --- a/cmd/release_config/crunch_flags/main.go +++ b/cmd/release_config/crunch_flags/main.go @@ -15,18 +15,30 @@ import ( "google.golang.org/protobuf/proto" ) -// When a flag declaration has an initial value that is a string, the default workflow is PREBUILT. -// If the flag name starts with any of prefixes in manualFlagNamePrefixes, it is MANUAL. -var manualFlagNamePrefixes []string = []string{ - "RELEASE_ACONFIG_", - "RELEASE_PLATFORM_", -} +var ( + // When a flag declaration has an initial value that is a string, the default workflow is PREBUILT. + // If the flag name starts with any of prefixes in manualFlagNamePrefixes, it is MANUAL. + manualFlagNamePrefixes []string = []string{ + "RELEASE_ACONFIG_", + "RELEASE_PLATFORM_", + "RELEASE_BUILD_FLAGS_", + } + + // Set `aconfig_flags_only: true` in these release configs. + aconfigFlagsOnlyConfigs map[string]bool = map[string]bool{ + "trunk_food": true, + } + + // Default namespace value. This is intentionally invalid. + defaultFlagNamespace string = "android_UNKNOWN" -var defaultFlagNamespace string = "android_UNKNOWN" + // What is the current name for "next". + nextName string = "ap3a" +) func RenameNext(name string) string { if name == "next" { - return "ap3a" + return nextName } return name } @@ -89,7 +101,10 @@ func ProcessBuildFlags(dir string, namespaceMap map[string]string) error { for _, line := range lines { if comment := commentRegexp.FindStringSubmatch(commentRegexp.FindString(line)); comment != nil { // Description is the text from any contiguous series of lines before a `flag()` call. - description += fmt.Sprintf(" %s", strings.TrimSpace(comment[commentRegexp.SubexpIndex("comment")])) + descLine := strings.TrimSpace(comment[commentRegexp.SubexpIndex("comment")]) + if !strings.HasPrefix(descLine, "keep-sorted") { + description += fmt.Sprintf(" %s", descLine) + } continue } matches := declRegexp.FindStringSubmatch(declRegexp.FindString(line)) @@ -99,10 +114,13 @@ func ProcessBuildFlags(dir string, namespaceMap map[string]string) error { description = "" continue } - declValue := matches[declRegexp.SubexpIndex("value")] declName := matches[declRegexp.SubexpIndex("name")] - container := rc_proto.Container(rc_proto.Container_value[matches[declRegexp.SubexpIndex("container")]]) + declValue := matches[declRegexp.SubexpIndex("value")] description = strings.TrimSpace(description) + containers := []string{strings.ToLower(matches[declRegexp.SubexpIndex("container")])} + if containers[0] == "all" { + containers = []string{"product", "system", "system_ext", "vendor"} + } var namespace string var ok bool if namespace, ok = namespaceMap[declName]; !ok { @@ -112,7 +130,7 @@ func ProcessBuildFlags(dir string, namespaceMap map[string]string) error { Name: proto.String(declName), Namespace: proto.String(namespace), Description: proto.String(description), - Container: &container, + Containers: containers, } description = "" // Most build flags are `workflow: PREBUILT`. @@ -160,7 +178,7 @@ func ProcessBuildFlags(dir string, namespaceMap map[string]string) error { } func ProcessBuildConfigs(dir, name string, paths []string, releaseProto *rc_proto.ReleaseConfig) error { - valRegexp, err := regexp.Compile("[[:space:]]+value.\"(?<name>[A-Z_0-9]+)\",[[:space:]]*(?<value>[^,)]*)") + valRegexp, err := regexp.Compile("[[:space:]]+value.\"(?<name>[A-Z_0-9]+)\",[[:space:]]*(?<value>(\"[^\"]*\"|[^\",)]*))") if err != nil { return err } @@ -199,6 +217,9 @@ func ProcessBuildConfigs(dir, name string, paths []string, releaseProto *rc_prot fmt.Printf("%s: Unexpected value %s=%s\n", path, valName, valValue) } if flagValue != nil { + if releaseProto.GetAconfigFlagsOnly() { + return fmt.Errorf("%s does not allow build flag overrides", RenameNext(name)) + } valPath := filepath.Join(dir, "flag_values", RenameNext(name), fmt.Sprintf("%s.textproto", valName)) err := WriteFile(valPath, flagValue) if err != nil { @@ -210,6 +231,12 @@ func ProcessBuildConfigs(dir, name string, paths []string, releaseProto *rc_prot return err } +var ( + allContainers = func() []string { + return []string{"product", "system", "system_ext", "vendor"} + }() +) + func ProcessReleaseConfigMap(dir string, descriptionMap map[string]string) error { path := filepath.Join(dir, "release_config_map.mk") if _, err := os.Stat(path); err != nil { @@ -218,7 +245,7 @@ func ProcessReleaseConfigMap(dir string, descriptionMap map[string]string) error } else { fmt.Printf("Processing %s\n", path) } - configRegexp, err := regexp.Compile("^..call[[:space:]]+declare-release-config,[[:space:]]+(?<name>[_a-z0-0A-Z]+),[[:space:]]+(?<files>[^,]*)(,[[:space:]]*(?<inherits>.*)|[[:space:]]*)[)]$") + configRegexp, err := regexp.Compile("^..call[[:space:]]+declare-release-config,[[:space:]]+(?<name>[_a-z0-9A-Z]+),[[:space:]]+(?<files>[^,]*)(,[[:space:]]*(?<inherits>.*)|[[:space:]]*)[)]$") if err != nil { return err } @@ -232,16 +259,16 @@ func ProcessReleaseConfigMap(dir string, descriptionMap map[string]string) error return err } cleanDir := strings.TrimLeft(dir, "../") - var defaultContainer rc_proto.Container + var defaultContainers []string switch { case strings.HasPrefix(cleanDir, "build/") || cleanDir == "vendor/google_shared/build": - defaultContainer = rc_proto.Container(rc_proto.Container_ALL) + defaultContainers = allContainers case cleanDir == "vendor/google/release": - defaultContainer = rc_proto.Container(rc_proto.Container_ALL) + defaultContainers = allContainers default: - defaultContainer = rc_proto.Container(rc_proto.Container_VENDOR) + defaultContainers = []string{"vendor"} } - releaseConfigMap := &rc_proto.ReleaseConfigMap{DefaultContainer: &defaultContainer} + releaseConfigMap := &rc_proto.ReleaseConfigMap{DefaultContainers: defaultContainers} // If we find a description for the directory, include it. if description, ok := descriptionMap[cleanDir]; ok { releaseConfigMap.Description = proto.String(description) @@ -273,6 +300,9 @@ func ProcessReleaseConfigMap(dir string, descriptionMap map[string]string) error releaseConfig := &rc_proto.ReleaseConfig{ Name: proto.String(RenameNext(name)), } + if aconfigFlagsOnlyConfigs[name] { + releaseConfig.AconfigFlagsOnly = proto.Bool(true) + } configFiles := config[configRegexp.SubexpIndex("files")] files := strings.Split(strings.ReplaceAll(configFiles, "$(local_dir)", dir+"/"), " ") configInherits := config[configRegexp.SubexpIndex("inherits")] @@ -299,15 +329,26 @@ func main() { var dirs rc_lib.StringList var namespacesFile string var descriptionsFile string + var debug bool + defaultTopDir, err := rc_lib.GetTopDir() - flag.StringVar(&top, "top", ".", "path to top of workspace") + flag.StringVar(&top, "top", defaultTopDir, "path to top of workspace") flag.Var(&dirs, "dir", "directory to process, relative to the top of the workspace") flag.StringVar(&namespacesFile, "namespaces", "", "location of file with 'flag_name namespace' information") flag.StringVar(&descriptionsFile, "descriptions", "", "location of file with 'directory description' information") + flag.BoolVar(&debug, "debug", false, "turn on debugging output for errors") flag.Parse() + errorExit := func(err error) { + if debug { + panic(err) + } + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } + if err = os.Chdir(top); err != nil { - panic(err) + errorExit(err) } if len(dirs) == 0 { dirs = rc_lib.StringList{"build/release", "vendor/google_shared/build/release", "vendor/google/release"} @@ -317,12 +358,12 @@ func main() { if namespacesFile != "" { data, err := os.ReadFile(namespacesFile) if err != nil { - panic(err) + errorExit(err) } for idx, line := range strings.Split(string(data), "\n") { fields := strings.Split(line, " ") if len(fields) > 2 { - panic(fmt.Errorf("line %d: too many fields: %s", idx, line)) + errorExit(fmt.Errorf("line %d: too many fields: %s", idx, line)) } namespaceMap[fields[0]] = fields[1] } @@ -334,7 +375,7 @@ func main() { if descriptionsFile != "" { data, err := os.ReadFile(descriptionsFile) if err != nil { - panic(err) + errorExit(err) } for _, line := range strings.Split(string(data), "\n") { if strings.TrimSpace(line) != "" { @@ -348,12 +389,12 @@ func main() { for _, dir := range dirs { err = ProcessBuildFlags(dir, namespaceMap) if err != nil { - panic(err) + errorExit(err) } err = ProcessReleaseConfigMap(dir, descriptionMap) if err != nil { - panic(err) + errorExit(err) } } } diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go index a43fdccbe..54328068a 100644 --- a/cmd/release_config/release_config/main.go +++ b/cmd/release_config/release_config/main.go @@ -33,6 +33,9 @@ func main() { var configs *rc_lib.ReleaseConfigs var json, pb, textproto bool var product string + var allMake bool + var useBuildVar bool + var guard bool defaultRelease := os.Getenv("TARGET_RELEASE") if defaultRelease == "" { @@ -48,6 +51,10 @@ func main() { flag.BoolVar(&textproto, "textproto", true, "write artifacts as text protobuf") flag.BoolVar(&json, "json", true, "write artifacts as json") flag.BoolVar(&pb, "pb", true, "write artifacts as binary protobuf") + flag.BoolVar(&allMake, "all_make", true, "write makefiles for all release configs") + flag.BoolVar(&useBuildVar, "use_get_build_var", false, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS") + flag.BoolVar(&guard, "guard", true, "whether to guard with RELEASE_BUILD_FLAGS_IN_PROTOBUF") + flag.Parse() if quiet { @@ -57,7 +64,7 @@ func main() { if err = os.Chdir(top); err != nil { panic(err) } - configs, err = rc_lib.ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease) + configs, err = rc_lib.ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease, useBuildVar) if err != nil { panic(err) } @@ -65,16 +72,36 @@ func main() { if err != nil { panic(err) } - releaseName := config.Name err = os.MkdirAll(outputDir, 0775) if err != nil { panic(err) } - makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, releaseName)) + + makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, targetRelease)) + useProto, ok := config.FlagArtifacts["RELEASE_BUILD_FLAGS_IN_PROTOBUF"] + if guard && (!ok || rc_lib.MarshalValue(useProto.Value) == "") { + // We were told to guard operation and either we have no build flag, or it is False. + // Write an empty file so that release_config.mk will use the old process. + os.WriteFile(makefilePath, []byte{}, 0644) + return + } + // Write the makefile where release_config.mk is going to look for it. err = configs.WriteMakefile(makefilePath, targetRelease) if err != nil { panic(err) } + if allMake { + // Write one makefile per release config, using the canonical release name. + for k, _ := range configs.ReleaseConfigs { + if k != targetRelease { + makefilePath = filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, k)) + err = configs.WriteMakefile(makefilePath, k) + if err != nil { + panic(err) + } + } + } + } if json { err = configs.WriteArtifact(outputDir, product, "json") if err != nil { @@ -93,4 +120,8 @@ func main() { panic(err) } } + if err = config.WritePartitionBuildFlags(outputDir, product, targetRelease); err != nil { + panic(err) + } + } diff --git a/cmd/release_config/release_config_lib/flag_artifact.go b/cmd/release_config/release_config_lib/flag_artifact.go index 4446655f7..cba1b5cd8 100644 --- a/cmd/release_config/release_config_lib/flag_artifact.go +++ b/cmd/release_config/release_config_lib/flag_artifact.go @@ -36,6 +36,10 @@ type FlagArtifact struct { // The value of the flag. Value *rc_proto.Value + + // This flag is redacted. Set by UpdateValue when the FlagValue proto + // says to redact it. + Redacted bool } // Key is flag name. @@ -85,6 +89,11 @@ func (src FlagArtifacts) Clone() (dst FlagArtifacts) { func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error { name := *flagValue.proto.Name fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value}) + if flagValue.proto.GetRedacted() { + fa.Redacted = true + fmt.Printf("Redacting flag %s in %s\n", name, flagValue.path) + return nil + } if fa.Value.GetObsolete() { return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces) } @@ -111,9 +120,23 @@ func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error { // Marshal the FlagArtifact into a flag_artifact message. func (fa *FlagArtifact) Marshal() (*rc_proto.FlagArtifact, error) { + if fa.Redacted { + return nil, nil + } return &rc_proto.FlagArtifact{ FlagDeclaration: fa.FlagDeclaration, Value: fa.Value, Traces: fa.Traces, }, nil } + +// Marshal the FlagArtifact without Traces. +func (fa *FlagArtifact) MarshalWithoutTraces() (*rc_proto.FlagArtifact, error) { + if fa.Redacted { + return nil, nil + } + return &rc_proto.FlagArtifact{ + FlagDeclaration: fa.FlagDeclaration, + Value: fa.Value, + }, nil +} diff --git a/cmd/release_config/release_config_lib/flag_value.go b/cmd/release_config/release_config_lib/flag_value.go index e155e7782..59021e260 100644 --- a/cmd/release_config/release_config_lib/flag_value.go +++ b/cmd/release_config/release_config_lib/flag_value.go @@ -52,6 +52,9 @@ func UnmarshalValue(str string) *rc_proto.Value { } func MarshalValue(value *rc_proto.Value) string { + if value == nil { + return "" + } switch val := value.Val.(type) { case *rc_proto.Value_UnspecifiedValue: // Value was never set. diff --git a/cmd/release_config/release_config_lib/flag_value_test.go b/cmd/release_config/release_config_lib/flag_value_test.go index aaa4cafeb..8a98baf6a 100644 --- a/cmd/release_config/release_config_lib/flag_value_test.go +++ b/cmd/release_config/release_config_lib/flag_value_test.go @@ -24,7 +24,7 @@ import ( "google.golang.org/protobuf/proto" ) -type testCaseFlagValue struct { +type testCaseFlagValueFactory struct { protoPath string name string data []byte @@ -32,14 +32,14 @@ type testCaseFlagValue struct { err error } -func (tc testCaseFlagValue) assertProtoEqual(t *testing.T, expected, actual proto.Message) { +func (tc testCaseFlagValueFactory) 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{ +func TestFlagValueFactory(t *testing.T) { + testCases := []testCaseFlagValueFactory{ { name: "stringVal", protoPath: "build/release/flag_values/test/RELEASE_FOO.textproto", @@ -65,3 +65,50 @@ func TestFlagValue(t *testing.T) { tc.assertProtoEqual(t, &tc.expected, &actual.proto) } } + +type testCaseMarshalValue struct { + name string + value *rc_proto.Value + expected string +} + +func TestMarshalValue(t *testing.T) { + testCases := []testCaseMarshalValue{ + { + name: "nil", + value: nil, + expected: "", + }, + { + name: "unspecified", + value: &rc_proto.Value{}, + expected: "", + }, + { + name: "false", + value: &rc_proto.Value{Val: &rc_proto.Value_BoolValue{false}}, + expected: "", + }, + { + name: "true", + value: &rc_proto.Value{Val: &rc_proto.Value_BoolValue{true}}, + expected: "true", + }, + { + name: "string", + value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{"BAR"}}, + expected: "BAR", + }, + { + name: "obsolete", + value: &rc_proto.Value{Val: &rc_proto.Value_Obsolete{true}}, + expected: " #OBSOLETE", + }, + } + for _, tc := range testCases { + actual := MarshalValue(tc.value) + if actual != tc.expected { + t.Errorf("Expected %q found %q", tc.expected, actual) + } + } +} diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go index c67cee54a..820482239 100644 --- a/cmd/release_config/release_config_lib/release_config.go +++ b/cmd/release_config/release_config_lib/release_config.go @@ -15,7 +15,11 @@ package release_config_lib import ( + "cmp" "fmt" + "path/filepath" + "slices" + "sort" "strings" rc_proto "android/soong/cmd/release_config/release_config_proto" @@ -25,7 +29,7 @@ import ( // One directory's contribution to the a release config. type ReleaseConfigContribution struct { - // Paths to files providing this config. + // Path of the file providing this config contribution. path string // The index of the config directory where this release config @@ -58,6 +62,10 @@ type ReleaseConfig struct { // The names of release configs that we inherit InheritNames []string + // True if this release config only allows inheritance and aconfig flag + // overrides. Build flag value overrides are an error. + AconfigFlagsOnly bool + // Unmarshalled flag artifacts FlagArtifacts FlagArtifacts @@ -66,12 +74,37 @@ type ReleaseConfig struct { // We have begun compiling this release config. compileInProgress bool + + // Partitioned artifacts for {partition}/etc/build_flags.json + PartitionBuildFlags map[string]*rc_proto.FlagArtifacts } func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) { return &ReleaseConfig{Name: name, DeclarationIndex: index} } +func (config *ReleaseConfig) InheritConfig(iConfig *ReleaseConfig) error { + for _, fa := range iConfig.FlagArtifacts { + name := *fa.FlagDeclaration.Name + myFa, ok := config.FlagArtifacts[name] + if !ok { + return fmt.Errorf("Could not inherit flag %s from %s", name, iConfig.Name) + } + if name == "RELEASE_ACONFIG_VALUE_SETS" { + if len(fa.Traces) > 0 { + myFa.Traces = append(myFa.Traces, fa.Traces...) + myFa.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{ + myFa.Value.GetStringValue() + " " + fa.Value.GetStringValue()}} + } + } else if len(fa.Traces) > 1 { + // A value was assigned. Set our value. + myFa.Traces = append(myFa.Traces, fa.Traces[1:]...) + myFa.Value = fa.Value + } + } + return nil +} + func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error { if config.ReleaseConfigArtifact != nil { return nil @@ -82,6 +115,10 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro config.compileInProgress = true isRoot := config.Name == "root" + // Start with only the flag declarations. + config.FlagArtifacts = configs.FlagArtifacts.Clone() + releaseAconfigValueSets := config.FlagArtifacts["RELEASE_ACONFIG_VALUE_SETS"] + // Generate any configs we need to inherit. This will detect loops in // the config. contributionsToApply := []*ReleaseConfigContribution{} @@ -103,72 +140,68 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro return err } iConfig.GenerateReleaseConfig(configs) - contributionsToApply = append(contributionsToApply, iConfig.Contributions...) + if err := config.InheritConfig(iConfig); err != nil { + return err + } } contributionsToApply = append(contributionsToApply, config.Contributions...) - myAconfigValueSets := []string{} - myAconfigValueSetsMap := map[string]bool{} - myFlags := configs.FlagArtifacts.Clone() workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL) - container := rc_proto.Container(rc_proto.Container_ALL) - releaseAconfigValueSets := FlagArtifact{ - FlagDeclaration: &rc_proto.FlagDeclaration{ - Name: proto.String("RELEASE_ACONFIG_VALUE_SETS"), - Namespace: proto.String("android_UNKNOWN"), - Description: proto.String("Aconfig value sets assembled by release-config"), - Workflow: &workflowManual, - Container: &container, - Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{""}}, - }, - DeclarationIndex: -1, - Traces: []*rc_proto.Tracepoint{ - &rc_proto.Tracepoint{ - Source: proto.String("$release-config"), - Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{""}}, - }, - }, - } - myFlags["RELEASE_ACONFIG_VALUE_SETS"] = &releaseAconfigValueSets myDirsMap := make(map[int]bool) for _, contrib := range contributionsToApply { - if len(contrib.proto.AconfigValueSets) > 0 { - contribAconfigValueSets := []string{} - for _, v := range contrib.proto.AconfigValueSets { - if _, ok := myAconfigValueSetsMap[v]; !ok { - contribAconfigValueSets = append(contribAconfigValueSets, v) - myAconfigValueSetsMap[v] = true - } - } - myAconfigValueSets = append(myAconfigValueSets, contribAconfigValueSets...) - releaseAconfigValueSets.Traces = append( - releaseAconfigValueSets.Traces, - &rc_proto.Tracepoint{ - Source: proto.String(contrib.path), - Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.Join(contribAconfigValueSets, " ")}}, - }) + contribAconfigValueSets := []string{} + // Gather the aconfig_value_sets from this contribution, allowing duplicates for simplicity. + for _, v := range contrib.proto.AconfigValueSets { + contribAconfigValueSets = append(contribAconfigValueSets, v) } + contribAconfigValueSetsString := strings.Join(contribAconfigValueSets, " ") + releaseAconfigValueSets.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{ + releaseAconfigValueSets.Value.GetStringValue() + " " + contribAconfigValueSetsString}} + releaseAconfigValueSets.Traces = append( + releaseAconfigValueSets.Traces, + &rc_proto.Tracepoint{ + Source: proto.String(contrib.path), + Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{contribAconfigValueSetsString}}, + }) + myDirsMap[contrib.DeclarationIndex] = true + if config.AconfigFlagsOnly && len(contrib.FlagValues) > 0 { + return fmt.Errorf("%s does not allow build flag overrides", config.Name) + } for _, value := range contrib.FlagValues { - fa, ok := myFlags[*value.proto.Name] + name := *value.proto.Name + fa, ok := config.FlagArtifacts[name] if !ok { - return fmt.Errorf("Setting value for undefined flag %s in %s\n", *value.proto.Name, value.path) + return fmt.Errorf("Setting value for undefined flag %s in %s\n", 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) + return fmt.Errorf("Setting value for flag %s not allowed in %s\n", name, value.path) } if isRoot && *fa.FlagDeclaration.Workflow != workflowManual { // The "root" release config can only contain workflow: MANUAL flags. - return fmt.Errorf("Setting value for non-MANUAL flag %s is not allowed in %s", *value.proto.Name, value.path) + return fmt.Errorf("Setting value for non-MANUAL flag %s is not allowed in %s", name, value.path) } if err := fa.UpdateValue(*value); err != nil { return err } + if fa.Redacted { + delete(config.FlagArtifacts, name) + } + } + } + // Now remove any duplicates from the actual value of RELEASE_ACONFIG_VALUE_SETS + myAconfigValueSets := []string{} + myAconfigValueSetsMap := map[string]bool{} + for _, v := range strings.Split(releaseAconfigValueSets.Value.GetStringValue(), " ") { + if myAconfigValueSetsMap[v] { + continue } + myAconfigValueSetsMap[v] = true + myAconfigValueSets = append(myAconfigValueSets, v) } - releaseAconfigValueSets.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.Join(myAconfigValueSets, " ")}} + releaseAconfigValueSets.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.TrimSpace(strings.Join(myAconfigValueSets, " "))}} directories := []string{} for idx, confDir := range configs.configDirs { @@ -177,13 +210,32 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro } } - config.FlagArtifacts = myFlags + // Now build the per-partition artifacts + config.PartitionBuildFlags = make(map[string]*rc_proto.FlagArtifacts) + for _, v := range config.FlagArtifacts { + artifact, err := v.MarshalWithoutTraces() + if err != nil { + return err + } + for _, container := range v.FlagDeclaration.Containers { + if _, ok := config.PartitionBuildFlags[container]; !ok { + config.PartitionBuildFlags[container] = &rc_proto.FlagArtifacts{} + } + config.PartitionBuildFlags[container].FlagArtifacts = append(config.PartitionBuildFlags[container].FlagArtifacts, artifact) + } + } config.ReleaseConfigArtifact = &rc_proto.ReleaseConfigArtifact{ Name: proto.String(config.Name), OtherNames: config.OtherNames, FlagArtifacts: func() []*rc_proto.FlagArtifact { ret := []*rc_proto.FlagArtifact{} - for _, flag := range myFlags { + flagNames := []string{} + for k := range config.FlagArtifacts { + flagNames = append(flagNames, k) + } + sort.Strings(flagNames) + for _, flagName := range flagNames { + flag := config.FlagArtifacts[flagName] ret = append(ret, &rc_proto.FlagArtifact{ FlagDeclaration: flag.FlagDeclaration, Traces: flag.Traces, @@ -200,3 +252,16 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro config.compileInProgress = false return nil } + +func (config *ReleaseConfig) WritePartitionBuildFlags(outDir, product, targetRelease string) error { + var err error + for partition, flags := range config.PartitionBuildFlags { + slices.SortFunc(flags.FlagArtifacts, func(a, b *rc_proto.FlagArtifact) int { + return cmp.Compare(*a.FlagDeclaration.Name, *b.FlagDeclaration.Name) + }) + if err = WriteMessage(filepath.Join(outDir, fmt.Sprintf("build_flags_%s-%s-%s.json", partition, config.Name, product)), flags); err != nil { + return err + } + } + return nil +} diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go index 6efdb2f08..8a4e2d58b 100644 --- a/cmd/release_config/release_config_lib/release_configs.go +++ b/cmd/release_config/release_config_lib/release_configs.go @@ -95,7 +95,7 @@ func (configs *ReleaseConfigs) WriteArtifact(outDir, product, format string) err } func ReleaseConfigsFactory() (c *ReleaseConfigs) { - return &ReleaseConfigs{ + configs := ReleaseConfigs{ Aliases: make(map[string]*string), FlagArtifacts: make(map[string]*FlagArtifact), ReleaseConfigs: make(map[string]*ReleaseConfig), @@ -103,6 +103,21 @@ func ReleaseConfigsFactory() (c *ReleaseConfigs) { configDirs: []string{}, configDirIndexes: make(ReleaseConfigDirMap), } + workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL) + releaseAconfigValueSets := FlagArtifact{ + FlagDeclaration: &rc_proto.FlagDeclaration{ + Name: proto.String("RELEASE_ACONFIG_VALUE_SETS"), + Namespace: proto.String("android_UNKNOWN"), + Description: proto.String("Aconfig value sets assembled by release-config"), + Workflow: &workflowManual, + Containers: []string{"system", "system_ext", "product", "vendor"}, + Value: &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}}, + }, + DeclarationIndex: -1, + Traces: []*rc_proto.Tracepoint{}, + } + configs.FlagArtifacts["RELEASE_ACONFIG_VALUE_SETS"] = &releaseAconfigValueSets + return &configs } func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) { @@ -116,10 +131,44 @@ func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) { return m } +// Find the top of the release config contribution directory. +// Returns the parent of the flag_declarations and flag_values directories. +func (configs *ReleaseConfigs) GetDirIndex(path string) (int, error) { + for p := path; p != "."; p = filepath.Dir(p) { + if idx, ok := configs.configDirIndexes[p]; ok { + return idx, nil + } + } + return -1, fmt.Errorf("Could not determine release config directory from %s", path) +} + +// Determine the default directory for writing a flag value. +// +// Returns the path of the highest-Indexed one of: +// - Where the flag is declared +// - Where the release config is first declared +// - The last place the value is being written. +func (configs *ReleaseConfigs) GetFlagValueDirectory(config *ReleaseConfig, flag *FlagArtifact) (string, error) { + current, err := configs.GetDirIndex(*flag.Traces[len(flag.Traces)-1].Source) + if err != nil { + return "", err + } + index := max(flag.DeclarationIndex, config.DeclarationIndex, current) + return configs.configDirs[index], nil +} + func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error { + if _, err := os.Stat(path); err != nil { + return fmt.Errorf("%s does not exist\n", path) + } m := ReleaseConfigMapFactory(path) - if m.proto.DefaultContainer == nil { - return fmt.Errorf("Release config map %s lacks default_container", path) + if m.proto.DefaultContainers == nil { + return fmt.Errorf("Release config map %s lacks default_containers", path) + } + for _, container := range m.proto.DefaultContainers { + if !validContainer(container) { + return fmt.Errorf("Release config map %s has invalid container %s", path, container) + } } dir := filepath.Dir(path) // Record any aliases, checking for duplicates. @@ -138,9 +187,16 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error { flagDeclaration := FlagDeclarationFactory(path) // Container must be specified. - if flagDeclaration.Container == nil { - flagDeclaration.Container = m.proto.DefaultContainer + if flagDeclaration.Containers == nil { + flagDeclaration.Containers = m.proto.DefaultContainers + } else { + for _, container := range flagDeclaration.Containers { + if !validContainer(container) { + return fmt.Errorf("Flag declaration %s has invalid container %s", path, container) + } + } } + // TODO: once we have namespaces initialized, we can throw an error here. if flagDeclaration.Namespace == nil { flagDeclaration.Namespace = proto.String("android_UNKNOWN") @@ -151,6 +207,9 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex } m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration) name := *flagDeclaration.Name + if name == "RELEASE_ACONFIG_VALUE_SETS" { + return fmt.Errorf("%s: %s is a reserved build flag", path, name) + } if def, ok := configs.FlagArtifacts[name]; !ok { configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex} } else if !proto.Equal(def.FlagDeclaration, flagDeclaration) { @@ -160,6 +219,9 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex configs.FlagArtifacts[name].UpdateValue( FlagValue{path: path, proto: rc_proto.FlagValue{ Name: proto.String(name), Value: flagDeclaration.Value}}) + if configs.FlagArtifacts[name].Redacted { + return fmt.Errorf("%s may not be redacted by default.", name) + } return nil }) if err != nil { @@ -185,12 +247,18 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex if fmt.Sprintf("%s.textproto", *flagValue.proto.Name) != filepath.Base(path) { return fmt.Errorf("%s incorrectly sets value for flag %s", path, *flagValue.proto.Name) } + if *flagValue.proto.Name == "RELEASE_ACONFIG_VALUE_SETS" { + return fmt.Errorf("%s: %s is a reserved build flag", path, *flagValue.proto.Name) + } releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue) return nil }) if err2 != nil { return err2 } + if releaseConfigContribution.proto.GetAconfigFlagsOnly() { + config.AconfigFlagsOnly = true + } m.ReleaseConfigContributions[name] = releaseConfigContribution config.Contributions = append(config.Contributions, releaseConfigContribution) return nil @@ -250,19 +318,12 @@ func (configs *ReleaseConfigs) WriteMakefile(outFile, targetRelease string) erro flag := myFlagArtifacts[name] decl := flag.FlagDeclaration - // cName := strings.ToLower(rc_proto.Container_name[decl.GetContainer()]) - cName := strings.ToLower(decl.Container.String()) - if cName == strings.ToLower(rc_proto.Container_ALL.String()) { - partitions["product"] = append(partitions["product"], name) - partitions["system"] = append(partitions["system"], name) - partitions["system_ext"] = append(partitions["system_ext"], name) - partitions["vendor"] = append(partitions["vendor"], name) - } else { - partitions[cName] = append(partitions[cName], name) + for _, container := range decl.Containers { + partitions[container] = append(partitions[container], name) } value := MarshalValue(flag.Value) makeVars[name] = value - addVar(name, "PARTITIONS", cName) + addVar(name, "PARTITIONS", strings.Join(decl.Containers, " ")) addVar(name, "DEFAULT", MarshalValue(decl.Value)) addVar(name, "VALUE", value) addVar(name, "DECLARED_IN", *flag.Traces[0].Source) @@ -357,23 +418,35 @@ func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) erro return nil } -func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string) (*ReleaseConfigs, error) { +func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string, useBuildVar bool) (*ReleaseConfigs, error) { var err error if len(releaseConfigMapPaths) == 0 { - releaseConfigMapPaths = GetDefaultMapPaths() + releaseConfigMapPaths, err = GetDefaultMapPaths(useBuildVar) + if err != nil { + return nil, err + } 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 ")) + if !useBuildVar { + warnf("No --map argument provided. Using: --map %s\n", strings.Join(releaseConfigMapPaths, " --map ")) + } } configs := ReleaseConfigsFactory() + mapsRead := make(map[string]bool) for idx, releaseConfigMapPath := range releaseConfigMapPaths { // Maintain an ordered list of release config directories. configDir := filepath.Dir(releaseConfigMapPath) + if mapsRead[configDir] { + continue + } + mapsRead[configDir] = true configs.configDirIndexes[configDir] = idx configs.configDirs = append(configs.configDirs, configDir) + // Force the path to be the textproto path, so that both the scl and textproto formats can coexist. + releaseConfigMapPath = filepath.Join(configDir, "release_config_map.textproto") err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx) if err != nil { return nil, err diff --git a/cmd/release_config/release_config_lib/util.go b/cmd/release_config/release_config_lib/util.go index 86940da68..c0ea7897b 100644 --- a/cmd/release_config/release_config_lib/util.go +++ b/cmd/release_config/release_config_lib/util.go @@ -19,14 +19,19 @@ import ( "fmt" "io/fs" "os" + "os/exec" "path/filepath" + "regexp" "strings" "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" ) -var disableWarnings bool +var ( + disableWarnings bool + containerRegexp, _ = regexp.Compile("^[a-z][a-z0-9]*([._][a-z][a-z0-9]*)*$") +) type StringList []string @@ -123,11 +128,15 @@ func DisableWarnings() { func warnf(format string, args ...any) (n int, err error) { if !disableWarnings { - return fmt.Printf(format, args...) + return fmt.Fprintf(os.Stderr, format, args...) } return 0, nil } +func validContainer(container string) bool { + return containerRegexp.MatchString(container) +} + // Returns the default value for release config artifacts. func GetDefaultOutDir() string { outEnv := os.Getenv("OUT_DIR") @@ -137,22 +146,64 @@ func GetDefaultOutDir() string { return filepath.Join(outEnv, "soong", "release-config") } +// Find the top of the workspace. +// +// This mirrors the logic in build/envsetup.sh's gettop(). +func GetTopDir() (topDir string, err error) { + workingDir, err := os.Getwd() + if err != nil { + return + } + topFile := "build/make/core/envsetup.mk" + for topDir = workingDir; topDir != "/"; topDir = filepath.Dir(topDir) { + if _, err = os.Stat(filepath.Join(topDir, topFile)); err == nil { + return filepath.Rel(workingDir, topDir) + } + } + return "", fmt.Errorf("Unable to locate top of workspace") +} + // Return the default list of map files to use. -func GetDefaultMapPaths() StringList { - var defaultMapPaths StringList - defaultLocations := StringList{ +func GetDefaultMapPaths(queryMaps bool) (defaultMapPaths StringList, err error) { + var defaultLocations StringList + workingDir, err := os.Getwd() + if err != nil { + return + } + defer func() { + os.Chdir(workingDir) + }() + topDir, err := GetTopDir() + os.Chdir(topDir) + + 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 { + if _, err = os.Stat(path); err == nil { defaultMapPaths = append(defaultMapPaths, path) } } - prodMaps := os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS") - if prodMaps != "" { + + var prodMaps string + if queryMaps { + getBuildVar := exec.Command("build/soong/soong_ui.bash", "--dumpvar-mode", "PRODUCT_RELEASE_CONFIG_MAPS") + var stdout strings.Builder + getBuildVar.Stdin = strings.NewReader("") + getBuildVar.Stdout = &stdout + err = getBuildVar.Run() + if err != nil { + return + } + prodMaps = stdout.String() + } else { + prodMaps = os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS") + } + prodMaps = strings.TrimSpace(prodMaps) + if len(prodMaps) > 0 { defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...) } - return defaultMapPaths + return } diff --git a/cmd/release_config/release_config_proto/build_flags_out.pb.go b/cmd/release_config/release_config_proto/build_flags_out.pb.go index 0372d633b..483cffac1 100644 --- a/cmd/release_config/release_config_proto/build_flags_out.pb.go +++ b/cmd/release_config/release_config_proto/build_flags_out.pb.go @@ -11,7 +11,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: build_flags_out.proto @@ -153,6 +153,54 @@ func (x *FlagArtifact) GetTraces() []*Tracepoint { return nil } +type FlagArtifacts struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The artifacts + FlagArtifacts []*FlagArtifact `protobuf:"bytes,1,rep,name=flag_artifacts,json=flagArtifacts" json:"flag_artifacts,omitempty"` +} + +func (x *FlagArtifacts) Reset() { + *x = FlagArtifacts{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_out_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagArtifacts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagArtifacts) ProtoMessage() {} + +func (x *FlagArtifacts) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_out_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagArtifacts.ProtoReflect.Descriptor instead. +func (*FlagArtifacts) Descriptor() ([]byte, []int) { + return file_build_flags_out_proto_rawDescGZIP(), []int{2} +} + +func (x *FlagArtifacts) GetFlagArtifacts() []*FlagArtifact { + if x != nil { + return x.FlagArtifacts + } + return nil +} + type ReleaseConfigArtifact struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -179,7 +227,7 @@ type ReleaseConfigArtifact struct { func (x *ReleaseConfigArtifact) Reset() { *x = ReleaseConfigArtifact{} if protoimpl.UnsafeEnabled { - mi := &file_build_flags_out_proto_msgTypes[2] + mi := &file_build_flags_out_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -192,7 +240,7 @@ func (x *ReleaseConfigArtifact) String() string { func (*ReleaseConfigArtifact) ProtoMessage() {} func (x *ReleaseConfigArtifact) ProtoReflect() protoreflect.Message { - mi := &file_build_flags_out_proto_msgTypes[2] + mi := &file_build_flags_out_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -205,7 +253,7 @@ func (x *ReleaseConfigArtifact) ProtoReflect() protoreflect.Message { // Deprecated: Use ReleaseConfigArtifact.ProtoReflect.Descriptor instead. func (*ReleaseConfigArtifact) Descriptor() ([]byte, []int) { - return file_build_flags_out_proto_rawDescGZIP(), []int{2} + return file_build_flags_out_proto_rawDescGZIP(), []int{3} } func (x *ReleaseConfigArtifact) GetName() string { @@ -266,7 +314,7 @@ type ReleaseConfigsArtifact struct { func (x *ReleaseConfigsArtifact) Reset() { *x = ReleaseConfigsArtifact{} if protoimpl.UnsafeEnabled { - mi := &file_build_flags_out_proto_msgTypes[3] + mi := &file_build_flags_out_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -279,7 +327,7 @@ func (x *ReleaseConfigsArtifact) String() string { func (*ReleaseConfigsArtifact) ProtoMessage() {} func (x *ReleaseConfigsArtifact) ProtoReflect() protoreflect.Message { - mi := &file_build_flags_out_proto_msgTypes[3] + mi := &file_build_flags_out_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -292,7 +340,7 @@ func (x *ReleaseConfigsArtifact) ProtoReflect() protoreflect.Message { // Deprecated: Use ReleaseConfigsArtifact.ProtoReflect.Descriptor instead. func (*ReleaseConfigsArtifact) Descriptor() ([]byte, []int) { - return file_build_flags_out_proto_rawDescGZIP(), []int{3} + return file_build_flags_out_proto_rawDescGZIP(), []int{4} } func (x *ReleaseConfigsArtifact) GetReleaseConfig() *ReleaseConfigArtifact { @@ -344,58 +392,64 @@ var file_build_flags_out_proto_rawDesc = []byte{ 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 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, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x22, 0x8e, 0x02, 0x0a, 0x17, 0x72, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x74, 0x68, - 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, - 0x6f, 0x74, 0x68, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x0e, 0x66, 0x6c, - 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x18, 0x03, 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, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, - 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 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, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, - 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, - 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x22, 0xe8, 0x03, 0x0a, 0x18, 0x72, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, - 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x5c, 0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x35, 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, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x69, 0x0a, 0x15, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x72, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 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, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x13, 0x6f, 0x74, 0x68, - 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, - 0x12, 0x87, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x50, 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, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x1a, 0x79, 0x0a, 0x19, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, - 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x46, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, + 0x74, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x22, 0x64, 0x0a, 0x0e, 0x66, 0x6c, 0x61, + 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x52, 0x0a, 0x0e, 0x66, + 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 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, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x52, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, + 0x8e, 0x02, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, + 0x12, 0x52, 0x0a, 0x0e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x73, 0x18, 0x03, 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, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, + 0x61, 0x63, 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, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, + 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, + 0x22, 0xe8, 0x03, 0x0a, 0x18, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x5c, 0x0a, + 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 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, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x69, 0x0a, 0x15, 0x6f, + 0x74, 0x68, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 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, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x52, 0x13, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x87, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x5f, 0x6d, + 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x50, 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, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 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, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, + 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x72, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, + 0x1a, 0x79, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x46, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 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, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 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, } var ( @@ -410,32 +464,34 @@ func file_build_flags_out_proto_rawDescGZIP() []byte { return file_build_flags_out_proto_rawDescData } -var file_build_flags_out_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_build_flags_out_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_build_flags_out_proto_goTypes = []interface{}{ (*Tracepoint)(nil), // 0: android.release_config_proto.tracepoint (*FlagArtifact)(nil), // 1: android.release_config_proto.flag_artifact - (*ReleaseConfigArtifact)(nil), // 2: android.release_config_proto.release_config_artifact - (*ReleaseConfigsArtifact)(nil), // 3: android.release_config_proto.release_configs_artifact - nil, // 4: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry - (*Value)(nil), // 5: android.release_config_proto.value - (*FlagDeclaration)(nil), // 6: android.release_config_proto.flag_declaration - (*ReleaseConfigMap)(nil), // 7: android.release_config_proto.release_config_map + (*FlagArtifacts)(nil), // 2: android.release_config_proto.flag_artifacts + (*ReleaseConfigArtifact)(nil), // 3: android.release_config_proto.release_config_artifact + (*ReleaseConfigsArtifact)(nil), // 4: android.release_config_proto.release_configs_artifact + nil, // 5: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry + (*Value)(nil), // 6: android.release_config_proto.value + (*FlagDeclaration)(nil), // 7: android.release_config_proto.flag_declaration + (*ReleaseConfigMap)(nil), // 8: android.release_config_proto.release_config_map } var file_build_flags_out_proto_depIdxs = []int32{ - 5, // 0: android.release_config_proto.tracepoint.value:type_name -> android.release_config_proto.value - 6, // 1: android.release_config_proto.flag_artifact.flag_declaration:type_name -> android.release_config_proto.flag_declaration - 5, // 2: android.release_config_proto.flag_artifact.value:type_name -> android.release_config_proto.value - 0, // 3: android.release_config_proto.flag_artifact.traces:type_name -> android.release_config_proto.tracepoint - 1, // 4: android.release_config_proto.release_config_artifact.flag_artifacts:type_name -> android.release_config_proto.flag_artifact - 2, // 5: android.release_config_proto.release_configs_artifact.release_config:type_name -> android.release_config_proto.release_config_artifact - 2, // 6: android.release_config_proto.release_configs_artifact.other_release_configs:type_name -> android.release_config_proto.release_config_artifact - 4, // 7: android.release_config_proto.release_configs_artifact.release_config_maps_map:type_name -> android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry - 7, // 8: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry.value:type_name -> android.release_config_proto.release_config_map - 9, // [9:9] is the sub-list for method output_type - 9, // [9:9] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 6, // 0: android.release_config_proto.tracepoint.value:type_name -> android.release_config_proto.value + 7, // 1: android.release_config_proto.flag_artifact.flag_declaration:type_name -> android.release_config_proto.flag_declaration + 6, // 2: android.release_config_proto.flag_artifact.value:type_name -> android.release_config_proto.value + 0, // 3: android.release_config_proto.flag_artifact.traces:type_name -> android.release_config_proto.tracepoint + 1, // 4: android.release_config_proto.flag_artifacts.flag_artifacts:type_name -> android.release_config_proto.flag_artifact + 1, // 5: android.release_config_proto.release_config_artifact.flag_artifacts:type_name -> android.release_config_proto.flag_artifact + 3, // 6: android.release_config_proto.release_configs_artifact.release_config:type_name -> android.release_config_proto.release_config_artifact + 3, // 7: android.release_config_proto.release_configs_artifact.other_release_configs:type_name -> android.release_config_proto.release_config_artifact + 5, // 8: android.release_config_proto.release_configs_artifact.release_config_maps_map:type_name -> android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry + 8, // 9: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry.value:type_name -> android.release_config_proto.release_config_map + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file_build_flags_out_proto_init() } @@ -470,7 +526,7 @@ func file_build_flags_out_proto_init() { } } file_build_flags_out_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReleaseConfigArtifact); i { + switch v := v.(*FlagArtifacts); i { case 0: return &v.state case 1: @@ -482,6 +538,18 @@ func file_build_flags_out_proto_init() { } } file_build_flags_out_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReleaseConfigArtifact); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_out_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReleaseConfigsArtifact); i { case 0: return &v.state @@ -500,7 +568,7 @@ func file_build_flags_out_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_build_flags_out_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/cmd/release_config/release_config_proto/build_flags_out.proto b/cmd/release_config/release_config_proto/build_flags_out.proto index 05e770f3e..6f34d6f67 100644 --- a/cmd/release_config/release_config_proto/build_flags_out.proto +++ b/cmd/release_config/release_config_proto/build_flags_out.proto @@ -52,6 +52,11 @@ message flag_artifact { repeated tracepoint traces = 8; } +message flag_artifacts { + // The artifacts + repeated flag_artifact flag_artifacts = 1; +} + message release_config_artifact { // The name of the release config. // See # name for format detail 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 d0c924dae..dded97566 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 @@ -11,7 +11,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: build_flags_src.proto @@ -98,76 +98,6 @@ func (Workflow) EnumDescriptor() ([]byte, []int) { return file_build_flags_src_proto_rawDescGZIP(), []int{0} } -type Container int32 - -const ( - Container_UNSPECIFIED_container Container = 0 - // All containers - Container_ALL Container = 1 - // Specific containers - Container_PRODUCT Container = 2 - Container_SYSTEM Container = 3 - Container_SYSTEM_EXT Container = 4 - Container_VENDOR Container = 5 -) - -// Enum value maps for Container. -var ( - Container_name = map[int32]string{ - 0: "UNSPECIFIED_container", - 1: "ALL", - 2: "PRODUCT", - 3: "SYSTEM", - 4: "SYSTEM_EXT", - 5: "VENDOR", - } - Container_value = map[string]int32{ - "UNSPECIFIED_container": 0, - "ALL": 1, - "PRODUCT": 2, - "SYSTEM": 3, - "SYSTEM_EXT": 4, - "VENDOR": 5, - } -) - -func (x Container) Enum() *Container { - p := new(Container) - *p = x - return p -} - -func (x Container) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (Container) Descriptor() protoreflect.EnumDescriptor { - return file_build_flags_src_proto_enumTypes[1].Descriptor() -} - -func (Container) Type() protoreflect.EnumType { - return &file_build_flags_src_proto_enumTypes[1] -} - -func (x Container) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Do not use. -func (x *Container) UnmarshalJSON(b []byte) error { - num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) - if err != nil { - return err - } - *x = Container(num) - return nil -} - -// Deprecated: Use Container.Descriptor instead. -func (Container) EnumDescriptor() ([]byte, []int) { - return file_build_flags_src_proto_rawDescGZIP(), []int{1} -} - type Value struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -298,7 +228,7 @@ type FlagDeclaration struct { Workflow *Workflow `protobuf:"varint,205,opt,name=workflow,enum=android.release_config_proto.Workflow" json:"workflow,omitempty"` // 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"` + Containers []string `protobuf:"bytes,206,rep,name=containers" json:"containers,omitempty"` } func (x *FlagDeclaration) Reset() { @@ -368,11 +298,11 @@ func (x *FlagDeclaration) GetWorkflow() Workflow { return Workflow_UNSPECIFIED_workflow } -func (x *FlagDeclaration) GetContainer() Container { - if x != nil && x.Container != nil { - return *x.Container +func (x *FlagDeclaration) GetContainers() []string { + if x != nil { + return x.Containers } - return Container_UNSPECIFIED_container + return nil } type FlagValue struct { @@ -385,6 +315,9 @@ type FlagValue struct { Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` // Value for the flag Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` + // If true, the flag is completely removed from the release config as if + // never declared. + Redacted *bool `protobuf:"varint,202,opt,name=redacted" json:"redacted,omitempty"` } func (x *FlagValue) Reset() { @@ -433,6 +366,13 @@ func (x *FlagValue) GetValue() *Value { return nil } +func (x *FlagValue) GetRedacted() bool { + if x != nil && x.Redacted != nil { + return *x.Redacted + } + return false +} + // This replaces $(call declare-release-config). type ReleaseConfig struct { state protoimpl.MessageState @@ -447,6 +387,8 @@ type ReleaseConfig struct { // List of names of the aconfig_value_set soong module(s) for this // contribution. AconfigValueSets []string `protobuf:"bytes,3,rep,name=aconfig_value_sets,json=aconfigValueSets" json:"aconfig_value_sets,omitempty"` + // Only aconfig flags are allowed in this release config. + AconfigFlagsOnly *bool `protobuf:"varint,4,opt,name=aconfig_flags_only,json=aconfigFlagsOnly" json:"aconfig_flags_only,omitempty"` } func (x *ReleaseConfig) Reset() { @@ -502,6 +444,13 @@ func (x *ReleaseConfig) GetAconfigValueSets() []string { return nil } +func (x *ReleaseConfig) GetAconfigFlagsOnly() bool { + if x != nil && x.AconfigFlagsOnly != nil { + return *x.AconfigFlagsOnly + } + return false +} + // Any aliases. These are used for continuous integration builder config. type ReleaseAlias struct { state protoimpl.MessageState @@ -571,7 +520,7 @@ type ReleaseConfigMap struct { // Description of this map and its intended use. Description *string `protobuf:"bytes,2,opt,name=description" json:"description,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"` + DefaultContainers []string `protobuf:"bytes,3,rep,name=default_containers,json=defaultContainers" json:"default_containers,omitempty"` } func (x *ReleaseConfigMap) Reset() { @@ -620,11 +569,11 @@ func (x *ReleaseConfigMap) GetDescription() string { return "" } -func (x *ReleaseConfigMap) GetDefaultContainer() Container { - if x != nil && x.DefaultContainer != nil { - return *x.DefaultContainer +func (x *ReleaseConfigMap) GetDefaultContainers() []string { + if x != nil { + return x.DefaultContainers } - return Container_UNSPECIFIED_container + return nil } var File_build_flags_src_proto protoreflect.FileDescriptor @@ -643,7 +592,7 @@ 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, 0xbd, 0x02, + 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0x96, 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, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, @@ -658,57 +607,50 @@ var file_build_flags_src_proto_rawDesc = []byte{ 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, 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, 0xd3, 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, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 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, 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, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1f, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0xce, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x06, + 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x79, 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, 0x12, 0x1b, 0x0a, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, + 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, + 0x64, 0x22, 0x9c, 0x01, 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, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x6c, + 0x61, 0x67, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, + 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x4f, 0x6e, 0x6c, 0x79, + 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, 0xac, 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, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, + 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 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, 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, } var ( @@ -723,30 +665,27 @@ func file_build_flags_src_proto_rawDescGZIP() []byte { return file_build_flags_src_proto_rawDescData } -var file_build_flags_src_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_build_flags_src_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_build_flags_src_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_build_flags_src_proto_goTypes = []interface{}{ (Workflow)(0), // 0: android.release_config_proto.workflow - (Container)(0), // 1: android.release_config_proto.container - (*Value)(nil), // 2: android.release_config_proto.value - (*FlagDeclaration)(nil), // 3: android.release_config_proto.flag_declaration - (*FlagValue)(nil), // 4: android.release_config_proto.flag_value - (*ReleaseConfig)(nil), // 5: android.release_config_proto.release_config - (*ReleaseAlias)(nil), // 6: android.release_config_proto.release_alias - (*ReleaseConfigMap)(nil), // 7: android.release_config_proto.release_config_map + (*Value)(nil), // 1: android.release_config_proto.value + (*FlagDeclaration)(nil), // 2: android.release_config_proto.flag_declaration + (*FlagValue)(nil), // 3: android.release_config_proto.flag_value + (*ReleaseConfig)(nil), // 4: android.release_config_proto.release_config + (*ReleaseAlias)(nil), // 5: android.release_config_proto.release_alias + (*ReleaseConfigMap)(nil), // 6: android.release_config_proto.release_config_map } var file_build_flags_src_proto_depIdxs = []int32{ - 2, // 0: android.release_config_proto.flag_declaration.value:type_name -> android.release_config_proto.value + 1, // 0: android.release_config_proto.flag_declaration.value:type_name -> android.release_config_proto.value 0, // 1: android.release_config_proto.flag_declaration.workflow:type_name -> android.release_config_proto.workflow - 1, // 2: android.release_config_proto.flag_declaration.container:type_name -> android.release_config_proto.container - 2, // 3: android.release_config_proto.flag_value.value:type_name -> android.release_config_proto.value - 6, // 4: android.release_config_proto.release_config_map.aliases:type_name -> android.release_config_proto.release_alias - 1, // 5: android.release_config_proto.release_config_map.default_container:type_name -> android.release_config_proto.container - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 1, // 2: android.release_config_proto.flag_value.value:type_name -> android.release_config_proto.value + 5, // 3: android.release_config_proto.release_config_map.aliases:type_name -> android.release_config_proto.release_alias + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_build_flags_src_proto_init() } @@ -839,7 +778,7 @@ func file_build_flags_src_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_build_flags_src_proto_rawDesc, - NumEnums: 2, + NumEnums: 1, NumMessages: 6, NumExtensions: 0, NumServices: 0, 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 c077f5cd8..0ef1a5ffa 100644 --- a/cmd/release_config/release_config_proto/build_flags_src.proto +++ b/cmd/release_config/release_config_proto/build_flags_src.proto @@ -53,19 +53,6 @@ enum workflow { MANUAL = 3; } -enum container { - UNSPECIFIED_container = 0; - - // All containers - ALL = 1; - - // Specific containers - PRODUCT = 2; - SYSTEM = 3; - SYSTEM_EXT = 4; - VENDOR = 5; -} - message value { oneof val { bool unspecified_value = 200; @@ -100,7 +87,7 @@ message flag_declaration { // The container for this flag. This overrides any default container given // in the release_config_map message. - optional container container = 206; + repeated string containers = 206; // The package associated with this flag. // (when Gantry is ready for it) optional string package = 207; @@ -114,6 +101,10 @@ message flag_value { // Value for the flag optional value value = 201; + + // If true, the flag is completely removed from the release config as if + // never declared. + optional bool redacted = 202; } // This replaces $(call declare-release-config). @@ -128,6 +119,9 @@ message release_config { // List of names of the aconfig_value_set soong module(s) for this // contribution. repeated string aconfig_value_sets = 3; + + // Only aconfig flags are allowed in this release config. + optional bool aconfig_flags_only = 4; } // Any aliases. These are used for continuous integration builder config. @@ -148,7 +142,7 @@ message release_config_map { optional string description = 2; // The default container for flags declared here. - optional container default_container = 3; + repeated string default_containers = 3; // If needed, we can add these fields instead of hardcoding the location. // Flag declarations: `flag_declarations/*.textproto` diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index d1c1d853e..025ba27aa 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -55,6 +55,9 @@ func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory) ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory) ctx.RegisterModuleType("prebuilt_usr_hyphendata", PrebuiltUserHyphenDataFactory) + ctx.RegisterModuleType("prebuilt_usr_keylayout", PrebuiltUserKeyLayoutFactory) + ctx.RegisterModuleType("prebuilt_usr_keychars", PrebuiltUserKeyCharsFactory) + ctx.RegisterModuleType("prebuilt_usr_idc", PrebuiltUserIdcFactory) ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory) ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory) ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory) @@ -609,6 +612,39 @@ func PrebuiltUserHyphenDataFactory() android.Module { return module } +// prebuilt_usr_keylayout is for a prebuilt artifact that is installed in +// <partition>/usr/keylayout/<sub_dir> directory. +func PrebuiltUserKeyLayoutFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "usr/keylayout") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_usr_keychars is for a prebuilt artifact that is installed in +// <partition>/usr/keychars/<sub_dir> directory. +func PrebuiltUserKeyCharsFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "usr/keychars") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_usr_idc is for a prebuilt artifact that is installed in +// <partition>/usr/idc/<sub_dir> directory. +func PrebuiltUserIdcFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "usr/idc") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) + return module +} + // prebuilt_font installs a font in <partition>/fonts directory. func PrebuiltFontFactory() android.Module { module := &PrebuiltEtc{} diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index dd9958caf..3ee234069 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -287,6 +287,48 @@ func TestPrebuiltPrebuiltUserHyphenDataInstallDirPath(t *testing.T) { android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) } +func TestPrebuiltPrebuiltUserKeyLayoutInstallDirPath(t *testing.T) { + result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` + prebuilt_usr_keylayout { + name: "foo.conf", + src: "foo.conf", + sub_dir: "bar", + } + `) + + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) + expected := "out/soong/target/product/test_device/system/usr/keylayout/bar" + android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) +} + +func TestPrebuiltPrebuiltUserKeyCharsInstallDirPath(t *testing.T) { + result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` + prebuilt_usr_keychars { + name: "foo.conf", + src: "foo.conf", + sub_dir: "bar", + } + `) + + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) + expected := "out/soong/target/product/test_device/system/usr/keychars/bar" + android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) +} + +func TestPrebuiltPrebuiltUserIdcInstallDirPath(t *testing.T) { + result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` + prebuilt_usr_idc { + name: "foo.conf", + src: "foo.conf", + sub_dir: "bar", + } + `) + + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) + expected := "out/soong/target/product/test_device/system/usr/idc/bar" + android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) +} + func TestPrebuiltFontInstallDirPath(t *testing.T) { result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` prebuilt_font { diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index cadf9c246..b342ae930 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -127,6 +127,10 @@ type filesystemProperties struct { // the make version. Include_make_built_files string + // When set, builds etc/event-log-tags file by merging logtags from all dependencies. + // Default is false + Build_logtags *bool + Fsverity fsverityProperties } @@ -137,6 +141,7 @@ type filesystemProperties struct { // partitions like system.img. For example, cc_library modules are placed under ./lib[64] directory. func filesystemFactory() android.Module { module := &filesystem{} + module.filterPackagingSpec = module.filterInstallablePackagingSpec initFilesystemModule(module) return module } @@ -189,6 +194,12 @@ func (f *filesystem) partitionName() string { return proptools.StringDefault(f.properties.Partition_name, f.Name()) } +func (f *filesystem) filterInstallablePackagingSpec(ps android.PackagingSpec) bool { + // Filesystem module respects the installation semantic. A PackagingSpec from a module with + // IsSkipInstall() is skipped. + return !ps.SkipInstall() +} + var pctx = android.NewPackageContext("android/soong/filesystem") func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -288,6 +299,7 @@ func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) androi f.buildNonDepsFiles(ctx, builder, rootDir) f.addMakeBuiltFiles(ctx, builder, rootDir) f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir) + f.buildEventLogtagsFile(ctx, builder, rebasedDir) // run host_init_verifier // Ideally we should have a concept of pluggable linters that verify the generated image. @@ -428,6 +440,7 @@ func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) f.buildNonDepsFiles(ctx, builder, rootDir) f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir) + f.buildEventLogtagsFile(ctx, builder, rebasedDir) output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath cmd := builder.Command(). @@ -485,6 +498,37 @@ func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *andro Text(android.PathForArbitraryOutput(ctx, stagingDir).String()) } +func (f *filesystem) buildEventLogtagsFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) { + if !proptools.Bool(f.properties.Build_logtags) { + return + } + + logtagsFilePaths := make(map[string]bool) + ctx.WalkDeps(func(child, parent android.Module) bool { + if logtagsInfo, ok := android.OtherModuleProvider(ctx, child, android.LogtagsProviderKey); ok { + for _, path := range logtagsInfo.Logtags { + logtagsFilePaths[path.String()] = true + } + } + return true + }) + + if len(logtagsFilePaths) == 0 { + return + } + + etcPath := rebasedDir.Join(ctx, "etc") + eventLogtagsPath := etcPath.Join(ctx, "event-log-tags") + builder.Command().Text("mkdir").Flag("-p").Text(etcPath.String()) + cmd := builder.Command().BuiltTool("merge-event-log-tags"). + FlagWithArg("-o ", eventLogtagsPath.String()). + FlagWithInput("-m ", android.MergedLogtagsPath(ctx)) + + for _, path := range android.SortedKeys(logtagsFilePaths) { + cmd.Text(path) + } +} + type partition interface { PartitionType() string } diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index 3a5071d34..acd481352 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -299,43 +299,6 @@ func TestAvbAddHashFooter(t *testing.T) { cmd, "--include_descriptors_from_image ") } -func TestFileSystemShouldInstallCoreVariantIfTargetBuildAppsIsSet(t *testing.T) { - context := android.GroupFixturePreparers( - fixture, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.Unbundled_build_apps = []string{"bar"} - }), - ) - result := context.RunTestWithBp(t, ` - android_system_image { - name: "myfilesystem", - deps: [ - "libfoo", - ], - linker_config_src: "linker.config.json", - } - - cc_library { - name: "libfoo", - shared_libs: [ - "libbar", - ], - stl: "none", - } - - cc_library { - name: "libbar", - sdk_version: "9", - stl: "none", - } - `) - - inputs := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img").Implicits - android.AssertStringListContains(t, "filesystem should have libbar even for unbundled build", - inputs.Strings(), - "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so") -} - func TestFileSystemWithCoverageVariants(t *testing.T) { context := android.GroupFixturePreparers( fixture, @@ -479,3 +442,26 @@ func TestInconsistentPartitionTypesInDefaults(t *testing.T) { } `) } + +func TestPreventDuplicatedEntries(t *testing.T) { + fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern( + "packaging conflict at")). + RunTestWithBp(t, ` + android_filesystem { + name: "fs", + deps: [ + "foo", + "foo_dup", + ], + } + + cc_binary { + name: "foo", + } + + cc_binary { + name: "foo_dup", + stem: "foo", + } + `) +} diff --git a/filesystem/system_image.go b/filesystem/system_image.go index 5028a493e..15cacfb4f 100644 --- a/filesystem/system_image.go +++ b/filesystem/system_image.go @@ -98,5 +98,5 @@ func (s *systemImage) buildLinkerConfigFile(ctx android.ModuleContext, root andr // Note that "apex" module installs its contents to "apex"(fake partition) as well // for symbol lookup by imitating "activated" paths. func (s *systemImage) filterPackagingSpec(ps android.PackagingSpec) bool { - return ps.Partition() == "system" + return s.filesystem.filterInstallablePackagingSpec(ps) && ps.Partition() == "system" } diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go index 47fd8f439..306d65e29 100644 --- a/fuzz/fuzz_common.go +++ b/fuzz/fuzz_common.go @@ -449,10 +449,10 @@ func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrame } } -func IsValid(fuzzModule FuzzModule) bool { +func IsValid(ctx android.ConfigAndErrorContext, fuzzModule FuzzModule) bool { // Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of // fuzz targets we're going to package anyway. - if !fuzzModule.Enabled() || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() { + if !fuzzModule.Enabled(ctx) || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() { return false } diff --git a/genrule/genrule.go b/genrule/genrule.go index 43f4fe5ee..67b96ca92 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -299,7 +299,7 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { case android.HostToolProvider: // A HostToolProvider provides the path to a tool, which will be copied // into the sandbox. - if !t.(android.Module).Enabled() { + if !t.(android.Module).Enabled(ctx) { if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{tool}) } else { @@ -714,13 +714,13 @@ func NewGenSrcs() *Module { rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil)) for _, in := range shard { - outFile := android.GenPathWithExt(ctx, finalSubDir, in, String(properties.Output_extension)) + outFile := android.GenPathWithExtAndTrimExt(ctx, finalSubDir, in, String(properties.Output_extension), String(properties.Trim_extension)) // If sharding is enabled, then outFile is the path to the output file in // the shard directory, and copyTo is the path to the output file in the // final directory. if len(shards) > 1 { - shardFile := android.GenPathWithExt(ctx, genSubDir, in, String(properties.Output_extension)) + shardFile := android.GenPathWithExtAndTrimExt(ctx, genSubDir, in, String(properties.Output_extension), String(properties.Trim_extension)) copyTo = append(copyTo, outFile) outFile = shardFile } @@ -786,6 +786,9 @@ type genSrcsProperties struct { // Additional files needed for build that are not tooling related. Data []string `android:"path"` + + // Trim the matched extension for each input file, and it should start with ".". + Trim_extension *string } const defaultShardSize = 50 diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go index 2dc6a7954..1df887b3e 100644 --- a/genrule/genrule_test.go +++ b/genrule/genrule_test.go @@ -894,6 +894,155 @@ func TestGenSrcsWithSrcsFromExternalPackage(t *testing.T) { ) } +func TestGenSrcsWithTrimExtAndOutpuExtension(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForGenRuleTest, + android.FixtureMergeMockFs(android.MockFS{ + "external-protos/path/Android.bp": []byte(` + filegroup { + name: "external-protos", + srcs: [ + "baz.a.b.c.proto/baz.a.b.c.proto", + "bar.a.b.c.proto", + "qux.ext.a.b.c.proto", + ], + } + `), + "package-dir/Android.bp": []byte(` + gensrcs { + name: "module-name", + cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)", + srcs: [ + "src/foo.a.b.c.proto", + ":external-protos", + ], + + trim_extension: ".a.b.c.proto", + output_extension: "proto.h", + } + `), + }), + ).RunTest(t) + + exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs" + gen := result.Module("module-name", "").(*Module) + + android.AssertPathsRelativeToTopEquals( + t, + "include path", + []string{exportedIncludeDir}, + gen.exportedIncludeDirs, + ) + android.AssertPathsRelativeToTopEquals( + t, + "files", + []string{ + exportedIncludeDir + "/package-dir/src/foo.proto.h", + exportedIncludeDir + "/external-protos/path/baz.a.b.c.proto/baz.proto.h", + exportedIncludeDir + "/external-protos/path/bar.proto.h", + exportedIncludeDir + "/external-protos/path/qux.ext.proto.h", + }, + gen.outputFiles, + ) +} + +func TestGenSrcsWithTrimExtButNoOutpuExtension(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForGenRuleTest, + android.FixtureMergeMockFs(android.MockFS{ + "external-protos/path/Android.bp": []byte(` + filegroup { + name: "external-protos", + srcs: [ + "baz.a.b.c.proto/baz.a.b.c.proto", + "bar.a.b.c.proto", + "qux.ext.a.b.c.proto", + ], + } + `), + "package-dir/Android.bp": []byte(` + gensrcs { + name: "module-name", + cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)", + srcs: [ + "src/foo.a.b.c.proto", + ":external-protos", + ], + + trim_extension: ".a.b.c.proto", + } + `), + }), + ).RunTest(t) + + exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs" + gen := result.Module("module-name", "").(*Module) + + android.AssertPathsRelativeToTopEquals( + t, + "include path", + []string{exportedIncludeDir}, + gen.exportedIncludeDirs, + ) + android.AssertPathsRelativeToTopEquals( + t, + "files", + []string{ + exportedIncludeDir + "/package-dir/src/foo", + exportedIncludeDir + "/external-protos/path/baz.a.b.c.proto/baz", + exportedIncludeDir + "/external-protos/path/bar", + exportedIncludeDir + "/external-protos/path/qux.ext", + }, + gen.outputFiles, + ) +} + +func TestGenSrcsWithOutpuExtension(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForGenRuleTest, + android.FixtureMergeMockFs(android.MockFS{ + "external-protos/path/Android.bp": []byte(` + filegroup { + name: "external-protos", + srcs: ["baz/baz.a.b.c.proto", "bar.a.b.c.proto"], + } + `), + "package-dir/Android.bp": []byte(` + gensrcs { + name: "module-name", + cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)", + srcs: [ + "src/foo.a.b.c.proto", + ":external-protos", + ], + + output_extension: "proto.h", + } + `), + }), + ).RunTest(t) + + exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs" + gen := result.Module("module-name", "").(*Module) + + android.AssertPathsRelativeToTopEquals( + t, + "include path", + []string{exportedIncludeDir}, + gen.exportedIncludeDirs, + ) + android.AssertPathsRelativeToTopEquals( + t, + "files", + []string{ + exportedIncludeDir + "/package-dir/src/foo.a.b.c.proto.h", + exportedIncludeDir + "/external-protos/path/baz/baz.a.b.c.proto.h", + exportedIncludeDir + "/external-protos/path/bar.a.b.c.proto.h", + }, + gen.outputFiles, + ) +} + func TestPrebuiltTool(t *testing.T) { testcases := []struct { name string diff --git a/java/aar.go b/java/aar.go index f8955ce90..47c64bfe8 100644 --- a/java/aar.go +++ b/java/aar.go @@ -418,6 +418,9 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio if a.isLibrary { linkFlags = append(linkFlags, "--static-lib") } + if opts.forceNonFinalResourceIDs { + linkFlags = append(linkFlags, "--non-final-ids") + } linkFlags = append(linkFlags, "--no-static-lib-packages") if a.isLibrary && a.useResourceProcessorBusyBox(ctx) { @@ -968,6 +971,9 @@ type AARImportProperties struct { // will be passed transitively through android_libraries to an android_app. //TODO(b/241138093) evaluate whether we can have this flag default to true for Bazel conversion Extract_jni *bool + + // If set, overrides the manifest extracted from the AAR with the provided path. + Manifest *string `android:"path"` } type AARImport struct { @@ -990,7 +996,7 @@ type AARImport struct { exportPackage android.WritablePath transitiveAaptResourcePackagesFile android.Path extraAaptPackagesFile android.WritablePath - manifest android.WritablePath + manifest android.Path assetsPackage android.WritablePath rTxt android.WritablePath rJar android.WritablePath @@ -1166,7 +1172,15 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { jarName := ctx.ModuleName() + ".jar" extractedAARDir := android.PathForModuleOut(ctx, "aar") classpathFile := extractedAARDir.Join(ctx, jarName) - a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml") + + extractedManifest := extractedAARDir.Join(ctx, "AndroidManifest.xml") + providedManifest := android.OptionalPathForModuleSrc(ctx, a.properties.Manifest) + if providedManifest.Valid() { + a.manifest = providedManifest.Path() + } else { + a.manifest = extractedManifest + } + a.rTxt = extractedAARDir.Join(ctx, "R.txt") a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip") a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt") @@ -1187,7 +1201,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.Build(pctx, android.BuildParams{ Rule: unzipAAR, Input: a.aarPath, - Outputs: android.WritablePaths{classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, a.rTxt}, + Outputs: android.WritablePaths{classpathFile, a.proguardFlags, extractedManifest, a.assetsPackage, a.rTxt}, Description: "unzip AAR", Args: map[string]string{ "outDir": extractedAARDir.String(), diff --git a/java/aar_test.go b/java/aar_test.go index d6dbe3c25..18efd2067 100644 --- a/java/aar_test.go +++ b/java/aar_test.go @@ -15,8 +15,9 @@ package java import ( - "android/soong/android" "testing" + + "android/soong/android" ) func TestAarImportProducesJniPackages(t *testing.T) { @@ -98,6 +99,7 @@ func TestLibraryFlagsPackages(t *testing.T) { aconfig_declarations { name: "bar", package: "com.example.package.bar", + container: "com.android.foo", srcs: [ "bar.aconfig", ], @@ -105,6 +107,7 @@ func TestLibraryFlagsPackages(t *testing.T) { aconfig_declarations { name: "baz", package: "com.example.package.baz", + container: "com.android.foo", srcs: [ "baz.aconfig", ], diff --git a/java/androidmk.go b/java/androidmk.go index a52d43965..9cd0bafea 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -92,11 +92,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { if len(library.logtagsSrcs) > 0 { - var logtags []string - for _, l := range library.logtagsSrcs { - logtags = append(logtags, l.Rel()) - } - entries.AddStrings("LOCAL_LOGTAGS_FILES", logtags...) + entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", library.logtagsSrcs.Strings()...) } if library.installFile == nil { @@ -457,6 +453,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if app.Name() != "framework-res" { android.SetAconfigFileMkEntries(&app.ModuleBase, entries, app.mergedAconfigFiles) } + + entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", app.logtagsSrcs.Strings()...) }, }, ExtraFooters: []android.AndroidMkExtraFootersFunc{ diff --git a/java/app_import_test.go b/java/app_import_test.go index 5de50e794..496fc1308 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -509,7 +509,7 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { variant := ctx.ModuleForTests("foo", "android_common") if test.expected == "" { - if variant.Module().Enabled() { + if variant.Module().Enabled(android.PanickingConfigAndErrorContext(ctx)) { t.Error("module should have been disabled, but wasn't") } rule := variant.MaybeRule("genProvenanceMetaData") @@ -586,7 +586,7 @@ func TestAndroidAppImport_SoongConfigVariables(t *testing.T) { variant := ctx.ModuleForTests("foo", "android_common") if test.expected == "" { - if variant.Module().Enabled() { + if variant.Module().Enabled(android.PanickingConfigAndErrorContext(ctx)) { t.Error("module should have been disabled, but wasn't") } rule := variant.MaybeRule("genProvenanceMetaData") @@ -629,7 +629,7 @@ func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { if !a.prebuilt.UsePrebuilt() { t.Errorf("prebuilt foo module is not active") } - if !a.Enabled() { + if !a.Enabled(android.PanickingConfigAndErrorContext(ctx)) { t.Errorf("prebuilt foo module is disabled") } } diff --git a/java/app_test.go b/java/app_test.go index eab40e7da..a7c48a1ed 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -4382,6 +4382,7 @@ func TestAppFlagsPackages(t *testing.T) { aconfig_declarations { name: "bar", package: "com.example.package.bar", + container: "com.android.foo", srcs: [ "bar.aconfig", ], @@ -4389,6 +4390,7 @@ func TestAppFlagsPackages(t *testing.T) { aconfig_declarations { name: "baz", package: "com.example.package.baz", + container: "com.android.foo", srcs: [ "baz.aconfig", ], diff --git a/java/boot_jars.go b/java/boot_jars.go index 5d40ec389..6223dede8 100644 --- a/java/boot_jars.go +++ b/java/boot_jars.go @@ -21,8 +21,8 @@ import ( // isActiveModule returns true if the given module should be considered for boot // jars, i.e. if it's enabled and the preferred one in case of source and // prebuilt alternatives. -func isActiveModule(module android.Module) bool { - if !module.Enabled() { +func isActiveModule(ctx android.ConfigAndErrorContext, module android.Module) bool { + if !module.Enabled(ctx) { return false } return android.IsModulePreferred(module) diff --git a/java/bootclasspath.go b/java/bootclasspath.go index c7dc3afae..77ddf5c05 100644 --- a/java/bootclasspath.go +++ b/java/bootclasspath.go @@ -127,7 +127,10 @@ func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variat // added by addDependencyOntoApexModulePair. func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tag blueprint.DependencyTag) []android.Module { var modules []android.Module - ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) { + isActiveModulePred := func(module android.Module) bool { + return isActiveModule(ctx, module) + } + ctx.VisitDirectDepsIf(isActiveModulePred, func(module android.Module) { t := ctx.OtherModuleDependencyTag(module) if t == tag { modules = append(modules, module) diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index cc3da7656..82a34ca9d 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -474,7 +474,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // Only perform a consistency check if this module is the active module. That will prevent an // unused prebuilt that was created without instrumentation from breaking an instrumentation // build. - if isActiveModule(ctx.Module()) { + if isActiveModule(ctx, ctx.Module()) { b.bootclasspathFragmentPropertyCheck(ctx) } @@ -519,7 +519,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // empty string if this module should not provide a boot image profile. func (b *BootclasspathFragmentModule) getProfileProviderApex(ctx android.BaseModuleContext) string { // Only use the profile from the module that is preferred. - if !isActiveModule(ctx.Module()) { + if !isActiveModule(ctx, ctx.Module()) { return "" } @@ -590,7 +590,7 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) // So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS. // TODO(b/202896428): Add better way to handle this. _, unknown = android.RemoveFromList("android.car-module", unknown) - if isActiveModule(ctx.Module()) && len(unknown) > 0 { + if isActiveModule(ctx, ctx.Module()) && len(unknown) > 0 { ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown) } } diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go index 0ebab4d8c..07bc5c163 100644 --- a/java/classpath_fragment.go +++ b/java/classpath_fragment.go @@ -151,10 +151,14 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars return jars } +func (c *ClasspathFragmentBase) outputFilename() string { + return strings.ToLower(c.classpathType.String()) + ".pb" +} + func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, configuredJars android.ConfiguredJarList, jars []classpathJar) { generateProto := proptools.BoolDefault(c.properties.Generate_classpaths_proto, true) if generateProto { - outputFilename := strings.ToLower(c.classpathType.String()) + ".pb" + outputFilename := c.outputFilename() c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths") @@ -181,6 +185,10 @@ func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.M android.SetProvider(ctx, ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo) } +func (c *ClasspathFragmentBase) installClasspathProto(ctx android.ModuleContext) android.InstallPath { + return ctx.InstallFile(c.installDirPath, c.outputFilename(), c.outputFilepath) +} + func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) { var content strings.Builder diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index f7e3cb93a..7229ca02d 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -562,7 +562,7 @@ func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android. return ctx.Config().Once(dexBootJarsFragmentsKey, func() interface{} { fragments := make(map[string]android.Module) ctx.WalkDeps(func(child, parent android.Module) bool { - if !isActiveModule(child) { + if !isActiveModule(ctx, child) { return false } tag := ctx.OtherModuleDependencyTag(child) @@ -1125,7 +1125,7 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p image.unstrippedInstalls = unstrippedInstalls // Only set the licenseMetadataFile from the active module. - if isActiveModule(ctx.Module()) { + if isActiveModule(ctx, ctx.Module()) { image.licenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile()) } diff --git a/java/droidstubs.go b/java/droidstubs.go index 02b81a4fe..730be14b0 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -532,8 +532,8 @@ func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.Ru cmd.Flag(config.MetalavaAnnotationsFlags) if params.migratingNullability { - previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api)) - cmd.FlagWithInput("--migrate-nullness ", previousApi) + previousApiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Previous_api)}) + cmd.FlagForEachInput("--migrate-nullness ", previousApiFiles) } if s := String(d.properties.Validate_nullability_from_list); s != "" { @@ -604,6 +604,11 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a } } +// AndroidPlusUpdatableJar is the name of some extra jars added into `module-lib` and +// `system-server` directories that contain all the APIs provided by the platform and updatable +// modules because the `android.jar` files do not. See b/337836752. +const AndroidPlusUpdatableJar = "android-plus-updatable.jar" + func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) { if len(d.properties.Api_levels_annotations_dirs) == 0 { ctx.PropertyErrorf("api_levels_annotations_dirs", @@ -614,25 +619,72 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") + // TODO: Avoid the duplication of API surfaces, reuse apiScope. + // Add all relevant --android-jar-pattern patterns for Metalava. + // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines + // an actual file present on disk (in the order the patterns were passed). For system APIs for + // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs + // for older releases. Similarly, module-lib falls back to system API. + var sdkDirs []string + apiLevelsSdkType := proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") + switch apiLevelsSdkType { + case "system-server": + sdkDirs = []string{"system-server", "module-lib", "system", "public"} + case "module-lib": + sdkDirs = []string{"module-lib", "system", "public"} + case "system": + sdkDirs = []string{"system", "public"} + case "public": + sdkDirs = []string{"public"} + default: + ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes) + return + } + + // Construct a pattern to match the appropriate extensions that should be included in the + // generated api-versions.xml file. + // + // Use the first item in the sdkDirs array as that is the sdk type for the target API levels + // being generated but has the advantage over `Api_levels_sdk_type` as it has been validated. + // The exception is for system-server which needs to include module-lib and system-server. That + // is because while system-server extends module-lib the system-server extension directory only + // contains service-* modules which provide system-server APIs it does not list the modules which + // only provide a module-lib, so they have to be included separately. + extensionSurfacesPattern := sdkDirs[0] + if apiLevelsSdkType == "system-server" { + // Take the first two items in sdkDirs, which are system-server and module-lib, and construct + // a pattern that will match either. + extensionSurfacesPattern = strings.Join(sdkDirs[0:2], "|") + } + extensionsPattern := fmt.Sprintf(`/extensions/[0-9]+/(%s)/.*\.jar`, extensionSurfacesPattern) + var dirs []string var extensions_dir string ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { if t, ok := m.(*ExportedDroiddocDir); ok { - extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`) + extRegex := regexp.MustCompile(t.dir.String() + extensionsPattern) // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps; // ideally this should be read from prebuiltApis.properties.Extensions_* for _, dep := range t.deps { + // Check to see if it matches an extension first. + depBase := dep.Base() if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil { if extensions_dir == "" { extensions_dir = t.dir.String() + "/extensions" } cmd.Implicit(dep) - } - if dep.Base() == filename { + } else if depBase == filename { + // Check to see if it matches a dessert release for an SDK, e.g. Android, Car, Wear, etc.. cmd.Implicit(dep) - } - if filename != "android.jar" && dep.Base() == "android.jar" { + } else if depBase == AndroidPlusUpdatableJar && d.properties.Extensions_info_file != nil { + // The output api-versions.xml has been requested to include information on SDK + // extensions. That means it also needs to include + // so + // The module-lib and system-server directories should use `android-plus-updatable.jar` + // instead of `android.jar`. See AndroidPlusUpdatableJar for more information. + cmd.Implicit(dep) + } else if filename != "android.jar" && depBase == "android.jar" { // Metalava implicitly searches these patterns: // prebuilts/tools/common/api-versions/android-%/android.jar // prebuilts/sdk/%/public/android.jar @@ -650,29 +702,25 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an } }) - // Add all relevant --android-jar-pattern patterns for Metalava. - // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines - // an actual file present on disk (in the order the patterns were passed). For system APIs for - // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs - // for older releases. Similarly, module-lib falls back to system API. - var sdkDirs []string - switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") { - case "system-server": - sdkDirs = []string{"system-server", "module-lib", "system", "public"} - case "module-lib": - sdkDirs = []string{"module-lib", "system", "public"} - case "system": - sdkDirs = []string{"system", "public"} - case "public": - sdkDirs = []string{"public"} - default: - ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes) - return - } - + // Generate the list of --android-jar-pattern options. The order matters so the first one which + // matches will be the one that is used for a specific api level.. for _, sdkDir := range sdkDirs { for _, dir := range dirs { - cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename)) + addPattern := func(jarFilename string) { + cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, jarFilename)) + } + + if sdkDir == "module-lib" || sdkDir == "system-server" { + // The module-lib and system-server android.jars do not include the updatable modules (as + // doing so in the source would introduce dependency cycles and the prebuilts have to + // match the sources). So, instead an additional `android-plus-updatable.jar` will be used + // that does include the updatable modules and this pattern will match that. This pattern + // is added in addition to the following pattern to decouple this change from the change + // to add the `android-plus-updatable.jar`. + addPattern(AndroidPlusUpdatableJar) + } + + addPattern(filename) } } @@ -692,11 +740,11 @@ func (d *Droidstubs) apiCompatibilityFlags(ctx android.ModuleContext, cmd *andro ctx.PropertyErrorf("out", "out property may not be combined with check_api") } - apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) - removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) + apiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Check_api.Last_released.Api_file)}) + removedApiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Check_api.Last_released.Removed_api_file)}) - cmd.FlagWithInput("--check-compatibility:api:released ", apiFile) - cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile) + cmd.FlagForEachInput("--check-compatibility:api:released ", apiFiles) + cmd.FlagForEachInput("--check-compatibility:removed:released ", removedApiFiles) baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file) if baselineFile.Valid() { @@ -708,8 +756,8 @@ func metalavaUseRbe(ctx android.ModuleContext) bool { return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") } -func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths, - srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand { +func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, + srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams) *android.RuleBuilderCommand { rule.Command().Text("rm -rf").Flag(homeDir.String()) rule.Command().Text("mkdir -p").Flag(homeDir.String()) @@ -739,14 +787,14 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")). Flag(config.JavacVmFlags). Flag(config.MetalavaAddOpens). - FlagWithArg("--java-source ", javaVersion.String()). - FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs). + FlagWithArg("--java-source ", params.javaVersion.String()). + FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, fmt.Sprintf("%s.metalava.rsp", params.stubsType.String())), srcs). FlagWithInput("@", srcJarList) // Metalava does not differentiate between bootclasspath and classpath and has not done so for // years, so it is unlikely to change any time soon. - combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...) - combinedPaths = append(combinedPaths, classpath.Paths()...) + combinedPaths := append(([]android.Path)(nil), params.deps.bootClasspath.Paths()...) + combinedPaths = append(combinedPaths, params.deps.classpath.Paths()...) if len(combinedPaths) > 0 { cmd.FlagWithInputList("--classpath ", combinedPaths, ":") } @@ -827,8 +875,7 @@ func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *andr srcJarList := zipSyncCmd(ctx, rule, params.srcJarDir, d.Javadoc.srcJars) homeDir := android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "home") - cmd := metalavaCmd(ctx, rule, params.stubConfig.javaVersion, d.Javadoc.srcFiles, srcJarList, - params.stubConfig.deps.bootClasspath, params.stubConfig.deps.classpath, homeDir) + cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig) cmd.Implicits(d.Javadoc.implicits) d.stubsFlags(ctx, cmd, params.stubsDir, params.stubConfig.stubsType, params.stubConfig.checkApi) @@ -950,12 +997,12 @@ func (d *Droidstubs) everythingOptionalCmd(ctx android.ModuleContext, cmd *andro // Add API lint options. if doApiLint { - newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since) - if newSince.Valid() { - cmd.FlagWithInput("--api-lint ", newSince.Path()) - } else { - cmd.Flag("--api-lint") + var newSince android.Paths + if d.properties.Check_api.Api_lint.New_since != nil { + newSince = android.PathsForModuleSrc(ctx, []string{proptools.String(d.properties.Check_api.Api_lint.New_since)}) } + cmd.Flag("--api-lint") + cmd.FlagForEachInput("--api-lint-previous-api ", newSince) d.apiLintReport = android.PathForModuleOut(ctx, Everything.String(), "api_lint_report.txt") cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint" @@ -1323,7 +1370,7 @@ func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) { // use a strict naming convention var ( droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{ - //public is commented out since the core libraries use public in their java_sdk_library names + // public is commented out since the core libraries use public in their java_sdk_library names "intracore": android.SdkIntraCore, "intra.core": android.SdkIntraCore, "system_server": android.SdkSystemServer, diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go index 8da695f08..6a14f3645 100644 --- a/java/droidstubs_test.go +++ b/java/droidstubs_test.go @@ -379,6 +379,7 @@ func TestAconfigDeclarations(t *testing.T) { aconfig_declarations { name: "bar", package: "com.example.package", + container: "com.android.foo", srcs: [ "bar.aconfig", ], @@ -434,6 +435,7 @@ func TestReleaseExportRuntimeApis(t *testing.T) { aconfig_declarations { name: "bar", package: "com.example.package", + container: "com.android.foo", srcs: [ "bar.aconfig", ], diff --git a/java/fuzz.go b/java/fuzz.go index fb31ce794..d37c55804 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -179,7 +179,7 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { javaFuzzModule.ApexModuleBase, } - if ok := fuzz.IsValid(fuzzModuleValidator); !ok { + if ok := fuzz.IsValid(ctx, fuzzModuleValidator); !ok { return } diff --git a/java/gen.go b/java/gen.go index 68a9b53fe..1b4f4c7dc 100644 --- a/java/gen.go +++ b/java/gen.go @@ -27,7 +27,6 @@ import ( func init() { pctx.SourcePathVariable("logtagsCmd", "build/make/tools/java-event-log-tags.py") - pctx.SourcePathVariable("mergeLogtagsCmd", "build/make/tools/merge-event-log-tags.py") pctx.SourcePathVariable("logtagsLib", "build/make/tools/event_log_tags.py") } @@ -37,12 +36,6 @@ var ( Command: "$logtagsCmd -o $out $in", CommandDeps: []string{"$logtagsCmd", "$logtagsLib"}, }) - - mergeLogtags = pctx.AndroidStaticRule("mergeLogtags", - blueprint.RuleParams{ - Command: "$mergeLogtagsCmd -o $out $in", - CommandDeps: []string{"$mergeLogtagsCmd", "$logtagsLib"}, - }) ) func genAidl(ctx android.ModuleContext, aidlFiles android.Paths, aidlGlobalFlags string, aidlIndividualFlags map[string]string, deps android.Paths) android.Paths { @@ -178,37 +171,9 @@ func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths, outSrcFiles = append(outSrcFiles, srcJarFiles...) } - return outSrcFiles -} - -func LogtagsSingleton() android.Singleton { - return &logtagsSingleton{} -} - -type logtagsProducer interface { - logtags() android.Paths -} - -func (j *Module) logtags() android.Paths { - return j.logtagsSrcs -} - -var _ logtagsProducer = (*Module)(nil) - -type logtagsSingleton struct{} - -func (l *logtagsSingleton) GenerateBuildActions(ctx android.SingletonContext) { - var allLogtags android.Paths - ctx.VisitAllModules(func(module android.Module) { - if logtags, ok := module.(logtagsProducer); ok { - allLogtags = append(allLogtags, logtags.logtags()...) - } + android.SetProvider(ctx, android.LogtagsProviderKey, &android.LogtagsInfo{ + Logtags: j.logtagsSrcs, }) - ctx.Build(pctx, android.BuildParams{ - Rule: mergeLogtags, - Description: "merge logtags", - Output: android.PathForIntermediates(ctx, "all-event-log-tags.txt"), - Inputs: allLogtags, - }) + return outSrcFiles } diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index ae587eac3..cab5402e9 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -1428,7 +1428,7 @@ func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.M // should not contribute to anything. So, rather than have a missing dex jar cause a Soong // failure defer the error reporting to Ninja. Unless the prebuilt build target is explicitly // built Ninja should never use the dex jar file. - if !isActiveModule(module) { + if !isActiveModule(ctx, module) { return true } diff --git a/java/jacoco.go b/java/jacoco.go index a820b3855..696a0cc37 100644 --- a/java/jacoco.go +++ b/java/jacoco.go @@ -53,7 +53,7 @@ func jacocoDepsMutator(ctx android.BottomUpMutatorContext) { } j, ok := ctx.Module().(instrumentable) - if !ctx.Module().Enabled() || !ok { + if !ctx.Module().Enabled(ctx) || !ok { return } diff --git a/java/java.go b/java/java.go index 54d2aa6e0..0df96a3a5 100644 --- a/java/java.go +++ b/java/java.go @@ -75,7 +75,6 @@ func registerJavaBuildComponents(ctx android.RegistrationContext) { ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel() }) - ctx.RegisterParallelSingletonType("logtags", LogtagsSingleton) ctx.RegisterParallelSingletonType("kythe_java_extract", kytheExtractJavaFactory) } @@ -587,6 +586,7 @@ const ( JAVA_VERSION_9 = 9 JAVA_VERSION_11 = 11 JAVA_VERSION_17 = 17 + JAVA_VERSION_21 = 21 ) func (v javaVersion) String() string { @@ -605,6 +605,8 @@ func (v javaVersion) String() string { return "11" case JAVA_VERSION_17: return "17" + case JAVA_VERSION_21: + return "21" default: return "unsupported" } @@ -647,6 +649,8 @@ func normalizeJavaVersion(ctx android.BaseModuleContext, javaVersion string) jav return JAVA_VERSION_11 case "17": return JAVA_VERSION_17 + case "21": + return JAVA_VERSION_21 case "10", "12", "13", "14", "15", "16": ctx.PropertyErrorf("java_version", "Java language level %s is not supported", javaVersion) return JAVA_VERSION_UNSUPPORTED diff --git a/java/java_test.go b/java/java_test.go index a1192bb5f..2f2793202 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2801,6 +2801,7 @@ func TestApiLibraryAconfigDeclarations(t *testing.T) { aconfig_declarations { name: "bar", package: "com.example.package", + container: "com.android.foo", srcs: [ "bar.aconfig", ], diff --git a/java/jdeps.go b/java/jdeps.go index 91f7ce715..340026318 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -48,7 +48,7 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont moduleInfos := make(map[string]android.IdeInfo) ctx.VisitAllModules(func(module android.Module) { - if !module.Enabled() { + if !module.Enabled(ctx) { return } diff --git a/java/lint.go b/java/lint.go index 31e7f353d..82fac91cf 100644 --- a/java/lint.go +++ b/java/lint.go @@ -612,7 +612,7 @@ func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) { apiVersionsDb := findModuleOrErr(ctx, files.apiVersionsModule) if apiVersionsDb == nil { if !ctx.Config().AllowMissingDependencies() { - ctx.Errorf("lint: missing module api_versions_public") + ctx.Errorf("lint: missing module %s", files.apiVersionsModule) } return } @@ -620,7 +620,7 @@ func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) { sdkAnnotations := findModuleOrErr(ctx, files.annotationsModule) if sdkAnnotations == nil { if !ctx.Config().AllowMissingDependencies() { - ctx.Errorf("lint: missing module sdk-annotations.zip") + ctx.Errorf("lint: missing module %s", files.annotationsModule) } return } diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 4db426e0d..b3c9ce50f 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -221,6 +221,7 @@ func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx and // ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, BOOTCLASSPATH, DEX2OATBOOTCLASSPATH) b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) + b.classpathFragmentBase().installClasspathProto(ctx) } func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList { diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index 2fc6c02a6..99fa092be 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -19,6 +19,7 @@ import ( "path/filepath" "android/soong/android" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -233,7 +234,7 @@ func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.Singlet var compatConfigMetadata android.Paths ctx.VisitAllModules(func(module android.Module) { - if !module.Enabled() { + if !module.Enabled(ctx) { return } if c, ok := module.(platformCompatConfigMetadataProvider); ok { diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 6a79e5883..00613eee3 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -367,10 +367,23 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { info := latest[k] name := PrebuiltApiCombinedModuleName(info.module, info.scope, "latest") + // Iterate until the currentApiScope does not extend any other api scopes + // i.e. is not a superset of any other api scopes + // the relationship between the api scopes is defined in java/sdk_library.go var srcs []string currentApiScope := scopeByName[info.scope] - srcs = append(srcs, PrebuiltApiModuleName(info.module, currentApiScope.name, "latest")) + for currentApiScope != nil { + if _, ok := latest[fmt.Sprintf("%s.%s", info.module, currentApiScope.name)]; ok { + srcs = append(srcs, PrebuiltApiModuleName(info.module, currentApiScope.name, "latest")) + } + currentApiScope = currentApiScope.extends + } + // srcs is currently listed in the order from the widest api scope to the narrowest api scopes + // e.g. module lib -> system -> public + // In order to pass the files in metalava from the narrowest api scope to the widest api scope, + // the list has to be reversed. + android.ReverseSliceInPlace(srcs) createCombinedApiFilegroupModule(mctx, name, srcs) } } diff --git a/java/robolectric.go b/java/robolectric.go index 9e8850ce9..18386c90c 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -46,6 +46,7 @@ const robolectricPrebuiltLibPattern = "platform-robolectric-%s-prebuilt" var ( roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"} roboRuntimesTag = dependencyTag{name: "roboRuntimes"} + roboRuntimeOnlyTag = dependencyTag{name: "roboRuntimeOnlyTag"} ) type robolectricProperties struct { @@ -70,6 +71,9 @@ type robolectricProperties struct { // Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectric // to use. /external/robolectric closely tracks github's master, and will fully replace /external/robolectric-shadows Upstream *bool + + // Use strict mode to limit access of Robolectric API directly. See go/roboStrictMode + Strict_mode *bool } type robolectricTest struct { @@ -112,7 +116,7 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" { ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v)) - } else { + } else if !proptools.Bool(r.robolectricProperties.Strict_mode) { if proptools.Bool(r.robolectricProperties.Upstream) { ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib+"_upstream") } else { @@ -120,6 +124,10 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { } } + if proptools.Bool(r.robolectricProperties.Strict_mode) { + ctx.AddVariationDependencies(nil, roboRuntimeOnlyTag, robolectricCurrentLib+"_upstream") + } + ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...) ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...) @@ -192,19 +200,25 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) combinedJarJars = append(combinedJarJars, instrumentedApp.implementationAndResourcesJar) } - handleLibDeps := func(dep android.Module) { + handleLibDeps := func(dep android.Module, runtimeOnly bool) { m, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider) - r.libs = append(r.libs, ctx.OtherModuleName(dep)) + if !runtimeOnly { + r.libs = append(r.libs, ctx.OtherModuleName(dep)) + } if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) { combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...) } } for _, dep := range ctx.GetDirectDepsWithTag(libTag) { - handleLibDeps(dep) + handleLibDeps(dep, false) } for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) { - handleLibDeps(dep) + handleLibDeps(dep, false) + } + // handle the runtimeOnly tag for strict_mode + for _, dep := range ctx.GetDirectDepsWithTag(roboRuntimeOnlyTag) { + handleLibDeps(dep, true) } r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base()) diff --git a/java/rro_test.go b/java/rro_test.go index d697ec627..742c83982 100644 --- a/java/rro_test.go +++ b/java/rro_test.go @@ -421,6 +421,7 @@ func TestRuntimeResourceOverlayFlagsPackages(t *testing.T) { aconfig_declarations { name: "bar", package: "com.example.package.bar", + container: "com.android.foo", srcs: [ "bar.aconfig", ], @@ -428,6 +429,7 @@ func TestRuntimeResourceOverlayFlagsPackages(t *testing.T) { aconfig_declarations { name: "baz", package: "com.example.package.baz", + container: "com.android.foo", srcs: [ "baz.aconfig", ], diff --git a/java/sdk_library.go b/java/sdk_library.go index bc3e7e912..677b32a5e 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -705,10 +705,10 @@ type scopePaths struct { annotationsZip android.OptionalPath // The path to the latest API file. - latestApiPath android.OptionalPath + latestApiPaths android.Paths // The path to the latest removed API file. - latestRemovedApiPath android.OptionalPath + latestRemovedApiPaths android.Paths } func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { @@ -829,28 +829,25 @@ func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx an }) } -func extractSingleOptionalOutputPath(dep android.Module) (android.OptionalPath, error) { +func extractOutputPaths(dep android.Module) (android.Paths, error) { var paths android.Paths if sourceFileProducer, ok := dep.(android.SourceFileProducer); ok { paths = sourceFileProducer.Srcs() + return paths, nil } else { - return android.OptionalPath{}, fmt.Errorf("module %q does not produce source files", dep) + return nil, fmt.Errorf("module %q does not produce source files", dep) } - if len(paths) != 1 { - return android.OptionalPath{}, fmt.Errorf("expected one path from %q, got %q", dep, paths) - } - return android.OptionalPathForPath(paths[0]), nil } func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error { - outputPath, err := extractSingleOptionalOutputPath(dep) - paths.latestApiPath = outputPath + outputPaths, err := extractOutputPaths(dep) + paths.latestApiPaths = outputPaths return err } func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error { - outputPath, err := extractSingleOptionalOutputPath(dep) - paths.latestRemovedApiPath = outputPath + outputPaths, err := extractOutputPaths(dep) + paths.latestRemovedApiPaths = outputPaths return err } @@ -1675,11 +1672,15 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) scopes[scope.name] = scopeInfo scopeInfo["current_api"] = scope.snapshotRelativeCurrentApiTxtPath(baseModuleName) scopeInfo["removed_api"] = scope.snapshotRelativeRemovedApiTxtPath(baseModuleName) - if p := scopePaths.latestApiPath; p.Valid() { - scopeInfo["latest_api"] = p.Path().String() + if p := scopePaths.latestApiPaths; len(p) > 0 { + // The last path in the list is the one that applies to this scope, the + // preceding ones, if any, are for the scope(s) that it extends. + scopeInfo["latest_api"] = p[len(p)-1].String() } - if p := scopePaths.latestRemovedApiPath; p.Valid() { - scopeInfo["latest_removed_api"] = p.Path().String() + if p := scopePaths.latestRemovedApiPaths; len(p) > 0 { + // The last path in the list is the one that applies to this scope, the + // preceding ones, if any, are for the scope(s) that it extends. + scopeInfo["latest_removed_api"] = p[len(p)-1].String() } } android.SetProvider(ctx, android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo}) @@ -2352,7 +2353,7 @@ func (module *SdkLibrary) getApiDir() string { // once for public API level and once for system API level func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) { // If the module has been disabled then don't create any child modules. - if !module.Enabled() { + if !module.Enabled(mctx) { return } @@ -3370,6 +3371,7 @@ func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleConte android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent) module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir()) + ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath) } func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 1c94a8a8f..d240e701b 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -1085,18 +1085,6 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) { t.Run("prefer", func(t *testing.T) { testJavaSdkLibraryImport_Preferred(t, "prefer: true,", android.NullFixturePreparer) }) - - t.Run("use_source_config_var", func(t *testing.T) { - testJavaSdkLibraryImport_Preferred(t, - "use_source_config_var: {config_namespace: \"acme\", var_name: \"use_source\"},", - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.VendorVars = map[string]map[string]string{ - "acme": { - "use_source": "false", - }, - } - })) - }) } // If a module is listed in `mainline_module_contributions, it should be used @@ -1727,6 +1715,7 @@ func TestSdkLibraryExportableStubsLibrary(t *testing.T) { aconfig_declarations { name: "bar", package: "com.example.package", + container: "com.android.foo", srcs: [ "bar.aconfig", ], diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index b291e708b..bad2cf1cf 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -69,6 +69,7 @@ func (p *platformSystemServerClasspathModule) GenerateAndroidBuildActions(ctx an configuredJars = configuredJars.AppendList(&standaloneConfiguredJars) classpathJars = append(classpathJars, standaloneClasspathJars...) p.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) + p.classpathFragmentBase().installClasspathProto(ctx) } func (p *platformSystemServerClasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList { diff --git a/java/testing.go b/java/testing.go index 631d51662..5ae326d93 100644 --- a/java/testing.go +++ b/java/testing.go @@ -711,7 +711,7 @@ var PrepareForTestWithFakeApexMutator = android.GroupFixturePreparers( func registerFakeApexMutator(ctx android.RegistrationContext) { ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("apex", fakeApexMutator).Parallel() + ctx.Transition("apex", &fakeApexMutator{}) }) } @@ -726,16 +726,30 @@ var _ apexModuleBase = (*SdkLibrary)(nil) // `apex_available`. It helps us avoid a dependency on the real mutator defined in "soong-apex", // which will cause a cyclic dependency, and it provides an easy way to create an APEX variant for // testing without dealing with all the complexities in the real mutator. -func fakeApexMutator(mctx android.BottomUpMutatorContext) { - switch mctx.Module().(type) { +type fakeApexMutator struct{} + +func (f *fakeApexMutator) Split(ctx android.BaseModuleContext) []string { + switch ctx.Module().(type) { case *Library, *SdkLibrary: - if len(mctx.Module().(apexModuleBase).ApexAvailable()) > 0 { - modules := mctx.CreateVariations("", "apex1000") - apexInfo := android.ApexInfo{ - ApexVariationName: "apex1000", - } - mctx.SetVariationProvider(modules[1], android.ApexInfoProvider, apexInfo) + return []string{"", "apex1000"} + } + return []string{""} +} + +func (f *fakeApexMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + return sourceVariation +} + +func (f *fakeApexMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + return incomingVariation +} + +func (f *fakeApexMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + if variation != "" { + apexInfo := android.ApexInfo{ + ApexVariationName: "apex1000", } + android.SetProvider(ctx, android.ApexInfoProvider, apexInfo) } } diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go index 97345afc3..679632c10 100644 --- a/provenance/provenance_singleton.go +++ b/provenance/provenance_singleton.go @@ -18,6 +18,7 @@ package provenance import ( "android/soong/android" + "github.com/google/blueprint" ) @@ -68,6 +69,15 @@ type provenanceInfoSingleton struct { func (p *provenanceInfoSingleton) GenerateBuildActions(context android.SingletonContext) { allMetaDataFiles := make([]android.Path, 0) + moduleFilter := func(module android.Module) bool { + if !module.Enabled(context) || module.IsSkipInstall() { + return false + } + if p, ok := module.(ProvenanceMetadata); ok { + return p.ProvenanceMetaDataFile().String() != "" + } + return false + } context.VisitAllModulesIf(moduleFilter, func(module android.Module) { if p, ok := module.(ProvenanceMetadata); ok { allMetaDataFiles = append(allMetaDataFiles, p.ProvenanceMetaDataFile()) @@ -91,16 +101,6 @@ func (p *provenanceInfoSingleton) GenerateBuildActions(context android.Singleton context.Phony("droidcore", android.PathForPhony(context, "provenance_metadata")) } -func moduleFilter(module android.Module) bool { - if !module.Enabled() || module.IsSkipInstall() { - return false - } - if p, ok := module.(ProvenanceMetadata); ok { - return p.ProvenanceMetaDataFile().String() != "" - } - return false -} - func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath android.Path, installedFile android.InstallPath) android.OutputPath { onDevicePathOfInstalledFile := android.InstallPathToOnDevicePath(ctx, installedFile) artifactMetaDataFile := android.PathForIntermediates(ctx, "provenance_metadata", ctx.ModuleDir(), ctx.ModuleName(), "provenance_metadata.textproto") diff --git a/python/binary.go b/python/binary.go index d6750c655..c84eeeedb 100644 --- a/python/binary.go +++ b/python/binary.go @@ -203,7 +203,7 @@ func (p *PythonBinaryModule) OutputFiles(tag string) (android.Paths, error) { } func (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool { - return Bool(p.properties.Embedded_launcher) + return BoolDefault(p.properties.Embedded_launcher, true) } func (b *PythonBinaryModule) autorun() bool { diff --git a/python/python.go b/python/python.go index 621e429b9..e14fdf333 100644 --- a/python/python.go +++ b/python/python.go @@ -59,7 +59,7 @@ type VersionProperties struct { // list of the Python libraries used only for this Python version. Libs []string `android:"arch_variant"` - // whether the binary is required to be built with embedded launcher for this version, defaults to false. + // whether the binary is required to be built with embedded launcher for this version, defaults to true. Embedded_launcher *bool // TODO(b/174041232): Remove this property } diff --git a/python/scripts/precompile_python.py b/python/scripts/precompile_python.py index 07b8fe97b..b3cf950d9 100644 --- a/python/scripts/precompile_python.py +++ b/python/scripts/precompile_python.py @@ -30,6 +30,7 @@ def process_one_file(name, infile, outzip): # Date was chosen to be the same as # https://cs.android.com/android/platform/superproject/main/+/main:build/soong/jar/jar.go;l=36;drc=2863e4535eb65e15f955dc8ed48fa99b1d2a1db5 info = zipfile.ZipInfo(filename=name, date_time=(2008, 1, 1, 0, 0, 0)) + info.compress_type = zipfile.ZIP_DEFLATED if not info.filename.endswith('.py'): outzip.writestr(info, infile.read()) diff --git a/rust/afdo.go b/rust/afdo.go index 6116c5e21..6bd4bae1a 100644 --- a/rust/afdo.go +++ b/rust/afdo.go @@ -39,7 +39,7 @@ func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorCont return } - if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() { + if mod, ok := ctx.Module().(*Module); ok && mod.Enabled(ctx) { fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName()) if err != nil { ctx.ModuleErrorf("%s", err.Error()) diff --git a/rust/bindgen.go b/rust/bindgen.go index 11ba74d45..427775351 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -101,6 +101,18 @@ type BindgenProperties struct { // // "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]" Custom_bindgen string + + // flag to indicate if bindgen should handle `static inline` functions (default is false). + // If true, Static_inline_library must be set. + Handle_static_inline *bool + + // module name of the corresponding cc_library_static which includes the static_inline wrapper + // generated functions from bindgen. Must be used together with handle_static_inline. + // + // If there are no static inline functions provided through the header file, + // then bindgen (as of 0.69.2) will silently fail to output a .c file, and + // the cc_library_static depending on this module will fail compilation. + Static_inline_library *string } type bindgenDecorator struct { @@ -156,6 +168,18 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr var cflags []string var implicits android.Paths + var implicitOutputs android.WritablePaths + var validations android.Paths + + if Bool(b.Properties.Handle_static_inline) && b.Properties.Static_inline_library == nil { + ctx.PropertyErrorf("handle_static_inline", + "requires declaring static_inline_library to the corresponding cc_library module that includes the generated C source from bindgen.") + } + + if b.Properties.Static_inline_library != nil && !Bool(b.Properties.Handle_static_inline) { + ctx.PropertyErrorf("static_inline_library", + "requires declaring handle_static_inline.") + } implicits = append(implicits, deps.depGeneratedHeaders...) @@ -232,6 +256,12 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr bindgenFlags := defaultBindgenFlags bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...) + if Bool(b.Properties.Handle_static_inline) { + outputStaticFnsFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".c") + implicitOutputs = append(implicitOutputs, outputStaticFnsFile) + validations = append(validations, outputStaticFnsFile) + bindgenFlags = append(bindgenFlags, []string{"--experimental", "--wrap-static-fns", "--wrap-static-fns-path=" + outputStaticFnsFile.String()}...) + } // cat reads from stdin if its command line is empty, // so we pass in /dev/null if there are no other flag files @@ -279,11 +309,13 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr } ctx.Build(pctx, android.BuildParams{ - Rule: bindgen, - Description: strings.Join([]string{cmdDesc, wrapperFile.Path().Rel()}, " "), - Output: outputFile, - Input: wrapperFile.Path(), - Implicits: implicits, + Rule: bindgen, + Description: strings.Join([]string{cmdDesc, wrapperFile.Path().Rel()}, " "), + Output: outputFile, + Input: wrapperFile.Path(), + Implicits: implicits, + ImplicitOutputs: implicitOutputs, + Validations: validations, Args: map[string]string{ "cmd": cmd, "flags": strings.Join(bindgenFlags, " "), @@ -293,6 +325,14 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr }) b.BaseSourceProvider.OutputFiles = android.Paths{outputFile} + + // Append any additional implicit outputs after the entry point source. + // We append any generated .c file here so it can picked up by cc_library_static modules. + // Those CC modules need to be sure not to pass any included .rs files to Clang. + // We don't have to worry about the additional .c files for Rust modules as only the entry point + // is passed to rustc. + b.BaseSourceProvider.OutputFiles = append(b.BaseSourceProvider.OutputFiles, implicitOutputs.Paths()...) + return outputFile } @@ -344,6 +384,14 @@ func (b *bindgenDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps { deps = muslDeps(ctx, deps, false) } + if !ctx.RustModule().Source() && b.Properties.Static_inline_library != nil { + // This is not the source variant, so add the static inline library as a dependency. + // + // This is necessary to avoid a circular dependency between the source variant and the + // dependent cc module. + deps.StaticLibs = append(deps.StaticLibs, String(b.Properties.Static_inline_library)) + } + deps.SharedLibs = append(deps.SharedLibs, b.ClangProperties.Shared_libs...) deps.StaticLibs = append(deps.StaticLibs, b.ClangProperties.Static_libs...) deps.HeaderLibs = append(deps.HeaderLibs, b.ClangProperties.Header_libs...) diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go index 0c0a6dad0..2b7362f08 100644 --- a/rust/bindgen_test.go +++ b/rust/bindgen_test.go @@ -227,3 +227,63 @@ func TestBindgenFlagFile(t *testing.T) { // TODO: The best we can do right now is check $flagfiles. Once bindgen.go switches to RuleBuilder, // we may be able to check libbinder.RuleParams.Command to see if it contains $(cat /dev/null flag_file.txt) } + +func TestBindgenHandleStaticInlining(t *testing.T) { + ctx := testRust(t, ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + handle_static_inline: true, + static_inline_library: "libbindgen_staticfns" + } + + cc_library_static { + name: "libbindgen_staticfns", + srcs: [":libbindgen"], + include_dirs: ["src/"], + } + `) + libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") + // Make sure the flag to support `static inline` functions is present + if !strings.Contains(libbindgen.Args["flags"], "--wrap-static-fns") { + t.Errorf("missing flag to handle static inlining in rust_bindgen rule: flags %#v", libbindgen.Args["flags"]) + } + + if !strings.Contains(libbindgen.Args["flags"], "--wrap-static-fns-path") { + t.Errorf("missing flag to define path for static inlining C source from bindgen (--wrap-static-fns-path): flags %#v", libbindgen.Args["flags"]) + } + +} + +func TestBindgenStaticInlineProperties(t *testing.T) { + // Make sure handle_static_inline without static_inline_library generates an error + testRustError(t, "requires declaring static_inline_library to the corresponding cc_library module that includes the generated C source from bindgen", ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + handle_static_inline: true + } + `) + testRustError(t, "requires declaring handle_static_inline", ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + static_inline_library: "libbindgen_staticfns" + } + + cc_library_static { + name: "libbindgen_staticfns", + srcs: [":libbindgen"], + include_dirs: ["src/"], + } + `) +} diff --git a/rust/config/global.go b/rust/config/global.go index ba085600b..e83e23aa5 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -24,7 +24,7 @@ import ( var ( pctx = android.NewPackageContext("android/soong/rust/config") - RustDefaultVersion = "1.77.1" + RustDefaultVersion = "1.77.1.p1" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2021" Stdlibs = []string{ @@ -53,6 +53,9 @@ var ( "--color=always", "-Z dylib-lto", "-Z link-native-libraries=no", + + // cfg flag to indicate that we are building in AOSP with Soong + "--cfg soong", } LinuxHostGlobalLinkFlags = []string{ diff --git a/rust/coverage.go b/rust/coverage.go index bc6504ddc..91a78060d 100644 --- a/rust/coverage.go +++ b/rust/coverage.go @@ -39,9 +39,11 @@ func (cov *coverage) props() []interface{} { func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps { if cov.Properties.NeedCoverageVariant { - ctx.AddVariationDependencies([]blueprint.Variation{ - {Mutator: "link", Variation: "static"}, - }, cc.CoverageDepTag, CovLibraryName) + if ctx.Device() { + ctx.AddVariationDependencies([]blueprint.Variation{ + {Mutator: "link", Variation: "static"}, + }, cc.CoverageDepTag, CovLibraryName) + } // no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency. if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() { @@ -60,12 +62,14 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags if cov.Properties.CoverageEnabled { flags.Coverage = true - coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface) flags.RustFlags = append(flags.RustFlags, "-C instrument-coverage", "-g") - flags.LinkFlags = append(flags.LinkFlags, - profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open") - deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path()) + if ctx.Device() { + coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface) + flags.LinkFlags = append(flags.LinkFlags, + profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open") + deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path()) + } // no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency. if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() { diff --git a/rust/doc.go b/rust/doc.go index 6970d7979..fe205233d 100644 --- a/rust/doc.go +++ b/rust/doc.go @@ -38,7 +38,7 @@ func (n *rustdocSingleton) GenerateBuildActions(ctx android.SingletonContext) { FlagWithArg("-D ", docDir.String()) ctx.VisitAllModules(func(module android.Module) { - if !module.Enabled() { + if !module.Enabled(ctx) { return } diff --git a/rust/library.go b/rust/library.go index 6be4917bf..f58a54fcc 100644 --- a/rust/library.go +++ b/rust/library.go @@ -713,7 +713,7 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { if sourceVariant { sv := modules[0] for _, v := range modules[1:] { - if !v.Enabled() { + if !v.Enabled(mctx) { continue } mctx.AddInterVariantDependency(sourceDepTag, v, sv) diff --git a/rust/project_json.go b/rust/project_json.go index ad9b69020..24dcc89f1 100644 --- a/rust/project_json.go +++ b/rust/project_json.go @@ -96,7 +96,7 @@ func (singleton *projectGeneratorSingleton) mergeDependencies(ctx android.Single var childId int cInfo, known := singleton.knownCrates[rChild.Name()] if !known { - childId, ok = singleton.addCrate(ctx, rChild, make(map[string]int)) + childId, ok = singleton.addCrate(ctx, rChild) if !ok { return } @@ -119,7 +119,7 @@ func isModuleSupported(ctx android.SingletonContext, module android.Module) (*Mo if !ok { return nil, false } - if !rModule.Enabled() { + if !rModule.Enabled(ctx) { return nil, false } return rModule, true @@ -128,7 +128,8 @@ func isModuleSupported(ctx android.SingletonContext, module android.Module) (*Mo // addCrate adds a crate to singleton.project.Crates ensuring that required // dependencies are also added. It returns the index of the new crate in // singleton.project.Crates -func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module, deps map[string]int) (int, bool) { +func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module) (int, bool) { + deps := make(map[string]int) rootModule, err := rModule.compiler.checkedCrateRootPath() if err != nil { return 0, false @@ -180,7 +181,7 @@ func (singleton *projectGeneratorSingleton) appendCrateAndDependencies(ctx andro if cInfo, ok := singleton.knownCrates[module.Name()]; ok { // If we have a new device variant, override the old one if !cInfo.Device && rModule.Device() { - singleton.addCrate(ctx, rModule, cInfo.Deps) + singleton.addCrate(ctx, rModule) return } crate := singleton.project.Crates[cInfo.Idx] @@ -188,7 +189,7 @@ func (singleton *projectGeneratorSingleton) appendCrateAndDependencies(ctx andro singleton.project.Crates[cInfo.Idx] = crate return } - singleton.addCrate(ctx, rModule, make(map[string]int)) + singleton.addCrate(ctx, rModule) } func (singleton *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) { diff --git a/rust/protobuf.go b/rust/protobuf.go index 0b26b80fa..fab5259a5 100644 --- a/rust/protobuf.go +++ b/rust/protobuf.go @@ -16,6 +16,7 @@ package rust import ( "fmt" + "strconv" "strings" "android/soong/android" @@ -122,41 +123,65 @@ func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) // stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point. var outputs android.WritablePaths - rule := android.NewRuleBuilder(pctx, ctx) + for i, shard := range android.ShardPaths(protoFiles, 50) { + rule := android.NewRuleBuilder(pctx, ctx) - for _, protoFile := range protoFiles { - // Since we're iterating over the protoFiles already, make sure they're not redeclared in grpcFiles - if android.InList(protoFile.String(), grpcFiles.Strings()) { - ctx.PropertyErrorf("protos", - "A proto can only be added once to either grpc_protos or protos. %q is declared in both properties", - protoFile.String()) - } + for _, protoFile := range shard { + // Since we're iterating over the protoFiles already, make sure they're not redeclared in grpcFiles + if android.InList(protoFile.String(), grpcFiles.Strings()) { + ctx.PropertyErrorf("protos", + "A proto can only be added once to either grpc_protos or protos. %q is declared in both properties", + protoFile.String()) + } + + protoName := strings.TrimSuffix(protoFile.Base(), ".proto") + proto.protoNames = append(proto.protoNames, protoName) + + protoOut := android.PathForModuleOut(ctx, protoName+".rs") + depFile := android.PathForModuleOut(ctx, protoName+".d") - protoName := strings.TrimSuffix(protoFile.Base(), ".proto") - proto.protoNames = append(proto.protoNames, protoName) + ruleOutputs := android.WritablePaths{protoOut, depFile} - protoOut := android.PathForModuleOut(ctx, protoName+".rs") - depFile := android.PathForModuleOut(ctx, protoName+".d") + android.ProtoRule(rule, protoFile, protoFlags, protoFlags.Deps, outDir, depFile, ruleOutputs) + outputs = append(outputs, ruleOutputs...) + } - ruleOutputs := android.WritablePaths{protoOut, depFile} + ruleName := "protoc" + ruleDesc := "protoc" + if i > 0 { + ruleName += "_" + strconv.Itoa(i+1) + ruleDesc += " " + strconv.Itoa(i+1) + } - android.ProtoRule(rule, protoFile, protoFlags, protoFlags.Deps, outDir, depFile, ruleOutputs) - outputs = append(outputs, ruleOutputs...) + rule.Build(ruleName, ruleDesc) } - for _, grpcFile := range grpcFiles { - grpcName := strings.TrimSuffix(grpcFile.Base(), ".proto") - proto.grpcNames = append(proto.grpcNames, grpcName) + for i, shard := range android.ShardPaths(grpcFiles, 50) { + rule := android.NewRuleBuilder(pctx, ctx) + + for _, grpcFile := range shard { + grpcName := strings.TrimSuffix(grpcFile.Base(), ".proto") + proto.grpcNames = append(proto.grpcNames, grpcName) - // GRPC protos produce two files, a proto.rs and a proto_grpc.rs - protoOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+".rs")) - grpcOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+grpcSuffix+".rs")) - depFile := android.PathForModuleOut(ctx, grpcName+".d") + // GRPC protos produce two files, a proto.rs and a proto_grpc.rs + protoOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+".rs")) + grpcOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+grpcSuffix+".rs")) + depFile := android.PathForModuleOut(ctx, grpcName+".d") - ruleOutputs := android.WritablePaths{protoOut, grpcOut, depFile} + ruleOutputs := android.WritablePaths{protoOut, grpcOut, depFile} - android.ProtoRule(rule, grpcFile, grpcProtoFlags, grpcProtoFlags.Deps, outDir, depFile, ruleOutputs) - outputs = append(outputs, ruleOutputs...) + android.ProtoRule(rule, grpcFile, grpcProtoFlags, grpcProtoFlags.Deps, outDir, depFile, ruleOutputs) + outputs = append(outputs, ruleOutputs...) + } + + ruleName := "protoc_grpc" + ruleDesc := "protoc grpc" + if i > 0 { + ruleName += "_" + strconv.Itoa(i+1) + ruleDesc += " " + strconv.Itoa(i+1) + } + + rule.Build(ruleName, ruleDesc) } // Check that all proto base filenames are unique as outputs are written to the same directory. @@ -168,8 +193,6 @@ func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.WriteFileRule(ctx, stemFile, proto.genModFileContents()) - rule.Build("protoc_"+ctx.ModuleName(), "protoc "+ctx.ModuleName()) - // stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point. proto.BaseSourceProvider.OutputFiles = append(android.Paths{stemFile}, outputs.Paths()...) diff --git a/rust/rust.go b/rust/rust.go index c2b61515c..de049f77f 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -1697,7 +1697,7 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { } func BeginMutator(ctx android.BottomUpMutatorContext) { - if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() { + if mod, ok := ctx.Module().(*Module); ok && mod.Enabled(ctx) { mod.beginMutator(ctx) } } diff --git a/rust/sanitize.go b/rust/sanitize.go index bfd397155..c086880ed 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -258,7 +258,7 @@ func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps { func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { if mod, ok := mctx.Module().(*Module); ok && mod.sanitize != nil { - if !mod.Enabled() { + if !mod.Enabled(mctx) { return } diff --git a/scripts/gen-kotlin-build-file.py b/scripts/gen-kotlin-build-file.py index 83b4cd8a3..99afdca75 100644 --- a/scripts/gen-kotlin-build-file.py +++ b/scripts/gen-kotlin-build-file.py @@ -79,7 +79,7 @@ def main(): elif src.endswith('.kt'): f.write(' <sources path="%s"/>\n' % path) else: - raise RuntimeError('unknown source file type %s' % file) + raise RuntimeError(f'unknown source file type {src} from rspfile {rsp_file}') for rsp_file in args.common_srcs: for src in NinjaRspFileReader(rsp_file): diff --git a/scripts/run-soong-tests-with-go-tools.sh b/scripts/run-soong-tests-with-go-tools.sh index 93c622ea4..1fbb1fc77 100755 --- a/scripts/run-soong-tests-with-go-tools.sh +++ b/scripts/run-soong-tests-with-go-tools.sh @@ -74,6 +74,6 @@ for dir in "${go_modules[@]}"; do (cd "$dir"; eval ${network_jail} -- ${GOROOT}/bin/go build ./... eval ${network_jail} -- ${GOROOT}/bin/go test ./... - eval ${network_jail} -- ${GOROOT}/bin/go test -race -short ./... + eval ${network_jail} -- ${GOROOT}/bin/go test -race -timeout 20m -short ./... ) done diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 275860f32..0a5483b07 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -688,6 +688,12 @@ func TestSnapshotWithJavaSystemModules(t *testing.T) { public: { enabled: true, }, + system: { + enabled: true, + }, + module_lib: { + enabled: true, + }, } java_system_modules { @@ -752,6 +758,20 @@ java_sdk_library_import { removed_api: "sdk_library/public/myjavalib-removed.txt", sdk_version: "current", }, + system: { + jars: ["sdk_library/system/myjavalib-stubs.jar"], + stub_srcs: ["sdk_library/system/myjavalib_stub_sources"], + current_api: "sdk_library/system/myjavalib.txt", + removed_api: "sdk_library/system/myjavalib-removed.txt", + sdk_version: "system_current", + }, + module_lib: { + jars: ["sdk_library/module-lib/myjavalib-stubs.jar"], + stub_srcs: ["sdk_library/module-lib/myjavalib_stub_sources"], + current_api: "sdk_library/module-lib/myjavalib.txt", + removed_api: "sdk_library/module-lib/myjavalib-removed.txt", + sdk_version: "module_current", + }, } java_system_modules_import { @@ -771,6 +791,12 @@ java_system_modules_import { .intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar .intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt .intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt +.intermediates/myjavalib.stubs.exportable.system/android_common/combined/myjavalib.stubs.exportable.system.jar -> sdk_library/system/myjavalib-stubs.jar +.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt +.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt +.intermediates/myjavalib.stubs.exportable.module_lib/android_common/combined/myjavalib.stubs.exportable.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar +.intermediates/myjavalib.stubs.source.module_lib/android_common/exportable/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt +.intermediates/myjavalib.stubs.source.module_lib/android_common/exportable/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt `), checkInfoContents(result.Config, ` [ @@ -805,11 +831,23 @@ java_system_modules_import { "@name": "myjavalib", "dist_stem": "myjavalib", "scopes": { + "module-lib": { + "current_api": "sdk_library/module-lib/myjavalib.txt", + "latest_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib.api.module-lib.latest/gen/myjavalib.api.module-lib.latest", + "latest_removed_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib-removed.api.module-lib.latest/gen/myjavalib-removed.api.module-lib.latest", + "removed_api": "sdk_library/module-lib/myjavalib-removed.txt" + }, "public": { "current_api": "sdk_library/public/myjavalib.txt", "latest_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib.api.public.latest/gen/myjavalib.api.public.latest", "latest_removed_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib-removed.api.public.latest/gen/myjavalib-removed.api.public.latest", "removed_api": "sdk_library/public/myjavalib-removed.txt" + }, + "system": { + "current_api": "sdk_library/system/myjavalib.txt", + "latest_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib.api.system.latest/gen/myjavalib.api.system.latest", + "latest_removed_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib-removed.api.system.latest/gen/myjavalib-removed.api.system.latest", + "removed_api": "sdk_library/system/myjavalib-removed.txt" } } }, diff --git a/snapshot/host_fake_snapshot.go b/snapshot/host_fake_snapshot.go index 63cd4e1b6..b416ebdd4 100644 --- a/snapshot/host_fake_snapshot.go +++ b/snapshot/host_fake_snapshot.go @@ -116,7 +116,7 @@ func (c *hostFakeSingleton) GenerateBuildActions(ctx android.SingletonContext) { prebuilts[android.RemoveOptionalPrebuiltPrefix(module.Name())] = true return } - if !module.Enabled() || module.IsHideFromMake() { + if !module.Enabled(ctx) || module.IsHideFromMake() { return } apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider) diff --git a/tradefed_modules/test_module_config.go b/tradefed_modules/test_module_config.go index 686753713..b2d563129 100644 --- a/tradefed_modules/test_module_config.go +++ b/tradefed_modules/test_module_config.go @@ -160,35 +160,17 @@ func (m *testModuleConfigModule) GenerateAndroidBuildActions(ctx android.ModuleC } -// Any test suites in base should not be repeated in the derived class, except "general-tests". -// We may restrict derived tests to only be "general-tests" as it doesn't make sense to add a slice -// of a test to compatibility suite. +// Ensure at least one test_suite is listed. Ideally it should be general-tests +// or device-tests, whichever is listed in base and prefer general-tests if both are listed. +// However this is not enforced yet. // -// Returns ErrorMessage, false on problems -// Returns _, true if okay. +// Returns true if okay and reports errors via ModuleErrorf. func (m *testModuleConfigModule) validateTestSuites(ctx android.ModuleContext) bool { if len(m.tradefedProperties.Test_suites) == 0 { - ctx.ModuleErrorf("At least one test-suite must be set or this won't run. Use \"general-tests\"") + ctx.ModuleErrorf("At least one test-suite must be set or this won't run. Use \"general-tests\" or \"device-tests\"") return false } - derivedSuites := make(map[string]bool) - // See if any suites in base is also in derived (other than general-tests) - for _, s := range m.tradefedProperties.Test_suites { - if s != "general-tests" { - derivedSuites[s] = true - } - } - if len(derivedSuites) == 0 { - return true - } - for _, baseSuite := range m.provider.TestSuites { - if derivedSuites[baseSuite] { - ctx.ModuleErrorf("TestSuite %s exists in the base, do not add it here", baseSuite) - return false - } - } - return true } @@ -297,10 +279,16 @@ func (m *testModuleConfigModule) validateBase(ctx android.ModuleContext, depTag // 1. manifest file to testcases dir // 2. New Module.config / AndroidTest.xml file with our options. func (m *testModuleConfigModule) generateManifestAndConfig(ctx android.ModuleContext) { + // Keep before early returns. + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: true, + TopLevelTarget: true, + }) + if !m.validateTestSuites(ctx) { return } - // Ensure the provider is accurate + // Ensure the base provider is accurate if m.provider.TestConfig == nil { return } diff --git a/tradefed_modules/test_module_config_test.go b/tradefed_modules/test_module_config_test.go index 41dd3d479..b2049b1af 100644 --- a/tradefed_modules/test_module_config_test.go +++ b/tradefed_modules/test_module_config_test.go @@ -19,6 +19,8 @@ import ( "strconv" "strings" "testing" + + "github.com/google/blueprint" ) const bp = ` @@ -323,28 +325,65 @@ func TestModuleConfigHostNeedsATestSuite(t *testing.T) { RunTestWithBp(t, badBp) } -func TestModuleConfigHostDuplicateTestSuitesGiveErrors(t *testing.T) { - badBp := ` - java_test_host { - name: "base", - srcs: ["a.java"], - test_suites: ["general-tests", "some-compat"], - } - +func TestTestOnlyProvider(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + java.PrepareForTestWithJavaDefaultModules, + android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents), + ).RunTestWithBp(t, ` + // These should be test-only test_module_config_host { - name: "derived_test", + name: "host-derived-test", + base: "host-base", + exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"], + include_annotations: ["android.platform.test.annotations.LargeTest"], + test_suites: ["general-tests"], + } + + test_module_config { + name: "derived-test", base: "base", exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"], include_annotations: ["android.platform.test.annotations.LargeTest"], - test_suites: ["general-tests", "some-compat"], - }` + test_suites: ["general-tests"], + } - android.GroupFixturePreparers( - java.PrepareForTestWithJavaDefaultModules, - android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents), - ).ExtendWithErrorHandler( - android.FixtureExpectsAtLeastOneErrorMatchingPattern("TestSuite some-compat exists in the base")). - RunTestWithBp(t, badBp) + android_test { + name: "base", + sdk_version: "current", + data: ["data/testfile"], + } + + java_test_host { + name: "host-base", + srcs: ["a.java"], + test_suites: ["general-tests"], + }`, + ) + + // 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{ + "host-derived-test", + "derived-test", + // android_test and java_test_host are tests too. + "host-base", + "base", + } + + 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) + } } // Use for situations where the entries map contains pairs: [srcPath:installedPath1, srcPath2:installedPath2] diff --git a/ui/build/rbe.go b/ui/build/rbe.go index 5142a416f..8fa147f70 100644 --- a/ui/build/rbe.go +++ b/ui/build/rbe.go @@ -159,12 +159,6 @@ func CheckProdCreds(ctx Context, config Config) { fmt.Fprintln(ctx.Writer, "") return } - if config.GoogleProdCredsExist() { - return - } - fmt.Fprintln(ctx.Writer, "") - fmt.Fprintln(ctx.Writer, "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This is required for a successful build execution. See go/rbe-android-default-announcement for more information.\033[0m") - fmt.Fprintln(ctx.Writer, "") } // DumpRBEMetrics creates a metrics protobuf file containing RBE related metrics. |