背景
希望 OpenLess 在 Android 上实现类似李跳跳、闹钟类应用的后台工作能力:用户在 OpenLess 可见时启动听写后,即使关闭 Activity、按 Home,甚至在部分设备上划掉最近任务,录音/悬浮入口仍能尽量继续工作;如果进程确实被系统回收,也应能恢复或安全收尾。
这里的目标不是绕过 Android 的 force-stop、Android 13+ Task Manager Stop 或厂商的强制冻结,而是采用 Android 官方支持的系统托管机制,并让进程死亡后可恢复。
调研结论
1. 不建议复制 Shizuku 的保活方式
Shizuku 的 shizuku_server 是由 ADB UID 2000 或 root UID 0 通过 app_process 启动的独立进程。管理器 Activity 被划掉,并不等于该独立进程被杀掉。
普通 OpenLess APK 无法复制这个身份。连接 Shizuku 可以提供特权 Binder/ UserService 能力,但不会改变 OpenLess 主进程的 UID、前台服务生命周期或麦克风权限,也不适合承载完整 Tauri/WebView/Core。
参考:
2. 李跳跳的核心参考价值是 AccessibilityService
李跳跳的公开资料和仿制项目能够确认的核心机制是 AccessibilityService:用户在系统设置中启用服务后,由 Android 系统绑定并在后台分发界面事件。它不是 Root/ADB,也不是普通 Activity 常驻。
这类服务仍然受用户关闭无障碍、force-stop、低内存和厂商后台策略影响;“前台服务、锁定任务卡片、关闭电池优化、自启动白名单”等属于增强兼容性的组合措施,不是永久保活保证。
参考:
3. 闹钟类应用不是一直保持进程
闹钟应用通常采用:
AlarmManager.setAlarmClock()
-> 系统到点唤醒 BroadcastReceiver
-> 启动前台服务
-> 播放声音/振动/显示通知或锁屏界面
应用在两个闹钟之间可以完全不运行。setAlarmClock() 能够在 Doze 中唤醒,但不是常驻心跳;重启后还需要重新注册,force-stop 后也不能保证继续触发。
开源参考:
OpenLess 当前状态与缺口
android/kotlin/OpenLessAccessibilityService.kt 已经是系统绑定的无障碍入口,并且 Manifest 使用了独立的 :accessibility 进程。
OpenLessApplication.kt 在 Activity 进入后台时显示 Overlay,但当前 ACTION_SHOW 使用普通 startService;Overlay Service 只有录音时才提升为 microphone Foreground Service。
OpenLessOverlayService.kt 返回 START_STICKY,但没有 onTaskRemoved();系统重建时的 null Intent 也没有恢复会话逻辑。
- Overlay Service 默认与 Tauri 主进程同进程。
src-tauri/src/mobile_runtime.rs 只在 Tauri setup 中初始化 Core,src-tauri/src/android/native_bridge.rs 的 CORE_BACKEND 也是进程内 OnceLock,因此冷启动 Overlay/独立进程时不能直接假设 Rust Core 已存在。
crates/openless-core/src/external_audio.rs 已有外部 PCM 输入和录音归档抽象,可以作为 Android 原生录音服务与 Core 之间的适配基础,但目前 session 主要仍在内存中。
- 当前没有用于后台恢复的持久 session journal、BOOT_COMPLETED reschedule 或 headless Android 录音入口。
最可行的方案
阶段 1:用户可见启动的 microphone Foreground Service
- 用户在 Activity 可见时点击开始听写。
- 立即启动/提升 Android microphone Foreground Service,并显示持续通知。
- 前台服务负责录音生命周期和悬浮控制;Tauri/WebView 只负责 UI 与配置。
onStartCommand(null)、Service 重建、录音结束、取消、ASR 失败都必须有明确状态转换和清理逻辑。
- 不从
BOOT_COMPLETED 自动启动麦克风;Android 14+ 对这类启动有明确限制。
Android 官方限制:
- Android 12+ 限制后台启动 Foreground Service;
- Android 14+ microphone FGS 需要
RECORD_AUDIO、FOREGROUND_SERVICE_MICROPHONE,且通常必须在 Activity 可见时启动;
- Foreground Service 也不能绕过 Task Manager Stop、force-stop 或厂商杀进程。
参考:https://developer.android.com/develop/background-work/services/fgs/restrictions-bg-start
阶段 2:持久化 session,做到“被杀后可恢复”
- 将
RECORDING / FINALIZING / ORPHANED / COMPLETED 等状态写入 App 私有存储。
- PCM/WAV 采用分段或追加 journal,避免进程被杀时整段录音丢失。
- Service 重建或下一次用户启动时扫描未完成 session,完成 WAV 收尾、恢复 ASR 或给出明确失败状态。
- 无障碍进程不依赖 WebView;主进程不可用时先缓存事件,Core 恢复后再同步。
阶段 3:仅在真机证明必要时拆分录音进程
第一阶段先复用现有 Core,降低实现风险。如果测试证明 Recents 划掉会连同主进程杀死,再将“录音采集 + 持久化 journal”拆到 :recorder 进程。
不能只给现有 Overlay Service 增加 android:process:需要为该进程设计 headless 初始化、AIDL/文件队列或其他 IPC,并处理 ndk-context、Core 初始化、凭证和存储并发问题。录音服务应能在没有 WebView 的情况下工作,Tauri Core 可在恢复后消费已归档音频。
明确不纳入目标
- 不把 Shizuku UserService 当作 OpenLess 的常驻守护进程。
- 不使用 AlarmManager 周期性心跳模拟保活。
- 不尝试绕过 force-stop、Task Manager Stop 或系统的 stopped package 状态。
- 不用 AccessibilityService 伪装通用录音守护进程;它只承担跨应用 UI 事件与输入辅助。
- 不为 OpenLess 申请仅用于保活的精确闹钟或 Full-screen Intent 权限。
验收建议
- Activity 关闭、按 Home 后,已由用户启动的录音仍能持续,且有前台通知。
- 在支持的设备上划掉最近任务后,Overlay/录音行为有明确、可重复的结果。
- 模拟普通进程回收后,session 能恢复或安全收尾,WAV 不损坏。
- AccessibilityService 在主 Activity 不可见时仍能接收事件,主进程未就绪时不崩溃。
- Android 13/14/15+ 至少覆盖 AOSP/Pixel、HyperOS/MIUI、ColorOS 等环境。
- Task Manager Stop 和 force-stop 的行为明确记录为“系统终止,不承诺绕过”。
相关 Issue
背景
希望 OpenLess 在 Android 上实现类似李跳跳、闹钟类应用的后台工作能力:用户在 OpenLess 可见时启动听写后,即使关闭 Activity、按 Home,甚至在部分设备上划掉最近任务,录音/悬浮入口仍能尽量继续工作;如果进程确实被系统回收,也应能恢复或安全收尾。
这里的目标不是绕过 Android 的 force-stop、Android 13+ Task Manager Stop 或厂商的强制冻结,而是采用 Android 官方支持的系统托管机制,并让进程死亡后可恢复。
调研结论
1. 不建议复制 Shizuku 的保活方式
Shizuku 的
shizuku_server是由 ADB UID 2000 或 root UID 0 通过app_process启动的独立进程。管理器 Activity 被划掉,并不等于该独立进程被杀掉。普通 OpenLess APK 无法复制这个身份。连接 Shizuku 可以提供特权 Binder/ UserService 能力,但不会改变 OpenLess 主进程的 UID、前台服务生命周期或麦克风权限,也不适合承载完整 Tauri/WebView/Core。
参考:
2. 李跳跳的核心参考价值是 AccessibilityService
李跳跳的公开资料和仿制项目能够确认的核心机制是
AccessibilityService:用户在系统设置中启用服务后,由 Android 系统绑定并在后台分发界面事件。它不是 Root/ADB,也不是普通 Activity 常驻。这类服务仍然受用户关闭无障碍、force-stop、低内存和厂商后台策略影响;“前台服务、锁定任务卡片、关闭电池优化、自启动白名单”等属于增强兼容性的组合措施,不是永久保活保证。
参考:
3. 闹钟类应用不是一直保持进程
闹钟应用通常采用:
应用在两个闹钟之间可以完全不运行。
setAlarmClock()能够在 Doze 中唤醒,但不是常驻心跳;重启后还需要重新注册,force-stop 后也不能保证继续触发。开源参考:
OpenLess 当前状态与缺口
android/kotlin/OpenLessAccessibilityService.kt已经是系统绑定的无障碍入口,并且 Manifest 使用了独立的:accessibility进程。OpenLessApplication.kt在 Activity 进入后台时显示 Overlay,但当前ACTION_SHOW使用普通startService;Overlay Service 只有录音时才提升为 microphone Foreground Service。OpenLessOverlayService.kt返回START_STICKY,但没有onTaskRemoved();系统重建时的null Intent也没有恢复会话逻辑。src-tauri/src/mobile_runtime.rs只在 Taurisetup中初始化 Core,src-tauri/src/android/native_bridge.rs的CORE_BACKEND也是进程内OnceLock,因此冷启动 Overlay/独立进程时不能直接假设 Rust Core 已存在。crates/openless-core/src/external_audio.rs已有外部 PCM 输入和录音归档抽象,可以作为 Android 原生录音服务与 Core 之间的适配基础,但目前 session 主要仍在内存中。最可行的方案
阶段 1:用户可见启动的 microphone Foreground Service
onStartCommand(null)、Service 重建、录音结束、取消、ASR 失败都必须有明确状态转换和清理逻辑。BOOT_COMPLETED自动启动麦克风;Android 14+ 对这类启动有明确限制。Android 官方限制:
RECORD_AUDIO、FOREGROUND_SERVICE_MICROPHONE,且通常必须在 Activity 可见时启动;参考:https://developer.android.com/develop/background-work/services/fgs/restrictions-bg-start
阶段 2:持久化 session,做到“被杀后可恢复”
RECORDING / FINALIZING / ORPHANED / COMPLETED等状态写入 App 私有存储。阶段 3:仅在真机证明必要时拆分录音进程
第一阶段先复用现有 Core,降低实现风险。如果测试证明 Recents 划掉会连同主进程杀死,再将“录音采集 + 持久化 journal”拆到
:recorder进程。不能只给现有 Overlay Service 增加
android:process:需要为该进程设计 headless 初始化、AIDL/文件队列或其他 IPC,并处理ndk-context、Core 初始化、凭证和存储并发问题。录音服务应能在没有 WebView 的情况下工作,Tauri Core 可在恢复后消费已归档音频。明确不纳入目标
验收建议
相关 Issue