- P1: meow_ui_dialog.c 对话框底框 radius_card→MEOW_SHAPE_EXTRA_LARGE(28) 三处(:103填充/:104描边/:361 BottomSheet); meow_ui_widgets.h 新增 MEOW_SHAPE_EXTRA_LARGE 28 宏; TextField/FAB/Slider/Progress 按设计文档保留 - 批②: np_gesture.h 新增 NP_GEST_HOME+np_home_gesture(底部热区上滑,与左缘返回对称互斥); now_playing.c 新增 np_draw_home_bar(屏底左缘pill指示条)+手势衔接; test_now_playing_widgets G5b - 批6: ncm home.c 顶栏加回播放页按钮(MEOW_ICON_QUEUE_MUSIC)→push(ACT_PLAYER), 无音频也生效 - 批④: meowpanel /api/ams/bg 只读端点+前端后台列表页+杀/清复用kill通道 - UI微调: now_playing.c 播放页布局宏下移(NP_COVER_Y 84/NP_BTN_Y 612消底部留白)+歌词页背景统一黑色半透明叠层(弃封面取色底,删 np_draw_lyric_coverbg) - 封面保留: now_playing.c/notif_center.c 空artwork保留上一张已解码封面(防暂停/开歌单致META报空artwork后封面闪没); test_np_cover C2断言更新+mirror同步 0warning;宿主测试 test_np_cover ALL PASS;launcher/ncm/panel 宿主测试无回归。二进制留批量批次未入库
MeowPanel 后端(meowpanel.c)
MeowOS(HiBy R3 Pro II 第三方系统,MIPS32 静态交叉编译)的外置 Web 面板后端:单进程、零第三方依赖的
C 静态二进制,内嵌 HTTP/JSON 服务器 + 前端静态托管 + 框架专项服务 IPC 客户端 + settings.conf 设置镜像。
- 定位(
MEOWPANEL_DESIGN.md):外置于 TF 卡MeowOS/opt/MeowPanel/的系统组件,由meow_svcd读 TF 卡MeowOS/services.d/meowpanel.conf启动、meow_sysui监管。不进固件;无卡时系统核心 (launcher/sdk/设置/通知)绝不依赖它。 - 协议:
devdocs/plan/MEOWPANEL_PROTOCOL.md(HTTP/JSON 端点;本实现以「实现为准,协议/README 记录出入」)。 - 数据路径(
SYSTEM_FRAMEWORK_SERVICES.md §2/§4):读侧(/api/{status,perf,system})经meow_svc_perfIPC(MSG_PERF_QUERY→RESULT)聚合,绝不各自爬 /proc(M2.73 起 perf 聚合含network段);动作侧(/api/system/{reboot,shutdown,ota})经meow_svc_powerIPC(MSG_POWER_ACTION→STATUS),不再直连poweroff/写 mtd5。两专项服务为板载 svcd 托管 (trigger=boot),拔卡保留,与无卡依赖最小化自洽。 - ⚠️ OTA 检查升级 ≠ 升级:前端「检查升级」只读
GET /api/system的ota{current,available,latest},勿POST /api/system/ota(那是触发升级进升级模式)。
1. 编译
工具链:交叉编译器 /home/Aska/Project/R3ProII/.tools/zig-mipsel-cc(mipsel 32 位、musl 静态,可用)。
cd /home/Aska/Project/R3ProII/patch_v2/meowpanel
./build_meowpanel.sh # 交叉编译 → meowpanel(mipsel 静态,firmware-ready)
./build_meowpanel.sh host # 宿主编译 → meowpanel_host(本机 ld,仅供调试)
- 两分支均以
-Os -Wall -Wextra复核,0 warning(-Werror亦通过)。 - 产出(本次构建实测):
meowpanel:mipsel 静态,ELF 32-bit LSB executable, MIPS, MIPS32 rel2, statically linked, stripped, 体积约 256 KB(固件阈值内)。md5:820b24541ed69f2e27e4a301aff10c98(UTF-8 加固:sA_str统一嵌 JSON 字符串做 UTF-8 消毒,非法/截断字节逐字节回退?——amsd 曾把「流媒体客户端」截成 16B 腰斩「端」字导致浏览器拒收整页,面板侧防任一上游再产坏字节;--selftest宿主回归;原始 IPC JSON(perf/power/net 含 ssid)先utf8_valid_n校验,坏字节降级不拖垮 /api/overview)。 重防火墙注意:运行中二进制先.new再mv,切勿直接覆盖运行中的meowpanel)。meowpanel_host:aarch64 动态链接(宿主编译,仅供调试),体积约 148 KB。
- 依赖:仅 libc + Linux 内核头(
linux/input.h),零第三方库(设备无 python3/lua)。鉴权用内联 SHA-256(拷贝自meow_verify/sha256.c公有领域参考写法,前缀mp_sha256_*避免符号冲突;未改meow_verify/目录)。 阶段 C 实时画面用自研最小 baseline JPEG 编码器mp_jpeg.c(顺序 DCT + 4:2:0 + 标准 Huffman 表 Annex K; 无 libm、零依赖,仅 malloc/realloc),质量 70 下 480×720 帧约 41 KB。 字体库导入/导出(用户 2026-08-31 定案):与.mpk同构、放弃 zip,改走 busyboxgzip -dc | tar管道 (设备必带 tar/gzip,零新增依赖、不引入 zlib/miniz/自研 zip,见 §5.11)。 性能:设备为 mipsel muslsf 无 FPU,初版逐块double矩阵 DCT 编码 480×720 一帧约 3.96 s(掉帧到 5-6 s/帧的根因)。 已改为整数定点 DCT + 整数 YCbCr(FSCALE=13,BT.601 256 系数,纯整型乘加), 实测编码降至约 0.19 s(≈20×),单请求端到端(本机 localhost)约 0.20 s、LAN 约 0.22-0.31 s, 质量/体积与 double 版 PSNR 等价(主机 480×720 高频测试图两者差 <0.1 dB)。 - 头文件引用:
-I patch_v2/meow_launcherd(meow_ipc.h帧格式 /m_perf_*/m_power_*/POWER_*, header 为权威源,结构体字段以它为准)。
2. 部署到 TF 卡
# 1) 后端 + 前端(web/index.html + meowpanel.css + meowpanel.js)放在同一目录
sudo mkdir -p /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel
sudo cp patch_v2/meowpanel/meowpanel /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/
sudo cp patch_v2/meowpanel/web/index.html /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/
sudo cp patch_v2/meowpanel/web/meowpanel.css /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/
sudo cp patch_v2/meowpanel/web/meowpanel.js /usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/
# 2) 服务配置(svcd 读 TF 卡 services.d 拉起)
sudo mkdir -p /usr/data/mnt/sd_0/MeowOS/services.d
sudo cp patch_v2/meowpanel/services.d/meowpanel.conf /usr/data/mnt/sd_0/MeowOS/services.d/
说明:
- 前端资源与后端同目录(后端
GET /→index.html,GET /meowpanel.css/meowpanel.js同目录取)。 后端也支持GET /assets/<file>(映射到同目录文件),前端当前用根相对路径。 - 服务启动后整卡由
meow_svcd按trigger=boot拉起;meow_sysui监管(restart/backoff/max_restart)。 - 无卡:
MeowOS/services.d/不可读 → svcd 跳过本服务;系统核心照常。
3. 访问
浏览器(同局域网):
http://<host>.local:8080/
- mDNS 由板载
meow_mdns应答<host>.local。 - 端口默认 8080,可用
-p PORT/ 环境变量MEOWPORT/ 与后端同目录meowpanel.conf(port=N)覆盖。 (优先级:-p>MEOWPORT>meowpanel.conf> 默认 8080。) - 访问级 PIN 鉴权(用户 2026-09-01 定案):访问面板即需登录(4 位 PIN,
panel.pin,见 §5.9);未认证请求一律 401。 除/api/auth/{login,setup,logout,status}外全部/api/需有效会话(token 存面板进程内存,重启失效,3 天固定不滑动续期)。- 上传/下载/管理类请求统一带
X-MeowToken: <token>(或Authorization: Bearer <token>/Cookie: meow_token=<token>); 缺/错/过期 → 401UNAUTHORIZED。HTTP 明文(无 TLS),内网使用;请勿把 8080 暴露公网。
- 上传/下载/管理类请求统一带
4. 端点实现清单(对照 MEOWPANEL_PROTOCOL §2 端点总览)
已实现(返回 200/2xx 或语义错误码)
| 方法 | 路径 | 说明 | 实现 |
|---|---|---|---|
| GET | /、/meowpanel.css、/meowpanel.js、/assets/<f> |
静态托管 | ✅ |
| GET | /api/screen.jpeg |
实时画面:fb0 当前帧 → RGB565→JPEG(?q=1-100 质量,默认 70;?delta=1 开启增量帧,见 §5.10) |
✅(阶段 C) |
| POST | /api/input/tap |
触摸注入:{x,y}(480×720 原生坐标;write 进 goodix event1,本机实测可投递);本机触摸后 5s 内忽略注入 |
✅(阶段 C) |
| GET | /api/auth/status |
访问鉴权状态(auth_enabled/session/pin_set/legacy/locked/lock_remaining_ms) | ✅(公开) |
| POST | /api/auth/setup |
首次设置 4 位 PIN(仅未设 PIN 时;{pin} 4 位数字;已设→409) |
✅(公开;非法→422) |
| POST | /api/auth/login |
PIN 登录发 token({pin};未设 PIN 时接受旧密码 {password} 迁移;错→401,连错 5 次→429 LOCKED) |
✅(公开) |
| POST | /api/auth/logout |
登出失效 token | ✅(公开;幂等) |
| GET | /api/status |
性能+系统(meow_svc_perf IPC subset=all 透传) |
✅ |
| GET | /api/perf |
仅性能(subset=perf 透传) | ✅ |
| GET | /api/system |
perf IPC + boot/network/ota 局部补全(network 含蓝牙,无网口;ota 只读检查,勿误触升级) |
✅ |
| POST | /api/system/reboot、/shutdown、/ota |
meow_svc_power IPC |
✅ |
| GET | /api/settings |
全量+元数据(items/count/groups) | ✅ |
| GET | /api/settings/:key |
单项 | ✅ |
| PUT | /api/settings/:key |
写单项(clamp/枚举校验) | ✅(越界/非法枚举→422) |
| POST | /api/settings |
批量写 | ✅ |
| POST | /api/settings/restore |
恢复默认 | ✅ |
| GET | /api/theme |
读主题 | ✅ |
| PUT | /api/theme |
写主题(style/theme/background 子集) | ✅(非法→422) |
| GET | /api/files?path= |
目录列表(白名单) | ✅(无卡→503) |
| GET | /api/files/read?path= |
读文本(<1MB;二进制→415) | ✅ |
| GET | /api/files/download?path= |
下载流 | ✅ |
| POST | /api/files/upload |
multipart 上传 | ✅ |
| POST | /api/files/mkdir |
新建目录(已存在→409) | ✅ |
| POST | /api/files/rename |
重命名 | ✅ |
| DELETE | /api/files?path= |
删除(可 recursive=1;非空未 recursive→409) | ✅ |
| GET | /api/fonts |
字体库列表(扫描 MeowOS/fonts/<family>/<weight>/ 三件套齐) |
✅(无卡→503) |
| POST | /api/fonts/import |
上传字体库 .tar.gz(multipart file,可带 ?force=1 覆盖) |
✅(缺件/坏json/穿越→400,冲突→409,超限→413) |
| GET | /api/fonts/export |
导出 <family>/<weight>/ 三件套为 .tar.gz(?family=&weight=) |
✅(缺件→404) |
| GET | /api/audio |
音频状态快照:meow_audiod IPC MSG_AUDIO_QUERY→STATE 透传(当前流/路由/音量/underrun + rms/peak/lvlseq 电平 + vol_max,见 §5.12) |
✅(audiod 不在→available:false,不报错) |
| POST | /api/audio/route |
手动切输出路由(写级,PIN 已护):MSG_AUDIO_ROUTE,仅接受 {port: 0|2|3},绝不接受 1/4/5(4=SPDIF、5=audiod 内部强制重烧值);前端切换前确认弹窗(选错口会无声) |
✅(非法端口→422;audiod 不在→503) |
| POST | /api/audio/volume |
写音量(写级,PIN 已护):MSG_AUDIO_VOLUME,clamp 到系统 vol_max(读 settings.conf audio.volume_max,缺省 100;设备当前 50);audiod 仅 clamp 0-100 无 vol_max 防护,面板是把守方(防炸耳红线) |
✅(clamp 后写;audiod 不在→503) |
| GET | /api/power |
功耗管理:meow_powermgr IPC MSG_PM_QUERY→RESULT(battery/estimate/breakdown,confidence 原样透传) |
✅(powermgr 不在→503 POWER_UNAVAILABLE) |
| GET | /api/ams |
App 运行表:am list(pkg/name/state/pid/launches/crashes/last_kind/last_code) |
✅(amsd 不在→available:false) |
| GET | /api/svcd |
服务表:meow_svcd status all(name/state/pid/restart/backoff_ms/trigger/src/exit/exec) |
✅(svcd 不在→available:false) |
| GET | /api/overview |
首页聚合(单线程后端只暴露聚合):后端顺序 fan-out perf/power/audio/net/ams/svcd 六源合成一份 JSON;任一源失败→该子块 available:false,绝不假数据 |
✅(读级,需 PIN 会话) |
| GET | /api/apps |
扫描 MeowAPPs/ 读 app.json |
✅ |
| GET | /api/apps/:pkg |
应用详情 | ✅ |
| POST | /api/apps/install |
经 nyai install(multipart 或 path) |
✅ |
| GET | /api/apps/:pkg/export |
nyai export 下载流 |
✅ |
| DELETE | /api/apps/:pkg |
nyai remove [--purge] |
✅ |
| POST | /api/key/:code |
按键注入(tap/long) | ✅(物理键红线内) |
| POST | /api/key |
批量/顺序注入 | ✅ |
| GET | /api/logs |
MeowOS/logs 文件列表(每文件含 group 来源分组) |
✅(无卡→503) |
| GET | /api/logs/crash |
崩溃汇总:解析最新 crash_<bootts>.log(meow_crash 落盘格式)→ 每实体崩溃数 + 最近崩溃时间/信号 + dmesg 计数 |
✅(无卡→503;无 crash 日志→空汇总) |
| GET | /api/logs/read?file=&lines= |
读日志(上限 1000 行;../绝对→403;敏感名→403) |
✅ |
| GET | /api/notifications |
通知列表(优先 launcher IPC 内存活跃集 source:"ipc";IPC 不可达回退 TF 转储日志 source:"tf";见 §5.8) |
✅(无源→空态 source:none,不 503) |
| DELETE | /api/notifications/:id |
单条删除(优先 IPC 撤下 launcher 内存;IPC 不可达回退重写日志移除该 id) | ✅(不存在→404) |
| POST | /api/notifications/dismiss_all(别名 /api/notifications/clear) |
一键清空:优先 IPC 联动 launcher 内存,保留活动中的媒体/进度通知;IPC 不可达回退重写日志 | ✅ |
| GET | /api/files/read?path= |
读文本:预览上限 1MB,超限 truncated:true(不再 404);二进制→415 |
✅ |
返回 501 NOT_IMPLEMENTED 的端点(诚实标注)
| 端点 | 原因 |
|---|---|
/api/key/:code 的 press:"hold" |
hold 需常驻持续注入通道(阶段 D),后端未实现;tap/long 已实现。 |
OTA 升级模式(/api/system/ota 带 url) |
升级为草案(MEOWPANEL_PROTOCOL §6 待定案);当前 POST /api/system/ota 空 body 触发 meow_svc_power 的 POWER_UPGRADE(写 mtd5 进升级模式),带 url 的下载+升级未实现。 |
通知端点已从 501 落地,且现为实时:优先经 launcher IPC
MSG_NOTIFY_QUERY(0x25)→QUERY_RESULT(0x27)取 内存活跃集(source:"ipc");IPC 不可达/超时回退读 TF 卡通知转储日志(source:"tf",会话级归档);两者皆无source:"none"。撤/清(DELETE/dismiss_all)同样优先走 IPC联动 launcher 内存(launcher 撤下时自动归档留档)。 详见 §5.8。
前端对
501显示「该功能后端尚未实现」(ok:false,error.code=NOT_IMPLEMENTED)。
5. 关键实现说明
5.1 HTTP 路由 / JSON 序列化
- 单线程 + poll 串行(面板访问量极小)。
accept→read_request(先读头到\r\n\r\n,在缓冲区内搜索头边界, 处理「头+body 同段到达」,再按Content-Length精确读 body)→handle→ 写响应 → 关闭连接(Connection: close)。 - 读/写均有
poll超时(读头部 5s、body 分段 5s,IPC 2s)。SIGPIPE忽略。 - JSON 响应信封:成功
{"ok":true,"data":<payload>};失败{"ok":false,"error":{"code","message"}}(MEOWPANEL_PROTOCOL §1.1/§1.2,HTTP 状态码映射照抄)。 - 无 JSON 库:手写最小递归下降解析器(对象/数组/字符串转义/数字/bool/null),仅覆盖实际用到的收发。
- 下载/上传用流式(
multipart/form-data极简解析:按 boundary 切,取path+file字段)。
5.2 IPC 对接(meow_svc_perf / meow_svc_power)
- 帧:复用
meow_ipc.h——16B 头(magic0x4D4F5701/version 1/type/req_id/len,全小端)+ 变长负载,MEOW_IPC_MAX=4096。帧读写x_read_full/x_write_full+send_frame/recv_frame(与 meow_svc_perf.c 对称)。 - 握手:连接后先
MSG_HELLO(app_id="os.meow.panel",系统面板身份,§5 二期拟名)→ 读MSG_ACK(code=0)。 - 读侧:
MSG_PERF_QUERY(m_perf_query_t.subset)→MSG_PERF_RESULT(m_perf_result_t,code/json_len/json), 直接透传服务端聚合 JSON(/api/status=全部、/api/perf=perf 子集、/api/system=全量取 uptime/storage/tfcard/system)。 读取防溢出:json_len以sizeof(m_perf_result_t.json)-1与cap双钳位。 - 动作侧:
MSG_POWER_ACTION(m_power_action_t.cmd=POWER_REBOOT/SHUTDOWN/UPGRADE)→MSG_POWER_STATUS(code/msg)。 收到MEOW_OK→{"accepted":true};否则按code(PERM→403 / NOENT/IO→503 / 其余→500)返回错误信封。 - 失败语义:socket 不存在/连接拒/超时/应答非 OK → 返回 500
INTERNAL(或 503NO_CARD当缺升级文件) 并带中文 message。绝不静默失败、绝不降级直连 /proc 或 poweroff(单一权威源)。 - 连接超时:非阻塞 connect +
poll(POLLOUT)2s,SO_RCVTIMEO/SO_SNDTIMEO兜底。
5.3 设置镜像(读写板载 settings.conf)
- 不旁路:只经
settings_get_value(=切分 + key 去首尾空白精确匹配,防audio.volume误配audio.volume_max, 照meow_ui_vol_read/meow_svc_power settings_get_int_trim同款解析)与settings_write_one("key = value\n", 保留# meow-settings 1头、逐行重写、缺键追加;目录缺失自动mkdir)。不绕过此函数直接改文件。 - 键表/默认值来源:
patch_v2/meow_launcherd/meow_settings.c的g_defs[](权威来源,逐键一致), 含 type/def/min/max/enum_names/enum_labels;GET /api/settings返回items/count/groups(分组按键前缀, 如display.*→显示、font.*|ui.*→字体主题…)。 - 类型:
int→number(带 min/max/def 字符串)、bool→原生布尔、enum→options(name/label)+default_name+def、str→string。越界/非法枚举 → 422UNSUPPORTED。 - 语义 clamp:
display.brightness读/写都 clamp 到[display.brightness_min(默认1), 100](防 101 闪屏, 与meow_settings_brightness_clamped/clamp_brightness同口径);boot.default写后同步/data/meow_boot_default(meow→0/hiby→1,同meow_settings_save)。 - 注:后端为独立进程,无法调用 launcher 进程内的
meow_settings_*(那是其内存表),故直接镜像同一份settings.conf,保持与实体设置页/CLI 同一存储契约(协议 §3.2 说「经 meow_settings_*」,此处以 「镜像同一文件 + 同款 parse/save 契约」落地,见 §8 出入记录)。
5.4 文件白名单
- 根
/usr/data/mnt/sd_0;白名单子目录MeowOS/Music/MeowData/MeowAPPs/book(allowed数组)。 - 路径经
normalize_path规范化(去./..,拒绝逃逸出根)后path_in_whitelist校验(== 根或属于某一白名单 一级子目录)。../绝对路径逃逸 → 403FORBIDDEN;无卡 → 503NO_CARD。 - 读取拒绝敏感名(
settings.conf/setting.bak/.env/passwd/shadow/meow.conf/user.ini/config.json)。 - 列表/上传/下载/读文本(1MB+二进制→415)/mkdir(已存在→409)/rename(new_name 不含
/)/delete(递归,非空未 recursive→409)。
5.5 nyai 对接
- 包管理器 CLI 绝对路径
/usr/data/mnt/sd_0/MeowOS/opt/bin/nyai(M2.12+ 固件经meow_card_path.sh前插 PATH,可直接调; 本后端用绝对路径,兼容更早固件)。包名 =app.json的package=.mpk文件名茎。 install:multipart 上传.mpk落临时文件(MeowOS/tmp/)或 JSON{path}→nyai install <file>;用popen捕获输出+退出码, 非 0 → 422。export:nyai export <pkg> <tmp>→ 以Content-Disposition: attachment流式下发。remove:nyai remove <pkg> [--purge]。GET /api/apps/:pkg详情:直接扫描MeowAPPs/<dir>/app.json(手写 JSON 解析提取 name/version/exec/framework/immersive/fullscreen), 不依赖 nyai(nyai 未部署时列表/详情仍可用)。解析失败项invalid:true。nyai未部署 → install/export/remove 返回 500(带 nyai 输出)。
5.6 按键注入通道
- 复用现有先例:
patch_v2/uinput_tap/uinput_tap.c的write-到-evdev 注入机制。launcher 实际轮询meow_launcher_internal.h:/dev/input/event0(md-gpio-keys: POWER/PREVIOUS)、/dev/input/event2(jz adc keyboard: VOL/PLAY/NEXT)。后端 openO_WRONLY写EV_KEY press/release + SYN_REPORT即可到达 launcher 按键处理。 - 物理键红线(APPS.md / 任务约束):只注入音量(114/115)/电源(116)/播放(164)/上下曲(163/165);
禁止注入 返回(158)/主页(172)/确认(28)/退出(96) → 403
FORBIDDEN。 tap(默认,抬起间隔 80ms)、long(按住 ms,缺省 3000);hold→ 501。- 局限:若
/dev/input/event0/event2在设备上不可写(权限/路径差异),注入失败 → 500;注入为即时性注入, 不在 launcher 内维护长按状态机(与实体按键的longpressed语义近似,见 README 已知边界)。
5.7 日志
GET /api/logs:MeowOS/logs下常规文件列表(跳过敏感名)。GET /api/logs/read?file=&lines=:file必须相对MeowOS/logs/,禁../绝对路径 → 403,敏感名 → 403; 缺省lines=200,上限1000;返回{file,lines[],total,truncated}。
5.8 通知(数据源 = 优先 launcher 内存活跃集,回退 TF 归档)
- 数据源优先级:① launcher IPC 内存活跃集(实时,
source:"ipc")→② TF 转储文件(source:"tf")→③ 空态(source:"none")。- ① launcher IPC:后端连
/usr/data/meow_ipc.sock,MSG_HELLO握手(app_id=os.meow.panel)→MSG_NOTIFY_QUERY(0x25)(空 payload=全部 app)→ 期望MSG_NOTIFY_QUERY_RESULT(0x27)(m_notify_query_result_t,JSON 数组文本,字段同 TF 归档,ts为 epoch 毫秒)。launcher 在主循环单写者序列化(绝不把通知存储读到 IPC 线程)。后端按ms升序重排 (oldest..newest,与 TF 一致),emit 时倒序= newest first;ts除以 1000 出秒(与 TF 同口径)。 - ② TF 转储文件(回退):
<卡根>/MeowOS/notifications/notifications.log(launchermeow_notif_dump_tf一行一条 CSV, 字段timestamp,id,app_id,app_icon,category,urgency,progress,title,body,target_activity,ongoing,media,dismissed;meow_notif_clear_tf开机清空 → 会话级归档)。后端逐行流式读取(环形保留最新NOTIF_PREVIEW_MAX=200条,不全量进内存)。 注意 TF 是归档快照(归档时dismissed尚未置 1,故该列恒 ≈0 不可靠,且非活跃快照)。
- ① launcher IPC:后端连
GET /api/notifications:返回{count, items:[...], notifications:[...], source};items=notifications别名 (兼容前端读.notifications与任务约定空态items:[])。字段含id/app_id/app_name/app_icon/category/summary/body/ urgency/ts/progress/ongoing/media/target_activity/dismissed。progress<0→null;app_name对system→系统,其余用app_id兜底。 无源(无卡/文件不存在)→{count:0,items:[],notifications:[],source:"none"}(不 503、不伪造数据)。DELETE /api/notifications/:id:优先 IPCMSG_NOTIFY_DISMISS(0x22)(4B id →MSG_ACK;launcher 撤下时自动归档留档); IPC 不可达/未受理 → 回退从日志移除该行(写临时 + rename)。IPC 未受理且日志也无该 id → 404。POST /api/notifications/dismiss_all:优先 IPCMSG_NOTIFY_DISMISS_ALL(0x26)(→MSG_ACK.status=清除数; launcher 保留 ongoing/media/progress 红线项);IPC 不可达 → 回退重写日志(ongoing||media||progress>=0||category=="media"保留)。- 实时性:IPC 路径直接反映 launcher 内存活跃集——新通知(含未到期/未归档)立即出现在面板(实测:post 一条
通知后面板同时刻即见,
source:"ipc");撤/清经 IPC 联动 launcher 内存(实测:面板 DELETE 后 launcher 活跃集即无该 id)。 TF 路径仅为 launcher 不可达时的诚实降级(会显示自动过期的历史通知,直到 clear)。 - 并发:IPC 可用时面板不写 TF(撤清由 launcher 自行归档),避免与 launcher
O_APPEND竞写;仅 IPC 回退到「写临时 + rename」。
5.9 访问级 PIN 鉴权(panel.pin;用户定案 2026-09-01)
- 模型(覆盖 282 报告「默认无鉴权」前提):访问面板即需登录。未认证请求一律 401(静态登录页自身 + css/js 放行——
serve_static先于require_auth);未设 PIN 前无法建立会话,故读端点也全拦(登录/设置流程除外),写端点自然一律拒绝。 - 设置键:
panel.pin(str,存salt:hex= sha256(salt||pin) 带盐哈希,绝不存明文),写板载settings.conf(与实体设置页/CLI 同一存储契约,面板独立进程直接镜像文件);与未来 MeowOS 锁屏 PIN 同源:设置键system.pin预留(本后端只读面板键,见g_sets注记)。panel.pin的GET /api/settings恒回"value":"" + "set":<bool>,绝不回传哈希/明文。 - PIN:4 位数字(
pin_validate);校验时重算 sha256(salt||pin) 并恒定比较(memcmp)。 - 门禁:
require_auth在路由分发前执行——除/api/auth/{login,setup,logout,status}外全部/api/需有效会话; 缺/错/过期 → 401UNAUTHORIZED。危险端点(reboot/shutdown/ota、key 注入、settings 写等)一律纳入会话校验(不再有「未开启」旁路)。 - 会话 token:
/dev/urandom16B → 32 hex(128bit),只存面板进程内存(g_sess[],AUTH_MAX_SESS=8,满淘汰最早过期), 无卡上持久化——设备重启自然清(会话即失效)。有效期 3 天(AUTH_TOKEN_TTL,固定不滑动续期,逐 token 校验到期戳); 多会话并存。logout失效当前 token。 - 锁定(防爆破):连续
PIN_MAX_FAILS=5次错 PIN → 锁PIN_LOCK_SEC=300s(429 LOCKED,响应附lock_remaining_ms;status透出locked/lock_remaining_ms);内存态,重启清。 - 旧密码机制兼容迁移(
panel.auth_enabled/panel.auth_pass保留):旧密码存在且未设 PIN 时,视为「已设访问屏障」的同等物—— 登录可用旧密码({"password":…}),status透出legacy:true并提示改设 4 位 PIN;一旦设置panel.pin,新代码以 PIN 为准 (登录只认 PIN,旧密码不再作为凭据)。PUT /api/settings/panel.auth_pass仍可写(引导迁移),panel.auth_enabled已不作门禁(保留兼容)。 - 前端:api 客户端统一带
X-MeowToken(token 存localStorage);收到 401 → 自动切登录页;未设 PIN → 首次设置流程 (#loginoverlay 双态:设置=输入+确认,登录=单输入);429LOCKED→ 显示锁定提示。设置页「面板鉴权」卡片沿用旧密码项。 - 静态屏蔽:
serve_static额外拒绝后端可执行文件(403),防可执行被 HTTP 读取。
5.10 实时画面(/api/screen.jpeg,含增量帧 ?delta=1)+ 触摸注入(/api/input/tap)— 阶段 C
- 实时画面(整帧,默认):
GET /api/screen.jpeg读/dev/fb0当前显示帧(FBIOGET_VSCREENINFO取yoffset/xres/yres/bpp,FBIOGET_FSCREENINFO取line_length,pread活动缓冲,只读,不影响渲染;16bpp RGB565)→mp_jpeg_encode_rgb565()编码为内存 JPEG(自研最小 baseline 编码器,见 §1),返回Content-Type: image/jpeg。?q=1-100控制质量(默认 70)。恢复line_length != xres*2(行尾填充)时先压缩为紧凑 RGB565。 - 增量帧(
?delta=1,阶段 C 增强):服务端缓存上一帧紧凑 RGB565(单线程 accept 循环跨请求持有),按 8×8 块逐行memcmp比对(1 块=8×8 像素×2B),只编码变化块的外接矩形子图(8 对齐、钳到屏内)为独立 JPEG,并以响应头回传偏移/几何 (X-Meow-Delta:1/X-Meow-Full:0|1/X-Meow-W/H(整屏)/X-Meow-Sub-X/Y/W/H(子图原点与尺寸)/X-Meow-Changed/X-Meow-Blocks)。- 冷启动/几何变化/变化块覆盖全屏 → 发整帧(
X-Meow-Full:1);帧无变化 →Content-Length:0+X-Meow-Changed:0(前端跳过叠加)。 - 体积:近静态帧(只刷新状态栏时钟等)增量子图可低至数百 B(实测 6 变化块=804 B,对比整帧 ~27 KB @q70)。
- 不破坏默认:未带
?delta=1仍为整帧image/jpeg(零回归)。 - 前端「屏幕」页新增「增量传输(省流量)」开关:开启后走
?delta=1,用<canvas>叠加(整帧播种/替换,子图drawImage(x,y)); 关闭走原<img>+objectURL 整帧。默认关。
- 冷启动/几何变化/变化块覆盖全屏 → 发整帧(
- 触摸注入:
POST /api/input/tap,body{x,y}(0..479 × 0..719 原生像素坐标,前端按 480×720 映射,后端再 clamp)。 机制 = write 进 goodix evdev(/dev/input/event1)——本机实测 write 注入可投递(见 §7 修正历史结论), 事件序列与真实 goodix 一致:先BTN_TOUCH=1(按下边沿)后ABS_MT_*/ABS_X/Y(坐标),SYN→ 按住 100ms →BTN_TOUCH=0+ABS_MT_TRACKING_ID=-1+SYN。关键:launcher/meow_touch在按下边沿会重置坐标 -1, 只在 down 之后到来的首个有效 ABS 才锁原点(goodix 时序免疫)——故坐标必须在 BTN_TOUCH=1 之后,否则原点永不 锁定 → 抬手被判无效 tap(只高亮不启动)。注入前不写 uinput(本设备厂商内核 write 进 goodix 即可投递,逐 UB 少)。 - 仲裁(本机优先打断):注入前
touch_last_local_ms()排空 event1,取「最近一次本机真实触摸」的单调毫秒时间 (剔除本进程自注入事件:事件时间 ≤ 上次注入时刻+200ms),若now-last < 5000→ 忽略注入,返回{"dispatched":false,"reason":"local_touch_active","cooldown_ms":N};否则注入并返回{"dispatched":true,"x","y"}。 MIPS 的struct input_event无time成员(ABI),按 launcher 同款读裸 16 字节取偏移 0/4 的tv_sec/tv_usec(单调时钟)。 - 前端「屏幕」页(
web/#/screen,导航「屏幕」):<img>轮询GET /api/screen.jpeg?t=…&q=70(fetch→blob→objectURL, 防重叠 + 旧 URL 回收;后端不可达提示「后端未连接」);默认 1fps,滑条 0.2–2fps(存screen.fps,页面隐藏/切走即停刷,visibilitychange回前台续刷);点击画面按 480×720 比例换算坐标 →POST /api/input/tap,dispatched:false时 toast「本机触摸中」。
5.11 字体库 tar.gz 导入 / 导出(/api/fonts*,新增)
- 定位(MEOWOS_SPEC_REF §5.7.6 / FONT_SYSTEM.md,2026-08-31 用户定案:放弃 zip,与 .mpk 同构走 tar.gz):
系统字库按
MeowOS/fonts/<family>/<weight>/三件套存放(schema 见 SPEC_REF §5.2:family/weight/name/ glyph_count/charset/tier/size_list/bit_depth/sha256_png/sha256_idx…)。设备 busybox tar/gzip 必定存在, 后端全部走gzip -dc | tar管道(nyai .mpk 同款),零新增依赖、不引入 zlib/miniz/自研 zip。 - 导入
POST /api/fonts/import(multipartfile=<.tar.gz>,上限MAX_FONT_UPLOAD=32MB,可带?force=1):- multipart
file落临时<TF_CARD>/tmp/mp_font_...tar.gz(multipart_extract_file,二进制安全mem_find)。 - 成员预校验:
gzip -dc '<tmp>' | tar -t,每成员经sanitize_member(去前导//./,拒..组件与 shell 危险字符)且恰为三件套平铺(多出条目/子目录/绝对/..→ 400)。 - 解压到临时目录:
gzip -dc | tar -x -C stg→ opendir/lstat 锁:恰为 3 个普通文件 (拒软链/目录/设备;总大小 ≤FONT_EXTRACT_MAX=32MB 防 gzip 炸弹)→ 缺件/坏 json 400。 font.json手写 JSON 解析 →family(缺省回退name)/weight(缺省regular),safe_dir_segment消毒(拒/、\、控制符、./..)→ 非法 422。- 覆盖冲突:目标目录任一文件已存在且非
force=1→ 409CONFLICT(前端 confirm 后带force=1重试)。 - sha256 仅 WARN(对齐 font.json 约定):流式重算
sha256_png/sha256_idx与声明比对,不符写warning字段、仍导入成功(不硬失败);响应含family/weight/imported/hint(提示进设备「设置→字体」页 列表自动重扫生效——后端不触发 launcher 重扫,扫描时机=启动/进设置页,勿加热路径)。 mkdir(系统调用,不用system(),防注入)→rename三件套到目标目录(原子替换)。
- multipart
- 导出
GET /api/fonts/export?family=&weight=:校验 family/weight 段 → 目标目录三件套须齐(缺件 404)→tar -cf - -C <font_dir> font.png font.idx font.json | gzip -c > <tmp>落临时文件(求Content-Length)→Content-Disposition: attachment; filename="<family>-<weight>.font.tar.gz"+application/gzip→ 流式下发。 - 列表
GET /api/fonts:扫描MeowOS/fonts/<family>/<weight>/,三件套齐才列出,读font.json取 name/tier/glyph_count(容错)。无卡 → 503。 - 往返验证(宿主):Python tarfile 生成的平铺三件套
.tar.gz导入→导出→逐字节比对源文件一致;本后端导出 再导入→逐字节一致;GNU tar/tarfile均能读;目录穿越..//绝对路径/软链成员/缺件/坏 font.json/多出条目/ 子目录包裹/非 gzip——全部拒绝;打包文件名<family>-<weight>.font.tar.gz。见 §7 宿主测试备注。
5.12 音频状态(/api/audio,新增,AUDIOD_DESIGN §8 面板对接)
- 数据源:
meow_audiod独占音频守护(板载进固件,svcd 托管;HibyOS 模式按门控不启动)。 后端连/usr/data/meow_audio.sock(可被--sock-audio/ envMEOW_AUDIO_SOCK覆盖,宿主/qemu 测试用, 与 audiod CLI 同 env),发MSG_AUDIO_QUERY(0x00C7) 空负载,收MSG_AUDIO_STATE(0x00C8) 文本帧 (active=.. app=.. sid=.. rate=.. ch=.. fmt=.. written=.. played=.. underrun=.. paused=.. route_mode=.. port=.. vol=.., 空格分隔 k=v、NUL 结尾)。audiod 无 MSG_HELLO 握手(见 meow_audio.c CLI),与 perf/power/launcher 路径不同。 - 响应:解析 k=v 为 JSON——
{available:true, active, app, sid, rate, ch, fmt, written_frames, played_frames, underrun, paused, route_mode("auto"/"manual"), port, vol, **rms, peak, lvlseq**};port为 amixer numid=9 路由口 (0=空闲 1=lineout 2=3.5 3=4.4 4=Type-C SPDIF;宿主无 amixer 时为 -1)。 - 电平(追加键,ABI/协议兼容):
rms/peak= deci-dB(-990=‑inf;如-139=‑13.9dBFS),lvlseq= 快照代际 (每次结算/开流复位递增,前端可用其判「新刻度」驱动 sparkline)。仅追加键,不破坏既有字段。 - audiod 不在(socket 缺失/连接拒/超时/非预期应答)→ HTTP 200
{"available":false},不报错(面板音频页显示 「audiod 不可用」)。只读端点;不放测试音(真机乱响风险,tone 留给 CLImeow_audio tone)。 - 前端:「音频」页(
web/#/audio)5s 轮询展示——当前流(app/rate/ch/fmt/已写帧/已播放帧/underrun/暂停态)+ 路由口 + 音量 + audiod 可用性;切页即停轮询。
5.13 字体管理页(前端 web/#/fonts,新增)
- 后端
/api/fonts*三端点(§5.11,agent-243 落地)的专属页面:表格列出 family/weight/name/tier/glyph_count, 行内「导出」(busy 防连点「打包中…」)+ 顶部「上传字体库 .tar.gz」(导入中禁用按钮=进度态)+「刷新」。 - 上传遇 409 CONFLICT(同 family/weight 已存在)→ 弹确认框,确认后带
?force=1重试;成功 toast 带family/weight与warning(sha256 不符仅提示)/hint。 - 设置页原「字体库」卡保留(同一后端,互不影响)。
5.14 批1-A 新增只读端点(供批1-B 前端消费;JSON 形状)
本批只做后端端点 + 最小前端支撑(登录),首页/电源/进程页归批1-B。前端调用统一带 PIN 会话 token(见 §5.9)。
GET /api/overview(首页生命线,单线程后端只暴露聚合):{ "ts": 1788268891, "perf": { "...": "meow_svc_perf 聚合 JSON(cpu/memory/storage/tfcard/temp/system/network,透传)" }, "power": { "mode":"meow","battery":{"state","pct","mv","health","technology","temp_c10","charger_temp_c10","cycle_count","nominal_mah_note"}, "estimate":{"est_mw","confidence":"estimated|derived|measured|none","calibrated","degraded"}, "breakdown":{"baseline_mw","cpu_mw","cpu_util_pct","backlight_mw","panel_mw","brightness_pct","wifi_mw","wifi_state","bt_mw","bt_state","audio_mw","audio_state","degraded"}, "policy": null }, "audio": { "available": true, "active","app","sid","rate","ch","fmt","written_frames","played_frames","underrun","paused", "route_mode","port","vol","rms","peak","lvlseq" }, "net": { "...": "netmgrd 概览 JSON(mode/ifaces[]/wifi/bt/rfkill/hostname_local,透传)" }, "ams": { "available": true, "count": 3, "apps":[ {"pkg","name","state":"fg|bg|stop","pid","launches","crashes","last_kind":"clean|exit|sig","last_code"} ] }, "svcd": { "available": true, "count": 3, "services":[ {"name","state":"running|stopped|stopping|disabled|failed","pid","restart","restart_str","backoff_ms","trigger","src":"board|tf","exit","exit_time","exec"} ] } }- 任一源失败 → 该子块
{"available":false}(perf/power/net失败也是{"available":false},绝不假数据);audio/ams/svcd成功时自带available:true。perf/power/net成功时为对应源原始 JSON(无available字段)。
- 任一源失败 → 该子块
GET /api/power:即 overview 的power子块(可 503POWER_UNAVAILABLE,非available:false)。GET /api/ams/GET /api/svcd:即 overview 的ams/svcd子块;源不在 →{"available":false}。GET /api/audio:overview 的audio子块 + rms/peak/lvlseq 消费说明见 §5.12。
5.15 批2:崩溃/日志中心 + 音频写 + 后端补缺口(PANEL_ENHANCE_PLAN 批2)
- 崩溃/日志中心(升级
#/logs):GET /api/logs/crash:读最新crash_<bootts>.log(meow_crash 落盘格式:<epoch> <uptime> <svc|dmesg> <detail>; svc 的detail=<name> exit=<code>/<name> signal=<sig>)。聚合出{file,count,dmesg_count,dmesg_tail,entities:[ {name,source:"svc",count,last_epoch,last_kind,last_code,last_time,last_detail}]};只读、无副作用。 读取有界CRASH_TAIL_MAX=256KB、实体CRASH_ENT_MAX=64、dmesg 保留最近CRASH_DMESG_TAIL=5 行(行数上限保护)。/api/logs文件列表每项带group(meow_*→system/crash_*→crash/ams_*→ams/audio_monitor_*→audio_monitor/net_*→net/power_*→power/其余→app),供前端按来源分组 + 前缀过滤;group为追加键,向后兼容。- 崩溃尾巴前置:崩溃汇总实体行「stdout 尾部」按钮复用批1-B 读取路径(
/api/files?path=/MeowOS/logs/<name>/找最新stdout_*.log→/api/logs/read?file=<name>/<file>&lines=200读尾部)。
- 音频写(写级,PIN 已护;前端切换/调高前确认弹窗):
POST /api/audio/route:body {port}。仅 0=auto/2=3.5/3=4.4,其余(含 1=lineout/4=SPDIF、5=audiod 内部 强制重烧 FPGA 值)→ 422。audiod 对非法 port 也回 MEOW_OK(内部仅记录不应用),故面板在发出前自行校验。 应答{accepted,port};audiod 不在 → 503AUDIO_UNAVAILABLE。POST /api/audio/volume:body {value}。clamp 到系统 vol_max(settings.audio.volume_max,缺省PANEL_VOL_MAX_DEFAULT=100;设备当前 50)。audiod 内部仅 clamp 0-100、无 vol_max 防护——面板是唯一把守方 (防炸耳红线:平方锥度dac=(100-pct)²×192/10000,接近 100 极响)。应答{accepted,value(clamped),applied,vol_max}。/api/audio补vol_max(读 settingsaudio.volume_max),前端滑条上限同步 + 「平方锥度非线性」标注 + 「当前值只读显示锥度后百分比」。
- 后端补缺口:
/api/system补reboot_reason/upgrade_status:svc_power 读级查询POWER_REBOOT_REASON(8)/POWER_UPGRADE_STATUS(9)(st.msg分别为coldboot=reboot|shutdown|unknown、upgrade=yes|no);查询失败回空串不谎报。 前端批1-B 已留位(读d.reboot_reason/d.upgrade_status),此处点亮。/api/overviewnet 块并入 DNS 统计:netmgrd 状态 JSON 剥外层括号拼入{"net":{…,"dns":{…}}}(复用/api/net/dns同款统计);DNS 不可用则省略dns键仅保留网络状态,绝不假数据。首页 netCard 改读net.dns,去掉单独/api/net/dns(首页严格单请求)。
6. 与协议的出入(「实现为准 + 原因」,供回改 MEOWPANEL_PROTOCOL.md)
ui.style值域:meow_settings.c g_defs源码为"md3,miui"(label "Material You,MIUI"),但 SYSTEM_SETTINGS.md 定案 + MEOWPANEL_PROTOCOL §5 一致行为miuix(对应MEOW_STYLE_MIUIX),前端data-style也用miuix。 → 本表对齐为"md3,miuix"/ "Material You,MIUIx"。建议同步改回meow_settings.c g_defs(否则实体设置页与面板值域漂移)。- 设置项映射:协议 §3.2 称后端经
meow_settings_*读写;因后端为独立进程,无法链接 launcher 内 API, 改为直接镜像同一份settings.conf(同款 parse/save 契约)。改哪边都会落同一文件,实体/网页/CLI 仍同步(listener/落盘)。 display.brightness元数据:g_defs为min=0 max=255 def=101;但语义 clamp 到[brightness_min(1),100](防 101 闪屏)。后端给前端min=1 max=100(协议 §3.2 期望),读值经 clamp 后返回(默认→100)。若回改协议可注明「原始表 0-255,面板展示语义 1-100」。/api/system的network/ota:M2.73 起 perf 服务已聚合network段(真实 WiFiwpa_cli/ip+ 蓝牙hci0/sysfs +hostname_local,SYSTEM 子集),后端直接透传;只补boot.default(读/data/meow_boot_default)与ota{current=version,available:false,url:null}。网络栏以「蓝牙」为准(设备无网口,无以太网一行,bluetooth.available=false显示「无蓝牙」)。若回改协议可注明「network 已并入 perf 服务,ota 为面板占位」。/api/files上传/删除/重命名等 path:前端对这些操作传绝对路径(d.path/子项),列表传相对 root; 后端normalize_path对两者均容错(相对则拼 root,绝对则直用),符合协议「白名单根 + 规范化」。GET /api/files返回值:files_list返回500语义时以 500 封装(协议未定义root之外错误枚举,用通用错误信封)。- 通知清单数据源:协议 §3.8 称后端「经通知后端读取」。launcher 现已有客户端查询/撤/清 IPC(
MSG_NOTIFY_QUERY(0x25)/MSG_NOTIFY_DISMISS(0x22)/MSG_NOTIFY_DISMISS_ALL(0x26),agent-199 落地),后端改为优先经这些 IPC 取 launcher 内存活跃集 (实时,source:"ipc");IPC 不可达/超时回退读 TF 卡通知转储日志(source:"tf",会话级归档)。响应额外带source与items别名 (与notifications同内容);items为任务约定空态形状,notifications为前端实际读取字段,二者并存。撤/清同样优先走 IPC联动 launcher 内存;clear语义为「保留活动中的媒体/进度通知」(ongoing||media||progress>=0),对应通知中心既定语义。 /api/files/read文本截断:协议 §3.4 称「仅文本(<1MB)→ 二进制 415」;现实现为「预览上限 1MB,超限truncated:true, 不再整体 404」,二进制仍 415(比协议更友好,返回文件真实size+truncated)。/api/files/upload/rename修正:上传文件名经safe_filename取 basename、拒绝../分隔符(防../../etc/passwd逃逸), 落盘前对 dir 与拼接后路径双重normalize_path+白名单校验;rename 的新路径 = 原路径父目录 +new_name(原实现误拼到文件尾部, 恒 ENOTDIR 失败)。上传体上限MAX_UPLOAD_BODY=8MB,超限 → 413PAYLOAD_TOO_LARGE。- TF 卡根可覆盖(宿主测试):
env MEOW_TF_ROOT覆盖卡根(设备上不设,恒用/usr/data/mnt/sd_0);env MEOW_NOTIF_LOG覆盖通知转储日志路径。设MEOW_TF_ROOT时tf_present()恒真(测试用)。 - 实时画面/触摸注入(阶段 C):协议 §6 待定案项称「实时画面(
/api/frame等,本文件暂未定义)」。本面板落地为GET /api/screen.jpeg+POST /api/input/tap(命名自定:.jpeg表达二进制帧 +input/tap表达触摸注入), 见 §5.10。回改协议时可补这两端点(以及frames语义、/api/input/tap的dispatched:false/reason软失败约定)。 - multipart 二进制查找修正(strstr→memmem,本次修复,属 bug 修复非出入变更):
parse_multipart/multipart_extract_file均用strstr(data_start, boundary)定位 part 数据边界——strstr 遇到数据中的 NUL 字节即提前停止(含 NUL 的二进制 .tar.gz/.mpk/图会误把后续 boundary 与拖尾算进数据 → 解压出错)。已改二进制安全的mem_find(memmem 语义,手写字节扫描, 不依赖 glibc/musl 扩展)。这修复了字体库 tar.gz 导入,也顺带修复了二进制.mpk/文件上传的潜在同病。实现优先,供回改协议/审计。 /api/fonts*(新增,§5.11):协议 §2 端点总览无此组;按 SPEC_REF §5.7.6「MeowPanel 预留 .zip 导入/导出」落地——但用户 2026-08-31 定案:改 tar.gz、放弃 zip(与 .mpk 同构)。落地为/api/fonts(列表)//api/fonts/import(导入,POST multipart, 上限 32MB,?force=1覆盖)//api/fonts/export(导出,GET,<family>-<weight>.font.tar.gz)。前两者由前端设置页「字体库」卡接入。 还修正了/api/files排序:目录优先 + 名称自然排序(数字感知 track2<track10,中文按无符号字节序,见 §5.4)。 导入不触发 launcher 重扫(扫描时机=启动/进设置页),响应用hint提示。/api/audio(新增,§5.12):协议 §2 无此端点。按 AUDIOD_DESIGN §8「MSG_AUDIO_STATE 供 MeowPanel 系统/音频页展示」落地—— 连 audiod sock 发MSG_AUDIO_QUERY(0x00C7)、收MSG_AUDIO_STATE(0x00C8) k=v 文本解析为 JSON 透传;audiod 无握手、 不在时回{"available":false}(200,非错误)。前端新增「音频」页(5s 轮询只读)。同批新增前端「字体」页(§5.13,/api/fonts*的专属页;设置页字体库卡保留)。
7. 已知边界 / 风险
- 单线程串行:面板访问量极小,但并发请求会被排队(长上传/下载期间其它请求等待)。对面板用途可接受。
- 字体导入内存/体积上限:
POST /api/fonts/import上传体上限 32MB(MAX_FONT_UPLOAD,仅此端点放宽;其余 multipart 仍 8MB);tar 解压到临时目录的总大小 ≤FONT_EXTRACT_MAX=32MB(防 gzip 炸弹)。全程不做整读进内存 (写临时文件 +gzip -dc | tar管道 + rename),峰值内存很小,不依赖 dma/font.png 大件缓冲——相比内存解压方案的 14MB 约束更稳健。 ⚠️ 依赖设备 busyboxgzip/tar(必带);若某内核裁剪过二者,导入/导出会失败(400/500),列表不受影响。 - 无鉴权(默认):设备内网信任模型(协议 §1.3)。高危端点(
reboot/shutdown/ota/apps/删除/上传)在默认关鉴权时无鉴权, 请勿把 8080 暴露到不可信网络。meow_svc_power服务端做SO_PEERCRED uid==0` 基础校验(root 才受理动作),后端以 root 运行可过;launcher 电源菜单/后端同链路。 可选鉴权(§5.9)开启后可对内网作加固(登录密码 + 会话),但密码经局域网明文 HTTP 传输,不提供 TLS。 - IPC 服务未起:
meow_svc_perf/meow_svc_power为板载trigger=boot服务,正常恒在;若异常退出,读侧返回 500INTERNAL, 动作侧返回 500/503,绝不静默。请勿拔除这两服务。 - 升级保护:
POWER_UPGRADE由meow_svc_power在写 mtd5 前校验卡根r3proii.upt(存在/可读/非空/size>0),失败不写 mtd5;期望 md5/hash 校验留二期。 - 文件/日志/应用均依赖 TF 卡:无卡统一 503
NO_CARD(不阻塞系统核心)。settings/system/perf/key无卡也可用(板载/rootfs)。 /api/files/upload上传路径:multipart 需要path字段(目标目录);缺失时上传文件会被忽略(前端总是带着path)。- 数据一致性:设置直接写
settings.conf;display.brightness/boot.default的 clamp/同步与 launchermeow_settings_*同口径。 若 launcher 未来改 clamp 逻辑,需同步本表。 - 通知 IPC 路径为 launcher 内存活跃集(实时):优先
MSG_NOTIFY_QUERY取活跃集;TF 归档日志仅在 launcher 不可达时作为 回退(此时才出现「会话级归档」语义——非 activity 通知 10s TTL 自动归档后仍留日志,会显示已过期历史直到 clear;媒体/进度/ongoing 常驻)。 IPC 响应为 launcher 的m_notify_query_result_t单帧文本(≤4KB),活跃通知超限时 launcher 侧meow_notif_serialize_json保前缀截断 (理论上最多 ~30 条,实际通知数远小,可接受)。 - 通知撤/清联动 launcher 内存:面板 delete/dismiss_all 优先走 IPC(launcher 撤下时自动归档留档);仅 IPC 不可达时回退重写 TF 日志。
- 增量帧依赖单线程基线:
/api/screen.jpeg?delta=1用上一帧缓存比对,面板为单线程 accept 循环(跨请求持久);对单面板用户直接有效。 多客户端混用(一全帧+一增量、跨浏览器)时增量基线可能被另一客户端发的全帧刷新,前端「canvas 未播种则整帧取图」兜底自愈;极端并发下增量图 可能基于过期基线(可容忍,仅多发一帧整帧即校准)。子图为独立 JPEG(4:2:0 在子图内自采样),与整帧同源同质量,无拼接色差。 - 上传为「限长缓冲」非全流式:multipart 请求体整体读入(上限 8MB,超限 413),下载为流式(8KB 分块)。严格「socket 逐字节流式上传 解析」未实现(需增量 multipart 解析器),列为后续;14MB 内存约束下 8MB 上限 + 流式下载已覆盖大文件读侧。
- 存储为
meowpanel编译时刻写死的 socket/路径会因--sock-perf/--sock-power(qemu sim)可覆盖,但默认走/usr/data/meow_*.sock。 - 触摸注入在设备息屏时不生效:launcher 主界面在
meow_screen_on==0时不处理触摸(main_menu.c,息屏防误触);设备自动息屏 (30s 空闲)后注入的 tap 会被 launcher 忽略——面板无法用触摸唤醒(需先电源键点亮)。前端「屏幕」页已提示「设备息屏请先点亮」; 对「正在看」设备的正常使用场景(屏幕亮着)注入即有效。 - 实时画面读取 fb0 当前帧(只读):双层缓冲下
pread活动缓冲,存在翻页瞬间撕裂一行的可能(1fps 预览可接受);/dev/fb0不可读/非 16bpp → 500INTERNAL(绝不静默)。 - JPEG 编码器为 baseline 4:2:0:质量 70 下 480×720 ≈ 24KB;质量越高体积越大(
q=100约 60-80KB)。编码为单线程 串行(面板本就单线程),一帧编码约几十 ms(MIPS 单核),1fps 轮询无压力。 - 触摸注入为即时性注入:不维护长按/多指手势状态机(与按键注入一致);
dispatched:false(本机触摸仲裁)属软失败, 前端可按reason提示,不视为错误。
8. 文件清单(本目录)
patch_v2/meowpanel/
├── meowpanel.c # 后端源码(约 5590 行,-Wall -Wextra 0 warning;含可选鉴权/内联 SHA-256/实时画面+增量帧/触摸注入/通知 IPC 实时化/字体库 tar.gz 导入导出/自然排序/audiod 状态快照 + 批2 崩溃/日志中心 + 音频写 + overview DNS 聚合)
├── mp_jpeg.c # 最小 baseline JPEG 编码器(顺序 DCT + 4:2:0 + 标准 Huffman,整数定点,无 libm,-Wall -Wextra 0 warning)
├── mp_jpeg.h # mp_jpeg.c 接口(RGB565 → 内存 JPEG)
├── build_meowpanel.sh # 交叉编译 + host 分支(-Wall -Wextra 0 warning;meowpanel.c + mp_jpeg.c)
├── meowpanel # 交叉产物(mipsel 静态,约 218 KB,md5 015f9cf1…)
├── meowpanel_host # 宿主编译(本机 ld,调试用)
├── services.d/
│ └── meowpanel.conf # 部署到 TF 卡 MeowOS/services.d/meowpanel.conf
├── web/ # 前端(已存在;部署时拷到后端同目录)
│ ├── index.html # 含登录页 overlay + 设置密码对话框 + 音频/字体导航
│ ├── meowpanel.css # 含登录页样式
│ └── meowpanel.js # API 客户端带 token/401 登录、设置页鉴权卡片、音频页(5s轮询)/字体页
└── README.md # 本文件