如何使用Java中基于信号处理的机制捕获JNI崩溃作为异常

时间:2015-05-07 15:37:23

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

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

1 个答案:

答案 0 :(得分: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);
}

假设您已将libcorkscrew纳入您的ndk项目,那么您可以获得崩溃堆栈:

#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);
}

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