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