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