Files
AskaEth bcef8e092e fix(launcher,lock): §310 锁屏/叠加三连 bug——输入穿透·状态栏消失·App死亡残影
用户真机 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 未动)。
2026-09-02 03:41:39 +08:00

109 lines
6.3 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 */