问题:
在Android的JNI开发中,你是否看到如下一堆崩溃日志,不知如何下手分析问题,崩溃在哪一行?
11-16 17:20:44.844 23077 23077 W test_jni_h: jni_preload: Starting for process=ln
11-16 17:20:44.844 23077 23077 W test_jni_h: jni_preload: =============================== Call doJniMain()
11-16 17:20:44.844 23077 23077 W test_jni_h: doJniMain: Starting for process=ln, isHook=CONFIG:VPN:SE_MAIN:SIG:PT1:AES, is_preload=1
11-16 17:20:44.845 23077 23077 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 23077 (ln), pid 23077 (ln)
11-16 17:20:44.857 2599 5691 I MiuiNetworkPolicy: bandwidth: 15 KB/s, Max bandwidth: 1846 KB/s
....
11-16 17:20:44.892 23080 23080 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstoneProto
11-16 17:20:44.893 1120 1120 I tombstoned: received crash request for pid 23077
11-16 17:20:44.895 23080 23080 I crash_dump64: performing dump of process 23077 (target tid = 23077)
11-16 17:20:44.902 23081 23081 E .android.camera: Not starting debugger since process cannot load the jdwp agent.
....
11-16 17:20:45.103 23080 23080 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
11-16 17:20:45.103 23080 23080 F DEBUG : Build fingerprint: 'Xiaomi/cupid/cupid:13/TKQ1.220807.001/V14.0.8.0.TLCCNXM:user/release-keys'
11-16 17:20:45.103 23080 23080 F DEBUG : Revision: '0'
11-16 17:20:45.103 23080 23080 F DEBUG : ABI: 'arm64'
11-16 17:20:45.103 23080 23080 F DEBUG : Timestamp: 2023-11-16 17:20:44.913140070+0800
11-16 17:20:45.103 23080 23080 F DEBUG : Process uptime: 2s
11-16 17:20:45.103 23080 23080 F DEBUG : ZygotePid: 108306913
11-16 17:20:45.103 23080 23080 F DEBUG : Cmdline: ln -s /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtbs.libtencentpos.so.so /data/user/0/com.test.zwwx/app_tbs_64/core_static_tbs_tmp/libtencentpos.so
11-16 17:20:45.103 23080 23080 F DEBUG : pid: 23077, tid: 23077, name: ln >>> ln <<<
11-16 17:20:45.103 23080 23080 F DEBUG : uid: 10398
11-16 17:20:45.103 23080 23080 F DEBUG : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
11-16 17:20:45.103 23080 23080 F DEBUG : pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
11-16 17:20:45.103 23080 23080 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000000
11-16 17:20:45.103 23080 23080 F DEBUG : Cause: null pointer dereference
11-16 17:20:45.103 23080 23080 F DEBUG : x0 0000000000000000 x1 0000000000000073 x2 0000000000000000 x3 0000000000000000
11-16 17:20:45.103 23080 23080 F DEBUG : x4 00000000c0300c03 x5 0000000040100401 x6 000000000000003c x7 62682e6d6f632f30
11-16 17:20:45.103 23080 23080 F DEBUG : x8 b400007170487fb2 x9 0000000000000001 x10 000000003a534947 x11 000000003a534947
11-16 17:20:45.103 23080 23080 F DEBUG : x12 000000003a534947 x13 0000000000000050 x14 000000004749533a x15 000000003a565000
11-16 17:20:45.103 23080 23080 F DEBUG : x16 00000071f0d81ab0 x17 00000071f0d00200 x18 0000007225754000 x19 0000007204c0c2f8
11-16 17:20:45.103 23080 23080 F DEBUG : x20 0000007204d0e000 x21 0000007204cd2000 x22 0000007fd4689e8b x23 0000007204d0e000
11-16 17:20:45.104 23080 23080 F DEBUG : x24 0000007fd4689e8b x25 0000007204cd0000 x26 0000007fd4689f10 x27 0000007fd4689e40
11-16 17:20:45.104 23080 23080 F DEBUG : x28 0000007204c02000 x29 0000007fd4686090
11-16 17:20:45.104 23080 23080 F DEBUG : lr 00000071f0d509ec sp 0000007fd4686090 pc 00000071f0d00270 pst 0000000040001000
11-16 17:20:45.104 23080 23080 F DEBUG : backtrace:
11-16 17:20:45.104 23080 23080 F DEBUG : #00 pc 0000000000086270 /apex/com.android.runtime/lib64/bionic/libc.so (__strchr_aarch64+112) (BuildId: 607a29162b319a50c57abd2b2141d335)
11-16 17:20:45.104 23080 23080 F DEBUG : #01 pc 00000000000d69e8 /apex/com.android.runtime/lib64/bionic/libc.so (strstr+28) (BuildId: 607a29162b319a50c57abd2b2141d335)
11-16 17:20:45.104 23080 23080 F DEBUG : #02 pc 0000000000086ffc /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtest64.so
11-16 17:20:45.104 23080 23080 F DEBUG : #03 pc 0000000000074f28 /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtest64.so
11-16 17:20:45.104 23080 23080 F DEBUG : #04 pc 0000000000054078 /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtest64.so
11-16 17:20:45.104 23080 23080 F DEBUG : #05 pc 0000000000054a3c /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtest64.so
11-16 17:20:45.104 23080 23080 F DEBUG : #06 pc 0000000000052b28 /apex/com.android.runtime/bin/linker64 (__dl__ZN6soinfo17call_constructorsEv+752) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
11-16 17:20:45.104 23080 23080 F DEBUG : #07 pc 00000000000528d0 /apex/com.android.runtime/bin/linker64 (__dl__ZN6soinfo17call_constructorsEv+152) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
11-16 17:20:45.104 23080 23080 F DEBUG : #08 pc 00000000000b7a08 /apex/com.android.runtime/bin/linker64 (__dl__ZL29__linker_init_post_relocationR19KernelArgumentBlockR6soinfo+4204) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
11-16 17:20:45.104 23080 23080 F DEBUG : #09 pc 00000000000b6944 /apex/com.android.runtime/bin/linker64 (__dl___linker_init+832) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
11-16 17:20:45.104 23080 23080 F DEBUG : #10 pc 00000000000554c8 /apex/com.android.runtime/bin/linker64 (__dl__start+8) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
11-16 17:20:45.104 22354 22584 W weworklocal: [22354:22584:1116/17:20:45.104:W:(tcp_connection.cpp:132)] GapTcpConnection(0): Performing destruction reset
11-16 17:20:45.104 22354 22584 I pjsip: : [, , 0]:fd_list_del:173
.....
11-16 17:20:45.154 23081 23118 D CAM_HybridZoomingSystem: [1.0, 2.0]
11-16 17:20:45.157 2599 6270 W NativeCrashListener: Couldn't find ProcessRecord for pid 23077
别着急,请看本文即可轻松拿捏Native层的崩溃栈。
准本分析
实际上android已经为开发者提供了崩溃栈的分析工具: ndk-stack。
准备一下三个东西:
1. 准备分析工具:
ndk工具,由于使用ndk开发jni并编译,一定有这个工具了。
2. 需要分析的so文件:
在你编译项目的输出目录下,比如Android.mk编译出来的目录为:
工程根目录下的...xxx/xxx/Demo/obj/local/, 里面有armeabi-v7a和arm64-v8a等等子目录,Cmake编译的在 build output(自己研究下)。
在...xxx/xxx/Demo/obj/local/当前目录下执行也可,也可以直接拷贝出来在某个自己的目录下。
3. 崩溃栈日志:
把adb logcat 抓出来的本亏日志文件(如果太多,可以直接去一个完整的崩溃栈)拷贝到分析目录下。 注:不在分析目录下分析就放在任意地方,能找到就行。
分析问题
下面以分析arm64-v8a目录下的
在...xxx/xxx/Demo/obj/local/打开Terminal终端,执行命令:
ndk-stack -sym arm64-v8a/ -dump arm64-v8a/hook_preload_fatal_log.txt
执行命令
user@hulk-shell_test-shell_test_vpn:~/projects/shell_test/shell_test_vpn/encap/shell_test/mam/ShellTest/obj/local$
user@hulk-shell_test-shell_test_vpn:~/projects/shell_test/shell_test_vpn/encap/shell_test/mam/ShellTest/obj/local$ ndk-stack -sym arm64-v8a/ -dump arm64-v8a/hook_preload_fatal_log.txt
********** Crash dump: **********
Build fingerprint: 'Xiaomi/cupid/cupid:13/TKQ1.220807.001/V14.0.8.0.TLCCNXM:user/release-keys'
pid: 23077, tid: 23077, name: ln >>> ln <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000000
Stack frame #00 pc 0000000000086270 /apex/com.android.runtime/lib64/bionic/libc.so (__strchr_aarch64+112) (BuildId: 607a29162b319a50c57abd2b2141d335)
Stack frame #01 pc 00000000000d69e8 /apex/com.android.runtime/lib64/bionic/libc.so (strstr+28) (BuildId: 607a29162b319a50c57abd2b2141d335)
Stack frame #02 pc 0000000000086ffc /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtest64.so: Routine is_shell_test at /home/user/projects/shell_test/shell_test_vpn/encap/shell_test/mam/ShellTest/jni/./enc_dec.c:8701
Stack frame #03 pc 0000000000074f28 /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtest64.so: Routine initPackageName(char*) at /home/user/projects/shell_test/shell_test_vpn/encap/shell_test/mam/ShellTest/jni/./app-context.cc:231
Stack frame #04 pc 0000000000054078 /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtest64.so: Routine doJniMainExt(char*, char*, char*, char*, char*, char*, char*, char*, char*, char*, char*, char*, char*, int) at /home/user/projects/shell_test/shell_test_vpn/encap/shell_encap/mam/ShellTest/jni/./Java_com_hulk_test_jni_h.cc:400
Stack frame #05 pc 0000000000054a3c /data/app/~~yJTBwDTAb9UQbvJ96gDx8g==/com.test.zwwx-ZA2ckl4hnybAXhmaCpjn7Q==/lib/arm64/libtest64.so: Routine jni_preload() at /home/user/projects/shell_test/shell_test_vpn/encap/shell_test/mam/ShellTest/jni/./Java_com_hulk_test_jni_h.cc:633 (discriminator 12)
Stack frame #06 pc 0000000000052b28 /apex/com.android.runtime/bin/linker64 (__dl__ZN6soinfo17call_constructorsEv+752) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
Stack frame #07 pc 00000000000528d0 /apex/com.android.runtime/bin/linker64 (__dl__ZN6soinfo17call_constructorsEv+152) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
Stack frame #08 pc 00000000000b7a08 /apex/com.android.runtime/bin/linker64 (__dl__ZL29__linker_init_post_relocationR19KernelArgumentBlockR6soinfo+4204) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
Stack frame #09 pc 00000000000b6944 /apex/com.android.runtime/bin/linker64 (__dl___linker_init+832) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
Stack frame #10 pc 00000000000554c8 /apex/com.android.runtime/bin/linker64 (__dl__start+8) (BuildId: 92b6d7d677c276f6b53d86e83a2c0bc0)
user@hulk-shell_test-shell_test_vpn:~/projects/shell_test/shell_test_vpn/encap/shell_test/mam/ShellTest/obj/local$
结论
看上面的执行结果,函数调用关系如下:
Routine jni_preload() > Routine doJniMainExt() > initPackageName(char*) > is_shell_test() 函数,位于 enc_dec.c:8701 enc_dec文件的8701行么,如下:
Routine is_shell_test at /home/user/projects/shell_test/shell_test_vpn/encap/shell_test/mam/ShellTest/jni/./enc_dec.c:8701