用户真机 M6.2 实测三症状,全部位于锁屏/通知中心叠加路径。根因与修法: S1 锁屏输入穿透(PIN 触摸打到下层 App / 解锁后「启动奇怪界面」) 根因:run_app_lock_overlay / run_app_notif_overlay 关闭路径先 unlink /tmp/meow_notif_active 再 SIGCONT App——App 被 SIGSTOP 冻结期间缓冲的 evdev 触摸事件在解除瞬间被 SDK 输入线程在无隔离态回放成 App 内点击(穿透触发)。 修法:反序——标记仍在时先 SIGCONT,让 SDK 输入线程排空冻结期缓冲事件 + EVIOCGKEY 对齐,等 OVERLAY_DRAIN_WINDOW_MS(300ms > SDK 200ms 节流) 再 unlink。 S2 解锁后状态栏消失(App 无状态栏全屏残留) 根因:S1 的回放点击常把 App 导航进全屏页(状态栏随 app.json/fullscreen 隐掉); 叠加关闭路径也未强制状态栏重同步。 修法:解锁后 g_sb_mode_last=-1 + 立即 app_overlay_statusbar() 重叠加(不等 1s 慢刷)。 S3 App 异常死亡(OOM sig=9)残影——fb0 停 App 死帧、无状态栏、launcher 不重绘主屏 根因:锁屏叠加(run_app_lock_overlay→run_lock_screen)阻塞于 lock_screen 内, App 叠加期崩溃不被感知(notif 叠加有 run_notif_center 的 proc_is_zombie 探测, 锁屏独缺),launcher 卡在锁屏会话永不回 menu 重绘。 修法:run_app_lock_overlay 置位 g_lock_overlay_pid,run_lock_screen 每圈 proc_is_zombie 探测,App 死即中止锁屏(LCK_OVERLAY_RET_DIED)走统一退出路径 (reap_wait 回收 + ams_status_valid + break → run_menu 重绘主屏含状态栏)。 新增 overlay_gate.h(纯决策,宿主可单测)+ test_overlay_gate.c(10 断言)+ test_lock_screen.c 扩展(4 断言 overlay-abort)。launcher 全量宿主回归 + SDK 叠加/状态栏回归(overlay_suppress/sb_collapse/notif_open/notif_gesture/ sdk_fixes/sdk_input_keys)全 PASS;mipsel 交叉 -Wall -Wextra 0 warning。 md5 136dc67c086a9d75c0ad9c83d519ff0d(/usr/bin 只读,待固件打包;fw_content.conf 未动)。
109 lines
6.3 KiB
C
109 lines
6.3 KiB
C
/* lock_screen.h — MeowOS 锁屏 4 位 PIN(系统级安全,纯逻辑;宿主可单测)。
|
||
*
|
||
* 模型(用户定案,2026-09-02):
|
||
* - 设置键 `system.pin`:4 位数字 PIN 的 sha256+salt 哈希,存 settings.conf。
|
||
* 格式与面板 panel.pin **全等**:`<salt_hex>:<sha256_hex(salt||pin)>`,salt 16B
|
||
* /dev/urandom → 32 hex;绝不存明文、绝不在日志/响应中输出 hash。
|
||
* - 面板同源迁移:`panel.pin` 已设而 `system.pin` 未设时,锁屏接受 panel.pin,并在
|
||
* **首次验证成功后并入 system.pin**(lck_pin_success 把 panel.pin 值拷入 system.pin)。
|
||
* - 锁屏时机:息屏唤醒后(默认开,`system.pin_lock_on_wake=1` 可关)+ 电源菜单「锁定」
|
||
* 手动锁;**开机不锁**(boot 进主屏不拦,本逻辑不被 boot 路径调用)。
|
||
* - 错 5 次锁 5 分钟:`system.pin_fails`(连续错计数)与 `system.pin_lock_until`(锁定
|
||
* 截止 epoch 秒)**持久化到 settings.conf**——launcher 重启不清零(面板的进程内存方案
|
||
* 在重启后失效,这里要落盘)。
|
||
* - 兜底:SSH root 删 `system.pin` 键即解锁(无其它后门)。
|
||
*
|
||
* 本头只声明纯逻辑接口;渲染/输入循环在 lock_screen_ui.c(run_lock_screen)。逻辑依赖
|
||
* meow_settings_* API(与 meowpanel 的 settings_get_value 语义同源,走同一 settings.conf)。
|
||
* 宿主测试:#include "lock_screen.c" + 真实 meow_settings.c(-DMEOW_SETTINGS_FILE 覆盖)。
|
||
*/
|
||
#ifndef MEOW_LOCK_SCREEN_H
|
||
#define MEOW_LOCK_SCREEN_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include <time.h>
|
||
|
||
#define LCK_PIN_LEN 4 /* 恰好 4 位数字 */
|
||
#define LCK_PIN_MAX_FAILS 5 /* 连续错 PIN 锁定阈值 */
|
||
#define LCK_PIN_LOCK_SEC 300 /* 锁定 5 分钟 */
|
||
#define LCK_HASH_LEN 64 /* sha256 hex 长度 */
|
||
|
||
/* ---- 设置键(必须已在 meow_settings.c g_defs 注册)---- */
|
||
#define LCK_KEY_PIN "system.pin"
|
||
#define LCK_KEY_WAKE "system.pin_lock_on_wake"
|
||
#define LCK_KEY_LOCK_UNTIL "system.pin_lock_until"
|
||
#define LCK_KEY_FAILS "system.pin_fails"
|
||
#define LCK_KEY_PANEL_PIN "panel.pin" /* 面板 PIN(read-only 兼容源) */
|
||
|
||
/* ---- 文件标志(tmpfs,重启自然消失)---- */
|
||
#define LCK_UNLOCK_ONCE_FILE "/tmp/meow_pin_unlock_once" /* 面板一次性解锁恢复口:存在即消费放行 */
|
||
#define LCK_MANUAL_LOCK_FILE "/tmp/meow_pin_locked" /* 电源菜单「锁定」主动锁标志:唤醒必锁屏 */
|
||
|
||
/* PIN 合法:恰好 4 位数字(0-9)。NULL/长度不符/含非数字 → 0。 */
|
||
int lck_pin_valid(const char *pin);
|
||
|
||
/* 是否已配锁屏凭据:system.pin 设 或 panel.pin 设(锁屏可开)。 */
|
||
int lck_pin_configured(void);
|
||
|
||
/* 唤醒是否应锁屏:system.pin_lock_on_wake(默认 1) 且 已配凭据。
|
||
* 仅由「息屏唤醒」路径调用——boot 路径不调,天然开机不锁。
|
||
* allow_disable=0 时忽略 WAKE 键(电源菜单「锁定」手动锁用,锁前需已配凭据)。 */
|
||
int lck_lock_required(int allow_disable);
|
||
|
||
/* 明文校验:system.pin 优先;未设时回退校验 panel.pin(迁移)。恒定比较,不反解。 */
|
||
int lck_pin_check(const char *pin);
|
||
|
||
/* 设置/修改 system.pin(明文→sha256+salt 落盘):校验 4 位数字;清连续错计数+锁定戳;**落盘**。
|
||
* 返回 MEOW_OK / 负错误。设置页/CLI 设锁屏 PIN 走此。 */
|
||
int lck_pin_set(const char *pin);
|
||
/* 清除 system.pin(解锁兜底,SSH root 删键即解锁的同义 API):清计数+锁定戳,**落盘**。 */
|
||
int lck_pin_clear(void);
|
||
|
||
/* 记录一次成功验证:首次成功时把 panel.pin 并入 system.pin(迁移);清连续错计数 + 清
|
||
* 锁定戳;**落盘**。返回 MEOW_OK。 */
|
||
int lck_pin_success(void);
|
||
|
||
/* 记录一次失败:递增连续错计数(持久化);达 LCK_PIN_MAX_FAILS → 设锁定戳(now+300s)并清
|
||
* 计数。已处于锁定(now<截止)时不递增。返回**剩余锁定秒**(0=未锁)。
|
||
* 调用方须先 lck_lock_remaining() 确认未锁才让输入;已锁时本函数不改变截止。 */
|
||
int lck_pin_fail(void);
|
||
|
||
/* 剩余锁定秒(0=未锁定)。若截止已过,自动清锁定戳+计数并落盘(进程内已解禁)。 */
|
||
time_t lck_lock_remaining(void);
|
||
|
||
/* ---- 面板一次性解锁恢复口(tmpfs 标志文件)----
|
||
* 锁屏页进入时 / 每次重试前调用:LCK_UNLOCK_ONCE_FILE 存在 → **删除并返回 1(放行进入系统一次)**;
|
||
* 不存在 → 0。不校验 PIN、不清除 system.pin 本身、不重置失败计数(重启标志自然消失)。 */
|
||
int lck_unlock_once_consume(void);
|
||
|
||
/* ---- 电源菜单「锁定」主动锁标志(tmpfs,重启消失)----
|
||
* 主动锁屏:写 LCK_MANUAL_LOCK_FILE → 之后唤醒 `lck_wake_should_lock()` 无论 system.pin_lock_on_wake
|
||
* 是否开都必走锁屏;解锁(PIN 或面板绕过)时清除。 */
|
||
int lck_manual_lock_set(void); /* 写标志;返回 MEOW_OK */
|
||
void lck_manual_lock_clear(void); /* 删标志(幂等) */
|
||
/* 唤醒是否应锁屏:已配凭据 且 (system.pin_lock_on_wake=1 或 主动锁标志存在)。
|
||
* 取代 lck_lock_required(1) 作为唤醒门——主动锁强制锁屏,覆盖「关闭唤醒锁」的手动锁场景。 */
|
||
int lck_wake_should_lock(void);
|
||
|
||
/* ── 锁屏叠加期 App 存活探针(§310 残影修复,纯判定,宿主可单测;header-only inline)----
|
||
* 锁屏运行在 App 前台叠加会话中(overlay_pid>0,run_app_lock_overlay 置位)且该进程已成僵尸
|
||
* (调用方 proc_is_zombie 判定后传入 proc_zombie=1)→ 应中止锁屏走统一退出(返回 1)。
|
||
* 菜单直接锁屏(overlay_pid=0,无 App 可死)恒 0;此谓词不实际读 /proc。 */
|
||
static inline int lck_overlay_should_abort(int overlay_pid, int proc_zombie)
|
||
{
|
||
return (overlay_pid > 0 && proc_zombie) ? 1 : 0;
|
||
}
|
||
|
||
/* run_lock_screen() 返回值:1=已解锁,0=锁屏期间电源键息屏。叠加期 App 崩溃时返回
|
||
* LCK_OVERLAY_RET_DIED(-1)——调用方 run_app_lock_overlay 据此外走「统一退出路径」
|
||
* (不再 SIGCONT 死进程/不恢复死帧,交回 waitpid 循环回收,run_menu 重绘主屏)。 */
|
||
#define LCK_OVERLAY_RET_DIED (-1)
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif /* MEOW_LOCK_SCREEN_H */
|