【发布时间】:2015-05-07 15:37:22
【问题描述】:
我开发了一个 Java 工具,它有很多 JNI 函数,我经常遇到 JNI 崩溃。是否有可能避免这些崩溃或将这些崩溃作为异常捕获。我在网上冲浪,发现可以通过信号处理、信号通道、sigaction() 等。但我找不到可靠的来源来指导我。请在这方面指导我。
【问题讨论】:
标签: java c exception-handling java-native-interface signal-handling
我开发了一个 Java 工具,它有很多 JNI 函数,我经常遇到 JNI 崩溃。是否有可能避免这些崩溃或将这些崩溃作为异常捕获。我在网上冲浪,发现可以通过信号处理、信号通道、sigaction() 等。但我找不到可靠的来源来指导我。请在这方面指导我。
【问题讨论】:
标签: java c exception-handling java-native-interface signal-handling
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_OnLoad 中。
Sample.java ` Sample{` ` native void callJavatoC();` } Sample.C JNIEXPORT void Java_Class_callJavatoC(JNIEnv* env, jobject obj) { "发生崩溃的地方" }`
JNI_OnLoad 的开头。然后当崩溃发生时,您的代码会从adb logcat 或磁盘上的文件中获取信息,这取决于您的选择。