Highlights
🐛 RemoteXPC services no longer crash on a second request
RemoteXPC gives each side of a connection its own message-id parity: the connecting side's ids are odd, the listener's even. The client numbered its messages 0, 1, 2, 3, so every other request carried an even id, and a device daemon asked to reply to one aborts with Attempted to send non-reply msg on the reply channel. In practice only the first reply-wanting request on a connection was safe.
Requests are now numbered 1, 3, 5. Several reply-wanting requests on one connection work against notification_proxy, restoreserviced, cryptexd, the pasteboard service and the display service.
The workarounds this made unnecessary are gone: device-side restore preflight and pasteboard reads use one connection, and the touch session and RTP capture helpers stop a media stream on the connection that started it.
✨ Typed notification events
receive_notification() on NotificationProxyService and RemoteNotificationProxyService now yields NotificationEvent, a dataclass with command, name and state. It is still the dict the device sent, so existing code that subscripts it, compares it with a dict or serializes it to JSON keeps working.
state is the notification's 64-bit notify_get_state() value, which the secure proxy relays since iOS 27.2.
async with NotificationProxyService(lockdown) as proxy:
await proxy.notify_register_dispatch("com.apple.springboard.lockstate")
async for event in proxy.receive_notification():
print(event.name, event.state)✨ TimeSyncService: measure the device clock
com.apple.timed.remote answers SNTP requests carried as RemoteXPC messages. TimeSyncService uses it to measure how far the device clock is from the host's, to well under a millisecond. It is a library API (no CLI command), needs an RSD tunnel and was verified on iOS 27.2. The service only answers; it cannot set the device time.
from pymobiledevice3.services.timesync import TimeSyncService
async with TimeSyncService(rsd) as timesync:
sample = await timesync.measure()
print(sample.offset, sample.delay)What's Changed
- dd17e32 notification_proxy: Yield typed notification events (#2004) (@doronz88)
- f89957e timesync: Add the timed remote clock service (#2003) (@doronz88)
- ad994cd cryptexd: Drop the one-routine-per-connection claim (#2003) (@doronz88)
- 09b0524 display: Stop a media stream on the connection that started it (#2003) (@doronz88)
- 136bb30 pasteboard: Read the pasteboard over one connection (#2003) (@doronz88)
- d970ebc restore: Collect device-side preflight over one connection (#2003) (@doronz88)
- 635d81d notification_proxy: Accept the relay State added in iOS 27.2 (#2003) (@doronz88)
- 283b621 remotexpc: Number requests with odd message ids (#2003) (@doronz88)
Full Changelog: v11.23.1...v11.24.0