Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BLE Device Bonding Remove Automatically in Android

We are doing below process to do pair with BLE Device.

Connect() + discoverServices() + Pairing(Bonding) .

Sometimes Android OS unpaired our BT device in a weird way, that is:

  • without sending broadcast notification that bonding state has changed
  • even system Bluetooth settings app thinks that device is still paired
  • only bt restart (turning off and on via settings app) refreshes state and shows that device is not paired any longer

When Device is Successfully Paired the ACTION_BOND_STATE is change as below.

[6:19:28 PM] Himen Patel: 04-09 18:18:27.325: D/BluetoothGatt(8380): onCharacteristicWrite() - Device=C2:69:E9:57:93:A4 UUID=860b2c07-e3c5-11e2-a28f-0800200c9a66 Status=5 04-09 18:18:27.365: E/millisUntilFinished(8380): millisUntilFinished = 15 04-09 18:18:28.105: E/BelwithDeviceActor(8380): Bond state changed for: C2:69:E9:57:93:A4 new state: 11 previous: 10

04-09 18:18:28.105: E/millisUntilFinished(8380): millisUntilFinished = 20 04-09 18:18:29.135: E/millisUntilFinished(8380): millisUntilFinished = 18 04-09 18:18:30.135: E/millisUntilFinished(8380): millisUntilFinished = 17 04-09 18:18:31.145: E/millisUntilFinished(8380): millisUntilFinished = 16 04-09 18:18:32.145: E/millisUntilFinished(8380): millisUntilFinished = 15

04-09 18:18:33.105: D/BluetoothGatt(8380): onCharacteristicWrite() - Device=C2:69:E9:57:93:A4 UUID=032a0000-0000-0000-0000-000000000000 Status=137 04-09 18:18:33.115: E/BelwithDeviceActor(8380): Bond state changed for: C2:69:E9:57:93:A4 new state: 12 previous: 11

04-09 18:18:33.115: I/System.out(8380): unregisterReceiver true

Now when Pairing is removed by OS in weird way the ACTION_BOND_STATE is change as below. . . . . Bond state changed for: C2:69:E9:57:93:A4 new state: 10.

we also get immediate event of act=android.bluetooth.device.action.ACL_DISCONNECTED flg=0x4000010 in our APP.

what's important here, at this point we just lost pairing with the device and protected characteristics don't work for us any longer. if we restart bt using system settings app or BluetoothAdapter::disable() and enable() we can see that we are not paired with the device.

what's funny, without the bt restart, system settings app still thinks and shows that we are paired with the device.

tested with nexus 4 running 4.4.2, nexus 5 running 4.4.2 and even Samsung galaxy s4 running 4.3.

our expectation is that:

  • in case of unpairing there should be system broadcast
  • system preferences app should show current paring status even without bt restart

We have also Observed and get the sniffed data in which we found that our encryption is set to 0x000000 when our bonding is removed by OS in weird way.

like image 413
himen patel Avatar asked Apr 15 '14 06:04

himen patel


People also ask

Is BLE always on?

Because BLE is designed to save power, the device is typically dormant until action is required. I have also found this quote: A large number of BLE products sleep most of the time, waking up only to advertise and connect when needed.

How do you Unpair Bluetooth device programmatically in Android?

Using Android Bluetooth API, we can use createBond method to pair with a device or removeBond to unpair. This is an asynchronous call so that it will return immediately. To catch the pairing process, we have to register a BroadcastReceiver with ACTION_BOND_STATE_CHANGED intent to catch the process.

How does BLE bonding work?

Both BLE central and peripheral will connect to the malicious device, which in turn routes the communication between the other two devices. The malicious device intercepts all data being sent and can inject false data or remove data before it reaches its recipient.

How do I enable BLE on Android?

Once your app has permission to use Bluetooth, your app needs to access the BluetoothAdapter and determine if Bluetooth is available on the device. If Bluetooth is available, the device will scan for nearby BLE devices.


1 Answers

I have no idea whether you still need help or whether you eventually solved your own problem (you know, since you did post this question back in April), but I wanted to go ahead and post the workaround I came up with because I know other people are having this problem.

Using a Nexus 7, I ran basically the same tests you did and came to the same conclusion: If the Android tablet and the remote device were already bonded, there was a high chance that calling BluetoothGatt.discoverServices() would both disconnect and unbond the tablet from the remote device. But, certain parts of the Android OS seemed completely oblivious to the unbonding; although the Broadcast Receiver you registered to listen for bonding changes was notified that the bond between the two devices had been broken, the rest of the Android OS considered the bond to still be intact. Since the OS considered the tablet and the remote device to be bonded, the tablet could not write to any of the encrypted descriptors on the remote device, giving a write status of 15 (GATT_INSUFFICIENT_ENCRYPTION) whenever a descriptor write was attempted.

The Solution

The key is to unpair the Nexus and the remote device before they have the chance to unpair themselves in that weird way. What I do is check to see if the tablet and the remote device are bonded right before I start a Bluetooth Low Energy scan. If they are paired, I remove the bond using the function below and then start the scan. Unpairing the two devices programmatically ensures that the Android OS is aware that they are no longer bonded and, therefore, will go through the usual bonding process.

Below is the code is use to check to see if the remote device is paired with the tablet and unpair it if it is:

// Get the paired devices and put them in a Set
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

// Loop through the Set of paired devices, checking to see
// if one of the devices is the device you need to unpair
// from. I use the device name, but I'm sure you can find
// another way to determine whether or not its your device
// -- if you need to. :)
for (BluetoothDevice bt : pairedDevices) {
        if (bt.getName().contains("String you know has to be in device name")) {
            unpairDevice(bt);
        }
}

// Function to unpair from passed in device
private void unpairDevice(BluetoothDevice device) {
    try {
        Method m = device.getClass().getMethod("removeBond", (Class[]) null);
        m.invoke(device, (Object[]) null);
    } catch (Exception e) { Log.e(TAG, e.getMessage()); }
}



Why waiting for the error and then solving it by restarting the Bluetooth is a bad idea...

As you have already pointed out in your question, restarting the Bluetooth after the tablet and the remote device mysteriously unbond from each other forces the Android OS to realize that it is no longer bonded to the remote deivce. This was the original workaround I used, but it soon became clear that there were two major problems that came with this "solution":

  1. Turning the Bluetooth on and off will disconnect all of the devices that were connected to the tablet.
  2. Turning the Bluetooth on and off wastes a lot of time.

I would only restart the Bluetooth as a last resort. For example, if the unbonding error still miraculously occurred, your only choice would be to restart the Bluetooth.

like image 52
Hunter S Avatar answered Sep 24 '22 07:09

Hunter S