我开发了一个使用本机C库的Android应用程序。我可以用JNI成功编译整个东西,一切顺利。
然而,偶尔本机C库崩溃(最常见的是SIGSEGV)。反过来,这会导致我的应用程序在没有任何有意义的用户通知的情况下崩溃。我想要实现的目标如下:
如果这对你有用 - 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 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)在我的调试终端上,我收到以下四条消息
2)应用程序窗口关闭,但我没有收到Android消息 “很遗憾......已关闭”,通常会在应用崩溃时出现
我真的不明白为什么我得到第三和第四个信号消息,因为我认为抛出了异常。另外,我认为异常永远不会被抛出(对Java)。
我迷失了,非常感谢任何帮助。
答案 0 :(得分:0)
我不知道您在这里尝试做什么在技术上是否可行。 @Michael的评论暗示不可能。
但是,如果可能的话,这是一个坏主意。
当您正在使用的本机库触发SIGSEGV时,它很可能造成了无法估量的损失;例如覆盖堆中的对象,等等。如果您尝试恢复,则先前的损坏很可能会导致意外的行为或错误的结果……或者GC稍后会由于堆损坏而崩溃。
这就是为什么在本机代码或Java代码中发生意外的SIGSEGV时,JVM会惊慌的标准行为。
虽然给用户一个有意义的错误是很好的,但是如果告诉您随机的SIGSEGV错误和其他JVM紧急情况,您可以告诉他们的意义不大。