Commit Graph

11 Commits

Author SHA1 Message Date
郑博文
114e8431a6 test(android-3a): 连接生命周期 proof 入仓 + 四个 proof 的主机默认值跟上环境
新增 tools\connect_lifecycle_proof.ps1(V-A1a/A1b/A2/A3/A4/A5 + 一键重连,
含 keep-awake、tap 前唤醒、期望文案码点从 Kotlin 源提取)。
四个既有 proof 的 -PhoneIp 默认值 .180 -> .110(2026-10-31 办公网实测;
stale 默认值曾静默吃掉一次 proof 运行,注释写明 DHCP 需按需传参)。
capture_evidence 的 192.168.1.199 保持不变——那是 V5 故意不可达的路径。
2026-10-31 15:57:57 +08:00
郑博文
99ffffa393 test(android-2b): 真机 emoji 人工验收工具 + 链路 proof 参数化主机地址
V7 设备侧此前转人工,原因是 IME 的 emoji 面板对 uiautomator 不可见、adb 无法
驱动。工具只负责准备接收窗口并读回**实际到达的码元**,点 emoji 由人完成——
判据仍是真实字节,不是截图。

真机实测通过:靶窗收到 U+D83D U+DE02 -> U+1F602,两个 code unit 相邻成对、
无 U+FFFD。这证明手机 IME 把增补平面字符作为一次 commitText 送出,协议 v3
保住了代理对相邻性。至此 V7 双侧都有证据。

同时修掉 phone_chain_proof 里硬编码的 192.168.1.180:本机 LAN 地址变成
192.168.1.110 后,表单连接打向旧地址超时,看起来像产品缺陷,实为脚本过期。
改为从 -PhoneIp 参数逐字符生成 keyevent,并在断言里比对实际输入值。
2026-10-31 11:08:16 +08:00
郑博文
8993a38658 fix(android): BACK 键改用自测键盘可见性——isAcceptingText 会让会话永远断不掉
真机实测(vivo S6 + 讯飞,2026-10-30):软键盘已隐藏、mInputShown=false,
但 imm.isAcceptingText 仍返回 true——只要 InputConnection 还绑着它就是 true。
原先用它判断「先关键盘还是先断会话」,后果是第一次 BACK 空转,第二次也进不来
(我们已 return true),会话再也断不掉。这不是推测,是完整链路 proof 跑到
step 5 时实测失败的。

改为自测:比较根窗口可见区域与窗口高度,被 IME 吃掉超过 15% 视为可见;
用 OnGlobalLayoutListener 被动跟踪(没有公开 API 能直接查询,API 34 上
getInputMethodWindowVisibleHeight 也不是公开接口)。阈值用比例不用固定像素。

验证:diag 依次显示「键盘可见」→「键盘隐藏」→ 会话断开回表单;
随后完整链路 proof 与中文 proof 均复跑通过。

同时修正 phone_chain_proof 的 V4 断言:uiautomator 属性顺序是 text= 在
class= 之前,原正则要求反序,导致打印空表单行仍判 PASS(假绿)。
空 EditText 的 text 会回显 hint,所以判据改为比对实际输入值。
2026-10-30 13:31:28 +08:00
郑博文
9792662181 test(android-2b): 真机中文候选词 proof——拼音组词经 commitText 落到 Windows
V6 的判据是「手机中文输入法能把汉字送进远端」,此前只能靠人手点候选词。
实测发现两条关键事实,决定了 proof 的可行形态:
1. adb keyevent 相当于物理键盘输入,中文 IME **不组词**,字母原样透传到
   Activity.onKeyDown——所以驱动候选词必须用 adb input text(走 IME)。
2. IME 自己的按键视图对 uiautomator 不可见(dump 里只有我们 App 的 15 个节点),
   中/英切换按钮读不到坐标,只能按截图标定一次点击位;且该按钮**有状态**,
   于是写成幂等重试:先试,只收到字母才翻转模式再来一次。

跑通结果:讯飞拼音 nihao + 空格 -> commitText 2u -> 靶窗收到 U+4F60 U+597D。
这补上了方案风险 R1(vivo ROM + 第三方中文 IME 行为未观测)的核心一环。
2026-10-30 13:15:27 +08:00
郑博文
0089ae86e1 test(android-2b): 真机 IME 提交 proof 与字节安全证据采集
ime_commit_proof 补上 phone_chain_proof 没覆盖的那半段:IME **显示**状态下
按键被输入法消费,只有 RemoteInputConnection.commitText 能到达我们——这正是
方案风险 R1(vivo ROM + 第三方中文 IME 行为未观测)此前唯一没有证据的点。
真机实测:mInputShown=true、mHaveConnection=true、状态栏 commit 2u、
Windows 靶窗收到 Hi(讯飞把首字母自动大写,属输入法行为,不是链路缺陷)。
back 键第一次只关键盘不断会话,也在这支脚本里断言。

shot.ps1 / capture_evidence.ps1:PS 5.1 的 '>' 以 UTF-16 写文件,
'adb exec-out screencap -p > x.png' 产出的 9 张证据图首字节全是 FF FE,
全部不可用;改为设备内 screencap 落地再 pull,并校验 PNG 签名。

V5 等待预算 30s→50s:不可达 IP 实测 32s 才回表单报 timed out,
预算过小会把「仍在超时中」误判成验收失败。
2026-10-30 13:06:08 +08:00
郑博文
9f0b0742a8 feat(android): 键盘事件双通道 + 手机到 Windows 全链路 proof
真机暴露出 IME/按键通道的缺口,一并补上并证明:
1. RemoteInputConnection.sendKeyEvent 与 Activity.onKeyDown 都先处理**可打印**
   unicodeChar(走 v3 Text 通道),再退到扫描码查表。原先只查表:软键盘发的是
   keyCode=UNKNOWN + unicodeChar,查不到表就被当未映射键吞掉,字整个丢了。
   门槛排除控制值(Enter/Tab)——远端应用要的是按键事件而非 WM_CHAR。
2. onKeyDown/onKeyUp 补齐硬键与物理键盘路径(阶段 2 验收里的软键盘按键),
   repeatCount>0 只发一次 down,避免长按把远端消息队列刷爆。
   isAutorepeat() 是 @hide,改用公开的 getRepeatCount()(javap 核实)。
3. getUnicodeChar() 返回的是单个 UTF-16 code unit 而非码点,注释按此改正:
   BMP 外字符由 IME commitText 成对送达,不经这条路。

tools/phone_chain_proof.ps1:手机按键 -> v3 Text -> agent SendInput -> 自有
Windows 靶窗自报内容,全链路一次跑通(真机 vivo S6 实测 abc 到位、ENTER 走
scan 28、BACK 断开回表单、表单 UI 重连成功)。要点:
- 靶窗必须自报窗口句柄(pid+hwnd 两行),Get-Process 取 MainWindowHandle 有竞态;
- 不能用 keybd_event(VK_MENU) 破前台锁:ALT 之后的首个字符被当菜单助记键吞掉,
  实测三个字符只剩 b;改用 AttachThreadInput + SetForegroundWindow,不合成按键;
- 退役遗留靶窗只能 touch 已存在的 stop.flag:新建会命中即将启动那次的停止路径,
  靶窗刚起就自杀(实测 pid 报了又消失);
- adb 进度信息走 stderr,PS 5.1 + ErrorActionPreference=Stop 会当终止错误,
  按 build-android.ps1 同款办法临时放宽并只看退出码。
- 表单填字用 keyevent 而非 adb input text:设备只有第三方中文 IME,text 注入会被
  组词(ASCII 句点变 U+3002)。跑前记录并禁用原 IME,finally 精确还原。
2026-10-30 12:58:36 +08:00
郑博文
a93430dd3f chore(tools): 2b 注入 proof 路径随仓库位置推导,缺失参数报错文案改正
proof 脚本原先硬编码 D 盘绝对路径,换机器就失效;仓库内已有同约定
(build-android.ps1 用 \ 推导),此处对齐。
text_check 的报错文案说「为空」,实际触发条件是 --units 缺失,改正。
2026-10-30 12:21:19 +08:00
郑博文
936986a940 test(android-2b): 文本注入真边界工具——viewer-core 直发 Text,靶窗自报收到内容
text_check 走的是产品同一条路径(Session::send_text → v3 线格式 → agent
SendInput KEYEVENTF_UNICODE),手机掉线也能先把 Windows 半段验实。
参数是十进制 code unit 列表而不是自然语言字符串:命令行到 Rust 的编码往返
会引入与本轮无关的变量,由 PowerShell 从 .NET 字符串取 char[] 更忠实。

proof 脚本刻意用自有 WinForms 靶窗而非记事本:Win11 记事本所有标签页同进程,
本机当时开着用户文档,往里注入等于改用户文件。靶窗自报文本(写文件),
判据不依赖截图和 OCR。注入前后各断言一次前台窗口——SendInput 打的是前台,
靶窗不在前台时的注入会进别的应用,宁可失败也不误注入。
2026-10-30 12:09:48 +08:00
yu
18d12baba1 fix(tools): 探针区分信令回复与打洞包,修掉打洞假阳性
问题:客户端反复注册引来的 PEER/WAIT 回复在 discover_peer 返回后才到达,
被接收线程当成「对方打进来了」,输出假的「✅ 打洞成功」。
实测形态:报告的对方地址实为信令服务器 47.98.245.66:47999,包长 22 字节
(真打洞包固定 16 字节 = PUNCHv1| + 8 字节时间戳)。

修复:
- 接收线程只认以 MAGIC 开头、且长度正确的包
- 显式排除信令服务器的 IP:端口
- 失败结论里报告被忽略的非打洞包数量,避免再次误读
- 验证记录补 4.5 节,写明 Rust 实现的对应判据
2026-10-23 18:02:14 +08:00
yu
d659a4e7f1 feat(tools): 打洞探针与极简 rendezvous 服务器(Python POC)
- punch_probe.py: UDP 打洞探针,支持 STUN 查映射、--peer 手工配对、--server/--room 信令配对
- rendezvous.py: 极简 UDP 信令服务器,只做房间配对与地址回推,不承载媒体
- 已在 47.98.245.66 实测跨公网注册/配对可用
2026-10-23 17:32:17 +08:00
dev-team
7dbb04da17 feat(hud): B1 基线指标——抖动/帧间隔p95/丢包率/解码失败计数 + 测试脚本
- common: Pong 扩展 lost/sent(agent 发送方向 QUIC 计数,经交叉评审项)
- agent: Pong 附带 conn.stats().path 丢包统计
- viewer: Stats 加 GapRing(64)/jitter EMA/dec_fail;HUD 新增 JIT/P95/LOSS/DECFAIL 四行,% 字形
- tools/bench.md: 三场景基线测试脚本
2026-10-23 09:47:09 +08:00