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

Commit c32bedce authored by David Duarte's avatar David Duarte Committed by Android (Google) Code Review
Browse files

Merge changes from topic "bluetooth_pb2" into udc-dev

* changes:
  Battery: Only connect or disconnect BAS for BLE ACL link
  Check LE audio support before resetting the pairing state
  CSIP: Fix notifying about connected devices
  Ensure services are searched over BR/EDR transport after BR/EDR pairing
  bt: Fix getting device type.
  LE Audio: Return SDP services if GATT discovery on LE transport fails
  LeAudioService: Fix starting scanner
  leaudio: Remove CIG when all ASEs are in the Releasing state
  Fix for infinite loop in free_gatt_resources
parents a14dc09e 0813a54e
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -892,7 +892,9 @@ final class RemoteDevices {
                            break;
                        case AbstractionLayer.BT_PROPERTY_BDADDR:
                            deviceProperties.setAddress(val);
                            debugLog("Remote Address is:" + Utils.getRedactedAddressStringFromByte(val));
                            debugLog(
                                    "Remote Address is:"
                                            + Utils.getRedactedAddressStringFromByte(val));
                            break;
                        case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
                            final int newBluetoothClass = Utils.byteArrayToInt(val);
@@ -1103,7 +1105,7 @@ final class RemoteDevices {
                intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_CONNECTED);
            }
            BatteryService batteryService = BatteryService.getBatteryService();
            if (batteryService != null) {
            if (batteryService != null && transportLinkType == BluetoothDevice.TRANSPORT_LE) {
                batteryService.connectIfPossible(device);
            }
            SecurityLog.writeEvent(SecurityLog.TAG_BLUETOOTH_CONNECTION,
@@ -1139,7 +1141,8 @@ final class RemoteDevices {
                BatteryService batteryService = BatteryService.getBatteryService();
                if (batteryService != null
                        && batteryService.getConnectionState(device)
                        != BluetoothProfile.STATE_DISCONNECTED) {
                                != BluetoothProfile.STATE_DISCONNECTED
                        && transportLinkType == BluetoothDevice.TRANSPORT_LE) {
                    batteryService.disconnect(device);
                }
                resetBatteryLevel(device);
+42 −7
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ public class CsipSetCoordinatorService extends ProfileService {
    private final Map<Integer, Integer> mGroupIdToGroupSize = new HashMap<>();
    // Tracks the number of available devices mapped to the group id
    private final Map<Integer, Set<BluetoothDevice>> mGroupIdToConnectedDevices = new HashMap<>();
    private final Map<BluetoothDevice, Integer> mFoundSetMemberToGroupId = new HashMap<>();
    private final Map<ParcelUuid, Map<Executor, IBluetoothCsipSetCoordinatorCallback>> mCallbacks =
            new HashMap<>();
    private final Map<Integer, Pair<UUID, IBluetoothCsipSetCoordinatorLockCallback>> mLocks =
@@ -221,6 +222,7 @@ public class CsipSetCoordinatorService extends ProfileService {

        mDeviceGroupIdRankMap.clear();
        mCallbacks.clear();
        mFoundSetMemberToGroupId.clear();
        mGroupIdToGroupSize.clear();
        mGroupIdToConnectedDevices.clear();
        mGroupIdToUuidMap.clear();
@@ -832,6 +834,25 @@ public class CsipSetCoordinatorService extends ProfileService {
        }
    }

    void notifySetMemberAvailable(BluetoothDevice device, int groupId) {
        if (DBG) {
            Log.d(TAG, "notifySetMemberAvailable: " + device + ", " + groupId);
        }

        /* Sent intent as well */
        Intent intent = new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId);

        intent.addFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        sendBroadcast(intent, BLUETOOTH_PRIVILEGED);

        /* Notify registered parties */
        handleSetMemberAvailable(device, groupId);
    }

    void messageFromNative(CsipSetCoordinatorStackEvent stackEvent) {
        BluetoothDevice device = stackEvent.device;
        Log.d(TAG, "Message from native: " + stackEvent);
@@ -854,13 +875,12 @@ public class CsipSetCoordinatorService extends ProfileService {
        } else if (stackEvent.type
                == CsipSetCoordinatorStackEvent.EVENT_TYPE_SET_MEMBER_AVAILABLE) {
            Objects.requireNonNull(device, "Device should never be null, event: " + stackEvent);
            /* Notify registered parties */
            handleSetMemberAvailable(device, stackEvent.valueInt1);

            /* Sent intent as well */
            intent = new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE);
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
            intent.putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId);
            if (!mFoundSetMemberToGroupId.containsKey(device)) {
                mFoundSetMemberToGroupId.put(device, groupId);
            }
            if (mGroupIdToConnectedDevices.containsKey(groupId)) {
                notifySetMemberAvailable(device, groupId);
            }
        } else if (stackEvent.type == CsipSetCoordinatorStackEvent.EVENT_TYPE_GROUP_LOCK_CHANGED) {
            int lock_status = stackEvent.valueInt2;
            boolean lock_state = stackEvent.valueBool1;
@@ -953,6 +973,10 @@ public class CsipSetCoordinatorService extends ProfileService {
        if (DBG) {
            Log.d(TAG, "Bond state changed for device: " + device + " state: " + bondState);
        }
        if (bondState == BluetoothDevice.BOND_BONDING
                && mFoundSetMemberToGroupId.containsKey(device)) {
            mFoundSetMemberToGroupId.remove(device);
        }

        // Remove state machine if the bonding for a device is removed
        if (bondState != BluetoothDevice.BOND_NONE) {
@@ -1017,6 +1041,11 @@ public class CsipSetCoordinatorService extends ProfileService {
            if (!mGroupIdToConnectedDevices.containsKey(groupId)) {
                mGroupIdToConnectedDevices.put(groupId, new HashSet<>());
            }
            for (Map.Entry<BluetoothDevice, Integer> entry : mFoundSetMemberToGroupId.entrySet()) {
                if (entry.getValue() == groupId) {
                    notifySetMemberAvailable(entry.getKey(), groupId);
                }
            }
            mGroupIdToConnectedDevices.get(groupId).add(device);
            disableCsipIfNeeded(groupId);
        }
@@ -1337,5 +1366,11 @@ public class CsipSetCoordinatorService extends ProfileService {
        for (CsipSetCoordinatorStateMachine sm : mStateMachines.values()) {
            sm.dump(sb);
        }
        ProfileService.println(sb, "mFoundSetMemberToGroupId: ");
        for (Map.Entry<BluetoothDevice, Integer> entry : mFoundSetMemberToGroupId.entrySet()) {
            ProfileService.println(
                    sb,
                    "  member device: " + entry.getKey() + ", group ID: " + entry.getValue());
        }
    }
}
+8 −3
Original line number Diff line number Diff line
@@ -1182,15 +1182,20 @@ public class LeAudioService extends ProfileService {

        @Override
        public void onScanFailed(int errorCode) {
            Log.w(TAG, "Scan failed " + errorCode + " scan retries: " + mScanRetries);
            Log.w(TAG, "Scan failed err: " + errorCode + " scan retries: " + mScanRetries);
            switch(errorCode) {
                case SCAN_FAILED_INTERNAL_ERROR: {
                case SCAN_FAILED_INTERNAL_ERROR:
                case SCAN_FAILED_APPLICATION_REGISTRATION_FAILED:
                    if (mScanRetries < mMaxScanRetires) {
                        mScanRetries++;
                        Log.w(TAG, "Failed to start. Let's retry");
                        mHandler.post(() -> startAudioServersBackgroundScan(/* retry = */ true));
                    }
                }
                    break;
                default:
                    /* Indicate scan is no running */
                    mScanCallback = null;
                    break;
            }
        }
    }
+75 −5
Original line number Diff line number Diff line
@@ -521,23 +521,93 @@ public class CsipSetCoordinatorServiceTest {
    }

    /**
     * Test that native callback generates proper intent.
     * Test that native callback generates proper intent after group connected.
     */
    @Test
    public void testStackEventSetMemberAvailable() {
    public void testStackEventSetMemberAvailableAfterGroupConnected() {
        int group_id = 0x01;
        int group_size = 0x02;
        long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits();
        long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits();

        // Make sure to use real methods when needed below
        doCallRealMethod()
                .when(mCsipSetCoordinatorNativeInterface)
                .onDeviceAvailable(any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(),
                        anyLong());
        doCallRealMethod()
                .when(mCsipSetCoordinatorNativeInterface)
                .onConnectionStateChanged(any(byte[].class), anyInt());
        doCallRealMethod()
                .when(mCsipSetCoordinatorNativeInterface)
                .onSetMemberAvailable(any(byte[].class), anyInt());

        mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
                getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);

        mCsipSetCoordinatorNativeInterface.onConnectionStateChanged(
                getByteAddress(mTestDevice), BluetoothProfile.STATE_CONNECTED);

        // Comes from state machine
        mService.connectionStateChanged(mTestDevice, BluetoothProfile.STATE_CONNECTING,
                BluetoothProfile.STATE_CONNECTED);

        mCsipSetCoordinatorNativeInterface.onSetMemberAvailable(
                getByteAddress(mTestDevice), group_id);
                getByteAddress(mTestDevice2), group_id);

        Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice));
        Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2));
        Assert.assertNotNull(intent);
        Assert.assertEquals(
                BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, intent.getAction());
        Assert.assertEquals(mTestDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
        Assert.assertEquals(mTestDevice2, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
        Assert.assertEquals(
                group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1));
    }

    /**
     * Test that native callback generates proper intent before group connected.
     */
    @Test
    public void testStackEventSetMemberAvailableBeforeGroupConnected() {
        int group_id = 0x01;
        int group_size = 0x02;
        long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits();
        long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits();

        // Make sure to use real methods when needed below
        doCallRealMethod()
                .when(mCsipSetCoordinatorNativeInterface)
                .onDeviceAvailable(any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(),
                        anyLong());
        doCallRealMethod()
                .when(mCsipSetCoordinatorNativeInterface)
                .onSetMemberAvailable(any(byte[].class), anyInt());
        doCallRealMethod()
                .when(mCsipSetCoordinatorNativeInterface)
                .onConnectionStateChanged(any(byte[].class), anyInt());

        mCsipSetCoordinatorNativeInterface.onDeviceAvailable(
                getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb);

        mCsipSetCoordinatorNativeInterface.onConnectionStateChanged(
                getByteAddress(mTestDevice), BluetoothProfile.STATE_CONNECTED);

        mCsipSetCoordinatorNativeInterface.onSetMemberAvailable(
                getByteAddress(mTestDevice2), group_id);

        Intent intent = TestUtils.waitForNoIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2));
        Assert.assertNull(intent);

          // Comes from state machine
        mService.connectionStateChanged(mTestDevice, BluetoothProfile.STATE_CONNECTING,
                BluetoothProfile.STATE_CONNECTED);

        intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2));
        Assert.assertNotNull(intent);

        Assert.assertEquals(
                BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, intent.getAction());
        Assert.assertEquals(mTestDevice2, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
        Assert.assertEquals(
                group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1));
    }
+37 −10
Original line number Diff line number Diff line
@@ -1436,10 +1436,18 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
    return true;
  }

  static void CisCreateForDevice(LeAudioDevice* leAudioDevice) {
  static bool CisCreateForDevice(LeAudioDeviceGroup* group,
                                 LeAudioDevice* leAudioDevice) {
    std::vector<EXT_CIS_CREATE_CFG> conn_pairs;
    struct ase* ase = leAudioDevice->GetFirstActiveAse();

    /* Make sure CIG is there */
    if (group->GetCigState() != CigState::CREATED) {
      LOG_ERROR("CIG is not created for group_id %d ", group->group_id_);
      group->PrintDebugState();
      return false;
    }

    std::stringstream extra_stream;
    do {
      /* First in ase pair is Sink, second Source */
@@ -1472,9 +1480,11 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {

    IsoManager::GetInstance()->EstablishCis(
        {.conn_pairs = std::move(conn_pairs)});

    return true;
  }

  static void CisCreate(LeAudioDeviceGroup* group) {
  static bool CisCreate(LeAudioDeviceGroup* group) {
    LeAudioDevice* leAudioDevice = group->GetFirstActiveDevice();
    struct ase* ase;
    std::vector<EXT_CIS_CREATE_CFG> conn_pairs;
@@ -1482,6 +1492,13 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
    LOG_ASSERT(leAudioDevice)
        << __func__ << " Shouldn't be called without an active device.";

    /* Make sure CIG is there */
    if (group->GetCigState() != CigState::CREATED) {
      LOG_ERROR("CIG is not created for group_id %d ", group->group_id_);
      group->PrintDebugState();
      return false;
    }

    do {
      ase = leAudioDevice->GetFirstActiveAse();
      LOG_ASSERT(ase) << __func__
@@ -1513,6 +1530,8 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {

    IsoManager::GetInstance()->EstablishCis(
        {.conn_pairs = std::move(conn_pairs)});

    return true;
  }

  static void PrepareDataPath(int group_id, const struct ase* ase) {
@@ -2510,7 +2529,10 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
        if (group->GetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
          if (ase->data_path_state < AudioStreamDataPathState::CIS_PENDING) {
            /* We are here because of the reconnection of the single device. */
            CisCreateForDevice(leAudioDevice);
            if (!CisCreateForDevice(group, leAudioDevice)) {
              StopStream(group);
              return;
            }
          }

          if (!leAudioDevice->HaveAllActiveAsesCisEst()) {
@@ -2768,15 +2790,17 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
        break;
      }
      case AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED:
        /* At this point all of the active ASEs within group are released. */
        RemoveCigForGroup(group);

        SetAseState(leAudioDevice, ase,
                    AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);

        if (group->HaveAllActiveDevicesAsesTheSameState(
                AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING))
                AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING)) {
          group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_RELEASING);

          /* At this point all of the active ASEs within group are released. */
          RemoveCigForGroup(group);
        }

        break;

      case AseState::BTA_LE_AUDIO_ASE_STATE_ENABLING:
@@ -2832,13 +2856,16 @@ class LeAudioGroupStateMachineImpl : public LeAudioGroupStateMachine {
      group->SetState(AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING);
    }

    if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
      CisCreate(group);
    } else {
    if (group->GetTargetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
      LOG_ERROR(", invalid state transition, from: %s , to: %s ",
                ToString(group->GetState()).c_str(),
                ToString(group->GetTargetState()).c_str());
      StopStream(group);
      return;
    }

    if (!CisCreate(group)) {
      StopStream(group);
    }
  }

Loading