From 29e91d21219485f0bc675c4d6034b5726be4ca92 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 2 Apr 2020 01:41:41 +0900 Subject: [PATCH] Apex: support codenames for min_sdk_version Apex can use codenames like "Q", "R" for its min_sdk_version property. Also, cc_library can use codenames for its stubs.versions. Bug: 152655956 Test: vendor/google/build/build_mainline_modules.sh Change-Id: I077ad7b2ac5d90b4c8708921e43846206f05ba70 --- android/api_levels.go | 16 ++++++++---- apex/apex.go | 12 +++------ apex/apex_test.go | 58 +++++++++++++++++++++++++++++++++++++++++-- cc/library.go | 12 ++++++--- cc/library_test.go | 54 ++++++++++++++++++++++++++++++++++++++++ cc/ndk_library.go | 2 ++ 6 files changed, 135 insertions(+), 19 deletions(-) diff --git a/android/api_levels.go b/android/api_levels.go index 4f6efee70..62a5fce32 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -16,6 +16,7 @@ package android import ( "encoding/json" + "fmt" "strconv" ) @@ -84,14 +85,19 @@ func getApiLevelsMap(config Config) map[string]int { // Converts an API level string into its numeric form. // * Codenames are decoded. // * Numeric API levels are simply converted. -// * "minimum" and "current" are not currently handled since the former is -// NDK specific and the latter has inconsistent meaning. +// * "current" is mapped to FutureApiLevel(10000) +// * "minimum" is NDK specific and not handled with this. (refer normalizeNdkApiLevel in cc.go) func ApiStrToNum(ctx BaseModuleContext, apiLevel string) (int, error) { - num, ok := getApiLevelsMap(ctx.Config())[apiLevel] - if ok { + if apiLevel == "current" { + return FutureApiLevel, nil + } + if num, ok := getApiLevelsMap(ctx.Config())[apiLevel]; ok { return num, nil } - return strconv.Atoi(apiLevel) + if num, err := strconv.Atoi(apiLevel); err == nil { + return num, nil + } + return 0, fmt.Errorf("SDK version should be one of \"current\", or : %q", apiLevel) } func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) { diff --git a/apex/apex.go b/apex/apex.go index 00963655b..8e3e56216 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -19,7 +19,6 @@ import ( "path" "path/filepath" "sort" - "strconv" "strings" "sync" @@ -1995,14 +1994,11 @@ func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int { ver := proptools.StringDefault(a.properties.Min_sdk_version, "current") - if ver != "current" { - minSdkVersion, err := strconv.Atoi(ver) - if err != nil { - ctx.PropertyErrorf("min_sdk_version", "should be \"current\" or , but %q", ver) - } - return minSdkVersion + intVer, err := android.ApiStrToNum(ctx, ver) + if err != nil { + ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) } - return android.FutureApiLevel + return intVer } // Ensures that the dependencies are marked as available for this APEX diff --git a/apex/apex_test.go b/apex/apex_test.go index ba7d91639..80d8153b4 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -1106,6 +1106,60 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { expectNoLink("liba", "shared_otherapex", "libz", "shared") } +func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libx"], + min_sdk_version: "R", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "libx", + shared_libs: ["libz"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + + cc_library { + name: "libz", + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["29", "R"], + }, + } + `, func(fs map[string][]byte, config android.Config) { + config.TestProductVariables.Platform_version_active_codenames = []string{"R"} + }) + + expectLink := func(from, from_variant, to, to_variant string) { + ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") + } + expectNoLink := func(from, from_variant, to, to_variant string) { + ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") + } + // 9000 is quite a magic number. + // Finalized SDK codenames are mapped as P(28), Q(29), ... + // And, codenames which are not finalized yet(active_codenames + future_codenames) are numbered from 9000, 9001, ... + // to distinguish them from finalized and future_api(10000) + // In this test, "R" is assumed not finalized yet( listed in Platform_version_active_codenames) and translated into 9000 + // (refer android/api_levels.go) + expectLink("libx", "shared_myapex", "libz", "shared_9000") + expectNoLink("libx", "shared_myapex", "libz", "shared_29") + expectNoLink("libx", "shared_myapex", "libz", "shared") +} + func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) { ctx, _ := testApex(t, ` apex { @@ -1296,11 +1350,11 @@ func TestInvalidMinSdkVersion(t *testing.T) { } `) - testApexError(t, `"myapex" .*: min_sdk_version: should be "current" or `, ` + testApexError(t, `"myapex" .*: min_sdk_version: SDK version should be .*`, ` apex { name: "myapex", key: "myapex.key", - min_sdk_version: "R", + min_sdk_version: "abc", } apex_key { diff --git a/cc/library.go b/cc/library.go index e79ad9983..c7488ee30 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1455,18 +1455,22 @@ func LatestStubsVersionFor(config android.Config, name string) string { return "" } -func checkVersions(ctx android.BaseModuleContext, versions []string) { +func normalizeVersions(ctx android.BaseModuleContext, versions []string) { numVersions := make([]int, len(versions)) for i, v := range versions { - numVer, err := strconv.Atoi(v) + numVer, err := android.ApiStrToNum(ctx, v) if err != nil { - ctx.PropertyErrorf("versions", "%q is not a number", v) + ctx.PropertyErrorf("versions", "%s", err.Error()) + return } numVersions[i] = numVer } if !sort.IsSorted(sort.IntSlice(numVersions)) { ctx.PropertyErrorf("versions", "not sorted: %v", versions) } + for i, v := range numVersions { + versions[i] = strconv.Itoa(v) + } } func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) { @@ -1488,7 +1492,7 @@ func VersionMutator(mctx android.BottomUpMutatorContext) { if library, ok := mctx.Module().(LinkableInterface); ok && !library.InRecovery() { if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 { versions := library.StubsVersions() - checkVersions(mctx, versions) + normalizeVersions(mctx, versions) if mctx.Failed() { return } diff --git a/cc/library_test.go b/cc/library_test.go index b8d889544..cb167252d 100644 --- a/cc/library_test.go +++ b/cc/library_test.go @@ -17,6 +17,8 @@ package cc import ( "reflect" "testing" + + "android/soong/android" ) func TestLibraryReuse(t *testing.T) { @@ -186,3 +188,55 @@ func TestLibraryReuse(t *testing.T) { } }) } + +func TestStubsVersions(t *testing.T) { + bp := ` + cc_library { + name: "libfoo", + srcs: ["foo.c"], + stubs: { + versions: ["29", "R", "10000"], + }, + } + ` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.Platform_version_active_codenames = []string{"R"} + ctx := testCcWithConfig(t, config) + + variants := ctx.ModuleVariantsForTests("libfoo") + for _, expectedVer := range []string{"29", "9000", "10000"} { + expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer + if !inList(expectedVariant, variants) { + t.Errorf("missing expected variant: %q", expectedVariant) + } + } +} + +func TestStubsVersions_NotSorted(t *testing.T) { + bp := ` + cc_library { + name: "libfoo", + srcs: ["foo.c"], + stubs: { + versions: ["29", "10000", "R"], + }, + } + ` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.Platform_version_active_codenames = []string{"R"} + testCcErrorWithConfig(t, `"libfoo" .*: versions: not sorted`, config) +} + +func TestStubsVersions_ParseError(t *testing.T) { + bp := ` + cc_library { + name: "libfoo", + srcs: ["foo.c"], + stubs: { + versions: ["29", "10000", "X"], + }, + } + ` + + testCcError(t, `"libfoo" .*: versions: SDK version should be`, bp) +} diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 00338b953..eb8e9d3be 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -96,6 +96,8 @@ type libraryProperties struct { Unversioned_until *string // Private property for use by the mutator that splits per-API level. + // can be one of or or "current" + // passed to "gen_stub_libs.py" as it is ApiLevel string `blueprint:"mutated"` // True if this API is not yet ready to be shipped in the NDK. It will be