Files
MeowOS-For-R3P2/patch_v2/meowpanel/src/mp_power.c
T
AskaEth 2826c1e905 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;宿主测试全过;二进制留批量批次未入库
2026-09-04 18:13:18 +08:00

168 lines
8.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 未运行)"); }