Android开发中,在Java层可以方便的捕获crashlog,但对于 Native 层的 crashlog 通常无法直接获取,只能通过系统的logcat来分析crash日志。

做过 Linux 和 Win32 开发的都知道,在pc上程序crash时可以生成 core dump 文件通过相关的工具分析函数调用堆栈及崩溃时的内存信息。

那么作为软件开发者有没有方法自己获取native层的crashlog呢?Android 系统是 Linux 内核,既然在Linux中crash时可以生成dump文件,那么在Android中也是有办法的。

Linux系统的Crash dump

Linux 栈调用回溯

对 Linux 应用程序而言, 因为有 glibc 库的支持, 所以构造程序的函数调用链相对容易。在 glibc 库提供的关于堆栈回朔的一系列库函数中,其核心函数是 backtrace()。它负责遍历从程序入口点到当前调用点的所有堆栈帧,然后生成函数调用的地址序列。为了完成函数地址和函数名称的转换,函数backtrace_symbols() 负责将 backtrace()生成的地址序列转换成一系列字符串列表,在每个字符串列表中包括了函数名称,当前指令在函数中的偏移量和函数的返回地址。由于 backtrace_symbols() 需要动态申请空间以保存字符串列表,如果应用程序 crash 时破坏了系统内存,可能导致 backtrace_symbols()结果错误。为此,glibc库还提供了一个更安全的地址转换函数:backtrace_symbols_fd() 。该函数将生成的字符串直接输出到外部文件,而不再需要申请新的内存空间。对于 backtrace() 的详细使用方法可以通过man backtrace 查看。

在Andrid中,由于谷歌没有使用glibc库,而是使用了精简版本的bionic库,其中并没有 backtrace() 可用。获取调用堆栈还需要采用其他方法。

Linux 信号机制

信号机制是 Linux 进程间通信的一种重要方式,Linux 信号一方面用于正常的进程间通信和同步,如任务控制(SIGINT, SIGTSTP,SIGKILL, SIGCONT,……);另一方面,它还负责监控系统异常及中断。 当应用程序运行异常时, Linux 内核将产生错误信号并通知当前进程。 当前进程在接收到该错误信号后,可以有三种不同的处理方式。 1. 忽略该信号。
2. 捕捉该信号并执行对应的信号处理函数(signal handler)。
3. 执行该信号的缺省操作(如 SIGTERM, 其缺省操作是终止进程)。

当 Linux 应用程序在执行时发生严重错误,一般会导致程序 crash。其中,Linux 专门提供了一类 crash 信号,在程序接收到此类信号时,缺省操作是将 crash 的现场信息记录到 core 文件,然后终止进程。

Crash信号列表

Signal Description
SIGSEGV Invalid memory reference.
SIGBUS Access to an undefined portion of a memory object.
SIGFPE Arithmetic operation error, like divide by zero.
SIGILL Illegal instruction, like execute garbage or a privileged instruction
SIGSYS Bad system call.
SIGXCPU CPU time limit exceeded.
SIGXFSZ File size limit exceeded.

Linux 信号处理 sigaction

#include<signal.h>
int sigaction(int sig, struct sigaction *act , struct sigaction *oact) ; struct sigaction{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}

这个函数可以: 1. 给一个signal安装一个handler,并且在使用sigaction修改该handler之前,不用reinstall。 2. 使用sigaction结构,该结构包含handler,其中可以指定2个handler,一个是使用sigiinfo_t等参数的handler,即支持给handler更多的参数,使其可以知道自己是被什么进程,那个用户,发来的什么信号,发来该信号的具体的原因是什么,当然要像这样,得给sigaction的sa_flags设置SA_SIGINFO标记。 3.使用sigaction的sa_flags标记还可以指定系统调用被这个信号打断后,是直接返回,还是自动restart. 一个典型就是,一般我们不让SIGALRM信号将被打断的系统调用restart,因为SIGALARM一般本来就是用来打断一个block的调用的。 4. 为了模仿老的signal函数的作用,实现unreliable 的类似signal的操作,可以通过给sa_flags设置SA_RESETHAND使handler不会自动reinstall,以及SA_NODEFER标记来使在本信号的handler内部,本信号不被自动block,当然如果你手动在sa_mask中指定要block本信号的话就可以将其block了。 5. 通过使用sigaction结构中的sa_mask,可以在该handler执行的过程中,block一些信号,注意,这个mask是与我们使用sigprocmask设置的mask不同的mask,这个mask的作用范围仅限于本handler函数,而且他不会将我们用sigprocmask设置的mask取消,而仅仅是在其基础上再次将一些信号block掉,当handler结束时,系统会自动将mask恢复成以前的样子,所以这个sigaction中的sa_mask只作用本信号的handler的执行时间。

一个使用 sigaction 进行信号处理的示例:

#include <signal.h>

void sig_handler_with_arg(int sig,siginfo_t *sig_info,void *unused){……}

int main(int argc,char **argv)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = sig_handler_with_arg;
sa.sa_flags = SA_RESETHAND; sigaction(SIGSEGV, &sa, NULL);
...
}

Android tombstones 分析

Android系统中应用出现nativecrash时,会在 /data/tombstones 目录下生成 tombstone_xx 的日志文件,记录了应用crash发生时的内存、寄存器、堆栈信息等。并且通过logcat将其内容输出。

Android 4.0中tombstones处理部分的源码位于 /system/core/debuggerd 和 bonic/linker/debugger.c 中。

在 bonic/linker/debugger.c 中的 debugger_init() 中对7个Signal进行了注册处理,debugger_signal_handler作为信号处理函数。

void debugger_init()
{
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = debugger_signal_handler;
act.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&act.sa_mask); sigaction(SIGILL, &act, NULL);
sigaction(SIGABRT, &act, NULL);
sigaction(SIGBUS, &act, NULL);
sigaction(SIGFPE, &act, NULL);
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGSTKFLT, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
}

debugger_signal_handler 中,通过socket client 与 /system/core/debuggerd 中的socket server进行通信,在/system/core/debuggerd中进行crash进程的分析( handle_crashing_process 函数中),生成tombstones文件(dump_crash_report 函数)。

unwind_backtrace_with_ptrace 函数获取backtrae,通过 ptrace 读取寄存器和相关内存地址。

Google Breakpad 项目

Google Breakpad 是Google开源的跨平台崩溃转储和分析模块,他支持Windows,Linux和Mac和Solaris系统,并可以编译到Android工程中。Google-breakpad的好处在于可以屏蔽了不同平台的差异,使用统一的文件格式记录和分析符号文件格式和崩溃栈信息。

在Linux系统上,google-breakpad也是通过信号机制来捕获crash,大致过程可以通过源码中的注释了解:

//    The signal flow looks like this:

//  SignalHandler (uses a global stack of ExceptionHandler objects to find
// | one to handle the signal. If the first rejects it, try
// | the second etc...)
// V
// HandleSignal ----------------------------| (clones a new process which
// | | shares an address space with
// (wait for cloned | the crashed process. This
// process) | allows us to ptrace the crashed
// | | process)
// V V
// (set signal handler to ThreadEntry (static function to bounce
// SIG_DFL and rethrow, | back into the object)
// killing the crashed |
// process) V
// DoDump (writes minidump)
// |
// V
// sys_exit

客户端中google-breakpad的使用也很简单,可以参照官方wiki的教程文档:How To Add Breakpad To Your Linux Application 。

Android平台抓取native crash log的更多相关文章

  1. android adb命令 抓取系统各种 log

    getLog.bat: adb root adb remount adb wait-for-device adb logcat -v time > C:\log.txt 在Android中不同的 ...

  2. 如何抓取崩溃的log日志

    4.手机录屏工具的推荐 Andriod:录屏大师,易录屏等等. iOS:AirPlayer,iTools. 5.如何抓取崩溃的log日志? android闪退获取日志方法: 1.下载adb工具包 2. ...

  3. 高通qxdm抓取sensor的log【学习笔记】

    高通qxdm抓取sensor的log 打开qxdm,打开设置界面,去掉其他无关的log,打开Log packets .Message packets的SNS的log 之后需要把端口打开,把端口打开之后 ...

  4. android 抓取native层奔溃

    使用android的breakpad工具 使用这个工具需要下载Breakpad的源码,然后进行编译,编译之后会生成两个工具 我们使用这两个工具来解析奔溃的位置.这里我们可以下载已经编译好的工具 下载地 ...

  5. MTK平台-抓取蓝牙log

    一.MTKLOG抓取 .在拔号键盘输入暗码 *#*##*#* 进入工模EngineerMode .在 Log and Debugging -> MTKLogger 点击开始 .MTKLog存储路 ...

  6. 抓取崩溃的log日志

    1.下载adb工具包 也就是解锁软件,如果要解锁的话,需确认有fastboot 安装jdk.sdk 2.注意事项 请确保电脑上只连接了一台手机设备(最好只连接一条USB线),同时确保手机已开启USB调 ...

  7. 抓取 USB 总线LOG

    在实际工作中经常会遇到需要分析USB报文的情形.比如对比不同厂家4G/5G模块.解决实际IP over USB传输效率低下问题. 这时候如果能抓取到 USBMOM 总线的报文将会大有裨益.毕竟所有ho ...

  8. 《React Native 精解与实战》书籍连载「Android 平台与 React Native 混合开发」

    此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...

  9. Android端抓取日志

    一.背景: ADT-Bundlee for Windows 是由GoogleAndroid官方提供的集成式IDE,已经包含了Eclipse,你无需再去下载Eclipse,并且里面已集成了插件,它解决大 ...

随机推荐

  1. [Protractor] Locators and Suites in Protractor

    HTML: <ul class="list"> <li ng-repeat="item in itmes" ng-click="se ...

  2. Android应用程序框架层和系统运行库层日志系统源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6598703 在开发Android应用程序时,少 ...

  3. 向html某个元素中添加信息

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  4. Webfrom 上传 单个上传 多个上传

    文件上传控件:FileUpload - 控件,界面+方法+属性Button/LinkButton/ImageButton FileUpload控件:1.SaveAs("要上传到服务器的绝对路 ...

  5. 值栈和OGNL 之 7.1 值栈

    7.1  值栈 7.1.1  值栈是什么 简单的说:值栈是对应每一个请求对象的轻量级的内存数据中心. Struts2中一个很激动人心的特性就是引入了值栈,在这里统一管理着数据,供Action.Resu ...

  6. 7、Khala设备资源的申请和释放

    在实际业务中,我们每次登录后,可能需要在服务端维护一些设备相关的资源信息,而不同设备所需维护的资源信息又不尽相同.Khala提供了设备资源的维护储存功能,在此我们通过一个具体的业务中对其进行展示. 一 ...

  7. 算法_Longest Palindromic Substring(寻找最长回文字串)

    题目:Given a string S, find the longest palindromic substring in S. You may assume that the maximum le ...

  8. block中无法使用C数组变量

    在Objective-C的block中无法使用C数组,即使我们不对C数组做任何改变,编译的时候也会报错: #include <stdio.h> int main() { const cha ...

  9. MySql移植到嵌入式Linux平台

    最近在做考勤机系统,硬件采用的cortex-A8,哈哈,其实是有点浪费的,2410就可以的.所以就要考虑到考勤数据的存储问题,本来是打算用sqlite数据库存储的,可是后来发现,这个数据库只是一个本地 ...

  10. 手机扫描二维码下载APP,根据操作系统不同自动下载

    Android和IOS手机扫描二维码下载APP,根据OS不同,自动处理相应下载操作.IOS自动跳转至AppStore应用下载页,Android自动下载应用的apk包. <script type= ...