背景:锁屏页(run_lock_screen)此前常亮不灭屏——用户停在锁屏页不操作,屏幕一直亮着耗电。
M6.6 上机后用户反馈,补 294 遗留项「锁屏页未做空闲超时自动息屏」。
实现(/usr/bin 只读,待 M6.7 固件打包,fw_content.conf 未动):
- run_lock_screen 循环加空闲跟踪(last_act)+ 自睡状态(asleep):
① 阈值 = overlay_lock_idle_off_sec(screen_off_timeout) = min(系统 screen_off_timeout, 30s)。
系统未设/设 0(常亮)/超 30 → 锁屏页封顶 30s(锁屏页不应常亮耗电);系统设更短 → 尊重更短。
② 活跃态空闲超阈值 → meow_panel_off()(与息屏路径一致:panel 模式 FBIOBLANK 4 挂起 goodix /
black 模式仅背光 0)+ asleep=1 —— 锁态保持,仍留在锁屏循环(=「锁屏页自己也会睡」)。
③ asleep 后电源键按下边沿 或 触摸活动 → meow_panel_on() + lk_draw 重画锁屏页(本循环唤醒链
回锁),输入活动(任意按键 change / 触摸)都重置 last_act。
④ 音量键本页不动,仅计入输入活动重置计时;自睡期面板已关,不重绘(唤醒时统一重画)。
- EVIOCGRAB 与灭屏交互(核对结论):灭屏期 grab **保持**(tfd 不关)。panel 模式 FBIOBLANK 4
挂起 goodix → 灭屏期无触摸事件,唤醒只走电源键;black 模式触摸仍活动且被抓取者(launcher)独占
→ 唤醒第一下触摸进锁屏(不穿透 App、不被吞——被锁屏作为活动消费,可能命中 PIN 键)。唤醒后
FBIOBLANK 0 + grab 仍在,全程无穿透。
- App 前台叠加锁屏(run_app_lock_overlay)期间 App 的 /tmp/meow_notif_active 标记在整个自睡/
唤醒周期保持(仅锁屏退出才 unlink),故媒体保活 App 自睡期仍被 present 抑制,不覆盖锁屏。
overlay_gate.h 增 overlay_lock_idle_off_sec / overlay_lock_should_sleep / overlay_lock_wake_now
(纯决策,可单测)。test_overlay_gate.c 扩展 S4(12 断言:阈值 tradeoff / 超时灭屏 / 唤醒回锁屏 /
屏幕关不重睡)。launcher 全量宿主回归 + SDK 叠加/状态栏/输入回归全 PASS;mipsel 交叉 -Wall -Wextra
0 warning。md5 42b6633afde37035585fc36b074a73c6(待 M6.7 固件打包,不部署)。
94 lines
5.7 KiB
C
94 lines
5.7 KiB
C
/* overlay_gate.h — SIGSTOP 叠加会话(通知中心 §10.5 / 锁屏 M2.x)关闭与死亡回退的**纯决策**。
|
||
*
|
||
* 宿主可单测(无信号/无设备/无文件系统依赖,全部 static inline);app_launcher.c 的两处叠加
|
||
* 关闭路径(run_app_notif_overlay / run_app_lock_overlay)调用,避免把「排空窗口」「中止条件」
|
||
* 这类时序/判定散落内联难验证。三个 bug 的定案语义都收敛到这里:
|
||
*
|
||
* ① 输入穿透(S1 根因):App 被 SIGSTOP 冻结过 → 关闭时必须在 /tmp/meow_notif_active 仍存在
|
||
* 时先 SIGCONT,让 SDK 输入线程(meow_ui_input.c overlay_input_suppressed)排空冻结期缓冲的
|
||
* evdev 事件副本 + 对齐 EVIOCGKEY,再等 OVERLAY_DRAIN_WINDOW_MS 后 unlink 标记。
|
||
* 若反序(unlink->SIGCONT,改动前写法),App 在无隔离态恢复 → 解冻瞬间把积累的触摸回放成
|
||
* App 内点击(锁屏穿透 /「启动奇怪界面」/ 解锁后状态栏消失的触发源)。
|
||
* ② 状态栏恢复(S2):解锁后强制 g_sb_mode_last=-1 让 app 循环立即重叠加,不等 1s 慢刷。
|
||
* ③ 死亡重绘(S3):锁屏叠加中 App 崩溃(/proc/<pid>/stat==Z)→ 中止锁屏走统一退出路径,
|
||
* 由 waitpid 循环回收 + run_menu dirty=1 重绘主屏(含状态栏)。
|
||
*/
|
||
#ifndef MEOW_OVERLAY_GATE_H
|
||
#define MEOW_OVERLAY_GATE_H
|
||
|
||
/* SDK overlay_input_suppressed() 的标记存在性节流窗是 200ms;排空窗须 > 该值(留 100ms 余量),
|
||
* 保证 App 恢复后 SDK 输入线程确实重新 stat 到标记再整批丢弃缓冲事件。 */
|
||
#define OVERLAY_DRAIN_WINDOW_MS 300
|
||
|
||
/* ① 排空是否必要:App 被 SIGSTOP 冻结过(非保活)才需要「SIGCONT 保持隔离 → 排窗 → unlink」;
|
||
* 媒体保活(keep_running,从未 STOP)直接「恢复帧上屏 → unlink」(自抑随标记消失自然解除)。 */
|
||
static inline int overlay_drain_required(int keep_running)
|
||
{
|
||
return !keep_running ? 1 : 0;
|
||
}
|
||
|
||
/* ③ 锁屏叠加中 App 崩溃是否触发「统一退出路径」(= 中止锁屏、交回 waitpid 循环回收、run_menu 重绘)。
|
||
* proc_zombie=1(/proc/<pid>/stat==Z)→ 走退出(返回 1);否则正常恢复(返回 0)。 */
|
||
static inline int lock_overlay_app_died_exit(int proc_zombie)
|
||
{
|
||
return proc_zombie ? 1 : 0;
|
||
}
|
||
|
||
/* ② 解锁后是否需要强制状态栏重同步(返回 1):始终需要——把 g_sb_mode_last 拨回 -1,
|
||
* 使 run_menu / app 循环的「模式变化→立即重叠加」分支命中(-1 != m 恒真除非 m==-1,
|
||
* 但 m==-1 表示无模式文件=展开态,同样被 app_overlay_statusbar 兜底到展开整条)。 */
|
||
static inline int overlay_force_sb_resync(void)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/* 未冻结(媒体保活,keep_running)App 是否**需要 EVIOCGRAB 独占隔离**(返回 1)。
|
||
* §310 问题1真根:媒体保活 App 从不 SIGSTOP(保 PCM),SDK 输入线程**实时读 evdev**(不走缓冲),
|
||
* 标记(/tmp/meow_notif_active)让 SDK 排空只在有该新 SDK 的 App 上生效;launcher 侧可**无条件**
|
||
* 用 EVIOCGRAB 独占触控设备,使包括保活 App 在内的**任何**前台进程在锁屏期收不到触摸(且抓取期
|
||
* 事件不为未抓取 fd 缓冲/回放)。keep_alive=1 → 隔离靠 grab(overlay_drain_required==0,无
|
||
* SIGCONT 排空语义);冻结 App(keep_running=0)→ 隔离靠 SIGSTOP+SIGCONT 排空(drain_required==1)。 */
|
||
static inline int overlay_keepalive_needs_grab(int keep_running)
|
||
{
|
||
return keep_running ? 1 : 0;
|
||
}
|
||
|
||
/* 锁屏进场后「重铺全屏不透明底」的阈值(ms)。SDK present 抑制标记节流窗(MEOW_OVERLAY_CHK_MS)
|
||
* 是 200ms——媒体保活 App 不冻结、锁定瞬间还会进 1-2 帧(部分脏区盖到锁屏上)。阈值取 300ms
|
||
* (> 200ms),保证覆盖到抑制窗内 App 的残帧;App 此后被抑制不再上屏,锁屏稳定遮盖。
|
||
* 由 lock_screen_ui.c 的 run_lock_screen 重铺逻辑使用(单测同源断言)。 */
|
||
#define OVERLAY_LOCK_COVER_MS 300
|
||
|
||
/* 唤醒是否应触发锁屏(§310 M6.5 问题1):超时息屏(meow_auto_slept)与电源键手动息屏(watchdog
|
||
* 直接 blank 面板、背光 0 → launcher 检测得 app_panel_manual_off)两类唤醒都须走 lck_wake_should_lock
|
||
* 语义——真机实测「App 内电源键手动息屏→亮屏无锁屏」(手动路径丢了锁屏触发、超时路径接了)。 */
|
||
static inline int overlay_wake_should_lock(int auto_slept, int manual_panel_off)
|
||
{
|
||
return (auto_slept || manual_panel_off) ? 1 : 0;
|
||
}
|
||
|
||
/* 锁屏页自睡阈值(秒,§310 M6.7,294 遗留):min(系统 screen_off_timeout, 30s)。
|
||
* 系统未设/设 0(常亮)/超 30 → 锁屏页封顶 30s(锁屏页不应常亮耗电);系统设更短 → 尊重更短。
|
||
* 返回正数秒。lock_screen_ui.c 的 run_lock_screen 空闲超时用它(单测同源断言)。 */
|
||
static inline int overlay_lock_idle_off_sec(int screen_off_timeout)
|
||
{
|
||
return (screen_off_timeout > 0 && screen_off_timeout < 30)
|
||
? screen_off_timeout : 30;
|
||
}
|
||
|
||
/* 锁屏页是否应自睡(§310 M6.7):屏幕亮(meow_screen_on)且在本循环 && 空闲(now-last_act) ≥ 阈值。
|
||
* 返回 1=超时灭屏(锁态保持)。 */
|
||
static inline int overlay_lock_should_sleep(int screen_on, unsigned long long idle_ms,
|
||
unsigned long long off_ms)
|
||
{
|
||
return (screen_on && idle_ms >= off_ms) ? 1 : 0;
|
||
}
|
||
|
||
/* 锁屏自睡后应否唤醒回锁屏页:电源键按下边沿 或 触摸活动。返回 1=唤醒(meow_panel_on+重画锁屏)。 */
|
||
static inline int overlay_lock_wake_now(int pwr_edge, int touch_ready)
|
||
{
|
||
return (pwr_edge || touch_ready) ? 1 : 0;
|
||
}
|
||
|
||
#endif /* MEOW_OVERLAY_GATE_H */
|