Perfowl Collector Core 单 DTX 基座与版本冻结决策 ​
批次结论 ​
Perfowl 不再把 pymobiledevice3 与 py-ios-device 设计为两个并行运行的采集 Provider。新基座定为 Perfowl Collector Core:以 pymobiledevice3 作为唯一设备连接、Tunnel、RSD 和 DTX 内核,在同一个 DvtProvider / DTXConnection 上补充 Perfowl 自己的深度采集 Adapter;py-ios-device 仅作为深度协议、字段、解码器与反例算法的冻结研究来源。
这意味着“结合两个库的优势”不是合并两套 socket、线程和生命周期,而是:
- 保留 pymobiledevice3 的现代连接与 DTX 实现;
- 将 py-ios-device 多出的 Channel、selector、配置、raw schema 和解码知识迁移为 Perfowl Adapter;
- 所有 raw event 进入 Perfowl 自己的质量层和 Metric Engine;
- 相同指标只选择一个 Session 级主源,禁止同一曲线混用两种口径。
本批只完成版本冻结、静态能力对照、架构与升级门禁,证据等级是 E1。没有修改 MacApp/、没有替换当前 Collector,也没有产生新版真机可用结论。
冻结版本 ​
| 对象 | 本批冻结版本 | 精确源码 | 角色 | 说明 |
|---|---|---|---|---|
| Perfowl 当前已打包基线 | pymobiledevice3 4.21.3 |
已构建产物元数据 | 回滚基线 | 当前同步 RemoteServer + Perfowl DVTEventPump 链;已有有限 iOS 16 E4,不代表新版兼容 |
| pymobiledevice3 候选 | v11.3.1 |
e0dc322f4a0fa293353f8c13765516fbf15b1caa |
唯一连接与 DTX 内核 | 发布 tag;新版为 async DvtProvider / DTXConnection,不是原位小升级 |
| py-ios-device 研究源 | 源码版本 2.4.26 |
67b36f0c526e5bcf1d697f700df232af1bce0943 |
深度能力研究源 | 仓库当前源码版本;PyPI 最新发布包仍为 2.4.25,不把源码版本伪装成已发布 wheel |
| py-ios-device 发布包对照 | 2.4.25 |
PyPI sdist / wheel | 可重建对照 | 用于核对源码差异、依赖和 SBOM,不作为正式运行时 Provider |
“最新”只用于进入候选评估。正式基线始终固定精确版本、commit、依赖锁和 hash,不追随浮动 latest。
为什么以 pymobiledevice3 为内核 ​
冻结源码显示,pymobiledevice3 v11.3.1 已有:
- 设备发现、配对、Lockdown、Developer image、RSD 与 iOS 17+ Tunnel 路由;
- 支持预构建
DTXConnection的DvtProvider,可以让多个 service wrapper 复用同一 transport; - Sysmontap、Graphics、NetworkMonitor、EnergyMonitor、Notifications、CoreProfileSessionTap、Screenshot 与 ProcessControl;
- 通用
TapChannel以及 async service / notification 分发模型。
py-ios-device 的独特价值集中在深度采集与解析:
NetworkStatistics按 PID 的 debug gauge 调用;- CoreProfile/KDebug 的事件识别、逐帧和生命周期解析线索;
- Metal GPU 的设备 schema、counter 配置和流解码;
- App Launch Lifecycle 阶段解析;
- 已知算法反例,例如旧代码中曾出现固定 time factor、实验性 GPU 解析与直接输出最终 Jank。
因此,复制 py-ios-device 的整个连接层只会重复 USBMux、Lockdown、RemoteLockdown 和 DTX,并增加抢读与关闭顺序风险;迁移其深度协议知识才是有增量价值的部分。
目标架构 ​
Perfowl Mac App
└── IPC
└── Perfowl Collector Sidecar
└── Perfowl Collector Core
├── DeviceGateway [pymobiledevice3]
│ ├── USBMux / Pairing / Lockdown
│ ├── Developer image
│ └── RSD / Tunnel route
├── DtxSessionOwner [唯一所有者]
│ ├── DvtProvider
│ ├── DTXConnection
│ ├── Channel Router
│ └── request / reply / event dispatcher
├── CollectorAdapter
│ ├── SysmonAdapter
│ ├── GraphicsAdapter
│ ├── DeviceNetworkAdapter
│ ├── CoreProfileAdapter
│ ├── ProcessNetworkAdapter
│ ├── EnergyAdapter
│ ├── GPUCounterAdapter
│ └── LifecycleAdapter
├── Raw Event + Quality Layer
└── Metric Engine
不变约束 ​
- 一个
DeviceSession只有一个DtxSessionOwner; - 只有底层
DTXConnection可以读取 transport;Adapter 只消费按 channel 分发的数据; - Mac App、Session Schema 和 UI 不引用两上游库的类或输出格式;
- Adapter 输出 raw fact,不直接发布 FPS、Jank、Energy 或 StartupTiming;
- Session 开始后固定 source plan;不静默切源;
- 缺失、断流、重连、重置和未知 schema 显式标记,缺值不写成
0。
新库的稳定接口 ​
DeviceGateway ​
负责设备、应用与连接路线,不暴露 pymobiledevice3 对象到 UI:
discoverDevices() -> DeviceSnapshot[]
listApplications(deviceKey) -> ApplicationSnapshot[]
openSession(deviceKey) -> DeviceSession
probeCapabilities(session) -> CapabilitySnapshot
DtxSessionOwner ​
负责唯一 DTX 生命周期:
openChannel(identifier, serviceType)
invoke(channel, selector, arguments, replyPolicy)
subscribe(channel, eventKind)
close(reason)
必须具备 bounded queue、channel 级丢包计数、请求超时、停止顺序、重连 generation 和 backpressure 记录。
CollectorAdapter ​
每项采集能力遵守同一协议:
adapterID / adapterVersion
requiredCapabilities
probe(session) -> supported | unsupported(reason) | candidate(reason)
prepare(target, options)
start()
rawEvents()
stop()
RawEventEnvelope ​
最小审计字段:
eventType
service / channel / selector
transportSource / adapterID / adapterVersion
upstreamVersion / upstreamCommit
deviceMachTimestamp / machNumer / machDenom
hostReceiveMonotonicNs / wallTimestamp
targetPID / targetGeneration / identityStatus
scope / rawUnit
rawPayload / rawPayloadHash
decodeStatus / quality / droppedEventCount / reconnectGeneration
重叠指标如何选择“支持最好”的方式 ​
选择单位是“原始数据源 + Adapter + 公式版本”,不是库名。每个指标先建立候选集,再按同一 Fixture、同一设备、同一 App、同一时间窗 A/B。
硬门槛 ​
任一项不满足就不能成为默认源:
- Bundle ID → PID → process generation 身份闭环;
- scope 与 unit 可以从协议和实验同时证明;
- warmup、counter reset、进程重启与 missing 不转
0; - 30 分钟采集无不可解释断流,stop 后无残留 reader;
- iOS 版本不支持时 fail-closed;
- raw 可保存、可脱机重放、可追溯到 Adapter 与算法版本。
评分模型 ​
| 维度 | 权重 | 核验方法 |
|---|---|---|
| 数值正确性 | 35% | 自有 Fixture + xctrace + PerfDog 同场偏差 |
| 目标归属准确性 | 20% | 前后台切换、同名进程、PID 重启 |
| iOS 15+ 覆盖 | 15% | 分版本 capability probe 与短/长采集 |
| 稳定性 | 10% | 30 分钟丢样、断流、恢复、停止 |
| 采集开销 | 10% | Sidecar CPU、内存、事件延迟 |
| 字段完整度 | 5% | raw schema、时间基、丢包与错误字段 |
| 维护成本 | 5% | 上游稳定性、测试面、私有协议漂移面积 |
同分时优先顺序:pymobiledevice3 已有 wrapper → Perfowl 基于 pymobiledevice3 DTX 的自有 Adapter → 更复杂的自有 decoder。py-ios-device 的最终格式化指标不直接成为候选。
初始来源决策 ​
| 能力 | 初始主实现 | py-ios-device 的贡献 | 当前发布状态 |
|---|---|---|---|
| 设备、应用、Lockdown、RSD、Tunnel | pymobiledevice3 | 不迁移重复实现 | 候选升级;旧基线仍可回滚 |
| DTX transport 与分发 | pymobiledevice3 DvtProvider |
只核对协议行为 | E1;待 CORE-1/2 |
| App CPU / TotalCPU / Memory / Threads / Disk | pmd3 Sysmontap + Perfowl 质量层 | 字段对照、异常样本反例 | 维持现有 Experimental;升级需回归 |
| 秒级 FPS | pmd3 Graphics raw + Perfowl 公式 | 同 channel 调用时序对照 | 维持 Experimental |
| 设备级 Network | pmd3 NetworkMonitor | 回包解析对照 | 维持 device scope,不冒充 App Network |
| 进程级 Network | Perfowl ProcessNetworkAdapter |
NetworkStatistics channel/selector/schema 研究 |
Unsupported,待 raw E4 |
| FrameTime / Jank | Perfowl CoreProfileAdapter |
KDebug 事件与解析线索 | Unsupported,待 60/120Hz E4 |
| Energy | 优先复用 pmd3 EnergyMonitor raw | 属性完整性与 PID sample 调用对照 | Unsupported,待单位校准 |
| GPU Counter | Perfowl GPUCounterAdapter |
schema discovery、配置与 decoder 研究 | Unsupported,未知 schema fail-closed |
| StartupTiming | Perfowl LifecycleAdapter |
CoreProfile lifecycle 事件映射 | Unsupported,被动/受控模式分别校准 |
| Screenshot / Logs / Crash | pymobiledevice3 | 不迁移重复实现 | 维持现有路径,升级需回归 |
iOS 15+ 路线 ​
| 系统段 | 连接路线 | DTX 基座要求 | 本批证据 |
|---|---|---|---|
| iOS 15.x | USBMux + Lockdown + legacy DVT service | 运行时 capability probe;不假定所有深度 channel 存在 | E1,待设备 |
| iOS 16.x | USBMux + Lockdown + secure DVT service | Developer Mode / Developer image;保留现有 4.21.3 回滚 | 现有基础链有限 E4;11.3.1 待 E4 |
| iOS 17.0–17.3.1 | persistent tunneld → RSD |
单独兼容分支,不与 17.4+ 合并验收 | E1,高风险段 |
| iOS 17.4+ | 进程内 userspace tunnel / CoreDeviceProxy → RSD | Session 内持有 tunnel 生命周期 | E1,待 E4 |
| iOS 18+ / 26.x | capability 协商,不从旧版本外推 | channel、selector、schema 均动态探测 | E1,待 E4 |
升级风险 ​
当前 Collector 直接依赖旧版同步 RemoteServer、MessageAux、Tap、DvtSecureSocketProxyService 和自定义 DVTEventPump。v11.3.1 已转向 async DvtProvider / DTXConnection / DTXService,因此升级会触及:
- 连接创建与关闭方式;
- ProcessControl / DeviceInfo 请求响应;
- Sysmontap、Graphics 与 Network 的读取方式;
- Sidecar 主循环和取消模型;
- PyInstaller hidden imports 与双架构打包;
- 现有 raw fixture 的兼容和 provenance 字段。
升级必须建立并行的 legacy-4.21.3 与 core-11.3.1 Adapter,通过门禁前不删除旧链,也不把当前默认源直接切到新版。
实施批次与批准边界 ​
| 批次 | 内容 | 交付与门禁 |
|---|---|---|
| CORE-0 | 本页:版本冻结、能力矩阵、接口与来源策略 | 本批已完成,E1 |
| CORE-1 | 新建 Collector Core 骨架与 pmd3 11.3.1 Compatibility Spike | fake + raw replay;不切默认 Provider |
| CORE-2 | 唯一 DtxSessionOwner,迁移 Sysmon / Graphics / Device Network |
单 reader、stop/reconnect、旧新 fixture 一致性 |
| CORE-3 | 当前普通指标 A/B 与真机回归 | iOS 16 当前设备 + 可取得的 iOS 15/17/18;未过项回滚旧源 |
| CORE-4 | Process Network / CoreProfile / Energy raw Adapter | 公式先入档;只产 raw candidate |
| CORE-5 | GPU schema / Lifecycle raw Adapter | 未知 schema fail-closed;被动/受控启动分开 |
| CORE-6 | xctrace / PerfDog 同场校准与 SourcePolicy 定版 | 每项单独 E4,逐指标开放 UI |
| CORE-7 | universal2、SBOM、NOTICE、对应源码与法务门禁 | 对外分发前硬门禁 |
下一次产品代码批准建议限定为 CORE-1。它只建立新核心接口、锁定依赖和离线测试,不切换用户当前可用链路;完成并提交后再单独批准 CORE-2。
许可与分发门禁 ​
pymobiledevice3 标注 GPL-3.0-or-later,py-ios-device 仓库包含 GPL-3.0 许可证。直接复制、修改或组合源码时,新库的许可证、对应源码、修改声明、NOTICE、安装信息与 Mac App 聚合/衍生边界需要正式法务结论。独立 Sidecar 与 IPC 是工程隔离,不自动形成许可豁免。
当前决策允许内部 E1/E2/E4 实验;对外 App/DMG 分发仍保持 Hold。