我要搬家了 一个专案 到新的 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 的此类库。

有帮助吗?

解决方案

编辑: 从 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 为您记录一个很好的本机跟踪,然后该进程就会终止。(调试器.c, 调试器c)
  6. 与此同时,您的崩溃处理活动正在启动。实际上,您应该将 PID 传递给它,以便它可以等待步骤 5 完成;我不做这个。这里你向用户道歉并询问是否可以发送日志。如果是这样,收集输出 logcat -d -v threadtime 并启动一个 ACTION_SEND 填写收件人、主题和正文。用户必须按“发送”。(CrashHandler.java, SGTPuzzles.java:462, 字符串.xml:41
  7. 留意 logcat 失败或花费超过几秒钟。我遇到过一种设备,T-Mobile Pulse / 华为 U8220,logcat 立即进入 T (跟踪)状态并挂起。(CrashHandler.java:70, 字符串.xml:51)

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

其他提示

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

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

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top