feat(log): App日志目录扁平化为 MeowOS/logs/<包名>/ (agent-198, 用户定案) — launcher MEOW_LOG_DIR 注入改 logs/<appid>+mkdir_p; SDK meow_ui_log.c 去 apps/ 嵌套; 卡可用时一次性迁移 logs/apps/* 并入新路径; APPS.md/APP_LOG_MANAGER.md 同步
launcher→61f6b0db; files→ac2c2781; 编译0warning(新增代码)
This commit is contained in:
1 parent
32a6a8ed1e
commit
5f7e7542bd
6 files changed
+132
-5
No files matched your search
@@ -194,7 +194,7 @@
|
||||
- **⚠️ 应用启动后须防 goodix 幽灵触摸**(v6.8,Bug 2 根因):goodix 在启动触摸的尾部发出一段幽灵触摸(实测启动后 1.2-2.25s,§18.16),无防护时应用会**误把幽灵当下按而立即退出画 BYE**,且 launcher 菜单会把同一幽灵重放成行点击而**重开应用**(用户看到「bye 后又回 hello 主界面、需再点一次」)。hello v6.8 增加 `COOLDOWN_MS=2500`:启动后前 2.5s 忽略一切按下边沿,只有用户**真正**的下按才触发退出。launcher 侧同步在应用退出后 drain + 冷却(见 §4.7)。
|
||||
- 沉浸应用写 `/tmp/meowapp_state`,处理 `SIGUSR1` 作为「返回事件」
|
||||
- 应用异常卡死 → 虚拟返回键(若可见)→ SIGKILL;沉浸态卡死 → 音量减连按 3 次(强杀序列)
|
||||
- **应用日志**:launcher 通过环境变量 `MEOW_LOG_DIR` 告知 TF 卡日志目录(无卡时不设),应用自行决定文件名(示例 hello 写 `apps/<app_id>/logs/<ts>_<pid>.log`;[源:审计 2026-08-30]);启动时先 drain 输入队列、只响应"按下边沿"退出(释放事件/轨迹事件忽略)
|
||||
- **应用日志**:launcher 通过环境变量 `MEOW_LOG_DIR` 直接告知 TF 卡上该应用的日志目录 `MeowOS/logs/<app_id>/`(无卡时不设),应用写 `<ts>_<pid>.log`([源:M2.x 简化 logs/apps/<app_id>/logs → logs/<app_id>]);启动时先 drain 输入队列、只响应"按下边沿"退出(释放事件/轨迹事件忽略)
|
||||
|
||||
### 3.6 应用运行期卡移除(M2.11 最佳努力)
|
||||
|
||||
@@ -275,12 +275,12 @@ meow_launcherd --sim-exit N # 菜单打开 N 毫秒后模拟退出
|
||||
|
||||
### 4.5 统一日志系统(MeowAPPs 组件共用)
|
||||
|
||||
- **默认位置**:TF 卡 `/usr/data/mnt/sd_0/MeowOS/logs/meow_<bootts>.log`(如 `meow_20260828_020123.log`;`bootts` = 当前墙钟 − /proc/uptime,同一 boot 会话内多次启动共用同一文件)。**系统日志**(launcher/watchdog 等 MeowOS 组件)写此文件;**应用日志**另按 `apps/<app_id>/logs/<ts>_<pid>.log` 分文件(见本 §4.5「组件环境变量」)。⚠️ `meow_bootmenu` 仍用 `MeowAPPs/logs`(代码侧不一致;bootmenu 与 launcher 日志目录**待统一为 `MeowOS/logs`**,[源:审计 2026-08-30])
|
||||
- **默认位置**:TF 卡 `/usr/data/mnt/sd_0/MeowOS/logs/meow_<bootts>.log`(如 `meow_20260828_020123.log`;`bootts` = 当前墙钟 − /proc/uptime,同一 boot 会话内多次启动共用同一文件)。**系统日志**(launcher/watchdog 等 MeowOS 组件)写此文件;**应用日志**另按 `logs/<app_id>/<ts>_<pid>.log` 分文件(`<app_id>` 即该应用目录;见本 §4.5「组件环境变量」)。⚠️ `meow_bootmenu` 仍用 `MeowAPPs/logs`(代码侧不一致;bootmenu 与 launcher 日志目录**待统一为 `MeowOS/logs`**,[源:审计 2026-08-30])。旧布局 `logs/apps/<app_id>/logs/` 已废弃:launcher 启动时一次性迁移到 `logs/<app_id>/` 后删除
|
||||
- **无 TF 卡 / 卡晚挂载(S90 早于卡挂载)**:**开不了卡日志**——日志落 **/tmp 启动缓冲**(`/tmp/meow_boot.log`,上限 256KB 滚动),**绝不写板载存储**(/usr/data 只剩 ~10MB);**卡出现后自动迁移**(主循环 ~1s 周期重试 + 输入设备重试循环内也检查;无需开菜单)——`log_poll_card()` 打开卡日志并把 /tmp 缓冲整段搬入后删除 /tmp 文件
|
||||
- **容量上限**:logs/ 目录总量 1GB,开机时超限按 mtime 删最旧
|
||||
- **组件环境变量**:
|
||||
- `MEOW_LOG_FILE` → meow_watchdog:追加写同一 boot 日志文件(无该变量则走 stderr)
|
||||
- `MEOW_LOG_DIR` → 应用:日志目录(每 App `MeowOS/logs/apps/<app_id>/logs/`,应用写 `<ts>_<pid>.log`;[源:审计 2026-08-30])
|
||||
- `MEOW_LOG_DIR` → 应用:日志目录(每 App `MeowOS/logs/<app_id>/`,应用写 `<ts>_<pid>.log`;[源:M2.x 简化,弃 `logs/apps/<app_id>/logs/`])
|
||||
- 内容:时间戳 + 全部按键边沿/菜单/应用事件(真机按键证据)
|
||||
- PID 文件:`/usr/data/meow_launcherd.pid`;播放器发现:扫描 `/proc/N/exe` == `/usr/bin/hiby_player`
|
||||
|
||||
|
||||
Binary file not shown.
@@ -807,10 +807,12 @@ int launch_app(struct app *a)
|
||||
/* child: exec the app. M2.12 注入 MEOW_LOG_DIR + MEOW_DATA_DIR/MEOW_CACHE_DIR
|
||||
* (exFAT 无 symlink,数据目录用 env 传给应用)。PATH 继承 launcher(含卡上 opt/bin
|
||||
* 若在),卡不在则回退普通 PATH。M2.52 追加注入 MEOW_LOG_APP(app_id)+MEOW_LOG_LEVEL
|
||||
* (读全局 log.level),使 SDK meow_log() 按 app 分离写 apps/<app_id>.log 并做级别过滤。 */
|
||||
* (读全局 log.level),使 SDK meow_log() 按 app 分离写 logs/<id>/<ts>_<pid>.log 并做级别过滤。
|
||||
* M2.x 简化:MEOW_LOG_DIR 从 logs/apps/<id>/logs 改注入 logs/<id>(目录不存在则建)。 */
|
||||
close(execpipe[0]);
|
||||
char *argv[] = { a->exec, NULL };
|
||||
char env_path[320], env_log[320], env_data[320], env_cache[320];
|
||||
char app_log_dir[288];
|
||||
char env_app[MEOW_APP_ID_MAX + 16], env_lvl[48];
|
||||
char env_fpng[400], env_fidx[400], env_fapp[96];
|
||||
char env_mf[24];
|
||||
@@ -823,7 +825,15 @@ int launch_app(struct app *a)
|
||||
snprintf(env_path, sizeof env_path, "PATH=%s", cp ? cp : "/usr/bin:/bin");
|
||||
envp[ne++] = env_path;
|
||||
envp[ne++] = "HOME=/root";
|
||||
if (log_dir[0]) { snprintf(env_log, sizeof env_log, "MEOW_LOG_DIR=%s", log_dir); envp[ne++] = env_log; }
|
||||
/* M2.x 简化:MEOW_LOG_DIR 注入 logs/<id>(id=app_id,空则 "app",与 SDK app 分离前缀一致)。
|
||||
* 目录不存在则用 meow_mkdir_p 建(幂等),失败不阻塞注入——SDK 侧还有 mkdir_p 兜底。 */
|
||||
if (log_dir[0]) {
|
||||
const char *logid = a->id[0] ? a->id : "app";
|
||||
snprintf(app_log_dir, sizeof app_log_dir, "%s/%s", log_dir, logid);
|
||||
meow_mkdir_p(app_log_dir);
|
||||
snprintf(env_log, sizeof env_log, "MEOW_LOG_DIR=%s", app_log_dir);
|
||||
envp[ne++] = env_log;
|
||||
}
|
||||
/* M2.52:MEOW_LOG_APP=app_id(=app.json.package,缺省回退目录名;与注册表一致;无 id 则跳过,SDK 兜底 "app") */
|
||||
if (a->id[0]) { snprintf(env_app, sizeof env_app, "MEOW_LOG_APP=%s", a->id); envp[ne++] = env_app; }
|
||||
/* M2.52:MEOW_LOG_LEVEL 读全局 log.level(error/warn/info/debug→索引0/1/2/3),
|
||||
|
||||
@@ -530,6 +530,8 @@ extern char ipc_sock_path[MEOW_IPC_SOCK_LEN];
|
||||
extern char log_dir[256];
|
||||
extern int log_fd;
|
||||
extern char log_file[256];
|
||||
/* M2.x 应用日志目录简化(apps/<id>/logs → <id>):mkdir -p 幂等;迁移用。 */
|
||||
int meow_mkdir_p(const char *path);
|
||||
extern uint32_t menu_bg;
|
||||
extern int menu_opened_blank;
|
||||
extern int meow_auto_slept;
|
||||
|
||||
Binary file not shown.
@@ -2,6 +2,9 @@
|
||||
/* 本文件由拆分工具从 meow_launcherd.c 按职责搬移;逻辑与原文 0-diff(仅 static 可见性按跨模块需求调整)。*/
|
||||
#include "meow_launcher_internal.h"
|
||||
|
||||
/* M2.x 应用日志目录简化:一次性迁移 logs/apps/<id>/logs → logs/<id>(定义见下,log_open_card 先调用)。 */
|
||||
static void log_migrate_apps(void);
|
||||
|
||||
int log_fd = -1; /* file log fd on the TF card */
|
||||
|
||||
char log_dir[256] = ""; /* "MeowOS/logs" on card, or "" */
|
||||
@@ -133,6 +136,7 @@ int log_open_card(void)
|
||||
{
|
||||
if (log_fd >= 0) return 0;
|
||||
if (!card_available()) return -1;
|
||||
log_migrate_apps(); /* M2.x 一次性迁移:logs/apps/<id>/logs → logs/<id>(幂等,见下) */
|
||||
char ts[64];
|
||||
boot_timestamp(ts, sizeof ts);
|
||||
snprintf(log_dir, sizeof log_dir, "%s", LOG_DIR_CARD);
|
||||
@@ -144,6 +148,117 @@ int log_open_card(void)
|
||||
}
|
||||
|
||||
|
||||
/* M2.x 应用日志目录简化:mkdir -p(幂等,已存在 EEXIST 视为成功)。返回 0=成功 -1=失败。
|
||||
* 供 launcher 为每 App 建新布局日志目录 logs/<id>/ 用(沿用 SDK 同款逐分量 mkdir)。 */
|
||||
int meow_mkdir_p(const char *path)
|
||||
{
|
||||
char tmp[256];
|
||||
size_t len, i;
|
||||
if (!path || !path[0] || strlen(path) >= sizeof tmp) return -1;
|
||||
len = strlen(path);
|
||||
memcpy(tmp, path, len + 1);
|
||||
if (tmp[len - 1] == '/') tmp[len - 1] = '\0'; /* 去尾斜杠 */
|
||||
for (i = 1; i <= strlen(tmp); i++) {
|
||||
if (tmp[i] == '/' || tmp[i] == '\0') {
|
||||
char ch = tmp[i];
|
||||
tmp[i] = '\0';
|
||||
if (tmp[0] && mkdir(tmp, 0755) != 0 && errno != EEXIST) return -1;
|
||||
tmp[i] = ch;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* M2.x 一次性迁移(幂等,代码可后续移除):旧布局 LOG_DIR_CARD/apps/<id>/logs/<file>.log
|
||||
* 并入新布局 LOG_DIR_CARD/<id>/<file>.log,然后删除旧 apps/ 整树。卡可用时随 log_open_card
|
||||
* 跑一次;apps/ 已不存在则直接返回。同卡同 fs,文件用 rename() 移动(目标同名被覆盖——迁移
|
||||
* 内只挪旧文件,不写新日志)。总容量上限纪律不变:应用日志仍由 SDK 按 App 50MB 清理,boot 日志
|
||||
* 仍走 log_cleanup_old()。 */
|
||||
static void log_rm_rf(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(path, &st) != 0) return;
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
DIR *d = opendir(path);
|
||||
if (d) {
|
||||
struct dirent *e;
|
||||
while ((e = readdir(d)) != NULL) {
|
||||
if (e->d_name[0] == '.' && (e->d_name[1] == '\0' ||
|
||||
(e->d_name[1] == '.' && e->d_name[2] == '\0'))) continue;
|
||||
char sub[512];
|
||||
snprintf(sub, sizeof sub, "%s/%s", path, e->d_name);
|
||||
log_rm_rf(sub);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
rmdir(path);
|
||||
} else {
|
||||
unlink(path);
|
||||
}
|
||||
}
|
||||
|
||||
static void log_migrate_apps(void)
|
||||
{
|
||||
char old_root[512], old_dir[512], old_logs[512], new_dir[512];
|
||||
DIR *d, *dl, *dd;
|
||||
struct dirent *e;
|
||||
|
||||
snprintf(old_root, sizeof old_root, "%s/apps", LOG_DIR_CARD);
|
||||
d = opendir(old_root);
|
||||
if (!d) return; /* 旧路径不存在,无需迁移 */
|
||||
|
||||
while ((e = readdir(d)) != NULL) {
|
||||
struct stat st;
|
||||
if (e->d_name[0] == '.') continue;
|
||||
snprintf(old_dir, sizeof old_dir, "%s/%s", old_root, e->d_name);
|
||||
if (stat(old_dir, &st) != 0 || !S_ISDIR(st.st_mode)) continue;
|
||||
|
||||
snprintf(new_dir, sizeof new_dir, "%s/%s", LOG_DIR_CARD, e->d_name);
|
||||
if (meow_mkdir_p(new_dir) != 0) continue; /* 新目录建不了,跳过该 App */
|
||||
|
||||
/* 旧布局 apps/<id>/logs/<file>.log → logs/<id>/<file>.log */
|
||||
snprintf(old_logs, sizeof old_logs, "%s/logs", old_dir);
|
||||
dl = opendir(old_logs);
|
||||
if (dl) {
|
||||
struct dirent *el;
|
||||
while ((el = readdir(dl)) != NULL) {
|
||||
struct stat stl;
|
||||
char src[512], dst[512];
|
||||
if (el->d_name[0] == '.') continue;
|
||||
snprintf(src, sizeof src, "%s/%s", old_logs, el->d_name);
|
||||
if (stat(src, &stl) != 0 || !S_ISREG(stl.st_mode)) continue;
|
||||
snprintf(dst, sizeof dst, "%s/%s", new_dir, el->d_name);
|
||||
rename(src, dst);
|
||||
}
|
||||
closedir(dl);
|
||||
}
|
||||
|
||||
/* 早期设计若直接把 .log 散在 apps/<id>/ 下,一并并入(跳过已处理的 logs/ 子目录) */
|
||||
dd = opendir(old_dir);
|
||||
if (dd) {
|
||||
struct dirent *ed;
|
||||
while ((ed = readdir(dd)) != NULL) {
|
||||
struct stat stf;
|
||||
char src[512], dst[512];
|
||||
if (ed->d_name[0] == '.') continue;
|
||||
if (strcmp(ed->d_name, "logs") == 0) continue;
|
||||
snprintf(src, sizeof src, "%s/%s", old_dir, ed->d_name);
|
||||
if (stat(src, &stf) != 0 || !S_ISREG(stf.st_mode)) continue;
|
||||
snprintf(dst, sizeof dst, "%s/%s", new_dir, ed->d_name);
|
||||
rename(src, dst);
|
||||
}
|
||||
closedir(dd);
|
||||
}
|
||||
|
||||
log_rm_rf(old_dir);
|
||||
}
|
||||
closedir(d);
|
||||
rmdir(old_root); /* apps/ 清空则删;非空则忽略 */
|
||||
fprintf(stderr, "log_migrate: logs/apps/* -> logs/<id> done\n");
|
||||
}
|
||||
|
||||
|
||||
/* flush the /tmp boot buffer into the file log (once the card mounts) */
|
||||
void log_poll_card(void)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user