flutter_reactive_ble icon indicating copy to clipboard operation
flutter_reactive_ble copied to clipboard

Android: Writing to disconnected device creates a new connection

Open maBarabas opened this issue 2 years ago • 2 comments

Describe the bug On Android, when I try to write to a disconnected device, a new connection is created with an infinite timeout. This causes several issues:

  • If the device is not in range, then the future returned by the write function is never completed. There is no way to configure the timeout on this connection.
  • If the connection succeeds then the connection is leaked, as the write function does not return a Stream<ConnectionStateUpdate> that we could cancel like connectToDevice does. There is no way to cancel this connection, and all subsequent calls to connectToAdvertisingDevice fail.

To Reproduce Steps to reproduce the behavior:

  1. Have a connectable peripheral device advertising
  2. Initialise BLE
  3. Scan to get the device ID
  4. Write to a characteristic without connecting to the device
  5. See in the logs that a new connection is created
  6. Try to use connectToAdvertisingDevice on the same device ID
  7. Connection will fail as we are still connected to the device and it is not advertising any more
I/flutter (32695): INFO: 2022-07-11 10:36:46.900749: Trying to write without connecting
D/BluetoothGatt(32695): connect() - device: FC:F5:C4:65:8B:7A, auto: true
D/BluetoothGatt(32695): registerApp()
D/BluetoothGatt(32695): registerApp() - UUID=1292522e-2cd4-4320-b7b9-b6182d097935
D/BluetoothGatt(32695): onClientRegistered() - status=0 clientIf=8
I/flutter (32695): FINE: 2022-07-11 10:36:46.967818: ConnectionStateUpdate(deviceId: FC:F5:C4:65:8B:7A, connectionState: DeviceConnectionState.connecting, failure: null)
D/BluetoothGatt(32695): onClientConnectionState() - status=0 clientIf=8 device=FC:F5:C4:65:8B:7A
D/BluetoothGatt(32695): discoverServices() - device: FC:F5:C4:65:8B:7A
I/flutter (32695): FINE: 2022-07-11 10:36:59.007188: ConnectionStateUpdate(deviceId: FC:F5:C4:65:8B:7A, connectionState: DeviceConnectionState.connected, failure: null)
D/BluetoothGatt(32695): onSearchComplete() = Device=FC:F5:C4:65:8B:7A Status=0
I/flutter (32695): INFO: 2022-07-11 10:36:59.427412: Write without connecting completed
I/flutter (32695): INFO: 2022-07-11 10:37:09.441815: Trying to connect
D/BluetoothAdapter(32695): isLeEnabled(): ON
D/BluetoothLeScanner(32695): onScannerRegistered() - status=0 scannerId=9 mScannerId=0
D/BluetoothAdapter(32695): isLeEnabled(): ON
I/flutter (32695): SEVERE: 2022-07-11 10:37:14.505441: Device is disconnected

Expected behavior

I expect an error to be reported by the library when trying to perform illegal operations such as writing to a disconnected device.

  • Calls to write/read/subscribe with a disconnected device to raise an exception.

  • Calls to write/read/subscribe with a disconnected device do not create new connections. The only way to create connections is using the connectToDevice, connectToAdvertisingDevice functions.

  • [ ] I tried doing the same with a general BLE scanner application (e.g. nRF Connect) and it exhibits the expected behavior as described above

The nRF connect UI does not allow read write while the device is not connected.

Smartphone / tablet

  • Device: Nokia 4.2
  • OS: Android 11
  • Package version: 5.0.2

Peripheral device

  • Vendor, model: CUSTOM
  • Does it run a custom firmware / software: yes

This issue should be reproducible on any peripheral device.

Additional context

This seems to be caused by this line: https://github.com/PhilipsHue/flutter_reactive_ble/blob/c25bedf9bc00abdac60927f42a8aafdc5ae5dbf8/packages/reactive_ble_mobile/android/src/main/kotlin/com/signify/hue/flutterreactiveble/ble/ReactiveBleClient.kt#L245

When the connection for the selected deviceId is not active, a new connection is created. I've looked through the git history for clues as to why a new connection is created here, but that line of code has been there since the inital commit to the repo.

On iOS, an exception is raised as expected:

flutter: SEVERE: 2022-07-08 16:57:34.075327: Exception: GenericFailure<WriteCharacteristicFailure>(code: WriteCharacteristicFailure.unknown, message: "A peripheral 26C77996-F075-9120-8B13-1571327087C7 is unknown (make sure it has been discovered)")

flutter: SEVERE: 2022-07-08 16:57:34.075642: #0      Result.dematerialize.<anonymous closure> (package:reactive_ble_platform_interface/src/model/result.dart:22:13)
flutter: #1      Result.iif (package:reactive_ble_platform_interface/src/model/result.dart:34:21)
flutter: #2      Result.dematerialize (package:reactive_ble_platform_interface/src/model/result.dart:15:28)
flutter: #3      ConnectedDeviceOperationImpl.writeCharacteristicWithResponse.<anonymous closure> (package:flutter_reactive_ble/src/connected_device_operation.dart:63:39)
flutter: #4      _rootRunUnary (dart:async/zone.dart:1434:47)
flutter: #5      _CustomZone.runUnary (dart:async/zone.dart:1335:19)
flutter: <asynchronous suspension>
flutter: #6      SystemSetupModel.setWifiCredentials (package:attessa_ui_test/system_setup/model/system_setup.dart:95:5)
flutter: <asynchronous suspension>
flutter:
flutter: INFO: 2022-07-08 16:57:34.075845: Write without connecting completed

I'll try wrapping the write/read/subscribe function so that using them on a device that is not in the connected state throws. Monitoring the connection state for all devices should be possible using the bleStatusStream property.

maBarabas avatar Jul 11 '22 09:07 maBarabas

I am also running into the same issue

tnchoe98 avatar Sep 28 '22 20:09 tnchoe98

I also have the same issue. @maBarabas did you succeed with listening to the bleStatusStream. I added gates on the write/read/subscribe functions in my code, for when state != connected but somehow this is not always working out.

Is this issue still being tracked?

rolandmosimann avatar Jan 31 '24 16:01 rolandmosimann