Skip to content

Windows: Harden BLE connection lifetime, async callbacks, and notification subscription handling - #278

Merged
rohitsangwan01 merged 3 commits into
Navideck:mainfrom
usmanmehmood55:windows_ble_hardening
Aug 11, 2026
Merged

Windows: Harden BLE connection lifetime, async callbacks, and notification subscription handling#278
rohitsangwan01 merged 3 commits into
Navideck:mainfrom
usmanmehmood55:windows_ble_hardening

Conversation

@usmanmehmood55

@usmanmehmood55 usmanmehmood55 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR hardens the Windows BLE implementation against connection lifecycle races, stale native callbacks, unsafe WinRT completion handling, and inconsistent notification subscription state.

It builds on the exception handling introduced in #217, focusing on cases where GATT operations, disconnects, reconnects, and asynchronous callbacks overlap.

Problem

Connected-device state is accessed by Flutter method handlers, WinRT callbacks, and coroutine continuations. Without synchronized ownership and stale-operation protection, this can allow:

  • disconnect cleanup to destroy state still used by an in-flight operation;
  • an older connection attempt or callback to interfere with a newer connection;
  • a pending connection to report success after it was disconnected;
  • GATT service or subscription state to change while another operation uses it;
  • failed or cancelled WinRT operations to call GetResults();
  • exceptions to escape native completion callbacks;
  • subscription tokens to become inconsistent with registered native handlers;
  • overlapping notification operations on the same characteristic.

Changes

Connection ownership and synchronization

  • Store connected-device agents using shared_ptr.
  • Synchronize connection lookup, installation, replacement, and removal.
  • Retain device agents for operations that may outlive map ownership.
  • Remove connections from shared storage before disposing native resources.
  • Atomically replace existing connections and dispose the previous agent.

Stale connection protection

  • Assign a generation to each connection attempt.
  • Allow only the current attempt to install a connection or publish its result.
  • Invalidate pending attempts when disconnect is requested.
  • Ignore callbacks and failures from superseded device instances.
  • Prevent an older attempt from replacing or disconnecting a newer connection.

Deterministic cleanup

  • Unregister connection-status handlers before releasing services.
  • Detach GATT state before disposing subscriptions.
  • Close the native device after handlers and services are released.
  • Publish consistent disconnected events for explicit disconnects.

GATT and notification safety

  • Protect GATT characteristics and subscription tokens with an agent-level mutex.
  • Return copied characteristic handles instead of references into shared maps.
  • Use GATT snapshots during asynchronous service discovery.
  • Serialize notification changes per characteristic, not globally.
  • Commit subscription-token changes only after native handler operations succeed.
  • Roll back newly registered handlers if the device disconnects during subscription.
  • Avoid conflicting cleanup while a notification operation owns the characteristic.

WinRT completion safety

  • Verify AsyncStatus::Completed before calling GetResults().
  • Report cancelled reads, writes, MTU requests, and Bluetooth operations separately.
  • Capture asynchronous callback data by value instead of retaining stack references.
  • Catch exceptions raised inside completion callbacks.
  • Safely contain exceptions produced while returning results to Dart.

Scope

The changes are limited to the Windows central/client implementation. Public Dart APIs and behavior on Android, Apple, Linux, and Web are unchanged.

Verification

  • flutter analyze and test
  • Manual Windows testing with a physical BLE device
    • Device scanning
    • Connection and service discovery
    • Notification subscription and unsubscription
    • Repeated characteristic reads and writes
    • Intentional disconnect

- synchronize connected-device and GATT state access
- retain device agents safely across in-flight operations
- reject callbacks from stale connection instances
- make disconnect and reconnect cleanup deterministic
- validate WinRT completion status before reading results
- handle cancelled asynchronous operations explicitly
- own notification arguments across coroutine suspension
- prevent Flutter reply exceptions from terminating the runner
- avoid unsafe reference captures in asynchronous callbacks
- ignore stale connect completions after reconnect or disconnect
- prevent superseded attempts from replacing active connections
- catch exceptions from WinRT completion callbacks and Flutter replies
- serialize notification changes per characteristic
- update subscription tokens only after native handler changes succeed
- preserve notification state during concurrent disconnect cleanup
- document the additional Windows hardening
- restore the example lockfile package version

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the Windows BLE central/client implementation against connection lifecycle races and unsafe async callback handling, with additional serialization around notification subscription updates.

Changes:

  • Introduces synchronized, generation-guarded connection ownership using shared_ptr plus a connection-attempt generation map to ignore stale attempts/callbacks.
  • Adds WinRT completion safety (status checking before GetResults(), exception containment, and safer value-captures in async callbacks).
  • Serializes notification subscription changes per characteristic using an agent-level mutex and “operation in progress” tracking; updates changelog.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
windows/src/universal_ble_plugin.h Adds agent-level GATT mutex + per-characteristic notification-operation tracking; switches connected device storage to shared_ptr and adds connection-generation helpers.
windows/src/universal_ble_plugin.cpp Implements generation-guarded connection install/removal, safer WinRT completion handling, and serialized notification subscribe/unsubscribe flows with rollback.
CHANGELOG.md Adds an Unreleased entry describing the Windows hardening work.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread windows/src/universal_ble_plugin.cpp Outdated

@rohitsangwan01 rohitsangwan01 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thankyou for the PR, LGTM

@rohitsangwan01
rohitsangwan01 merged commit cbc543e into Navideck:main Aug 11, 2026
2 checks passed
@usmanmehmood55

Copy link
Copy Markdown
Contributor Author

@rohitsangwan01 @fotiDim I have another potential PR relevant to this.

To verify these changes on Windows side, I have implemented 38 additional hardware in loop tests using a bare nRF52DK development kit.

Some focus on baseline BLE features like scanning, connection, MTU exchange, data exchange etc., and a good portion of them are fault injection tests which use the hardware jig to create real peripheral side faults and test the edge cases of this library.

The fault injection tests make the nRF52 deliberately return ATT errors, delay operations, disconnect while operations are pending, interrupt notification bursts, and create connection and subscription races. The tests then verify error propagation, cleanup, reconnection, event ordering, and continued operation after recovery.

I ran the changes in this PR against this suite today. The HIL setup could be useful as a separate, opt-in regression test suite for Windows BLE changes that cannot be exercised reliably with mocks or unit tests. In future it can also be extended to all other platforms.

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.

3 participants