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

Commit 446748e1 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

gatt: Improve queueing of GATT messages

There is couple of places where the GATT queuing is happening:
1) bta_gattc_queue. Queuing is done per conn_id, which is per GATT
   client. This API is used by most of the GATT Clients in native code
   and Java
2) stack/gatt  in the tGATT_TCB where is cl_cmd_q. Also each of the EATT
   channel has similar queue. Here it is assured that only one Command
   goes on the specific CID. Note that this lower layer API is used by
   GATT Caching and gatt_attr, plus of course bta_gattc_queue.

In addition to above, whenever, GATT API sends GATT Request,
it allocates pGATT_CLCB for each request. Before this patch,
GATT API allow for only num = 1 + #of eatt
channels  CLCBs per conn_id. This created the limitation for the users
of GATT API and actually put requirement on them to implement own
queuing mechanism.

This patch removes, the limit of possiblme CLBC allocated per conn_id,
as this can be easly queued in the tGATT_TCB.

Bug: 249431973
Test: atest BluetoothInstrumentationTests
Test: manual test with devices having EATT support.
Tag: #feature
Change-Id: If19de77a8a6842a90e3a231745274ed610f65b23
parent 32b2c52c
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@

#pragma once

#include <queue>
#include <deque>

#include "stack/gatt/gatt_int.h"
#include "types/raw_address.h"
@@ -54,7 +54,7 @@ class EattChannel {
  /* indication confirmation timer */
  alarm_t* ind_confirmation_timer_;
  /* GATT client command queue */
  std::queue<tGATT_CMD_Q> cl_cmd_q_;
  std::deque<tGATT_CMD_Q> cl_cmd_q_;

  EattChannel(RawAddress& bda, uint16_t cid, uint16_t tx_mtu, uint16_t rx_mtu)
      : bda_(bda),
@@ -79,7 +79,7 @@ class EattChannel {
  void EattChannelSetState(EattChannelState state) {
    if (state_ == EattChannelState::EATT_CHANNEL_PENDING) {
      if (state == EattChannelState::EATT_CHANNEL_OPENED) {
        cl_cmd_q_ = std::queue<tGATT_CMD_Q>();
        cl_cmd_q_ = std::deque<tGATT_CMD_Q>();
        memset(&server_outstanding_cmd_, 0, sizeof(tGATT_SR_CMD));
        char name[64];
        sprintf(name, "eatt_ind_ack_timer_%s_cid_0x%04x",
+7 −0
Original line number Diff line number Diff line
@@ -111,6 +111,13 @@ struct eatt_impl {
  }

  void remove_channel_by_cid(eatt_device* eatt_dev, uint16_t lcid) {
    auto channel = eatt_dev->eatt_channels[lcid];
    if (!channel->cl_cmd_q_.empty()) {
      LOG_WARN("Channel %c, for device %s is not empty on disconnection.", lcid,
               channel->bda_.ToString().c_str());
      channel->cl_cmd_q_.clear();
    }

    eatt_dev->eatt_channels.erase(lcid);

    if (eatt_dev->eatt_channels.size() == 0) eatt_dev->eatt_tcb_ = NULL;
+7 −3
Original line number Diff line number Diff line
@@ -436,7 +436,8 @@ static tGATT_STATUS attp_cl_send_cmd(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
  if (gatt_tcb_is_cid_busy(tcb, p_clcb->cid) &&
      cmd_code != GATT_HANDLE_VALUE_CONF) {
    gatt_cmd_enq(tcb, p_clcb, true, cmd_code, p_cmd);
    LOG_DEBUG("Enqueued ATT command");
    LOG_DEBUG("Enqueued ATT command %p conn_id=0x%04x, cid=%d", p_clcb,
              p_clcb->conn_id, p_clcb->cid);
    return GATT_CMD_STARTED;
  }

@@ -445,7 +446,9 @@ static tGATT_STATUS attp_cl_send_cmd(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
      p_clcb->cid, tcb.eatt, bt_transport_text(tcb.transport).c_str());
  tGATT_STATUS att_ret = attp_send_msg_to_l2cap(tcb, p_clcb->cid, p_cmd);
  if (att_ret != GATT_CONGESTED && att_ret != GATT_SUCCESS) {
    LOG_WARN("Unable to send ATT command to l2cap layer");
    LOG_WARN(
        "Unable to send ATT command to l2cap layer %p conn_id=0x%04x, cid=%d",
        p_clcb, p_clcb->conn_id, p_clcb->cid);
    return GATT_INTERNAL_ERROR;
  }

@@ -453,7 +456,8 @@ static tGATT_STATUS attp_cl_send_cmd(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
    return att_ret;
  }

  LOG_DEBUG("Starting ATT response timer");
  LOG_DEBUG("Starting ATT response timer %p conn_id=0x%04x, cid=%d", p_clcb,
            p_clcb->conn_id, p_clcb->cid);
  gatt_start_rsp_timer(p_clcb);
  gatt_cmd_enq(tcb, p_clcb, false, cmd_code, NULL);
  return att_ret;
+10 −33
Original line number Diff line number Diff line
@@ -701,11 +701,6 @@ tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) {
    return GATT_ERROR;
  }

  if (gatt_is_clcb_allocated(conn_id)) {
    LOG_WARN("Connection is already used conn_id:%hu", conn_id);
    return GATT_BUSY;
  }

  tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
  if (!p_clcb) {
    LOG_WARN("Unable to allocate connection link control block");
@@ -764,11 +759,6 @@ tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
    return GATT_ILLEGAL_PARAMETER;
  }

  if (gatt_is_clcb_allocated(conn_id)) {
    LOG(ERROR) << __func__ << "GATT_BUSY conn_id = " << +conn_id;
    return GATT_BUSY;
  }

  tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
  if (!p_clcb) {
    LOG(WARNING) << __func__ << " No resources conn_id=" << loghex(conn_id)
@@ -834,11 +824,6 @@ tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type,
    return GATT_ILLEGAL_PARAMETER;
  }

  if (gatt_is_clcb_allocated(conn_id)) {
    LOG(ERROR) << "GATT_BUSY conn_id=" << loghex(conn_id);
    return GATT_BUSY;
  }

  tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
  if (!p_clcb) return GATT_NO_RESOURCES;

@@ -941,11 +926,6 @@ tGATT_STATUS GATTC_Write(uint16_t conn_id, tGATT_WRITE_TYPE type,
    return GATT_ILLEGAL_PARAMETER;
  }

  if (gatt_is_clcb_allocated(conn_id)) {
    LOG(ERROR) << "GATT_BUSY conn_id=" << loghex(conn_id);
    return GATT_BUSY;
  }

  tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
  if (!p_clcb) return GATT_NO_RESOURCES;

@@ -994,11 +974,6 @@ tGATT_STATUS GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) {
    return GATT_ILLEGAL_PARAMETER;
  }

  if (gatt_is_clcb_allocated(conn_id)) {
    LOG(ERROR) << " GATT_BUSY conn_id=" << loghex(conn_id);
    return GATT_BUSY;
  }

  tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
  if (!p_clcb) return GATT_NO_RESOURCES;

@@ -1184,7 +1159,7 @@ void GATT_Deregister(tGATT_IF gatt_if) {
  /* When an application deregisters, check remove the link associated with the
   * app */
  tGATT_TCB* p_tcb;
  int i, j;
  int i;
  for (i = 0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) {
    if (!p_tcb->in_use) continue;

@@ -1192,13 +1167,15 @@ void GATT_Deregister(tGATT_IF gatt_if) {
      gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
    }

    tGATT_CLCB* p_clcb;
    for (j = 0, p_clcb = &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++) {
      if (p_clcb->in_use && (p_clcb->p_reg->gatt_if == gatt_if) &&
          (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) {
        alarm_cancel(p_clcb->gatt_rsp_timer_ent);
        gatt_clcb_dealloc(p_clcb);
        break;
    for (auto clcb_it = gatt_cb.clcb_queue.begin();
         clcb_it != gatt_cb.clcb_queue.end();) {
      if (clcb_it->in_use && (clcb_it->p_reg->gatt_if == gatt_if) &&
          (clcb_it->p_tcb->tcb_idx == p_tcb->tcb_idx)) {
        alarm_cancel(clcb_it->gatt_rsp_timer_ent);
        gatt_clcb_invalidate(p_tcb, &(*clcb_it));
        clcb_it = gatt_cb.clcb_queue.erase(clcb_it);
      } else {
        clcb_it++;
      }
    }
  }
+10 −4
Original line number Diff line number Diff line
@@ -1130,7 +1130,7 @@ uint8_t gatt_cmd_to_rsp_code(uint8_t cmd_code) {

/** Find next command in queue and sent to server */
bool gatt_cl_send_next_cmd_inq(tGATT_TCB& tcb) {
  std::queue<tGATT_CMD_Q>* cl_cmd_q;
  std::deque<tGATT_CMD_Q>* cl_cmd_q = nullptr;

  while (!tcb.cl_cmd_q.empty() ||
         EattExtension::GetInstance()->IsOutstandingMsgInSendQueue(tcb.peer_bda)) {
@@ -1153,7 +1153,7 @@ bool gatt_cl_send_next_cmd_inq(tGATT_TCB& tcb) {

    if (att_ret != GATT_SUCCESS && att_ret != GATT_CONGESTED) {
      LOG(ERROR) << __func__ << ": L2CAP sent error";
      cl_cmd_q->pop();
      cl_cmd_q->pop_front();
      continue;
    }

@@ -1185,7 +1185,7 @@ bool gatt_cl_send_next_cmd_inq(tGATT_TCB& tcb) {
void gatt_client_handle_server_rsp(tGATT_TCB& tcb, uint16_t cid,
                                   uint8_t op_code, uint16_t len,
                                   uint8_t* p_data) {
  VLOG(1) << __func__ << " opcode: " << loghex(op_code);
  VLOG(1) << __func__ << " opcode: " << loghex(op_code) << " cid" << +cid;

  uint16_t payload_size = gatt_tcb_get_payload_size_rx(tcb, cid);

@@ -1205,7 +1205,13 @@ void gatt_client_handle_server_rsp(tGATT_TCB& tcb, uint16_t cid,
  uint8_t cmd_code = 0;
  tGATT_CLCB* p_clcb = gatt_cmd_dequeue(tcb, cid, &cmd_code);
  uint8_t rsp_code = gatt_cmd_to_rsp_code(cmd_code);
  if (!p_clcb || (rsp_code != op_code && op_code != GATT_RSP_ERROR)) {
  if (!p_clcb) {
    LOG_WARN("ATT - clcb already not in use, ignoring response");
    gatt_cl_send_next_cmd_inq(tcb);
    return;
  }

  if (rsp_code != op_code && op_code != GATT_RSP_ERROR) {
    LOG(WARNING) << StringPrintf(
        "ATT - Ignore wrong response. Receives (%02x) Request(%02x) Ignored",
        op_code, rsp_code);
Loading