A multi-display dev/test harness that reproduces the BYD DiLink 5.0 cockpit on the Android Automotive (AAOS) emulator — IVI + driver cluster + front passenger + HUD, all driven by a shared vehicle-signal bus you can feed manually or from the real AAOS Car API (VHAL).
It's not BYD's firmware. It's a clean re-implementation you own, built from
ground-truth analysis of the real firmware (Android 12, Qualcomm SM7325, EV
powertrain, the real BYD app set). See docs/GROUND_TRUTH.md.
Repo: github.com/i99dev/dilink5-sim · Package: com.byd.dilinksim
Prereqs: Android Studio (brings JDK 17+ and the SDK) with platform-tools,
emulator, cmdline-tools;latest, and the AAOS image
system-images;android-33;android-automotive;<abi>. Internet for the first build.
git clone git@github.com:i99dev/dilink5-sim.git && cd dilink5-sim
export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk"
chmod +x scripts/*.sh
./scripts/create-avd.sh # one time: builds the multi-display emulator
./scripts/start-dilink.sh # build + boot + show all 4 screensgit clone git@github.com:i99dev/dilink5-sim.git ; cd dilink5-sim
.\scripts\create-avd.ps1 # one time: builds the emulator
.\Start-DiLink.bat # build + boot + show all 4 screens (double-clickable)That's it. start-dilink / Start-DiLink.bat is safe to re-run anytime — it starts
the emulator if needed and (re)launches every screen on its correct display.
Build only:
./gradlew assembleDebug(Win:.\gradlew assembleDebug) →app/build/outputs/apk/debug/app-debug.apk. The Gradle wrapper is committed, so no pre-installed Gradle is needed.
| Screen | Activity | Display | Size | Notes |
|---|---|---|---|---|
| Main IVI + test panel | IviActivity |
0 (main) | 1920×1080 | DTB-grounded panel size |
| Driver cluster | ClusterActivity |
secondary | 1920×720 | Fission/Qt on the real car (see below) |
| Front passenger | PassengerActivity |
secondary | 1920×1080 | SmartCopilot-style |
| HUD (speed + turn arrow) | HudActivity |
secondary | 640×480 | real small aux panel; supports glass-mirror flip |
Sizes come from the firmware kernel DTB (docs/GROUND_TRUTH.md). All four run in one
process, so they share one in-process signal bus. They auto-appear on boot via
BootReceiver; display 0 is left to the system launcher / your i99dash.
Real-car nuance: on DiLink 5.0 the cluster + HUD are a separate Qt app on the Qualcomm "Fission" hypervisor VM, not Android displays. They're modeled here as Android displays because the emulator can't run the Fission VM. The "ClusterHome" screen the AAOS emulator ships is a Google sample (Fuel/RPM gauges) — it is not part of this sim or the real car. Leave it enabled: it's a persistent system app, so
pm disable-ing it makes its Application crash-loop and destabilizes the emulator. It runs harmlessly on its own internal cluster display.
Two interchangeable signal sources behind the same UI:
1. Mock engine (default) — animates a plausible drive, or drive it by hand from the TEST CONTROLS on the IVI:
- Auto-drive toggle · Speed slider · Gear P/R/N/D · Drive mode ECO/NORMAL/SPORT/SNOW
- Force maneuver Left/Right/U-turn/Straight/Roundabout (drives HUD + cluster nav)
- Blinkers · High beam · ADAS · HUD mirror (windshield flip)
2. Real AAOS Car API (VHAL) — toggle "VHAL (real Car API)" on the IVI, then feed the platform VHAL exactly like production code reads it:
adb shell pm grant com.byd.dilinksim android.car.permission.CAR_SPEED
adb shell am start --display 0 -n com.byd.dilinksim/.IviActivity --ez vhal true
adb shell cmd car_service inject-continuous-events 291504647 16.67 -s 10 -d 30 # 60 km/hVhalSignalSource connects CarPropertyManager and publishes speed/gear/EV-battery
into the same bus. On real DiLink hardware the same code reads real CAN values, no
change. (Caveats — privileged perms, emulator sensor behavior — in DELIVERY.md.)
┌── MockSignalEngine ──┐
│ (sim + manual) │
▼ ▼
SignalBus (StateFlow<VehicleState>) ◄── VhalSignalSource (real CarPropertyManager)
│
├──► IviActivity (IVI + controls)
├──► ClusterView (twin-arc EV cluster)
├──► HudView (speed + turn arrow, mirror flip)
└──► PassengerView (entertainment)
SignalBus is the single source of truth; swapping in real CAN touches only the
signal layer, never the screens.
App.kt— starts the mock engine + VHAL sourcesignal/—VehicleState,SignalBus,MockSignalEngine,VhalSignalSource*Activity.kt— one per screen (+BaseScreenActivityfor fullscreen/state)ui/—ClusterView,HudView,PassengerView,NavArrow(pureCanvas, no image assets)BootReceiver.kt— auto-launches secondary screens on boot
- Works identically on macOS (incl. Apple Silicon → arm64 image) and Windows — see
SETUP.md. The emulator is recreated fromscripts/create-avd.*, not committed (AVDs are machine/OS-specific). DELIVERY.md— full operations guide + verified behaviors.docs/GROUND_TRUTH.md— firmware analysis (screens, apps, DTB sizes).docs/VM_RESEARCH.md— why the real image can't be virtualized.- Firmware files are not in this repo (multi-GB, proprietary) — only the findings are.