Skip to content
This repository was archived by the owner on Oct 18, 2026. It is now read-only.

Apply the review fixes from ytai/ioio#466 and #468 - #2

Merged
lordfolken merged 4 commits into
e6d2474+xcsoarfrom
accessory-review-fixes
Oct 17, 2026
Merged

lordfolken merged 4 commits into
e6d2474+xcsoarfrom
accessory-review-fixes

Conversation

@dspreitz

@dspreitz dspreitz commented Oct 17, 2026 •

Copy link
Copy Markdown

Review on the upstream PRs found three races in the accessory connection and an API-level problem in the socket bootstrap that #1 also carries:

  • A disconnect() between the state check and waitForOpen() was lost: waitForOpen() set shouldTryOpen_ again and, without an accessory, waited forever. The check and the open now hold the lock together; only the handshake runs without it.
  • A disconnect() after the handshake but before CONNECTED was overwritten (commit by @hannesa2).
  • A cancelled connection could still be in its handshake while a new one opened, and the descriptor, the streams and shouldTryOpen_ were shared: it could write to the new connection's stream, take its handshake reply or close its descriptor. Each connection now keeps its own descriptor and streams.
  • InetAddress.getLoopbackAddress() is API 19 while the library declares minSdk 14; the address is now built from its bytes.

All four compile against android-34 with javac 21. Tested on an IOIO-OTG (SPRK0020, firmware IOIO0506) behind an LXNAV S10 with a Pixel 3a, through XCSoar built with this branch (66c80028): connect, exit while connected or while connecting, and unplug/replug while running all work; details in ytai#466. Restarting without replugging right after a connected session still hangs in the handshake (Android OpenAccessory bug), but the hang can now be cancelled.

hannesa2 and others added 3 commits October 17, 2026 08:35
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Since the handshake left the lock, a disconnect() between the state
check and waitForOpen() was lost: waitForOpen() set shouldTryOpen_
again, and without an accessory the thread waited forever.  Check the
state and open under one lock; only the handshake runs without it.
An instance that was disconnected before waitForConnect() reports a
lost connection.
InetAddress.getLoopbackAddress() exists on Android only since API 19,
and the library declares minSdkVersion 14: on API 14 to 18, opening
the socket bootstrap threw NoSuchMethodError.  Build the address from
its bytes instead; adbd and "adb forward" connect to 127.0.0.1.
@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: dd9e0047-ee6d-48f3-8b72-30dff2d15fde

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Since the handshake runs without the lock, a cancelled connection A
could still be in its handshake while a new connection B opens.  The
descriptor, the streams and shouldTryOpen_ lived in the bootstrap,
shared by all connections: A wrote to B's stream and could take B's
handshake reply, B set shouldTryOpen_ again so that A was no longer
cancelled, and A's failed handshake closed B's descriptor.

Keep the descriptor and the streams in the Connection, and end
waitForOpen() and the handshake on that connection's own state.
disconnect() closes only that connection's descriptor; the permission
request is cancelled when a connection that is still opening gives
up, and dropped once the accessory is open.
@hannesa2

Copy link
Copy Markdown

I would recommend to use upstream and fix issues there. I'll approve it for sure

@lordfolken
lordfolken merged commit b1dcfac into e6d2474+xcsoar Oct 17, 2026
3 of 4 checks passed
@lordfolken
lordfolken deleted the accessory-review-fixes branch October 17, 2026 14:57
@lordfolken

Copy link
Copy Markdown
Member

I d love to not having maintain a fork. We will switch once its all upstreamed.

lordfolken pushed a commit to XCSoar/XCSoar that referenced this pull request Oct 17, 2026
All of the IOIOLib fixes XCSoar needs are now in upstream master:
the accessory handshake outside the lock and its connection races
(ytai/ioio#466), canClose() (#465), the disconnect deadlock (#469),
the USB permission read from UsbManager (#471), the loopback-only
socket (#468), the other #470-#474 fixes, and the fallback to
interface IOIO0003 for older firmware such as the Androport's (#485).

The XCSoar/ioio fork is no longer needed, so point the submodule at
ytai/ioio directly.  74c87c6 lacked the race fixes from XCSoar/ioio#2
and the permission fix.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants