Files

116 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Android 测试常见问题与排障
## WiFi 传输经验
- 原 `mobile.transport` 是 BLE 计数对象,不能改为字符串。实际业务链路使用新增 `mobile.active_transport`;以 BluezRuntime 组合后的状态测试,避免只测试 SessionManager 漏掉字段覆盖。
- `cmd wifi status` 的启用文字可能为 `Wifi` 或 `Wi-Fi`,只在内存中忽略大小写与连字符后判断,不输出包含 SSID/IP 的原始内容。
- `invokeOnCompletion` 不是协程异常处理器。网络监听的 collectLatest 内恢复屏障也可能因 BLE 已断开而失败;必须在 launch 主体捕获并结束会话,不能仅在完成回调做清理,否则可能断开成功后仍崩溃。
- 网络回调取消不能截断正在发出的加密 BLE 消息。通道协商/撤销须有界地完成 BLE 交换,再响应取消;旧网络回调按注册实例隔离。
- 无线开关恢复分为“启用命令完成”和“网络实际可用”。测试先等关闭稳定,再启用并等待 Network 回调;一次重测通过不能单独证明此前恢复超时的根因。
- 模拟器冷启动超时不代表 Compose 测试失败。先检查已有 Emulator、加速能力和登记系统镜像,不重复下载;可用独立进程记录启动诊断、确认 boot_completed 后运行选定场景。只关闭本次启动实例。
测试前阅读本文件及 [可重复测试流程](README.md)。这里维护可复用的方法;单次失败、重测次数、耗时与验收结果写入 `../测试结果归档/`。本页依据 [四栏版真机记录](../测试结果归档/2026-09-26_四栏界面优化.md) 整理,方法有效不等于所有同类错误均有相同根因。
## 1. root 命令在 instrumentation 中失败
主机 ADB 的 `su -c` 检查通过,但 `UiDevice.executeShellCommand("su -c '...'")` 失败时,先检查命令解析。该入口不能假设经过交互 shell;字符串中的引号不保证按 shell 语法处理。已验证做法是调用短时上传的 LF shell 辅助文件,由文件内部执行 `su -c "$*"`。布局检查使用 `authorized_root_command.sh`;点击、滑动、编辑使用有前台限制的 `authorized_app_input.sh`。运行器结束清理手机临时文件。
区分命令构造错误与真实权限不足。真实 root/ADB/授权不可用时停止等待用户,不继续测试、不使用普通注入或无障碍动作替代。辅助文件只用于已授权的本软件调试,不扩大用途。
## 2. Windows 写出的 shell 文件无法执行
CRLF 会破坏 Android/Linux shell 的解释器或参数。生成 `.sh` 使用显式 UTF-8/LF(例如 `Path.write_bytes`,或文本写入指定 `newline="\n"`),不要依赖 Windows 文本默认换行。上传前检查不含 CRLF;Git 的 `*.sh eol=lf` 不能代替对本次生成文件的检查。不要因脚本解析失败反复请求 root。
## 3. 布局变更终止测试进程
在 instrumentation 运行中改变密度、字体或方向,可能使应用/测试进程重建或终止。不要把此类 `Process crashed` 直接当成产品崩溃,也不要在同一进程里继续依赖原窗口句柄。
使用 `run_ui_layout_test.py`:电脑端先保存原密度覆盖、字体和旋转设置,在每组测试启动前设置目标布局;测试启动后显式启动 Activity,再读取语义节点并执行 root 输入。电脑端 `finally` 在正常结束或失败时恢复原值,原设置不存在时删除对应项,原密度未覆盖时使用 reset。字体/方向回读核验;若新增 USB 保持唤醒等设置改动,同样必须先保存、恢复并核验,不以默认值猜测。安全锁屏不能正常解锁时等待用户,不绕过密码。
## 4. 窗口转储看不到控件、文字重复或节点不可点击
独立 `uiautomator dump` 在本机 MIUI 上曾无法稳定读取 App 控件。使用已验证的持久 instrumentation 入口读取语义节点;读取不是无障碍动作注入。不要盲点坐标,也不要因此改用无障碍点击。
Compose 的可见文字节点未必有 clickable 标志,导航“连接”也可能与扫描结果按钮同名。先限制 App 包、当前页面/条目容器,再筛选可见且边界非空的节点;底栏可按同名可见节点位置选择。检查边界在当前屏幕内,重新读取中心点后执行 root tap。等待页面加载完成再取位置,布局变化后不可复用旧坐标。列表滚动只在语义识别出的本 App 可见滚动区域内执行 root swipe。
## 5. 找不到 DHCP 开关或密码可见复选框
Compose 语义树不保证使用 `android.widget.Switch`/`CheckBox` 类名。定位标签附近的 checkable 节点:按标签实时纵向范围筛选,并结合行内左右位置区分 DHCP 开关与密码可见复选框。点击后检查 checked 状态或静态地址字段是否出现;不要只认按钮类名,也不能用一个任意 checkable 节点代替。
## 6. 文本未清空、中文/密码输入失败、返回键退出 App
Ctrl+A 在该测试环境下不可靠。现有做法:App 前台进程设置临时剪贴板,root 点击实时字段位置,按 MOVE_END,再按当前文本长度加余量执行有界 DEL,最后 root paste。清空操作计数有上限,输入后回读字段核验。剪贴板在 `finally` 清理,密码不放 ADB 参数、日志或公开转储中。
仅在输入法实际显示时发送 BACK 收起键盘;否则 BACK 可能退出页面。使用 helper 的 `hide-keyboard` 分支检查 `mInputShown`。等“屏幕方向”等设置数据就绪后才展开 WiFi 表单,避免数据加载改变控件位置。
## 7. 保存按钮的禁用断言失败
Compose 的禁用语义可能位于父节点,文字节点自身仍 enabled。检查文字所在控件及祖先链的 enabled 状态,并结合实际行为(空名称不能打开确认/提交)判断;不要只断言文字节点的 enabled。
## 8. 安装成功后权限又被 MIUI 重置
`adb install` 成功不证明蓝牙权限稳定。现有运行器在覆盖安装后通过 root 授予本 App 必需权限,等待 3 秒并回读;最多三轮,仍未稳定则停止等待用户。不能无限重试,不能修改其他系统安全开关。测试前仍检查登记、ADB、root、前台和必要权限。
## 9. 连续测试的 BLE 扫描或握手偶发失败
每个正常测试阶段结束时通过连接页显式断开,等待释放后再结束进程;不要只依赖紧接着的 force-stop。异常时按失败阶段记录扫描、GATT、握手/任务是否已开始,清理旧测试会话后重新扫描,不跨会话复用临时句柄。主机超时不会自动终止 instrumentation,运行器还需结束本 App 的旧测试进程。
确需核验板端服务恢复时,先确认手机已断开,再执行 `check_mobile_lifecycle.py --restart-service`;它会真实停启服务并核验运行目录、持久摘要和接口恢复。保留首次失败,恢复后通过不证明偶发扫描失败的根因。若重现持续存在,停止反复重启,针对具体阶段排查,不降低超时/断言来制造通过。
## 10. WiFi 专项不具备第二网络、错误密码时 SSH 断开
`--validate-only`、`--wrong-only`、`--final-check` 不要求电脑热点;错误密码单测使用当前受管网络。跨 SSID 的 DHCP/静态往返才需要第二个可用网络;缺少时标未验证,不拿重应用原网络或表单测试替代。
任何真实切网先保存受保护原 NetworkManager 配置,并核验定时恢复已建立。错误密码可能使 SSH 断开,继续通过 BLE 查看任务,等待定时恢复;连通后比较原配置摘要、活动网络与服务状态,再清理备份和定时器。网络恢复没有核验就不能写通过,也不能提前删除唯一恢复材料。
失败任务必须区分提交前握手失败与已经提交后的网络失败。“密码错误”只在可靠认证证据/结构化 AUTH_FAILED 下通过验收;超时、缺少 secret 或未知错误不能强行归类。确认密码未进入日志,清理手机私有文件和临时剪贴板,最后执行 `--final-check`。
## 11. 测试完成后的固定复盘
每轮检查:本轮有哪些失败/调整、是否已有可重复防范步骤、恢复是否核验、哪些原因仍未知。已验证解法更新本页和对应流程/构建说明;一次性证据留归档,不能将未证实推测写成固定根因。
最终反馈写明经验已更新的文档,以及尚未解决的问题或未验证边界。若没有新增经验,说明沿用现有方法即可,不复制重复条目。遵守根协作规则:不写真实凭据、手机标识、开发机绝对路径,文档更新后执行仓库卫生检查。
## 12. 轮询或滑动后节点失效、名称可见但按钮无法点击
本轮三种布局已验证:读取语义节点期间可能出现 StaleObjectException,应在原有有界期限内丢弃旧节点并重新查找,不复用旧坐标、不放宽断言。滚动定位使用 connection_list 的实时可见边界;扫描按钮还要限制在目标设备条目容器,检查按钮启用且 visibleBounds 非空。名称露出不证明兄弟按钮可见,空边界不能取中心点点击。
滑动后通过两次间隔400毫秒的实时边界相等检查确认目标停稳(最多5秒),然后仅发送一次 root 点击;不因未看到中间状态而重复点击连接。记录初次连接、连接中扫描、两处预览、条目断开、手动重连等阶段。短暂“连接中”未被观测不代表未发起请求,终态以认证连接和条目状态核验为准。
本轮失败、恢复与最终结果见 `../测试结果归档/2026-09-27_界面细节优化/`;重测通过不证明此前连接未出现的唯一根因。字体、旋转和密度恢复后均回读核验。
## 13. 按影响选测与独立模拟器(2026-09-29)
- 先读 [按影响选测](按影响选测.md),选中场景后才执行环境门禁。不能因为手机登记/网络不可用而阻塞不依赖它们的 JVM、模拟器或文档检查。需要真机但环境不可用时仍是“未验证”。
- `--list-scenarios` / `--dry-run` 不导入远端联调依赖、不访问凭据或 ADB。电脑系统 Python 未装 Paramiko 时,使用本机 `local_env.py setup ssh` 重建 `.local/ssh/venv` 并检查 import;不要给核桃派添加主机依赖。
- com.android.test 插件已由同版本 AGP 放入 classpath 时,uiTest 使用无版本 `id("com.android.test")`;显式重复版本可能导致 unknown version 冲突。uiTest 的 Compose 测试库与现有 Compose Multiplatform 锁定版本一致。
- 独立 uiTest 使用 self-instrumenting APK 和实际 Controller,不从反射篡改内部状态。fake RPC 必须遵循真实字段契约:内容条目需要 revision,缺失会在 thumbnailKey 中失败。此类夹具错误应修夹具,不弱化产品断言。
- 真机 navigation 临时撤销扫描/连接权限,防止已有记忆触发自动重连;finally 恢复原权限并回读,不访问板端身份。不将此场景用于权限允许/拒绝的产品验收。
- AVD 镜像 ZIP 手动解压不等于 SDK 包已登记。单独存放 SDK 时,avdmanager 必须定位同一 SDK 根;镜像 package.xml 保留官方 type-details/版本/许可证,复用已有 Emulator。优先使用 Android Studio SDK Manager 正常安装的包,不能靠反复下载解决根目录不一致。
- 模拟器测试出现失败,保留场景与配置结果,独立恢复字体、旋转、密度;只重跑受影响/未运行场景。失败不能记成全量通过。标准 Compose 输入仅适用于模拟器,登记真机仍用 root。
## 14. 内容预览在真实动画条目返回 BAD_REQUEST(2026-09-29)
真实用户动画的首帧可能是 `path` 指向持久图片,演示动画则可能是内嵌 `image`。新增 BLE 图片接口时要先检查 `animations.playback_snapshot` 的实际首帧结构,并沿设备既有路径验证与解码规则读取两种形式;不能把 `path` 当作无图或错误参数。空动画仍应按不可播放条目处理。复测须覆盖用户动画和演示动画,并做全库图片只读读取;本轮修正和实测见 [内容缓存验收](../测试结果归档/2026-09-29_内容缓存/README.md)。
模拟器 AVD 名称若存在但启动提示系统目录不存在,先核对该名称的配置指向和镜像登记。保留旧配置,使用已安装镜像新建专用 AVD 再测试;不要因名称存在就反复启动,也不要擅自清空原 AVD。真机 instrumentation 前同时确认产品 APK 与 androidTest APK 已构建,只有测试 APK 时先补产品构建,再运行选中场景。
## 15. 项目本机环境迁移与中文路径(2026-10-01)
- 本项目专用 venv、AVD/系统镜像和私有主机状态使用 [本机环境入口](../../../测试相关资料/如何测试/本机测试环境/README.md),不再依赖全局项目目录。旧全局 AVD 索引存在不代表 AVD 数据存在,先检查实际目录;缺失的数据和主机密钥不能写成迁移成功。
- venv 不能直接搬动后作为可移植环境:`pyvenv.cfg` 和入口脚本可能仍引用原位置。保留旧目录,用完整版本/哈希锁定 wheel 在新位置重建,再检查依赖与解释器。
- 本机 Emulator 在中文路径下报告 `Could not write file`、损坏的中文路径和无法读取 kernel;同一系统镜像通过 ASCII 目录联接启动后 settings/baseline 通过,确认本次启动失败属于路径访问问题。用 `local_env.py ui-smoke android` 自动创建短期入口,镜像/AVD 留在项目内,不移动到全局目录或再次下载镜像。临时入口结束后移除,AVD 的持久 image 路径恢复为项目内位置。
- AGP 构建入口传入 ASCII 目录联接时,不应先 `resolve()` 展开为中文目标;`build_android.py` 保留用户传入的 ASCII 拼写,构建实际写入项目 `.local/work/`。只读路径解析使用常规 resolve,不把此规则扩展到其他环境。
- Emulator 可能把 `config.ini` 重写成 `key = value`,读取时应修剪键值空白,不能把格式变化误报为失效路径。复制项目后 setup 只刷新本工具管理的路径,保留用户数据。
- Windows Python 控制台在诊断输出包含替换字符时可能触发 GBK 编码错误;仅对本次 Python 进程使用 `-X utf8`,不全局调整系统设置。
单次启动失败与复测结果记录在 `各种归档/2026-10-01_本机环境迁移/README.md`;模拟器结果不代表任何真机或板端验收。
## 2026-10-10 动画浏览
动画预览仅有首帧时,先核对设备是否声明library_animation及是否实际读取动画帧,不能只替换静态解码器。已缓存完整图片点开浏览器时应立即判定完成,不能等待队列再清除下载提示(完成项不会重新入队)。暖动画缓存应先校验完整高清清单并直接恢复播放,避免重新下载低清。动画两类读取必须加入HybridRpc只读集合,WiFi故障才可安全回退BLE。
JVM构建如使用指向中文项目的ASCII联接,Gradle可能解析回中文真实路径并重现已登记的类加载失败;本次已用独立真实ASCII临时构建目录验证通过。临时构建属于本轮中间产物,验证并交付后清理;持续SDK/AVD/项目环境仍保留项目内。
部署数据检查:必须在更新前将逐项文件摘要保存到受保护材料,区分用户源/配置与已登记可再生缓存;不能只保留进程内字典和总差异数。更新后逐项核验,报告仅输出脱敏分类与统计。原始受保护基线不进入普通日志或Git。缺少基线时明确标记追溯验证不足,不能用启动成功替代源文件不变证据。