Stop versioning NDK stubs pre-M.

Test: make ndk # readelf various stubs to check version info
Bug: https://github.com/android-ndk/ndk/issues/622
Change-Id: Ic2930cfe5ee8377bb89bfb1bc051b6975f6e57d3
Merged-In: Ic2930cfe5ee8377bb89bfb1bc051b6975f6e57d3
(cherry picked from commit c229f38e93da71bcf9beca3683f5a603b7dd3bca)
diff --git a/android/api_levels.go b/android/api_levels.go
index b1b954c..1b56625 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -16,6 +16,7 @@
 
 import (
 	"encoding/json"
+	"strconv"
 )
 
 func init() {
@@ -50,28 +51,48 @@
 	return PathForOutput(ctx, "api_levels.json")
 }
 
-func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
-	baseApiLevel := 9000
-	apiLevelsMap := map[string]int{
-		"G":     9,
-		"I":     14,
-		"J":     16,
-		"J-MR1": 17,
-		"J-MR2": 18,
-		"K":     19,
-		"L":     21,
-		"L-MR1": 22,
-		"M":     23,
-		"N":     24,
-		"N-MR1": 25,
-		"O":     26,
-		"O-MR1": 27,
-		"P":     28,
-	}
-	for i, codename := range ctx.Config().PlatformVersionCombinedCodenames() {
-		apiLevelsMap[codename] = baseApiLevel + i
-	}
+func getApiLevelsMap(config Config) map[string]int {
+	return config.Once("ApiLevelsMap", func() interface{} {
+		baseApiLevel := 9000
+		apiLevelsMap := map[string]int{
+			"G":     9,
+			"I":     14,
+			"J":     16,
+			"J-MR1": 17,
+			"J-MR2": 18,
+			"K":     19,
+			"L":     21,
+			"L-MR1": 22,
+			"M":     23,
+			"N":     24,
+			"N-MR1": 25,
+			"O":     26,
+			"O-MR1": 27,
+			"P":     28,
+		}
+		for i, codename := range config.PlatformVersionCombinedCodenames() {
+			apiLevelsMap[codename] = baseApiLevel + i
+		}
 
+		return apiLevelsMap
+	}).(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.
+func ApiStrToNum(ctx BaseContext, apiLevel string) (int, error) {
+	num, ok := getApiLevelsMap(ctx.Config())[apiLevel]
+	if ok {
+		return num, nil
+	}
+	return strconv.Atoi(apiLevel)
+}
+
+func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
+	apiLevelsMap := getApiLevelsMap(ctx.Config())
 	apiLevelsJson := GetApiLevelsJson(ctx)
 	createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap)
 }
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 5a76666..db96325 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -156,11 +156,11 @@
 	return strconv.Atoi(firstSupportedVersion)
 }
 
-func shouldUseVersionScript(stub *stubDecorator) (bool, error) {
-	// unversioned_until is normally empty, in which case we should use the version script.
-	if String(stub.properties.Unversioned_until) == "" {
-		return true, nil
-	}
+func shouldUseVersionScript(ctx android.BaseContext, stub *stubDecorator) (bool, error) {
+	// https://github.com/android-ndk/ndk/issues/622
+	// The loader spews warnings to stderr on L-MR1 when loading a library that
+	// has symbol versioning.
+	firstVersionSupportingRelease := 23
 
 	if String(stub.properties.Unversioned_until) == "current" {
 		if stub.properties.ApiLevel == "current" {
@@ -174,16 +174,31 @@
 		return true, nil
 	}
 
-	unversionedUntil, err := strconv.Atoi(String(stub.properties.Unversioned_until))
+	version, err := android.ApiStrToNum(ctx, stub.properties.ApiLevel)
 	if err != nil {
 		return true, err
 	}
 
-	version, err := strconv.Atoi(stub.properties.ApiLevel)
+	// unversioned_until is normally empty, in which case we use the version
+	// script as long as we are on a supported API level.
+	if String(stub.properties.Unversioned_until) == "" {
+		return version >= firstVersionSupportingRelease, nil
+	}
+
+	unversionedUntil, err := android.ApiStrToNum(ctx, String(stub.properties.Unversioned_until))
 	if err != nil {
 		return true, err
 	}
 
+	if unversionedUntil < firstVersionSupportingRelease {
+		return true, fmt.Errorf("unversioned_until must be at least %d",
+			firstVersionSupportingRelease)
+	}
+
+	if version < firstVersionSupportingRelease {
+		return false, nil
+	}
+
 	return version >= unversionedUntil, nil
 }
 
@@ -318,7 +333,7 @@
 func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
 	objs Objects) android.Path {
 
-	useVersionScript, err := shouldUseVersionScript(stub)
+	useVersionScript, err := shouldUseVersionScript(ctx, stub)
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
 	}