dilink-auto-android

Progress Tracker

Current version: v0.16.0 (stable) Last updated: 2026-04-29

Milestones

v0.16.0 (2026-04-29)

v0.15.0 (2026-04-28)

v0.14.0

v0.13.1 — First Release (2026-04-26)

v0.13.0 — USB ADB Auth Fix (2026-04-25)

Root cause found and fixed: Signature.getInstance("SHA1withRSA") double-hashes the ADB AUTH_TOKEN. ADB’s 20-byte token is a pre-hashed value — AOSP’s RSA_sign(NID_sha1) treats it as already hashed. Now uses NONEwithRSA with manually prepended SHA-1 DigestInfo ASN.1 prefix (prehashed signing). “Always allow” now persists correctly — AUTH_SIGNATURE accepted on reconnect without dialog.

v0.13.0 — Display Power + Key Encoding (2026-04-25)

v0.12.5 — Connection Stability (2026-04-24)

v0.12.0–v0.12.4 — Bug Fixes & Polish (2026-04-24)

v0.11.0–v0.11.3 — Non-Blocking Pipeline + Encoder Fix (2026-04-24)

v0.10.0 — 3-Connection Architecture (2026-04-24)

Split single multiplexed TCP connection into 3 dedicated connections to eliminate cross-channel interference causing video stalls:

Each connection has its own Connection instance with independent SocketChannel, NioReader, and write queue. Heartbeat/watchdog on control only.

v0.9.2 — Diagnostic Build (2026-04-23)

Comprehensive logging for investigating video frame stall after ~420 frames:

v0.9.0-v0.9.1 — Write Stall Investigation (2026-04-23)

Investigating root cause of video stall. Added TCP buffer size logging, write stall diagnostics.

v0.8.4-v0.8.8 — Bug Fixes + Log Routing (2026-04-23)

v0.8.3 — Final Polish + VD Wait Fix + USB Key Diagnostic (2026-04-23)

Final milestone + bug fixes:

v0.8.2 — Polish + VD ServerSocket + USB Key Persistence (2026-04-23)

6 polish fixes + 2 critical fixes:

v0.8.1 — Touch + Decoder Performance + Hotfixes (2026-04-23)

4 performance optimizations + 2 crash fixes:

v0.8.0 — I/O Pipeline Performance (2026-04-23)

3 I/O performance optimizations + hotfix:

v0.7.4 — Write Queue + Flow Sequencing (2026-04-23)

Write architecture change + flow improvements:

v0.7.3 — Network Resilience + HyperOS Freeze Fix (2026-04-23)

Network resilience + critical HyperOS fix discovered via logcat evidence:

v0.7.2 — Car-Side Stability + Selector Fix (2026-04-23)

5 stability fixes + critical NioReader fix:

v0.7.1 — Critical Bug Fixes (2026-04-23)

6 critical/high fixes from comprehensive review:

v0.7.0 — Full NIO + Service Fix (2026-04-23)

All socket operations converted to non-blocking NIO. mDNS registration no longer blocks listen loop. Version code read at runtime via PackageManager.

Changes:

v0.6.2 — Parallel Connection Model + Auto-Update (2026-04-23)

Major architecture rewrite: parallel WiFi + USB tracks, NIO non-blocking sockets, phone-driven auto-update, multi-touch via IInputManager.

Working:

Architecture changes from v0.5.0:

v0.5.0 — USB ADB + Automated Setup (2026-04-22)

Major architecture change: the car deploys the VD server to the phone via USB ADB. Wireless Debugging eliminated.

v0.4.0 — GPU-Scaled VirtualDisplay (2026-04-22)

Apps render at phone’s native DPI (480dpi), GPU downscales to car viewport. SurfaceScaler EGL/GLES pipeline.

v0.3.0 — Persistent Navigation Bar (2026-04-21)

Car UI with always-visible left nav bar, TextureView, real app icons.

v0.2.0–v0.2.3 — Virtual Display Foundation (2026-04-21)

VD creation, self-ADB, resilient server, multi-app support.

v0.1.0–v0.1.1 — Initial Implementation (2026-04-21)

Project created. Screen mirroring on emulators.


Fix Tracker

Comprehensive review performed 2026-04-23 covering performance, stability, and flow-continuity.

Phase 1 — Critical (fix before next release)

ID Category Finding Status
C1 Stability/Perf writeAll() spins indefinitely on full send buffer — no timeout, holds outputLock, blocks all senders. System freeze risk v0.7.1
C2 Flow VD server dies on USB disconnect (shellNoWait ties process to ADB stream). Full reconnect 5-15s REVERTED — setsid/nohup broke localhost. Using shellNoWait+exec (v0.6.2 approach). Reconnects on re-plug.
C3 Flow Auto-update has no loop-break — if pm install silently fails, infinite restart cycle v0.7.1
C4 Flow Car WiFi track runs once and gives up — hotspot enabled after USB plug → stuck forever v0.7.3
C5 Stability WakeLock acquired without timeout — battery drain if service killed without onDestroy() v0.7.1
C6 Stability VirtualDisplayClient.touch() non-blocking write spin + channel field not volatile — data race v0.7.1

Phase 2 — High (latency & stability)

ID Category Finding Status
H1 Perf NIO delay(1) polling adds 1-4ms latency floor per read + 1000 wake-ups/sec idle. Use Selector or runInterruptible v0.7.2
H2 Perf Two syscalls per frame write (6-byte header + payload). Use GatheringByteChannel.write(ByteBuffer[]) v0.8.0
H3 Perf Per-frame ByteArray.copyOf() in video relay (~30 allocs/sec of 10-100KB). Pass offset+length v0.8.0
H4 Perf synchronized(outputLock) serializes video+touch+heartbeat. Keyframe write blocks touch ~200ms v0.7.4
H5 Stability Connection.connect() leaks SocketChannel on cancellation — no try/finally v0.7.1
H6 Stability disconnectListener invoked synchronously in CAS — potential deadlock v0.7.1
H7 Stability Car state flags (wifiReady, usbReady) not volatile — can get stuck in CONNECTING v0.7.2
H8 Stability VideoDecoder.stop() doesn’t join feed thread before codec.stop() — native crash risk v0.7.2
H9 Flow Phone network callback ignores CONNECTED/STREAMING — hotspot toggle causes 10s frozen frame v0.7.3
H10 Flow Handshake + auto-update + VD deploy all race — deployAssets may not be done, concurrent ADB ops v0.7.4
H11 Flow No user feedback during 5-12s VD server startup — car shows static spinner v0.7.4
H12 Flow First-time USB ADB auth dialog on phone with no guidance on car screen — 30s timeout v0.7.4

Phase 3 — Medium (noticeable issues)

ID Category Finding Status
M1 Perf VD server flushes after every frame on localhost — unnecessary syscall v0.8.0
M2 Perf checkStackEmpty() blocks command reader 500ms — touch blackout after Back v0.8.1
M3 Perf Multi-touch sends N separate frames per MOVE — should batch all pointers v0.8.3
M4 Perf MotionEvent PointerProperties/Coords allocated per injection — pool these v0.8.1
M5 Perf Decoder frame queue 6 deep (200ms) — reduce to 2-3 for lower latency v0.8.1
M6 Perf execFast("cmd display power-off 0") on touch thread — move to timer v0.8.1
M7 Stability Double cleanup() in VD server — handleClient finally + run both call it v0.7.2
M8 Stability cleanupSession() doesn’t reset _serviceState — stale UI during delay v0.7.2
M9 Stability Static MutableStateFlow in companion survives service restarts — stale activeConnection v0.7.2
M10 Flow User disconnect (eject) not persisted — car reconnects after process kill v0.8.3
M11 Flow Car mDNS + gateway IP probe one-shot — need periodic retry v0.7.3
M12 Flow dumpsys activity parsing in checkStackEmpty fragile across Android versions v0.8.2

Phase 4 — Low (polish)

ID Category Finding Status
L1 Perf TouchEvent.encode() allocates 25-byte ByteArray per event — can’t pool with async write queue WONTFIX
L2 Perf VD server localhost socket missing send/receive buffer size config v0.8.2
L3 Perf Video decoder uses fixed 33,333us timestamp — should use wall clock v0.8.2
L4 Stability NioReader direct ByteBuffer not freed deterministically v0.8.3
L5 Stability UsbAdbConnection.readFile() doesn’t guarantee full read v0.8.2
L6 Stability SurfaceScaler HandlerThread never quit v0.8.2
L7 Flow App icons 48x48px — blurry on car displays, need 96-128px v0.8.2

Known Issues

Issue Impact Status
USB ADB auth dialog on replug Phone asked “Allow USB debugging?” each time FIXED v0.13.1 — was double-hashing AUTH_TOKEN with SHA1withRSA. Now uses NONEwithRSA + prehashed SHA-1 DigestInfo. “Always allow” persists.
VD server dies on USB disconnect Stream stops if USB unplugged Accepted — setsid/nohup detachment broke localhost connectivity. Car re-deploys on reconnect.
Touch injection wakes physical display Screen turns on briefly during interaction Mitigated with throttled re-power-off (1s, on background thread)
Portrait apps letterboxed on landscape VD Petal Maps home screen narrow Android limitation
Hotspot must be enabled manually User enables before plugging in Android 16 limitation

Architecture (Current)

Phone (Xiaomi 17 Pro Max, HyperOS 3, Android 16)
├── DiLink Auto Client App
│   ├── ConnectionService (3-port accept: 9637/9638/9639)
│   │   ├── Control (9637): handshake, heartbeat, commands, data, car logs
│   │   ├── Video (9638): H.264 relay from VD server to car
│   │   ├── Input (9639): touch events from car, dispatched on Dispatchers.IO
│   │   ├── VD JAR deploy to /sdcard/DiLinkAuto/ (CRC32 checked)
│   │   ├── Car auto-update: sends UPDATING_CAR, then dadb push+install
│   │   ├── Smart network callback (ignores unrelated network drops)
│   │   ├── Battery exemption (REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
│   │   └── FileLog: /sdcard/DiLinkAuto/client.log (rotation, 10 max)
│   ├── VirtualDisplayClient (videoConnection + controlConnection)
│   │   ├── startListening() — synchronous ServerSocket on localhost:19637
│   │   ├── acceptConnection() — NIO non-blocking accept
│   │   ├── NioReader (Selector-based, FRAME_INTERVAL_MS timeout)
│   │   └── Video relay via videoConnection, stack empty via controlConnection
│   └── NotificationService (captures phone notifications with progress)
│
├── VD Server (app_process, shell UID 2000)
│   ├── NIO write queue (ConcurrentLinkedQueue) + Selector-based command reader
│   ├── IInputManager injection (ServiceManager → injectInputEvent)
│   ├── Multi-touch: pre-allocated PointerProperties/Coords pools (10 slots)
│   ├── VirtualDisplay (TRUSTED + OWN_DISPLAY_GROUP + OWN_FOCUS)
│   ├── SurfaceScaler (EGL/GLES GPU downscale, skips GL work on idle, encoder repeat-previous-frame)
│   ├── H.264 encoder (8Mbps CBR, Main profile, configurable FPS, backpressure at 6 frames)
│   ├── Screen power-off (background thread, proximity/lift disabled)
│   └── Reverse NIO connection to phone on localhost:19637
│
Car (BYD DiLink 3.0, Android 10)
├── DiLink Auto Server App
│   ├── CarConnectionService — 3 connections + parallel USB track
│   │   ├── controlConnection (9637): heartbeat, commands, data
│   │   ├── videoConnection (9638): video frames → VideoDecoder
│   │   ├── inputConnection (9639): touch events from MirrorScreen
│   │   ├── Track B (USB): UsbAdbConnection with logSink → carLogSend
│   │   ├── UPDATING_CAR handling: shows status, skips reconnect
│   │   ├── Early decoder start: offscreen surface on first CONFIG
│   │   ├── carLogSend() + logSink callbacks → phone FileLog
│   │   └── Eject state persisted to SharedPreferences
│   ├── VideoDecoder (queue=15, early start, logSink, 4-zone catchup)
│   ├── PersistentNavBar (76dp, 40dp icons, 14sp text, recent apps pruned)
│   ├── LauncherScreen (64dp icons, 160dp grid, imePadding search)
│   ├── NotificationScreen (progress bars, tap-to-launch, dedup by ID)
│   └── MirrorScreen (TextureView + touch forwarding, decoder restart)

Connection Flow

1. Phone app starts → deploys VD JAR, rotates FileLog, requests battery exemption
2. Phone plugged into car USB → car detects USB_DEVICE_ATTACHED
3. Track A (WiFi): car discovers phone via gateway IP (3s retry) or mDNS
4. Track B (USB): car connects USB ADB (logSink for diagnostics), launches phone app
5. Control (9637): TCP connect → handshake (viewport + DPI + version + targetFps)
6. Phone: checks version → if mismatch, sends UPDATING_CAR → auto-updates via dadb
7. Video (9638) + Input (9639): car connects in parallel after handshake
8. Phone: accepts both, opens VD ServerSocket on localhost:19637
9. USB: car starts VD server (shellNoWait + exec app_process, FPS as arg)
10. VD server: VD + SurfaceScaler (periodic re-draw) + encoder → NIO connect localhost:19637
11. Car: starts VideoDecoder on offscreen surface on first CONFIG frame
12. MirrorScreen shows → decoder restarts with real TextureView surface
13. Video: VD → SurfaceScaler → encoder → NIO write queue → localhost → phone NioReader → videoConnection → WiFi TCP → car NioReader → VideoDecoder → TextureView
14. Touch: car TextureView → inputConnection → WiFi TCP → phone (Dispatchers.IO) → VD server NIO Selector → IInputManager injection
15. Car logs: carLogSend() + logSink callbacks → DATA CAR_LOG → phone FileLog