Android NativeCrash 捕获与解析

strip之前的so路径:build/intermediates/transforms/mergeJniLibs

strip之后的so路径:build/intermediates/transforms/stripDebugSymbol

另外也可以通过Android SDK提供的工具aarch64-linux-android-strip手动进行strip,aarch64-linux-android-strip这个工具位于/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains目录下。

这个工具有多种版本,主要针对不同的手机CPU架构,如果不知道手机的CPU架构,可以连接手机使用以下命令查看:

adb shell cat /proc/cpuinfo

Processor : AArch64 Processor rev 12 (aarch64)

如上图可以看到我的手机CPU用的是aarch64,所以使用aarch64对应的工具aarch64-linux-android-strip,由于NDK提供了很多工具,后续都依照此原则使用即可:

aarch64架构

/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-strip

arm架构

/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-android-strip

使用如下命令可以直接将debug的so进行strip

aarch64-linux-android-strip --strip-all libbreakpad-core.so

使用Cmake进行编译的时候,可以增加如下命令,可以直接编译出strip的so

#set(CMAKE_C_FLAGS_RELEASE “${CMAKE_C_FLAGS_RELEASE} -s”)

#set(CMAKE_CXX_FLAGS_RELEASE “${CMAKE_CXX_FLAGS_RELEASE} -s”)

使用mk文件进行编译的时候,可以增加如下命令,也可以直接编译出strip的so

-fvisibility=hidden

二、NE 捕获与解析

===========================================================================

NE解析顾名思议就是堆栈解析,当然所有的前提就是需要保存一份带符号表、也就是未被strip的so,如果你只有strip之后的so,那就无能为力了,堆栈基本无法还原了。

一般有以下三种方式可以捕获和还原堆栈。

2.1 logcat捕获


顾名思义,就是通过logcat进行捕获,我们通过Android Studio打开logcat,制造一个NE,只能看到很多类似#00 pc 00000000000161a0的符号,并没有一个可以直接阅读的日志,我们想通过logcat直接输出一份可以直接阅读的log。

可以使用Android/SDK/NDK下面提供的一个工具ndk-stack,它可以直接将NE输出的log解析为可阅读的日志。

ndk-stack一般是位于ndk的工具下面,Mac下的地址为

/Users/XXXX/Library/Android/sdk/ndk/21.3.6528147/ndk-stack

然后在该目录下执行控制台命令,或者在 Android Studio的terminal中执行也可

adb shell logcat | androidsdk绝对路径/ndk-stack -sym so所在目录

如此控制台在应用发生NE的时候便会输出如下日志,由日志可以看出,崩溃对应的so以及对应的方法名,如果有c的源码,那么就很容易定位问题。

promote:~ njvivo$ adb shell logcat | ndk-stack -sym libbreakpad-core.so

********** Crash dump: **********

Build fingerprint: ‘vivo/PD1809/PD1809:8.1.0/OPM1.171019.026/compil04252203:user/release-keys’

#00 0x00000000000161a0 /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/lib/arm64/libbreakpad-core.so (Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo+16)

#01 0x00000000000090cc /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/oat/arm64/base.odex (offset 0x9000)

Crash dump is completed

其实ndk-stack这个工具原理就是内部集成利用了addr2line来实时解析堆栈并且显示在控制台中。

看到这里有的小伙伴就觉得那这个不是很简单,但是实际的崩溃场景一是不容易复现,二是用户的场景有时候很难模拟,那么线上的NE崩溃又该如何监测和定位呢,有两种方式。

2.2 通过DropBox日志解析–适用于系统应用


这个很简单,DropBox会记录JE,NE,ANR的各种日志,只需要将DropBox下面的日志传上来即可进行分析解决,下面贴上一份日志示例。

解析方案1:

借助上述的ndk-stack工具,可以直接将DropBox下面的日志解析成堆栈,从中可以看出,崩溃在breakpad.cpp第111行的Crash()方法中。

ndk-stack -sym /Users/njvivo/Desktop/NE -dump data_app_native_crash@1605531663898.txt

********** Crash dump: **********

Build fingerprint: ‘vivo/PD1809/PD1809:8.1.0/OPM1.171019.026/compil04252203:user/release-keys’

#00 0x00000000000161a0 /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/lib/arm64/libbreakpad-core.so (Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo+16)

Crash()

/Users/njvivo/Documents/project/Breakpad/breakpad-build/src/main/cpp/breakpad.cpp:111:8

Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo

/Users/njvivo/Documents/project/Breakpad/breakpad-build/src/main/cpp/breakpad.cpp:122:0

#01 0x00000000000090cc /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/oat/arm64/base.odex (offset 0x9000)

Crash dump is completed

解析方案2:

还是利用Android/SDK/NDK提供的工具linux-android-addr2line,这个工具位于/Users/njvivo/Library/Android/sdk/ndk目录下,有两个版本。

aarch64架构

/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line

arm架构

/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line

命令使用方法如下,结合未被strip的so以及日志里面出现的堆栈符号00000000000161a0,同样可以解析出崩溃地址和方法。

aarch64-linux-android-addr2line -f -C -e libbreakpad-core.so 00000000000161a0

Crash()

/Users/njvivo/Documents/project/Breakpad/breakpad-build/src/main/cpp/breakpad.cpp:111

基于以上,看似也很简单,但是有一个致命的问题就是DropBox只有系统应用能访问,非系统应用根本拿不到日志,那么,非系统应用该怎么办呢?

2.3 通过BreakPad捕获解析–适用于所有应用


非系统应用可以通过google提供的开源工具BreakPad进行监测分析,CrashSDK也是采用的此种方式,可以实时监听到NE的发生,并且记录相关的文件, 从而可以将崩溃和相应的应用崩溃时的启动、场景等结合起来上报。

下面简单介绍一下BreakPad的使用方式。

2.3.1 BreakPad的实现功能

BreakPad主要提供两个个功能,NE的监听和回调,生成minidump文件,也就是dmp结尾的文件,另外提供两个工具,符号表工具和堆栈还原工具。

  • **符号表工具:**用于从so中提取出debug信息,获取到堆栈对应的符号表。

  • **堆栈还原工具:**用于将BreakPad生成的dump文件还原成符号,也就是堆栈偏移值。

这两个工具会在编译BreakPad源码的时候产生。

编译完之后会产生minidump_stackwalk工具,有些同学不想编译的话,Android Studio本身也提供了这个工具。

这个minidump_stackwalk程序在Android Studio的目录下面也存在,可以拿出来直接使用,如果不想编译的话,直接到该目录下面取即可,Mac路径为:

/Applications/Android Studio.app/Contents/bin/lldb/bin/minidump_stackwalk

2.3.2 BreakPad的捕获原理

由上述可以得知,BreakPad在应用发生NE崩溃时,可以将NE对应的minidump文件写入到本地,同时会回调给应用层,应用层可以针对本次崩溃做一些处理,达到捕获统计的作用,后续将minidump文件上传之后结合minidump_stackwalk以及addr2line工具可以还原出实际堆栈,示意图如下:

在应用发生NE时,BreakPad会在手机本地生成一个dump文件,如图所示:

得到了以上文件,我们只能知道应用发生了NE,但是这些文件其实是不可读的,需要解析这些文件。

下面着重讲一下如何分析上面产生的NE:

2.3.3 解析dump文件

1、获取NE崩溃的dump文件,将刚才得到的minidump_stackwalk和dump文件放在同一个目录,也可以不放,填写路径的时候填写绝对路径即可。

然后在该目录下的终端窗口执行以下命令,该命令表示用minidump_stackwalk解析dump文件,解析后的信息输出到当前目录下的crashLog.txt文件。

./minidump_stackwalk xxxxxxxx.dmp >crashLog.txt

2、执行完之后,minidump_stackwalk会将NE的相关信息写到crashLog.txt里面,详细信息如图所示:

3、根据解析出的NE信息,关注图中红框,可以得知,这个崩溃发生的 libbreakpad-core.so 里面,0x161a0代表崩溃发生在相对根位置偏移161a0的位置

2.3.4 获取崩溃堆栈

1、利用之前提到的addr2line工具,可以根据发生Crash的so文件以及偏移地址(0x161a0)可以得出产生crash的方法、行数和调用堆栈关系。

2、在其根目录对的终端窗口运行以下命令。

arm-linux-androideabi-addr2line -C -f -e ${SOPATH} ${Address}

-C -f //打印错误行数所在的函数名称

-e //打印错误地址的对应路径及行数

${SOPATH} //so库路径

${Address} //需要转换的堆栈错误信息地址,可以添加多个,但是中间要用空格隔开,例如:0x161a0

3、如下图是真实运行的示例

aarch64-linux-android-addr2line -f -C -e libbreakpad-core.so 0x161a0

Crash()

/Users/njvivo/Documents/project/Breakpad/breakpad-build/src/main/cpp/breakpad.cpp:111

由上图可以知道,该崩溃发生在breakpad.cpp文件的第111行,函数名是Crash(),与真实的文件一致,崩溃代码如下:

void Crash() {

volatile int *a = (int *) (NULL);

*a = 1; //此处在代码里是111行

}

extern “C”

JNIEXPORT void JNICALL

Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo(JNIEnv *env, jobject instance,

jstring mLaunchInfoStr_) {

DO_TRY

{

Crash();

const char *mLaunchInfoStr = env->GetStringUTFChars(mLaunchInfoStr_, 0);

launch_info = (char *) mLaunchInfoStr;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

学习宝典

对我们开发者来说,一定要打好基础,随时准备战斗。不论寒冬是否到来,都要把自己的技术做精做深。虽然目前移动端的招聘量确实变少了,但中高端的职位还是很多的,这说明行业只是变得成熟规范起来了。竞争越激烈,产品质量与留存就变得更加重要,我们进入了技术赋能业务的时代。

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我针对Android程序员,我这边给大家整理了一套学习宝典!包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

向感,不知道该从那里入手去学习,对此我针对Android程序员,我这边给大家整理了一套学习宝典!包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

[外链图片转存中…(img-lMolPv8k-1712508441307)]

【算法合集】

[外链图片转存中…(img-PQo6fn6c-1712508441308)]

【延伸Android必备知识点】

[外链图片转存中…(img-4ui7N8Qe-1712508441308)]

【Android部分高级架构视频学习资源】

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值