如何在Android上的JNI下捕获SIGSEGV(分段错误)并获得堆栈跟踪?

Chr*_*yle 90 java-native-interface android signals segmentation-fault android-ndk

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

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

我听说过J2SE中的信号链接库,libjsig.so,如果我可以在Android上安全地安装这样的信号处理程序,这将解决我的问题的捕捉部分,但我看不到Android/Dalvik这样的库.

Chr*_*yle 81

编辑:从Jelly Bean开始,你无法获得堆栈跟踪,因为它READ_LOGS消失了.:-(

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

  1. 使用sigaction()捕捉到信号并存储旧的处理程序.(android.c:570)
  2. 时间过去了,发生了一个段错误.
  3. 在信号处理程序中,最后一次调用JNI然后调用旧处理程序.(android.c:528)
  4. 在该JNI调用中,记录任何有用的调试信息,并调用startActivity()标记为需要在其自己的进程中的活动.(SGTPuzzles.java:962,AndroidManifest.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 /华为U8220,其中logcat立即进入T(跟踪)状态并挂起.(CrashHandler.java:70,strings.xml中:51)

在非Android情况下,其中一些会有所不同.您需要收集自己的本机跟踪,请查看其他问题,具体取决于您拥有的libc类型.您需要处理转储跟踪,启动单独的崩溃处理程序进程,以及以适当的方式为您的平台发送电子邮件,但我认为一般方法仍然有效.

  • 从服务启动新进程中的活动还需要以下代码:`newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);` (3认同)
  • 理想情况下,您需要检查崩溃是否发生在您的库中.如果它发生在其他地方(例如,在VM内),那么来自信号处理程序的JNI调用可能会使事情变得非常混乱.这不是世界末日,因为你无论如何都处于崩溃中,但它可能会使VM崩溃的诊断更加困难(或导致一个奇怪的虚拟机崩溃,最终导致Android错误报告并让所有人感到困惑). (2认同)

小智 14

我是有点晚,但我有完全相同的需求,我已经开发了一个小型图书馆,以解决这一问题,通过捕捉常见的崩溃(SEGV,SIBGUS里面等)JNI代码,并定期更换他们java.lang.Error 的例外.奖励,如果客户端在Android> =上运行4.1.1,则堆栈跟踪会嵌入已解决的崩溃回溯(包含完整本机堆栈跟踪的伪跟踪).你不会从恶性崩溃中恢复(例如,如果你破坏了分配器),但至少它应该允许你从大多数崩溃中恢复.(请报告成功与失败,代码是全新的)

更多信息,访问https://github.com/xroche/coffeecatch (代码是BSD 2-Clauses许可证)


Ted*_*rek 6

FWIW,Google Breakpad在Android上运行良好.我做了移植工作,我们将它作为Firefox Mobile的一部分发布.它需要一些设置,因为它不会在客户端提供堆栈跟踪,但会向您发送原始堆栈内存并执行堆栈服务器端(因此您不必使用应用程序发送调试符号) ).


mas*_*s90 5

在我有限的经验(非Android)中,JNI代码中的SIGSEGV通常会在控制返回到Java代码之前使JVM崩溃.我依旧回忆起一些非Sun JVM,它可以让你捕获SIGSEGV,但AFAICR你不能指望能够这样做.

您可以尝试在C中捕获它们(请参阅sigaction(2)),尽管在SIGSEGV(或SIGFPE或SIGILL)处理程序之后您可以做很少的事情,因为正式未定义进程的持续行为.