【问题标题】:How to catch JNI Crashes as exceptions using Signal handling based mechanism in Java [duplicate]如何在Java中使用基于信号处理的机制将JNI崩溃作为异常捕获[重复]
【发布时间】:2015-05-07 15:37:22
【问题描述】:

我开发了一个 Java 工具,它有很多 JNI 函数,我经常遇到 JNI 崩溃。是否有可能避免这些崩溃或将这些崩溃作为异常捕获。我在网上冲浪,发现可以通过信号处理、信号通道、sigaction() 等。但我找不到可靠的来源来指导我。请在这方面指导我。

【问题讨论】:

    标签: java c exception-handling java-native-interface signal-handling


    【解决方案1】:

    JNI 异常被视为信号。您可以通过sigaction 设置信号处理程序,然后您可以尝试展开崩溃堆栈,例如通过libcorkscrew,将其保存在磁盘上。之后,您可以通过 JNI 接口调用 Java 方法来处理您保存的信息。

    示例:

    int watched_signals[] = { SIGABRT, SIGILL, SIGSEGV, SIGINT, SIGKILL };
    
    void sighandler_func(int sig, siginfo_t* sig_info, void* ptr)
    {
        // Dump the callstack by libcorkscrew
        ...
        // Call a JNI interface to process the stack info
        ...
    }
    
    struct sigaction sighandler;
    sighandler.sa_sigaction = &sighandler_func;
    sighandler.sa_mask = 0;
    sighandler.sa_flags = SA_SIGINFO | SA_ONSTACK;
    
    for(int signal : watched_signals)
    {
        sigaction(signal, &sighandler, nullptr);
    }
    

    假设您在 ndk 项目中加入了 libcorkscrew,那么您可以获得崩溃堆栈:

    #include <dlfcn.h>
    #include <ucontext.h>
    #include <corkscrew/backtrace.h>
    #include <backtrace-arch.h>
    
    void dump_stack(int sig, siginfo_t* sig_info, void* ptr)
    {
        const size_t BACKTRACE_FRAMES_MAX = 0xFF;
    
        static backtrace_frame_t frames[BACKTRACE_FRAMES_MAX];
        static backtrace_symbol_t symbols[BACKTRACE_FRAMES_MAX];
    
        map_info_t* const info = acquire_my_map_info_list();
        const ssize_t size = unwind_backtrace_signal_arch(sig_info, ptr, info, frames, 0, BACKTRACE_FRAMES_MAX);
        get_backtrace_symbols(frames, size, symbols);
    
        for (int i = 0; i < size; i++)
        {
            backtrace_symbol_t& symbol = symbols[i];
            // You could change the printf to fwrite if you want to save the info on disk
            printf("#%02d pc %08X  %s (%s+%d)",
                        i,
                        symbol.relative_pc,
                        symbol.map_name ? symbol.map_name : "<unknown>",
                        symbol.demangled_name ? symbol.demangled_name : symbol.symbol_name,
                        symbol.relative_pc - symbol.relative_symbol_addr);
        }
        free_backtrace_symbols(symbols, size);
        release_my_map_info_list(info);
    }
    

    即使您可以在处理完信号后继续程序,但我强烈建议您将信息保存在磁盘上并在下次启动应用程序时进行处理。因为大多数时候你的程序会在信号出现时失败。

    【讨论】:

    • 你能给出一个简单的示例代码或链接以更好地理解这个概念吗?
    • 既然您提到了 JNI,我想您的项目中涉及到了 NDK 项目。然后你可以将 sn-p 添加到任何 c/cpp 源代码中。在大多数情况下,您最好将其放在本机代码的入口点 JNI_OnLoad 中。
    • 感谢您的更新,我是 JNI 实现的新手。我无法理解。需要在我的代码中附加代码 sn-p 的位置? Sample.java ` Sample{` ` native void callJavatoC();` } Sample.C JNIEXPORT void Java_Class_callJavatoC(JNIEnv* env, jobject obj) { "发生崩溃的地方" }`
    • 如果你只是想调试你的原生代码,请参考 ndk-gdb:stackoverflow.com/questions/10534367/… 如果你想让你的应用程序捕捉到意外的原生崩溃尝试添加 sn-p 在JNI_OnLoad 的开头。然后当崩溃发生时,您的代码会从adb logcat 或磁盘上的文件中获取信息,这取决于您的选择。
    • 有什么方法可以使用 hs_err* 报告找出崩溃的原因吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    相关资源
    最近更新 更多