aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Eisenbach <eisenbach@google.com>2015-09-17 15:16:20 -0700
committerScott James Remnant <keybuk@google.com>2015-10-19 10:36:18 -0700
commit8c24123f9897991d228865c7eec35e33569e46bb (patch)
treeeb2954b2eba8e1407f2752599ac119351882e027
parent7f2eed693f328843ed912144ed6ffcab0f2e3e75 (diff)
downloadbt-8c24123f9897991d228865c7eec35e33569e46bb.tar.gz
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
-rw-r--r--btif/co/bta_hh_co.c57
-rw-r--r--btif/include/btif_hh.h1
-rw-r--r--btif/src/btif_hh.c2
3 files changed, 46 insertions, 14 deletions
diff --git a/btif/co/bta_hh_co.c b/btif/co/bta_hh_co.c
index 063326a28..0b090d5d6 100644
--- a/btif/co/bta_hh_co.c
+++ b/btif/co/bta_hh_co.c
@@ -43,11 +43,23 @@ const char *dev_path = "/dev/uhid";
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 @@ static int uhid_write(int fd, const struct uhid_event *ev)
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 @@ static int uhid_event(btif_hh_device_t *p_dev)
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 inline pthread_t create_thread(void *(*start_routine)(void *), void * arg
*******************************************************************************/
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 @@ void bta_hh_co_destroy(int fd)
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 @@ int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len)
return -1;
}
memcpy(ev.u.input.data, rpt, len);
+
return uhid_write(fd, &ev);
}
@@ -280,9 +304,11 @@ void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_ma
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 @@ void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_ma
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 @@ void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MO
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 @@ void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 ven
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 @@ void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 ven
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/btif/include/btif_hh.h b/btif/include/btif_hh.h
index dc34d653c..1088c53bf 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -64,6 +64,7 @@ typedef struct
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/btif/src/btif_hh.c b/btif/src/btif_hh.c
index f668143ab..52296de9c 100644
--- a/btif/src/btif_hh.c
+++ b/btif/src/btif_hh.c
@@ -518,6 +518,8 @@ void btif_hh_remove_device(bt_bdaddr_t bd_addr)
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--;
}