/* 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 #include #include #include #include #include /* 覆盖存储路径到临时目录(需父目录存在;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; }