EASession intermittently opens with an input stream that never delivers data, iOS 27

We use ExternalAccessory to talk to a smart card, i.e. a YubiKey 5Ci, over Lightning. On iOS 27.0, most EASession objects we open are unable to receive. NSStreamEventHasBytesAvailable never fires on the input stream and not one byte arrives, yet the session reports no problem anywhere.

Environment

iPhone 11, iOS 27.0 build 24A437 (public release), YubiKey 5Ci on Lightning, protocol com.yubico.ylp.

What we see on an affected session

both streams streamStatus        2 (NSStreamStatusOpen)
streamError on both              nil
NSStreamEventOpenCompleted       fires on both
hasSpaceAvailable before write   YES
write:maxLength:                 returns 18 of 18
NSStreamEventHasSpaceAvailable   fires
NSStreamEventErrorOccurred       never
NSStreamEventEndEncountered      never
NSStreamEventHasBytesAvailable   never fires
inputStream.hasBytesAvailable    false on every poll over 10 s

Everything reports success. Only the reply is missing.

Behaviour

A healthy session replies in single digit milliseconds. An affected one returns nothing at all, ever. The condition is set when the session is created and never changes. Opening another session on the same accessory is an independent roll of the dice. Quitting and relaunching the app does not help. Only physically detaching and reattaching the key does, after which connectionID increments and the next session works.

15 of 25 sessions affected on 24A437. Also 9 of 20 on the 24A5430a beta, so it predates the public release.

Already ruled out

Not a late reply, we waited 10 s. Not a missed event, we polled hasBytesAvailable directly about 200 times per failure. Not a leaked session, teardown is instrumented and every session deallocates exactly once. Not the hardware, another app on the same phone and key reads its serial and firmware every time, and that app opens one session and never closes it. The USB C interface of the same key, via CryptoTokenKit, never fails.

Questions

  1. Is there any supported way to tell at creation time that an EASession input stream will not deliver data? Nothing we can read distinguishes the two cases.

  2. Is repeatedly creating and releasing EASession objects for the same accessory and protocol supported, and is any teardown step needed beyond clearing the delegates, closing the streams, removing them from the run loop and releasing the session?

  3. Is there a supported way to recover without asking the user to unplug the accessory?

On iOS 27.0, most EASession objects we open are unable to receive. NSStreamEventHasBytesAvailable never fires on the input stream, and not one byte arrives, yet the session reports no problem anywhere.

Have you filed a bug on this and, if so, what is the bug number?

  1. Is there any supported way to tell at creation time that an EASession input stream will not deliver data? Nothing we can read distinguishes the two cases.

No. I'm not sure what actually went wrong, but I suspect it happened in the lower-level system, outside your app’s visibility or control.

  1. Is repeatedly creating and releasing EASession objects for the same accessory and protocol supported, and is any teardown step needed beyond clearing the delegates, closing the streams, removing them from the run loop, and releasing the session?

Yes, this should "work“; however, I wouldn't expect it to get your accessory working. If the problem happened in the lower-level system, then you'll generally end up just creating and destroying connections to the same object/infrastructure without anything actually changing.

  1. Is there a supported way to recover without asking the user to unplug the accessory?

This is the only option I'd consider reliable.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

EASession intermittently opens with an input stream that never delivers data, iOS 27
 
 
Q