From 38be5e78bcf8f13d74169cc6b9c654792f315753 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Thu, 5 Nov 2026 13:28:46 +0800 Subject: [PATCH] =?UTF-8?q?fix(sdk):=20=E6=97=B6=E9=92=9F=20ABI=20?= =?UTF-8?q?=E6=A0=B9=E5=9B=A0=E4=BF=AE=E5=A4=8D=20=E2=80=94=20meow=5Fui=5F?= =?UTF-8?q?time=20=E6=8C=89=20o32=20time32=20=E5=8F=96=E6=97=B6=E5=B9=B6?= =?UTF-8?q?=E9=93=BE=E6=8E=A5=E6=9C=9F=E6=8E=A5=E7=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 真机 meow_ui_time_ms() 返回「低 32=秒×1000、高 32 随机」的根因不是 SDK 写法, 而是 zig 0.17 自带 musl 在 mipsel 上的 time64 ABI 自相矛盾: - zig 头(mips-linux-musl/bits/alltypes.h)无条件 64 位 time_t、struct timespec 16 字节; - zig 的 clang 给 32 位 mips 预定义 __ILP32__,musl 的 time64 回退分支 `#if defined(SYS_x_time64) && !defined(__ILP32__)`(本意只排除 x32)被编译掉; - 于是 libc 的 __clock_gettime64 实为 o32 time32 实现(SYS_clock_gettime 4263), 只写 8 字节 {int32 sec; int32 nsec},与头的 16 字节布局错配。 修复(patch_v2/sdk/meow_ui_time.c): - meow_ui_time_ms() 直接按内核 o32 ABI 取 8 字节 time32,再升 64 位毫秒; - 同 TU 强定义 __clock_gettime/__clock_gettime64(归档先于 -lc,链接期接管, time()/gettimeofday()/pthread 定时等待的内部取时随之修正); - 同源缺陷一并修:__nanosleep_time64/__clock_nanosleep(_time64) 转换 time32 后重发 (修复前 usleep(16000) 等亚秒睡眠立即返回、变忙等空转); - gfx/sys/input/cachegov 四处重复 now_ms 收敛到 meow_ui_time_ms; - build_sdk.sh OBJS 增加 meow_ui_time;新增 test_meow_time 宿主单测、 tools/clock_abi_probe.c 探针、CLOCK_ABI.md 根因/验证/影响面文档; - 26 个宿主测试的编译注释补 meow_ui_time.c(cachegov 测试补时钟源)。 验证:宿主单测 PASS;anim(32)/view_event 宿主用例全过;build_sdk_host.sh --verify 76 成员全 MIPS32r2、0 warning;探针链接后无 libc cgt_init/__vdsosym, __time64/__timedwait_cp 的取时指向本 TU,睡眠走 4166/4265 且用本地 8 字节结构。 --- patch_v2/sdk/CLOCK_ABI.md | 187 +++++++++++++++++++++++ patch_v2/sdk/build_sdk.sh | 6 +- patch_v2/sdk/meow_cachegov.c | 4 +- patch_v2/sdk/meow_ui_gfx.c | 21 +-- patch_v2/sdk/meow_ui_input.c | 33 ++-- patch_v2/sdk/meow_ui_internal.h | 4 + patch_v2/sdk/meow_ui_sys.c | 9 +- patch_v2/sdk/meow_ui_time.c | 147 ++++++++++++++++++ patch_v2/sdk/test_ime_fix.c | 2 +- patch_v2/sdk/test_meow_cachegov.c | 4 +- patch_v2/sdk/test_meow_img_color.c | 2 +- patch_v2/sdk/test_meow_lyric_view.c | 2 +- patch_v2/sdk/test_meow_md3.c | 2 +- patch_v2/sdk/test_meow_time.c | 91 +++++++++++ patch_v2/sdk/test_meow_ui_anim.c | 2 +- patch_v2/sdk/test_meow_ui_box.c | 2 +- patch_v2/sdk/test_meow_ui_dispatch.c | 2 +- patch_v2/sdk/test_meow_ui_ft.c | 2 +- patch_v2/sdk/test_meow_ui_home_gesture.c | 2 +- patch_v2/sdk/test_meow_ui_iconbtn.c | 2 +- patch_v2/sdk/test_meow_ui_lazygrid.c | 2 +- patch_v2/sdk/test_meow_ui_listvirt.c | 2 +- patch_v2/sdk/test_meow_ui_scroll.c | 2 +- patch_v2/sdk/test_meow_ui_select.c | 2 +- patch_v2/sdk/test_meow_ui_swipe.c | 2 +- patch_v2/sdk/test_meow_ui_theme.c | 2 +- patch_v2/sdk/test_meow_ui_theme_export.c | 2 +- patch_v2/sdk/test_meow_ui_view_event.c | 2 +- patch_v2/sdk/test_meow_ui_widgets.c | 2 +- patch_v2/sdk/test_notif_gesture.c | 2 +- patch_v2/sdk/test_notif_open.c | 2 +- patch_v2/sdk/test_overlay_suppress.c | 2 +- patch_v2/sdk/test_p1p2p3_repro.c | 2 +- patch_v2/sdk/test_pinyin.c | 2 +- patch_v2/sdk/test_sb_collapse.c | 2 +- patch_v2/sdk/test_sdk_fixes.c | 2 +- patch_v2/sdk/tools/clock_abi_probe.c | 94 ++++++++++++ 37 files changed, 577 insertions(+), 75 deletions(-) create mode 100644 patch_v2/sdk/CLOCK_ABI.md create mode 100644 patch_v2/sdk/meow_ui_time.c create mode 100644 patch_v2/sdk/test_meow_time.c create mode 100644 patch_v2/sdk/tools/clock_abi_probe.c diff --git a/patch_v2/sdk/CLOCK_ABI.md b/patch_v2/sdk/CLOCK_ABI.md new file mode 100644 index 0000000..f44cc64 --- /dev/null +++ b/patch_v2/sdk/CLOCK_ABI.md @@ -0,0 +1,187 @@ +# SDK 时钟 ABI 说明(meow_ui_time_ms 真机故障的根因与修复) + +面向对象:维护 SDK / 工具链 / 重链 App 的人。**结论先行**:这不是 SDK 代码写错, +是 zig 0.17 自带 musl 在 mipsel 上的 time64 ABI 自相矛盾;修复落在 SDK 链上 +(`patch_v2/sdk/meow_ui_time.c` + 链接期强定义),改后需重编 `meow_ui.a` 并重链四 App。 + +## 1. 现象(真机) + +M10 抓到的日志首列(`meow_ui_time_ms()`,64 位)可拆成: + +``` +6607363222717682072 → lo=1135000 hi=1538396632 +8754846870717682072 → lo=1135000 hi=2038396632 +18138485921460348192 → lo=1140000 hi=4223195352 +``` + +- 低 32 位 = 开机秒数 × 1000,**恒为 1000 的倍数 → 毫秒位丢失**; +- 高 32 位每次调用随机、无单调性。 + +同进程另一份取时(旧容器编的 core)正常 → 问题只在「zig 0.17 编的那部分」。 + +## 2. 根因链(三段证据) + +### 2.1 zig 头文件:`time_t` 是 64 位,`struct timespec` 16 字节 + +`/libc/include/mips-linux-musl/bits/alltypes.h`: + +```c +#define _REDIR_TIME64 1 +#define __USE_TIME_BITS64 1 +typedef _Int64 time_t; /* 无条件 64 位 */ +struct timespec { time_t tv_sec; ...; long tv_nsec; ... }; /* tv_sec@0(8B)、tv_nsec@8 */ +``` + +`include/generic-musl/time.h` 因此在 `_REDIR_TIME64` 下把 `clock_gettime` 重定向到 +`__clock_gettime64`。用该链编译的 C 代码一律按「16 字节、tv_sec 8 字节」取数 +(`patch_v2/sdk/meow_ui.a(meow_ui_gfx.o)` 的旧 `meow_ui_time_ms` 反汇编:`lw 0x10/0x14` +取 tv_sec、`lw 0x18` 取 tv_nsec,正是这个布局)。 + +### 2.2 zig 的 clang 给 mipsel 预定义了 `__ILP32__` + +``` +$ echo | zig cc --target=mipsel-linux-musleabi -dM -E - | grep __ILP32__ +#define __ILP32__ 1 +``` + +(arm-linux-musleabi 同样为 1;x86-linux-musl / aarch64 为 0。容器里的 gcc 对 mips o32 +**不定义** `__ILP32__`。) + +### 2.3 musl 的 time64 回退分支被这句 `!__ILP32__` 整体编译掉 + +`/libc/musl/src/time/clock_gettime.c`: + +```c +#if defined(SYS_clock_gettime64) && !defined(__ILP32__) + ... __syscall(SYS_clock_gettime64, clk, ts); /* 4403 */ + ... 失败(ENOSYS) 再 __syscall(SYS_clock_gettime, clk, ts32); /* 4263 + 宽度转换 */ +#else + r = __syscall(SYS_clock_gettime, clk, ts); /* 直接把 8 字节 time32 写进调用者缓冲 */ +#endif +``` + +这句 `!__ILP32__` 本意只排除 x32(`__ILP32__` 是 x32 的标记),但 clang 把它当成 +「32 位数据模型」的通名。于是 zig 的 mipsel libc 走进 `#else`: +`__clock_gettime64` 实际执行 **SYS_clock_gettime(4263)**,只写 8 字节 +`{ int32 tv_sec; int32 tv_nsec; }`。 + +**证据(反汇编,当前 zig 0.17 静态链接的探针)**: + +``` +0002576c <__clock_gettime64>: + 257c8: addiu $2,$zero,0x10a7 ; 4263 = SYS_clock_gettime(time32) + 257cc: syscall ; $5 直接是调用者的 16 字节 struct 指针,无 4403 尝试、无转换 +``` + +同一符号在**旧容器产物** `patch_v2/ncm_app/ncm`(已入库,gcc 构建)里是: + +``` +115748: addiu $2,$zero,0x1133 ; 4403 = SYS_clock_gettime64 +11574c: syscall +... +115774: addiu $2,$zero,0x10a7 ; ENOSYS 后回退 4263,写入本地 ts32 +... + ; 再把 ts32 升成 64 位写回调用者(tv_sec=tv_sec、tv_nsec=tv_nsec) +``` + +两者对比即根因:**头文件 ABI(64 位 time_t)与 libc 实现 ABI(32 位 time32)不一致**。 + +### 2.4 数值解释(为什么「低 32 = 秒×1000、高 32 随机」) + +libc 把 `{sec, nsec}` 当两个 int32 写进 16 字节缓冲的前 8 字节;SDK 按 64 位读: + +``` +tv_sec = sec | (nsec << 32) // 低字正确、高字=纳秒 +tv_nsec = 缓冲偏移 8 的未初始化值 // 毫秒项≈0 +result = tv_sec*1000 + tv_nsec/1e6 + = sec*1000 + (nsec*1000 mod 2^32)<<32 + 垃圾/1e6 +``` + +- 低 32 位只剩 `sec*1000`(nsec 项左移 32 位不落到低字)→ 恒为 1000 的倍数; +- 高 32 位 = `nsec*1000 mod 2^32` → 每次随机、不单调; +- `tv_nsec` 来自越界读 → 通常是小值/0(真机上恰好 0,所以没有额外尾数)。 + +## 3. 修复(`patch_v2/sdk/meow_ui_time.c`) + +1. **取数走内核 o32 ABI**:`meow_ui_time_ms()` 用 + `syscall(SYS_clock_gettime32, CLOCK_MONOTONIC, &{int32 sec; int32 nsec;})`, + 再 `meow_time_ms_from_parts(sec, nsec)` 升成 64 位毫秒。完全不依赖 libc 头声明的 + `struct timespec` 宽度 —— 即使将来 zig 修好(或换回容器链),内核 time32 入口始终存在。 +2. **链接期修 libc 入口**:同一 TU 强定义 `__clock_gettime` / `__clock_gettime64` + (musl 的 `time()`、`gettimeofday()`、`__timedwait_cp()`(pthread 定时等待)内部都调 + `__clock_gettime`)。应用链接顺序是 `... meow_ui.a ... -lc`,归档先解析符号,libc 里那份 + 坏实现(及其 VDSO 前导)不会被拉入 —— 用 `nm` 验证链接产物里没有 `cgt_init/__vdsosym`, + 且 `__time64`/`__timedwait_cp` 的 `jal` 指向本 TU 的实现。 +3. **睡眠入口一并修正(同源缺陷)**:`__nanosleep_time64` / `__clock_nanosleep(_time64)` + 先按 time32 转换再发 `SYS_nanosleep`/`SYS_clock_nanosleep`,`rem` 再扩回 64 位。 + 修复前 zig libc 把 16 字节 time64 结构直接交给 time32 系统调用,内核读到的 nsec 恒为 0 → + SDK 里 `usleep(16000)`(帧节拍、输入轮询、IME 冷却)全部变成忙等空转。 +4. **去掉四处重复的 `now_ms()`**:`meow_ui_gfx.c` / `meow_ui_sys.c` / `meow_ui_input.c` / + `meow_cachegov.c` 统一调 `meow_ui_time_ms()`(cachegov 保留宿主测试注入桩)。 +5. 构建脚本 `build_sdk.sh` 的 OBJS 增加 `meow_ui_time`;宿主单测 `test_meow_time.c` + 固定换算边界与「单调且前进」;探针 `tools/clock_abi_probe.c` 用于宿主/真机一眼验收。 + +非 mips 目标(宿主单测、aarch64 宿主)走普通 `clock_gettime`,行为不变。 + +## 4. 验证 + +宿主: + +``` +cd patch_v2/sdk +gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o /tmp/meow_ui_time.o +gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time.c /tmp/meow_ui_time.o -o /tmp/test_meow_time +/tmp/test_meow_time # == PASS ==(换算边界 + 单调前进) +``` + +交叉: + +``` +bash patch_v2/sdk/build_sdk_host.sh --verify # 成员清单/架构自检 + 0 warning +llvm-objdump -d meow_ui.a(meow_ui_time.o) # meow_ui_time_ms: syscall 4263, lw 0x18 取 nsec、sra 扩展 tv_sec +``` + +链接期接管(用真实归档链一个探针,检查符号来源): + +``` +# 不应出现 libc 的 VDSO 前导(cgt_init/__vdsosym)→ libc 的取时实现未被拉入 +strings -a clock_abi_probe_sdk | grep -c __vdso # 期望 0 +llvm-nm clock_abi_probe_sdk | grep -E 'clock_gettime|nanosleep' +# __time64 / __timedwait_cp 的 jal 应指向本 TU 的 __clock_gettime;睡眠走 SYS_nanosleep(4166)/clock_nanosleep(4265) +``` + +探针 `tools/clock_abi_probe.c`(宿主 `gcc` 或 mipsel 交叉;加 `-DMEOW_PROBE_WITH_SDK` +并链 `meow_ui.a` 可同时验收 `meow_ui_time_ms`):把 `struct timespec` 预填 0xAA 后取时, +若偏移 8..11 仍是 0xAA 即说明 libc 只写了 8 字节(ABI 不一致),退出码 2。 + +真机(塔台批准后):日志首列应连续、出现非整千差;`meow_ui_time_ms()` 两次取样差 = 真实毫秒。 +本次设备已离线,真机确认**待办**。 + +## 5. 影响面 + +- **SDK 内**:`meow_ui_time_ms()` 及其上层 —— 动画 tween(`meow_ui_anim.c`)、滚动/fling + (`meow_ui_scroll.c`/`meow_select.c`)、IME 冷却(`meow_ui_ime.c`)、状态栏动画 + (`meow_ui_gfx.c`)、通知 TTL(`meow_ui_notify.c`)、输入层 tick/启动冷却 + (`meow_ui_input.c`)、cachegov 回退窗口(`meow_cachegov.c`)、日志首列(`meow_ui_log.c`)。 +- **App 侧**:`on_tick` 入参 `now`、`meow_anim_*`、以及任何自行调用 `meow_ui_time_ms()` 的 + App(hello/reader/files/ncm…)。 +- **产物**:`meow_ui.a` 变更 → 需**重编并重链四 App**(ncm/reader/files/hello); + `time()`/`gettimeofday()` 的修正也在同一份归档里生效(链接期覆盖)。 +- 真机写入红线未触碰;本单只改 SDK 源与构建脚本。 + +## 6. 同源残余(未在本单修复,需单独安排) + +同一句 `!__ILP32__` 还打穿了以下路径(睡眠族已在上文一并修掉,余下这些症状不同、 +修复面更大): + +| 路径 | 症状 | 说明 | +| --- | --- | --- | +| `futex` 相对超时 | 亚秒 timed wait 立即超时 | `__timedwait_cp` 的 `__futex4_cp` 同款 `!__ILP32__` 守卫;`pthread_cond_timedwait` 的「now」已由本单修正,但相对超时仍按 8 字节读(>1s 的整秒等待基本可用,亚秒等待失效) | +| `timerfd_settime` | 到期时间错乱 | `struct itimerspec`(32 字节)当 16 字节读;当前 SDK 未用 timerfd | +| `clock_settime`/`clock_adjtime`/`pselect`/`ppoll`/`sigtimedwait`/`semtimedop` 等 | 未验证 | 同族守卫;SDK 目前未直接使用 | + +建议:向 zig 上游报 musl `__ILP32__` 守卫问题(clang 对 32 位目标统一定义 `__ILP32__`, +而该守卫本意只排除 x32);根治应换用容器旧链(gcc,不定义 `__ILP32__`)编 SDK,或 +downgrade/修补 zig 内置 musl。**不要**指望 `-D_TIME_BITS=32`:zig 的 +`alltypes.h` 是无条件 `#define __USE_TIME_BITS64 1`,命令行改不动;而只改用户侧头文件会让 +用户结构(8 字节)与 libc 内部(16 字节,pthread 等)再次错配。 diff --git a/patch_v2/sdk/build_sdk.sh b/patch_v2/sdk/build_sdk.sh index 8415543..90b4706 100755 --- a/patch_v2/sdk/build_sdk.sh +++ b/patch_v2/sdk/build_sdk.sh @@ -6,6 +6,10 @@ # 禁 zlib/png/brotli/bzip2/harfbuzz(-DFT_DISABLE_*),静态 musl(zig-mipsel-cc); # 产物 sdk/vendor/freetype-build/libfreetype.a,其 .o 编入 meow_ui.a —— 应用只链 meow_ui.a # 即获得矢量字能力;不调 meow_ft_* 的 App 链接器不会拉取 freetype 成员(零增量)。 +# +# 时钟(meow_ui_time):mipsel 上 zig 0.17 musl 的 time64 ABI 自相矛盾(头 64 位 / 实现 +# time32),该 TU 按内核 o32 ABI 取时并强定义 __clock_gettime*/睡眠入口,链接期接管。 +# 根因与验证见 sdk/CLOCK_ABI.md;改动后必须重编 meow_ui.a 并重链四 App。 set -e ROOT="$HOME/Project/R3ProII" cd "$(dirname "$0")" @@ -40,7 +44,7 @@ FT_INCS="-I$FT_BUILD -I$FT_BUILD/include -I$FT_SRC/include" rm -f meow_ui.a *.o # -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移) -OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_lazygrid meow_select meow_ui_str meow_ui_ft meow_net_ipc meow_cachegov" +OBJS="meow_ui_time meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_lazygrid meow_select meow_ui_str meow_ui_ft meow_net_ipc meow_cachegov" CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd" for f in $OBJS; do echo "== cc $f ==" diff --git a/patch_v2/sdk/meow_cachegov.c b/patch_v2/sdk/meow_cachegov.c index f538df3..b755525 100644 --- a/patch_v2/sdk/meow_cachegov.c +++ b/patch_v2/sdk/meow_cachegov.c @@ -62,9 +62,7 @@ static int64_t g_test_now_ms = -1; static int64_t now_ms(void) { if (g_test_now_ms >= 0) return g_test_now_ms; - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + return (int64_t)meow_ui_time_ms(); } void meow_cachegov_test_set_time_ms(int64_t t) { g_test_now_ms = t; } diff --git a/patch_v2/sdk/meow_ui_gfx.c b/patch_v2/sdk/meow_ui_gfx.c index 98db7a1..3ed6115 100644 --- a/patch_v2/sdk/meow_ui_gfx.c +++ b/patch_v2/sdk/meow_ui_gfx.c @@ -172,15 +172,6 @@ static void refresh_governor(unsigned long long cost_ms, int period) } /* ---- 工具 ---- */ -static uint64_t now_ms(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000u + (uint64_t)ts.tv_nsec / 1000000u; -} - -uint64_t meow_ui_time_ms(void) { return now_ms(); } - static uint16_t rgb565(uint32_t c) { return (uint16_t)(((c >> 8) & 0xF800) | ((c >> 5) & 0x07E0) | ((c >> 3) & 0x001F)); @@ -895,7 +886,7 @@ static void statusbar_collapse_step(void) int tgt = g_sbar_collapsed ? MUI_SBAR_H : 0; if (g_sbar_collapse_h == tgt) return; if (g_sbar_collapse_anim_ms <= 0) { g_sbar_collapse_h = tgt; return; } - unsigned long long now = now_ms(); + unsigned long long now = meow_ui_time_ms(); unsigned long long el = now - g_sbar_collapse_start_ms; int span = g_sbar_collapse_anim_ms; if ((int)el >= span) { g_sbar_collapse_h = tgt; return; } @@ -932,7 +923,7 @@ void meow_ui_statusbar_set_collapsed(int on) if (tgt == g_sbar_collapsed) return; g_sbar_collapsed = tgt; g_sbar_collapse_from_h = g_sbar_collapse_h; - g_sbar_collapse_start_ms = now_ms(); + g_sbar_collapse_start_ms = meow_ui_time_ms(); dirty_full(); /* 顶栏显隐/上收变化 → 全帧重画 */ meow_ui_sbar_write_mode(); /* App 进程上报顶条模式(launcher 感知全屏/收合,agent-146) */ } @@ -1012,7 +1003,7 @@ int meow_ui_overlay_suppressed_active(void) snprintf(s_path, sizeof s_path, "%s", (e && e[0]) ? e : MEOW_NOTIF_ACTIVE_DEFAULT); s_path_init = 1; } - unsigned long long now = now_ms(); + unsigned long long now = meow_ui_time_ms(); if (s_last_chk && now - s_last_chk < MEOW_OVERLAY_CHK_MS) return s_last_res; s_last_chk = now; { @@ -1066,7 +1057,7 @@ static void present(void) } /* 帧率门控(A-1/A-2,从 launcher 迁入):present 距上次 ≥ period(1000/eff_rate) 才呈现; * 未满周期则保留脏区(不 dirty_reset),下一轮再试。refresh_always_max=1 时跳过门控(恒满速)。 */ - unsigned long long now = now_ms(); + unsigned long long now = meow_ui_time_ms(); int period = (g_eff_rate > 0) ? (1000 / g_eff_rate) : 16; if (!g_refresh_always_max) { if (g_last_present_ms && now - g_last_present_ms < (unsigned long long)period) return; @@ -1096,7 +1087,7 @@ static void present(void) } if (g_fb_mem) { ioctl(g_fb_fd, FBIO_WAITFORVSYNC, 0); /* 等垂直同步 */ - unsigned long long tbg = now_ms(); + unsigned long long tbg = meow_ui_time_ms(); /* 「同一个状态栏」闭环:App 进程不渲染状态栏(meow_ui_sys_render_enabled()==0),也绝不向 * 真实 fb 写顶条 inset 区(顶条由 launcher 系统进程叠加绘制)。否则 App 首帧全量拷贝 * (meow_ui_init 置 dirty_full)会把 launcher 刚叠画的顶条冲成未初始化数据——真机 @@ -1133,7 +1124,7 @@ static void present(void) } } } - refresh_governor(now_ms() - tbg, period); + refresh_governor(meow_ui_time_ms() - tbg, period); } g_last_present_ms = now; g_frames_presented++; diff --git a/patch_v2/sdk/meow_ui_input.c b/patch_v2/sdk/meow_ui_input.c index 4fe2038..514aa79 100644 --- a/patch_v2/sdk/meow_ui_input.c +++ b/patch_v2/sdk/meow_ui_input.c @@ -122,13 +122,6 @@ static uint64_t last_tick_ms = 0; static uint64_t startup_cooldown_until = 0; #define STARTUP_COOLDOWN_MS 500 -static uint64_t now_ms(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000u + (uint64_t)ts.tv_nsec / 1000000u; -} - /* settings.conf 路径(可被 env MEOW_SETTINGS_FILE 覆盖,宿主测试用;设备默认同 meow_ui_sys.c)。 */ static const char *meow_settings_path(void) { @@ -294,7 +287,7 @@ static void touch_press(int x, int y) t_origin_valid = 0; t_cx = -1; t_cy = -1; t_dx = 0; t_dy = 0; - t_down_ms = now_ms(); /* 记按下时刻:供实时按住时长/按住视觉 */ + t_down_ms = meow_ui_time_ms(); /* 记按下时刻:供实时按住时长/按住视觉 */ t_mv_x = -1; t_mv_y = -1; /* M2.71:拖动过程起点未定 */ t_long_fired = 0; /* §6.3:每次新按压复位长按触发标记 */ } @@ -392,7 +385,7 @@ int meow_input_touch_y(void) { return t_cy; } unsigned int meow_input_touch_hold_ms(void) { if (!t_down) return 0; - uint64_t e = now_ms() - t_down_ms; + uint64_t e = meow_ui_time_ms() - t_down_ms; if (e > 0xFFFFFFFFu) e = 0xFFFFFFFFu; return (unsigned int)e; } @@ -403,7 +396,7 @@ void meow_input_touch_set(int down, int x, int y, unsigned hold_ms) if (down) { t_down = 1; t_press_valid = 1; t_origin_valid = 1; t_long_fired = 0; t_cx = x; t_cy = y; t_dx = x; t_dy = y; - uint64_t now = now_ms(); + uint64_t now = meow_ui_time_ms(); t_down_ms = (now > (uint64_t)hold_ms) ? (now - (uint64_t)hold_ms) : 0; } else { t_down = 0; t_press_valid = 0; t_origin_valid = 0; t_long_fired = 0; @@ -544,7 +537,7 @@ static uint64_t g_sys_press_ms = 0; static void sys_key_press(int code) { - uint64_t now = now_ms(); + uint64_t now = meow_ui_time_ms(); if (code == g_sys_press_code && now - g_sys_press_ms < SYS_KEY_DEDUP_MS) return; /* 事件流 + EVIOCGKEY 双源去重:同码窗口内只消化一次 */ g_sys_press_code = code; @@ -702,7 +695,7 @@ void meow_ui_request_exit(void) { g_exit = 1; } static uint64_t g_activity_last_ms = 0; void meow_ui_activity_ping(void) { - uint64_t now = now_ms(); + uint64_t now = meow_ui_time_ms(); if (now - g_activity_last_ms < 500) return; /* 节流:任意交互连续触摸也只 ~2 次/s */ g_activity_last_ms = now; if (!meow_gfx_is_device()) return; /* 离屏/宿主:无 launcher 消费 */ @@ -715,8 +708,8 @@ void meow_ui_run(const meow_ui_events *ev) if (ev) { g_events = *ev; g_events_set = 1; } g_exit = 0; meow_input_start(); - last_tick_ms = now_ms(); - startup_cooldown_until = now_ms() + STARTUP_COOLDOWN_MS; /* M2.22(C):启动窗口丢弃 SWIPE */ + last_tick_ms = meow_ui_time_ms(); + startup_cooldown_until = meow_ui_time_ms() + STARTUP_COOLDOWN_MS; /* M2.22(C):启动窗口丢弃 SWIPE */ while (!g_exit) { /* agent-119:实时触摸按压/按住/释放 → 即时重绘命中按钮区(不等 app 重绘)。 @@ -724,10 +717,10 @@ void meow_ui_run(const meow_ui_events *ev) * §6.3 通用长按:每帧检测「按下 ≥ 阈值且位移 ≤ 容忍」跨越(IME 打开不驱动;启动窗口不触发)。 */ if (!meow_ime_active()) { meow_widget_touch_refresh(); - if (now_ms() >= startup_cooldown_until) meow_input_long_press_poll(); + if (meow_ui_time_ms() >= startup_cooldown_until) meow_input_long_press_poll(); } else if (meow_ime_mode_pinyin()) { /* 拼音 IME 打开:喂长按轮询(长按退格清空字段)。英文模式不喂(保持既有行为)。 */ - if (now_ms() >= startup_cooldown_until) meow_input_long_press_poll(); + if (meow_ui_time_ms() >= startup_cooldown_until) meow_input_long_press_poll(); } meow_input_ev e; @@ -736,7 +729,7 @@ void meow_ui_run(const meow_ui_events *ev) if (g_exit) break; /* 已请求退出:不再分发剩余事件,杜绝「退出后又触发」的偶发再进/退 */ got = 1; meow_ui_activity_ping(); /* M2.71-bug5:任意交互事件都喂 launcher 重置息屏计时(节流) */ - int in_startup = (now_ms() < startup_cooldown_until); /* M2.22(C) */ + int in_startup = (meow_ui_time_ms() < startup_cooldown_until); /* M2.22(C) */ if (e.type == MEOW_EV_TAP) { if (in_startup) continue; /* 启动窗口也吞 TAP:旧手势残留点按(如上一次左滑抬起) * 在进入瞬间命中 UI 按钮(如全屏按钮)会误触发——丢弃。 */ @@ -851,7 +844,7 @@ void meow_ui_run(const meow_ui_events *ev) } } - uint64_t now = now_ms(); + uint64_t now = meow_ui_time_ms(); if (g_events_set && g_events.on_tick) { if (now - last_tick_ms >= 16) { last_tick_ms = now; @@ -877,7 +870,7 @@ void meow_ui_run(const meow_ui_events *ev) if (meow_ime_active()) { /* 软键盘覆盖层随帧绘制(30fps 节流,省 CPU) */ static uint64_t last_ime_ms = 0; - uint64_t n = now_ms(); + uint64_t n = meow_ui_time_ms(); if (n - last_ime_ms >= 33) { last_ime_ms = n; meow_ime_draw(); @@ -897,7 +890,7 @@ void meow_ui_run(const meow_ui_events *ev) void meow_ui_feed_tick(void) { if (!(g_events_set && g_events.on_tick)) return; - uint64_t now = now_ms(); + uint64_t now = meow_ui_time_ms(); if (now - last_tick_ms < 16) return; last_tick_ms = now; g_events.on_tick(); diff --git a/patch_v2/sdk/meow_ui_internal.h b/patch_v2/sdk/meow_ui_internal.h index a6457f5..798e0e0 100644 --- a/patch_v2/sdk/meow_ui_internal.h +++ b/patch_v2/sdk/meow_ui_internal.h @@ -300,4 +300,8 @@ int meow_ime_handle_event(const meow_input_ev *e); /* 当前 IME 是否拼音模式(供 meow_ui_input.c 决定是否喂长按轮询)。 */ int meow_ime_mode_pinyin(void); +/* ---- 时钟(meow_ui_time.c)---- */ +/* 秒/纳秒 → 单调毫秒的唯一换算点(meow_ui_time_ms 与宿主单测共用)。 */ +uint64_t meow_time_ms_from_parts(int64_t sec, int64_t nsec); + #endif /* MEOW_UI_INTERNAL_H */ diff --git a/patch_v2/sdk/meow_ui_sys.c b/patch_v2/sdk/meow_ui_sys.c index 6bce425..563bd58 100644 --- a/patch_v2/sdk/meow_ui_sys.c +++ b/patch_v2/sdk/meow_ui_sys.c @@ -46,13 +46,6 @@ static int g_statusbar_force = 0; /* 1s 刷新后置位,强制重画顶部 * present() 据此决定是否画出顶条/提示线;App 进程保持 0(不渲染)+ 仍 inset 28(launcher 叠加)。 */ static int g_sys_render = 0; /* 1=本进程为系统 UI(渲染);0=App(不渲染,仅 inset) */ -static uint64_t now_ms(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000u + (uint64_t)ts.tv_nsec / 1000000u; -} - /* 读一份 sysfs/文件字符串(剥尾随换行);失败回退 "" */ static void read_str(const char *path, char *buf, size_t n) { @@ -163,7 +156,7 @@ void meow_ui_sys_refresh(void) /* 蓝牙:hci0 存在性检查便宜;上电状态贵(hciconfig spawn),30s 缓存。 */ static uint64_t last_bt_ms = 0; - uint64_t n = now_ms(); + uint64_t n = meow_ui_time_ms(); g_sys.bt_seen = access("/sys/class/bluetooth/hci0", F_OK) == 0; if (!g_sys.bt_seen) { g_sys.bt_on = 0; diff --git a/patch_v2/sdk/meow_ui_time.c b/patch_v2/sdk/meow_ui_time.c new file mode 100644 index 0000000..dd72a1d --- /dev/null +++ b/patch_v2/sdk/meow_ui_time.c @@ -0,0 +1,147 @@ +/* meow_ui_time.c — SDK 单调时钟(meow_ui_time_ms)+ mipsel o32 时间 ABI 兜底。 + * + * 根因(M11;真机日志 + 反汇编证据链见 sdk/CLOCK_ABI.md): + * zig 0.17 的 clang 前端给 32 位 mips 目标预定义了 __ILP32__;zig 自带 musl 的 + * time64 回退分支统一写作 `#if defined(SYS_x_time64) && !defined(__ILP32__)` + * (该 `!__ILP32__` 本意只排除 x32),于是 mipsel 的 libc 把「time64 入口」编译成了 + * 老 32 位实现:__clock_gettime64 直接做 SYS_clock_gettime(4263),只写 8 字节 + * `{ int32 tv_sec; int32 tv_nsec; }`。而 zig 头文件又无条件把 time_t 声明成 64 位 + * (struct timespec 16 字节、tv_sec 8 字节),两边 ABI 不一致: + * tv_sec 低字 = 真 sec,高字 = 真 nsec → 64 位结果高 32 位随机、非单调; + * tv_nsec(结构偏移 8)根本没被写 → 毫秒位恒 0(真机实测全是 1000 的倍数)。 + * 容器旧链(gcc)不定义 __ILP32__,time64 回退正确——对照 patch_v2/ncm_app/ncm: + * 同一函数里先 SYS_clock_gettime64(4403)、ENOSYS 后走 4263 并做宽度转换。 + * + * 修复:不依赖 libc 头声明的 struct timespec 宽度,直接按**内核 o32 ABI** + * (8 字节 time32:int32 sec + int32 nsec)取时,再自行升成 64 位毫秒; + * 同时在本 TU 给出 __clock_gettime / __clock_gettime64 的强定义。应用链接顺序是 + * `... meow_ui.a ... -lc`,归档先参与解析,因此链接期整体替换掉 libc 里那份 + * ABI 不一致的实现:time()、gettimeofday()、pthread 定时等待的内部取时 + * (musl 的 time()/__timedwait_cp 都调 __clock_gettime)随之修正。 + * 上层时间位宽仍是 64 位,只有内核取数按 o32 time32;2038 前有效。 + * + * 同一句 `!__ILP32__` 还打穿了睡眠:__nanosleep_time64/__clock_nanosleep 走 `#else` + * 把 16 字节 time64 结构直接交给 time32 系统调用,内核读到的 nsec 恒为 0 → + * `usleep(16000)` 立即返回(SDK 里帧节拍/轮询会变忙等空转)。这里一并按 time32 + * 转换后重发,恢复亚秒睡眠。 + * + * 残余(未修):futex 相对超时(pthread 定时等待的剩余时间按 8 字节读)、timerfd_settime、 + * clock_settime/adjtime、pselect/ppoll 超时——同为该守卫的受害者,见 CLOCK_ABI.md §6。 + */ +#include +#include +#include + +#include "meow_ui.h" + +#if defined(__mips__) && !defined(__mips64) && (__SIZEOF_LONG__ == 4) +#define MEOW_TIME32_KERNEL_ABI 1 +#include +#include +#else +#define MEOW_TIME32_KERNEL_ABI 0 +#endif + +uint64_t meow_time_ms_from_parts(int64_t sec, int64_t nsec) +{ + return (uint64_t)sec * 1000u + (uint64_t)nsec / 1000000u; +} + +uint64_t meow_ui_time_ms(void) +{ +#if MEOW_TIME32_KERNEL_ABI + struct meow_time32 { int32_t tv_sec; int32_t tv_nsec; } t; + t.tv_sec = 0; + t.tv_nsec = 0; + if (syscall(SYS_clock_gettime32, CLOCK_MONOTONIC, &t) != 0) return 0; + return meow_time_ms_from_parts(t.tv_sec, t.tv_nsec); +#else + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0; + return meow_time_ms_from_parts((int64_t)ts.tv_sec, (int64_t)ts.tv_nsec); +#endif +} + +#if MEOW_TIME32_KERNEL_ABI +/* 内核 o32 time32 布局(与 libc 头的 time_t 宽度无关)。 */ +struct meow_time32 { + int32_t tv_sec; + int32_t tv_nsec; +}; + +static int32_t time32_clamp(int64_t v) +{ + if (v > INT32_MAX) return INT32_MAX; + if (v < 0) return 0; + return (int32_t)v; +} + +/* ---- libc 取时入口的强定义 ---- + * 返回约定与 musl 一致:0 成功 / -1 失败(errno)。 + * 说明: 在 _REDIR_TIME64 下把标识符 clock_gettime 的引用改名为 + * __clock_gettime64,故本 TU 不定义 clock_gettime 这个名字;musl 里它只是 + * __clock_gettime 的 weak alias,同一份语义已由下面的强定义接管。 */ +int __clock_gettime(clockid_t clk, struct timespec *ts); +int __clock_gettime64(clockid_t clk, struct timespec *ts); + +int __clock_gettime(clockid_t clk, struct timespec *ts) +{ + struct meow_time32 t; + if (!ts) { errno = EFAULT; return -1; } + t.tv_sec = 0; + t.tv_nsec = 0; + if (syscall(SYS_clock_gettime32, clk, &t) != 0) return -1; + ts->tv_sec = t.tv_sec; + ts->tv_nsec = t.tv_nsec; + return 0; +} + +int __clock_gettime64(clockid_t clk, struct timespec *ts) +{ + return __clock_gettime(clk, ts); +} + +/* ---- 睡眠入口(同源缺陷:亚秒 usleep 变空转)---- + * __clock_nanosleep 按 musl 内部约定返回 0 或正 errno;__nanosleep_time64 是 + * nanosleep/usleep 的重定向目标,按公共约定返回 0/-1(errno)。 */ +int __clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem); +int __clock_nanosleep_time64(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem); +int __nanosleep_time64(const struct timespec *req, struct timespec *rem); + +int __clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem) +{ + struct meow_time32 rq, rm; + long r; + + if (clk == CLOCK_THREAD_CPUTIME_ID) return EINVAL; + if (!req) return EFAULT; + if (req->tv_nsec < 0 || req->tv_nsec >= 1000000000L) return EINVAL; + rq.tv_sec = time32_clamp(req->tv_sec); + rq.tv_nsec = (int32_t)req->tv_nsec; + rm.tv_sec = 0; + rm.tv_nsec = 0; + + if (clk == CLOCK_REALTIME && !flags) + r = syscall(SYS_nanosleep, &rq, rem ? &rm : 0); + else + r = syscall(SYS_clock_nanosleep_time32, clk, flags, &rq, rem ? &rm : 0); + if (r != 0) return errno; + if (rem) { + rem->tv_sec = rm.tv_sec; + rem->tv_nsec = rm.tv_nsec; + } + return 0; +} + +int __clock_nanosleep_time64(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem) +{ + return __clock_nanosleep(clk, flags, req, rem); +} + +int __nanosleep_time64(const struct timespec *req, struct timespec *rem) +{ + int r = __clock_nanosleep(CLOCK_REALTIME, 0, req, rem); + if (r) { errno = r; return -1; } + return 0; +} +#endif diff --git a/patch_v2/sdk/test_ime_fix.c b/patch_v2/sdk/test_ime_fix.c index 9c11896..9ca0b9b 100644 --- a/patch_v2/sdk/test_ime_fix.c +++ b/patch_v2/sdk/test_ime_fix.c @@ -8,7 +8,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \ * meow_ui_anim.c meow_ui_media.c meow_ui_nav.c meow_pinyin.c meow_ui_box.c meow_ui_scroll.c \ diff --git a/patch_v2/sdk/test_meow_cachegov.c b/patch_v2/sdk/test_meow_cachegov.c index e516bc3..fd86341 100644 --- a/patch_v2/sdk/test_meow_cachegov.c +++ b/patch_v2/sdk/test_meow_cachegov.c @@ -7,9 +7,9 @@ * - meow_cachegov_test_set_time_ms() 注入时钟驱动 refault 滚窗回退(放大 keep_hot→降L0→关A); * - MEOW_CACHEGOV_C_FILE 指向临时文件写入 fake C 状态,断言 download_paused/prefetch_paused。 * - * 编译(patch_v2/sdk 目录下): + * 编译(patch_v2/sdk 目录下;meow_cachegov.c 的 now_ms 走 meow_ui_time.c,M11 起需一并编译): * gcc -Os -Wall -Wextra -I. -Iinclude -I../meow_launcherd -c meow_cachegov.c -o /tmp/cg.o - * gcc -Os -Wall -Wextra -I. -Iinclude -I../meow_launcherd test_meow_cachegov.c /tmp/cg.o -lpthread -o test_meow_cachegov + * gcc -Os -Wall -Wextra -I. -Iinclude -I../meow_launcherd test_meow_cachegov.c meow_ui_time.c /tmp/cg.o -lpthread -o test_meow_cachegov * 运行:./test_meow_cachegov (exit 0=PASS / 1=FAIL) */ #define _GNU_SOURCE diff --git a/patch_v2/sdk/test_meow_img_color.c b/patch_v2/sdk/test_meow_img_color.c index 433826c..f414afd 100644 --- a/patch_v2/sdk/test_meow_img_color.c +++ b/patch_v2/sdk/test_meow_img_color.c @@ -13,7 +13,7 @@ * 编译(在 patch_v2/sdk 下;链法同 test_meow_lyric_view + 单链 meow_img_color.c): * gcc -Wall -Wextra -o test_meow_img_color test_meow_img_color.c test_host_stub.c \ * meow_img_color.c meow_lyric.c meow_lyric_view.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_lyric_view.c b/patch_v2/sdk/test_meow_lyric_view.c index 5be898d..02e849f 100644 --- a/patch_v2/sdk/test_meow_lyric_view.c +++ b/patch_v2/sdk/test_meow_lyric_view.c @@ -5,7 +5,7 @@ * 另链批1 meow_lyric.c 提供歌词数据;meow_lyric_view.c 为被测控件): * gcc -Wall -Wextra -o test_meow_lyric_view test_meow_lyric_view.c test_host_stub.c \ * meow_lyric.c meow_lyric_view.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_md3.c b/patch_v2/sdk/test_meow_md3.c index 918964e..58363c7 100644 --- a/patch_v2/sdk/test_meow_md3.c +++ b/patch_v2/sdk/test_meow_md3.c @@ -6,7 +6,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -Wall -Wextra -o test_meow_md3 test_meow_md3.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_time.c b/patch_v2/sdk/test_meow_time.c new file mode 100644 index 0000000..8e1b0c5 --- /dev/null +++ b/patch_v2/sdk/test_meow_time.c @@ -0,0 +1,91 @@ +/* test_meow_time.c — 宿主单测:SDK 时钟换算(meow_ui_time.c / meow_time_ms_from_parts)。 + * + * 背景(M11):mipsel 真机上 meow_ui_time_ms() 曾返回「低 32 位=秒×1000、高 32 位随机」, + * 根因是 zig musl 头(time_t 64 位)与 libc 实现(o32 time32 取数)ABI 不一致,见 + * sdk/CLOCK_ABI.md。修复后取数统一走 meow_time_ms_from_parts(sec, nsec),本测试把 + * 换算边界(毫秒进位/截断/大秒数)与「真时钟单调且前进」固定在宿主上。 + * + * 编译(patch_v2/sdk 目录下): + * gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o /tmp/meow_ui_time.o + * gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time.c /tmp/meow_ui_time.o -o test_meow_time + * 运行:./test_meow_time (exit 0=PASS / 1=FAIL) + */ +#include +#include +#include + +#include "meow_ui.h" +#include "meow_ui_internal.h" + +static int g_fail = 0; + +static void eq_ms(const char *name, int64_t sec, int64_t nsec, uint64_t want) +{ + uint64_t got = meow_time_ms_from_parts(sec, nsec); + if (got != want) { + printf("FAIL %s: sec=%lld nsec=%lld got=%llu want=%llu\n", + name, (long long)sec, (long long)nsec, + (unsigned long long)got, (unsigned long long)want); + g_fail = 1; + } else { + printf("ok %s = %llu\n", name, (unsigned long long)got); + } +} + +int main(void) +{ + /* ---- 1) 换算边界:毫秒 = sec*1000 + nsec/1e6(整除截断) ---- */ + eq_ms("零", 0, 0, 0); + eq_ms("1s", 1, 0, 1000); + eq_ms("999999ns 截断", 0, 999999, 0); + eq_ms("1ms 进位", 0, 1000000, 1); + eq_ms("1ns 截断", 0, 1, 0); + eq_ms("开机 1135.008s", 1135, 8000000, 1135008); + eq_ms("开机 1204.999999999s", 1204, 999999999, 1204999); + eq_ms("接近 2038", 2147483647, 999999999, 2147483647999ULL); + + /* ---- 2) 真时钟:非零、单调不减、量级合理(不上溢成「高 32 随机」) ---- */ + uint64_t prev = meow_ui_time_ms(); + if (prev == 0) { + printf("FAIL 时钟返回 0(clock_gettime 失败?)\n"); + g_fail = 1; + } + if (prev >= (1ULL << 40)) { + printf("FAIL 时钟量级异常(>=2^40 ms):%llu\n", (unsigned long long)prev); + g_fail = 1; + } + /* 40s 量级以内取值 = 开机时长(宿主 monotonic),并要求前进 */ + int advanced = 0; + for (int i = 0; i < 200000 && !advanced; i++) { + uint64_t now = meow_ui_time_ms(); + if (now < prev) { + printf("FAIL 单调倒退:%llu -> %llu\n", + (unsigned long long)prev, (unsigned long long)now); + g_fail = 1; + break; + } + advanced = now > prev; + prev = now; + } + if (!advanced) { + printf("FAIL 时钟未前进(200000 次采样内无变化)\n"); + g_fail = 1; + } else { + printf("ok 时钟前进且单调\n"); + } + + /* ---- 3) 动画常用差值:两次取样的差 = 毫秒(不能是 0 恒等/整千) ---- */ + uint64_t t0 = meow_ui_time_ms(); + while (meow_ui_time_ms() == t0) { } + uint64_t t1 = meow_ui_time_ms(); + if (t1 <= t0 || t1 - t0 > 5000) { + printf("FAIL 取样差值异常:%llu -> %llu\n", + (unsigned long long)t0, (unsigned long long)t1); + g_fail = 1; + } else { + printf("ok 取样差值 %llu ms\n", (unsigned long long)(t1 - t0)); + } + + printf(g_fail ? "== FAIL ==\n" : "== PASS ==\n"); + return g_fail; +} diff --git a/patch_v2/sdk/test_meow_ui_anim.c b/patch_v2/sdk/test_meow_ui_anim.c index 9ac1720..bf913ef 100644 --- a/patch_v2/sdk/test_meow_ui_anim.c +++ b/patch_v2/sdk/test_meow_ui_anim.c @@ -4,7 +4,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/draw/activity/ime + 打桩 font/global): * gcc -o test_meow_ui_anim test_meow_ui_anim.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_box.c b/patch_v2/sdk/test_meow_ui_box.c index 2ec9aaa..2d89199 100644 --- a/patch_v2/sdk/test_meow_ui_box.c +++ b/patch_v2/sdk/test_meow_ui_box.c @@ -4,7 +4,7 @@ * * 编译(宿主 gcc,链真实 widget/draw/activity/theme/gfx + 打桩 font/global): * gcc -o test_meow_ui_box test_meow_ui_box.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_dispatch.c b/patch_v2/sdk/test_meow_ui_dispatch.c index aaea24a..1265e31 100644 --- a/patch_v2/sdk/test_meow_ui_dispatch.c +++ b/patch_v2/sdk/test_meow_ui_dispatch.c @@ -13,7 +13,7 @@ * 编译(宿主 gcc,链真实 widget/draw/input/activity/gfx/sys/theme/vol/log/dialog/ime/notify/ipc + * 打桩 font/global;完整超集便于链接): * gcc -Wall -Wextra -o test_meow_ui_dispatch test_meow_ui_dispatch.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_ft.c b/patch_v2/sdk/test_meow_ui_ft.c index 363d2f7..c2fc5e0 100644 --- a/patch_v2/sdk/test_meow_ui_ft.c +++ b/patch_v2/sdk/test_meow_ui_ft.c @@ -3,7 +3,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/notify_ipc + 打桩 font/global + meow_ui_ft + 宿主 freetype): * gcc -o test_meow_ui_ft test_meow_ui_ft.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c meow_notify_ipc.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c meow_notify_ipc.c \ * meow_ui_ft.c \ * -I. -Iinclude -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread vendor/freetype-build-host/libfreetype.a * 用法:./test_meow_ui_ft [font.otf] (缺省用仓库 font/src/MiSans-Regular.otf) diff --git a/patch_v2/sdk/test_meow_ui_home_gesture.c b/patch_v2/sdk/test_meow_ui_home_gesture.c index 7bc97aa..0fbe5eb 100644 --- a/patch_v2/sdk/test_meow_ui_home_gesture.c +++ b/patch_v2/sdk/test_meow_ui_home_gesture.c @@ -16,7 +16,7 @@ * 编译(宿主 gcc,链真实 SDK 源全集 + 打桩 font/global;**不链 meow_ui_nav.c**——本测以测试内 * meow_ui_nav_request_exit 桩计数验证触发): * gcc -Wall -Wextra -o test_meow_ui_home_gesture test_meow_ui_home_gesture.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_iconbtn.c b/patch_v2/sdk/test_meow_ui_iconbtn.c index 6da9656..7014c68 100644 --- a/patch_v2/sdk/test_meow_ui_iconbtn.c +++ b/patch_v2/sdk/test_meow_ui_iconbtn.c @@ -9,7 +9,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -Wall -Wextra -o test_meow_ui_iconbtn test_meow_ui_iconbtn.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_lazygrid.c b/patch_v2/sdk/test_meow_ui_lazygrid.c index 806bc67..f063bca 100644 --- a/patch_v2/sdk/test_meow_ui_lazygrid.c +++ b/patch_v2/sdk/test_meow_ui_lazygrid.c @@ -8,7 +8,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -o test_meow_ui_lazygrid test_meow_ui_lazygrid.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_lazygrid.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_listvirt.c b/patch_v2/sdk/test_meow_ui_listvirt.c index f7844c0..010ba62 100644 --- a/patch_v2/sdk/test_meow_ui_listvirt.c +++ b/patch_v2/sdk/test_meow_ui_listvirt.c @@ -10,7 +10,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -o test_meow_ui_listvirt test_meow_ui_listvirt.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_scroll.c b/patch_v2/sdk/test_meow_ui_scroll.c index 9aef33f..fe06408 100644 --- a/patch_v2/sdk/test_meow_ui_scroll.c +++ b/patch_v2/sdk/test_meow_ui_scroll.c @@ -4,7 +4,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/draw/activity/ime + 打桩 font/global): * gcc -o test_meow_ui_scroll test_meow_ui_scroll.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_select.c b/patch_v2/sdk/test_meow_ui_select.c index 08c0726..cb5d96b 100644 --- a/patch_v2/sdk/test_meow_ui_select.c +++ b/patch_v2/sdk/test_meow_ui_select.c @@ -6,7 +6,7 @@ * 阻塞式模态用后台线程驱动(同 test_ime_fix 范式),主线程经 meow_input_inject 喂触摸。 * 编译(宿主 gcc): * gcc -o test_meow_ui_select test_meow_ui_select.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_select.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_swipe.c b/patch_v2/sdk/test_meow_ui_swipe.c index d40787b..ad7b692 100644 --- a/patch_v2/sdk/test_meow_ui_swipe.c +++ b/patch_v2/sdk/test_meow_ui_swipe.c @@ -8,7 +8,7 @@ * * 编译(宿主 gcc): * gcc -o test_meow_ui_swipe test_meow_ui_swipe.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_theme.c b/patch_v2/sdk/test_meow_ui_theme.c index b9acdeb..01f014f 100644 --- a/patch_v2/sdk/test_meow_ui_theme.c +++ b/patch_v2/sdk/test_meow_ui_theme.c @@ -8,7 +8,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -o test_meow_ui_theme test_meow_ui_theme.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm diff --git a/patch_v2/sdk/test_meow_ui_theme_export.c b/patch_v2/sdk/test_meow_ui_theme_export.c index 6260499..b3c9d96 100644 --- a/patch_v2/sdk/test_meow_ui_theme_export.c +++ b/patch_v2/sdk/test_meow_ui_theme_export.c @@ -11,7 +11,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -Wall -Wextra -o test_meow_ui_theme_export test_meow_ui_theme_export.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_view_event.c b/patch_v2/sdk/test_meow_ui_view_event.c index 42c1a2e..3c6f336 100644 --- a/patch_v2/sdk/test_meow_ui_view_event.c +++ b/patch_v2/sdk/test_meow_ui_view_event.c @@ -8,7 +8,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -Wall -Wextra -o test_meow_ui_view_event test_meow_ui_view_event.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \ * meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \ diff --git a/patch_v2/sdk/test_meow_ui_widgets.c b/patch_v2/sdk/test_meow_ui_widgets.c index d2005d1..a45ab96 100644 --- a/patch_v2/sdk/test_meow_ui_widgets.c +++ b/patch_v2/sdk/test_meow_ui_widgets.c @@ -3,7 +3,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -o test_meow_ui_widgets test_meow_ui_widgets.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm diff --git a/patch_v2/sdk/test_notif_gesture.c b/patch_v2/sdk/test_notif_gesture.c index 4c5db97..19aedbc 100644 --- a/patch_v2/sdk/test_notif_gesture.c +++ b/patch_v2/sdk/test_notif_gesture.c @@ -15,7 +15,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/ime/media/notify_ipc + 打桩 font/global): * gcc -Wall -Wextra -o test_notif_gesture test_notif_gesture.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_ime.c meow_ui_str.c meow_ui_media.c meow_notify_ipc.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * 运行:./test_notif_gesture diff --git a/patch_v2/sdk/test_notif_open.c b/patch_v2/sdk/test_notif_open.c index 394d34f..2a55030 100644 --- a/patch_v2/sdk/test_notif_open.c +++ b/patch_v2/sdk/test_notif_open.c @@ -8,7 +8,7 @@ * * 编译(宿主 gcc,链 meow_notify_ipc + meow_ui_sys + gfx/theme/vol/log + 打桩 font/global): * gcc -Wall -o test_notif_open test_notif_open.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_notify_ipc.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm * 运行:./test_notif_open diff --git a/patch_v2/sdk/test_overlay_suppress.c b/patch_v2/sdk/test_overlay_suppress.c index d0f7f54..a48d0aa 100644 --- a/patch_v2/sdk/test_overlay_suppress.c +++ b/patch_v2/sdk/test_overlay_suppress.c @@ -17,7 +17,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -Wall -Wextra -o test_overlay_suppress test_overlay_suppress.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_draw.c meow_ui_view.c meow_notify_ipc.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread diff --git a/patch_v2/sdk/test_p1p2p3_repro.c b/patch_v2/sdk/test_p1p2p3_repro.c index 474480b..cfe23ab 100644 --- a/patch_v2/sdk/test_p1p2p3_repro.c +++ b/patch_v2/sdk/test_p1p2p3_repro.c @@ -22,7 +22,7 @@ * -I. -I../hello_app ../hello_app/app.c -o app.o * 2) 编译本文件 + 其余 hello 模块 + SDK 源 + 打桩,链接 app.o: * gcc -Wall -Wextra -DMEOW_UI_HOST_TEST -o test_p1p2p3_repro test_p1p2p3_repro.c app.o \ - * test_host_stub.c meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * test_host_stub.c meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c meow_ui_draw.c \ * meow_ui_view.c meow_ui_nav.c meow_ui_media.c stb_image.c \ diff --git a/patch_v2/sdk/test_pinyin.c b/patch_v2/sdk/test_pinyin.c index 6b9a764..418bd45 100644 --- a/patch_v2/sdk/test_pinyin.c +++ b/patch_v2/sdk/test_pinyin.c @@ -8,7 +8,7 @@ * * 编译(宿主 gcc,同 test_ime_fix): * gcc -Wall -Wextra -o test_pinyin test_pinyin.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_ui_media.c \ * meow_notify_ipc.c stb_image.c -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm diff --git a/patch_v2/sdk/test_sb_collapse.c b/patch_v2/sdk/test_sb_collapse.c index 3967769..430bb84 100644 --- a/patch_v2/sdk/test_sb_collapse.c +++ b/patch_v2/sdk/test_sb_collapse.c @@ -9,7 +9,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log + 打桩 font/global + meow_notify_ipc): * gcc -o test_sb_collapse test_sb_collapse.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c meow_notify_ipc.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c meow_notify_ipc.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread */ #include "meow_ui.h" diff --git a/patch_v2/sdk/test_sdk_fixes.c b/patch_v2/sdk/test_sdk_fixes.c index 1134668..c041088 100644 --- a/patch_v2/sdk/test_sdk_fixes.c +++ b/patch_v2/sdk/test_sdk_fixes.c @@ -8,7 +8,7 @@ * * 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global): * gcc -Wall -o test_sdk_fixes test_sdk_fixes.c test_host_stub.c \ - * meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ + * meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \ * meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \ * meow_ui_draw.c meow_ui_view.c meow_notify_ipc.c \ * -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread diff --git a/patch_v2/sdk/tools/clock_abi_probe.c b/patch_v2/sdk/tools/clock_abi_probe.c new file mode 100644 index 0000000..8aca840 --- /dev/null +++ b/patch_v2/sdk/tools/clock_abi_probe.c @@ -0,0 +1,94 @@ +/* clock_abi_probe.c — 时钟 ABI 最小探针(M11)。 + * + * 用途:在宿主或真机上一眼看出「编译器头文件声明的 time_t 宽度」与「libc 实际写入的 + * struct timespec 宽度」是否一致——这正是 meow_ui_time_ms 真机故障的根因(详见 + * sdk/CLOCK_ABI.md)。做法:先把 struct timespec 整块填 0xAA,再调 clock_gettime, + * 看哪些字节被写回: + * - 正确(time64:tv_sec 8B + tv_nsec 4B):偏移 0..11 被写,8..11 不再是 0xAA; + * - 坏(libc 只做 o32 time32:只写 8B):偏移 8..11 仍是 0xAA → 退出码 2; + * - 头/库宽度相反(头 8B、库写 16B)也会在偏移检查里暴露。 + * + * 构建(宿主): + * gcc -Os -Wall -Wextra tools/clock_abi_probe.c -o clock_abi_probe + * 构建(mipsel 静态,测裸 zig libc): + * ~/.tools/zig-mipsel-cc -Os -static tools/clock_abi_probe.c -o clock_abi_probe + * 构建(mipsel + SDK,测修复后的归档是否接管 clock_gettime): + * ~/.tools/zig-mipsel-cc -Os -static -DMEOW_PROBE_WITH_SDK -I. -Iinclude \ + * tools/clock_abi_probe.c meow_ui.a /lib/libz.a -lpthread -o clock_abi_probe_sdk + * + * 运行:./clock_abi_probe + * 退出码:0=ABI 一致且时钟单调、量级合理;1=时钟值异常;2=libc 只写了 8 字节(ABI 不一致)。 + */ +#include +#include +#include +#include +#include + +#ifdef MEOW_PROBE_WITH_SDK +#include "meow_ui.h" +#endif + +#define PAD_BYTE 0xAA + +static uint64_t now_ms(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000u + (uint64_t)ts.tv_nsec / 1000000u; +} + +int main(void) +{ + int rc = 0; + struct timespec ts; + unsigned char raw[sizeof(struct timespec)]; + + printf("sizeof(time_t)=%u sizeof(long)=%u sizeof(struct timespec)=%u\n", + (unsigned)sizeof(time_t), (unsigned)sizeof(long), (unsigned)sizeof(struct timespec)); + printf("offsetof(tv_sec)=%u offsetof(tv_nsec)=%u\n", + (unsigned)offsetof(struct timespec, tv_sec), (unsigned)offsetof(struct timespec, tv_nsec)); + + memset(&ts, PAD_BYTE, sizeof ts); + int r = clock_gettime(CLOCK_MONOTONIC, &ts); + memcpy(raw, &ts, sizeof raw); + printf("clock_gettime ret=%d tv_sec=%lld tv_nsec=%ld\n", r, (long long)ts.tv_sec, (long)ts.tv_nsec); + printf("raw:"); + for (unsigned i = 0; i < sizeof raw; i++) printf(" %02x", raw[i]); + printf("\n"); + + if (r != 0) { + printf("FAIL clock_gettime 失败\n"); + return 1; + } + /* tv_nsec 所在 4 字节必须被 libc 写过 */ + if (sizeof(struct timespec) > 8 && raw[8] == PAD_BYTE && raw[9] == PAD_BYTE && + raw[10] == PAD_BYTE && raw[11] == PAD_BYTE) { + printf("FAIL libc 只写了 8 字节 time32(头声明 %u 字节)→ ABI 不一致\n", + (unsigned)sizeof(struct timespec)); + rc = 2; + } + + uint64_t a = now_ms(); + uint64_t b = now_ms(); + if (b < a || b - a > 5000 || b >= (1ULL << 40)) { + printf("FAIL 毫秒值异常: a=%llu b=%llu\n", + (unsigned long long)a, (unsigned long long)b); + rc = rc ? rc : 1; + } else { + printf("ok now_ms a=%llu b=%llu\n", (unsigned long long)a, (unsigned long long)b); + } + +#ifdef MEOW_PROBE_WITH_SDK + uint64_t s1 = meow_ui_time_ms(); + uint64_t s2 = meow_ui_time_ms(); + printf("meow_ui_time_ms: %llu %llu\n", (unsigned long long)s1, (unsigned long long)s2); + if (s2 < s1 || s2 - s1 > 5000 || s2 >= (1ULL << 40) || s2 == 0) { + printf("FAIL meow_ui_time_ms 异常\n"); + rc = rc ? rc : 1; + } +#endif + + printf(rc ? "== FAIL (rc=%d) ==\n" : "== PASS ==\n", rc); + return rc; +}