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

问题描述:

我正在将a project移动到新的Android本地开发工具包(即JNI),我想捕获SIGSEGV,如果它发生(可能还包括SIGILL,SIGABRT,SIGFPE),以便提供一个很好的崩溃报告对话框(或之前)发生的事情:进程的直接不必要的死亡,以及操作系统可能尝试重新启动它。 (编辑: JVM/Dalvik VM捕获信号并记录堆栈跟踪和其他有用信息;我只是想给用户提供将该信息发送给我的选项)如何在Android上的JNI下捕获SIGSEGV(分段错误)并获取堆栈跟踪?

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

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

+0

如果你可以通过一个包装脚本启动Java VM,你可以检查应用程序是否异常退出,并执行错误报告。这将允许你干净地捕捉各种异常退出,无论是SIGSEGV,SIGKILL或其他。不过,我认为这不适用于股票Android应用,因此将其作为评论发布(从答案转换而来)。 – sleske 2015-07-07 06:59:07

+0

另见:不能运行使用Valgrind的的Java的Android程序(http://*.com/questions/13531496/cant-run-a-java-android-program-with-valgrind/19235439#19235439)为如何使用包装脚本启动Android应用程序(在adb shell中)。 – sleske 2015-07-07 07:00:09

编辑:从果冻豆开始,你不能得到堆栈跟踪,因为READ_LOGS went away。 :-(

我居然得到了一个信号处理程序没有做任何事情太奇特的工作,并利用它,你可以看到on 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.javaSGTPuzzles.java:462strings.xml:41
  7. 当心logcat失败或服用超过几秒钟。我曾经遇到过一个装置,T-Mobile的脉冲/华为U8220,其中的logcat立即进入T(跟踪)状态和挂起(CrashHandler.java:70strings.xml:51

在非Android的情况下,一些这方面会有所不同。你需要收集自己的原生的跟踪,看到this other question,这取决于什么样的libc中你有你。需要处理转储跟踪,启动单独的崩溃处理程序进程,并以适当的方式为您的平台发送电子邮件,但我imagigi一般的方法应该仍然有效。

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

虽然在SIGSEGV(或SIGFPE或SIGILL)处理程序之后,您可以尝试用C捕获它们(请参阅sigaction(2)),因为进程的正在进行的行为尚未正式定义。

+0

那么,行为在“忽略不是由kill(2)或raise(3)产生的SIGFPE,SIGILL或SIGSEGV信号”之后未定义,但不一定在捕获这样的信号期间。目前的计划是尝试一个C语言处理程序,它调用回到Java,并以某种方式终止线程而不终止进程。这可能会也可能不会。 :-) – 2009-07-06 13:03:01

+1

Ç回溯说明:http://*.com/questions/76822/how-to-generate-a-stacktrace-when-my-c-app-crashes-using-gcc-compiler/77281#77281 – 2009-07-06 13:21:02

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

我是有点晚,但我有完全相同的需求,我已经开发了一个小型图书馆,以解决这一问题,通过捕捉内部JNI代码常见的崩溃(SEGVSIBGUS等),并通过常规取代java.lang.Error例外。奖金,如果客户端在Android运行> = 4.1.1,堆栈跟踪嵌入崩溃的解决回溯(含有完整的本地栈跟踪伪迹线)。你不会从恶性崩溃中恢复(例如,如果你损坏分配器),但至少它应该允许你从中恢复最多的。 (请举报成功和失败,代码是全新的)

更多信息以https://github.com/xroche/coffeecatch (代码BSD 2条款许可