Skip to content

feat(ble): Handle invalid BLE attributes#4485

Merged
jamesarich merged 7 commits into
mainfrom
fix/firebase-issues
Feb 7, 2026
Merged

feat(ble): Handle invalid BLE attributes#4485
jamesarich merged 7 commits into
mainfrom
fix/firebase-issues

Conversation

@jamesarich

@jamesarich jamesarich commented Feb 6, 2026

Copy link
Copy Markdown
Collaborator

This pull request focuses on improving BLE error handling and logging, enhancing robustness for Bluetooth operations, and making the codebase more testable. The most significant changes include switching many BLE error logs from error to warning level, updating the BLE error recovery strategy for invalid attributes, handling Android foreground service startup failures more gracefully, and improving dependency management for testing.

Bluetooth error handling and robustness:

  • Changed BLE error logs from Logger.e (error) to Logger.w (warning) in multiple locations, reflecting that many BLE failures are transient and not always critical. This applies to both the Nordic and TCP interfaces. [1] [2] [3] [4] [5] [6] [7] [8] [9]
  • Updated the BLE error recovery strategy for invalid GATT attributes: InvalidAttribute errors are now treated as recoverable by attempting a fresh connection and discovery, and characteristics are cleared when such errors occur. Added a dedicated handleInvalidAttribute method for this logic. [1] [2] [3] [4]
  • Refactored characteristic cleanup by introducing a clearCharacteristics() method, which is called on disconnect or when attributes are invalidated. [1] [2]

Foreground service startup improvements:

  • Improved handling of SecurityException when starting a foreground service with location type on Android 14+: now retries with a reduced service type and logs appropriately, preventing unnecessary app crashes. [1] [2]

Testability and dependency management:

  • Changed RadioInterfaceService from @Singleton to open class and made handleFromRadio open, allowing easier mocking and subclassing in tests. [1] [2]
  • Added mock dependencies for the Nordic BLE client and core libraries to test dependencies in app/build.gradle.kts.
  • Updated the main Nordic BLE dependency to the correct client artifact.

Other minor improvements:

  • Updated copyright years in source files. [1] [2]
  • Minor code cleanup, such as removing unused imports and improving comments. [1] [2] [3] [4]

This change introduces handling for `InvalidAttributeException` which can occur when GATT handles become stale, for instance, after a service change or an unexpected disconnect.

When an `InvalidAttributeException` is caught during a read or write operation:
- The existing BLE characteristics are cleared.
- The service is notified of the disconnection with an `InvalidAttribute` error.
- The `shouldReconnect` flag for this error is now set to `true`, allowing the connection to be re-established.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
@github-actions github-actions Bot added the bugfix PR tag label Feb 6, 2026
@jamesarich jamesarich enabled auto-merge February 6, 2026 18:47
@codecov

codecov Bot commented Feb 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 23.52941% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 10.57%. Comparing base (edd658f) to head (8b21026).
⚠️ Report is 8 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...sville/mesh/repository/radio/NordicBleInterface.kt 33.33% 14 Missing ⚠️
...core/analytics/platform/GooglePlatformAnalytics.kt 0.00% 8 Missing ⚠️
...main/java/com/geeksville/mesh/model/BTScanModel.kt 0.00% 2 Missing ⚠️
...a/com/geeksville/mesh/repository/radio/BleError.kt 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##            main    #4485      +/-   ##
=========================================
+ Coverage   9.22%   10.57%   +1.34%     
=========================================
  Files        427      427              
  Lines      14332    14356      +24     
  Branches    2385     2386       +1     
=========================================
+ Hits        1322     1518     +196     
+ Misses     12757    12542     -215     
- Partials     253      296      +43     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
@jamesarich jamesarich added this pull request to the merge queue Feb 6, 2026
@jamesarich jamesarich removed this pull request from the merge queue due to a manual request Feb 6, 2026
This commit adjusts the log levels for several common and often transient error conditions to reduce noise in the logs.

- Change many common BLE and TCP connection errors from `Error` to `Warning`. These failures are frequently due to environmental factors (e.g., device out of range) and don't necessarily indicate a bug.
- Similarly, bonding failures are now logged as `Warning` because they can be caused by user actions or temporary connectivity issues.
- Modify analytics to only record exceptions to Crashlytics for severities of `Error` or higher, preventing lower-severity warnings from cluttering crash reports.
- Add a retry mechanism when starting the foreground service. If it fails with a `SecurityException` (possible on Android 14+ when requesting location from the background), it will attempt to restart without the location service type.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit updates the Nordic BLE library dependencies and refactors their usage.

Key changes include:
- Renaming `libs.nordic` to `libs.nordic.client.android` for clarity.
- Adding a new `nordic-ble` version variable in `libs.versions.toml`.
- Introducing mock dependencies for the Nordic BLE library (`client-android-mock`, `client-mock`, `core-android-mock`, `core-mock`).
- Implementing new test classes using these mocks:
    - `BleOtaTransportNordicMockTest` to simulate and verify the OTA update flow.
    - `NordicBleInterfaceTest` to test the connection and notification lifecycle.
- Modifying `RadioInterfaceService` and its `handleFromRadio` method to be `open` to allow for mocking in tests.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit introduces a suite of new tests for the `NordicBleInterface` to improve test coverage and ensure its robustness.

The new tests verify several key behaviors:
- Writing data to the `toRadioCharacteristic` is successful.
- The `onDisconnect` callback is correctly triggered when a peripheral disconnects.
- Service discovery fails as expected if a required characteristic is missing.
- An exception during a write operation correctly triggers a disconnect event.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Adds a new test suite, `NordicBleInterfaceRetryTest`, to verify the retry mechanism for BLE write operations in the `NordicBleInterface`.

The tests cover two main scenarios:
- A write operation that succeeds after one retry.
- A write operation that ultimately fails and triggers a disconnect after exhausting the maximum number of retries.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Adds new test suites for BLE functionality using the Nordic BLE mock library.

-   **OTA Error Handling**: Introduces `BleOtaTransportErrorTest` to verify the correct handling of various Over-the-Air update failures, including hash rejection, connection loss during transfer, and verification mismatches.
-   **Packet Drain Logic**: Implements `NordicBleInterfaceDrainTest` to ensure that when a notification indicates multiple packets are available, the interface correctly reads and processes all of them until the queue is empty.
-   **Code Formatting**: Minor code style adjustment in `NordicBleInterfaceRetryTest`.

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
@jamesarich jamesarich added this pull request to the merge queue Feb 7, 2026
Merged via the queue into main with commit ba03aac Feb 7, 2026
9 checks passed
@jamesarich jamesarich deleted the fix/firebase-issues branch February 7, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix PR tag

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant