解决方案:
设置 android:extractNativeLibs="true"
直接在 AndroidManifest.xml
里加上:
<application
android:extractNativeLibs="true">
</application>
这样,so 文件会被解压,崩溃时可以正常打印完整的 native 堆栈。
分析
1. android:extractNativeLibs
的作用
android:extractNativeLibs
是 AndroidManifest.xml
中 application
标签的一个属性:
<application
android:extractNativeLibs="true">
</application>
它控制的是 应用安装时是否解压 native 库(.so 文件)到 /data/data/<package>/lib/
目录。
true
(传统模式):- 系统会解压 APK 内的 .so 文件到
/data/data/<package>/lib/
目录。 System.loadLibrary()
直接加载这个解压后的 .so 文件。- 崩溃时堆栈信息可见。
- 系统会解压 APK 内的 .so 文件到
false
(默认,优化模式):- 直接在 APK 的 ZIP 文件中使用 mmap 方式映射 .so 文件,不解压。
- 这是一种更高效的加载方式(节省存储空间)。
- 但如果 native 代码崩溃,可能不会打印完整的堆栈信息。
2. 为什么 false
时堆栈信息可能缺失?
当 android:extractNativeLibs="false"
时:
.so
文件不会被解压,而是直接通过 mmap 映射到进程地址空间。- 但如果发生 native 崩溃(如
SIGSEGV
),gdb、ndk-stack 等调试工具可能无法正确解析内存中的 so 文件,导致:- 崩溃日志中的 so 文件路径可能是
/apex/.../libfoo.so
(映射路径)。 - 符号解析失败,导致堆栈信息缺失或不完整。
- 崩溃日志中的 so 文件路径可能是
当 android:extractNativeLibs="true"
时:
.so
文件被解压到/data/data/<package>/lib/
,进程使用的是磁盘上的真实文件。- 崩溃时,日志工具能正确解析符号表,所以 堆栈信息可以正确显示。
在 Android 6.0 (API 23) 之前,extractNativeLibs 默认为 true;在 Android Gradle Plugin 3.6.0+ 后,该属性默认为 false,需显式设置为 true。
3. 总结
android:extractNativeLibs="false"
(默认):节省空间,但可能导致 native 崩溃堆栈缺失。android:extractNativeLibs="true"
:.so 文件被解压,崩溃日志可以正确解析。- 建议
- 开发调试时,设为
true
,确保看到完整的崩溃日志。 - 正式发布时,设为
false
,减少存储占用,但保留unstripped
so 文件用于离线解析崩溃日志。
- 开发调试时,设为
你可以根据实际情况选择适合的方案!