我怎样才能捕获SIGSEGV(分段错误),并得到在Android上的JNI下的堆栈跟踪?
我将项目移动到新的Android本地开发工具包(即JNI),我想赶上SIGSEGV,如果它发生(也可能是SIGILL,SIGABRT,SIGFPE),以提供一个很好的崩溃报告对话框,而不是(或之前)目前发生的事情:该进程的直接不必要的死亡,以及操作系统可能尝试重启该进程。 ( 编辑: JVM / Dalvik虚拟机捕捉信号并logging堆栈跟踪和其他有用的信息;我只是想提供给用户的选项,真正的电子邮件信息给我)。
情况是:大量的C代码我没有写在这个应用程序的大部分工作(所有的游戏逻辑),虽然它在许多其他平台上经过了充分的testing,但是我完全有可能在我的Android端口,会喂它垃圾并导致在本机代码崩溃,所以我想崩溃转储(本机和Java),目前在Android日志中显示(我想这将是在非Android情况下stderr)。 我可以自由地修改C和Java代码,尽pipecallback函数(进出JNI)的数量大约为40,显然,小差异的奖励点。
我听说过J2SE中的信号链接库libjsig.so,如果我可以在Android上安全地安装一个信号处理程序,这将解决我的问题的捕捉部分,但是我看不到Android / Dalvik这样的库。
编辑:从果冻豆开始,你不能得到堆栈跟踪,因为READ_LOGS
消失了 。 🙁
我实际上得到了一个信号处理程序,没有做任何异乎寻常的事情,并已经发布了代码,你可以在github上看到(编辑:链接到历史版本;我从那时起删除了crash程序)。 就是这样:
- 使用
sigaction()
来捕获信号并存储旧的处理程序。 ( android.c:570 ) - 时间stream逝,段落发生。
- 在信号处理程序中,最后一次调用JNI,然后调用旧的处理程序。 ( android.c:528 )
- 在那个JNI调用中,logging任何有用的debugging信息,并且对被标记为需要在其自己的进程中的活动调用
startActivity()
。 ( SGTPuzzles.java:962,AndroidManifest.xml:28 ) - 当你从Java回来,并调用旧的处理程序,Android框架将连接到
debuggerd
为您logging一个很好的原生跟踪,然后过程将会死亡。 ( debugger.c , debuggerd.c ) - 同时,您的碰撞处理活动正在启动。 真的,你应该通过它的PID,所以它可以等待第5步完成; 我不这样做。 在这里你向用户道歉,并询问你是否可以发送日志。 如果是这样的话,请收集
logcat -d -v threadtime
的输出,并启动一个ACTION_SEND
,收件人,主题和正文填充。用户将不得不按下发送。 ( CrashHandler.java , SGTPuzzles.java : 462 , strings.xml:41 - 注意
logcat
失败或需要几秒钟。 我遇到过一个设备,T-Mobile Pulse / Huawei U8220,logcat马上进入T
(跟踪)状态并挂起。 ( CrashHandler.java:70,strings.xml:51 )
在非Android情况下,其中一些情况会有所不同。 你需要收集你自己的本地跟踪,看看这个问题 ,这取决于你有什么样的libc。 您需要处理转储跟踪,启动单独的崩溃处理程序进程,并以适当的方式为您的平台发送电子邮件,但是我认为一般方法仍然可行。
我有点晚了,但我有完全相同的需求,我已经开发了一个小型库来解决它,通过在JNI代码中捕获常见的崩溃( SEGV
, SIBGUS
等),并用普通的java.lang.Error
代替它们java.lang.Error
exception 。 附加的,如果客户端在Android> = 4.1.1
上运行,堆栈跟踪会embedded崩溃的parsing回溯 (包含完整本地堆栈跟踪的伪跟踪)。 你不会从恶性的崩溃中恢复过来(例如,如果你损坏了分配器),但是至less它应该允许你从大多数崩溃中恢复过来。 (请报告成功和失败,代码是全新的)
更多信息在https://github.com/xroche/coffeecatch (代码是BSD 2-clause license )
FWIW, Google Breakpad在Android上运行良好。 我做了移植工作,我们将其作为Firefox Mobile的一部分发布。 它需要一些设置,因为它不会给你在客户端的堆栈跟踪,而是向你发送原始的堆栈内存,并执行栈走在服务器端(所以你不必在你的应用程序中运送debugging符号)。
在我有限的经验(非Android)中,JNI代码中的SIGSEGV通常会在控制返回到Java代码之前使JVM崩溃。 我隐约听到有些非Sun的JVM可以让你抓住SIGSEGV,但AFAICR你不能指望能够这样做。
尽pipe在SIGSEGV(或SIGFPE或SIGILL)处理程序之后,你可以做很less的事情,因为进程的正在进行的行为是正式的未定义的,你可以尝试用C来捕捉它们(见sigaction(2))。