disconnect() should actually stop a connect() that never finished - on every platform, down to the OS
Status: ๐ง In Progress
The Problem
The Web Bluetooth spec is explicit: step 1 of disconnect() clears the active algorithms map to cancel any pending connections. In practice, a gatt.connect() aimed at a device that is not currently available would just hang, and calling disconnect() did not reliably cancel it.
The expected behavior is simple:
gatt.connect()starts while the known device is unavailable.- Calling
disconnect()should make the pending promise reject promptly withAbortError. - After that,
requestDevice()and a fresh connect attempt to another device should still work - no page reload required.
This one has been open a while: issue 40502943 was filed in January 2017.
The Background
The cross-platform core fix landed first:
That wires up the general "disconnect cancels a pending connect" behavior in Chromium. But the actual cancellation has to be honored by each platform backend - and below the browser, by the OS Bluetooth stack itself.
The Windows Backend
IN REVIEW bluetooth: Enable pending GATT connect cancellation on Windows
On Windows, a disconnect() during an in-flight connect needs to fail the pending connection callbacks, and the canceled WinRT service discovery has to be handled without tripping the async-results DCHECK. This CL makes the Windows path actually reject the pending connect instead of leaving it dangling.
Down to the OS: My First AOSP Patch
The most interesting part is that the fix does not stop at Chromium. On Android, BluetoothGatt.disconnect() did not cancel a connectGatt() that was still waiting for client registration - so a pending connect could not be cleanly aborted at the platform level.
That fix lives in the Android OS itself, in packages/modules/Bluetooth:
Bluetooth: Cancel pending GATT connects - make
BluetoothGatt.disconnect()cancel aconnectGatt()request that is still waiting for client registration, and report the cancellation throughonConnectionStateChange().
This is my first patch to the Android platform (AOSP), and it is still being iterated on. It is a fun milestone: a Web Bluetooth spec line about disconnect() ends up requiring a change three layers down, in the OS Bluetooth stack.
The Test Rig
Verifying a "cancel" path needs a device that you can make appear and then yank away. The sampler uses ESP32-C3 firmware advertising as dino c(h)ancler with serial commands to start/stop advertising, disconnect the central, or deep-sleep - so you can reliably create the "device went away mid-connect" condition.
The flow:
- Select the ESP32-C3 while it is advertising.
- Make it unavailable (stop advertising / deep sleep) and start a connect.
- Hit Disconnect / cancel pending connect - the pending promise should reject with
AbortError. - Confirm a fresh
requestDevice()+ connect to another device still works without reloading.
The sampler ships a patched ARM64 ChromePublic APK and the firmware source so reviewers can reproduce it on real hardware.