Files
ArjenandJohnathan Corgan d208a9db81 feat(ble): lend the radio to the macOS daemon from a login-session agent
macOS never grants Bluetooth to a root launchd daemon: CoreBluetooth
answers it Unauthorized whatever the privacy settings say, so the
packaged daemon could not use the CoreBluetooth backend at all.

When CoreBluetooth refuses the daemon, it listens on ble-agent.sock
beside the control socket (/var/run/fips, group fips), and a per-user
LaunchAgent runs `fips-ble-agent --ble-agent` in the login session,
lending its radio to the daemon over a small framed protocol
(io_macos/agent*.rs). Each agent connection that says a valid hello is
installed as the radio, replacing the previous one, so the transport is
unchanged; a lost agent is a radio switched off. A connection has five
seconds to say hello. The agent re-resolves the socket path on every
reconnect, so one started before the daemon created its runtime
directory does not settle on a fallback path.

The agent connects only once its radio is up, and its hello carries the
PSM CoreBluetooth published, read afresh for every connection. Before the
radio is up `listen` reports only the requested fallback, so a hello sent
then told the daemon PSM 133 while the listener was on another, and kept
telling it so across reconnects and Bluetooth toggles.

fips-ble-agent is a hard link to fips, so Activity Monitor tells the two
processes apart. The agent logs to ~/Library/Logs/fips/ble-agent.log,
rolled like the daemon's log, rather than to a shared path in /tmp
another account could plant a file or symlink in. Install, upgrade and
uninstall stop and start the agent in every GUI session, so none keeps
running a replaced binary. The agent ends on the stop signal the process holds from
the start, so a bootout does not wait out launchd's timeout.

The daemon/agent pair is tested end to end over a real Unix socket and
MockBleIo on every host: listener PSM, advertising, adverts, dialled and
inbound channels both ways, refusal, a lost agent, a connection that
never says hello, and an agent whose radio comes up after it starts.
2026-10-13 20:56:07 +00:00
..