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

Commit c5fdf478 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "HFP: Fix connection colision handling" into pi-dev

parents ea617a9d c1a4efca
Loading
Loading
Loading
Loading
+62 −38
Original line number Diff line number Diff line
@@ -177,11 +177,9 @@ void bta_ag_start_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
  RawAddress pending_bd_addr = {};

  /* store parameters */
  if (!data.IsEmpty()) {
  p_scb->peer_addr = data.api_open.bd_addr;
  p_scb->open_services = data.api_open.services;
  p_scb->cli_sec_mask = data.api_open.sec_mask;
  }

  /* Check if RFCOMM has any incoming connection to avoid collision. */
  if (PORT_IsOpening(pending_bd_addr)) {
@@ -330,6 +328,7 @@ void bta_ag_open_fail(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
 *
 ******************************************************************************/
void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) {
  RawAddress peer_addr = p_scb->peer_addr;
  /* reinitialize stuff */
  p_scb->conn_handle = 0;
  p_scb->conn_service = 0;
@@ -346,7 +345,7 @@ void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR const tBTA_AG_DATA& data) {
  bta_ag_start_servers(p_scb, p_scb->reg_services);

  /* call open cback w. failure */
  bta_ag_cback_open(p_scb, RawAddress::kEmpty, BTA_AG_FAIL_RFCOMM);
  bta_ag_cback_open(p_scb, peer_addr, BTA_AG_FAIL_RFCOMM);
}

/*******************************************************************************
@@ -502,12 +501,6 @@ void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
 *
 ******************************************************************************/
void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
  uint16_t lcid;
  int i;
  tBTA_AG_SCB *ag_scb, *other_scb;
  RawAddress dev_addr = {};
  int status;

  /* set role */
  p_scb->role = BTA_AG_ACP;

@@ -515,43 +508,45 @@ void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
                   p_scb->serv_handle[0], p_scb->serv_handle[1]);

  /* get bd addr of peer */
  if (PORT_SUCCESS !=
      (status = PORT_CheckConnection(data.rfc.port_handle, dev_addr, &lcid))) {
    APPL_TRACE_DEBUG(
        "bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d",
        status);
  uint16_t lcid = 0;
  RawAddress dev_addr = RawAddress::kEmpty;
  int status = PORT_CheckConnection(data.rfc.port_handle, dev_addr, &lcid);
  if (status != PORT_SUCCESS) {
    LOG(ERROR) << __func__ << ", PORT_CheckConnection returned " << status;
    return;
  }

  /* Collision Handling */
  for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_MAX_NUM_CLIENTS;
       i++, ag_scb++) {
    if (ag_scb->in_use && alarm_is_scheduled(ag_scb->collision_timer)) {
      alarm_cancel(ag_scb->collision_timer);

      if (dev_addr == ag_scb->peer_addr) {
        /* If incoming and outgoing device are same, nothing more to do. */
        /* Outgoing conn will be aborted because we have successful incoming
         * conn.  */
      } else {
        /* Resume outgoing connection. */
        other_scb = bta_ag_get_other_idle_scb(p_scb);
        if (other_scb) {
          other_scb->peer_addr = ag_scb->peer_addr;
          other_scb->open_services = ag_scb->open_services;
          other_scb->cli_sec_mask = ag_scb->cli_sec_mask;

          bta_ag_resume_open(other_scb);
  for (tBTA_AG_SCB& ag_scb : bta_ag_cb.scb) {
    // Cancel any pending collision timers
    if (ag_scb.in_use && alarm_is_scheduled(ag_scb.collision_timer)) {
      alarm_cancel(ag_scb.collision_timer);
      if (dev_addr != ag_scb.peer_addr && p_scb != &ag_scb) {
        // Resume outgoing connection if incoming is not on the same device
        bta_ag_resume_open(&ag_scb);
      }
      }

      break;
    }
    if (dev_addr == ag_scb.peer_addr && p_scb != &ag_scb) {
      // Fail the outgoing connection to clean up any upper layer states
      bta_ag_rfc_fail(&ag_scb, tBTA_AG_DATA::kEmpty);
      // If client port is opened, close it
      if (ag_scb.conn_handle > 0) {
        status = RFCOMM_RemoveConnection(ag_scb.conn_handle);
        if (status != PORT_SUCCESS) {
          LOG(WARNING) << __func__ << ": RFCOMM_RemoveConnection failed for "
                       << dev_addr << ", handle "
                       << std::to_string(ag_scb.conn_handle) << ", error "
                       << status;
        }
      }
    }
  }

  p_scb->peer_addr = dev_addr;

  /* determine connected service from port handle */
  for (i = 0; i < BTA_AG_NUM_IDX; i++) {
  for (int i = 0; i < BTA_AG_NUM_IDX; i++) {
    APPL_TRACE_DEBUG(
        "bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", i,
        p_scb->serv_handle[i], data.rfc.port_handle);
@@ -813,3 +808,32 @@ void bta_ag_setcodec(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {

  (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG*)&val);
}

static void bta_ag_collision_timer_cback(void* data) {
  if (data == nullptr) {
    LOG(ERROR) << __func__ << ": data should never be null in a timer callback";
    return;
  }
  /* If the peer haven't opened AG connection     */
  /* we will restart opening process.             */
  bta_ag_resume_open(static_cast<tBTA_AG_SCB*>(data));
}

void bta_ag_handle_collision(tBTA_AG_SCB* p_scb,
                             UNUSED_ATTR const tBTA_AG_DATA& data) {
  /* Cancel SDP if it had been started. */
  if (p_scb->p_disc_db) {
    SDP_CancelServiceSearch(p_scb->p_disc_db);
    bta_ag_free_db(p_scb, tBTA_AG_DATA::kEmpty);
  }

  /* reopen registered servers */
  /* Collision may be detected before or after we close servers. */
  if (bta_ag_is_server_closed(p_scb)) {
    bta_ag_start_servers(p_scb, p_scb->reg_services);
  }

  /* Start timer to han */
  alarm_set_on_mloop(p_scb->collision_timer, BTA_AG_COLLISION_TIMEOUT_MS,
                     bta_ag_collision_timer_cback, p_scb);
}
+3 −1
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ enum {
  BTA_AG_DISC_FAIL_EVT,
  BTA_AG_RING_TIMEOUT_EVT,
  BTA_AG_SVC_TIMEOUT_EVT,
  BTA_AG_COLLISION_EVT,
  BTA_AG_MAX_EVT,
};

@@ -306,7 +307,6 @@ extern uint8_t bta_ag_service_to_idx(tBTA_SERVICE_MASK services);
extern uint16_t bta_ag_idx_by_bdaddr(const RawAddress* peer_addr);
extern bool bta_ag_other_scb_open(tBTA_AG_SCB* p_curr_scb);
extern bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb);
extern tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb);
extern void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event,
                              const tBTA_AG_DATA& data);
extern void bta_ag_sm_execute_by_handle(uint16_t handle, uint16_t event,
@@ -378,6 +378,8 @@ extern void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
extern void bta_ag_result(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
extern void bta_ag_setcodec(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
extern void bta_ag_send_ring(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data);
extern void bta_ag_handle_collision(tBTA_AG_SCB* p_scb,
                                    const tBTA_AG_DATA& data);

/* Internal utility functions */
extern void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result);
+37 −82
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ enum {
  BTA_AG_RESULT,
  BTA_AG_SETCODEC,
  BTA_AG_SEND_RING,
  BTA_AG_HANDLE_COLLISION,
  BTA_AG_NUM_ACTIONS
};

@@ -133,6 +134,7 @@ static const char* bta_ag_evt_str(uint16_t event) {
    CASE_RETURN_STR(BTA_AG_DISC_FAIL_EVT)
    CASE_RETURN_STR(BTA_AG_RING_TIMEOUT_EVT)
    CASE_RETURN_STR(BTA_AG_SVC_TIMEOUT_EVT)
    CASE_RETURN_STR(BTA_AG_COLLISION_EVT)
    default:
      return "Unknown AG Event";
  }
@@ -160,7 +162,11 @@ const tBTA_AG_ACTION bta_ag_action[] = {
    bta_ag_sco_conn_close, bta_ag_sco_listen,    bta_ag_sco_open,
    bta_ag_sco_close,      bta_ag_sco_shutdown,  bta_ag_post_sco_open,
    bta_ag_post_sco_close, bta_ag_svc_conn_open, bta_ag_result,
    bta_ag_setcodec,       bta_ag_send_ring};
    bta_ag_setcodec,       bta_ag_send_ring,     bta_ag_handle_collision};

static_assert(sizeof(bta_ag_action) / sizeof(tBTA_AG_ACTION) ==
                  BTA_AG_NUM_ACTIONS,
              "bta_ag_action must handle all actions");

/* state table information */
#define BTA_AG_ACTIONS 2    /* number of actions */
@@ -189,7 +195,8 @@ const uint8_t bta_ag_st_init[][BTA_AG_NUM_COLS] = {
    /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
    /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
    /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
    /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}};

/* state table for opening state */
const uint8_t bta_ag_st_opening[][BTA_AG_NUM_COLS] = {
@@ -216,7 +223,9 @@ const uint8_t bta_ag_st_opening[][BTA_AG_NUM_COLS] = {
    /* DISC_OK_EVT */ {BTA_AG_RFC_DO_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
    /* DISC_FAIL_EVT */ {BTA_AG_DISC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
    /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}};
    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
    /* COLLISION_EVT */
    {BTA_AG_HANDLE_COLLISION, BTA_AG_IGNORE, BTA_AG_INIT_ST}};

/* state table for open state */
const uint8_t bta_ag_st_open[][BTA_AG_NUM_COLS] = {
@@ -243,7 +252,8 @@ const uint8_t bta_ag_st_open[][BTA_AG_NUM_COLS] = {
    /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
    /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
    /* RING_TOUT_EVT */ {BTA_AG_SEND_RING, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
    /* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
    /* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
    /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}};

/* state table for closing state */
const uint8_t bta_ag_st_closing[][BTA_AG_NUM_COLS] = {
@@ -269,7 +279,19 @@ const uint8_t bta_ag_st_closing[][BTA_AG_NUM_COLS] = {
    /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
    /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
    /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
    /* COLLISION_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};

constexpr size_t BTA_AG_NUM_EVENTS =
    BTA_AG_MAX_EVT - BTA_SYS_EVT_START(BTA_ID_AG);
static_assert(sizeof(bta_ag_st_init) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
              "bta_ag_st_init must handle all AG events");
static_assert(sizeof(bta_ag_st_opening) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
              "bta_ag_st_opening must handle all AG events");
static_assert(sizeof(bta_ag_st_open) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
              "bta_ag_st_open must handle all AG events");
static_assert(sizeof(bta_ag_st_closing) / BTA_AG_NUM_COLS == BTA_AG_NUM_EVENTS,
              "bta_ag_st_closing must handle all AG events");

/* type for state table */
typedef const uint8_t (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
@@ -494,52 +516,6 @@ bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb) {
         p_curr_scb->state == BTA_AG_OPEN_ST;
}

/*******************************************************************************
 *
 * Function         bta_ag_get_other_idle_scb
 *
 * Description      Return other scb if it is in INIT st.
 *
 *
 * Returns          Pointer to other scb if INIT st, NULL otherwise.
 *
 ******************************************************************************/
tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb) {
  tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
  uint8_t xx;

  for (xx = 0; xx < BTA_AG_MAX_NUM_CLIENTS; xx++, p_scb++) {
    if (p_scb->in_use && (p_scb != p_curr_scb) &&
        (p_scb->state == BTA_AG_INIT_ST)) {
      return p_scb;
    }
  }

  /* no other scb found */
  APPL_TRACE_DEBUG("bta_ag_get_other_idle_scb: No idle AG scb");
  return nullptr;
}

/*******************************************************************************
 *
 * Function         bta_ag_collision_timer_cback
 *
 * Description      AG connection collision timer callback
 *
 *
 * Returns          void
 *
 ******************************************************************************/
static void bta_ag_collision_timer_cback(void* data) {
  tBTA_AG_SCB* p_scb = (tBTA_AG_SCB*)data;

  APPL_TRACE_DEBUG("%s", __func__);

  /* If the peer haven't opened AG connection     */
  /* we will restart opening process.             */
  bta_ag_resume_open(p_scb);
}

/*******************************************************************************
 *
 * Function         bta_ag_collision_cback
@@ -568,24 +544,7 @@ void bta_ag_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, uint8_t id,
      LOG(WARNING) << __func__ << "AG found collision (UNKNOWN) for handle "
                   << unsigned(handle) << " device " << peer_addr;
    }

    p_scb->state = BTA_AG_INIT_ST;

    /* Cancel SDP if it had been started. */
    if (p_scb->p_disc_db) {
      SDP_CancelServiceSearch(p_scb->p_disc_db);
      bta_ag_free_db(p_scb, tBTA_AG_DATA::kEmpty);
    }

    /* reopen registered servers */
    /* Collision may be detected before or after we close servers. */
    if (bta_ag_is_server_closed(p_scb)) {
      bta_ag_start_servers(p_scb, p_scb->reg_services);
    }

    /* Start timer to han */
    alarm_set_on_mloop(p_scb->collision_timer, BTA_AG_COLLISION_TIMEOUT_MS,
                       bta_ag_collision_timer_cback, p_scb);
    bta_ag_sm_execute(p_scb, BTA_AG_COLLISION_EVT, tBTA_AG_DATA::kEmpty);
  }
}

@@ -600,20 +559,16 @@ void bta_ag_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, uint8_t id,
 *
 ******************************************************************************/
void bta_ag_resume_open(tBTA_AG_SCB* p_scb) {
  if (p_scb) {
    APPL_TRACE_DEBUG("%s: handle=%d, bd_addr=%s", __func__,
                     bta_ag_scb_to_idx(p_scb),
                     p_scb->peer_addr.ToString().c_str());
    /* resume opening process.  */
  if (p_scb->state == BTA_AG_INIT_ST) {
      LOG(WARNING) << __func__
                   << ": handle=" << unsigned(bta_ag_scb_to_idx(p_scb))
                   << ", bd_addr=" << p_scb->peer_addr;
      p_scb->state = BTA_AG_OPENING_ST;
      bta_ag_start_open(p_scb, tBTA_AG_DATA::kEmpty);
    }
    LOG(INFO) << __func__ << ": Resume connection to " << p_scb->peer_addr
              << ", handle" << bta_ag_scb_to_idx(p_scb);
    tBTA_AG_DATA open_data = {.api_open.bd_addr = p_scb->peer_addr,
                              .api_open.services = p_scb->open_services,
                              .api_open.sec_mask = p_scb->cli_sec_mask};
    bta_ag_sm_execute(p_scb, BTA_AG_API_OPEN_EVT, open_data);
  } else {
    LOG(ERROR) << __func__ << ": null p_scb";
    VLOG(1) << __func__ << ": device " << p_scb->peer_addr
            << " is already in state " << std::to_string(p_scb->state);
  }
}

+6 −5
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <cstring>
#include <ctime>

#include <bta/include/bta_ag_api.h>
#include <hardware/bluetooth.h>
#include <hardware/bluetooth_headset_callbacks.h>
#include <hardware/bluetooth_headset_interface.h>
@@ -327,11 +328,11 @@ static void btif_hf_upstreams_evt(uint16_t event, char* p_param) {
                   << unsigned(p_data->open.status);
        btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
      } else {
        BTIF_TRACE_WARNING(
            "%s: AG open failed, but another device connected. status=%d "
            "state=%d connected device=%s",
            __func__, p_data->open.status, btif_hf_cb[idx].state,
            btif_hf_cb[idx].connected_bda.ToString().c_str());
        LOG(WARNING) << __func__ << ": AG open failed for "
                     << p_data->open.bd_addr << ", error "
                     << std::to_string(p_data->open.status)
                     << ", local device is " << btif_hf_cb[idx].connected_bda
                     << ". Ignoring as not expecting to open";
        break;
      }
      bt_hf_callbacks->ConnectionStateCallback(btif_hf_cb[idx].state,
+3 −4
Original line number Diff line number Diff line
@@ -319,8 +319,7 @@ tPORT* port_find_mcb_dlci_port(tRFC_MCB* p_mcb, uint8_t dlci) {

  uint8_t inx = p_mcb->port_inx[dlci];
  if (inx == 0) {
    LOG(WARNING) << __func__
                 << ": Cannot find allocated RFCOMM app port for DLCI "
    LOG(INFO) << __func__ << ": Cannot find allocated RFCOMM app port for DLCI "
              << std::to_string(dlci) << " on " << p_mcb->bd_addr
              << ", p_mcb=" << p_mcb;
    return nullptr;
Loading