Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BleClient Becomes Non-Responsive (Hangs Indefinitely) #734

Open
wittigtech opened this issue Dec 4, 2024 · 7 comments
Open

BleClient Becomes Non-Responsive (Hangs Indefinitely) #734

wittigtech opened this issue Dec 4, 2024 · 7 comments
Labels
android Impacts the Android platform bug Something isn't working

Comments

@wittigtech
Copy link

Describe the bug
After successfully connecting and disconnecting, the next connection attempt causes the plugin to hang indefinitely. After the subsequent BleClient.connect(), the following call to BleClient.startNotifications() never resolves. Instead, after a brief pause onDisconnect callback is triggered. At this point, the plugin functionality is not recoverable. Attempting a connect() retry (or call to any BleClient function) results in no response. When in this state, the only resolution seems to be to restart to application.

To Reproduce
Steps to reproduce the behavior:

  1. Call BleClient.connect() to establish connection to a device
  2. Call BleClient.startNotifications() to listen for changes of a characteristic
  3. After satisfied with successful connection, call BleClient.stopNotifications() to stop listening
  4. Call BleClient.disconnect() to disconnect from device
  5. Up until here, there are no issues. At some point, a user wants to connect to another device or same device, so the steps are repeated.
  6. Call BleClient.connect() to establish connection to a device
  7. Call BleClient.startNotifications() to listen for changes of a characteristic <- this never resolves
  8. onDisconnect callback is triggered without any error, bluetooth-le plugin is non-responsive at this point

Expected behavior
Functions for Connect, StartNotifications, StopNotifications, Disconnect should work consistently across supported Android devices.

Plugin version:

  • @capacitor-community/bluetooth-le: 2.3.0

Smartphone (please complete the following information):

  • Device: Google Pixel 7 Pro
  • OS: Android 15

Additional context
This issue does not affect all Android devices. The following devices reproduce this bug fairly consistently:

  • Google Pixel 7 Pro Android 15
  • Microsoft Surface Duo Android 12

The following devices work as expected:

  • Samsung Galaxy S21 Android 14
  • Samsung Galaxy S9+ Android 10
  • Samsung Galaxy Tab SM-T720 Android 10
@wittigtech wittigtech added the bug Something isn't working label Dec 4, 2024
@peitschie
Copy link
Collaborator

Hi @wittigtech

It's possible there is a quirk difference here between the Google/Samsung devices. It's also worth looking at the behaviour when using nrf Connect with the Samsung tablets to see if that application shows any issues subscribing to notifications.

Another possibility is that this is a peripheral issue that is handled slightly differently by the different Android Bluetooth stacks.

The startNotifications call expects the peripheral to acknowledge the descriptor via an onDescriptorWrite reply:

Are you able to see if these callbacks are being triggered on the Samsung devices?

@peitschie peitschie added the android Impacts the Android platform label Dec 4, 2024
@wittigtech
Copy link
Author

@peitschie, thanks for the feedback.

I was able to put some breakpoints and confirmed onDescriptoreWrite() is being triggered consistently for all devices, including Samsung and Pixel devices. However, this helped me to narrow it down.

Prior to this descriptor write event, the phone will prompt the user to Pair with the peripheral. If this prompt is reached, connectivity and functionality works as expected. In the instances where the plugin hangs, we never got the prompt to Pair.

Here is a side by side order of events between the Samsung and Google Pixel:

Samsung (Android 14) Pixel (Android 15) Comparison
connect() => resolves connect() => resolves OK
startNotifications() startNotifications() OK
[prompted to Pair] [prompted to Pair] OK
onDescriptorWrite callback onDescriptorWrite callback OK
[everything works, then user disconnects] [everything works, then user disconnects] OK
stopNotifications() stopNotifications() OK
disconnect() disconnect() OK
onDisconnect callback onDisconnect callback OK
[user ready to connect again] [user ready to connect again] OK
connect() => resolves connect() => resolves OK
startNotifications() startNotifications() OK
[prompted to Pair] onDisconnect callback uh oh
[everything works] [plugin unresponsive] yikes!

I am thinking the Pixel's 2nd connect() is resolving prematurely. Is there a way to confirm at this point (before calling startNotifications) to verify successful connection?

@peitschie
Copy link
Collaborator

This is some great research @wittigtech

Apologies, I haven't had time to dig into this further.

Out of interest... which characteristics are marked as encrypted here (triggering the pairing dialog)?

@wittigtech
Copy link
Author

Thanks @peitschie

We are connecting to a proprietary peripheral device. The characteristic is an internal key.

@wittigtech
Copy link
Author

@peitschie, thought I'd check in if you had any further questions or ideas.

@wittigtech
Copy link
Author

@peitschie, Happy New Year! I had some more information to share with you on this issue.

We upgraded to capacitor 6.x and the corresponding bluetooth-le plugin to 6.x, the issue remains.

When testing on the Pixel device, we noticed that after having disconnected from the peripheral, the Pixel had a widget on the home screen that was still showing as connected to that peripheral. However we did not see it listed in the Settings > Bluetooth connected devices.

Our suspicion is that the disconnect() is not functioning as expected for the Pixel, leaving a lingering connection, so that the next attempt to connect results in a hang. Thoughts?

@peitschie
Copy link
Collaborator

Our suspicion is that the disconnect() is not functioning as expected for the Pixel, leaving a lingering connection, so that the next attempt to connect results in a hang.

I have definitely seen manufacturer-specific bugs that cause the Bluetooth connection to remain in strange connected states (e.g., if there are active notification subscriptions) at various points in time. So... what you're describing here is definitely possible in my experience.

The bit that I can't figure out though is that in your testing matrix above, the second connection for each phone seemed to work... it was only on the subsequent start notifications call (which triggers the pairing) that everything went wrong.

Still... something to try is calling BleClient.disableQueue() (this is a very unsupported mode, so I would only recommend this as a debugging step!) and see if this changes the behaviour here in a good or bad way between the devices?

Another random thought I had is whether you can attempt to call read on the characteristic you want to start notifications on first? Just in case the read-with-pairing workflow (as opposed to start notifications-with-pairing) goes down a different path in the OS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android Impacts the Android platform bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants