fix(android): prevent app crashes when USB devices disconnect
USB unplug can terminate an Android app when reconnect tries to open the removed device. openDeviceFd throws a Java exception, but with_env previously returned through ? before clearing it. The pending exception then escapes native-thread teardown as an uncaught Android exception.
This change always clears and maps pending Java exceptions before returning a JNI result, including exceptions raised while reading the original exception message. It also rejects I/O and control operations on closed USB handles, preventing stale adapter clones from panicking on endpoints cleared during detach.
Validation:
- Real-JVM regression reproduces the pending-exception leak with the old control flow and passes with the fix; all 5 harness tests pass.
- USB driver suite passes, including three new stale-handle/close/reopen regressions.
- The consuming Equinno Android app was rebuilt and tested by its owner, who confirmed that unplugging the dongle no longer crashes the app. Wireless logcat captured the original
ExecutionException: IOException: device not foundfailure.
The JNI harness runs independently of desktop Tauri/WebView dependencies: cargo test --manifest-path tests/jni-bridge/Cargo.toml (requires a JDK and JAVA_HOME).
Summary by cubic
Prevents Android crashes when USB devices disconnect. The JNI bridge now clears and maps pending Java exceptions before returning from failed USB operations, so they no longer escape during native-thread teardown. Closed serial handles reject I/O and control operations with Disconnected instead of panicking in stale adapter clones.
Bug Fixes
- Clears pending Java exceptions, including secondary exceptions raised while reading the original message.
- Closed handles return
Disconnectedfor read/write, line and flow control, DTR/RTS, break, purge, and reader setup. - Adds regression tests for the exception leak and stale handles, plus a desktop JNI harness at
tests/jni-bridgethat runs in CI on Ubuntu (cargo test --manifest-path tests/jni-bridge/Cargo.toml, requires a JDK).