am 7b4fdb40: Eliminate recursive calling when handling GATT related errors

* commit '7b4fdb40e81a68d254f6bf7cefbc385d978fb9d0':
  Eliminate recursive calling when handling GATT related errors
diff --git a/audio_a2dp_hw/Android.mk b/audio_a2dp_hw/Android.mk
index e745d0c..8581941 100644
--- a/audio_a2dp_hw/Android.mk
+++ b/audio_a2dp_hw/Android.mk
@@ -15,7 +15,7 @@
 LOCAL_MODULE := audio.a2dp.default
 LOCAL_MODULE_RELATIVE_PATH := hw
 
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libpower
 LOCAL_STATIC_LIBRARIES := libosi
 
 LOCAL_MODULE_TAGS := optional
diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c
index 613061a..ee0cb46 100644
--- a/audio_a2dp_hw/audio_a2dp_hw.c
+++ b/audio_a2dp_hw/audio_a2dp_hw.c
@@ -698,7 +698,6 @@
 
     INFO("state %d", out->common.state);
 
-
     hash_map_t *params = hash_map_utils_new_from_string_params(kvpairs);
     int status = 0;
 
diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
index 353c853..a7e3679 100644
--- a/bta/dm/bta_dm_act.c
+++ b/bta/dm/bta_dm_act.c
@@ -3681,7 +3681,7 @@
                 }
 
                 if((bta_dm_cb.device_list.peer_device[i].pref_role == BTA_MASTER_ROLE_ONLY)
-                    || (bta_dm_cb.device_list.count > 1))
+                    || (br_count > 1))
                 {
 
                 /* Initiating immediate role switch with certain remote devices
@@ -3690,7 +3690,8 @@
                   versions are stored in a blacklist and role switch with these devices are
                   delayed to avoid the collision with link encryption setup */
 
-                    if (delay_role_switch == FALSE)
+                    if (bta_dm_cb.device_list.peer_device[i].pref_role != BTA_SLAVE_ROLE_ONLY &&
+                            delay_role_switch == FALSE)
                     {
                         BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
                                         HCI_ROLE_MASTER, NULL);
diff --git a/bta/dm/bta_dm_cfg.c b/bta/dm/bta_dm_cfg.c
index 014c431..744a6fc 100644
--- a/bta/dm/bta_dm_cfg.c
+++ b/bta/dm/bta_dm_cfg.c
@@ -86,7 +86,11 @@
 #define BTA_AV_ROLE BTA_MASTER_ROLE_PREF
 #endif
 
-#define BTA_DM_NUM_RM_ENTRY    4
+#ifndef BTA_PANU_ROLE
+/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */
+#define BTA_PANU_ROLE BTA_SLAVE_ROLE_ONLY
+#endif
+#define BTA_DM_NUM_RM_ENTRY    6
 
 /* appids for PAN used by insight sample application
    these have to be same as defined in btui_int.h */
@@ -100,8 +104,10 @@
 const tBTA_DM_RM bta_dm_rm_cfg[] =
 {
     {BTA_ID_SYS, BTA_DM_NUM_RM_ENTRY, BTA_DM_SCATTERNET},
-    {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_MASTER_ROLE_ONLY},
-    {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_MASTER_ROLE_ONLY},
+    {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_ANY_ROLE},
+    {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_ANY_ROLE},
+    {BTA_ID_PAN, BTA_APP_ID_PAN_MULTI, BTA_MASTER_ROLE_ONLY},
+    {BTA_ID_PAN, BTUI_PAN_ID_PANU, BTA_PANU_ROLE},
     {BTA_ID_HH,  BTA_ALL_APP_ID, BTA_HH_ROLE},
     {BTA_ID_AV,  BTA_ALL_APP_ID, BTA_AV_ROLE}
 };
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index 6977e5c..c41c46e 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -181,6 +181,7 @@
 /* Ignore for Discoverable, Connectable only for LE modes */
 #define BTA_DM_LE_IGNORE           0xFF00
 
+#define BTA_APP_ID_PAN_MULTI    0xFE    /* app id for pan multiple connection */
 #define BTA_ALL_APP_ID          0xFF
 
 /* Discoverable Modes */
@@ -248,6 +249,7 @@
 #define BTA_ANY_ROLE          0x00
 #define BTA_MASTER_ROLE_PREF  0x01
 #define BTA_MASTER_ROLE_ONLY  0x02
+#define BTA_SLAVE_ROLE_ONLY   0x03     /* Used for PANU only, skip role switch to master */
 
 typedef UINT8 tBTA_PREF_ROLES;
 
diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
index ef7bee7..4ed52e3 100644
--- a/bta/pan/bta_pan_act.c
+++ b/bta/pan/bta_pan_act.c
@@ -295,6 +295,53 @@
 
 /*******************************************************************************
 **
+** Function         bta_pan_has_multiple_connections
+**
+** Description      Check whether there are multiple GN/NAP connections to
+**                  different devices
+**
+**
+** Returns          BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN bta_pan_has_multiple_connections(UINT8 app_id)
+{
+    tBTA_PAN_SCB *p_scb = NULL;
+    BOOLEAN     found = FALSE;
+    BD_ADDR     bd_addr;
+
+    for (UINT8 index = 0; index < BTA_PAN_NUM_CONN; index++)
+    {
+        p_scb = &bta_pan_cb.scb[index];
+        if (p_scb->in_use == TRUE && app_id == p_scb->app_id)
+        {
+            /* save temp bd_addr */
+            bdcpy(bd_addr, p_scb->bd_addr);
+            found = TRUE;
+            break;
+        }
+    }
+
+    /* If cannot find a match then there is no connection at all */
+    if (found == FALSE)
+        return FALSE;
+
+    /* Find whether there is another connection with different device other than PANU.
+        Could be same service or different service */
+    for (UINT8 index = 0; index < BTA_PAN_NUM_CONN; index++)
+    {
+        p_scb = &bta_pan_cb.scb[index];
+        if (p_scb->in_use == TRUE && p_scb->app_id != bta_pan_cb.app_id[0] &&
+                bdcmp(bd_addr, p_scb->bd_addr))
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/*******************************************************************************
+**
 ** Function         bta_pan_enable
 **
 ** Description
@@ -554,7 +601,6 @@
     if(p_data->conn.result == PAN_SUCCESS)
     {
         data.status = BTA_PAN_SUCCESS;
-        bta_pan_co_open(p_scb->handle, p_scb->app_id, p_scb->local_role, p_scb->peer_role, p_scb->bd_addr);
         p_scb->pan_flow_enable = TRUE;
         p_scb->app_flow_enable = TRUE;
         bta_sys_conn_open(BTA_ID_PAN ,p_scb->app_id, p_scb->bd_addr);
@@ -565,6 +611,18 @@
         data.status = BTA_PAN_FAIL;
     }
 
+    p_scb->pan_flow_enable = TRUE;
+    p_scb->app_flow_enable = TRUE;
+
+    /* If app_id is NAP/GN, check whether there are multiple connections.
+       If there are, provide a special app_id to dm to enforce master role only. */
+    if ((p_scb->app_id == bta_pan_cb.app_id[1] || p_scb->app_id == bta_pan_cb.app_id[2]) &&
+            bta_pan_has_multiple_connections(p_scb->app_id))
+    {
+        p_scb->app_id = BTA_APP_ID_PAN_MULTI;
+    }
+
+    bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
     bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data);
 
 
@@ -589,7 +647,6 @@
 
     data.handle = p_data->hdr.layer_specific;
 
-
     bta_sys_conn_close( BTA_ID_PAN ,p_scb->app_id, p_scb->bd_addr);
 
     /* free all queued up data buffers */
@@ -598,8 +655,6 @@
 
     GKI_init_q(&p_scb->data_queue);
 
-    bta_pan_co_close(p_scb->handle, p_scb->app_id);
-
     bta_pan_scb_dealloc(p_scb);
 
     bta_pan_cb.p_cback(BTA_PAN_CLOSE_EVT, (tBTA_PAN *)&data);
diff --git a/btcore/Android.mk b/btcore/Android.mk
index aa07cbe..8c9e1f1 100644
--- a/btcore/Android.mk
+++ b/btcore/Android.mk
@@ -86,7 +86,7 @@
 LOCAL_CFLAGS := -Wall -Werror -Werror=unused-variable
 LOCAL_MODULE := net_test_btcore
 LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libpower
 LOCAL_STATIC_LIBRARIES := libbtcore libosi
 include $(BUILD_NATIVE_TEST)
 
diff --git a/btcore/src/counter.c b/btcore/src/counter.c
index e1f3da4..d693fc3 100644
--- a/btcore/src/counter.c
+++ b/btcore/src/counter.c
@@ -256,6 +256,10 @@
 }
 
 static bool counter_socket_open(void) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+  return true;          // Disable using network sockets for security reasons
+#endif
+
   assert(listen_socket_ == NULL);
   assert(thread_ == NULL);
   assert(clients_ == NULL);
@@ -293,6 +297,10 @@
 }
 
 static void counter_socket_close(void) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+  return;               // Disable using network sockets for security reasons
+#endif
+
   socket_free(listen_socket_);
   thread_free(thread_);
   list_free(clients_);
diff --git a/btif/co/bta_hh_co.c b/btif/co/bta_hh_co.c
index 063326a..0b090d5 100644
--- a/btif/co/bta_hh_co.c
+++ b/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/btif/include/btif_hh.h b/btif/include/btif_hh.h
index dc34d65..1088c53 100644
--- a/btif/include/btif_hh.h
+++ b/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/btif/src/btif_dm.c b/btif/src/btif_dm.c
index 6ba33f8..649a708 100644
--- a/btif/src/btif_dm.c
+++ b/btif/src/btif_dm.c
@@ -2938,9 +2938,9 @@
             state = BT_BOND_STATE_NONE;
         } else {
             btif_dm_save_ble_bonding_keys();
+            BTA_GATTC_Refresh(bd_addr.address);
+            btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
         }
-        BTA_GATTC_Refresh(bd_addr.address);
-        btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
     }
     else
     {
diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c
index f668143..52296de 100644
--- a/btif/src/btif_hh.c
+++ b/btif/src/btif_hh.c
@@ -518,6 +518,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--;
     }
diff --git a/btif/src/btif_pan.c b/btif/src/btif_pan.c
index 13ada4e..d3fb89b 100644
--- a/btif/src/btif_pan.c
+++ b/btif/src/btif_pan.c
@@ -276,10 +276,10 @@
     btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
     if (conn && conn->handle >= 0)
     {
-        BTA_PanClose(conn->handle);
         /* Inform the application that the disconnect has been initiated successfully */
         btif_transfer_context(btif_in_pan_generic_evt, BTIF_PAN_CB_DISCONNECTING,
                               (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
+        BTA_PanClose(conn->handle);
         return BT_STATUS_SUCCESS;
     }
     return BT_STATUS_FAIL;
@@ -491,6 +491,62 @@
     return NULL;
 }
 
+static void btpan_open_conn(btpan_conn_t* conn, tBTA_PAN *p_data)
+{
+    BTIF_TRACE_API("btpan_open_conn: local_role:%d, peer_role: %d,  handle:%d, conn: %p",
+            p_data->open.local_role, p_data->open.peer_role, p_data->open.handle, conn);
+
+    if (conn == NULL)
+        conn = btpan_new_conn(p_data->open.handle, p_data->open.bd_addr, p_data->open.local_role,
+                p_data->open.peer_role);
+    if (conn)
+    {
+        BTIF_TRACE_DEBUG("btpan_open_conn:tap_fd:%d, open_count:%d, "
+                "conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d",
+                btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, p_data->open.handle,
+                conn->local_role, conn->remote_role);
+
+        btpan_cb.open_count++;
+        conn->handle = p_data->open.handle;
+        if (btpan_cb.tap_fd < 0)
+        {
+            btpan_cb.tap_fd = btpan_tap_open();
+            if(btpan_cb.tap_fd >= 0)
+                create_tap_read_thread(btpan_cb.tap_fd);
+        }
+
+        if (btpan_cb.tap_fd >= 0)
+        {
+            btpan_cb.flow = 1;
+            conn->state = PAN_STATE_OPEN;
+        }
+    }
+}
+
+static void btpan_close_conn(btpan_conn_t* conn)
+{
+    BTIF_TRACE_API("btpan_close_conn: %p",conn);
+
+    if (conn && conn->state == PAN_STATE_OPEN)
+    {
+        BTIF_TRACE_DEBUG("btpan_close_conn: PAN_STATE_OPEN");
+
+        conn->state = PAN_STATE_CLOSE;
+        btpan_cb.open_count--;
+
+        if (btpan_cb.open_count == 0)
+        {
+            destroy_tap_read_thread();
+            if (btpan_cb.tap_fd != INVALID_FD)
+            {
+                btpan_tap_close(btpan_cb.tap_fd);
+                btpan_cb.tap_fd = INVALID_FD;
+            }
+        }
+    }
+}
+
+
 static void btpan_cleanup_conn(btpan_conn_t* conn)
 {
     if (conn)
@@ -615,6 +671,7 @@
                 {
                     state = BTPAN_STATE_CONNECTED;
                     status = BT_STATUS_SUCCESS;
+                    btpan_open_conn(conn, p_data);
                 }
                 else
                 {
@@ -632,9 +689,9 @@
             }
         case BTA_PAN_CLOSE_EVT:
             {
-                btpan_conn_t* conn = btpan_find_conn_handle(p_data->close.handle);
-
                 LOG_INFO(LOG_TAG, "%s: event = BTA_PAN_CLOSE_EVT handle %d", __FUNCTION__, p_data->close.handle);
+                btpan_conn_t* conn = btpan_find_conn_handle(p_data->close.handle);
+                btpan_close_conn(conn);
 
                 if (conn && conn->handle >= 0)
                 {
diff --git a/device/Android.mk b/device/Android.mk
index ed60803..1ed85e1 100644
--- a/device/Android.mk
+++ b/device/Android.mk
@@ -61,7 +61,7 @@
 LOCAL_CFLAGS := -Wall -Werror -Werror=unused-variable
 LOCAL_MODULE := net_test_device
 LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := liblog libdl
+LOCAL_SHARED_LIBRARIES := liblog libdl libpower
 LOCAL_STATIC_LIBRARIES := libbtdevice libbtcore libosi libcutils
 
 include $(BUILD_NATIVE_TEST)
diff --git a/device/src/interop.c b/device/src/interop.c
index bc76201..84decd7 100644
--- a/device/src/interop.c
+++ b/device/src/interop.c
@@ -47,9 +47,8 @@
     if (feature == interop_database[i].feature &&
         memcmp(addr, &interop_database[i].addr, interop_database[i].len) == 0) {
       char bdstr[20] = {0};
-      LOG_WARN(LOG_TAG, "%s() Device %s is a match for interop workaround %s",
-          __func__, bdaddr_to_string(addr, bdstr, sizeof(bdstr)),
-                        interop_feature_string(feature));
+      LOG_WARN("%s() Device %s is a match for interop workaround %s", __func__,
+          bdaddr_to_string(addr, bdstr, sizeof(bdstr)), interop_feature_string(feature));
       return true;
     }
   }
diff --git a/hci/Android.mk b/hci/Android.mk
index a36d6b7..97179da 100644
--- a/hci/Android.mk
+++ b/hci/Android.mk
@@ -75,7 +75,7 @@
 LOCAL_CFLAGS := -Wall -Werror $(bdroid_CFLAGS)
 LOCAL_MODULE := net_test_hci
 LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := liblog libdl
+LOCAL_SHARED_LIBRARIES := liblog libdl libpower
 LOCAL_STATIC_LIBRARIES := libbt-hci libosi libcutils libbtcore
 
 include $(BUILD_NATIVE_TEST)
diff --git a/hci/src/btsnoop_net.c b/hci/src/btsnoop_net.c
index f797558..e0c1ccf 100644
--- a/hci/src/btsnoop_net.c
+++ b/hci/src/btsnoop_net.c
@@ -46,6 +46,10 @@
 static int client_socket_ = -1;
 
 void btsnoop_net_open() {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+  return;               // Disable using network sockets for security reasons
+#endif
+
   listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
   if (!listen_thread_valid_) {
     LOG_ERROR(LOG_TAG, "%s pthread_create failed: %s", __func__, strerror(errno));
@@ -55,6 +59,10 @@
 }
 
 void btsnoop_net_close() {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+  return;               // Disable using network sockets for security reasons
+#endif
+
   if (listen_thread_valid_) {
     shutdown(listen_socket_, SHUT_RDWR);
     pthread_join(listen_thread_, NULL);
@@ -64,6 +72,10 @@
 }
 
 void btsnoop_net_write(const void *data, size_t length) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+  return;               // Disable using network sockets for security reasons
+#endif
+
   pthread_mutex_lock(&client_socket_lock_);
   if (client_socket_ != -1) {
     if (send(client_socket_, data, length, 0) == -1 && errno == ECONNRESET) {
diff --git a/hci/src/hci_hal_h4.c b/hci/src/hci_hal_h4.c
index 2310a7d..e9364c4 100644
--- a/hci/src/hci_hal_h4.c
+++ b/hci/src/hci_hal_h4.c
@@ -28,10 +28,15 @@
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 #include "osi/include/reactor.h"
+#include "osi/include/thread.h"
 #include "vendor.h"
 
 #define HCI_HAL_SERIAL_BUFFER_SIZE 1026
 
+// Increased HCI thread priority to keep up with the audio sub-system
+// when streaming time sensitive data (A2DP).
+#define HCI_THREAD_PRIORITY -19
+
 // Our interface and modules we import
 static const hci_hal_t interface;
 static const hci_hal_callbacks_t *callbacks;
@@ -84,6 +89,10 @@
   stream_has_interpretation = false;
   eager_reader_register(uart_stream, thread_get_reactor(thread), event_uart_has_bytes, NULL);
 
+  // Raise thread priorities to keep up with audio
+  thread_set_priority(thread, HCI_THREAD_PRIORITY);
+  thread_set_priority(eager_reader_get_read_thread(uart_stream), HCI_THREAD_PRIORITY);
+
   return true;
 
 error:
diff --git a/hci/src/hci_inject.c b/hci/src/hci_inject.c
index ea25fd0..7efb374 100644
--- a/hci/src/hci_inject.c
+++ b/hci/src/hci_inject.c
@@ -62,6 +62,10 @@
 static void client_free(void *ptr);
 
 bool hci_inject_open(const hci_t *hci_interface) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+  return true;          // Disable using network sockets for security reasons
+#endif
+
   assert(listen_socket == NULL);
   assert(thread == NULL);
   assert(clients == NULL);
@@ -93,6 +97,10 @@
 }
 
 void hci_inject_close(void) {
+#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
+  return;               // Disable using network sockets for security reasons
+#endif
+
   socket_free(listen_socket);
   list_free(clients);
   thread_free(thread);
diff --git a/main/Android.mk b/main/Android.mk
index 7a7fb77..ff7b4a5 100644
--- a/main/Android.mk
+++ b/main/Android.mk
@@ -130,6 +130,7 @@
     libcutils \
     libdl \
     liblog \
+    libpower \
     libz
 
 LOCAL_STATIC_LIBRARIES := \
diff --git a/osi/Android.mk b/osi/Android.mk
index f2f5af4..6954cb4 100644
--- a/osi/Android.mk
+++ b/osi/Android.mk
@@ -83,7 +83,7 @@
 LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
 LOCAL_MODULE := libosi
 LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := libc liblog
+LOCAL_SHARED_LIBRARIES := libc liblog libpower
 LOCAL_MODULE_CLASS := STATIC_LIBRARIES
 include $(BUILD_STATIC_LIBRARY)
 
@@ -119,7 +119,7 @@
 LOCAL_CFLAGS := -Wall -UNDEBUG
 LOCAL_MODULE := net_test_osi
 LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libpower
 LOCAL_STATIC_LIBRARIES := libosi
 include $(BUILD_NATIVE_TEST)
 
diff --git a/osi/include/eager_reader.h b/osi/include/eager_reader.h
index 3bf1e6e..a172f06 100644
--- a/osi/include/eager_reader.h
+++ b/osi/include/eager_reader.h
@@ -23,6 +23,7 @@
 #include <stdint.h>
 
 #include "allocator.h"
+#include "osi/include/thread.h"
 
 typedef struct eager_reader_t eager_reader_t;
 typedef struct reactor_t reactor_t;
@@ -61,3 +62,7 @@
 // but you should probably only be reading from one thread anyway,
 // otherwise the byte stream probably doesn't make sense.
 size_t eager_reader_read(eager_reader_t *reader, uint8_t *buffer, size_t max_size, bool block);
+
+// Returns the inbound read thread for a given |reader| or NULL if the thread
+// is not running.
+thread_t* eager_reader_get_read_thread(const eager_reader_t *reader);
diff --git a/osi/include/thread.h b/osi/include/thread.h
index def4aa5..9c4068e 100644
--- a/osi/include/thread.h
+++ b/osi/include/thread.h
@@ -58,6 +58,11 @@
 // |thread| may not be NULL.
 void thread_stop(thread_t *thread);
 
+// Attempts to sets the |priority| of a given |thread|.
+// The |thread| has to be running for this call to succeed.
+// Returns true on success.
+bool thread_set_priority(thread_t *thread, int priority);
+
 // Returns true if the current thread is the same as the one represented by |thread|.
 // |thread| may not be NULL.
 bool thread_is_self(const thread_t *thread);
diff --git a/osi/src/alarm.c b/osi/src/alarm.c
index 8774769..482c151 100644
--- a/osi/src/alarm.c
+++ b/osi/src/alarm.c
@@ -30,6 +30,7 @@
 #include <time.h>
 
 #include <hardware/bluetooth.h>
+#include <hardware_legacy/power.h>
 
 #include "osi/include/allocator.h"
 #include "osi/include/list.h"
@@ -61,6 +62,7 @@
 // unit tests to run faster. It should not be modified by production code.
 int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
 static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
+static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
 static const char *WAKE_LOCK_ID = "bluedroid_timer";
 
 // This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
@@ -69,6 +71,7 @@
 static pthread_mutex_t monitor;
 static list_t *alarms;
 static timer_t timer;
+static timer_t wakeup_timer;
 static bool timer_set;
 
 // All alarm callbacks are dispatched from |callback_thread|
@@ -83,6 +86,7 @@
 static void reschedule_root_alarm(void);
 static void timer_callback(void *data);
 static void callback_dispatch(void *context);
+static bool timer_create_internal(const clockid_t clock_id, timer_t *timer);
 
 alarm_t *alarm_new(void) {
   // Make sure we have a list we can insert alarms into.
@@ -214,38 +218,64 @@
 static bool lazy_initialize(void) {
   assert(alarms == NULL);
 
+  // timer_t doesn't have an invalid value so we must track whether
+  // the |timer| variable is valid ourselves.
+  bool timer_initialized = false;
+  bool wakeup_timer_initialized = false;
+
   pthread_mutex_init(&monitor, NULL);
 
   alarms = list_new(NULL);
   if (!alarms) {
     LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__);
-    return false;
+    goto error;
   }
 
-  struct sigevent sigevent;
-  memset(&sigevent, 0, sizeof(sigevent));
-  sigevent.sigev_notify = SIGEV_THREAD;
-  sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
-  if (timer_create(CLOCK_ID, &sigevent, &timer) == -1) {
-    LOG_ERROR(LOG_TAG, "%s unable to create timer: %s", __func__, strerror(errno));
-    return false;
-  }
+  if (!timer_create_internal(CLOCK_ID, &timer))
+    goto error;
+  timer_initialized = true;
+
+  if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer))
+    goto error;
+  wakeup_timer_initialized = true;
 
   alarm_expired = semaphore_new(0);
   if (!alarm_expired) {
     LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__);
-    return false;
+    goto error;
   }
 
   callback_thread_active = true;
   callback_thread = thread_new("alarm_callbacks");
   if (!callback_thread) {
     LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__);
-    return false;
+    goto error;
   }
 
   thread_post(callback_thread, callback_dispatch, NULL);
   return true;
+
+error:
+  thread_free(callback_thread);
+  callback_thread = NULL;
+
+  callback_thread_active = false;
+
+  semaphore_free(alarm_expired);
+  alarm_expired = NULL;
+
+  if (wakeup_timer_initialized)
+    timer_delete(wakeup_timer);
+
+  if (timer_initialized)
+    timer_delete(timer);
+
+  list_free(alarms);
+  alarms = NULL;
+
+  pthread_mutex_destroy(&monitor);
+
+  return false;
 }
 
 static period_ms_t now(void) {
@@ -292,41 +322,65 @@
 
 // NOTE: must be called with monitor lock.
 static void reschedule_root_alarm(void) {
-  bool timer_was_set = timer_set;
   assert(alarms != NULL);
 
-  // If used in a zeroed state, disarms the timer
-  struct itimerspec wakeup_time;
-  memset(&wakeup_time, 0, sizeof(wakeup_time));
+  const bool timer_was_set = timer_set;
+
+  // If used in a zeroed state, disarms the timer.
+  struct itimerspec timer_time;
+  memset(&timer_time, 0, sizeof(timer_time));
 
   if (list_is_empty(alarms))
     goto done;
 
-  alarm_t *next = list_front(alarms);
-  int64_t next_expiration = next->deadline - now();
+  const alarm_t *next = list_front(alarms);
+  const int64_t next_expiration = next->deadline - now();
   if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) {
     if (!timer_set) {
-      int status = bt_os_callouts->acquire_wake_lock(WAKE_LOCK_ID);
-      if (status != BT_STATUS_SUCCESS) {
+      int status = acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+      if (status != (int) strlen(WAKE_LOCK_ID)) {
         LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock: %d", __func__, status);
         goto done;
       }
     }
 
+    timer_time.it_value.tv_sec = (next->deadline / 1000);
+    timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
+
+    // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec for
+    // timers with *_ALARM clock IDs. Although the man page states that the timer
+    // would be canceled, the current behavior (as of Linux kernel 3.17) is that
+    // the callback is issued immediately. The only way to cancel an *_ALARM timer
+    // is to delete the timer. But unfortunately, deleting and re-creating a timer
+    // is rather expensive; every timer_create(2) spawns a new thread. So we simply
+    // set the timer to fire at the largest possible time.
+    //
+    // If we've reached this code path, we're going to grab a wake lock and wait for
+    // the next timer to fire. In that case, there's no reason to have a pending wakeup
+    // timer so we simply cancel it.
+    struct itimerspec end_of_time;
+    memset(&end_of_time, 0, sizeof(end_of_time));
+    end_of_time.it_value.tv_sec = (time_t)((1ULL << (sizeof(time_t) * 8 - 1)) - 1);
+    timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL);
+  } else {
+    // WARNING: do not attempt to use relative timers with *_ALARM clock IDs
+    // in kernels before 3.17 unless you have the following patch:
+    // https://lkml.org/lkml/2014/7/7/576
+    struct itimerspec wakeup_time;
+    memset(&wakeup_time, 0, sizeof(wakeup_time));
     wakeup_time.it_value.tv_sec = (next->deadline / 1000);
     wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
-  } else {
-    if (!bt_os_callouts->set_wake_alarm(next_expiration, true, timer_callback, NULL))
-      LOG_ERROR(LOG_TAG, "%s unable to set wake alarm for %" PRId64 "ms.", __func__, next_expiration);
+    if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
+      LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", __func__, strerror(errno));
   }
 
 done:
-  timer_set = wakeup_time.it_value.tv_sec != 0 || wakeup_time.it_value.tv_nsec != 0;
+  timer_set = timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0;
   if (timer_was_set && !timer_set) {
-    bt_os_callouts->release_wake_lock(WAKE_LOCK_ID);
+    release_wake_lock(WAKE_LOCK_ID);
   }
 
-  if (timer_settime(timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
+  if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1)
     LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno));
 
   // If next expiration was in the past (e.g. short timer that got context switched)
@@ -400,3 +454,18 @@
 
   LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__);
 }
+
+static bool timer_create_internal(const clockid_t clock_id, timer_t *timer) {
+  assert(timer != NULL);
+
+  struct sigevent sigevent;
+  memset(&sigevent, 0, sizeof(sigevent));
+  sigevent.sigev_notify = SIGEV_THREAD;
+  sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
+  if (timer_create(clock_id, &sigevent, timer) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", __func__, clock_id, strerror(errno));
+    return false;
+  }
+
+  return true;
+}
diff --git a/osi/src/compat.c b/osi/src/compat.c
index ea26c18..4e6f869 100644
--- a/osi/src/compat.c
+++ b/osi/src/compat.c
@@ -30,7 +30,9 @@
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
+
 #include "osi/include/compat.h"
+#include "osi/include/osi.h"
 
 #if __GLIBC__
 pid_t
@@ -129,3 +131,8 @@
   return (dlen + (s - src)); /* count does not include NUL */
 }
 #endif
+
+#if _GNU_SOURCE
+int acquire_wake_lock(UNUSED_ATTR int lock, UNUSED_ATTR const char *id) { return strlen(id); }
+int release_wake_lock(UNUSED_ATTR const char *id) { return 0; }
+#endif
diff --git a/osi/src/eager_reader.c b/osi/src/eager_reader.c
index 78d6eac..6b07561 100644
--- a/osi/src/eager_reader.c
+++ b/osi/src/eager_reader.c
@@ -30,7 +30,6 @@
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 #include "osi/include/reactor.h"
-#include "osi/include/thread.h"
 
 #if !defined(EFD_SEMAPHORE)
 #  define EFD_SEMAPHORE (1 << 0)
@@ -212,6 +211,11 @@
   return bytes_consumed;
 }
 
+thread_t* eager_reader_get_read_thread(const eager_reader_t *reader) {
+  assert(reader != NULL);
+  return reader->inbound_read_thread;
+}
+
 static bool has_byte(const eager_reader_t *reader) {
   assert(reader != NULL);
 
diff --git a/osi/src/thread.c b/osi/src/thread.c
index 9410acb..4386e45 100644
--- a/osi/src/thread.c
+++ b/osi/src/thread.c
@@ -26,6 +26,7 @@
 #include <pthread.h>
 #include <string.h>
 #include <sys/prctl.h>
+#include <sys/resource.h>
 #include <sys/types.h>
 
 #include "osi/include/allocator.h"
@@ -155,6 +156,20 @@
   reactor_stop(thread->reactor);
 }
 
+bool thread_set_priority(thread_t *thread, int priority) {
+  if (!thread)
+    return false;
+
+  const int rc = setpriority(PRIO_PROCESS, thread->tid, priority);
+  if (rc < 0) {
+    LOG_ERROR(LOG_TAG, "%s unable to set thread priority %d for tid %d, error %d",
+      __func__, priority, thread->tid, rc);
+    return false;
+  }
+
+  return true;
+}
+
 bool thread_is_self(const thread_t *thread) {
   assert(thread != NULL);
   return !!pthread_equal(pthread_self(), thread->pthread);
diff --git a/stack/btu/btu_init.c b/stack/btu/btu_init.c
index 8e50b65..8afdf9a 100644
--- a/stack/btu/btu_init.c
+++ b/stack/btu/btu_init.c
@@ -44,6 +44,10 @@
 #endif
 #endif
 
+// Increase BTU task thread priority to avoid pre-emption
+// of audio realated tasks.
+#define BTU_TASK_THREAD_PRIORITY -19
+
 extern fixed_queue_t *btif_msg_queue;
 
 // Communication queue from bta thread to bt_workqueue.
@@ -192,6 +196,8 @@
     if (bt_workqueue_thread == NULL)
         goto error_exit;
 
+    thread_set_priority(bt_workqueue_thread, BTU_TASK_THREAD_PRIORITY);
+
     // Continue startup on bt workqueue thread.
     thread_post(bt_workqueue_thread, btu_task_start_up, NULL);
     return;
diff --git a/test/suite/Android.mk b/test/suite/Android.mk
index 3caec79..6dc45e3 100644
--- a/test/suite/Android.mk
+++ b/test/suite/Android.mk
@@ -42,6 +42,7 @@
     liblog \
     libhardware \
     libhardware_legacy \
+    libpower \
     libcutils
 
 LOCAL_STATIC_LIBRARIES += \
diff --git a/tools/bdtool/Android.mk b/tools/bdtool/Android.mk
index 7ed5c4a..ff2cec7 100644
--- a/tools/bdtool/Android.mk
+++ b/tools/bdtool/Android.mk
@@ -40,6 +40,6 @@
   $(LOCAL_PATH)/../..
 
 LOCAL_SHARED_LIBRARIES += \
-  libhardware liblog
+  libhardware liblog libpower
 
 include $(BUILD_EXECUTABLE)
diff --git a/tools/hci/Android.mk b/tools/hci/Android.mk
index 9477db3..996c68e 100644
--- a/tools/hci/Android.mk
+++ b/tools/hci/Android.mk
@@ -23,6 +23,7 @@
 
 LOCAL_SRC_FILES := main.c
 LOCAL_STATIC_LIBRARIES := libosi
+LOCAL_SHARED_LIBRARIES := libpower
 LOCAL_CFLAGS := -std=c99 $(bdroid_CFLAGS)
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../
 
diff --git a/utils/src/bt_utils.c b/utils/src/bt_utils.c
index 69106a1..6bc429b 100644
--- a/utils/src/bt_utils.c
+++ b/utils/src/bt_utils.c
@@ -157,8 +157,7 @@
     // its prio individually. All other threads can be dynamically adjusted voa
     // adjust_priority_a2dp()
 
-    if (high_task == TASK_HIGH_HCI_WORKER)
-       priority = ANDROID_PRIORITY_URGENT_AUDIO;
+    priority = ANDROID_PRIORITY_URGENT_AUDIO;
 
     if (setpriority(PRIO_PROCESS, tid, priority) < 0) {
         LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);