screen-auto-wake-proposal.md 11 KB

息屏自动唤醒亮屏方案讨论

背景:Pixel 10 Pro Fold (Android 15) 息屏状态下微信消息发送失败 核心问题:息屏是否必然导致发送失败?能否通过"自动亮屏"绕过限制? 时间:2026-05-23


一、为什么息屏会导致发送失败?(Android 15 限制分析)

1.1 息屏 ≠ 只是屏幕变黑

Android 15 在息屏时会同时激活多层限制:

用户按下电源键 / 超时息屏
    │
    ├──→ Display OFF(屏幕关闭)
    │
    ├──→ Keyguard ON(锁屏界面激活,若有密码需解锁)
    │
    ├──→ Doze Mode(浅睡眠,限制网络/闹钟/JobScheduler)
    │       └── 进入 doze 后:网络批量处理、闹钟延迟、wakelock 忽略
    │
    ├──→ App Standby(应用待机桶,限制后台活动)
    │       └── 微信可能被分到 RARE/RESTRICTED 桶
    │
    └──→ Background Activity Launch 限制
            └── 后台应用(包括通过 su 启动的)禁止启动 Activity

1.2 我们遇到的限制层级

层级 当前是否受影响 说明
屏幕关闭 ✅ 是 am start 不执行,需要 input keyevent 26 点亮
锁屏界面 ⚠️ 未知 Pixel 是否有密码/指纹?亮屏后是否卡在 Keyguard?
Doze 模式 ⚠️ 可能 即使亮屏,Doze 可能仍在运行,限制网络调度
后台启动限制 ⚠️ 可能 Termux 通过 su 执行命令,但微信进程本身不是前台
NetScene 队列冻结 ⚠️ 可能 微信内部可能在息屏时暂停消息发送队列

关键结论:即使屏幕亮了,如果 Doze 仍在运行、或微信 NetSceneDispatcher 未恢复,发送仍可能失败。


二、自动唤醒亮屏的技术方案(6 种)

方案 A:模拟电源键点亮(已部分实现)

做法:

input keyevent 26      # 模拟电源键,Toggle 屏幕开关

限制:

  • 只点亮屏幕,不解锁锁屏界面
  • 如果手机有 PIN/密码/指纹,会卡在 Keyguard
  • Doze 模式不会退出(需要传感器运动或插拔充电)

适用条件:手机无密码(Swipe only)或 Smart Lock 已信任当前位置/设备

可行性:⭐⭐⭐ 部分可行


方案 B:模拟滑动手势解锁

做法:

# 先点亮
input keyevent 26
sleep 300ms
# 模拟从底部向上滑解锁(无密码时)
input swipe 500 1200 500 500 300

限制:

  • 仅适用于无密码的 Swipe 解锁
  • 有 PIN/密码/图案/指纹时完全无效
  • 不同手机分辨率不同,滑动坐标需适配

适用条件:手机未设置任何安全锁屏

可行性:⭐⭐ 受限极大


方案 C:发送高优先级通知唤醒

原理:Android 允许某些通知唤醒屏幕(如来电、闹钟)

做法:

# 通过 termux-notification 发送一个 IMPORTANCE_HIGH 通知
# 并设置唤醒屏幕标志

限制:

  • 需要 termux-api 应用及后台服务运行
  • Android 15 对通知唤醒屏幕有严格限制,通常只有电话/闹钟应用可以做到
  • 用户需在设置中允许 Termux "唤醒屏幕"

适用条件:用户手动授权 + Termux API 常驻

可行性:⭐⭐ 不可靠


方案 D:通过 AlarmManager / 精确闹钟触发

原理:设置一个精确闹钟,闹钟触发时系统会短暂退出 Doze,允许应用执行操作

做法:

# 通过 termux 的脚本或 Android 应用设置 AlarmManager
# 触发时执行发送逻辑

限制:

  • 闹钟只能唤醒自己的应用,不能直接唤醒微信
  • 闹钟触发时屏幕不一定亮
  • Android 15 需要 SCHEDULE_EXACT_ALARM 权限

适用条件:仅适用于定时任务,不适用于实时消息回复

可行性:⭐ 不适合实时回复场景


方案 E:保持屏幕常亮( prevention 而非 cure )

原理:不让手机息屏,从根本上避免问题

做法:

# 方法 1:修改系统设置(需要 root)
su -c "settings put system screen_off_timeout 2147483647"

# 方法 2:使用 WakeLock(需要应用支持)
# Termux 中运行 termux-wake-lock(但这只保持 CPU,不关屏幕)

# 方法 3:充电时保持亮屏(设置中 Developer Options)

限制:

  • 耗电严重
  • OLED 屏幕可能烧屏
  • 用户接受度低
  • 如果手机在口袋里,误触问题

适用条件:设备长期插电使用,且用户接受屏幕常亮

可行性:⭐⭐⭐ 技术可行,但体验差


方案 F:利用 Smart Lock / 信任设备自动解锁

原理:Android Smart Lock 可以在特定条件下(如连接到信任的蓝牙设备、位于信任的地理位置)自动跳过锁屏。

做法:

  1. 用户在手机设置中开启 Smart Lock
  2. 添加信任条件(如连接到家里 Wi-Fi、信任的蓝牙手表/耳机)
  3. 当条件满足时,input keyevent 26 点亮屏幕后自动解锁

限制:

  • 需要用户手动配置
  • 安全性降低
  • 如果条件不满足,仍然卡在锁屏

适用条件:用户愿意配置 Smart Lock,且有稳定的信任条件

可行性:⭐⭐⭐ 依赖用户配置


三、更深层的分析:亮屏后发送就一定成功吗?

3.1 当前 Frida 测试结果告诉我们什么?

我们在亮屏状态下调用 u01.m1.a(),返回 true,但 DB 中没有新消息。

这说明:

  1. 调用链可能本身就是错的 — m1.a() 不是真正发送消息的方法
  2. 或者,微信内部需要额外的初始化步骤

关键推论:即使我们通过某种方式让屏幕亮了,如果调用链不正确,发送仍然失败。

3.2 需要先解决"亮屏发送",再解决"息屏唤醒"

当前问题的优先级应该是:

P0: 亮屏 + 微信前台 → 能否成功发送?(Frida 测试 q1.b() / d())
    │
    ├──→ 如果亮屏也失败:调用链有问题,与息屏无关
    │
    └──→ 如果亮屏成功:再解决息屏限制
            │
            ├──→ 方案 A/B/F:自动亮屏+解锁
            └──→ 方案 E:保持常亮

四、综合方案推荐

方案 1:双路径发送(推荐)

消息检测(sqlcipher 轮询 / 通知监听)
    │
    ├──→ 检测到微信在前台 ──→ 直接调用发送 API
    │
    └──→ 检测到息屏 ────────→ input keyevent 26 唤醒
                                │
                                ├──→ 无密码 / Smart Lock ──→ 自动解锁
                                │                            └──→ 微信前台 → 发送
                                │
                                └──→ 有密码且未 Smart Lock ──→ 发送失败,记录待发送队列
                                                                   │
                                                                   └──→ 下次用户解锁时批量发送

优点:

  • 前台时实时发送
  • 息屏时尝试唤醒,成功则发,失败则缓存
  • 不丢失消息

缺点:

  • 息屏时回复有延迟(需等用户下次解锁)
  • 需要维护待发送队列

方案 2:保持微信前台常驻(激进方案)

# 1. 设置屏幕常亮(root)
su -c "settings put system screen_off_timeout 2147483647"

# 2. 微信保持在 LauncherUI 前台
# 3. 使用 termux-wake-lock 防止 CPU 休眠

配合硬件:

  • 手机长期连接充电器
  • 降低屏幕亮度到最低
  • 使用 OLED 黑色主题减少烧屏

优点:

  • 完全绕过息屏限制
  • 发送实时性最好

缺点:

  • 耗电
  • 烧屏风险
  • 用户体验差(手机一直亮着)

方案 3:Termux 前台服务 + 通知监听(折中方案)

原理:

  1. Termux 运行在前台服务模式(显示一个常驻通知)
  2. 前台服务不受 Doze 限制,可以持续运行
  3. 收到微信通知时,通过 input keyevent 26 唤醒屏幕
  4. 如果手机无密码/Smart Lock,微信启动后自动前台
  5. 发送消息

关键条件:

  • Termux 需要在前台服务模式下运行
  • 手机不能有密码锁,或已配置 Smart Lock

五、针对 Pixel 10 Pro Fold 的具体建议

5.1 先确认锁屏状态

# 检查当前 Keyguard 状态
adb shell dumpsys window | grep -i "keyguard"
# 或
adb shell dumpsys deviceidle | grep -i "screen"

输出分析:

  • mDreamingLockscreen=true → 有锁屏界面
  • mInputRestricted=true → 需要解锁才能操作

5.2 如果手机有密码

路径 1:建议用户开启 Smart Lock

  • 设置 → 安全 → Smart Lock → 信任的地点/设备
  • 添加家里位置或连接的蓝牙耳机

路径 2:使用 ADB + 电脑保持连接

  • 电脑端运行 adb shell svc power stayon usb
  • 手机连接电脑时屏幕常亮
  • 但这要求电脑一直在旁边

路径 3:接受延迟回复

  • 息屏时缓存回复到队列
  • 用户下次解锁手机时自动发送队列中的消息

5.3 如果手机无密码

直接实现方案 A + B:

async function wakeAndUnlock() {
    await shell('input keyevent 26', 3000);     // 点亮
    await sleep(500);
    await shell('input swipe 500 1200 500 500 300', 3000); // 上滑解锁
    await sleep(300);
    await shell('am start -n com.tencent.mm/.ui.LauncherUI', 5000); // 启动微信
}

六、结论与下一步

核心结论

  1. 息屏限制是真实存在的:Android 15 的 Doze + 后台启动限制确实会阻止消息发送
  2. 但当前更大的问题是调用链:亮屏状态下 u01.m1.a() 也不工作,说明不是单纯的息屏问题
  3. 自动亮屏技术上可行:input keyevent 26 已验证可用,但解锁是瓶颈
  4. 优先级应该是:
    • P0:用 Frida 测试 q1.b() 和 q1.d(),找到真正发送方法
    • P1:确认亮屏+前台状态下能否稳定发送
    • P2:解决息屏唤醒(根据用户锁屏配置选择方案 A/B/F/E)

建议用户决策

你的手机状态 推荐方案 实施难度
无密码 / Swipe only 方案 A + B:唤醒 + 滑动解锁 低
有密码,可开 Smart Lock 方案 F:Smart Lock 自动解锁 中(需配置)
有密码,不能开 Smart Lock 方案 1(双路径):前台实时发,息屏缓存延迟发 中
长期插电放在桌上 方案 E:屏幕常亮 低(但耗电)

七、待确认问题(需要用户回答)

  1. 你的 Pixel 10 Fold 有设置锁屏密码/PIN/指纹吗?

    • 如果有,能否开启 Smart Lock?
  2. 手机通常是放在桌上插电,还是随身携带?

    • 这影响"屏幕常亮"方案的可行性
  3. 对回复延迟的容忍度如何?

    • 是否接受息屏时延迟到下次解锁才发送?
  4. 是否愿意安装 Termux:API 并保持其前台服务运行?

    • 这可以绕过部分后台限制

根据你的回答,我可以给出最精准的实施方案。