Change UHID socket to be non-blocking
On some platforms, the logs indicate that the BTU task is stalled by
UHID driver when writing the HID descriptor to the kernel. This patch
converts the UHID socket to non-blocking to avoid stalling the main
BTU task.
Bug: 23978964
Change-Id: I5a7a3e106fb2c967d68f077faedcd4fe62bbd912
diff --git a/system/btif/co/bta_hh_co.c b/system/btif/co/bta_hh_co.c
index 31dfde1..bd6fd6f 100644
--- a/system/btif/co/bta_hh_co.c
+++ b/system/btif/co/bta_hh_co.c
@@ -43,11 +43,23 @@
static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
#endif
+void uhid_set_non_blocking(int fd)
+{
+ int opts = fcntl(fd, F_GETFL);
+ if (opts < 0)
+ APPL_TRACE_ERROR("%s() Getting flags failed (%s)", __func__, strerror(errno));
+
+ opts |= O_NONBLOCK;
+
+ if (fcntl(fd, F_SETFL, opts) < 0)
+ APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__, strerror(errno));
+}
+
/*Internal function to perform UHID write and error checking*/
static int uhid_write(int fd, const struct uhid_event *ev)
{
- ssize_t ret;
- ret = write(fd, ev, sizeof(*ev));
+ ssize_t ret = write(fd, ev, sizeof(*ev));
+
if (ret < 0){
int rtn = -errno;
APPL_TRACE_ERROR("%s: Cannot write to uhid:%s",
@@ -57,9 +69,9 @@
APPL_TRACE_ERROR("%s: Wrong size written to uhid: %zd != %zu",
__FUNCTION__, ret, sizeof(*ev));
return -EFAULT;
- } else {
- return 0;
}
+
+ return 0;
}
/* Internal function to parse the events received from UHID driver*/
@@ -82,24 +94,31 @@
APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __FUNCTION__,
strerror(errno));
return -errno;
- } else if (ret < (ssize_t)sizeof(ev.type)) {
- APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+ } else if ((ev.type == UHID_OUTPUT) || (ev.type==UHID_OUTPUT_EV)) {
+ // Only these two types havae payload,
+ // ensure we read full event descriptor
+ if (ret < (ssize_t)sizeof(ev)) {
+ APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %ld != %lu",
__FUNCTION__, ret, sizeof(ev.type));
- return -EFAULT;
+ return -EFAULT;
+ }
}
switch (ev.type) {
case UHID_START:
APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
+ p_dev->ready_for_data = TRUE;
break;
case UHID_STOP:
APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
+ p_dev->ready_for_data = FALSE;
break;
case UHID_OPEN:
APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
break;
case UHID_CLOSE:
APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
+ p_dev->ready_for_data = FALSE;
break;
case UHID_OUTPUT:
if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) {
@@ -175,14 +194,17 @@
*******************************************************************************/
static void *btif_hh_poll_event_thread(void *arg)
{
-
btif_hh_device_t *p_dev = arg;
APPL_TRACE_DEBUG("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd);
struct pollfd pfds[1];
int ret;
+
pfds[0].fd = p_dev->fd;
pfds[0].events = POLLIN;
+ // Set the uhid fd as non-blocking to ensure we never block the BTU thread
+ uhid_set_non_blocking(p_dev->fd);
+
while(p_dev->hh_keep_polling){
ret = poll(pfds, 1, 50);
if (ret < 0) {
@@ -224,7 +246,8 @@
int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len)
{
- APPL_TRACE_DEBUG("bta_hh_co_data: UHID write");
+ APPL_TRACE_DEBUG("%s: UHID write %d", __func__, len);
+
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = UHID_INPUT;
@@ -235,6 +258,7 @@
return -1;
}
memcpy(ev.u.input.data, rpt, len);
+
return uhid_write(fd, &ev);
}
@@ -280,9 +304,11 @@
if (p_dev->fd < 0){
APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
__FUNCTION__,strerror(errno));
+ return;
}else
APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
}
+
p_dev->hh_keep_polling = 1;
p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
break;
@@ -307,6 +333,7 @@
if (p_dev->fd < 0){
APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
__FUNCTION__,strerror(errno));
+ return;
}else{
APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
p_dev->hh_keep_polling = 1;
@@ -397,11 +424,13 @@
APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __FUNCTION__, dev_handle);
return;
}
- // Send the HID report to the kernel.
- if (p_dev->fd >= 0) {
+
+ // Send the HID data to the kernel.
+ if ((p_dev->fd >= 0) && p_dev->ready_for_data) {
bta_hh_co_write(p_dev->fd, p_rpt, len);
}else {
- APPL_TRACE_WARNING("%s: Error: fd = %d, len = %d", __FUNCTION__, p_dev->fd, len);
+ APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __FUNCTION__, p_dev->fd,
+ p_dev->ready_for_data, len);
}
}
@@ -437,7 +466,7 @@
vendor_id, product_id,
version, ctry_code);
-//Create and send hid descriptor to kernel
+ //Create and send hid descriptor to kernel
memset(&ev, 0, sizeof(ev));
ev.type = UHID_CREATE;
strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1);
@@ -455,7 +484,7 @@
ev.u.create.country = ctry_code;
result = uhid_write(p_dev->fd, &ev);
- APPL_TRACE_WARNING("%s: fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
+ APPL_TRACE_WARNING("%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
p_dev->fd, dscp_len, result);
if (result) {
diff --git a/system/btif/include/btif_hh.h b/system/btif/include/btif_hh.h
index dc34d65..1088c53 100644
--- a/system/btif/include/btif_hh.h
+++ b/system/btif/include/btif_hh.h
@@ -64,6 +64,7 @@
UINT8 sub_class;
UINT8 app_id;
int fd;
+ BOOLEAN ready_for_data;
pthread_t hh_poll_thread_id;
UINT8 hh_keep_polling;
BOOLEAN vup_timer_active;
diff --git a/system/btif/src/btif_hh.c b/system/btif/src/btif_hh.c
index 3b9220a..633975d 100644
--- a/system/btif/src/btif_hh.c
+++ b/system/btif/src/btif_hh.c
@@ -527,6 +527,8 @@
p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN;
p_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ p_dev->ready_for_data = FALSE;
+
if (btif_hh_cb.device_num > 0) {
btif_hh_cb.device_num--;
}