解決方案:
設置 android:extractNativeLibs="true"
直接在 AndroidManifest.xml
里加上:
<applicationandroid:extractNativeLibs="true">
</application>
這樣,so 文件會被解壓,崩潰時可以正常打印完整的 native 堆棧。
分析
1. android:extractNativeLibs
的作用
android:extractNativeLibs
是 AndroidManifest.xml
中 application
標簽的一個屬性:
<applicationandroid: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 文件用于離線解析崩潰日志。
- 開發調試時,設為
你可以根據實際情況選擇適合的方案!