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--;
     }