Add timeout when connecting to GATT server

This commit is contained in:
José Rebelo
2026-01-01 22:42:47 +00:00
parent 305f1827e0
commit 43fc2e4727
@@ -98,6 +98,7 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
private final Thread mDispatchThread;
private final HandlerThread mReceiverThread;
private final Handler mReceiverHandler;
private final Handler mGattConnectTimeoutHandler;
private class DispatchRunnable implements Runnable {
@Override
@@ -214,7 +215,7 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
}
LOG.debug("finished thread {}", Thread.currentThread().getName());
}
};
}
BtLEQueue(GBDevice gbDevice, Set<? extends BluetoothGattService> supportedServerServices, AbstractBTLEDeviceSupport deviceSupport) {
final long threadIdx = THREAD_COUNTER.getAndIncrement();
@@ -234,6 +235,7 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
mSupportedServerServices = supportedServerServices;
// #5414 - some older android versions misbehave with the new constructor
connectionForceLegacyGatt = deviceSupport.getDevicePrefs().getConnectionForceLegacyGatt();
mGattConnectTimeoutHandler = new Handler(Looper.getMainLooper());
// 2) create new objects
mDisposed = new AtomicBoolean(false);
@@ -323,6 +325,12 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
mPauseTransaction = false;
LOG.info("Attempting to connect to {}", mGbDevice.getName());
mGattConnectTimeoutHandler.postDelayed(() -> {
LOG.warn("Timed out connecting to GATT for {}", mGbDevice.getName());
handleDisconnected(0x93 /* BluetoothGatt.GATT_CONNECTION_TIMEOUT */);
}, 5000L);
mBluetoothAdapter.cancelDiscovery();
BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(mGbDevice.getAddress());
if(!mSupportedServerServices.isEmpty()) {
@@ -362,7 +370,9 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
}
void disconnect() {
LOG.debug("disconnecting");
synchronized (mGattMonitor) {
mGattConnectTimeoutHandler.removeCallbacksAndMessages(null);
BluetoothGatt gatt = mBluetoothGatt;
if (gatt != null) {
mBluetoothGatt = null;
@@ -392,6 +402,7 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
mPauseTransaction = false;
mAbortTransaction = true;
mAbortServerTransaction = true;
mGattConnectTimeoutHandler.removeCallbacksAndMessages(null);
final CountDownLatch clientLatch = mWaitForActionResultLatch;
if (clientLatch != null) {
clientLatch.countDown();
@@ -402,16 +413,17 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
}
boolean forceDisconnect;
switch(status){
//noinspection EnhancedSwitchMigration
switch(status) {
case 0x81: // 0x81 129 GATT_INTERNAL_ERROR
case 0x85: // 0x85 133 GATT_ERROR
// Bluetooth stack has a fundamental problem:
case BluetoothGatt.GATT_INSUFFICIENT_AUTHORIZATION:
case 0x8: // BluetoothGatt.GATT_INSUFFICIENT_AUTHORIZATION only on API 35
case BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION:
case BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION:
// a Bluetooth bonding / pairing issue
// some devices report AUTHORIZATION instead of TIMEOUT during connection setup
case BluetoothGatt.GATT_CONNECTION_TIMEOUT:
case 0x93: // BluetoothGatt.GATT_CONNECTION_TIMEOUT only on API 35
forceDisconnect = true;
break;
default:
@@ -489,8 +501,6 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
/**
* Adds a transaction to the end of the queue.
*
* @param transaction
*/
void add(Transaction transaction) {
LOG.debug("add: {}", transaction);
@@ -617,6 +627,7 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
LOG.info("Connected to GATT server.");
mGattConnectTimeoutHandler.removeCallbacksAndMessages(null);
setDeviceConnectionState(State.CONNECTED);
// discover services in the main thread (appears to fix Samsung connection problems)
@@ -730,7 +741,7 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
@Override
public void onCharacteristicRead(@NonNull BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
@NonNull BluetoothGattCharacteristic characteristic,
@NonNull byte[] value, int status) {
if (LOG.isDebugEnabled()) {
String content = GB.hexdump(value);
@@ -762,7 +773,7 @@ public final class BtLEQueue implements Thread.UncaughtExceptionHandler {
}
@Override
public void onDescriptorRead(@NonNull BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
public void onDescriptorRead(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
if (LOG.isDebugEnabled()) {
String content = GB.hexdump(value);
LOG.debug("descriptor read: {} {} - {}", descriptor.getUuid(),