我开发了一个使用本地C库的Android应用程序。 我可以成功地使用JNI编译整个项目,一切都运行顺利。然而,时不时地,本地C库会崩溃(最常见的是SIGSEGV)。这反过来会导致我的应用程序崩溃,对用户没有任何有意义的通知。我想要实现以下目标:
我已经检查过http://blog.httrack.com/blog/2013/08/23/catching-posix-signals-on-android/和https://github.com/xroche/coffeecatch,但我无法将其编译。
当我的本地C代码发生SIGILL时,会出现以下情况:
1)在我的调试终端上,我会收到以下四条消息:
我真的不明白为什么我会收到第三和第四个信号消息,因为我认为异常已经被抛出。此外,我认为异常实际上从未被真正抛出(到Java)。
我很困惑,非常感谢任何帮助。
- 使用信号处理程序(sigaction)在本地代码中捕获信号,以防止随机崩溃
- 在C库中抛出Java可以捕获的异常
- 在Java中捕获异常,为用户生成有意义的警告消息并保持应用程序运行
我已经检查过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 Java以及https://www.developer.com/java/data/exception-handling-in-jni.html的建议,我执行了以下步骤:
在我的本地代码中,我添加了以下函数(据我理解)设置一个信号处理程序:
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
}
当我的本地C代码发生SIGILL时,会出现以下情况:
1)在我的调试终端上,我会收到以下四条消息:
- Sighandler: 4(对应SIGILL)
- 抛出异常
- Sighandler: 4
- Sighandler: 11
我真的不明白为什么我会收到第三和第四个信号消息,因为我认为异常已经被抛出。此外,我认为异常实际上从未被真正抛出(到Java)。
我很困惑,非常感谢任何帮助。
ThrowNew
听起来像是会尝试分配一些内存)在C++中被认为是未定义行为。我知道这是C语言,但很可能类似的限制也适用于那里。 - Michael