Search code examples
androidc++android-ndkjava-native-interfacejnienv

Why does the Android jvm->GetEnv() return the same "env" for multiple threads.?


I'm using jvm->GetEnv(&envThread, JNI_VERSION_1_6) to get the "env" for multple threads in order to make multiple envThread->GetMethodID() calls. Both threads are properly attached to the JVM.

I call the function returned by "GetMethodID()" on the first thread with no problems, but when the second thread attemps the call I see this message:

art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: thread Thread[13,tid=8207,Native,Thread*=0xaed08400,peer=0x12dcd080,"Thread-10224"]
  using JNIEnv* from thread Thread[1,tid=8148,Runnable,Thread*=0xb4e07800,peer=0x87bc5ef0,"main"]

A/art(8148): art/runtime/check_jni.cc:65 in call to CallVoidMethodV
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] "Thread-10224" prio=10 tid=13 Runnable
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] group="main" sCount=0 dsCount=0 obj=0x12dcd080 self=0xaed08400
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] sysTid=8207 nice=-11 cgrp=apps sched=0/0 handle=0xafb18b00
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] state=R schedstat=( 17710887 6014947 64 ) utm=1 stm=0 core=3 HZ=100
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65]   | stack=0xaee04000-0xaee06000 stackSize=1012KB

Because my call to jvm->getEnv() returns JNI_OK for the second thread, it is already attached (as expected). But what isn't expected is that the JniENV returned is exactly the same as the one from the first thread. Thus causing the crash.

Has anyone seen this sort of thing before? I'm quite lost for what to do...

Thanks.


Solution

  • I think you should be using AttachCurrentThread from the other thread.

    Here's a similar question on SO:

    void callback(int val) {
        JNIEnv * g_env;
        // double check it's all ok
        int getEnvStat = g_vm->GetEnv((void **)&g_env, JNI_VERSION_1_6);
        if (getEnvStat == JNI_EDETACHED) {
            std::cout << "GetEnv: not attached" << std::endl;
            if (g_vm->AttachCurrentThread((void **) &g_env, NULL) != 0) {
                std::cout << "Failed to attach" << std::endl;
            }
        } else if (getEnvStat == JNI_OK) {
            //
        } else if (getEnvStat == JNI_EVERSION) {
            std::cout << "GetEnv: version not supported" << std::endl;
        }
    
        g_env->CallVoidMethod(g_obj, g_mid, val);
    
        if (g_env->ExceptionCheck()) {
            g_env->ExceptionDescribe();
        }
    
        g_vm->DetachCurrentThread();
    }