Describe the bug
KeyboardMap::releaseKeyCharacterMap() always calls JavaVM::DetachCurrentThread() after deleting the KeyCharacterMap global ref. getJNIEnvFromJavaVM() only attaches when GetEnv returns JNI_EDETACHED; if the thread is already attached it just returns the existing JNIEnv and does not record that fact.
The documented call site is a NativeActivity command handler (APP_CMD_INIT_WINDOW / APP_CMD_DESTROY). That thread is already attached by android_native_app_glue before android_main runs, so VSG never attaches it, then releaseKeyCharacterMap() detaches the glue’s attach. Later JNI on the same thread (including the glue’s own cleanup DetachCurrentThread) can then see a detached env.
DeleteGlobalRef itself is paired with NewGlobalRef; the bug is only the unconditional detach.
To Reproduce
This is from source inspection of the documented Android path; no runtime log attached.
- NativeActivity app using
android_native_app_glue.
- On
APP_CMD_INIT_WINDOW, call KeyboardMap::initializeKeyCharacterMap(app->activity->vm) as documented in Android_Window.h.
- On
APP_CMD_DESTROY, call KeyboardMap::releaseKeyCharacterMap().
- That destroy path detaches the native thread even though VSG did not attach it.
Relevant code:
static JNIEnv* getJNIEnvFromJavaVM(JavaVM* vm)
{
jint ret = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (ret == JNI_EDETACHED)
ret = vm->AttachCurrentThread(&env, &args);
// JNI_OK: already attached, no flag returned
return env;
}
void KeyboardMap::releaseKeyCharacterMap()
{
if (classKeyCharacterMap)
{
JNIEnv* env = getJNIEnvFromJavaVM(javaVM);
if (env)
{
env->DeleteGlobalRef(classKeyCharacterMap);
classKeyCharacterMap = nullptr;
}
javaVM->DetachCurrentThread(); // always, even if this call did not Attach
}
}
Expected behavior
Detach only if this code attached the thread. getJNIEnvFromJavaVM should return whether it attached (e.g. bool* attached), and releaseKeyCharacterMap should call DetachCurrentThread only when that flag is true. initializeKeyCharacterMap / getUnicodeChar should follow the same rule.
Screenshots
N/A
Desktop (please complete the following information):
- OS: N/A (Android native)
- Browser: N/A
- Version: current
master (Android_Window.cpp KeyboardMap JNI helpers)
Smartphone (please complete the following information):
- Device: NativeActivity /
android_native_app_glue
- OS: Android
- Browser: N/A
- Version: N/A
Additional context
initializeKeyCharacterMap and getUnicodeChar never detach (attach-and-stay). Combined with an unconditional detach in releaseKeyCharacterMap, the intended NativeActivity usage is the mismatched path, not a rare edge case.
Describe the bug
KeyboardMap::releaseKeyCharacterMap()always callsJavaVM::DetachCurrentThread()after deleting theKeyCharacterMapglobal ref.getJNIEnvFromJavaVM()only attaches whenGetEnvreturnsJNI_EDETACHED; if the thread is already attached it just returns the existingJNIEnvand does not record that fact.The documented call site is a NativeActivity command handler (
APP_CMD_INIT_WINDOW/APP_CMD_DESTROY). That thread is already attached byandroid_native_app_gluebeforeandroid_mainruns, so VSG never attaches it, thenreleaseKeyCharacterMap()detaches the glue’s attach. Later JNI on the same thread (including the glue’s own cleanupDetachCurrentThread) can then see a detached env.DeleteGlobalRefitself is paired withNewGlobalRef; the bug is only the unconditional detach.To Reproduce
This is from source inspection of the documented Android path; no runtime log attached.
android_native_app_glue.APP_CMD_INIT_WINDOW, callKeyboardMap::initializeKeyCharacterMap(app->activity->vm)as documented inAndroid_Window.h.APP_CMD_DESTROY, callKeyboardMap::releaseKeyCharacterMap().Relevant code:
APP_CMD_INIT_WINDOW, release afterAPP_CMD_DESTROY)Expected behavior
Detach only if this code attached the thread.
getJNIEnvFromJavaVMshould return whether it attached (e.g.bool* attached), andreleaseKeyCharacterMapshould callDetachCurrentThreadonly when that flag is true.initializeKeyCharacterMap/getUnicodeCharshould follow the same rule.Screenshots
N/A
Desktop (please complete the following information):
master(Android_Window.cppKeyboardMap JNI helpers)Smartphone (please complete the following information):
android_native_app_glueAdditional context
initializeKeyCharacterMapandgetUnicodeCharnever detach (attach-and-stay). Combined with an unconditional detach inreleaseKeyCharacterMap, the intended NativeActivity usage is the mismatched path, not a rare edge case.