From 5663acfbb9e0192c76658279058606db6b4b0e76 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Wed, 2 Sep 2026 16:25:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(powermgr):=20=E6=9C=9F3=20policy=20?= =?UTF-8?q?=E7=94=9F=E6=95=88=20+=20=E6=A0=87=E5=AE=9A=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=20+=20=E6=A8=A1=E5=9E=8B=E5=8D=95=E9=94=AE=20setter=20+=20even?= =?UTF-8?q?ts=20=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - policy:IPC 0xD2/0xD3 GET/SET(SET 动作级鉴权=root+系统身份,SO_PEERCRED→pid→exe→classify,同 svc_power) + CLI `meow_power policy show|set`。策略项 profile 四档(performance/balanced/powersave/ultra) + 低电阈值(power.low_pct/critical_pct 读 settings.conf) + 亮度上限(power.brightness_cap) + 息屏上限(power.screen_timeout_cap)。**默认全关**(profile=balanced 无操作=现状, cap=0 不生效, 只能用户手动开)。生效方式: powermgr 不直接写系统——只写 settings.conf power.* 键(原子), launcher/sysui 期4 消费; 本服务绝不 poke 背光/息屏/wlan0/bt。低电/极低阈值改从 settings.conf 读, 事件检测即时生效。 - calibrate:`meow_power calibrate start <场景>|stop|list`——守护内 2s 节拍采样 电流(mp2731 current_now)+亮度+CPU+wifi/bt 状态+电量%变化,写 TF MeowOS/logs/power_calib_.csv (无卡降级 /tmp,逐行 fflush),用户实验中 start/stop 两命令即可。 - model:`meow_power model set ` 读改写单键+原子写(tmp+rename),守护每拍重载 conf。 - events:App 前后台切换——launcher MSG_ACT_FOCUS 为单向 app→launcher 上报,powermgr 侧无导出点 可接,诚实标注「期4 接 launcher」扩展,本期不编造该事件(延续期2 口径)。 - 验证:宿主+qemu 全量 76/76 PASS(期1/2 全过+新增 policy/calibrate/model-set 用例),mipsel 静态交叉 0 warning,二进制 151516B(<200KB 阈值)。md5 1ef2f8afc07acc7aa09dee9f7149aba8。 --- patch_v2/meow_powermgr/meow_powermgr | Bin 132812 -> 151516 bytes patch_v2/meow_powermgr/meow_powermgr.c | 839 +++++++++++++++++++++- patch_v2/meow_powermgr/meow_powermgr_host | Bin 77488 -> 79304 bytes patch_v2/meow_powermgr/test_powermgr.sh | 70 +- 4 files changed, 875 insertions(+), 34 deletions(-) diff --git a/patch_v2/meow_powermgr/meow_powermgr b/patch_v2/meow_powermgr/meow_powermgr index 6912ce93678c370929a35fe2bad541e4f76d9951..9558e42d3027291cfe445b988f15fb45005bd37f 100755 GIT binary patch delta 56713 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 delta 39548 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 diff --git a/patch_v2/meow_powermgr/meow_powermgr.c b/patch_v2/meow_powermgr/meow_powermgr.c index 470aa0d..8589e5c 100644 --- a/patch_v2/meow_powermgr/meow_powermgr.c +++ b/patch_v2/meow_powermgr/meow_powermgr.c @@ -12,6 +12,22 @@ * 模型系数路径迁移到 /data/meow/powermgr/power_model.conf(=/usr/data symlink,组件持久化目录定案)。 * IPC 新增 MSG_PM_HISTORY/D5 + MSG_PM_EVENTS/D7(号段 0x00D0-0x00D7 剩余位;数字本文件局部定, * meow_ipc.h 仅注释保留——只动本目录,不碰 meow_launcherd/meow_ipc.h)。 + * 期 3 新增(本文件,POWER_MANAGER_DESIGN §9 期 3): + * ① policy 生效(期 2 桩落地):IPC MSG_PM_POLICY_GET/D2 + MSG_PM_POLICY_SET/D3 + CLI + * `meow_power policy show|set`。策略项:profile 四档(performance/balanced/powersave/ultra) + * + 低电阈值(power.low_pct/critical_pct 读 settings.conf)+ 亮度上限(power.brightness_cap) + * + 息屏上限(power.screen_timeout_cap)。**默认全关**(profile=balanced 无操作=现状,cap=0 不生效), + * 用户手动开(§附 3 只能用户手动开)。**生效方式:powermgr 不直接写系统**——policy 只写 settings.conf + * `power.*` 键(launcher/sysui 期 4 消费;本服务只报告 effective 值,绝不 poke sysfs/背光/息屏)。 + * ② 标定工具(为用户的标定实验备好,§7 项 7/8):`meow_power calibrate start <场景>|stop|list`—— + * 守护进程内 2s 节拍采样 电流(mp2731 current_now)+亮度+CPU+wifi/bt 状态+电量%变化,写 TF + * MeowOS/logs/power_calib_.csv(无卡降级 /tmp);用户实验只需在真机跑 start/stop。 + * ③ 模型 conf 单键 setter:`meow_power model set `(读改写单键 + 原子写 tmp+rename)。 + * ④ events 扩展:App 前后台切换——launcher MSG_ACT_FOCUS 为 app→launcher 单向上报,powermgr 侧无 + * 导出点可接,**诚实标注**:记录「期 4 接 launcher」扩展,本期不编造该事件(延续期 2 口径)。 + * ⑤ 动作级鉴权(POLICY_SET/CALIB_*):SO_PEERCRED→pid→exe→classify(同 svc_power), + * 动作级须 root + 系统身份(os.meow 前缀或受信系统二进制);读级(POLICY_GET)任意调用者。 + * MEOW_PM_AUTH_TEST=1 仅宿主测试关闭动作级鉴权(生产绝不设)。 * * 单一二进制双形态(同 svc_power): * - svcd 空参拉起(板载 services.d/meow_powermgr.conf,trigger=boot/restart=on-fail)→ @@ -61,12 +77,22 @@ /* 期 2 消息号:meow_ipc.h 仅以注释保留(0x00D4-0x00D7),本文件局部定义,避免动 meow_launcherd/。 * 响应帧复用 m_pm_result_t(code+subset+json_len+json),type 区分 HISTORY_RESULT/EVENTS_RESULT。 */ #ifndef MSG_PM_HISTORY -#define MSG_PM_HISTORY 0x00D4 /* ↑ 历史采样查询(req: u32 count=N,0=默认) */ +#define MSG_PM_POLICY_GET 0x00D2 /* ↑ 策略读(base 空负载 → 回 MSG_PM_RESULT policy JSON;读级任意调用者) */ +#define MSG_PM_POLICY_SET 0x00D3 /* ↑ 策略写(req: m_pm_policy_set_t;动作级=root+系统身份,期 3) */ +#define MSG_PM_HISTORY 0x00D4 /* ↑ 历史采样查询(req: u32 count=N,0=默认) */ #define MSG_PM_HISTORY_RESULT 0x00D5 /* ↓ 历史 JSON(采样点清单 + 窗口汇总) */ -#define MSG_PM_EVENTS 0x00D6 /* ↑ 事件流查询(req: u32 count=N,0=默认) */ -#define MSG_PM_EVENTS_RESULT 0x00D7 /* ↓ 事件 JSON 清单 */ +#define MSG_PM_EVENTS 0x00D6 /* ↑ 事件流查询(req: u32 count=N,0=默认) */ +#define MSG_PM_EVENTS_RESULT 0x00D7 /* ↓ 事件 JSON 清单 */ +#define MSG_PM_CALIB_START 0x00D8 /* ↑ 标定启动(req: 场景名 NUL 串;动作级;0x00D8 空闲位,期 3) */ +#define MSG_PM_CALIB_STOP 0x00D9 /* ↑ 标定停止(req 空;动作级)→ 回 MSG_PM_RESULT calib JSON */ #endif +/* 期 3 · 策略写负载(item="profile" / "low-pct" / "crit-pct" / "bri-cap" / "scr-cap")。 */ +typedef struct m_pm_policy_set { + char item[16]; /* 策略项名 */ + char val[32]; /* 值(profile 枚举字符串或数字) */ +} m_pm_policy_set_t; /* 48 B */ + /* ---------------- 路径(全部可经 env 覆盖,宿主/qemu 桩测试用) ---------------- */ static char g_ps_dir[128] = "/sys/class/power_supply"; /* MEOW_PS_DIR */ static char g_bl_dir[128] = "/sys/class/backlight/backlight_pwm0"; /* MEOW_BL_DIR */ @@ -80,6 +106,10 @@ static char g_model_conf[160] = "/usr/data/meow/powermgr/power_model.conf"; /* M (= /data/meow/powermgr/power_model.conf,/data=/usr/data symlink, 组件持久化目录定案 SPECIAL_REF §1.1;存量平铺件不动) */ static char g_audio_sock[128] = "/usr/data/meow_audio.sock"; /* MEOW_AUDIO_SOCK */ +static char g_settings[160] = "/usr/data/meow/settings.conf"; /* MEOW_SETTINGS_FILE + (policy power.* 键落点;与 svc_power/launcher 同单点事实源) */ +static char g_log_dir[192] = "/usr/data/mnt/sd_0/MeowOS/logs"; /* MEOW_LOG_DIR(标定 CSV 落点, + 无卡降级 /tmp;同 netmgrd/audiod 日志根) */ static const char *g_sock = "/usr/data/meow_pm.sock"; /* MEOW_PM_SOCK/--sock */ #define SAMPLE_SEC_DEF 30 /* 电池采样/状态刷新节拍(秒;MEOW_PM_SAMPLE_SEC 覆盖,测试用) */ @@ -134,6 +164,166 @@ static void ps_path(char *buf, size_t cap, const char *node) snprintf(buf, cap, "%s/%s", g_ps_dir, node); } +/* ---------------- settings.conf 读写(policy power.* 键;单点事实源与 svc_power/launcher 共用) ---------------- + * 键格式:key=value('=' 切分,key 去首尾空白精确匹配,避免 power.low_pct 误配 power.low_pct_xx + * 或 audio.volume 误配 audio.volume_max——同 svc_power settings_get_int_trim 解析口径)。 + * 写:读原文件→逐字保留非目标行→命中替换/末尾追加→**原子写**(tmp+rename,避免半截文件), + * 比 svc_power 的 O_TRUNC 更稳(settings 与 launcher 同写,防写一半被读到)。 */ +static int settings_get_str(const char *key, char *out, int cap, const char *def) +{ + FILE *f = fopen(g_settings, "r"); + if (!f) { snprintf(out, cap, "%s", def ? def : ""); return 1; } + size_t kl = strlen(key); + char line[256]; + int found = 0; + while (fgets(line, sizeof line, f)) { + char *eq = strchr(line, '='); + if (!eq) continue; + char *k = line; + while (*k == ' ' || *k == '\t') k++; + long n = (long)(eq - k); + while (n > 0 && (k[n - 1] == ' ' || k[n - 1] == '\t')) n--; + if ((size_t)n != kl || strncmp(k, key, kl) != 0) continue; + char *v = eq + 1; + while (*v == ' ' || *v == '\t') v++; + int i = 0; + while (v[i] && v[i] != '\n' && v[i] != '\r' && v[i] != ' ' && v[i] != '\t' && i < cap - 1) { out[i] = v[i]; i++; } + out[i] = 0; + found = 1; + break; + } + fclose(f); + if (!found) { snprintf(out, cap, "%s", def ? def : ""); return 1; } + return 0; +} + +/* 读 settings.conf 某键(找到整数写入 *out)。返回 0=命中。 */ +static int settings_get_int_x(const char *key, int *out) +{ + char buf[32]; + if (settings_get_str(key, buf, sizeof buf, "") != 0 || !buf[0]) return 1; + *out = atoi(buf); + return 0; +} + +/* 原子写 settings.conf(tmp+rename)。text 为完整新内容。成功 0。 */ +static int settings_write_atomic(const char *text) +{ + char tmp[192]; + snprintf(tmp, sizeof tmp, "%s.tmp", g_settings); + int fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) return -1; + size_t tl = strlen(text); + ssize_t w = write(fd, text, tl); + close(fd); + if (w < 0 || (size_t)w != tl) { unlink(tmp); return -1; } + if (rename(tmp, g_settings) < 0) { unlink(tmp); return -1; } + return 0; +} + +/* 读 settings.conf 全文(≤2KB,settings 为 KB 级小文件)。返回字节数;无文件返回 0。 */ +static size_t settings_read_text(char *buf, size_t cap) +{ + FILE *f = fopen(g_settings, "r"); + if (!f) { buf[0] = 0; return 0; } + size_t n = 0; + int c; + while (n < cap - 1 && (c = fgetc(f)) != EOF) buf[n++] = (char)c; + fclose(f); + buf[n] = 0; + return n; +} + +/* 更新/插入 settings.conf 某键(值字符串;保留头部注释与其余键逐字,原子写)。 */ +static int settings_set_str(const char *key, const char *val) +{ + char txt[2048], out[2048]; + size_t n = settings_read_text(txt, sizeof txt); + size_t kl = strlen(key), o = 0; + int found = 0; + size_t start = 0; + while (start < n) { + size_t i = 0; + while (start + i < n && txt[start + i] != '\n') i++; + char line[256]; + if (i >= sizeof line - 1) i = sizeof line - 2; + memcpy(line, txt + start, i); line[i] = 0; + start += i; + if (start < n && txt[start] == '\n') start++; + char *q = line; + while (*q == ' ' || *q == '\t') q++; + int is_target = (strncmp(q, key, kl) == 0 && (q[kl] == '=' )); + if (is_target) { + int l = snprintf(out + o, sizeof out - o, "%s=%s\n", key, val); + if (l > 0 && o + (size_t)l < sizeof out) o += (size_t)l; + found = 1; + continue; /* 跳过旧行 */ + } + int l = snprintf(out + o, sizeof out - o, "%s\n", line); + if (l > 0 && o + (size_t)l < sizeof out) o += (size_t)l; + } + if (o > 0 && out[o - 1] == '\n') o--; /* 去掉尾多余换行(避免双空行) */ + if (!found) { + int l = snprintf(out + o, sizeof out - o, "%s%s=%s\n", o ? "\n" : "", key, val); + if (l > 0 && o + (size_t)l < sizeof out) o += (size_t)l; + } + out[o] = 0; + return settings_write_atomic(out); +} + +static int settings_set_int(const char *key, int val) +{ + char v[32]; + snprintf(v, sizeof v, "%d", val); + return settings_set_str(key, v); +} + +/* ---------------- 策略(policy)模型:profile 四档 + 低电阈值 + 亮度/息屏上限 ---------------- + * 默认全关(POWER_MANAGER_DESIGN §9 期 3):profile=balanced(无操作=现状),cap=0(不生效)。 + * 用户手动开(§附 3)。**powermgr 不直接写系统**:policy set 只写 settings.conf `power.*` 键, + * launcher/sysui 期 4 消费;本服务只算 effective 值用于报告,绝不 poke 背光/息屏/wlan0/bt。 */ +typedef struct { + char profile[16]; /* performance/balanced/powersave/ultra */ + int low_pct; /* power.low_pct(默认 15) */ + int crit_pct; /* power.critical_pct(默认 5) */ + int bri_cap; /* power.brightness_cap(0=off;量程 0-101 实测) */ + int scr_cap; /* power.screen_timeout_cap(0=off;秒) */ +} pm_policy_t; + +static void policy_defaults(pm_policy_t *p) +{ + snprintf(p->profile, sizeof p->profile, "balanced"); + p->low_pct = 15; p->crit_pct = 5; p->bri_cap = 0; p->scr_cap = 0; +} + +static const char *const k_policy_profiles[] = { "performance", "balanced", "powersave", "ultra", NULL }; + +/* 读 settings.conf 的 power.* 键(键缺失/无文件 → 默认=全关)。 */ +static void policy_load(pm_policy_t *p) +{ + policy_defaults(p); + settings_get_str("power.profile", p->profile, sizeof p->profile, "balanced"); + if (settings_get_int_x("power.low_pct", &p->low_pct)) p->low_pct = 15; + if (settings_get_int_x("power.critical_pct", &p->crit_pct)) p->crit_pct = 5; + if (settings_get_int_x("power.brightness_cap", &p->bri_cap)) p->bri_cap = 0; + if (settings_get_int_x("power.screen_timeout_cap", &p->scr_cap)) p->scr_cap = 0; + /* 背光量程 0-101(POWER_HW_FACTS 项 6);cap 越界 clamp,防手误写 255 造成无效上限。 + * profile 单独存(供期 4 launcher 依据 §5.1 表计算 min(用户值,档位值));本服务不在此推算 + * 档位隐含数值——设计 §5.1 的 180/120 是按 0-255 假定写的旧值,0-101 实测量程下推算会失真, + * 诚实处理:只透传用户显式 cap,档位映射留给 launcher 期 4 定案后落地。 */ + if (p->bri_cap < 0) p->bri_cap = 0; + if (p->bri_cap > 101) p->bri_cap = 101; + if (p->scr_cap < 0) p->scr_cap = 0; + if (p->low_pct < 1) p->low_pct = 1; + if (p->crit_pct < 1) p->crit_pct = 1; +} + +/* 是否已有「被手动开启」的策略(非默认全关态):profile!=balanced 或任一 cap>0。 */ +static int policy_enacted(const pm_policy_t *p) +{ + return (strcmp(p->profile, "balanced") != 0) || p->bri_cap > 0 || p->scr_cap > 0; +} + /* ---------------- 权威充电链(0-diff 照抄 svc_power charging_status_str 口径) ---------------- * mp2731-charger/status(Charging/Full=充电中)为权威;不可读回退 fusb302-typec-source/online==1 * (USB-C PD 控制器插线检测);再回退旧逻辑 battery/status==Charging || ac/online==1。 */ @@ -277,6 +467,90 @@ static int model_load(pm_model_t *m) return 0; } +/* 模型键是否在已知集合(CLI `model set` 校验用,拒绝未知键防写坏 conf)。 */ +static int model_key_is_known(const char *key) +{ + static const char *const keys[] = { + "nominal_mah", "bl_low_mw", "bl_mid_mw", "bl_high_mw", "panel_on_mw", + "wifi_unassoc_mw", "wifi_idle_mw", "wifi_tx_mw", "bt_up_mw", "bt_conn_mw", + "audio_idle_mw", "audio_play_mw", "cpu_full_mw", "baseline_mw", NULL + }; + for (int i = 0; keys[i]; i++) if (!strcmp(key, keys[i])) return 1; + return 0; +} + +static int atomic_write_path(const char *path, const char *text); /* fwd:model_conf_set_key 用它 */ + +/* 模型单键 setter:读改写单键 + **原子写**(tmp+rename,同 netmgrd 口径)。成功 0。 + * 保留其它键与注释行逐字;conf 缺失 → 生成 `key=value`(model_load 缺失键仍走内置默认)。 */ +static int model_conf_set_key(const char *key, int val) +{ + char txt[2048] = "", out[2048]; + size_t n = 0; + FILE *f = fopen(g_model_conf, "r"); + if (f) { + size_t r = 0; + int c; + while (r < sizeof txt - 1 && (c = fgetc(f)) != EOF) txt[r++] = (char)c; + txt[r] = 0; + n = r; + fclose(f); + } + if (!model_key_is_known(key)) return -1; + size_t kl = strlen(key), o = 0; + if (n == 0) { + /* conf 缺失 → 生成注释头 + 键(其余键 model_load 走内置默认) */ + int l = snprintf(out, sizeof out, "# meow_powermgr 经验功耗模型(POWER_MANAGER_DESIGN §3.2)\n" + "# 系数待真机标定(POWER_HW_FACTS §1 项 7/8)\n%s=%d\n", key, val); + if (l > 0) o = (size_t)l; + } else { + int found = 0; + size_t start = 0; + while (start < n) { + size_t i = 0; + while (start + i < n && txt[start + i] != '\n') i++; + char line[256]; + if (i >= sizeof line - 1) i = sizeof line - 2; + memcpy(line, txt + start, i); line[i] = 0; + start += i; + if (start < n && txt[start] == '\n') start++; + char *q = line; + while (*q == ' ' || *q == '\t') q++; + int is_target = (strncmp(q, key, kl) == 0 && q[kl] == '='); + if (is_target) { + int l = snprintf(out + o, sizeof out - o, "%s=%d\n", key, val); + if (l > 0 && o + (size_t)l < sizeof out) o += (size_t)l; + found = 1; + continue; + } + int l = snprintf(out + o, sizeof out - o, "%s\n", line); + if (l > 0 && o + (size_t)l < sizeof out) o += (size_t)l; + } + if (o > 0 && out[o - 1] == '\n') o--; + if (!found) { + int l = snprintf(out + o, sizeof out - o, "\n%s=%d\n", key, val); + if (l > 0 && o + (size_t)l < sizeof out) o += (size_t)l; + } + } + out[o] = 0; + return atomic_write_path(g_model_conf, out); +} + +/* 通用原子写(写 path.tmp → rename(path);同 netmgrd 口径,防半截配置)。成功 0。 */ +static int atomic_write_path(const char *path, const char *text) +{ + char tmp[256]; + snprintf(tmp, sizeof tmp, "%s.tmp", path); + int fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) return -1; + size_t tl = strlen(text); + ssize_t w = write(fd, text, tl); + close(fd); + if (w < 0 || (size_t)w != tl) { unlink(tmp); return -1; } + if (rename(tmp, path) < 0) { unlink(tmp); return -1; } + return 0; +} + /* ---------------- 采样环(守护进程;容量差分速率 → 续航估算 §3.1/§3.3 derived; * 期 2 同时服务 history 采样点:pct/est_mw/充电态/屏幕态/亮度,内存环形不落盘,重启清零) ---------------- */ typedef struct { @@ -707,10 +981,68 @@ static void build_json(uint32_t subset, int full, const batt_t *b, jadd(&w, "}"); } } - if (subset & PM_SUBSET_POLICY) jadd(&w, ",\"policy\":null"); /* 期 3 桩 */ + if (subset & PM_SUBSET_POLICY) { + /* 期 3:策略快照(读 settings.conf power.* 键)。powermgr 只读+报告 effective,绝不写系统。 */ + pm_policy_t pol; + policy_load(&pol); + jadd(&w, ",\"policy\":{"); + jadd(&w, "\"profile\":\"%s\",", pol.profile); + jadd(&w, "\"low_pct\":%d,\"critical_pct\":%d,", pol.low_pct, pol.crit_pct); + jadd(&w, "\"brightness_cap\":%d,\"screen_timeout_cap\":%d,", pol.bri_cap, pol.scr_cap); + jadd(&w, "\"enacted\":%d,", policy_enacted(&pol) ? 1 : 0); + jadd(&w, "\"note\":\"powermgr 只写 power.* 键,launcher/sysui 期4消费;本服务不直接写系统/绝不poke背光息屏\"}"); + } jadd(&w, "}"); } +/* 策略 JSON(IPC GET 响应 / CLI policy show 共用;纯读 settings,无副作用)。 */ +static void build_policy_json(const pm_policy_t *p, char *out, size_t cap) +{ + jw_t w = { out, cap, 0 }; + out[0] = 0; + jadd(&w, "{\"kind\":\"policy\",\"profile\":\"%s\",\"low_pct\":%d,\"critical_pct\":%d,", + p->profile, p->low_pct, p->crit_pct); + jadd(&w, "\"brightness_cap\":%d,\"screen_timeout_cap\":%d,\"enacted\":%d,", + p->bri_cap, p->scr_cap, policy_enacted(p) ? 1 : 0); + jadd(&w, "\"note\":\"powermgr 只写 power.* 键;launcher/sysui 期4消费生效;本服务不直接写系统\"}"); +} + +/* 应用一条 policy set(item+val → 写 settings.conf power.* 键,原子)。成功 0;失败写 why。 */ +static int policy_set_item(const char *item, const char *val, char *why, int cap) +{ + if (!item || !val) { snprintf(why, cap, "缺少 item/val"); return -1; } + if (!strcmp(item, "profile")) { + for (int i = 0; k_policy_profiles[i]; i++) { + if (!strcmp(k_policy_profiles[i], val)) { + if (settings_set_str("power.profile", val) != 0) { snprintf(why, cap, "写 settings 失败"); return -1; } + return 0; + } + } + snprintf(why, cap, "profile 须为 %s/%s/%s/%s", k_policy_profiles[0], k_policy_profiles[1], + k_policy_profiles[2], k_policy_profiles[3]); + return -1; + } + int v = atoi(val); + if (!strcmp(item, "low-pct")) { + if (v < 1 || v > 99) { snprintf(why, cap, "low-pct 须 1-99"); return -1; } + return settings_set_int("power.low_pct", v); + } + if (!strcmp(item, "crit-pct")) { + if (v < 1 || v > 99) { snprintf(why, cap, "crit-pct 须 1-99"); return -1; } + return settings_set_int("power.critical_pct", v); + } + if (!strcmp(item, "bri-cap")) { + if (v < 0 || v > 101) { snprintf(why, cap, "bri-cap 须 0-101(背光实测量程,0=不生效)"); return -1; } + return settings_set_int("power.brightness_cap", v); + } + if (!strcmp(item, "scr-cap")) { + if (v < 0) { snprintf(why, cap, "scr-cap 须 ≥0 秒(0=不生效)"); return -1; } + return settings_set_int("power.screen_timeout_cap", v); + } + snprintf(why, cap, "未知 item(profile|low-pct|crit-pct|bri-cap|scr-cap)"); + return -1; +} + /* ---------------- IPC 帧读写(同 svc_power 约定,全小端) ---------------- */ static int x_read_full(int fd, uint8_t *buf, size_t n) { @@ -793,6 +1125,22 @@ static pm_model_t g_model; /* 上一拍状态(事件检测用;-1=首拍未初始化,跳过跃迁判定) */ static int g_prev_charging = -1, g_prev_pct = -1, g_prev_screen = -1, g_prev_bri_pct = -1; +/* ---------------- 标定(calibrate)会话态(期 3;守护进程内 2s 节拍,用户跑 start/stop) ---------------- + * 为用户标定实验(§7 项 7/8:纯亮屏/息屏待机/放音乐/放视频四类场景)采集样本流: + * ts,cap_pct,vol_mv,current_ua,charge_mw,brightness_pct,cpu_util_pct,wifi_state,bt_state,scene + * 写 TF MeowOS/logs/power_calib_.csv(无卡降级 /tmp)。2 行一节拍逐行 fflush(突发掉电不丢)。 */ +#define CALIB_SEC 2 /* 标定采样节拍(秒) */ +#define CALIB_SCENE_MAX 48 /* 场景名上限(UTF-8 字节) */ +static int g_calib_active = 0; +static char g_calib_scene[CALIB_SCENE_MAX]; +static FILE *g_calib_fp = NULL; +static char g_calib_csv[384]; +static long g_calib_rows = 0; +static long g_calib_first_pct = -1, g_calib_last_pct = -1; +static long g_calib_start_mono = 0; +static long g_calib_cpu_pt = -1, g_calib_cpu_pi = 0; /* 标定专用 CPU 差分基线(与 history 无关) */ +static long g_calib_prx = -1, g_calib_ptx = 0; /* 标定专用 netdev 增量基线(判 wifi tx 档) */ + static int boot_mode_is_meow(void) { char buf[16] = ""; @@ -802,12 +1150,12 @@ static int boot_mode_is_meow(void) /* ---------------- 电源事件流(守护进程;内存环形,重启清零,不落盘) ---------------- * 可检测:① 充电器插拔(charging 位翻转)② 低电阈值穿越(低 15%/极低 5%/回到 20% 恢复,§5.2 默认) - * ③ 屏幕亮灭 ④ 背光跳变(≥30% 点)。⚠ App 前后台切换:期 2 无可轮询的 fg/bg 导出点(launcher 对外 - * 无 App 前台态;/tmp/meow_*_active 是 watchdog 让位的行为标记而非 App 前后台),**诚实标注不支持**, - * 不编造事件——留期 3 接 launcher MSG_ACT_FOCUS 后再扩。 */ -#define EV_LOW_PCT 15 /* 低电阈值(§5.2 power.low_pct 默认 15,期 3 接 settings) */ -#define EV_CRIT_PCT 5 /* 极低电阈值(§5.2 power.critical_pct 默认 5) */ -#define EV_LOW_REC 20 /* 恢复阈值(low+5;电量回到 ≥20% 触发恢复事件) */ + * ③ 屏幕亮灭 ④ 背光跳变(≥30% 点)。⚠ App 前后台切换:launcher MSG_ACT_FOCUS 为 app→launcher 单向上报, + * powermgr 侧**无导出点可接**(launcher 未对外提供当前顶层 activity 查询;/tmp/meow_*_active 是 watchdog + * 让位的行为标记而非 App 前后台),**诚实标注**:记录「期 4 接 launcher」扩展,本期不编造该事件(延续期 2 口径)。 */ +#define EV_LOW_PCT 15 /* 低电阈值默认(期 3 改由 settings power.low_pct 覆盖,见 detect_events) */ +#define EV_CRIT_PCT 5 /* 极低电阈值默认(期 3 改由 settings power.critical_pct 覆盖) */ +#define EV_LOW_REC 20 /* 恢复阈值默认(=low+5) */ #define EV_BRI_JUMP 30 /* 背光跳变阈值(百分点) */ typedef struct { @@ -836,6 +1184,13 @@ static void ev_push(int type, int arg, int pct, const char *fmt, ...) static void detect_events(const batt_t *b, const est_t *e) { + /* 期 3:低电阈值读 settings power.low_pct/critical_pct(§5.2;键缺失 → 默认 15/5,恢复=low+5)。 */ + pm_policy_t pol; + policy_load(&pol); + int low = pol.low_pct, crit = pol.crit_pct, rec = pol.low_pct + 5; + if (low < 1) low = EV_LOW_PCT; + if (crit < 1) crit = EV_CRIT_PCT; + if (rec <= crit) rec = crit + 1; /* ① 充电器插拔 */ if (g_prev_charging >= 0 && g_prev_charging != b->charging) { if (b->charging) ev_push(0, 1, b->pct, "插上充电器,开始充电 (state=%s)", b->state); @@ -844,13 +1199,13 @@ static void detect_events(const batt_t *b, const est_t *e) /* ② 低电阈值(放电下降沿触发;充电回阈值恢复) */ if (b->pct >= 0 && g_prev_pct >= 0) { if (!b->charging) { - if (g_prev_pct >= EV_LOW_PCT && b->pct < EV_LOW_PCT) - ev_push(1, 0, b->pct, "电量低 %d%%(阈值 %d%%)", b->pct, EV_LOW_PCT); - if (g_prev_pct >= EV_CRIT_PCT && b->pct < EV_CRIT_PCT) - ev_push(1, 1, b->pct, "电量极低 %d%%(阈值 %d%%)", b->pct, EV_CRIT_PCT); + if (g_prev_pct >= low && b->pct < low) + ev_push(1, 0, b->pct, "电量低 %d%%(阈值 %d%%)", b->pct, low); + if (g_prev_pct >= crit && b->pct < crit) + ev_push(1, 1, b->pct, "电量极低 %d%%(阈值 %d%%)", b->pct, crit); } - if (g_prev_pct < EV_LOW_REC && b->pct >= EV_LOW_REC) - ev_push(1, 2, b->pct, "电量回到 %d%%(≥%d%% 恢复)", b->pct, EV_LOW_REC); + if (g_prev_pct < rec && b->pct >= rec) + ev_push(1, 2, b->pct, "电量回到 %d%%(≥%d%% 恢复)", b->pct, rec); } /* ③ 屏幕亮灭 / ④ 背光跳变(只读模式 screen=-1 → 跳过;息屏时不算背光跳变) */ if (e->screen_on >= 0) { @@ -878,6 +1233,8 @@ static void daemon_tick(void) g_boot_mode, fm ? "=meow" : "!=meow/missing"); g_full_mode = fm; } + /* 期 3:每拍重载模型 conf(`model set`/手工改系数即时生效;conf 缺失走内置默认,读侧无害)。 */ + if (g_full_mode) model_load(&g_model); batt_t b; batt_read(&b); long t = -1, i = 0; @@ -891,6 +1248,146 @@ static void daemon_tick(void) detect_events(&b, &e); } +/* ---------------- 标定(calibrate)实现(守护进程内;用户 CLI start/stop 驱动) ---------------- */ +static void calib_csv_path(void) +{ + time_t t = time(NULL); + char ts[32]; + snprintf(ts, sizeof ts, "%ld", (long)t); + /* TF 可写 → MeowOS/logs;否则 /tmp(同 netmgrd 无卡降级)。路径去重(同秒 → _N)。 */ + if (access(g_log_dir, W_OK) != 0) { + char d[200]; + snprintf(d, sizeof d, "%s", g_log_dir); + char *s = strrchr(d, '/'); + if (s) *s = 0; + mkdir(d, 0755); /* 建父层(如 /usr/data/mnt/sd_0/MeowOS);外层已挂载则瞬时成功 */ + mkdir(g_log_dir, 0755); + } + const char *base = (access(g_log_dir, W_OK) == 0) ? g_log_dir : "/tmp"; + char p[384]; + for (int n = 0; n < 100; n++) { + if (n == 0) snprintf(p, sizeof p, "%s/power_calib_%s.csv", base, ts); + else snprintf(p, sizeof p, "%s/power_calib_%s_%d.csv", base, ts, n); + if (access(p, F_OK) != 0) break; + } + snprintf(g_calib_csv, sizeof g_calib_csv, "%s", p); +} + +static void calib_write_header(const char *scene) +{ + if (!g_calib_fp) return; + fprintf(g_calib_fp, "# meow_powermgr calibrate scene=%s ts=%ld\n", scene, (long)time(NULL)); + fprintf(g_calib_fp, "ts,cap_pct,vol_mv,current_ua,charge_mw,brightness_pct,cpu_util_pct,wifi_state,bt_state\n"); + fflush(g_calib_fp); +} + +/* 启动标定会话(CLI calibrate start 经 IPC;已启动 → 报错)。返回 0=启动成功。 */ +static int calib_start(const char *scene) +{ + if (g_calib_active) return -1; + if (!scene || !scene[0]) return -1; + if (!g_full_mode) { svc_log("calib: readonly 模式不采样(HibyOS 降级)"); return -1; } + calib_csv_path(); + g_calib_fp = fopen(g_calib_csv, "w"); + if (!g_calib_fp) { svc_log("calib: open %s fail: %s", g_calib_csv, strerror(errno)); return -1; } + snprintf(g_calib_scene, sizeof g_calib_scene, "%s", scene); + calib_write_header(scene); + g_calib_active = 1; + g_calib_rows = 0; + g_calib_first_pct = -1; g_calib_last_pct = -1; + g_calib_start_mono = mono_now(); + g_calib_cpu_pt = -1; g_calib_cpu_pi = 0; + g_calib_prx = -1; g_calib_ptx = 0; + svc_log("calib: start scene=%s -> %s", scene, g_calib_csv); + return 0; +} + +/* 单次标定采样(CALIB_SEC 节拍):电流(μA)/充电功率/亮度/CPU 差分/wifi/bt/电量%。 */ +static void calib_tick(void) +{ + if (!g_calib_active || !g_calib_fp) return; + batt_t b; + batt_read(&b); + /* CPU 差分(独立基线,勿动 history 的 g_cpu_prev_*) */ + long t = -1, i = 0; + int cu = cpu_util_pct(g_calib_cpu_pt, g_calib_cpu_pi, &t, &i); + if (t >= 0) { g_calib_cpu_pt = t; g_calib_cpu_pi = i; } + if (cu < 0) cu = -1; + /* 亮度/面板、wifi 状态、bt 状态 */ + int on = -1; + int bp = bl_read_pct(&on); + long rx = -1, tx = -1; + int ws = wifi_read_state(&rx, &tx); + if (ws == 1 && g_calib_prx >= 0 && rx >= 0 && (rx - g_calib_prx) + (tx - g_calib_ptx) > 4096) ws = 2; + g_calib_prx = rx; g_calib_ptx = tx; + int bs = bt_read_state(); + /* 充电功率(mp2731 实测;放电恒 0 无实测轨) */ + int cmw = pm_charge_mw(&b); + if (g_calib_rows == 0) g_calib_first_pct = b.pct; + g_calib_last_pct = b.pct; + long now = mono_now() - g_calib_start_mono; + fprintf(g_calib_fp, "%ld,%d,%d,%d,%d,%d,%d,%d,%d\n", + now, b.pct, b.mv, b.chg_cur_ua, cmw, bp, cu, ws, bs); + fflush(g_calib_fp); + g_calib_rows++; +} + +/* 停止标定会话:写尾注 + 关文件;返回样本数。 */ +static long calib_stop(void) +{ + if (!g_calib_active) return -1; + if (g_calib_fp) { + fprintf(g_calib_fp, "# end rows=%ld duration_s=%ld cap=%ld->%ld\n", + g_calib_rows, mono_now() - g_calib_start_mono, + g_calib_first_pct, g_calib_last_pct); + fclose(g_calib_fp); + g_calib_fp = NULL; + } + long rows = g_calib_rows; + g_calib_active = 0; + char scene[CALIB_SCENE_MAX]; + snprintf(scene, sizeof scene, "%s", g_calib_scene); + svc_log("calib: stop scene=%s rows=%ld csv=%s", scene, rows, g_calib_csv); + return rows; +} + +/* 守护退出时收尾(SIGTERM/INT → g_stop):若标定未停则落地收尾,防半截/丢缓冲。 */ +static void calib_finalize_on_exit(void) +{ + if (g_calib_active && g_calib_fp) calib_stop(); +} + +/* 标定 JSON(IPC 响应/CLI 用):列出指定目录下的 power_calib_*.csv + 当前会话态。 */ +static void build_calib_json(char *out, size_t cap) +{ + jw_t w = { out, cap, 0 }; + out[0] = 0; + jadd(&w, "{\"kind\":\"calib\",\"active\":%d,", g_calib_active ? 1 : 0); + if (g_calib_active) { + jadd(&w, "\"scene\":\"%s\",\"csv\":\"%s\",\"rows\":%ld,", g_calib_scene, g_calib_csv, g_calib_rows); + } else { + jadd(&w, "\"scene\":null,\"csv\":null,\"rows\":0,"); + } + jadd(&w, "\"files\":["); + DIR *d = opendir(g_log_dir); + int first = 1; + if (d) { + struct dirent *de; + while ((de = readdir(d))) { + if (strncmp(de->d_name, "power_calib_", 12) != 0 || !strstr(de->d_name, ".csv")) continue; + char p[512]; + snprintf(p, sizeof p, "%s/%s", g_log_dir, de->d_name); + struct stat st; + if (stat(p, &st) == 0) { + jadd(&w, "%s\"%s\"", first ? "" : ",", de->d_name); + first = 0; + } + } + closedir(d); + } + jadd(&w, "]}"); +} + /* 期 2 · history:从采样环出最近最多 count 条 + 全环窗口汇总(内存环形,重启清零)。 * JSON: {kind:history,count,n_samples,window_sec,start_pct,end_pct,min_pct,max_pct,avg_mw,samples:[[ts,pct,est_mw,chg,scr,bri],...]} */ static void build_history_json(uint32_t count, char *out, size_t cap) @@ -956,8 +1453,82 @@ static void build_events_json(uint32_t count, char *out, size_t cap) jadd(&w, "]}"); } +/* ---------------- 动作级鉴权(期 3 POLICY_SET/CALIB_*;同 svc_power 模型,0-diff 可移植) ---------------- + * 读级(POLICY_GET/QUERY/HISTORY/EVENTS)任意调用者;动作级(POLICY_SET/CALIB_START/CALIB_STOP) + * 须 root(uid==0) + 系统身份(CALL_SYS 或 os.meow.* 包)。 + * MEOW_PM_AUTH_TEST=1(仅宿主测试)关闭动作级鉴权——生产绝不设置。 */ +typedef enum { CALL_OTHER, CALL_PKG, CALL_SYS } caller_kind_t; +typedef struct { + caller_kind_t kind; + uid_t uid; + char pkg[MEOW_APP_ID_MAX]; +} caller_t; + +static void classify_exe(const char *exe, caller_t *out) +{ + static const char *mp = "/usr/data/mnt/sd_0/MeowAPPs/"; + if (strncmp(exe, mp, strlen(mp)) == 0) { + const char *p = exe + strlen(mp); + if (*p == '/') p++; + const char *end = strchr(p, '/'); + int plen = end ? (int)(end - p) : (int)strlen(p); + if (plen > 0 && plen < MEOW_APP_ID_MAX) { + memcpy(out->pkg, p, (size_t)plen); out->pkg[plen] = 0; + out->kind = CALL_PKG; + return; + } + } + char tmp[MEOW_APP_ID_MAX]; + if (strcmp(exe, "/usr/bin/meow_launcherd") == 0) { + snprintf(tmp, sizeof tmp, "%s", "os.meow.launcher"); + } else if (strcmp(exe, "/usr/data/mnt/sd_0/MeowOS/opt/MeowPanel/meowpanel") == 0) { + snprintf(tmp, sizeof tmp, "%s", "os.meow.panel"); + } else if (strncmp(exe, "/usr/bin/meow_", 14) == 0) { + size_t l = strlen(exe + 11); + if (l >= sizeof tmp) l = sizeof tmp - 1; + memcpy(tmp, exe + 11, l); tmp[l] = 0; + } else if (strncmp(exe, "/usr/data/meow/", 15) == 0) { + snprintf(tmp, sizeof tmp, "%s", "os.meow.core"); + } else { + return; /* CALL_OTHER */ + } + snprintf(out->pkg, sizeof out->pkg, "%s", tmp); + out->kind = CALL_SYS; +} + +static void classify_caller(int fd, caller_t *out) +{ + memset(out, 0, sizeof *out); + out->uid = (uid_t)-1; + struct ucred cred; + socklen_t cl = sizeof cred; + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &cl) != 0) return; + out->uid = cred.uid; + char procpath[64], exe[256]; + snprintf(procpath, sizeof procpath, "/proc/%d/exe", (int)cred.pid); + ssize_t n = readlink(procpath, exe, sizeof exe - 1); + if (n <= 0) return; + exe[n] = 0; + classify_exe(exe, out); +} + +static int is_sys_identity(const caller_t *c) +{ + if (c->kind == CALL_SYS) return 1; + if (c->kind == CALL_PKG && !strncmp(c->pkg, "os.meow.", 8)) return 1; + return 0; +} + +static int caller_is_action_allowed(const caller_t *c) +{ + if (getenv("MEOW_PM_AUTH_TEST")) return 1; /* 宿主测试专用:关闭动作级鉴权 */ + return (c->uid == 0) && is_sys_identity(c); +} + static void handle_conn(int c) { + caller_t caller; + classify_caller(c, &caller); /* 连接级身份(pid→exe→classify);期 3 动作级鉴权用 */ for (;;) { uint8_t hdr[MEOW_IPC_HDR_LEN]; if (x_read_full(c, hdr, sizeof hdr) < 0) break; @@ -1023,7 +1594,82 @@ static void handle_conn(int c) continue; } - send_err(c, req_id, MEOW_ERR_INVAL, "unknown type (期1 PM_QUERY / 期2 HISTORY/EVENTS)"); + if (type == MSG_PM_POLICY_GET) { + /* 期 3:策略读(读级任意调用者)。回 policy JSON(MSG_PM_RESULT)。 */ + pm_policy_t p; + policy_load(&p); + char json[MEOW_IPC_MAX]; + build_policy_json(&p, json, sizeof json); + send_pm_result(c, MSG_PM_RESULT, req_id, PM_SUBSET_POLICY, json); + continue; + } + + if (type == MSG_PM_POLICY_SET) { + /* 期 3:策略写(动作级=root+系统身份)。req: m_pm_policy_set_t{item,val}。 + * 生效方式:只写 settings.conf power.* 键(原子),powermgr 不直接写系统。 */ + if (!caller_is_action_allowed(&caller)) { + send_err(c, req_id, MEOW_ERR_PERM, "policy set 需 root+系统身份"); + continue; + } + m_pm_policy_set_t s; + memset(&s, 0, sizeof s); + if (rlen > sizeof s) rlen = sizeof s; + memcpy(&s, payload, rlen); + s.item[sizeof s.item - 1] = 0; s.val[sizeof s.val - 1] = 0; + char why[128] = ""; + int rc = policy_set_item(s.item, s.val, why, sizeof why); + pm_policy_t p; + policy_load(&p); + char json[MEOW_IPC_MAX]; + if (rc != 0) { + snprintf(json, sizeof json, "{\"kind\":\"policy\",\"ok\":false,\"why\":\"%s\"}", why); + } else { + build_policy_json(&p, json, sizeof json); + } + send_pm_result(c, MSG_PM_RESULT, req_id, rc == 0 ? PM_SUBSET_POLICY : 0, json); + continue; + } + + if (type == MSG_PM_CALIB_START) { + /* 期 3:标定启动(动作级)。req: 场景名 NUL 串。 */ + if (!caller_is_action_allowed(&caller)) { + send_err(c, req_id, MEOW_ERR_PERM, "calib start 需 root+系统身份"); + continue; + } + char scene[CALIB_SCENE_MAX]; + memset(scene, 0, sizeof scene); + if (rlen > sizeof scene - 1) rlen = sizeof scene - 1; + memcpy(scene, payload, rlen); + if (calib_start(scene) != 0) { + send_err(c, req_id, MEOW_ERR_BUSY, g_calib_active ? "calib 已启动" : "calib 启动失败(只读或打不开csv)"); + continue; + } + char json[MEOW_IPC_MAX]; + build_calib_json(json, sizeof json); + send_pm_result(c, MSG_PM_RESULT, req_id, 0, json); + continue; + } + + if (type == MSG_PM_CALIB_STOP) { + /* 期 3:标定停止(动作级)。req 空。 */ + if (!caller_is_action_allowed(&caller)) { + send_err(c, req_id, MEOW_ERR_PERM, "calib stop 需 root+系统身份"); + continue; + } + if (!g_calib_active) { + send_err(c, req_id, MEOW_ERR_BUSY, "calib 未启动"); + continue; + } + long rows = calib_stop(); + char json[MEOW_IPC_MAX]; + snprintf(json, sizeof json, + "{\"kind\":\"calib\",\"stopped\":true,\"rows\":%ld,\"csv\":\"%s\",\"scene\":\"%s\"}", + rows, g_calib_csv, g_calib_scene); + send_pm_result(c, MSG_PM_RESULT, req_id, 0, json); + continue; + } + + send_err(c, req_id, MEOW_ERR_INVAL, "unknown type (期1 QUERY / 期2 HISTORY/EVENTS / 期3 POLICY/CALIB)"); break; } } @@ -1057,14 +1703,23 @@ static int run_daemon(const char *sock) sock, g_full_mode ? "full" : "readonly", g_sample_sec, access(g_model_conf, R_OK) == 0 ? g_model_conf : "builtin-default(待标定)"); - long next_tick = 0; /* 立即首拍 */ + long next_tick = 0; /* 立即首拍 */ + long next_calib = 0; /* 标定节拍(仅 g_calib_active 时推进) */ while (!g_stop) { long now = mono_now(); if (now >= next_tick) { daemon_tick(); next_tick = now + g_sample_sec; } - int wait_ms = (int)((next_tick - mono_now()) * 1000); + if (g_calib_active && now >= next_calib) { + calib_tick(); + next_calib = now + CALIB_SEC; + } + /* poll 休眠取「下一事件」最近者:采样拍、标定拍(活动时)。上界 g_sample_sec 冗余保护。 */ + long d_tick = next_tick - mono_now(); + long d_calib = g_calib_active ? (next_calib - mono_now()) : d_tick; + long dmin = d_tick < d_calib ? d_tick : d_calib; + int wait_ms = (int)(dmin * 1000); if (wait_ms < 50) wait_ms = 50; if (wait_ms > g_sample_sec * 1000) wait_ms = g_sample_sec * 1000; struct pollfd pfd = { lfd, POLLIN, 0 }; @@ -1074,6 +1729,7 @@ static int run_daemon(const char *sock) if (c >= 0) { handle_conn(c); close(c); } } } + calib_finalize_on_exit(); /* 期 3:守护退出前收尾标定(SIGTERM 等) */ svc_log("meow_powermgr exit"); close(lfd); unlink(sock); @@ -1329,8 +1985,30 @@ static int cli_estimate(void) return 0; } -static int cli_model(void) +static int cli_model(int n, char **v) { + /* 期 3:`model set `——读改写单键 + 原子写(标定后即时改系数)。 */ + if (n >= 1 && !strcmp(v[0], "set")) { + if (n >= 3) { + const char *key = v[1]; + int mw = atoi(v[2]); + if (!model_key_is_known(key)) { + fprintf(stderr, "model set: 未知键 %s(可用键见 model 输出)\n", key); + return 1; + } + if (mw < 0 || mw > 1000000) { fprintf(stderr, "model set: mw 须 0-1000000\n"); return 1; } + if (model_conf_set_key(key, mw) != 0) { + fprintf(stderr, "model set: 写 %s 失败(原子写)\n", g_model_conf); + return 1; + } + pm_model_t m; + model_load(&m); + printf("model set %s=%d(%s)✓\n", key, mw, g_model_conf); + return 0; + } + fprintf(stderr, "usage: meow_power model set \n"); + return 1; + } pm_model_t m; int def = model_load(&m); printf("# meow_powermgr 经验功耗模型(POWER_MANAGER_DESIGN §3.2)\n"); @@ -1354,6 +2032,109 @@ static int cli_model(void) return 0; } +/* 期 3 · policy:show|set。策略数据源 = settings.conf power.* 键;powermgr 只写键不写系统。 */ +static int cli_policy(int n, char **v) +{ + if (n >= 1 && !strcmp(v[0], "show")) { + /* 优先 IPC(守护 view),不可达降级直读 settings.conf(读侧无副作用、口径一致)。 */ + char js[MEOW_IPC_MAX]; + if (pm_ipc_json(MSG_PM_POLICY_GET, NULL, 0, MSG_PM_RESULT, js, sizeof js) != 0) { + pm_policy_t p; + policy_load(&p); + build_policy_json(&p, js, sizeof js); + fprintf(stderr, "note: powermgr 守护不可达,直读 settings.conf(无 daemon 侧差)\n"); + } + char prof[16]; + int low = -1, crit = -1, bcap = -1, scap = -1, enacted = -1; + jstr(js, "profile", prof, sizeof prof); + jint(js, "low_pct", &low); + jint(js, "critical_pct", &crit); + jint(js, "brightness_cap", &bcap); + jint(js, "screen_timeout_cap", &scap); + jint(js, "enacted", &enacted); + printf("policy: profile=%s low_pct=%d critical_pct=%d\n", prof[0] ? prof : "?", low, crit); + printf(" brightness_cap=%d screen_timeout_cap=%d enact=%s\n", bcap, scap, enacted == 1 ? "on" : "off"); + printf("生效方式: powermgr 只写 settings.conf power.* 键,launcher/sysui 期4消费(本服务不直接写系统," + "绝不poke背光/息屏/wlan0/bt)\n"); + printf("默认全关: profile=balanced 无操作=现状; cap=0 不生效; 用户手动开(只能用户手动开)\n"); + if (enacted == 1) + printf("注意: 已开启策略档——但 launcher 未接入前仅持久化,不实际生效(期4接 launcher)\n"); + return 0; + } + if (n >= 2 && !strcmp(v[0], "set")) { + const char *item = v[1], *val = n >= 3 ? v[2] : ""; + char why[128] = ""; + int rc = policy_set_item(item, val, why, sizeof why); + if (rc != 0) { fprintf(stderr, "policy set %s %s: %s\n", item, val, why[0] ? why : "写 settings 失败"); return 1; } + printf("policy set %s=%s ✓(settings.conf power.* 键;launcher 期4消费)\n", item, val); + return 0; + } + fprintf(stderr, "usage: meow_power policy show| set profile <档>|set low-pct |set crit-pct |" + "set bri-cap <0-101>|set scr-cap <秒>\n"); + return 1; +} + +/* 期 3 · calibrate:start|stop|list(用户标定实验;start/stop 经 IPC 驱动守护 2s 采样写 CSV)。 */ +static int cli_calibrate(int n, char **v) +{ + if (n >= 1 && !strcmp(v[0], "start")) { + if (n < 2) { fprintf(stderr, "usage: meow_power calibrate start <场景名>\n"); return 1; } + char js[MEOW_IPC_MAX]; + if (pm_ipc_json(MSG_PM_CALIB_START, v[1], (uint32_t)strlen(v[1]), MSG_PM_RESULT, js, sizeof js) != 0) { + fprintf(stderr, "powermgr 守护不可达:calibrate 需 meow_powermgr 常驻(trigger=boot)\n"); + return 1; + } + if (strstr(js, "\"active\":1") || strstr(js, "\"active\": true")) { + char csv[260] = "", sc[64] = ""; + jstr(js, "csv", csv, sizeof csv); jstr(js, "scene", sc, sizeof sc); + printf("calibrate 已启动: scene=%s csv=%s(2s 节拍采样,实验后 `meow_power calibrate stop` 停止)\n", + sc[0] ? sc : v[1], csv[0] ? csv : "?"); + return 0; + } + fprintf(stderr, "calibrate start 失败: %s\n", strstr(js, "why") ? js : "未知"); + return 1; + } + if (n >= 1 && !strcmp(v[0], "stop")) { + char js[MEOW_IPC_MAX]; + if (pm_ipc_json(MSG_PM_CALIB_STOP, NULL, 0, MSG_PM_RESULT, js, sizeof js) != 0) { + fprintf(stderr, "powermgr 守护不可达:calibrate stop 需 meow_powermgr 常驻\n"); + return 1; + } + long rows = -1; char csv[260] = "", sc[64] = ""; + int rr = 0; + if (jint(js, "rows", &rr) == 0) rows = rr; + jstr(js, "csv", csv, sizeof csv); + jstr(js, "scene", sc, sizeof sc); + if (rows >= 0) + printf("calibrate 已停止: scene=%s rows=%ld csv=%s\n", sc, rows, csv); + else + printf("calibrate 停止: %s\n", strstr(js, "未启动") ? "calib 未启动" : js); + return 0; + } + if (n >= 1 && !strcmp(v[0], "list")) { + DIR *d = opendir(g_log_dir); + int cnt = 0; + printf("calibrate 列表(%s):\n", g_log_dir); + if (!d) { printf(" (日志目录不可读,无卡降级?)\n"); return 0; } + struct dirent *de; + while ((de = readdir(d))) { + if (strncmp(de->d_name, "power_calib_", 12) != 0 || !strstr(de->d_name, ".csv")) continue; + char p[512]; + snprintf(p, sizeof p, "%s/%s", g_log_dir, de->d_name); + struct stat st; + long kb = 0; + if (stat(p, &st) == 0) kb = (long)st.st_size; + printf(" %s (%ldB)\n", de->d_name, kb); + cnt++; + } + closedir(d); + if (cnt == 0) printf(" (无标定记录)\n"); + return 0; + } + fprintf(stderr, "usage: meow_power calibrate start <场景名>| stop| list\n"); + return 1; +} + /* 期 2 · history:最近 N 个采样点 + 全环窗口汇总(不落盘,重启清零) */ static int cli_history(int n, char **v) { @@ -1419,7 +2200,8 @@ static int cli_events(int n, char **v) return 1; } int cnt = 0; jint(js, "count", &cnt); - printf("events: %d 条(内存环形,重启清零;App 前后台切换无可轮询导出点——期2诚实标注不支持)\n", cnt); + printf("events: %d 条(内存环形,重启清零;App 前后台切换——launcher MSG_ACT_FOCUS 为单向 app→launcher 上报," + "powermgr 侧无导出点可接,期 4 接 launcher 扩展)\n", cnt); if (cnt == 0) { printf(" (无事件)\n"); return 0; } long ts[64]; char tn[64][16]; int pct[64]; char txt[64][128]; int m = 0; @@ -1499,15 +2281,9 @@ static int cli_top(void) return 0; } -static int cli_stub(const char *what, const char *phase) -{ - printf("meow_power %s: 期 %s 落地,当前未实现(POWER_MANAGER_DESIGN §9 分期)\n", what, phase); - return 1; -} - static const char *cli_usage(void) { - return "status|estimate|model|history[N]|top|events[N]|policy(history/top/events 期2已落地;policy 期3桩)"; + return "status|estimate|model[set ]|history[N]|top|events[N]|policy show|set ...|calibrate start|stop|list"; } static int cli_run(int n, char **v) @@ -1515,11 +2291,12 @@ static int cli_run(int n, char **v) const char *cmd = v[0]; if (!strcmp(cmd, "status")) return cli_status(); if (!strcmp(cmd, "estimate")) return cli_estimate(); - if (!strcmp(cmd, "model")) return cli_model(); + if (!strcmp(cmd, "model")) return cli_model(n - 1, v + 1); if (!strcmp(cmd, "history")) return cli_history(n - 1, v + 1); if (!strcmp(cmd, "top")) return cli_top(); if (!strcmp(cmd, "events")) return cli_events(n - 1, v + 1); - if (!strcmp(cmd, "policy")) return cli_stub("policy", "3"); + if (!strcmp(cmd, "policy")) return cli_policy(n - 1, v + 1); + if (!strcmp(cmd, "calibrate")) return cli_calibrate(n - 1, v + 1); fprintf(stderr, "usage: meow_power <%s>\n", cli_usage()); return 1; } @@ -1537,6 +2314,8 @@ int main(int argc, char **argv) if ((e = getenv("MEOW_PROC_STAT")) && e[0]) snprintf(g_proc_stat, sizeof g_proc_stat, "%s", e); if ((e = getenv("MEOW_BOOT_MODE")) && e[0]) snprintf(g_boot_mode, sizeof g_boot_mode, "%s", e); if ((e = getenv("MEOW_PM_MODEL")) && e[0]) snprintf(g_model_conf, sizeof g_model_conf, "%s", e); + if ((e = getenv("MEOW_SETTINGS_FILE")) && e[0]) snprintf(g_settings, sizeof g_settings, "%s", e); + if ((e = getenv("MEOW_LOG_DIR")) && e[0]) snprintf(g_log_dir, sizeof g_log_dir, "%s", e); if ((e = getenv("MEOW_AUDIO_SOCK")) && e[0]) snprintf(g_audio_sock, sizeof g_audio_sock, "%s", e); if ((e = getenv("MEOW_PM_SOCK")) && e[0]) g_sock = e; if ((e = getenv("MEOW_PM_SAMPLE_SEC")) && atoi(e) > 0) g_sample_sec = atoi(e); diff --git a/patch_v2/meow_powermgr/meow_powermgr_host b/patch_v2/meow_powermgr/meow_powermgr_host index d9054e21241ab6b739ef441596521f778a36e8f8..42eb4e4d0ca302ba5e0d67ffc300adce0b2246d0 100755 GIT binary patch literal 79304 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 U?oQiIV?=9aD$Xe$0gqSwFR-KP#sB~S literal 77488 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 "$T/proc_stat" echo meow > "$T/boot_mode" +mkdir -p "$T/logs" # 标定 CSV 落点(MEOW_LOG_DIR) +cat > "$T/settings.conf" <<'SEOF' +# meow-settings 1 (测试桩:policy power.* 键落点) +SEOF ENVS="MEOW_PS_DIR=$PS MEOW_BL_DIR=$BL MEOW_NET_DIR=$NET MEOW_RFKILL_DIR=$RF MEOW_BT_DIR=$BT MEOW_NETDEV=$T/netdev MEOW_PROC_STAT=$T/proc_stat MEOW_BOOT_MODE=$T/boot_mode - MEOW_PM_MODEL=$T/model.conf MEOW_AUDIO_SOCK=$T/no_audio.sock MEOW_PM_SOCK=$T/pm.sock - MEOW_PM_NO_HCICONFIG=1" + MEOW_PM_MODEL=$T/model.conf MEOW_SETTINGS_FILE=$T/settings.conf MEOW_LOG_DIR=$T/logs + MEOW_AUDIO_SOCK=$T/no_audio.sock MEOW_PM_SOCK=$T/pm.sock + MEOW_PM_NO_HCICONFIG=1 MEOW_PM_AUTH_TEST=1" ln -sf "$(readlink -f "$BIN")" "$T/meow_power" # argv[0] 双形态 # ---- T1: 守护直读(无守护 → 降级直读) ---- @@ -143,8 +148,65 @@ ck T9a "history:" "$OUT" ck T9b "采样点" "$OUT" ck T9c "est_mW" "$OUT" echo "$OUT" | grep -q "守护不可达" && { FAIL=$((FAIL+1)); echo "FAIL T9d 应走守护"; } || { PASS=$((PASS+1)); echo "PASS T9d via-daemon"; } -OUT=$(env $ENVS $Q "$T/meow_power" policy 2>&1) -ck T9e "期 3" "$OUT" +# ---- T9e: 期 3 policy show(默认全关:profile=balanced / cap=0 / enact=off)---- +OUT=$(env $ENVS $Q "$T/meow_power" policy show 2>&1) +ck T9e "profile=balanced low_pct=15 critical_pct=5" "$OUT" +ck T9e2 "brightness_cap=0 screen_timeout_cap=0 enact=off" "$OUT" +ck T9e3 "默认全关" "$OUT" + +# ---- T9f: 期 3 policy set profile powersave(写入 settings.conf;enact=on)---- +OUT=$(env $ENVS $Q "$T/meow_power" policy set profile powersave 2>&1) +ck T9f "policy set profile=powersave" "$OUT" +OUT=$(env $ENVS $Q "$T/meow_power" policy show 2>&1) +ck T9f2 "profile=powersave" "$OUT" +ck T9f3 "enact=on" "$OUT" +grep -q "power.profile=powersave" "$T/settings.conf" && { PASS=$((PASS+1)); echo "PASS T9f4 settings 键"; } || { FAIL=$((FAIL+1)); echo "FAIL T9f4: $(cat "$T/settings.conf")"; } + +# ---- T9g: 期 3 低电阈值读 settings.conf(power.low_pct=20 生效于事件判定)---- +env $ENVS $Q "$T/meow_power" policy set low-pct 20 >/dev/null 2>&1 +echo 19 > "$PS/battery/capacity" # 从 93 跳到 19 < 20 → 低电事件(阈值 20%) +sleep 4 # 等守护节拍采样 +OUT=$(env $ENVS $Q "$T/meow_power" policy show 2>&1) +ck T9g "low_pct=20" "$OUT" +OUT=$(env $ENVS $Q "$T/meow_power" events 2>&1) +ck T9g2 "阈值 20%" "$OUT" +echo 93 > "$PS/battery/capacity" # 恢复 +env $ENVS $Q "$T/meow_power" policy set low-pct 15 >/dev/null 2>&1 +env $ENVS $Q "$T/meow_power" policy set profile balanced >/dev/null 2>&1 + +# ---- T9h: 期 3 policy set bri-cap(0-101 越界拒绝)---- +OUT=$(env $ENVS $Q "$T/meow_power" policy set bri-cap 88 2>&1) +ck T9h "policy set bri-cap=88" "$OUT" +OUT=$(env $ENVS $Q "$T/meow_power" policy set bri-cap 255 2>&1) +ck T9h2 "0-101" "$OUT" +env $ENVS $Q "$T/meow_power" policy set bri-cap 0 >/dev/null 2>&1 + +# ---- T9i: 期 3 标定工具 calibrate start/stop/list 出 CSV ---- +OUT=$(env $ENVS $Q "$T/meow_power" calibrate start 纯亮屏 2>&1) +ck T9i "calibrate 已启动" "$OUT" +ck T9i2 "power_calib_" "$OUT" +sleep 5 # 等 2s×2 拍 +OUT=$(env $ENVS $Q "$T/meow_power" calibrate stop 2>&1) +ck T9i3 "calibrate 已停止" "$OUT" +ck T9i4 "rows=" "$OUT" +CSV=$(ls "$T/logs"/power_calib_*.csv 2>/dev/null | head -1) +if [ -n "$CSV" ]; then PASS=$((PASS+1)); echo "PASS T9i5 csv exists ($CSV)"; else FAIL=$((FAIL+1)); echo "FAIL T9i5 CSV 未生成"; fi +[ -n "$CSV" ] && grep -q "ts,cap_pct,vol_mv,current_ua,charge_mw,brightness_pct,cpu_util_pct,wifi_state,bt_state" "$CSV" && { PASS=$((PASS+1)); echo "PASS T9i6 csv header"; } || { FAIL=$((FAIL+1)); echo "FAIL T9i6 csv header"; } +[ -n "$CSV" ] && grep -q "scene=纯亮屏" "$CSV" && { PASS=$((PASS+1)); echo "PASS T9i7 csv scene"; } || { FAIL=$((FAIL+1)); echo "FAIL T9i7 csv scene"; } +OUT=$(env $ENVS $Q "$T/meow_power" calibrate list 2>&1) +ck T9i8 "power_calib_" "$OUT" + +# ---- T9j: 期 3 模型单键 setter model set (守护每拍重载生效)---- +OUT=$(env $ENVS $Q "$T/meow_power" model set baseline_mw 999 2>&1) +ck T9j "model set baseline_mw=999" "$OUT" +OUT=$(env $ENVS $Q "$T/meow_power" model 2>/dev/null) +ck T9j2 "baseline_mw=999" "$OUT" +sleep 2 # 等守护重载 model +OUT=$(env $ENVS $Q "$T/meow_power" estimate 2>/dev/null) +ck T9j3 "baseline=999" "$OUT" # 守护侧 estimate 用新系数 +OUT=$(env $ENVS $Q "$T/meow_power" model set bad_key 5 2>&1) +ck T9j4 "未知键" "$OUT" +env $ENVS $Q "$T/meow_power" model set baseline_mw 300 >/dev/null 2>&1 # ---- T10: meow_powermgr 名直调子命令也走 CLI ---- OUT=$(env $ENVS $Q "$BIN" model 2>/dev/null)