用户真机 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 未动)。
170 lines
9.3 KiB
C
170 lines
9.3 KiB
C
/* 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;
|
||
}
|