如何在 Android 上的 JNI 下捕获 SIGSEGV(分段错误)并获取堆栈跟踪? [英] How can I catch SIGSEGV (segmentation fault) and get a stack trace under JNI on Android?

查看:44
本文介绍了如何在 Android 上的 JNI 下捕获 SIGSEGV(分段错误)并获取堆栈跟踪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将一个项目转移到新的 Android 原生开发工具包(即 JNI) 并且我想抓住 SIGSEGV,它是否应该发生(也可能是 SIGILL、SIGABRT、SIGFPE)以呈现一个很好的崩溃报告对话框,而不是(或之前)当前发生的事情:进程的直接死亡和操作系统可能会尝试重新启动它.( JVM/Dalvik VM 捕获信号并记录堆栈跟踪和其他有用信息;我只是想为用户提供将这些信息通过电子邮件发送给我的选项.)

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. ( 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.)

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

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.

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

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.

推荐答案

从 Jelly Bean 开始,您无法获得堆栈跟踪,因为 READ_LOGS 消失了.:-(

From Jelly Bean onwards you can't get the stack trace, because READ_LOGS went away. :-(

我实际上得到了一个信号处理程序,没有做任何太奇怪的事情,并且已经发布了使用它的代码,你可以看到 在 github 上(链接到历史版本;从那时起我删除了崩溃处理程序).方法如下:

I actually got a signal handler working without doing anything too exotic, and have released code using it, which you can see on github (edit: linking to historical release; I removed the crash handler since then). Here's how:

  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, 调试器.c)
  6. 与此同时,您的崩溃处理活动正在启动.实际上,您应该将 PID 传递给它,以便它可以等待第 5 步完成;我不这样做.在这里你向用户道歉并询问是否可以发送日志.如果是这样,请收集 logcat -d -v threadtime 的输出并启动一个 ACTION_SEND,其中填写了收件人、主题和正文.用户必须按发送.(CrashHandler.java, SGTPuzzles.java:462, strings.xml:41
  7. 注意 logcat 失败或超过几秒钟的时间.我遇到过一种设备,T-Mobile Pulse/华为 U8220,其中 logcat 立即进入 T(跟踪)状态并挂起.(CrashHandler.java:70strings.xml:51)
  1. Use sigaction() to catch the signals and store the old handlers. (android.c:570)
  2. Time passes, a segfault happens.
  3. In the signal handler, call up to JNI one last time and then call the old handler. (android.c:528)
  4. In that JNI call, log any useful debugging info, and call startActivity() on an activity that is flagged as needing to be in its own process. (SGTPuzzles.java:962, AndroidManifest.xml:28)
  5. When you come back from Java and call that old handler, the Android framework will connect to debuggerd to log a nice native trace for you, and then the process will die. (debugger.c, debuggerd.c)
  6. Meanwhile, your crash-handling activity is starting up. Really you should pass it the PID so it can wait for step 5 to complete; I don't do this. Here you apologise to the user and ask if you can send a log. If so, gather the output of logcat -d -v threadtime and launch an ACTION_SEND with recipient, subject and body filled in. The user will have to press Send. (CrashHandler.java, SGTPuzzles.java:462, strings.xml:41
  7. Watch out for logcat failing or taking more than a few seconds. I have encountered one device, the T-Mobile Pulse / Huawei U8220, where logcat immediately goes into the T (traced) state and hangs. (CrashHandler.java:70, strings.xml:51)

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

In a non-Android situation, some of this would be different. You'd need to gather your own native trace, see this other question, depending on what sort of libc you have. You'd need to handle dumping that trace, launching your separate crash-handler process, and sending the email in some appropriate ways for your platform, but I imagine the general approach should still work.

这篇关于如何在 Android 上的 JNI 下捕获 SIGSEGV(分段错误)并获取堆栈跟踪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆