AndroidNE问题分析⽅法介绍
⽂章⽬录
简介
NE,全称Native Exception,在Android中主要指在⽤户空间运⾏的native程序或者natvie库发⽣异常。NE问题通常带来程序奔溃现象,导致功能模块不稳定。
本⽂主要介绍有关NE的基本知识、NE问题出现后的基本分析⽅法、常见的NE问题和常⽤调试⼯具。
Native内存布局
这⾥主要介绍Native进程的虚拟地址空间,分32bit和64bit进程,camerarver就是32bit的,⽽
android.hardware.camera.provider@2.4-rvice_64是64bit的,主要是寻址范围不⼀样,32bit的进程寻址范围是4G,⽽64bit进程寻址范围是2的64次⽅,实际可⽤的是2的48次⽅,也就是256TB。
进程的内存空间按低地址到⾼地址通常分为代码段、数据段、BSS段、堆、栈和内核数据区这⼏个部分:
代码段:存放可执⾏的⼆进制指令,也就是代码占⽤的空间
数据段:存放初始化过的全局变量、静态变量
BSS段:Block Started by Symbol,存放程序中未初始化的全局变量和静态变量,默认初始化时全部为0
堆:存放进程运⾏中被动态分配的内存段,向上增长
栈:存放程序临时创建的局部变量,向下增长
(下⽂两张图来源于⽹络,出处忘记了…,见谅)
32位的虚拟地址空间
64位的虚拟地址空间
虚拟地址空间⽂件解读
通过adb shell cat /proc/$PID/maps或者adb shell pmap -x $PID可获取进程的虚拟地址空间映射⽂件,⽰例内容如:
00000070'ebb15000-00000070'ebc8ffff r-- 0 17b000 /vendor/lib64/libmegface_denlmk.so (BuildId: 5bb83f57711ebbf34c416d3feb706e) 00000070'ebc90000-00000070'ebc94fff --- 0 5000
00000070'ebc95000-00000070'ec2e8fff r-x 180000 654000 /vendor/lib64/libmegface_denlmk.so (BuildId: 5bb83f57711ebbf34c416d3feb706e) 00000070'ec2e9000-00000070'ec2f4fff --- 0 c000
00000070'ec2f5000-00000070'ec328fff rw- 7e0000 34000 /vendor/lib64/libmegface_denlmk.so (BuildId: 5bb83f57711ebbf34c416d3feb706e) 00000070'ec329000-00000070'ec3aefff rw- 0 86000 [anon:.bss]
00000070'fadd3000-00000070'fae4afff rw- 0 78000 anon_inode:dmabuf4044
00000071'7fa00000-00000071'801fffff rw- 0 800000 [anon:libc_malloc]
0000007f'f1c61000-0000007f'f1d18fff rw- 0 b8000 [stack]
每⼀条记录对应⼀个VMA(虚拟内存区域)结构。
第⼀段 “r–” 则是这个lib 使⽤的只读变量段,第三段 “r-x” 则是只读并可执⾏的主体代码段,第五段 “rw-” 则是这个lib 使⽤的数据段,第六段则是bss段。
第8⾏是ion memory 段,ion buffer 的 vma name 标注成dmabuf,即已经mmap 的ion memory 可以从这个直接统计算出。
第10⾏是malloc通过jemalloc 所管控的空间, 常见的malloc leaks 都会可以看到这种libc_malloc段空间显著增长。
第12⾏是栈空间。
NE问题常见类型
下⾯介绍⼏种常见的Native Crash情况:
主动抛出异常,代码中调⽤了abort(),系统会给进程发送信号SIGABRT(6),这种问题通常是代码执⾏到了异常分⽀,需要检查看看什么条件导致的,CamX代码使⽤的⽐较多。
进程被信号SIGKILL(9)杀死,⽐如通过adb shell kill -9 $PID或者某进程管理机制杀掉,APP进程可能进程会碰到这个问题,⼀般不会⽣成tombstone⽂件。
空指针,在进程的地址空间中,从0开始的第⼀个页⾯的权限被设置为不可读也不可写,当进程的指令试图访问该页⾯中的地址时(如读取空指针指向的内存),处理器就会产⽣⼀个异常,然后Linux内核会给该进程发送⼀个段错误信号SIGSEGV(11)。
野指针,指向的是⼀个⽆效的地址,该地址如果是不可读不可写的,那么会马上Crash(内核给进程发送段错误信号SIGSEGV),这时bug会很快被发现。
如果访问的地址为可写,⽽且通过野指针修改了该处的内存,那么很有可能会等⼀段时间(其它的代码使⽤了该处的内存后)才发⽣Crash。这时查看Crash时显⽰的调⽤栈,和野指针所在的代码部分,有可能基本上没有任何关联。是踩内存的⼀种。
数组越界/缓冲区溢出,情况与野指针类似,访问了⽆效的地址,踩了别⼈的内存区域。
常⽤调试⼯具
GNU C/C++⼯具,如addr2line、readelf、objdump、gdb等
prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/
Malloc Debug,检测内存踩踏、内存泄漏等问题
bionic/libc/malloc_debug/README.md
AddressSanitizer
AddressSanitizer (ASan) 是⼀种基于编译器的快速检测⼯具,⽤于检测原⽣代码中的内存错误。
ASan 可以检测以下问题:
堆栈和堆缓冲区上溢/下溢
释放之后的堆使⽤情况
超出范围的堆栈使⽤情况
重复释放/错误释放
ASan 可在 32 位和 64 位 ARM 以及 x86 和 x86-64 上运⾏。ASan 的 CPU 开销约为 2 倍,代码⼤⼩开销在⼀半到 2 倍之间,并且内存开销很⼤(具体取决于您的分配模式,但约为 2 倍)。
Android 10 和 AArch64 上的 AOSP master 分⽀⽀持,这是⼀种 RAM 开销更⼩、检测到的错误范围更⼤的类似⼯具。除了ASan 可以检测到的错误之外,HWASan 还可以检测返回之后的堆栈使⽤情况。
HWASan 具有类似的 CPU 和代码⼤⼩开销,但 RAM 开销要⼩得多 (15%)。HWASan 具有不确定性。只有 256 个可能的标记值,因此忽略任何错误的概率为 0.4%。ASan 对检测溢出规定了有限⼤⼩的红⾊区域,并对检测释放后使⽤情况规定了有限容量隔离区,⽽ HWAsan 没有这些规定,因此溢出⼤⼩或多久之前内存解除分配对 HWAsan ⽽⾔并不重要。这使得 HWASan 优于 ASan。您可以详细了解 或 的使⽤。
除了堆溢出外,ASan 还能检测堆栈/全局溢出,并能以最低的内存开销实现很⾼的速度。
HWAddressSanitizer 即HWASan
了解⼯作原理,可参考
tombstone抓取流程
Native Exception发⽣时,CPU将产⽣中断触发异常处理流程。Kernel处理中断,统⼀成信号发送,应⽤进程注册和处理信号。
在Android中,所有so都需要通过linker(Android的链接器)加载,linker会默认注册信号处理函数,代码在
bionic/linker/linker_main.cpp : debuggerd_init(),调⽤debuggerd_init()。debuggerd中注册接收的信号有9个:
SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGSEGV,SIGSTKFLT,SIGSYS,SIGTRAP,DEBUGGER_SIGNAL。
当NE发⽣时,debuggerd(代码在system/core/debuggerd)的默认信号处理函数被调⽤,它会打印"Fatal signal"异常信息,然后clone⼀直⼦进程,在其内执⾏/system/bin/crasher_dump64(32),这个crasher_dump就会去抓取各种异常信息,如signal、寄存器、backtrace、maps等输出到log中,并通过socket通知tombstoned进程保存到/data/tombstones/tombstone_xx⽂件。
实例分析
tombstone⽂件内容
举例
heap-buffer-overflow:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'qti/ALPS/ALPS:10/QKQ1.200202.20200410.105316:urdebug/relea-keys'
Revision: '0'
ABI: 'arm64'
Timestamp: 2020-04-14 15:50:43+0800
pid: 5822, tid: 6322, name: HwBinder:5822_3 >>> /vendor/bin/hw/android.hardware.camera.provider@2.4-rvice_64 <<<
uid: 1047
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: '=================================================================
==5822==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x0058e2a26f82 at pc 0x007
e04e767a0 bp 0x007d2f68fe20 sp 0x007d2f68f5b0 READ of size 2048 at 0x0058e2a26f82 thread T307 (HwBinder:5822_3)
#0 0x7e04e7679c (/system/lib64/libclang_rt.asan-aarch64-android.so+0x7179c)
#1 0x7d6a294200 (/vendor/lib64/libremosaic_wrapper.so+0x5200)
#2 0x7d68a33bb4 (/vendor/lib64/hw/com.qti.chi.override.so+0x19fbb4)
#3 0x7d68a76f80 (/vendor/lib64/hw/com.qti.chi.override.so+0x1e2f80)
#4 0x7d689e5b18 (/vendor/lib64/hw/com.qti.chi.override.so+0x151b18)
#5 0x7d689dbe28 (/vendor/lib64/hw/com.qti.chi.override.so+0x147e28)
#6 0x7d7e0dda04 (/vendor/lib64/hw/camera.qcom.so+0x30ea04)
#7 0x7d7e0d4578 (/vendor/lib64/hw/camera.qcom.so+0x305578)
#8 0x7e00769a98 (/vendor/lib64/camera.device@3.4-impl.so+0x16a98)
#9 0x7e007e6e3c (/vendor/lib64/camera.device@3.5-impl.so+0x1ce3c)
#10 0x7e04b7f234 (/system/lib64/vndk-29/android.hardware.camera.device@3.5.so+0x33234)
#11 0x7e04b80164 (/system/lib64/vndk-29/android.hardware.camera.device@3.5.so+0x34164)
#12 0x7e0421b6d8 (/system/lib64/vndk-sp-29/libhidlba.so+0x986d8)
#13 0x7e0421f078 (/system/lib64/vndk-sp-29/libhidlba.so+0x9c078)
#14 0x7e04220290 (/system/lib64/vndk-sp-29/libhidlba.so+0x9d290)
#15 0x7e0422f1d0 (/system/lib64/vndk-sp-29/libhidlba.so+0xac1d0)
#16 0x7e04beb5f0 (/system/lib64/vndk-sp-29/libutils.so+0x135f0)
#17 0x7e047c3b60 (/apex/com.android.runtime/lib64/bionic/libc.so+0xe6b60)
#18 0x7e04761b6c (/apex/com.android.runtime/lib64/bionic/libc.so+0x84b6c)
0x0058e2a26f82 is located 1 bytes to the right of 1793-byte region [0x0058e2a26880,0x0058e2a26f81)
allocated by thread T0 here:
heap-u-after-free:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'XXXX/G5/G5:10/QKQ1.200216.002/eng.XXXX.20200723.094420:urdebug/relea-keys'
Revision: '0'
ABI: 'arm64'
Timestamp: 2020-07-24 14:04:35+0800
pid: 26851, tid: 6803, name: provider@2.4- >>> /vendor/bin/hw/android.hardware.camera.provider@2.4-rvice_64 <<<
uid: 1047
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: '===============================================================
==
==26851==ERROR: AddressSanitizer: heap-u-after-free on address 0x0073896a5300 at pc 0x0075423717a0 bp 0x0074754e69e0 sp 0x0074754e6170 READ of size 777600 at 0x0073896a5300 thread T84843
#0 0x754237179c (/system/lib64/libclang_rt.asan-aarch64-android.so+0x7179c)
#1 0x74adaec310 (/vendor/lib64/libanc_single_rt_bokeh.so+0x2eb310)
#2 0x74ad896134 (/vendor/lib64/libanc_single_rt_bokeh.so+0x95134)
#3 0x74ad8904cc (/vendor/lib64/libanc_single_rt_bokeh.so+0x8f4cc)
#4 0x74ad8901ec (/vendor/lib64/libanc_single_rt_bokeh.so+0x8f1ec)
#5 0x74ad876f88 (/vendor/lib64/libanc_single_rt_bokeh.so+0x75f88)
#6 0x74ad874818 (/vendor/lib64/libanc_single_rt_bokeh.so+0x73818)
#7 0x74ad874644 (/vendor/lib64/libanc_single_rt_bokeh.so+0x73644)
#8 0x74ad8753ac (/vendor/lib64/libanc_single_rt_bokeh.so+0x743ac)
#9 0x7541fd8b60 (/apex/com.android.runtime/lib64/bionic/libc.so+0xe6b60)
#10 0x7541f76b6c (/apex/com.android.runtime/lib64/bionic/libc.so+0x84b6c)
0x0073896a5300 is located 1555200 bytes inside of 2332800-byte region [0x007389529800,0x007389763080)
freed by thread T100 (HwBinder:26851_) here:
SUMMARY: AddressSanitizer: heap-u-after-free (/system/lib64/libclang_rt.asan-aarch64-android.so+0x7179c)
Shadow bytes around the buggy address:
0x001e712d4a10: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4a20: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4a30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4a40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4a50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x001e712d4a60:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4a70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4a80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4a90: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4aa0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x001e712d4ab0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte reprents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack u after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by ur: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
空指针问题