mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Docs] (P12 review): the P12 decision log, ARCHITECTURE §15.2's on-screen path, and the ROADMAP P12 row record the review round
- notes/p12/INTEGRATOR-DECISIONS-P12.md (new): ID-P12-1..4 the subset's shape (the user rulings, one surface mode per session, the lost-window order, the in-process thread hand-off), ID-P12-5..11 the review round's ten fixes (two majors: the lost window answered before every ring record, the ended session's Espryt unit shadows emptied with its twins), ID-P12-12 IterationRP out of scope, ID-P12-13 the device stage not re-run in this environment. - ARCHITECTURE.md §15.2: the deleted Surface -> AIDL window path is struck through, and the server-owned window path, the lost-window contract and the in-process session boundary are described. - ROADMAP.md: the P12 row's status names the review round and that the device checks were not repeated.
This commit is contained in:
@@ -523,7 +523,9 @@ TCP 上的两个数量级差别(RTT 毫秒级、带宽 30–100 MB/s)使 §1
|
||||
- 交付链:APK 唯一可 exec 的位置是 `lib/<abi>/`,server 以 `add_executable` + `PREFIX "lib"/SUFFIX ".so"` 构建(真 PIE),`RUNTIME_OUTPUT_DIRECTORY` 指到 AGP 收集原生产物的目录(`MOBILEGL_BUILD_SERVER_SPIKE`)。**两台设备上都已证明**:从 `untrusted_app` 进程 `fork`+`execve` 子进程落在同一域、exit 0、零 avc denial。
|
||||
- `fork`+`execve` 而非 `posix_spawn`:bionic 从 API 28 才声明后者,minSdk 26。fork 与 execve 之间只做 async-signal-safe 调用。应用进程的 stdout/stderr 是 `/dev/null`:子进程用 marker 文件证明自己活过,exec 被拒的 errno 经 close-on-exec pipe 回传。
|
||||
- 生产 server 主体是 ~30 行 stub:`dlopen(libMobileGL.so)` → `dlsym("mobilegl_server_main")`。一份共享库、两个角色。
|
||||
- minSdk 26 没有公开 NDK API 能扁平化 `ANativeWindow`。**P5–P11 验证路径无窗口**(pbuffer / `AImageReader`)。**P12 生产路径**:Java `Surface` → Messenger/AIDL → `MobileGLServerService`(`android:process=":mgl"`)→ JNI `ANativeWindow_fromSurface`;代价 server 进程多一个 ART(~15–25 MB)。
|
||||
- minSdk 26 没有公开 NDK API 能扁平化 `ANativeWindow`。**P5–P11 验证路径无窗口**(pbuffer / `AImageReader`)。~~P12 生产路径:Java `Surface` → Messenger/AIDL → `MobileGLServerService` → JNI `ANativeWindow_fromSurface`~~——按重审 §6 删掉(client 的窗口不跨进程,Rule H)。
|
||||
- **P12 上屏路径(2026-09-24,子集,[`notes/p12/INTEGRATOR-DECISIONS-P12.md`](notes/p12/INTEGRATOR-DECISIONS-P12.md))**:窗口是 **server 自己的**。`MobileGLDisplayActivity`(`android:process=":mglwin"`)持有全屏 SurfaceView,并在**自己的进程里**用一个线程跑 TCP server(`mobilegl_server_serve_inprocess`,即 `--serve` 的线程形状:会话串行、会话间重置 latch、后端按进程钉住);`ServerDisplay` 以 acquire/release/几何上调三个钩子持有该窗口,apply 线程以**租约**使用它。client 设 `MOBILEGL_IPC_SURFACE=server` 后**无头**:`eglCreateWindowSurface(NULL)` 发一帧 `WindowKind::ServerOwned`(token 0,控制修订 3),不发 `SetWindowHandle`,reply 带回窗口真实尺寸;client 的 resize 变成对 server 窗口的几何请求(`setFixedSize` / 0/0 = `setSizeFromLayout`),同样以真实尺寸应答。离屏 service(`MobileGLServerService`,fork-per-session)保留,**一台设备同一时刻一个 server**,一个会话一种表面模式(`SurfaceModeMismatch` 具名拒绝);无显示的 server 对 ServerOwned 具名拒绝(`NoServerDisplay`)。
|
||||
- **失窗与会话边界(P12)**:`surfaceDestroyed` 有界(3 s)阻塞,直到 apply 线程——在批内每条记录之前也检查——放掉后端表面并以 `Fatal{ServerWindowLost}` 闩会话,之后才返回;server 继续监听。进程内的会话结束手动做进程退出原本白给的清理:Espryt 丢弃全部 twin 及指向它们的纹理/采样器单元影子、忘掉 swap interval,Magma 丢弃进程全局 renderer;进程内 server 停止时不再 drain 仍在推流的 client 的队列;日志只转发当前会话自己线程的行,且不在日志互斥下发送。
|
||||
- `HeadlessGL` 的 fork 预检会 fork 一个子进程跑完整 EGL bring-up 然后 `_exit`——拆分模式下那个子进程会 spawn 一个孤儿 server。规则:server 的 EOF 检测**即时且无条件退出**;client 的 socket fd 设成 `_exit` 会确定性关闭的形态;握手有界重试。P6 验收。
|
||||
- 通用 env 透传 `--env K=V`(`run_android_retrace_local.py` → intent extra → `trace_replay_core.cpp` 在加载库前 `setenv`)已接进 retrace 通道。
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
| **P9** 反向通道 | 待排,**P6.5 之后**(2026-09-22 重定范围) | **异步 reply 语义**,机制建立在 P6.5 的消息式 reply 之上(不再造 `SEG_REPLY` slot 池——池今天就有,stream 链路会删它);2 MiB reply cap 与 chunked readback(契约 §10.2.3 从 P6 改判至此,ID-47);PACK-PBO 回读 fire-and-forget + client 侧 `MarkGpuWritten`(ID-57,P6 未做);十个回调里未武装的四个:`OnTextureWriteback`、`OnTexturePullRequest`、`OnMipLevelsGenerated`、`OnLog` 分级(`OnXfbScatterReady` 是零生产者、零消费者、无 EventKind 的死声明——随 P3b/P4b 删除,`kMGPipeCallbackCount` 10→9;`ClientSession.cpp:429`;`OnBufferWriteback` / `OnGpuWritten` / `OnSurfaceChanged` / `OnGlError` / `OnCapsInvalidated` 已武装);`OnGpuWritten` 收窄;`OnBufferWriteback` 批处理 + epoch 排序;`OnGlError` 有序(CONTRACT-P5C §4.2);纹理拉取四条缓解 + 终止符;XFB 命名空间(`DeleteTransformFeedback` 的 server 侧泄漏——按裁定无行、最后两个 class-C 之一)。~~`SEG_EVENT` 溢出策略~~ 机制已由 P5e 落地(`ARCHITECTURE.md` §11.7),剩余的"不排空对端杀宿主"归 Ph | 回读 / XFB 场景在 split 下绿;`TextureRemintPullScenario`(含无解用例);拉取计数逐 trace 发布;两条故障注入 |
|
||||
| **P10** sync / query / present 节奏 | 待排 | ~~client 铸造 query handle~~(已是:`QueryCreate` 为 `kWaitNone`);轮询入口成门铃点 + `MOBILEGL_IPC_POLL_ESCALATE`(0 处;TCP 上是首要杠杆之一);DirectGLES 的 fence 完成度来自逐 fence 退休(`g_completedFrameSerial` 仍只在 `Present` 前进;Magma 那半已由 run-ahead 落地);非 present fence tick(唯一记载处);`present` 1:1(已是);~~credit 默认 1~~(已是默认,`ConfigLoader.cpp:414`);**`PRESENT_CREDIT > 1` 从未量过**(重审 §8.7)——带延迟链路上的首要杠杆,inproc 臂上即可取;roundtrip 计数器与输入延迟直方图(今天只有 `MapPersistentRoundtrips`);`SetSwapInterval`(最后一个手写 class-C,`EmitTables.cpp:1665`) | query / XFB / `AsyncCompile` 场景在 split 下绿;trace 上 draw / state / upload 路径 roundtrip 读零;零 timeout 轮询有界退出;credit 1..3 在 TCP loopback 与跨机臂上的配对记录;配对 A/B 记录 |
|
||||
| **P11** persistent map 与 ≥16 MiB 采纳 | 待排,**同机臂专属、已让位**(2026-09-22) | T0 / T1 只对共享映射成立:`dataPlane = Stream` 上点名 T0 / T1 是具名拒绝并强制 T2(重审 §6 第 5 项),今天 `MOBILEGL_IPC_ADOPT_TIER` 0/1 已是 Fatal-at-use、`kSegAdopt` 只有枚举;前置开放问题 3。POST 探针档位选择(T0 主攻,Adreno 可选 T1,T2 回退);`SEG_ADOPT` 生命周期绑 `completedFrameSerial`;**`gPipeInputs` 版本化 / 双缓冲**(P5d 研究:draw barrier 延后一个 verb 的前提,须在 P3b/P4b 的句柄键控 twin 表之后)。**P5e 的更正**:P5e 退役 draw lockstep **没有**需要它——ra2 实测证明字段**值**已由 `SuppliedFieldMask` 分区,当时那次竞态在**元数据标量**上,修法是让守卫测事实而非断言未来(ID-135)。本行保留采纳存储的一般版本/时序问题;契约 §3.2 的 per-role stamp 已由 P5f 落地,不再是待办 | `LargeArenaAdoptionScenario` 在所选档下绿;26.3 与两个 Create fixture SSIM ≥ 0.99;Adreno 830 上 p99 帧时与峰值 RSS 对采纳基线(163→21 ms / 40→115 fps / ~400 MB)回归不超过 10% |
|
||||
| **P12** Android 生产窗口路径 | **子集已实现、未收官(2026-09-24,`p12/onscreen`,自 `9f669e52`,15 提交)**:上屏 server 窗口、`WindowKind::ServerOwned`、无头 client、失窗 device-lost 已落地并过真机七项检查;两个出口门均未打(见 [`notes/p12/PLAN-P12.md`](notes/p12/PLAN-P12.md) §3) | **按重审 §6 改小**:~~Service 收 Java `Surface`~~ 删掉 Surface 传递那一半——server app 拥有自己的 SurfaceView,client 根本没有窗口,于是 minSdk 26 没有扁平化 `ANativeWindow` 的 NDK API 这条约束不再成立;`WindowKind::ServerOwned`;两个后端各一条 `CreateEGLWindowSurface` 臂;`m_windowHandle` 四处写点 + `sameHandle` 去重键(a6 §6);DirectGLES `g_Display` / `g_Surface` / `g_Context` 去全局;`kEventSurfaceChanged` 的 Width / Height 缺口(Espryt 只发布格式,server 拥有显示时 client 默认 FBO 会停在 512×512 占位值);client 侧不再无条件发 `SetWindowHandle`(`BackendObject_Remote.cpp:215`——今天 FCL 里开 spawn,第一次 `eglCreateWindowSurface` 就在 server 进程 abort);server app 监听 `unix:` 与 `tcp://`(后者 Ph 之后);server 生命周期绑 Activity;cached-app freezer(SPAWN-PLAN §8.2);多 context(契约 §11);FCL env 与 plugin APK 开关表接线 | 两个门:(a) Minecraft 经 FCL **同机 spawn** 在 Adreno 830 双后端入世界,杀 server 产生干净 device-lost latch;(b) **另一台机器上的 client 经 TCP** 在 Redmi 上进世界(数据面 stream),并记录 P6.5 的必测数 |
|
||||
| **P12** Android 生产窗口路径 | **子集已实现、未收官(2026-09-24,自 `9f669e52`,15 提交 + 审查轮 8 提交)**:上屏 server 窗口、`WindowKind::ServerOwned`、无头 client、失窗 device-lost 已落地并过真机七项检查;审查轮 10 个问题已修(两个大项:批内失窗、会话间 Espryt 单元影子悬空;裁定 [`notes/p12/INTEGRATOR-DECISIONS-P12.md`](notes/p12/INTEGRATOR-DECISIONS-P12.md) ID-P12-5–11),主机门复跑,**真机未复测**(ID-P12-13);两个出口门均未打(见 [`notes/p12/PLAN-P12.md`](notes/p12/PLAN-P12.md) §3) | **按重审 §6 改小**:~~Service 收 Java `Surface`~~ 删掉 Surface 传递那一半——server app 拥有自己的 SurfaceView,client 根本没有窗口,于是 minSdk 26 没有扁平化 `ANativeWindow` 的 NDK API 这条约束不再成立;`WindowKind::ServerOwned`;两个后端各一条 `CreateEGLWindowSurface` 臂;`m_windowHandle` 四处写点 + `sameHandle` 去重键(a6 §6);DirectGLES `g_Display` / `g_Surface` / `g_Context` 去全局;`kEventSurfaceChanged` 的 Width / Height 缺口(Espryt 只发布格式,server 拥有显示时 client 默认 FBO 会停在 512×512 占位值);client 侧不再无条件发 `SetWindowHandle`(`BackendObject_Remote.cpp:215`——今天 FCL 里开 spawn,第一次 `eglCreateWindowSurface` 就在 server 进程 abort);server app 监听 `unix:` 与 `tcp://`(后者 Ph 之后);server 生命周期绑 Activity;cached-app freezer(SPAWN-PLAN §8.2);多 context(契约 §11);FCL env 与 plugin APK 开关表接线 | 两个门:(a) Minecraft 经 FCL **同机 spawn** 在 Adreno 830 双后端入世界,杀 server 产生干净 device-lost latch;(b) **另一台机器上的 client 经 TCP** 在 Redmi 上进世界(数据面 stream),并记录 P6.5 的必测数 |
|
||||
| **P13** 退役 pull 路径 | 待排 | 删 `SnapshotFromGLContext()` 非 verify 分支、`MGB_CTX`、`MOBILEGL_PIPE_PUSH`、`MOBILEGL_PIPE_LEGACY_MEMOS`;保留 `MOBILEGL_PIPE_VERIFY`;MGPipe recorder;删 `set_residual_value_state`;在计数器活着的情况下重调幸存缓存容量;建立模块 target 与边界(D12:`SOURCE_FILES` 是一张平表喂两个库 target,无模块可链)| `static_assert(sizeof(ResidualValueBlock) == 0)`;三道纯度门在非 verify 构建上转绿;recorder 金标建立;monolith 逐线程 CPU 不差于 P0 基线 |
|
||||
|
||||
CTS 周转单独计价(`gl44to46` 约 56,271 例):逐阶段只跑该阶段可能影响的具名块;完整 caselist 只在架构边界与合并 `dev` 之前跑,放 CI 不放关键路径。
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# P12 集成者裁定日志(「server 自有屏幕窗口」子集)
|
||||
|
||||
> 形式沿用 [`../p7/INTEGRATOR-DECISIONS-P7.md`](../p7/INTEGRATOR-DECISIONS-P7.md):一条裁定一个 ID,只记「定了什么、为什么、影响哪些文件」,不记来回。计划与交接见 [`PLAN-P12.md`](PLAN-P12.md),任务书见 [`BRIEF-onscreen.md`](BRIEF-onscreen.md)。
|
||||
|
||||
| ID | 日期 | 裁定 | 理由 | 影响 |
|
||||
|---|---|---|---|---|
|
||||
| ID-P12-1 | 2026-09-24 | 用户四条裁定为本子集的边界:server APK 自建 `ANativeWindow`(自己的 SurfaceView)**上屏**,离屏(pbuffer)路径保留;**同一时刻只一条活跃**,在 server 初始化 / context 创建时决定;拓扑为**进程内 server**(display Activity 自己的进程里一个线程跑 TCP server,会话串行);client 以新的 `WindowKind::ServerOwned`(控制修订 3)接入,可**完全无头**,几何由 server 回传。 | 用户裁定(`BRIEF-onscreen.md` §User rulings);ROADMAP P12 行「按重审 §6 改小」已删掉 Surface 传递那一半。 | 全部 15 个 `(P12)` 提交 |
|
||||
| ID-P12-2 | 2026-09-24 | 会话的表面模式在**第一次成功的表面创建**时闩定(ServerOwned 窗口 → 上屏,pbuffer → 离屏),之后另一种表面**具名拒绝**(`SurfaceRefusal::SurfaceModeMismatch`,reply ok=false,不闩会话);client 自己命名的窗口(X11/Win32/None,D8 未关)两种都不算、不闩也不拒。 | 「同一时刻只一条活跃」落到每会话;拒绝是配置答复,不是对端坏字节。 | `ServerLoop.{h,cpp}`(`SessionSurfaceModeAdmits`) |
|
||||
| ID-P12-3 | 2026-09-24 | 失窗(`surfaceDestroyed` → `ServerDisplay::Detach`)的顺序即契约:apply 线程先让后端放掉窗口(Espryt 销毁 EGL surface/context,Magma 销毁 swapchain/VkSurface),再以 `Fatal{ServerWindowLost}` 闩会话(client 读干净 device lost),**最后**才结束租约、让回调返回;`Detach` 有界 3 s,超时不抽走窗口(引用留到租约结束),具名 `TimedOut`。 | GLSurfaceView 契约:回调返回后不得再往窗口渲染;UI 线程不能被无界占住。 | `ServerDisplay.{h,cpp}`、`ServerLoop.cpp`、`FatalFamilies.def`、`DisplayServerJni.cpp` |
|
||||
| ID-P12-4 | 2026-09-24 | 进程内 server 用线程交接会话(`TcpSupervisor::Handoff::Thread`):预认证、Busy、DataBind 路由与 fork 形状同一份代码;会话间 `ResetSessionLatch`;后端**按进程钉住**(无 `MOBILEGL_BACKEND_TYPE` 时取第一个会话的);fork 出的会话子进程 `PR_SET_PDEATHSIG` 随监督进程去。以崩溃隔离换窗口可达:会话里一个未武装的 `SessionFail` 会带走 Activity 进程。 | `ANativeWindow` 过不了 fork / exec;Espryt 与 Magma 永不同进程(`BenchService.java` 的规则)。 | `ServerMain.cpp`、`InProcessServer.h` |
|
||||
| ID-P12-5 | 2026-09-24 | 以下是**审查轮的修复**(15 条发现归并为 10 个问题,2 条被驳回为本改动之前就有的问题、不在本 diff 内)。**大项一**:失窗请求在 `DrainRing` 的**每次 pop 之前**也检查(在 latch 检查之后,`ph_latch_sites.py` 的 MECHANICS 行仍钉 latch 检查为循环首句),不再只在批与批之间由 `PumpControlRequest` 应答。 | 持续推帧的 client 让命令环数秒不空:`surfaceDestroyed` 在 UI 线程等满 3 s 后 `TimedOut`,会话继续往已销毁的窗口 present。 | `ServerLoop.cpp`;`ServerLoopLatchTest.ALostServerWindowIsReleasedMidBatchWhileTheClientStreams` |
|
||||
| ID-P12-6 | 2026-09-24 | **大项二**:`DropEveryTwinForEndedServerSession` 同时清空 `TextureImpl::g_boundTexturesCache`、`SamplerImpl::g_boundSamplersCache`,并把 `g_activeTextureUnit` 置回 0。 | twin 在 `InProcessTeardown()` 为真时不从单元影子里擦掉自己,影子留下指向已释放 twin 的裸指针;下一会话的 twin 落在回收地址上就读成「已绑定」而跳过真实绑定,上传落到 texture 0、画面黑。新 context 的活动单元是 `GL_TEXTURE0`。 | `Managers.cpp`;`SanityTest EsprytServerSession.TheServerBackendsDestructionEmptiesTheTextureAndSamplerUnitShadows` |
|
||||
| ID-P12-7 | 2026-09-24 | **停在推流中**:进程内 server 停止(`mobilegl_server_stop_inprocess`)时,`RunSession` 在 `loop.Stop()` 之前调 `ServerLoop::AbandonQueuedRecords()`:drain 在手上这条记录后停,退出路径不再 drain 剩余队列(与 `ReverseChannelForfeit` 同形)。**正常的 client EOF 仍 drain 完**。 | 批内剩余 + 退出 drain 一个仍在被补满的环,会超出 `Stop()` 的 5 s 有界 join,`Fatal{ApplyThreadJoinTimeout}` 带走 Activity 进程。 | `ServerLoop.{h,cpp}`、`ServerMain.cpp`;`ServerLoopTest.StoppingTheServerUnderAStreamingClientLeavesTheQueueAndJoinsPromptly` |
|
||||
| ID-P12-8 | 2026-09-24 | **会话结束的清理补齐两处**:Magma 的 `~BackendObject_DirectVulkan` 在传输下丢弃进程全局的 `pVulkanRenderer`(带代际递增与程序反射缓存清理,同 `ReleaseEGLResources`);Espryt 的析构调 `ForgetRequestedSwapInterval()`。monolith 不变;pull 构建的析构仍为 `= default` / 不变(G1)。 | 未经 `eglTerminate` 就断开的 client 不会发 `ReleaseEGLResources`,renderer(窗口上的 swapchain / VkSurface)在租约结束后仍挂在窗口上;swap interval 是有意跨表面重建保留的进程全局,下一会话会静默继承上一个 client 的值。 | `BackendObject_DirectVulkan.cpp`、`DirectGLES.{h,cpp}`、`BackendObject_DirectGLES.cpp` |
|
||||
| ID-P12-9 | 2026-09-24 | **陈旧尺寸**:`ServerDisplay` 记下最后请求的几何与布局最后报告的尺寸;在固定尺寸之后请求 0/0(窗口自己的尺寸)时,等(几何宽限内)布局尺寸回来,或等请求之后任何一次不等于旧固定尺寸的报告。 | `setSizeFromLayout` 与 `setFixedSize` 一样是异步应答;原实现对 0/0 立即授租,拿到的是上一会话的固定尺寸。 | `ServerDisplay.{h,cpp}`;`ServerDisplayTest.TheWindowsOwnSizeAfterAFixedSizeIsTheLayoutsNotTheStaleFixedOne` |
|
||||
| ID-P12-10 | 2026-09-24 | **client 侧几何三条**:(a) 对 server-owned 表面的 `ResizeEGLWindowSurface` 走几何请求(同一持有者重取租约、等 display),后端表面随窗口**真实**尺寸,reply 带回该尺寸,client 采用它而不是自己请求的值(`ServerResizeServerOwnedWindowSurface`);(b) client 跟踪**全部** server-owned 表面,一个 extent 应用到所有(它们共用 server 的一个窗口);(c) Espryt 的 extent 发布只针对 server 自己的窗口——`ServerLoop` 经 split-only 的 `MGPipeServerSetOwnedWindow` 告诉后端哪个窗口是自己的,client 自己命名的窗口保持只发格式。 | (a) 原实现只改后端记录,手机上的 SurfaceView 不变,EGL 状态报的是请求值;(b) 单槽让第二个表面抢走第一个的更新、释放后第一个再无更新;(c) 不带旋钮的会话被切到了重分配臂。 | `ServerLoop.{h,cpp}`、`BackendObject_Remote.cpp`、`ClientSession.{h,cpp}`、`PipeInputs.{h,cpp}`、`DirectGLES.cpp` |
|
||||
| ID-P12-11 | 2026-09-24 | **日志转发**:进程内 server 装 `SetSessionLogForwarder`——只有会话线程与选择加入的线程(该会话的 apply 线程,`SetThreadForwardsLogToPeer`)转发,且在释放日志互斥之后、在独立的转发互斥下发送(`WithLogBarrier` 两把都拿,flush ack 仍在每条已开始的发送之后;发送本身打的日志不再转发)。fork 出的会话子进程仍用 `SetLogForwarder`,pull 构建的 `Log()` 不变(G1)。 | `MOBILEGL_IPC_ROLE=server` 让 Activity 进程里每个线程都是 server 角色:UI 线程与监听线程(含别的对端地址、Busy 拒绝)的日志进了当前 client 的控制 socket;而阻塞的 `SendFrame` 在全局日志互斥下执行,不读的 client 会在 UI 线程下一次打日志时把它挂住。 | `Log.{h,cpp}`、`ServerMain.cpp`、`ServerLoop.cpp` |
|
||||
| ID-P12-12 | 2026-09-24 | `IterationRPProgram203Scenario`(`integration-magma-full-split`)**不在本轮范围内**,门里出现时按「既有、环境敏感」读(ID-P7-22),不阻塞 P12 的合并。 | 用户裁定(2026-09-24);PLAN-P12 §2 已独立复核非本包引入。 | 过程 |
|
||||
| ID-P12-13 | 2026-09-24 | 审查轮修复**未在真机上复测**:本轮的执行环境是没有 Android 设备与 NDK 的云容器,APK 重建、设备七项检查、以及「推流中按 HOME、回调返回前 surface 已释放并记录耗时」这一项都**没有跑**,留作 P12 收尾的下一次设备窗口。主机门见 ID-P12-14。 | 如实记录;设备证据仍是 `device/` 下审查轮之前(`29b7b284`)的。 | 过程 |
|
||||
Reference in New Issue
Block a user