Raise BTU and HCI thread priorities

The audio sub-system and audio related tasks run at elevated thread
priorities in order to ensure timely handling of audio packets. This
patch raises the thread priority of lower layer Bluetooth tasks involved
in delivering audio packets to avoid thread pre-emption and subsequent
audio skipping.

Bug: 24570959
Change-Id: I5e19ee4590207df753f7b8bfc22174959722ec2d
diff --git a/hci/src/hci_hal_h4.c b/hci/src/hci_hal_h4.c
index 4fc4274..f19755f 100644
--- a/hci/src/hci_hal_h4.c
+++ b/hci/src/hci_hal_h4.c
@@ -27,10 +27,15 @@
 #include "osi/include/osi.h"
 #include "osi/include/log.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;
@@ -83,6 +88,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/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/eager_reader.c b/osi/src/eager_reader.c
index 63b190e..3ca8ad1 100644
--- a/osi/src/eager_reader.c
+++ b/osi/src/eager_reader.c
@@ -30,7 +30,6 @@
 #include "osi/include/osi.h"
 #include "osi/include/log.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 c6c8979..d53d16c 100644
--- a/osi/src/thread.c
+++ b/osi/src/thread.c
@@ -24,6 +24,7 @@
 #include <pthread.h>
 #include <string.h>
 #include <sys/prctl.h>
+#include <sys/resource.h>
 #include <sys/types.h>
 
 #include "osi/include/allocator.h"
@@ -154,6 +155,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("%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 0888cb5..250c1c4 100644
--- a/stack/btu/btu_init.c
+++ b/stack/btu/btu_init.c
@@ -45,6 +45,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.
@@ -193,6 +197,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;