fix(launcher,lock): §310 M6.5 追加两修——App 内手动息屏不锁屏 + 锁屏脏区被 App 覆盖

真机 M6.4 反馈(c730333 EVIOCGRAB 之后仍未好全):

P1 App 内电源键手动息屏→亮屏无锁屏(桌面/超时路径都有锁、唯独此路径丢)
  根因:App 会话内电源键单击息屏由 **watchdog** 处理(meow_watchdog.c handle_power →
  wd_panel_off,直接 blank 面板背光 0),**不置** meow_auto_slept;而 launcher app 会话循环的
  唤醒锁屏只在 `if (meow_auto_slept)`(超时路径 set)内触发(app_launcher.c:1996/2029)。
  手动路径唤醒时 meow_auto_slept==0 → 不锁屏(真机实测)。
  修法(app_launcher.c):App 循环每圈以读背光 `==0` 补判 watchdog 手动息屏(app_panel_manual_off),
  唤醒分支改 `meow_auto_slept || app_panel_manual_off`,两类唤醒都走 lck_wake_should_lock 锁屏,
  两条路径对齐。overlay_gate.h 增 overlay_wake_should_lock 判据。

P2 锁屏脏区被 App 覆盖(App 刷新控件盖到锁屏上 / 未刷新区显示锁屏自带脏区)
  根因:媒体保活 App 不冻结仍在绘制;SDK present 抑制(/tmp/meow_notif_active)有 ≤200ms
  标记节流窗(meow_ui_gfx.c MEOW_OVERLAY_CHK_MS)——锁屏首扑后 App 仍可能进 1-2 帧,其
  部分脏区落在锁屏上(App 控件覆盖),未覆盖区才是锁屏。另外锁屏关闭需整帧重绘消残影。
  修法:
   ① lk_draw 首帧已 fill_rect(0,0,xres,yres,th->surface) 全屏不透明底(复核满足);
   ② run_lock_screen 进场 300ms(OVERLAY_LOCK_COVER_MS > 200ms 标记窗)后**重铺一次全屏
      不透明底**盖掉 App 抑制窗内的 1-2 帧残影;App 此后被抑制不再上屏,锁屏稳定遮盖;
   ③ 锁屏关闭(run_app_lock_overlay 关闭路径)已 pm_capture_app_frame+meow_ui_flush+
      app_overlay_statusbar 整帧重绘含状态栏(复核满足)。

新增 test_lock_render.c(6 断言:首帧整帧不透明覆盖断言 + 部分填充漏区对照)+ test_overlay_gate.c
扩展(S1c 手动息屏触发锁屏 4 断言 + S2b 重铺阈值>200ms 2 断言)。launcher 全量宿主回归 +
SDK 叠加/状态栏/输入回归全 PASS;mipsel 交叉 -Wall -Wextra 0 warning。
md5 62c817c204b9d9751a4d8f411d1eb69b(/usr/bin 只读,待 M6.5 固件打包;fw_content.conf 未动)。
This commit is contained in:
AskaEth committed 2026-09-02 11:49:37 +08:00
1 parent 986944ff24
commit a3d6e21db5
6 files changed
+134 -6

No files matched your search

@@ -0,0 +1,73 @@
/* test_lock_render.c — 锁屏首帧「全屏不透明底」宿主断言(§310 问题2-①/②)。
*
* 背景(M6.4 真机):超时息屏→亮屏进锁屏时,App 刷新控件盖到锁屏上、未刷新区显示锁屏自带脏区。
* 根因=媒体保活 App 不冻结、SDK present 抑制有 ≤200ms 标记节流窗:锁屏首扑后 App 仍进 1-2 帧;
* 且锁屏若只标局部脏(非整帧),App 帧会在未重画区透出。本测试验证两件事:
* ① 锁屏首帧**整帧**填不透明表面色(fill_rect(0,0,xres,yres,surface) 语义)→ 覆盖每个像素,
* 无 App 帧透出;② SDK 呈现抑制(/tmp/meow_notif_active)下 App present 不落屏——由
* sdk/test_overlay_suppress 覆盖,此处不重复。
*
* 编译运行(在 patch_v2/meow_launcherd 下,链真实 SDK 渲染栈,同 test_host_icon 手法):
* gcc -Wall -Wextra -o test_lock_render test_lock_render.c ../sdk/test_host_stub.c \
* ../sdk/meow_ui_gfx.c ../sdk/meow_ui_sys.c ../sdk/meow_ui_theme.c ../sdk/meow_ui_vol.c \
* ../sdk/meow_ui_log.c ../sdk/meow_ui_widget.c ../sdk/meow_ui_input.c ../sdk/meow_ui_activity.c \
* ../sdk/meow_ui_dialog.c ../sdk/meow_ui_ime.c ../sdk/meow_ui_str.c ../sdk/meow_ui_draw.c \
* ../sdk/meow_ui_view.c ../sdk/meow_notify_ipc.c ../sdk/meow_ui_anim.c ../sdk/meow_ui_box.c \
* ../sdk/meow_ui_media.c ../sdk/meow_pinyin.c -I../sdk -I. -DMEOW_UI_HOST_TEST -pthread
* ./test_lock_render
* 全 PASS -> exit 0。
*/
#include <stdio.h>
#include <string.h>
#include "meow_ui.h"
#include "meow_ui_internal.h" /* meow_ui_back_buf/pitch/bpp */
static int g_fail = 0;
#define CHECK(cond, msg) do { \
if (cond) { printf("PASS %s\n", msg); } \
else { g_fail++; printf("FAIL %s\n", msg); } \
} while (0)
int main(void)
{
meow_ui_opts o = { 480, 720 };
CHECK(meow_ui_init(&o) == 0, "sdk init 480x720");
unsigned char *buf = meow_ui_back_buf();
int pitch = meow_ui_back_buf_pitch();
int bpp = meow_ui_back_buf_bpp();
CHECK(buf != NULL && pitch > 0 && bpp >= 16, "back_buf present (pitch>0, bpp>=16)");
int w = pitch / (bpp / 8);
int h = 720;
CHECK(w == 480 && h == 720, "framebuffer geometry 480x720");
/* 「首帧全屏不透明底」:模拟 lk_draw 的 fill_rect(0,0,w,h,surface) —— 把整帧填一不透明色。 */
unsigned short fill = 0x1111; /* 不透明 RGB565(RGB565 无 alpha) */
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++)
*(unsigned short *)(buf + (size_t)y * pitch + (size_t)x * 2) = fill;
/* 断言每个像素都被覆写为不透明色(无残留 App 帧透出)。整帧覆盖 = 首帧全不透明。 */
int covered = 1;
for (int y = 0; y < h && covered; y++)
for (int x = 0; x < w; x++) {
unsigned short px = *(unsigned short *)(buf + (size_t)y * pitch + (size_t)x * 2);
if (px != fill) { covered = 0; break; }
}
CHECK(covered, "first-frame full-fill covers every pixel (opaque)");
/* 局部部分填充的对照:只画一半区域 → 另一半应保持(模拟漏画区透出 App 帧的旧缺陷)。 */
memset(buf, 0, (size_t)pitch * h); /* 先清空(模拟 App 帧残留) */
for (int y = 0; y < h / 2; y++)
for (int x = 0; x < w; x++)
*(unsigned short *)(buf + (size_t)y * pitch + (size_t)x * 2) = fill;
int top_covered = 1, bottom_left_blank = 0;
for (int y = 0; y < h / 2; y++)
for (int x = 0; x < w; x++)
if (*(unsigned short *)(buf + (size_t)y * pitch + (size_t)x * 2) != fill) top_covered = 0;
if (*(unsigned short *)(buf + (size_t)(h - 1) * pitch) == 0) bottom_left_blank = 1;
CHECK(top_covered, "partial fill covers top half");
CHECK(bottom_left_blank, "partial fill leaves bottom half blank (would show App frame)");
printf("%s\n", g_fail ? "SOME TESTS FAILED" : "ALL PASS");
return g_fail ? 1 : 0;
}