CORE-2A 单 DTX Async Backend 与三路 Raw Adapter
结论
CORE-2 的第一批实现已经把冻结的 pymobiledevice3 11.3.1 接到 DtxSessionOwner 后面,并新增 Sysmontap、Graphics、Device Network 三路 raw-only Adapter。三个 Adapter 共享一个 DvtProvider / DTXConnection,Perfowl 不再增加第二个 socket reader。
本批在隔离的 CPython 3.12.3 / macOS x86_64 环境完成 11.3.1 全依赖安装、pip check 和 9/9 runtime API import,达到 E3 环境证据;fake stream、错误注入和全量回归达到 E2。尚未连接真机,因此不把任一新版指标标记为可用,也不切换当前 4.21.3 默认链。
批准范围
用户已批准后续基座 CORE-2~CORE-7 连续开发。后续批次不再重复等待产品代码批准,但仍保持:
- 指标公式先入档;
- 每批做匹配验证并本地窄范围提交;
- 默认不推送远端;
- 真机、发布包、签名、公证与 GPL 法务门禁分别验收,低等级证据不冒充 E4。
实现范围
| 模块 | 作用 | 边界 |
|---|---|---|
pmd3_backend.py | 冻结版 async backend | 一个 backend 最多创建一个 DvtProvider;不暴露裸 DTXConnection |
Pmd3Subscription | 有界事件队列 | 满队列丢最旧事件并累计 droppedEventCount;支持显式取消 |
adapters.py | Sysmontap / Graphics / Device Network raw Adapter | 只保存源字段,不在本批新增指标计算 |
feature_flags.py | 候选运行时选择 | 默认 legacy-4.21.3;只有显式 flag + 精确版本/API 门禁通过才选择候选 |
runtime.py | reconnect generation | 新 Session 的连接代数写入每条 raw envelope |
requirements-core-py312-macos-x86_64.lock | 完整传递依赖版本锁 | 101 个精确版本;仅对应 CPython 3.12 / macOS x86_64 候选环境 |
单 DTX 生命周期
DtxSessionOwner.open
└─ Pmd3AsyncBackend.connect
└─ exactly one DvtProvider.connect
└─ pymobiledevice3 DTXConnection owns socket reader
Adapter.start
├─ Sysmontap.create(provider)
├─ Graphics(provider)
└─ NetworkMonitor(provider)
stop
├─ cancel bounded subscriptions (reverse order)
├─ stop managed services (reverse order)
└─ provider.close
pymobiledevice3 11.3.1 自己的 DTXConnection 已有唯一后台 reader 和 channel dispatcher。Perfowl 的 subscription 只消费各 service 的 async iterator,并在独立有界队列做背压;它不会再读取底层 socket。
Timeout、取消与背压
- provider connect、channel start、selector invoke、service stop 和 provider close 都有统一 operation timeout;
- connect 超时后关闭已创建 provider,并保持门禁失败;
- 同一个 stream 禁止创建两个 Perfowl subscriber;
- consumer 落后且队列已满时丢弃最旧事件,
droppedEventCount单调增加; - stop 先取消 consumer,再逆序停止 service,最后关闭 provider;
- reconnect 通过新建 owner 并递增
reconnectGeneration表达,不复用已关闭 Session。
Raw 语义
三个 Adapter 均输出 perfowl.raw-event/1:
sysmontap.raw:scopeprocess+system;graphics.raw:scopeforeground-device;network.device.raw:scopedevice,额外保留事件 class;- bytes 使用 base64 对象保存,dataclass / enum / mapping 递归转为 JSON-safe;
- 空 payload 标记
missing,不生成数值0; - 保存 upstream version/commit、target PID/generation、identity status、drop count 与 reconnect generation。
本批没有新增 CPU、FPS、Network 等派生公式,不改变既有指标 Registry,也没有触发指标 knowledge 双写。
候选运行时与回滚
| 条件 | 结果 |
|---|---|
未设置 PERFOWL_COLLECTOR_CORE | legacy-4.21.3 |
| 设置 flag,但安装版本或 9 项 API 任一不匹配 | fail closed 到 legacy-4.21.3 |
设置 flag,且 11.3.1 精确版本和 9/9 API 通过 | core-11.3.1 candidate |
选择器目前只属于 Collector Core,并未接入 App 的默认启动链。现有 perfowl_collector.py、PyInstaller 入口和构建脚本未改,回滚链保持原样。
验证结果
| 验证 | 结果 | 证据 |
|---|---|---|
| CPython 3.12 隔离安装 | pymobiledevice3 11.3.1 + 101 个环境包精确版本;pip check clean | E3 |
| 冻结 runtime API probe | 9/9 import,ready=true | E3 |
| Python 3.12 Sidecar 全量测试 | 43/43 | E2 |
| Python 3.9 Sidecar 全量测试 | 43/43;不含 pmd3 完整依赖安装 | E2 |
| Swift 全量测试 | 62/62 | E2 |
| 单 provider / 多 stream | fake provider 断言 connect 仅一次 | E2 |
| backpressure / stop 顺序 / timeout / duplicate subscriber | 错误注入测试通过 | E2 |
| 真机连接与 raw 回包 | 未执行 | 门禁开放 |
| 候选 Sidecar / App 打包 | 未执行 | 门禁开放 |
Python 3.9 上游传递依赖包含缺少当前平台 wheel 的 source-build 路径,本批不把其隔离安装记为通过;候选发布运行时暂以已验证的 CPython 3.12 x86_64 环境为准,universal2 仍属于 CORE-7。
后续
1. CORE-2B:把候选 composition root 接到独立 Sidecar 入口,建立 JSONL raw 录制/回放与候选打包;仍不切默认链。
2. CORE-3:使用当前连接设备做 11.3.1 新旧 A/B,验证连接、身份闭环、Sysmontap、Graphics、Device Network、停止与重连。
3. 按 iOS 15 / 16 / 17 早期 / 17.4+ / 18+ 分段补兼容矩阵;没有设备的分段保持未测试。
冻结归档:CORE-2A 实施归档。