如何捕获 SIGSEGV(分段错误)并在 Android 上的 JNI 下获取堆栈跟踪?
我正在将一个项目移动到新的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 的此类库。
I'm moving a project to the new Android Native Development Kit (i.e. JNI) and I'd like to catch SIGSEGV, should it occur (possibly also SIGILL, SIGABRT, SIGFPE) in order to present a nice crash reporting dialog, instead of (or before) what currently happens: the immediate unceremonious death of the process and possibly some attempt by the OS to restart it. (Edit: The JVM/Dalvik VM catches the signal and logs a stack trace and other useful information; I just want to offer the user the option to email that info to me really.)
The situation is: a large body of C code which I didn't write does most of the work in this application (all the game logic) and although it's well-tested on numerous other platforms, it's entirely possible that I, in my Android port, will feed it garbage and cause a crash in native code, so I want the crash dumps (both native and Java) that currently show up in the Android log (I guess it would be stderr in a non-Android situation). I'm free to modify both C and Java code arbitrarily, although the callbacks (both going in and coming out of JNI) number about 40 and obviously, bonus points for small diffs.
I've heard of the signal chaining library in J2SE, libjsig.so, and if I could safely install a signal handler like that on Android, that would solve the catching part of my question, but I see no such library for Android/Dalvik.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我有点晚了,但我有完全相同的需求,并且我开发了一个小型库来解决它,通过捕获常见的崩溃(
SEGV
,SIBGUS
等)在JNI代码中,并用常规java.lang.Error
异常替换它们。 另外,如果客户端在 Android >=4.1.1
上运行,堆栈跟踪会嵌入已解析的崩溃回溯(包含完整本机堆栈的伪跟踪)痕迹)。 您将无法从恶性崩溃中恢复(例如,如果您损坏了分配器),但至少它应该允许您从大多数中恢复。 (请报告成功和失败,代码是全新的)更多信息请访问 https://github.com/xroche/coffeecatch
(代码是BSD 2-Clauses 许可证)
I'm a little bit late, but I had the exact same need, and I've developed a small library to address it, by catching common crashes (
SEGV
,SIBGUS
, etc.) inside JNI code, and replace them by regularjava.lang.Error
exceptions. Bonus, if the client is running on Android >=4.1.1
, the stack trace embeds the resolved backtrace of the crash (a pseudo-trace containing the full native stack trace). You will not recover from vicious crashes (ie. if you corrupt the allocator, for example), but at least it should allows you to recover from most of them. (please report successes and failures, the code is brand new)More info at https://github.com/xroche/coffeecatch
(code is BSD 2-Clauses license)
FWIW,Google Breakpad 在 Android 上运行良好。 我完成了移植工作,我们将其作为 Firefox Mobile 的一部分提供。 它需要一些设置,因为它不会在客户端提供堆栈跟踪,而是向您发送原始堆栈内存并在服务器端执行堆栈行走(因此您不必在应用程序中附带调试符号) )。
FWIW, Google Breakpad works fine on Android. I did the porting work, and we're shipping it as part of Firefox Mobile. It requires a little setup, since it doesn't give you stack traces on the client-side, but sends you the raw stack memory and does the stack walking server-side (so you don't have to ship debug symbols with your app).
根据我有限的经验(非 Android),JNI 代码中的 SIGSEGV 通常会在控制权返回到 Java 代码之前使 JVM 崩溃。 我依稀记得听说过一些非 Sun JVM 可以让您捕获 SIGSEGV,但 AFAICR 您不能指望能够这样做。
您可以尝试在 C 中捕获它们(请参阅 sigaction(2)),尽管在 SIGSEGV(或 SIGFPE 或 SIGILL)处理程序之后您可以做的很少,因为进程的持续行为未正式定义。
In my limited experience (non-Android), SIGSEGV in JNI code will generally crash the JVM before control is returned to your Java code. I vaguely recall hearing about some non-Sun JVM which lets you catch SIGSEGV, but AFAICR you can't expect to be able to do so.
You can try to catch them in C (see sigaction(2)), although you can do very little after a SIGSEGV (or SIGFPE or SIGILL) handler as the ongoing behaviour of a process is officially undefined.