feat(system): 系统框架一期 — 专项服务(性能/电源)+IPC+电源CLI+电菜单改经服务(agent-155)
- meow_svc_power: 单一二进制(svcd空参IPC常驻 /usr/data/meow_power.sock + root CLI免鉴权), 12命令(shutdown/reboot强制=0/upgrade/set-default-hiby/reboot--hiby + set-default-meow/status/screen/dac(status仅)/battery/reboot-reason/upgrade-status); 动作同源sys_do_reboot/set_boot_default_hiby/mtd5=ota:kernel2; dac on/off无控制点不支持 - meow_svc_perf: IPC(/usr/data/meow_perf.sock MSG_PERF_*) + CLI, 聚合/proc/df/thermal/version/uname JSON(与MEOWPANEL_PROTOCOL对齐) - power_menu.c 改经 meow_power_action(launcher先转储再IPC), 删sys_do_reboot/set_boot_default_hiby; 4动作+8s强关+confirm_reboot_player+3处长按强关全经服务; launcher内 sys_do_reboot/bootmode.sh/set_boot_default_hiby 0调用 - meow_ipc.h 仅加 MSG_PERF_QUERY/RESULT(0x50/51)+MSG_POWER_ACTION/STATUS(0x60/61)+POWER_*(12)+m_perf/power_t; 未动既有 - S89meow_svcd 预置 meow_svc_perf/power.conf(trigger=boot); 各独立socket - IPC鉴权一期=SO_PEERCRED uid==0基础(完整os.meow.*二期); 通知转储=launcher先转储再IPC(二期补launcher→服务通道); 失败安全(服务不可达→按取消,不静默不直连) - meow_svc_power=32d6be92/meow_svc_perf=7b0f3b64/launcher=d90f09e9/svcd=fb2d608b(未动)/meow_ui.a=92e61fb8(未改); 全0warning; 备份power_menu.c.pre-svc.bak回退
This commit is contained in:
1 parent
898bc176c9
commit
23727cf400
16 files changed
+1559
-41
No files matched your search
@@ -555,7 +555,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
* M2.37:阈值接 power.forceoff_ms(默认 8000),强关保持 > 弹菜单上限。 */
|
||||
if (t - pwr_hold_at >= power_forceoff_ms && !pwr_menu_state) {
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] POWER HOLD %dms -> would force poweroff", power_forceoff_ms); }
|
||||
else { logmsg("pm: POWER HOLD %dms -> force poweroff", power_forceoff_ms); sys_do_reboot(LINUX_REBOOT_CMD_POWER_OFF); }
|
||||
else { logmsg("pm: POWER HOLD %dms -> force poweroff", power_forceoff_ms); meow_power_action(POWER_SHUTDOWN); }
|
||||
m_prev_pwr = pwr; continue;
|
||||
} else if (t - pwr_hold_at >= power_longpress_menu_ms && !pwr_menu_state) {
|
||||
pwr_menu_state = 1;
|
||||
|
||||
@@ -52,6 +52,10 @@ enum {
|
||||
MSG_ACT_BACK = 0x0034, /* ↑ 上报回到根/无 activity(清 keep_awake,M2.17) */
|
||||
MSG_NAV = 0x0040, /* ↑ 上报导航/请求退出 */
|
||||
MSG_SHOW_ACTIVITY= 0x0041, /* ↓ 令前端应用显示某屏 */
|
||||
MSG_PERF_QUERY = 0x0050, /* ↑ 性能/系统聚合查询(专项服务 meow_svc_perf) */
|
||||
MSG_PERF_RESULT = 0x0051, /* ↓ 聚合 JSON(perf/system 子集) */
|
||||
MSG_POWER_ACTION = 0x0060, /* ↑ 电源/系统动作信号(专项服务 meow_svc_power) */
|
||||
MSG_POWER_STATUS = 0x0061, /* ↓ 动作受理/结果 + 状态文本 */
|
||||
MSG_SYS = 0x00F0 /* ↓ 系统事件(守护关闭/服务死亡/播放器状态) */
|
||||
};
|
||||
|
||||
@@ -165,4 +169,56 @@ typedef struct m_notify_progress {
|
||||
int32_t progress; /* 0-100;<0=清除进度条 */
|
||||
} m_notify_progress_t; /* 8 B */
|
||||
|
||||
/* ================= 专项服务 IPC(SYSTEM_FRAMEWORK_SERVICES §2.2/§2.3)= */
|
||||
|
||||
/* ---- MSG_PERF_QUERY 子集位(0=全部)---- */
|
||||
#define PERF_SUBSET_PERF (1u << 0) /* cpu/mem/uptime/temp/storage/tfcard */
|
||||
#define PERF_SUBSET_SYSTEM (1u << 1) /* system(version/hostname/kernel/arch) */
|
||||
|
||||
/* MSG_PERF_QUERY ↑:性能/系统聚合查询(服务端 meow_svc_perf) */
|
||||
typedef struct m_perf_query {
|
||||
uint32_t subset; /* 0=全部;PERF_SUBSET_* 组合 */
|
||||
} m_perf_query_t; /* 4 B */
|
||||
|
||||
/* MSG_PERF_RESULT ↓:聚合 JSON(payload 为 NUL 结尾 JSON 文本) */
|
||||
typedef struct m_perf_result {
|
||||
uint32_t code; /* MEOW_OK / MEOW_ERR_* */
|
||||
uint32_t subset; /* 回显请求 subset */
|
||||
uint16_t json_len; /* json 有效字节(不含 NUL) */
|
||||
uint16_t pad;
|
||||
char json[MEOW_IPC_MAX - 12]; /* 聚合 JSON(.data 形状,§2.2) */
|
||||
} m_perf_result_t;
|
||||
|
||||
/* ---- POWER_* 动作枚举(m_power_action_t.cmd;与 CLI §2.4 同源)---- */
|
||||
enum {
|
||||
POWER_SHUTDOWN = 0, /* 关机 */
|
||||
POWER_REBOOT = 1, /* 重启回 MeowOS(强制写 boot_default=0) */
|
||||
POWER_UPGRADE = 2, /* 写 mtd5=ota:kernel2 进升级模式 */
|
||||
POWER_BACK_HIBY = 3, /* 写 boot_default=1 + reboot(回 HiBy) */
|
||||
POWER_SET_DEFAULT_MEOW = 4, /* 只写 boot_default=0,不重启 */
|
||||
POWER_SET_DEFAULT_HIBY = 5, /* 只写 boot_default=1,不重启 */
|
||||
POWER_STATUS = 6, /* 综合状态查询 */
|
||||
POWER_BATTERY = 7, /* 电池查询 */
|
||||
POWER_REBOOT_REASON = 8, /* 上次重启原因 */
|
||||
POWER_UPGRADE_STATUS = 9, /* 升级标志(mtd5=ota:kernel2?) */
|
||||
POWER_SCREEN = 10, /* 屏幕电源:flag 0=off/1=on/2=timeout(秒取 arg) */
|
||||
POWER_DAC = 11 /* DAC:flag 0=off/1=on/2=status */
|
||||
};
|
||||
|
||||
/* MSG_POWER_ACTION ↑:电源/系统动作信号(服务端 meow_svc_power) */
|
||||
typedef struct m_power_action {
|
||||
uint32_t cmd; /* POWER_* 枚举 */
|
||||
uint32_t flag; /* 随 cmd;POWER_SCREEN/DAC 用 */
|
||||
char arg[32]; /* 可选文本参数(如 screen timeout 秒数字符串) */
|
||||
} m_power_action_t; /* 40 B */
|
||||
|
||||
/* MSG_POWER_STATUS ↓:动作受理/结果 + 状态文本(CLI/IPC 展示) */
|
||||
typedef struct m_power_status {
|
||||
uint32_t code; /* MEOW_OK / MEOW_ERR_PERM / MEOW_ERR_INVAL / MEOW_ERR_NODEV */
|
||||
uint32_t cmd; /* 回显 cmd */
|
||||
uint16_t msg_len; /* msg 有效字节(不含 NUL) */
|
||||
uint16_t pad;
|
||||
char msg[96]; /* 结果/状态文本 */
|
||||
} m_power_status_t;
|
||||
|
||||
#endif /* MEOW_IPC_H */
|
||||
@@ -624,7 +624,9 @@ void settings_volume_adj(int delta);
|
||||
int settings_volume_get(void);
|
||||
int show_power_menu(void);
|
||||
int stop_player(void);
|
||||
void sys_do_reboot(int cmd);
|
||||
/* 电源管理服务 IPC(SYSTEM_FRAMEWORK_SERVICES §3.2:launcher 电源动作经 meow_svc_power 执行) */
|
||||
int pm_power_ipc(uint32_t cmd, uint32_t flag, const char *arg, char *res, int reslen);
|
||||
int meow_power_action(uint32_t cmd);
|
||||
void ui_draw(int x, int y, const char *s, uint32_t color, int size);
|
||||
int ui_width(const char *s, int size);
|
||||
void unblank_panel(void);
|
||||
|
||||
Binary file not shown.
@@ -930,7 +930,7 @@ void run_notif_center(struct app *apps, int napps, int *want_launch,
|
||||
if (pwr && pwr_hold_at) {
|
||||
if (now - pwr_hold_at >= power_forceoff_ms && !pwr_menu_state) {
|
||||
if (sim_no_exec) logmsg("notif-center pm: [sim-no-exec] hold %dms -> would forceoff", power_forceoff_ms);
|
||||
else { logmsg("notif-center pm: hold %dms -> force poweroff", power_forceoff_ms); sys_do_reboot(LINUX_REBOOT_CMD_POWER_OFF); }
|
||||
else { logmsg("notif-center pm: hold %dms -> force poweroff", power_forceoff_ms); meow_power_action(POWER_SHUTDOWN); }
|
||||
} else if (now - pwr_hold_at >= power_longpress_menu_ms && !pwr_menu_state) {
|
||||
pwr_menu_state = 1;
|
||||
logmsg("notif-center pm: hold %dms -> power menu", power_longpress_menu_ms);
|
||||
|
||||
@@ -70,25 +70,102 @@ static void draw_pm_button(int i, int selected)
|
||||
}
|
||||
}
|
||||
|
||||
void sys_do_reboot(int cmd)
|
||||
/* ---- 电源管理服务 IPC 客户端(SYSTEM_FRAMEWORK_SERVICES §3.2:launcher 经服务触发电源动作)----
|
||||
* launcher 不再直连 reboot(2)syscall/写 mtd5/写 boot 默认 —— 统一经 meow_svc_power 的
|
||||
* `/usr/data/meow_power.sock`(`MEOW_IPC_POWER_SOCK` 可覆盖)发 MSG_POWER_ACTION。 */
|
||||
#define PW_SOCK_DEFAULT "/usr/data/meow_power.sock"
|
||||
|
||||
static int pw_write_all(int fd, const uint8_t *b, size_t n)
|
||||
{
|
||||
/* M2a:正常电源事件(关机/重启)触发清除板载通知数据之前,先转储所有未上卡通知
|
||||
* (NOTIFICATION_SYSTEM.md §8)。meow_notif_before_poweroff 幂等安全(未 init 直接返回)。 */
|
||||
meow_notif_before_poweroff();
|
||||
sync(); /* 先落盘,避免数据丢失 */
|
||||
logmsg("sys_do_reboot cmd=0x%x", cmd);
|
||||
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, NULL);
|
||||
logmsg("sys_do_reboot returned: %s", strerror(errno)); /* 正常不会返回 */
|
||||
for (;;) usleep(1000); /* 防御:永不返回 */
|
||||
size_t off = 0;
|
||||
while (off < n) { ssize_t w = write(fd, b + off, n - off); if (w <= 0) return -1; off += (size_t)w; }
|
||||
return 0;
|
||||
}
|
||||
static int pw_read_all(int fd, uint8_t *b, size_t n)
|
||||
{
|
||||
size_t off = 0;
|
||||
while (off < n) { ssize_t r = read(fd, b + off, n - off); if (r <= 0) return -1; off += (size_t)r; }
|
||||
return 0;
|
||||
}
|
||||
/* 发一帧并等应答(读超时 1.5s,服务不可达/无响应不至于卡死菜单)。 */
|
||||
static int pw_xchg(int fd, uint16_t type, uint32_t req, const void *pl, uint32_t len,
|
||||
uint8_t *rbuf, uint32_t rcap, uint16_t *rtype)
|
||||
{
|
||||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||||
uint32_t magic = MEOW_IPC_MAGIC, rlen = len;
|
||||
uint16_t ver = MEOW_IPC_VERSION, t = type;
|
||||
memcpy(hdr + 0, &magic, 4); memcpy(hdr + 4, &ver, 2); memcpy(hdr + 6, &t, 2);
|
||||
memcpy(hdr + 8, &req, 4); memcpy(hdr + 12, &rlen, 4);
|
||||
if (pw_write_all(fd, hdr, sizeof hdr) < 0) return -1;
|
||||
if (len && pl && pw_write_all(fd, pl, len) < 0) return -1;
|
||||
struct pollfd pf = { fd, POLLIN, 0 };
|
||||
int pr = poll(&pf, 1, 1500);
|
||||
if (pr <= 0) return -1;
|
||||
uint8_t rhdr[MEOW_IPC_HDR_LEN];
|
||||
if (pw_read_all(fd, rhdr, sizeof rhdr) < 0) return -1;
|
||||
uint32_t rmagic, rlen2; uint16_t rver, rt;
|
||||
memcpy(&rmagic, rhdr, 4); memcpy(&rver, rhdr + 4, 2); memcpy(&rt, rhdr + 6, 2);
|
||||
memcpy(&rlen2, rhdr + 12, 4);
|
||||
if (rmagic != MEOW_IPC_MAGIC || rver != MEOW_IPC_VERSION) return -1;
|
||||
if (rlen2 > rcap) rlen2 = rcap;
|
||||
if (rlen2 && pw_read_all(fd, rbuf, rlen2) < 0) return -1;
|
||||
if (rtype) *rtype = rt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 回HibyOS:写板载 /data/meow_boot_default=1(开机默认权威标记,O_TRUNC 单值、不写 TF 卡),
|
||||
* 再 reboot 回选单并默认 HibyOS。meow.conf 不再写/承载 boot_default(bootmenu 以板载标记为准)。 */
|
||||
static void set_boot_default_hiby(void)
|
||||
/* 经电源服务执行动作。返回 MEOW_OK 或错误码;res/reslen 可收状态文本。 */
|
||||
int pm_power_ipc(uint32_t cmd, uint32_t flag, const char *arg, char *res, int reslen)
|
||||
{
|
||||
int fd = open("/data/meow_boot_default", O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd >= 0) { write(fd, "1\n", 2); close(fd); logmsg("pm: /data/meow_boot_default=1"); }
|
||||
const char *sock = getenv("MEOW_IPC_POWER_SOCK");
|
||||
if (!sock || !sock[0]) sock = PW_SOCK_DEFAULT;
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) return MEOW_ERR_IO;
|
||||
struct sockaddr_un a;
|
||||
memset(&a, 0, sizeof a);
|
||||
a.sun_family = AF_UNIX;
|
||||
strncpy(a.sun_path, sock, sizeof a.sun_path - 1);
|
||||
if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { close(fd); return MEOW_ERR_IO; }
|
||||
m_hello_t h;
|
||||
memset(&h, 0, sizeof h);
|
||||
snprintf(h.app_id, sizeof h.app_id, "%s", "os.meow.launcher");
|
||||
h.version = 1;
|
||||
uint8_t rbuf[256]; uint16_t rtype = 0;
|
||||
if (pw_xchg(fd, MSG_HELLO, 0x100, &h, sizeof h, rbuf, sizeof rbuf, &rtype) < 0 || rtype != MSG_ACK) {
|
||||
close(fd); return MEOW_ERR_IO;
|
||||
}
|
||||
m_ack_t ak;
|
||||
memcpy(&ak, rbuf, sizeof ak);
|
||||
if (ak.code != MEOW_OK) { close(fd); return (int)ak.code; }
|
||||
m_power_action_t pa;
|
||||
memset(&pa, 0, sizeof pa);
|
||||
pa.cmd = cmd;
|
||||
pa.flag = flag;
|
||||
if (arg) snprintf(pa.arg, sizeof pa.arg, "%s", arg);
|
||||
if (pw_xchg(fd, MSG_POWER_ACTION, 0x101, &pa, sizeof pa, rbuf, sizeof rbuf, &rtype) < 0 || rtype != MSG_POWER_STATUS) {
|
||||
close(fd); return MEOW_ERR_IO;
|
||||
}
|
||||
m_power_status_t st;
|
||||
memcpy(&st, rbuf, sizeof st);
|
||||
close(fd);
|
||||
if (res && reslen > 0) {
|
||||
uint16_t ml = st.msg_len;
|
||||
if (ml >= (uint16_t)reslen) ml = (uint16_t)(reslen - 1);
|
||||
memcpy(res, st.msg, ml);
|
||||
res[ml] = 0;
|
||||
}
|
||||
return (int)st.code;
|
||||
}
|
||||
|
||||
/* launcher 侧统一电源动作入口:先转储未上卡通知(进程本地,见 §3.2 定案),再经服务 IPC 执行。
|
||||
* 返回 MEOW_OK=已受理(服务将执行,通常随即 reboot/poweroff);非 OK=服务不可达/拒绝,调用方应
|
||||
* 稳妥处理(如菜单按「取消」返回,绝不误报动作成功导致 launcher 退出卡死)。 */
|
||||
int meow_power_action(uint32_t cmd)
|
||||
{
|
||||
meow_notif_before_poweroff(); /* 幂等安全(未 init 直接返回) */
|
||||
int rc = pm_power_ipc(cmd, 0, NULL, NULL, 0);
|
||||
if (rc != MEOW_OK)
|
||||
logmsg("meow_power_action cmd=%u FAILED rc=%d (power service unavailable?)", cmd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -225,8 +302,12 @@ int show_power_menu(void)
|
||||
/* 8s 强关(绕过):仅当电源持续按住、且用户全程未与菜单互动才触发 —— 放在触摸/按键处理
|
||||
* 之后,避免「用户已点选按钮」的同一轮被强关抢先(M2.10 Bug)。 */
|
||||
if (pwr && !pm_interacted && now_ms() - pm_t0 >= 5000) {
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] POWER HOLD 8s -> would force poweroff"); }
|
||||
else { logmsg("pm: POWER HOLD 8s -> force poweroff"); sys_do_reboot(LINUX_REBOOT_CMD_POWER_OFF); }
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] POWER HOLD 8s -> would force poweroff"); return 1; }
|
||||
logmsg("pm: POWER HOLD 8s -> force poweroff");
|
||||
if (meow_power_action(POWER_SHUTDOWN) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort force-off (menu closed, no action)");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -247,35 +328,44 @@ int show_power_menu(void)
|
||||
}
|
||||
if (tfd >= 0) close(tfd);
|
||||
|
||||
/* M2.11 B:电源键在菜单 = 按当前项确认。act 与 syscall 类型逐项核对:
|
||||
* act==4(取消) -> 只关菜单,绝不关机(return 0,永不到 reboot);
|
||||
* act==0(关机) -> 才 poweroff;act==1(重启)/act==2(回HibyOS)/act==3(升级模式) -> 才 reboot。
|
||||
* 只有 act 为 0/1/2/3 才可能执行 sys_do_reboot;power 键本身绝不触发关机。 */
|
||||
/* M2.11 B:电源键在菜单 = 按当前项确认。act 与电源动作逐项核对:
|
||||
* act==4(取消) -> 只关菜单,绝不关机(return 0,永不到电源动作);
|
||||
* act==0(关机)/act==1(重启)/act==2(回HibyOS)/act==3(升级模式) -> 才经服务 IPC 执行电源动作。
|
||||
* 只有 act 为 0/1/2/3 才可能发电源动作;power 键本身绝不触发关机。 */
|
||||
logmsg("pm: act=%d -> %s", act,
|
||||
act == 0 ? "关机" : act == 1 ? "重启" : act == 2 ? "回HibyOS" : act == 3 ? "升级模式" : "取消");
|
||||
if (act == 4) { logmsg("pm: cancel (close menu only)"); return 0; }
|
||||
/* 动作统一经电源管理服务 IPC(meow_svc_power);launcher 不再直连 poweroff/reboot(2)/写 mtd5/
|
||||
* 写 boot 默认——关机/重启/升级/回HiBy 的动作原语都在服务内实现(§3.2 单一动作链路)。 */
|
||||
/* 公共服务:执行动作;服务不可达 → 按「取消」返回(launcher 存活,绝不误报已动作卡死)。
|
||||
* meow_power_action 内部已先 meow_notif_before_poweroff()(转储未上卡通知)。 */
|
||||
if (act == 0) {
|
||||
logmsg("pm: POWER OFF");
|
||||
if (!sim_no_exec) {
|
||||
/* 先显关机 logo(cmd_jpeg_display 是独立二进制,能正常显图),再直连 poweroff */
|
||||
system("PATH=/bin:/sbin:/usr/bin:/usr/sbin cmd_jpeg_display /etc/shutdown_logo.jpeg >/dev/null 2>&1");
|
||||
sys_do_reboot(LINUX_REBOOT_CMD_POWER_OFF);
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would poweroff"); return 1; }
|
||||
if (meow_power_action(POWER_SHUTDOWN) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort (menu closed, no action)");
|
||||
return 0;
|
||||
}
|
||||
} else if (act == 1) {
|
||||
logmsg("pm: REBOOT");
|
||||
if (!sim_no_exec) sys_do_reboot(LINUX_REBOOT_CMD_RESTART);
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would reboot"); return 1; }
|
||||
if (meow_power_action(POWER_REBOOT) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort (menu closed, no action)");
|
||||
return 0;
|
||||
}
|
||||
} else if (act == 2) {
|
||||
logmsg("pm: RETURN TO HIBYOS");
|
||||
set_boot_default_hiby();
|
||||
if (!sim_no_exec) sys_do_reboot(LINUX_REBOOT_CMD_RESTART);
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would reboot to hiby"); return 1; }
|
||||
if (meow_power_action(POWER_BACK_HIBY) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort (menu closed, no action)");
|
||||
return 0;
|
||||
}
|
||||
} else if (act == 3) {
|
||||
/* M2.29 升级模式:写 mtd5=ota:kernel2(bootmode.sh Recovery = flash_erase + nandwrite)
|
||||
* 再 reboot —— uboot 读 mtd5=ota:kernel2 引导 kernel2(升级模式,自动刷 TF 卡
|
||||
* r3proii.upt,双进度条,跑完重启进新固件)。已验证此链路可靠。 */
|
||||
logmsg("pm: ENTER UPGRADE");
|
||||
if (!sim_no_exec) {
|
||||
system("PATH=/bin:/sbin:/usr/bin:/usr/sbin /usr/bin/bootmode.sh Recovery >/dev/null 2>&1");
|
||||
sys_do_reboot(LINUX_REBOOT_CMD_RESTART);
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would enter upgrade"); return 1; }
|
||||
if (meow_power_action(POWER_UPGRADE) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort (menu closed, no action)");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
@@ -396,8 +486,11 @@ int confirm_reboot_player(void)
|
||||
if (tfd >= 0) close(tfd);
|
||||
if (act == 0) {
|
||||
logmsg("reboot-to-player: YES -> default HibyOS + reboot");
|
||||
set_boot_default_hiby();
|
||||
if (!sim_no_exec) sys_do_reboot(LINUX_REBOOT_CMD_RESTART);
|
||||
if (sim_no_exec) { logmsg("reboot-to-player: [sim-no-exec] would reboot to hiby"); return 1; }
|
||||
if (meow_power_action(POWER_BACK_HIBY) != MEOW_OK) {
|
||||
logmsg("reboot-to-player: power service unavailable, abort (stay in MeowOS)");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
logmsg("reboot-to-player: cancel");
|
||||
|
||||
@@ -1045,7 +1045,7 @@ void run_settings_page(void)
|
||||
* 时触发;开过菜单则交给菜单内确认/取消,杜绝「开菜单->取消->仍按住->强关」残留。 */
|
||||
if (now - pwr_hold_at >= power_forceoff_ms && !pwr_menu_state) {
|
||||
if (sim_no_exec) { logmsg("settings pm: [sim-no-exec] POWER HOLD %dms -> would force poweroff", power_forceoff_ms); }
|
||||
else { logmsg("settings pm: POWER HOLD %dms -> force poweroff", power_forceoff_ms); sys_do_reboot(LINUX_REBOOT_CMD_POWER_OFF); }
|
||||
else { logmsg("settings pm: POWER HOLD %dms -> force poweroff", power_forceoff_ms); meow_power_action(POWER_SHUTDOWN); }
|
||||
/* 关机一般不复返;若 reboot 失败返回仍按按住处理(m_prev 由下方统一复写) */
|
||||
} else if (now - pwr_hold_at >= power_longpress_menu_ms && !pwr_menu_state) {
|
||||
pwr_menu_state = 1;
|
||||
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
# build_svc_perf.sh — meow_svc_perf 交叉编译(mipsel 静态)+ 宿主编译可选。
|
||||
#
|
||||
# 目标:R3 Pro II / MeowOS(mipsel-linux-muslsf,静态)。性能服务仅 POSIX + Linux 基接口
|
||||
# (复用 meow_ipc.h 帧格式,无 launcher 依赖),单文件满足「固件内、不入卡」(<200KB 阈值)。
|
||||
#
|
||||
# 用法:
|
||||
# ./build_svc_perf.sh # 交叉编译 → patch_v2/meow_svc_perf/meow_svc_perf(mipsel 静态)
|
||||
# ./build_svc_perf.sh host # 宿主编译 → patch_v2/meow_svc_perf/meow_svc_perf_host
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
ROOT="$HOME/Project/R3ProII"
|
||||
CC="$ROOT/.tools/zig-mipsel-cc"
|
||||
I_HDR="$ROOT/patch_v2/meow_launcherd" # meow_ipc.h(帧/m_perf_query_t/m_perf_result_t)
|
||||
|
||||
if [ "$1" = "host" ]; then
|
||||
HOST_CC="${CC_HOST:-cc}"
|
||||
"$HOST_CC" -Os -Wall -Wextra -I"$I_HDR" meow_svc_perf.c -o meow_svc_perf_host
|
||||
echo "== host build =="
|
||||
ls -la meow_svc_perf_host
|
||||
file meow_svc_perf_host
|
||||
exit 0
|
||||
fi
|
||||
|
||||
"$CC" -Os -Wall -Wextra -static -I"$I_HDR" meow_svc_perf.c -o meow_svc_perf
|
||||
echo "== meow_svc_perf (mipsel static) =="
|
||||
ls -la meow_svc_perf
|
||||
md5sum meow_svc_perf
|
||||
file meow_svc_perf
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,523 @@
|
||||
#define _GNU_SOURCE /* gethostname 等 GNU/musl 扩展 */
|
||||
|
||||
/* meow_svc_perf.c — MeowOS 性能分析专项子服务(SYSTEM_FRAMEWORK_SERVICES §1.2/§2.2)。
|
||||
*
|
||||
* 单一二进制双形态:
|
||||
* - svcd 以**空参**拉起(§1.3 conf `args=` 空)→ IPC 服务常驻:bind `/usr/data/meow_perf.sock`
|
||||
* (`--sock`/`MEOW_IPC_PERF_SOCK` 可覆盖),收 MSG_HELLO→MSG_ACK、MSG_PERF_QUERY→MSG_PERF_RESULT。
|
||||
* - root shell `meow_svc_perf [query]` → 一次性 CLI(免鉴权)打印聚合 JSON(不常驻)。
|
||||
*
|
||||
* 聚合的数据源与 launcher `about.c`/`util.c`/bootmenu**同源**(/proc/stat、/proc/meminfo、
|
||||
* /proc/uptime、/proc/loadavg、/sys/class/thermal 各 zone、df/mount、/proc/cpuinfo、/etc/meowos_version、
|
||||
* gethostname/uname),聚合成与 MEOWPANEL_PROTOCOL §3.1 `/api/status`/.data 对齐的 JSON——
|
||||
* 单一权威源,MeowPanel 后端/launcher 不再各自爬 /proc。
|
||||
*
|
||||
* MSG_PERF_QUERY.subset 位掩码(m_perf_query_t):0=全部;PERF_SUBSET_PERF / PERF_SUBSET_SYSTEM。
|
||||
* 鉴权(一期):性能查询**只读安全**,本批不强制 os.meow.*;完整读级鉴权见 §5.3(二期)。
|
||||
*
|
||||
* 编译(mipsel 静态):build_svc_perf.sh;宿主编译 build_svc_perf.sh host。
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "meow_ipc.h" /* 帧格式/消息号 + m_perf_query_t/m_perf_result_t(与 launcher 同源) */
|
||||
|
||||
#define VERSION_FILE "/etc/meowos_version"
|
||||
#define TF_MOUNT "/usr/data/mnt/sd_0"
|
||||
#define MEOW_PIPE_MAX 4096
|
||||
#define MEOW_TIMEOUT_MS 1500
|
||||
|
||||
static const char *g_sock = "/usr/data/meow_perf.sock";
|
||||
|
||||
static void svc_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "[meow_svc_perf] ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* ---------------- 有界 JSON 追加 ---------------- */
|
||||
typedef struct { char *b; size_t n; size_t cap; } sbuf_t;
|
||||
|
||||
static void sA(sbuf_t *s, const char *fmt, ...)
|
||||
{
|
||||
if (s->n >= s->cap - 1) return;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int w = vsnprintf(s->b + s->n, s->cap - s->n, fmt, ap);
|
||||
va_end(ap);
|
||||
if (w < 0) return;
|
||||
if ((size_t)w >= s->cap - s->n) s->n = s->cap - 1;
|
||||
else s->n += (size_t)w;
|
||||
}
|
||||
|
||||
/* JSON 字符串转义(version/hostname 等;ASCII 常见字符直通,引号/反斜杠转义) */
|
||||
static void sA_str(sbuf_t *s, const char *v)
|
||||
{
|
||||
if (!v) v = "";
|
||||
sA(s, "\"");
|
||||
for (const char *p = v; *p; p++) {
|
||||
unsigned char c = (unsigned char)*p;
|
||||
if (c == '"' || c == '\\') { sA(s, "\\%c", (int)c); }
|
||||
else if (c < 0x20) { sA(s, "\\u%04x", c); }
|
||||
else sA(s, "%c", (int)c); /* buf 0x80.. 按字节透传(utf-8) */
|
||||
}
|
||||
sA(s, "\"");
|
||||
}
|
||||
|
||||
/* ---------------- 限时读整文件 ---------------- */
|
||||
static int read_file_txt(const char *path, char *buf, int cap)
|
||||
{
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd < 0) return -1;
|
||||
int n = 0;
|
||||
while (n < cap - 1) {
|
||||
ssize_t r = read(fd, buf + n, (size_t)(cap - 1 - n));
|
||||
if (r <= 0) break;
|
||||
n += (int)r;
|
||||
}
|
||||
close(fd);
|
||||
buf[n] = 0;
|
||||
while (n > 0 && (buf[n - 1] == '\n' || buf[n - 1] == '\r')) buf[--n] = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* ---------------- popen 限时读(kill 子进程防挂) ---------------- */
|
||||
static char *popen_read_tmo(int tmo_ms, const char *cmd)
|
||||
{
|
||||
int p[2];
|
||||
if (pipe(p) < 0) return NULL;
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) { close(p[0]); close(p[1]); return NULL; }
|
||||
if (pid == 0) { dup2(p[1], 1); close(p[0]); close(p[1]); execl("/bin/sh", "sh", "-c", cmd, (char *)0); _exit(127); }
|
||||
close(p[1]);
|
||||
fcntl(p[0], F_SETFL, fcntl(p[0], F_GETFL, 0) | O_NONBLOCK);
|
||||
char *buf = malloc(MEOW_PIPE_MAX);
|
||||
if (!buf) { close(p[0]); waitpid(pid, NULL, 0); return NULL; }
|
||||
size_t off = 0;
|
||||
int remain = tmo_ms;
|
||||
while (remain > 0 && off < MEOW_PIPE_MAX - 1) {
|
||||
struct pollfd pf = { p[0], POLLIN, 0 };
|
||||
int r = poll(&pf, 1, remain);
|
||||
if (r < 0) { if (errno == EINTR) continue; break; }
|
||||
if (r == 0) break;
|
||||
ssize_t rd = read(p[0], buf + off, MEOW_PIPE_MAX - 1 - off);
|
||||
if (rd == 0) break;
|
||||
if (rd < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; break; }
|
||||
off += (size_t)rd;
|
||||
}
|
||||
close(p[0]);
|
||||
waitpid(pid, NULL, 0);
|
||||
buf[off] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* ---------------- CPU ---------------- */
|
||||
/* /proc/stat 首行 "cpu user nice system idle iowait irq softirq steal ..."。 */
|
||||
static int g_cpu_prev[10];
|
||||
static int g_cpu_prev_init = 0;
|
||||
|
||||
static double cpu_usage_pct(void)
|
||||
{
|
||||
FILE *f = fopen("/proc/stat", "r");
|
||||
char line[256];
|
||||
if (!f || !fgets(line, sizeof line, f)) { if (f) fclose(f); return -1; }
|
||||
fclose(f);
|
||||
unsigned long long vals[10];
|
||||
char *p = line + 3; /* skip "cpu" */
|
||||
int n = 0;
|
||||
while (n < 10) {
|
||||
while (*p == ' ') p++;
|
||||
if (!*p || !isdigit((unsigned char)*p)) break;
|
||||
vals[n++] = strtoull(p, &p, 10);
|
||||
}
|
||||
if (n < 4) return -1;
|
||||
unsigned long long total = 0, idle = 0;
|
||||
for (int i = 0; i < n; i++) total += vals[i];
|
||||
idle = vals[3] + (n > 4 ? vals[4] : 0);
|
||||
if (!g_cpu_prev_init) {
|
||||
for (int i = 0; i < 10; i++) g_cpu_prev[i] = (int)vals[i];
|
||||
g_cpu_prev_init = 1;
|
||||
return 0;
|
||||
}
|
||||
unsigned long long dtotal = total, didle = idle;
|
||||
for (int i = 0; i < n; i++) if (i < 10) dtotal -= (unsigned long long)g_cpu_prev[i];
|
||||
if (n > 4) didle -= (unsigned long long)g_cpu_prev[3] + (unsigned long long)g_cpu_prev[4];
|
||||
else didle -= (unsigned long long)g_cpu_prev[3];
|
||||
for (int i = 0; i < 10; i++) g_cpu_prev[i] = (int)vals[i];
|
||||
if (!dtotal) return 0;
|
||||
double u = 100.0 * (double)(dtotal - didle) / (double)dtotal;
|
||||
if (u < 0) u = 0;
|
||||
return u;
|
||||
}
|
||||
|
||||
static int core_count(void)
|
||||
{
|
||||
FILE *f = fopen("/proc/stat", "r");
|
||||
char line[256];
|
||||
int n = 0;
|
||||
if (!f) return 1;
|
||||
while (fgets(line, sizeof line, f)) {
|
||||
if (line[0] == 'c' && line[1] == 'p' && line[2] == 'u' && isdigit((unsigned char)line[3]))
|
||||
n++;
|
||||
if (line[0] != 'c') break;
|
||||
}
|
||||
fclose(f);
|
||||
return n > 0 ? n : 1;
|
||||
}
|
||||
|
||||
static void loadavg(double *l1, double *l5, double *l15)
|
||||
{
|
||||
FILE *f = fopen("/proc/loadavg", "r");
|
||||
*l1 = *l5 = *l15 = 0;
|
||||
if (f) { if (fscanf(f, "%lf %lf %lf", l1, l5, l15) != 3) { *l1 = *l5 = *l15 = 0; } fclose(f); }
|
||||
}
|
||||
|
||||
/* ---------------- 内存 ---------------- */
|
||||
static void meminfo(unsigned long *total, unsigned long *used, unsigned long *free_kb,
|
||||
unsigned long *avail, unsigned long *stotal, unsigned long *sused)
|
||||
{
|
||||
*total = *used = *free_kb = *avail = *stotal = *sused = 0;
|
||||
FILE *f = fopen("/proc/meminfo", "r");
|
||||
if (!f) return;
|
||||
char k[64], line[256];
|
||||
unsigned long mtot = 0, mfree = 0, mavail = 0, swapT = 0, swapF = 0;
|
||||
while (fgets(line, sizeof line, f)) {
|
||||
unsigned long v;
|
||||
if (sscanf(line, "%63s %lu", k, &v) != 2) continue;
|
||||
if (!strcmp(k, "MemTotal:")) mtot = v;
|
||||
else if (!strcmp(k, "MemFree:")) mfree = v;
|
||||
else if (!strcmp(k, "MemAvailable:")) mavail = v;
|
||||
else if (!strcmp(k, "SwapTotal:")) swapT = v;
|
||||
else if (!strcmp(k, "SwapFree:")) swapF = v;
|
||||
}
|
||||
fclose(f);
|
||||
*total = mtot;
|
||||
*free_kb = mfree;
|
||||
if (mavail > 0) { *avail = mavail; *used = (mtot >= mavail) ? mtot - mavail : 0; }
|
||||
else { *avail = mfree; *used = (mtot >= mfree) ? mtot - mfree : 0; }
|
||||
*stotal = swapT;
|
||||
*sused = (swapT >= swapF) ? swapT - swapF : 0;
|
||||
}
|
||||
|
||||
static double uptime_sec(void)
|
||||
{
|
||||
FILE *f = fopen("/proc/uptime", "r");
|
||||
double up = 0;
|
||||
if (f) { if (fscanf(f, "%lf", &up) != 1) up = 0; fclose(f); }
|
||||
return up;
|
||||
}
|
||||
|
||||
/* ---------------- 温度(/sys/class/thermal/thermal_zone*;type 匹配 cpu→cpu,其余→board) ---------------- */
|
||||
static void temp_json(sbuf_t *s, int *any)
|
||||
{
|
||||
DIR *d = opendir("/sys/class/thermal");
|
||||
*any = 0;
|
||||
if (!d) { sA(s, "{}"); return; }
|
||||
double cpu = -1, board = -1;
|
||||
struct dirent *e;
|
||||
while ((e = readdir(d))) {
|
||||
if (strncmp(e->d_name, "thermal_zone", 12) != 0) continue;
|
||||
char path[300], typ[64] = "", tmp[32] = "";
|
||||
snprintf(path, sizeof path, "/sys/class/thermal/%s/type", e->d_name);
|
||||
read_file_txt(path, typ, sizeof typ);
|
||||
snprintf(path, sizeof path, "/sys/class/thermal/%s/temp", e->d_name);
|
||||
read_file_txt(path, tmp, sizeof tmp);
|
||||
long millideg = atol(tmp);
|
||||
if (millideg <= 0) continue;
|
||||
double c = (double)millideg / 1000.0;
|
||||
if (strstr(typ, "cpu") || strstr(typ, "CPU")) { if (cpu < 0) cpu = c; }
|
||||
else if (board < 0) board = c;
|
||||
}
|
||||
closedir(d);
|
||||
if (cpu < 0 && board < 0) { sA(s, "{}"); return; }
|
||||
sA(s, "{");
|
||||
int first = 1;
|
||||
if (cpu >= 0) { sA(s, "\"cpu\":%.1f", cpu); first = 0; }
|
||||
if (board >= 0) { if (!first) sA(s, ","); sA(s, "\"board\":%.1f", board); }
|
||||
sA(s, "}");
|
||||
*any = 1;
|
||||
}
|
||||
|
||||
/* ---------------- 存储(df -k <path> 第 2 行:右 5 字段 = fs,total,used,avail,use%,mount) ---------------- */
|
||||
static int df_parse(const char *path, unsigned long *total, unsigned long *used, unsigned long *avail)
|
||||
{
|
||||
*total = *used = *avail = 0;
|
||||
char cmd[160];
|
||||
snprintf(cmd, sizeof cmd, "PATH=/bin:/sbin:/usr/bin:/usr/sbin df -k %s 2>/dev/null", path);
|
||||
char *o = popen_read_tmo(MEOW_TIMEOUT_MS, cmd);
|
||||
if (!o) return -1;
|
||||
char *ln = strchr(o, '\n');
|
||||
if (ln) ln++;
|
||||
char *save = NULL;
|
||||
char *toks[8]; int nt = 0;
|
||||
for (char *tk = strtok_r(ln ? ln : o, " \t", &save); tk && nt < 8; tk = strtok_r(NULL, " \t", &save))
|
||||
toks[nt++] = tk;
|
||||
if (nt >= 5) { *total = strtoul(toks[nt - 5], NULL, 10); *used = strtoul(toks[nt - 4], NULL, 10); *avail = strtoul(toks[nt - 3], NULL, 10); }
|
||||
free(o);
|
||||
return (*total || *avail) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int tf_present(void)
|
||||
{
|
||||
FILE *f = fopen("/proc/mounts", "r");
|
||||
if (!f) return 0;
|
||||
char line[512];
|
||||
int present = 0;
|
||||
while (fgets(line, sizeof line, f)) {
|
||||
if (strstr(line, TF_MOUNT)) { present = 1; break; }
|
||||
}
|
||||
fclose(f);
|
||||
return present;
|
||||
}
|
||||
|
||||
/* ---------------- 系统静态(version/hostname/kernel/arch) ---------------- */
|
||||
static void sys_arch(char *out, int cap)
|
||||
{
|
||||
struct utsname u;
|
||||
const char *m = "mipsel";
|
||||
if (uname(&u) == 0) m = u.machine;
|
||||
if (strstr(m, "mips")) m = "mipsel"; /* mipsel-linux-muslsf 目标 */
|
||||
snprintf(out, cap, "%.31s", m);
|
||||
}
|
||||
|
||||
static void sys_kernel(char *out, int cap)
|
||||
{
|
||||
struct utsname u;
|
||||
size_t rl = 0;
|
||||
if (uname(&u) != 0) { snprintf(out, cap, "-"); return; }
|
||||
rl = strnlen(u.release, 64);
|
||||
if (rl > (size_t)(cap - 1)) rl = (size_t)(cap - 1);
|
||||
memcpy(out, u.release, rl);
|
||||
out[rl] = 0;
|
||||
}
|
||||
|
||||
/* ---------------- 聚合 JSON(subset 位掩码;与 MEOWPANEL_PROTOCOL §3.1 .data 对齐) ---------------- */
|
||||
static int agg_json(int subset, char *out, int cap)
|
||||
{
|
||||
int ip = (subset == 0) || (subset & PERF_SUBSET_PERF);
|
||||
int isys = (subset == 0) || (subset & PERF_SUBSET_SYSTEM);
|
||||
sbuf_t s = { out, 0, (size_t)cap };
|
||||
sA(&s, "{");
|
||||
int first = 1;
|
||||
#define SEP() do { if (!first) sA(&s, ","); first = 0; } while (0)
|
||||
|
||||
if (ip) {
|
||||
SEP(); sA(&s, "\"ts\":%ld", (long)time(NULL));
|
||||
SEP(); sA(&s, "\"uptime_sec\":%.0f", uptime_sec());
|
||||
double u = cpu_usage_pct(); int cores = core_count();
|
||||
double l1, l5, l15; loadavg(&l1, &l5, &l15);
|
||||
SEP(); sA(&s, "\"cpu\":{\"usage\":%.1f,\"cores\":%d,\"load\":[%.2f,%.2f,%.2f]}", u, cores, l1, l5, l15);
|
||||
unsigned long mtot, mused, mfree, mavail, swapT, swapU;
|
||||
meminfo(&mtot, &mused, &mfree, &mavail, &swapT, &swapU);
|
||||
SEP(); sA(&s, "\"memory\":{\"total\":%lu,\"used\":%lu,\"free\":%lu,\"available\":%lu,\"swap_total\":%lu,\"swap_used\":%lu}",
|
||||
mtot, mused, mfree, mavail, swapT, swapU);
|
||||
unsigned long st, su, sa;
|
||||
if (df_parse("/", &st, &su, &sa) == 0) {
|
||||
SEP();
|
||||
sA(&s, "\"storage\":{\"path\":\"/\",\"total\":%lu,\"used\":%lu,\"avail\":%lu}", st, su, sa);
|
||||
} else {
|
||||
SEP();
|
||||
sA(&s, "\"storage\":{\"path\":\"/\",\"total\":0,\"used\":0,\"avail\":0}");
|
||||
}
|
||||
if (tf_present()) {
|
||||
unsigned long tt, tu, ta;
|
||||
if (df_parse(TF_MOUNT, &tt, &tu, &ta) == 0) {
|
||||
SEP();
|
||||
sA(&s, "\"tfcard\":{\"present\":true,\"path\":\"" TF_MOUNT "\",\"total\":%lu,\"used\":%lu,\"avail\":%lu,\"filesystem\":\"exfat\"}", tt, tu, ta);
|
||||
} else {
|
||||
SEP();
|
||||
sA(&s, "\"tfcard\":{\"present\":true,\"path\":\"" TF_MOUNT "\",\"total\":0,\"used\":0,\"avail\":0,\"filesystem\":\"exfat\"}");
|
||||
}
|
||||
} else {
|
||||
SEP();
|
||||
sA(&s, "\"tfcard\":{\"present\":false,\"path\":\"" TF_MOUNT "\",\"total\":0,\"used\":0,\"avail\":0,\"filesystem\":null}");
|
||||
}
|
||||
int any;
|
||||
SEP(); sA(&s, "\"temp\":"); temp_json(&s, &any);
|
||||
}
|
||||
if (isys) {
|
||||
char ver[64] = "-", host[64] = "-", ker[64] = "-", arch[32] = "-";
|
||||
if (read_file_txt(VERSION_FILE, ver, sizeof ver) <= 0 || !ver[0]) snprintf(ver, sizeof ver, "-");
|
||||
if (gethostname(host, sizeof host) != 0 || !host[0]) snprintf(host, sizeof host, "-");
|
||||
sys_kernel(ker, sizeof ker);
|
||||
sys_arch(arch, sizeof arch);
|
||||
SEP(); sA(&s, "\"system\":{\"version\":");
|
||||
sA_str(&s, ver);
|
||||
sA(&s, ",\"hostname\":");
|
||||
sA_str(&s, host);
|
||||
sA(&s, ",\"kernel\":"); sA_str(&s, ker);
|
||||
sA(&s, ",\"arch\":"); sA_str(&s, arch);
|
||||
sA(&s, "}");
|
||||
}
|
||||
sA(&s, "}"); /* 外层闭合 */
|
||||
#undef SEP
|
||||
if (s.n >= (size_t)cap) s.n = (size_t)cap - 1;
|
||||
s.b[s.n] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------- IPC 帧读写 ---------------- */
|
||||
static int x_read_full(int fd, uint8_t *buf, size_t n)
|
||||
{
|
||||
size_t off = 0;
|
||||
while (off < n) { ssize_t r = read(fd, buf + off, n - off); if (r <= 0) return -1; off += (size_t)r; }
|
||||
return 0;
|
||||
}
|
||||
static int x_write_full(int fd, const uint8_t *buf, size_t n)
|
||||
{
|
||||
size_t off = 0;
|
||||
while (off < n) { ssize_t w = write(fd, buf + off, n - off); if (w <= 0) return -1; off += (size_t)w; }
|
||||
return 0;
|
||||
}
|
||||
static int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len)
|
||||
{
|
||||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||||
uint32_t magic = MEOW_IPC_MAGIC, rlen = len;
|
||||
uint16_t ver = MEOW_IPC_VERSION, t = type;
|
||||
memcpy(hdr + 0, &magic, 4); memcpy(hdr + 4, &ver, 2); memcpy(hdr + 6, &t, 2);
|
||||
memcpy(hdr + 8, &req_id, 4); memcpy(hdr + 12, &rlen, 4);
|
||||
if (x_write_full(fd, hdr, MEOW_IPC_HDR_LEN) < 0) return -1;
|
||||
if (len && payload && x_write_full(fd, payload, len) < 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
static int send_ack(int fd, uint32_t req_id, uint32_t code, uint32_t status)
|
||||
{
|
||||
m_ack_t a; memset(&a, 0, sizeof a); a.code = code; a.status = status;
|
||||
return send_frame(fd, MSG_ACK, req_id, &a, sizeof a);
|
||||
}
|
||||
static int send_err(int fd, uint32_t req_id, uint32_t code, const char *msg)
|
||||
{
|
||||
m_err_t e; memset(&e, 0, sizeof e);
|
||||
uint16_t ml = msg ? (uint16_t)strlen(msg) : 0;
|
||||
if (ml > 63) ml = 63;
|
||||
e.code = code; e.msg_len = ml;
|
||||
if (ml) memcpy(e.msg, msg, ml);
|
||||
return send_frame(fd, MSG_ERR, req_id, &e, sizeof e);
|
||||
}
|
||||
static int send_perf_result(int fd, uint32_t req_id, int subset, const char *json)
|
||||
{
|
||||
m_perf_result_t r;
|
||||
memset(&r, 0, sizeof r);
|
||||
r.code = MEOW_OK;
|
||||
r.subset = (uint32_t)subset;
|
||||
uint16_t jl = (uint16_t)strlen(json);
|
||||
if (jl > sizeof r.json - 1) jl = (uint16_t)(sizeof r.json - 1);
|
||||
memcpy(r.json, json, jl);
|
||||
r.json[jl] = 0;
|
||||
r.json_len = jl;
|
||||
return send_frame(fd, MSG_PERF_RESULT, req_id, &r, sizeof r);
|
||||
}
|
||||
|
||||
/* MSG_PERF_QUERY:读取 subset 后聚合。0=全部。 */
|
||||
static void handle_query(int c, uint32_t req_id, const uint8_t *payload, uint32_t rlen)
|
||||
{
|
||||
m_perf_query_t q;
|
||||
memset(&q, 0, sizeof q);
|
||||
if (rlen > sizeof q) rlen = sizeof q;
|
||||
memcpy(&q, payload, rlen);
|
||||
int subset = (q.subset == 0) ? 0 : (int)q.subset;
|
||||
char json[MEOW_IPC_MAX - 12];
|
||||
agg_json(subset, json, sizeof json);
|
||||
send_perf_result(c, req_id, subset, json);
|
||||
}
|
||||
|
||||
static void handle_conn(int c)
|
||||
{
|
||||
for (;;) {
|
||||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||||
if (x_read_full(c, hdr, sizeof hdr) < 0) break;
|
||||
uint32_t magic, rlen, req_id; uint16_t ver, type;
|
||||
memcpy(&magic, hdr, 4); memcpy(&ver, hdr + 4, 2); memcpy(&type, hdr + 6, 2);
|
||||
memcpy(&req_id, hdr + 8, 4); memcpy(&rlen, hdr + 12, 4);
|
||||
if (magic != MEOW_IPC_MAGIC || ver != MEOW_IPC_VERSION) { send_err(c, req_id, MEOW_ERR_INVAL, "bad magic/ver"); break; }
|
||||
if (rlen > MEOW_IPC_MAX) { send_err(c, req_id, MEOW_ERR_INVAL, "payload too big"); break; }
|
||||
uint8_t payload[MEOW_IPC_MAX];
|
||||
if (rlen && x_read_full(c, payload, rlen) < 0) break;
|
||||
if (type == MSG_HELLO) { send_ack(c, req_id, MEOW_OK, 0); continue; }
|
||||
if (type == MSG_PERF_QUERY) { handle_query(c, req_id, payload, rlen); continue; }
|
||||
send_err(c, req_id, MEOW_ERR_INVAL, "unknown type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int run_daemon(const char *sock)
|
||||
{
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
cpu_usage_pct(); /* 预热:设 /proc/stat 基线,首次查询即有值 */
|
||||
int lfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (lfd < 0) { svc_log("socket fail: %s", strerror(errno)); return 1; }
|
||||
struct sockaddr_un a;
|
||||
memset(&a, 0, sizeof a);
|
||||
a.sun_family = AF_UNIX;
|
||||
strncpy(a.sun_path, sock, sizeof a.sun_path - 1);
|
||||
unlink(sock);
|
||||
if (bind(lfd, (struct sockaddr *)&a, sizeof a) < 0) { svc_log("bind %s fail: %s", sock, strerror(errno)); close(lfd); return 1; }
|
||||
chmod(sock, 0666);
|
||||
if (listen(lfd, 8) < 0) { svc_log("listen fail: %s", strerror(errno)); close(lfd); return 1; }
|
||||
svc_log("meow_svc_perf listening on %s", sock);
|
||||
for (;;) {
|
||||
int c = accept(lfd, NULL, NULL);
|
||||
if (c < 0) { if (errno == EINTR) continue; continue; }
|
||||
handle_conn(c);
|
||||
close(c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------- CLI ---------------- */
|
||||
static int cli_run(int n, char **v)
|
||||
{
|
||||
int subset = 0;
|
||||
if (n >= 1) {
|
||||
if (!strcmp(v[0], "perf")) subset = PERF_SUBSET_PERF;
|
||||
else if (!strcmp(v[0], "system")) subset = PERF_SUBSET_SYSTEM;
|
||||
else if (!strcmp(v[0], "all") || !strcmp(v[0], "-")) subset = 0;
|
||||
else { fprintf(stderr, "usage: meow_svc_perf [all|perf|system]\n"); return 1; }
|
||||
}
|
||||
cpu_usage_pct(); /* 预热基线 */
|
||||
usleep(100000); /* 采样间隔,取 delta */
|
||||
char json[4096];
|
||||
agg_json(subset, json, sizeof json);
|
||||
puts(json);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *cli_usage(void)
|
||||
{
|
||||
return "meow_svc_perf [all|perf|system] (CLI 免鉴权;无参=全部)";
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *env = getenv("MEOW_IPC_PERF_SOCK");
|
||||
if (env && env[0]) g_sock = env;
|
||||
int i = 1;
|
||||
for (; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--sock") && i + 1 < argc) g_sock = argv[++i];
|
||||
else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { puts(cli_usage()); return 0; }
|
||||
else break;
|
||||
}
|
||||
if (i >= argc) return run_daemon(g_sock); /* svcd 空参 → IPC 常驻 */
|
||||
return cli_run(argc - i, argv + i);
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
# build_svc_power.sh — meow_svc_power 交叉编译(mipsel 静态)+ 宿主编译可选。
|
||||
#
|
||||
# 目标:R3 Pro II / MeowOS(mipsel-linux-muslsf,静态)。电源服务仅 POSIX + Linux 基接口
|
||||
# (复用 meow_ipc.h 帧格式,无 launcher 依赖),单文件满足「固件内、不入卡」(<200KB 阈值)。
|
||||
#
|
||||
# 用法:
|
||||
# ./build_svc_power.sh # 交叉编译 → patch_v2/meow_svc_power/meow_svc_power(mipsel 静态)
|
||||
# ./build_svc_power.sh host # 宿主编译 → patch_v2/meow_svc_power/meow_svc_power_host
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
ROOT="$HOME/Project/R3ProII"
|
||||
CC="$ROOT/.tools/zig-mipsel-cc"
|
||||
I_HDR="$ROOT/patch_v2/meow_launcherd" # meow_ipc.h(帧/SACK/POWER_*/m_power_*)
|
||||
|
||||
if [ "$1" = "host" ]; then
|
||||
HOST_CC="${CC_HOST:-cc}"
|
||||
"$HOST_CC" -Os -Wall -Wextra -I"$I_HDR" meow_svc_power.c -o meow_svc_power_host
|
||||
echo "== host build =="
|
||||
ls -la meow_svc_power_host
|
||||
file meow_svc_power_host
|
||||
exit 0
|
||||
fi
|
||||
|
||||
"$CC" -Os -Wall -Wextra -static -I"$I_HDR" meow_svc_power.c -o meow_svc_power
|
||||
echo "== meow_svc_power (mipsel static) =="
|
||||
ls -la meow_svc_power
|
||||
md5sum meow_svc_power
|
||||
file meow_svc_power
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,745 @@
|
||||
#define _GNU_SOURCE /* 启用 struct ucred / SO_PEERCRED、asprintf 等 GNU/musl 扩展 */
|
||||
|
||||
/* meow_svc_power.c — MeowOS 电源管理专项子服务(SYSTEM_FRAMEWORK_SERVICES §1.2/§2.3/§2.4)。
|
||||
*
|
||||
* 单一二进制双形态:
|
||||
* - svcd 以**空参**拉起(§1.3 conf `args=` 空)→ IPC 服务常驻:bind `/usr/data/meow_power.sock`
|
||||
* (`--sock`/`MEOW_IPC_POWER_SOCK` 可覆盖),收 MSG_HELLO→MSG_ACK、MSG_POWER_ACTION→MSG_POWER_STATUS。
|
||||
* - root shell `meow_svc_power <cmd>` → 一次性 CLI(免鉴权)执行对应动作(不常驻)。
|
||||
*
|
||||
* 动作逻辑与 launcher `power_menu.c` 的 `sys_do_reboot`/`set_boot_default_hiby`/`bootmode.sh Recovery`
|
||||
* **同源 0-diff 搬移**,仅入口(CLI vs IPC)与鉴权层不同。
|
||||
*
|
||||
* 鉴权(一期基础校验):IPC 服务端受理 MSG_POWER_ACTION 前以 `SO_PEERCRED` 校验调用方 `uid==0`(root)
|
||||
* ——非 root 直接 `MEOW_ERR_PERM` 拒绝;完整 `os.meow.*` 包名鉴权(§5)留二期。CLI=root 免鉴权。
|
||||
*
|
||||
* 通知转储归属(§3.2/§3.3 已定案):通知存储为 launcher 进程内存(meow_notif.c g_slots[]),服务跨进程
|
||||
* 不可达——**转储由调用方 launcher 先做**,服务对关机/重启/升级一律 `sync()` 落盘,不重实现转储。
|
||||
*
|
||||
* 编译(mipsel 静态):build_svc_power.sh;宿主编译 build_svc_power.sh host。
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "meow_ipc.h" /* 帧格式/消息号 + POWER_* 枚举 + m_power_* 负载(与 launcher 同源) */
|
||||
|
||||
/* ---- 路径常量(与 launcher 同源)---- */
|
||||
#define FB_DEV "/dev/fb0"
|
||||
#define FBIOBLANK 0x4611
|
||||
#define BACKLIGHT "/sys/class/backlight/backlight_pwm0/brightness"
|
||||
#define BACKLIGHT_POWER "/sys/class/backlight/backlight_pwm0/bl_power"
|
||||
#define BOOT_DEFAULT "/data/meow_boot_default" /* 0=MeowOS(默认),1=HibyOS */
|
||||
#define COLD_BOOT "/data/meow_cold_boot" /* 冷启标记:1=上次关机,0=上次重启 */
|
||||
#define MTD_OTA "/dev/mtd5" /* ota 标记分区(8M) */
|
||||
#define SETTINGS_FILE "/usr/data/meow/settings.conf"
|
||||
#define SETTINGS_HDR "# meow-settings 1"
|
||||
#define VERSION_FILE "/etc/meowos_version"
|
||||
#define BATT_CAP "/sys/class/power_supply/battery/capacity"
|
||||
#define BATT_STATUS "/sys/class/power_supply/battery/status"
|
||||
#define BATT_VOLT "/sys/class/power_supply/battery/voltage_now"
|
||||
#define DAC_NUMID "amixer -c 0 cget numid=%d 2>/dev/null"
|
||||
|
||||
#define LINUX_REBOOT_MAGIC1 0xfee1dead
|
||||
#define LINUX_REBOOT_MAGIC2 672274793 /* 0x28121969 */
|
||||
#define LINUX_REBOOT_CMD_RESTART 0x01234567
|
||||
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc
|
||||
|
||||
#define SV_PIPE_MAX 4096 /* popen_read_tmo 上限 */
|
||||
#define SV_TIMEOUT_MS 1500 /* popen 子命令读超时 */
|
||||
|
||||
static const char *g_sock = "/usr/data/meow_power.sock";
|
||||
|
||||
/* ---------------- 极简日志(stderr;svcd supervisor 捕获) ---------------- */
|
||||
static void svc_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "[meow_svc_power] ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* ---------------- 文件小工具 ---------------- */
|
||||
/* 读整个文本文件到 buf(NUL 结尾),返回字节数(不含 NUL);失败 -1。 */
|
||||
static int read_file_txt(const char *path, char *buf, int cap)
|
||||
{
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd < 0) return -1;
|
||||
int n = 0;
|
||||
while (n < cap - 1) {
|
||||
ssize_t r = read(fd, buf + n, (size_t)(cap - 1 - n));
|
||||
if (r <= 0) break;
|
||||
n += (int)r;
|
||||
}
|
||||
close(fd);
|
||||
buf[n] = 0;
|
||||
while (n > 0 && (buf[n - 1] == '\n' || buf[n - 1] == '\r')) buf[--n] = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* 读 int(atoi 首值);失败默认 def。 */
|
||||
static int read_file_int_def(const char *path, int def)
|
||||
{
|
||||
char buf[32];
|
||||
if (read_file_txt(path, buf, sizeof buf) <= 0) return def;
|
||||
char *p = buf;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
int v = atoi(p);
|
||||
return v;
|
||||
}
|
||||
|
||||
static int write_file_str(const char *path, const char *s, mode_t mode)
|
||||
{
|
||||
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
if (fd < 0) return -1;
|
||||
size_t l = strlen(s);
|
||||
ssize_t w = write(fd, s, l);
|
||||
int ok = (w == (ssize_t)l) ? 0 : -1;
|
||||
close(fd);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* 读 settings.conf 某键值(key=value,行首忽略空白),找不到→def。 */
|
||||
static int settings_get_int(const char *key, int def)
|
||||
{
|
||||
FILE *f = fopen(SETTINGS_FILE, "r");
|
||||
if (!f) return def;
|
||||
char line[256];
|
||||
int val = def, found = 0;
|
||||
size_t klen = strlen(key);
|
||||
while (fgets(line, sizeof line, f)) {
|
||||
char *p = line;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
if (strncmp(p, key, klen) == 0 && p[klen] == '=') {
|
||||
val = atoi(p + klen + 1);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
return found ? val : def;
|
||||
}
|
||||
|
||||
/* 更新/插入 settings.conf 某键(保留头,O_TRUNC 重写)。成功 0。 */
|
||||
static int settings_set_int(const char *key, int val)
|
||||
{
|
||||
FILE *f = fopen(SETTINGS_FILE, "r");
|
||||
char tmp[1024];
|
||||
size_t klen = strlen(key);
|
||||
int found = 0;
|
||||
|
||||
if (!f) {
|
||||
/* 无文件 → 新建头 + 键 */
|
||||
FILE *nf = fopen(SETTINGS_FILE, "w");
|
||||
if (!nf) return -1;
|
||||
fprintf(nf, "%s\n%s=%d\n", SETTINGS_HDR, key, val);
|
||||
fclose(nf);
|
||||
return 0;
|
||||
}
|
||||
/* 先把原文件读入 tmp(限 1KB,settings 为 KB 级小文件) */
|
||||
size_t n = 0;
|
||||
int c;
|
||||
while (n < sizeof tmp - 1 && (c = fgetc(f)) != EOF) tmp[n++] = (char)c;
|
||||
fclose(f);
|
||||
tmp[n] = 0;
|
||||
FILE *nf = fopen(SETTINGS_FILE, "w");
|
||||
if (!nf) return -1;
|
||||
/* 逐行写:头照抄;命中 key 行替换 */
|
||||
char *save = NULL;
|
||||
for (char *ln = strtok_r(tmp, "\n", &save); ln; ln = strtok_r(NULL, "\n", &save)) {
|
||||
char *p = ln;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
if (strncmp(p, key, klen) == 0 && p[klen] == '=') {
|
||||
fprintf(nf, "%s=%d\n", key, val);
|
||||
found = 1;
|
||||
} else {
|
||||
fprintf(nf, "%s\n", ln);
|
||||
}
|
||||
}
|
||||
if (!found) fprintf(nf, "%s=%d\n", key, val);
|
||||
fclose(nf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------- popen 限时读(kill 子进程防挂) ---------------- */
|
||||
static char *popen_read_tmo(int tmo_ms, const char *cmd)
|
||||
{
|
||||
int p[2];
|
||||
if (pipe(p) < 0) return NULL;
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) { close(p[0]); close(p[1]); return NULL; }
|
||||
if (pid == 0) {
|
||||
dup2(p[1], 1);
|
||||
close(p[0]); close(p[1]);
|
||||
execl("/bin/sh", "sh", "-c", cmd, (char *)0);
|
||||
_exit(127);
|
||||
}
|
||||
close(p[1]);
|
||||
fcntl(p[0], F_SETFL, fcntl(p[0], F_GETFL, 0) | O_NONBLOCK);
|
||||
char *buf = malloc(SV_PIPE_MAX);
|
||||
if (!buf) { close(p[0]); waitpid(pid, NULL, 0); return NULL; }
|
||||
size_t off = 0;
|
||||
int remain = tmo_ms;
|
||||
while (remain > 0 && off < SV_PIPE_MAX - 1) {
|
||||
struct pollfd pf = { p[0], POLLIN, 0 };
|
||||
int r = poll(&pf, 1, remain);
|
||||
if (r < 0) { if (errno == EINTR) continue; break; }
|
||||
if (r == 0) break; /* 超时 */
|
||||
ssize_t rd = read(p[0], buf + off, SV_PIPE_MAX - 1 - off);
|
||||
if (rd == 0) break; /* EOF(子进程退出/关写端) */
|
||||
if (rd < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; break; }
|
||||
off += (size_t)rd;
|
||||
}
|
||||
close(p[0]);
|
||||
waitpid(pid, NULL, 0);
|
||||
buf[off] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* 前置声明:CLI 用法串(cli_run 用到)。 */
|
||||
static const char *cli_usage(void);
|
||||
|
||||
/* ---------------- reboot / 关机 syscall ---------------- */
|
||||
static void sys_reboot_do(int cmd)
|
||||
{
|
||||
/* 与 power_menu.c sys_do_reboot 同源:sync() 落盘 → reboot(2) syscall → 永不返回。 */
|
||||
sync();
|
||||
svc_log("sys_reboot_do cmd=0x%x", cmd);
|
||||
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, NULL);
|
||||
svc_log("sys_reboot_do returned: %s", strerror(errno));
|
||||
for (;;) usleep(1000);
|
||||
}
|
||||
|
||||
/* ---------------- boot 默认 ---------------- */
|
||||
/* 写 /data/meow_boot_default(0=MeowOS 默认 / 1=HibyOS 默认)。 */
|
||||
static void write_boot_default(int v)
|
||||
{
|
||||
char b[8];
|
||||
snprintf(b, sizeof b, "%d\n", v);
|
||||
if (write_file_str(BOOT_DEFAULT, b, 0644) < 0) svc_log("write %s fail: %s", BOOT_DEFAULT, strerror(errno));
|
||||
else svc_log("boot_default=%d", v);
|
||||
}
|
||||
|
||||
/* ---------------- 关机 logo ---------------- */
|
||||
static void show_shutdown_logo(void)
|
||||
{
|
||||
/* 独立二进制 cmd_jpeg_display 能显图;SSH 无 fb 时重定向无害。 */
|
||||
int rc = system("PATH=/bin:/sbin:/usr/bin:/usr/sbin cmd_jpeg_display /etc/shutdown_logo.jpeg >/dev/null 2>&1");
|
||||
(void)rc;
|
||||
}
|
||||
|
||||
/* ---------------- 升级(mtd5=ota:kernel2) ---------------- */
|
||||
static void enter_upgrade(void)
|
||||
{
|
||||
int rc = system("PATH=/bin:/sbin:/usr/bin:/usr/sbin /usr/bin/bootmode.sh Recovery >/dev/null 2>&1");
|
||||
(void)rc;
|
||||
}
|
||||
|
||||
/* 读 /dev/mtd5 头,命中 "ota:kernel2" → 升级模式已设。 */
|
||||
static int mtd_ota_is_upgrade(void)
|
||||
{
|
||||
int fd = open(MTD_OTA, O_RDONLY);
|
||||
if (fd < 0) return 0;
|
||||
char buf[16];
|
||||
memset(buf, 0, sizeof buf);
|
||||
ssize_t n = read(fd, buf, sizeof buf - 1);
|
||||
close(fd);
|
||||
if (n <= 0) return 0;
|
||||
return strstr(buf, "ota:kernel2") != NULL;
|
||||
}
|
||||
|
||||
/* ---------------- 有界拼接(printf 截断分析免疫;host/cross 均 0 warning) ---------------- */
|
||||
static void cat_b(char *dst, size_t cap, const char *src)
|
||||
{
|
||||
size_t dl = strlen(dst);
|
||||
if (dl >= cap - 1) return;
|
||||
size_t sl = strlen(src);
|
||||
if (sl > cap - 1 - dl) sl = cap - 1 - dl;
|
||||
if (sl) memcpy(dst + dl, src, sl);
|
||||
dst[dl + sl] = 0;
|
||||
}
|
||||
|
||||
/* ---------------- 电池/状态读组(同 util.c/about.c/bootmenu 数据源) ---------------- */
|
||||
static void battery_fill(char *out, int cap)
|
||||
{
|
||||
int pct = read_file_int_def(BATT_CAP, -1);
|
||||
char st[32] = "";
|
||||
read_file_txt(BATT_STATUS, st, sizeof st);
|
||||
int mv = read_file_int_def(BATT_VOLT, -1) / 1000; /* µV → mV */
|
||||
if (pct < 0) { snprintf(out, cap, "battery=unknown"); return; }
|
||||
char one[64];
|
||||
snprintf(one, sizeof one, "battery=%d%%(%s)", pct, st[0] ? st : "?");
|
||||
out[0] = 0;
|
||||
cat_b(out, cap, one);
|
||||
if (mv >= 0) { char more[24]; snprintf(more, sizeof more, " %dmV", mv); cat_b(out, cap, more); }
|
||||
}
|
||||
|
||||
static const char *boot_default_str(void)
|
||||
{
|
||||
int v = read_file_int_def(BOOT_DEFAULT, -1);
|
||||
if (v < 0) return "unknown";
|
||||
return v ? "hiby" : "meow";
|
||||
}
|
||||
|
||||
static int cold_boot_flag(void) { return read_file_int_def(COLD_BOOT, -1); }
|
||||
|
||||
static void status_fill(char *out, int cap)
|
||||
{
|
||||
char ver[32] = "-", batt[48] = "";
|
||||
if (read_file_txt(VERSION_FILE, ver, sizeof ver) <= 0 || !ver[0]) snprintf(ver, sizeof ver, "-");
|
||||
battery_fill(batt, sizeof batt);
|
||||
int cold = cold_boot_flag();
|
||||
char head[96];
|
||||
snprintf(head, sizeof head, "system=%s boot=%s upgrade=%s coldboot=%s ",
|
||||
ver, boot_default_str(),
|
||||
mtd_ota_is_upgrade() ? "yes" : "no",
|
||||
cold < 0 ? "unknown" : (cold ? "shutdown" : "reboot"));
|
||||
out[0] = 0;
|
||||
cat_b(out, cap, head);
|
||||
cat_b(out, cap, batt);
|
||||
}
|
||||
|
||||
/* ---------------- 屏幕电源(同 launcher keys.c meow_panel_off/on + backlight.c) ---------------- */
|
||||
static int backlight_write(int val)
|
||||
{
|
||||
char b[16];
|
||||
snprintf(b, sizeof b, "%d", val);
|
||||
return write_file_str(BACKLIGHT, b, 0644) < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
static int screen_on(void)
|
||||
{
|
||||
int f = open(FB_DEV, O_RDWR);
|
||||
if (f >= 0) { ioctl(f, FBIOBLANK, 0); close(f); }
|
||||
int bri = settings_get_int("display.brightness", 60);
|
||||
int bmin = settings_get_int("display.brightness_min", 1);
|
||||
if (bri < bmin) bri = bmin;
|
||||
if (bri > 100) bri = 100;
|
||||
backlight_write(bri);
|
||||
svc_log("screen ON (brightness %d)", bri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int screen_off(void)
|
||||
{
|
||||
int f = open(FB_DEV, O_RDWR);
|
||||
if (f >= 0) { ioctl(f, FBIOBLANK, 4); close(f); }
|
||||
backlight_write(0);
|
||||
svc_log("screen OFF (blank 4 + brightness 0)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------- DAC(CS43198) ---------------- */
|
||||
/* 原机 cs43198 驱动 pwr_gpio=-1:无上电/下电控制点(sysfs/amixer),on/off 不支持。
|
||||
* status 仅报 amixer numid=1/2(L/R)当前音量上报值。 */
|
||||
static int dac_status(char *out, int cap)
|
||||
{
|
||||
char l[48] = "?", r[48] = "?";
|
||||
char *o1 = popen_read_tmo(SV_TIMEOUT_MS, "PATH=/bin:/sbin:/usr/bin:/usr/sbin amixer -c 0 cget numid=1 2>/dev/null");
|
||||
if (o1) {
|
||||
char *p = strstr(o1, ": values=");
|
||||
if (p) snprintf(l, sizeof l, "%.40s", p + 9);
|
||||
free(o1);
|
||||
}
|
||||
char *o2 = popen_read_tmo(SV_TIMEOUT_MS, "PATH=/bin:/sbin:/usr/bin:/usr/sbin amixer -c 0 cget numid=2 2>/dev/null");
|
||||
if (o2) {
|
||||
char *p = strstr(o2, ": values=");
|
||||
if (p) snprintf(r, sizeof r, "%.40s", p + 9);
|
||||
free(o2);
|
||||
}
|
||||
out[0] = 0;
|
||||
cat_b(out, cap, "dac=cs43198 L=");
|
||||
cat_b(out, cap, l);
|
||||
cat_b(out, cap, " R=");
|
||||
cat_b(out, cap, r);
|
||||
cat_b(out, cap, " powerctl=unsupported(no_gpio)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac_cmd(const char *sub, char *out, int cap)
|
||||
{
|
||||
if (!sub) return MEOW_ERR_INVAL;
|
||||
if (!strcmp(sub, "status")) { return dac_status(out, cap); }
|
||||
if (!strcmp(sub, "on") || !strcmp(sub, "off")) {
|
||||
snprintf(out, cap, "DAC %s: unsupported (cs43198 pwr_gpio=-1, no on/off control point)", sub);
|
||||
return MEOW_ERR_NODEV;
|
||||
}
|
||||
return MEOW_ERR_INVAL;
|
||||
}
|
||||
|
||||
/* ---------------- 动作执行(CLI + IPC 共用) ----------------
|
||||
* 返回 0 = 已同步执行并填好 st(调用方直接应答 st 给客户端/CLI 已打印);
|
||||
* 返回 1 = 系统动作(关机/重启/升级/回HiBy),调用方应「先应答 MEOW_OK 受理,再执行」(执行后通常不返回)。 */
|
||||
static int execute_action(const m_power_action_t *a, m_power_status_t *st)
|
||||
{
|
||||
memset(st, 0, sizeof *st);
|
||||
st->cmd = a->cmd;
|
||||
switch (a->cmd) {
|
||||
case POWER_SHUTDOWN:
|
||||
sync(); /* 通知转储由 launcher 先做;服务 sync() 落盘 */
|
||||
st->code = MEOW_OK;
|
||||
snprintf(st->msg, sizeof st->msg, "shutdown accepted");
|
||||
return 1; /* 应答后:logo + poweroff(不返回) */
|
||||
case POWER_REBOOT:
|
||||
write_boot_default(0); /* 普通重启恒回 MeowOS(无视之前) */
|
||||
sync();
|
||||
st->code = MEOW_OK;
|
||||
snprintf(st->msg, sizeof st->msg, "reboot accepted (boot=meow)");
|
||||
return 1;
|
||||
case POWER_UPGRADE:
|
||||
sync();
|
||||
st->code = MEOW_OK;
|
||||
snprintf(st->msg, sizeof st->msg, "upgrade accepted");
|
||||
return 1;
|
||||
case POWER_BACK_HIBY:
|
||||
write_boot_default(1);
|
||||
sync();
|
||||
st->code = MEOW_OK;
|
||||
snprintf(st->msg, sizeof st->msg, "reboot -> hiby accepted");
|
||||
return 1;
|
||||
case POWER_SET_DEFAULT_MEOW:
|
||||
write_boot_default(0);
|
||||
st->code = MEOW_OK;
|
||||
snprintf(st->msg, sizeof st->msg, "boot_default=meow (next boot)");
|
||||
return 0;
|
||||
case POWER_SET_DEFAULT_HIBY:
|
||||
write_boot_default(1);
|
||||
st->code = MEOW_OK;
|
||||
snprintf(st->msg, sizeof st->msg, "boot_default=hiby (next boot)");
|
||||
return 0;
|
||||
case POWER_STATUS:
|
||||
status_fill(st->msg, sizeof st->msg);
|
||||
st->code = MEOW_OK;
|
||||
return 0;
|
||||
case POWER_BATTERY:
|
||||
battery_fill(st->msg, sizeof st->msg);
|
||||
st->code = MEOW_OK;
|
||||
return 0;
|
||||
case POWER_REBOOT_REASON:
|
||||
{ int c = cold_boot_flag();
|
||||
snprintf(st->msg, sizeof st->msg, "coldboot=%s", c < 0 ? "unknown" : (c ? "shutdown" : "reboot"));
|
||||
st->code = MEOW_OK; }
|
||||
return 0;
|
||||
case POWER_UPGRADE_STATUS:
|
||||
snprintf(st->msg, sizeof st->msg, "upgrade=%s", mtd_ota_is_upgrade() ? "yes" : "no");
|
||||
st->code = MEOW_OK;
|
||||
return 0;
|
||||
case POWER_SCREEN:
|
||||
if (a->flag == 0) { screen_off(); st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "screen off"); return 0; }
|
||||
if (a->flag == 1) { screen_on(); st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "screen on"); return 0; }
|
||||
if (a->flag == 2) { /* timeout 秒(arg) */
|
||||
int sec = a->arg[0] ? atoi(a->arg) : -1;
|
||||
if (sec < 0 || sec > 86400) { st->code = MEOW_ERR_INVAL;
|
||||
snprintf(st->msg, sizeof st->msg, "screen timeout: bad sec"); return 0; }
|
||||
settings_set_int("display.screen_off_timeout", sec);
|
||||
st->code = MEOW_OK;
|
||||
snprintf(st->msg, sizeof st->msg, "screen_off_timeout=%ds", sec);
|
||||
return 0;
|
||||
}
|
||||
st->code = MEOW_ERR_INVAL;
|
||||
snprintf(st->msg, sizeof st->msg, "screen: bad flag");
|
||||
return 0;
|
||||
case POWER_DAC:
|
||||
{ int rc = dac_cmd(a->flag == 2 ? "status" : (a->flag == 1 ? "on" : "off"),
|
||||
st->msg, sizeof st->msg);
|
||||
st->code = rc; }
|
||||
return 0;
|
||||
default:
|
||||
st->code = MEOW_ERR_INVAL;
|
||||
snprintf(st->msg, sizeof st->msg, "unknown cmd %u", a->cmd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 执行「系统动作」(在应答 MEOW_OK 之后调用;通常不返回)。 */
|
||||
static void run_system_action(uint32_t cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case POWER_SHUTDOWN:
|
||||
show_shutdown_logo();
|
||||
sys_reboot_do(LINUX_REBOOT_CMD_POWER_OFF);
|
||||
break;
|
||||
case POWER_REBOOT:
|
||||
sys_reboot_do(LINUX_REBOOT_CMD_RESTART);
|
||||
break;
|
||||
case POWER_UPGRADE:
|
||||
enter_upgrade();
|
||||
sys_reboot_do(LINUX_REBOOT_CMD_RESTART);
|
||||
break;
|
||||
case POWER_BACK_HIBY:
|
||||
sys_reboot_do(LINUX_REBOOT_CMD_RESTART);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------- IPC 帧读写(同 meow_ipc 客户端约定,全小端) ---------------- */
|
||||
static int x_read_full(int fd, uint8_t *buf, size_t n)
|
||||
{
|
||||
size_t off = 0;
|
||||
while (off < n) {
|
||||
ssize_t r = read(fd, buf + off, n - off);
|
||||
if (r <= 0) return -1;
|
||||
off += (size_t)r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int x_write_full(int fd, const uint8_t *buf, size_t n)
|
||||
{
|
||||
size_t off = 0;
|
||||
while (off < n) {
|
||||
ssize_t w = write(fd, buf + off, n - off);
|
||||
if (w <= 0) return -1;
|
||||
off += (size_t)w;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len)
|
||||
{
|
||||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||||
uint32_t magic = MEOW_IPC_MAGIC, rlen = len;
|
||||
uint16_t ver = MEOW_IPC_VERSION, t = type;
|
||||
memcpy(hdr + 0, &magic, 4);
|
||||
memcpy(hdr + 4, &ver, 2);
|
||||
memcpy(hdr + 6, &t, 2);
|
||||
memcpy(hdr + 8, &req_id, 4);
|
||||
memcpy(hdr + 12, &rlen, 4);
|
||||
if (x_write_full(fd, hdr, MEOW_IPC_HDR_LEN) < 0) return -1;
|
||||
if (len && payload && x_write_full(fd, payload, len) < 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_ack(int fd, uint32_t req_id, uint32_t code, uint32_t status)
|
||||
{
|
||||
m_ack_t a;
|
||||
memset(&a, 0, sizeof a);
|
||||
a.code = code;
|
||||
a.status = status;
|
||||
return send_frame(fd, MSG_ACK, req_id, &a, sizeof a);
|
||||
}
|
||||
|
||||
static int send_err(int fd, uint32_t req_id, uint32_t code, const char *msg)
|
||||
{
|
||||
m_err_t e;
|
||||
memset(&e, 0, sizeof e);
|
||||
e.code = code;
|
||||
uint16_t ml = msg ? (uint16_t)strlen(msg) : 0;
|
||||
if (ml > 63) ml = 63;
|
||||
e.msg_len = ml;
|
||||
if (ml) memcpy(e.msg, msg, ml);
|
||||
return send_frame(fd, MSG_ERR, req_id, &e, sizeof e);
|
||||
}
|
||||
|
||||
static int send_power_status(int fd, uint32_t req_id, const m_power_status_t *st)
|
||||
{
|
||||
m_power_status_t s = *st;
|
||||
uint16_t ml = (uint16_t)strlen(s.msg);
|
||||
if (ml >= sizeof s.msg) ml = (uint16_t)(sizeof s.msg - 1);
|
||||
s.msg_len = ml;
|
||||
return send_frame(fd, MSG_POWER_STATUS, req_id, &s, sizeof s);
|
||||
}
|
||||
|
||||
/* 处理单条连接(连接内循环读帧:客户端先 MSG_HELLO 握手,再 MSG_POWER_ACTION)。 */
|
||||
static void handle_conn(int c)
|
||||
{
|
||||
/* 基础鉴权:调用方 uid==0(root)才受理动作。 */
|
||||
struct ucred cred;
|
||||
socklen_t cl = sizeof cred;
|
||||
int uid0 = 0;
|
||||
if (getsockopt(c, SOL_SOCKET, SO_PEERCRED, &cred, &cl) == 0 && cred.uid == 0)
|
||||
uid0 = 1;
|
||||
|
||||
for (;;) {
|
||||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||||
if (x_read_full(c, hdr, sizeof hdr) < 0) break; /* EOF/错误 */
|
||||
uint32_t magic, rlen, req_id;
|
||||
uint16_t ver, type;
|
||||
memcpy(&magic, hdr, 4);
|
||||
memcpy(&ver, hdr + 4, 2);
|
||||
memcpy(&type, hdr + 6, 2);
|
||||
memcpy(&req_id, hdr + 8, 4);
|
||||
memcpy(&rlen, hdr + 12, 4);
|
||||
if (magic != MEOW_IPC_MAGIC || ver != MEOW_IPC_VERSION) {
|
||||
send_err(c, req_id, MEOW_ERR_INVAL, "bad magic/ver"); break;
|
||||
}
|
||||
if (rlen > MEOW_IPC_MAX) {
|
||||
send_err(c, req_id, MEOW_ERR_INVAL, "payload too big"); break;
|
||||
}
|
||||
uint8_t payload[MEOW_IPC_MAX];
|
||||
if (rlen && x_read_full(c, payload, rlen) < 0) break;
|
||||
|
||||
if (type == MSG_HELLO) { send_ack(c, req_id, MEOW_OK, 0); continue; }
|
||||
|
||||
if (type == MSG_POWER_ACTION) {
|
||||
m_power_action_t a;
|
||||
memset(&a, 0, sizeof a);
|
||||
if (rlen > sizeof a) rlen = sizeof a;
|
||||
memcpy(&a, payload, rlen);
|
||||
if (!uid0) {
|
||||
m_power_status_t st;
|
||||
memset(&st, 0, sizeof st);
|
||||
st.code = MEOW_ERR_PERM;
|
||||
st.cmd = a.cmd;
|
||||
snprintf(st.msg, sizeof st.msg, "permission denied (uid!=0)");
|
||||
send_power_status(c, req_id, &st);
|
||||
continue;
|
||||
}
|
||||
m_power_status_t st;
|
||||
int act = execute_action(&a, &st);
|
||||
if (act == 0) { send_power_status(c, req_id, &st); continue; }
|
||||
/* 系统动作:先应答受理(客户端不阻塞),再执行(常不返回) */
|
||||
send_power_status(c, req_id, &st);
|
||||
run_system_action(a.cmd);
|
||||
break;
|
||||
}
|
||||
send_err(c, req_id, MEOW_ERR_INVAL, "unknown type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int run_daemon(const char *sock)
|
||||
{
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
int lfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (lfd < 0) { svc_log("socket fail: %s", strerror(errno)); return 1; }
|
||||
struct sockaddr_un a;
|
||||
memset(&a, 0, sizeof a);
|
||||
a.sun_family = AF_UNIX;
|
||||
strncpy(a.sun_path, sock, sizeof a.sun_path - 1);
|
||||
unlink(sock);
|
||||
if (bind(lfd, (struct sockaddr *)&a, sizeof a) < 0) {
|
||||
svc_log("bind %s fail: %s", sock, strerror(errno));
|
||||
close(lfd);
|
||||
return 1;
|
||||
}
|
||||
chmod(sock, 0666);
|
||||
if (listen(lfd, 8) < 0) { svc_log("listen fail: %s", strerror(errno)); close(lfd); return 1; }
|
||||
svc_log("meow_svc_power listening on %s", sock);
|
||||
for (;;) {
|
||||
int c = accept(lfd, NULL, NULL);
|
||||
if (c < 0) { if (errno == EINTR) continue; continue; }
|
||||
handle_conn(c);
|
||||
close(c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------- CLI ---------------- */
|
||||
static int cli_run(int n, char **v)
|
||||
{
|
||||
const char *cmd = v[0];
|
||||
if (!strcmp(cmd, "shutdown")) {
|
||||
show_shutdown_logo();
|
||||
sys_reboot_do(LINUX_REBOOT_CMD_POWER_OFF);
|
||||
return 0; /* 不返回 */
|
||||
}
|
||||
if (!strcmp(cmd, "reboot")) {
|
||||
if (n > 1 && !strcmp(v[1], "--hiby")) { write_boot_default(1); }
|
||||
else write_boot_default(0); /* 普通重启恒回 MeowOS */
|
||||
sys_reboot_do(LINUX_REBOOT_CMD_RESTART);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cmd, "upgrade")) {
|
||||
enter_upgrade();
|
||||
sys_reboot_do(LINUX_REBOOT_CMD_RESTART);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cmd, "set-default-hiby")) {
|
||||
write_boot_default(1);
|
||||
printf("boot_default=hiby (next boot)\n");
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cmd, "set-default-meow")) {
|
||||
write_boot_default(0);
|
||||
printf("boot_default=meow (next boot)\n");
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cmd, "status")) {
|
||||
char out[128];
|
||||
status_fill(out, sizeof out);
|
||||
printf("%s\n", out);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cmd, "battery")) {
|
||||
char out[64];
|
||||
battery_fill(out, sizeof out);
|
||||
printf("%s\n", out);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cmd, "reboot-reason")) {
|
||||
int c = cold_boot_flag();
|
||||
printf("coldboot=%s\n", c < 0 ? "unknown" : (c ? "shutdown" : "reboot"));
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cmd, "upgrade-status")) {
|
||||
printf("upgrade=%s\n", mtd_ota_is_upgrade() ? "yes" : "no");
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cmd, "screen")) {
|
||||
if (n < 2) { fprintf(stderr, "screen needs on|off|timeout<秒>\n"); return 1; }
|
||||
if (!strcmp(v[1], "on")) return screen_on();
|
||||
if (!strcmp(v[1], "off")) return screen_off();
|
||||
if (!strcmp(v[1], "timeout")) {
|
||||
if (n < 3) { fprintf(stderr, "screen timeout needs <秒>\n"); return 1; }
|
||||
int sec = atoi(v[2]);
|
||||
if (sec < 0 || sec > 86400) { fprintf(stderr, "screen timeout: bad sec\n"); return 1; }
|
||||
settings_set_int("display.screen_off_timeout", sec);
|
||||
printf("screen_off_timeout=%ds\n", sec);
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "screen: bad sub %s\n", v[1]);
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(cmd, "dac")) {
|
||||
if (n < 2) { fprintf(stderr, "dac needs on|off|status\n"); return 1; }
|
||||
char out[160];
|
||||
int rc = dac_cmd(v[1], out, sizeof out);
|
||||
printf("%s\n", out);
|
||||
return rc == MEOW_OK ? 0 : 1;
|
||||
}
|
||||
fprintf(stderr, "usage: meow_svc_power <cmd> (%s)\n", cli_usage());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *cli_usage(void)
|
||||
{
|
||||
return "shutdown|reboot[--hiby]|upgrade|set-default-hiby|set-default-meow|"
|
||||
"status|battery|reboot-reason|upgrade-status|screen on|off|timeout<秒>|dac on|off|status";
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *env = getenv("MEOW_IPC_POWER_SOCK");
|
||||
if (env && env[0]) g_sock = env;
|
||||
|
||||
int i = 1;
|
||||
for (; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--sock") && i + 1 < argc) g_sock = argv[++i];
|
||||
else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
|
||||
printf("meow_svc_power (%s)\n", cli_usage());
|
||||
return 0;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (i >= argc) return run_daemon(g_sock); /* svcd 空参 → IPC 常驻 */
|
||||
return cli_run(argc - i, argv + i);
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -7,7 +7,8 @@
|
||||
# --fork` 会阻塞 rcS(选单后 exec meow_launcherd 或 fork 播放器监督),故任何 S90
|
||||
# 之后的 init.d(如 S91/S92)**都不会执行**——svcd 必须排在 S90 之前。
|
||||
# * 本脚本只装「稳定框架/KB级设置」:主机名 + 板载服务配置
|
||||
# (/usr/data/meow/services.d/,Data 区,首启预置 mdnsd.conf)。
|
||||
# (/usr/data/meow/services.d/,Data 区,首启预置 mdnsd.conf + meow_svc_perf.conf +
|
||||
# meow_svc_power.conf —— 后者为框架专项服务,trigger=boot 恒存在即启动)。
|
||||
# * **svcd 拉起权**:若 meow_sysui(系统进程总监)已运行 → svcd 由 sysui 监管拉起
|
||||
# (sysui.d/svcd.conf),本脚本仅在其已运行时 `meow_svcd reload` 让 svcd 补载 mdnsd.conf,
|
||||
# 不重复拉起、不重挂(避免与 sysui 双重监护 svcd)。仅当 **sysui 未运行**时才回退到
|
||||
@@ -57,6 +58,46 @@ EOF
|
||||
echo -n "skip mdnsd.conf (/usr/data/meow not writable) "
|
||||
fi
|
||||
|
||||
# 2b) 首启预置板载**专项服务**配置(性能/电源;trigger=boot 恒存在即启动,拔卡保留)。
|
||||
# perf=on-fail(纯读组,崩即拉起);power=always(系统动作服务应随时可用)。
|
||||
if [ -d /usr/data/meow ] && [ -w /usr/data/meow ]; then
|
||||
mkdir -p /usr/data/meow/services.d
|
||||
if [ -f /usr/data/meow/services.d/meow_svc_perf.conf ]; then
|
||||
echo -n "perf.conf exists "
|
||||
else
|
||||
cat > /usr/data/meow/services.d/meow_svc_perf.conf <<'EOF'
|
||||
exec=/usr/bin/meow_svc_perf
|
||||
args=
|
||||
enabled=1
|
||||
restart=on-fail
|
||||
backoff_ms=2000
|
||||
max_restart=5
|
||||
trigger=boot
|
||||
cap=
|
||||
EOF
|
||||
chmod 644 /usr/data/meow/services.d/meow_svc_perf.conf
|
||||
echo -n "provisioned perf.conf "
|
||||
fi
|
||||
if [ -f /usr/data/meow/services.d/meow_svc_power.conf ]; then
|
||||
echo -n "power.conf exists "
|
||||
else
|
||||
cat > /usr/data/meow/services.d/meow_svc_power.conf <<'EOF'
|
||||
exec=/usr/bin/meow_svc_power
|
||||
args=
|
||||
enabled=1
|
||||
restart=always
|
||||
backoff_ms=2000
|
||||
max_restart=5
|
||||
trigger=boot
|
||||
cap=
|
||||
EOF
|
||||
chmod 644 /usr/data/meow/services.d/meow_svc_power.conf
|
||||
echo -n "provisioned power.conf "
|
||||
fi
|
||||
else
|
||||
echo -n "skip svc confs (/usr/data/meow not writable) "
|
||||
fi
|
||||
|
||||
# 3) svcd 拉起权判归:sysui 运行 → 交给 sysui 监管;否则回退重挂循环。
|
||||
rm -f /tmp/meow_svcd.stop
|
||||
sysui_alive=0
|
||||
|
||||
Reference in new issue
Block a user