【问题标题】:JNI call fails in driver callbackJNI 调用在驱动程序回调中失败
【发布时间】:2017-07-16 15:11:00
【问题描述】:

我正在开发一个与硬件设备交互的应用程序。使用硬件官方应用程序提供的 dll 文件,我初始化设备并注册一些函数作为回调,以便在某些用户交互时调用。在这个回调函数中,我想调用一个Java函数来传输数据。但是,整个应用程序在回调中的这个调用中退出,没有任何错误日志:

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

如果在 Java 直接调用的函数中执行相同的调用,则该调用有效。 这种行为的原因是什么?从设备驱动程序调用中调用 JNI 有何不同?任何帮助表示赞赏。

编辑:我尝试了 Vernee 的建议并尝试将驱动程序线程附加到 JVM,但是行为没有改变。此外,我丢失了printf 输出,不幸的是,这是我调试 JNI 端的唯一选择。它们在附加操作之前工作,但之后停止工作。

【问题讨论】:

标签: java windows java-native-interface


【解决方案1】:

如果你是在 Windows 上开发,我强烈建议你使用 Visual Studio 来调试 C 代码。您可以启动您的 java 程序并在 System.load 上放置一个断点,当 Java 程序在这一点停止时,转到 Visual Studio 并从工具 > 附加进程,这样您就可以在 C 代码中放置的断点处停止。之后,只需恢复 java 代码。从 C 线程调用 java 方法需要一些准备工作:

1- 缓存 JVM 对象

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

2- 缓存包含您的 java 回调方法的 Class 的 Class 对象。

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

3- 如果你调用实例方法,你还需要cahce被调用的实例

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

4- 将本机线程附加到虚拟机(当您需要调用 java 方法时)

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

5-获取你需要调用的方法ID(当你需要调用java方法时)

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

6- 进行方法调用

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

7- 分离原生线程

(*j_javaVm)->DetachCurrentThread(j_javaVm);

步骤 1,2 和 3 需要 java 环境,它们可以在 JNI_OnLoad 方法中完成,也可以在本机 Java 方法的实现中完成。

【讨论】:

  • 我提交了修改但未获批准。你能包括你的答案如何缓存 JVM 对象吗?当它存储在全局变量中时,它显然不起作用。我通过将它写入文件然后在驱动程序调用我的 C++ 回调时读取它来解决它。
猜你喜欢
  • 1970-01-01
  • 2021-09-26
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 2016-04-26
  • 1970-01-01
  • 2015-02-16
  • 2019-11-27
相关资源
最近更新 更多