息屏自动唤醒亮屏方案讨论
背景: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 可以在特定条件下(如连接到信任的蓝牙设备、位于信任的地理位置)自动跳过锁屏。
做法:
- 用户在手机设置中开启 Smart Lock
- 添加信任条件(如连接到家里 Wi-Fi、信任的蓝牙手表/耳机)
- 当条件满足时,
input keyevent 26点亮屏幕后自动解锁
限制:
- 需要用户手动配置
- 安全性降低
- 如果条件不满足,仍然卡在锁屏
适用条件:用户愿意配置 Smart Lock,且有稳定的信任条件
可行性:⭐⭐⭐ 依赖用户配置
三、更深层的分析:亮屏后发送就一定成功吗?
3.1 当前 Frida 测试结果告诉我们什么?
我们在亮屏状态下调用 u01.m1.a(),返回 true,但 DB 中没有新消息。
这说明:
- 调用链可能本身就是错的 —
m1.a()不是真正发送消息的方法 - 或者,微信内部需要额外的初始化步骤
关键推论:即使我们通过某种方式让屏幕亮了,如果调用链不正确,发送仍然失败。
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 前台服务 + 通知监听(折中方案)
原理:
- Termux 运行在前台服务模式(显示一个常驻通知)
- 前台服务不受 Doze 限制,可以持续运行
- 收到微信通知时,通过
input keyevent 26唤醒屏幕 - 如果手机无密码/Smart Lock,微信启动后自动前台
- 发送消息
关键条件:
- 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); // 启动微信
}
六、结论与下一步
核心结论
- 息屏限制是真实存在的:Android 15 的 Doze + 后台启动限制确实会阻止消息发送
- 但当前更大的问题是调用链:亮屏状态下
u01.m1.a()也不工作,说明不是单纯的息屏问题 - 自动亮屏技术上可行:
input keyevent 26已验证可用,但解锁是瓶颈 - 优先级应该是:
- P0:用 Frida 测试
q1.b()和q1.d(),找到真正发送方法 - P1:确认亮屏+前台状态下能否稳定发送
- P2:解决息屏唤醒(根据用户锁屏配置选择方案 A/B/F/E)
- P0:用 Frida 测试
建议用户决策
| 你的手机状态 | 推荐方案 | 实施难度 |
|---|---|---|
| 无密码 / Swipe only | 方案 A + B:唤醒 + 滑动解锁 | 低 |
| 有密码,可开 Smart Lock | 方案 F:Smart Lock 自动解锁 | 中(需配置) |
| 有密码,不能开 Smart Lock | 方案 1(双路径):前台实时发,息屏缓存延迟发 | 中 |
| 长期插电放在桌上 | 方案 E:屏幕常亮 | 低(但耗电) |
七、待确认问题(需要用户回答)
你的 Pixel 10 Fold 有设置锁屏密码/PIN/指纹吗?
- 如果有,能否开启 Smart Lock?
手机通常是放在桌上插电,还是随身携带?
- 这影响"屏幕常亮"方案的可行性
对回复延迟的容忍度如何?
- 是否接受息屏时延迟到下次解锁才发送?
是否愿意安装 Termux:API 并保持其前台服务运行?
- 这可以绕过部分后台限制
根据你的回答,我可以给出最精准的实施方案。