- 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;宿主测试全过;二进制留批量批次未入库
168 lines
8.2 KiB
C
168 lines
8.2 KiB
C
/* mp_power.c — 功耗管理域:meow_powermgr IPC(/api/power*,policy,window,events)。 */
|
||
#include "mp.h"
|
||
|
||
|
||
int ipc_pm_query(uint32_t subset, char *out, int cap)
|
||
{
|
||
int fd = ipc_connect_tmo(g_sock_pm, IPC_TIMEOUT_MS);
|
||
if (fd < 0) return MEOW_ERR_NODEV;
|
||
int rc = MEOW_ERR_INTERNAL;
|
||
if (ipc_hello(fd) < 0) { rc = MEOW_ERR_INTERNAL; goto done; }
|
||
m_pm_query_t q;
|
||
memset(&q, 0, sizeof q);
|
||
q.subset = subset;
|
||
if (send_frame(fd, MSG_PM_QUERY, 0x31, &q, sizeof q) < 0) { rc = MEOW_ERR_IO; goto done; }
|
||
uint8_t buf[MEOW_IPC_MAX];
|
||
uint16_t type; uint32_t rid;
|
||
int n = recv_frame(fd, &type, &rid, buf, sizeof buf);
|
||
if (n < 12) { rc = MEOW_ERR_IO; goto done; } /* code(4)+subset(4)+json_len(2)+pad(2) */
|
||
if (type != MSG_PM_RESULT) { rc = MEOW_ERR_INVAL; goto done; }
|
||
uint32_t c; memcpy(&c, buf, 4);
|
||
if (c != MEOW_OK) { rc = (int)c; goto done; }
|
||
/* powermgr 发**紧凑**负载:json 从偏移 12 起(json_len 在偏移 8);同 m_pm_result_t 布局,兼容全量/紧凑。 */
|
||
uint16_t jl; memcpy(&jl, buf + 8, 2);
|
||
if (jl > MEOW_IPC_MAX - 12) jl = (uint16_t)(MEOW_IPC_MAX - 12);
|
||
if ((size_t)jl >= (size_t)cap) jl = (uint16_t)(cap - 1);
|
||
memcpy(out, buf + 12, jl);
|
||
out[jl] = 0;
|
||
rc = MEOW_OK;
|
||
done:
|
||
close(fd);
|
||
return rc;
|
||
}
|
||
|
||
int api_power(int sock)
|
||
{
|
||
char js[MEOW_IPC_MAX];
|
||
int rc = ipc_pm_query(0, js, sizeof js);
|
||
if (rc != MEOW_OK || !utf8_valid_n(js, strlen(js))) /* 上游坏字节 → 不返回,降级 */
|
||
return send_err(sock, 503, "POWER_UNAVAILABLE", "电源管理服务不可用");
|
||
return send_json(sock, 200, js);
|
||
}
|
||
|
||
int ipc_pm_send(uint16_t req_type, const void *pl, uint32_t plen,
|
||
uint16_t *rtype, char *out, int cap)
|
||
{
|
||
int fd = ipc_connect_tmo(g_sock_pm, IPC_TIMEOUT_MS);
|
||
if (fd < 0) return MEOW_ERR_NODEV;
|
||
int rc = MEOW_ERR_INTERNAL;
|
||
if (rtype) *rtype = 0;
|
||
if (ipc_hello(fd) < 0) { rc = MEOW_ERR_INTERNAL; goto done; }
|
||
if (send_frame(fd, req_type, 0x41, pl, plen) < 0) { rc = MEOW_ERR_IO; goto done; }
|
||
uint8_t buf[MEOW_IPC_MAX];
|
||
uint16_t type; uint32_t rid;
|
||
int n = recv_frame(fd, &type, &rid, buf, sizeof buf);
|
||
if (n <= 0) { rc = MEOW_ERR_IO; goto done; }
|
||
if (rtype) *rtype = type;
|
||
if (type == MSG_ERR) {
|
||
m_err_t e; memcpy(&e, buf, sizeof e);
|
||
rc = (int)e.code; goto done;
|
||
}
|
||
if (n < 12) { rc = MEOW_ERR_IO; goto done; } /* code(4)+subset(4)+json_len(2)+pad(2) */
|
||
uint32_t c; memcpy(&c, buf, 4);
|
||
if (c != MEOW_OK) { rc = (int)c; goto done; }
|
||
uint16_t jl; memcpy(&jl, buf + 8, 2);
|
||
if (jl > MEOW_IPC_MAX - 12) jl = (uint16_t)(MEOW_IPC_MAX - 12);
|
||
if ((size_t)jl >= (size_t)cap) jl = (uint16_t)(cap - 1);
|
||
memcpy(out, buf + 12, jl); out[jl] = 0;
|
||
rc = (int)jl;
|
||
done:
|
||
close(fd);
|
||
return rc;
|
||
}
|
||
|
||
/* 在对象 JSON(已剥尾部 `}`、经 utf8 校验)上拼 guard③ `policy_write_enabled` 顶层键:
|
||
* 拼完 jv_parse 自校验,绝不发非法 JSON(防 overview 教训);失败返回 -1(调用方回 500,绝不带病下发)。 */
|
||
int power_policy_append_flag(sbuf_t *out, const char *obj)
|
||
{
|
||
sA(out, "%s", obj);
|
||
sA(out, ",\"policy_write_enabled\":%s}", panel_policy_write_enabled() ? "true" : "false");
|
||
jv_t *chk = jv_parse(out->b ? out->b : "{}", (int)(out->b ? out->n : 2));
|
||
if (!chk) return -1;
|
||
jv_free(chk);
|
||
return 0;
|
||
}
|
||
|
||
int api_power_policy_get(int sock)
|
||
{
|
||
char js[MEOW_IPC_MAX];
|
||
uint16_t rt = 0;
|
||
int rc = ipc_pm_send(MSG_PM_POLICY_GET, NULL, 0, &rt, js, sizeof js);
|
||
if (rc <= 0)
|
||
return send_err(sock, 503, "POWER_UNAVAILABLE", "电源管理服务不可用(powermgr 未运行/IPC 不可达)");
|
||
if (rt != MSG_PM_RESULT || !utf8_valid_n(js, strlen(js)))
|
||
return send_err(sock, 503, "POWER_UNAVAILABLE", "电源管理服务应答包含非法字节");
|
||
/* 追加顶层 `policy_write_enabled`(面板侧 gate 状态,独立于 powermgr 的 `enacted`):
|
||
* 稳妥剥外层括号再拼(同 net_block_fill 手法)。上游非对象(数组/文本)时原样透传、不带该键
|
||
* (前端缺省视为已开启,兼容旧 powermgr)。 */
|
||
size_t l = strlen(js);
|
||
while (l && (js[l - 1] == ' ' || js[l - 1] == '\t' || js[l - 1] == '\n' || js[l - 1] == '\r')) js[--l] = 0;
|
||
if (l < 2 || js[0] != '{' || js[l - 1] != '}') return send_json(sock, 200, js);
|
||
js[l - 1] = 0; /* 去尾部 } */
|
||
sbuf_t s = {0};
|
||
if (power_policy_append_flag(&s, js) != 0) { sbuf_free(&s); return send_err(sock, 500, "INTERNAL", "电源策略聚合输出未通过 JSON 自校验"); }
|
||
int out = send_json(sock, 200, s.b ? s.b : "{}");
|
||
sbuf_free(&s);
|
||
return out;
|
||
}
|
||
|
||
int api_power_policy_set(int sock, const char *body, size_t body_len)
|
||
{
|
||
if (!body || !body[0]) return send_err(sock, 400, "BAD_REQUEST", "缺少 body");
|
||
/* guard③ policy 默认关:写端点默认关闭,须在设置开启 panel.policy_enabled 才放行(只读 GET 不受此限)。
|
||
* 注意:powermgr 侧另有 `enacted`(策略是否已应用),本 gate 是面板侧写入口门禁,二者独立。 */
|
||
if (!panel_policy_write_enabled())
|
||
return send_err(sock, 403, "POLICY_DISABLED", "电源策略写默认关闭:先到面板设置开启 panel.policy_enabled(危险操作)");
|
||
jv_t *root = jv_parse(body, (int)body_len);
|
||
if (!root) return send_err(sock, 400, "BAD_REQUEST", "body 非合法 JSON");
|
||
jv_t *ji = jv_obj_get(root, "item"), *jv = jv_obj_get(root, "value");
|
||
char item[20] = "", val[40] = "";
|
||
if (ji && ji->type == J_STR && ji->str) snprintf(item, sizeof item, "%s", ji->str);
|
||
if (jv && jv->type == J_STR && jv->str) snprintf(val, sizeof val, "%s", jv->str);
|
||
else if (jv && jv->type == J_NUM) snprintf(val, sizeof val, "%lld", jv->inum);
|
||
jv_free(root);
|
||
if (!item[0]) return send_err(sock, 422, "UNSUPPORTED", "缺 item(profile/low-pct/crit-pct/bri-cap/scr-cap)");
|
||
if (!val[0]) return send_err(sock, 422, "UNSUPPORTED", "缺 value");
|
||
|
||
m_pm_policy_set_t s; memset(&s, 0, sizeof s);
|
||
snprintf(s.item, sizeof s.item, "%.15s", item); /* item[16] 留一个 NUL;防越界截断告警 */
|
||
snprintf(s.val, sizeof s.val, "%.31s", val); /* val[32] 同理 */
|
||
char js[MEOW_IPC_MAX];
|
||
uint16_t rt = 0;
|
||
int rc = ipc_pm_send(MSG_PM_POLICY_SET, &s, sizeof s, &rt, js, sizeof js);
|
||
if (rc <= 0) {
|
||
if (rt == MSG_ERR) /* 权限不足:powermgr 拒绝(面板 root 仅当被白名单才放行;如实回传) */
|
||
return send_err(sock, 403, "FORBIDDEN", rc == MEOW_ERR_PERM ? "设备身份不允许写电源策略" : "电源策略写入被拒绝");
|
||
return send_err(sock, 503, "POWER_UNAVAILABLE", "电源管理服务不可用(powermgr 未运行/IPC 不可达)");
|
||
}
|
||
if (rt != MSG_PM_RESULT || !utf8_valid_n(js, strlen(js)))
|
||
return send_err(sock, 503, "POWER_UNAVAILABLE", "电源管理服务应答包含非法字节");
|
||
/* 服务端对非法值回 ok:false(HTTP 层 200,code 仍 OK);按其 why 映射 422。 */
|
||
if (strstr(js, "\"ok\":false")) {
|
||
char why[96] = "";
|
||
jv_t *jr = jv_parse(js, (int)strlen(js));
|
||
if (jr) { jv_t *w = jv_obj_get(jr, "why"); if (w && w->type == J_STR && w->str) snprintf(why, sizeof why, "%s", w->str); jv_free(jr); }
|
||
return send_err(sock, 422, "UNSUPPORTED", why[0] ? why : "非法电源策略值");
|
||
}
|
||
return send_json(sock, 200, js);
|
||
}
|
||
|
||
int api_power_window(int sock, uint16_t req_type, uint16_t want_type, const char *unavail)
|
||
{
|
||
uint32_t count = 0;
|
||
char js[MEOW_IPC_MAX];
|
||
uint16_t rt = 0;
|
||
int rc = ipc_pm_send(req_type, &count, sizeof count, &rt, js, sizeof js);
|
||
if (rc <= 0)
|
||
return send_err(sock, 503, "POWER_UNAVAILABLE", unavail);
|
||
if (rt != want_type || !utf8_valid_n(js, strlen(js)))
|
||
return send_err(sock, 503, "POWER_UNAVAILABLE", "电源管理服务应答包含非法字节");
|
||
return send_json(sock, 200, js);
|
||
}
|
||
|
||
int api_power_history(int sock)
|
||
{ return api_power_window(sock, MSG_PM_HISTORY, MSG_PM_HISTORY_RESULT, "电源历史采样不可用(powermgr 未运行)"); }
|
||
|
||
int api_power_events(int sock)
|
||
{ return api_power_window(sock, MSG_PM_EVENTS, MSG_PM_EVENTS_RESULT, "电源事件不可用(powermgr 未运行)"); }
|