Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38a128a7 authored by Kyunglyul Hyun's avatar Kyunglyul Hyun
Browse files

Remove device only upon the last cancellation

While multiple clients attempt to connect to the
same device, if one client cancels, the device
should not be removed from the accept list,
as this would prevent other clients from connecting.

This change checks if other clients are still
interested in the device and avoids removing it
from the accept list in such cases.

Bug: 349232327
Bug: 349234039
Test: atest GattClientTest
Change-Id: If5fea38d6034b581c7a401351090c65305af3476
parent 92f95470
Loading
Loading
Loading
Loading
+45 −32
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.bluetooth;

import static android.bluetooth.BluetoothGatt.GATT_SUCCESS;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;

@@ -118,7 +121,7 @@ public class GattClientTest {
        BluetoothGattCallback gattCallback2 = mock(BluetoothGattCallback.class);
        BluetoothGatt gatt2 = device.connectGatt(mContext, false, gattCallback2);
        verify(gattCallback2, timeout(1000))
                .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED));
                .onConnectionStateChange(any(), anyInt(), eq(STATE_CONNECTED));
        disconnectAndWaitDisconnection(gatt2, gattCallback2);

        // After reconnecting, verify the first callback was not invoked.
@@ -147,7 +150,7 @@ public class GattClientTest {

        BluetoothGatt gatt = device.connectGatt(mContext, false, gattCallback);
        inOrder.verify(gattCallback, timeout(1000))
                .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED));
                .onConnectionStateChange(any(), anyInt(), eq(STATE_CONNECTED));

        gatt.disconnect();
        inOrder.verify(gattCallback, timeout(1000))
@@ -155,7 +158,7 @@ public class GattClientTest {

        gatt.connect();
        inOrder.verify(gattCallback, timeout(1000))
                .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED));
                .onConnectionStateChange(any(), anyInt(), eq(STATE_CONNECTED));

        // TODO(323889717): Fix callback being called after gatt.close(). This disconnect shouldn't
        //  be necessary.
@@ -172,8 +175,7 @@ public class GattClientTest {

        try {
            gatt.discoverServices();
            verify(gattCallback, timeout(10000))
                    .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS));
            verify(gattCallback, timeout(10000)).onServicesDiscovered(any(), eq(GATT_SUCCESS));

            assertThat(gatt.getServices().stream().map(BluetoothGattService::getUuid))
                    .contains(GAP_UUID);
@@ -190,8 +192,7 @@ public class GattClientTest {

        try {
            gatt.discoverServices();
            verify(gattCallback, timeout(10000))
                    .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS));
            verify(gattCallback, timeout(10000)).onServicesDiscovered(any(), eq(GATT_SUCCESS));

            BluetoothGattService firstService = gatt.getServices().get(0);

@@ -216,8 +217,7 @@ public class GattClientTest {

        try {
            gatt.discoverServices();
            verify(gattCallback, timeout(10000))
                    .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS));
            verify(gattCallback, timeout(10000)).onServicesDiscovered(any(), eq(GATT_SUCCESS));

            BluetoothGattCharacteristic characteristic =
                    gatt.getService(TEST_SERVICE_UUID).getCharacteristic(TEST_CHARACTERISTIC_UUID);
@@ -228,8 +228,7 @@ public class GattClientTest {
                    characteristic, newValue, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);

            verify(gattCallback, timeout(5000))
                    .onCharacteristicWrite(
                            any(), eq(characteristic), eq(BluetoothGatt.GATT_SUCCESS));
                    .onCharacteristicWrite(any(), eq(characteristic), eq(GATT_SUCCESS));

        } finally {
            disconnectAndWaitDisconnection(gatt, gattCallback);
@@ -246,8 +245,7 @@ public class GattClientTest {

        try {
            gatt.discoverServices();
            verify(gattCallback, timeout(10000))
                    .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS));
            verify(gattCallback, timeout(10000)).onServicesDiscovered(any(), eq(GATT_SUCCESS));

            BluetoothGattCharacteristic characteristic =
                    gatt.getService(TEST_SERVICE_UUID).getCharacteristic(TEST_CHARACTERISTIC_UUID);
@@ -260,7 +258,7 @@ public class GattClientTest {
            assertThat(gatt.writeDescriptor(descriptor)).isTrue();

            verify(gattCallback, timeout(5000))
                    .onDescriptorWrite(any(), eq(descriptor), eq(BluetoothGatt.GATT_SUCCESS));
                    .onDescriptorWrite(any(), eq(descriptor), eq(GATT_SUCCESS));

            gatt.setCharacteristicNotification(characteristic, true);

@@ -315,10 +313,8 @@ public class GattClientTest {
        try {
            gatt.discoverServices();
            gatt2.discoverServices();
            verify(gattCallback, timeout(10000))
                    .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS));
            verify(gattCallback2, timeout(10000))
                    .onServicesDiscovered(any(), eq(BluetoothGatt.GATT_SUCCESS));
            verify(gattCallback, timeout(10000)).onServicesDiscovered(any(), eq(GATT_SUCCESS));
            verify(gattCallback2, timeout(10000)).onServicesDiscovered(any(), eq(GATT_SUCCESS));

            BluetoothGattCharacteristic characteristic =
                    gatt.getService(TEST_SERVICE_UUID).getCharacteristic(TEST_CHARACTERISTIC_UUID);
@@ -341,11 +337,9 @@ public class GattClientTest {
                            == BluetoothStatusCodes.SUCCESS);

            verify(gattCallback, timeout(5000))
                    .onCharacteristicWrite(
                            any(), eq(characteristic), eq(BluetoothGatt.GATT_SUCCESS));
                    .onCharacteristicWrite(any(), eq(characteristic), eq(GATT_SUCCESS));
            verify(gattCallback2, never())
                    .onCharacteristicWrite(
                            any(), eq(characteristic), eq(BluetoothGatt.GATT_SUCCESS));
                    .onCharacteristicWrite(any(), eq(characteristic), eq(GATT_SUCCESS));

            assertThat(
                            gatt2.writeCharacteristic(
@@ -354,14 +348,33 @@ public class GattClientTest {
                                    BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT))
                    .isEqualTo(BluetoothStatusCodes.SUCCESS);
            verify(gattCallback2, timeout(5000))
                    .onCharacteristicWrite(
                            any(), eq(characteristic2), eq(BluetoothGatt.GATT_SUCCESS));
                    .onCharacteristicWrite(any(), eq(characteristic2), eq(GATT_SUCCESS));
        } finally {
            disconnectAndWaitDisconnection(gatt, gattCallback);
            disconnectAndWaitDisconnection(gatt2, gattCallback2);
        }
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_GATT_FIX_MULTIPLE_DIRECT_CONNECT)
    public void connectMultiple_closeOne_shouldSuccess() {
        BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class);
        BluetoothGattCallback gattCallback2 = mock(BluetoothGattCallback.class);

        advertiseWithBumble();
        BluetoothDevice device =
                mAdapter.getRemoteLeDevice(
                        Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);
        BluetoothGatt gatt = device.connectGatt(mContext, false, gattCallback);
        BluetoothGatt gatt2 = device.connectGatt(mContext, false, gattCallback2);

        gatt.disconnect();
        gatt.close();

        verify(gattCallback2, timeout(1000))
                .onConnectionStateChange(eq(gatt2), eq(GATT_SUCCESS), eq(STATE_CONNECTED));
    }

    private void registerWritableGattService() {
        GattCharacteristicParams characteristicParams =
                GattCharacteristicParams.newBuilder()
@@ -439,8 +452,8 @@ public class GattClientTest {
    }

    private BluetoothGatt connectGattAndWaitConnection(BluetoothGattCallback callback) {
        final int status = BluetoothGatt.GATT_SUCCESS;
        final int state = BluetoothProfile.STATE_CONNECTED;
        final int status = GATT_SUCCESS;
        final int state = STATE_CONNECTED;

        advertiseWithBumble();

@@ -503,7 +516,7 @@ public class GattClientTest {
            assertThat(gatt.requestMtu(MTU_REQUESTED)).isTrue();
            // Check that only the ANDROID_MTU is returned, not the MTU_REQUESTED
            verify(gattCallback, timeout(5000))
                    .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS));
                    .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(GATT_SUCCESS));
        } finally {
            disconnectAndWaitDisconnection(gatt, gattCallback);
        }
@@ -518,11 +531,11 @@ public class GattClientTest {
            assertThat(gatt.requestMtu(MTU_REQUESTED)).isTrue();
            // Check that only the ANDROID_MTU is returned, not the MTU_REQUESTED
            verify(gattCallback, timeout(5000))
                    .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS));
                    .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(GATT_SUCCESS));

            assertThat(gatt.requestMtu(ANOTHER_MTU_REQUESTED)).isTrue();
            verify(gattCallback, timeout(5000).times(2))
                    .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS));
                    .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(GATT_SUCCESS));
        } finally {
            disconnectAndWaitDisconnection(gatt, gattCallback);
        }
@@ -536,17 +549,17 @@ public class GattClientTest {
        try {
            assertThat(gatt.requestMtu(MTU_REQUESTED)).isTrue();
            verify(gattCallback, timeout(5000))
                    .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS));
                    .onMtuChanged(eq(gatt), eq(ANDROID_MTU), eq(GATT_SUCCESS));

            BluetoothGattCallback gattCallback2 = mock(BluetoothGattCallback.class);
            BluetoothGatt gatt2 = connectGattAndWaitConnection(gattCallback2);
            try {
                // first callback because there is already a connected device
                verify(gattCallback2, timeout(9000))
                        .onMtuChanged(eq(gatt2), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS));
                        .onMtuChanged(eq(gatt2), eq(ANDROID_MTU), eq(GATT_SUCCESS));
                assertThat(gatt2.requestMtu(ANOTHER_MTU_REQUESTED)).isTrue();
                verify(gattCallback2, timeout(9000).times(2))
                        .onMtuChanged(eq(gatt2), eq(ANDROID_MTU), eq(BluetoothGatt.GATT_SUCCESS));
                        .onMtuChanged(eq(gatt2), eq(ANDROID_MTU), eq(GATT_SUCCESS));
            } finally {
                disconnectAndWaitDisconnection(gatt2, gattCallback2);
            }
+4 −1
Original line number Diff line number Diff line
@@ -1569,7 +1569,10 @@ bool gatt_cancel_open(tGATT_IF gatt_if, const RawAddress& bda) {
  } else {
    if (!connection_manager::direct_connect_remove(gatt_if, bda)) {
      if (!connection_manager::is_background_connection(bda)) {
        if (!com::android::bluetooth::flags::gatt_fix_multiple_direct_connect() ||
            p_tcb->app_hold_link.empty()) {
          BTM_AcceptlistRemove(bda);
        }
        log::info(
            "Gatt connection manager has no background record but  removed "
            "filter acceptlist gatt_if:{} peer:{}",