Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_lock_screen.c
T
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

170 lines
9.3 KiB
C
Raw 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.
/* test_lock_screen.c — M6.x 宿主测试:锁屏 4 位 PIN(lock_screen.c 纯逻辑 + 真实 meow_settings 后端)。
*
* 直接 #include "meow_settings.c" + "lock_screen.c" 于同一 TU(同 test_notif_tf.c 手法),以「真实
* settings.conf」验证:设置/校验/错5锁定持久化(重启不清)/唤醒路径触发/panel.pin 迁移。
* 与面板面板访问级 PIN 同格式(`salt:sha256(salt||pin)`),sha256 算法与 meowpanel 逐字一致。
*
* 运行:gcc -D_GNU_SOURCE -DMEOW_SETTINGS_FILE=\"/tmp/meow_lock_test/settings.conf\" \
* -o test_lock_screen test_lock_screen.c mydir? —— 实际在 launcher 目录:
* gcc -D_GNU_SOURCE -DMEOW_SETTINGS_FILE=\"/tmp/meow_lock_test/settings.conf\" \
* -I. -o test_lock_screen test_lock_screen.c && ./test_lock_screen
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <time.h>
/* 覆盖存储路径到临时目录(需父目录存在;test 内 mkdir) */
#include "meow_settings.c"
#include "lock_screen.c"
static int g_fail = 0;
#define CHECK(cond, msg) do { \
if (!(cond)) { fprintf(stderr, "FAIL: %s (%s:%d)\n", msg, __FILE__, __LINE__); g_fail++; } \
else fprintf(stderr, "ok: %s\n", msg); \
} while (0)
int main(void)
{
const char *conf = MEOW_SETTINGS_FILE;
mkdir("/tmp/meow_lock_test", 0755);
unlink(conf);
unlink("/data/meow_boot_default"); /* 尽力清掉 save 的 boot.default 同步残留(非 root 会失败,无碍) */
/* ---- 初始化(空文件:默认值激活)---- */
CHECK(meow_settings_init() == MEOW_OK, "init (empty conf)");
CHECK(lck_pin_configured() == 0, "no pin configured initially");
CHECK(lck_lock_required(1) == 0, "wake-required=0 when no pin");
/* ---- 设置/校验(lck_pin_set 落盘 + 校验正确/错误)---- */
CHECK(lck_pin_set("1234") == MEOW_OK, "set pin 1234");
CHECK(lck_pin_configured() == 1, "configured after set");
CHECK(lck_lock_required(1) == 1, "wake-required=1 (pin set, wake=1 default)");
CHECK(lck_pin_check("1234") == 1, "check correct pin");
CHECK(lck_pin_check("0000") == 0, "check wrong pin");
CHECK(lck_pin_valid("1234") == 1, "valid 4-digit");
CHECK(lck_pin_valid("12") == 0, "invalid len 2");
CHECK(lck_pin_valid("12a4") == 0, "invalid non-digit");
CHECK(lck_pin_valid("") == 0, "invalid empty");
CHECK(lck_pin_set("12") == MEOW_ERR_INVAL, "reject set non-4-digit");
/* ---- 唤醒路径触发 / 开关 ---- */
CHECK(lck_lock_required(0) == 1, "manual lock(allow_disable=0) always required");
meow_settings_set_int("system.pin_lock_on_wake", 0);
meow_settings_save();
CHECK(lck_lock_required(1) == 0, "wake-required=0 after wake=0");
CHECK(lck_lock_required(0) == 1, "manual still required after wake=0");
meow_settings_set_int("system.pin_lock_on_wake", 1);
meow_settings_save();
CHECK(lck_lock_required(1) == 1, "wake-required=1 after wake=1");
/* 开机不锁是结构性(boot 路径不调 lck_lock_required)——此处断言决策函数正确即隔离该项 */
/* ---- 唤醒门=主动锁标志:唤醒锁关 + 主动锁标志 → 仍必锁屏(电源菜单「锁定」语义)---- */
unlink("/tmp/meow_pin_locked");
meow_settings_set_int("system.pin_lock_on_wake", 0);
meow_settings_save();
CHECK(lck_wake_should_lock() == 0, "wake_should_lock=0 (wake=0, no manual marker)");
CHECK(lck_manual_lock_set() == MEOW_OK, "manual_lock_set ok");
CHECK(lck_wake_should_lock() == 1, "wake_should_lock=1 (manual marker, wake=0)");
lck_manual_lock_clear();
CHECK(lck_wake_should_lock() == 0, "wake_should_lock=0 after manual marker cleared");
meow_settings_set_int("system.pin_lock_on_wake", 1);
meow_settings_save();
CHECK(lck_wake_should_lock() == 1, "wake_should_lock=1 (wake=1)");
/* ---- §310 残影:锁屏叠加期 App 崩溃中止探针(纯判定)----
* 锁屏在 App 前台叠加会话(overlay_pid>0)且该 App 已成僵尸 → 中止锁屏(返回 1);
* 菜单直接锁屏(overlay_pid=0)恒不中止;叠加期 App 仍活(proc_zombie=0)也不中止。 */
CHECK(lck_overlay_should_abort(0, 0) == 0, "overlay abort=0 (no overlay pid, not zombie)");
CHECK(lck_overlay_should_abort(1234, 0) == 0, "overlay abort=0 (overlay pid, app alive)");
CHECK(lck_overlay_should_abort(0, 1) == 0, "overlay abort=0 (no overlay pid, zombie ignored)");
CHECK(lck_overlay_should_abort(1234, 1) == 1, "overlay abort=1 (overlay pid + zombie -> unified exit)");
/* ---- 面板一次性解锁恢复口(bypass 标志)---- */
CHECK(lck_unlock_once_consume() == 0, "unlock_once_consume=0 when flag absent");
{
int fd = open("/tmp/meow_pin_unlock_once", O_WRONLY | O_CREAT | O_TRUNC, 0644);
CHECK(fd >= 0, "create unlock_once flag");
if (fd >= 0) { write(fd, "1", 1); close(fd); }
}
CHECK(lck_unlock_once_consume() == 1, "unlock_once_consume=1 when flag present");
CHECK(access("/tmp/meow_pin_unlock_once", F_OK) != 0, "bypass flag consumed (deleted)");
CHECK(lck_unlock_once_consume() == 0, "unlock_once_consume=0 after consumed");
/* ---- 错 5 次锁定(持久化,重启不清)---- */
CHECK(lck_lock_remaining() == 0, "not locked before fails");
int r1 = lck_pin_fail(); /* 1 */
int r2 = lck_pin_fail(); /* 2 */
int r3 = lck_pin_fail(); /* 3 */
int r4 = lck_pin_fail(); /* 4 */
CHECK(r1 == 0 && r2 == 0 && r3 == 0 && r4 == 0, "first 4 fails not locked");
int r5 = lck_pin_fail(); /* 5 -> lock */
CHECK(r5 > 280 && r5 <= 300, "5th fail locks ~300s");
time_t rem1 = lck_lock_remaining();
CHECK(rem1 > 280 && rem1 <= 300, "lock_remaining reflects lockout");
/* 模拟 launcher 重启(重读 settings.conf)→ 锁定戳持久,不因重启清零 */
meow_settings_shutdown();
CHECK(meow_settings_init() == MEOW_OK, "re-init after shutdown (simulated reboot)");
time_t re = lck_lock_remaining();
CHECK(re > 280 && re <= 300, "lock persists after reboot (persisted)");
/* 锁定期间:正确 PIN 仍被识别(但 UI 层禁 input;此处验证逻辑不因锁定改变凭据) */
CHECK(lck_pin_check("1234") == 1, "correct pin still recognized during lockout");
/* 锁定到期:把截止戳拨到过去 → remaining 自动清 + 清零(进程内解禁) */
meow_settings_set_int("system.pin_lock_until", (int)time(NULL) - 1);
meow_settings_save();
CHECK(lck_lock_remaining() == 0, "expired lock auto-clears");
int fails_now; meow_settings_get_int("system.pin_fails", &fails_now);
CHECK(fails_now == 0, "fail counter cleared after expiry");
/* ---- panel.pin 迁移:system.pin 未设 + panel.pin 已设 → 接受 panel.pin;首成功并入 system.pin ---- */
/* 造一个合法 panel.pin(复用本库的哈希:先 set 得 hash 值,清 system.pin 转写 panel.pin) */
lck_pin_set("5678");
char pphash[MEOW_SET_MAX_LEN];
CHECK(meow_settings_get_str("system.pin", pphash, sizeof pphash) == MEOW_OK, "get system.pin hash");
meow_settings_set_str("system.pin", ""); /* 模拟 system.pin 未设 */
meow_settings_set_str("panel.pin", pphash); /* 面板已设 panel.pin(同 hash 格式) */
meow_settings_save();
CHECK(lck_pin_configured() == 1, "configured via panel.pin only");
CHECK(lck_lock_required(1) == 1, "wake-required via panel.pin");
CHECK(lck_pin_check("5678") == 1, "accept panel.pin when system.pin absent");
CHECK(lck_pin_check("1234") == 0, "reject wrong pin during migration");
/* 首次成功 → 并入 system.pin */
lck_pin_success();
char sp2[MEOW_SET_MAX_LEN];
CHECK(meow_settings_get_str("system.pin", sp2, sizeof sp2) == MEOW_OK && sp2[0], "system.pin set after migrate");
CHECK(strcmp(sp2, pphash) == 0, "system.pin == panel.pin after migrate");
CHECK(lck_pin_check("5678") == 1, "still accept after migrate (via system.pin)");
/* ---- 清除免旧 PIN(设置页清除语义:物理持机即授权,无旧密码要求)---- */
/* 先设一个 PIN,然后**不验旧 PIN** 直接 lck_pin_clear()(清除 API 本身无旧 PIN 前置)。
* 先清 panel.pin(迁移残留),确保「已设」只由 system.pin 贡献。 */
meow_settings_set_str("panel.pin", "");
meow_settings_save();
CHECK(lck_pin_set("2468") == MEOW_OK, "set pin 2468 for clear");
CHECK(lck_pin_configured() == 1, "configured before clear");
CHECK(lck_pin_clear() == MEOW_OK, "clear WITHOUT old PIN succeeds");
CHECK(lck_pin_configured() == 0, "not configured after clear (no old PIN path)");
/* ---- 清除(兜底解锁):lck_pin_clear 后不再要求锁 ---- */
/* lck_pin_clear 只清 system.pin;panel.pin 仍存(迁移源),先清掉再断言全部未配 */
meow_settings_set_str("panel.pin", "");
meow_settings_save();
CHECK(lck_pin_clear() == MEOW_OK, "pin clear (final)");
CHECK(lck_pin_configured() == 0, "not configured after clear");
CHECK(lck_lock_required(1) == 0, "wake-required=0 after clear");
/* 清理临时标志文件(幂等) */
unlink("/tmp/meow_pin_unlock_once");
unlink("/tmp/meow_pin_locked");
unlink(conf);
printf("\n%s\n", g_fail ? "SOME TESTS FAILED" : "ALL PASS");
return g_fail ? 1 : 0;
}