95

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

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

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

4

4 回答 4

83

编辑:从 Jelly Bean 开始,您无法获取堆栈跟踪,因为READ_LOGSgo away。:-(

我实际上得到了一个信号处理程序,没有做任何太奇特的事情,并且已经发布了使用它的代码,你可以在 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 / Huawei U8220,其中 logcat 立即进入T(跟踪)状态并挂起。(CrashHandler.java:70,strings.xml:51_ _

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

于 2009-11-24T12:49:12.870 回答
15

我有点晚了,但我有完全相同的需求,并且我开发了一个小型库来解决它,通过在JNI 代码SEGV中捕获常见的崩溃( ,SIBGUS等) ,并用常规异常替换它们。另外,如果客户端在 Android >= 上运行,堆栈跟踪会嵌入崩溃的已解决回溯(包含完整本机堆栈跟踪的伪跟踪)。您不会从恶性崩溃中恢复(例如,如果您破坏了分配器),但至少它应该允许您从大多数崩溃中恢复。(请报告成功和失败,代码是全新的)java.lang.Error 4.1.1

更多信息在https://github.com/xroche/coffeecatch (代码是BSD 2-Clauses license

于 2013-08-28T17:08:50.507 回答
6

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

于 2011-11-08T20:17:39.087 回答
5

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

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

于 2009-07-05T01:55:16.597 回答