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的使用