FATAL Error in native method: Using JNIEnv in non-java thread

I'm implementing some JNI callback (native -> java) functionality alongside another larger native framework and on one of the framework's callbacks I'm getting this error when trying to callback to java.

FATAL Error in native method: Using JNIEnv in non-java thread

What exactly does this mean? What is a java-thread and how do I go about using JNI in another native thread?

Upvotes: 2

Views: 2093

Answers (1)

Java must be attached to the thread on which it is to be executing.

The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread need to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method.

To do this, you must store a pointer to the JVM object, either through the JNI_OnLoad() export or by storing it via a JNI native call you've implemented using (JNIEnv*)java->GetJavaVm(&(JavaVM*)jvm);.

From there, each time you need to use JNI, simply call the following in order to attach to the current thread and retrieve a new JNIEnv* pointer.

JNIEnv* AttachJava()
{
    JavaVMAttachArgs args = {JNI_VERSION_1_2, 0, 0};
    JNIEnv* java;
    jvm->AttachCurrentThread((void**) &java, &args);
    return java;
}

Do not save instances of JNIEnv* unless you are sure they will be referenced in the same thread.

As the documentation states, calling AttachCurrentThread on an already attached thread is a no-op and thus is innocuous.

Upvotes: 8

Related Questions