android 如何分析应用的内存(十二)

上一篇介绍了ASan,这次介绍ASan的加强版HWASan

HWASan的使用

从NDK r21和Android 10 开始,Android支持HWAsan。HWAsan仅仅支持arm64架构的设备。

系统级准备

HWASan需要系统的支持,因此,需要重新编译系统镜像。可以是android模拟器,也可以是真机。
本次实验,选择了Pixel3的真机作为演示。同时使用了android-12.0.0_r34分支。

第一步:初始化repo

mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

第二步:同步代码,如下:

repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-12.0.0_r34
repo sync -j32

这里使用了清华镜像站。可以参考:https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/

第三步:下载设备相关的驱动,下载地址:https://developers.google.cn/android/drivers?hl=zh-cn

## 在aosp的根目录下创建一个vendor目录
mkdir vendor 
## 解压下载的文件
cd vendor
tar -xzvf ../google_devices-blueline-sp1a.210812.016.c2-47172864.tgz
## 运行解压之后的脚本
./extract-google_devices-blueline.sh

第四步:开始编译,并打开HWASan的编译开关

## 初始化环境
. build//envsetup.sh
## 选择编译的目标
lunch aosp_blueline-userdebug
## 打开HWASan开关
export SANITIZE_TARGET=hwaddress
## 开始编译
m -j32

注意:这里仅仅是为了演示,如果在开发中,可以参考,下面的链接,进行文件配置:https://cs.android.com/android/platform/superproject/+/master:device/google/coral/aosp_coral_hwasan.mk?hl=zh-cn

第五步:下载编译好的镜像到手机中

## 进入bootloader模式.或者长按电源键和音量下键进入bootloader模式
adb reboot bootloader 
## 使用fastboot 刷入
fastboot flashall -w

一切ok之后,手机重启,可检查手机是否是正常刷入。如下
在这里插入图片描述

注意:如果出现:“No valid slot to boot” 错误。请执行第三步

系统级准备(非自我编译)

除了可以自己编译aosp的镜像以外,还可以使用已经编译好的镜像。访问如下网址https://flash.android.com/
然后允许“allow adb access”。

然后选择aosp_blueline_hwasan-userdebug即可。截图如下
在这里插入图片描述

启用HWASan

同ASan一样,只需要改变编译选项即可。如下

APP_STL := c++_shared # Or system, or none, but not c++_static.
APP_CFLAGS := -fsanitize=hwaddress -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=hwaddress

或者在cmake中做如下配置

target_compile_options(test_malloc PUBLIC -fsanitize=hwaddress -g -O0 -fno-omit-frame-pointer)
set_target_properties(test_malloc PROPERTIES LINK_FLAGS -fsanitize=hwaddress )

他们和ASan的配置几乎一模一样。

注意-fsanitize后面的名字即可。

但是需要注意的是,在使用Cmakefile.txt时,需要在build.gradle文件中做如下配置

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                # Can also use system or none as ANDROID_STL, but not c++_static.
                arguments "-DANDROID_STL=c++_shared"
            }
        }
    }
}

为何要配置-DANDROID_STL=c++_shared

设置Android的STL为c++_shared。如果不设置,Android会使用默认的STL,这个默认的STL在编译的时候,通常不带有栈帧指针。

注意:如同ASan配置一样,HWASan也需要将相应的运行时库,放入项目中。它与ASan运行时库的位置相同。

测试

在测试代码中,加入如下的错误使用:

//分配一个int大小的空间
volatile int * pInt  = (volatile int *)malloc(sizeof(int));
//访问的时候,超出这个int大小的空间
*(pInt+6) = 12345;

则会看到如下的测试结果
在这里插入图片描述

解析

从上面的log输出中,解析如下栈帧

 #0 0x7909126710  (/data/app/~~KRSuefEcZY9JtCH0m729KA==/com.example.test_malloc-NzWK4ADc7lagct58AY6Qnw==/lib/arm64/libtest_malloc.so+0x4710)

解析过程如下
在这里插入图片描述
可以看到出现问题在native-lib.cpp的第219行15列

HWASan忽略错误,继续运行

在编译选项中加入-fsanitize-recover=hwaddress,在运行时选项中,加入halt_on_error=0
分别如下:
在这里插入图片描述

在这里插入图片描述

HWASan查看所有支持的选项

在运行时选项中,加入help=1.如下:

export HWASAN_OPTIONS=allow_user_segv_handler=1,halt_on_error=0,help=1

剩下的选项,和ASan类似,不再做过多的介绍,可参考上一篇文章:android 如何分析应用的内存(十一)——ASan

同上一篇文章一样,在做内存泄漏检测的时候,没有通过,所以没有列出,后续可能会补充。

诚然,这篇文章和上篇文章,已经脱离了内存分析的范围,转向了指针错误使用的范畴。但考虑到整个知识框架的完整性,也依然将其列出。后续若有读者能找到更好的资料,感谢分享~

至此,HWASan介绍完毕,本来这部分应该多写一点。多出来的内容应该在aosp的编译上面,但是考虑到这是介绍内存的文章,就不再过多介绍aosp的编译了,只是对需要用的编译过程做了描述。

下面是native的最后一个部分,perfetto的使用

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐