I am modifying an existing library written in native C to get it to work on Android. To access some hardware elements, I need to use some Java functions. So, I'm using JNI to call Java functions from native C.
My approach is the the following:
- Use JNI_OnLoad to get a reference to the Java VM.
- Get the JNI environment (JNIEnv)
- Find the Java class using FindClass
- Create an instance of the Java class using NewObject
- Create a reference to the Java method I need to call.
Later on, I call a different function which actually calls the Java method using the previously stored reference. All objects and references are stored in global variables in order to initialize them on JNI_OnLoad and use them at the additional function.
The problem is that when I call the actual Java method I always get 0 (it should return an int). If I check for exceptions, it seems there is one but but I cannot see exactly what is creating the exception.
If I call the method from the JNI_OnLoad function, then it works. This makes me think that some reference is lost when the JNI_OnLoad function exits. I am converting all objects to global references but there must be still something getting lost.
Here is a minimal example of my setup. Any help will be highly appreciated.
Thanks!
JC
Native C:
JNIEnv *jni_env = NULL;
jclass jni_cls = NULL;
jobject jni_obj = NULL;
jmethodID jni_myJavaFunc= NULL;
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
(void)reserved;
jint ver = JNI_VERSION_1_6;
if (vm == NULL)
return JNI_ERR;
if ((*vm)->GetEnv(vm, (void **)&jni_env, ver) != JNI_OK)
return JNI_ERR;
jni_cls = (jclass)(*jni_env)->NewGlobalRef(jni_env, (*jni_env)->FindClass(jni_env, "org/java/MyJavaClass"));
if (jni_cls == NULL)
return JNI_ERR;
jmethodID init = (*jni_env)->GetMethodID(jni_env, jni_cls, "<init>", "()V");
if (init == NULL)
return JNI_ERR;
jni_obj = (*jni_env)->NewGlobalRef(jni_env, (*jni_env)->NewObject(jni_env, jni_cls, init));
if (jni_obj == NULL)
return JNI_ERR;
jni_myJavaFunc = (*jni_env)->GetMethodID(jni_env, jni_cls, "myJavaFunc", "()I");
return ver;
}
int myNativeFunc()
{
if (jni_myJavaFunc != NULL) {
(*jni_env)->ExceptionClear(jni_env);
int n = (*jni_env)->CallIntMethod(jni_env, jni_obj, jni_myJavaFunc);
if (!(*jni_env)->ExceptionCheck(jni_env))
return n;
else
return -1;
}
}
Java class:
public class MyJavaClass extends Activity
{
public MyJavaClass()
{
}
public int myJavaFunc()
{
return 1;
}
}