为什么Android jvm-> GetEnv()为多个线程返回相同的“env”。

时间:2015-08-31 21:47:39

标签: android c++ android-ndk java-native-interface jnienv

我正在使用jvm->GetEnv(&envThread, JNI_VERSION_1_6)来获取多线程的“env”,以便进行多次envThread->GetMethodID()调用。两个线程都正确连接到JVM。

我在第一个线程上调用“GetMethodID()”返回的函数没有问题,但是当第二个线程尝试调用时,我看到了这样的消息:

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

因为我对jvm->getEnv()的调用为第二个线程返回JNI_OK,所以它已经附加(如预期的那样)。但是没有预料到的是JniENV的返回与第一个线程中的JniENV完全相同。从而导致崩溃。

以前有人见过这种事吗?我很遗憾该怎么做......

感谢。

3 个答案:

答案 0 :(得分:1)

我认为您应该使用其他帖子中的AttachCurrentThread

这是SO上的similar question

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();
}

答案 1 :(得分:0)

项目中的JNI代码可能不是为多任务编写的,而是将Java内容保存在静态变量中。我见过这样的代码。据我所知,在一个项目中,这些人有一些传统的C / C ++代码没有传递所有这些env参数,但在某些时候他们需要调用Java。在另一个项目中,据我所知,使用全局变量的原因是管理层在工程师向他们展示原型时开始销售的决定。如果您看到g_env等变量名称,则表明变量曾是全局变量。

另一方面,我没有看到你的代码,可能这个注释对后来的旁路者来说比对你更有意义。

答案 2 :(得分:0)

这是我们的代码库中的一个错误,它不是很明显。