Android稳定性-01-Android 系统稳定性测试到底在测什么
做 稳定性测试目标 相关的 Android 稳定性测试时,最重要的不是先给现象下结论,而是把问题放回系统链路里。
把设备、系统服务、应用和硬件能力放在持续运行、异常输入、资源压力、恢复流程里验证,而不是只统计有没有 Crash。
这篇文章的目标不是罗列术语,而是把测试人员在现场应该问的问题、应该抓的证据、应该避免的误判,以及可以交付给开发的输出物写清楚。
一、具体问题背景
很多团队把稳定性测试等同于 Monkey 或长稳压测,跑完以后只得到一堆崩溃日志和截图。这样的测试能发现问题,但很难说明覆盖了什么、遗漏了什么、风险是否可接受。
真正的系统稳定性测试要回答三个问题:系统是否持续可用,异常后是否可恢复,问题发生时是否可诊断。只要其中一个答案含糊,报告就不能支撑版本发布。
围绕“Android 系统稳定性测试到底在测什么”,测试同学需要从现象、时间线、层级和证据四个维度同时推进。只描述用户看到什么不够,还要说明系统内部哪个阶段开始偏离基线。
稳定性缺陷的价值不只在复现,还在于缩短定位路径。一个高质量问题单应当让接手开发能立刻知道先看哪类日志、哪个进程、哪个服务、哪个时间点。
二、它在 Android 稳定性测试里的位置
系列入口,负责定义测试边界、证据标准、风险分级和输出物格式。后续架构、核心进程、Binder、启动、Crash/ANR、底层异常和典型现象,都是在这个测试框架下展开。
在测试计划里,它不是孤立专项,而是和 Monkey、长稳、启动、功耗、性能、温度、网络、媒体、相机、车机/平板/手机形态的业务场景交叉。交叉越多,越需要统一的证据标准。
如果这一层没有定义清楚,后续问题会出现两个后果:严重问题被轻描淡写,偶发问题因为缺少证据无法关闭。
三、先给问题建立分层模型
围绕 稳定性测试目标,建议先按下面几层拆解。分层不是为了显得复杂,而是为了避免在错误层级反复试错。
用户可见层:桌面、关键应用、导航、输入、显示、音频、网络是否保持可用。
Framework 与系统服务层:ActivityManager、WindowManager、PackageManager、Power、Input、Display 等服务是否稳定响应。
Native 与 HAL 层:SurfaceFlinger、media、audio、camera、vendor HAL 是否阻塞、崩溃或返回异常。
Kernel 与硬件层:调度、内存、文件系统、驱动中断、电源状态是否出现 panic、OOM、hung task 或复位。
测试报告里最好显式写出当前证据支持哪一层、排除了哪一层、还有哪一层没有证据。这样开发、测试和项目经理对风险边界会更一致。
四、关键观察对象和判断信号
现场判断可以先抓四类信号:时间信号、进程信号、资源信号和用户可见信号。时间信号用于对齐问题发生点,进程信号用于判断影响范围,资源信号用于发现压力来源,用户可见信号用于评估严重度。
不要只问“有没有复现”。更有价值的问题是:复现前系统有没有变慢,复现时哪个服务先异常,复现后系统能否自动恢复,恢复后是否留下 dropbox、tombstone、pstore 或 traces。
对于 稳定性测试目标,最应该记录的不是单条日志,而是从触发动作到异常出现之间的完整链路。只要链路完整,即使偶现一次也能推进定位。
五、关键命令和日志入口
下面这些命令不是每次都全部执行,但它们覆盖了最常用的入口。测试脚本可以按场景自动化保存,避免人工复现时漏抓。
基础现场:
1 | adb devices -l |
采集 基础现场 时要同时记录设备时间、电脑时间和测试步骤编号,否则后续很难把日志与操作对齐。
系统日志:
1 | adb logcat -b all -v threadtime -d > logcat_all.txt |
采集 系统日志 时要同时记录设备时间、电脑时间和测试步骤编号,否则后续很难把日志与操作对齐。
资源快照:
1 | adb shell dumpsys meminfo |
采集 资源快照 时要同时记录设备时间、电脑时间和测试步骤编号,否则后续很难把日志与操作对齐。
稳定性专项:
1 | adb shell dumpsys dropbox --print |
采集 稳定性专项 时要同时记录设备时间、电脑时间和测试步骤编号,否则后续很难把日志与操作对齐。
六、测试维度和证据表
| 观察项 | 主要判断 | 证据入口 |
| — | — | — |
| 长稳运行 | 长时间运行后是否劣化 | 内存泄漏、句柄泄漏、系统服务阻塞 |
| 压力与扰动 | 资源紧张时是否可控 | OOM、LMKD、调度延迟、I/O 堵塞 |
| 恢复能力 | 异常后能否回到可用状态 | 服务重启、进程拉起、网络恢复、亮灭屏恢复 |
| 可诊断性 | 证据是否足够定位 | bugreport、dropbox、tombstone、last_kmsg、trace |
表格里的入口要和问题单附件一一对应。只写“已抓日志”没有意义,最好写清楚附件名、采集时间、采集命令和异常时间点。
七、时间线比单点日志更重要
稳定性问题经常不是瞬间发生,而是先有资源曲线变化,再出现服务延迟,最后才变成用户可见故障。没有时间线,分析者只能在一堆日志里猜。
建议至少记录四个时间点:场景开始时间、最后一次正常时间、首次异常时间、恢复或重启时间。若是自动化场景,应把脚本步骤号、seed、循环次数和设备状态写入日志。
对于 稳定性测试目标,时间线还要覆盖相关进程或服务的状态变化。比如 PID 是否变化、服务是否重启、关键属性是否切换、队列长度是否增长。
八、分层分析方法
第一步先确认用户可见现象是否稳定复现:Android 系统稳定性测试到底在测什么 不能只靠截图描述,要说明触发条件、复现概率和影响范围。
第二步判断问题停留在哪个系统层级。App 层看主线程和生命周期,Framework 看服务调用和状态机,native/HAL 看 tombstone 与 service dump,Kernel 看 pstore、dmesg、bootreason 和资源压力。
第三步寻找“第一个异常”。后面的 Crash、ANR、重启、黑屏可能只是连锁反应。时间上最早、影响范围最大、能解释后续现象的证据,通常更接近首因。
第四步形成可验证假设。好的初步归因应该能推出验证动作:如果是资源泄漏,长稳曲线应改善;如果是 Binder 等待,服务端栈应变化;如果是驱动 hang,pstore 或 vendor log 应不再出现同类签名。
九、如何区分必现、偶现和环境问题
必现问题更适合缩短路径,先做最小复现;偶现问题更依赖自动化证据和周期性快照;环境问题则要把外设、网络、温度、电量、账号、数据量、SIM/蓝牙/Wi-Fi 状态写清楚。
不要因为问题偶现就降低严重度。系统级稳定性问题即使概率低,只要影响重启、黑屏、核心服务不可用,也应该按高优先级处理。
也不要因为环境复杂就放弃归因。复杂环境可以拆成变量矩阵:单设备/多设备、充电/不充电、弱网/正常网络、高温/常温、清数据/保留数据、首启/非首启。
十、完整案例:长稳 18 小时后桌面无响应但未重启
**现象:**自动化脚本在解锁后点击桌面图标无反应,屏幕仍亮,adb 可连接,未观察到整机重启。
**采集:**立即保存 logcat all、bugreport、dumpsys activity、dumpsys window、dumpsys input、top -H、dropbox,并记录脚本最后一次成功动作时间。
**分析:**logcat 中未见 FATAL EXCEPTION,但 system_server 主线程多次出现 Binder 调用耗时;dumpsys input 显示事件进入队列但窗口焦点长时间不切换;meminfo 显示某预装服务 PSS 持续上升。
**初步归因:**不是单纯桌面 App 卡死,而是系统服务处理窗口/输入链路被资源泄漏拖慢,最终表现为点击无响应。
**修复验证:**替换修复包后复跑 3 轮 24 小时长稳,加入每小时 meminfo 与 input/window 快照,确认 PSS 曲线稳定、事件延迟未再累积。
这个案例的关键点是把现象和系统链路连接起来。问题单里应避免只写最终结论,而要保留从采集到分析再到验证的路径。
如果后续修复没有覆盖原始触发条件,只能说明某个局部现象暂时消失,不能说明稳定性风险已经关闭。
十一、常见误判
只看 Monkey 结果,不看测试期间是否出现可恢复异常。
把所有无响应都归为 App 问题,忽略 system_server、Input、Window 和 Binder。
只提交最后一段 logcat,导致重启前证据丢失。
用单次复现判断修复成功,没有复跑长稳和压力组合。
误判的共同原因是证据太窄:只看一个进程、只看最后一段日志、只看用户态、只看平均指标。稳定性测试要主动扩展证据宽度。
十二、检查清单
测试目标是否区分可用性、恢复性、诊断性
是否记录 build、设备状态、测试时长、脚本版本
是否有基线版本作为对照
是否保存 bugreport、logcat、dropbox、tombstone、内核日志
是否把现象映射到系统层级
是否给出复现概率和影响范围
是否定义阻塞发布的门禁阈值
修复后是否做同场景回归和扩大场景回归
清单不是形式化动作。每一项都应该对应报告里的文字、附件或图表。没有证据的勾选应当视为无效。
十三、输出物模板
下面是一份可以直接放进缺陷系统的输出物模板。字段可以按团队习惯调整,但核心信息不要省略。
1 |
|
十四、和自动化平台的结合
如果测试平台只保存最终结果,稳定性分析会非常被动。建议平台在每轮场景开始、每次失败、每小时巡检、设备离线、重启后上线这几个节点自动拉取快照。
快照内容至少包括 logcat ring buffer、top、meminfo、cpuinfo、关键 dumpsys、设备属性、温度、电量、存储空间和进程列表。底层问题还要尽量拉 pstore 或触发 sysrq。
针对 稳定性测试目标,平台还可以把关键指标做趋势图。趋势图能把“偶现”变成“异常前已有征兆”,这是长稳测试最有价值的部分。
十五、修复验证怎么做才算闭环
修复验证不能只跑一次原步骤。至少要包含原始复现场景、扩大压力场景、长时间稳定性场景和相邻功能回归。
验证时要比较修复前后的关键证据,而不是只看现象有没有再出现。比如耗时是否下降、PID 是否稳定、内存是否不再增长、队列是否不再堆积、bootreason 是否不再出现同类值。
如果问题原本是偶现,验证轮次要按风险提高。影响重启、黑屏、核心服务不可用的问题,建议至少多设备、多轮次、跨夜验证。
十六、交付给开发时的沟通重点
好的稳定性问题单应当降低开发的第一小时成本。开发打开问题后,应能立刻看到异常时间、首个异常、关键附件、初步假设和建议查看的模块。
沟通时尽量避免“感觉像”“可能是系统问题”这种表述。可以写“当前证据显示调用端等待某服务返回,但服务端线程栈还缺失,需要补抓”。这比泛泛甩锅更容易推进。
如果证据不足,也要明确不足在哪里:缺少重启前 pstore,缺少服务端栈,缺少 perfetto,缺少对照版本。把缺口写清楚,本身就是有效输出。
十七、扩展阅读和后续文章关联
这篇文章与系统架构、核心进程、Binder、启动流程、问题分类、底层异常和典型现象是互相补充的。遇到复杂问题时不要只停在本文,而要按链路跳到对应专题继续分析。
如果问题表现为 App 到系统服务调用卡住,优先回到 Binder;如果表现为开机或桌面异常,优先回到启动流程和核心进程;如果表现为重启或 adb 断开,优先回到底层稳定性;如果表现为黑屏、卡顿、无响应,则按典型现象链路拆。
十八、专项场景设计
围绕 稳定性测试目标,专项场景不能只追求时长,还要覆盖容易触发状态切换的路径。长时间运行能发现累积问题,但很多稳定性缺陷发生在切换瞬间:进前台、退后台、亮屏、灭屏、网络切换、包扫描、服务重启、资源回收。
建议把场景拆成“基线场景、压力场景、扰动场景、恢复场景”四类。基线场景用于确认版本本身是否正常,压力场景用于放大资源瓶颈,扰动场景用于打断状态机,恢复场景用于确认异常后系统是否能回到可用状态。
Monkey 与定向业务混跑:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
待机唤醒与亮灭屏循环:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
弱网切换和账号同步:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
低内存与存储逼近阈值:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
充电高温长时间运行:执行前记录设备状态,执行中保留周期快照,执行后确认关键进程、关键服务和用户可见状态是否回到基线。
场景设计还要注意互斥变量。比如高温和低电量同时出现时,不能直接把结果归因到单一模块;弱网和低内存同时出现时,要用对照组拆开网络等待与资源回收。
十九、指标基线和异常阈值
稳定性测试目标 的指标建议至少覆盖:可用时长、异常恢复时间、Crash/ANR 密度、系统重启次数、关键服务响应时间。指标不是为了做漂亮报表,而是为了在问题出现前发现趋势,在问题出现后支撑归因。
| 指标类型 | 记录方式 | 判断方法 |
|---|---|---|
| 稳态指标 | 固定周期采集 可用时长 等数据 | 和同版本前一轮、上一稳定版本、同批设备对比 |
| 瞬时指标 | 异常发生时立刻抓取 dumpsys、top、trace、日志 | 观察是否有突增、阻塞、服务重启或队列堆积 |
| 趋势指标 | 每 5 到 15 分钟保存一次快照 | 观察是否单调增长、周期性抖动或在触发动作后不恢复 |
| 门禁指标 | 和发布标准绑定 | 超过门禁直接阻塞或要求风险签核 |
阈值不要只写绝对数字。更稳妥的方式是同时给出绝对阈值、相对退化比例和用户影响。例如启动时间增加 20% 且超过产品体验线,比单纯写“启动慢”更容易决策。
二十、证据判读细节
判读日志时先看时间,再看层级,最后看具体错误。很多日志里会有大量 warning,它们未必是根因;真正有价值的是第一个状态变化、第一次耗时超阈值、第一次进程死亡、第一次资源压力异常。
对 稳定性测试目标 来说,建议把证据分成三列:已经证明的事实、合理怀疑的方向、仍然缺失的证据。事实只能来自日志、dump、trace、截图、平台记录;怀疑可以写,但必须说明下一步用什么验证。
如果多个证据互相矛盾,不要强行给结论。比如用户看到黑屏但 Window 显示可见,可能说明问题在 Surface 或 HWC;如果 boot_completed 已经为 1 但桌面不可交互,说明启动完成和可用完成不是同一个概念。
二十一、缺陷分级和发布风险
系统重启、system_server Watchdog、核心链路黑屏不可恢复应作为阻塞项;普通应用 Crash 要结合频率、是否预装、是否影响主路径分级。
分级时建议同时考虑四个因素:影响范围、恢复能力、复现概率和证据完整度。影响范围越接近系统全局,恢复能力越差,复现概率越高,优先级越高。证据不完整不代表风险低,只代表需要补采。
对于阻塞类问题,报告里要明确写出阻塞理由:是否导致重启、是否导致核心功能不可用、是否影响首启或主路径、是否无法自动恢复、是否存在数据丢失风险。这样项目讨论时不会只围绕“复现概率高不高”打转。
二十二、复现最小化策略
稳定性问题经常来自复杂场景,但修复定位需要最小化路径。最小化不是删除所有条件,而是逐步去掉不必要变量,保留能触发同一异常签名的关键条件。
可以按下面顺序缩小:先固定版本和设备,再固定脚本 seed,再固定业务步骤,再拆掉网络、温度、外设、数据量等变量。每去掉一个变量,都要确认异常签名是否仍然一致。
如果 稳定性测试目标 的异常只在复杂场景出现,也要把复杂场景保留下来作为验收场景。最小复现用于定位,原始长链路用于验证修复没有只覆盖局部。
二十三、修复验证的对照方法
修复验证至少需要三个对照:修复前问题版本、修复后目标版本、已知稳定基线版本。没有基线时,只能证明“本轮没复现”,很难证明退化已经恢复。
验证报告要比较关键证据,而不是只写 pass。比如修复前线程栈卡在同一锁,修复后不再出现;修复前内存持续增长,修复后曲线稳定;修复前 bootreason 是 watchdog,修复后多轮压力不再出现。
如果修复涉及底层、核心服务或公共 Framework,验证范围要扩大到相邻功能。一个局部修复可能改变时序,导致其他链路出现新的稳定性问题。
二十四、团队协作边界
测试、应用、Framework、系统服务、驱动和平台团队需要共享同一条时间线。测试负责把现象和证据收齐,开发负责解释模块内部状态,平台负责补齐自动化采集和趋势报表。
不要把“归属不清”变成问题停滞的理由。归属不清时,先由最能解释第一异常的模块牵头,同时列出需要其他模块补充的证据。这样比在缺陷系统里反复改 owner 更有效。
只用单一 Monkey 指标会掩盖恢复能力和诊断能力,版本看似稳定,实际可能在亮灭屏、弱网或资源压力下快速劣化。
二十五、排障决策树
稳定性测试目标 的排障可以写成一棵简单决策树。第一问不是“哪个模块错了”,而是“当前证据能否说明问题发生在哪个层级”。先判断影响的是单应用、系统能力还是整机;再判断是否可恢复;最后判断证据是否足以复现和关闭。
1 | 用户可见现象 |
如果决策树走到某一步没有证据,就不要跳过。缺少证据本身要写进问题单,并在下一轮复现前补上自动采集。这样做会让偶现问题逐步收敛,而不是每次复现都从头开始。
二十六、附件命名和归档规范
稳定性问题的附件经常很多,命名混乱会直接增加分析成本。建议按“时间点_设备_场景_内容”命名,例如 20260102-213000_deviceA_monkey_logcat_all.txt、20260102-213005_deviceA_after_anr_bugreport.zip。
同一问题至少保留三组附件:异常前最近一次周期快照、异常发生时即时快照、异常后恢复或重启后的快照。对于 稳定性测试目标,这三组附件能帮助判断异常是突然发生还是逐步劣化,也能排除恢复过程引入的新噪声。
归档时不要只上传压缩包。问题单正文里要列出关键附件索引:哪个文件看首个异常,哪个文件看进程状态,哪个文件看资源曲线,哪个文件看修复验证。开发不应该靠猜去翻附件。
二十七、回归矩阵示例
| 回归维度 | 基础用例 | 压力用例 | 通过标准 |
|---|---|---|---|
| 场景覆盖 | 长稳、Monkey、资源压力、恢复能力、诊断能力 | 在原场景上叠加长时间、弱网、低内存或高温 | 用户可见现象不复现,关键日志无同类签名 |
| 指标覆盖 | Crash/ANR 密度、重启次数、恢复时间、关键服务响应 | 周期采集并和基线对比 | 无持续增长、无明显退化、无门禁失败 |
| 设备覆盖 | 单设备复现验证 | 多设备、多批次或不同硬件版本 | 不出现设备特异性新增问题 |
| 时间覆盖 | 最小步骤验证 | 跨夜长稳或多轮循环 | 异常概率降到发布门禁以内 |
回归矩阵要和风险匹配。普通应用 Crash 可以用较小矩阵验证;影响 system_server、启动、显示、底层重启的问题,必须扩大设备数和时长,并保留完整证据链。
二十八、报告里的结论应该怎么写
结论不要写成“怀疑某模块问题”就结束。更好的写法是:当前证据支持什么,已经排除了什么,还缺什么,下一步如何验证。例如:当前 traces 显示调用端等待系统服务返回,服务端线程栈指向同一锁等待;暂未发现 Kernel panic 和进程死亡;下一轮需要补充 Binder transactions 与服务端 debug dump。
稳定性测试目标 的结论还要区分“现象结论”和“根因结论”。现象结论可以在证据不足时先给出,比如“桌面可见但输入无响应”;根因结论必须能被日志或代码变更验证,比如“某服务锁顺序导致 Binder 线程池耗尽”。
当修复验证完成后,结论应补上版本、验证轮次和残留风险:修复版本 X 在 3 台设备上完成 24 小时回归,未再出现同类日志签名;仍建议在 OTA 首启场景加入一轮扩展验证。这样的结论能支撑关闭,也方便后续版本追溯。
二十九、版本发布前复核
稳定性测试目标的发布复核重点,是确认测试结论能支撑版本决策。复核人要看覆盖是否包含主路径、长稳、压力、恢复和可诊断性;要看高优问题是否都有修复版本和验证证据;要看未修复问题是否有明确风险接受人。若报告只给通过率,不给异常时间线和证据链,就不能作为发布依据。
发布前还要复核附件是否能独立说明问题:一个不了解背景的人,只看问题单、时间线和附件索引,应该能够复原触发过程、看到第一个异常、理解初步归因,并知道修复验证覆盖了什么。如果做不到,说明报告还停留在“记录现象”,没有达到稳定性测试输出标准。
最后要复核残留风险。并不是所有问题都必须在当前版本修完,但每个残留问题都要说明影响范围、触发概率、规避方案、监控方式和后续计划。对用户可见的黑屏、无响应、重启、核心服务不可用,风险接受必须非常谨慎;对只在实验室极端压力下出现的问题,也要确认是否可能被真实用户路径触发。
这一步看起来像流程,实际是在保护版本质量。稳定性缺陷的代价通常发生在发布后,复核越具体,线上不可控风险越少。
三十、线上监控与问题复盘
稳定性测试不应该在版本发布时结束。发布后的监控要继续沿用测试阶段的分类和证据语言,否则实验室问题和线上问题会变成两套体系,复盘时很难合并。建议把 Crash、ANR、Watchdog、Native Crash、重启、黑屏、卡顿、无响应分别建立看板,并保留版本、设备、地区、触发路径和恢复结果。
线上监控要特别关注低频高损问题。一次系统重启、一次无法恢复的黑屏、一次 system_server watchdog,数量可能不高,但用户影响远大于普通闪退。看板不能只按数量排序,还要按影响范围和恢复能力排序。对系统稳定性来说,严重度和频率同样重要。
复盘时要回到测试设计本身:这个问题是否在实验室场景里覆盖过,覆盖过为什么没有发现,没有覆盖是因为场景缺失、采集缺失、门禁缺失,还是因为版本差异。复盘的输出应当转化为下一轮自动化场景、采集脚本、门禁阈值或检查清单,而不是只停留在“以后注意”。
还要建立问题签名库。相同堆栈、相同 bootreason、相同 tombstone top frame、相同 Binder 等待关系、相同 SurfaceFlinger/HWC 错误,都应该能被归并。签名库能减少重复分析,也能帮助判断修复是否真正覆盖同类问题。
最后,稳定性指标要服务于决策,而不是服务于报表。一个版本如果没有明显 Crash,但存在无法解释的重启;或者没有 ANR 弹框,但存在大量输入延迟和长帧;或者启动总耗时达标,但 Launcher 首帧后不可交互,这些都不能简单判定为稳定。测试结论必须回到用户是否可用、系统是否可恢复、问题是否可诊断这三个基本问题。
三十一、小结
Android 系统稳定性测试到底在测什么 的答案不是一个单指标,而是一套从现象到证据、从分层到归因、从修复到验证的闭环。
对测试同学来说,掌握 稳定性测试目标 的核心价值,是把“发现了一个问题”升级为“交付了一个可定位、可验证、可关闭的问题”。
稳定性测试的质量最终体现在报告是否能解释风险。只要报告能说明影响范围、首个异常、证据链、误判排除和验证结果,它就能真正帮助版本决策。