Repository navigation
[RFC] Shizuku/ADB 本机 Android 虚拟桌面输入源方案 #40
Description
背景与范围
希望在 WheelPlay 中新增“Android 虚拟桌面”输入源:在宿主手机上创建独立虚拟显示屏,启动本机应用,将画面输出到车机浏览器,并将浏览器触控、按键返回到该显示屏。复用 #28 的多输入源框架,独立跟踪其中 Android 桌面方向的工作。
本 Issue 仅记录方案与后续实施计划,不在当前 PR #39 或分支 feat/28-android-projection 中实现,不作为该 PR 的合并前提。后续基于届时主线另开分支/PR。
术语说明:本讨论中的“AVD”指本机 Android 虚拟显示/桌面。它不是 Android Studio 的 Android Virtual Device 模拟器,不启动第二套 Android 系统,也不提供独立用户或应用数据隔离。
目标与用户体验
- 输入源列表新增独立的 Android 虚拟桌面卡片;打开卡片只进入二级设置页。
- 首次使用:检测 Shizuku → 引导安装/启动 → 用户授权 WheelPlay → 选择应用或桌面 → 启动投影。
- 已授权且 Shizuku 正在运行时,能够从二级页直接启动。
- 展示未安装、未启动、未授权、设备不支持、正在准备、已连接及连接失败等真实状态。
- 未满足依赖时,在停止当前输入源前拒绝切换;不影响 CarPlay、Android Auto 的独立使用。
- 不承诺任意应用都支持副屏,也不承诺手机主屏操作完全不受影响;应用任务复用、焦点、横竖屏与锁屏行为须实测。
技术路线:Shizuku 优先,ADB 作为可选后端
优先使用 Shizuku UserService 承载 WheelPlay 的特权辅助进程。WheelPlay 不自行维护 ADB 配对、密钥、网络连接或辅助进程的 ADB 启动流程,但仍负责辅助进程本身的功能和清理。
| 组件 | 职责 |
|---|---|
| Shizuku | 用户授权、提供 shell/root 执行身份、启动及绑定 UserService |
| WheelPlay 主进程 | 输入源注册与状态、会话仲裁、公共视频输出、浏览器控制租约及 UI |
| WheelPlay UserService | 创建/销毁虚拟显示屏、在目标显示屏启动应用、注入触控及按键、报告显示布局与失败 |
| 可选 ADB 启动后端 | 在后续确有需求时,通过用户授权的 ADB 启动同类辅助进程;不作为 Shizuku 首版必做项 |
抽象“特权后端的可用性、连接、能力、停止”接口,将 Shizuku 与将来的直接 ADB 接入方式留在 Android 平台层。共享多输入源接口不携带 Shizuku Binder 或 ADB 类型。
Shizuku 的 Binder 包装适合简单远程调用,本方案涉及持续持有显示屏和输入状态,优先 UserService。它不是常规 Android 应用进程,不能假设普通 Service/Context 的所有 API 都能工作;需针对实际系统服务与版本做适配。
权限与 API 边界
- 默认验证 shell 身份 + DisplayManager/VirtualDisplay + 显示屏定向输入 的路线,可参考 scrcpy 的虚拟显示实现。
- Shizuku 经无线调试启动通常提供 shell(UID 2000)身份;root 模式是不同能力,必须实际探测,不将 shell 当成 root。
- 不把 VirtualDeviceManager 的创建能力作为普通手机前提。 类可见不等于创建接口对普通 App 开放;
CREATE_VIRTUAL_DEVICE、系统角色和伴生关联等限制,不会因为接入 Shizuku 就自动消失。 - 系统集成或定制设备可另评估 VDM 后端,独立报告其权限和兼容性。
- 官方 Shizuku 说明:非 root 启动在重启后通常需要再次启动;Android 11+ 可使用本机无线调试。UI 要表达这一恢复步骤,不能承诺永久授权后一劳永逸。
- 同时验证厂商对 shell 输入注入和后台进程的额外限制;受保护画面与禁止副屏的应用按不支持处理,不以黑屏假装投影成功。
视频、输入与框架接入
视频
建议的数据流:
本机应用
→ UserService 创建的 VirtualDisplay
→ Binder 传入的 Surface
→ WheelPlay 公共画面/编码管线
→ WebRTC 或图像兼容输出
→ 车机浏览器
- 主进程创建并管理输出 Surface 的生命周期,通过 Binder 传递 Surface 句柄;不通过 Binder 逐帧传输 Bitmap 或大字节数组。
- 优先验证现有 Surface 视频入口;若需要新增 Surface/EGL → MediaCodec 编码能力,应放在公共 Android 视频管线中,并明确 WebRTC 与图像回退的分流方式。
- 分辨率、DPI、旋转、内容区域及布局版本是会话状态;输入映射与实际显示布局一致。
- 首帧、编码配置、浏览器输出就绪分别确认;仅创建显示屏成功不能判定投影可用。
- 动态尺寸、屏幕休眠、前后台切换和慢浏览器都要验证;队列必须有界。
触控与控制
浏览器输入
→ 公共控制租约/会话校验
→ 虚拟桌面适配器
→ UserService
→ 指定 displayId 的输入事件
- 首版覆盖单指/多指触控、返回键;Home 的行为与应用选择器/Launcher 方案一起验证。
- 严格区分目标虚拟屏与手机主屏,禁止因 displayId 丢失而默认为主屏。
- 为每次会话绑定代次、布局版本和显示屏所有权;拒绝旧会话的迟到输入。
- 旋转、切源、控制租约失效及断连时释放全部触点/按键;不能丢失抬手事件。
- 键盘、文本提交、剪贴板和鼠标作为后续能力,不将按键注入等同于完整中文输入支持。
应用与桌面
- 首个验证目标为在虚拟显示屏启动一个指定应用,完成画面和触控闭环。
- 然后提供本机应用选择器;按实际可启动 Activity 与系统查询规则列出应用。
- 如目标设备没有可用的副屏 Launcher,评估自有轻量桌面或显式启动指定 Launcher。
- 验证应用已在主屏运行、单任务应用、弹窗、权限界面、软键盘及退出后的任务去向;这是共享同一 Android 系统,不是独立应用实例保证。
音频与麦克风
视频和触控 MVP 不承诺浏览器音频或麦克风注入。初期可明确使用本机原有音频行为,并在能力中关闭尚未实现的浏览器音频/麦克风。
后续独立验证目标应用音频捕获、焦点、路由及麦克风;有 shell 权限或虚拟屏,不代表自动具备每应用音频隔离与麦克风注入能力。
生命周期与进程通信
- 可用性检查只检测,不创建显示屏或启动应用;仅用户启动且运行时接纳会话后执行这些动作。
- 控制 IPC 使用有版本的 AIDL/Binder 契约,限定创建会话、启动所选应用、输入和停止等操作,不暴露任意 shell 命令执行入口。
- 校验调用方与会话所有权;主进程退出后,辅助进程通过客户端 Binder 死亡通知释放显示屏和输入状态。
- 区分 Shizuku 服务断开、UserService 崩溃、授权撤销及主进程死亡;不能只依赖 Activity.onDestroy。
- 正常停止顺序:停止接收新输入 → 释放手势/按键 → 停止虚拟屏 producer 并确认释放 → 释放 Surface/编码器 → 解除资源占用。
- 清理失败不得宣称切源完成;恢复时创建新会话,拒绝旧 Binder 回调。
- 显式实现 UserService 的销毁与退出,验证 unbind 后没有残留进程/显示屏;按 Shizuku 契约处理服务版本和应用升级。
分阶段实施
- P0:真机可行性验证。选择代表性 Android 版本/设备,使用 shell 模式 Shizuku,验证 UserService、Surface 跨进程传递、虚拟屏创建、应用启动和输入注入;记录需要的厂商设置及最低支持范围。
- P1:独立输入源 MVP。接入公共会话,完成单虚拟屏、应用选择、视频、触控/返回及明确的不可用状态;首版使用固定尺寸,声明真实音频能力。
- P2:生命周期与交互完善。验证切源、Binder 死亡、授权撤销、升级、重启恢复、旋转/DPI、输入法及桌面/任务行为。
- P3:可选扩展。依据实测结果增加浏览器音频、键盘/文本、动态尺寸;有需求再添加直接 ADB 启动后端或系统 VDM 后端。
验收标准
- 无 Shizuku、未启动、拒绝授权时有清晰说明,且不会拆掉当前 CarPlay/AA 会话。
- 至少一台未 root 的目标设备,使用 Shizuku shell 模式运行指定本机应用,并从浏览器看到独立虚拟屏、完成触控与返回。
- 输入不会错误注入主屏;旋转、失焦、断网与切源不会留下卡住的触点。
- 手机主屏同时操作、锁屏/解锁及同一应用跨屏行为有明确兼容性记录。
- 停止、Shizuku/UserService/主进程异常退出后,不遗留虚拟屏、编码器、输入状态或不可控后台任务。
- 重启后能引导恢复 Shizuku;应用升级不会继续绑定旧版本辅助服务。
- 与 CarPlay、AA 来回切换正常,公共浏览器输出和图像回退行为不退化。
- 记录设备/系统版本、Shizuku 版本与身份、分辨率/DPI、浏览器、首帧时间、延迟、CPU/内存及持续运行表现;未验证能力保持不支持或实验性。
参考资料
- Shizuku API / UserService 开发指南
- Shizuku 启动及厂商限制说明
- scrcpy 虚拟显示功能
- scrcpy NewDisplayCapture 实现
- AOSP Companion app streaming 权限与角色
- AOSP VirtualDeviceManager 示例及宿主要求
以上为设计与待验证事项,尚未在 WheelPlay 实现或完成真机验证。实施时应固定实际参考版本。
Activity
fython commentedon Oct 26, 2026
同步实施进展:PR #52 已于 2026-10-26 合并到
main,合并提交ccd01f0。本 Issue 正文中的“尚未实现”是最初 RFC 的状态;当前已实现首版软件链路,但尚未完成真机验收,Issue 仍应保持开放。已合并的实现:
DesktopBackend / DesktopConnection隔离 Shizuku,公共输入源接口不依赖 Binder/ADB。代码门槛为 Android 10+、Shizuku 服务 API 13+,固定依赖 13.1.5;这不是已经验证的设备支持范围。moe.feng.wheelplay.projection.desktop。v7 协议包含握手、启动配置、实际显示信息、会话状态快照、健康检查、只读查询、停止和销毁。配置/能力/状态结果使用 structured parcelable;高频DesktopTouchFrame与DesktopStatus保留自定义紧凑格式。控制调用返回固定错误码及独立诊断,触控使用 oneway,无逐帧响应。验证证据:PR 最新提交
80ac0f6的 Android Debug Build 已通过;PR 中记录了单元测试、浏览器测试、lint 和 arm64 Debug 构建结果。上述属于软件验证,不能代替设备上的真实显示、输入和清理验收。实现边界、固定参考版本及真机记录表见 ANDROID_DESKTOP.md。对照本 Issue,剩余工作如下:
另有几项需要明确保留在后续范围:
建议下一步优先完成 P0,并按文档记录 P1/P2 验收证据,再判断可关闭哪些验收项;不因 PR 合并而勾选全部验收标准。