cmd/gomobile: add arg to set android api level

Fixes golang/go#31905

Change-Id: Icee0ece2e78028fa4afd8b273b86e4eed404d99a
Reviewed-on: https://go-review.googlesource.com/c/mobile/+/176077
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/cmd/gomobile/bind_androidapp.go b/cmd/gomobile/bind_androidapp.go
index 3b01adc..719e376 100644
--- a/cmd/gomobile/bind_androidapp.go
+++ b/cmd/gomobile/bind_androidapp.go
@@ -148,7 +148,7 @@
 	}
 	const manifestFmt = `<manifest xmlns:android="http://schemas.android.com/apk/res/android" package=%q>
 <uses-sdk android:minSdkVersion="%d"/></manifest>`
-	fmt.Fprintf(w, manifestFmt, "go."+pkgs[0].Name+".gojni", minAndroidAPI)
+	fmt.Fprintf(w, manifestFmt, "go."+pkgs[0].Name+".gojni", buildAndroidAPI)
 
 	w, err = aarwcreate("proguard.txt")
 	if err != nil {
@@ -365,7 +365,7 @@
 	defer sdkDir.Close()
 	fis, err := sdkDir.Readdir(-1)
 	if err != nil {
-		return "", fmt.Errorf("failed to find android SDK platform (min API level: %d): %v", minAndroidAPI, err)
+		return "", fmt.Errorf("failed to find android SDK platform (API level: %d): %v", buildAndroidAPI, err)
 	}
 
 	var apiPath string
@@ -376,7 +376,7 @@
 			continue
 		}
 		n, err := strconv.Atoi(name[len("android-"):])
-		if err != nil || n < minAndroidAPI {
+		if err != nil || n < buildAndroidAPI {
 			continue
 		}
 		p := filepath.Join(sdkDir.Name(), name)
@@ -387,8 +387,8 @@
 		}
 	}
 	if apiVer == 0 {
-		return "", fmt.Errorf("failed to find android SDK platform (min API level: %d) in %s",
-			minAndroidAPI, sdkDir.Name())
+		return "", fmt.Errorf("failed to find android SDK platform (API level: %d) in %s",
+			buildAndroidAPI, sdkDir.Name())
 	}
 	return apiPath, nil
 }
diff --git a/cmd/gomobile/build.go b/cmd/gomobile/build.go
index e19e041..c2f40c1 100644
--- a/cmd/gomobile/build.go
+++ b/cmd/gomobile/build.go
@@ -50,6 +50,9 @@
 Flag -iosversion sets the minimal version of the iOS SDK to compile against.
 The default version is 7.0.
 
+Flag -androidapi sets the Android API version to compile against.
+The default and minimum is 15.
+
 The -bundleid flag is required for -target ios and sets the bundle ID to use
 with the app.
 
@@ -230,6 +233,7 @@
 	buildWork       bool   // -work
 	buildBundleID   string // -bundleid
 	buildIOSVersion string // -iosversion
+	buildAndroidAPI int    // -androidapi
 )
 
 func addBuildFlags(cmd *command) {
@@ -239,6 +243,7 @@
 	cmd.flag.StringVar(&buildTarget, "target", "android", "")
 	cmd.flag.StringVar(&buildBundleID, "bundleid", "", "")
 	cmd.flag.StringVar(&buildIOSVersion, "iosversion", "7.0", "")
+	cmd.flag.IntVar(&buildAndroidAPI, "androidapi", minAndroidAPI, "")
 
 	cmd.flag.BoolVar(&buildA, "a", false, "")
 	cmd.flag.BoolVar(&buildI, "i", false, "")
diff --git a/cmd/gomobile/doc.go b/cmd/gomobile/doc.go
index e160b5a..5061f4c 100644
--- a/cmd/gomobile/doc.go
+++ b/cmd/gomobile/doc.go
@@ -106,6 +106,9 @@
 Flag -iosversion sets the minimal version of the iOS SDK to compile against.
 The default version is 7.0.
 
+Flag -androidapi sets the Android API version to compile against.
+The default and minimum is 15.
+
 The -bundleid flag is required for -target ios and sets the bundle ID to use
 with the app.
 
diff --git a/cmd/gomobile/env.go b/cmd/gomobile/env.go
index c70b2a1..cb42d1c 100644
--- a/cmd/gomobile/env.go
+++ b/cmd/gomobile/env.go
@@ -83,6 +83,9 @@
 	// Setup the cross-compiler environments.
 	if ndkRoot, err := ndkRoot(); err == nil {
 		androidEnv = make(map[string][]string)
+		if buildAndroidAPI < minAndroidAPI {
+			return fmt.Errorf("gomobile requires Android API level >= %d", minAndroidAPI)
+		}
 		for arch, toolchain := range ndk {
 			clang := toolchain.Path(ndkRoot, "clang")
 			clangpp := toolchain.Path(ndkRoot, "clang++")
@@ -283,15 +286,23 @@
 type ndkToolchain struct {
 	arch        string
 	abi         string
+	minAPI      int
 	toolPrefix  string
 	clangPrefix string
 }
 
+func (tc *ndkToolchain) ClangPrefix() string {
+	if buildAndroidAPI < tc.minAPI {
+		return fmt.Sprintf("%s%d", tc.clangPrefix, tc.minAPI)
+	}
+	return fmt.Sprintf("%s%d", tc.clangPrefix, buildAndroidAPI)
+}
+
 func (tc *ndkToolchain) Path(ndkRoot, toolName string) string {
 	var pref string
 	switch toolName {
 	case "clang", "clang++":
-		pref = tc.clangPrefix
+		pref = tc.ClangPrefix()
 	default:
 		pref = tc.toolPrefix
 	}
@@ -312,27 +323,31 @@
 	"arm": {
 		arch:        "arm",
 		abi:         "armeabi-v7a",
+		minAPI:      16,
 		toolPrefix:  "arm-linux-androideabi",
-		clangPrefix: "armv7a-linux-androideabi16",
+		clangPrefix: "armv7a-linux-androideabi",
 	},
 	"arm64": {
 		arch:        "arm64",
 		abi:         "arm64-v8a",
+		minAPI:      21,
 		toolPrefix:  "aarch64-linux-android",
-		clangPrefix: "aarch64-linux-android21",
+		clangPrefix: "aarch64-linux-android",
 	},
 
 	"386": {
 		arch:        "x86",
 		abi:         "x86",
+		minAPI:      16,
 		toolPrefix:  "i686-linux-android",
-		clangPrefix: "i686-linux-android16",
+		clangPrefix: "i686-linux-android",
 	},
 	"amd64": {
 		arch:        "x86_64",
 		abi:         "x86_64",
+		minAPI:      21,
 		toolPrefix:  "x86_64-linux-android",
-		clangPrefix: "x86_64-linux-android21",
+		clangPrefix: "x86_64-linux-android",
 	},
 }
 
diff --git a/cmd/gomobile/init.go b/cmd/gomobile/init.go
index ed40230..0ada746 100644
--- a/cmd/gomobile/init.go
+++ b/cmd/gomobile/init.go
@@ -182,7 +182,7 @@
 		cmd := exec.Command(cmake,
 			initOpenAL,
 			"-DCMAKE_TOOLCHAIN_FILE="+initOpenAL+"/XCompile-Android.txt",
-			"-DHOST="+t.clangPrefix)
+			"-DHOST="+t.ClangPrefix())
 		cmd.Dir = buildDir
 		tcPath := filepath.Join(ndkRoot, "toolchains", "llvm", "prebuilt", archNDK(), "bin")
 		if !buildN {