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

Commit 3edec369 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

csis: Make CSIS opportunistic when connecting from autoconnect

When CSIS is connected from Java it is expected to be Direct Connect,
otherwise CSIS should be treated as opportunistic service for LeAudio
devices.

Bug: 311578937
Test: atest bluetooth_csis_test
Tag: #feature
Change-Id: I23a4008457a43d56c005e630bda7146a57ebda37
parent ec94418d
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include "bta_gatt_api.h"
#include "bta_gatt_queue.h"
#include "bta_groups.h"
#include "bta_le_audio_uuids.h"
#include "bta_sec_api.h"
#include "btif_storage.h"
#include "crypto_toolbox/crypto_toolbox.h"
@@ -664,6 +665,7 @@ class CsisClientImpl : public CsisClient {
      devices_.push_back(device);
    }

    bool is_le_audio_device = false;
    for (const auto& csis_group : csis_groups_) {
      if (!csis_group->IsDeviceInTheGroup(device)) continue;

@@ -677,11 +679,20 @@ class CsisClientImpl : public CsisClient {
        callbacks_->OnDeviceAvailable(device->addr, group_id,
                                      csis_group->GetDesiredSize(), rank,
                                      csis_group->GetUuid());

        if (csis_group->GetUuid() ==
            bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)) {
          is_le_audio_device = true;
        }
      }
    }

    /* For now, if this is LeAudio device, CSIP is opportunistic profile. */
    bool is_opportunistic = is_le_audio_device;

    if (autoconnect) {
      BTA_GATTC_Open(gatt_if_, addr, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false);
      BTA_GATTC_Open(gatt_if_, addr, BTM_BLE_BKG_CONNECT_ALLOW_LIST,
                     is_opportunistic);
    }
  }

@@ -695,6 +706,7 @@ class CsisClientImpl : public CsisClient {
    }

    devices_.clear();
    csis_groups_.clear();

    CsisObserverSetBackground(false);
    dev_groups_->CleanUp(device_group_callbacks);
+139 −18
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include "bta_dm_api_mock.h"
#include "bta_gatt_api_mock.h"
#include "bta_gatt_queue_mock.h"
#include "bta_le_audio_uuids.h"
#include "btif_profile_storage.h"
#include "btm_api_mock.h"
#include "csis_types.h"
@@ -57,6 +58,7 @@ using bluetooth::csis::CsisGroupLockStatus;
using bluetooth::groups::DeviceGroups;

using testing::_;
using testing::AtLeast;
using testing::DoAll;
using testing::DoDefault;
using testing::Invoke;
@@ -125,6 +127,92 @@ class MockCsisCallbacks : public CsisClientCallbacks {

class CsisClientTest : public ::testing::Test {
 private:
  void set_sample_cap_included_database(uint16_t conn_id, bool csis,
                                        bool csis_broken, uint8_t rank,
                                        uint8_t sirk_msb = 1) {
    gatt::DatabaseBuilder builder;
    builder.AddService(0x0001, 0x0003, Uuid::From16Bit(0x1800), true);
    builder.AddCharacteristic(0x0002, 0x0003, Uuid::From16Bit(0x2a00),
                              GATT_CHAR_PROP_BIT_READ);
    if (csis) {
      builder.AddService(0x0005, 0x0009,
                         bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE),
                         true);
      builder.AddIncludedService(0x0006, kCsisServiceUuid, 0x0010, 0x0030);

      builder.AddService(0x0010, 0x0030, kCsisServiceUuid, true);
      builder.AddCharacteristic(
          0x0020, 0x0021, kCsisSirkUuid,
          GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);

      builder.AddDescriptor(0x0022,
                            Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
      builder.AddCharacteristic(
          0x0023, 0x0024, kCsisSizeUuid,
          GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
      builder.AddDescriptor(0x0025,
                            Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
      builder.AddCharacteristic(0x0026, 0x0027, kCsisLockUuid,
                                GATT_CHAR_PROP_BIT_READ |
                                    GATT_CHAR_PROP_BIT_NOTIFY |
                                    GATT_CHAR_PROP_BIT_WRITE);
      builder.AddDescriptor(0x0028,
                            Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
      builder.AddCharacteristic(0x0029, 0x0030, kCsisRankUuid,
                                GATT_CHAR_PROP_BIT_READ);
    }
    if (csis_broken) {
      builder.AddCharacteristic(
          0x0020, 0x0021, kCsisSirkUuid,
          GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);

      builder.AddDescriptor(0x0022,
                            Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
    }
    builder.AddService(0x0090, 0x0093,
                       Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER), true);
    builder.AddCharacteristic(0x0091, 0x0092,
                              Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD),
                              GATT_CHAR_PROP_BIT_NOTIFY);
    builder.AddDescriptor(0x0093,
                          Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
    services_map[conn_id] = builder.Build().Services();

    ON_CALL(gatt_queue, ReadCharacteristic(conn_id, _, _, _))
        .WillByDefault(
            Invoke([rank, sirk_msb](uint16_t conn_id, uint16_t handle,
                                    GATT_READ_OP_CB cb, void* cb_data) -> void {
              std::vector<uint8_t> value;

              switch (handle) {
                case 0x0003:
                  /* device name */
                  value.resize(20);
                  break;
                case 0x0021:
                  value.assign(17, 1);
                  value[16] = sirk_msb;
                  break;
                case 0x0024:
                  value.resize(1);
                  break;
                case 0x0027:
                  value.resize(1);
                  break;
                case 0x0030:
                  value.resize(1);
                  value.assign(1, rank);
                  break;
                default:
                  FAIL();
                  return;
              }

              cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
                 cb_data);
            }));
  }

  void set_sample_database(uint16_t conn_id, bool csis, bool csis_broken,
                           uint8_t rank, uint8_t sirk_msb = 1) {
    gatt::DatabaseBuilder builder;
@@ -456,19 +544,28 @@ class CsisClientTest : public ::testing::Test {
  }

  void TestAddFromStorage(const RawAddress& address, uint16_t conn_id,
                          std::vector<uint8_t>& storage_group_buf,
                          std::vector<uint8_t>& storage_buf) {
    EXPECT_CALL(*callbacks,
                OnConnectionState(address, ConnectionState::CONNECTED))
        .Times(1);
    EXPECT_CALL(*callbacks, OnDeviceAvailable(address, _, _, _, _)).Times(1);
    EXPECT_CALL(*callbacks, OnDeviceAvailable(address, _, _, _, _))
        .Times(AtLeast(1));

    /* In testing only whe set info is empty, there is no CAP context. */
    bool is_opportunistic = (storage_buf.size() != 0);

    EXPECT_CALL(gatt_interface,
                Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, _))
                Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST,
                     is_opportunistic))
        .WillOnce(Invoke([this, conn_id](tGATT_IF client_if,
                                         const RawAddress& remote_bda,
                                         bool is_direct, bool opportunistic) {
          InjectConnectedEvent(remote_bda, conn_id);
          GetSearchCompleteEvent(conn_id);
        }));

    DeviceGroups::AddFromStorage(address, storage_group_buf);
    CsisClient::AddFromStorage(address, storage_buf, true);
  }

@@ -583,6 +680,10 @@ class CsisClientTest : public ::testing::Test {
    gatt_callback(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC*)&event_data);
  }

  void SetSampleCapIncludedDatabaseCsis(uint16_t conn_id, uint8_t rank,
                                        uint8_t sirk_msb = 1) {
    set_sample_cap_included_database(conn_id, true, false, rank, sirk_msb);
  }
  void SetSampleDatabaseCsis(uint16_t conn_id, uint8_t rank,
                             uint8_t sirk_msb = 1) {
    set_sample_database(conn_id, true, false, rank, sirk_msb);
@@ -1207,30 +1308,33 @@ TEST_F(CsisClientTest, test_storage_calls) {

TEST_F(CsisClientTest, test_storage_content) {
  // Two devices in one set
  SetSampleDatabaseCsis(1, 1);
  SetSampleDatabaseCsis(2, 2);
  SetSampleCapIncludedDatabaseCsis(1, 1);
  SetSampleCapIncludedDatabaseCsis(2, 2);
  // Devices in the other set
  SetSampleDatabaseCsis(3, 1, 2);
  SetSampleDatabaseCsis(4, 1, 2);
  SetSampleCapIncludedDatabaseCsis(3, 1, 2);
  SetSampleCapIncludedDatabaseCsis(4, 1, 3);

  TestAppRegister();
  TestConnect(GetTestAddress(1));
  InjectConnectedEvent(GetTestAddress(1), 1);
  GetSearchCompleteEvent(1);
  ASSERT_EQ(1, CsisClient::Get()->GetGroupId(
                   GetTestAddress(1), bluetooth::Uuid::From16Bit(0x0000)));
                   GetTestAddress(1),
                   bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)));

  TestConnect(GetTestAddress(2));
  InjectConnectedEvent(GetTestAddress(2), 2);
  GetSearchCompleteEvent(2);
  ASSERT_EQ(1, CsisClient::Get()->GetGroupId(
                   GetTestAddress(2), bluetooth::Uuid::From16Bit(0x0000)));
                   GetTestAddress(2),
                   bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)));

  TestConnect(GetTestAddress(3));
  InjectConnectedEvent(GetTestAddress(3), 3);
  GetSearchCompleteEvent(3);
  ASSERT_EQ(2, CsisClient::Get()->GetGroupId(
                   GetTestAddress(3), bluetooth::Uuid::From16Bit(0x0000)));
                   GetTestAddress(3),
                   bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)));

  std::vector<uint8_t> dev1_storage;
  std::vector<uint8_t> dev2_storage;
@@ -1240,10 +1344,23 @@ TEST_F(CsisClientTest, test_storage_content) {
  CsisClient::GetForStorage(GetTestAddress(1), dev1_storage);
  CsisClient::GetForStorage(GetTestAddress(2), dev2_storage);
  CsisClient::GetForStorage(GetTestAddress(3), dev3_storage);

  ASSERT_NE(0u, dev1_storage.size());
  ASSERT_NE(0u, dev2_storage.size());
  ASSERT_NE(0u, dev3_storage.size());

  std::vector<uint8_t> dev1_group_storage;
  std::vector<uint8_t> dev2_group_storage;
  std::vector<uint8_t> dev3_group_storage;

  DeviceGroups::GetForStorage(GetTestAddress(1), dev1_group_storage);
  DeviceGroups::GetForStorage(GetTestAddress(2), dev2_group_storage);
  DeviceGroups::GetForStorage(GetTestAddress(3), dev3_group_storage);

  ASSERT_NE(0u, dev1_group_storage.size());
  ASSERT_NE(0u, dev2_group_storage.size());
  ASSERT_NE(0u, dev3_group_storage.size());

  // Clean it up
  TestAppUnregister();

@@ -1251,25 +1368,29 @@ TEST_F(CsisClientTest, test_storage_content) {
  TestAppRegister();

  // Restore dev1 from the byte buffer
  TestAddFromStorage(GetTestAddress(1), 1, dev1_storage);
  TestAddFromStorage(GetTestAddress(1), 1, dev1_group_storage, dev1_storage);
  ASSERT_EQ(1, CsisClient::Get()->GetGroupId(
                   GetTestAddress(1), bluetooth::Uuid::From16Bit(0x0000)));
                   GetTestAddress(1),
                   bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)));

  // Restore dev2 from the byte buffer
  TestAddFromStorage(GetTestAddress(2), 2, dev2_storage);
  TestAddFromStorage(GetTestAddress(2), 2, dev2_group_storage, dev2_storage);
  ASSERT_EQ(1, CsisClient::Get()->GetGroupId(
                   GetTestAddress(2), bluetooth::Uuid::From16Bit(0x0000)));
                   GetTestAddress(2),
                   bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)));

  // Restore dev3 from the byte buffer
  TestAddFromStorage(GetTestAddress(3), 3, dev3_storage);
  TestAddFromStorage(GetTestAddress(3), 3, dev3_group_storage, dev3_storage);
  ASSERT_EQ(2, CsisClient::Get()->GetGroupId(
                   GetTestAddress(3), bluetooth::Uuid::From16Bit(0x0000)));
                   GetTestAddress(3),
                   bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)));

  // Restore not inerrogated dev4 - empty buffer but valid sirk for group 2
  std::vector<uint8_t> no_set_info;
  TestAddFromStorage(GetTestAddress(4), 4, no_set_info);
  ASSERT_EQ(2, CsisClient::Get()->GetGroupId(
                   GetTestAddress(4), bluetooth::Uuid::From16Bit(0x0000)));
  TestAddFromStorage(GetTestAddress(4), 4, no_set_info, no_set_info);
  ASSERT_EQ(3, CsisClient::Get()->GetGroupId(
                   GetTestAddress(4),
                   bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE)));

  TestAppUnregister();
}