一、设备面板和刷新率配置
从 trace 可以看到,这台小米设备支持 两种 DDIC 显示模式:
| Config | hwcId | DDIC Mode | sf_fps | ddic_min_fps | Mode Group | 说明 | |
|---|---|---|---|---|---|---|---|
| id=3 | 3 | ddic_mode=1 (auto) | 120 | 1 | 24641792 | LTPO 自动模式,最低可降至 1fps | |
| id=4 | 4 | ddic_mode=2 (固定) | 120 | 10 | 41421312 | 固定模式,最低 10fps |
这是一块 LTPO OLED CMD 面板(分辨率 1224×2912,120Hz),支持 VRR(Vrr=1)。
二、进入 Doze 后的刷新率变化链路
阶段 1:正常状态(ON)
Config 4: ddic_mode=2, sf_fps=120, ddic_min_fps=10 → 面板工作在 120Hz 固定模式
阶段 2:准备休眠
MI-SF: updateScene: module=274 (ready_to_sleep), value=1, Vrr=1 MI-SF: setIdleFps choose FPS:120, mode:24641792, mode_group:24641792 → 收到 ready_to_sleep 信号 → Idle FPS 选择进入 mode_group=24641792 (ddic_mode=1/auto)
关键切换: SubmitDisplayConfig: Active configuration changed from config 4 to 3 → 从 config 4 (ddic_mode=2, min_fps=10) 切到 config 3 (ddic_mode=1/auto, min_fps=1)
阶段 3:Dim → OFF
MI-SF: updateScene: module=262 (Dim), value=0, pkg=system DisplayModeController: setDesiredMode: Idle status skip setActiveMode, isDdicIdleMode: 1 → DDIC 已进入 Idle 模式,跳过主动设置刷新率 → 此时面板已降低帧率
阶段 4:进入 DOZE (LP1)
dsi_panel_set_lp1 → DSI_CMD_SET_LP1 → 面板切入 LP1 (Low Power Mode 1) → LP1 模式下,DDIC 自主控制刷新 → ddic_mode=auto, ddic_min_fps=1, 面板帧率可降至 1fps 甚至更低
阶段 5:AOD 稳定态(定时器驱动刷新)
doze_time_tick: 每 ~53 秒触发一次(更新时间显示) smart_doze_time_tick: 每 7 秒触发一次(智能 AOD 检测) DozeScreenState alarm: 每 6 秒触发一次(屏幕状态重置) AODUpdatePosition: 每 10 秒触发一次(防烧屏位移)
这些定时器就是 Doze 下的”刷新率” —— 不再是 VSYNC 驱动的连续刷新,而是事件驱动的按需刷新。
三、刷新率降低的多层机制
┌─────────────────────────────────────────────────────────┐ │ 应用层 (SystemUI) │ │ DozeMachine 状态机:DOZE_AOD │ │ → 定时器驱动: 7s/10s/53s 间隔触发画面更新 │ │ → DozeScreenState: 控制屏幕亮/灭 (state 2→4) │ └──────────────────────┬──────────────────────────────────┘ │ ┌──────────────────────▼──────────────────────────────────┐ │ Framework 层 (SurfaceFlinger) │ │ ready_to_sleep → setIdleFps → config 4→3 │ │ ddic_mode: 固定(2) → auto(1) │ │ ddic_min_fps: 10 → 1 │ │ RefreshRateSelector: fixedMode_group=41421312 │ │ → 退出固定帧率策略,允许面板自由降帧 │ │ → Idle status skip setActiveMode, isDdicIdleMode=1 │ └──────────────────────┬──────────────────────────────────┘ │ ┌──────────────────────▼──────────────────────────────────┐ │ HWC/SDM 层 (Qualcomm) │ │ CommitThread: idle timeout, panel: cmd, 70000 us (70ms) │ │ → CMD 面板 idle 超时后停止主动提交帧 │ │ → 无新帧时面板进入 self-refresh │ └──────────────────────┬──────────────────────────────────┘ │ ┌──────────────────────▼──────────────────────────────────┐ │ 驱动/面板层 (DSI/DDIC) │ │ DSI_CMD_SET_LP1 → 面板进入 Low Power Mode 1 │ │ DSI PHY: ULPS (Ultra Low Power State) │ │ DDIC: 自主刷新 (Self-Refresh),帧率可低至 1fps │ │ → doze_brightness_high (AOD 高亮模式) │ │ → 只在收到新帧时才更新显示内容 │ └─────────────────────────────────────────────────────────┘
四、具体到 trace 中的刷新频率
进入 Doze AOD 后,屏幕 不再以固定帧率刷新,而是由以下事件触发画面更新:
| 触发源 | 间隔 | 触发内容 |
|---|---|---|
| smart_doze_time_tick | 7 秒 | MiuiShowStyleController 更新 AOD 样式 |
| AODUpdatePositionController | 10 秒 | 防烧屏位移(mTranslationYStep: 243.625) |
| doze_time_tick | ~53 秒 | 更新时钟显示 |
| DozeScreenState alarm | 6 秒 | 屏幕状态检查/重置 |
| DozeScreenBrightness sensor | 按需 | 环境光传感器触发亮度调整 |
每次画面更新的流程: 定时器触发 → acquire AODWakeLock → 更新 AOD View → SurfaceFlinger 提交一帧 → CMD面板接收 → release WakeLock → 面板回到 self-refresh (维持当前画面)
可以看到 trace 中 DozeScreenState 的状态变化序列: setDozeScreenState: 1 (未知) → 初始 setDozeScreenState: 2 (DOZE) → 进入 Doze 低功耗显示 setDozeScreenState: 4 (DOZE_SUSPEND) → 进入 Doze 挂起(完全停止刷新)
最终目标状态是 DOZE_SUSPEND(state=4),在这个状态下面板完全依赖 DDIC 的 self-refresh 维持画面,SurfaceFlinger 不再提交任何帧。
五、总结
进入 Doze 后刷新率降低是 四层协同控制 的结果:
| 层级 | 机制 | 效果 |
|---|---|---|
| 应用层 | DozeMachine 定时器驱动(7~53s) | 画面更新从连续变为间歇 |
| SF 层 | config 4→3, ddic_mode auto, min_fps=1 | 允许面板降至 1fps |
| HWC 层 | CMD 面板 idle timeout (70ms) + skip setActiveMode | 无新帧时停止提交 |
| 驱动层 | LP1 + ULPS + DDIC self-refresh | 面板自主维持画面,功耗最 |
核心目的是省电 —— AOD 场景下画面几乎是静态的(只有时钟在变),没必要以 120fps 连续刷新,用定时器按需刷新 + LP1 self-refresh 就够了,功耗可以从正常亮屏的数百 mW 降低到个位数 mW。