fix(watchdog+launcher+sdk): M40 电源键 time64 ABI + 锁屏/叠加残留链
- sdk/meow_time32: 抽出可独立链接的 o32 time32 取时/睡眠设施(不依赖 meow_ui.a, watchdog 等独立静态组件可直接链;可选 -DMEOW_TIME32_LIBC_OVERRIDES 接管 libc 入口) - watchdog: now_ms/usleep 改走 time32(修复 held 变天文数字→每次单击都弹菜单); 阈值读 power.longpress_menu_ms/forceoff_ms(缺省 3000/8000),删除 PWR_TOGGLE_MS==PWR_MENU_MS;新增 wd_power.h 纯判定 + 宿主行为矩阵测试 - launcher: App 前台电源菜单补齐 §10.5(notif 全抑制 + 帧恢复 + SIGCONT 排空 + 标记翻回前台);show_power_menu 恢复进入前背景帧(关闭后不再停留菜单画面); 重绘挪到首轮按键采样之后;activity 标记排空窗 + 会话入口清理 + manual_off 去闩锁 - lock_screen: 电源改按下边沿 + 进场 300ms 才熄屏;电源熄屏退出也恢复底层帧; launcher 在 SIGCONT 前写 /tmp/meow_app_repaint,SDK present 消费并 dirty_full - power_menu: 菜单内强关接 power.forceoff_ms(按 longpress 抵扣),日志不再谎称 8s - 重编 meow_ui.a 并重链 meow_launcherd/ncm/files/hello/reader(picbrowser 无源码) - fw_content.conf: 同步 launcherd/watchdog 新 md5;顺带修正 M35 遗留的 nyai 失效钉值 Host: test_wd_fw 66/66、test_overlay_gate 40/40、test_meow_time64/time/repaint PASS。 真机未验证(设备关机);未刷机、未写设备。
This commit is contained in:
1 parent
b1acc9096b
commit
63b278e13e
28 files changed
+977
-217
No files matched your search
Binary file not shown.
Binary file not shown.
@@ -1432,6 +1432,15 @@ static void notif_active_set(const char *owner)
|
||||
}
|
||||
}
|
||||
|
||||
/* M40 F5/P5-P6:请求 App 在恢复前台后整帧重画一次(SDK present 层消费)。
|
||||
* launcher 侧恢复的「底层帧」只能是快照;锁屏/菜单期间 App 若被冻结,它自己的 back_buf
|
||||
* 仍是旧内容,只按脏区上屏会留下 PIN/菜单残影。写这个文件让 App dirty_full 一次。 */
|
||||
static void meow_app_repaint_request(void)
|
||||
{
|
||||
int fd = open(MEOW_APP_REPAINT_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd >= 0) { (void)write(fd, "1", 1); close(fd); }
|
||||
}
|
||||
|
||||
/* §10.5:App 前台顶部下滑 → 展开「由 launcher 渲染」的通知中心叠加会话。
|
||||
* 复用电源菜单对 App 的冻结模板(show_power_menu 的 SIGSTOP/读回/叠加/接管/恢复):
|
||||
* ① SIGSTOP App → ② 写 /tmp/meow_notif_active(+ /tmp/meow_power_menu_active 让 watchdog 让位)
|
||||
@@ -1570,6 +1579,9 @@ static int run_app_lock_overlay(struct app *a, pid_t pid)
|
||||
|
||||
pm_capture_app_frame();
|
||||
meow_ui_flush();
|
||||
/* M40 F5/P5-P6:先写整帧重画请求,再 SIGCONT/放行——App 恢复后的第一次 present 会
|
||||
* 消费它并 dirty_full(),用自身完整帧盖掉 launcher 快照恢复可能留下的任何残影。 */
|
||||
meow_app_repaint_request();
|
||||
if (!keep_running) {
|
||||
/* §310 输入穿透定案(overlay_gate.h):App 被 SIGSTOP 冻结过 → 在 /tmp/meow_notif_active
|
||||
* 仍未更新时**先 SIGCONT**,让 SDK 输入线程排空冻结期缓冲的 evdev 事件副本 + 对齐
|
||||
@@ -1577,10 +1589,10 @@ static int run_app_lock_overlay(struct app *a, pid_t pid)
|
||||
* 防解锁瞬间把积累的触摸回放成 App 内点击(锁屏穿透→「启动奇怪界面」→ 状态栏消失的触发源)。 */
|
||||
kill(pid, SIGCONT);
|
||||
usleep(OVERLAY_DRAIN_WINDOW_MS * 1000);
|
||||
logmsg("lock-overlay: closed (lr=%d) -> SIGCONT app, drain %dms, then mark fg",
|
||||
logmsg("lock-overlay: closed (lr=%d) -> SIGCONT app, drain %dms, repaint req, then mark fg",
|
||||
lr, OVERLAY_DRAIN_WINDOW_MS);
|
||||
} else {
|
||||
logmsg("lock-overlay: closed (lr=%d) -> app never stopped (media keep-alive), no SIGCONT", lr);
|
||||
logmsg("lock-overlay: closed (lr=%d) -> app never stopped (media keep-alive), no SIGCONT, repaint req", lr);
|
||||
}
|
||||
/* 标记翻回前台归属(a->id):本 App 解除自抑恢复前台;后台常驻 App(如 ncm)随之继续自抑
|
||||
* (不叠帧 / 不穿输入——修复「锁屏解锁后 ncm 歌单帧叠加在 Hello 上 + 交互双响应」)。 */
|
||||
@@ -1595,6 +1607,72 @@ static int run_app_lock_overlay(struct app *a, pid_t pid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* M40 F2/P2:App 前台「电源菜单」会话——补齐 §10.5 协议。
|
||||
* 旧实现(M2.24)只有 SIGSTOP → show_power_menu → SIGCONT:
|
||||
* - 没有 notif_active 抑制标记(后台常驻 App 可能在这期间上屏/穿输入);
|
||||
* - 没有帧快照/恢复(菜单把「压暗 App 帧 + 菜单卡」present 后,关闭时 launcher 又
|
||||
* pm_capture_app_frame() 把**菜单帧**拍回 back_buf 再上屏 → 屏幕仍是菜单画面,
|
||||
* 用户看到「按了没反应」,而 App 只按脏区重绘、永远不会重画整屏(P2 主因);
|
||||
* - 没有 SIGCONT→300ms 排空→标记翻回前台 的输入隔离(冻结期触摸回放)。
|
||||
* show_power_menu() 现在会在所有退出路径恢复进入前的背景帧(power_menu.c),所以这里
|
||||
* 的 pm_capture_app_frame() 读到的是 App 帧而不是菜单帧。
|
||||
* 返回:0=取消(继续 App);1=已执行动作(调用方退出循环);2=App 在菜单期死亡。 */
|
||||
static int run_app_power_menu(struct app *a, pid_t pid)
|
||||
{
|
||||
int keep_running = meow_media_app_playing(a->id);
|
||||
if (keep_running) {
|
||||
logmsg("power-menu: open (app=%s pid=%d) PLAYING -> no SIGSTOP (SDK present suppressed)",
|
||||
a->name, pid);
|
||||
} else {
|
||||
logmsg("power-menu: open (app=%s pid=%d) SIGSTOP", a->name, pid);
|
||||
if (kill(pid, SIGSTOP) < 0) {
|
||||
logmsg("power-menu: SIGSTOP %d fail: %s", pid, strerror(errno));
|
||||
} else {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (proc_is_stopped(pid)) break;
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 叠加期全抑制:菜单盖在前台 App + 后台常驻 App 上;同时写 POWMENU_ACTIVE 让 watchdog
|
||||
* 对电源长按/强关让位(与通知中心/锁屏同款双标记)。 */
|
||||
notif_active_set("");
|
||||
int pfd = open(POWMENU_ACTIVE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (pfd >= 0) { write(pfd, "1", 1); close(pfd); }
|
||||
|
||||
meow_sys_light();
|
||||
meow_theme_reload();
|
||||
pm_capture_app_frame(); /* 背景 = App 帧(fb0 buffer0) */
|
||||
|
||||
int pm_ret = show_power_menu();
|
||||
|
||||
if (proc_is_zombie(pid)) {
|
||||
/* App 在菜单期死亡:不 SIGCONT、不把菜单帧当 App 帧恢复;交回 waitpid 统一回收。 */
|
||||
notif_active_set("");
|
||||
unlink(POWMENU_ACTIVE);
|
||||
logmsg("power-menu: app pid %d died during menu -> unified exit path", pid);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* 恢复 App 帧(show_power_menu 已还原进入前背景;再拍一次兜底覆盖任何非标准退出路径),
|
||||
* 然后按 §10.5:先请求整帧重画 → SIGCONT → 排空窗 → 标记翻回前台归属。 */
|
||||
pm_capture_app_frame();
|
||||
meow_ui_flush();
|
||||
meow_app_repaint_request();
|
||||
if (!keep_running) {
|
||||
kill(pid, SIGCONT);
|
||||
usleep(OVERLAY_DRAIN_WINDOW_MS * 1000);
|
||||
logmsg("power-menu: closed (ret=%d) -> SIGCONT app, drain %dms, repaint req, then mark fg",
|
||||
pm_ret, OVERLAY_DRAIN_WINDOW_MS);
|
||||
} else {
|
||||
logmsg("power-menu: closed (ret=%d) -> app never stopped (media keep-alive), no SIGCONT, repaint req",
|
||||
pm_ret);
|
||||
}
|
||||
notif_active_set(a ? a->id : "");
|
||||
unlink(POWMENU_ACTIVE);
|
||||
return pm_ret;
|
||||
}
|
||||
|
||||
/* launch_app_chain:launch_app / launch_activity 的共享核心。
|
||||
* chain 非空 → 向子进程注入 MEOW_ACTIVITY/MEOW_CHAIN 并初始化 nav_stack(M3);空/NULL → 裸启动。 */
|
||||
static int launch_app_chain(struct app *a, const char *chain)
|
||||
@@ -1963,6 +2041,11 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
* 修法:本循环以「背光==0 且非超时」补判手动息屏,唤醒时按 meow_auto_slept||manual 一并触发
|
||||
* lck_wake_should_lock 锁屏,两条路径对齐。 */
|
||||
int app_panel_manual_off = 0;
|
||||
/* M40 F3/P3:叠加层/电源菜单返回后的排空窗。watchdog 在电源菜单期间让位,菜单关闭后
|
||||
* 被 SIGCONT 的 App 会把冻结期缓存的触摸重放成 /tmp/meow_app_activity;若把它当用户
|
||||
* 触摸,会立刻「亮屏 + 弹锁屏」(P3 的 ACTIVITY 唤醒路径)。窗口内的标记只消费不唤醒。 */
|
||||
unsigned long long overlay_return_ms = now_ms();
|
||||
int overlay_return_valid = 0;
|
||||
/* M2.11 D:应用二进制/资源若在卡上,卡被拔可能 SIGBUS 崩。启动前记录,运行期监测卡移除。
|
||||
* (拷贝到内存/板载 staging 的方案先不做,仅记录 APPS.md 规范。) */
|
||||
int app_on_card = (strncmp(a->exec, MEOWAPPS, strlen(MEOWAPPS)) == 0);
|
||||
@@ -1986,9 +2069,12 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
g_sb_mode_last = -1; /* 强制首帧同步(进入新 App 会话清零,避免沿用上一 App 的缓存态) */
|
||||
unlink(MEOW_SBAR_MODE_FILE); /* 清可能残留的上一 App 顶条模式(崩溃/被杀未清),防新 App 误收合 */
|
||||
if (!a->fullscreen) app_overlay_statusbar();
|
||||
/* M2.24:清上一次会话可能残留的电源菜单标记,只认本次新 watchdog 生成的请求。 */
|
||||
/* M2.24:清上一次会话可能残留的电源菜单标记,只认本次新 watchdog 生成的请求。
|
||||
* M40 F3:同时清 /tmp/meow_app_activity——上一会话(或启动手势)遗留的标记不能在本会话
|
||||
* 首圈被当成「用户触摸」而触发息屏计时重置/唤醒+锁屏。 */
|
||||
unlink(POWMENU_MARKER);
|
||||
unlink(POWMENU_ACTIVE);
|
||||
unlink(MEOW_APP_ACTIVITY_FILE);
|
||||
/* §10.5:进入 App 前台会话。置位让 ipc_dispatch 的 MSG_NOTIF_OPEN 可入队(否则回 ERR);
|
||||
* 清残留 pending(防上一会话未消费的 OPEN 被本会话误展开)。 */
|
||||
g_app_session_active = 1;
|
||||
@@ -2057,6 +2143,8 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
m_notif_open_t nopen;
|
||||
if (meow_notif_open_take(&nopen)) {
|
||||
int nr = run_app_notif_overlay(a, pid);
|
||||
overlay_return_ms = now_ms(); /* M40 F3:排空窗起点(activity 标记忽略窗) */
|
||||
overlay_return_valid = 1;
|
||||
/* 输入基线重播(与电源菜单同款):面板期间按键可能已变化,重播防误判 key_edge */
|
||||
kp_poll(&kp_power, NULL, NULL);
|
||||
kp_poll(&kp_keys, NULL, NULL);
|
||||
@@ -2109,9 +2197,23 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
* M6.5 §310 问题1:watchdog 电源键手动息屏(背光 0、不置 meow_auto_slept)→ 唤醒时按
|
||||
* app_panel_manual_off 一并锁屏,与超时路径(meow_auto_slept)对齐。 */
|
||||
{
|
||||
/* 背光==0 => 面板已关(超时路径已置 auto_slept;手动路径靠此补判)。
|
||||
* read_brightness() 失败返回 -1(≠0),不误置位。 */
|
||||
if (read_brightness() == 0) app_panel_manual_off = 1;
|
||||
/* M40 F3:去掉单向闩锁。旧实现只在 watchdog 手动息屏时置 1、只有本循环唤醒分支清 1;
|
||||
* watchdog 之后把屏点亮(pwr_woke)闩锁仍是 1 → 任何 activity 标记都会再次
|
||||
* 「亮屏+锁屏」(P3 放大器)。改为每圈按真实背光复位:
|
||||
* - 背光==0 → 置 1(手动/超时熄屏都算);
|
||||
* - 背光>0 且**没有任何键按住** → 复位 0(屏已被 watchdog 点亮,不再残留闩锁);
|
||||
* - 背光>0 但电源键仍按住(本次唤醒按压)→ 保留一拍,让下面的 key-wake 分支仍能
|
||||
* 按 lck_wake_should_lock 弹锁屏(不牺牲「手动息屏后电源唤醒要锁屏」语义)。
|
||||
* read_brightness() 失败返回 -1(≠0),不误置/误清。 */
|
||||
int bri_now = read_brightness();
|
||||
if (bri_now == 0) {
|
||||
app_panel_manual_off = 1;
|
||||
} else if (bri_now > 0) {
|
||||
int any_key_down = 0;
|
||||
for (int w = 0; w < KEYBUF_WORDS; w++)
|
||||
if (kp_power.cur[w] || kp_keys.cur[w]) { any_key_down = 1; break; }
|
||||
if (!any_key_down) app_panel_manual_off = 0;
|
||||
}
|
||||
int key_edge = 0;
|
||||
for (int w = 0; w < KEYBUF_WORDS; w++)
|
||||
if (kp_power.cur[w] != save_pow[w] || kp_keys.cur[w] != save_keys[w]) { key_edge = 1; break; }
|
||||
@@ -2141,6 +2243,8 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
* (launcher 不崩、run_menu 重绘主屏),同 run_app_notif_overlay 的 died 分支。 */
|
||||
if (lck_wake_should_lock()) {
|
||||
int lr2 = run_app_lock_overlay(a, pid);
|
||||
overlay_return_ms = now_ms(); /* M40 F3:排空窗起点 */
|
||||
overlay_return_valid = 1;
|
||||
if (lr2 != 0) {
|
||||
reap_wait(pid, &status);
|
||||
ams_status_valid = 1;
|
||||
@@ -2161,11 +2265,15 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
}
|
||||
}
|
||||
/* M2.71-bug5:App 前台触摸/交互(launcher 看不到应用内触摸,SDK 写标记)→ 重置自动息屏
|
||||
* 计时;若已自动息屏,按 key-wake 同款路径唤醒(面板上电 + 落 buffer0)。 */
|
||||
* 计时;若已自动息屏,按 key-wake 同款路径唤醒(面板上电 + 落 buffer0)。
|
||||
* M40 F3:叠加层/电源菜单刚返回的排空窗内,该标记是 App 被 SIGCONT 后重放的冻结期
|
||||
* 输入,只消费不唤醒(否则「亮屏 + 弹 PIN」,P3)。 */
|
||||
if (access(MEOW_APP_ACTIVITY_FILE, F_OK) == 0) {
|
||||
unlink(MEOW_APP_ACTIVITY_FILE);
|
||||
app_last_input = now_ms();
|
||||
if (meow_auto_slept || app_panel_manual_off) {
|
||||
if (overlay_activity_drain_active(overlay_return_valid, overlay_return_ms, now_ms())) {
|
||||
logmsg("activity marker consumed in overlay drain window -> no wake");
|
||||
} else if (meow_auto_slept || app_panel_manual_off) {
|
||||
logmsg("screen-off (app): touch wake (auto=%d manual=%d)",
|
||||
meow_auto_slept, app_panel_manual_off);
|
||||
meow_panel_on();
|
||||
@@ -2176,6 +2284,8 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
* §310:叠加期 App 崩溃 → 回收僵尸走统一退出路径(launcher 不崩、run_menu 重绘主屏)。 */
|
||||
if (lck_wake_should_lock()) {
|
||||
int lr2 = run_app_lock_overlay(a, pid);
|
||||
overlay_return_ms = now_ms(); /* M40 F3:排空窗起点 */
|
||||
overlay_return_valid = 1;
|
||||
if (lr2 != 0) {
|
||||
reap_wait(pid, &status);
|
||||
ams_status_valid = 1;
|
||||
@@ -2216,20 +2326,16 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
app_prev_vold = vold;
|
||||
if (app_seq_hits > 0 && now_ms() - app_seq_last > (unsigned)seq_gap_ms * 2)
|
||||
app_seq_hits = 0;
|
||||
/* M2.24 全面按键接管:watchdog 检测到电源长按≥3s 写 /tmp/meow_power_menu → 此处消费:
|
||||
* SIGSTOP 应用冻结 → 写 powmenu_active 让 watchdog 让位 → 统一电源菜单(launcher 一处绘制,
|
||||
* 复用 show_power_menu,含触摸/音量导航/电源确认/8s 强关/pm_interacted 保护)→ 菜单关 →
|
||||
* 清 active → SIGCONT 应用续跑。 */
|
||||
/* M2.24/M40 全面按键接管:watchdog 检测到电源长按≥power.longpress_menu_ms 写
|
||||
* /tmp/meow_power_menu → 此处消费。M40 F2 起走 run_app_power_menu() 的完整 §10.5
|
||||
* 协议(SIGSTOP + 全抑制标记 + 帧恢复 + SIGCONT→排空→标记翻回前台 + 整帧重画请求),
|
||||
* 不再只 SIGSTOP/show_power_menu/SIGCONT(旧实现关闭后屏幕仍是菜单帧 = P2 主因)。 */
|
||||
if (access(POWMENU_MARKER, F_OK) == 0) {
|
||||
unlink(POWMENU_MARKER);
|
||||
logmsg("watchdog: power menu request (app %s) -> SIGSTOP + menu", a->name);
|
||||
kill(pid, SIGSTOP);
|
||||
int mfd = open(POWMENU_ACTIVE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (mfd >= 0) { write(mfd, "1", 1); close(mfd); }
|
||||
int pm_ret = show_power_menu();
|
||||
unlink(POWMENU_ACTIVE);
|
||||
kill(pid, SIGCONT);
|
||||
logmsg("watchdog: power menu closed (ret=%d) -> SIGCONT app", pm_ret);
|
||||
logmsg("watchdog: power menu request (app %s) -> overlay session", a->name);
|
||||
int pm_ret = run_app_power_menu(a, pid);
|
||||
overlay_return_ms = now_ms(); /* M40 F3:排空窗起点(activity 标记忽略窗) */
|
||||
overlay_return_valid = 1;
|
||||
/* M2.25:菜单期间按键可能已变化,重播 save_pow/save_keys 防误判 key_edge
|
||||
* (避免菜单关闭瞬间误触发「键唤醒」或刷新自动息屏计时)。 */
|
||||
kp_poll(&kp_power, NULL, NULL);
|
||||
@@ -2237,6 +2343,11 @@ static int launch_app_chain(struct app *a, const char *chain)
|
||||
memcpy(save_pow, kp_power.cur, sizeof save_pow);
|
||||
memcpy(save_keys, kp_keys.cur, sizeof save_keys);
|
||||
app_last_input = now_ms(); /* M2.17:菜单交互即输入,重置应用会话自动息屏计时 */
|
||||
if (pm_ret == 2) { /* App 在菜单期死亡:回收僵尸走统一退出路径 */
|
||||
reap_wait(pid, &status);
|
||||
ams_status_valid = 1;
|
||||
break;
|
||||
}
|
||||
if (pm_ret != 0) break; /* 关机/重启/回HibyOS:系统通常已 reboot,防御性退出 */
|
||||
}
|
||||
/* 「同一个状态栏」闭环:常驻顶条叠加(agent-146 全屏收合接入)。
|
||||
|
||||
@@ -315,11 +315,12 @@ int run_lock_screen(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* M7.1 解锁恢复:锁屏是整帧不透明覆盖(lk_draw fill_rect 全屏),退出后底层界面不会自动重绘
|
||||
* —— 只有 App 自绘的控件区域刷新,未刷新区残留锁屏 PIN 最后一帧(解锁后整屏脏区根因)。此处
|
||||
* 在锁屏首扑前把底层帧(SDK back_buf = 进入前的 App 帧/主界面帧)快照下来;解锁(unlocked=1)
|
||||
* 时整帧回写 back_buf + present,强制底层界面完整重绘(app_launcher.c 的 lock-overlay 关闭路径
|
||||
* 随后 pm_capture_app_frame 读 fb0 即得到正确 App 帧,不再读到锁帧)。 */
|
||||
/* M7.1/M40 F5 解锁/熄屏恢复:锁屏是整帧不透明覆盖(lk_draw fill_rect 全屏),退出后底层界面
|
||||
* 不会自动重绘 —— 只有 App 自绘的控件区域刷新,未刷新区残留锁屏 PIN 最后一帧。
|
||||
* 此处把锁屏首扑前的底层帧(SDK back_buf = 进入前的 App 帧/主界面帧)快照下来;
|
||||
* **任何退出路径**(解锁 unlocked=1 或电源键熄屏 unlocked=0)都整帧回写 back_buf + present,
|
||||
* 保证 app_launcher.c 的 lock-overlay 关闭路径随后 pm_capture_app_frame 读 fb0 得到的是
|
||||
* 正确 App 帧,而不是 PIN 帧(后者会被下一次锁屏当成底层帧 → P5 残影链)。 */
|
||||
unsigned char *lk_bg_snap = NULL;
|
||||
size_t lk_bg_len = 0;
|
||||
if (back_buf_ok && fb && fb_line > 0 && fb_yres > 0) {
|
||||
@@ -400,7 +401,7 @@ int run_lock_screen(void)
|
||||
}
|
||||
|
||||
/* 电源键/音量键轮询 + 输入活动检测(重置自睡计时) + 自睡/唤醒切换。
|
||||
* 活跃态:电源键按下 → 息屏并退出锁屏(回 App/主屏,下次唤醒再锁)——沿用原语义;
|
||||
* 活跃态:电源键**按下边沿**(进场 ≥300ms)→ 息屏并退出锁屏(回 App/主屏,下次唤醒再锁);
|
||||
* 空闲超 lk_off_ms → 自睡(asleep=1,锁态保持,仍在本循环)。
|
||||
* asleep:电源键按下边沿 / 触摸活动 → meow_panel_on + 重画锁屏页(本循环唤醒链回锁)。
|
||||
* 音量键本页不动(仅视为输入活动,重置计时)。 */
|
||||
@@ -429,9 +430,14 @@ int run_lock_screen(void)
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* 电源键=息屏(允许再睡;下次唤醒按 lck_wake_should_lock 再锁) */
|
||||
if (pwr_down) {
|
||||
logmsg("lock: power key -> screen off (stay locked)");
|
||||
/* 电源键=息屏(允许再睡;下次唤醒按 lck_wake_should_lock 再锁)。
|
||||
* M40 F4/P4:必须用**按下边沿**且进场 ≥300ms 才生效。旧实现用电平
|
||||
* (pwr_down):打开电源菜单的那次长按在 PIN 页出现时仍按着,页面被同一次
|
||||
* 按住立刻熄灭(用户症状「手动锁屏不熄屏而是进 PIN,此时点电源才熄屏」)。
|
||||
* 边沿判定在 overlay_gate.h(宿主单测同源)。 */
|
||||
if (overlay_lock_power_off_now(pwr_edge, now_ms() - entry_ms)) {
|
||||
logmsg("lock: power key edge (%llums after entry) -> screen off (stay locked)",
|
||||
now_ms() - entry_ms);
|
||||
meow_panel_off();
|
||||
break; /* return 0 */
|
||||
}
|
||||
@@ -569,13 +575,17 @@ int run_lock_screen(void)
|
||||
done:
|
||||
meow_ui_activity_pop(); /* M7.1b:锁屏控件 owner 闸门关闭(与进场 push 对称) */
|
||||
g_lk_down_key = LK_DOWN_NONE;
|
||||
/* M7.1 解锁恢复:把锁屏首扑前快照的底层帧整帧回写 back_buf + present,强制底层 App/主界面
|
||||
* 完整重绘(消除「解锁后整屏 = PIN 最后一帧,仅 App 控件自绘区刷新」的脏区残留)。 */
|
||||
if (unlocked && lk_bg_snap && back_buf_ok && fb && lk_bg_len > 0) {
|
||||
/* M7.1/M40 F5:把锁屏首扑前快照的底层帧整帧回写 back_buf + present。
|
||||
* M40 起**不再限定 unlocked**:电源键熄屏退出(lr=0)也必须恢复,否则 fb0 会停留在
|
||||
* PIN 最后一帧;launcher 的 lock-overlay 关闭路径紧接着 pm_capture_app_frame() 会把
|
||||
* 这帧 PIN 抄进 back_buf 并上屏,下一次锁屏再把它当「底层帧」快照 —— P5 残影链的起点。
|
||||
* 屏黑时 present 无害(面板已下电),解锁时则同时消除「整屏 = PIN」的脏区残留。
|
||||
* 「解锁后 App 整帧重画」由 launcher 写 /tmp/meow_app_repaint(SDK present 消费)完成。 */
|
||||
if (lk_bg_snap && back_buf_ok && fb && lk_bg_len > 0) {
|
||||
memcpy(fb, lk_bg_snap, lk_bg_len);
|
||||
meow_dirty_full();
|
||||
meow_ui_flush();
|
||||
logmsg("lock: unlock -> restore underlying frame (full repaint)");
|
||||
logmsg("lock: exit (unlocked=%d) -> restore underlying frame (full repaint)", unlocked);
|
||||
}
|
||||
if (lk_bg_snap) { free(lk_bg_snap); lk_bg_snap = NULL; lk_bg_len = 0; }
|
||||
if (tfd >= 0) {
|
||||
|
||||
@@ -268,6 +268,9 @@ static inline const char *meow_str_zh(const char *id, const char *zh)
|
||||
#define MEOW_SBAR_MODE_FILE "/tmp/meowapp_sbar"
|
||||
/* M2.71-bug5:App 前台触摸/交互 → SDK 写该标记;launcher 前台 app 循环消费(unlink + 重置息屏计时) */
|
||||
#define MEOW_APP_ACTIVITY_FILE "/tmp/meow_app_activity"
|
||||
/* M40 F5/P5-P6:解锁/菜单关闭后强制 App 整帧重画的请求文件。launcher 在 SIGCONT 前写,
|
||||
* SDK present 层(sdk/meow_ui_repaint.c)看到就 dirty_full() 一次并删除。 */
|
||||
#define MEOW_APP_REPAINT_FILE "/tmp/meow_app_repaint"
|
||||
|
||||
/* ---- 共享结构体/枚举(来自 meow_launcherd.c,拆分后统一放置)---- */
|
||||
struct kd_state { int raw, stable, down; int longpressed; unsigned long long since, down_at; };
|
||||
|
||||
Binary file not shown.
@@ -91,4 +91,26 @@ static inline int overlay_lock_wake_now(int pwr_edge, int touch_ready)
|
||||
return (pwr_edge || touch_ready) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* M40 F4/P4:锁屏页「电源按下=息屏退出」必须在**按下边沿**生效,且进场后 ≥300ms 才允许。
|
||||
* 旧实现用电平(kp_is_down)且无防抖:打开电源菜单的那次按压在 PIN 页出现时仍按着,
|
||||
* PIN 页会被同一次按住立刻熄灭(用户症状「手动锁屏不熄屏而是进 PIN,此时点电源才熄屏」)。
|
||||
* 300ms 也避开 launcher 进入锁屏页时的按键基线窗口。 */
|
||||
#define OVERLAY_LOCK_POWER_GRACE_MS 300
|
||||
|
||||
static inline int overlay_lock_power_off_now(int pwr_down_edge, unsigned long long since_entry_ms)
|
||||
{
|
||||
return (pwr_down_edge && since_entry_ms >= OVERLAY_LOCK_POWER_GRACE_MS) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* M40 F3/P3:叠加层/电源菜单返回后的排空窗内,`/tmp/meow_app_activity` 是 App 被 SIGCONT
|
||||
* 后重放的冻结期输入(不是用户新触摸),必须消费掉但不得触发「亮屏+锁屏」。
|
||||
* 返回 1=仍在排空窗(忽略 activity 标记)。 */
|
||||
static inline int overlay_activity_drain_active(int have_return_mark,
|
||||
unsigned long long since_return_ms,
|
||||
unsigned long long now_ms)
|
||||
{
|
||||
if (!have_return_mark) return 0;
|
||||
return (now_ms - since_return_ms < OVERLAY_DRAIN_WINDOW_MS) ? 1 : 0;
|
||||
}
|
||||
|
||||
#endif /* MEOW_OVERLAY_GATE_H */
|
||||
@@ -355,22 +355,59 @@ int meow_power_action(uint32_t cmd)
|
||||
}
|
||||
|
||||
|
||||
/* M40 F2/P2:关闭菜单时恢复进入前的背景帧并 present。
|
||||
* dim_screen() 就地压暗 back_buf;若不恢复,app_launcher 关闭会话时的 pm_capture_app_frame()
|
||||
* 会把「压暗 App 帧 + 菜单卡」当成 App 帧拍回并上屏 → 菜单关闭后屏幕仍是菜单画面,
|
||||
* 用户看到「再次单击没反应」(P2 主因)。所有退出路径(取消/锁定/关机/强关)统一恢复。 */
|
||||
static void pm_restore_bg(unsigned char *snap, size_t len)
|
||||
{
|
||||
if (!snap || !len || !back_buf_ok || !fb) return;
|
||||
memcpy(fb, snap, len);
|
||||
meow_dirty_full();
|
||||
meow_ui_flush();
|
||||
}
|
||||
|
||||
/* 电源菜单(M2.6):2×2 网格,dirty 绘制消频闪;输入修复:
|
||||
* - 触摸按下捕获坐标、抬起命中按钮即确认(同 run_menu MT 防抖);
|
||||
* - 音量上/下导航;播放=确认;电源新按(松开长按后)=确认当前钮(非取消);
|
||||
* - 取消=选「取消」钮;8s 持续按住=强制关机(绕过)。
|
||||
* - 取消=选「取消」钮;按住 power.forceoff_ms(缺省 8s,从按下起算)=强制关机(绕过)。
|
||||
* 返回 1=采取动作,0=取消。 */
|
||||
int show_power_menu(void)
|
||||
{
|
||||
int fbfd = open(FB_DEV, O_RDWR);
|
||||
if (fbfd >= 0) { ioctl(fbfd, FBIOBLANK, 0); close(fbfd); } /* 亮起面板 */
|
||||
pm_capture_app_frame(); /* A-0:菜单背景 = app 当前帧(fb0 buffer0),再压暗绘制其上 */
|
||||
meow_screen_on = 1; /* 菜单打开即视为亮屏 */
|
||||
|
||||
/* M40 F2:先开输入设备并采样第一轮基线。旧顺序把这一步放在 pm_capture/dim/建卡之后
|
||||
* (真机实测菜单请求→keypoll ready 相隔 75ms),一次完整的按下+抬起若落在这段阻塞绘制里
|
||||
* 就永远看不到边沿(EVIOCGKEY 是电平采样,不回溯事件队列)。重活挪到采样之后。 */
|
||||
meow_touch mt;
|
||||
mt_reset(&mt);
|
||||
int tfd = open(DEV_TOUCH, O_RDONLY | O_NONBLOCK);
|
||||
struct keypoll kp_power, kp_keys;
|
||||
kp_open(&kp_power, DEV_POWER);
|
||||
kp_open(&kp_keys, DEV_KEYS);
|
||||
int prev_vold = 0, prev_volu = 0, prev_pwr = 0;
|
||||
kp_poll(&kp_power, NULL, NULL); kp_poll(&kp_keys, NULL, NULL);
|
||||
prev_pwr = kp_is_down(&kp_power, KEY_POWER) ? 1 : 0;
|
||||
prev_vold = kp_is_down(&kp_keys, KEY_VOLUMEDOWN) ? 1 : 0;
|
||||
prev_volu = kp_is_down(&kp_keys, KEY_VOLUMEUP) ? 1 : 0;
|
||||
|
||||
/* 背景帧:先把 app 当前帧读回 back_buf,快照后再压暗绘制 */
|
||||
pm_capture_app_frame(); /* A-0:菜单背景 = app 当前帧(fb0 buffer0) */
|
||||
unsigned char *pm_bg_snap = NULL;
|
||||
size_t pm_bg_len = 0;
|
||||
if (back_buf_ok && fb && fb_line > 0 && fb_yres > 0) {
|
||||
pm_bg_len = (size_t)fb_line * (size_t)fb_yres;
|
||||
pm_bg_snap = malloc(pm_bg_len);
|
||||
if (pm_bg_snap) memcpy(pm_bg_snap, fb, pm_bg_len);
|
||||
else { pm_bg_len = 0; logmsg("pm: bg snapshot malloc fail (len=%zu)", pm_bg_len); }
|
||||
}
|
||||
dim_screen();
|
||||
/* M2.8 Bug 3-residual:若电源菜单是在「息屏」态打开(按住 3s),此处 FBIOBLANK(0)
|
||||
* 刚上电,LCDC 扫描地址可能非 buffer0;强制 re-pan 让压暗的应用列表 + 菜单落在被显示的
|
||||
* 缓冲,否则菜单画在非显示缓冲上不可见。 */
|
||||
fb_pan_buf0_force();
|
||||
meow_screen_on = 1; /* 菜单打开即视为亮屏 */
|
||||
|
||||
/* M2.11 B:默认光标 = 「取消」(安全项,index 4)。用户打开菜单后未导航就按电源/播放,
|
||||
* 只会取消关菜单,绝不因「按电源键」本身关机/重启。要真关机必须先导航到「关机」再确认。 */
|
||||
@@ -383,29 +420,25 @@ int show_power_menu(void)
|
||||
pm_draw_card(); /* 卡片 + 标题 POWER MENU + 底部提示(SDK 主题色,i18n 文案) */
|
||||
meow_dirty_full(); /* M2.16:把压暗列表+卡片+标题+(下方圆钮)作为一整帧呈现 */
|
||||
|
||||
/* 触摸状态(按下→抬起):统一 meow_touch 接口(goodix 时序免疫,原点由首个有效 ABS 锁) */
|
||||
meow_touch mt;
|
||||
mt_reset(&mt);
|
||||
int tfd = open(DEV_TOUCH, O_RDONLY | O_NONBLOCK);
|
||||
|
||||
struct keypoll kp_power, kp_keys;
|
||||
kp_open(&kp_power, DEV_POWER);
|
||||
kp_open(&kp_keys, DEV_KEYS);
|
||||
int prev_vold = 0, prev_volu = 0, prev_pwr = 0;
|
||||
kp_poll(&kp_power, NULL, NULL); kp_poll(&kp_keys, NULL, NULL);
|
||||
prev_pwr = kp_is_down(&kp_power, KEY_POWER) ? 1 : 0;
|
||||
prev_vold = kp_is_down(&kp_keys, KEY_VOLUMEDOWN) ? 1 : 0;
|
||||
prev_volu = kp_is_down(&kp_keys, KEY_VOLUMEUP) ? 1 : 0;
|
||||
|
||||
int act = -1;
|
||||
int pm_rc = 0;
|
||||
unsigned long long pm_t0 = now_ms();
|
||||
/* 强关阈值:power.forceoff_ms 是**从按下起算**的总时长;菜单在 longpress 阈值处打开,
|
||||
* 因此菜单内剩余等待 = forceoff - longpress(缺省 8000-3000=5000ms,与原硬编码值一致,
|
||||
* 但不再忽略 settings)。配置异常(剩余<1s)时退回完整 forceoff。 */
|
||||
unsigned long long pm_forceoff_after_ms = 5000;
|
||||
if (power_forceoff_ms > power_longpress_menu_ms &&
|
||||
power_forceoff_ms - power_longpress_menu_ms >= 1000)
|
||||
pm_forceoff_after_ms = (unsigned long long)(power_forceoff_ms - power_longpress_menu_ms);
|
||||
else if (power_forceoff_ms > 0)
|
||||
pm_forceoff_after_ms = (unsigned long long)power_forceoff_ms;
|
||||
unsigned long long pm_last_interact = pm_t0; /* M2.33:菜单空闲自动关闭基准(任何互动刷新) */
|
||||
int pm_init = 0, last_sel = -1;
|
||||
/* M2.10 Bug:电源菜单 8s 强关(按住电源≥8s=绕过强关)会覆盖用户的菜单操作 —— 用户按住
|
||||
* 电源打开菜单后(尤其仍按着电源)点选「回到HibyOS/重启」等按钮,8s 一到先触发强关 → 关机
|
||||
/* M2.10 Bug:电源菜单强关(按住电源到 forceoff)会覆盖用户的菜单操作 —— 用户按住
|
||||
* 电源打开菜单后(尤其仍按着电源)点选「回到HibyOS/重启」等按钮,强关一到先触发 → 关机
|
||||
* 而非执行所选动作。修法:一旦用户与菜单互动(音量导航/触摸/播放/电源确认),置 pm_interacted=1
|
||||
* 取消 8s 强关,让所选动作(如「回到HibyOS」→ reboot RESTART)生效。仅当全程未互动才保留「按住
|
||||
* 8s=强关」。*/
|
||||
* 取消强关,让所选动作(如「回到HibyOS」→ reboot RESTART)生效。仅当全程未互动才保留「按住
|
||||
* 到 forceoff=强关」。*/
|
||||
int pm_interacted = 0;
|
||||
int pm_press_idx = -1; /* M7.0b:当前按下钮(按压态走 SDK 状态机位) */
|
||||
for (;;) {
|
||||
@@ -488,17 +521,25 @@ 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"); meow_ui_activity_pop(); return 1; }
|
||||
logmsg("pm: POWER HOLD 8s -> force poweroff");
|
||||
/* 强关(绕过):仅当电源持续按住、且用户全程未与菜单互动才触发 —— 放在触摸/按键处理
|
||||
* 之后,避免「用户已点选按钮」的同一轮被强关抢先(M2.10 Bug)。
|
||||
* M40:阈值接 power.forceoff_ms(从按下起算的剩余时长),不再硬编码 5000/日志谎称 8s。 */
|
||||
if (pwr && !pm_interacted && now_ms() - pm_t0 >= pm_forceoff_after_ms) {
|
||||
if (sim_no_exec) {
|
||||
logmsg("pm: [sim-no-exec] POWER HOLD %dms (menu-open + %llums) -> would force poweroff",
|
||||
power_forceoff_ms, pm_forceoff_after_ms);
|
||||
pm_rc = 1;
|
||||
goto out;
|
||||
}
|
||||
logmsg("pm: POWER HOLD %dms (menu-open + %llums) -> force poweroff",
|
||||
power_forceoff_ms, pm_forceoff_after_ms);
|
||||
if (meow_power_action(POWER_SHUTDOWN) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort force-off (menu closed, no action)");
|
||||
meow_ui_activity_pop(); return 0;
|
||||
pm_rc = 0;
|
||||
goto out;
|
||||
}
|
||||
meow_ui_activity_pop();
|
||||
return 1;
|
||||
pm_rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* M2.33 菜单空闲超时自动关闭:菜单受 MeowOS screen_off_timeout 管理(系统界面不豁免)。
|
||||
@@ -516,57 +557,64 @@ int show_power_menu(void)
|
||||
if (act >= 0) break;
|
||||
usleep(POLL_MS * 1000);
|
||||
}
|
||||
if (tfd >= 0) close(tfd);
|
||||
meow_ui_activity_pop(); /* M7.0b:退出电源菜单,回主 activity(控件 owner 仍钉哨兵,复用) */
|
||||
|
||||
/* M2.11 B:电源键在菜单 = 按当前项确认。act 与电源动作逐项核对:
|
||||
* act==PM_NUM-1(取消) -> 只关菜单,绝不关机(return 0,永不到电源动作);
|
||||
* act==PM_NUM-1(取消) -> 只关菜单,绝不关机(rc=0,永不到电源动作);
|
||||
* act==4(锁定) -> 手动锁(meow_lock_screen_engage,未配 PIN 则 no-op),关菜单;
|
||||
* 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 ? "升级模式"
|
||||
: act == 4 ? "锁定" : "取消");
|
||||
if (act == PM_NUM - 1) { logmsg("pm: cancel (close menu only)"); return 0; }
|
||||
if (act == PM_NUM - 1) { logmsg("pm: cancel (close menu only)"); pm_rc = 0; goto out; }
|
||||
if (act == 4) {
|
||||
logmsg("pm: LOCK SCREEN");
|
||||
meow_lock_screen_engage();
|
||||
return 0; /* 关菜单;run_menu 继续(锁屏页已阻塞到解锁或电源息屏) */
|
||||
pm_rc = 0; /* 关菜单;run_menu 继续(锁屏页已阻塞到解锁或电源息屏) */
|
||||
goto out;
|
||||
}
|
||||
/* 动作统一经电源管理服务 IPC(meow_svc_power);launcher 不再直连 poweroff/reboot(2)/写 mtd5/
|
||||
* 写 boot 默认——关机/重启/升级/回HiBy 的动作原语都在服务内实现(§3.2 单一动作链路)。 */
|
||||
/* 公共服务:执行动作;服务不可达 → 按「取消」返回(launcher 存活,绝不误报已动作卡死)。
|
||||
* meow_power_action 内部已先 meow_notif_before_poweroff()(转储未上卡通知)。 */
|
||||
pm_rc = 1;
|
||||
if (act == 0) {
|
||||
logmsg("pm: POWER OFF");
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would poweroff"); return 1; }
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would poweroff"); goto out; }
|
||||
if (meow_power_action(POWER_SHUTDOWN) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort (menu closed, no action)");
|
||||
return 0;
|
||||
pm_rc = 0;
|
||||
}
|
||||
} else if (act == 1) {
|
||||
logmsg("pm: REBOOT");
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would reboot"); return 1; }
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would reboot"); goto out; }
|
||||
if (meow_power_action(POWER_REBOOT) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort (menu closed, no action)");
|
||||
return 0;
|
||||
pm_rc = 0;
|
||||
}
|
||||
} else if (act == 2) {
|
||||
logmsg("pm: RETURN TO HIBYOS");
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would reboot to hiby"); return 1; }
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would reboot to hiby"); goto out; }
|
||||
if (meow_power_action(POWER_BACK_HIBY) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort (menu closed, no action)");
|
||||
return 0;
|
||||
pm_rc = 0;
|
||||
}
|
||||
} else if (act == 3) {
|
||||
logmsg("pm: ENTER UPGRADE");
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would enter upgrade"); return 1; }
|
||||
if (sim_no_exec) { logmsg("pm: [sim-no-exec] would enter upgrade"); goto out; }
|
||||
if (meow_power_action(POWER_UPGRADE) != MEOW_OK) {
|
||||
logmsg("pm: power service unavailable, abort (menu closed, no action)");
|
||||
return 0;
|
||||
pm_rc = 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
out:
|
||||
if (tfd >= 0) close(tfd);
|
||||
meow_ui_activity_pop(); /* M7.0b:退出电源菜单,回主 activity(控件 owner 仍钉哨兵,复用) */
|
||||
/* M40 F2:恢复进入前的背景帧(否则 app_launcher 会把菜单帧当 App 帧上屏 = P2)。
|
||||
* 放在动作执行之后:锁屏动作已 meow_panel_off(),此时恢复只写 fb0(面板黑),
|
||||
* 下次唤醒 / App 整帧重画时得到的是正确底层帧而不是 PIN/菜单帧。 */
|
||||
pm_restore_bg(pm_bg_snap, pm_bg_len);
|
||||
if (pm_bg_snap) free(pm_bg_snap);
|
||||
return pm_rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
* S4 锁屏页自睡(294 遗留) → overlay_lock_idle_off_sec():阈值 = min(系统 screen_off_timeout, 30s)
|
||||
* (0/超30→30,尊重更短);overlay_lock_should_sleep()/overlay_lock_wake_now()
|
||||
* 判定超时灭屏(锁态保持)与唤醒回锁屏。
|
||||
* M40 F3/F4 → overlay_activity_drain_active():叠加/菜单返回后的排空窗内忽略
|
||||
* activity 标记(防冻结期输入重放成「亮屏+锁屏」);
|
||||
* overlay_lock_power_off_now():锁屏电源必须按下边沿 + 进场≥300ms。
|
||||
*
|
||||
* 编译运行(在 patch_v2/meow_launcherd 下,无其它依赖):
|
||||
* gcc -Wall -Wextra -o test_overlay_gate test_overlay_gate.c && ./test_overlay_gate
|
||||
@@ -80,6 +83,19 @@ int main(void)
|
||||
CHECK(overlay_lock_wake_now(0, 1) == 1, "S4 touch -> wake to lock");
|
||||
CHECK(overlay_lock_wake_now(0, 0) == 0, "S4 no wake input -> stay asleep");
|
||||
|
||||
/* ---- M40 F4/P4:锁屏页电源「按下边沿 + 进场 ≥300ms」才熄屏 ----
|
||||
* 电平判定会让「打开菜单的那次长按」在 PIN 页出现时立刻把页面熄灭(用户症状)。 */
|
||||
CHECK(OVERLAY_LOCK_POWER_GRACE_MS == 300, "F4 lock power grace = 300ms");
|
||||
CHECK(overlay_lock_power_off_now(1, 299) == 0, "F4 press edge inside 300ms grace -> no off");
|
||||
CHECK(overlay_lock_power_off_now(1, 300) == 1, "F4 press edge at 300ms -> off");
|
||||
CHECK(overlay_lock_power_off_now(0, 5000) == 0, "F4 held level (no edge) -> never re-fires");
|
||||
CHECK(overlay_lock_power_off_now(1, 5000) == 1, "F4 new press edge after grace -> off");
|
||||
|
||||
/* ---- M40 F3/P3:叠加层/菜单返回后的 activity 标记排空窗 ---- */
|
||||
CHECK(overlay_activity_drain_active(0, 0, 999999) == 0, "F3 no overlay return mark -> activity honored");
|
||||
CHECK(overlay_activity_drain_active(1, 1000, 1299) == 1, "F3 marker inside 300ms drain -> ignored");
|
||||
CHECK(overlay_activity_drain_active(1, 1000, 1300) == 0, "F3 marker after drain -> honored");
|
||||
|
||||
/* ---- S3 App 死亡触发主屏重绘:崩溃必须走统一退出路径 ---- */
|
||||
CHECK(lock_overlay_app_died_exit(1) == 1, "S3 app died -> unified exit path (redraw home)");
|
||||
CHECK(lock_overlay_app_died_exit(0) == 0, "S3 app alive -> normal restore");
|
||||
|
||||
@@ -12,13 +12,16 @@ INC="$ROOT/patch_v2/meow_launcherd" # meow_ipc.h(音量收编 v2:MSG_AUDIO
|
||||
|
||||
if [ "$1" = "host" ]; then
|
||||
gcc -Wall -Wextra -Os -I"$INC" -DWd_NO_MAIN -Wno-unused-function -Wno-unused-parameter \
|
||||
-Wno-unused-variable test_wd_fw.c -o test_wd_fw -lm
|
||||
-Wno-unused-variable test_wd_fw.c ../sdk/meow_time32.c -o test_wd_fw -lm
|
||||
./test_wd_fw
|
||||
exit $?
|
||||
fi
|
||||
|
||||
echo "== meow_watchdog (mipsel static) =="
|
||||
"$CC" -Os -Wall -Wextra -static -I"$INC" meow_watchdog.c -o meow_watchdog
|
||||
# meow_time32.c:独立 time32 取时/睡眠(watchdog 不链 meow_ui.a)。LIBC_OVERRIDES 让
|
||||
# 未逐个改写的 libc 取时/睡眠入口也一并修正(静态链接,本对象强定义覆盖 libc 归档成员)。
|
||||
"$CC" -Os -Wall -Wextra -static -I"$INC" -DMEOW_TIME32_LIBC_OVERRIDES \
|
||||
meow_watchdog.c ../sdk/meow_time32.c -o meow_watchdog
|
||||
ls -la meow_watchdog
|
||||
md5sum meow_watchdog
|
||||
file meow_watchdog
|
||||
Binary file not shown.
@@ -12,13 +12,14 @@
|
||||
* run — short press (<3s release) = toggle screen off/on (brightness 0 +
|
||||
* FBIOBLANK(4) / FBIOBLANK(0)+brightness restore, with a force re-pan to
|
||||
* buffer0 on wake).
|
||||
* - M2.24 全面按键接管(KEY_CONTROL_DESIGN):应用运行期所有物理键由本进程统一消费,
|
||||
* - M2.24/M40 全面按键接管(KEY_CONTROL_DESIGN):应用运行期所有物理键由本进程统一消费,
|
||||
* 应用绝不碰物理键。
|
||||
* 电源单击(<2s) -> 息屏/亮屏(沿用 M2.22);
|
||||
* 电源长按 ≥2s -> 写 /tmp/meow_power_menu,由 launcher SIGSTOP app 后弹统一电源菜单
|
||||
* (launcher 在 waitpid 轮询中消费;菜单期该进程靠 /tmp/meow_power_menu_active
|
||||
* 让位,绝不与 launcher 抢屏/抢键);launcher 画菜单,本进程不自绘。
|
||||
* 电源长按 ≥8s -> 强制关机兜底(仅当菜单未生效/launcher 未接管)。
|
||||
* 电源单击(松开时 held < power.longpress_menu_ms,缺省 3000)-> 息屏/亮屏(沿用 M2.22);
|
||||
* 电源长按 ≥power.longpress_menu_ms -> 写 /tmp/meow_power_menu,由 launcher SIGSTOP app
|
||||
* 后弹统一电源菜单(launcher 在 waitpid 轮询中消费;菜单期该进程靠
|
||||
* /tmp/meow_power_menu_active 让位,绝不与 launcher 抢屏/抢键);
|
||||
* launcher 画菜单,本进程不自绘。
|
||||
* 电源长按 ≥power.forceoff_ms(缺省 8000)-> 强制关机兜底(仅当菜单未被 launcher 接管)。
|
||||
* 音量±(115/114) -> 音量收编 v2(FUTURE_AUDIO 事项三):首选发 audiod 权威
|
||||
* MSG_AUDIO_VOLUME(audiod 写 DAC numid=1/2 + DSD_VOLUME + 持久化
|
||||
* settings.conf,同源同键单写者);audiod 未起(HibyOS/开机早期)
|
||||
@@ -62,6 +63,8 @@
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include "meow_ipc.h" /* MSG_AUDIO_VOLUME/MSG_ACK/帧格式(音量收编 v2:首选 audiod 权威) */
|
||||
#include "../sdk/meow_time32.h" /* o32 time32 取时/睡眠(watchdog 不链 meow_ui.a) */
|
||||
#include "wd_power.h" /* 电源阈值/边沿纯判定(宿主单测同源) */
|
||||
|
||||
/* device-verified: VSCREENINFO=0x4600, FSCREENINFO=0x4602 (do not swap) */
|
||||
#define FBIOGET_VSCREENINFO 0x4600
|
||||
@@ -95,11 +98,10 @@
|
||||
#define KEY_NEXTSONG 163
|
||||
#define KEY_PREVIOUS 19
|
||||
#define BACKLIGHT "/sys/class/backlight/backlight_pwm0/brightness"
|
||||
/* M2.24 全面按键接管:电源单击(<2s)=息屏/亮屏;长按≥2s=通知 launcher 弹统一电源菜单;
|
||||
* ≥8s=强制关机兜底(仅当 launcher 未接管菜单时)。音量± = 写真实 DAC;播放/上下曲 = 抓消费。 */
|
||||
#define PWR_TOGGLE_MS 2000 /* 短按上限:<2s 松开=单击(镜像 launcher 单单击语义) */
|
||||
#define PWR_MENU_MS 2000 /* 长按≥2s -> 写 /tmp/meow_power_menu 请 launcher 弹菜单 */
|
||||
#define PWR_FORCE_MS 8000 /* 长按≥8s -> 强制关机(launcher 未接管时的兜底) */
|
||||
/* M2.24 全面按键接管:电源单击(<power.longpress_menu_ms)=息屏/亮屏;长按≥该值=通知
|
||||
* launcher 弹统一电源菜单;≥power.forceoff_ms=强制关机兜底(launcher 未接管菜单时)。
|
||||
* 阈值不硬编码:启动时读 settings.conf(缺省 3000/8000),与 launcher 主屏同一语义。
|
||||
* 音量± = 写真实 DAC;播放/上下曲 = 抓消费。 */
|
||||
#define PWR_MENU_MARKER "/tmp/meow_power_menu" /* watchdog->launcher 菜单请求 */
|
||||
#define PWR_MENU_ACTIVE "/tmp/meow_power_menu_active" /* launcher 画菜单中,watchdog 让位 */
|
||||
#define MEOW_SETTINGS_FILE "/usr/data/meow/settings.conf" /* 音量持久化(与 launcher settings.conf 同源) */
|
||||
@@ -150,11 +152,14 @@ static int read_state_file(void)
|
||||
* stderr when unset (e.g. no TF card at launch time). */
|
||||
static int wd_log_fd = -1;
|
||||
|
||||
/* 单调毫秒:**必须**走 meow_time32(o32 内核 time32 取时)。
|
||||
* zig musl 的 time64 ABI 在 mipsel 上自相矛盾:直接 clock_gettime() 时结构按 16 字节写、
|
||||
* libc 只写 8 字节 time32,tv_sec 高 32 位会读成 nsec → held 变天文数字,每次单击都被
|
||||
* 判成长按并立刻弹菜单(真机日志 `power hold 12392415168036864000ms`,反汇编证实只有
|
||||
* 4263/无 4403)。meow_time32.c 不依赖 meow_ui.a,静态链入即可修正。 */
|
||||
static unsigned long long now_ms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (unsigned long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
return (unsigned long long)meow_time32_monotonic_ms();
|
||||
}
|
||||
|
||||
static void wd_log_init(void)
|
||||
@@ -216,6 +221,9 @@ static int wd_fbfd = -1; /* fb0 fd(main 里打开,供 FB
|
||||
#define WD_SETTINGS_GAP_MS 10
|
||||
|
||||
static int wd_saved_bri = WD_BRI_UNKNOWN; /* 熄屏前亮度快照;未知=WD_BRI_UNKNOWN(不再用 60) */
|
||||
/* 电源阈值(启动时读 settings.conf;缺省 3000/8000,与 launcher 主屏一致)。 */
|
||||
static unsigned long long wd_pwr_longpress_ms = WD_PWR_LONGPRESS_DEFAULT_MS;
|
||||
static unsigned long long wd_pwr_forceoff_ms = WD_PWR_FORCEOFF_DEFAULT_MS;
|
||||
static int pwr_down = 0; /* 电源当前按住 */
|
||||
static unsigned long long pwr_down_ms = 0;
|
||||
static int pwr_woke = 0; /* 按下时屏已黑 → 本次只作唤醒,松开不再 toggle */
|
||||
@@ -278,7 +286,7 @@ static int wd_settings_brightness(void)
|
||||
for (int i = 0; i < WD_SETTINGS_TRIES; i++) {
|
||||
f = fopen(wd_settings_path(), "r");
|
||||
if (f) break;
|
||||
if (i + 1 < WD_SETTINGS_TRIES) usleep(WD_SETTINGS_GAP_MS * 1000);
|
||||
if (i + 1 < WD_SETTINGS_TRIES) meow_time32_sleep_us(WD_SETTINGS_GAP_MS * 1000);
|
||||
}
|
||||
if (!f) return -1;
|
||||
int b = 101; /* display.brightness 默认(与 launcher 设置表同值,键缺失时 clamp→100) */
|
||||
@@ -301,6 +309,42 @@ static int wd_settings_brightness(void)
|
||||
return b;
|
||||
}
|
||||
|
||||
/* 读电源阈值(power.longpress_menu_ms / power.forceoff_ms,缺省 3000/8000)。
|
||||
* 与 wd_settings_brightness 同款重试窗口;文件不可读时**保留缺省**(绝不退回 2000——
|
||||
* 旧硬编码会让 App 内 2s 出菜单、主屏 3s,且 PWR_TOGGLE==PWR_MENU 时「长按不出菜单」
|
||||
* 的区间不存在)。解析后经 pure helper 清洗(非正数→缺省;forceoff≤longpress→抬 1s)。 */
|
||||
static void wd_power_settings_load(void)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
for (int i = 0; i < WD_SETTINGS_TRIES; i++) {
|
||||
f = fopen(wd_settings_path(), "r");
|
||||
if (f) break;
|
||||
if (i + 1 < WD_SETTINGS_TRIES) meow_time32_sleep_us(WD_SETTINGS_GAP_MS * 1000);
|
||||
}
|
||||
if (!f) {
|
||||
wd_pwr_resolve_thresholds(0, 0, &wd_pwr_longpress_ms, &wd_pwr_forceoff_ms);
|
||||
wd_log("power: settings unreadable -> defaults longpress=%llums forceoff=%llums",
|
||||
wd_pwr_longpress_ms, wd_pwr_forceoff_ms);
|
||||
return;
|
||||
}
|
||||
int lp = 0, fo = 0;
|
||||
char buf[128];
|
||||
while (fgets(buf, sizeof buf, f)) {
|
||||
char *eq = strchr(buf, '=');
|
||||
if (!eq) continue;
|
||||
*eq = 0;
|
||||
char *k = buf; int kl = (int)strlen(k);
|
||||
while (kl > 0 && (k[kl-1] == ' ' || k[kl-1] == '\t')) k[--kl] = 0;
|
||||
char *v = eq + 1; while (*v == ' ' || *v == '\t') v++;
|
||||
if (!strcmp(k, "power.longpress_menu_ms")) lp = atoi(v);
|
||||
else if (!strcmp(k, "power.forceoff_ms")) fo = atoi(v);
|
||||
}
|
||||
fclose(f);
|
||||
wd_pwr_resolve_thresholds(lp, fo, &wd_pwr_longpress_ms, &wd_pwr_forceoff_ms);
|
||||
wd_log("power: settings longpress=%llums forceoff=%llums (raw %d/%d)",
|
||||
wd_pwr_longpress_ms, wd_pwr_forceoff_ms, lp, fo);
|
||||
}
|
||||
|
||||
/* 强制 re-pan 到 buffer0:FBIOBLANK(4)->(0) 后 LCDC 扫描地址可能已复位到非 buffer0/失效
|
||||
* 位置(launcher M2.8 Bug-3-residual 根因),而应用始终画 buffer0,必须无条件把显示翻回
|
||||
* buffer0,否则唤醒后黑屏/旧帧。 */
|
||||
@@ -378,15 +422,17 @@ static void wd_do_poweroff(void)
|
||||
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
|
||||
LINUX_REBOOT_CMD_POWER_OFF, NULL);
|
||||
wd_log("sys_reboot returned: %s", strerror(errno)); /* 正常不会返回 */
|
||||
for (;;) usleep(1000000);
|
||||
for (;;) meow_time32_sleep_us(1000000);
|
||||
}
|
||||
|
||||
/* 电源键(KEY_POWER)边沿驱动:单击(短按松开 <3s)= 息屏/亮屏;按下时屏已黑 = 只唤醒。
|
||||
* 长按(≥3s)由 wd_power_tick() 在轮询中检测 → 写 /tmp/meow_power_menu 请 launcher 弹菜单;
|
||||
* 松开边沿不再 toggle(菜单/长按语义归 launcher 菜单,防「长按后仍 toggle」)。 */
|
||||
/* 电源键(KEY_POWER)边沿驱动:单击(松开时 held < power.longpress_menu_ms,缺省 3s)= 息屏/亮屏;
|
||||
* 按下时屏已黑 = 只唤醒。长按(≥longpress)由 wd_power_tick() 在轮询中检测 → 写
|
||||
* /tmp/meow_power_menu 请 launcher 弹菜单;松开边沿不再 toggle(菜单/长按语义归 launcher
|
||||
* 菜单,防「长按后仍 toggle」)。 */
|
||||
static void handle_power(int val)
|
||||
{
|
||||
if (wd_menu_active()) return; /* 电源菜单期:launcher 独占物理键语义 */
|
||||
if (val == 2) return; /* EV_KEY 重复值:本设备 event0 无 EV_REP,防御性忽略 */
|
||||
if (val) {
|
||||
/* 按下边沿 */
|
||||
pwr_down = 1;
|
||||
@@ -396,28 +442,40 @@ static void handle_power(int val)
|
||||
int br = read_brightness();
|
||||
pwr_woke = (br <= 0) ? 1 : 0; /* 屏已黑:本次电源=唤醒,松开不 toggle */
|
||||
if (pwr_woke) wd_panel_on(); /* 立即亮屏(launcher 自动息屏唤醒路径同步醒,双保险幂等) */
|
||||
wd_log("power down (bri=%d woke=%d)", br, pwr_woke);
|
||||
wd_log("power down (bri=%d woke=%d longpress=%llums)", br, pwr_woke,
|
||||
wd_pwr_longpress_ms);
|
||||
return;
|
||||
}
|
||||
/* 松开边沿 */
|
||||
if (!pwr_down) return; /* 未跟踪到按下(启动前已按住/残留):忽略,防误 toggle */
|
||||
pwr_down = 0;
|
||||
unsigned long long held = now_ms() - pwr_down_ms;
|
||||
if (pwr_woke) { pwr_woke = 0; wd_log("power release after wake (%llums) -> no toggle", held); return; }
|
||||
int br = read_brightness();
|
||||
wd_pwr_release_act act = wd_pwr_release_action(pwr_woke, pwr_menu_notified, held,
|
||||
wd_pwr_longpress_ms, br);
|
||||
if (pwr_woke) {
|
||||
pwr_woke = 0;
|
||||
wd_log("power release after wake (%llums) -> no toggle", held);
|
||||
return;
|
||||
}
|
||||
if (pwr_menu_notified) {
|
||||
/* 本次已请求电源菜单(≥3s):菜单是否画出由 launcher 负责,这里绝不 toggle。 */
|
||||
/* 本次已请求电源菜单(≥longpress):菜单是否画出由 launcher 负责,这里绝不 toggle。 */
|
||||
wd_log("power release after menu req (%llums) -> menu owns toggle", held);
|
||||
pwr_menu_notified = 0;
|
||||
return;
|
||||
}
|
||||
if (held >= PWR_TOGGLE_MS) { wd_log("power hold %llums -> no-op (menu/force-off in tick)", held); return; }
|
||||
int br = read_brightness();
|
||||
if (br > 0) wd_panel_off();
|
||||
else wd_panel_on(); /* 屏已黑仍短按:亮屏 */
|
||||
if (act == WD_PWR_REL_NONE) {
|
||||
/* held ≥ longpress 但 tick 还没发出菜单(轮询粒度/边界):仍按长按处理,不 toggle。 */
|
||||
wd_log("power hold %llums -> no-op (menu/force-off in tick)", held);
|
||||
return;
|
||||
}
|
||||
if (act == WD_PWR_REL_TOGGLE_OFF) wd_panel_off();
|
||||
else wd_panel_on(); /* 屏已黑仍短按:亮屏 */
|
||||
wd_log("power short-press %llums -> toggle panel (bri was %d)", held, br);
|
||||
}
|
||||
|
||||
/* 电源长按检测(每轮询 tick 调):≥3s 写菜单请求;≥8s 强制关机兜底(仅当菜单未生效时)。 */
|
||||
/* 电源长按检测(每轮询 tick 调):≥longpress 写菜单请求;≥forceoff 强制关机兜底
|
||||
* (launcher 已接管菜单时顶部即让位,不会走到这里)。阈值来自 settings。 */
|
||||
static void wd_power_tick(void)
|
||||
{
|
||||
/* launcher 已接管电源菜单:本进程完全让位,清空电源状态,下一手势从零开始。 */
|
||||
@@ -428,14 +486,15 @@ static void wd_power_tick(void)
|
||||
}
|
||||
if (!pwr_down) return;
|
||||
unsigned long long held = now_ms() - pwr_down_ms;
|
||||
if (held >= PWR_MENU_MS && !pwr_menu_notified) {
|
||||
wd_pwr_tick_act act = wd_pwr_tick_action(0, pwr_down, pwr_menu_notified, pwr_force_done,
|
||||
held, wd_pwr_longpress_ms, wd_pwr_forceoff_ms);
|
||||
if (act == WD_PWR_TICK_MENU) {
|
||||
int fd = open(PWR_MENU_MARKER, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd >= 0) { write(fd, "1", 1); close(fd); }
|
||||
pwr_menu_notified = 1;
|
||||
wd_log("power hold %llums -> %s (launcher draws menu)", held, PWR_MENU_MARKER);
|
||||
}
|
||||
if (held >= PWR_FORCE_MS && !pwr_force_done && !pwr_menu_notified) {
|
||||
/* 长按 8s 仍无菜单接管(launcher 未响应/未消费)→ 强制关机兜底。 */
|
||||
} else if (act == WD_PWR_TICK_FORCEOFF) {
|
||||
/* 长按 ≥forceoff 仍无菜单接管(launcher 未响应/未消费)→ 强制关机兜底。 */
|
||||
pwr_force_done = 1;
|
||||
wd_log("power hold %llums -> FORCE POWER OFF", held);
|
||||
wd_do_poweroff();
|
||||
@@ -805,6 +864,7 @@ int main(int argc, char **argv)
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
wd_log_init();
|
||||
wd_vol_load(); /* M2.24:音量初始值读自与 launcher 同源 settings.conf */
|
||||
wd_power_settings_load(); /* M40:电源长按/强关阈值(缺省 3000/8000,与 launcher 主屏同源) */
|
||||
/* M2.86(226):SDK 框架 App 判定(app.json framework=1)-> 音量/媒体键让位 SDK。 */
|
||||
g_fw_app = wd_framework_from_pid(app_pid);
|
||||
wd_log("app_pid=%d sim_tap=%d sim_swipe=%d framework=%d%s",
|
||||
@@ -870,7 +930,7 @@ int main(int argc, char **argv)
|
||||
if (sim_tap && elapsed >= (long)sim_tap * 1000) {
|
||||
wd_log("SIM TAP");
|
||||
kill(app_pid, SIGTERM);
|
||||
usleep(1000000);
|
||||
meow_time32_sleep_us(1000000);
|
||||
kill(app_pid, SIGKILL);
|
||||
break;
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,9 +1,10 @@
|
||||
/* test_wd_fw.c — 宿主单测:meow_watchdog 的纯逻辑(M2.86 框架 App 判定 + M20 亮屏亮度)。
|
||||
/* test_wd_fw.c — 宿主单测:meow_watchdog 的纯逻辑(M2.86 框架 App 判定 + M20 亮屏亮度 +
|
||||
* M40 time32 取时/睡眠 + 电源阈值行为矩阵)。
|
||||
*
|
||||
* 编译:#include meow_watchdog.c(去 main 拿 wd_app_is_framework/json_str/from_pid、
|
||||
* wd_bri_decide、wd_settings_brightness、wd_panel_off/on)。
|
||||
* wd_bri_decide、wd_settings_brightness、wd_panel_off/on;wd_power.h 的纯判定)。
|
||||
* gcc -Wall -Wextra -Os -DWd_NO_MAIN -Wno-unused-function -Wno-unused-parameter \
|
||||
* test_wd_fw.c -o test_wd_fw
|
||||
* test_wd_fw.c ../sdk/meow_time32.c -o test_wd_fw
|
||||
* (meow_watchdog.c 含仅 main 使用的静态函数,宿主去 main 后须 -Wno-unused-function 静音;
|
||||
* mips 目标构建不定义 WD_NO_MAIN,不受影响。)
|
||||
* 运行:./test_wd_fw;全 PASS -> exit 0。
|
||||
@@ -223,6 +224,84 @@ static void test_panel_brightness_e2e(void)
|
||||
unsetenv("MEOW_SETTINGS_FILE");
|
||||
}
|
||||
|
||||
/* ---- M40:time32 取时/睡眠(与 libc 正常取时一致;o32 syscall 路径由交叉二进制反汇编验证)---- */
|
||||
static void test_time32(void)
|
||||
{
|
||||
struct meow_time32 t;
|
||||
check("time32 gettime ok", meow_time32_clock_gettime(CLOCK_MONOTONIC, &t) == 0, 1);
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
check("time32 sec == libc sec", t.tv_sec == (int32_t)ts.tv_sec, 1);
|
||||
long dn = (long)t.tv_nsec - (long)ts.tv_nsec;
|
||||
if (dn < 0) dn = -dn;
|
||||
check("time32 nsec == libc nsec (<1ms)", dn < 1000000, 1);
|
||||
|
||||
uint64_t a = meow_time32_monotonic_ms();
|
||||
uint64_t b = meow_time32_monotonic_ms();
|
||||
check("monotonic nonzero", a > 0, 1);
|
||||
check("monotonic nondecreasing", b >= a, 1);
|
||||
check("ms from parts 1135.008s", meow_time_ms_from_parts(1135, 8000000) == 1135008ULL, 1);
|
||||
|
||||
unsigned long long s0 = now_ms();
|
||||
meow_time32_sleep_us(20000);
|
||||
unsigned long long el = now_ms() - s0;
|
||||
check("sleep 20ms actually sleeps (>=15ms)", el >= 15, 1);
|
||||
}
|
||||
|
||||
/* ---- M40:电源阈值/边沿行为矩阵(settings 取不同值)---- */
|
||||
static void test_power_matrix(void)
|
||||
{
|
||||
unsigned long long lp = 0, fo = 0;
|
||||
|
||||
wd_pwr_resolve_thresholds(0, 0, &lp, &fo);
|
||||
check("pwr default longpress=3000", lp == 3000, 1);
|
||||
check("pwr default forceoff=8000", fo == 8000, 1);
|
||||
|
||||
wd_pwr_resolve_thresholds(1500, 5000, &lp, &fo);
|
||||
check("pwr settings longpress=1500", lp == 1500, 1);
|
||||
check("pwr settings forceoff=5000", fo == 5000, 1);
|
||||
|
||||
wd_pwr_resolve_thresholds(-1, 0, &lp, &fo);
|
||||
check("pwr invalid -> default longpress", lp == 3000, 1);
|
||||
check("pwr invalid -> default forceoff", fo == 8000, 1);
|
||||
|
||||
wd_pwr_resolve_thresholds(3000, 2000, &lp, &fo);
|
||||
check("pwr forceoff<=longpress lifted to lp+1000", fo == 4000, 1);
|
||||
|
||||
/* 松开边沿:单击 / 长按但未到阈值 / 到阈值 / 唤醒 / 菜单已请求 */
|
||||
check("release 100ms screen-on -> toggle off",
|
||||
wd_pwr_release_action(0, 0, 100, 3000, 50) == WD_PWR_REL_TOGGLE_OFF, 1);
|
||||
check("release 100ms screen-off -> toggle on",
|
||||
wd_pwr_release_action(0, 0, 100, 3000, 0) == WD_PWR_REL_TOGGLE_ON, 1);
|
||||
check("release 2500ms (<3000) still click -> toggle off",
|
||||
wd_pwr_release_action(0, 0, 2500, 3000, 50) == WD_PWR_REL_TOGGLE_OFF, 1);
|
||||
check("release 3000ms (>=longpress) -> no toggle",
|
||||
wd_pwr_release_action(0, 0, 3000, 3000, 50) == WD_PWR_REL_NONE, 1);
|
||||
check("release after wake -> no toggle",
|
||||
wd_pwr_release_action(1, 0, 100, 3000, 0) == WD_PWR_REL_NONE, 1);
|
||||
check("release after menu req -> no toggle",
|
||||
wd_pwr_release_action(0, 1, 3500, 3000, 50) == WD_PWR_REL_NONE, 1);
|
||||
|
||||
/* 按住 tick:单击窗 / 长按出菜单 / 强关兜底 / 菜单已接管 / 已强关 */
|
||||
check("tick 2999ms -> none",
|
||||
wd_pwr_tick_action(0, 1, 0, 0, 2999, 3000, 8000) == WD_PWR_TICK_NONE, 1);
|
||||
check("tick 3000ms -> menu",
|
||||
wd_pwr_tick_action(0, 1, 0, 0, 3000, 3000, 8000) == WD_PWR_TICK_MENU, 1);
|
||||
check("tick 8000ms menu requested, no takeover -> forceoff",
|
||||
wd_pwr_tick_action(0, 1, 1, 0, 8000, 3000, 8000) == WD_PWR_TICK_FORCEOFF, 1);
|
||||
check("tick 8000ms launcher menu active -> none",
|
||||
wd_pwr_tick_action(1, 1, 1, 0, 8000, 3000, 8000) == WD_PWR_TICK_NONE, 1);
|
||||
check("tick forceoff already done -> none",
|
||||
wd_pwr_tick_action(0, 1, 1, 1, 9000, 3000, 8000) == WD_PWR_TICK_NONE, 1);
|
||||
check("tick not down -> none",
|
||||
wd_pwr_tick_action(0, 0, 0, 0, 9000, 3000, 8000) == WD_PWR_TICK_NONE, 1);
|
||||
/* settings 取短值:1000/2000 */
|
||||
check("tick custom 1000ms -> menu",
|
||||
wd_pwr_tick_action(0, 1, 0, 0, 1000, 1000, 2000) == WD_PWR_TICK_MENU, 1);
|
||||
check("tick custom 2000ms no takeover -> forceoff",
|
||||
wd_pwr_tick_action(0, 1, 1, 0, 2000, 1000, 2000) == WD_PWR_TICK_FORCEOFF, 1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
signal(SIGUSR1, on_sigusr1); /* 捕获 handle_touch 可能发出的 SIGUSR1(测命中) */
|
||||
@@ -270,6 +349,10 @@ int main(void)
|
||||
test_settings_brightness();
|
||||
test_panel_brightness_e2e();
|
||||
|
||||
/* ---- M40:time32 取时/睡眠 + 电源阈值行为矩阵 ---- */
|
||||
test_time32();
|
||||
test_power_matrix();
|
||||
|
||||
/* 清理 */
|
||||
{
|
||||
char path[560];
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/* wd_power.h — watchdog 电源键判定(纯函数,宿主可单测,无设备/无文件系统依赖)。
|
||||
*
|
||||
* 语义与 launcher 主屏(main_menu.c)统一:
|
||||
* 单击(松开时 held < power.longpress_menu_ms) → 息屏/亮屏切换;
|
||||
* 长按 held ≥ power.longpress_menu_ms → 写菜单请求(watchdog 让位 launcher);
|
||||
* 长按 held ≥ power.forceoff_ms 且菜单未被接管 → 强制关机兜底。
|
||||
* 旧实现把 PWR_TOGGLE_MS 与 PWR_MENU_MS 都硬编码成 2000,导致「长按但不出菜单」的区间
|
||||
* 不存在,且 App 内 2s / launcher 主屏 3s 不一致;现在两者都读 settings(缺省 3000/8000)。
|
||||
*
|
||||
* 阈值清洗:
|
||||
* - 非正数 → 默认 3000 / 8000(settings 允许 0,但 0ms 阈值会让每次按下立刻出菜单,无意义);
|
||||
* - forceoff ≤ longpress → 抬到 longpress+1000,避免「强关先于菜单」的自相矛盾配置。
|
||||
*/
|
||||
#ifndef WD_POWER_H
|
||||
#define WD_POWER_H
|
||||
|
||||
#define WD_PWR_LONGPRESS_DEFAULT_MS 3000
|
||||
#define WD_PWR_FORCEOFF_DEFAULT_MS 8000
|
||||
|
||||
static inline void wd_pwr_resolve_thresholds(int cfg_longpress, int cfg_forceoff,
|
||||
unsigned long long *longpress_ms,
|
||||
unsigned long long *forceoff_ms)
|
||||
{
|
||||
unsigned long long lp = (cfg_longpress > 0)
|
||||
? (unsigned long long)cfg_longpress
|
||||
: WD_PWR_LONGPRESS_DEFAULT_MS;
|
||||
unsigned long long fo = (cfg_forceoff > 0)
|
||||
? (unsigned long long)cfg_forceoff
|
||||
: WD_PWR_FORCEOFF_DEFAULT_MS;
|
||||
if (fo <= lp) fo = lp + 1000;
|
||||
*longpress_ms = lp;
|
||||
*forceoff_ms = fo;
|
||||
}
|
||||
|
||||
/* 松开边沿的动作。bright>0=屏亮 → 息屏;否则亮屏。
|
||||
* woke(按下时屏已黑,本次只唤醒)/ menu_notified(已请求菜单)→ 不再 toggle。 */
|
||||
typedef enum {
|
||||
WD_PWR_REL_NONE = 0,
|
||||
WD_PWR_REL_TOGGLE_OFF,
|
||||
WD_PWR_REL_TOGGLE_ON
|
||||
} wd_pwr_release_act;
|
||||
|
||||
static inline wd_pwr_release_act wd_pwr_release_action(int woke, int menu_notified,
|
||||
unsigned long long held_ms,
|
||||
unsigned long long longpress_ms,
|
||||
int bright)
|
||||
{
|
||||
if (woke || menu_notified) return WD_PWR_REL_NONE;
|
||||
if (held_ms >= longpress_ms) return WD_PWR_REL_NONE; /* 长按已由 tick 处理 */
|
||||
return (bright > 0) ? WD_PWR_REL_TOGGLE_OFF : WD_PWR_REL_TOGGLE_ON;
|
||||
}
|
||||
|
||||
/* 轮询 tick(按住中)的动作。menu_active=launcher 已接管 → 全让位。
|
||||
* 强关不要求 menu_notified:launcher 未接管菜单时 8s 兜底仍须生效。 */
|
||||
typedef enum {
|
||||
WD_PWR_TICK_NONE = 0,
|
||||
WD_PWR_TICK_MENU,
|
||||
WD_PWR_TICK_FORCEOFF
|
||||
} wd_pwr_tick_act;
|
||||
|
||||
static inline wd_pwr_tick_act wd_pwr_tick_action(int menu_active, int down,
|
||||
int menu_notified, int force_done,
|
||||
unsigned long long held_ms,
|
||||
unsigned long long longpress_ms,
|
||||
unsigned long long forceoff_ms)
|
||||
{
|
||||
if (menu_active || !down) return WD_PWR_TICK_NONE;
|
||||
if (held_ms >= forceoff_ms && !force_done) return WD_PWR_TICK_FORCEOFF;
|
||||
if (held_ms >= longpress_ms && !menu_notified) return WD_PWR_TICK_MENU;
|
||||
return WD_PWR_TICK_NONE;
|
||||
}
|
||||
|
||||
#endif /* WD_POWER_H */
|
||||
Binary file not shown.
@@ -316,3 +316,33 @@ llvm-nm probe_sdk | grep -c __timedwait_cp # 1(libc 那份未被拉入)
|
||||
|
||||
真机验证仍待设备(本单未碰真机):`pthread_cond_timedwait` 传 100ms 超时的等待应真的等
|
||||
约 100ms 再超时,而不是立即返回。
|
||||
|
||||
## 9. M40:独立链接的 time32 基础设施(系统组件解药)
|
||||
|
||||
M16 的全部修复都只在 **链接 meow_ui.a** 的进程里生效。不链 SDK 的系统组件(watchdog /
|
||||
sysui / svcd / bootmenu / amsd / audiod / netmgrd / crash / svc_perf / powermgr / meowpanel)
|
||||
仍然各自中招:它们的 `now_ms()`/超时/退避全部按 16 字节 time64 读、libc 只写 8 字节 time32。
|
||||
|
||||
M40 把与 SDK 无关的部分抽成可独立链接的 TU:
|
||||
|
||||
| 文件 | 内容 | 依赖 |
|
||||
| --- | --- | --- |
|
||||
| `sdk/meow_time32.h` | o32 结构、纯换算、`meow_time32_clock_gettime()` / `meow_time32_monotonic_ms()` / `meow_time32_sleep_us()` | 仅 stdint |
|
||||
| `sdk/meow_time32.c` | 上述实现;mips o32 走 `SYS_clock_gettime32` / `SYS_nanosleep`,宿主回退 libc | libc |
|
||||
| `sdk/meow_ui_time.c` | 保留 futex/timerfd/clock_settime 接管;换算/取时改为调用 `meow_time32.c` | SDK |
|
||||
|
||||
系统组件构建脚本只需把 `../sdk/meow_time32.c` 加进链接命令;若希望链接期整体接管
|
||||
libc 的取时/睡眠入口(不必逐个改调用点),再编译该 TU 时加 `-DMEOW_TIME32_LIBC_OVERRIDES`
|
||||
(**不要**与 meow_ui.a 同时链接,否则 `__clock_gettime` 等重复定义)。
|
||||
|
||||
当前已接入:`meow_watchdog`(`build_watchdog.sh`)。待接入清单与各自脚本见 M40 报文;
|
||||
本单不改那些组件的源码/脚本(scope 限制),只提供设施与接入范式。
|
||||
|
||||
宿主单测:
|
||||
|
||||
```
|
||||
cd patch_v2/meow_watchdog
|
||||
bash build_watchdog.sh host # time32 取时/睡眠 + 电源阈值矩阵(66 项)
|
||||
cd ../sdk
|
||||
gcc -Wall -Wextra -I. test_meow_repaint.c -o /tmp/tr && /tmp/tr
|
||||
```
|
||||
@@ -7,8 +7,9 @@
|
||||
# 产物 sdk/vendor/freetype-build/libfreetype.a,其 .o 编入 meow_ui.a —— 应用只链 meow_ui.a
|
||||
# 即获得矢量字能力;不调 meow_ft_* 的 App 链接器不会拉取 freetype 成员(零增量)。
|
||||
#
|
||||
# 时钟(meow_ui_time):mipsel 上 zig 0.17 musl 的 time64 ABI 自相矛盾(头 64 位 / 实现
|
||||
# time32),该 TU 按内核 o32 ABI 取时并强定义 __clock_gettime*/睡眠入口,链接期接管。
|
||||
# 时钟(meow_ui_time + meow_time32):mipsel 上 zig 0.17 musl 的 time64 ABI 自相矛盾(头 64 位 /
|
||||
# 实现 time32)。meow_time32.c 是可独立链接的 o32 取时/睡眠设施(系统组件不链 SDK 也能用);
|
||||
# meow_ui_time.c 在其上做链接期接管(__clock_gettime*/futex/timerfd/clock_settime)。
|
||||
# 根因与验证见 sdk/CLOCK_ABI.md;改动后必须重编 meow_ui.a 并重链四 App。
|
||||
set -e
|
||||
ROOT="$HOME/Project/R3ProII"
|
||||
@@ -44,7 +45,7 @@ FT_INCS="-I$FT_BUILD -I$FT_BUILD/include -I$FT_SRC/include"
|
||||
rm -f meow_ui.a *.o
|
||||
|
||||
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
|
||||
OBJS="meow_ui_time meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_jpeg meow_png_stream meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_lazygrid meow_select meow_ui_str meow_ui_ft meow_net_ipc meow_cachegov"
|
||||
OBJS="meow_time32 meow_ui_time meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_jpeg meow_png_stream meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_lazygrid meow_select meow_ui_str meow_ui_ft meow_net_ipc meow_cachegov"
|
||||
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
|
||||
for f in $OBJS; do
|
||||
echo "== cc $f =="
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/* meow_time32.c — mipsel o32 内核 time32 ABI 兜底(独立链接,不依赖 meow_ui.a)。
|
||||
*
|
||||
* 根因与逐项证据:sdk/CLOCK_ABI.md(M11/M16)。核心一句话:
|
||||
* zig 0.17 的 musl 在 mipsel 上按 `#if defined(SYS_x_time64) && !defined(__ILP32__)`
|
||||
* 守卫 time64 回退,而 zig clang 又预定义了 __ILP32__,于是「time64 入口」被编成
|
||||
* 老的 time32 实现:内核只写 8 字节 {int32 sec; int32 nsec;},调用方却按 16 字节
|
||||
* 结构读。本文件不猜 libc 头的结构宽度,**直接按内核 ABI 取数/睡眠**。
|
||||
*
|
||||
* 本 TU 不引用 SDK 符号;系统组件(watchdog 等)可单独链接它。宿主(非 mips o32)
|
||||
* 自动退回 libc 的 clock_gettime/nanosleep,行为等价,宿主单测可直接编译运行。
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "meow_time32.h"
|
||||
|
||||
#if defined(__mips__) && !defined(__mips64) && (__SIZEOF_LONG__ == 4)
|
||||
#define MEOW_TIME32_KERNEL_ABI 1
|
||||
#include <sys/syscall.h>
|
||||
#else
|
||||
#define MEOW_TIME32_KERNEL_ABI 0
|
||||
#endif
|
||||
|
||||
/* ---- 纯换算 ---- */
|
||||
|
||||
void meow_time32_rel_from_parts(int64_t sec, int64_t nsec, struct meow_time32 *out)
|
||||
{
|
||||
if (sec > INT32_MAX) sec = INT32_MAX;
|
||||
else if (sec < INT32_MIN) sec = INT32_MIN;
|
||||
out->tv_sec = (int32_t)sec;
|
||||
out->tv_nsec = (int32_t)nsec;
|
||||
}
|
||||
|
||||
int meow_time32_abs_from_parts(int64_t sec, int64_t nsec, struct meow_time32 *out)
|
||||
{
|
||||
if (sec > INT32_MAX || sec < INT32_MIN) return -1;
|
||||
out->tv_sec = (int32_t)sec;
|
||||
out->tv_nsec = (int32_t)nsec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int meow_time32_itimerspec_from_64(const struct meow_time64_itimerspec *in,
|
||||
struct meow_itimerspec32 *out)
|
||||
{
|
||||
struct meow_itimerspec32 t;
|
||||
if (meow_time32_abs_from_parts(in->it_interval.tv_sec, in->it_interval.tv_nsec,
|
||||
&t.it_interval)) return -1;
|
||||
if (meow_time32_abs_from_parts(in->it_value.tv_sec, in->it_value.tv_nsec,
|
||||
&t.it_value)) return -1;
|
||||
*out = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void meow_time64_itimerspec_from_32(const struct meow_itimerspec32 *in,
|
||||
struct meow_time64_itimerspec *out)
|
||||
{
|
||||
out->it_interval.tv_sec = in->it_interval.tv_sec;
|
||||
out->it_interval.tv_nsec = in->it_interval.tv_nsec;
|
||||
out->it_value.tv_sec = in->it_value.tv_sec;
|
||||
out->it_value.tv_nsec = in->it_value.tv_nsec;
|
||||
}
|
||||
|
||||
uint64_t meow_time_ms_from_parts(int64_t sec, int64_t nsec)
|
||||
{
|
||||
return (uint64_t)sec * 1000u + (uint64_t)nsec / 1000000u;
|
||||
}
|
||||
|
||||
/* ---- 内核取时 ---- */
|
||||
|
||||
int meow_time32_clock_gettime(int clk, struct meow_time32 *out)
|
||||
{
|
||||
if (!out) { errno = EFAULT; return -1; }
|
||||
#if MEOW_TIME32_KERNEL_ABI
|
||||
out->tv_sec = 0;
|
||||
out->tv_nsec = 0;
|
||||
if (syscall(SYS_clock_gettime32, clk, out) != 0) return -1;
|
||||
return 0;
|
||||
#else
|
||||
struct timespec ts;
|
||||
if (clock_gettime((clockid_t)clk, &ts) != 0) return -1;
|
||||
out->tv_sec = (int32_t)ts.tv_sec;
|
||||
out->tv_nsec = (int32_t)ts.tv_nsec;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t meow_time32_monotonic_ms(void)
|
||||
{
|
||||
struct meow_time32 t;
|
||||
if (meow_time32_clock_gettime(CLOCK_MONOTONIC, &t) != 0) return 0;
|
||||
return meow_time_ms_from_parts(t.tv_sec, t.tv_nsec);
|
||||
}
|
||||
|
||||
/* ---- 睡眠(usleep 同源受损:16 字节 time64 直接交给 time32 系统调用时 nsec 恒 0,
|
||||
* 亚秒睡眠立即返回 → 轮询/退避变忙等空转)---- */
|
||||
|
||||
int meow_time32_sleep_us(unsigned usec)
|
||||
{
|
||||
#if MEOW_TIME32_KERNEL_ABI
|
||||
struct meow_time32 rq, rm;
|
||||
rq.tv_sec = (int32_t)(usec / 1000000u);
|
||||
rq.tv_nsec = (int32_t)((usec % 1000000u) * 1000u);
|
||||
for (;;) {
|
||||
long r = syscall(SYS_nanosleep, &rq, &rm);
|
||||
if (r == 0) return 0;
|
||||
if (errno != EINTR) return -1;
|
||||
rq = rm; /* 被信号打断:按剩余时间续睡 */
|
||||
}
|
||||
#else
|
||||
struct timespec rq, rm;
|
||||
rq.tv_sec = (time_t)(usec / 1000000u);
|
||||
rq.tv_nsec = (long)((usec % 1000000u) * 1000u);
|
||||
for (;;) {
|
||||
if (nanosleep(&rq, &rm) == 0) return 0;
|
||||
if (errno != EINTR) return -1;
|
||||
rq = rm;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---- 可选:链接期接管 libc 取时/睡眠入口 ----
|
||||
* 系统组件加 -DMEOW_TIME32_LIBC_OVERRIDES 编译本文件即可让未改写的 clock_gettime()/
|
||||
* usleep() 调用点也恢复正确(静态链接时本对象的强定义覆盖 libc 归档成员)。
|
||||
* 不要在同时链接 meow_ui.a(meow_ui_time.o) 的进程里启用——两者符号重复。
|
||||
* 与 meow_ui_time.c 的差别:这里只接管取时 + nanosleep;futex 相对超时 / timerfd /
|
||||
* clock_settime 的接管仍在 meow_ui_time.c(SDK 消费方自动获得)。 */
|
||||
#if MEOW_TIME32_KERNEL_ABI && defined(MEOW_TIME32_LIBC_OVERRIDES)
|
||||
|
||||
static int32_t meow_time32_clamp(int64_t v)
|
||||
{
|
||||
if (v > INT32_MAX) return INT32_MAX;
|
||||
if (v < 0) return 0;
|
||||
return (int32_t)v;
|
||||
}
|
||||
|
||||
int __clock_gettime(clockid_t clk, struct timespec *ts)
|
||||
{
|
||||
if (!ts) { errno = EFAULT; return -1; }
|
||||
struct meow_time32 t;
|
||||
if (meow_time32_clock_gettime(clk, &t) != 0) return -1;
|
||||
ts->tv_sec = t.tv_sec;
|
||||
ts->tv_nsec = t.tv_nsec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __clock_gettime64(clockid_t clk, struct timespec *ts)
|
||||
{
|
||||
return __clock_gettime(clk, ts);
|
||||
}
|
||||
|
||||
int __clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem)
|
||||
{
|
||||
struct meow_time32 rq, rm;
|
||||
long r;
|
||||
|
||||
if (clk == CLOCK_THREAD_CPUTIME_ID) return EINVAL;
|
||||
if (!req) return EFAULT;
|
||||
if (req->tv_nsec < 0 || req->tv_nsec >= 1000000000L) return EINVAL;
|
||||
rq.tv_sec = meow_time32_clamp(req->tv_sec);
|
||||
rq.tv_nsec = (int32_t)req->tv_nsec;
|
||||
rm.tv_sec = 0;
|
||||
rm.tv_nsec = 0;
|
||||
|
||||
if (clk == CLOCK_REALTIME && !flags)
|
||||
r = syscall(SYS_nanosleep, &rq, rem ? &rm : 0);
|
||||
else
|
||||
r = syscall(SYS_clock_nanosleep_time32, clk, flags, &rq, rem ? &rm : 0);
|
||||
if (r != 0) return errno;
|
||||
if (rem) {
|
||||
rem->tv_sec = rm.tv_sec;
|
||||
rem->tv_nsec = rm.tv_nsec;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __clock_nanosleep_time64(clockid_t clk, int flags, const struct timespec *req,
|
||||
struct timespec *rem)
|
||||
{
|
||||
return __clock_nanosleep(clk, flags, req, rem);
|
||||
}
|
||||
|
||||
int __nanosleep_time64(const struct timespec *req, struct timespec *rem)
|
||||
{
|
||||
int r = __clock_nanosleep(CLOCK_REALTIME, 0, req, rem);
|
||||
if (r) { errno = r; return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* MEOW_TIME32_KERNEL_ABI && MEOW_TIME32_LIBC_OVERRIDES */
|
||||
@@ -0,0 +1,78 @@
|
||||
/* meow_time32.h — mipsel o32 内核 time32 ABI 兜底(**可独立链接**的公共设施)。
|
||||
*
|
||||
* 为什么单独成文件(M40):
|
||||
* zig 0.17 给 32 位 mips 预定义 __ILP32__,打穿 musl 的 time64 回退守卫:调用方按
|
||||
* 16 字节 time64 结构取数,libc 却只发 time32 系统调用(只写前 8 字节)。结果是
|
||||
* 「秒在低 32 位、毫秒位恒 0、高 32 位是 nsec」的垃圾时间,任何 now_ms()/超时/退避
|
||||
* 都会失真。meow_ui_time.c 的修复只对**链接 meow_ui.a** 的进程生效;系统组件
|
||||
* (watchdog / sysui / svcd / bootmenu / amsd / audiod / netmgrd / crash / svc_perf /
|
||||
* powermgr / meowpanel)各自独立静态链接,不链 SDK,因此需要一份不依赖 SDK 的实现。
|
||||
*
|
||||
* 本 TU 只依赖 libc(stdint/unistd/time/syscall),不引用 meow_ui.a 的任何符号:
|
||||
* - 纯换算函数(与内核结构宽度解耦,宿主可直接单测);
|
||||
* - 内核 o32 time32 取时(meow_time32_clock_gettime / meow_time32_monotonic_ms);
|
||||
* - 亚秒睡眠(meow_time32_sleep_us;usleep 同源受损,见 meow_ui_time.c 注释)。
|
||||
*
|
||||
* 用法(系统组件的构建脚本):
|
||||
* $CC ... meow_watchdog.c ../sdk/meow_time32.c -o meow_watchdog
|
||||
* 若希望**链接期整体接管 libc 的取时/睡眠入口**(不再逐个改调用点),额外加宏
|
||||
* -DMEOW_TIME32_LIBC_OVERRIDES
|
||||
* 该宏只在 mipsel o32 上生效;此时**不要**同时链接 meow_ui.a 里的 meow_ui_time.o
|
||||
* (两者都会强定义 __clock_gettime 等符号)。
|
||||
*/
|
||||
#ifndef MEOW_TIME32_H
|
||||
#define MEOW_TIME32_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* mipsel o32 内核结构(与 libc 头里的 time_t 宽度无关):
|
||||
* { int32 tv_sec; int32 tv_nsec; } —— 固定 8 字节。 */
|
||||
struct meow_time32 {
|
||||
int32_t tv_sec;
|
||||
int32_t tv_nsec;
|
||||
};
|
||||
struct meow_itimerspec32 {
|
||||
struct meow_time32 it_interval;
|
||||
struct meow_time32 it_value;
|
||||
};
|
||||
/* 与 libc 结构解耦的 64 位镜像(宿主/交叉两端 time_t 宽度不同,测试不依赖它)。 */
|
||||
struct meow_time64_spec {
|
||||
int64_t tv_sec;
|
||||
int64_t tv_nsec;
|
||||
};
|
||||
struct meow_time64_itimerspec {
|
||||
struct meow_time64_spec it_interval;
|
||||
struct meow_time64_spec it_value;
|
||||
};
|
||||
|
||||
/* ---- 纯换算(无系统调用;宿主单测直接覆盖)---- */
|
||||
/* 相对超时(futex / nanosleep 的「等多久」):sec 超出 int32 时饱和
|
||||
* (正→INT32_MAX、负→INT32_MIN,与 musl CLAMP 一致),nsec 原样。 */
|
||||
void meow_time32_rel_from_parts(int64_t sec, int64_t nsec, struct meow_time32 *out);
|
||||
/* 绝对时刻(clock_settime / timerfd):sec 落不进 int32 返回 -1,nsec 原样。 */
|
||||
int meow_time32_abs_from_parts(int64_t sec, int64_t nsec, struct meow_time32 *out);
|
||||
/* itimerspec 转换;任一侧越界返回 -1 且 *out 不变。 */
|
||||
int meow_time32_itimerspec_from_64(const struct meow_time64_itimerspec *in,
|
||||
struct meow_itimerspec32 *out);
|
||||
void meow_time64_itimerspec_from_32(const struct meow_itimerspec32 *in,
|
||||
struct meow_time64_itimerspec *out);
|
||||
/* 秒/纳秒 → 单调毫秒的唯一换算点。 */
|
||||
uint64_t meow_time_ms_from_parts(int64_t sec, int64_t nsec);
|
||||
|
||||
/* ---- 内核取时 / 睡眠 ---- */
|
||||
/* 按内核 o32 ABI 取时(clk 用 <time.h> 的 CLOCK_*)。返回 0=成功 / -1=失败(errno)。 */
|
||||
int meow_time32_clock_gettime(int clk, struct meow_time32 *out);
|
||||
/* CLOCK_MONOTONIC 毫秒;失败返回 0。 */
|
||||
uint64_t meow_time32_monotonic_ms(void);
|
||||
/* 睡眠 usec 微秒(EINTR 自动续睡)。返回 0=正常 / -1=失败(errno)。 */
|
||||
int meow_time32_sleep_us(unsigned usec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MEOW_TIME32_H */
|
||||
@@ -1140,6 +1140,9 @@ unsigned long long meow_gfx_overlay_suppressed_count(void) { return g_overlay_su
|
||||
static void present(void)
|
||||
{
|
||||
if (!g_init_ok || !g_back_buf) return;
|
||||
/* M40 F5/P5-P6:launcher 关闭锁屏/菜单前写的「强制整帧重画」请求。必须在脏区早退与
|
||||
* 叠加抑制早退**之前**消费:抑制期只置 dirty_full(标记翻回前台后的下一帧整屏上屏)。 */
|
||||
if (meow_ui_repaint_requested()) dirty_full();
|
||||
if (!(g_dirty_full || g_ndirty > 0)) return;
|
||||
/* §10.5 叠加让位自抑(仅 App 进程):App 前台播放中唤起通知中心时 launcher 不 SIGSTOP
|
||||
* (保 PCM 供流,ncm 播放线程同进程),改由 App 进程在此自抑上屏——绘制照常进 back_buf,
|
||||
|
||||
@@ -169,6 +169,12 @@ unsigned long long meow_gfx_overlay_suppressed_count(void);
|
||||
* 系统 UI(launcher)恒 0;200ms 节流缓存。meow_ui_gfx.c 实现,input 层复用。 */
|
||||
int meow_ui_overlay_suppressed_active(void);
|
||||
|
||||
/* M40 F5/P5-P6:解锁后强制 App 整帧重画。launcher 在 SIGCONT 前写请求文件;present 层
|
||||
* 调用 meow_ui_repaint_requested():文件存在 → 删除并返回 1(调用方 dirty_full 一次)。
|
||||
* 抑制期也消费(dirty_full 保留到标记翻回前台后的下一帧)。实现见 meow_ui_repaint.h
|
||||
* (static inline,宿主单测只 include 头即可,不必链接渲染栈)。 */
|
||||
#include "meow_ui_repaint.h"
|
||||
|
||||
/* 中文/日文字库(mfont)是否已加载(状态栏「蓝牙」CJK 与回退 "BT" 二选一)。 */
|
||||
int meow_gfx_mfont_ready(void);
|
||||
|
||||
@@ -300,42 +306,9 @@ int meow_ime_handle_event(const meow_input_ev *e);
|
||||
/* 当前 IME 是否拼音模式(供 meow_ui_input.c 决定是否喂长按轮询)。 */
|
||||
int meow_ime_mode_pinyin(void);
|
||||
|
||||
/* ---- 时钟(meow_ui_time.c)---- */
|
||||
/* 秒/纳秒 → 单调毫秒的唯一换算点(meow_ui_time_ms 与宿主单测共用)。 */
|
||||
uint64_t meow_time_ms_from_parts(int64_t sec, int64_t nsec);
|
||||
|
||||
/* ---- mipsel o32 的 time32 结构(内核布局,与 libc 头的 time_t 宽度无关)----
|
||||
* 背景:zig clang 给 32 位目标预定义 __ILP32__,打穿 musl 的 time64 回退守卫,
|
||||
* 一批封装把 16 字节 time64 结构直接交给 time32 系统调用(CLOCK_ABI.md §6)。
|
||||
* 接管这些入口时统一走下面这几个纯转换函数——它们不依赖平台,宿主单测直接覆盖。 */
|
||||
struct meow_time32 {
|
||||
int32_t tv_sec;
|
||||
int32_t tv_nsec;
|
||||
};
|
||||
struct meow_itimerspec32 {
|
||||
struct meow_time32 it_interval;
|
||||
struct meow_time32 it_value;
|
||||
};
|
||||
/* 与 libc 结构解耦的 64 位镜像(避免宿主/交叉两端 time_t 宽度差异进测试)。 */
|
||||
struct meow_time64_spec {
|
||||
int64_t tv_sec;
|
||||
int64_t tv_nsec;
|
||||
};
|
||||
struct meow_time64_itimerspec {
|
||||
struct meow_time64_spec it_interval;
|
||||
struct meow_time64_spec it_value;
|
||||
};
|
||||
|
||||
/* 相对超时(futex / poll / select 的「等多久」):sec 超出 int32 时饱和
|
||||
* (正→INT32_MAX、负→INT32_MIN,与 musl CLAMP 一致),nsec 原样。 */
|
||||
void meow_time32_rel_from_parts(int64_t sec, int64_t nsec, struct meow_time32 *out);
|
||||
/* 绝对时刻(clock_settime / timerfd / utimensat):sec 落不进 int32 返回 -1
|
||||
* (调用方回 ENOTSUP,与 musl time64 路径的判定一致),nsec 原样。 */
|
||||
int meow_time32_abs_from_parts(int64_t sec, int64_t nsec, struct meow_time32 *out);
|
||||
/* itimerspec(timerfd / POSIX timer)转换;任一侧越界返回 -1 且 *out 不变。 */
|
||||
int meow_time32_itimerspec_from_64(const struct meow_time64_itimerspec *in,
|
||||
struct meow_itimerspec32 *out);
|
||||
void meow_time64_itimerspec_from_32(const struct meow_itimerspec32 *in,
|
||||
struct meow_time64_itimerspec *out);
|
||||
/* ---- 时钟(meow_ui_time.c + meow_time32.c)----
|
||||
* 换算/内核 time32 取时/睡眠的唯一实现在 meow_time32.c(独立 TU,系统组件可单独链接);
|
||||
* 本头只把它带进来,SDK 内部仍按原名字使用。 */
|
||||
#include "meow_time32.h"
|
||||
|
||||
#endif /* MEOW_UI_INTERNAL_H */
|
||||
@@ -0,0 +1,39 @@
|
||||
/* meow_ui_repaint.h — 解锁后「强制 App 整帧重画」请求文件(M40 F5/P5-P6)。
|
||||
*
|
||||
* 背景:锁屏/电源菜单是整帧不透明覆盖。关闭后 launcher 会恢复它快照的底层帧,但 App
|
||||
* 进程只按自己的脏矩形 present;锁屏期间它可能被 SIGSTOP 冻结,从未观测到
|
||||
* /tmp/meow_notif_active 的抑制态,因此 SDK 的「抑制→恢复」整帧重画边沿不会触发 ——
|
||||
* PIN 帧/菜单帧会残留在屏幕上,直到用户点到某个控件产生新脏区才刷新(真机 P6)。
|
||||
*
|
||||
* 机制:launcher 在 SIGCONT 前写 /tmp/meow_app_repaint;App 的 SDK present 看到文件就
|
||||
* dirty_full() 一次并删除(消费一次即失效)。请求在 present 最前面检查,**抑制期也消费**
|
||||
* (先置 dirty_full,等标记翻回前台后的下一帧整屏上屏),避免排空窗口把请求吃掉后不生效。
|
||||
*
|
||||
* 实现放在头文件里(static inline):present 层(meow_ui_gfx.c)直接调用;宿主单测只
|
||||
* include 本头即可验证写/读/删语义,不必链接整个渲染栈。路径可用 MEOW_APP_REPAINT_FILE
|
||||
* 覆盖(宿主单测隔离;真机无 env 走默认)。
|
||||
*/
|
||||
#ifndef MEOW_UI_REPAINT_H
|
||||
#define MEOW_UI_REPAINT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MEOW_APP_REPAINT_DEFAULT "/tmp/meow_app_repaint"
|
||||
|
||||
static inline const char *meow_ui_repaint_path(void)
|
||||
{
|
||||
const char *e = getenv("MEOW_APP_REPAINT_FILE");
|
||||
return (e && e[0]) ? e : MEOW_APP_REPAINT_DEFAULT;
|
||||
}
|
||||
|
||||
/* 返回 1=消费了一次重画请求(调用方应 dirty_full);0=无请求。 */
|
||||
static inline int meow_ui_repaint_requested(void)
|
||||
{
|
||||
const char *p = meow_ui_repaint_path();
|
||||
if (access(p, F_OK) != 0) return 0;
|
||||
unlink(p); /* 一次性请求:读到即消费,防每帧整帧重画 */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* MEOW_UI_REPAINT_H */
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include "meow_ui.h"
|
||||
#include "meow_ui_internal.h"
|
||||
#include "meow_time32.h"
|
||||
|
||||
#if defined(__mips__) && !defined(__mips64) && (__SIZEOF_LONG__ == 4)
|
||||
#define MEOW_TIME32_KERNEL_ABI 1
|
||||
@@ -54,64 +55,11 @@
|
||||
#define MEOW_TIME32_KERNEL_ABI 0
|
||||
#endif
|
||||
|
||||
/* ---- 平台无关的 time64 → 内核 o32 time32 换算(宿主单测直接覆盖)----
|
||||
* 这几个函数不碰系统调用,只为“结构宽度”这件事提供唯一实现;mips 分支的接管入口
|
||||
* 全部经它们转换,宿主 test_meow_time64.c 用同一份代码验边界。 */
|
||||
void meow_time32_rel_from_parts(int64_t sec, int64_t nsec, struct meow_time32 *out)
|
||||
{
|
||||
if (sec > INT32_MAX) sec = INT32_MAX;
|
||||
else if (sec < INT32_MIN) sec = INT32_MIN;
|
||||
out->tv_sec = (int32_t)sec;
|
||||
out->tv_nsec = (int32_t)nsec;
|
||||
}
|
||||
|
||||
int meow_time32_abs_from_parts(int64_t sec, int64_t nsec, struct meow_time32 *out)
|
||||
{
|
||||
if (sec > INT32_MAX || sec < INT32_MIN) return -1;
|
||||
out->tv_sec = (int32_t)sec;
|
||||
out->tv_nsec = (int32_t)nsec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int meow_time32_itimerspec_from_64(const struct meow_time64_itimerspec *in,
|
||||
struct meow_itimerspec32 *out)
|
||||
{
|
||||
struct meow_itimerspec32 t;
|
||||
if (meow_time32_abs_from_parts(in->it_interval.tv_sec, in->it_interval.tv_nsec,
|
||||
&t.it_interval)) return -1;
|
||||
if (meow_time32_abs_from_parts(in->it_value.tv_sec, in->it_value.tv_nsec,
|
||||
&t.it_value)) return -1;
|
||||
*out = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void meow_time64_itimerspec_from_32(const struct meow_itimerspec32 *in,
|
||||
struct meow_time64_itimerspec *out)
|
||||
{
|
||||
out->it_interval.tv_sec = in->it_interval.tv_sec;
|
||||
out->it_interval.tv_nsec = in->it_interval.tv_nsec;
|
||||
out->it_value.tv_sec = in->it_value.tv_sec;
|
||||
out->it_value.tv_nsec = in->it_value.tv_nsec;
|
||||
}
|
||||
|
||||
uint64_t meow_time_ms_from_parts(int64_t sec, int64_t nsec)
|
||||
{
|
||||
return (uint64_t)sec * 1000u + (uint64_t)nsec / 1000000u;
|
||||
}
|
||||
|
||||
/* 换算/取时的唯一实现已抽到 meow_time32.c(不依赖 SDK,系统组件可单独链接)。
|
||||
* 本 TU 只保留「libc 入口接管」与 futex/timerfd/clock_settime 的 time64 修复。 */
|
||||
uint64_t meow_ui_time_ms(void)
|
||||
{
|
||||
#if MEOW_TIME32_KERNEL_ABI
|
||||
struct meow_time32 t;
|
||||
t.tv_sec = 0;
|
||||
t.tv_nsec = 0;
|
||||
if (syscall(SYS_clock_gettime32, CLOCK_MONOTONIC, &t) != 0) return 0;
|
||||
return meow_time_ms_from_parts(t.tv_sec, t.tv_nsec);
|
||||
#else
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0;
|
||||
return meow_time_ms_from_parts((int64_t)ts.tv_sec, (int64_t)ts.tv_nsec);
|
||||
#endif
|
||||
return meow_time32_monotonic_ms();
|
||||
}
|
||||
|
||||
#if MEOW_TIME32_KERNEL_ABI
|
||||
@@ -134,9 +82,7 @@ int __clock_gettime(clockid_t clk, struct timespec *ts)
|
||||
{
|
||||
struct meow_time32 t;
|
||||
if (!ts) { errno = EFAULT; return -1; }
|
||||
t.tv_sec = 0;
|
||||
t.tv_nsec = 0;
|
||||
if (syscall(SYS_clock_gettime32, clk, &t) != 0) return -1;
|
||||
if (meow_time32_clock_gettime(clk, &t) != 0) return -1;
|
||||
ts->tv_sec = t.tv_sec;
|
||||
ts->tv_nsec = t.tv_nsec;
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* test_meow_repaint.c — M40 F5:解锁后「强制 App 整帧重画」请求文件的写/读/删除语义。
|
||||
*
|
||||
* 编译(patch_v2/sdk 下):
|
||||
* gcc -Wall -Wextra -I. test_meow_repaint.c -o test_meow_repaint
|
||||
* 运行:./test_meow_repaint (exit 0=PASS)
|
||||
*
|
||||
* 语义:launcher 写文件 → SDK present 调 meow_ui_repaint_requested() 读到即删并返回 1
|
||||
* (dirty_full 一次);文件不存在返回 0。路径可用 MEOW_APP_REPAINT_FILE 覆盖(测试隔离)。
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "meow_ui_repaint.h"
|
||||
|
||||
static int g_fail = 0;
|
||||
|
||||
static void check(const char *name, int ok)
|
||||
{
|
||||
if (ok) {
|
||||
printf("ok %s\n", name);
|
||||
} else {
|
||||
printf("FAIL %s\n", name);
|
||||
g_fail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int write_file(const char *path)
|
||||
{
|
||||
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) return -1;
|
||||
if (write(fd, "1", 1) != 1) { close(fd); return -1; }
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *tmp = getenv("TMPDIR");
|
||||
char path[512];
|
||||
snprintf(path, sizeof path, "%s/m40_repaint_XXXXXX", (tmp && tmp[0]) ? tmp : "/tmp");
|
||||
int fd = mkstemp(path);
|
||||
if (fd < 0) { perror("mkstemp"); return 2; }
|
||||
close(fd);
|
||||
unlink(path); /* 先清空,测试从「无请求」开始 */
|
||||
|
||||
setenv("MEOW_APP_REPAINT_FILE", path, 1);
|
||||
check("path follows env", !strcmp(meow_ui_repaint_path(), path));
|
||||
|
||||
check("no request file -> 0", meow_ui_repaint_requested() == 0);
|
||||
|
||||
check("write request", write_file(path) == 0);
|
||||
check("request present", access(path, F_OK) == 0);
|
||||
check("first check consumes -> 1", meow_ui_repaint_requested() == 1);
|
||||
check("file deleted after consume", access(path, F_OK) != 0);
|
||||
check("second check -> 0 (one-shot)", meow_ui_repaint_requested() == 0);
|
||||
|
||||
/* 再写一次仍能消费(launcher 每次解锁/菜单关闭都会写) */
|
||||
check("write again", write_file(path) == 0);
|
||||
check("consume again -> 1", meow_ui_repaint_requested() == 1);
|
||||
|
||||
unlink(path);
|
||||
printf("\n%s\n", g_fail ? "SOME TESTS FAILED" : "ALL PASS");
|
||||
return g_fail ? 1 : 0;
|
||||
}
|
||||
@@ -7,7 +7,9 @@
|
||||
*
|
||||
* 编译(patch_v2/sdk 目录下):
|
||||
* gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o /tmp/meow_ui_time.o
|
||||
* gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time.c /tmp/meow_ui_time.o -o test_meow_time
|
||||
* gcc -Os -Wall -Wextra -I. -Iinclude -c meow_time32.c -o /tmp/meow_time32.o
|
||||
* gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time.c /tmp/meow_ui_time.o /tmp/meow_time32.o \
|
||||
* -o test_meow_time
|
||||
* 运行:./test_meow_time (exit 0=PASS / 1=FAIL)
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
*
|
||||
* 编译(patch_v2/sdk 目录下):
|
||||
* gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o /tmp/meow_ui_time.o
|
||||
* gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time64.c /tmp/meow_ui_time.o \
|
||||
* gcc -Os -Wall -Wextra -I. -Iinclude -c meow_time32.c -o /tmp/meow_time32.o
|
||||
* gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time64.c /tmp/meow_ui_time.o /tmp/meow_time32.o \
|
||||
* -o test_meow_time64
|
||||
* 运行:./test_meow_time64 (exit 0=PASS / 1=FAIL)
|
||||
*/
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
|
||||
# ---- 用户态/服务守护二进制(usr/bin,全部 chmod 755 静态 MIPS)----
|
||||
patch_v2/bootmenu/meow_bootmenu|/usr/bin/meow_bootmenu|4441822d87e76bfce2ce584604ac3830|引导选单 M6.25(开机菜单/第二屏亮度按用户设置恢复:显示前读 settings.conf 写回,方案A)
|
||||
patch_v2/meow_launcherd/meow_launcherd|/usr/bin/meow_launcherd|e342d24fa9fd878c840e5b3e918cfbdf|M39 点击输入门(launcher 触摸守卫 1200ms→drain+MENU_TOUCH_GUARD_MS 150ms(App退出)/800ms×6(子页返回)/300ms×8(菜单/子页打开)统一收窄,drain 同时复位 t_down/原点防幽灵抬手重放;SDK meow_ui_run 500ms 全量吞窗→启动 meow_input_drain 一次+TAP/TOUCH_DOWN/MOVE/LONG_PRESS 不再按时间吞,仅系统手势(SWIPE/HOME/NOTIF_PULL/SWIPE_PROGRESS)保留 150ms 防穿透), 链 meow_ui.a 8525aa6b;继承 M6.46 编入杀后台修复(M7:bgmgr_can_kill 门控 framework→protected_app+后台页 sub 指针持久化(悬垂修正)+am kill 走 meow_bg_terminate 与页面按钮同通道)+SDK 时钟 ABI 修复(M11:meow_ui_time 按 o32 time32 取时并链接期接管, 旧链 meow_ui.a 4c4a1554);继承M6.41 收编启动失败原因透传(subpage_t/meow_launcher_internal启动失败原因)+后台管理按钮点不动修复(bg_page)+主菜单字体/样式微调;继承M6.40(系统级音量翻页映射+P1 MD3 select面板28/对话框按钮胶囊)+M6.39(SDK LazyGrid/LazyColumn/LazyRow MD3容器化+SDK全局App内底部上滑回桌面)+M6.38(批②上滑回桌面+SDK对话框MD3细化+UI微调+空artwork)+M6.37(SDK默认列表MD3容器化)+M6.36(批①叠加/穿透根治+MD3全面对齐+后台图标/圆角卡+批①后台常驻框架+批③后台管理页+i18n);链meow_ui.a(sdk meow_lyric/lyric_view/meow_img_color,meow_img_pixels访问器);0warning
|
||||
patch_v2/meow_watchdog/meow_watchdog|/usr/bin/meow_watchdog|ad8c1f2bfe5481d2069466e22d5e1cf6|应用看门狗(亮屏亮度按 settings 恢复,四支决策不再回退固定 60;M6.23 源码修复首次真正编入固件)
|
||||
patch_v2/meow_launcherd/meow_launcherd|/usr/bin/meow_launcherd|605e13a9d154d179f4131e0c5e85c90f|M40 电源键/锁屏链修复(App 前台电源菜单补齐 §10.5:notif 全抑制+帧恢复+SIGCONT 排空+标记翻回,关闭后不再停留菜单画面;show_power_menu 恢复进入前背景帧+重绘挪到首轮按键采样后;activity 标记排空窗+会话入口清理+manual_off 去单向闩锁;锁屏电源改按下边沿+进场 300ms,熄屏退出也恢复底层帧;SIGCONT 前写 /tmp/meow_app_repaint), 链 meow_ui.a 86800633;继承 M39 点击输入门(M39 触摸守卫/MENU_TOUCH_GUARD_MS 150ms + SDK 启动排空);继承 M6.46 杀后台修复+SDK 时钟 ABI 修复(M11/M40);0warning
|
||||
patch_v2/meow_watchdog/meow_watchdog|/usr/bin/meow_watchdog|37c57e0feb9cd220978bfd5deff75a1f|应用看门狗 M40:o32 time32 取时/睡眠(修 held 天文数字→单击误判长按)、电源阈值读 power.longpress_menu_ms/forceoff_ms(缺省 3000/8000,与 launcher 主屏统一);继承 M20 亮屏亮度按 settings 恢复(四支决策不再回退固定 60)
|
||||
patch_v2/meow_svcd/meow_svcd|/usr/bin/meow_svcd|605646c4cc93f2baf29071ea6bc870ea|服务管理器 M2.77(+崩溃上报 meow_crash agent-187)
|
||||
mips-repo/bins/meow_mdns/bin/meow_mdns|/usr/bin/meow_mdns|d6b0151bda26768f19952dae1342610d|mDNS 应答器 M2.78(启动竞态+换IP重检 agent-194)
|
||||
patch_v2/meow_sysui/meow_sysui|/usr/bin/meow_sysui|173013cc8f0899b3001d0b894ac0d9e6|系统 UI(sysui)
|
||||
|
||||
Reference in new issue
Block a user