Skip to content

fix(android): let a newer host replace a session that went quiet - #32

Merged
heoblitz merged 1 commit into
toss:feature/android-supportfrom
easyhooon:feature/android-reconnect
Oct 30, 2026
Merged

heoblitz merged 1 commit into
toss:feature/android-supportfrom
easyhooon:feature/android-reconnect

Conversation

@easyhooon

Copy link
Copy Markdown

Summary

Fixes the reconnect after a cable replug reported in #31: the Android app stayed out of Necto until it was restarted.

Cause. NectoSdkRuntime.serve handled one session to the end before it called accept() again. After an unplug the phone kept the old connection established, so the runtime stayed blocked reading it, and the Mac's probes after the replug piled up in the backlog. handle() already closed a previous session when a new one arrived, but a second one never got that far.

Fix.

  • Each accepted connection is handled in its own coroutine, so accepting never waits on a session.
  • A connection replaces the current session only once its handshake is accepted. Until then the working session, its requests and its status are left alone, so a connection that never answers, or is refused, cannot end it.
  • stop() also closes connections that are still handshaking, since their reads block and are not woken by cancellation.

Tests

  • aNewerHostReplacesOneThatWentQuiet: a connected host goes silent, a second host handshakes, the first is closed and the second answers test.echo. On the old runtime this test hangs.
  • aHostStillSayingHelloLeavesTheConnectedOneAlone: a second connection that has only read the hello, then is refused, leaves the first answering and the status Connected.
  • SDK/Android/gradlew -p SDK/Android test passes.

Device check

Galaxy S25+ over USB, script/android-sample R3CY70P3F4H, then unplug and replug without touching the app:

Time Necto lists the app ADB sees the phone
23:47:08 yes yes
23:47:24 (unplugged) no no
23:47:32 (plugged in) no yes
23:47:34 yes yes

After the replug, plugin send plugin-sample host.info answered, the app kept the same process, and /proc/net/unix showed only the listener and one connection.

Not in this PR

  • iOS has the same loop shape in NectoSDKRuntime.swift. I have not unplugged an iPhone, so I don't know whether usbmuxd closes the socket on the phone and hides this there.
  • Two Neccos on one app still don't work together. Before, the second waited in the backlog; now they would take the session from each other on every probe. This is no worse, but it isn't solved.
  • Possible follow-ups: a protocol level heartbeat so either side notices a dead connection without a new one arriving, or serving several hosts at once with per session state.

After the cable is pulled, the phone can keep the old connection open, and
the runtime handled one session to the end before accepting another, so the
Mac's probes after a replug waited in the backlog until the app restarted.

Each accepted connection is now handled on its own, and it replaces the
current session only once its handshake is accepted. A connection that
never answers, or is refused, leaves a working session and its status alone.
@heoblitz
heoblitz merged commit bebbfcd into toss:feature/android-support Oct 30, 2026
6 checks passed
@easyhooon easyhooon mentioned this pull request Nov 3, 2026
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.

2 participants