From f2551a28a20749fdc5fd0287659212cfd09252b3 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Thu, 5 Nov 2026 21:32:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(watchdog):=20M20=20=E4=BA=AE=E5=B1=8F?= =?UTF-8?q?=E4=BA=AE=E5=BA=A6=E4=B8=8D=E5=86=8D=E5=9B=9E=E9=80=80=E5=9B=BA?= =?UTF-8?q?=E5=AE=9A=2060=EF=BC=88settings=20=E8=AF=BB=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E9=87=8D=E8=AF=95=20+=20=E6=9C=AA=E7=9F=A5=E5=BF=AB=E7=85=A7?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=E6=8B=86=E5=88=86=EF=BC=89=E2=80=94=20?= =?UTF-8?q?=E9=87=8D=E7=BC=96=E5=87=BA=E8=B4=A7=E4=BA=8C=E8=BF=9B=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 真机 0.8.46(2026-11-05 21:09 日志)复现「开机/亮屏背光跳到固定值」: 76646 [watchdog] power: panel ON (blank 0 + brightness 60) 而 /usr/data/meow/settings.conf 是 display.brightness = 1。根因链: - 出货 /usr/bin/meow_watchdog(md5 553840cd…,与仓库内二进制逐字节相同)是 2026-09-01 6a4d330 编出的旧版:不含 M6.23 的 settings 读取(strings 无 display.brightness_min,日志仍是旧格式 "brightness %d")—— M6.23 只改了源码、 没重编。旧版 wd_panel_on 无条件 write_brightness(wd_saved_bri>0?wd_saved_bri:60), wd_saved_bri 初值 60 且该 session 未熄屏过 → 亮屏写 60,覆盖 launcher 刚设的 1。 - 源码侧同样有 60 兜底:wd_settings_brightness() fopen 失败即 -1 → 回退快照 60。 改动(patch_v2/meow_watchdog/): - wd_settings_brightness():fopen 失败重试 3×10ms。覆盖 settings.conf「写 tmp+rename」 原子替换、开机早期 /usr/data 未就绪的瞬时窗口;只在失败时发生(成功路径 0 开销), 最坏 20ms,远小于亮屏轮询粒度 REFRESH_MS=100ms。 - 新增 wd_bri_decide() 纯函数:settings(clamp 后)→ 本次运行期真实快照 → 不写 (面板已亮,untouched)→ 安全低亮 10(面板黑且无任何值来源)。任何路径都不再写 60。 - wd_saved_bri 初值 60 → WD_BRI_UNKNOWN(0);wd_panel_off 只在读到正亮度时更新快照, 读失败/被 launcher 抢先写 0 时保留上一次真实值(不再是 (br>0)?br:60)。 - panel ON/OFF 日志带 src=settings|snapshot|untouched|safe-low 与 user/saved/cur, 真机一眼看出用的是哪一支。 - 背光路径加 MEOW_BACKLIGHT env 测试钩子(与 MEOW_SETTINGS_FILE 同款,真机无 env)。 - test_wd_fw.c 新增 21 条用例(决策 7 + settings 解析/重试 6 + panel OFF/ON 端到端 8); 端到端用例真的读写背光文件,复现「settings=1 → 亮屏写 1」而不是 60。 - 重编 meow_watchdog:mipsel 静态 MIPS32r2 ELF,md5 ad8c1f2b…,0 warning。 验证:./build_watchdog.sh host → 38 pass / 0 fail;交叉编译(-Os -Wall -Wextra -static) 0 warning,产物静态 MIPS32r2。 生效条件:meow_watchdog 在 squashfs /usr/bin,必须刷固件(或等价的重打包流程)才生效。 后续(不在本单 scope):scripts/build/fw_content.conf 第 32 行仍 pin 旧 md5 553840cd…, 不更新会让 build_fw_apps.sh 的强校验失败。 --- patch_v2/meow_watchdog/meow_watchdog | Bin 85580 -> 94308 bytes patch_v2/meow_watchdog/meow_watchdog.c | 98 ++++++++++++--- patch_v2/meow_watchdog/test_wd_fw | Bin 74448 -> 20336 bytes patch_v2/meow_watchdog/test_wd_fw.c | 167 ++++++++++++++++++++++++- 4 files changed, 246 insertions(+), 19 deletions(-) diff --git a/patch_v2/meow_watchdog/meow_watchdog b/patch_v2/meow_watchdog/meow_watchdog index 403541abdfdf5f273592d176b1b6ba37d9d0a7bf..2e6c4abd1dab44ae52c8c0996d32214e9936341e 100755 GIT binary patch delta 36740 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 Th2p&VC^eK1;`9vv2r>Tx$vATz delta 29586 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 K|4RE^|9>6`o}Q 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 diff --git a/patch_v2/meow_watchdog/meow_watchdog.c b/patch_v2/meow_watchdog/meow_watchdog.c index 78ff440..48b4a80 100644 --- a/patch_v2/meow_watchdog/meow_watchdog.c +++ b/patch_v2/meow_watchdog/meow_watchdog.c @@ -31,6 +31,9 @@ * (true|1|yes)。判定为 SDK 框架 App -> 音量/媒体键让位 SDK 输入层(meow_ui_input.c 已消化, * 防同一次按键双步进);电源仍由本进程兜底(SDK 对电源是 no-op)。裸自绘 App(framework=0/ * 无 framework)或 app.json 不可读 -> 音量/媒体键仍由本进程兜底(不造成功能真空)。 + * - M20 亮屏亮度:settings.conf 的 display.brightness(clamp 到 brightness_min..100)为唯一 + * 权威;settings 瞬时不可读用**真实观测快照**;两者都未知时**不写背光**(不再回退固定 60, + * 那会覆盖 launcher 刚设好的用户值 → 开机/亮屏跳 60)。面板已黑且无任何值来源才写安全低亮。 * Exits when the app process disappears (kill(pid,0) -> ESRCH) or on * SIGTERM from the parent. * @@ -192,16 +195,44 @@ static int g_fw_app = 0; /* ---- M2.22(A)+ M2.24 电源键接管:息屏/亮屏 + 长按菜单/强关 ---- */ static int wd_fbfd = -1; /* fb0 fd(main 里打开,供 FBIOBLANK/FBIOPAN 用) */ -static int wd_saved_bri = 60; /* 熄屏前亮度快照 */ + +/* M20(远古 bug 回归:开机/亮屏背光跳到固定 60):0 是「未知」哨兵,不是亮度值 + * (0 = 面板全黑/息屏,任何情况下都不是有效用户亮度)。旧代码让 60 同时表达 + * 「未知快照」和「兜底值」,于是一旦没有可信来源就把 60 写进背光,覆盖 launcher + * 刚按 display.brightness 设好的用户值(真机 0.8.46:用户亮度 1,亮屏仍写 60)。 */ +#define WD_BRI_UNKNOWN 0 +/* 唯一保留的固定亮度:settings 读不到 + 快照未知 + **当前亮度确实是 0**(面板黑)时才用。 + * 这条退路上不存在任何可保留的有效用户值,不写就是永久黑屏;取低亮(≈10% of + * max_brightness 101)而不是 60 —— 宁可暗到用户手动调亮,也不要夜里突然刺眼。 + * 注意 60 是固件 S11jpeg_display_shell 画完开机 logo 后写死的值(/etc/init.d,不在本仓库), + * 本进程任何分支都不再写 60。 */ +#define WD_BRI_SAFE_LOW 10 +/* M20 短期修复 A:settings 读取重试。settings.conf 由 launcher/audiod 以 + * 「写 .tmp + rename」原子替换,开机早期 /usr/data(UBIFS) 也可能尚未就绪, + * fopen 存在瞬时失败窗口。3 次 × 10ms 只覆盖该窗口:最坏总阻塞 (3-1)*10 = 20ms, + * 且只在失败时发生(成功路径 0 开销)。亮屏轮询粒度本身是 REFRESH_MS=100ms, + * 20ms 在「按键→亮屏」路径上不可感知(见 M20 报文)。 */ +#define WD_SETTINGS_TRIES 3 +#define WD_SETTINGS_GAP_MS 10 + +static int wd_saved_bri = WD_BRI_UNKNOWN; /* 熄屏前亮度快照;未知=WD_BRI_UNKNOWN(不再用 60) */ static int pwr_down = 0; /* 电源当前按住 */ static unsigned long long pwr_down_ms = 0; static int pwr_woke = 0; /* 按下时屏已黑 → 本次只作唤醒,松开不再 toggle */ static int pwr_menu_notified = 0; /* 已写 /tmp/meow_power_menu 请 launcher 弹菜单 */ static int pwr_force_done = 0; /* 8s 强关已发(防重复) */ +/* 背光 sysfs 路径(缺省 BACKLIGHT;env MEOW_BACKLIGHT 覆盖,供宿主测试隔离——与 + * MEOW_SETTINGS_FILE 同款测试钩子,真机无 env 走默认,行为不变)。 */ +static const char *wd_backlight_path(void) +{ + const char *e = getenv("MEOW_BACKLIGHT"); + return (e && e[0]) ? e : BACKLIGHT; +} + static int read_brightness(void) { - int fd = open(BACKLIGHT, O_RDONLY); + int fd = open(wd_backlight_path(), O_RDONLY); if (fd < 0) return -1; char buf[16]; int n = read(fd, buf, sizeof buf - 1); @@ -215,7 +246,7 @@ static void write_brightness(int val) { char buf[8]; int l = snprintf(buf, sizeof buf, "%d\n", val); - int fd = open(BACKLIGHT, O_WRONLY); + int fd = open(wd_backlight_path(), O_WRONLY); if (fd < 0) return; if (write(fd, buf, l) < 0) wd_log("backlight write %d: %s", val, strerror(errno)); close(fd); @@ -231,16 +262,24 @@ static const char *wd_settings_path(void) /* M6.23:亮屏恢复亮度以**用户设置**为准(/usr/data/meow/settings.conf 的 display.brightness), * 而非 wd_saved_bri 快照——该快照可能被污染:panel OFF 前 read_brightness() 可能读到 launcher - * 先写好的 0(launcher meow_panel_off 已 write_brightness(0)),`wd_saved_bri=(br>0)?br:60` 便落到 + * 先写好的 0(launcher meow_panel_off 已 write_brightness(0)),旧代码 `(br>0)?br:60` 便落到 * 默认 60;panel ON 恢复 60 与 launcher 按用户设置恢复 7 竞态 → 亮屏亮度跳变(真机「跳高到 60 / - * 又降回 7」,2026-09-03)。 + * 又降回 7」,2026-09-03)。旧公式里的 `:60` 已在 M20 移除。 * 与 launcher meow_settings_brightness_clamped() 同源(同文件、同 clamp:下限 display.brightness_min * 默认 1=极暗但可见、上限 100=防闪屏);本进程自身 wd_vol_load 早已读该文件,不引入 launcher 全量 * 依赖,保持 watchdog 独立性。返回 clamped 值;settings 文件不可读(S70 早启动 /usr/data 未就绪) - * → 返回 -1,调用方回退 wd_saved_bri(保持旧行为,防开机竞态)。 */ + * M20 起:fopen 失败做 WD_SETTINGS_TRIES 次、间隔 WD_SETTINGS_GAP_MS 的短重试, + * 覆盖 settings.conf 原子替换 / 开机早期 /usr/data 未就绪的瞬时窗口;仍失败才返回 -1。 + * 只重试 open:rename 是原子的,已打开的 fd 指向旧 inode、内容完整,读内容无需重试。 + * 返回 -1 时调用方**不再**回退「默认 60」,取值语义统一由 wd_bri_decide() 决定。 */ static int wd_settings_brightness(void) { - FILE *f = fopen(wd_settings_path(), "r"); + FILE *f = NULL; + for (int i = 0; i < WD_SETTINGS_TRIES; i++) { + f = fopen(wd_settings_path(), "r"); + if (f) break; + if (i + 1 < WD_SETTINGS_TRIES) usleep(WD_SETTINGS_GAP_MS * 1000); + } if (!f) return -1; int b = 101; /* display.brightness 默认(与 launcher 设置表同值,键缺失时 clamp→100) */ int mn = 1; /* display.brightness_min 默认(极暗但可见;键缺失时保底) */ @@ -276,26 +315,53 @@ static void wd_pan_buf0_force(void) ioctl(wd_fbfd, FBIOPAN_DISPLAY, v); } +/* 亮屏亮度决策(纯函数:宿主单测直接断言,见 test_wd_fw.c)。 + * 返回 >0 = 要写入的背光值;返回 -1 = **不写背光**(保持当前值)。 + * *src 输出取值来源,原样写进日志供真机排查: + * settings settings.conf 的 display.brightness(已 clamp)—— 唯一权威 + * snapshot 本次运行期熄屏前读到的真实亮度(>0 才算数)—— settings 瞬时不可读时的过渡值 + * untouched settings 与快照都未知、但面板已亮 → 不覆盖现场(M20 核心修复) + * safe-low settings/快照都未知且面板当前为 0(黑)→ 点亮,用低亮而不是 60 + * 优先级:settings → 快照(真实近似值)→ 保持现状 → 安全低亮。 + * 任何分支都不再写「固定 60」:60 只在固件 S11 画完开机 logo 后写一次(固件侧问题,非本进程)。 */ +static int wd_bri_decide(int user, int saved, int cur, const char **src) +{ + if (user > 0) { *src = "settings"; return user; } /* 用户设置优先 */ + if (saved > 0) { *src = "snapshot"; return saved; } /* 真实观测到的近似值 */ + if (cur > 0) { *src = "untouched"; return -1; } /* 已有可见亮度:绝不覆盖 */ + *src = "safe-low"; return WD_BRI_SAFE_LOW; /* 面板黑 + 无任何值来源 */ +} + static void wd_panel_off(void) { int br = read_brightness(); - wd_saved_bri = (br > 0) ? br : 60; + /* M20:快照只记「真实观测到的正亮度」。br<=0(读失败,或 launcher meow_panel_off 抢先 + * 写成 0)时保留上一次已知真实值,绝不写死 60 —— 否则 60 会在下次亮屏被当成用户值回放 + * (远古 bug 的燃料)。真的一次都没观测到正亮度时保持 WD_BRI_UNKNOWN。 */ + if (br > 0) wd_saved_bri = br; write_brightness(0); if (wd_fbfd >= 0) ioctl(wd_fbfd, FBIOBLANK, 4); /* 面板下电 + 挂起 goodix 触摸 */ - wd_log("power: panel OFF (was %d -> 0, blank 4)", br); + wd_log("power: panel OFF (was %d -> 0, blank 4, saved=%d)", br, wd_saved_bri); } static void wd_panel_on(void) { if (wd_fbfd >= 0) ioctl(wd_fbfd, FBIOBLANK, 0); - /* M6.23:恢复亮度以**用户设置**为准(wd_settings_brightness),settings 不可用时才回退 - * wd_saved_bri 快照(再退默认 60)——与 launcher meow_panel_on 同语义,杜绝「亮屏恢复 60 - * 与 launcher 恢复 7 竞态 → 跳变」。 */ - int b = wd_settings_brightness(); - int restore = (b > 0) ? b : (wd_saved_bri > 0 ? wd_saved_bri : 60); - write_brightness(restore); + /* M6.23 + M20:用户设置为唯一权威;settings 瞬时不可读用真实快照;两者都未知时 + * **不写背光**(旧代码在这里写死 60,直接覆盖 launcher 刚按 display.brightness 设好的 + * 用户值 → 开机/亮屏跳 60,真机 0.8.46 实证)。取值分支见 wd_bri_decide()。 */ + int user = wd_settings_brightness(); /* >0=用户设置;-1=不可读 */ + int cur = read_brightness(); /* 当前系统背光:判定「不写」是否安全 + 日志 */ + const char *src = "?"; + int restore = wd_bri_decide(user, wd_saved_bri, cur, &src); + if (restore > 0) write_brightness(restore); wd_pan_buf0_force(); /* 唤醒后强制回 buffer0 */ - wd_log("power: panel ON (blank 0 + brightness %d, user=%d saved=%d)", restore, b, wd_saved_bri); + if (restore > 0) + wd_log("power: panel ON (blank 0 + brightness %d src=%s user=%d saved=%d cur=%d)", + restore, src, user, wd_saved_bri, cur); + else + wd_log("power: panel ON (blank 0 + brightness UNTOUCHED cur=%d src=%s user=%d saved=%d)", + cur, src, user, wd_saved_bri); } /* launcher 正在画电源菜单(/tmp/meow_power_menu_active 存在)→ watchdog 完全让位。 */ diff --git a/patch_v2/meow_watchdog/test_wd_fw b/patch_v2/meow_watchdog/test_wd_fw index 4da5ce547d356b301027f2a88a3a38dfc38e2198..9ec00be1698d00906ba0055a46a03e775e96246f 100755 GIT binary patch literal 20336 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 literal 74448 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 EUy5DZ4FCWD diff --git a/patch_v2/meow_watchdog/test_wd_fw.c b/patch_v2/meow_watchdog/test_wd_fw.c index 567091c..a62f46c 100644 --- a/patch_v2/meow_watchdog/test_wd_fw.c +++ b/patch_v2/meow_watchdog/test_wd_fw.c @@ -1,11 +1,14 @@ -/* test_wd_fw.c — 宿主单测:meow_watchdog 的「SDK 框架 App 判定」逻辑(M2.86, issue 226)。 +/* test_wd_fw.c — 宿主单测:meow_watchdog 的纯逻辑(M2.86 框架 App 判定 + M20 亮屏亮度)。 * - * 编译:#include meow_watchdog.c(去 main 拿 wd_app_is_framework/wd_json_str/wd_framework_from_pid)。 + * 编译:#include meow_watchdog.c(去 main 拿 wd_app_is_framework/json_str/from_pid、 + * wd_bri_decide、wd_settings_brightness、wd_panel_off/on)。 * gcc -Wall -Wextra -Os -DWd_NO_MAIN -Wno-unused-function -Wno-unused-parameter \ * test_wd_fw.c -o test_wd_fw * (meow_watchdog.c 含仅 main 使用的静态函数,宿主去 main 后须 -Wno-unused-function 静音; * mips 目标构建不定义 WD_NO_MAIN,不受影响。) * 运行:./test_wd_fw;全 PASS -> exit 0。 + * M20 用例用 env MEOW_BACKLIGHT / MEOW_SETTINGS_FILE 把背光与 settings 指到临时文件, + * 真的走 wd_panel_off/wd_panel_on 的读写路径(真机无这两个 env,走 /sys 与 /usr/data 默认)。 */ #define WD_NO_MAIN #include "meow_watchdog.c" @@ -24,6 +27,14 @@ static void check(const char *name, int got, int want) else { g_fail++; printf("FAIL %s: got %d want %d\n", name, got, want); } } +/* 临时目录根:优先 $TMPDIR(Termux/Android 上 /tmp 属于 shell 用户、本进程不可写), + * 否则 /tmp(Linux 构建容器)。让 `build_watchdog.sh host` 在两种环境都能直接跑。 */ +static const char *tmp_root(void) +{ + const char *t = getenv("TMPDIR"); + return (t && t[0]) ? t : "/tmp"; +} + /* ---- M2.87:SIGUSR1 手势让位(handle_touch 左缘滑动分支)---- * 判定(meow_watchdog.c):`!g_fw_app && immersive` 才发 SIGUSR1(只给裸沉浸 App); * SDK 框架 App(g_fw_app=1)不发(返回由 SDK on_swipe 处理),防 SIGUSR1 杀死 App。 */ @@ -68,10 +79,155 @@ static int expect_fw(const char *base, const char *name, const char *appjson, in return 1; } +/* ---- M20:亮屏亮度决策(wd_bri_decide 纯函数)---- + * 真机 bug(0.8.46,2026-11-05):settings display.brightness=1,亮屏时 watchdog 写入固定 60 + * 覆盖它。新语义:settings 优先 → 真实快照 → 面板已亮则不写 → 面板黑才写安全低亮。 */ +static void test_bri_decide(void) +{ + const char *src = NULL; + int v; + + v = wd_bri_decide(1, 60, 60, &src); /* 用户值 1 对上被污染的 60/当前 60:必须写 1 */ + check("bri: settings wins over saved/cur", v == 1 && !strcmp(src, "settings"), 1); + v = wd_bri_decide(7, 0, 7, &src); + check("bri: settings 7", v == 7 && !strcmp(src, "settings"), 1); + v = wd_bri_decide(-1, 42, 3, &src); /* settings 不可读 → 用真实快照 */ + check("bri: snapshot fallback", v == 42 && !strcmp(src, "snapshot"), 1); + v = wd_bri_decide(-1, 0, 3, &src); /* 都未知但面板已亮 → 不写(核心修复) */ + check("bri: untouched keeps cur", v == -1 && !strcmp(src, "untouched"), 1); + v = wd_bri_decide(-1, 0, 0, &src); /* 都未知且面板黑 → 安全低亮,绝不 60 */ + check("bri: safe-low not 60", v == WD_BRI_SAFE_LOW && v != 60 && v > 0 && + !strcmp(src, "safe-low"), 1); + v = wd_bri_decide(-1, 0, -1, &src); /* 背光读失败按「黑」处理,仍要点亮 */ + check("bri: read-fail -> safe-low", v == WD_BRI_SAFE_LOW && !strcmp(src, "safe-low"), 1); + v = wd_bri_decide(0, -1, 5, &src); /* 非正值一律按「未知」,不当作亮度 */ + check("bri: non-positive treated unknown", v == -1 && !strcmp(src, "untouched"), 1); +} + +/* ---- M20:settings 解析 + 重试 ---- + * 用真机 /usr/data/meow/settings.conf 的关键行断言「路径/键名/解析/clamp 都是对的」, + * 证明真机写 60 不是本函数返回 -1(原因见报文:出货二进制根本没编进这段代码)。 */ +static void test_settings_brightness(void) +{ + char path[600]; + snprintf(path, sizeof path, "%s/wdsetXXXXXX", tmp_root()); + int fd = mkstemp(path); + if (fd < 0) { g_fail++; printf("FAIL settings: mkstemp\n"); return; } + FILE *f = fdopen(fd, "w"); + fputs("# meow-settings 1\n" + "display.brightness = 1\n" + "display.brightness_min = 1\n" + "audio.volume = 10\n", f); + fclose(f); + setenv("MEOW_SETTINGS_FILE", path, 1); + check("settings: device file -> 1", wd_settings_brightness(), 1); + + f = fopen(path, "w"); /* clamp 抬到 brightness_min */ + fputs("display.brightness = 0\ndisplay.brightness_min = 3\n", f); + fclose(f); + check("settings: clamp up to min", wd_settings_brightness(), 3); + + f = fopen(path, "w"); /* clamp 压到 100 */ + fputs("display.brightness = 200\ndisplay.brightness_min = 1\n", f); + fclose(f); + check("settings: clamp down to 100", wd_settings_brightness(), 100); + + f = fopen(path, "w"); /* 键缺失:与 launcher 设置表同默认 101 -> clamp 100 */ + fputs("audio.volume = 10\n", f); + fclose(f); + check("settings: missing key -> 100", wd_settings_brightness(), 100); + + /* 不可读(原子替换/未挂载窗口):open 重试 3 次仍失败才 -1,总耗时 ≈ 20ms */ + unlink(path); + unsigned long long t0 = now_ms(); + int r = wd_settings_brightness(); + unsigned long long dt = now_ms() - t0; + check("settings: missing -> -1", r, -1); + check("settings: open retried (>=15ms)", dt >= 15, 1); + unsetenv("MEOW_SETTINGS_FILE"); +} + +static void put_file(const char *path, const char *body) +{ + FILE *f = fopen(path, "w"); + if (!f) return; + fputs(body, f); + fclose(f); +} + +static int get_file_int(const char *path) +{ + FILE *f = fopen(path, "r"); + if (!f) return -1; + int v = -1; + if (fscanf(f, "%d", &v) != 1) v = -1; + fclose(f); + return v; +} + +/* ---- M20:panel OFF/ON 端到端(真的读写一个「背光文件」,不 mock 函数)---- + * 复现真机场景:settings display.brightness=1 → 熄屏 → 亮屏。旧代码亮屏写 60, + * 新代码必须写 1;且 settings 不可读、快照未知时保持当前值而不是回退 60。 */ +static void test_panel_brightness_e2e(void) +{ + char bl[600], st[600]; + snprintf(bl, sizeof bl, "%s/wdblXXXXXX", tmp_root()); + snprintf(st, sizeof st, "%s/wdstXXXXXX", tmp_root()); + int fd = mkstemp(bl); + if (fd < 0) { g_fail++; printf("FAIL e2e: mkstemp bl\n"); return; } + close(fd); + fd = mkstemp(st); + if (fd < 0) { g_fail++; printf("FAIL e2e: mkstemp st\n"); unlink(bl); return; } + close(fd); + setenv("MEOW_BACKLIGHT", bl, 1); + setenv("MEOW_SETTINGS_FILE", st, 1); + + /* 1) 真机 bug 场景:settings=1、屏亮 1 → OFF 快照 1;ON 必须写 1,绝不 60 */ + put_file(bl, "1\n"); + put_file(st, "display.brightness = 1\ndisplay.brightness_min = 1\n"); + wd_saved_bri = WD_BRI_UNKNOWN; + wd_panel_off(); + check("e2e: panel OFF writes 0", get_file_int(bl), 0); + check("e2e: panel OFF snapshot = 1", wd_saved_bri, 1); + wd_panel_on(); + check("e2e: panel ON restores settings 1 (not 60)", get_file_int(bl), 1); + + /* 2) 用户改了亮度:settings 仍是唯一权威(旧快照 1 不得覆盖 5) */ + put_file(st, "display.brightness = 5\ndisplay.brightness_min = 1\n"); + put_file(bl, "0\n"); + wd_panel_on(); + check("e2e: panel ON follows new settings 5", get_file_int(bl), 5); + + /* 3) settings 不可读 + 快照未知 + 屏亮 3 → 不写(保持 3,不再回退 60) */ + unlink(st); + put_file(bl, "3\n"); + wd_saved_bri = WD_BRI_UNKNOWN; + wd_panel_on(); + check("e2e: panel ON leaves 3 untouched", get_file_int(bl), 3); + + /* 4) settings 不可读 + 快照未知 + 屏黑 0 → 写安全低亮(>0 且 != 60) */ + put_file(bl, "0\n"); + wd_panel_on(); + check("e2e: panel ON dark -> safe-low", get_file_int(bl), WD_BRI_SAFE_LOW); + + /* 5) settings 不可读但本次运行期真观测到 7 → 快照优先于「不动」 */ + put_file(bl, "7\n"); + wd_saved_bri = WD_BRI_UNKNOWN; + wd_panel_off(); /* 观测到 7,写 0 */ + check("e2e: panel OFF snapshot = 7", wd_saved_bri, 7); + wd_panel_on(); + check("e2e: panel ON uses real snapshot 7", get_file_int(bl), 7); + + unlink(bl); + unsetenv("MEOW_BACKLIGHT"); + unsetenv("MEOW_SETTINGS_FILE"); +} + int main(void) { signal(SIGUSR1, on_sigusr1); /* 捕获 handle_touch 可能发出的 SIGUSR1(测命中) */ - char dir[] = "/tmp/wdfwXXXXXX"; + char dir[600]; + snprintf(dir, sizeof dir, "%s/wdfwXXXXXX", tmp_root()); if (!mkdtemp(dir)) { perror("mkdtemp"); return 2; } /* 框架 App:各值形态 */ @@ -109,6 +265,11 @@ int main(void) check("sigusr1 bare-immersive -> 1", sim_swipe_sigusr1(0, 1), 1); /* 裸沉浸:发(命中) */ check("sigusr1 bare-nonimmersive -> 0", sim_swipe_sigusr1(0, 0), 0); /* 裸非沉浸:不发 */ + /* ---- M20:亮屏亮度(决策 + settings 解析/重试 + panel OFF/ON 端到端)---- */ + test_bri_decide(); + test_settings_brightness(); + test_panel_brightness_e2e(); + /* 清理 */ { char path[560];