fix(watchdog): M20 亮屏亮度不再回退固定 60(settings 读失败重试 + 未知快照语义拆分)— 重编出货二进制
真机 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 的强校验失败。
This commit is contained in:
1 parent
bcb11e012f
commit
f2551a28a2
4 files changed
+246
-19
No files matched your search
@@ -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];
|
||||
|
||||
Reference in new issue
Block a user