feat: M6.40批 — 阅读器UI改版(书架list·grid+空态骨架+界面设置+App设置页+header·footer+背景黑默认) + 系统级音量翻页映射 + P1 MD3(select面板28/对话框按钮胶囊) + MeowPanel写端点护栏 + SDK公开仓·文档同步

- reader: app.c/shelf.c/reader.c 全套UI; 新增 reader_conf(reader.conf)/settings(App设置页)/reader_ipc(音量翻页IPC响应); app.json加volume_page
- launcher: keys.c meow_volpage_*门 + util.c app_id→fd映射(HELLO记fd/断开清) + app_launcher.c 前台三处接线(进入sink/按键路径volpage_key/离开clear) → 前台声明volume_page的App音量键→MSG_KEY_PAGEUP/PAGEDOWN翻页(非阅读器前台音量照旧)
- sdk: meow_select.c 底部面板28 + meow_ui_dialog.c 对话框按钮胶囊(h/2) + test_meow_ui_select.c修采样
- meowpanel: /api/net/policy·/api/power/policy 加防自锁+policy默认关两条护栏(panel.policy_enabled默认0)
- 文档: MEOW_APP_SDK.md §12.6 + meowpanel README端点表

0warning;宿主测试全过;二进制留批量批次未入库
This commit is contained in:
AskaEth committed 2026-09-04 18:13:18 +08:00
1 parent b364b6371a
commit 2826c1e905
27 files changed
+1704 -129

No files matched your search

+81 -10
View File
@@ -25,6 +25,10 @@ cd /home/Aska/Project/R3ProII/patch_v2/meowpanel
./build_meowpanel.sh host # 宿主编译 → meowpanel_host(本机 ld,仅供调试)
```
- **后端源码已按模块拆分**(`src/*.c` + 共享内部头 `src/mp.h`):`mp_server`(HTTP/路由/main) + `mp_util`/`mp_json` + `mp_store`(设置/主题) + `mp_ipc`(IPC 帧/单一收发) + 各 api_* 域 `mp_perf`/`mp_power`/`mp_audio`/`mp_net`/`mp_ams`/`mp_svcd`/`mp_files`/`mp_fonts`/`mp_apps`/`mp_logs`/`mp_notif`/`mp_auth`/`mp_key`/`mp_screen`。
`mp.h` 承载全部共享类型/常量/外部全局 + 跨模块函数原型;每个 `.c` 以 `#include "mp.h"` 起步。
拆分保持后端接口/行为**完全不变**(宿主 `-Wall -Wextra` 0 warning;重编产物与拆分前**逐字节一致**——同一 mock 环境全端点 diff 无差异)。
原单体 `meowpanel.c` 保留在根目录作参考,**不在构建源列表**(构建以 `src/*.c` 为准)。
- 两分支均以 `-Os -Wall -Wextra` 复核,**0 warning**(`-Werror` 亦通过)。
- 产出(本次构建实测):
- `meowpanel`:mipsel 静态,`ELF 32-bit LSB executable, MIPS, MIPS32 rel2, statically linked, stripped`,
@@ -120,8 +124,19 @@ http://<host>.local:8080/
| 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/ams/bg` | **后台活动列表**(M6.38,批④):`am list` 仅取 `state=="bg"`,逐进程 `/proc` 采样 `VmRSS`/`cpu_pct`(首采样/不可得→`null` 前端显 `—`,绝不编造);同源于 amsd FG/BG 元数据,杀/清走既有 `/api/ams/:pkg/kill` | ✅(只读,需 PIN 会话;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/overview` | **首页聚合**(单线程后端只暴露聚合):后端顺序 fan-out perf/power+events/audio/net+union dns/ams+fg/svcd 六源合成一份 JSON;任一源失败→该子块 `available:false`,绝不假数据 | ✅(**读级,需 PIN 会话**) |
| GET | `/api/net/ifaces` | 接口列表详情(kind/ip/gw/rx/tx/rssi/rfkill/dns;netmgrd 0xE2+0xE0 合成) | ✅(只读,需 PIN 会话) |
| GET | `/api/net/policy` | 管控策略只读(0xEA SHOW;`enforce=dns_only` 如实)+ **`policy_write_enabled`**(guard③ 门禁状态)| ✅(只读,需 PIN 会话;上游坏字节→`available:false`) |
| POST | `/api/net/policy` | 写管控策略(`set_net`/`set_domain`/`del`):**guard① 防自锁**(`SELF_LOCK` 422)+ **guard③ 默认关**(`POLICY_DISABLED` 403)+ 二次确认 | ✅(**写级**,PIN 会话;自锁→422,门禁→403,IPC 权限→403 FORBIDDEN) |
| GET | `/api/power/policy` | 电源策略快照(profile 四档/阈值/`enacted`)+ **`policy_write_enabled`**(guard③;注入后 jv_parse 自校验) | ✅(只读,需 PIN 会话;坏字节→503) |
| POST | `/api/power/policy` | 写电源策略(**只写 settings.conf `power.*` 键**):**guard③ 默认关**(`POLICY_DISABLED` 403)+ 二次确认 | ✅(**写级**,PIN 会话;非法值→422,权限→403) |
| GET | `/api/power/events` | 电源异常事件(充放电/低电/亮灭屏/背光跳变;overview 摘要 top2 的来源) | ✅(只读,需 PIN 会话;powermgr 不在→503) |
| GET | `/api/power/history` | 功耗采样历史(30s 环形 4h,不落盘) | ✅(只读,需 PIN 会话;powermgr 不在→503) |
| GET | `/api/ams/:pkg` | 单 App incident 历史(`am history`,崩溃根因 detail;坏 detail→降级 `available:false`) | ✅(只读,需 PIN 会话) |
| POST | `/api/ams/:pkg/start` | 启动 App(`am start <pkg>`;**写级**,PIN 会话) | ✅(包名非法→400,launcher 离线→503) |
| POST | `/api/ams/:pkg/kill` | 结束 App(`am kill <pkg>`;**写级**,PIN 会话,前台前端二次确认) | ✅(包名非法→400,not registered→404,busy→409) |
| GET | `/api/apps` | 扫描 `MeowAPPs/` 读 `app.json` | ✅ |
| GET | `/api/apps/:pkg` | 应用详情 | ✅ |
| POST | `/api/apps/install` | 经 `nyai install`(multipart 或 path) | ✅ |
@@ -396,6 +411,33 @@ http://<host>.local:8080/
同款统计);DNS 不可用则省略 `dns` 键仅保留网络状态,**绝不假数据**。首页 netCard 改读 `net.dns`,去掉单独 `/api/net/dns`
(首页严格单请求)。
### 5.16 批 P1 写端点(power/net/ams 写)+ 三条护栏(MEOWPANEL_ENHANCE_PLAN P1)
> 三个写端点全部落在 `POST` 分支 + `require_auth` 之后(无一漏到无鉴权路径);响应**如实回错误码**,绝不掩盖。
- **三条护栏**:
1. **guard① 防自锁**(仅 `/api/net/policy`):对系统关键网络/服务组件禁设「阻断」(`set_net`+`arg=block`、
或任何 `set_domain` 域名限制)。命中即 `422 {"code":"SELF_LOCK"}`。自锁实体(取 `svc:|app:|proc:` 后裸名),
`net_locked_entity()` 精确比对 `dropbear/wpa_supplicant/udhcpc/netmgrd/svcd/sysui/init`(netmgrd 加载时也剔除,面板侧抢先硬拒)。
「放行 / 删除规则」不阻断(恢复连通)仍放行。
2. **guard② PIN 会话鉴权**:复用全局 `require_auth`(§5.9);无会话 → `401 UNAUTHORIZED`。
3. **guard③ 策略写默认关**:`panel.policy_enabled`(新设置项,`settings.conf`「面板」组,默认 `0`)。
`0`(缺省)时 `POST /api/net/policy`、`POST /api/power/policy` 在解析 body **前**即拒 `403 POLICY_DISABLED`
(只读 GET 不受此限);置 `1`(设置页 / 电源·网络策略卡的「开启策略写」)放行。与 powermgr `enacted` **独立**。
- **`POST /api/net/policy`**:`{op:"set_net|set_domain|del", entity:"app:…|svc:…|proc:…", arg:"…"}`(`del` 免 `arg`)。
成功 `{"accepted":true,"message":…}`;权限→`403 FORBIDDEN`、非法→`422 UNSUPPORTED`、自锁→`422 SELF_LOCK`、门禁→`403 POLICY_DISABLED`、
IPC 不可达→`503 NET_UNAVAILABLE`。`enforce=dns_only` 如实显示「仅 DNS 层拒绝」,不谎称断连。
- **`GET /api/net/policy`**:`net_policy_parse` 输出 `{"available":true,"policy_write_enabled":<bool>,"enforce","log_level","rules":[…]}`;
坏字节(实体名/域名)降级 `{"available":false}`。前端据此渲染「默认关」横幅 + 「开启策略写」(`enablePolicyWrite`)。
- **`POST /api/power/policy`**:`{item:"profile|low-pct|crit-pct|bri-cap|scr-cap", value:"…"}`,**只写 settings.conf `power.*` 键**;
成功后透传 powermgr 应答。非法值→`422`(服务端 `ok:false` 按 `why` 映射)、权限→`403`、门禁→`403 POLICY_DISABLED`、
IPC 不可达→`503 POWER_UNAVAILABLE`。
- **`GET /api/power/policy`**:透传 powermgr 策略快照(含 `enacted`)后经 `power_policy_append_flag()` **追加顶层 `policy_write_enabled`**
(剥尾拼键 + jv_parse 自校验,绝不发非法 JSON);非对象答原样透传。
- **`POST /api/ams/:pkg/{start,kill}`**:`am start/kill <pkg>`;包名经 `ams_pkg_ok`(仅 ASCII 可见、禁 `/ : 空白`)。成功
`{"accepted":true,"op","pkg","message"}`;`not registered`→404、`busy`/`not running`→409、`launcher offline`→503、其余→500。
**kill 前台 App 前端二次确认**。
---
## 6. 与协议的出入(「实现为准 + 原因」,供回改 MEOWPANEL_PROTOCOL.md)
@@ -486,17 +528,46 @@ http://<host>.local:8080/
```
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)
├── meowpanel.c # 拆分前单体源码(约 6372 行,保留作参考,**不在构建源列表**;构建以 src/*.c 为准)
├── src/ # 后端模块化源码(模块化拆分,接口/行为不变,-Wall -Wextra 0 warning)
│ ├── mp.h # 共享内部头:全部共享类型/常量/外部全局 + 跨模块函数原型(含鉴权/实时画面等)
│ ├── mp_server.c # HTTP 服务器/路由分发 + 静态托管 + main(单线程 + poll 串行)
│ ├── mp_util.c # sbuf/UTF-8 消毒/内存搜索/命令管道/路径与 token 工具
│ ├── mp_json.c # 最简 JSON 解析/序列化(jv_t 树)
│ ├── mp_store.c # 设置镜像(settings.conf)+ 主题 + /api/settings*,/api/theme* + g_sets 表
│ ├── mp_ipc.c # IPC 帧读写 + meow_svc_perf/power/netmgr 客户端(单点收发)+ socket 路径
│ ├── mp_perf.c # /api/perf,/api/system,action,pin-unlock(perf 聚合)
│ ├── mp_power.c # meow_powermgr IPC(/api/power*,policy,window,events)+ ipc_pm_send
│ ├── mp_audio.c # meow_audiod IPC(状态快照 + 写命令 route/volume)
│ ├── mp_net.c # meow_netmgrd IPC(状态/连接/DNS/ifaces/policy,期2/期3)
│ ├── mp_ams.c # App 运行表 + amd 历史 + start/kill 控制
│ ├── mp_svcd.c # svcd 服务表 + 首页聚合 /api/overview
│ ├── mp_files.c # 路径安全/白名单 + /api/files* + multipart 上传 + 卡根路径
│ ├── mp_fonts.c # 字体库 tar.gz 导入/导出 + 列表(busybox gzip|tar 管道)
│ ├── mp_apps.c # MeowAPPs 扫描 + nyai 安装/导出/移除
│ ├── mp_logs.c # /api/logs 列表 + 读 + 崩溃汇总
│ ├── mp_notif.c # 通知(优先 launcher IPC 活跃集,回退 TF 归档)
│ ├── mp_auth.c # 访问级 PIN 鉴权(panel.pin)+ 内联 SHA-256 + 内存会话
│ ├── mp_key.c # 按键注入(写 /dev/input/event* EV_KEY,物理键红线内)
│ └── mp_screen.c # 实时画面(fb0→JPEG,增量帧)+ 触摸注入 + delta 缓存
├── mp_jpeg.c # 最小 baseline JPEG 编码器(顺序 DCT + 4:2:0 + 标准 Huffman,整数定点,无 libm)
├── 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…)
├── build_meowpanel.sh # 交叉编译 + host 分支(-Wall -Wextra 0 warning;src/*.c + mp_jpeg.c + -I.)
├── meowpanel # 交叉产物(mipsel 静态,本次 md5 fead4852…)
├── 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 # 本文件
└── web/ # 前端(模块化拆分;部署时拷到后端同目录)
├── index.html # 含登录页 overlay + 设置密码对话框 + 音频/字体导航;脚本按序加载
├── meowpanel.css # 含登录页样式 + 「屏幕·遥控」合并页样式(screen-remote/remote-btn)
├── mp_shared.js # 共享框架:全局状态 + API 客户端(token/401) + 公共工具 + 主题/弹窗/登录/滑条(window.MP)
├── mp_pages.js # 各页渲染/绑定:home/perf/power/audio/net/files/apps/fonts/settings/system/logs/notif/proc + 合并的屏幕·遥控
└── meowpanel.js # 前端入口:ROUTES/路由/启动(读取 window.MP 装配)
```
**前端拆分说明**:`meowpanel.js`(单体 IIFE)按「公共 util+api(client) / 各页渲染 / 应用入口」拆为
`mp_shared.js` + `mp_pages.js` + `meowpanel.js` 三文件(经典脚本按序加载,函数体保持原样,仅顶部从
`window.MP` 解构共享框架,**行为不变**)。
「屏幕」+「控制」两页**合并为一页**(route `screen`,导航「屏幕·遥控」):内容区左侧=屏幕实时画面
(复用 /api/screen.jpeg + 触摸注入 + fps 滑条 + 增量省流开关),右侧=MD3 矢量图标遥控板(音量± / 亮度± /
指定亮度滑条 / 播放·暂停 / 下一曲 / 上一曲 / 电源单击 / 电源长按),**全矢量内联 SVG,无 emoji**。
`返回`/`主页` 属物理键红线(后端 /api/key 禁注入 158/172),未提供注入按钮(遥控板附说明)。