Skip to content

fix(android): prevent app crashes when USB devices disconnect - #43

Merged
s00d merged 4 commits into
s00d:mainfrom
barbarbar338:main
Oct 14, 2026
Merged

s00d merged 4 commits into
s00d:mainfrom
barbarbar338:main

Conversation

@barbarbar338

@barbarbar338 barbarbar338 commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

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 found failure.

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 Disconnected for 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-bridge that runs in CI on Ubuntu (cargo test --manifest-path tests/jni-bridge/Cargo.toml, requires a JDK).

Written for commit ff01912. Summary will update on new commits.

View guided diff

Copilot AI lite review requested due to automatic review settings September 27, 2026 16:30
@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 10 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread tests/jni-bridge/Cargo.toml
barbarbar338 and others added 2 commits October 14, 2026 01:18
Apply rustfmt formatting to the Android serial compatibility code and desktop API test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@s00d

s00d commented Oct 14, 2026

Copy link
Copy Markdown
Owner

@cubic

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 14, 2026

Copy link
Copy Markdown

@cubic

@s00d I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 13 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/jni-bridge/.gitignore">

<violation number="1" location="tests/jni-bridge/.gitignore:2">
P2: Ignoring this standalone harness's `Cargo.lock` lets its floating dependencies resolve differently over time, making regression results less reproducible. Remove this ignore so the harness lockfile can be committed.</violation>
</file>

Click Fix with cubic on a comment, or reply @cubic-dev-ai fix this, and cubic writes the fix.

View guided diff | Re-trigger cubic

@@ -0,0 +1,2 @@
/target/
/Cargo.lock

@cubic-dev-ai cubic-dev-ai Bot Oct 14, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Ignoring this standalone harness's Cargo.lock lets its floating dependencies resolve differently over time, making regression results less reproducible. Remove this ignore so the harness lockfile can be committed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At tests/jni-bridge/.gitignore, line 2:

<comment>Ignoring this standalone harness's `Cargo.lock` lets its floating dependencies resolve differently over time, making regression results less reproducible. Remove this ignore so the harness lockfile can be committed.</comment>

<file context>
@@ -0,0 +1,2 @@
+/target/
+/Cargo.lock
</file context>
Fix with cubic

@s00d
s00d merged commit 70371fc into s00d:main Oct 14, 2026
4 of 5 checks passed
@s00d

s00d commented Oct 14, 2026

Copy link
Copy Markdown
Owner

Thanks a lot for this PR — really solid work.

The root cause and the fix were spot on: pending Java exceptions after a failed USB JNI call were escaping during native-thread teardown and crashing the Android app on dongle unplug/reconnect. Clearing/mapping those exceptions in with_env (including secondary failures while reading the exception message), plus rejecting I/O/control on closed handles with Disconnected, is exactly what we needed. The regression coverage (tests/jni-bridge + disconnect tests) and the Equinno real-device confirmation were especially helpful.

After merge we followed up on the CI/tooling side that was blocking the green check:

  • Fixed android-integration setup — android-actions/setup-android@v3 defaulted to the removed SDK tools package (sdkmanager exit 1).
  • Wired Android Lint + a Gradle-compatible JDK picker (scripts/java-home-for-gradle.sh) so local/CI runs don’t blow up on newer JDKs (e.g. 27).
  • Committed the jni-bridge Cargo.lock for reproducible harness runs.

This shipped in v3.0.8 / v3.0.9 (android-usb-serial 0.1.2). Appreciate the careful JNI/Android debugging — thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants