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

Commit 564ef814 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Automerger Merge Worker
Browse files

leaudio: Fix handling Service Changed am: 0ec94da0

parents f5c05ca9 0ec94da0
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -2441,7 +2441,7 @@ class LeAudioClientImpl : public LeAudioClient {
          DeviceConnectState::CONNECTED_BY_USER_GETTING_READY);
    }

    btif_storage_remove_leaudio(leAudioDevice->address_);
    btif_storage_leaudio_clear_service_data(leAudioDevice->address_);

    BTA_GATTC_ServiceSearchRequest(
        leAudioDevice->conn_id_,
@@ -2450,12 +2450,21 @@ class LeAudioClientImpl : public LeAudioClient {

  void OnServiceChangeEvent(const RawAddress& address) {
    LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address);
    if (!leAudioDevice || (leAudioDevice->conn_id_ == GATT_INVALID_CONN_ID)) {
    if (!leAudioDevice) {
      LOG_WARN("Skipping unknown leAudioDevice %s (%p)",
               ADDRESS_TO_LOGGABLE_CSTR(address), leAudioDevice);
      return;
    }

    if (leAudioDevice->conn_id_ != GATT_INVALID_CONN_ID) {
      ClearDeviceInformationAndStartSearch(leAudioDevice);
      return;
    }

    /* If device is not connected, just clear the handle information and this
     * will trigger service search onGattConnected */
    leAudioDevice->known_service_handles_ = false;
    btif_storage_leaudio_clear_service_data(address);
  }

  void OnMtuChanged(uint16_t conn_id, uint16_t mtu) {
+151 −0
Original line number Diff line number Diff line
@@ -417,6 +417,20 @@ class UnicastTestNoInit : public Test {
            first_device));
  }

  void InjectServiceChangedEvent(const RawAddress& address, uint16_t conn_id) {
    tBTA_GATTC_SERVICE_CHANGED event_data = {.remote_bda = address,
                                             .conn_id = conn_id};

    do_in_main_thread(FROM_HERE,
                      base::BindOnce(
                          [](tBTA_GATTC_CBACK* gatt_callback,
                             tBTA_GATTC_SERVICE_CHANGED event_data) {
                            gatt_callback(BTA_GATTC_SRVC_CHG_EVT,
                                          (tBTA_GATTC*)&event_data);
                          },
                          base::Unretained(this->gatt_callback), event_data));
  }

  void InjectConnectedEvent(const RawAddress& address, uint16_t conn_id,
                            tGATT_STATUS status = GATT_SUCCESS) {
    ASSERT_NE(conn_id, GATT_INVALID_CONN_ID);
@@ -3829,6 +3843,143 @@ TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGrouped) {
  DisconnectLeAudioWithAclClose(test_address1, 2);
}

TEST_F(UnicastTestNoInit, ServiceChangedBeforeServiceIsConnected) {
  // Prepare two devices
  uint8_t group_size = 2;
  uint8_t group_id = 2;

  /* Prepare  mock to not inject connect event so the device can stay in
   * CONNECTING state*/
  ON_CALL(mock_gatt_interface_, Open(_, _, BTM_BLE_DIRECT_CONNECTION, false))
      .WillByDefault(DoAll(Return()));

  const RawAddress test_address0 = GetTestAddress(0);
  SetSampleDatabaseEarbudsValid(
      1, test_address0, codec_spec_conf::kLeAudioLocationFrontLeft,
      codec_spec_conf::kLeAudioLocationFrontLeft, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      true,                                /*add_pacs*/
      default_ase_cnt,                     /*add_ascs_cnt*/
      group_size, 1);

  const RawAddress test_address1 = GetTestAddress(1);
  SetSampleDatabaseEarbudsValid(
      2, test_address1, codec_spec_conf::kLeAudioLocationFrontRight,
      codec_spec_conf::kLeAudioLocationFrontRight, default_channel_cnt,
      default_channel_cnt, 0x0004,
      /* source sample freq 16khz */ true, /*add_csis*/
      true,                                /*add_cas*/
      true,                                /*add_pacs*/
      default_ase_cnt,                     /*add_ascs_cnt*/
      group_size, 2);

  // Load devices from the storage when storage API is called
  bool autoconnect = true;

  /* Common storage values */
  std::vector<uint8_t> handles;
  LeAudioClient::GetHandlesForStorage(test_address0, handles);

  std::vector<uint8_t> ases;
  LeAudioClient::GetAsesForStorage(test_address0, ases);

  std::vector<uint8_t> src_pacs;
  LeAudioClient::GetSourcePacsForStorage(test_address0, src_pacs);

  std::vector<uint8_t> snk_pacs;
  LeAudioClient::GetSinkPacsForStorage(test_address0, snk_pacs);

  EXPECT_CALL(mock_storage_load, Call()).WillOnce([&]() {
    do_in_main_thread(
        FROM_HERE,
        base::BindOnce(&LeAudioClient::AddFromStorage, test_address0,
                       autoconnect, codec_spec_conf::kLeAudioLocationFrontLeft,
                       codec_spec_conf::kLeAudioLocationFrontLeft, 0xff, 0xff,
                       std::move(handles), std::move(snk_pacs),
                       std::move(src_pacs), std::move(ases)));
    do_in_main_thread(
        FROM_HERE,
        base::BindOnce(&LeAudioClient::AddFromStorage, test_address1,
                       autoconnect, codec_spec_conf::kLeAudioLocationFrontRight,
                       codec_spec_conf::kLeAudioLocationFrontRight, 0xff, 0xff,
                       std::move(handles), std::move(snk_pacs),
                       std::move(src_pacs), std::move(ases)));
    SyncOnMainLoop();
  });

  // Expect stored device0 to connect automatically (first directed connection )
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address0, BTM_BLE_DIRECT_CONNECTION, _))
      .Times(1);

  // Expect stored device1 to connect automatically (first direct connection)
  EXPECT_CALL(mock_gatt_interface_,
              Open(gatt_if, test_address1, BTM_BLE_DIRECT_CONNECTION, _))
      .Times(1);

  ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address1, _))
      .WillByDefault(DoAll(Return(true)));
  ON_CALL(mock_btm_interface_, BTM_IsEncrypted(test_address0, _))
      .WillByDefault(DoAll(Return(true)));

  ON_CALL(mock_groups_module_, GetGroupId(_, _))
      .WillByDefault(DoAll(Return(group_id)));

  ON_CALL(mock_btm_interface_,
          GetSecurityFlagsByTransport(test_address0, NotNull(), _))
      .WillByDefault(
          DoAll(SetArgPointee<1>(BTM_SEC_FLAG_ENCRYPTED), Return(true)));

  std::vector<::bluetooth::le_audio::btle_audio_codec_config_t>
      framework_encode_preference;

  // Initialize
  BtaAppRegisterCallback app_register_callback;
  ON_CALL(mock_gatt_interface_, AppRegister(_, _, _))
      .WillByDefault(DoAll(SaveArg<0>(&gatt_callback),
                           SaveArg<1>(&app_register_callback)));
  LeAudioClient::Initialize(
      &mock_audio_hal_client_callbacks_,
      base::Bind([](MockFunction<void()>* foo) { foo->Call(); },
                 &mock_storage_load),
      base::Bind([](MockFunction<bool()>* foo) { return foo->Call(); },
                 &mock_hal_2_1_verifier),
      framework_encode_preference);
  if (app_register_callback) app_register_callback.Run(gatt_if, GATT_SUCCESS);

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

  /* Inject Service Changed */
  InjectServiceChangedEvent(test_address1, 0xffff);
  SyncOnMainLoop();
  InjectServiceChangedEvent(test_address0, 0xffff);
  SyncOnMainLoop();
  /* Stack should rediscover services as storage is broken */
  EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(2, _)).Times(1);
  EXPECT_CALL(mock_gatt_interface_, ServiceSearchRequest(1, _)).Times(1);

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

  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address1))
      .Times(1);

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

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

TEST_F(UnicastTestNoInit, LoadStoredEarbudsCsisGroupedDifferently) {
  // Prepare two devices
  uint8_t group_size = 1;
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,11 @@ void btif_storage_set_leaudio_supported_context_types(
                                             source_supported_context_type);
}

void btif_storage_leaudio_clear_service_data(RawAddress const& addr) {
  LOG_ASSERT(btif_storage_interface) << "Mock storage module not set!";
  btif_storage_interface->ClearLeAudioServiceData(addr);
}

void btif_storage_remove_leaudio(RawAddress const& addr) {
  LOG_ASSERT(btif_storage_interface) << "Mock storage module not set!";
  btif_storage_interface->RemoveLeaudio(addr);
+3 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ class BtifStorageInterface {
                                   uint32_t source_location) = 0;
  virtual void SetLeAudioContexts(RawAddress const& addr, uint16_t sink_context,
                                  uint16_t source_context) = 0;
  virtual void ClearLeAudioServiceData(RawAddress const& addr) = 0;
  virtual void RemoveLeaudio(RawAddress const& addr) = 0;
  virtual void AddLeaudioHasDevice(const RawAddress& address,
                                   std::vector<uint8_t> presets_bin,
@@ -74,6 +75,8 @@ class MockBtifStorageInterface : public BtifStorageInterface {
              (RawAddress const& addr, uint16_t sink_context,
               uint16_t source_context),
              (override));
  MOCK_METHOD((void), ClearLeAudioServiceData, (RawAddress const& addr),
              (override));
  MOCK_METHOD((void), RemoveLeaudio, (RawAddress const& addr), (override));
  MOCK_METHOD((void), AddLeaudioHasDevice,
              (const RawAddress& address, std::vector<uint8_t> presets_bin,
+3 −0
Original line number Diff line number Diff line
@@ -123,6 +123,9 @@ void btif_storage_set_leaudio_supported_context_types(
    const RawAddress& addr, uint16_t sink_supported_context_type,
    uint16_t source_supported_context_type);

/** Remove Le Audio device service data */
void btif_storage_leaudio_clear_service_data(const RawAddress& address);

/** Remove Le Audio device from the storage */
void btif_storage_remove_leaudio(const RawAddress& address);

Loading