DevEcoTesting-for-handle-leak:”探索测试“工具的发掘利用与AI赋能的内存泄漏检测和复现(上)

01 引言

任何APP开发过程中,代码引起的内存泄漏都难以避免,其中有一些内存泄漏还可能会引起重大事故。以往的鸿蒙APP内存泄漏检测基本采用 人类 手工探索APP的方式,进行反复的点击、滑动、输入等操作,并实时监测内存泄漏日志或拉取内存快照进行分析。这种方式不但耗费人力,还效率极低,便自然地联想到鸿蒙开发者的一柄利器------ DevEcoTesting ,这是一款鸿蒙应用测试工具,可以提供多种测试功能,我们在其 探索测试 功能上进行了新的研究,对探索测试的产物进行了再次发掘利用。

02 摘要

本文从将从以下几方面来讨论该标题的前半部分------DevEcoTesting-for-handle-leak:"探索测试"工具的发掘利用:

  • 生成并找到DevEcoTesing探索测试产物
  • 分析探索测试产物结构与内容
  • 发掘利用探索测试产物

03 生成并找到DevEcoTesing探索测试产物

对于DevEcoTesting的数据路径,在安装时会选择一次,如果忘记了,可以在设置里找到该路径

想要实现探索测试功能,只需要连接开发者模式的鸿蒙系统手机,开启USB调试后,在探索测试-应用探索测试对某个APP启动测试即可。

04 分析探索测试产物结构与内容

以我的设置举例,每一次探索测试的产物文件夹都存放在"D:\huwei\devecotesting\data\43120\tasks"这个目录下,可以通过创建时间来区分是哪一次测试的产物。

进入某一个目录后的结构是这样的:

这里我们使用 recorddata 目录进行后续分析。首先分析record目录下的内容,只有eventSequence.json这一个文件,我们来分析它的内容:

json 复制代码
{"event":"operation","timeStamp":1770282910418,"uri":"","exactSceneId":"","actionList":[]}
{"event":"operation","timeStamp":1770282920770,"uri":"","exactSceneId":"09FC6EBCE4E86A82152CD143ABF7D39D","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Stack/Stack/Swiper"}]}
{"event":"operation","timeStamp":1770282927063,"uri":"","exactSceneId":"B810969532282B290C1C46817C3786E1","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Stack/Stack/Swiper"}]}
{"event":"operation","timeStamp":1770282933475,"uri":"","exactSceneId":"09FC6EBCE4E86A82152CD143ABF7D39D","actionList":[{"type":"CLICK","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Row/Stack[4]"}]}
{"event":"operation","timeStamp":1770282938853,"uri":"","exactSceneId":"9389E3D9E803F8262C7907662FEFD66F","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/RelativeContainer/Column[0]/__Common__/Column/Refresh"}]}
{"event":"operation","timeStamp":1770282944824,"uri":"","exactSceneId":"3AD1F91195F2E9CF1D0B3343F688BA4A","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/RelativeContainer/Column[0]/__Common__/Column/Refresh"}]}
{"event":"operation","timeStamp":1770282950967,"uri":"","exactSceneId":"9389E3D9E803F8262C7907662FEFD66F","actionList":[{"type":"CLICK","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Row/Stack[3]"}]}
{"event":"operation","timeStamp":1770282955646,"uri":"","exactSceneId":"2B121B27A0A7D1D7ABA4596B812C9AB9","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Stack/Navigation/NavBar/NavBarContent/Stack/Stack/Stack/Stack[0]/Stack/List"}]}
{"event":"operation","timeStamp":1770282961489,"uri":"","exactSceneId":"5A0656898D33E060CD1D769314010AAB","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Stack/Navigation/NavBar/NavBarContent/Stack/Stack/Stack/Stack[0]/Stack/List"}]}
{"event":"operation","timeStamp":1770282966881,"uri":"","exactSceneId":"2B121B27A0A7D1D7ABA4596B812C9AB9","actionList":[{"type":"CLICK","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Row"}]}
{"event":"operation","timeStamp":1770282971408,"uri":"","exactSceneId":"18F69BF6132F1F85AFD2ED0D0B5A8390","actionList":[{"type":"CLICK","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Row/Stack[2]"}]}
{"event":"operation","timeStamp":1770282976128,"uri":"","exactSceneId":"18F69BF6132F1F85AFD2ED0D0B5A8390","actionList":[{"type":"CLICK","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Row/Stack[1]"}]}
{"event":"operation","timeStamp":1770282980397,"uri":"","exactSceneId":"8439DBF823E2C79AE9E5759B55674BBC","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Column/Stack/Column[0]/Stack/Swiper"}]}
{"event":"operation","timeStamp":1770282985457,"uri":"","exactSceneId":"6598A30D8A7BFDCB28F3A3C66206C479","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Column/Stack/Column[0]/Stack/Swiper"}]}
{"event":"operation","timeStamp":1770282990256,"uri":"","exactSceneId":"6598A30D8A7BFDCB28F3A3C66206C479","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Column/Stack/Column[0]/Stack/Swiper"}]}
{"event":"operation","timeStamp":1770282994943,"uri":"","exactSceneId":"6598A30D8A7BFDCB28F3A3C66206C479","actionList":[{"type":"PRESS_BACK","xpath":"PRESS_BACK"}]}
{"event":"operation","timeStamp":1770283001679,"uri":"","exactSceneId":"8439DBF823E2C79AE9E5759B55674BBC","actionList":[{"type":"CLICK","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Row/Stack[0]"}]}
{"event":"operation","timeStamp":1770283006745,"uri":"","exactSceneId":"09FC6EBCE4E86A82152CD143ABF7D39D","actionList":[{"type":"CLICK","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Stack/Stack/__Common__/Stack/Column[1]/__Common__/Column/Row/Column/Column/Row/Stack[3]"}]}
{"event":"operation","timeStamp":1770283011206,"uri":"","exactSceneId":"98192559725181F7B41187DFC12CE972","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Stack/Stack/Swiper"}]}
{"event":"operation","timeStamp":1770283016569,"uri":"","exactSceneId":"98192559725181F7B41187DFC12CE972","actionList":[{"type":"SWIPE","xpath":"/root/RelativeContainer/Column/Stack/Navigation/NavBar/NavBarContent/Stack/Swiper/Stack/Stack/Stack/Swiper"}]}

这里会记录DevEcoTesting的每一次操作的时间戳、类型、对象、内容(多在输入操作时存在)。

接下来分析data目录下的内容,有一个设备号\resources目录,其中有layoutscreenshot两个子目录。

screenshot目录下保存了DevEcoTesting在探索过程中的APP截图,layout目录下存放了这些时间戳对应的APP布局文件。

05 发掘利用探索测试产物

首先需要引入一些命令:

bash 复制代码
# 获取已连接设备列表
hdc list targets

# 禁用hilog二进制加密
hdc shell param set persist.sys.hilog.binary.on false

# 清理遗留的hilog
hdc rm data/log/hilog/*

# 监听hilog并捕获疑似内存泄漏点,可在子线程流式执行防止阻塞
# "handle leak"是hilog的tag,根据系统版本不同可能略有不同
hdc shell hilog | grep "handle leak"

这里为什么是 疑似 内存泄漏呢?是因为在内存异常增长时都会产生handle leak的日志,这有可能是进入新页面的缓存引起的,而非组件没有释放内存和回收。

通过这些命令,我们可以得到捕获到handle leak的命令,并记录其时间戳,提取其后面输出的栈状态,通过每一个被捕获点的栈状态作为唯一标识进行聚合和统计。如下:

arduino 复制代码
"#00 pc /system/lib64/platformsdk/libark_jsruntime.so",
"#01 pc /system/lib64/platformsdk/libark_jsruntime.so",
"#02 pc /system/lib64/platformsdk/libark_jsruntime.so",
"#03 pc /system/lib64/platformsdk/libace_napi.z.so",
"#04 pc /data/storage/el1/bundle/libs/arm64/libxuanji.so",
"#05 pc /data/storage/el1/bundle/libs/arm64/libxuanji.so",
"#06 pc /data/storage/el1/bundle/libs/arm64/libxuanji.so",
"#07 pc /data/storage/el1/bundle/libs/arm64/libxuanji.so",
"#08 pc /data/storage/el1/bundle/libs/arm64/libxuanji.so",
"#09 pc /data/storage/el1/bundle/libs/arm64/libxuanji.so",
"#10 pc /system/lib64/platformsdk/libuv.so",
"#11 pc /system/lib64/platformsdk/libuv.so",
"#12 pc /system/lib64/platformsdk/libruntime.z.so",
"#13 pc /system/lib64/platformsdk/libruntime.z.so",
"#14 pc /system/lib64/chipset-pub-sdk/libeventhandler.z.so",
"#15 pc /system/lib64/chipset-pub-sdk/libeventhandler.z.so",
"#16 pc /system/lib64/chipset-pub-sdk/libeventhandler.z.so",
"#17 pc /system/lib64/chipset-pub-sdk/libeventhandler.z.so",
"#18 pc /system/lib64/platformsdk/libappkit_native.z.so",
"#19 pc /system/lib64/appspawn/appspawn/libappspawn_ace.z.so",
"#20 pc /system/bin/appspawn",
"#21 pc /system/bin/appspawn",
"#22 pc /system/bin/appspawn",
"#23 pc /system/lib64/chipset-pub-sdk/libbegetutil.z.so",
"#24 pc /system/lib64/chipset-pub-sdk/libbegetutil.z.so",
"#25 pc /system/lib64/chipset-pub-sdk/libbegetutil.z.so",
"#26 pc /system/lib64/chipset-pub-sdk/libbegetutil.z.so",
"#27 pc /system/bin/appspawn",
"#28 pc /system/bin/appspawn",
"#29 pc /lib/ld-musl-aarch64.so.1",
"#30 pc /system/bin/appspawn"

这里实际是忽略了包内偏移的,即默认同一个so文件内的函数运行状态不代表宏观状态,这样既能聚合很多本质上相同、但包内函数运行位置有微小差别的内存泄漏点,又能在一定程度上实现不过度聚合、不漏报。

此时,我们便得到了所有疑似内存泄漏的时间戳。回顾前两节的内容,我们此时可以用这些时间戳在eventSequence.json中寻找时间戳前最近的几个操作事件,根据这几个操作事件的时间戳在screenshot下找到操作前后对应的截图。因为已知操作场景、操作类型、操作内容、操作结果,此时已经可以较容易地人工进行复现与压力测试了,此外,还可以去layout目录下找到对应的布局文件,进一步确认具体的操作组件,更准确地复现和压力测试。

至此,已经可以通过DevEcoTesting来做全流程的内存泄漏监测与复现压力测试了,前半部分完结,接下来将对AI赋能的内存泄漏点复现与压力测试进行讨论。

相关推荐
Swift社区4 小时前
鸿蒙游戏中的“智能 NPC”架构设计
游戏·华为·harmonyos
2601_949593655 小时前
Flutter_OpenHarmony_三方库_webview_flutter网页内容嵌入与交互适配详解
flutter·harmonyos
前端不太难6 小时前
为什么 AI 游戏更适合鸿蒙?
人工智能·游戏·harmonyos
特立独行的猫a7 小时前
HarmonyOS 鸿蒙PC三方库移植:vcpkg方式的 Port 脚本编写简明教程
华为·harmonyos·openharmony·vcpkg·三方库移植
Ww.xh7 小时前
鸿蒙Flutter混合开发实战:跨平台UI无缝集成
flutter·华为·harmonyos
chenbin___7 小时前
鸿蒙RN position: ‘absolute‘ 和 zIndex 的兼容性问题(转自千问)
前端·javascript·react native·harmonyos
苏杰豪8 小时前
DevEco Studio 启动鸿蒙模拟器提示未开启 Hyper-V,怎么处理?
华为·harmonyos
chenjixue8 小时前
记录下我理解的安卓,鸿蒙,ios, rn , fullter, Jetpack Compose,react 的相似与不同
android·华为·harmonyos
想你依然心痛9 小时前
HarmonyOS 6(API 23)悬浮导航与沉浸光感实战:打造下一代玻璃拟态UI体验
ui·华为·harmonyos·悬浮导航·沉浸光感