android 调用c++封装库,c++库崩溃crash问题排查方案
打包Debug版的c++库
为了方便定位具体问题代码位置,首先是将自己的代码编译成debug版本的可执行程序,编译完成后可以验证下是否为debug版本,输入如下命令:
readelf -S your_program |grep debug
如果输出了debug字眼,则说明是debug版本,如果什么都没输出,则表示不是debug版本。
如下图:
注意,编译debug版本的时候一定不要用strip。strip会将debug版本库中的调试信息给优化掉,这样就会导致最终崩溃给出的地址,可能会定位错误问题。
android studio打包保留有调试信息的apk
android studio在打包apk时,默认会执行strip,对so库进行优化瘦身,同样会导致调试信息的丢失。安卓开发中,通常会使用到gradle来编译,在安卓项目的app目录下的build.gradle中是用来对编译进行配置的,不同的版本,设置的方法可能不一样,故一下列出几个供参考,可挨个尝试
packagingOptions {
doNotStrip "lib/armeabi/libCommon.so"
doNotStrip "lib/armeabi-v7a/libCommon.so"
}
buildTypes {
debug {
jniLibs.keepDebugSymbols true
}
release {
// 你可以选择在 release 版本中也保留调试符号,但这通常不推荐
// jniLibs.keepDebugSymbols false // 默认就是 false,所以这一行通常是可选的
}
}
buildTypes {
debug {
packaging.jniLibs.keepDebugSymbols.add("**/*.so")
}
release {
// 你可以选择在 release 版本中也保留调试符号,但这通常不推荐
// packaging.jniLibs.keepDebugSymbols.add("**/*.so")
}
}
我的版本用的是最后一种,在编译后so库112M,如果不加上述命令,打包apk时,会对so库进行优化,变为11M;加了上述命令后,so库保持原来大小。调试后,可在logcat中看到崩溃信息,如下:
箭头所指是崩溃的地址,可以帮助我们定位到在哪一行代码,绿框中是崩溃的函数名
根据崩溃信息,定位代码行数
崩溃信息拿到后,可以用addr2line命令获取具体行数
示例如下:
aarch64-linux-android-addr2line -i -e ***.so 00bdae74 00bc1bbc 00bc1ea0 -f
结果如下,可以打印出崩溃所在的cpp及行数,这样就能定位问题及修改了