Closed NathanRussak closed 3 years ago
@NathanRussak Can you provide the code you have in your application?
Just finished throwing together a simple demo activity that replicates the problem. You can find the source and logs within the attached ZIP.
@NathanRussak I've replicated the setup (except the pixel phone, used S10 with Android R) and was not able to replicate the issue. Same services, characteristics and indication setup and running your demo app.
Both with or without the debugger the connection remains stable and am able to get changes indication.
Do you encounter this issue if you use a different phone model?
Sorry for the delayed response @ionutlepi. I actually have an S10 on hand. I'll give it a shot this weekend and provide feedback.
I was able to reproduce the issue on my S10.
My S10 was originally still running Android Q. I ran my sample app and was unable to replicate. I then applied a pending system update to bump it up to Android R and ran the app again. I was able to replicate the issue rather quickly. See the attached logs.
One interesting variance I noticed. When it fails on the Pixel I see this:
V/GattClientCallback: [TEMP] onConnectionStateChange: Gatt Response Status GATT_INSUF_AUTHORIZATION
When it fails on the S10 I see this:
E/GattClientCallback: [TEMP] onConnectionStateChange: Gatt Response Status GATT_ERROR
Different error codes.
I don't believe the update to Android R caused this. I think that was purely coincidence. I didn't test enough before upgrading to Android R. The bug doesn't happen 100% of the time but it does happen rather frequently. Typically, if it doesn't happen right away just disconnecting/reconnecting the BLE device or restarting the app will trigger it.
This issue has been, so far, observed on a:
@NathanRussak thanks for the fresh information will check it out
Checking back in on this.. any update @ionutlepi? Do you require anything further from me to diagnose or replicate the problem?
@NathanRussak checking the S10 log it seems that in this case S10 cannot even connect initially but than manages to connect and the logs end so a little different from the pixel behavior
But based logs i don't see an issue with how bitgatt handless the transactions but rather something going wrong at a lower level.
You can use something the nRF Connect for Mobile to validate the peripheral behaviour outside this library context.
Is your device bonded by any chance? An instability in the bond link could explain this as well.
Thank you
@ionutlepi
Are you referring to CreateBondTransaction
? If so then no. My demo app was not attempting to establish a bond. I faintly remember trying this in the past to see if it improved my connectivity issues but gave up on it for some reason.
If this is what I'm missing I can give it another shot. Could you confirm a few things first?
My app needs to be able to connect to 1+ BLE devices. The readme states:
because of the many shifts in connection interval and the other changes that occur it is wise to not try to attempt other gatt operations while a bond attempt is in progress.
Can you confirm where in the connection process I should be attempting to bond? For example...
GattConnectTransaction
against connection.CreateBondTransaction
against connection.GattClientDiscoverServicesTransaction
, SubscribeToCharacteristicNotificationsTransaction
, WriteGattDescriptorTransaction
, etc.@NathanRussak Was not referring to the transaction. With some devices you can bond directly from the android Bluetooth options and was thinking if that was happening
Scanning or running operations on another device should not affect running bond operations.
Did you get a chance to test the device connection also with nRF Connect for Mobile ?
Ah ok. No I don't believe I've tried that. I assumed that bitgatt handled the bonding if it were necessary.
Thanks for the feedback @ionutlepi. Let me try establishing a bond and experimenting with nRF Connect. I'll get back to you with feedback when I'm done.
@ionutlepi was finally able to check out nRF Connect for Mobile. It was able to establish a connection to the BLE thermometer and receive updates via the indicate characteristic. All without bonding.
Just in case it helps I've attached the logs from nRF Connect to this post.
At this point I'm running out of ideas of how to resolve this. The issue impacts only some of the BLE devices I'm interacting with and only in release builds.
@ionutlepi, I observed some interesting things tonight. In an act of desperation I completely removed bitgatt from my demo app and tried to directly use Android's Bluetooth APIs instead. Everything looked great while debugging but as soon as I ran my app without the debugger the same error started happening!
BluetoothProfile.STATE_DISCONNECTED
was being sent to BluetoothGattCallback#onConnectionStateChange
with a status code of 8. I did some searching and found this stackoverflow post. I tried delaying my call to BluetoothGatt#writeDescriptor
as was recommended and the problem vanished!
You can check out the source code of my edits here
I went back to my original usage of bitgatt to apply a similar edit...
// Connect...
gatt.runTx(GattConnectTransaction(...)) {
// Discover...
gatt.runTx(GattClientDiscoverServicesTransaction(...)) {
// Find my service/characteristic/descriptor
val service: BluetoothGattService
val characteristic: BluetoothGattCharacteristic
val descriptor: BluetoothGattDescriptor
// Delay a tiny bit...
Handler(Looper.myLooper()).postDelayed({
// Subscribe
descriptor.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
gatt.runTx(CompositeClientTransaction(this, listOf(
SubscribeToCharacteristicNotificationsTransaction(...),
WriteGattDescriptorTransaction(...)))) {
// Should be good to go!
}
}, 500L)
}
}
... and the problem disappeared.
There appears to be some kind of race condition happening in the Android Bluetooth stack that causes problems if you try to subscribe to a characteristic immediately after performing a service discovery. Having my app inject a delay between its calls to bitgatt solved the problem but this feels like a weird android Bluetooth nuance that bitgatt should be responsible for handling. What are your thoughts?
@NathanRussak great find.
The debugger slows everything down so that is why you may not be seeing during a debug session. Also debug builds contain more logs states so that may slow things a little as well.
Per Bitgatt you could set the IntraTransactionDelay by calling this
Let me know if this works for you.
As per root cause of this issue it could also stem from a combination of a certain peripheral bluetooth chip + Android (i don't think its os specific since you encountered it with different os versions/phones) . I was not able to replicate the issue for example with an nrf52840 DK board or with other internal testing.
For Android i would recommend filling a bug following this process https://source.android.com/setup/contribute/report-bugs and using the barebones android code as a sample for the bug.
As per bitgatt handle of this: IntraTransactionDelay should cover this as fixing the behaviour.
Not sure yet if bitgatt should contain more code specific for this issue as it seems to occur only with certain peripherals. But will consider it and think how the best approach would be.
Thank you for documenting this and all the information provided.
Ah, excellent callout on #setIntraTransactionDelay
. I didn't know that property was available. It sounds like exactly what I need! Glad to see this is already part of bitgatt! I'll give it a shot and report my findings.
After leveraging #setIntraTransactionDelay
I think I've seen enough improvement to consider this issue closed/resolved. Thanks again for hashing this out with me @ionutlepi.
Describe the bug I am trying to connect to a BLE thermometer that has an "indicate" characteristic. When running my app with the debugger attached everything works perfectly. I can connect to the device, discover services, subscribe to the characteristic, get updates, etc. But anytime I run my app without the debugger my device connection is always severed after 2-3 seconds. The logs call out a GATT_INSUF_AUTHORIZATION error.
Here are logs from the setup process:
And here are logs when the connection is lost:
To Reproduce Steps to reproduce the behavior:
Expected behavior The BLE device should remain connected until it is intentionally disconnected, turned off, or walks out of range.
Peripheral (please complete the following information):
Smartphone (please complete the following information):
Additional context This seems to happen primarily on devices with "indicate" characteristics. In my testing, "notify" characteristics do not seem to be impacted.