AltBeacon/android-beacon-library

Gatt connections leak if app crashes

bensadiku opened this issue · 6 comments

Expected behavior

If app crashes, GATT connection needs to be closed and cleaned up.

Actual behavior

Gatt connection leaks, if the leak reaches max GATT clients defined on the OS level, Bluetooth becomes in-operable.

Steps to reproduce this behavior

Reproduced with the Kotlin sample app:
https://github.com/davidgyoung/android-beacon-library-reference-kotlin/tree/master
Inside MainActivity's onCreate, throw a random exception:

       Handler(Looper.getMainLooper()).postDelayed({
            Log.d(TAG, "onCreate: running")
            throw NullPointerException("abscc")
        },10000)

and observe the gatt clients in logcat
adb logcat | grep gatt_if

output:

bt_stack: [INFO:gatt_api.cc(968)] allocated gatt_if=x

where x is the number of app interfaces registered gatt callbacks, which increases incrementally on every app install & crash.

A hacky solution is to power cycle BT, but there must be a better way to do this.

Mobile device model and OS version

Behaviour tested on Android 9 up to Android 13 and was reproduced. Used Pixels and Samsung devices. Does not seem to be device/OS specific

Android Beacon Library version

implementation 'org.altbeacon:android-beacon-library:2.19.6'

IMPORTANT: This forum is reserved for feature requests or reproducible bugs with the library itself. If you need help with using the library with your project, please open a new question on StackOverflow.com.

cc @davidgyoung if you have any recommendations, this seems to be a big issue.;

I really do not think that I have seen this -- crashes happen pretty normally during app development, and I know I do not need to reboot my phones or power cycle bluetooth regularly during beacon scanning app development. Are you sure that the value of x in bt_stack: [INFO:gatt_api.cc(968)] allocated gatt_if=x always increments after a crash no matter how long you wait? Is it possible it will go down in time if you wait, say 10 minutes between force crashes?

If the number does not go down, then I suspect there may be something different about your devices or the apps running on them that makes the OS gatt clients never get recycled. The core problem you are seeing should in theory exist even for apps not using this library, if they start an Android's Bluetooth LE scan using Android's built-in SDKs, then crash.

It may be possible to prevent a GATT client leak by using an uncaught exception handler and making it stop any scan started by the app.

But before even considering the above I think it is important to confirm there is no existing recovery mechanism.

This is the main problem here, there does not seem to be a recovery mechanism OS side because we've had devices reach max GATT clients while running the app that has beacon lib.
Ran some more tests with the sample app and the time does not play a role. FYI, testing with the Kotlin sample app i linked.
In theory this seems like a GATT issue but i was unable to reproduce with a plain GATT server connection. The behavior with this simple server is that Gatt clients increase by 1 on app install and decrease by 1 when app crashes.

When using a plain GATT server connection, OS seems to do some clean-up in background when app crashes:

2023-10-03 11:19:28.180 30682-30733/com.android.bluetooth E/bt_stack: [ERROR:gatt_api.cc(313)] Active Service Found: 00001805-0000-1000-8000-00805f9b34fb
2023-10-03 11:19:28.181 30682-30733/com.android.bluetooth I/bt_stack: [INFO:gatt_api.cc(380)] GATTS_StopService: 0x28

It is not doing so using the Beacon Kotlin sample app, though. I suspect it's something to do with the way this library is utilizing GATT..

Can you share the code used to start the scan in this test?

unable to reproduce with a plain GATT server connection. The behavior with this simple server is that Gatt clients increase by 1 on app install and decrease by 1 when app crashes.

@bensadiku, I cannot reproduce this issue with the official reference app using a Google Pixel 6a / Android 13.

I created a Git branch with the same code to crash the app here: https://github.com/davidgyoung/android-beacon-library-reference-kotlin/tree/test-gatt-client-leaks

I then grep logcat as you describe, and repeatedly launch the app after it crashes 10 seconds later. I also have a beacon transmitter going and I confirm it detects before it crashes. Note that in the logs below I do not see new gatt_if creations.

 % adb logcat | grep gatt_if

10-05 10:40:38.920  2588  3372 I bt_stack: [INFO:gatt_api.cc(1355)] GATT_CancelConnect: gatt_if:7, address: 00:00:00:00:00:00, direct:0
10-05 10:40:38.921  2588  3372 I bt_stack: [INFO:gatt_api.cc(1147)] GATT_Deregister gatt_if=7

I suggest you try with this same code to see if you see the same thing. There may also be differences with Android version and OEM customizations.

closed due to inactivity