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

Commit 06e4b602 authored by Archie Pusaka's avatar Archie Pusaka Committed by Archie Pusaka
Browse files

hh: Forward the GET/SET REPORT failures to UHID

Currently when GET/SET REPORT request from UHID fails for any reason,
we just silently drop it and doesn't notify UHID. This is against the
expectation and may cause UHID to be stuck.

This CL forwards the GET/SET REPORT replies on the failure cases,
including when the request fails even before it's sent to the
peripheral device.

Bug: 307923455
Bug: 369748430
Test: m -j
Test: Pair with a Lenovo Thinkpad Trackpoint keyboard.
      Then plug in a security key and verify it's usable.
Flag: com.android.bluetooth.flags.forward_get_set_report_failure_to_uhid

Change-Id: I7ae8e07d900b3dc7131094d650e1afbb091083f3
parent 6666a717
Loading
Loading
Loading
Loading
+111 −33
Original line number Diff line number Diff line
@@ -1785,6 +1785,24 @@ void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb) {
  bta_hh_le_remove_dev_bg_conn(p_cb);
}

/*******************************************************************************
 *
 * Function         send_read_report_reply
 *
 * Description      send GET_REPORT_EVT to application with the report data
 *
 * Returns          void
 *
 ******************************************************************************/
static void send_read_report_reply(uint8_t hid_handle, tBTA_HH_STATUS status, BT_HDR* rpt_data) {
  tBTA_HH_HSDATA hs_data = {
          .status = status,
          .handle = hid_handle,
          .rsp_data.p_rpt_data = rpt_data,
  };
  (*bta_hh_cb.p_cback)(BTA_HH_GET_RPT_EVT, (tBTA_HH*)&hs_data);
}

/*******************************************************************************
 *
 * Function         read_report_cb
@@ -1802,10 +1820,17 @@ static void read_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handl
    log::warn("Unexpected Read response, w4_evt={}", bta_hh_event_text(p_dev_cb->w4_evt));
    return;
  }
  if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
    p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT;
  }

  uint8_t hid_handle = p_dev_cb->hid_handle;
  const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(conn_id, handle);
  if (p_char == nullptr) {
    log::error("Unknown handle");
    if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
      send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr);
    }
    return;
  }

@@ -1819,21 +1844,30 @@ static void read_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handl
      break;
    default:
      log::error("Unexpected Read UUID: {}", p_char->uuid.ToString());
      if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
        send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr);
      }
      return;
  }

  if (!com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
    p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT;
  }

  if (status != GATT_SUCCESS) {
    send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr);
    return;
  }

  tBTA_HH_HSDATA hs_data = {};
  hs_data.status = BTA_HH_ERR;
  hs_data.handle = p_dev_cb->hid_handle;
  if (status == GATT_SUCCESS) {
    tBTA_HH_LE_RPT* p_rpt;
  const gatt::Service* p_svc = BTA_GATTC_GetOwningService(conn_id, p_char->value_handle);
  const tBTA_HH_LE_RPT* p_rpt =
          bta_hh_le_find_report_entry(p_dev_cb, p_svc->handle, char_uuid, p_char->value_handle);
  if (p_rpt == nullptr || len == 0) {
    send_read_report_reply(hid_handle, BTA_HH_ERR, nullptr);
    return;
  }

    p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_svc->handle, char_uuid, p_char->value_handle);
    if (p_rpt != nullptr && len) {
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + len + 1);
      /* pack data send to app */
      hs_data.status = BTA_HH_OK;
  p_buf->len = len + 1;
  p_buf->layer_specific = 0;
  p_buf->offset = 0;
@@ -1844,13 +1878,8 @@ static void read_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handl
  UINT8_TO_STREAM(pp, p_rpt->rpt_id);
  memcpy(pp, value, len);

      hs_data.rsp_data.p_rpt_data = p_buf;
    }
  }

  p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT;
  (*bta_hh_cb.p_cback)(BTA_HH_GET_RPT_EVT, (tBTA_HH*)&hs_data);
  osi_free(hs_data.rsp_data.p_rpt_data);
  send_read_report_reply(hid_handle, BTA_HH_OK, p_buf);
  osi_free(p_buf);
}

/*******************************************************************************
@@ -1866,8 +1895,11 @@ static void bta_hh_le_get_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, uin
  tBTA_HH_LE_RPT* p_rpt =
          bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id);

  if (p_rpt == NULL) {
  if (p_rpt == nullptr) {
    log::error("no matching report");
    if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
      send_read_report_reply(p_cb->hid_handle, BTA_HH_ERR, nullptr);
    }
    return;
  }

@@ -1875,9 +1907,34 @@ static void bta_hh_le_get_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, uin
  BtaGattQueue::ReadCharacteristic(p_cb->conn_id, p_rpt->char_inst_id, read_report_cb, p_cb);
}

/*******************************************************************************
 *
 * Function         send_write_report_reply
 *
 * Description      send SET_REPORT_EVT to application with the report data
 *
 * Returns          void
 *
 ******************************************************************************/
static void send_write_report_reply(uint8_t hid_handle, tBTA_HH_STATUS status, uint16_t event) {
  tBTA_HH_CBDATA cback_data = {
          .status = status,
          .handle = hid_handle,
  };
  (*bta_hh_cb.p_cback)(event, (tBTA_HH*)&cback_data);
}

/*******************************************************************************
 *
 * Function         write_report_cb
 *
 * Description      Process the Write report complete.
 *
 * Returns          void
 *
 ******************************************************************************/
static void write_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handle,
                            uint16_t /*len*/, const uint8_t* /*value*/, void* data) {
  tBTA_HH_CBDATA cback_data;
  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
  uint16_t cb_evt = p_dev_cb->w4_evt;
  if (cb_evt == BTA_HH_EMPTY_EVT) {
@@ -1885,10 +1942,17 @@ static void write_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t hand
  }

  log::verbose("w4_evt:{}", bta_hh_event_text(p_dev_cb->w4_evt));
  if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
    p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT;
  }

  uint8_t hid_handle = p_dev_cb->hid_handle;
  const gatt::Characteristic* p_char = BTA_GATTC_GetCharacteristic(conn_id, handle);
  if (p_char == nullptr) {
    log::error("Unknown characteristic handle: {}", handle);
    if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
      send_write_report_reply(hid_handle, BTA_HH_ERR, cb_evt);
    }
    return;
  }

@@ -1896,14 +1960,22 @@ static void write_report_cb(tCONN_ID conn_id, tGATT_STATUS status, uint16_t hand
  if (uuid16 != GATT_UUID_HID_REPORT && uuid16 != GATT_UUID_HID_BT_KB_INPUT &&
      uuid16 != GATT_UUID_HID_BT_MOUSE_INPUT && uuid16 != GATT_UUID_HID_BT_KB_OUTPUT) {
    log::error("Unexpected characteristic UUID: {}", p_char->uuid.ToString());
    if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
      send_write_report_reply(hid_handle, BTA_HH_ERR, cb_evt);
    }
    return;
  }

  /* Set Report finished */
  cback_data.handle = p_dev_cb->hid_handle;
  cback_data.status = (status == GATT_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR;
  if (!com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
    p_dev_cb->w4_evt = BTA_HH_EMPTY_EVT;
  (*bta_hh_cb.p_cback)(cb_evt, (tBTA_HH*)&cback_data);
  }

  if (status == GATT_SUCCESS) {
    send_write_report_reply(hid_handle, BTA_HH_OK, cb_evt);
  } else {
    send_write_report_reply(hid_handle, BTA_HH_ERR, cb_evt);
  }
}
/*******************************************************************************
 *
@@ -1921,6 +1993,9 @@ static void bta_hh_le_write_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, B

  if (p_buf == NULL || p_buf->len == 0) {
    log::error("Illegal data");
    if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
      send_write_report_reply(p_cb->hid_handle, BTA_HH_ERR, w4_evt);
    }
    return;
  }

@@ -1932,6 +2007,9 @@ static void bta_hh_le_write_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type, B
  p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id);
  if (p_rpt == NULL) {
    log::error("no matching report");
    if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
      send_write_report_reply(p_cb->hid_handle, BTA_HH_ERR, w4_evt);
    }
    osi_free(p_buf);
    return;
  }
+8 −3
Original line number Diff line number Diff line
@@ -1115,7 +1115,8 @@ void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status, const uint8_t* p_
    return;
  }

  if (len == 0 || len > UHID_DATA_MAX) {
  // len of zero is allowed, it's possible on failure case.
  if (len > UHID_DATA_MAX) {
    log::warn("Invalid report size = {}", len);
    return;
  }
@@ -1126,7 +1127,9 @@ void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status, const uint8_t* p_
    to_uhid.uhid.type = UHID_GET_REPORT_REPLY;
    to_uhid.uhid.u.get_report_reply.err = status;
    to_uhid.uhid.u.get_report_reply.size = len;
    if (len > 0) {
      memcpy(to_uhid.uhid.u.get_report_reply.data, p_rpt, len);
    }

    to_uhid_thread(p_dev->internal_send_fd, &to_uhid, uhid_calc_msg_len(&to_uhid.uhid, len));
    return;
@@ -1162,7 +1165,9 @@ void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status, const uint8_t* p_
                                  },
                  },
  };
  if (len > 0) {
    memcpy(ev.u.get_report_reply.data, p_rpt, len);
  }

  uhid_write(p_dev->uhid.fd, &ev, uhid_calc_msg_len(&ev, len));
  osi_free(context);
+3 −0
Original line number Diff line number Diff line
@@ -692,6 +692,9 @@ static void hh_get_rpt_handler(tBTA_HH_HSDATA& hs_data) {
    HAL_CBACK(bt_hh_callbacks, handshake_cb, (RawAddress*)&(p_dev->link_spec.addrt.bda),
              p_dev->link_spec.addrt.type, p_dev->link_spec.transport,
              (bthh_status_t)hs_data.status);
    if (com::android::bluetooth::flags::forward_get_set_report_failure_to_uhid()) {
      bta_hh_co_get_rpt_rsp(p_dev->dev_handle, (tBTA_HH_STATUS)hs_data.status, NULL, 0);
    }
  }
}