最近碰一次Android App NDK崩溃的问题,这个NE(Native Exception)是从NDK层xxx.so
库文件里抛出来的,进行了tombstone
的日志分析,定位分析并解决了问题。
相比于Java上层的崩溃问题的解决,NDK层xxx.so
库文件里抛出异常比较难定位及解决。 最重要的步骤是提取崩溃日志。
手机连接电脑,可以在Android Studio里直接查看Logcat的日志:
...(省略) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
2023-03-07 09:25:45.323 29167-29167 DEBUG pid-29167 A pid: 26758, tid: 26758, name: .aa.bb.cc.dd >>> sg.aa.bb.cc.dd <<<
2023-03-07 09:25:45.329 29167-29167 DEBUG pid-29167 A #03 pc 00000000001199e0 /data/app/~~RW3C1fUQ0X24VpdWWeRdqg==/sg.aa.bb.cc.dd-4IaZ9lJY132Qxf-Jxajm3w==/base.apk!libJni.so (offset 0xa57000) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
2023-03-07 09:25:45.329 29167-29167 DEBUG pid-29167 A #04 pc 00000000001197c8 /data/app/~~RW3C1fUQ0X24VpdWWeRdqg==/sg.aa.bb.cc.dd-4IaZ9lJY132Qxf-Jxajm3w==/base.apk!libJni.so (offset 0xa57000) (CSystem::aaaaa(char*, char*)+972) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
2023-03-07 09:25:45.329 29167-29167 DEBUG pid-29167 A #05 pc 0000000000091b1c /data/app/~~RW3C1fUQ0X24VpdWWeRdqg==/sg.aa.bb.cc.dd-4IaZ9lJY132Qxf-Jxajm3w==/base.apk!libJni.so (offset 0xa57000) (Java_aa.bb.cc.dd_jniqta_Process+2124) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
2023-03-07 09:25:45.329 29167-29167 DEBUG pid-29167 A #06 pc 0000000000070b98 /data/app/~~RW3C1fUQ0X24VpdWWeRdqg==/sg.aa.bb.cc.dd-4IaZ9lJY132Qxf-Jxajm3w==/oat/arm64/base.odex (deleted)
...(省略)
tombstone
的记录通过指令adb bugreport
提取tombstone
的日志。
C:\Users\John\AppData\Local\Android\Sdk\platform-tools>adb bugreport
/data/user_de/0/com.android.shell/files/bugreports/dumpstate-2023-03-10-00-09-22.zip: 1 file pulled, 0 skipped. 26.7 MB/s (10556968 bytes in 0.377s)
Bug report copied to C:\Users\John\AppData\Local\Android\Sdk\platform-tools\dumpstate-2023-03-10-00-09-22.zip
在dumpstate-2023-03-10-00-09-22.zip\FS\data\tombstones
这个目录下有10个tombstone
日志,是在程序崩溃时生成的。
以下是通过logcat的输出,再通过ndk-stack
来输出崩溃日志。
C:\Users\John\AppData\Local\Android\Sdk\platform-tools>adb shell logcat | C:\Users\John\AppData\Local\Android\Sdk\ndk\25.1.8937393\ndk-stack -sym C:\John_Development\library_jni\debug\jni\arm64-v8a\libJni.so
或者通过ndk-stack
来分析tombstone
的记录
=================
C:\Users\John\AppData\Local\Android\Sdk\platform-tools>C:\Users\John\AppData\Local\Android\Sdk\ndk\25.1.8937393\ndk-stack -sym C:\John_Development\library_jni\debug\jni\arm64-v8a\libJni.so -dump C:\John_Development\tombstone_00
********** Crash dump: **********
...(省略)
以下是取得的日志,但是不管是哪种办法取得的崩溃日志,都不能具体到程序的导致崩溃的那一行。
查看日志,SIGABRT (6) 是指通过c函数abort()
发送,为assert()
使用。日志中有一个关键字比较重要:
Abort message: 'FORTIFY: vsprintf: prevented 173-byte write into 30-byte buffer'
似乎是写入某一段内存里写入到边界外了,173个字节要写入一个30个字节的缓存区。
...(省略)
2023-03-09 23:20:22.958 6426-6426 ScrollView pid-6426 D initGoToTop
2023-03-09 23:20:22.987 6426-6426 libc pid-6426 A FORTIFY: vsprintf: prevented 173-byte write into 30-byte buffer
2023-03-09 23:20:22.988 6426-6426 libc pid-6426 A Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 6426 (.aa.bb.cc.dd), pid 6426 (.aa.bb.cc.dd)
2023-03-09 23:20:23.051 4172-4227 SensorManager pid-4172 D TYPE_LIGHT (5): 9.000000
2023-03-09 23:20:23.061 7176-7176 crash_dump64 pid-7176 I obtaining output fd from tombstoned, type: kDebuggerdTombstone
2023-03-09 23:20:23.062 3708-3708 tombstoned pid-3708 I received crash request for pid 6426
2023-03-09 23:20:23.064 7176-7176 crash_dump64 pid-7176 I performing dump of process 6426 (target tid = 6426)
2023-03-09 23:20:23.076 7176-7176 DEBUG pid-7176 A *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2023-03-09 23:20:23.076 7176-7176 DEBUG pid-7176 A Build fingerprint: 'samsung/aaa/aaa:11/RP1A.200720.012/aaa:user/release-keys'
2023-03-09 23:20:23.076 7176-7176 DEBUG pid-7176 A Revision: '2'
2023-03-09 23:20:23.076 7176-7176 DEBUG pid-7176 A ABI: 'arm64'
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A Timestamp: 2023-03-09 23:20:23+0800
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A pid: 6426, tid: 6426, name: .aa.bb.cc.dd >>> sg.aa.bb.cc.dd <<<
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A uid: 10270
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A Abort message: 'FORTIFY: vsprintf: prevented 173-byte write into 30-byte buffer'
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A x0 0000000000000000 x1 000000000000191a x2 0000000000000006 x3 0000007fd3050530
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A x4 0000000000000000 x5 0000000000000000 x6 0000000000000000 x7 0000000000000040
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A x8 00000000000000f0 x9 6105dba6615d8073 x10 0000000000000000 x11 ffffffc0fffffbdf
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A x12 0000000000000001 x13 000000006409f936 x14 003a9ebdec035bec x15 00004092cc9cc37a
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A x16 00000070e064e948 x17 00000070e062d2d0 x18 00000070e1fee000 x19 000000000000191a
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A x20 000000000000191a x21 00000000ffffffff x22 00000070e1584000 x23 0000006fc04a3000
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A x24 00000000a88031a0 x25 00000070e1584000 x26 0000000000000069 x27 0000000000000002
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A x28 0000000000000000 x29 0000007fd30505b0
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A lr 00000070e05e0ca4 sp 0000007fd3050510 pc 00000070e05e0cd0 pst 0000000000000000
2023-03-09 23:20:23.251 4172-4227 SensorManager pid-4172 D TYPE_LIGHT (5): 10.000000
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A backtrace:
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #00 pc 0000000000089cd0 /apex/com.android.runtime/lib64/bionic/libc.so (abort+164) (BuildId: 698b6aef520f034a9d40736d477f7a96)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #01 pc 00000000000b2360 /apex/com.android.runtime/lib64/bionic/libc.so (__fortify_fatal(char const*, ...)+124) (BuildId: 698b6aef520f034a9d40736d477f7a96)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #02 pc 00000000000b2f9c /apex/com.android.runtime/lib64/bionic/libc.so (__vsprintf_chk+144) (BuildId: 698b6aef520f034a9d40736d477f7a96)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #03 pc 00000000001199e0 /data/app/~~l8Fk9UOg3WqEsbf_8ul2pg==/sg.aa.bb.cc.dd-c3ewrrLy2U1YDGg7VQZPnA==/base.apk!libJni.so (offset 0xa57000) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #04 pc 00000000001197c8 /data/app/~~l8Fk9UOg3WqEsbf_8ul2pg==/sg.aa.bb.cc.dd-c3ewrrLy2U1YDGg7VQZPnA==/base.apk!libJni.so (offset 0xa57000) (CSystem::aaaaa(char*, char*)+972) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #05 pc 0000000000091b1c /data/app/~~l8Fk9UOg3WqEsbf_8ul2pg==/sg.aa.bb.cc.dd-c3ewrrLy2U1YDGg7VQZPnA==/base.apk!libJni.so (offset 0xa57000) (Java_aa.bb.cc.dd_jniqta_Process+2124) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #06 pc 000000000009cb98 /data/app/~~l8Fk9UOg3WqEsbf_8ul2pg==/sg.aa.bb.cc.dd-c3ewrrLy2U1YDGg7VQZPnA==/oat/arm64/base.odex (art_jni_trampoline+152)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #07 pc 0000000000134564 /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 88f26013f87f4da3613557f39f57fd6a)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #08 pc 00000000001a9a78 /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200) (BuildId: 88f26013f87f4da3613557f39f57fd6a)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #09 pc 000000000032129c /apex/com.android.art/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+376) (BuildId: 88f26013f87f4da3613557f39f57fd6a)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #10 pc 00000000003175c8 /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+996) (BuildId: 88f26013f87f4da3613557f39f57fd6a)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #11 pc 000000000068cd1c /apex/com.android.art/lib64/libart.so (MterpInvokeVirtualQuick+672) (BuildId: 88f26013f87f4da3613557f39f57fd6a)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #12 pc 0000000000132594 /apex/com.android.art/lib64/libart.so (mterp_op_invoke_virtual_quick+20) (BuildId: 88f26013f87f4da3613557f39f57fd6a)
...(省略)
注意这三行:
...(省略)
2023-03-09 23:20:22.987 6426-6426 libc pid-6426 A FORTIFY: vsprintf: prevented 173-byte write into 30-byte buffer
2023-03-09 23:20:22.988 6426-6426 libc pid-6426 A Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 6426 (.aa.bb.cc.dd), pid 6426 (.aa.bb.cc.dd)
...(省略)
2023-03-09 23:20:23.077 7176-7176 DEBUG pid-7176 A Abort message: 'FORTIFY: vsprintf: prevented 173-byte write into 30-byte buffer'
...(省略)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #03 pc 00000000001199e0 /data/app/~~l8Fk9UOg3WqEsbf_8ul2pg==/sg.aa.bb.cc.dd-c3ewrrLy2U1YDGg7VQZPnA==/base.apk!libJni.so (offset 0xa57000) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #04 pc 00000000001197c8 /data/app/~~l8Fk9UOg3WqEsbf_8ul2pg==/sg.aa.bb.cc.dd-c3ewrrLy2U1YDGg7VQZPnA==/base.apk!libJni.so (offset 0xa57000) (CSystem::aaaaa(char*, char*)+972) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
2023-03-09 23:20:23.348 7176-7176 DEBUG pid-7176 A #05 pc 0000000000091b1c /data/app/~~l8Fk9UOg3WqEsbf_8ul2pg==/sg.aa.bb.cc.dd-c3ewrrLy2U1YDGg7VQZPnA==/base.apk!libJni.so (offset 0xa57000) (Java_aa.bb.cc.dd_jniqta_Process+2124) (BuildId: 4cf43bec77672ebce12c16cca6693b03939d28da)
...(省略)
以上有三个信息,
signal 6 (SIGABRT)
信号6发生产生崩溃。以下是通过llvm-addr2line.exe
来定位具体出错的是哪一行:
C:\Users\John\AppData\Local\Android\Sdk\platform-tools>C:\Users\John\AppData\Local\Android\Sdk\ndk\25.1.8937393\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-addr2line.exe -f -C -e C:\John_Development\libJni.so 00000000001199e0
sprintf(char*, char const* pass_object_size1, ...)
C:/Users/John/AppData/Local/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/bits/fortify/stdio.h:74
C:\Users\John\AppData\Local\Android\Sdk\platform-tools>C:\Users\John\AppData\Local\Android\Sdk\ndk\25.1.8937393\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-addr2line.exe -f -C -e C:\John_Development\libJni.so 00000000001197c8
CSystem::aaaaa(char*, char*)
D:/src/aaaaa.cpp:110
C:\Users\John\AppData\Local\Android\Sdk\platform-tools>C:\Users\John\AppData\Local\Android\Sdk\ndk\25.1.8937393\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-addr2line.exe -f -C -e C:\John_Development\libJni.so 0000000000091b1c
Java_aa.bb.cc.dd_jniqta_Process
D:/src/bbbbb.cpp:468
C:\Users\John\AppData\Local\Android\Sdk\platform-tools>
具体出错的是sprintf(str, "%.2fMB(%.2f%%)", double_a, double_b);
这一行,由于sprintf(…)不进行边界检查,写操作溢出边界,173个字节要写入一个30个字节的缓存区, 并导致程序崩溃。使用更为安全的snprintf(…)方法进行格式化,可以解决问题。
CSDN: Android NDK Crash 定位分析
CSDN: Android NativeCrash 捕获与解析
CSDN: 使用 ndk-stack 寻找Android程序Crash的原因
Cnblogs: Android Tombstone 分析
CSDN:导出ANR、tombstones文件 - 无惧Permission denied
CSDN: 使用addr2line 定位 FORTIFY: vsprintf: prevented write past end of buffer‘ 报错解决思路
CSDN: bug解决-内核C库写保护(FORTIFY: write: prevented read past end of buffer)
知乎: Android NDK Tombstone/Crash 分析
Native crash (Tombstone) in android AOSP