
オープンソースのAndroid Auto電話側実装。プロトコルリバースエンジニアリング、TLS相互認証、H.264ビデオ投影、タッチ入力インジェクション、USB AOAを介したセンサーデータストリーミングを備えています。
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` をビデオ、2 番目をオーディオとして割り当てています。これはカーヘッドユニット(チャンネル 1 = ビデオ)では動作しますが、openauto(チャンネル 4 = オーディオ、ビデオではない)では失敗します。修正: `av_channel` 内の `stream_type` フィールドを解析して `VIDEO(3)` と `AUDIO(1)` を区別します。
- **ビデオの安定性** — ヘッドユニットの USB バッファオーバーフローにより、長時間のストリーミング後に接続が切断されます。下記のテスト結果を参照してください。
- **ヘッドユニット上での重複デバイス表示** — ヘッドユニットのスマートフォンページに、アプリが 1 つのエントリ(Android Auto と Bluetooth の両方の機能を持つ)ではなく、2 つの別々のエントリ(1 つは Android Auto 用、もう 1 つは Bluetooth 用)として表示されます。これは、Android 12 以降が実際の Bluetooth 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"` で実際のアドレスを設定ファイルに書き込みます。ユーザーが手動で BT MAC を入力できる UI 設定画面が必要です。
- **音声アシスタントボタンが未対応** — ドライバーがヘッドユニットの音声/アシスタントボタンを押すと、`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 .
これにより、openautoとそのすべての依存関係(Qt5、boost、protobuf、OpenSSL)がDebianコンテナ内でビルドされます。初回ビルドには約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. チャンネルを開く(video、audio、input、sensor)
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の切り替え間でも電話機に保持されます(実際のカーヘッドユニットでのテストに便利です)。