Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android BLE unexpectedly and repeatedly reconnects to peripheral

I am developing an Android app that interfaces with a BLE device and recently stumbled across some strange behavior: when the app disconnects from the device, a few seconds later something else seems to establish the connection.

I am in the process of characterizing the issue more fully and have been focused on the Bluetooth MAP and PBAP profiles; they show up in the logs around the point of issue. I am unsure, however, if this is the root cause, nor have I found a workaround.

The app supports API 23-25. To date, I have only experienced the issue in phones with SIM cards present, which points again to PBAP since many phones seem to support this profile only with a SIM card. I haven't yet been able to reproduce on API 23, but for now those test phones do not have SIM cards.

The BLE device has nothing to do with automotive application, nor does it have the ability to deal with Contacts or Messaging. I haven't intentionally enabled any of this within the app. Furthermore, there is no pairing / bonding between my app and the device, nor does the device support pairing / bonding.

In most cases, the attempt to reconnect happens once, a few seconds after device disconnect via the app. Subsequent connect-disconnect sequences in the app have the same behavior. However, I have seen in at least one instance where the reconnects (outside of the app) continue indefinitely every few seconds.

The only thing that seems to resolve the issue short-term is to cycle Bluetooth on the phone, or force-stop the Bluetooth Share process. I don't believe the reconnects come back on their own, but it is common that they do reappear once the user connects-disconnects with the device through my app.

I am not very familiar with PBAP / MAP so am unaware how they get enabled or, if possible, how to disable them. I am not sure if they are the culprit, but they appear in the logs at the moment of reconnect.

Following is the log statements around the point of disconnection and subsequent reconnection. The interface name here is "Foo04" with MAC = B0:B4:48:E8:FA:04.

03-31 14:27:44.305 D/RxBle#Radio(14105):  STARTED RxBleRadioOperationDisconnect(186827491)
03-31 14:27:44.319 D/BluetoothManager(14105): getConnectionState()
03-31 14:27:44.320 D/BluetoothManager(14105): getConnectedDevices
03-31 14:27:44.332 D/BluetoothGatt(14105): cancelOpen() - device: B0:B4:48:E8:FA:04
03-31 14:27:44.334 D/BtGatt.GattService(13168): clientDisconnect() - address=B0:B4:48:E8:FA:04, connId=5
03-31 14:27:44.339 E/bt_btif (13168): bta_gattc_mark_bg_conn unable to find the bg connection mask for: b0:b4:48:e8:fa:04
03-31 14:27:44.340 D/BtGatt.GattService(13168): onDisconnected() - clientIf=5, connId=5, address=B0:B4:48:E8:FA:04
03-31 14:27:44.341 D/BluetoothGatt(14105): onClientConnectionState() - status=0 clientIf=5 device=B0:B4:48:E8:FA:04
03-31 14:27:44.342 D/RxBle#BluetoothGatt(14105): onConnectionStateChange newState=0 status=0
03-31 14:27:44.345 D/RxBle#Radio(14105): FINISHED RxBleRadioOperationDisconnect(186827491)
03-31 14:27:44.352 D/BluetoothGatt(14105): close()
03-31 14:27:44.352 D/BluetoothGatt(14105): unregisterApp() - mClientIf=5
03-31 14:27:44.354 D/BtGatt.GattService(13168): unregisterClient() - clientIf=5
03-31 14:27:45.376 W/bt_l2cap(13168): l2cble_process_conn_update_evt: Error status: 22
03-31 14:27:45.377 W/bt_btif (13168): bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x0016
03-31 14:27:45.377 W/bt_btif (13168): bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x0016
03-31 14:27:45.377 I/bt_btm_sec(13168): btm_sec_disconnected clearing pending flag handle:13 reason:22
03-31 14:27:45.381 E/BluetoothRemoteDevices(13168): state12newState1
03-31 14:27:45.393 D/BluetoothMapService(13168): onReceive
03-31 14:27:45.393 D/BluetoothMapService(13168): onReceive: android.bluetooth.device.action.ACL_DISCONNECTED
03-31 14:27:45.402 D/BluetoothPbapReceiver(13168): PbapReceiver onReceive action = 
03-31 14:27:45.404 D/BluetoothPbapReceiver(13168): Calling start service with action = null
03-31 14:27:45.405 I/TrustAgent.Tracker(15208): [BluetoothConnectionTracker] Bluetooth disconnect broadast for Foo04 B0:B4:48:E8:FA:04
03-31 14:27:46.407 W/bt_smp  (13168): smp_br_connect_callback is called on unexpected transport 2
03-31 14:27:46.408 W/bt_btif (13168): bta_dm_acl_change info: 0x0
03-31 14:27:46.408 I/bt_bta_dm(13168): bta_dm_gatt_disc_result service_id_uuid_len=2 
03-31 14:27:46.408 I/bt_bta_dm(13168): bta_dm_gatt_disc_result service_id_uuid_len=2 
03-31 14:27:46.408 D/bt_btif_dm(13168): remote version info [b0:b4:48:e8:fa:04]: 0, 0, 0
03-31 14:27:46.408 I/bt_bta_dm(13168): bta_dm_gatt_disc_result service_id_uuid_len=2 
03-31 14:27:46.408 I/bt_bta_dm(13168): bta_dm_gatt_disc_result service_id_uuid_len=16 
03-31 14:27:46.408 I/bt_bta_dm(13168): bta_dm_gatt_disc_result service_id_uuid_len=2 
03-31 14:27:46.412 E/BluetoothRemoteDevices(13168): state12newState0
03-31 14:27:46.457 I/TrustAgent.Tracker(15208): [BluetoothConnectionTracker] Bluetooth connect broadast for Foo04 B0:B4:48:E8:FA:04
03-31 14:27:47.317 I/WCNSS_FILTER(13194): ibs_msm_serial_clock_vote: vote UART CLK OFF using UART driver's ioctl()
03-31 14:27:48.421 I/WCNSS_FILTER(13194): ibs_msm_serial_clock_vote: vote UART CLK ON using UART driver's ioctl()
03-31 14:27:48.483 W/bt_btif (13168): bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x0016
03-31 14:27:48.483 W/bt_btif (13168): bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x0016
03-31 14:27:48.483 I/bt_btm_sec(13168): btm_sec_disconnected clearing pending flag handle:14 reason:22
03-31 14:27:48.488 E/BluetoothRemoteDevices(13168): state12newState1
03-31 14:27:48.506 D/BluetoothMapService(13168): onReceive
03-31 14:27:48.506 D/BluetoothMapService(13168): onReceive: android.bluetooth.device.action.ACL_DISCONNECTED
03-31 14:27:48.524 D/BluetoothPbapReceiver(13168): PbapReceiver onReceive action = android.bluetooth.device.action.ACL_DISCONNECTED
03-31 14:27:48.527 D/BluetoothPbapReceiver(13168): Calling start service with action = null
03-31 14:27:48.530 I/TrustAgent.Tracker(15208): [BluetoothConnectionTracker] Bluetooth disconnect broadast for Foo04 B0:B4:48:E8:FA:04
03-31 14:27:49.430 I/WCNSS_FILTER(13194): ibs_msm_serial_clock_vote: vote UART CLK OFF using UART driver's ioctl()

Further Investigation

I posted a related question in Android BLE ACL_DISCONNECTED sometimes delayed.

One commonality among the devices where I've seen the problem has been the existence of a SIM card, but another one is API 24 or 25. I haven't yet been able to reproduce on an API 23 device or, regardless of version, one without a SIM card physically installed.

After even further investigation, I'm less suspect of the SIM card, and more of the API version. There are several outstanding (or recently fixed) bugs that have related behavior, some of which points to API versions > 23; however, I have subsequently been able to reproduce on API 23.

  • BLE: Having two pending direct connections and cancelling the second one does not work
  • BLE: Disconnecting/closing GATT directly after connect sometimes has no effect due to race conditions
  • BLE: Closing gatt object or app does not remove pending connection since Android N
  • Race condition in BluetoothGatt when using BluetoothDevice#connectGatt()

I'm feeling this has little to do with PBAP / MAP profiles. Rather, the existence of them in the logs points simply to these profiles being activated with any BLE disconnection. While not manifesting the reconnection behavior, I was able to see similar PBAP / MAP activation when messing with a TI SensorTag: these profiles again logged any disconnect (unrelated to my application).

List of Affected Devices

I've been able to reproduce this issue, to varying degrees, on the following devices:

  • Samsung S6 - API 23
  • Samsung S7 - API 23
  • Samsung S7 Edge - API 24
  • Sony Xperia Z5 Compact - API 24
  • Motorola Droid Turbo 2 - API 24
  • Nexus 5x - API 25
  • Google Pixel - API 25
like image 309
Steve Yohanan Avatar asked Apr 01 '17 17:04

Steve Yohanan


People also ask

Can Android be a BLE peripheral?

When using BLE, an Android device can act as a peripheral device, a central device, or both. Peripheral mode lets devices send advertisement packets. Central mode lets devices scan for advertisements.

What is MTU BLE Android?

The ATT Maximum Transmission Unit (MTU) is the maximum length of an ATT packet. Per the Bluetooth Core Specification, the maximum length of an attribute can be 512 bytes. In reality, it can be slightly larger than this to accommodate the ATT header. On Android, the maximum MTU can be 517 bytes.

How many BLE devices can Android connect?

x protocol SPEC, when the iPhone/Android phone play as role of BLE central mode, the limitation to have active connection at the same time is up to 8 devices.

What is BLE setting in Android?

Android provides built-in platform support for Bluetooth Low Energy (BLE) in the central role and provides APIs that apps can use to discover devices, query for services, and transmit information. Common use cases include the following: Transferring small amounts of data between nearby devices.


2 Answers

After a great deal of investigation, I was able to determine the root cause of my issue: Spotify.

Having Spotify installed on the Android device was enough to manifest this aberrant behavior; the user need not have logged into or ever started the Spotify app. Uninstalling or force-stopping the app in all cases rectified the issue.

It appears that Spotify has a service that registers for disconnects from any bluetooth peripheral. When the system notifies Spotify, the service immediately connects to the just-disconnected peripheral --- I didn't bother to characterize the communication from Spotify. After ~5 seconds the connection is dropped; however, since Spotify is notified of bluetooth disconnection events, the service again tries to connect with the peripheral. This effectively is an infinite loop that can be aborted only by force-stopping Spotify or cycling bluetooth on the Android device.

To investigate, I developed a simple app that is notified of and reports bluetooth connection and disconnection (ACL_CONNECTED, ACL_DISCONNECTED) events. I used a BLE scanner on my Android device and connected / disconnected with a variety of bluetooth peripherals. My test app would show my initial interaction with the peripheral followed by an infinite stream of connect then disconnect events. Again, this would continue until Spotify was force-stopped.

Following is example logging...

04-10 19:56:24.109  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_CONNECTED
04-10 19:56:32.057  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_DISCONNECTED
04-10 19:56:34.197  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_CONNECTED
04-10 19:56:40.396  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_DISCONNECTED
04-10 19:56:43.857  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_CONNECTED
04-10 19:56:49.962  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_DISCONNECTED
04-10 19:56:51.130  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_CONNECTED
04-10 19:57:17.348  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_DISCONNECTED
04-10 19:57:17.927  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_CONNECTED
04-10 19:57:37.621  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_DISCONNECTED
04-10 19:57:38.157  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_CONNECTED
04-10 19:57:44.364  D/BluetoothConnectionMoni: onReceive: deviceName=System05 deviceAddr=B0:B4:48:E8:D7:03 action=ACL_DISCONNECTED
...

It was difficult to determine Spotify was the root cause.

My first indication was through looking at Developer Options -> Running Services and noting Spotify regularly popping up correlated with peripheral connection / disconnection.

In the end, though, it came down to process of elimination: Once the aberrant behavior started, I selectively went through the list of installed apps, force-stopping ones that likely had some interest in bluetooth, eventually seeing the issue cease immediately when I stopped Spotify.

I have provided a detailed bug report to Spotify several weeks ago, but I have yet to hear back from them.

like image 81
Steve Yohanan Avatar answered Sep 18 '22 22:09

Steve Yohanan


This seems to be fixed beginning in Spotify 8.4.19.792 released 2017-09-14.

like image 40
Pete Doyle Avatar answered Sep 16 '22 22:09

Pete Doyle