app: make GoNativeActivity.getKey static

The input queue runs concurrent with the native activity lifecycle,
and so the getKey helper Java method might be called after the
app has been destroyed. This is particularly likely for "back"
key presses that destroys activities.

Change the getKey method to be static so that it can be called
outside the app lifecycle.

Run `go generate ./cmd/gomobile` to update the compiled dex file that
contains GoNativeActivity.

Fixes golang/go#27652

Change-Id: Id2c863ee07e5447f033e67d6948fbfe746916ffa
Reviewed-on: https://go-review.googlesource.com/135215
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/app/GoNativeActivity.java b/app/GoNativeActivity.java
index 7017853..e829c8c 100644
--- a/app/GoNativeActivity.java
+++ b/app/GoNativeActivity.java
@@ -21,7 +21,7 @@
 		return getCacheDir().getAbsolutePath();
 	}
 
-	int getRune(int deviceId, int keyCode, int metaState) {
+	static int getRune(int deviceId, int keyCode, int metaState) {
 		try {
 			int rune = KeyCharacterMap.load(deviceId).get(keyCode, metaState);
 			if (rune == 0) {
diff --git a/app/android.c b/app/android.c
index bde2592..0ceb9f6 100644
--- a/app/android.c
+++ b/app/android.c
@@ -15,7 +15,7 @@
 #define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "Go", __VA_ARGS__)
 #define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Go", __VA_ARGS__)
 
-static jobject current_ctx;
+static jclass current_class;
 
 static jclass find_class(JNIEnv *env, const char *class_name) {
 	jclass clazz = (*env)->FindClass(env, class_name);
@@ -37,6 +37,16 @@
 	return m;
 }
 
+static jmethodID find_static_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
+	jmethodID m = (*env)->GetStaticMethodID(env, clazz, name, sig);
+	if (m == 0) {
+		(*env)->ExceptionClear(env);
+		LOG_FATAL("cannot find method %s %s", name, sig);
+		return 0;
+	}
+	return m;
+}
+
 static jmethodID key_rune_method;
 
 jint JNI_OnLoad(JavaVM* vm, void* reserved) {
@@ -63,16 +73,15 @@
 		JNIEnv* env = activity->env;
 
 		// Note that activity->clazz is mis-named.
-		current_ctx = activity->clazz;
+		current_class = (*env)->GetObjectClass(env, activity->clazz);
+		current_class = (*env)->NewGlobalRef(env, current_class);
+		key_rune_method = find_static_method(env, current_class, "getRune", "(III)I");
 
-		jclass clazz = (*env)->GetObjectClass(env, current_ctx);
-		key_rune_method = find_method(env, clazz, "getRune", "(III)I");
-
-		setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, current_ctx));
+		setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz));
 
 		// Set TMPDIR.
-		jmethodID gettmpdir = find_method(env, clazz, "getTmpdir", "()Ljava/lang/String;");
-		jstring jpath = (jstring)(*env)->CallObjectMethod(env, current_ctx, gettmpdir, NULL);
+		jmethodID gettmpdir = find_method(env, current_class, "getTmpdir", "()Ljava/lang/String;");
+		jstring jpath = (jstring)(*env)->CallObjectMethod(env, activity->clazz, gettmpdir, NULL);
 		const char* tmpdir = (*env)->GetStringUTFChars(env, jpath, NULL);
 		if (setenv("TMPDIR", tmpdir, 1) != 0) {
 			LOG_INFO("setenv(\"TMPDIR\", \"%s\", 1) failed: %d", tmpdir, errno);
@@ -180,9 +189,9 @@
 }
 
 int32_t getKeyRune(JNIEnv* env, AInputEvent* e) {
-	return (int32_t)(*env)->CallIntMethod(
+	return (int32_t)(*env)->CallStaticIntMethod(
 		env,
-		current_ctx,
+		current_class,
 		key_rune_method,
 		AInputEvent_getDeviceId(e),
 		AKeyEvent_getKeyCode(e),
diff --git a/cmd/gomobile/dex.go b/cmd/gomobile/dex.go
index 946497e..ff844b3 100644
--- a/cmd/gomobile/dex.go
+++ b/cmd/gomobile/dex.go
@@ -6,7 +6,7 @@
 
 package main
 
-var dexStr = `ZGV4CjAzNQDLd99M/fS0PS92C6RiRJwxvmoe+xpwV/GQCAAAcAAAAHhWNBIAAAAAAAAAAP` +
+var dexStr = `ZGV4CjAzNQAoeJK42wHKtxuGg5UGeZAqfLMlHcB49+eQCAAAcAAAAHhWNBIAAAAAAAAAAP` +
 	`AHAAAxAAAAcAAAABEAAAA0AQAADwAAAHgBAAACAAAALAIAABMAAAA8AgAAAQAAANQCAACc` +
 	`BQAA9AIAAHIEAAB6BAAAfgQAAJUEAACYBAAAnQQAAKMEAACoBAAArgQAALEEAAC1BAAAuQ` +
 	`QAAL4EAADcBAAA/QQAABcFAAA6BQAAXwUAAHQFAACIBQAAvQUAAN0FAADtBQAABAYAABgG` +
@@ -20,12 +20,12 @@
 	`AAAAEADQAwAAAAAwAEACQAAAAFAAYAIgAAAAYACwAoAAAABwACAB4AAAAHAAMAHgAAAAkA` +
 	`AAAgAAAACQAIACsAAAAKAAoAIQAAAA0ADgAsAAAADwAMAAAAAAAPAAkAIwAAAA8ABQAlAA` +
 	`AADwAHACYAAAAPAAEAJwAAAA8ACgApAAAADwAMACsAAAAPAA0AMAAAAA8AAAABAAAAAQAA` +
-	`AAAAAAACAAAAAAAAANIHAAAAAAAAAQABAAEAAACeBwAABgAAAHAQAAAAAGkAAQAOAAQAAQ` +
-	`ADAAEApQcAADMAAABuEA4AAwAMAG4QDQADAAwBbhACAAEADAETAoAAbjADABACDABUAQAA` +
-	`OQEKABoAAQAaAS4AcSAFABAADgBUAAAAGgEdAG4gBAAQAAwAcRAKAAAAKPQNABoBAQAaAi` +
-	`0AcTAGACEAKOsAAAAAAAApAAEAAQELKggABAADAAEAtQcAABkAAAAS8HEQCAAFAAwBbjAH` +
-	`AGEHCgE5AQMADwABECj+DQEaAgEAGgMfAHEwBgAyASj1DQEo8wAAAQAAAAcAAQABAggXCw` +
-	`4AAAIAAQABAAAAxQcAAAkAAABuEAwAAQAMAG4QCQAAAAwAEQAAAAIAAgACAAAAygcAAAcA` +
+	`AAAAAAACAAAAAAAAANIHAAAAAAAAAQABAAEAAACeBwAABgAAAHAQAAAAAGkAAQAOAAcAAw` +
+	`ADAAEApQcAABkAAAAS8HEQCAAEAAwBbjAHAFEGCgE5AQMADwABECj+DQEaAgEAGgMfAHEw` +
+	`BgAyASj1DQEo8wAAAQAAAAcAAQABAggXCw4AAAQAAQADAAEAtQcAADMAAABuEA4AAwAMAG` +
+	`4QDQADAAwBbhACAAEADAETAoAAbjADABACDABUAQAAOQEKABoAAQAaAS4AcSAFABAADgBU` +
+	`AAAAGgEdAG4gBAAQAAwAcRAKAAAAKPQNABoBAQAaAi0AcTAGACEAKOsAAAAAAAApAAEAAQ` +
+	`ELKgIAAQABAAAAxQcAAAkAAABuEAwAAQAMAG4QCQAAAAwAEQAAAAIAAgACAAAAygcAAAcA` +
 	`AABwEBEAAABvIAEAEAAOAAAAAgAAAAAAAAADAAAAAAAAAAAAAAACAAAADAAMAAMAAAAMAA` +
 	`wADgAAAAIAAAACAAAAAQAAAAAAAAABAAAADAAAAAEAAAAGAAY8aW5pdD4AAkdvABVHb05h` +
 	`dGl2ZUFjdGl2aXR5LmphdmEAAUkAA0lJSQAESUlJSQADSUxMAARJTExMAAFMAAJMSQACTE` +
@@ -43,8 +43,8 @@
 	`dFBhY2thZ2VNYW5hZ2VyAAdnZXRSdW5lAAlnZXRTdHJpbmcACWdldFRtcGRpcgAQZ29OYX` +
 	`RpdmVBY3Rpdml0eQAEbG9hZAALbG9hZExpYnJhcnkAEmxvYWRMaWJyYXJ5IGZhaWxlZAAn` +
 	`bG9hZExpYnJhcnk6IG5vIG1hbmlmZXN0IG1ldGFkYXRhIGZvdW5kAAhtZXRhRGF0YQAIb2` +
-	`5DcmVhdGUAEAAHDjwtADEABw5Lo0xLfwJ7HYdLHgAaAwAAAAcdhzQCeywgHoMAFQAHDgBA` +
-	`AQAHDjw8AAEAAgMBCguBgAT0BQYCkAYPAJQHAQDoBwIBjAgAAA0AAAAAAAAAAQAAAAAAAA` +
+	`5DcmVhdGUAEAAHDjwtABoDAAAABx2HNAJ7LCAegwAxAAcOS6NMS38Cex2HSx4AFQAHDgBA` +
+	`AQAHDjw8AAEAAwIBCguBgAT0BQQIkAYCAuQGEADoBwIBjAgAAA0AAAAAAAAAAQAAAAAAAA` +
 	`ABAAAAMQAAAHAAAAACAAAAEQAAADQBAAADAAAADwAAAHgBAAAEAAAAAgAAACwCAAAFAAAA` +
 	`EwAAADwCAAAGAAAAAQAAANQCAAABIAAABQAAAPQCAAABEAAACAAAACwEAAACIAAAMQAAAH` +
 	`IEAAADIAAABQAAAJ4HAAAAIAAAAQAAANIHAAAAEAAAAQAAAPAHAAA=` +
diff --git a/cmd/gomobile/doc.go b/cmd/gomobile/doc.go
index ff7a964..e30c6f8 100644
--- a/cmd/gomobile/doc.go
+++ b/cmd/gomobile/doc.go
@@ -24,7 +24,7 @@
 	bind        build a library for Android and iOS
 	build       compile android APK and iOS app
 	clean       remove object files and cached gomobile files
-	init        build OpenAL for Android
+	init        install NDK toolchains and build OpenAL for Android
 	install     compile android APK and install on device
 	version     print version
 
@@ -124,11 +124,15 @@
 Clean removes object files and cached NDK files downloaded by gomobile init
 
 
-Build OpenAL for Android
+Install NDK toolchains and build OpenAL for Android
 
 Usage:
 
-	gomobile init -openal dir
+	gomobile init [-ndk dir] [-openal dir]
+
+If the -ndk flag is specified or the Android NDK is installed at
+$ANDROID_HOME/ndk-bundle, init will create NDK standalone toolchains
+for Android targets.
 
 If a OpenAL source directory is specified with -openal, init will
 build an Android version of OpenAL for use with gomobile build