Android NE问题分析方法介绍

简介

NE,全称Native Exception,在Android中主要指在用户空间运行的native程序或者natvie库发生异常。NE问题通常带来程序奔溃现象,导致功能模块不稳定。

本文主要介绍有关NE的基本知识、NE问题出现后的基本分析方法、常见的NE问题和常用调试工具。

Native内存布局

这里主要介绍Native进程的虚拟地址空间,分32bit和64bit进程,cameraserver就是32bit的,而[email protected]_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_denselmk.so (BuildId: 5bb83f57711ebbf34c416d3feb706e)
00000070'ebc90000-00000070'ebc94fff ---         0      5000
00000070'ebc95000-00000070'ec2e8fff r-x    180000    654000  /vendor/lib64/libmegface_denselmk.so (BuildId: 5bb83f57711ebbf34c416d3feb706e)
00000070'ec2e9000-00000070'ec2f4fff ---         0      c000
00000070'ec2f5000-00000070'ec328fff rw-    7e0000     34000  /vendor/lib64/libmegface_denselmk.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 倍,

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值