真机 M6.3 反馈(bcef8e0 三连修复未好全,追加两问题):
P1 锁屏 PIN 输入穿透仍在(媒体保活 App 实时读 evdev)
根因:媒体保活 App(播放中)从不 SIGSTOP(保 PCM),SDK 输入线程实时读 evdev,不走缓冲。
bcef8e0 的「SIGCONT 排空」只作用于冻结 App;对未冻结 App,隔离全靠 /tmp/meow_notif_active
让 SDK 排空——若 App 的 meow_ui.a 缺该排空(或节流窗内漏网),锁屏期触摸依旧抵达 App。
修法:run_lock_screen() 与 lck_input_pin_modal() 打开 DEV_TOUCH 后 EVIOCGRAB 独占触控设备
(真机 goodix 实测 EVIOCGRAB 返回 0)——抓取期事件只投递抓取者、不为其它 fd 缓冲/回放,
故**任何**前台进程(冻结或未冻结)锁屏期都收不到触摸(真全模态)。失败时记日志降级
(仍靠标记+SIGSTOP 隔离)。overlay_gate.h 增 overlay_keepalive_needs_grab 判据。
P2 主界面应用名只显示 5 字(「流媒体客户」式,半字残形)
根因:app_launcher.c `strncpy(a->name, name, 16)` 仍把显示名硬截 16 字节——M6.3 只扩了
name[49]+json_str 整序列,漏改此二处。UTF-8 下 16B = 5 汉字 + 「端」首字节 + 无 NUL,
显示成「流媒体客户」+ 残形;main_menu.c menu_name_fit 按字节回退又停在半截字符、加 "..." 溢出。
修法:新增 meow_utf8.h(meow_utf8_char_len / meow_utf8_copy_bounded,纯决策可单测)——
app_launcher.c 两处 strncpy(16) 改 app_name_copy(=copy_bounded, 拷满 sizeof name=49);
menu_name_fit 改整字符前进 + 预留省略号宽度(mfont 用「…」/点阵用 "..."),总宽 ≤ maxw,
绝不劈开多字节字符。
新增 test_utf8_name.c(14 断言:整字符长/整序列有界拷贝,含 cap=16/17/12 边界不劈字)+
test_overlay_gate.c 扩展(S1b 未冻结 App 靠 EVIOCGRAB 隔离 4 断言)。launcher 全量宿主回归
+ SDK 叠加/状态栏/输入回归全 PASS;mipsel 交叉 -Wall -Wextra 0 warning。
md5 56dac860841c3884b4322707246e22af(/usr/bin 只读,待固件打包 M6.4;fw_content.conf 未动)。
66 lines
3.6 KiB
C
66 lines
3.6 KiB
C
/* test_utf8_name.c — 问题2(主界面应用名截断)宿主单测:UTF-8 整序列有界拷贝 / 字符步进。
|
||
*
|
||
* 背景(M6.3 真机):主界面应用名「流媒体客户端」被截成 5 字 + 半个字。真因 = app_launcher.c
|
||
* `strncpy(a->name, name, 16)` 仍把显示名硬截 16 字节(UTF-8 下 16B = 5 汉字 + 「端」首字节),且
|
||
* main_menu.c `menu_name_fit` 按字节回退停在半截字符、加 "..." 又溢出 maxw。本测试验证 meow_utf8.h
|
||
* 的整序列有界拷贝:绝不劈开多字节字符、给出完整汉字序列(修复 strncpy(16) 与 menu_name_fit)。
|
||
*
|
||
* 编译运行(在 patch_v2/meow_launcherd 下):
|
||
* gcc -Wall -Wextra -o test_utf8_name test_utf8_name.c && ./test_utf8_name
|
||
* 全 PASS -> exit 0。
|
||
*/
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include "meow_utf8.h"
|
||
|
||
static int g_pass = 0, g_fail = 0;
|
||
#define CHECK(cond, msg) do { \
|
||
if (cond) { g_pass++; printf("PASS %s\n", msg); } \
|
||
else { g_fail++; printf("FAIL %s\n", msg); } \
|
||
} while (0)
|
||
|
||
int main(void)
|
||
{
|
||
/* meow_utf8_char_len:由首字节求整字符长。 */
|
||
CHECK(meow_utf8_char_len('A') == 1, "char_len ASCII = 1");
|
||
CHECK(meow_utf8_char_len((unsigned char)0xC3) == 2, "char_len 2-byte lead = 2");
|
||
CHECK(meow_utf8_char_len((unsigned char)0xE6) == 3, "char_len 3-byte lead = 3");
|
||
CHECK(meow_utf8_char_len((unsigned char)0xF0) == 4, "char_len 4-byte lead = 4");
|
||
CHECK(meow_utf8_char_len((unsigned char)0x80) == 1, "char_len lone continuation = 1 (no merge)");
|
||
|
||
/* meow_utf8_copy_bounded:不劈多字节字符。 */
|
||
char buf[64];
|
||
/* 源「流媒体客户端」= 18B(6×3B)。cap=49 → 全量(修复 strncpy(16) 后的正确行为)。 */
|
||
meow_utf8_copy_bounded(buf, (int)sizeof buf, "流媒体客户端");
|
||
CHECK(strcmp(buf, "流媒体客户端") == 0, "copy cap=49 keeps full '流媒体客户端'");
|
||
CHECK(strlen(buf) == 18, "copy cap=49 len=18 (6 chars)");
|
||
|
||
/* cap=16(旧 bug 的容量):旧 strncpy(16) 给 5 汉字+半个字+无NUL;现应给 5 整汉字+ NUL。 */
|
||
meow_utf8_copy_bounded(buf, 16, "流媒体客户端");
|
||
CHECK(strcmp(buf, "流媒体客户") == 0, "copy cap=16 -> 5 whole chars '流媒体客户'");
|
||
CHECK(strlen(buf) == 15, "copy cap=16 -> 15 bytes (5 CJK, no partial 6th)");
|
||
|
||
/* cap=17:尾部「端」首字节越界 → 整字符去掉,仍 5 整汉字,绝不半字残形。 */
|
||
meow_utf8_copy_bounded(buf, 17, "流媒体客户端");
|
||
CHECK(strcmp(buf, "流媒体客户") == 0, "copy cap=17 -> still 5 whole chars (no partial)");
|
||
|
||
/* cap=12:缓冲区 12B 含 NUL → 内容上限 11B,4 整汉字(12B)放不下 → 截到 3 整汉字(绝非半字)。
|
||
* 注:snprintf 语义 = cap 字节含 NUL,故内容 ≤ cap-1(旧 strncpy(dst,src,12) 拷 12B 无 NUL,
|
||
* 有越界读风险;此处改为安全 NUL 结尾,代价是内容少 1B——正确取舍)。 */
|
||
meow_utf8_copy_bounded(buf, 12, "流媒体客户端");
|
||
CHECK(strcmp(buf, "流媒体") == 0, "copy cap=12 -> 3 whole chars '流媒体' (no partial 4th)");
|
||
|
||
/* ASCII / 混合:不劈 ASCII。 */
|
||
meow_utf8_copy_bounded(buf, (int)sizeof buf, "Hello App");
|
||
CHECK(strcmp(buf, "Hello App") == 0, "copy ASCII unchanged");
|
||
|
||
/* NULL/空源安全性。 */
|
||
meow_utf8_copy_bounded(buf, (int)sizeof buf, NULL);
|
||
CHECK(buf[0] == 0, "copy NULL src -> empty");
|
||
meow_utf8_copy_bounded(buf, 1, "流媒体客户端");
|
||
CHECK(buf[0] == 0, "copy cap=1 -> empty (no write overflow)");
|
||
|
||
printf("\n%s (%d passed, %d failed)\n", g_fail ? "SOME TESTS FAILED" : "ALL PASS", g_pass, g_fail);
|
||
return g_fail ? 1 : 0;
|
||
}
|