Summary
An Honor device connected via USB debugging suddenly stopped providing log output and hot reload functionality after a successful flutter run. The Gradle build and APK installation completed, but the observatory/VM service connection failed to establish silently. This broke log streaming, stdin command processing (hot reload/restart), and debugging. The root cause was likely a USB cable/port issue or an Android OS-level security/prompt that blocked the Dart VM binding, not a code or project configuration error.
Root Cause
- Failed VM Service Handshake: The Flutter tool relies on the device notifying the host machine when the Dart VM starts and on which port (typically ephemeral, e.g.,
127.0.0.1:54321). This is done via JDWP (Java Debug Wire Protocol) port forwarding. When this notification is missed or blocked,flutterthinks the app is running but disconnected. - ADB Connection Instability: The physical connection between the PC and the Honor phone became unstable. While
adb installsucceeded (pushing the file), the continuousadb logcatstream required for live logs and theadb reverse/forwarding required for hot reload dropped packets or timed out. - Android 11+ “Wireless Debugging” Interference: If “Wireless Debugging” was toggled on the Honor phone, it can conflict with standard USB debugging, hijacking the connection port or requiring a new pairing code that
fluttercannot prompt for automatically. - Aggressive Battery Optimization/OS Kill: Honor/Huawei devices have aggressive power management (PowerGenie). If the OS detected the debug bridge as “heavy” or “background,” it might have suspended the process communication without killing the app UI itself.
Why This Happens in Real Systems
- Ephemeral Ports: Flutter uses dynamic ports for the VM service. If the port mapping in
adbdrops, the tools cannot find where to send commands like “reload.” - ADB Transport Layer: ADB is not a robust network protocol; it’s a multiplexing stream over USB. High I/O load (during
assembleDebug) or loose USB contacts can desynchronize the stream state, causing a “zombie” session where the install finishes but the shell listener dies. - OEM Android Skins: Manufacturers like Honor often modify the Android framework to aggressively kill background processes or restrict debugging interfaces to save battery, which violates standard Android behavior expected by
flutter run.
Real-World Impact
- Zero Observability: Developers cannot see
print()statements,debugPrint(), or stack traces. This renders debugging effectively impossible. - Broken Developer Workflow: The standard cycle of Code -> Save -> Hot Reload -> Verify is broken. The developer must manually uninstall/reinstall the app on every change, increasing cycle time from seconds to minutes.
- False Positives: The build success message (
✓ Built...) makes it look like the tool worked, leading to confusion about why the code isn’t reflecting changes.
Example or Code
No code fixes this specific issue, but flutter doctor -v is the diagnostic tool. It reveals the “Attached” vs “Unattached” state of the specific device ID.
flutter doctor -v
How Senior Engineers Fix It
- Isolate the Physical Layer: Immediately swap the USB cable and try a different USB port (USB 2.0 ports are often more stable for debugging than 3.0 on older hardware).
- Reset the ADB Bridge: Don’t restart the whole machine; kill the
adbserver to force a clean handshake.- Run
adb kill-server - Run
adb start-server - Run
adb devicesto verify the device isauthorized.
- Run
- Clean the Pipe: Run
flutter cleanto wipe build artifacts. While the APK installed, cached connection metadata might be corrupted. - Force Explicit Connection: If
flutter runfails to attach, useflutter attach --device-id <your_device_id>. This decouples the build from the attach process, allowing you to see if the VM service is actually listening on a port. - Check for OS Prompts: Look at the phone screen for a “Allow USB Debugging?” prompt or a “Wireless Debugging Pairing” prompt that may be hidden behind other windows.
Why Juniors Miss It
- Attribution Error: Juniors often assume the code is broken or the project is misconfigured (e.g., “Did I break
main.dart?”) because the app UI launches fine. They don’t realize the transport layer (USB/Cable/ADB) is the culprit. - Symptom Confusion: They interpret “No Logs” as “App isn’t running,” not “App is running but disconnected from the host.”
- Reliance on IDE: They rely entirely on VS Code or Android Studio’s visual debug buttons. When those fail, they don’t know how to use the CLI (
flutter run --verbose) to see the raw output where connection errors usually appear.