Skip to content

deps(deps): bump com.github.mik3y:usb-serial-for-android from 3.7.0 to v3.10.0#636

Open
dependabot[bot] wants to merge 2 commits into
mainfrom
dependabot/gradle/com.github.mik3y-usb-serial-for-android-v3.10.0
Open

deps(deps): bump com.github.mik3y:usb-serial-for-android from 3.7.0 to v3.10.0#636
dependabot[bot] wants to merge 2 commits into
mainfrom
dependabot/gradle/com.github.mik3y-usb-serial-for-android-v3.10.0

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Mar 9, 2026

Copy link
Copy Markdown
Contributor

Bumps com.github.mik3y:usb-serial-for-android from 3.7.0 to v3.10.0.

API Changes Required

SerialInputOutputManager no longer implements Runnable in v3.10.0. It now manages its own read/write threads internally via start()/stop(). The following changes were made to KotlinUSBBridge.kt:

  • Replaced ioExecutor.submit(manager) with manager.start() (2 call sites)
  • Removed ioExecutor (SingleThreadExecutor) and ioManagerFuture fields — no longer needed
  • Rewrote waitForManagerStop() to poll manager.state instead of Future.get()

Manual USB Testing Required

This is a 3-minor-version jump (3.7.0 → 3.10.0) with a breaking API change in the threading model. Extensive manual testing with physical USB serial hardware is required before merge:

  • USB serial connect — Plug in FTDI/CP210x/CH340 adapter, verify device detection and connection
  • Data read/write — Send data over serial, verify no corruption or dropped bytes
  • Hot-plug — Unplug/replug during active connection, verify cleanup and reconnect
  • RNS over serial — Full Reticulum traffic over USB serial to another node
  • DFU/raw mode — enableRawMode/disableRawMode cycle (firmware flashing path)
  • Multiple devices — Connect 2+ USB serial devices simultaneously if supported

Original Dependabot description:

Dependabot compatibility score

Note
Automatic rebases have been disabled on this pull request as it has been open for over 30 days.

Bumps com.github.mik3y:usb-serial-for-android from 3.7.0 to v3.10.0.

---
updated-dependencies:
- dependency-name: com.github.mik3y:usb-serial-for-android
  dependency-version: v3.10.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
// Use api() so KotlinUSBBridge types are accessible to app module
api("com.github.mik3y:usb-serial-for-android:3.7.0")
api("com.github.mik3y:usb-serial-for-android:v3.10.0")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The usb-serial-for-android library upgrade requires changing how SerialInputOutputManager is started. The current use of ioExecutor.submit(manager) will silently fail, breaking USB communication.
Severity: CRITICAL

Suggested Fix

In KotlinUSBBridge.kt, replace the deprecated ioExecutor.submit(manager) calls in both the connect() and disableRawMode() methods with the new API call, ioManager.start(), to correctly start the serial I/O manager.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: reticulum/build.gradle.kts#L70

Potential issue: The upgrade of the `usb-serial-for-android` library to v3.10.0
introduces a breaking change from v3.9.0 that is not accounted for. The
`SerialInputOutputManager` is initialized using `ioExecutor.submit(manager)` in the
`connect()` and `disableRawMode()` methods within `KotlinUSBBridge.kt`. This pattern is
deprecated and will cause the I/O manager to fail to start silently at runtime. As a
result, no data will be read from connected USB devices, breaking all RNode USB
communication which is a core feature of the application.

Did we get this right? 👍 / 👎 to inform future reviews.

@sentry

sentry Bot commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

SerialInputOutputManager no longer implements Runnable in v3.10.0.
Replace ioExecutor.submit(manager) with manager.start() which now
manages its own read/write threads internally. Remove the ioExecutor
and ioManagerFuture fields that are no longer needed. Rewrite
waitForManagerStop to poll manager.state instead of Future.get().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@torlando-tech

Copy link
Copy Markdown
Owner

@greptileai

@greptile-apps

greptile-apps Bot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR bumps com.github.mik3y:usb-serial-for-android from 3.7.0 to v3.10.0 and adapts KotlinUSBBridge to the library's breaking threading-model change: SerialInputOutputManager no longer implements Runnable, so the old ioExecutor.submit(manager) pattern is replaced with manager.start()/manager.stop(), and the waitForManagerStop helper is rewritten to poll manager.state instead of blocking on a Future.

Key changes:

  • build.gradle.kts: version string updated to v3.10.0
  • KotlinUSBBridge.kt: both manager.start() call sites updated; ioExecutor (SingleThreadExecutor), ioManagerFuture, and ioExecutor.shutdown() removed; waitForManagerStop rewritten as a 500 ms state-polling loop
  • One style issue found: Thread.sleep(10) inside waitForManagerStop does not catch InterruptedException, which could leave the thread interrupt flag unset and skip drainPortAfterManagerStop() / readBuffer.clear() if the calling thread is interrupted during DFU/raw-mode transitions
  • The PR description correctly flags this as a 3-minor-version jump requiring extensive manual USB hardware testing before merge

Confidence Score: 4/5

  • Safe to merge after resolving the InterruptedException handling issue and completing the manual USB hardware testing checklist.
  • The API migration is correct and complete — all call sites updated, unused fields removed cleanly. The only code-level concern is the unhandled InterruptedException in the polling loop, which is a low-severity style issue unlikely to trigger in practice but worth fixing. The bigger risk is the 3-minor-version library jump, which the author has appropriately flagged as requiring physical USB testing before merge.
  • reticulum/src/main/java/com/lxmf/messenger/reticulum/usb/KotlinUSBBridge.kt — specifically the waitForManagerStop polling loop and the manual testing checklist items in the PR description.

Important Files Changed

Filename Overview
reticulum/build.gradle.kts Version bump of usb-serial-for-android from 3.7.0 to v3.10.0; straightforward single-line change with no other side effects.
reticulum/src/main/java/com/lxmf/messenger/reticulum/usb/KotlinUSBBridge.kt Adapts to the v3.10.0 API change: replaces ioExecutor.submit(manager) with manager.start() at both call sites, removes the now-unused ioExecutor/ioManagerFuture fields, and rewrites waitForManagerStop to poll manager.state. Minor issue: Thread.sleep(10) inside the polling loop does not handle InterruptedException, which can leave the thread's interrupt flag unrestored and skip post-stop cleanup steps in enableRawMode.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant KotlinUSBBridge
    participant SerialInputOutputManager

    Note over KotlinUSBBridge,SerialInputOutputManager: connect() / disableRawMode()
    KotlinUSBBridge->>SerialInputOutputManager: new SerialInputOutputManager(port, listener)
    KotlinUSBBridge->>SerialInputOutputManager: manager.start()
    Note right of SerialInputOutputManager: Manages own read/write threads internally (v3.10.0+)
    SerialInputOutputManager-->>KotlinUSBBridge: onNewData(data) callbacks

    Note over KotlinUSBBridge,SerialInputOutputManager: enableRawMode() / disconnect()
    KotlinUSBBridge->>SerialInputOutputManager: manager.stop()
    loop Poll every 10ms (up to 500ms)
        KotlinUSBBridge->>SerialInputOutputManager: check manager.state
        SerialInputOutputManager-->>KotlinUSBBridge: state (RUNNING | STOPPING | STOPPED)
    end
    KotlinUSBBridge->>KotlinUSBBridge: drainPortAfterManagerStop() [raw mode only]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: reticulum/src/main/java/com/lxmf/messenger/reticulum/usb/KotlinUSBBridge.kt
Line: 1075-1085

Comment:
**`InterruptedException` not handled in polling loop**

`Thread.sleep(10)` can throw `InterruptedException`. If the calling thread is interrupted while waiting, the exception propagates uncaught out of `waitForManagerStop` and then out of `enableRawMode`, skipping both `drainPortAfterManagerStop()` and `readBuffer.clear()` — leaving the read buffer dirty and the thread's interrupt flag unrestored. The standard practice is to catch `InterruptedException` inside the loop and re-set the interrupt flag so callers can observe it.

```suggestion
    private fun waitForManagerStop(manager: SerialInputOutputManager) {
        val deadline = System.currentTimeMillis() + 500
        while (manager.state != SerialInputOutputManager.State.STOPPED &&
            System.currentTimeMillis() < deadline
        ) {
            try {
                Thread.sleep(10)
            } catch (e: InterruptedException) {
                Thread.currentThread().interrupt()
                break
            }
        }
        if (manager.state != SerialInputOutputManager.State.STOPPED) {
            Log.w(TAG, "Timeout waiting for SerialInputOutputManager to stop (state=${manager.state})")
        }
    }
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 1023371

Comment on lines +1075 to 1085
private fun waitForManagerStop(manager: SerialInputOutputManager) {
val deadline = System.currentTimeMillis() + 500
while (manager.state != SerialInputOutputManager.State.STOPPED &&
System.currentTimeMillis() < deadline
) {
Thread.sleep(10)
}
if (manager.state != SerialInputOutputManager.State.STOPPED) {
Log.w(TAG, "Timeout waiting for SerialInputOutputManager to stop (state=${manager.state})")
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InterruptedException not handled in polling loop

Thread.sleep(10) can throw InterruptedException. If the calling thread is interrupted while waiting, the exception propagates uncaught out of waitForManagerStop and then out of enableRawMode, skipping both drainPortAfterManagerStop() and readBuffer.clear() — leaving the read buffer dirty and the thread's interrupt flag unrestored. The standard practice is to catch InterruptedException inside the loop and re-set the interrupt flag so callers can observe it.

Suggested change
private fun waitForManagerStop(manager: SerialInputOutputManager) {
val deadline = System.currentTimeMillis() + 500
while (manager.state != SerialInputOutputManager.State.STOPPED &&
System.currentTimeMillis() < deadline
) {
Thread.sleep(10)
}
if (manager.state != SerialInputOutputManager.State.STOPPED) {
Log.w(TAG, "Timeout waiting for SerialInputOutputManager to stop (state=${manager.state})")
}
}
private fun waitForManagerStop(manager: SerialInputOutputManager) {
val deadline = System.currentTimeMillis() + 500
while (manager.state != SerialInputOutputManager.State.STOPPED &&
System.currentTimeMillis() < deadline
) {
try {
Thread.sleep(10)
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
break
}
}
if (manager.state != SerialInputOutputManager.State.STOPPED) {
Log.w(TAG, "Timeout waiting for SerialInputOutputManager to stop (state=${manager.state})")
}
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: reticulum/src/main/java/com/lxmf/messenger/reticulum/usb/KotlinUSBBridge.kt
Line: 1075-1085

Comment:
**`InterruptedException` not handled in polling loop**

`Thread.sleep(10)` can throw `InterruptedException`. If the calling thread is interrupted while waiting, the exception propagates uncaught out of `waitForManagerStop` and then out of `enableRawMode`, skipping both `drainPortAfterManagerStop()` and `readBuffer.clear()` — leaving the read buffer dirty and the thread's interrupt flag unrestored. The standard practice is to catch `InterruptedException` inside the loop and re-set the interrupt flag so callers can observe it.

```suggestion
    private fun waitForManagerStop(manager: SerialInputOutputManager) {
        val deadline = System.currentTimeMillis() + 500
        while (manager.state != SerialInputOutputManager.State.STOPPED &&
            System.currentTimeMillis() < deadline
        ) {
            try {
                Thread.sleep(10)
            } catch (e: InterruptedException) {
                Thread.currentThread().interrupt()
                break
            }
        }
        if (manager.state != SerialInputOutputManager.State.STOPPED) {
            Log.w(TAG, "Timeout waiting for SerialInputOutputManager to stop (state=${manager.state})")
        }
    }
```

How can I resolve this? If you propose a fix, please make it concise.

@dependabot @github

dependabot Bot commented on behalf of github Mar 30, 2026

Copy link
Copy Markdown
Contributor Author

A newer version of com.github.mik3y:usb-serial-for-android exists, but since this PR has been edited by someone other than Dependabot I haven't updated it. You'll get a PR for the updated version as normal once this PR is merged.

@serialrf433

Copy link
Copy Markdown
Contributor

A newer version of com.github.mik3y:usb-serial-for-android exists, but since this PR has been edited by someone other than Dependabot I haven't updated it. You'll get a PR for the updated version as normal once this PR is merged.

This is interesting. Where? I just see the same version like before to be the latest one: https://github.com/mik3y/usb-serial-for-android/releases

I have read a bit in the repo. It looks like the version currently in columba have known issues with serial data loss. The higher the serial speed, the more data is getting lost. This is one of the reasons why this new version got released to fix this issue. Maybe some of the inconsistencies there was, was exactly because of the serial data loss in the old version currently implemented.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants