外观
P2 CoreProfile 启动阶段分析方案
目标与边界
在 pymobiledevice3 11.3.1 唯一 DTX owner 上启用 coreprofilesessiontap KDebug RAW v2,将 py-ios-device 2.4.26 的 App Launch Lifecycle 作为协议与事件映射参考,不引入其 runtime,不建立第二条 DTX socket。保持无侵入:不改包、不注入、不 Hook、不依赖 WDA/XCTest Runner。
原始字段与单位
- 输入:
core-profile.chunk.raw.chunkBase64 原始块、timeConfig.numer/denom、KDebugtimestamp/arg0...arg3/tid/debugID。 - PID 归因:先读 RAW v2 header
threadmap(tid,pid,process),再处理TRACE_DATA_NEWTHREAD(0x07000004)与TRACE_DATA_EXEC(0x07000008)的运行时映射;跨 CPU/分块到达顺序不作为时间顺序。 - 时间换算:
timestampNs = floor(machTicks × numer / denom),使用整数算术,不使用 wall clock。 - 全部启动指标
scope=process、unit=milliseconds,计算层保留 Double,UI 格式化不回写。
阶段与公式
| metricID | 阶段 | 原始事件 |
|---|---|---|
ios.process.startup.system_interface_ms | System Interface Initialization | 0x1F07 dyld begin → 0x2BDC transition |
ios.process.startup.static_runtime_ms | Static Runtime Initialization | 0x2BDC transition → 0x1F07 static end |
ios.process.startup.uikit_initialization_ms | UIKit Initialization | 0x2B87 code=90 arg0=0x32 → code=21 |
ios.process.startup.uikit_scene_creation_ms | UIKit Scene Creation | 0x2B87 多段 begin/end,保留重复 Span 并求和 |
ios.process.startup.will_finish_launching_ms | willFinishLaunchingWithOptions() | code=23 → code=24 |
ios.process.startup.did_finish_launching_ms | didFinishLaunchingWithOptions() | code=25 → code=26 |
ios.process.startup.scene_will_connect_ms | sceneWillConnectTo() | code=300 → code=301 |
ios.process.startup.scene_will_enter_foreground_ms | sceneWillEnterForeground() | code=312 → code=313 |
ios.process.startup.initial_frame_rendering_ms | Initial Frame Rendering | code=12 → 0x31CA0006 |
ios.process.startup.app_launch_total_ms | App Launch Total | System Interface Initialization begin → 与 Initial Frame Rendering begin 配对的 0x31CA0006 |
text
spanDurationMs = (endTimestampNs - startTimestampNs) / 1,000,000
phaseTotalMs = sum(同 phase 所有完整 Span 的 spanDurationMs)
appLaunchTotalMs = initialFrameEndTimestampNs - systemInterfaceBeginTimestampNsApp Launch Total 按完整首尾锚点计算,不累加各阶段,因为阶段可以重叠。缺少 System Interface begin 时 App Launch Total 保持 null,即使能观察到后半段 Span 也不以局部耗时冒充总耗时。同名阶段用每线程 stack 配对,不覆盖重复 UIKit Scene Creation。
采集顺序与共享规则
选中 StartupTiming 时使用 controlled-cold-launch,避免把已有进程的前台切换误当成完整冷启动。顺序固定为:打开 owner/resolver → 以 py-ios-device 2.4.26 的 lifecycle 配置 bm=1 预启动唯一 CoreProfile adapter 并获得 start ACK → 通过同一 owner 的 ProcessControl 发送冷启动(OS_ACTIVITY_DT_MODE=1、HIPreventRefEncoding=1、DYLD_PRINT_TO_STDERR=1)→ 绑定返回 PID/generation → 启动其他 adapter。上述环境仅作用于受控启动进程,不改包、不重签、不注入。
同时选中 Frame Time 与 StartupTiming 时,只存在一个 CoreProfile adapter,filters = lifecycle filters ∪ presented-frame filter。所有 KDebug 记录先按 (machTicks, arrivalSequence) 排序,再做 PID/TID 归因;阶段 marker 再按 (timestampNs, arrivalSequence, actionOrder) 重建,同一 transition 固定先 END、后 BEGIN。
缺失、重置与质量语义
- PID 未映射、时间基变化、RAW v2 header/对齐错误:
missing或unsupported-schema,不接受其阶段。 - 只有 BEGIN 或 END:最终报告
partial,未闭合 Span 不参与时长;实时 wire 只发布闭合后的candidate,不抢先发布不可更新的 partial。 0x31CA0006只有在同 PID/TID 已出现code=12、能闭合 Initial Frame Rendering 时才是启动终点;此前的同码帧事件只计入 ignored,不得冒充 App Launch 终点。- 终点早于起点、逆序或溢出:丢弃该配对并计数,不写 0。
- 未识别 lifecycle debugID:保留计数,不自行推断阶段。
- 完整闭合但协议仍为私有实现线索:
candidate;未经真机门禁不描述为可用。
产物与验收
产物:launch-spans.jsonl、launch-trace-report.json,并将 SHA-256、status、Span 数量纳入 foundation-delivery.json。验收覆盖完整序列、重复 Scene、PID 未映射、缺 BEGIN/END、分块增量解码、未知事件、双次回放 hash、唯一 CoreProfile adapter 与 launch 前 ready。真机 E4 另行验证 PID 归因、Initial Frame 闭合和各阶段数值非伪 0。