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

Commit 35c5e00d authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

leaudio: Improve TA reconnection

With this patch, LeAudio tries to keep TA background connect registered
even device is already connected.
This is to avoid possible race, when there are other applications with
regular background connect enabled. Race happens on ACL disconnection
and might lead to unwanted reconnecet happen due to device being in the
allow list before Le Audio enabled TA again.

Bug: 311578937
Test: atest bluetooth_le_audio_client_test
Tag: #feature

Change-Id: Ifb7bf8c2a27921649b5ceb43900bf20385c91588
parent 3edec369
Loading
Loading
Loading
Loading
+18 −8
Original line number Diff line number Diff line
@@ -1860,12 +1860,19 @@ class LeAudioClientImpl : public LeAudioClient {
    /* If device belongs to streaming group, add it on allow list */
    auto address = leAudioDevice->address_;
    auto group = GetGroupIfEnabled(leAudioDevice->group_id_);
    if (group == nullptr) {
      LOG_INFO("Group %d is invalid or disabled ", leAudioDevice->group_id_);
      return;
    }

    if (group != nullptr && group->IsAnyDeviceConnected()) {
    leAudioDevice->SetConnectionState(
        DeviceConnectState::CONNECTING_AUTOCONNECT);

    /* Cancel previous bakcground connect */
    BTA_GATTC_CancelOpen(gatt_if_, address, false);
    if (group->IsAnyDeviceConnected()) {
      LOG_INFO("Group %d in connected state. Adding %s to allow list ",
               leAudioDevice->group_id_, ADDRESS_TO_LOGGABLE_CSTR(address));
      /* Make sure TA is canceled before adding to allow list */
      BTA_GATTC_CancelOpen(gatt_if_, address, false);
      BTA_GATTC_Open(gatt_if_, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false);
    } else {
      LOG_INFO(
@@ -1933,6 +1940,14 @@ class LeAudioClientImpl : public LeAudioClient {
      }
    }

    /* Remove device from the background connect (it might be either Allow list
     * or TA) and add it again with reconnection_mode_. In case it is TA, we are
     * sure that device will not be in the allow list for other applications
     * which are using background connect.
     */
    BTA_GATTC_CancelOpen(gatt_if_, address, false);
    BTA_GATTC_Open(gatt_if_, address, reconnection_mode_, false);

    if (controller_get_interface()->supports_ble_2m_phy()) {
      LOG(INFO) << ADDRESS_TO_LOGGABLE_STR(address)
                << " set preferred PHY to 2M";
@@ -2276,11 +2291,6 @@ class LeAudioClientImpl : public LeAudioClient {
      return;
    }

    /* Remove device from the background connect (it might be either Allow list
     * or TA) and it will be added back depends on needs.
     */
    BTA_GATTC_CancelOpen(gatt_if_, address, false);

    BtaGattQueue::Clean(leAudioDevice->conn_id_);
    LeAudioDeviceGroup* group = aseGroups_.FindById(leAudioDevice->group_id_);

+86 −20
Original line number Diff line number Diff line
@@ -1665,7 +1665,8 @@ class UnicastTestNoInit : public Test {
      ;
  }

  void ConnectLeAudio(const RawAddress& address, bool isEncrypted = true) {
  void ConnectLeAudio(const RawAddress& address, bool isEncrypted = true,
                      bool expect_connected_event = true) {
    // by default indicate link as encrypted
    ON_CALL(mock_btm_interface_, BTM_IsEncrypted(address, _))
        .WillByDefault(DoAll(Return(isEncrypted)));
@@ -1677,6 +1678,16 @@ class UnicastTestNoInit : public Test {
                Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, _))
        .Times(1);

    /* If connected event is not expected to arrive, don't test those two below
     */
    if (expect_connected_event) {
      EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, address, false));
      EXPECT_CALL(
          mock_gatt_interface_,
          Open(gatt_if, address, BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
          .Times(1);
    }

    do_in_main_thread(
        FROM_HERE,
        base::BindOnce(&LeAudioClient::Connect,
@@ -3267,24 +3278,42 @@ TEST_F(UnicastTest, ConnectRemoteDisconnectOneEarbud) {
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
  ConnectLeAudio(test_address0);
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::DISCONNECTED, test_address0))
      .Times(1);
  /* For remote disconnection, expect stack to try background re-connect */
  /* Make sure when remote device disconnects us, TA is used */
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);

  InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
  InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER);
  SyncOnMainLoop();

  /* When reconnected, we always remove background connect, as we do not track
   * which type (allow list or TA) was used and then make sure the TA is used.
   */
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);

  /* For background connect, test needs to Inject Connected Event */
  InjectConnectedEvent(test_address0, 1);
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
}

/* same as above case except the disconnect is initiated by remote */
@@ -3310,11 +3339,14 @@ TEST_F(UnicastTest, ConnectRemoteDisconnectOnTimeoutOneEarbud) {
              Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _))
      .Times(1);

  InjectDisconnectedEvent(1, GATT_CONN_TIMEOUT);
  SyncOnMainLoop();

  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(1);
  InjectDisconnectedEvent(1, GATT_CONN_TIMEOUT);
  SyncOnMainLoop();

  /* For background connect, test needs to Inject Connected Event */
  InjectConnectedEvent(test_address0, 1);
@@ -4055,9 +4087,17 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) {
      .Times(1);
  ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _))
      .WillByDefault(DoAll(Return(true)));

  // First device will got connected
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);

  // Expect stored device1 to NOT connect automatically
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
@@ -4102,12 +4142,20 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) {
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);

  /* For background connect, test needs to Inject Connected Event */
  InjectConnectedEvent(test_address0, 1);

  // We need to wait for the storage callback before verifying stuff
  SyncOnMainLoop();
  ASSERT_TRUE(LeAudioClient::IsLeAudioClientRunning());
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  std::vector<RawAddress> devs =
      LeAudioClient::Get()->GetGroupDevices(group_id0);
@@ -4786,7 +4834,7 @@ TEST_F(UnicastTest, RemoveDeviceWhenConnecting) {
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(0);
  ConnectLeAudio(test_address0);
  ConnectLeAudio(test_address0, true, false);

  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

@@ -4794,6 +4842,8 @@ TEST_F(UnicastTest, RemoveDeviceWhenConnecting) {
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, _, _))
      .Times(0);

  /*
   * StopStream will put calls on main_loop so to keep the correct order
@@ -4840,11 +4890,11 @@ TEST_F(UnicastTest, RemoveDeviceWhenGettingConnectionReady) {
  EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1));
  EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1);

  /* First time called when RemoveDevice is called and then second time
   * OnGattDisconnected. We accept this spare call.
   */
  /* Cancel should be called in RemoveDevice */
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(2);
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, _, _))
      .Times(0);

  /*
   * StopStream will put calls on main_loop so to keep the correct order
@@ -4925,7 +4975,7 @@ TEST_F(UnicastTest, DisconnectDeviceWhenConnecting) {
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(0);
  ConnectLeAudio(test_address0);
  ConnectLeAudio(test_address0, true, false);

  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

@@ -4935,6 +4985,8 @@ TEST_F(UnicastTest, DisconnectDeviceWhenConnecting) {
  ON_CALL(mock_gatt_interface_, Close(_)).WillByDefault(DoAll(Return()));
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, true))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, _, _))
      .Times(0);

  LeAudioClient::Get()->Disconnect(test_address0);
  SyncOnMainLoop();
@@ -4960,17 +5012,18 @@ TEST_F(UnicastTest, DisconnectDeviceWhenGettingConnectionReady) {
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
      .Times(0);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(0);
  ConnectLeAudio(test_address0);

  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  /* TA reconnect is enabled in ConnectLeAudio. Make sure this is not removed */
  EXPECT_CALL(mock_gatt_queue_, Clean(conn_id)).Times(AtLeast(1));
  EXPECT_CALL(mock_gatt_interface_, Close(conn_id)).Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _))
      .Times(0);
  EXPECT_CALL(mock_gatt_interface_, Open(gatt_if, test_address0, _, _))
      .Times(0);

  LeAudioClient::Get()->Disconnect(test_address0);
  SyncOnMainLoop();
@@ -6967,6 +7020,7 @@ TEST_F(UnicastTest, TwoEarbuds2ndDisconnected) {
  // Make sure the state machine knows about the disconnected device
  ASSERT_EQ(1, num_of_connected);

  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);

  // Expect one channel ISO Data to be sent
@@ -8309,6 +8363,8 @@ TEST_F(UnicastTest, AddMemberToAllowListWhenOneDeviceConnected) {

  SyncOnMainLoop();

  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
@@ -8325,6 +8381,8 @@ TEST_F(UnicastTest, AddMemberToAllowListWhenOneDeviceConnected) {
      .Times(1);

  /* Do not connect first  device but expect Open will arrive.*/
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _))
      .Times(1);
@@ -8373,7 +8431,7 @@ TEST_F(UnicastTest, ResetToDefaultReconnectionMode) {

  SyncOnMainLoop();

  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
@@ -8390,6 +8448,7 @@ TEST_F(UnicastTest, ResetToDefaultReconnectionMode) {
  EXPECT_CALL(mock_btif_storage_, AddLeaudioAutoconnect(test_address1, true))
      .Times(1);

  /* Verify first earbud will start doing direct connect first */
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);
  ON_CALL(mock_gatt_interface_,
@@ -8410,11 +8469,9 @@ TEST_F(UnicastTest, ResetToDefaultReconnectionMode) {
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_gatt_interface_);

  // Disconnect Device B, expect default reconnection mode
  // Disconnect Device B, expect default reconnection mode for Device A.
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, false))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address1, false))
      .Times(2);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
@@ -8423,6 +8480,8 @@ TEST_F(UnicastTest, ResetToDefaultReconnectionMode) {
              Open(gatt_if, test_address1,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address1, false))
      .Times(1);

  InjectDisconnectedEvent(conn_id_dev_1, GATT_CONN_TERMINATE_PEER_USER);
  SyncOnMainLoop();
@@ -8471,6 +8530,13 @@ TEST_F(UnicastTest, DisconnectAclBeforeGettingReadResponses) {
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _))
      .Times(1);
  /* When connected it will got to TA */
  EXPECT_CALL(mock_gatt_interface_, CancelOpen(gatt_if, test_address0, _))
      .Times(1);
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0,
                   BTM_BLE_BKG_CONNECT_TARGETED_ANNOUNCEMENTS, _))
      .Times(1);

  do_in_main_thread(
      FROM_HERE,