如何捕获 SIGSEGV(分段错误)并在 Android 上的 JNI 下获取堆栈跟踪? [英] How can I catch SIGSEGV (segmentation fault) and get a stack trace under JNI on Android?

查看:19
本文介绍了如何捕获 SIGSEGV(分段错误)并在 Android 上的 JNI 下获取堆栈跟踪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将一个项目迁移到新的Android Native Development Kit(即JNI) 并且我想捕获 SIGSEGV,如果它发生(可能还有 SIGILL、SIGABRT、SIGFPE),以便呈现一个很好的崩溃报告对话框,而不是(或之前)当前发生的情况:进程立即无礼地死亡和操作系统可能会尝试重新启动它.( JVM/Dalvik VM 捕获信号并记录堆栈跟踪和其他有用信息;我只是想为用户提供将这些信息通过电子邮件发送给我的选项.)

I'm moving a project to the new Android Native Development Kit (i.e. JNI) and I'd like to catch SIGSEGV, should it occur (possibly also SIGILL, SIGABRT, SIGFPE) in order to present a nice crash reporting dialog, instead of (or before) what currently happens: the immediate unceremonious death of the process and possibly some attempt by the OS to restart it. ( The JVM/Dalvik VM catches the signal and logs a stack trace and other useful information; I just want to offer the user the option to email that info to me really.)

情况是:我没有编写的大量 C 代码在这个应用程序中完成了大部分工作(所有游戏逻辑),虽然它在许多其他平台上经过了很好的测试,但我完全有可能,在我的 Android 端口中,会给它提供垃圾并导致本机代码崩溃,所以我想要当前显示在 Android 日志中的崩溃转储(本机和 Java)(我猜在非 Android 情况下它会是 stderr).我可以随意修改 C 和 Java 代码,尽管回调(传入和传出 JNI)大约有 40 个,而且很明显,小差异的奖励积分.

The situation is: a large body of C code which I didn't write does most of the work in this application (all the game logic) and although it's well-tested on numerous other platforms, it's entirely possible that I, in my Android port, will feed it garbage and cause a crash in native code, so I want the crash dumps (both native and Java) that currently show up in the Android log (I guess it would be stderr in a non-Android situation). I'm free to modify both C and Java code arbitrarily, although the callbacks (both going in and coming out of JNI) number about 40 and obviously, bonus points for small diffs.

我听说过 J2SE 中的信号链库 libjsig.so,如果我可以在 Android 上安全地安装这样的信号处理程序,那将解决我的问题的关键部分,但我看不到这样的库安卓/达尔维克.

I've heard of the signal chaining library in J2SE, libjsig.so, and if I could safely install a signal handler like that on Android, that would solve the catching part of my question, but I see no such library for Android/Dalvik.

推荐答案

从 Jelly Bean 开始,您无法获取堆栈跟踪,因为 READ_LOGS 消失了.:-(

From Jelly Bean onwards you can't get the stack trace, because READ_LOGS went away. :-(

我实际上得到了一个信号处理程序,没有做任何太奇特的事情,并且已经发布了使用它的代码,你可以看到 在 github (链接到历史版本;从那时起我删除了崩溃处理程序).方法如下:

I actually got a signal handler working without doing anything too exotic, and have released code using it, which you can see on github (edit: linking to historical release; I removed the crash handler since then). Here's how:

  1. 使用 sigaction() 来捕获信号并存储旧的处理程序.(android.c:570)
  2. 时间过去了,发生了段错误.
  3. 在信号处理程序中,最后一次调用 JNI,然后调用旧处理程序.(android.c:528)
  4. 在该 JNI 调用中,记录任何有用的调试信息,然后调用 startActivity() 标记为需要在自己的进程中的活动.(SGTPuzzles.java:962AndroidManifest.xml:28)
  5. 当您从 Java 中返回并调用旧处理程序时,Android 框架将连接到 debuggerd 为您记录一个不错的本地跟踪,然后该进程将终止.(debugger.c, debuggerd.c)
  6. 与此同时,您的崩溃处理活动正在启动.真的,您应该将 PID 传递给它,以便它可以等待第 5 步完成;我不这样做.在这里您向用户道歉并询问您是否可以发送日志.如果是这样,请收集 logcat -d -v threadtime 的输出并启动一个 ACTION_SEND 并填写收件人、主题和正文.用户必须按发送.(CrashHandler.java, SGTPuzzles.java:462, strings.xml:41
  7. 注意 logcat 失败或耗时超过几秒钟.我遇到了一个设备,T-Mobile Pulse/Huawei U8220,其中 logcat 立即进入 T (跟踪)状态并挂起.(CrashHandler.java:70, strings.xml:51)
  1. Use sigaction() to catch the signals and store the old handlers. (android.c:570)
  2. Time passes, a segfault happens.
  3. In the signal handler, call up to JNI one last time and then call the old handler. (android.c:528)
  4. In that JNI call, log any useful debugging info, and call startActivity() on an activity that is flagged as needing to be in its own process. (SGTPuzzles.java:962, AndroidManifest.xml:28)
  5. When you come back from Java and call that old handler, the Android framework will connect to debuggerd to log a nice native trace for you, and then the process will die. (debugger.c, debuggerd.c)
  6. Meanwhile, your crash-handling activity is starting up. Really you should pass it the PID so it can wait for step 5 to complete; I don't do this. Here you apologise to the user and ask if you can send a log. If so, gather the output of logcat -d -v threadtime and launch an ACTION_SEND with recipient, subject and body filled in. The user will have to press Send. (CrashHandler.java, SGTPuzzles.java:462, strings.xml:41
  7. Watch out for logcat failing or taking more than a few seconds. I have encountered one device, the T-Mobile Pulse / Huawei U8220, where logcat immediately goes into the T (traced) state and hangs. (CrashHandler.java:70, strings.xml:51)

在非 Android 情况下,其中一些会有所不同.您需要收集自己的本地跟踪,请参阅 this other question,取决于您拥有的 libc 类型.您需要处理转储该跟踪,启动单独的崩溃处理程序进程,并以适合您平台的某些方式发送电子邮件,但我认为一般方法应该仍然有效.

In a non-Android situation, some of this would be different. You'd need to gather your own native trace, see this other question, depending on what sort of libc you have. You'd need to handle dumping that trace, launching your separate crash-handler process, and sending the email in some appropriate ways for your platform, but I imagine the general approach should still work.

这篇关于如何捕获 SIGSEGV(分段错误)并在 Android 上的 JNI 下获取堆栈跟踪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆