Work around race condition between thread shutdown and vendor lib shutdown.

This race condition occurs because of a structural bug - the userial
thread depends on the HCI thread and the HCI thread depends on the
userial thread but both are independently owned and torn down. This
change fixes a crash bug due to the race condition (NULL pointer
access in userial thread).

http://b/16483216

Change-Id: I91ea274856ac72e9d72b92f0dc5c94e53aaf22f4
diff --git a/hci/src/bt_hci_bdroid.c b/hci/src/bt_hci_bdroid.c
index 174cc1f..c38536a 100644
--- a/hci/src/bt_hci_bdroid.c
+++ b/hci/src/bt_hci_bdroid.c
@@ -83,6 +83,7 @@
 typedef struct
 {
     thread_t        *worker_thread;
+    pthread_mutex_t worker_thread_lock;
     bool            epilog_timer_created;
     timer_t         epilog_timer_id;
 } bt_hc_cb_t;
@@ -213,17 +214,33 @@
 }
 
 void bthc_rx_ready(void) {
-  thread_post(hc_cb.worker_thread, event_rx, NULL);
+  pthread_mutex_lock(&hc_cb.worker_thread_lock);
+
+  if (hc_cb.worker_thread)
+    thread_post(hc_cb.worker_thread, event_rx, NULL);
+
+  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
 }
 
 void bthc_tx(HC_BT_HDR *buf) {
-  if (buf)
-    utils_enqueue(&tx_q, buf);
-  thread_post(hc_cb.worker_thread, event_tx, NULL);
+  pthread_mutex_lock(&hc_cb.worker_thread_lock);
+
+  if (hc_cb.worker_thread) {
+    if (buf)
+      utils_enqueue(&tx_q, buf);
+    thread_post(hc_cb.worker_thread, event_tx, NULL);
+  }
+
+  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
 }
 
 void bthc_idle_timeout(void) {
-  thread_post(hc_cb.worker_thread, event_lpm_idle_timeout, NULL);
+  pthread_mutex_lock(&hc_cb.worker_thread_lock);
+
+  if (hc_cb.worker_thread)
+    thread_post(hc_cb.worker_thread, event_lpm_idle_timeout, NULL);
+
+  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
 }
 
 /*******************************************************************************
@@ -238,8 +255,12 @@
 static void epilog_wait_timeout(UNUSED_ATTR union sigval arg)
 {
     ALOGI("...epilog_wait_timeout...");
+
     thread_free(hc_cb.worker_thread);
+
+    pthread_mutex_lock(&hc_cb.worker_thread_lock);
     hc_cb.worker_thread = NULL;
+    pthread_mutex_unlock(&hc_cb.worker_thread_lock);
 }
 
 /*******************************************************************************
@@ -305,6 +326,8 @@
     hc_cb.epilog_timer_created = false;
     fwcfg_acked = false;
 
+    pthread_mutex_init(&hc_cb.worker_thread_lock, NULL);
+
     /* store reference to user callbacks */
     bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb;
 
@@ -437,7 +460,10 @@
         }
 
         thread_free(hc_cb.worker_thread);
+
+        pthread_mutex_lock(&hc_cb.worker_thread_lock);
         hc_cb.worker_thread = NULL;
+        pthread_mutex_unlock(&hc_cb.worker_thread_lock);
 
         if (hc_cb.epilog_timer_created)
         {
@@ -454,6 +480,8 @@
     set_power(BT_VND_PWR_OFF);
     vendor_close();
 
+    pthread_mutex_destroy(&hc_cb.worker_thread_lock);
+
     fwcfg_acked = false;
     bt_hc_cbacks = NULL;
 }