AskaEth
|
8cd6e21cad
|
fix(bootmenu): M23 评审 r1 — 修 P2-1 降级路径 + P2-2 Bug4 防护退化
P2-1(降级路径把老 bug 请回来):settings 不可读时不再原样采信面板瞬时值。
bm_bri_pick_saved 的 panel 分支改为 min(面板, BM_BRI_SAFE_LOW),src 改名 panel-capped;
BM_BRI_SAFE_LOW 20 → 10,与 meow_watchdog 的 WD_BRI_SAFE_LOW 对齐(同一系统同一个安全下限)。
这样 settings 不可读 + 面板 60(播放器启动画面值)时 saved 是 10,扫描窗/确认框不会再写 60。
注释改掉「与 wd_bri_decide 同构」的断言:方向相同,但 bootmenu 没有运行期亮度快照,
降级走安全下限而不是 M20 的「快照 → cur>0 不写」链。
单测:把原先钉死 bug 的 "fallback keeps panel 60" 改成 "caps panel 60 -> SAFE_LOW 10",
并补「比 SAFE_LOW 更暗的真实值保留」「SAFE_LOW 与 M20 对齐」两个断言。
P2-2(busy 门可能让 Bug 4 防护变成空操作):删除 /proc D 态门,触发条件回到 pre-M23 的
「窗口内 + 面板暗(bri<=0)+ 面板未下电(bl_power<=0)」。
避免「熄屏瞬间爆亮」改由两条可观测信号承担:bl_power>0(播放器 FBIOBLANK)与
「电源键按下后 3s 内不补」(supervisor 已在 10ms 轮询 evdev,记录按下边沿)。
单测补 Bug4 防退化回归用例(窗口剩余 89999ms、面板暗、未下电 → 必须补)。
评审非阻塞三条:
- 日志节流:同一原因 ≥2s 一条、原因跃迁也 ≥1s(防 visible↔scan-floor 每 400ms 交替刷屏,
90s 窗口最坏 ~90 行);日志字段 busy= 换成 pwr_ago=。
- 单测复跑配方补 TMPDIR;tmp_root() 增加自愈(TMPDIR → 可写 /tmp → $HOME/tmp/m23test)。
- 验收配方(3 次亮/灭屏 + 进一次开机菜单 + 期望日志行)写进报文。
只交源码:不含二进制、不改 fw_content.conf、不动 build_bootmenu.sh。
|
2026-11-11 18:42:41 +08:00 |
|
AskaEth
|
bc7bafa5dc
|
fix(bootmenu): M23 亮度单一权威源(只交源码,二进制由 M43 统一重编)
真机 0.8.46 两个症状:
1) 开机菜单亮度 = 第一屏的 60(用户设置 1)——根因是 M6.25 的选单亮度写回只改了源码、
二进制没重编(strings 无 display.brightness_min),本次只交源码,重编交给 M43 批次。
2) HibyOS 亮/灭屏瞬间爆亮——supervisor 把启动瞬间面板读数(播放器写的 60)当保底,
且 >60 一律钉 60;扫描窗保底只要读到亮度<=0 就在 400ms 内写回该值,用户主动熄屏
也会被强行点亮。
改动(全部失败也沿用现状行为):
- saved_brightness 权威源改为 settings.conf 的 display.brightness(与 watchdog/launcher
同源同 clamp);面板读数只在 settings 不可读时兜底;两者都不可知才写 BM_BRI_SAFE_LOW。
- 旧的 `>60 → 60` 硬钉改为 clamp 进 [display.brightness_min, max_brightness](bm_bri_clamp),
不再用常量顶替用户值;为什么不会重新引入 M2.9 开机闪屏写在 bm_bri_pick_saved 注释里。
- 扫描窗保底加「播放器忙(proc 态 D)+ 面板未下电(bl_power<=0)」两门,窗口结束彻底放手。
- 热键熄屏恢复:面板真实正值优先(HibyOS 内改过亮度),否则用 settings 值,夹进 [min,max]。
- 决策抽纯函数 bm_bri_pick_saved / bm_bri_clamp / bm_bri_floor_decide / bm_bri_hotkey_saved。
- 亮度判定/写回补 bm_log 落卡(stderr 原行全部保留),只在状态跃迁时打,不在高频路径刷日志。
- test_bm_fw.c:宿主单测(settings=1/saved=60/now=0/blank 矩阵 + clamp 矩阵 + 真文件 e2e)。
- -Wall -Wextra 清理:3 处 unsigned/int 比较、未用参数、未用变量、sys/poll.h→poll.h。
不含二进制、不改 fw_content.conf 钉值(保持 4441822d)。
|
2026-11-11 18:42:41 +08:00 |
|
AskaEth
|
f49585dd62
|
fix(launcher): M47 r1 评审 P2 四项 — 未知态不写盘/不顶替 + deadline 从点击起算 + 开关弹窗后置清理
评审 r1 status=p2-4items / merge=fix-then-merge(reviewed e4eda3a)。逐条:
P2-1 未知态被写成 settings=0,把失真推到别的入口
- bt_page.c / wifi_page.c:`meow_settings_set_bool(..., disp == 1)` 加 `disp >= 0` 门。
disp == -1(daemon 与直连都读不到)时**保留用户原意图不动**。该键被 notif_center /
settings_page 当显示态读、被 app_launcher 用来决定自动拉起 WiFi,写 0 会把「不知道」
污染成「确定已关」。
- test_bt_page.c 5d 期望同步改:未知 → settings 保持原意图 1(不再期望「回滚为 0」)。
P2-2 收尾后「探测未知」仍显示成确定态,第三态丢失
- mtog_calc:显示态**只认 probe**,probe < 0 直接返回 -1;last_real 不再顶替确定态
(`(void)last_real`,仅由调用方用于弹窗文案)。超时/下发失败且探测未知 → 顶栏保留
「关+?」、行内保留「状态未知」,与文件头契约一致。
- 弹窗文案按结论区分:「无法确认当前状态(上次已知:开启/关闭/未知)」vs
「切换未生效:当前仍为开启/关闭」——不再出现「当前仍为开启」自相矛盾(该文案只在
probe 已知且 != 意图时出现)。日志加 elapsed。
P2-3 deadline 起点错,注释上限是假的
- bt_page/wifi_page:`deadline` 从**点击时刻**起算(含下发耗时)。
- 注释改成如实上限:快路径 1~2s / ≈16 次探测;慢路径(on-off 读超时 1.5s + hciconfig
0.3~2s,之后一次探测 status 1.5s + 直连 1.8s ≈3.3s)总阻塞最坏 ≈7s、预算内只够 1 次
探测,此时只能确认「探测超时」而非「设备无响应」——文案已按此区分。异步化留给后续单。
P2-4 开关路径弹窗后缺 after_modal / 按键基线复位
- subpage.c:顶开关命中分支补上与行命中分支相同的后置清理(排空触摸 + 40ms 二次排空、
触摸基线/cooldown、key_router_rebase、kd_*/kp_poll 基线、m_prev_*、after_modal=1)。
s_dd_modal 是全屏压暗层,否则关闭后状态栏(0..27)残留压暗到下一次时钟重绘,电源/播放键
也可能带进弹窗里的陈旧边沿。
顺带(评审观察,未改全局超时策略)
- netmgr_ipc.c:拆出 `nm_cmd_t(..., int *read_timeout)`;`nm_bt_power_state()` 走它,
**读超时 = 状态未知且不把可达性缓存打成 down**(netmgrd 单线程忙时 `bt status` 自己
跑 hciconfig 可能超 1.5s;旧行为会标 down 1s,令紧随的 bt_rows 闪出「服务未运行(直连
模式)」并把后续探测切到 1.8s 直连)。WiFi/DNS 等其它调用保持旧语义(传 NULL)。
验证
- `bash patch_v2/meow_launcherd/build_launcher.sh test` → exit 0,**65 PASS / 0 FAIL / 0 warning**
(矩阵 13 组,新增「下发失败·探测未知 → 未知不顶替」)。
- 交叉编译 0 warning;产物(临时副本,不入库)901020 B / md5 e21450ff6621a67fd854165413c58be1。
- `test_time32_abi.sh` → 4263=3 / 4403=0 ALL PASS;`pkg_install` 与 7 条切换中/未知态文案
均在 strings 中(旧的两条「无法确认蓝牙/WiFi 状态」已合并为「无法确认当前状态(上次已知:%s)」)。
- 真机 --sysdump(只读,临时文件已删):exit 0,bt_on=1/wifi_on=1 与设备现状一致;
Music du 前后 199164544;未替换 /usr/bin/meow_launcherd、未重启 launcherd。
- 交付形态不变:本 commit 只动 5 个源码文件;二进制与 scripts/build/fw_content.conf 对 main 零 diff。
|
2026-11-11 17:59:13 +08:00 |
|
AskaEth
|
e4eda3a06f
|
Merge branch 'main' into feat/m47-settings-bt-and-wifi-true-toggle-sta
|
2026-11-11 17:23:55 +08:00 |
|
AskaEth
|
514cc0e5d0
|
chore(m47): 只交源码 — 撤回本单的 launcherd 二进制与 fw 钉值
M42(pkg_install.c)已并入 main,本分支 base 的编译列表不含它,本单产出的
二进制/钉值是旧 base 的(1c88661a…)。为避免「每个单各改一次二进制和钉值」继续
制造 M48 审计查出的分叉,tower 立了 M51 统一重编批次:所有产物的最终重编、钉值
回写、语义指纹自证与 .upt 打包都在那一个受控批次里做一次。
本 commit 把两个文件恢复到 base 原值(不做任何手写钉值):
- patch_v2/meow_launcherd/meow_launcherd → 605e13a9…(base 版)
- scripts/build/fw_content.conf 的 launcherd 行 → base 原值
源码改动(bt_page/wifi_page/netmgr_ipc/net/subpage/两个测试/build_launcher.sh 的
ZIGCC/MIPS_SYSROOT 环境变量化)全部保留。合并 main 后编译列表需同时含 pkg_install.c。
|
2026-11-11 17:23:42 +08:00 |
|
AskaEth
|
b20e3c43e9
|
fix(launcher): M47 设置页蓝牙/WiFi 开关只认真实态 — 三态查询 + 待确认收敛 + 未知态呈现
用户原话:「开关都存在显示问题 我都不能判断它是不是真的开启还是关闭(包括 WiFi 页也是)」。
根因不是「没读到硬件态」,而是「读到/没读到都被拿去当用户意图的装饰」:
- bt_page.c:103 开关初值来自 settings 布尔;:112-114 下发后立刻 g_sys.bt_on = on(显示意图);
:129 c->bt_on = nm_bt_powered() 赋值后全文无人引用(M45 也独立发现)。
- wifi_page.c:40 读不到 settings 时默认 1(显示已开)。
- netmgrd 的 bt/wifi 查询本身把「问不到」塌缩成 0(nm_bt_powered/nm_wifi_connected)。
本单只解「状态可信」,不碰扫描/配对/音频(另有 M45/M46 单)。
1) 真实态三态(-1 未知 / 0 关 / 1 开)
- net.c 新增 net_bt_power_probe()(hciconfig hci0 UP/DOWN;无输出=未知)与
net_wifi_power_probe()(rfkill wlan soft/hard 汇总,回退 wlan0 IFF_UP;读不到=未知)。
- netmgr_ipc.c 新增 nm_bt_power_state()(daemon bt status 的 available/powered 权威,不可达
回退直连探测)与 nm_wifi_power_state()(netmgrd 的 wifi status 只有 wpa_state、不报射频态,
故取本地 rfkill——daemon 的 wifi on/off 改的就是同一份内核状态)。
- 两个子页的 top_sw/rows 只读这两个函数;settings 布尔降级为「意图持久化」,不再决定外观。
- 「读不到默认 1」删除:未知就是未知。
2) 点击 → 待确认 → 真实态定稿
- 纯函数 meow_toggle_{display,pending,rollback,error}(bt_page.c,无 I/O/UI):
只有 probe 确认才算收敛;probe 未知继续等,绝不因 last_real 恰好等于意图就宣布成功。
- 页面:落盘意图 → 下发 → 250ms 轮询(BT 上限 4s、WiFi 上限 5s;hciconfig 0.3~2s、
wifi_up.sh 起 supplicant/DHCP 更慢,故不用 20ms 级忙轮询)→ 真实态定稿;失败/超时把
settings 回滚到已确认真实态 + s_dd_modal 可见报错,不静默、不乐观。
- subpage.c:切换前先画「正在开启/关闭…(等待设备确认)」条(待确认态与稳定态可区分);
切换后回读 top_sw 定稿(取消原「点了就翻面」),live tick 也回读,外部改动驻留期间可见。
3) 第三态呈现(未知 ≠ 已关)
- SDK meow_switch 只有两态:未知时开关停「关」并在左侧画灰色「?」;行内另有
「蓝牙状态未知 / WiFi 开关状态未知」文字说明。选「?」是因为它不占用开关控件本身、
且「关+?」不会被读成「已关」。
4) 顺带修 net.c 三条开关失真(塔追加的 M45 盘点,同一病根)
- s_net_toggle_bt() 补 rfkill soft(与 netmgrd 的 bt on/off 同一语义;开:先 unblock 再 up;
关:先 down 再 block)。此前只发 hciconfig → 「BT 页关过再从头开」会被 rfkill 拦下。
- s_net_sync_from_sys() WiFi 判据从 wlan_connected()(已关联)改为射频态;BT 用三态,
读不到不写(旧写法把「网卡 up 未关联」写成 0,把未知写成已关)。
- rfkill 同类多节点(本机 2 wlan + 2 bluetooth)按「任一 block 即 block」读、全部写入。
测试(`bash patch_v2/meow_launcherd/build_launcher.sh test`,新增 test 入口)
- test_bt_page.c:P4 三态与未知占位、P5 收敛四例(达成/下发失败/超时/未知)、P6 收敛矩阵
12 组(真实开/关 × 下发成功/失败/超时 × probe 未知),全 PASS(64 条断言)。
- test_netmgr_ipc.c:新增 nm_bt_power_state 解析(powered=1/0、available=0、缺字段→-1)、
nm_wifi_power_state 透传、不可达回退=未知、wifi_rows 未知态占位;并修掉两处既有测试缺陷
(行内 UI 桩缺失导致本文件此前根本链不过;直连连接桩统一返回 "0\n" 导致等满 10s 必失败)。
- 交叉编译 0 warning(-Wall -Wextra,逐文件单独编 + 整链);launcherd 899388 B
md5 1c88661a9410ac1a4139304362281cdd,同 commit 同步 scripts/build/fw_content.conf 钉值。
真机(10.58.215.50,仅只读自检,未替换 /usr/bin/meow_launcherd、未刷机)
- 二进制放 /usr/data/mnt/sd_0/MeowOS/tmp/ 跑 --sysdump:exit 0,输出 wifi_on=1 / bt_seen=1
bt_on=0,与设备现状一致(rfkill 全 0 + wlan0 up + hci0 DOWN + netmgrd powered=0)。
- 卡上 du -s /usr/data/mnt/sd_0/Music 前后恒 199164544;临时文件已删;settings 未改。
- launcherd 在 squashfs 里 → 本改动需刷机生效。
已知不在本单:输出目标只写 settings(audiod 仅启动读一次)→ M45 finding / M46;
netmgrd 侧四处失真(未知当关、up 与 unblock 顺序、rfkill 只写首节点、wifi status 无射频字段)
已报 finding;设置主页/通知中心的开关显示仍是 settings(另立单)。
|
2026-11-11 17:16:28 +08:00 |
|
AskaEth
|
58cdb73bf8
|
fix(launcherd): M42 包安装入口改委托 nyai — 删内联解包/验签/部署,复用 M35 安全链
- app_launcher.c 删掉 meow_pkg_install 旧内联实现(文件名推包名、硬要 .mpk 后缀、
rm -rf 目标目录直解、失败不回滚 .bak_、不拒 ./..、系统包大小写敏感比较);
导出保留签名逻辑不动(验签仍只 shell-out meow_verify)。
- 新增 pkg_install.c:fork+exec /usr/bin/nyai install <路径>(argv 直传不经 shell;
MEOW_NYAI_BIN 覆写,缺省不走 PATH)。包身份/暂存/清理/防降级/大小写全由 nyai 闭环。
- stdout/stderr 分两条管道收:nyai 进度是缓冲 stdout,错误是即时 stderr,合流会把
真错误顶掉(真机首测即踩到);错误文案只取 stderr 尾行。
- start/poll 两段式(+busy 查询)供 UI 主循环按帧驱动不假死;同步封装 20ms 切片轮询,
180s 超时 SIGTERM→SIGKILL,不用时钟 ABI(M40 time32 教训)。
- main_menu --pkg-install 失败打 stderr 可读文案、退出码统一 0/1。
- test_pkg_install.c:44 断言(路径预检含任意文件名可装/目录/不可读/控制字符/超长、
错误文案矩阵、argv 直传、start 立即返回、并发拒装、超时、nyai 缺失)。
- 重链 meow_launcherd 894940B/cea0a735(链 meow_ui.a 86800633,0 warning);
fw_content.conf 同步钉值。
|
2026-11-11 16:37:00 +08:00 |
|
AskaEth
|
bd6fc8da3c
|
fix(reader): M41 r1 评审 P2 — 拖动重绘节流 + 终帧补齐 + 三条边界测试
P2-1(用户可感知):shelf_on_touch_move 每收到一条 TOUCH_MOVE 就同步全量重绘。
输入线程「坐标一变就一条 MOVE」且不合并(队列 128 条),folder ≤200 行走圆角卡
≈40ms/帧 → 主循环追不上手指、抬手后还会继续滑、极端情况丢 release。修法:
- 滚动位置仍每条 move 立即生效(纯算术,便宜);上屏节流:首帧立即画,之后每
max(16ms, 上一帧实测耗时) 一次(自适应窗口,圆角卡 40ms 帧自动降到 ~40ms 周期,
不再把队列拖垮)。
- 手势收尾(shelf_on_tap / shelf_on_swipe)无条件补终帧再清手势态;下一次按下也会
先把上一次遗留的未上屏帧补上(HOME/长按等没有 TAP/SWIPE 收尾的手势)。
- 位置没变(已到顶/底)连帧都不画。
P2-2(测试盲区):
- 新增三条边界:顶栏起手不拖、副题区起手不拖、横向手势判向取消后不再滚动。
- 吞 TAP 边界带:20/40/60px(>8px 且 <65px,SDK 报 TAP)抬在目录行上不得进目录;
6px 抖动(≤8px)仍算点击能进目录。
- 断言从「像素变了」升级为「像素**恰好**位移 N px」(内容区快照逐行比对,避开视口
边缘裁剪带):swipe 120 → 恰好 120;拖动 60 → 恰好 60;并新增 6 步×10px 多步拖动
断言终帧恰好 60(专测节流不丢最后一段)。
- 修掉把 20px 写成「< SHELF_DRAG_TAP_PX」的错误注释。
顺手:
- shelf_draw_notice 用 th->bg 而不是只在 shelf_redraw 赋值的 g_bg。
- build_reader.sh 用 trap 保证测试失败时也清 $TMPDIR/m41_scroll_sd。
验证:shelf_scroll_smoke 38/38、shelf_group_smoke 99/99、shelf_index_smoke 170/170。
红绿对照:dist=dy(旧 swipe 语义)→ 9 条 FAIL;拿掉「抬手补终帧」→ 恰好 1 条 FAIL
(6 步拖动终帧那条),证明节流与终帧都有测试盯着。
reader 1719220B md5 890175ec…;mpk 818162B md5 ffbb7097…(0.1.8/code9,未签名)。
|
2026-11-11 13:15:54 +08:00 |
|
AskaEth
|
2de47154bf
|
fix(reader): M41 书架补滚动输入通路 — 列表/宫格、format/folder 全都能滑
书架(shelf.c)从 M6.40 首版起就**没有**滚动输入通路,不是 M32/M33 的回归:
1) app_on_touch_down/move 只路由给阅读页 → 书架没有跟手拖动;
2) shelf_on_swipe 用 dy 去 scroll_by,而 SDK 固定按 on_swipe(dir, dist, 0)
分发(总位移在第 2 参 dx,dy 恒 0)→ 恒 scroll_by(0),死代码。
两条都在 shelf.c 自己身上,list/grid × format/folder 共用同一段,所以四种组合
全都「滑不动」(files/ncm 能滑是因为它们各自实现了 touch_down/move → scroll_by)。
修复:
- app.c:touch down/move 也路由给书架(阅读页优先级不变)。
- shelf.c:
* 新增 shelf_on_touch_down/move 跟手拖动:按下点在内容区才起手;纵向主导(≥4px)
才锁滚动,横向主导直接取消(不抢左缘返回);逐帧 scroll_by(-dy) 只重画内容区。
* shelf_on_swipe 改按 dist(=dx,兼容 dy 分支)+ 方向定符号;本次手势已跟手滚过
就不再叠加(防一划滚两倍)。
* 拖动后的抬手吞掉 TAP(<65px 的拖动 SDK 报 TAP)→ 滑动时不会误开书/误进目录。
* 控件重建(进/退目录、布局/分组切换、刷新)清滚动手势态,避免旧标记吃掉下一次滑动。
* 提示条抽成 shelf_draw_notice(),滚动局部重画时照常重贴。
- 新增宿主回归 test/shelf_scroll_smoke.c(真实 shelf.c + 真实 SDK 绘制 + back_buf
像素断言,27 条):format/folder × list/grid 都能滑;3 本书的目录滑不动;
拖动后不误进目录、干净点击仍能进目录;folder 进出目录仍正常。把 dist=dx 改回
dist=dy 后同一测试 6 条 FAIL(红绿对照证明它抓的就是这个 bug)。
- build_reader.sh 接入该测试;READER_SD_ROOT 加 #ifndef 以便宿主把扫描根指到临时目录。
- app.json 版本 0.1.7/code8 → 0.1.8/code9(同一版本号不发两个构建)。
宿主验证:shelf_scroll_smoke 27/27、shelf_group_smoke 99/99、shelf_index_smoke
170/170、其余 core/seg/chapter/loaders 全绿;reader 1718468B md5 259cb6ed5a60…
(meow_ui.a 用本仓 SDK 源码重编:79 成员全 MIPS32r2 o32)。真机验证待刷机
0.8.49 完成后部署(设备验证需用户手滑,面板无任意滑动注入端点)。
|
2026-11-11 13:01:12 +08:00 |
|
AskaEth
|
340c41afb7
|
fix(m40): 评审 r1 — rebase 解冲突 + 宿主构建/可复验断言(无运行逻辑改动)
- rebase 到 main(b1acc90,含 M39 r1):fw_content.conf 冲突取 launcherd 605e13a9、
watchdog 37c57e0f;nyai 保持 main 的 ef7940ec(M39 6c6da79 已修,本单不再改该行)
- build_ncm_host.sh:SDK_SRC 补 meow_time32(否则链接 U meow_time32_monotonic_ms);
顺带补 meow_jpeg/meow_png_stream/meow_img_color,脚本端到端可构建
- build_sdk.sh / build_launcher.sh 加 -Wall -Wextra 并重编:0 warning,产物 md5 不变
(meow_ui.a=86800633、meow_launcherd=605e13a9)
- 新增 sdk/test_time32_abi.sh:反汇编断言 4263≥1、4403=0(覆盖宿主 fallback 测不到的真机路径)
- 注释修正 sdk/meow_ui_repaint.c → .h
- P1-1(launcherd 只能刷固件;watchdog 可热更但需退出重进 App)为交付说明修正,无代码改动
|
2026-11-10 22:54:11 +08:00 |
|
AskaEth
|
63b278e13e
|
fix(watchdog+launcher+sdk): M40 电源键 time64 ABI + 锁屏/叠加残留链
- sdk/meow_time32: 抽出可独立链接的 o32 time32 取时/睡眠设施(不依赖 meow_ui.a,
watchdog 等独立静态组件可直接链;可选 -DMEOW_TIME32_LIBC_OVERRIDES 接管 libc 入口)
- watchdog: now_ms/usleep 改走 time32(修复 held 变天文数字→每次单击都弹菜单);
阈值读 power.longpress_menu_ms/forceoff_ms(缺省 3000/8000),删除
PWR_TOGGLE_MS==PWR_MENU_MS;新增 wd_power.h 纯判定 + 宿主行为矩阵测试
- launcher: App 前台电源菜单补齐 §10.5(notif 全抑制 + 帧恢复 + SIGCONT 排空 +
标记翻回前台);show_power_menu 恢复进入前背景帧(关闭后不再停留菜单画面);
重绘挪到首轮按键采样之后;activity 标记排空窗 + 会话入口清理 + manual_off 去闩锁
- lock_screen: 电源改按下边沿 + 进场 300ms 才熄屏;电源熄屏退出也恢复底层帧;
launcher 在 SIGCONT 前写 /tmp/meow_app_repaint,SDK present 消费并 dirty_full
- power_menu: 菜单内强关接 power.forceoff_ms(按 longpress 抵扣),日志不再谎称 8s
- 重编 meow_ui.a 并重链 meow_launcherd/ncm/files/hello/reader(picbrowser 无源码)
- fw_content.conf: 同步 launcherd/watchdog 新 md5;顺带修正 M35 遗留的 nyai 失效钉值
Host: test_wd_fw 66/66、test_overlay_gate 40/40、test_meow_time64/time/repaint PASS。
真机未验证(设备关机);未刷机、未写设备。
|
2026-11-10 22:51:00 +08:00 |
|
AskaEth
|
837cd47e7c
|
fix(sdk+launcher): M39 点击输入门 — 固定时长吞窗改为「启动排空 + 短系统手势防穿透」
根因(M36 已查实):不是布局竞态,而是固定时长的输入封闭窗口且窗口起点在首帧之后。
- SDK meow_ui_run:M2.22(C) 500ms 内丢弃 TAP/SWIPE/HOME/NOTIF_PULL/TOUCH_DOWN/MOVE/LONG_PRESS,
窗口在 App 画完首帧后才 arm → 用户看到界面后第一下必被吞。
改为入口 meow_input_drain() 排空一次(清环形队列 + 复位触摸状态机),
TAP/TOUCH_DOWN/TOUCH_MOVE/LONG_PRESS 立即生效;仅系统手势(左缘 SWIPE、底部上滑 HOME、
顶部下拉 NOTIF_PULL、SWIPE_PROGRESS)保留 STARTUP_GESTURE_GUARD_MS=150 防穿透。
- launcher:menu_after_app_exit 1200ms→150ms;子页返回 800ms→150ms;菜单/子页打开
300ms→150ms(统一 MENU_TOUCH_GUARD_MS)。menu_drain_touch() 同时复位 t_down/原点/坐标:
只清队列会把「按下已被 drain、抬手稍后才到」误判成一次 tap(幽灵重放的另一半)。
历史理由已核对:旧窗口是为 Bug2/4(App 运行期事件堆积在 launcher 自身 touch_fd 里被重放)
加的,真正的机制就是排空本进程 fd —— evdev 每 fd 各收一份,App/子页运行期全量事件都在
这个 fd 里,drain 后无历史事件可重放;窗口只兜面板重配尾巴。
- 单测:test_meow_ui_home_gesture 新增 T4(11 断言:立即点击生效/立即上滑被守卫挡+守卫后生效/
立即左缘 SWIPE 同理/TOUCH_DOWN+MOVE 立即下发/LONG_PRESS 立即下发/run 入口 drain 丢弃预置残留;
旧 SDK 下 8 条红、新 SDK 30 pass/0 fail);test_meow_ui_dispatch 新增 M5(drain 清队列+复位在途
手势+新点击不受影响,ALL PASS);swipe 35/0、view_event ALL PASS(回归)。
- 重编重链(铁律):meow_ui.a 8525aa6b(meow_ui_input.o 8248a6c6,旧 e54903ca)→
meow_launcherd e342d24f(891164) / files 17edac0f(383072) / hello 65c1c575(499380) /
ncm 1c2f5ff7(1225676) / reader a463645f(1716212,gitignore 不入库)。
picbrowser 仓库内 0 个 tracked 文件(源码不存在)→ 无法重链,见 finding。
- 真机:未验证(纪律禁止覆盖设备已装组件;uinput 注入是 M36 设备失联诱因)。
|
2026-11-10 21:58:13 +08:00 |
|
AskaEth
|
cf5703b32b
|
fix(nyai): M35 评审 r1 — 闭合 exFAT 大小写绕过(P1)+ 修 fmt_utc 1/2 月 + 成员名/炸弹纵深
P1(信任边界):is_system_pkg() 原用 strncmp,而落盘目录在 exFAT(名字比较
不区分大小写)。包内 app.json 写 "OS.MEOW.READER" 时 valid_pkg 放行、
is_system_pkg 返回 0 → 当第三方无签放行 → dst 解析到已装的
MeowAPPs/os.meow.reader → 备份后部署假包并删掉真系统 App(无需私钥)。
三层封堵:
1) is_system_pkg 改 strncasecmp(前缀判定不再受大小写影响);
2) valid_pkg 收紧为只收 [a-z0-9._-],并拒绝前导/尾随 '.'(现网包名全小写,
无兼容代价;tail-dot 同时挡 exFAT/Windows 名字映射怪癖);
3) 部署前 readdir 检查 MeowAPPs 里是否有与 pkg 仅大小写不同的已装目录
(有则拒装并报两个名字);部署后再用 readdir 复核 on-disk 名字与清单包名
逐字节相等,不等则回滚,杜绝「身份不明的 App 目录」。
P2-1:fmt_utc() 的 March-based 月份换算写成 +9(应为 -9),1/2 月会打成
20251901/20251931 且年份不 +1。修正为 int 运算;新增 test_fmt_utc.c
(直接 include nyai.c 测 static 函数)覆盖 epoch/负数、1/1、2/1、2/28、闰年
2/29(2024 与 2000)、3/1、12/31 23:59:59、2038-01-01、int32 上界、2100 非闰。
纵深防御(评审残留风险,一并做):
- tar 成员名净化不再依赖外部 tar:mpk_check_members 解析 tar -tv 的名字,
拒绝绝对路径 / 含 '..' 组件 / 首字符 '-' / 原始控制字符;解包后 stg_tree_ok
再用 readdir 的真实名字复核控制字符(tar 列名会把控制字符转义成可见文本,
原检查会漏)。
- 解压炸弹:累加 tar -tv 的体积,超过 512MB 上限拒装,并加 statvfs
「剩余空间 ≥ 体积 + 16MB」门禁(解包先于验签,恶意包可在验签前写满卡)。
- 顺手改掉 appmeta.package 注释里「== 文件名茎」的旧语义。
回归:test_nyai.sh 49 → 70 条断言全过(新增:fmt_utc 13 例、大写包名绕过顶替
已装系统包被拒且原 App 未变、尾点包名、与已装目录仅大小写不同、绝对路径/
../ / 首字符 '-' 成员名、控制字符成员名、700MB 解压炸弹),
`-Wall -Wextra` 零告警,二进制可重复构建。
交付:nyai 153,844 B / md5 ef7940ecf5ece993d718ac1d9019cc82(旧 4524ce6b…)。
真机 10.58.215.50 仍不可登录(22 端口 TCP 可连、15-50s 无 banner),本轮
**未做真机复核**,仅宿主验证。
|
2026-11-10 21:42:37 +08:00 |
|
AskaEth
|
829d4475e8
|
feat(nyai): M35 包身份以已签名 app.json 清单为准 + 暂存迁到 SD 并必清理
包名/版本/依赖不再从 .mpk 文件名推导(用户定案:不对安装包文件名强依赖,
一切信息从清单取),改为解包后读 app.json.package 作唯一权威:
- 落地目录 MeowAPPs/<pkg>、meow_verify --package <pkg>、防降级基准全用清单包名;
- 新增 footer.package == app.json.package 一致性检查,不一致拒装并同时报两个名字;
- valid_pkg 拒绝 "." / ".."(此前 MeowAPPs/.. 可越出安装目录并被 rm_rf);
- index 的 Package 字段同样取自清单(缺 package 的包跳过并告警);
- scan/export 同步;--help 与错误文案去掉「需要 <pkg>.mpk」。
暂存:MeowAPPs/.stg_<pid>_<pkg>(/usr/data NAND,仅剩 4MB)
→ <MeowROOT>/MeowOS/tmp/pkgs/<pkg>-<UTC时间戳>-<pid>-<n>/(真机即 SD 卡):
- mkdir 原子占位 + 失败重试 + pid/序号保证唯一,时间戳只给人看;
- SD 未挂载/不可写直接拒装(不回退 /usr/data:目标本就在 SD,且跨 fs rename 会 EXDEV);
- 解包前后各一道防护:tar -tv 只允许普通文件/目录(拒符号链接/硬链接/设备/FIFO),
解包后复核暂存树(非普通文件、nlink>1 一律拒);
- 中央化 cleanup + SIGINT/SIGTERM/SIGHUP handler(先收子进程组再清)+ atexit 兜底,
成功/验签失败/清单非法/降级/解压失败/被中断全部删除暂存目录。
真机 time() 受 zig 0.17 mipsel time64 ABI 缺陷影响返回垃圾(实测 3381223399391169494、
localtime_r=NULL),故时间戳直取内核 o32 time32(syscall 4263)并自行换算 UTC,
不依赖 libc time()/localtime_r()。
upgrade 复用 install 同一实现(清单包名必须等于目标包名、目标必须已装)。
新增 host 回归 patch_v2/meowpkg/test_nyai.sh(49 断言:改名包/真实 0.1.7 反例/
footer≠清单/os.meow 无签名/第三方无签名/恶意包名/解压失败/SIGTERM/索引路径/upgrade)。
真机验证(固件 0.8.48,二进制只放 MeowOS/tmp,未覆盖 /usr/bin/nyai):
os.meow.reader-0.1.4.bak.mpk 现在「签名校验通过 (package=os.meow.reader)」后才被
降级门禁拒绝(旧版此处是包名不符);weird-name.bin 装成 dev.m35.probe;SIGTERM
中断后暂存目录为空;Music=199164544、/usr/bin/nyai md5 a7d24553… 均未变。
|
2026-11-10 21:42:37 +08:00 |
|
AskaEth
|
2881ce908a
|
feat(reader): M33 目录模式逐级下钻 — 子目录/书分层显示(416 本不再平铺)
- folder 模式从「按第一级目录分段」改为当前目录视图:子目录在前(带子树书数),
直接书在后;进入/返回只过滤已扫平的 g_books,不 readdir、不重扫(M32 索引不动)。
- 纯函数 shelf_build_rows_at(books,n,folder,cwd,...) + nav 工具(enter/up/breadcrumb/
count)全部宿主可测;format 模式行序列/副题逐字不变,path 仍是完整路径(进度键不变)。
- 交互:点目录进入;顶栏返回箭头/左缘返回手势回上一级,根层再返回退出 App;顶栏标题=
当前目录名(按像素宽截断),副题行=面包屑全路径+当前层书数;list/grid 均支持导航。
- 状态:folder↔format、list↔grid 切换保留 cwd;刷新重扫后 cwd 失效则收缩到有书的祖先。
- 边界:空目录不显示(导航只读 g_books,不额外 readdir);深层目录逐级进入;真实名为
「未分类」的目录按普通目录处理,不与根层书合并。
- 测试:shelf_group_smoke 63→99 断言;M27 的按第一级分组断言改写为「逐级进入后可见该书」
(同等强度),新增进入/返回/面包屑/计数/空目录/纯内存/rowcap/UTF-8 截断断言。
- 交付 0.1.7/code8(M32 已占用任务书里的 0.1.6/code7);真机 0.1.4 未被覆盖。
|
2026-11-10 19:26:44 +08:00 |
|
AskaEth
|
58f2d9bff4
|
perf(reader): M32 r2 书架索引改 level-1 校验 — 真机冷缓存首开 3.47s→0.13–0.16s(r1 全目录校验被真机证伪)
r1 用宿主 1.1µs/stat + M28 的**热** stat 150µs 外推「434 次≈65ms」,真机 drop_caches 后
实测是 3.15s(7.26ms/次),与 readdir 的 3.0s 同量级:全目录校验的索引命中冷启动仍要
3.06s,只比全扫快 0.2s。「3.0s→0.15s」在冷启动不成立。按任务 1 自己定的判据
(stat 接近 1s 就退回 level-1)改为只校验 Books 根 + 每个一级目录。
真机冷缓存实测(exFAT /usr/data/mnt/sd_0,434 目录/646 文件/595 本;sync + drop_caches;
探针走 /proc/uptime,UI 走 meow_ui_time_ms):
- 索引命中首开:**127 / 138 / 157ms**(复测 147ms),热 dentry 107–120ms;
- 全量扫描首开:**3428 / 3477ms**(复测 3711ms),热 dentry 不变(readdir 不吃 page cache);
- 探针冷分项:索引载入 20–30ms;载入+rdprog×595 70–120ms;4 个目录 stat 0–30ms;
- 从阅读页返回书架 29–31ms(M29 语义未变)。
→ 冷启动 22–26 倍提升,方案值得做;索引实测 **63,579B**(v2;r1 全目录 97,490B)。
实现(格式 v2,magic MEOWIDX2 / version 2):
- writer 回调过滤 rel 含 '/' 的目录:只落 root + 一级目录的 mtime;书/大小/格式记录仍全量;
level-2+ 不落盘、载入不 stat。载入仍然 0 次 opendir/readdir(strace:0 getdents64,
真实库 4 次 stat;宿主模拟库 11 次)。
- 校验记录里出现 level-2+ rel 视为坏档;sum(books_here) 改为「≤ nbooks」合理性上界。
- fail-open/原子写/CRC/安全加固/ts 不缓存全部保留(r1 已过评审的部分未动)。
失效矩阵(报文逐条写清):
自动(根 mtime):Books 根下直接增/删/改名书;一级目录新增/删除/改名。
自动(一级目录 mtime):一级目录里直接增/删/改名书、新建子目录。
必须刷新:level-2 及更深处的任何变化(只改深层目录 mtime)。刷新=删索引+全扫。
真机 exFAT mtime 实测 **1 秒**(tm_nsec=0;同秒连续增删 mtime 不变)。我复测 10 轮
「目录刚改过就扫描、同秒再改」→ 9/10 仍命中(陈旧),与评审 29/30 一致;sleep 跨秒后
全部正常失效。头注释已把「10ms」改为「1 秒」,并写明「不在同一秒刻度的变更靠索引失效,
同秒二次变更需刷新」。
bench 修复(P3-3):MEOW_BENCH_IDX=only —— **不预先 load/scan**,直接进书架量生产首开;
miss —— 先删索引再进书架。两者配合 drop_caches 即冷启动口径。旧行为(先 bench_index/
bench_scan 焐热)保留为默认模式。新增 test/shelf_index_probe_mipsel(write/scan/load/
loadts/statpaths/mtime/size)用于真机分项与 mtime 粒度验证,不进发行包。
测试:shelf_index_smoke 170 pass(新增:level-3/level-2 内变更「索引仍命中且先看到旧
列表 → 刷新后可见」、新建 level-2 目录自动失效、一级目录直接删书自动失效、v2 ndirs=
根+一级数);ASan+UBSan 干净;build_reader.sh 0 warning,core 6846 / seg 19 / chapter 71 /
shelf_group 63 / index 170 / font 14 / loaders PASS。真机 6 场景逐项验证:一级直接增/
新建子目录/一级改名/根下删书/一级直接删书 = 自动失效;level-3 深处新增 = 仍命中(需刷新)。
交付:app.json 0.1.5/code6 → **0.1.6/code7**;reader md5 5c848c99… 1,711,988B;
mpk md5 10d676f5… 814,574B;未签名不 push。设备验证后已清理 /tmp 与 m32probe,
真实 MeowData 的 shelf.idx 已删(app 自己的章节 .idx 未动),Books 434/646 不变,
已装 0.1.4 md5 4036b889… 未变。
|
2026-11-10 18:49:48 +08:00 |
|
AskaEth
|
e0dfab95c3
|
perf(reader): M32 书架索引落盘 — 冷启动只 stat 434 个目录 mtime,跳过 readdir(3.0s→~0.15s)
M29 只解决了「回书架不重扫」;首次进书架仍要全量扫 434 目录(真机 3.0–3.4s,
其中 opendir+readdir 占 96%)。本单把扫描结果 + 每个扫描目录的 mtime 存到
MeowData/os.meow.reader/index/shelf.idx,冷启动逐目录 stat 比对 mtime,命中即
完全跳过 readdir;任何异常一律 fail-open 全量重扫。
先量再选(任务 1):宿主 434 目录/595 本/51 rar 虚拟库(贴真机量级)
- 434 次目录 stat = 0.48ms/pass(1.1µs/次,不含 readdir);
- 读 72KB 索引 = 0.009ms;全量扫描 3.54ms;索引命中 1.29ms(ts_fn=NULL)。
真机按 M28 实测 1079 次 stat=160–170ms(≈150µs/次)外推:434 次 ≈ 65ms,
远低于「可能不可行」的 1s 阈值 → 选「校验全部扫描目录 mtime」(非只 level-1)。
strace 断言:indexonly 载入 0 次 getdents64、恰好 434 次 stat(真的没 readdir)。
生产路径 ≈ 65ms(stat) + <20ms(索引读) + 40–50ms(rdprog×595) + <20ms(build_rows)
≈ 0.13–0.15s(对比 3.0s)。
索引格式 v1(手工小端序列化,不依赖结构体布局):
header(magic/version/header_size/root_len) + root + dir 记录×(rel,mtime_s,
mtime_ns,books_here) + book 记录×(rel,size,fmt) + trailer(ndirs,nbooks,flags,
depth_skipped,crc32,magic)。truncated/depth_skipped 存在 flags/字段里,载入时
如实重建提示条;**不存阅读进度 ts**,载入后每本由 rdprog_load 现读再排序。
失效语义(存每个扫描过的目录,不只 level-1):
- level-2 新增 / level-3 深处新增 / 删书 → 该目录 mtime 变 → 重扫;
- 一级目录改名 → 父目录 mtime 变 + 旧目录 stat ENOENT → 重扫;
- 超深(>6 层)未扫描子树不在索引内,其内部变化不自动失效(本来就不显示),
点「刷新」更新 depth_skipped 计数;mtime 精度受限(exFAT 10ms/FAT32 2s)的
同刻度变更也可能漏判,点「刷新」必可纠正。
M29 语义不变:首次进书架=索引或全扫;回书架=不扫;刷新=删索引+全扫(之后原子
写回新索引)。
安全/健壮(宁可慢不可错):
- 写:shelf.idx.tmp 全量写完(尽力 fsync)后 rename;中途被杀只剩 tmp,正式索引
要么旧要么完整新;rename 覆盖失败先删旧再改名;fflush/写错即放弃,绝不影响书架。
- 读:O_NOFOLLOW|O_NONBLOCK + S_ISREG(FIFO/符号链接直接拒绝不阻塞);CRC32 覆盖
全部记录;rel 做绝对路径/“..”/内嵌 NUL/长度校验;版本/根路径/计数/逐目录 mtime
任一不符即重扫;载入崩溃路径全部 goto 清理,不改书架可用性。
- writer_open 失败(卡满/写保护/无 MeowData)→ 扫描不采集目录、照常出书;
commit 失败(含只读目录 rename 失败)不留正式索引。
测试:test/shelf_index_smoke 154 pass(含四种变更场景失效、截断/字节翻转/垃圾/
缺失/FIFO/符号链接/版本不符/根路径不符、ts 现读、truncated/depth_skipped 重建、
只读目录写失败、空 Books、root 缺失、.tmp 残渣),ASan+UBSan 干净;
test/shelf_index_bench 模拟 434 目录/595 本/51 rar:scan/load 均 595 本、
truncated=0/depth_skipped=0、索引 72,156B。build_reader.sh 全绿 0 warning
(core 6846 / seg 19 / chapter 71 / shelf_group 63 / index 154 / font 14 /
loaders PASS)。shelf_bench_ondev 增加 index_load/scan_save 计时与
MEOW_BENCH_IDX=miss(真机首开命中 vs 未命中对比,待有卡复核)。
交付:app.json 0.1.4/code5 → 0.1.5/code6;reader md5 df4cadcf
1,711,924B;mpk md5 fec7b1bb 814,535B;未签名不推卡。
|
2026-11-10 18:14:52 +08:00 |
|
AskaEth
|
dc9bfdbdaf
|
perf(reader): M31 字体路径记忆化(开书字体查找 35 目录 walk → 1 次 stat)+ 「· 读」徽标即时刷新
字体:find_font_rec/resolve_font 从 reader.c 抽到 app/font_resolve.c 并加进程内记忆化。
只缓存成功路径;命中后仍做一次 access() 校验(字库被删即重扫);没找到不缓存,
用户之后拷入的字库下次开书即可找到。顶栏「刷新」额外调 font_cache_invalidate(),
给「新拷入字库、旧字库仍在」一条显式失效路径。宿主实测:35 目录树 walk 0.026~0.54ms
(=300+ 次系统调用)vs 命中 0.001ms(1 次 access);开书路径每次省一次完整 walk。
徽标:副题格式化抽成 shelf_fmt_sub()(扫描与「刚读完置顶」共用一份实现),
promote_just_read() 改 ts 后立即重算这本的 sub/sub_folder,「· 读」不再等下次全量刷新。
回归:test_reader_core 6846、shelf_group_smoke 63(+8)、font_resolve_smoke 14 全绿;
build_reader.sh 0 warning;扫描缓存/进度语义未改。app.json 0.1.3/code4 → 0.1.4/code5。
|
2026-11-10 13:39:32 +08:00 |
|
AskaEth
|
a9638fa59c
|
perf(reader): M30 删掉无人消费的下一页预取槽(refill 渲染减半、常驻 −0.69MB)+ 回书架置顶刚读完的书
|
2026-11-10 13:22:35 +08:00 |
|
AskaEth
|
bece9848e7
|
perf(reader): M29 书架扫描缓存 + 行数多时关圆角容器(回书架 3.4s→0.03s,滚动 52ms→19ms)
真机(0.8.48 / reader 0.1.1 基线,同机同字库 ztest 实测):
- 从阅读页返回书架:3435ms(3259–3531)→ 33ms(24–54)。根因是 shelf_on_enter 无条件
scan_books():exFAT 全量扫描 434 目录 = 3.1s。改为进程内缓存(首次进入才扫,顶栏
「刷新」强制重扫);truncated/depth_skipped 提示语义不变(首次扫描时算好并保留)。
行为变化:新进 Books/ 的书、刚读完那本书的「最近阅读置顶」需点一次「刷新」才更新。
- 书架滑动每步(62px,含 widget_draw + flush):51.9–56.2ms → 19.3–19.9ms。
行数 > 200 时 meow_listview_set_container(0)(扁平行),≤200 行仍用 MD3 圆角卡;
圆角卡走 meow_gfx_fill_round 逐像素 rr_inside(464×54 一张 3.8–6.4ms ×11 行)。
- 首次进书架仍需扫一次(3497ms,含 3157ms 扫描);595 本全可见、format/folder 分组不变。
另加 test/shelf_bench_ondev.c(真机耗时基准,不进 mpk)与 build_reader.sh 的编译步骤;
app.json 0.1.1/2 → 0.1.2/3。未做(按塔砍范围):字体路径记忆化、首屏只渲染当前页、
自绘行、mtime 失效检测。
|
2026-11-10 12:54:17 +08:00 |
|
AskaEth
|
e0a82a3d47
|
fix(reader): M27 r3 评审整改 — cap 边界截断/默认副题不变/提示两行且 6s 消失/版本号
对应评审 P2-1、P3-7、P3-1、P3-2、P3-10、P3-9:
- P2-1:scan_dir 在目录边界遇 cap 时探测子树(count_books_under)再置 truncated;
同目录内超限逻辑不变。新增两条断言:cap 卡边界 → truncated=1;恰好装满且后续为空目录 → 不误报
- P3-7:shelf_book 拆 sub(默认副题,与 base 逐字一致)/sub_folder(folder 模式前置子路径);
list 按模式选,宫格始终用 base;断言 format 副题逐字等于 base
- P3-1:超量+超深合并提示拆两行绘制(610 起,不再被 480px 右缘切掉)
- P3-2:提示 6s 到期自动消失(app.c 书架前台时调 shelf_on_tick)
- P3-10:app.json version 0.1.1 / version_code 2
- P3-9:shelf_scan_bench.c 头部注明 /proc/uptime 10ms 分辨率、只适合真机
|
2026-11-09 22:45:01 +08:00 |
|
AskaEth
|
63ead3ec1e
|
fix(reader): M27 r2 — 扫描深度提到 6 + 按 Books 第一级目录分组
真机真实布局暴露两处问题(评审 P1):
- Books/400+本高质量完本合集/<分类>/<作品>/<书名>.txt 在 depth 3-4,旧 depth≤2 让 413 本 3.8GB 不可见
→ SHELF_SCAN_MAX_DEPTH=2→6;report 新增 depth_skipped,超深书籍文件计数并在 g_notice 可见提示
(有 N 个文件因目录层数超过 6 层未显示),不再静默
- 按完整相对路径分组会把 413 本书炸成 410 个每条 1 书的段头
→ 分组键改为 Books/ 第一级目录(shelf_book.top);完整相对路径仍在 group[],
第一级之后的子路径(分类/作品)放进副题 sub(如 01、玄幻/01、斗破 · TXT · 2.1MB)
→ 真机书库只剩 3 组:400+本高质量完本合集 / kh / 轻小说
- 单测 50 断言:depth3/4 收录、depth7 计入 depth_skipped、四种真实路径的组名、
a/b 与 a/c 同组 a、副题含子路径、format 回归、根组未分类、path/进度不变
|
2026-11-09 22:29:46 +08:00 |
|
AskaEth
|
409fd1edf7
|
feat(reader): M27 书架按目录分组(ui.shelf_group=folder|format,默认 format 不变)
- 新增 shelf_model.c/.h:扫描/行序列从 shelf.c 拆出(纯 C,宿主可测);shelf_book 加 group[96](相对 Books/ 的目录路径,根下空串),path 语义/内容完全不变(进度键仍为 rdprog_hash(path))
- folder 模式:目录段头(根下=未分类),未分类置顶、其余按目录名排序;组内沿用最近阅读优先/其次书名;空目录不产生段头
- format 模式逐行保持旧行为;新增 reader.conf ui.shelf_group,缺键默认 format
- 上限 256→2048(SHELF_MAX_ROWS=2N=4096,段头≤书数),超限置可读提示,不再静默截断
- 顶栏加「目录/格式」切换,设置页加「书架分组」;UTF-8 安全截断长中文目录名
- 单测 test/shelf_group_smoke.c(38 断言)+ 计时 test/shelf_scan_bench.c
- build_reader.sh:链 meow_ui.a 解析冒烟 stbi_*;无 qemu 时跳过执行而非失败
|
2026-11-09 21:55:33 +08:00 |
|
AskaEth
|
281f4153ee
|
fix(sdk): M26 r1 P1 — ILP32 尺寸算术溢出(畸形 BMP 经公开入口 SIGSEGV)+ 加 S17 回归
评审在 ARM32(ILP32,与 mipsel 同数据模型)实测:54 字节 BMP 头声明 w=2^27、bpp=32
时 w*bpp 回绕成 0 → rowsize=0 → malloc(0) → 采样索引 row+sx*4 越界读 → SIGSEGV,
经 meow_img_load_file_dim 端到端可触发;同一文件在 LP64 宿主返回 NULL(不溢出),
合并前走 stb 也是 NULL。即这是相对旧路径的鲁棒性回归。
修复(只加闸,正常路径数值不变):
- meow_png_stream.c(P1 本体)
· 新增 ILP32 守卫 MZP_MAX_DIM=1<<20 与 mzp_bytes_ok()(unsigned long long 验算,
超过 SIZE_MAX 即拒)
· BMP:声明尺寸先升 int/long long 校验(w/h 单边 ≤1<<20;h=INT_MIN 用
-(long long)hi 取绝对值,不再有 -h 溢出);rowsize 用 64 位算并验;
行偏移 off / 采样下标 sx 改 long long,sx 夹在 [0,w-1];按行 fseek 前加
off > LONG_MAX 拒绝;目标 RGBA 字节数 64 位验后再 malloc
· PNG:IHDR 尺寸原已 ≤65535,补上 tw*th*4 的 64 位校验(32768²×4 = 2^32 会回绕),
emit_row 的 sy/sx 与输出行偏移改 64 位并夹紧
- meow_jpeg.c(顺手审计同类 32 位算术,评审要求「不要只修点名那处」)
· mj_layout 返回 unsigned long long(单平面/三平面之和都可能越 2^32),
越界返回 MJ_LAYOUT_BAD → mj_sof 各处重新布局后都检查
· target_bytes 与分量 plane malloc 改 64 位验算;目标图字节超 MJ_PEAK_CAP 直接拒
· mj_output:输出缓冲 64 位验;y*vh / x*vw 采样改 long long 并夹紧
· meow_img_target_dims / mj_pick_n 的 (long)h*maxdim、8*maxdim 改 long long
- test_meow_img_stream.c:新增 S17(10 组畸形 BMP 声明尺寸 + 2 个合法正例 +
PNG 回绕点),断言「后端拒绝 + 公开入口不崩(越界尺寸另断言 NULL 且不分配)」;
文件头补 ILP32 交叉编译命令(宿主 LP64 看不到 32 位回绕,测试注释里明写这一点)
验证:同一测试在 zig arm-linux-musleabi(sizeof(long)=4)下 S1-S17 全绿(206 checks,
exit 0);把后端换回 r1 提交的旧实现,同一 ARM32 二进制 exit 139(说明 S17 真能抓);
宿主 LP64 S1-S17 全绿、B1-B9 全绿;静态库 --verify 仍 78 成员 / 全 MIPS32r2。
同步提醒:这些行与公开仓 ~/Proj/MeowOS-SDK/sdk/{meow_png_stream.c,meow_jpeg.c} 逐字节
同源,同一补丁必须由控制塔同步过去,否则立刻产生双边漂移。
|
2026-11-06 21:27:03 +08:00 |
|
AskaEth
|
ee5796747d
|
feat(sdk): M26 公开仓真缩解图像栈并入主仓 — JPEG DCT/PNG 逐行/BMP 跳行后端 + RGB565 页图
主仓 SDK 的图片层原本是 220 行 stb 直通(整幅解码后重采样)。公开仓 MeowOS-SDK
的同一子系统已被真实 App(tuku 阅读器)驱动并做过峰值实测与像素比对,故以公开仓
为权威方向并入主仓 meow_ui.a,两个方向的新功能都保留(逐文件 diff 确认公开仓是
严格超集:无一处「双方互有增减」)。
- 新增 meow_jpeg.c / meow_jpeg.h:DCT 域缩解 1/8、1/4、1/2(N=1/2/4 点 IDCT),
渐进式只解到首个精细化扫描;不支持项(CMYK/YCCK、算术编码、过订阅 DHT、16bit
量化表)返回 0 由调用方回退 stb
- 新增 meow_png_stream.c:libz 逐行 inflate + 反滤波,按步长丢行丢列直写目标尺寸;
BMP 按目标行 seek + 行内跳列(8/16/24/32bpp)
- meow_ui_img.c + include/meow_ui_image.h:新增 meow_img_pick_scale /
load_file_step / load_file_step_ex / resample 四个公开入口;_dim 与 _mem_dim
先进后端,失败/不支持才回退 stb(对外语义不变)
- include/meow_ui_draw.h + meow_ui_gfx.c:M32 RGB565 页图 5 函数
(meow_gfx_rgb565 / rgba_to_rgb565 / blit_rgb565 / _scaled)。gfx 保留主仓的
`#include "../meow_launcherd/meow_font.h"` 与 <time.h>(公开仓自 vendored
meow_font.h 且无 <time.h>,机械覆盖会丢这两行)
- meow_jpeg.h 保持内部:不进 meow_ui.h 伞头,include/ 下无任何头暴露 meow_jpeg_*
- build_sdk.sh:OBJS 插入 meow_jpeg / meow_png_stream(32→34);成员数
76→78(+meow_font.o +43 freetype),--verify 全为 ELF32 MIPS32 rel2/o32
- 测试:新增 test_meow_img_stream.c(S1-S16),test_meow_img_budget.c 同步公开仓
版(B9 断言收紧为 p_new <= p_old);22 个既有宿主测试的编译注释行补
meow_jpeg.c / meow_png_stream.c / -lz(meow_ui_img.c 现引用后端符号,不加即
undefined reference)
宿主实测:S1-S16 全绿(S7 与 stb 网格像素一致:JPEG mad 4.35-13.69、PNG/BMP
mad 0.00;S9 回退矩阵 CMYK/1bpp BMP/Adam7 均拒绝且 stb 仍成功),B1-B9 全绿
(B9 PNG 峰值 25.65→0.61 MiB、BMP 14.65→0.59 MiB)。回归 test_meow_ui_widgets /
scroll / ime_fix / test_umbrella 全过。zlib 在应用链接期解析:meow_ui.a 只留
inflate* 未定义符号,四个 App 构建脚本原本就带 $SYSROOT/lib/libz.a,静态
linkcheck(meow_ui.a + libz.a -lpthread)通过。
注:主仓 patch_v2/reader_app 仍自带 vendored stb、不用 meow_img_*,本单不改变
阅读器的内存占用;RGB565 页图接入 reader_app 是另一个任务。
|
2026-11-06 20:44:22 +08:00 |
|
AskaEth
|
1f692ae2a7
|
fix(ntp): M22 r1 评审 P2×3 — 孤儿 ntpd 收尸 / 日志失败不吞 hwclock / 锁自证
r1 评审 verdict=p2-3items,三条均已按评审给的修法修掉,且都补了可证伪的回归断言。
P2-1 SIGTERM 后遗留孤儿 ntpd,之后每次静默 skip 且 rc=0
- attempt() 把子进程记进全局 NTPD_CHILD 并落盘 <锁目录>/ntpd.pid;
新增 cleanup()(EXIT trap)先收尸子进程再释放锁;新增 on_signal()
(INT/TERM/HUP)清理后 exit 143——旧代码的 TERM trap 只清锁、不 exit,
被杀后还会继续跑完看门狗。
- 取代原来的 "pidof ntpd 就 skip":新增 reap_or_skip_ntpd(),用
/proc/<pid>/cmdline 是否含本锁目录来区分「我们自己遗留的孤儿」(收尸)
与「别人的常驻 ntpd」(让路)。崩溃后留下的 ntpd.pid 也据此校验,
pid 被复用时不会误判成外部 daemon(不会永久 skip)。
- S45 stop 不再按陈旧 pid 文件盲杀:只从 <锁目录>/<pid> 取持有者,
再核对 /proc/<pid>/cmdline 含 meow_ntpsync 才 kill。
P2-2 日志重定向失败导致 hwclock 根本不执行
- persist_rtc 改 ">/dev/null 2>>$LOG_FILE":hwclock 的 rc 与日志写入解耦。
- 新增 prepare_log():启动时在子 shell 里试写日志,不可写就整体退化 /dev/null。
必须用子 shell——`:` 是 POSIX 特殊内建,它的重定向失败会让 dash 直接
退出整个脚本(本单自测先踩到了,rc=2)。
P2-3 锁 mkdir→写 pid 有窗口,并发抑制非原子
- 锁的持有者改由 <锁目录>/<pid> 子目录自证(mkdir 原子),不再写 pid 文件;
读到空锁时给 3s 宽限而不是立刻判死。
- 清失效锁改用 mv 到 <锁目录>.stale.$$(rename 原子),并发清锁时只有
一个能成功,避免「抢锁失败方删掉胜方的锁」。
- 退出只删自己的锁:没有自己的 <pid> 子目录就不动锁目录。
验证
- 新增回归断言 11-16(run_tests.sh):SIGTERM 收尸/锁释放、遗留孤儿收尸、
日志不可写仍写 RTC、锁被占用不抢、死锁可接管、pid 复用不阻断。
- 可证伪性:新套件跑旧代码(c9f0cba 的 meow_ntpsync)→ 6 条 FAIL
(孤儿 alive、日志不可写 rc=1 且 hwclock 未执行、抢锁并发调 ntpd×3)。
再跑「仅回退 STALE_NTPD 硬化」的变体 → pid 复用那条 FAIL
(rc=0 但 RTC 未写,正是评审指出的静默失效)。
- dash 与 busybox ash 各 41/41 PASS,rc=0;dash -n / busybox sh -n 均 0 错。
- 时间断言放宽为负载容忍(宿主是多 agent 共享机,实测 sleep 5 能跑成 85s),
假 ntpd 改为挂 3600s,保证上界仍能证明是看门狗掐断而非自然退出。
fw_content.conf: meow_ntpsync md5 ad324e3f→f3c3abe4,
S45meow_ntpsync md5 25454a3f→115e7592(50meow_ntpsync 未改,md5 不变)。
|
2026-11-06 13:34:45 +08:00 |
|
AskaEth
|
c9f0cbaab6
|
feat(ntp): M22 网络校时 — 复用固件自带 ntpd + hwclock 回写 RTC
真机实测(0.8.47,2026-11-06)定位到的根因不是「没有 NTP 客户端」:
固件自带 ntp-4.2.8p14(/usr/sbin/ntpd)和 /etc/ntp.conf(4 个 pool.ntp.org),
但没有任何 init 脚本/进程启动它 —— 有客户端、没启动。
实测证据:
- RTC 存在且可读(/dev/rtc0,10003000.rtc),内核开机 hctosys=1,
冷启动不回到 1970 → 掉电保持;RTC 存 UTC(since_epoch == date +%s)。
- 但 RTC 会走慢且无人纠正:实测系统时间比 NTP 慢 49 s;把系统时间人为
拨错 4 h 后观察 65 s 无人纠正,RTC 也不跟随系统时间。
- UDP/123 出网正常(ntpd -q 一次成功 time set +48.877s);DNS/HTTP 正常。
- udhcpc 的 default.script 不处理 option 42,实测热点也不下发。
- ntpd -q 不会回写 RTC(步进后 sys-rtc 仍差 49 s)→ 必须 hwclock -w -u。
- ntpd 没有超时参数,无服务器时永久存活 → 必须自带看门狗。
- -p 形式的 server 首个 poll 要 ~64 s;配置里加 iburst 后 8 s 内返回。
实现(新增,不改任何基线文件):
- /usr/bin/meow_ntpsync:一次性校时器。复用 ntpd -q -g + 运行时生成的
iburst 配置;内置 IP 兜底(阿里/腾讯/Cloudflare)→ DNS 名兜底;
单次 15 s 看门狗、默认路由轮询、1 h 短路、进程锁、失败静默。
成功严格校时后 hwclock -w -u 回写 RTC(RTC 存 UTC,必须 -u)。
- /etc/init.d/S45meow_ntpsync:开机只 setsid 后台拉起并立即返回
(关键路径 +0 秒;后台最长约 150 s 自行退出),失败不阻断 init。
- /usr/share/udhcpc/default.script.d/50meow_ntpsync:只在 bound/renew
触发(设备上唯一可靠的「网络就绪」事件),后台拉起后立即 exit 0;
有 $ntpsrv(option 42)就优先用。基线 default.script 本就有 HOOK_DIR
循环,目录原本为空。
- tests/run_tests.sh:宿主沙箱单测(假 ntpd/hwclock/网络探测)。
验证:dash 与 busybox sh 各 sh -n 通过;单测两套 shell 各 23/23 通过;
真机(/tmp 下运行,未装系统目录)首跑 8 s rc=0、ntpd slew 成功、
RTC 由 1793940395 写成 1793940452(49 s 偏差被纠正)、hwclock -u -r 吻合;
二次运行 0 s 短路;-b -t 3 无网络 5 s 退出 rc=1;
DHCP 灌入不可达服务器 192.0.2.x 仍靠 IP 兜底在 ~10 s 内成功。
|
2026-11-06 12:49:13 +08:00 |
|
AskaEth
|
f9c2ea42a4
|
fix(boot): M21 r1 评审 P1 — bl_cap 把 cur=0 当「无有效值」照写 20(+P2 两处)
P1 根因(评审给的真机驱动证据链,已按其最小修法改):
/module_driver/pwm_backlight.sh 是 `insmod pwm_backlight.ko ... default_brightness=0
max_brightness=101`,模块 init 把 props.brightness 置 0 再 update_status(PWM 0 分支)→ 上电即灭屏;
该模块由 S11module_driver_default 加载,rcS 自然序排在 S11jpeg_display_shell 之后。于是:
- 函数入口那次 bl_cap:背光节点还不存在,写必然失败(no-op);
- fb0 出现后画图前那次 bl_cap:读到 cur=0,旧条件 `cur <= cap` 命中「只降不升」跳过分支,
20 从未写入 → 画图时刻亮度 0。
物理后果两头都是缺陷:面板仍亮则 logo 依旧亮(原问题没修);面板灭则 S11~S21 无可见 logo,
settings.conf 缺失时直到 launcherd 才亮屏(相对 stock「0.1s 后写 60」是回归)。
修改:
- bl_cap 判定改为「仅 1 <= cur <= cap 才视为已有有效值跳过;0 / 空 / 非数字一律照写」。
S22 抢写 1 的竞态保护不变(1 落在 1..20 → 仍跳过,不会被顶回 20)。
- 删掉函数入口那次 bl_cap(节点未建,必然 no-op,且是重定向报错的来源);只保留 fb0 就绪后、
画 logo 前那一次 —— 同一驱动脚本里 pwm_backlight.ko 先于 soc_fb.ko 加载,fb0 出现即节点就绪。
- 写入成功时打一行 `backlight: -> 20 (was N)` 便于刷机后复核;`2>/dev/null` 移到 `>` 之前,
节点未就绪时连重定向报错一起吞掉(P2-1)。
- S22:失败路径日志由「保持 S11 低亮度」改为「不改背光(当前 brightness=N)」(P2-2);写入失败
日志同样附当前读数;写入处的 2>/dev/null 次序一并改正。
- 头部注释按时序真相重写(驱动默认 0 = 灭屏,不是「上电很亮」)。
实测(沙箱重写 sysfs 路径 + stub cmd_jpeg_display/nanddump/sleep,dash 与 busybox 各一遍):
cur=0 → 画图时刻 20、结束 20(修复前 0/0);cur=1 → 1/1;cur=60、cur=101 → 20/20;
竞态(fb0 就绪前外部写 1)→ 画图时刻 1、结束 1(未被顶回);节点不可写时 stderr 0 行、仍画图、rc=0。
S22 19 用例全 rc=0(仅 usage rc=1,rcS 不可达)、sleep 调用 0、行为与改文案前一致。
S11 与 S22 内容均变 → fw_content.conf 两条 md5 同步更新为
3ad33301fb9f0884102a47e17a1985ed / 1a0aa33d6f806f3f1648168cc1d8b953
(未改动 meow_watchdog 那条:main tip dfde95b 仍是 553840cd,与本单无关,已在报告中提示。)
|
2026-11-05 22:04:16 +08:00 |
|
AskaEth
|
0ab23161b6
|
fix(boot): M21 开机 logo 亮度 — S11 画前压到 <=20 + 新增 S22brightness 按用户设置恢复
冷启动 logo 很亮:stock S11 是画完 logo 之后才写死 60,画图那一刻用的是面板上电默认高亮;
而 S11 早于 S21mount_ubifs,那时 /usr/data 未挂载、读不到 settings.conf,只能写死一个值。
- S11jpeg_display_shell:以基线(249220f2)为底,把背光压制挪到画 logo 之前(jpeg_display
函数体内、先于 cmd_jpeg_display),值 20(只降不升:S22 已写更暗则不覆盖);删除画完后
写死 60 的那行;/dev/fb0 等待、mtd5 主题判定、后台 jpeg_display & 语义不变;
主题判定 `==` 改 `=`(POSIX test,语义不变,便于宿主验证)。
- S22brightness(新):S21mount_ubifs 之后运行,读 /usr/data/meow/settings.conf 的
display.brightness,按 display.brightness_min 与 sysfs max_brightness clamp 后写入;
读不到/解析失败不改背光(保持 S11 低值)、无 sleep/重试、任何运行期失败 exit 0;幂等。
- scripts/build/fw_content.conf:登记两条(S11 覆盖基线同名文件、S22 新增),md5 实算,
说明列写清 S11 < S21mount_ubifs < S22 的顺序依赖。
- scripts/build/README.md:补「覆盖基线已有文件」语义(无条件 cp -f,不校验基线 md5、
也不跳过已存在文件;唯一基线校验仍是 hiby_player)。
固件需整包刷机才生效,未刷机、未写设备。
|
2026-11-05 22:04:16 +08:00 |
|
AskaEth
|
f2551a28a2
|
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 的强校验失败。
|
2026-11-05 21:32:27 +08:00 |
|
AskaEth
|
bcb11e012f
|
fix(reader): stb_image 实现改由 meow_ui.a 提供,修 M6.45 收编后的重复定义
SDK 在 M6.45 收编 stb_image.c.o 进 meow_ui.a 后,reader 的 engine/rdimg.c 仍带
-DSTB_IMAGE_IMPLEMENTATION,链接期 stbi_* 与归档内 stb_image.o 重复定义,reader
无法重链。改为只编封装、实现取自归档;rdimg.c 用到的 stbi_info_from_memory /
stbi_load_from_memory 在归档中均已导出。
|
2026-11-05 21:12:42 +08:00 |
|
AskaEth
|
62b3603ade
|
merge(sdk): 回补 M19 滚动池槽泄漏修复(wrap 上下文归还 + 44 断言回归)
|
2026-11-05 21:00:22 +08:00 |
|
AskaEth
|
72c6e9889d
|
fix(sdk): 从公开仓回补 M19 滚动池修复(free 归还 wrap 槽)+ 宿主回归
meow_scroll_wrap 从 MEOW_SCROLL_POOL(=8) 个 wrap 上下文槽占一个,meow_scroll_free
只归还会话槽、从不归还 wrap 槽也不清 ctx.w → 进程内最多成功 wrap 8 次,之后恒 NULL。
主仓此前仍是有缺陷版本;本提交把公开 SDK 仓 c85877b 的修复按内容移植到主仓(唯一权威
源),meow_ui_scroll.c 结果与公开仓 sdk/meow_ui_scroll.c 逐字节一致,diff 仅 wrap 相关
hunk(之前两文件差异也只有这些 hunk,故无其它改动被覆盖)。
- meow_scroll 结构记 wrap_slot(create 置 -1),wrap 时写槽下标;free 按该下标清
g_wrap_ctx[].w/lv 并归还 g_wrap_used,随后置 -1(二次 free 不触碰任何槽)。
直接 create 的实例 wrap_slot=-1,free 不误清别人的槽。池满语义不变:8 个同时活跃时
第 9 个 wrap 仍返回 NULL;free(NULL) 安全。
- test_meow_ui_scroll 断言 17 → 44:64 次 wrap/free(修复前 8/64、修复后 64/64)、
free 后再 wrap、8 满 + 第 9 个 NULL + 释放其一即复用、交错 free 不串槽、直接 create
不误清槽、list→listview→list 槽复用不残留 kind、free(NULL)/二次 free。
头注释补 meow_ui_nav.c:原配方缺该 TU,链接期 meow_ui_nav_request_exit 未定义。
验证:LAUNCHER_DIR=主检出/patch_v2/meow_launcherd build_sdk_host.sh --verify
exit=0、0 warning/error、成员清单 76 项一致且全 MIPS32r2;宿主测试 44 pass / 0 fail;
同测试对修复前 meow_ui_scroll.c 为 13 pass / 19 fail(首条即 ok=8 first_fail=8)。
meow_ui.a 中 meow_ui_scroll.o 已变化,链 meow_ui.a 的 App 需重链。
|
2026-11-05 20:59:36 +08:00 |
|
AskaEth
|
9600f10352
|
fix(hello): demo 左滑列表行高按字体行高派生 — 首行标题不再丢失(M17)
根因(承接 M12/M15 finding):SDK meow_listview 双行 renderer 把
block = 2*meow_ui_text_height(font_body) + MEOW_LISTV_SUB_GAP(2) 在行内垂直居中
(ty = 行顶 + (item - block)/2),标题只在 ty >= 视口顶时才画。demo 的 swipe 列表
显式 set_item_renderer(2,1,0)(双行档位)却 set_item_h(48):真机 source_han_serif
20px 行高 30 → block 62 → ty = 行顶 - 7,首行「notif 0」标题被裁剪守卫整条跳过,
只剩 swipe left 副标题。
修复:
- hello_internal.h:新增 HELLO_ROW_H_MIN(56) / HELLO_ROW_SUB_GAP(2,与 SDK
MEOW_LISTV_SUB_GAP 同口径) + hello_row_h_for_line_h(line_h)
= max(56, 2*line_h + 2) + hello_row_h()(取当前主题 font_body 的
meow_ui_text_height)。本地派生,不依赖 M15 新增导出 meow_listview_item_h;
显式传值在 M15 之前的 SDK(默认 48/56 档位)与 M15 之后(默认已派生 62)都成立且一致。
- ui/demo/sdk2/sdk2.c:set_item_h(48) 改传 hello_row_h()(行高 30 → 62)。
列表视口 LV_H / 三节布局推进量不变(行高只影响行内几何与滚动量),其它 demo 区块
(LazyColumn 列表、宫格、选择器)不受影响。
验证(宿主,未碰真机):
- zig-mipsel-cc -Os -static -Wall -Wextra(另用 -Werror 复验)交叉编译 hello:0 warning;
- 新宿主 test/test_row_text_fit.c(32 断言,纯头文件派生、不链 SDK):
字库行高矩阵 14/21/26/27/30 下 block <= item、首行 ty >= 0;行高 30 → 62;
旧 48 → ty=-7 的 bug 形态哨兵;全 PASS。
影响:meow_ui.a 未改 → 无需重编 SDK;本 App 需重链重部署(热更 hello 二进制)。
|
2026-11-05 20:57:13 +08:00 |
|
AskaEth
|
e69b8efeeb
|
fix(files): 目录列表行高按字体行高派生 — 20px 字库下首行标题不再空白(M17)
根因(承接 M12/M15 finding):SDK meow_listview 双行 renderer 把
block = 2*meow_ui_text_height(font_body) + MEOW_LISTV_SUB_GAP(2) 在行内垂直居中
(ty = 行顶 + (item - block)/2),标题只在 ty >= 视口顶时才画。目录行是双行档位,
真机 source_han_serif 20px(ascent 24 + descent 6)行高 30 → block 62,而
browser_page_create 显式 set_item_h(56) → ty = 行顶 - 3:首行(行顶 == 视口顶)
标题被裁剪守卫整条跳过,只剩大小/时间副标题。
修复:
- files_internal.h:APP_ROW_H 降级为行高下限(56);新增 FILES_ROW_SUB_GAP(2,与
SDK MEOW_LISTV_SUB_GAP 同口径) + files_row_h_for_line_h(line_h)
= max(56, 2*line_h + 2) + files_row_h()(取当前主题 meow_theme_get()->font_body
的 meow_ui_text_height)。本地派生,不依赖 M15 新增导出 meow_listview_item_h;
显式传值在 M15 之前的 SDK(默认 56)与 M15 之后(默认已派生 62)都成立且一致。
- ui/browser.c:browser_page_create 的 set_item_h 改传 files_row_h()
(行高 30 → 62)。SDK 的 draw/hit/max_scroll 全部按这一个值换算,滚动/命中天然
同步;页脚几何(r_list 单独扣 APP_FOOTER_H)与行高无关。其它几何/交互不变。
验证(宿主,未碰真机):
- zig-mipsel-cc -Os -static -Wall -Wextra(另用 -Werror 复验)交叉编译 files:0 warning;
- 新宿主 test/test_row_text_fit.c(32 断言,纯头文件派生、不链 SDK):
字库行高矩阵 14/21/26/27/30 下 block <= item、首行 ty >= 0;行高 30 → 62;
旧 56 → ty=-3 的 bug 形态哨兵;全 PASS。
影响:meow_ui.a 未改 → 无需重编 SDK;本 App 需重链重部署(热更 files 二进制)。
|
2026-11-05 20:57:13 +08:00 |
|
AskaEth
|
a7bd6c44d9
|
fix(sdk): 评审 p2 修正 — 负 nsec 判 EINVAL / 音频条件等待计数改 5 处
- meow_ui_time.c `__timedwait_cp`:`at->tv_nsec` 是有符号 long,原写法
`>= 1000000000L` 会让负 nsec 通过(musl 原文用 `>= 1000000000UL`,负值按无符号
比较同样判 EINVAL)。改为 `< 0 || >= 1000000000L`,与本文件 M11 的
`__clock_nanosleep` 写法一致;同时避开 `-Wsign-compare`(UL 写法在 -Wextra 下
会告警)。反汇编确认 llvm 合并成一条 `sltu`,与 musl 的 unsigned 比较等价。
- CLOCK_ABI.md:meow_ui_audio.c 的 pthread_cond_timedwait 调用点由「3 处」改为
5 处(:312/:351/:417/:431/:499),§5/§6 两处同步;核对文中其它计数(四 App、
23 项单测)无误。
验证:宿主 gcc -Wall -Wextra 0 warning,test_meow_time64 23 项 PASS、
test_meow_time 回归 PASS;交叉 zig -Wall -Wextra 0 warning;
build_sdk_host.sh --verify 76 成员全 MIPS32r2、0 warning;归档内 meow_ui_time.o
与新鲜交叉构建逐字节一致。
|
2026-11-05 20:46:26 +08:00 |
|
AskaEth
|
40ac1e40f0
|
docs(sdk): CLOCK_ABI 补 M16 全量清点/接管机制/验证
§6 把「同源残余」换成逐条清点:zig musl 源里 20 处
`#if defined(SYS_*_time64) && !defined(__ILP32__)` 守卫,分「受损(回退分支直传
time64 结构)」与「不受影响(回退分支自带 long[]/宽度判断)」两类,各给源文件:行号
与反汇编证据;纠正 M11 对 pselect/ppoll 的保守判断(它们本来就正确)。
§7 记录接管机制:_REDIR_TIME64 让应用引用 __x_time64(不是 API 名);同一 .o 的
libc 符号必须一起定义(只定义 __timedwait_cp 会与 libc 的 __timedwait.o 撞
duplicate symbol,lld 实测);hidden 不阻止静态链接接管但要保证本 TU 被拉入;
结构宽度前提(整链 zig 头)。附未修 7 项的 5 步配方与「不建议顺手全改」的理由。
§8 记录本单验证:宿主 23 项换算单测 + M11 回归、build_sdk_host.sh --verify
(76 成员/全 MIPS32r2/0 warning)、四个入口的 syscall 号与缓冲宽度反汇编、
真实 meow_ui.a 链接探针的符号绑定。真机确认仍待设备。
|
2026-11-05 20:46:26 +08:00 |
|
AskaEth
|
0412994953
|
test(sdk): time64→o32 time32 换算宿主单测(23 项)
test_meow_time64.c 覆盖 meow_ui_time.c 接管入口共用的纯换算层:
- 相对超时(futex):普通值、亚秒、INT32_MAX 上界、上/下溢饱和、负值透传;
- 绝对时刻(clock_settime/timerfd):int32 上下界接受、越界拒绝(对应 ENOTSUP);
- itimerspec 四字段不串位、任一越界整体失败且不写坏输出、反向展开对称;
- 结构宽度 before/after:同一块 16B time64 内存按内核 o32 只读 8B 时,
0.4s 被读成 {0,0}(立即超时)、2.3s 被读成 2s 整;经本层转换后内核读到
{2, 300000000}。
宿主编译/运行:
gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o /tmp/m.o
gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time64.c /tmp/m.o -o test_meow_time64
./test_meow_time64 # == PASS ==
M11 的 test_meow_time.c 仍 PASS(回归)。
|
2026-11-05 20:46:26 +08:00 |
|
AskaEth
|
3b5ffece57
|
feat(sdk): 接管 mipsel time64 同源缺口 — futex 相对超时/timerfd/clock_settime
zig clang 给 mipsel 预定义 __ILP32__,打穿 musl 的 time64 回退守卫,以下入口把
16/32 字节 time64 结构直接交给 o32 time32 系统调用:
- thread/__timedwait.c:14:futex 相对超时(pthread_cond_timedwait / sem_timedwait /
pthread_join 超时 / aio_suspend / 非 PI timedlock / rwlock timed)。内核只读前 8B,
tv_nsec 落在 tv_sec 高半字(恒 0)→ 亚秒等待立即超时、整秒等待丢纳秒。SDK 的
meow_ui_audio 三处条件等待直接受害。按 musl 原文接管 __timedwait_cp/__timedwait,
只在发 futex 前把相对超时转成 time32;取消点仍走 libc 的 __syscall_cp。
- linux/timerfd.c:14/42:32B itimerspec 直传 → 内核按 16B 读、字段错位;接管
create/settime/gettime(同一 .o 的三个符号必须一起定义,否则重复定义)。
- time/clock_settime.c:9:16B 直传 → nsec 恒 0;接管 __clock_settime64。
换算抽成平台无关的 meow_time32_{rel,abs}_from_parts() / itimerspec 转换
(meow_ui_internal.h),宿主可测。pselect/ppoll/select、getrusage、wait4、
clock_adjtime 逐条反汇编确认回退分支自带宽度转换,不受影响(纠正 M11 §6 的保守
估计)。未修项(sigtimedwait/semtimedop/timer_settime/gettime/utimensat/recvmmsg/
mq_timedsend/PI timedlock)的清单与配方见 CLOCK_ABI.md §6/§7。
验证:宿主 gcc -Wall -Wextra 0 warning;交叉 zig -Wall -Wextra 0 warning;
build_sdk_host.sh --verify 76 成员全 MIPS32r2;真实 meow_ui.a 链接探针确认
__pthread_cond_timedwait_time64 的 jal 指向本实现、futex=4238 且超时为 8B、
timerfd 4323/4322、clock_settime 4262。
|
2026-11-05 20:46:26 +08:00 |
|
AskaEth
|
31c12892d6
|
test(sdk): 宿主回归 — --wrap 行高 30 下首行标题必须画出(listview 行高派生)
新 test_meow_ui_listview_rowh.c(35 断言)用链接期
-Wl,--wrap=meow_ui_text_height 把宿主 5x7 回退行高 14 换成真机 source_han_serif
20px 实测行高 30,驱动真实 SDK 渲染(同 M12 app/test/test_first_row_title_render.c
手法),断言全部读 back_buf 像素:
- T0 wrap 生效(meow_ui_text_height(font_body) == 30);
- T1 默认(不设 item_h):item_h == 62 = max(56, 2*30+2) ≥ 2*行高+间距;
max_scroll/hit 按 62 换算;scroll=0 时首行标题带与副标题带都有文字像素;
视口上方无标题泄漏;
- T2 裸 create(不调 renderer)同样派生;set_item_h(0) 忽略并保持派生;
- T3 显式 set_item_h(70)(ncm 语义):item_h/hit/max_scroll 全按 70,首行标题可见;
- T4 档位:tier(2) 恢复派生 62、tier(1) 48,单行档位不画副标题且标题可见;
- T5 pool 模式(set_vsource + 默认 renderer):同样派生 62,首行标题可见;
- T6 旧行为哨兵:显式 56 < block 62 时首行标题带 0 像素、副标题仍有 → 证明
像素断言能区分「画出/被跳过」,即 A/B 复现 bug 形态。
回归(宿主 gcc -O1 -Wall -Wextra,全部 0 warning):
- 新 test:35 pass / 0 fail;
- listvirt 44 / widgets ALL PASS / md3 ALL / scroll 17 / select 6 / swipe 35 /
lazygrid 32 全 PASS;
- 交叉 build_sdk_host.sh --verify:76 成员全 MIPS32r2 rel2,meow_ui_widget.c
-Wall -Wextra 0 warning(meow_ui.a 变更 → 下游 App 重链)。
|
2026-11-05 20:38:02 +08:00 |
|
AskaEth
|
4d9ba46a7b
|
fix(sdk): listview 默认行高按字体行高派生 — 双行列表首行标题不再被裁剪
根因(M12 finding / SDK 侧):meow_listview 双行 renderer 把「标题+副标题」
文本块 block = 2*meow_ui_text_height(font_body) + MEOW_LISTV_SUB_GAP(2) 在行内
垂直居中(ty = 行顶 + (item-block)/2),且文本只在 `ty >= 视口顶` 时才画。
旧默认行高固定 56 假定行高 ≤ 27;真机 source_han_serif 20px(ascent 24 +
descent 6)行高 30 → block 62 > 56 → ty = 行顶 - 3,首行(行顶 == 视口顶)
标题被裁剪守卫整条跳过、副标题仍在 → 所有用默认行高的 App 两行列表首行
标题消失。
修复(patch_v2/sdk/meow_ui_widget.c):
- item_h=0 改为「派生」哨兵:listv_item_h() 在未显式定行高时按当前主题正文
字体行高算 —— lines=2: max(56, 2*line_h+2)(行高 30 → 62)、lines=1:
max(48, line_h)。draw/hit/max_scroll 共用同一函数,行几何恒一致;
- meow_listview_create 不再写死 56;set_item_renderer 不再写死 48/56;
set_item_tier 恢复派生默认(仍是 1→≥48 / 2→≥56 的口径,字体大时自动长高);
- 显式 meow_listview_set_item_h(>0) 语义不变、优先且固定(ncm 传 70、files
传 56 等调用方不受影响);set_item_h(<=0) 仍忽略,返回值改为「当前生效行高」;
- 新增 meow_listview_item_h() 读当前生效行高(App 自绘行装饰对齐用,避免再
硬编码 56);
- src2 分支的双行判断补 `w->lines == 2`,与 pool 分支同口径:tier/renderer 设
单行档位时明确不画副标题(此前单行档位 48px 里仍塞 62px 文本块 → 同样丢标题)。
同类路径评估(不改):
- LazyColumn/LazyRow(W_LIST):单行 label,item_h 由 create 显式给(默认 44),
且 item_h 兼作横向列宽,按行高派生意味不明;默认 44 > 真机行高 30,当前不触发;
- lazygrid:格子几何由 App 显式给、文本底部对齐并整体 clip_push 裁剪,不受影响。
影响面:所有用默认行高的两行列表(hello/reader/files 及其它 App)在 20px 字库
下默认行高 56 → 62;显式 set_item_h 的调用方(ncm 70/launcher/files 等)零变化。
meow_ui.a 变更 → 下游 App 需重链(追加导出符号 meow_listview_item_h,ABI 兼容,
老 App 不重编也能跑)。
验证:见下一条 test 提交(宿主 --wrap 行高 30 + 像素断言 35 断言)。
|
2026-11-05 20:38:02 +08:00 |
|
AskaEth
|
c811913c06
|
build(fw): M6.46 固件 — 编入 M7 杀后台修复 + M11 SDK 时钟修复(0.8.46)
- launcher bb2d5f12 (863160B) 重编,链 meow_ui.a 4c4a1554:
M7(bgmgr_can_kill 门控 framework→protected_app / 后台页 sub 指针持久化 /
am kill 走 meow_bg_terminate 与页面按钮同通道) + M11(meow_ui_time 按 o32 time32 取时、
链接期接管 __clock_gettime*)
- meow_amsd b698f176 (139252B) 重编:M7 am kill 同通道 + cmd_kill/cmd_start 失败原因细分
(am CLI 9e323faf 保持不动:am.c 自 ca2290e 未变,与仓库发布物一致)
- fw_content.conf 8 条源 md5 对齐:bootmenu 4441822d / watchdog 553840cd / audiod b122c9b8 /
meow_audio 891ab264 / netmgrd×2 20243ea1 / launcher bb2d5f12 / amsd b698f176;头注 M6.46/0.8.46
- build_fw_apps.sh:repack.sh 改 bash 显式执行(#!/usr/bin/env bash 在 su 下 bad interpreter)
- 打包 r3proii_m6_46.upt md5 66501aaf(42,930,176B):rootfs 38,756,352<=45,088,768,
unpack 0 diff,87 files/1 folder 与 m6_45 一致
- 卡上写 r3proii.upt(66501aaf),原 0.8.45(3f4a8ad3) 备份 r3proii.upt.bak.0.8.45;
写前写后 du -sk Music 均 199164544;未刷机(运行中仍 43ac2312 / 0.8.45)
|
2026-11-05 20:16:29 +08:00 |
|
AskaEth
|
278e7eaa93
|
merge(sdk): 收编公开 SDK 仓的图片预算解码,主仓成为 SDK 唯一权威源
|
2026-11-05 20:07:26 +08:00 |
|
AskaEth
|
e23bdca26a
|
fix(sdk): 收编公开 SDK 仓独有改进(图片预算解码 + JPEG 解码期缩解),主仓成为唯一权威源
公开仓 ~/Proj/MeowOS-SDK 的 sdk/ 与主仓 patch_v2/sdk 无共同 git 历史(subtree split
重写了提交哈希,不做跨仓 merge/subtree pull),按内容逐文件裁决。公开仓侧的真增量只有
commit 21bffa1(图片预算解码)及其依赖;其余差异是公开仓的自包含打包(扁平 include/、
vendored 头与 meow_font.c)或主仓早已超越的旧快照。
一、取公开侧(纯追加,主仓该文件无独有改动)
- stb_image.h:新增 stbi_load_scaled / stbi_load_scaled_from_memory——JPEG 输出级按
步长抽取行/列,整幅原尺寸输出缓冲从不物化;进升级 JPEG 各分量系数 IDCT 进像素平面后
立即释放。scale<=1 与旧 API 等价,非 JPEG 忽略。主仓版本的 diff 全部是公开侧新增
(无主仓独有 hunk),故整体替换。
- meow_ui_img.c:追加 img_pick_scale / img_finish_dim / meow_img_probe_file /
meow_img_load_file_dim / meow_img_load_mem_dim。既有加载入口一字未改。
- include/meow_ui_image.h:追加上述三个公共声明。
- 新增 test_meow_img_budget.c + test_meow_img_budget_gen.py(--wrap malloc/free 打点
统计瞬时峰值,B1-B9 覆盖矩阵)。
二、取主仓(公开侧为旧快照或自包含适配,并入会回退功能)
- meow_ui_ime.c / test_ime_fix.c:主仓 bug3 修复(IME 打开瞬间 200ms TAP 冷却窗 +
drain/40ms/再 drain)及其回归用例为公开侧所无;公开侧同名文件不含该修复。
- meow_ui_input.c / meow_ui_internal.h:主仓 meow_input_touch_reset(drain 与叠加抑制
进入沿共用)、FreeType 渲染/字形声明、meow_time_ms_from_parts。公开侧此三处无独有声明
可并,取主仓即并集。
- meow_ui_gfx.c / meow_ui_sys.c / meow_cachegov.c:主仓时钟 ABI 根因修复(o32 time32,
meow_ui_time.c 链接期接管 __clock_gettime*)已把这些文件的本地 now_ms 统一为
meow_ui_time_ms();公开侧仍是各自 clock_gettime,回落即回退根因修复。
- meow_ui_dialog.c / meow_select.c:主仓 MD3 后续(对话框按钮胶囊 MEOW_SHAPE_FULL、
bottom sheet 顶角 28)晚于公开侧快照,公开侧等于旧版。
- include/meow_ui_font.h:主仓多出 FreeType 段与 stdint 自洽 include,公开侧缺。
- build_sdk.sh / build_sdk_host.sh:主仓含 FreeType vendor 裁剪构建、meow_ui_time TU、
launcher meow_font.a 打包;公开侧为自包含重写,不回流。
- 其余 test_*.c:差异仅为编译配方注释(公开仓用 -Iinclude、无 meow_ui_time.c、标注
「需主仓组件故公开仓跳过」等),对主仓目录布局不成立,不改。
三、不引入(vendored 副本 / 打包产物)
- meow_font.c、include/meow_font.h、include/meow_ipc.h、include/meow_notif.h:公开仓
为自包含 vendored 副本(meow_font.c 与主仓 font/meow_font.c 逐字节相同),主仓已有
权威源,复制会制造双源。
裁决说明(两边都改过的文件):
- test_meow_ui_select.c:公开仓把 T1 探针从 x=10 改到 x=12(commit 432875d)。主仓 x=10
在本树实测 6/6 PASS(容器卡左缘 8、文本左缘 24,x=10 已在卡内且避开圆角),无失败
可修,故不跟进该改动,避免无谓 churn。
- 公开侧「meow_media_playctl」一类 API 名:仅出现在公开仓 vendored 头/文档,主仓
sdk 无对应实现,未硬造。
四、验证(worktree / 分支 feat/sdk-absorb-public-deltas)
- build_sdk_host.sh --verify:0 warning / 0 error;成员清单 76 个(OBJS 32 +
meow_font.o + freetype 43)一致,全部 ELF32 MIPS32 rel2 (o32)。
- nm 确认 meow_ui.a 导出 meow_img_probe_file / meow_img_load_file_dim /
meow_img_load_mem_dim / stbi_load_scaled / stbi_load_scaled_from_memory。
- 宿主测试:对「未改动的 main SDK」跑同一套矩阵做基线对比,40 项同名结果逐项完全一致
(22 PASS / 11 FAIL / 7 建链失败,失败项与失败计数一字不差);本提交新增
test_meow_img_budget 为 PASS。补充按各测试正确配方单编:test_meow_img_color、
test_meow_lyric、test_meow_lyric_view、test_meow_ui_ft(显式传入 MiSans 字体)、
test_umbrella 均通过/0 warning。
- 既有失败全部是 Termux 环境问题,与本次合并无关(基线同样失败):/tmp 不可写导致
mkdtemp/fopen/bind EACCES(config/vol/notif_open/notify_ipc/notify_integration/
sb_collapse/overlay_suppress/input_keys),audiod 守护不在场(ui_audio_host),
test_sdk_fixes 阻塞循环超时(基线同样 124)。
- hello_app 用新 meow_ui.a 重链成功(0 warning,静态 MIPS32r2),可执行文件
471380→473636 字节(+2256,新解码路径)。
五、影响
meow_ui.a 内容变化(新增 4 个 MEOW_API + stb 解码路径改变)→ 需重编重链 hello / files /
reader / ncm 四 App 与 meow_launcherd。
|
2026-11-05 20:03:20 +08:00 |
|
AskaEth
|
22f9dab2ce
|
fix(ncm): 列表首行标题不显示 — 行高按字体行高派生(M12)
根因(真机 seated,非数据/颜色/遮挡):SDK meow_listview 双行渲染把
「2*行高 + 2」的文本块在行内垂直居中,且标题只在 ty >= 视口顶时才画
(meow_ui_widget.c:2061 的越界守卫)。真机 source_han_serif 20px 面
ascent 24 + descent 6 → 行高 30 → 文本块 62px,而 ncm 行高 APP_ROW_H=56
→ ty = 行顶 - 3;首行行顶 == 视口顶 → ty < 视口顶 → 标题被整条跳过,
副标题(ty+32)仍在视口内照画。两类列表同用该路径 + 同一行高,故症状一致。
修复(不动 SDK):ncm_app_internal.h 新增 ncm_row_h()/ncm_row_h_for_line_h(),
行高 = max(56, 2*字体行高 + 2 + 8)(偶数;本机 30 → 70,卡高 62 == 文本块);
home/playlist/queue/cache/search 在 page create 取一次 g_item_h,统一用于
set_item_h 与卡片几何/可见行/页脚/补载视口换算。
回归:
- app/test/test_meow_row_text_fit.c(新):真机字库行高矩阵 14/21/26/27/30
48 断言(文本块 ≤ 行高、首行 ty ≥ 0、卡高 ≥ 文本块、旧 56 哨兵)。
- app/test/test_first_row_title_render.c(新):--wrap 行高=30 驱动真实 SDK
渲染 + 读回 PPM 像素计数:旧 56 → 首行标题 0 像素/副标题 186;新 70 →
标题 84/副标题 100。
- test_meow_row_gap、plpage_sim 全 PASS;ncm_host 7 页出图与改动前逐字节相同
(宿主行高 14 → 行高仍 56,证重构无视觉回归);5 页自检 PASS;0 warning。
- plpage_sim 临时目录改 $TMPDIR(Termux /tmp 不可写,原写死无法运行)。
- REPORT §43:根因/排除方向/修复/验证/真机验收要点。
|
2026-11-05 19:51:01 +08:00 |
|
AskaEth
|
98b9169b86
|
build(ncm): 宿主构建补 meow_ui_time.c(M11 漏编,main 上 ncm_host 链接失败)
M11 新增 patch_v2/sdk/meow_ui_time.c 并把 SDK 各处取时收敛到 meow_ui_time_ms,
但 build_ncm_host.sh 的 SDK_SRC 未同步 → main 上跑本脚本链接报
`undefined symbol: meow_ui_time_ms`(且失败链接会删掉已入库的 ncm_host 产物)。
补一个源文件即可,宿主分支只编 meow_ui_time_ms 的非 mips 实现。
|
2026-11-05 19:50:51 +08:00 |
|
AskaEth
|
38be5e78bc
|
fix(sdk): 时钟 ABI 根因修复 — meow_ui_time 按 o32 time32 取时并链接期接管
真机 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 字节结构。
|
2026-11-05 13:41:52 +08:00 |
|
AskaEth
|
294ed6ffc7
|
test(ncm): M10 宿主回归三套(44 断言)+ 构建脚本 + REPORT §42
- bench/retry_storm_sim.c(25 断言):真实 retry_ctl.c/meta_gate.c,100ms tick 断网
120s→4 次/间隔 ≥30s;状态每 tick 抖动→2 次;时钟回退→不立即重试且间隔仍 ≥30s;
worker 45s>间隔→不并发;META 空闲 3 帧/60s(旧 600)、播放 13 帧(≤1/5s)、
状态抖动 ≤4 帧/秒、元数据变化/seek 立即报、超长标题截断不重报、回退不连发。
- bench/home_retry_sim.c(13 断言):真实 app/ui/home.c 的 home_tick 编进宿主
(--gc-sections + 桩),断网 120s→4 次重试、单飞、全帧重绘 0 次;
把真机形态的垃圾 64 位 now 喂给 home_tick 仍为 4 次/≥30s;回在线再断网不清基准。
- bench/meta_ipc_sim.c(6 断言):真实 ipc_media 线程 + 假 launcher AF_UNIX socket,
空闲 2s 只收到 1 帧 META(旧 ~10 帧),状态翻转恰好多 1 帧,帧头合法。
- build_ncm.sh / build_ncm_host.sh:源列表加 retry_ctl.c、meta_gate.c(host 补
mem_watch.c,否则 player_manager 链接失败);build_ncm_sims.sh 加三个 sim。
- REPORT §42:真机日志证据(时间戳低/高 32 位拆解、21016 帧 META)、根因三链、
实现、验证(session_gate 88 / http_truncate 13 / core 139 全过)、真机验证建议。
|
2026-11-05 13:00:32 +08:00 |
|
AskaEth
|
7f4e18b0ed
|
fix(ncm): META 改「变化+低频心跳」,不再每 100ms 刷 launcher(M10)
根因:ipc_media 主循环 `if (now - last_meta >= 1000)` 同样依赖 meow_ui_time_ms()
的坏 64 位值(REPORT §42)→ 条件恒真 → 每个 IPC 轮次都发 MSG_META。
launcher 日志 meow_20261105_122541.log:单次启动 21016 条
`ipc: META app=dev.player.ncm state=0 pos=0/0 -> ACK`,间隔 ~100ms,且全是
无变化的静止帧;launcher 每帧写 2 行日志+归并会话,SD 写放大到整机卡死。
修复:
- 新增 app/play/meta_gate.{h,c}(纯逻辑):状态/时长/标题/歌手/专辑/封面/歌词
标志变化 → 立即报;播放中位置偏移 ≥5s 重锚(launcher 自己按 last_active 外推);
心跳播放中 5s / 非播放 30s;硬下限 250ms(任何路径 ≤4 帧/秒);时钟回退不下溢;
字符串按发送侧截断长度比较(超长标题不得恒判「变了」)。
- ipc_media.send_meta 改为「组快照 → 闸判定 → 才发」,删除 1s 定时器;
时间改 ncm_monotonic_ms();首帧仍必发(注册媒体源);发送走 DEBUG 日志。
|
2026-11-05 13:00:28 +08:00 |
|
AskaEth
|
35a636ef42
|
fix(ncm): 离线重试改单调钟节奏闸,断网不再每个 tick 重试(M10)
根因(真机日志 19000100_000000_7534.log):meow_ui_time_ms() 在设备上返回坏值——
低 32 位是「开机秒数×1000」(无毫秒),高 32 位每次调用随机(REPORT §42)。
旧守卫 `!g_home_thr_on && (!g_offline_retry_ms || now - g_offline_retry_ms >= 30000)`
因此恒真:worker 一收工,下一个 tick 立刻再重试;真机 74s 内 10 次
(间隔 5-7s 只是失败请求本身的连接超时)。第二条链是 else 分支清零重试时刻,
online/offline 一抖动就再试。
修复:
- 新增 app/logic/retry_ctl.{h,c}:节奏闸只做差值,时钟由调用方给可信单调钟
(home.c 改传 core 的 ncm_monotonic_ms());回退不下溢(重定基准、不重试);
busy 单飞;在线/离线抖动不重置基准;首次进离线立即探测一次,之后严格 ≥30s。
- home_tick 不再使用入参 now(真机坏值无效化);新增 home_retry_reset()。
- 静默重试不再走完整 home_reload:新增 home_reload_ex(silent) 不预读盘
(旧实现每轮在 UI 线程同步读 playlists.bin)、home_apply_ex(keep_scroll)
保留滚动位置、worker 记 g_home_changed 决定是否需要重绘——旧实现每轮
home_apply() 复位滚动+整帧重绘,是「歌单列表滑动特别卡」的直接来源。
- worker 线程 pthread_detach(旧代码每轮泄漏线程栈)。
|
2026-11-05 13:00:24 +08:00 |
|