1

I am developing an application that interacts with a hardware device. Using the dll file provided with the hardware's official application, I initialize the device and register some function as a callback to be called upon some user interaction. In this callback function, I want to call a Java function to transfer data. However, the whole application exits without any error log just at this call in the callback:

jclass cls = env->FindClass("java/lang/String");

The same call works if it is executed in the function that is called directly by Java. What is the reason of this behaviour? How does it make difference to call JNI from device driver calls? Any help is appreciated.

EDIT: I tried Vernee's suggestion and tried to attach the driver thread to JVM, however the behaviour didn't change. Moreover, I lost the printf outputs, which are -unfortunately- my only option to debug JNI side. They work before the attach operation, but stop working thereafter.

ram
  • 1,099
  • 1
  • 7
  • 22

1 Answers1

1

If you are developing on Windows, I strongly suggest you that you use visual studio to debug the C code. You can start your java program and place a breakpoint on System.load, when the Java program stops at this point, go to Visual studio and from tools > attach process, this way you can stop at breakpoints placed in the C code. After that just resume the java code. Calling a java method from C thread requires some preperation:

1- Cache JVM object

JavaVM * javaVm;
(*jenv)->GetJavaVM(jenv, &javaVm);

2- Cache the Class object of the Class that contains your java callback method.

clazz = (*jenv)->NewGlobalRef(jenv, (*jenv)->FindClass(jenv, "com/something/somepackage/SomeClass"));

3- If you are calling instance method, you will also need to cahce the instance being called

callback = (*jenv)->NewGlobalRef(jenv, callbackInstance);

4- Attach native thread to virtual machine (When you need to make the call to java method)

JNIEnv * jenv;
int errorCode = (*j_javaVm)->AttachCurrentThread(j_javaVm, (void**) &jenv, NULL);

5- Get the method ID you need to call (When you need to make the call to java method)

jmethodID methodID = (*jenv)->GetMethodID(jenv, cachedhandlerClass, "methodNameHere", "methodSignetureHere");

6- Make the method call

(*jenv)->CallVoidMethod(jenv, cachedCallbackInstance, methodID, param1, param2,....);

7- deattach the native thread

(*j_javaVm)->DetachCurrentThread(j_javaVm);

Steps 1,2 and 3 require a java environment and they can be done in JNI_OnLoad method or in the implementation of a native Java method.

Yazan Jaber
  • 2,068
  • 25
  • 36
  • I submitted an edit but it is not approved. Can you include your answer how to cache JVM object? It apparently didn't work when it is stored in a global variable. I solved it by writing it to a file and then reading it when the driver calls my C++ callback. – ram Jul 25 '17 at 18:17