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

Commit 772c20f7 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "gd: Fragmentation for periodic advertising"

parents 54e60da0 f1983260
Loading
Loading
Loading
Loading
+64 −12
Original line number Diff line number Diff line
@@ -591,6 +591,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
        for (int i = 0; i < data.size(); i++) {
          if (data[i].size() > kLeMaximumFragmentLength) {
            LOG_WARN("AD data len shall not greater than %d", kLeMaximumFragmentLength);
            if (advertising_callbacks_ != nullptr) {
              if (set_scan_rsp) {
                advertising_callbacks_->OnScanResponseDataSet(
                    advertiser_id, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR);
@@ -598,6 +599,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
                advertising_callbacks_->OnAdvertisingDataSet(
                    advertiser_id, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR);
              }
            }
            return;
          }
          data_len += data[i].size();
@@ -730,13 +732,63 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
  }

  void set_periodic_data(AdvertiserId advertiser_id, std::vector<GapData> data) {
    // TODO(b/149221472): Support fragmentation
    auto operation = Operation::COMPLETE_ADVERTISEMENT;
    uint16_t data_len = 0;
    // check data size
    for (int i = 0; i < data.size(); i++) {
      if (data[i].size() > kLeMaximumFragmentLength) {
        LOG_WARN("AD data len shall not greater than %d", kLeMaximumFragmentLength);
        if (advertising_callbacks_ != nullptr) {
          advertising_callbacks_->OnPeriodicAdvertisingDataSet(
              advertiser_id, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR);
        }
        return;
      }
      data_len += data[i].size();
    }

    if (data_len > le_maximum_advertising_data_length_) {
      LOG_WARN(
          "advertising data len exceeds le_maximum_advertising_data_length_ %d", le_maximum_advertising_data_length_);
      if (advertising_callbacks_ != nullptr) {
        advertising_callbacks_->OnPeriodicAdvertisingDataSet(
            advertiser_id, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE);
      }
      return;
    }

    if (data_len <= kLeMaximumFragmentLength) {
      send_periodic_data_fragment(advertiser_id, data, Operation::COMPLETE_ADVERTISEMENT);
    } else {
      std::vector<GapData> sub_data;
      uint16_t sub_data_len = 0;
      Operation operation = Operation::FIRST_FRAGMENT;

      for (int i = 0; i < data.size(); i++) {
        if (sub_data_len + data[i].size() > kLeMaximumFragmentLength) {
          send_periodic_data_fragment(advertiser_id, sub_data, operation);
          operation = Operation::INTERMEDIATE_FRAGMENT;
          sub_data_len = 0;
          sub_data.clear();
        }
        sub_data.push_back(data[i]);
        sub_data_len += data[i].size();
      }
      send_periodic_data_fragment(advertiser_id, sub_data, Operation::LAST_FRAGMENT);
    }
  }

  void send_periodic_data_fragment(AdvertiserId advertiser_id, std::vector<GapData> data, Operation operation) {
    if (operation == Operation::COMPLETE_ADVERTISEMENT || operation == Operation::LAST_FRAGMENT) {
      le_advertising_interface_->EnqueueCommand(
          hci::LeSetPeriodicAdvertisingDataBuilder::Create(advertiser_id, operation, data),
          module_handler_->BindOnceOn(
              this, &impl::check_status_with_id<LeSetPeriodicAdvertisingDataCompleteView>, advertiser_id));
    } else {
      // For first and intermediate fragment, do not trigger advertising_callbacks_.
      le_advertising_interface_->EnqueueCommand(
          hci::LeSetPeriodicAdvertisingDataBuilder::Create(advertiser_id, operation, data),
          module_handler_->BindOnce(impl::check_status<LeSetPeriodicAdvertisingDataCompleteView>));
    }
  }

  void enable_periodic_advertising(AdvertiserId advertiser_id, bool enable) {
+80 −0
Original line number Diff line number Diff line
@@ -1104,6 +1104,86 @@ TEST_F(LeExtendedAdvertisingAPITest, set_periodic_data_test) {
  sync_client_handler();
}

TEST_F(LeExtendedAdvertisingAPITest, set_periodic_data_fragments_test) {
  // Set advertising data
  std::vector<GapData> advertising_data{};
  for (uint8_t i = 0; i < 3; i++) {
    GapData data_item{};
    data_item.data_.push_back(0xfa);
    data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
    uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i};
    std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
    uint8_t service_data[232];
    std::copy_n(service_data, 232, std::back_inserter(data_item.data_));
    advertising_data.push_back(data_item);
  }
  le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data);

  // First fragment
  test_hci_layer_->SetCommandFuture();
  test_hci_layer_->GetCommandPacket(OpCode::LE_SET_PERIODIC_ADVERTISING_DATA);

  // Intermediate fragment
  test_hci_layer_->SetCommandFuture();
  test_hci_layer_->GetCommandPacket(OpCode::LE_SET_PERIODIC_ADVERTISING_DATA);

  // Last fragment
  test_hci_layer_->SetCommandFuture();
  test_hci_layer_->GetCommandPacket(OpCode::LE_SET_PERIODIC_ADVERTISING_DATA);

  EXPECT_CALL(
      mock_advertising_callback_,
      OnPeriodicAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::SUCCESS));
  test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
  test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
  test_hci_layer_->IncomingEvent(LeSetPeriodicAdvertisingDataCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));

  sync_client_handler();
}

TEST_F(LeExtendedAdvertisingAPITest, set_perodic_data_with_invalid_ad_structure) {
  // Set advertising data with AD structure that length greater than 251
  std::vector<GapData> advertising_data{};
  GapData data_item{};
  data_item.data_.push_back(0xfb);
  data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
  uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00};
  std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
  uint8_t service_data[233];
  std::copy_n(service_data, 233, std::back_inserter(data_item.data_));
  advertising_data.push_back(data_item);

  EXPECT_CALL(
      mock_advertising_callback_,
      OnPeriodicAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::INTERNAL_ERROR));

  le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data);

  sync_client_handler();
}

TEST_F(LeExtendedAdvertisingAPITest, set_perodic_data_with_invalid_length) {
  // Set advertising data with data that greater than le_maximum_advertising_data_length_
  std::vector<GapData> advertising_data{};
  for (uint8_t i = 0; i < 10; i++) {
    GapData data_item{};
    data_item.data_.push_back(0xfb);
    data_item.data_type_ = GapDataType::SERVICE_DATA_128_BIT_UUIDS;
    uint8_t uuid[16] = {0xf0, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, i};
    std::copy_n(uuid, 16, std::back_inserter(data_item.data_));
    uint8_t service_data[200];
    std::copy_n(service_data, 200, std::back_inserter(data_item.data_));
    advertising_data.push_back(data_item);
  }

  EXPECT_CALL(
      mock_advertising_callback_,
      OnPeriodicAdvertisingDataSet(advertiser_id_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE));
  le_advertising_manager_->SetPeriodicData(advertiser_id_, advertising_data);

  sync_client_handler();
}

TEST_F(LeExtendedAdvertisingAPITest, disable_enable_periodic_advertiser_test) {
  // disable advertiser
  test_hci_layer_->SetCommandFuture();