一、设备面板和刷新率配置

从 trace 可以看到,这台小米设备支持 两种 DDIC 显示模式:

ConfighwcIdDDIC Modesf_fpsddic_min_fpsMode Group说明
id=33ddic_mode=1 (auto)120124641792LTPO 自动模式,最低可降至 1fps
id=44ddic_mode=2 (固定)1201041421312固定模式,最低 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_tick7 秒MiuiShowStyleController 更新 AOD 样式
AODUpdatePositionController10 秒防烧屏位移(mTranslationYStep: 243.625)
doze_time_tick~53 秒更新时钟显示
DozeScreenState alarm6 秒屏幕状态检查/重置
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。