Files
AskaEth 3d70a3dd2c feat: M6.10–M6.19 批量收编 + M6.19 推卡验收
- M7 launcher 重写 5 期(虚拟化宫格/meow_theme 单一权威/横幅动画/自定义 PIN 键盘)
- OOM 通用化(cachegov 上收 SDK)、自动切歌根治、meowpanel jv_free 泄漏修复、Hello 滚动卡顿修复
- ncm 歌词 UI / 媒体通知封面 / 封面分辨率 640
- 5 bug 修复:ncm 后台化 UI 叠层+点击穿透、再进 ncm 桌面叠层、播放页新旧 UI 叠层抢刷脏区(meow_ui_gfx 恢复边沿整帧重画)、PIN 亮屏亮度跳(keys.c meow_panel_on 按 settings_brightness_clamped 恢复)、通知中心封面显歌单封面(cover.c save_cover_raw 加 is_song + 命中块守卫)
- 四 App 统一重链新 meow_ui.a 51caee4a;M6.19=0.8.19 固件 2d2331f2 推卡自刷验收全绿
2026-09-03 12:16:01 +08:00

202 lines
7.0 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* play/mem_watch.c — 边播边监控**取证**实现(接口见 mem_watch.h;agent 32bit 大文件 OOM 取证)。
*
* 归属演进(2026-09-02 定案,ARCHITECTURE_PRINCIPLES ③混合):**降载决策上收通用层**——
* A(DONTNEED 治理)+ C(/proc/meminfo Cached 监控)分别归 SDK meow_cachegov / meow_svc_perf;
* 本模块退化为「RssAnon 取证」:低频读 /proc/self/status(优先 RssAnon,缺失回退 VmRSS),
* 记录匿名内存峰值,**仅供日志**。不再驱动下载/预取降载(那由 meow_cachegov_download_paused
* / prefetch_paused 查询)。**绝不打断解码/播放**。
*
* 阈值滞后(仅用于取证 level 标注):
* kb >= CRITICAL → level=2;kb >= HIGH 且当前<2 → level=1;kb <= LOW → level=0;其它保持。
* 本模块自含:只依赖 pthread + meow_log(SDK 日志),不依赖 core/app 其它 TU。
*/
#include "mem_watch.h"
#include "../sdk/include/meow_ui_log.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* 默认阈值(设备缺省;宿主单测用 env/force 桩覆盖) */
#define MEM_WATCH_PERIOD_MS 500
#define MEM_WATCH_HIGH_KB (30 * 1024)
#define MEM_WATCH_LOW_KB (20 * 1024)
#define MEM_WATCH_CRITICAL_KB (40 * 1024)
struct mw_cfg {
int period_ms;
long high_kb;
long low_kb;
long critical_kb;
};
static struct mw_cfg g_cfg = {
.period_ms = MEM_WATCH_PERIOD_MS,
.high_kb = MEM_WATCH_HIGH_KB,
.low_kb = MEM_WATCH_LOW_KB,
.critical_kb = MEM_WATCH_CRITICAL_KB,
};
static pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER;
static pthread_t g_thr;
static int g_thr_on;
static volatile int g_quit;
static long g_rss_anon_kb; /* 最近一次采样(KB;-1=不可读) */
static long g_peak_song_kb; /* 本曲匿名峰值(song_begin 清零) */
static int g_level; /* NCM_MEM_LVL_*(仅取证日志) */
static long g_forced_kb = -1; /* 宿主桩 ≥0 时替代真读 */
/* env 覆盖阈值:非法值回落默认。 */
static int env_int(const char *k, int def)
{
const char *e = getenv(k);
if (!e || !e[0]) return def;
int v = atoi(e);
return v > 0 ? v : def;
}
static long env_long(const char *k, long def)
{
const char *e = getenv(k);
if (!e || !e[0]) return def;
long v = atol(e);
return v > 0 ? v : def;
}
/* 读匿名 RSS(KB)。优先 RssAnon;缺则回退 VmRSS;都无 → -1。 */
static long read_rss_kb(void)
{
pthread_mutex_lock(&g_mu);
long forced = g_forced_kb;
pthread_mutex_unlock(&g_mu);
if (forced >= 0) return forced;
FILE *fp = fopen("/proc/self/status", "r");
if (!fp) return -1;
char line[256];
long anon = -1, rss = -1;
while (fgets(line, sizeof line, fp))
if (!strncmp(line, "RssAnon:", 8)) anon = atol(line + 8);
else if (rss < 0 && !strncmp(line, "VmRSS:", 6)) rss = atol(line + 6);
fclose(fp);
return anon >= 0 ? anon : rss;
}
static const char *level_str(int lvl)
{
switch (lvl) {
case NCM_MEM_LVL_HIGH: return "high";
case NCM_MEM_LVL_CRITICAL: return "critical";
default: return "normal";
}
}
static void *watch_thread(void *arg)
{
(void)arg;
while (!g_quit) {
long kb = read_rss_kb();
int lvl;
pthread_mutex_lock(&g_mu);
g_rss_anon_kb = kb;
if (kb > g_peak_song_kb) g_peak_song_kb = kb;
long hi = g_cfg.high_kb, lo = g_cfg.low_kb, cr = g_cfg.critical_kb;
/* 滞后三档(仅取证 level 标注) */
if (kb >= cr) lvl = NCM_MEM_LVL_CRITICAL;
else if (kb >= hi) lvl = (g_level == NCM_MEM_LVL_CRITICAL) ? NCM_MEM_LVL_CRITICAL : NCM_MEM_LVL_HIGH;
else if (kb <= lo) lvl = NCM_MEM_LVL_NORMAL;
else lvl = g_level; /* 滞后带:保持 */
if (lvl != g_level) {
meow_log(MEOW_LOG_INFO,
"[mem] rss_anon=%ldKB peak=%ldKB level=%s (H=%ldK/L=%ldK/C=%ldK)",
kb, g_peak_song_kb, level_str(lvl), hi, lo, cr);
}
g_level = lvl;
pthread_mutex_unlock(&g_mu);
usleep((useconds_t)g_cfg.period_ms * 1000u);
}
return NULL;
}
int mem_watch_start(void)
{
pthread_mutex_lock(&g_mu);
if (g_thr_on) { pthread_mutex_unlock(&g_mu); return 0; }
/* 开关(默认开;NCM_MEM_WATCH_ENABLED=0/off 关闭监控,行为退化为旧版零侵入) */
const char *en = getenv("NCM_MEM_WATCH_ENABLED");
if (en && (!en[0] || !strcmp(en, "0") || !strcmp(en, "off") || !strcmp(en, "false"))) {
pthread_mutex_unlock(&g_mu);
meow_log(MEOW_LOG_INFO, "[mem] watch disabled (NCM_MEM_WATCH_ENABLED=%s)", en);
return 0;
}
/* 阈值 env 覆盖(宿主单测) */
g_cfg.period_ms = env_int("NCM_MEM_WATCH_PERIOD_MS", MEM_WATCH_PERIOD_MS);
g_cfg.high_kb = env_long("NCM_MEM_WATCH_HIGH_KB", MEM_WATCH_HIGH_KB);
g_cfg.low_kb = env_long("NCM_MEM_WATCH_LOW_KB", MEM_WATCH_LOW_KB);
g_cfg.critical_kb = env_long("NCM_MEM_WATCH_CRITICAL_KB", MEM_WATCH_CRITICAL_KB);
g_quit = 0;
pthread_attr_t a;
pthread_attr_init(&a);
pthread_attr_setstacksize(&a, (size_t)(128 * 1024)); /* 同 ncm_thread_create 128KB(内存瘦身,OOM 修复) */
int rc = pthread_create(&g_thr, &a, watch_thread, NULL);
pthread_attr_destroy(&a);
if (rc != 0) { pthread_mutex_unlock(&g_mu); return -1; }
g_thr_on = 1;
pthread_mutex_unlock(&g_mu);
meow_log(MEOW_LOG_INFO,
"[mem] watch started period=%dms H=%ldK L=%ldK C=%ldK (RssAnon 优先)",
g_cfg.period_ms, g_cfg.high_kb, g_cfg.low_kb, g_cfg.critical_kb);
return 0;
}
void mem_watch_stop(void)
{
g_quit = 1;
pthread_mutex_lock(&g_mu);
if (g_thr_on) { g_thr_on = 0; pthread_detach(g_thr); }
pthread_mutex_unlock(&g_mu);
}
int mem_watch_level(void)
{
pthread_mutex_lock(&g_mu);
int v = g_level;
pthread_mutex_unlock(&g_mu);
return v;
}
long mem_watch_rss_anon_kb(void)
{
pthread_mutex_lock(&g_mu);
long v = g_rss_anon_kb;
pthread_mutex_unlock(&g_mu);
return v;
}
void mem_watch_song_begin(void)
{
long kb = read_rss_kb(); /* 起播即采样当前内存,本曲峰值从当前起算 */
pthread_mutex_lock(&g_mu);
g_peak_song_kb = kb;
pthread_mutex_unlock(&g_mu);
meow_log(MEOW_LOG_INFO, "[mem] song begin rss_anon=%ldKB", kb);
}
/* 播完/切歌释放钩子之后调用:落本曲峰值 + 重置计数。 */
void mem_watch_song_end(void)
{
pthread_mutex_lock(&g_mu);
long peak = g_peak_song_kb;
g_peak_song_kb = g_rss_anon_kb;
pthread_mutex_unlock(&g_mu);
meow_log(MEOW_LOG_INFO, "[mem] song end peak_anon=%ldKB (released)", peak);
}
void mem_watch_set_forced_kb(long kb)
{
pthread_mutex_lock(&g_mu);
g_forced_kb = kb;
pthread_mutex_unlock(&g_mu);
}