# CarClusterMirror
**Repository Path**: zombies/car-cluster-mirror
## Basic Information
- **Project Name**: CarClusterMirror
- **Description**: 车机中控投仪表屏方案
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2026-10-15
- **Last Updated**: 2026-10-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Car Cluster Mirror · 仪表盘投屏
把**车机中控屏上当前打开的画面**整屏镜像到**仪表盘辅助屏**。
面向已 root、可用 adb 安装任意应用的车机(Android 9 系车机系统)。
> ⚠️ **使用前必读**:[DISCLAIMER.md](DISCLAIMER.md)
> 本项目仅供个人自有车辆的学习与自用,需要 root 权限并会修改系统分区,
> 可能导致保修失效甚至车机故障,风险自负。
---
## ⚠️ 实测车型(先看这条)
| 项目 | 内容 |
|---|---|
| **实测车型** | **长安 UNI-V 2022款 尊贵版** |
| 车机系统 | 飞鱼 OS / Android 9 |
| 测试结论 | 唯一实测通过的车型,可正常投屏 |
> **除此之外的其它车型,本项目一律未做任何测试。**
>
> 不同车型 / 不同年款之间,车机系统版本、系统服务(尤其是"仪表投影"的握手协议)、
> 屏幕拓扑结构**可能存在本质差异**。本项目在其它车型上:
>
> - **可能完全无法使用**(找不到仪表盘屏、投不上去、黑屏);
> - **也可能引发车机异常**(开机自检失败、服务冲突等)。
>
> **请勿盲目套用。** 如要在其它车型上尝试,请先自行评估风险,
> 并务必提前做好完整备份与回滚准备
> (见 `deploy/全新车完整安装教程.txt` 的备份 / 回滚章节)。
---
## 🚀 要装车,只看这一个 → [`docs/安装指南.md`](docs/安装指南.md)
一页纸,两个脚本:
| 脚本(在 `deploy\`) | 干什么 |
|---|---|
| `uninstall_all.bat` | **一键彻底清除**(恢复到"从没装过",可选) |
| `install.bat` | **一键完整安装**(放 priv-app + 写 init 服务 + 装 App + 自动重启 + 自检) |
```
双击 uninstall_all.bat → 输入 YES → 自动重启 (可选,只为干净验证)
双击 install.bat → 直接回车选默认 APK → 自动装完并重启(约 3 分钟)
车机上:切 U 盘模式 → 点【开始投屏】 (v1.37 起不用选引擎,界面已固定)
```
> ⚠️ **不能只装 APK。** 实测:App 执行 `/system/xbin/su` 被拒(`error=13 Permission denied`),
> 所以必须保留「init 启动的 root 守护进程」。详见 [`docs/安装指南.md`](docs/安装指南.md) 开头。
> 🆕 **v1.37 起界面只保留能用的方案**:引擎选择器已移除(代码保留)。
> 实测「自动 / Root 帧流」可用、「直连镜像 / 媒体投影 / Root 截屏」不可用。
---
## 📍 当前进度(2026-10-15)
| 项 | 状态 |
|---|---|
| 当前版本 | **v1.37-only-ok**(versionCode 29,md5 `87e1cc5491eea7db6470ec7630baf3f7`) |
| **v1.37 界面精简** | 按实测结果,**引擎选择器已从界面移除**(代码与降级链保留):
保留「自动 / Root 帧流」(同一段代码,走 root 守护进程)
移除「直连镜像 / 媒体投影」(虚拟显示帧全 0)、「Root 截屏」(App 无权执行 su) |
| **★ 虚拟显示已定案作废** | 5 种 flag 变体 + 直连镜像(FLAG_SECURE) + 媒体投影,**全部** `alpha0=100% 首像素=0x00000000 判定=整块缓冲全 0(零填充,从未合成)`。
→ **与 flag 组合无关,本车拿不到画面。** 换 flag 救不回来 |
| ⚠️ 已作废的旧结论(两条) | ① 「直连镜像有图 → 普通 AUTO_MIRROR 可用」——错,见上;
② 「`CAPTURE_SECURE_VIDEO_OUTPUT` 必须平台签名、拿不到」——**也错**,实测 `granted=true`。但拿到也没用,虚拟显示照样全黑 |
| 实际能出图的(只有两条) | `root_socket`(守护进程 socket;**「自动」和「Root 帧流」是同一段代码**,`MainActivity:250`)
`root_capture`(`su` + `screencap` 循环)。实测 **10~14 fps**,瓶颈在采集侧 |
| 另一发现 | 车机上两个同名包并存:`/data/app` v1.35,`/system/priv-app` 里那份**一直是 1.27** —— 热更新从没写进过 priv-app。排查:`deploy\check_dup_pkg.bat` |
| **★ 安装方案(已修正)** | ⚠️ 上一版说的「只装一个 APK」**实测不成立,已撤回**:App 执行 `/system/xbin/su` 被拒(`error=13 Permission denied`),三条降级链全断。
→ **必须保留「init 启动的 root 守护进程」**,走完整安装:`deploy\install.bat` · [`docs/安装指南.md`](docs/安装指南.md) |
| 想干净验证新版本 | `deploy\uninstall_all.bat` → [`docs/彻底清除与干净重装.md`](docs/彻底清除与干净重装.md) |
| su 排查(只读) | `deploy\diag_su.bat`(查 App 的 SELinux 域 / su 标签 / avc denied) |
| 背景资料(装车不需要看) | [`docs/本轮实车结论与下一步.md`](docs/本轮实车结论与下一步.md) · [`docs/实车验证清单.md`](docs/实车验证清单.md) |
---
## 目录结构
```
ClusterMirror/ Android 工程(纯 Java,无 NDK)
├─ app/src/main/java/ 业务源码
├─ gradlew / gradlew.bat
└─ README.md 架构说明 / 双引擎 / 版本演进(先看这个)
deploy/ 部署与安装
├─ install_min.bat ★★ 新车最小安装(v1.36 新增):只装 APK,不碰 /system、不重启
├─ uninstall_all.bat/.sh ★★ 彻底清除(v1.36 新增):恢复到"从没装过",用于干净验证新版本
│ 清 init.aee.rc 里的服务定义 / priv-app / 白名单 / 数据区包 /
│ 应用数据 / 外部数据 / tmp 遗留;带备份 + 5 项校验
├─ 全新车完整安装教程.txt ★ 从零装到一辆新车的完整流程(含边界情况、回滚)
├─ install.bat Windows 一键安装(自动 push → 安装 → 校验)
├─ install_new_car.sh 车机端一键安装脚本(真正干活的)
├─ update_app.bat / update_app.sh ★ 热更新(换 APK + 重启守护进程,不重启车机;bat 为单文件版)
│ ★ v1.35 修时序:改成「你测完再取日志」,并补采 logcat
│ ★ v1.36 加 priv-app 写入校验:cp 之后两端 md5sum 比对,
│ 不一致直接报错(原先 ls -l 看不出 cp 静默失败)
├─ check_dup_pkg.bat ★★ 重复包 / priv-app 真实版本核对(v1.36 新增,只读)
│ 装了几份 / 跑的是哪份 / priv-app 里那份真实 versionName(aapt2 读)
├─ recon.bat ★ 环境侦察(adb 模式下一次性采集所有关键环境信息,单文件)
├─ test_mp.bat ★★ 引擎对比 + 虚拟显示取证(v1.36 起 3 轮):
│ 第1轮 直连镜像 / 第2轮 媒体投影 / 第3轮 虚拟显示取证(5 种 flag 各存一帧 PNG)
├─ collect_all.bat ★ 一键取证(只读不改):logcat/App日志/结论/首帧/环境快照/虚拟显示取证
├─ logconv.py ★ 日志编码转换(v1.35 新增):UTF-8 → GBK,解决控制台中文乱码
├─ diag_daemon.sh 守护进程状态诊断
├─ fix_daemon_autostart.sh 老车自启修复(仅旧版安装需要)
├─ head.txt / 守护进程自启修复说明.txt
├─ start_app.bat 免密启动 App(adb shell 有密码门,需管道喂口令)
└─ 【T2 实验】T2测试安装说明.txt / install_t2.bat / install_t2.sh
collect_t2_log.bat(切回 adb 后取日志)
验证"安全虚拟显示能否替代守护进程"(三段式:装→U盘模式测→取日志)
※ 已被 test_mp.bat 取代,仅供对照
> 📌 **日志标记约定(v1.35 起,重要)**
> App 侧所有关键日志的标记都是 **ASCII**,`findstr` / `grep` 可以直接匹配,
> 不受控制台代码页影响(Android 日志是 UTF-8,Windows 控制台默认 GBK —— 用中文词永远匹配不到,踩过):
>
> | 标记 | 含义 |
> |---|---|
> | `[ENG]` | 引擎切换 / 启动 |
> | `[CHK]` | 帧内容检测(平均亮度 / 黑色占比 / 判定) |
> | `[FPS]` | 帧率(送帧 fps / 上屏 fps) |
> | `[T2]` | 安全虚拟显示实验 + 无帧看门狗 |
> | `[VDP]` | 虚拟显示取证(v1.36 新增:5 种 flag 各存一帧 PNG + 像素统计判定) |
> | `[ERR]` | 异常 / 失败(原先是 `! ` 前缀) |
>
> 抓日志一行命令(adb 模式):
> ```bat
> adb shell logcat -d -s ClusterMirror/Log:V
> ```
> ⚠️ **维护注意(重要,踩过坑)**
> `deploy/` 与根目录下的 **`.bat` 文件是 GBK(cp936) 编码 + CRLF 行尾**,且内部用 `chcp 936`。
> 这是必须的,不要改成 UTF-8:
> - 纯 LF 行尾 → cmd 报「命令语法不正确」;
> - `chcp 65001` + UTF-8 中文 → cmd 重读批处理时字节错位,会把 `rem`/`echo` 行从中间截断,
> 残段被当命令执行(实测复现)。
>
> 因此:**不要用 UTF-8 编辑器直接改这些 .bat**。项目里带了一个转换器,
> 改完(改 UTF-8 源文件)跑一次就自动归一化:
> ```bash
> python .tmp_test/to_gbk_bat.py deploy # UTF-8 → GBK + CRLF
> ```
> 手工版:
> ```bash
> sed -i 's/chcp 65001 >nul/chcp 936 >nul/' x.bat
> iconv -f UTF-8 -t GBK x.bat > x.gbk && mv x.gbk x.bat
> sed -i 's/\r$//' x.bat && sed -i 's/$/\r/' x.bat
> ```
> ⚠️ **还有一个坑(踩过两次)**:用 `sed -i` 或用 Python 的文本模式
> (`open(f, encoding='gbk')` 读 + `open(f,'w',newline='')` 写)改这些文件,
> **会把 CRLF 弄丢**,之后 cmd 会再次报「命令语法不正确」。
> 正确写法是**按字节读写、显式写 CRLF**(见 `to_gbk_bat.py`)。
> 改完务必确认:
> ```bash
> od -c x.bat | grep -c '\r' # 应与行数相等
> ```
> 另外 GBK 不支持 `✅❌⚠★✔≥→` 等字符,正文里请用 `[OK]/[X]/[!]/*/>=/->` 代替。
docs/ 技术文档
├─ 本轮实车结论与下一步.md ★★ 最新(2026-10-15):直连镜像出图 = 突破;日志取不到的三个根因;架构三种结局
├─ 实车验证清单.md ★★ 实车操作总清单(你要做的全部事情,唯一权威版)
├─ 截屏链路评估与优化方案.md ★ 截屏成本拆解 + 备选捕获通道 + 录屏方案 + 验证计划
├─ 去守护进程改造方案.md ★ 目标架构(App 内虚拟显示)+ 延迟归因 + 分阶段改造
├─ 去特权化路径评估.md ★ 能否砍掉 priv-app/白名单/init.aee.rc/重启(含判定实验)
├─ JPEG传输改造与实车验证.md ★ v1.33 传输改造说明 + 实车验证步骤 + 回滚
├─ 实车侦察结果与发现.md ★ 2026-10-15 实车侦察(含 userdebug/test-keys 重大发现)
└─ 竞品分析_UNIV_ADB_Manager.md ★ 同类 App 架构对比(shell+ADB 路线 / JPEG 传输)
clustermirror.rc init 服务定义(参考)
install_privapp.bat priv-app 手工部署辅助脚本
privapp部署手册.txt / v1.26部署说明.txt 历史部署说明
```
---
## 快速开始
### 1. 编译
前置:Android Studio + JDK 17/21 + Android SDK。
```bat
cd ClusterMirror
gradlew.bat assembleDebug
```
产物:`ClusterMirror\app\build\outputs\apk\debug\app-debug.apk`
> 命令行直接编译时,`ClusterMirror\local.properties` 需要有一行 `sdk.dir=...` 指向你的 SDK。
> Android Studio 打开工程会自动生成;本项目未把它入库(每台机器路径不同)。
### 2. 部署到车机
见 **`deploy/全新车完整安装教程.txt`**(完整版,含边界情况与回滚)。
最省事的方式:
```bat
deploy\install.bat
```
它会自动:推送文件 → 请求 root → 执行安装脚本 → 等待重启 → 校验守护进程状态。
---
## 它是怎么工作的(一段话)
车机中控的画面要投到仪表盘,有一个绕不开的前提:**普通应用拿不到中控屏的合成帧**
(系统级截图接口不对外,`MediaProjection` 在部分车机 ROM 上返回黑帧),
而仪表盘的 HDMI 管线**只转发应用窗口层**(不转发悬浮窗)。
所以本项目分成两部分,用的是同一个 APK:
| 角色 | 说明 |
|---|---|
| **守护进程** | 由 `init` 以 root 身份开机启动,用系统截图接口抓中控整屏,经本地 TCP 回环推给 App |
| **App** | 普通安装在数据区,用 `Presentation` 把画面显示到仪表盘辅助屏 |
详细的架构、双引擎、版本演进见 `ClusterMirror/README.md`。
---
## 合规与免责
- 本项目需要车机 root 权限,**请自行通过合法途径获取**;本项目不提供、不鼓励任何绕过厂商安全机制的行为。
- 会修改系统分区与 init 服务定义,**可能导致保修失效或车机异常**,风险自负。
- 与任何汽车制造商、车机厂商、导航服务商**无关联**,未获其授权。文中商标归各自权利人所有。
- **禁止商业用途**,禁止用于非自有设备。**请勿在驾驶过程中操作**。
完整条款见 [DISCLAIMER.md](DISCLAIMER.md)。