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

Commit b7aa506b authored by Jakub Pawlowski's avatar Jakub Pawlowski
Browse files

Divide advertise data when needed

Bug: 30622771
Test: BleAdvertisingManagerTest.test_data_sender
Change-Id: I447fed753b08cef766d99ea8dfa47b1212a9ce03
parent c9cc16fc
Loading
Loading
Loading
Loading
+58 −8
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ extern void btm_gen_resolvable_private_addr(
    base::Callback<void(uint8_t[8])> cb);
extern fixed_queue_t* btu_general_alarm_queue;

constexpr int ADV_DATA_LEN_MAX = 251;

struct AdvertisingInstance {
  uint8_t inst_id;
  bool in_use;
@@ -586,14 +588,60 @@ class BleAdvertisingManagerImpl
    }

    VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());

    if (is_scan_rsp) {
      GetHciInterface()->SetScanResponseData(inst_id, 0x03, 0x01, data.size(),
                                             data.data(), cb);
    } else {
      GetHciInterface()->SetAdvertisingData(inst_id, 0x03, 0x01, data.size(),
                                            data.data(), cb);
    DivideAndSendData(
        inst_id, data, cb,
        base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender,
                   base::Unretained(this), is_scan_rsp));
  }

  void SetDataAdvDataSender(uint8_t is_scan_rsp, uint8_t inst_id,
                            uint8_t operation, uint8_t length, uint8_t* data,
                            MultiAdvCb cb) {
    if (is_scan_rsp)
      GetHciInterface()->SetScanResponseData(inst_id, operation, 0x01, length,
                                             data, cb);
    else
      GetHciInterface()->SetAdvertisingData(inst_id, operation, 0x01, length,
                                            data, cb);
  }

  using DataSender = base::Callback<void(
      uint8_t /*inst_id*/, uint8_t /* operation */, uint8_t /* length */,
      uint8_t* /* data */, MultiAdvCb /* done */)>;

  void DivideAndSendData(int inst_id, std::vector<uint8_t> data,
                         MultiAdvCb done_cb, DataSender sender) {
    DivideAndSendDataRecursively(true, inst_id, std::move(data), 0,
                                 std::move(done_cb), std::move(sender), 0);
  }

  static void DivideAndSendDataRecursively(bool isFirst, int inst_id,
                                           std::vector<uint8_t> data,
                                           int offset, MultiAdvCb done_cb,
                                           DataSender sender, uint8_t status) {
    constexpr uint8_t INTERMEDIATE =
        0x00;                        // Intermediate fragment of fragmented data
    constexpr uint8_t FIRST = 0x01;  // First fragment of fragmented data
    constexpr uint8_t LAST = 0x02;   // Last fragment of fragmented data
    constexpr uint8_t COMPLETE = 0x03;  // Complete extended advertising data

    int dataSize = (int)data.size();
    if (status != 0 || (!isFirst && offset == dataSize)) {
      /* if we got error writing data, or reached the end of data */
      done_cb.Run(status);
      return;
    }

    bool moreThanOnePacket = dataSize - offset > ADV_DATA_LEN_MAX;
    uint8_t operation = isFirst ? moreThanOnePacket ? FIRST : COMPLETE
                                : moreThanOnePacket ? INTERMEDIATE : LAST;
    int length = moreThanOnePacket ? ADV_DATA_LEN_MAX : dataSize - offset;
    int newOffset = offset + length;

    sender.Run(
        inst_id, operation, length, data.data() + offset,
        Bind(&BleAdvertisingManagerImpl::DivideAndSendDataRecursively, false,
             inst_id, std::move(data), newOffset, std::move(done_cb), sender));
  }

  void SetPeriodicAdvertisingParameters(uint8_t inst_id,
@@ -612,8 +660,10 @@ class BleAdvertisingManagerImpl

    VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());

    GetHciInterface()->SetPeriodicAdvertisingData(inst_id, 0x03, data.size(),
                                                  data.data(), cb);
    DivideAndSendData(
        inst_id, data, cb,
        base::Bind(&BleAdvertiserHciInterface::SetPeriodicAdvertisingData,
                   base::Unretained(GetHciInterface())));
  }

  void SetPeriodicAdvertisingEnable(uint8_t inst_id, uint8_t enable,
+146 −0
Original line number Diff line number Diff line
@@ -65,6 +65,12 @@ fixed_queue_t* btu_general_alarm_queue = nullptr;

namespace {

constexpr uint8_t INTERMEDIATE =
    0x00;                           // Intermediate fragment of fragmented data
constexpr uint8_t FIRST = 0x01;     // First fragment of fragmented data
constexpr uint8_t LAST = 0x02;      // Last fragment of fragmented data
constexpr uint8_t COMPLETE = 0x03;  // Complete extended advertising data

class AdvertiserHciMock : public BleAdvertiserHciInterface {
 public:
  AdvertiserHciMock() = default;
@@ -467,3 +473,143 @@ TEST_F(BleAdvertisingManagerTest, test_start_advertising_set_params_failed) {
  // Expect the whole flow to fail right away
  EXPECT_EQ(BTM_BLE_MULTI_ADV_FAILURE, start_advertising_status);
}

TEST_F(BleAdvertisingManagerTest, test_data_sender) {
  // prepare test input vector
  const int max_data_size = 1650;
  std::vector<uint8_t> data(max_data_size);
  for (int i = 0; i < max_data_size; i++) data[i] = i;

  BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind(
      &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
  int advertiser_id = reg_inst_id;

  status_cb set_data_cb;
  EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  EXPECT_CALL(*hci_mock,
              SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _))
      .Times(5)
      .WillRepeatedly(SaveArg<5>(&set_data_cb));
  EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 144, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  BleAdvertisingManager::Get()->SetData(
      advertiser_id, false, data,
      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
                 base::Unretained(this)));
  for (int i = 0; i < 7; i++) {
    set_data_cb.Run(0x00);
  }
  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
  // Expect the whole flow to succeed
  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);

  // ***************** Try again with different data size *********************
  data.resize(503);
  EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  EXPECT_CALL(*hci_mock,
              SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _))
      .Times(1)
      .WillRepeatedly(SaveArg<5>(&set_data_cb));
  EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 1, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  BleAdvertisingManager::Get()->SetData(
      advertiser_id, false, data,
      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
                 base::Unretained(this)));
  for (int i = 0; i < 3; i++) {
    set_data_cb.Run(0x00);
  }
  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
  // Expect the whole flow to succeed
  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);

  // ***************** Try again with different data size *********************
  data.resize(502);
  EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 251, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  BleAdvertisingManager::Get()->SetData(
      advertiser_id, false, data,
      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
                 base::Unretained(this)));
  for (int i = 0; i < 2; i++) {
    set_data_cb.Run(0x00);
  }
  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
  // Expect the whole flow to succeed
  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);

  // ***************** Try again with different data size *********************
  data.resize(501);
  EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 250, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  BleAdvertisingManager::Get()->SetData(
      advertiser_id, false, data,
      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
                 base::Unretained(this)));
  for (int i = 0; i < 2; i++) {
    set_data_cb.Run(0x00);
  }
  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
  // Expect the whole flow to succeed
  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);

  // ***************** Try again with different data size *********************
  data.resize(251);
  EXPECT_CALL(*hci_mock,
              SetAdvertisingData(advertiser_id, COMPLETE, _, 251, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  BleAdvertisingManager::Get()->SetData(
      advertiser_id, false, data,
      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
                 base::Unretained(this)));
  set_data_cb.Run(0x00);
  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
  // Expect the whole flow to succeed
  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);

  // ***************** Try again with different data size *********************
  data.resize(120);
  EXPECT_CALL(*hci_mock,
              SetAdvertisingData(advertiser_id, COMPLETE, _, 120, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  BleAdvertisingManager::Get()->SetData(
      advertiser_id, false, data,
      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
                 base::Unretained(this)));
  set_data_cb.Run(0x00);
  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
  // Expect the whole flow to succeed
  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);

  // ***************** Try again with different data size *********************
  data.resize(0);
  EXPECT_CALL(*hci_mock,
              SetAdvertisingData(advertiser_id, COMPLETE, _, 0, _, _))
      .Times(1)
      .WillOnce(SaveArg<5>(&set_data_cb));
  BleAdvertisingManager::Get()->SetData(
      advertiser_id, false, data,
      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
                 base::Unretained(this)));
  set_data_cb.Run(0x00);
  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
  // Expect the whole flow to succeed
  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
}