Android Native程序crash的一些定位方法简介

Android Native程序crash的一些定位方法简介

经常,避免不了,我们的代码会崩溃。如果crash在native代码上,Android会和其他Linux一样,生成一份core dump,将程序运行时的内存,寄存器状态,堆栈指针,内存管理信息以及各种函数调用堆栈信息等存到一个文件中,供调试者使用分析。

Core Dump的生成

Android的Core dump叫tombstone,墓碑文件。由专门的一个daemon服务debuggerd来搜集,保存到/data/tombstone/目录下[logcat中也会打印一份简要信息,基本够分析用]。一般生成过程为:

  1. 系统异常,内核丢出来signal信号
  2. 应用中,bionic中实现的默认signal处理过程,通过socket将pid/tid和异常退出信息,发给debuggerd进程
  3. debuggerd得到pid/tid信息,通过ptrace挂到异常进程,得到异常进程的各种信息,然后生成墓碑文件,保存起来。

debuggerd的具体实现和ptrace就不展开讲了,以前研究挂钩子和benchmark分析处理的时候,参考了这里不少代码。有兴趣同学可以好好学习一下这个,也可以玩出花来的。比如以前做老化测试,就是改了捕鱼达人的金钱,脚本一直放炮整周末自动老化,不过现在好多apk都防着ptrace了,你想调试它它就自杀,越来越没意思了…

Tombstone文件的基本信息:

Tombstone信息通常由如下几部分组成:
1. 系统信息
包括编译信息、版本号、进程信息等。
2. 异常信息
包括产生的异常的原因,如signal 11(即段错误,内存访问异常)、异常所在位置等。
3. 寄存器信息
Dump当前线程栈中的寄存器值,包括通用寄存器和浮点寄存器的值。
4. backtrace信息
Dump当前进程栈中的调用栈。这个信息对异常分析非常有用。Backtrace信息已经做过符号定位和demangle,PC地址已经减去基地址,基本可以直接和so文件中的偏移地址对应。
5. 栈帧数据
以ascii形式,dump当前线程栈的栈帧信息。
6. 通用寄存器周边数据信息
通用寄存器很可能存储的是指针等信息,Android的tombstone会将通用寄存器周边数据也dump出来供分析。
7. 进程的logcat信息
Tombstone中还会dump在发生异常前,该进程输出的logcat信息。

其中,3,4,5,6,7每个线程信息都有对应信息。也不展开详说了,基本玩Android的都见过,除了墓碑文件中保存,在dropbox下,以及logcat的DEBUG TAG打出来的log中也有。

错误大体定位

简单说一下tombstone文件的阅读方式,大体定位错误方法。
一般对tombstone文件,除了知道是哪个进程挂了外,我们首要要知道的,是下面画圈圈的几个信息:
这里写图片描述
第一个,是signum,一般debuggerd关注的是SIGILL,SIGBUS,SIGABRT,SIGFPE,SIGSEGV,SIGPIPE等。而这里,估计九成都是SIGSEGV (即signal 11),段错误,和非法内存访问等价。
第二个是sigcode。对于段错误来说,sigcode一般就两个:SEGV_MAPERR和SEGV_ACCERR,字面意思,一个是map错误,一个是访问错误。
第三个是错误地址。

简单定位

错误九成以上都是段错误,主要关注这个,其他像非法指令、浮点出错等,也可以分析一下,一般要么是代码越界改写,要么是系统硬件不稳定造成的
对于段错误,基本上大多是SEGV_MAPERR。先说一下段错误的两种类型:
SEGV_MAPERR:这个说明访问出错的地址,压根就没内map到进程地址空间来,这种情况,通常就是野指针,或者越界访问,当然访问空指针也是属于这类。
SEGV_ACCERR:这个说明访问出错地址,被map到地址空间来了,但是没访问权限。基本上是指针越界或野指针,比如写只读map的内存地址。
这里的tombstone中的错误地址,就是非法操作的地址。现在Adroid已经使用了ALSR(地址空间随机布局),错误地址也一般不容易猜出大约哪里出问题,不过有一类地址,还是比较容易猜出来的:即地址的值比较小,基本上都是空指针访问了。地址值是小于4K的地址,可以认为就是解引用空指针了。

根据错误地址,错误类型,再通过tombstone给出的backtrace信息,使用编译时带符号的那份库,用addr2line查PC,直接得到出错的行号,结合错误原因,基本上可以定位错误了,修复即可。

几个错误例子

这里写图片描述

SEGV_MAPERR,错误的虚拟地址。怀疑野指针或越界。可以通过addr2line定位到行号。
一般我们看backtrace,并不是死板的看栈帧最顶上的。一般最顶上的都是C库,C库通常是被调用的底层函数库,不会做太多容错处理,一般认为是调用它的code给出的参数等有问题,再回溯几个栈帧看一下。这里很明显可以看到,是栈帧号3的地方出问题了,调用的是realloc,可能是越界或野指针,错的代码在这:

SharedBuffer* SharedBuffer::editResize(size_t newSize) const
{
    if (onlyOwner()) {
        SharedBuffer* buf = const_cast<SharedBuffer*>(this);
        if (buf->mSize == newSize) return buf;
        buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);  //错在这
        if (buf != NULL) {
            buf->mSize = newSize;
            return buf;
        }
    }
    SharedBuffer* sb = alloc(newSize);
    if (sb) {
        const size_t mySize = mSize;
        memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
        release();
    }
    return sb;    
}

看一下代码逻辑,基本先怀疑传入的参数newSize有异常,加一些trace,复现看看。

这里写图片描述
Dalvik虚拟机中有空指针, addr2line看一下具体位置,再看上下文查逻辑

这里写图片描述
这种错误,已经报说heap有异常,corrupt了。一般是有人越界写,或者double free都有可能,这个要查。很多时候还不是必现的,主要查一下临界区的保护问题。

这里写图片描述
主动自杀abort的,这个查到代码调用的地方,看一下逻辑就好。其实tombstone上,这类问题,同时会打印abort的原因,解决就好。

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Android原生崩溃(android native crash)是指在Android平台上,由于代码执行错误或者资源耗尽等原因,导致应用程序无法正常运行而崩溃或者闪退的现象。原生崩溃产生的原因可能是由于C或者C++代码编写错误、内存溢出、线程竞争等。针对原生崩溃问题,开发人员需要使用调试工具进行定位和修复。 ### 回答2: Android Native Crash发生在安卓应用程序运行时,由于C或C++库的错误或者其他原因导致应用程序崩溃。有时候Native Crash可能会影响整个设备,尤其是当Native Crash发生在系统级别的代码中时。 产生Native Crash的原因通常包括以下几个方面: 1. 内存管理问题:Native Crash通常与内存管理问题相关,这可能是由于访问未初始化的内存,使用错误的指针或释放已释放的内存等原因引起的。 2. 硬件问题:Native Crash也可能与设备相关的硬件问题有关,例如访问不可用的硬件资源或硬件设备故障。 3. 应用程序代码问题:Native Crash可能发生在应用程序代码的错误、资源泄漏、堆栈溢出等问题引起的。 4. 第三方库问题:Native Crash也可能由第三方库中的错误或bug引起。这些库可能没有经过充分的测试,或者与设备硬件不兼容。 为了更好地解决Native Crash问题,开发者可以通过日志或崩溃报告(Crash Report)来检测和分析崩溃日志,并看堆栈跟踪信息来确定导致Native Crash的来源。在开发过程中,经常使用除了自己编写的代码之外的第三方库时,还可以考虑使用崩溃的回溯工具,如Firebase Crashlytics等。 总之,Native CrashAndroid应用程序开发过程中经常遇到的问题,它可能会对用户体验和开发进度产生重大影响,因此开发者需要强化对Native Crash的理解和分析能力,以更好地解决Native Crash的问题。 ### 回答3: Android Native Crash,指的是在 Android 系统中发生的本地崩溃。本地崩溃是指应用程序使用本地代码,而不是 Java 代码,导致应用程序崩溃的问题。本地代码可以是编写在 C/C++ 等语言中的库,或是应用程序本身所编写的 Native 代码。 本地代码崩溃后,会在应用程序崩溃的同时发生。本地崩溃可发生在 Android 应用程序中的任何部分,比如,应用程序本地库、Android 系统库等等。大多数情况下,本地崩溃是由于访问无效内存、访问不合法指针、数组越界等问题引起的。 为了解决本地崩溃问题,Android 提供了一些工具和技术。比如,使用 ndk-stack 工具可以解析本地崩溃日志。Android Studio 也提供了一些工具来分析应用程序崩溃的原因。同时,我们也可以在应用程序中添加自定义的日志跟踪信息,以便更好地了解应用程序的崩溃原因。 还有一些其他的技术可以使用,如使用 Google 的 Crashlytics 来跟踪应用程序的崩溃问题。这个平台可以帮助开发者收集和分析应用程序在用户设备上的崩溃信息,并彻底解决这些问题。此外,Android 还提供了一些实用工具和技术,如 ANR(Application Not Responding)错误处理器、Tracer for OpenGL ES 和 Traceview 示例等。 总之,Android Native CrashAndroid 系统中常见的崩溃问题之一。了解它的原因并采用适当的解决方案可以使得我们更好地保持我们的应用程序的稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值