Android Auto 手机端应用的开源实现。此应用在手机上运行,通过USB将画面投射到汽车头机,替代Google专有的 com.google.android.projection.gearhead APK。
本项目处于早期开发阶段。协议握手和视频投影已在真实头机上成功运行。手机屏幕可在汽车头机上成功显示约几秒钟后断开(视频稳定性正在改进)。
请自行承担风险使用。 本软件按“原样”提供,不提供任何形式的担保。
USB Plug-in → MainActivity → ProjectionService ↓ UsbAoaTransport (USB AOA accessory mode) ↓ MessageFramer (16KB frame fragmentation) ↓ InBandTls (TLSv1.2 via SSLEngine) ↓ ProtocolEngine (AAP state machine) ↓ ┌───────────┼───────────┐ Video Input Audio (H.264) (touch/keys) (PCM)
## 已知问题
- **通道分配假定顺序** — 我们分配 `SERVICE_DISCOVERY_RESPONSE` 中的第一个 `av_channel` 为视频,第二个为音频。这在车载主机上有效(通道1 = 视频),但在 openauto 上失败(通道4 = 音频,而非视频)。修复方案:解析 `av_channel` 内的 `stream_type` 字段以区分 `VIDEO(3)` 和 `AUDIO(1)`。
- **视频稳定性** — 由于车载主机 USB 缓冲区溢出,长时间流传输后连接会断开。参见下面的测试结果。
- **车载主机上设备重复显示** — 车载主机的智能手机页面将我们的应用显示为两个独立条目(一个用于 Android Auto,一个用于蓝牙),而非同时显示这两种功能的单个条目。这是由于 Android 12+ 阻止访问真实的蓝牙 MAC 地址(返回 `02:00:00:00:00:00`)。临时解决办法:通过 `adb shell "echo $(adb shell settings get secure bluetooth_address) > /sdcard/Android/data/org.openandroidauto/files/bt_address.txt"` 将真实地址写入配置文件。需要一个 UI 设置界面让用户手动输入其蓝牙 MAC 地址。
- **语音助手按钮未被处理** — 当驾驶员按下车载主机上的语音/助手按钮时,我们收到 `VOICE_SESSION_REQUEST` 并尝试启动一个语音助手(Dicio 或系统默认)。但启动的助手尚未接收到来自车载主机麦克风的音频。
### 视频稳定性测试结果
测试图案(彩条)在 800x480 分辨率下,I帧间隔 1 秒:
| FPS | 比特率 | 分片 | 持续时间 | 帧数 | 状态 |
|-----|--------|------|----------|------|------|
| 30 | 2Mbps | 否 | ~3s | ~90 | ❌ 过快 |
| 15 | 2Mbps | 否 | ~33s | ~500 | ⚠️ 较好 |
| 10 | 2Mbps | 否 | ~93s | ~930 | ⚠️ 良好 |
| 30 | 2Mbps | 是(2KB) | 5-25s | 150-750 | ⚠️ 不稳定 |
| 30 | 500Kbps | 是(2KB) | ~54s | ~1691 | ⚠️ 较好 |
| 15 | 250Kbps | 是(2KB) | ~67s+ | 1000+ | ⚠️ 良好 |
| 30 | 250Kbps | 是(2KB), I=5s | ~20s | ~600 | ❌ 较长 I帧时更差 |
| 15 | 250Kbps | 否 | ~13s | ~200 | ❌ 分片在此有帮助 |
根本原因:车载主机 USB 接收缓冲区在持续高吞吐量下溢出。较低的数据速率意味着更长的连接时间。
**最佳确认配置:** 10fps,2Mbps,无分片 = 93 秒。分片后加密的实现存在缺陷(车载主机无法重组)——需要进一步调查。
## 构建```bash
./gradlew assembleDebug
需要 Android SDK 及平台 35。
./gradlew testDebugUnitTest
113 个单元测试和集成测试,涵盖协议、帧、TLS、通道逻辑、视频状态机、传感器处理和触摸输入。
### 使用 openauto(Docker)进行集成测试
openauto 是一个第三方车机模拟器,支持完整的 Android Auto 协议。我们用它来验证我们的协议实现,无需真实车辆。
#### 前提条件
- Docker 已安装并运行
- 手机通过 ADB 连接(USB 或无线)
- 已在手机上安装应用:`./gradlew assembleDebug && adb install -r app/build/outputs/apk/debug/app-debug.apk`
#### 1. 构建 openauto Docker 镜像(一次性)```bash
cd thirdparty/openauto
docker build -f Dockerfile.headless -t openauto-headless .
此命令将在 Debian 容器中构建 openauto 及其所有依赖项(Qt5、boost、protobuf、OpenSSL)。首次构建大约需要5分钟。
docker run --rm -p 5100:5000 -e QT_QPA_PLATFORM=offscreen
openauto-headless timeout 60 /src/build/bin/autoapp
openauto 在容器内监听端口 5000,映射到主机的端口 5100。它以无头模式运行(无需显示器)。
#### 3. 设置 ADB 反向端口转发```bash
adb reverse tcp:5000 tcp:5100
这使得手机的 localhost:5000 隧道连接到计算机的 localhost:5100 (openauto)。当没有找到 USB 附件时,我们的应用作为 TCP 客户端连接到 localhost:5000。
adb shell am start -n org.openandroidauto/.MainActivity
该应用将会:
1. 无法找到USB配件
2. 连接到 `localhost:5000`(通过adb reverse的openauto)
3. 执行完整的协议握手(VERSION → TLS → AUTH → SERVICE_DISCOVERY)
4. 打开通道(视频、音频、输入、传感器)
5. 开始流式传输视频(测试图案)
#### 5. 在openauto日志中验证
你应该在openauto输出中看到:```
[OpenAuto] handleNewClient() - Handle WIFI Client Connection
[OpenAuto] [AndroidAutoEntity] Send Version Request.
[OpenAuto] [AndroidAutoEntity] onVersionResponse()
[OpenAuto] [AndroidAutoEntity] Beginning SSL handshake.
[OpenAuto] [AndroidAutoEntity] Handshake completed.
[OpenAuto] [AndroidAutoEntity] onServiceDiscoveryRequest()
[OpenAuto] [AndroidAutoEntity] onAudioFocusRequest()
[OpenAuto] [AudioMediaSinkService] onChannelOpenRequest()
[OpenAuto] [VideoMediaSinkService] onChannelOpenRequest() (if video focus granted)
adb pull /sdcard/Android/data/org.openandroidauto/files/aa_log.txt cat aa_log.txt
日志文件在 USB 切换之间持久保存在手机上(在真实车载主机上测试时很有用)。
#### 快速单行测试```bash
# Assumes openauto image already built and app installed
docker run --rm -p 5100:5000 -e QT_QPA_PLATFORM=offscreen openauto-headless timeout 20 /src/build/bin/autoapp &
sleep 3 && adb reverse tcp:5000 tcp:5100 && adb shell am start -n org.openandroidauto/.MainActivity
Message Id not Handled: 4 — 这是已知的 openauto 特性,非错误Android Auto 协议通过多个项目逆向工程得来。每个项目都基于前者的工作:
| 项目 | 年份 | Proto 文件 | 角色 |
|---|---|---|---|
| f1xpl/aasdk | 2018 | 1 个整体文件 (Wifi.proto) | 原始逆向工程 — 核心协议、视频、音频、输入、传感器 |
| AACS | 2020 | 28 个(按消息拆分) | 手机端实现 — 最简覆盖视频投射 |
| opencardev/aasdk | 2024 | 254 个(按服务分层) | 权威参考 — 包含所有服务的完整协议 |