有没有办法强制 Java VM 立即执行从 JNI 发送的异常?

Posted

技术标签:

【中文标题】有没有办法强制 Java VM 立即执行从 JNI 发送的异常?【英文标题】:Is there a way to force Java VM to execute immediately an exception sent from JNI? 【发布时间】:2019-11-01 11:05:03 【问题描述】:

我需要从主 jni 线程发送一个 Java 异常。我使用以下代码来做这样的事情:

if (vm->AttachCurrentThread(reinterpret_cast<void **>(&env), nullptr) != JNI_OK || env == nullptr) 
    std::cerr << "Get env for current thread failed.\n";
    return ;

jclass exClass = env->FindClass("[JavaClassName]");
if (exClass != nullptr) 
    env->ThrowNew(exClass, "[ExceptionMessage]");

env->DeleteLocalRef(exClass);
vm->DetachCurrentThread();

它以某种方式起作用。我发现如果我们不使用附加和分离(只使用抛出),那么只有在 Java VM 的 jni 调用完成后才会引发异常。如果我们使用附加和分离,那么在分离调用中会引发异常。这是使事情更快的正确方法吗?我仍然不明白为什么将异常处理推迟到调用 DetachCurrentThread() 之前?我用安卓。非常感谢。

【问题讨论】:

【参考方案1】:

当您在 JNI 代码中时,附加到当前线程的 Java 解释器没有运行。因此无法在 Java 端处理异常(展开堆栈帧、捕获等)。 Java 异常被创建为待处理,并且仅在 JNI 调用返回 Java 并且解释器继续执行当前 Java 线程时才真正抛出。

分离会伪造这个过程,但可能会使您的 JNI 代码处于不稳定状态:Java 正在运行,JNI 尚未返回并且仍在运行您的代码。

我首选的解决方案是像您一样抛出 Java 异常并立即抛出一个 C++ 异常,该异常仅(并且必须)在 JNI 边界处捕获并被丢弃。抛出 C++ 异常纯粹是为了导致堆栈展开和从 JNI 调用中快速干净退出。

【讨论】:

我的实验表明 JNI 在 detach 调用时停止运行。 Logcat 显示了 Java 和 C++ 的正确回溯,但在 Java 中无法捕获此异常。 :( @vollitwr As DetachCurrentThread 返回结果 "..成功时返回 JNI_OK;失败时返回合适的 JNI 错误代码(负数)......"我看不出这会如何导致 JNI 线程退出。它将被记录为 "does not return" 或类似的。 我在分离之前和之后对 android 日志进行了写入。只有前者写。这意味着 JNI 在 detach 调用中停止。

以上是关于有没有办法强制 Java VM 立即执行从 JNI 发送的异常?的主要内容,如果未能解决你的问题,请参考以下文章

如何将数组从 JNI 返回到 Java?

我可以创建一个从Java调用的Boost c ++光纤的JNI调用吗? [重复]

转:Delphi10.3 中通过JNI调用 Java 函数

如何在android的jni线程中实现回调

Android JNI 学习:JNI 简介

IDEA - 强制更新maven依赖,立即生效的办法