This question already has an answer here:
ART prevents any Java calls from JNI during native signal handling

(1个答案)


2年前关闭。




我已经开发了使用 native C库的Android应用程序。我可以使用JNI成功地编译整个程序,并且一切都可以顺利进行。

但是, native C库有时会崩溃(使用SIGSEGV时最常见)。反过来,这导致我的应用程序崩溃,而对用户没有任何有意义的通知。我想实现以下目标:
  • 使用信号处理程序(sigaction)在 native 代码中捕获信号,以防止随机崩溃
  • 在C库中引发Java可以捕获
  • 的异常
  • 捕获Java中的异常,为用户生成有意义的警告消息,并保持应用程序运行

  • 如果这对您有用,则JNI代码在单独的线程中运行(更确切地说,在AsyncTask中)。

    我已经检查了http://blog.httrack.com/blog/2013/08/23/catching-posix-signals-on-android/https://github.com/xroche/coffeecatch
    但是我无法编译它。

    遵循Best way to throw exceptions in JNI code?How to catch JNI Crashes as exceptions using Signal handling based mechanism in Javahttps://www.developer.com/java/data/exception-handling-in-jni.html的建议
    我执行了以下步骤:

    在我的 native 代码中,我添加了以下函数(据我所知)设置了信号处理程序:
    void initializeSignalHandler(JNIEnv* env){
        int watched_signals[] = { SIGABRT, SIGILL, SIGSEGV, SIGINT, SIGKILL }; // 6, 4, 11, 2, 9
        struct sigaction sighandler;
        memset(&sighandler, 0, sizeof(sighandler));
    
        sighandler.sa_sigaction = &sighandler_func;
        sighandler.sa_mask = 0;
        sighandler.sa_flags = SA_SIGINFO | SA_ONSTACK;
        for(int ii=0; ii<5; ii++){
            int signal = watched_signals[ii];
            sigaction(signal, &sighandler, NULL);
        }
        env = env;
    }
    

    我处理这些信号的函数如下所示:
    void sighandler_func(int sig, siginfo_t* sig_info, void* ptr){
        printerr("Sighandler: ", sig);
        jclass jcls = (*env)->FindClass(env, "java/lang/Error");
        jboolean flag = (*env)->ExceptionCheck(env);
        if (flag) {
            (*env)->ExceptionClear(env);
            /* code to handle exception */
        }
        if (jcls!=NULL){
            printerr("Throwing exception");
            (*env)->ThrowNew(env, jcls, "error message");
        }
    }
    

    我关键的JNI功能首先从配置信号处理程序开始:
    JNIEXPORT jint JNICALL Java_android_playground_criticalFuction
        (JNIEnv *env, jclass c, jlong handle, jshortArray out_buffer){
    
    
        // new signal handler
        struct sigaction sighandler;
        initializeSignalHandler(env);
    
        // ...here goes the critical code
    }
    

    当我的 native C代码中出现SIGILL时,将发生以下情况:

    1)在调试终端上,我收到以下四个消息
  • Sighandler:4个(对应于SIGILL)
  • 抛出异常
  • Sighandler:4
  • Sighandler:11

  • 2)应用程序窗口关闭,但我没有收到Android消息
    应用程序崩溃时通常会出现“不幸...已关闭”

    我真的不明白为什么我得到第三和第四信号消息,因为我认为抛出了异常。另外,我认为从未真正向Java抛出异常。

    我迷路了,任何帮助将不胜感激。

    最佳答案

    我不知道您在这里尝试做什么在技术上是否可行。 @Michael的评论暗示不可能。

    但是,如果可能的话,这是一个坏主意。

    当您正在使用的 native 库触发SIGSEGV时,它很可能造成了无法估量的损失;例如覆盖堆中的对象,等等。如果尝试恢复,则先前的损坏可能会导致意外的行为或错误的结果……或者GC稍后会由于堆损坏而崩溃。

    这就是为什么在 native 代码或Java代码中发生意外的SIGSEGV时,JVM会 panic 的标准行为。

    给用户一个有意义的错误是很好的做法,但是如果您遇到随机的SIGSEGV错误和其他JVM紧急情况,您可以告诉他们并没有太大的意义。

    关于java - 在Android上按异常(exception)替换JNI崩溃,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47873847/

    10-11 22:35
    查看更多