πŸ”„ Reconnection System

March 29, 2026 Β· View on GitHub

← Back to README

Everything about how Android DEX detects, handles, and recovers from connection loss β€” in one place. Phases, triggers, failure states, UI behaviour, and the overlay system.


Overview

Once the boot sequence completes successfully, ReconnectionManager takes over as the connection watchdog. It monitors both the Logic Engine (JAR) and Feature Hub (APK) connections independently, and executes a two-phase recovery strategy when either drops.

Boot Complete
     β”‚
     β–Ό
ReconnectionManager.startMonitoring()
     β”‚
     β–Ό  (Listens to ValueNotifier<bool>)
AndroidCore.jarConnected ──┐
AndroidCore.apkConnected ──┴──► _onConnectionChanged()
                                        β”‚
                            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                            β”‚  Is _busy? β†’ skip       β”‚
                            β”‚  Both connected? β†’ idle β”‚
                            └───────────┬────────────-β”˜
                                        β”‚
                                        β–Ό
                                  Begin Recovery

Recovery Phases

Phase 1 β€” Quick Reconnect

Triggered: Immediately on first disconnection detected
Goal: Re-establish the ADB link and restore TCP/WebSocket connections without re-deploying anything

Quick Reconnect
     β”‚
     β”œβ”€ adb connect [device ip or -d]
     β”œβ”€ adb reverse tcp:PORT tcp:PORT  (all ports)
     β”œβ”€ Wait for JAR to reconnect (if jarReconnecting)
     └─ Wait for APK to reconnect (if apkReconnecting)
          β”‚
          β”œβ”€ Both reconnected? β†’ phase: idle (success) βœ“
          └─ Failed? β†’ proceed to Phase 2

User Message: "Attempting to reconnect to device…"
UI: Reconnecting overlay shown; desktop apps frozen


Phase 2 β€” Full Restart (up to 2 attempts)

Triggered: Quick reconnect failed
Goal: Re-deploy the Logic Engine and re-launch the companion APK service from scratch

Full Restart (attempt 1 of 2)
     β”‚
     β”œβ”€ stopJar() ── kill existing process
     β”œβ”€ killJar() ── kill Android-side JAR
     β”œβ”€ pushJar() ── re-upload service module
     β”œβ”€ startJarRuntime() ── re-launch process
     β”œβ”€ startServerService() ── re-trigger APK service
     β”œβ”€ Wait for jar.hello + apk.hello
     β”‚
     β”œβ”€ Success? β†’ phase: idle βœ“
     └─ Failed?  β†’ Full Restart (attempt 2 of 2)
                        β”‚
                        β”œβ”€ Success? β†’ phase: idle βœ“
                        └─ Failed?  β†’ phase: FAILED βœ—

User Message: "Performing full restart (attempt N of 2)…"


Phase: Failed

Triggered: Both full restart attempts failed
Result: Reconnection overlay shows a permanent error state

User Messages:

  • Disconnection (clean): "Device disconnected. Check your USB cable or Wi-Fi connection."
  • Unexpected error: "Reconnection failed unexpectedly. Try restarting the application."

State Model

enum ReconnectionPhase {
  idle,           // Connected β€” no action needed
  quickReconnect, // Phase 1 in progress
  fullRestart,    // Phase 2 in progress
  failed,         // All recovery attempts exhausted
}

class ReconnectionStatus {
  final ReconnectionPhase phase;
  final bool jarReconnecting;   // JAR component specifically recovering
  final bool apkReconnecting;   // APK component specifically recovering
  final String message;         // Current user-facing status message
  final int attempt;            // Current attempt number (1 or 2 in Phase 2)
}

The UI observes ReconnectionManager.instance.status (a ValueNotifier<ReconnectionStatus>) and updates the overlay in real-time.


Partial Disconnection

The system handles partial disconnections β€” where only one component drops:

ScenariojarReconnectingapkReconnectingRecovery Action
JAR drops, APK finetruefalseOnly JAR-related steps run
APK drops, JAR finefalsetrueOnly APK-related steps run
Both droptruetrueFull recovery for both

Reconnecting Overlay

ReconnectingOverlay is a full-screen widget that appears over the desktop UI during recovery.

What it shows

  • Phase indicator β€” which phase is running
  • Component status β€” JAR and APK individual status pills
    • 🟑 Reconnecting...
    • πŸ”΄ Failed
    • 🟒 Connected
  • Attempt counter β€” "Attempt 1 of 2" during full restart
  • User message β€” plain-English status
  • Final error state β€” when phase == failed, shows the disconnect reason

What it prevents

The overlay blocks all user interaction with the desktop until either:

  • Recovery succeeds β†’ overlay dismisses automatically
  • Recovery fails β†’ overlay stays up with the error message

Monitoring Lifecycle

EventWhat ReconnectionManager does
startMonitoring() calledRegisters listeners on jarConnected + apkConnected notifiers
Connection dropsTriggers _onConnectionChanged() β†’ starts recovery if not _busy
Recovery succeedsSets phase = idle, clears _busy
Recovery failsSets phase = failed, clears _busy
App restartstartMonitoring() called again after next successful boot

Note: startMonitoring() is idempotent β€” calling it when already monitoring is a no-op.


← Back to README Β· Modules Β» Β· Data Model Β»