Disconnection issues while bonded on Huawei & Honor devices



    • Given one is using a Huawei or Honor device (tested on P9 with Android 7.0, P7 with Android 5.1.1, P8 with Android 6.0 and Honor Play with EMUI 9.1).
    • When one connects and bonds to a Nordic-based peripheral through an app (tested on my app which uses SweetBlue v3.2.2, the latest SweetBlue Toolbox v3 and the nRF Connect app).
    • And then one explicitly disconnects the device OR one closes the app.
    • Then –as reported by the Nordic peripheral's BLE stack– the connection is not killed and the services are not disconnected.
    • Finally, if one opens the SweetBlue-based app again, the device can't be connected anymore to the app since it's already connected to the OS.

    I've found that a workaround for the disconnection issue is to delete the bonding information on the phone (works from the OS' settings, the SweetBlue Toolbox and the nRF Connect apps), which successfully terminates the connection AND does not trigger a 'bonding' prompt/notification on further connections to that peripheral (it also does not trigger a reconnection which is great).

    Q1: Is this a known issue?
    Q2: Can you reproduce this with other bonded devices on your end? It does not happen with our other custom peripheral that does not require bonding to the Android device.
    Q3: Is the aforementioned workaround a valid one? It should be alright for when one is terminating the connection, but it does not solve anything when killing the app.
    Q4: If you can reproduce this, would you consider adding it as standard Huawei/Honor behavior to the library so that after an explicit disconnection, the local bonding keys are deleted?
    Q5: Related question about using a device that is already connected to the OS



  • @AlejandroHCruz , are you sure it's just Huawei and Honor devices? This sounds suspiciously like the android bond bug, where it leaves a connection open after the first bond. See https://sweetblue.io/docs/Android-BLE-Issues under connection issues (last bullet point).

    There is a workaround in the library, but it is very clunky, and heavy-handed. The "fix" is to bond, then unbond, then connect, and disconnect. From then on, bonding works properly. I know how crazy this sounds.

    If you'd like to try it, you will have to update the BondFilter like so:

    public class MyBondFilter extends DefaultBondFilter {
        @Override
        public ConnectionBugEvent.Please onEvent(ConnectionBugEvent e) {
            return ConnectionBugEvent.Please.tryFix();
        }
    }
    
    BleManagerConfig config = new BleManagerConfig();
    config.bondFilter = new MyBondFilter();
    BleManager mgr = BleManager.get(activity, config);
    

    I'm curious if using this fixes your problem (it should also make it so if the app closes, the connection gets killed).



  • @ryanbis, thank you for your suggestion.

    The issue seems to be the one you've pointed out: W/P_UhOhThrottler: UPDATE(24744) uhOh() - CONNECTION_STILL_ALIVE

    I've also been able to reproduce this issue on a OnePlus 1 device.

    Sometimes the onEvent(ConnectionBugEvent e) gets called, producing the log above, but sometimes it doesn't so the device stays stuck on this artificial “connected” state even in the cases in which the connection did not go through.

    Could it be related to this issue that I see on every connection attempt (even on those who succeed)?

    2019-12-11 15:03:11.399 E/BleManager: ASSERTION FAILED 
    java.lang.Exception
        at com.idevicesinc.sweetblue.internal.P_BleManagerImpl.ASSERT(P_BleManagerImpl.java:671)
        at com.idevicesinc.sweetblue.internal.P_DeviceConnectionManager.onConnected(P_DeviceConnectionManager.java:183)
        at com.idevicesinc.sweetblue.internal.P_BleDeviceImpl.onNativeConnect(P_BleDeviceImpl.java:1422)
        at com.idevicesinc.sweetblue.internal.P_BleDevice_ListenerProcessor.onNativeConnect(P_BleDevice_ListenerProcessor.java:213)
        at com.idevicesinc.sweetblue.internal.P_BleDevice_ListenerProcessor.onConnectionStateChange_updateThread(P_BleDevice_ListenerProcessor.java:162)
        at com.idevicesinc.sweetblue.internal.P_BleDevice_ListenerProcessor.lambda$onConnectionStateChange$0$P_BleDevice_ListenerProcessor(P_BleDevice_ListenerProcessor.java:142)
        at com.idevicesinc.sweetblue.internal.-$$Lambda$P_BleDevice_ListenerProcessor$YO_ZOMJ313stv1rjLiHfCHO_nkg.run(lambda)
        at com.idevicesinc.sweetblue.internal.ThreadHandler$SweetRunnable.run(ThreadHandler.java:173)
        at com.idevicesinc.sweetblue.internal.ThreadHandler.processRunnables(ThreadHandler.java:221)
        at com.idevicesinc.sweetblue.internal.ThreadHandler.loop(ThreadHandler.java:58)
        at com.idevicesinc.sweetblue.internal.P_SweetBlueThread$HandlerRunner.run(P_SweetBlueThread.java:30)
        at java.lang.Thread.run(Thread.java:776)


  • No, that assert is ok (its meant to inform us of when weird things happen we're not expecting). It's just showing how messed up bonding can be on android. It's tripping that assert because the device is reporting that it's bonded, but the device doesn't show up in the list of bonded devices from the system. SweetBlue isn't doing anything about it, just throwing the assert (which one do we trust to be accurate?).



  • I see. Thanks for the information on the asserts when bonding.

    I've also experienced a state in which the device was disconnecting and connecting again all the time in a loop.

    It could've been cause by a combination of using the ConnectionBugEvent.Please.tryFix() and something else my configuration file.

    This is what I've set it to do:

     forceBondDialog = true // does not always works
     useLeTransportForBonding = true
     autoBondFixes = true
     tryBondingWhileDisconnected = true
     bondingFailFailsConnection = true
     alwaysBondOnConnect = true
    

    Should I try anything else in the config? I'm thinking about changing useLeTransportForBonding to false and adding autoReconnectDeviceWhenBleTurnsBackOn = true



  • Hi.

    I've fixed the loop by ignoring multiple calls to the onEvent(ConnectionBugEvent e) however the disconnection issue is not fixed.

    I'm considering prompting the user to restart their Bluetooth adapter... Not sure what else to do when the UhOh's suggestion is to RECYCLE_CONNECTION 🤔



  • Unfortunately, thats a side effect of the bug fix. This is why it's not on by default. In most cases it fixes the problem, but not all. If it doesn't fix the problem, it will end up in a loop because the problem still exists. Do you find that recycling the bluetooth adapter fixes the problem?



  • Actually, it looks like we had a bug in the implementation. I've fixed it on our dev branch currently so it will not go into a perpetual loop. Still probably won't fix your issue, but at least in the next release, you won't end up in a connection loop.



  • It's great that you've fixed the connection loop issue! 🥳 Looking forward to that future update.

    By recycling the Bluetooth adapter you mean to turn it off and on again?
    When I do that manually, then I can connect the bonded device on the next attempt.

    Is it a good practice to do this on the background silently or to ask/notify/alert the user before doing this? I would go and do it silently if there's a way for me to detect that no other Bluetooth devices are connected to the OS...

    By the way, the issue even happens on the Google Pixel 2 if I delete the bonding keys on the phone but not on the bonded peripheral.



  • By recycling the Bluetooth adapter you mean to turn it off and on again?
    When I do that manually, then I can connect the bonded device on the next attempt.

    Interesting. When I was messing around with it, turning bluetooth off/on didn't seem to make any difference.

    Is it a good practice to do this on the background silently or to ask/notify/alert the user before doing this? I would go and do it silently if there's a way for me to detect that no other Bluetooth devices are connected to the OS...

    I would say it's always good practice to ask the user before doing it.



  • Thank you for your replies. It is interesting that you got different results than me. On my undersanding, turning off the Bluetooth adapter definitely terminates the connection and thus the device can be used again for further scanning/connection.

    I've been trying out a bunch of different things.

    Sometimes, when the device is stuck on this state, I am able to retrieve the device from the regular getDevice(String macAddress) method. And then I can establish a connection, verify the BONDED state, read the standard Device Information Service, and even enable some BleNotify. However, I am not able to negotiate the MTU as the operation fails with a REMOTE_GATT_FAILURE due to “no resources”.

    I'll activate autoNegotiateMtuOnReconnect and try again tomorrow, maybe you have some magic in there or I'm doing something wrong.

    Other than that, I think I'll use the getDevices_bonded() function, filter for the device, and unbond it. Then connect again. That seems to work on the Toolbox V3 app and does not retrigger a bonding notification for some reason.