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

Commit 481dfa26 authored by Kyunglyul Hyun's avatar Kyunglyul Hyun
Browse files

Fix background connection

The `cif_set` should have been used instead of `cif_mask`
when dynamic allocation is enabled.

Using `cif_mask` prevented background connections
from being established when the flag was turned on.

This change corrects the function call and adds a test
for background GATT connections to ensure
the issue is resolved and prevent future regressions.

Bug: 371617855
Bug: 348559823
Flag: gatt_client_dynamic_allocation
Test: atest GattClientTest

Change-Id: I5e8fba7e3b133475fe2e98581209145b75d3fb41
parent 3f8be643
Loading
Loading
Loading
Loading
+51 −25
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;

import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.test_utils.EnableBluetoothRule;
import android.content.Context;
import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -40,15 +39,17 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Log;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.platform.app.InstrumentationRegistry;

import com.android.bluetooth.flags.Flags;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;

import com.google.protobuf.ByteString;
import com.google.testing.junit.testparameterinjector.TestParameter;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;

import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,6 +74,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.UUID;

@RunWith(TestParameterInjector.class)
@@ -98,15 +100,38 @@ public class GattClientTest {
    public final PandoraDevice mBumble = new PandoraDevice();

    @Rule(order = 2)
    public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();

    @Rule(order = 3)
    public final EnableBluetoothRule mEnableBluetoothRule = new EnableBluetoothRule(false, true);

    private final Context mContext = ApplicationProvider.getApplicationContext();
    private final BluetoothManager mManager = mContext.getSystemService(BluetoothManager.class);
    private final BluetoothAdapter mAdapter = mManager.getAdapter();
    private final BluetoothLeScanner mLeScanner = mAdapter.getBluetoothLeScanner();

    private Host mHost;
    private BluetoothDevice mRemoteLeDevice;

    @Before
    public void setUp() throws Exception {
        InstrumentationRegistry.getInstrumentation()
                .getUiAutomation()
                .adoptShellPermissionIdentity();

        mHost = new Host(mContext);
        mRemoteLeDevice =
                mAdapter.getRemoteLeDevice(
                        Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);
        mRemoteLeDevice.removeBond();
    }

    @After
    public void tearUp() throws Exception {
        InstrumentationRegistry.getInstrumentation()
                .getUiAutomation()
                .dropShellPermissionIdentity();
        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
        if (bondedDevices.contains(mRemoteLeDevice)) {
            mRemoteLeDevice.removeBond();
        }
    }

    @Test
    public void directConnectGattAfterClose() throws Exception {
@@ -138,9 +163,12 @@ public class GattClientTest {
    }

    @Test
    public void fullGattClientLifecycle() throws Exception {
    public void fullGattClientLifecycle(@TestParameter boolean autoConnect) {
        if (autoConnect) {
            createLeBondAndWaitBonding(mRemoteLeDevice);
        }
        BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class);
        BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback);
        BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback, autoConnect);
        disconnectAndWaitDisconnection(gatt, gattCallback);
    }

@@ -148,13 +176,10 @@ public class GattClientTest {
    public void reconnectExistingClient() throws Exception {
        advertiseWithBumble();

        BluetoothDevice device =
                mAdapter.getRemoteLeDevice(
                        Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);
        BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class);
        InOrder inOrder = inOrder(gattCallback);

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

@@ -465,30 +490,27 @@ public class GattClientTest {
    }

    private BluetoothGatt connectGattAndWaitConnection(BluetoothGattCallback callback) {
        return connectGattAndWaitConnection(callback, /* autoConnect= */ false);
    }

    private BluetoothGatt connectGattAndWaitConnection(
            BluetoothGattCallback callback, boolean autoConnect) {
        final int status = GATT_SUCCESS;
        final int state = STATE_CONNECTED;

        advertiseWithBumble();

        BluetoothDevice device =
                mAdapter.getRemoteLeDevice(
                        Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);

        BluetoothGatt gatt = device.connectGatt(mContext, false, callback);
        BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, autoConnect, callback);
        verify(callback, timeout(1000)).onConnectionStateChange(eq(gatt), eq(status), eq(state));

        return gatt;
    }

    /** Tries to connect GATT, it could fail and return null. */
    private BluetoothGatt tryConnectGatt(BluetoothGattCallback callback) {
    private BluetoothGatt tryConnectGatt(BluetoothGattCallback callback, boolean autoConnect) {
        advertiseWithBumble();

        BluetoothDevice device =
                mAdapter.getRemoteLeDevice(
                        Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);

        BluetoothGatt gatt = device.connectGatt(mContext, false, callback);
        BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, autoConnect, callback);

        ArgumentCaptor<Integer> statusCaptor = ArgumentCaptor.forClass(Integer.class);
        ArgumentCaptor<Integer> stateCaptor = ArgumentCaptor.forClass(Integer.class);
@@ -596,7 +618,6 @@ public class GattClientTest {
    @Test
    @RequiresFlagsEnabled(Flags.FLAG_GATT_CLIENT_DYNAMIC_ALLOCATION)
    public void connectGatt_multipleClients() {
        advertiseWithBumble();
        registerGattService();

        List<BluetoothGatt> gatts = new ArrayList<>();
@@ -606,7 +627,7 @@ public class GattClientTest {
        try {
            for (int i = 0; i < repeatTimes; i++) {
                BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class);
                BluetoothGatt gatt = tryConnectGatt(gattCallback);
                BluetoothGatt gatt = tryConnectGatt(gattCallback, false);
                // If it fails, close an existing gatt instance and try again.
                if (gatt == null) {
                    failed = true;
@@ -664,4 +685,9 @@ public class GattClientTest {
            gatt.close();
        }
    }

    private void createLeBondAndWaitBonding(BluetoothDevice device) {
        advertiseWithBumble();
        mHost.createBondAndVerify(device);
    }
}
+15 −6
Original line number Diff line number Diff line
@@ -691,9 +691,12 @@ bool bta_gattc_mark_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda_ptr
        p_bg_tck->in_use = true;
        p_bg_tck->remote_bda = remote_bda_ptr;

        if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
          p_bg_tck->cif_set = {client_if};
        } else {
          p_cif_mask = &p_bg_tck->cif_mask;

          *p_cif_mask = ((tBTA_GATTC_CIF_MASK)1 << (client_if - 1));
        }
        return true;
      }
    }
@@ -719,12 +722,18 @@ bool bta_gattc_check_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda, u
  for (i = 0; i < ble_acceptlist_size() && !is_bg_conn; i++, p_bg_tck++) {
    if (p_bg_tck->in_use &&
        (p_bg_tck->remote_bda == remote_bda || p_bg_tck->remote_bda.IsEmpty())) {
      if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
        if (p_bg_tck->cif_set.contains(client_if) && role == HCI_ROLE_CENTRAL) {
          is_bg_conn = true;
        }
      } else {
        if (((p_bg_tck->cif_mask & ((tBTA_GATTC_CIF_MASK)1 << (client_if - 1))) != 0) &&
            role == HCI_ROLE_CENTRAL) {
          is_bg_conn = true;
        }
      }
    }
  }
  return is_bg_conn;
}
/*******************************************************************************