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

Commit 6ccd47b1 authored by Chris Manton's avatar Chris Manton Committed by Hansong Zhang
Browse files

Add queuing for incoming acl packets

If a second packet arrives to the acl while there is
already a packet being processed the code ASSERTS
with enqueue already registered.

Bug: 140778599
Test: Runs bt_headless for 100 runs with no errors

Change-Id: Ib7601eab2121b1888f58f71676f734080f41c8ec
parent 1761f89b
Loading
Loading
Loading
Loading
+28 −6
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ namespace bluetooth {
namespace hci {

constexpr uint16_t kQualcommDebugHandle = 0xedc;
constexpr size_t kMaxQueuedPacketsPerConnection = 10;

using common::Bind;
using common::BindOnce;
@@ -53,6 +54,9 @@ struct AclManager::acl_connection {
  bool is_registered_ = false;
  // Credits: Track the number of packets which have been sent to the controller
  uint16_t number_of_sent_packets_ = 0;
  bool enqueue_registered_{false};
  std::queue<packet::PacketView<kLittleEndian>> incoming_queue_;

  void call_disconnect_callback() {
    disconnect_handler_->Post(BindOnce(std::move(on_disconnect_callback_), disconnect_reason_));
  }
@@ -221,6 +225,17 @@ struct AclManager::impl {
    return std::unique_ptr<AclPacketBuilder>(raw_pointer);
  }

  std::unique_ptr<packet::PacketView<kLittleEndian>> OnIncomingReadReady(AclManager::acl_connection* connection) {
    auto packet = connection->incoming_queue_.front();
    connection->incoming_queue_.pop();
    if (connection->incoming_queue_.empty()) {
      auto queue_end = connection->queue_->GetDownEnd();
      queue_end->UnregisterEnqueue();
      connection->enqueue_registered_ = false;
    }
    return std::make_unique<PacketView<kLittleEndian>>(packet);
  }

  void dequeue_and_route_acl_packet_to_connection() {
    auto packet = hci_queue_end_->TryDequeue();
    ASSERT(packet != nullptr);
@@ -241,12 +256,19 @@ struct AclManager::impl {
    // TODO hsz: define enqueue callback
    auto queue_end = connection_pair->second.queue_->GetDownEnd();
    PacketView<kLittleEndian> payload = packet->GetPayload();
    queue_end->RegisterEnqueue(handler_, common::Bind(
                                             [](decltype(queue_end) queue_end, PacketView<kLittleEndian> payload) {
                                               queue_end->UnregisterEnqueue();
                                               return std::make_unique<PacketView<kLittleEndian>>(payload);
                                             },
                                             queue_end, std::move(payload)));

    if (connection_pair->second.incoming_queue_.size() > kMaxQueuedPacketsPerConnection) {
      LOG_INFO("Dropping packet due to congestion from remote:%s",
               connection_pair->second.address_with_type_.ToString().c_str());
      return;
    }

    connection_pair->second.incoming_queue_.push(payload);
    if (!connection_pair->second.enqueue_registered_) {
      connection_pair->second.enqueue_registered_ = true;
      queue_end->RegisterEnqueue(handler_, common::Bind(&AclManager::impl::OnIncomingReadReady,
                                                        common::Unretained(this), &connection_pair->second));
    }
  }

  void on_incoming_connection(EventPacketView packet) {