From 63d2fa3e785424d537b1a8cfe8bcb2c0026725ef Mon Sep 17 00:00:00 2001
From: Jack He <siyuanh@google.com>
Date: Wed, 25 Jul 2018 21:43:01 -0700
Subject: [PATCH] Use MessageLoopThread in A2DP source, JNI, BTA, HCI and
 module bring-up

* Replace OSI thread with MessageLoopThread in
  - btif_a2dp_source (A2DP encoding thread)
  - btif_core (JNI thread)
  - btu_init (BTA thread)
  - hci_layer (HCI thread)
  - module (module bring up thread)
  - various unit test threads
* Code that uses reactor from OSI thread is not replaced in this change
  because they need to move from using reactor to message loop first
* Main difference:
  - HCI layer no longer has access to mutex protecting message loop
    set up and tear down. Messages posted to thread after ShutDown()
    is called become no-op
  - In all cases QuitClosure() is used instead of QuitWhenIdleClosure().
    This means that we will never force kill a thread. An infinite loop
    will delay the shutdown of Bluetooth stack.
* do_in_hci_thread is actually do_in_bta_thread
* Move the definition of do_in_bta_thread from bta to btu since btu is
  where the thread actually lives
* Remove bta_closure_api.h and replace it with stack/include/btu.h
* Remove header inclusion in bta_sys.h and include stack/include/btu.h
  in individual compilation units
* Fixed a bug in btif_cleanup_bluetooth where btif_jni_disassociate()
  was not called on the JNI thread
* Make setting real time priority a requirement
* Crash during the following scenario:
  - When btif_profile_queue cleanup failed to be scheduled on JNI thread
  - When A2DP encoder thread failed to gain real time priority
  - When BTA thread failed to start up
  - When BTA thread failed to gain real time priority
  - When BTA thread failed to schedule its first callback
* Turn off Bluetooth in the following scenario:
  - When HCI thread failed to gain real time priority
  - When bt_workqueue thread failed to gain real time priority

Bug: 110303473
Test: make, native and Java unit tests,
      Connect to headset and listen to music through A2DP,
      testplans/details/184455/3975
Change-Id: Ib448992fc0ba5af82c2d117dd65f1abd45d2acb6
---
 system/bta/ag/bta_ag_api.cc                  |   1 +
 system/bta/ag/bta_ag_rfc.cc                  |   1 +
 system/bta/ag/bta_ag_sco.cc                  |   1 +
 system/bta/ag/bta_ag_sdp.cc                  |   1 +
 system/bta/dm/bta_dm_api.cc                  |   2 +-
 system/bta/dm/bta_dm_ci.cc                   |   3 +-
 system/bta/dm/bta_dm_pm.cc                   |   1 +
 system/bta/gatt/bta_gattc_act.cc             |   2 +-
 system/bta/gatt/bta_gattc_api.cc             |   2 +-
 system/bta/gatt/bta_gatts_api.cc             |   2 +-
 system/bta/include/bta_closure_api.h         |  38 ------
 system/bta/jv/bta_jv_api.cc                  |   2 +-
 system/bta/sys/bta_sys.h                     |   2 -
 system/bta/sys/bta_sys_main.cc               |  36 ------
 system/btcore/include/module.h               |   7 +-
 system/btcore/src/module.cc                  |  75 +++++------
 system/btif/Android.bp                       |   1 +
 system/btif/avrcp/avrcp_service.cc           |   2 +-
 system/btif/include/btif_common.h            |   4 +-
 system/btif/src/btif_a2dp_audio_interface.cc |   1 +
 system/btif/src/btif_a2dp_source.cc          | 104 ++-------------
 system/btif/src/btif_av.cc                   |   1 -
 system/btif/src/btif_ble_advertiser.cc       |   2 +-
 system/btif/src/btif_ble_scanner.cc          |   2 +-
 system/btif/src/btif_core.cc                 | 126 +++++--------------
 system/btif/src/btif_dm.cc                   |   1 -
 system/btif/src/btif_gatt_client.cc          |   2 +-
 system/btif/src/btif_gatt_server.cc          |   2 +-
 system/btif/src/btif_hearing_aid.cc          |   2 +-
 system/btif/src/btif_pan.cc                  |   2 +-
 system/btif/src/btif_profile_queue.cc        |   3 +-
 system/btif/src/btif_storage.cc              |   1 -
 system/btif/src/stack_manager.cc             |  55 ++++----
 system/btif/test/btif_profile_queue_test.cc  |   4 +-
 system/hci/src/hci_layer.cc                  |  85 ++++---------
 system/main/Android.bp                       |   1 +
 system/main/bte_main.cc                      |   1 -
 system/osi/Android.bp                        |   1 +
 system/osi/test/alarm_test.cc                |  36 ++----
 system/osi/test/future_test.cc               |  11 +-
 system/osi/test/semaphore_test.cc            |  14 ++-
 system/stack/Android.bp                      |   2 +
 system/stack/btm/btm_devctl.cc               |   8 +-
 system/stack/btu/btu_hcif.cc                 |  20 +--
 system/stack/btu/btu_init.cc                 |  59 ++++-----
 system/stack/btu/btu_task.cc                 |  57 ++++-----
 system/stack/include/btu.h                   |   3 +
 system/stack/test/stack_btu_test.cc          |  15 +--
 48 files changed, 246 insertions(+), 558 deletions(-)
 delete mode 100644 system/bta/include/bta_closure_api.h

diff --git a/system/bta/ag/bta_ag_api.cc b/system/bta/ag/bta_ag_api.cc
index 7497fa75fb3..7bd475283ce 100644
--- a/system/bta/ag/bta_ag_api.cc
+++ b/system/bta/ag/bta_ag_api.cc
@@ -31,6 +31,7 @@
 #include "bta_ag_int.h"
 #include "bta_api.h"
 #include "bta_sys.h"
+#include "stack/include/btu.h"
 
 /*****************************************************************************
  *  Constants
diff --git a/system/bta/ag/bta_ag_rfc.cc b/system/bta/ag/bta_ag_rfc.cc
index ba9bd7fbdf7..14f11169a03 100644
--- a/system/bta/ag/bta_ag_rfc.cc
+++ b/system/bta/ag/bta_ag_rfc.cc
@@ -34,6 +34,7 @@
 #include "osi/include/osi.h"
 #include "port_api.h"
 #include "rfcdefs.h"
+#include "stack/include/btu.h"
 #include "utl.h"
 
 /* Event mask for RfCOMM port callback */
diff --git a/system/bta/ag/bta_ag_sco.cc b/system/bta/ag/bta_ag_sco.cc
index 1ff4c7eed93..8e51e874593 100644
--- a/system/bta/ag/bta_ag_sco.cc
+++ b/system/bta/ag/bta_ag_sco.cc
@@ -32,6 +32,7 @@
 #include "device/include/controller.h"
 #include "device/include/esco_parameters.h"
 #include "osi/include/osi.h"
+#include "stack/include/btu.h"
 #include "utl.h"
 
 /* Codec negotiation timeout */
diff --git a/system/bta/ag/bta_ag_sdp.cc b/system/bta/ag/bta_ag_sdp.cc
index 8ff39fd78f5..2ae56a2bdc9 100644
--- a/system/bta/ag/bta_ag_sdp.cc
+++ b/system/bta/ag/bta_ag_sdp.cc
@@ -36,6 +36,7 @@
 #include "btm_api.h"
 #include "osi/include/osi.h"
 #include "sdp_api.h"
+#include "stack/include/btu.h"
 #include "utl.h"
 
 using bluetooth::Uuid;
diff --git a/system/bta/dm/bta_dm_api.cc b/system/bta/dm/bta_dm_api.cc
index 0740da0d2b5..b3e3a46f74e 100644
--- a/system/bta/dm/bta_dm_api.cc
+++ b/system/bta/dm/bta_dm_api.cc
@@ -26,13 +26,13 @@
 
 #include "bt_common.h"
 #include "bta_api.h"
-#include "bta_closure_api.h"
 #include "bta_dm_int.h"
 #include "bta_sys.h"
 #include "bta_sys_int.h"
 #include "btm_api.h"
 #include "btm_int.h"
 #include "osi/include/osi.h"
+#include "stack/include/btu.h"
 #include "utl.h"
 
 using bluetooth::Uuid;
diff --git a/system/bta/dm/bta_dm_ci.cc b/system/bta/dm/bta_dm_ci.cc
index 16174c0ad2d..968c3d59eb9 100644
--- a/system/bta/dm/bta_dm_ci.cc
+++ b/system/bta/dm/bta_dm_ci.cc
@@ -21,11 +21,12 @@
  *  This is the API implementation file for the BTA device manager.
  *
  ******************************************************************************/
+#include "bta_dm_ci.h"
 #include "bt_common.h"
 #include "bta_api.h"
-#include "bta_dm_ci.h"
 #include "bta_dm_int.h"
 #include "bta_sys.h"
+#include "stack/include/btu.h"
 
 #include <base/bind.h>
 #include <memory>
diff --git a/system/bta/dm/bta_dm_pm.cc b/system/bta/dm/bta_dm_pm.cc
index 731d2531202..03b1801a197 100644
--- a/system/bta/dm/bta_dm_pm.cc
+++ b/system/bta/dm/bta_dm_pm.cc
@@ -35,6 +35,7 @@
 #include "bta_dm_int.h"
 #include "bta_sys.h"
 #include "btm_api.h"
+#include "stack/include/btu.h"
 
 static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
                             uint8_t app_id, const RawAddress& peer_addr);
diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc
index cb9d1586a59..d49cd7f1634 100644
--- a/system/bta/gatt/bta_gattc_act.cc
+++ b/system/bta/gatt/bta_gattc_act.cc
@@ -30,13 +30,13 @@
 #include <base/callback.h>
 #include "bt_common.h"
 #include "bt_target.h"
-#include "bta_closure_api.h"
 #include "bta_gattc_int.h"
 #include "bta_sys.h"
 #include "btif/include/btif_debug_conn.h"
 #include "l2c_api.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
+#include "stack/include/btu.h"
 #include "stack/l2cap/l2c_int.h"
 #include "utl.h"
 
diff --git a/system/bta/gatt/bta_gattc_api.cc b/system/bta/gatt/bta_gattc_api.cc
index c60d2993e81..eac97696ff8 100644
--- a/system/bta/gatt/bta_gattc_api.cc
+++ b/system/bta/gatt/bta_gattc_api.cc
@@ -30,11 +30,11 @@
 #include <base/bind_helpers.h>
 #include <base/callback.h>
 #include "bt_common.h"
-#include "bta_closure_api.h"
 #include "bta_gatt_api.h"
 #include "bta_gattc_int.h"
 #include "bta_sys.h"
 #include "device/include/controller.h"
+#include "stack/include/btu.h"
 
 using bluetooth::Uuid;
 
diff --git a/system/bta/gatt/bta_gatts_api.cc b/system/bta/gatt/bta_gatts_api.cc
index 9d7cda0d6e2..67e65e15932 100644
--- a/system/bta/gatt/bta_gatts_api.cc
+++ b/system/bta/gatt/bta_gatts_api.cc
@@ -28,10 +28,10 @@
 #include <string.h>
 
 #include "bt_common.h"
-#include "bta_closure_api.h"
 #include "bta_gatt_api.h"
 #include "bta_gatts_int.h"
 #include "bta_sys.h"
+#include "stack/include/btu.h"
 
 /*****************************************************************************
  *  Constants
diff --git a/system/bta/include/bta_closure_api.h b/system/bta/include/bta_closure_api.h
deleted file mode 100644
index a4c0188cf1e..00000000000
--- a/system/bta/include/bta_closure_api.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/******************************************************************************
- *
- *  Copyright 2016 The Android Open Source Project
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at:
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- ******************************************************************************/
-
-#ifndef BTA_CLOSURE_API_H
-#define BTA_CLOSURE_API_H
-
-#include <base/bind.h>
-#include <base/callback_forward.h>
-#include <base/location.h>
-
-#include <hardware/bluetooth.h>
-
-/*
- * This method post a closure for execution on bta thread. Please see
- * documentation at
- * https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures
- * for how to handle dynamic memory ownership/smart pointers with base::Owned(),
- * base::Passed(), base::ConstRef() and others.
- */
-bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
-                             const base::Closure& task);
-
-#endif /* BTA_CLOSURE_API_H */
diff --git a/system/bta/jv/bta_jv_api.cc b/system/bta/jv/bta_jv_api.cc
index 74818b6a981..40165864008 100644
--- a/system/bta/jv/bta_jv_api.cc
+++ b/system/bta/jv/bta_jv_api.cc
@@ -29,13 +29,13 @@
 
 #include "bt_common.h"
 #include "bta_api.h"
-#include "bta_closure_api.h"
 #include "bta_jv_api.h"
 #include "bta_jv_int.h"
 #include "bta_sys.h"
 #include "gap_api.h"
 #include "port_api.h"
 #include "sdp_api.h"
+#include "stack/include/btu.h"
 #include "utl.h"
 
 using base::Bind;
diff --git a/system/bta/sys/bta_sys.h b/system/bta/sys/bta_sys.h
index a72f34b0950..ff1d0626570 100644
--- a/system/bta/sys/bta_sys.h
+++ b/system/bta/sys/bta_sys.h
@@ -31,8 +31,6 @@
 #include <base/logging.h>
 #include <base/threading/thread.h>
 
-#include "bta/include/bta_closure_api.h"
-
 /*****************************************************************************
  *  Constants and data types
  ****************************************************************************/
diff --git a/system/bta/sys/bta_sys_main.cc b/system/bta/sys/bta_sys_main.cc
index bdedcde78dd..7088214432f 100644
--- a/system/bta/sys/bta_sys_main.cc
+++ b/system/bta/sys/bta_sys_main.cc
@@ -26,8 +26,6 @@
 
 #include <base/bind.h>
 #include <base/logging.h>
-#include <base/threading/thread.h>
-#include <pthread.h>
 #include <string.h>
 
 #include "bt_common.h"
@@ -40,7 +38,6 @@
 #include "osi/include/fixed_queue.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
-#include "osi/include/thread.h"
 #include "utl.h"
 
 #if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == TRUE)
@@ -50,8 +47,6 @@
 /* system manager control block definition */
 tBTA_SYS_CB bta_sys_cb;
 
-extern thread_t* bt_workqueue_thread;
-
 /* trace level */
 /* TODO Hard-coded trace levels -  Needs to be configurable */
 uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING;  // APPL_INITIAL_TRACE_LEVEL;
@@ -541,37 +536,6 @@ void bta_sys_sendmsg(void* p_msg) {
       FROM_HERE, base::Bind(&bta_sys_event, static_cast<BT_HDR*>(p_msg)));
 }
 
-/*******************************************************************************
- *
- * Function         do_in_bta_thread
- *
- * Description      Post a closure to be ran in the bta thread
- *
- * Returns          BT_STATUS_SUCCESS on success
- *
- ******************************************************************************/
-bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
-                             const base::Closure& task) {
-  base::MessageLoop* bta_message_loop = get_message_loop();
-  if (!bta_message_loop) {
-    APPL_TRACE_ERROR("%s: MessageLooper not initialized", __func__);
-    return BT_STATUS_FAIL;
-  }
-
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-      bta_message_loop->task_runner();
-  if (!task_runner.get()) {
-    APPL_TRACE_ERROR("%s: task runner is dead", __func__);
-    return BT_STATUS_FAIL;
-  }
-
-  if (!task_runner->PostTask(from_here, task)) {
-    APPL_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
-    return BT_STATUS_FAIL;
-  }
-  return BT_STATUS_SUCCESS;
-}
-
 /*******************************************************************************
  *
  * Function         bta_sys_start_timer
diff --git a/system/btcore/include/module.h b/system/btcore/include/module.h
index 949d1473359..ca1d8b41f99 100644
--- a/system/btcore/include/module.h
+++ b/system/btcore/include/module.h
@@ -20,6 +20,7 @@
 
 #include <stdbool.h>
 
+#include "common/message_loop_thread.h"
 #include "osi/include/future.h"
 #include "osi/include/thread.h"
 
@@ -63,6 +64,6 @@ void module_clean_up(const module_t* module);
 // has finished, |callback| is called within the context of |callback_thread|
 // with |FUTURE_SUCCESS| or |FUTURE_FAIL| depending on whether startup succeeded
 // or not.
-void module_start_up_callbacked_wrapper(const module_t* module,
-                                        thread_t* callback_thread,
-                                        thread_fn callback);
+void module_start_up_callbacked_wrapper(
+    const module_t* module,
+    bluetooth::common::MessageLoopThread* callback_thread, thread_fn callback);
diff --git a/system/btcore/src/module.cc b/system/btcore/src/module.cc
index 88d4f80f25c..8f8e5f06976 100644
--- a/system/btcore/src/module.cc
+++ b/system/btcore/src/module.cc
@@ -26,10 +26,13 @@
 #include <unordered_map>
 
 #include "btcore/include/module.h"
+#include "common/message_loop_thread.h"
 #include "osi/include/allocator.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 
+using bluetooth::common::MessageLoopThread;
+
 typedef enum {
   MODULE_STATE_NONE = 0,
   MODULE_STATE_INITIALIZED = 1,
@@ -159,55 +162,45 @@ static void set_module_state(const module_t* module, module_state_t state) {
 
 // TODO(zachoverflow): remove when everything modulized
 // Temporary callback-wrapper-related code
-
-typedef struct {
+class CallbackWrapper {
+ public:
+  explicit CallbackWrapper(const module_t* module,
+                           MessageLoopThread* callback_thread,
+                           thread_fn callback)
+      : module(module),
+        lifecycle_thread("module_wrapper"),
+        callback_thread(callback_thread),
+        callback(callback),
+        success(false) {}
   const module_t* module;
-  thread_t* lifecycle_thread;
-  thread_t* callback_thread;  // we don't own this thread
+  MessageLoopThread lifecycle_thread;
+  // we don't own this thread
+  MessageLoopThread* callback_thread;
   thread_fn callback;
   bool success;
-} callbacked_wrapper_t;
-
-static void run_wrapped_start_up(void* context);
-static void post_result_to_callback(void* context);
+};
 
-void module_start_up_callbacked_wrapper(const module_t* module,
-                                        thread_t* callback_thread,
-                                        thread_fn callback) {
-  callbacked_wrapper_t* wrapper =
-      (callbacked_wrapper_t*)osi_calloc(sizeof(callbacked_wrapper_t));
-
-  wrapper->module = module;
-  wrapper->lifecycle_thread = thread_new("module_wrapper");
-  wrapper->callback_thread = callback_thread;
-  wrapper->callback = callback;
-
-  // Run the actual module start up
-  thread_post(wrapper->lifecycle_thread, run_wrapped_start_up, wrapper);
+static void post_result_to_callback(std::shared_ptr<CallbackWrapper> wrapper) {
+  CHECK(wrapper);
+  wrapper->lifecycle_thread.ShutDown();
+  wrapper->callback(wrapper->success ? FUTURE_SUCCESS : FUTURE_FAIL);
 }
 
-static void run_wrapped_start_up(void* context) {
-  CHECK(context);
-
-  callbacked_wrapper_t* wrapper = (callbacked_wrapper_t*)context;
+static void run_wrapped_start_up(std::shared_ptr<CallbackWrapper> wrapper) {
+  CHECK(wrapper);
   wrapper->success = module_start_up(wrapper->module);
-
   // Post the result back to the callback
-  thread_post(wrapper->callback_thread, post_result_to_callback, wrapper);
+  wrapper->callback_thread->DoInThread(
+      FROM_HERE, base::BindOnce(post_result_to_callback, wrapper));
 }
 
-static void post_result_to_callback(void* context) {
-  CHECK(context);
-
-  callbacked_wrapper_t* wrapper = (callbacked_wrapper_t*)context;
-
-  // Save the values we need for callback
-  void* result = wrapper->success ? FUTURE_SUCCESS : FUTURE_FAIL;
-  thread_fn callback = wrapper->callback;
-
-  // Clean up the resources we used
-  thread_free(wrapper->lifecycle_thread);
-  osi_free(wrapper);
-
-  callback(result);
+void module_start_up_callbacked_wrapper(const module_t* module,
+                                        MessageLoopThread* callback_thread,
+                                        thread_fn callback) {
+  std::shared_ptr<CallbackWrapper> wrapper =
+      std::make_shared<CallbackWrapper>(module, callback_thread, callback);
+  wrapper->lifecycle_thread.StartUp();
+  // Run the actual module start up
+  wrapper->lifecycle_thread.DoInThread(
+      FROM_HERE, base::BindOnce(run_wrapped_start_up, wrapper));
 }
diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index 3af4a7aa6d0..5887463a345 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -131,6 +131,7 @@ cc_test {
     static_libs: [
         "libbt-bta",
         "libbtcore",
+        "libbt-common",
         "libbt-stack",
         "libbt-sbc-encoder",
         "libbt-utils",
diff --git a/system/btif/avrcp/avrcp_service.cc b/system/btif/avrcp/avrcp_service.cc
index 186866b78d3..e30ff647d31 100644
--- a/system/btif/avrcp/avrcp_service.cc
+++ b/system/btif/avrcp/avrcp_service.cc
@@ -23,10 +23,10 @@
 #include <mutex>
 #include <sstream>
 
-#include "bta_closure_api.h"
 #include "btif_av.h"
 #include "btif_common.h"
 #include "device.h"
+#include "stack/include/btu.h"
 
 namespace bluetooth {
 namespace avrcp {
diff --git a/system/btif/include/btif_common.h b/system/btif/include/btif_common.h
index af0beb0c584..9ceaac68890 100644
--- a/system/btif/include/btif_common.h
+++ b/system/btif/include/btif_common.h
@@ -174,9 +174,9 @@ typedef struct {
  *  Functions
  ******************************************************************************/
 
-extern bt_status_t do_in_jni_thread(const base::Closure& task);
+extern bt_status_t do_in_jni_thread(base::OnceClosure task);
 extern bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
-                                    const base::Closure& task);
+                                    base::OnceClosure task);
 extern bool is_on_jni_thread();
 extern base::MessageLoop* get_jni_message_loop();
 /**
diff --git a/system/btif/src/btif_a2dp_audio_interface.cc b/system/btif/src/btif_a2dp_audio_interface.cc
index 944318e8a3f..ff0312993f0 100644
--- a/system/btif/src/btif_a2dp_audio_interface.cc
+++ b/system/btif/src/btif_a2dp_audio_interface.cc
@@ -42,6 +42,7 @@
 #include "btif_hf.h"
 #include "osi/include/metrics.h"
 #include "osi/include/osi.h"
+#include "stack/include/btu.h"
 
 using system_bt_osi::A2dpSessionMetrics;
 using system_bt_osi::BluetoothMetricsLogger;
diff --git a/system/btif/src/btif_a2dp_source.cc b/system/btif/src/btif_a2dp_source.cc
index efd842b7f9e..a385c6a5314 100644
--- a/system/btif/src/btif_a2dp_source.cc
+++ b/system/btif/src/btif_a2dp_source.cc
@@ -39,17 +39,14 @@
 #include "btif_av.h"
 #include "btif_av_co.h"
 #include "btif_util.h"
+#include "common/message_loop_thread.h"
 #include "osi/include/fixed_queue.h"
 #include "osi/include/log.h"
 #include "osi/include/metrics.h"
 #include "osi/include/osi.h"
-#include "osi/include/thread.h"
 #include "osi/include/time.h"
 #include "uipc.h"
 
-#include <condition_variable>
-#include <mutex>
-
 using system_bt_osi::BluetoothMetricsLogger;
 using system_bt_osi::A2dpSessionMetrics;
 
@@ -165,95 +162,6 @@ class BtifMediaStats {
   int codec_index = -1;
 };
 
-class BtWorkerThread {
- public:
-  BtWorkerThread(const std::string& thread_name)
-      : thread_name_(thread_name),
-        message_loop_(nullptr),
-        run_loop_(nullptr),
-        message_loop_thread_(nullptr),
-        started_(false) {}
-
-  void StartUp() {
-    if (message_loop_thread_ != nullptr) {
-      return;  // Already started up
-    }
-    message_loop_thread_ = thread_new(thread_name_.c_str());
-    CHECK(message_loop_thread_ != nullptr);
-    started_ = false;
-    thread_post(message_loop_thread_, &BtWorkerThread::RunThread, this);
-    {
-      // Block until run_loop_ is allocated and ready to run
-      std::unique_lock<std::mutex> start_lock(start_up_mutex_);
-      while (!started_) {
-        start_up_cv_.wait(start_lock);
-      }
-    }
-  }
-
-  bool DoInThread(const tracked_objects::Location& from_here,
-                  const base::Closure& task) {
-    if ((message_loop_ == nullptr) || !message_loop_->task_runner().get()) {
-      LOG_ERROR(
-          LOG_TAG,
-          "%s: Dropping message for thread %s: message loop is not initialized",
-          __func__, thread_name_.c_str());
-      return false;
-    }
-    if (!message_loop_->task_runner()->PostTask(from_here, task)) {
-      LOG_ERROR(LOG_TAG,
-                "%s: Posting task to message loop for thread %s failed",
-                __func__, thread_name_.c_str());
-      return false;
-    }
-    return true;
-  }
-
-  void ShutDown() {
-    if ((run_loop_ != nullptr) && (message_loop_ != nullptr)) {
-      message_loop_->task_runner()->PostTask(FROM_HERE,
-                                             run_loop_->QuitClosure());
-    }
-    thread_free(message_loop_thread_);
-    message_loop_thread_ = nullptr;
-  }
-
- private:
-  static void RunThread(void* context) {
-    auto wt = static_cast<BtWorkerThread*>(context);
-    wt->Run();
-  }
-
-  void Run() {
-    LOG_INFO(LOG_TAG, "%s: message loop for thread %s started", __func__,
-             thread_name_.c_str());
-    message_loop_ = new base::MessageLoop();
-    run_loop_ = new base::RunLoop();
-    {
-      std::unique_lock<std::mutex> start_lock(start_up_mutex_);
-      started_ = true;
-      start_up_cv_.notify_all();
-    }
-    // Blocking util ShutDown() is called
-    run_loop_->Run();
-    delete message_loop_;
-    message_loop_ = nullptr;
-    delete run_loop_;
-    run_loop_ = nullptr;
-    LOG_INFO(LOG_TAG, "%s: message loop for thread %s finished", __func__,
-             thread_name_.c_str());
-  }
-
-  std::string thread_name_;
-  base::MessageLoop* message_loop_;
-  base::RunLoop* run_loop_;
-  thread_t* message_loop_thread_;
-  // For start-up
-  bool started_;
-  std::mutex start_up_mutex_;
-  std::condition_variable start_up_cv_;
-};
-
 class BtifA2dpSource {
  public:
   enum RunState {
@@ -312,7 +220,8 @@ class BtifA2dpSource {
   BtifA2dpSource::RunState state_;
 };
 
-static BtWorkerThread btif_a2dp_source_thread("btif_a2dp_source_thread");
+static bluetooth::common::MessageLoopThread btif_a2dp_source_thread(
+    "btif_a2dp_source_thread");
 static BtifA2dpSource btif_a2dp_source_cb;
 
 static void btif_a2dp_source_init_delayed(void);
@@ -439,11 +348,12 @@ bool btif_a2dp_source_startup(void) {
   return true;
 }
 
-static void btif_a2dp_source_startup_delayed(void) {
+static void btif_a2dp_source_startup_delayed() {
   LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
            btif_a2dp_source_cb.StateStr().c_str());
-
-  raise_priority_a2dp(TASK_HIGH_MEDIA);
+  if (!btif_a2dp_source_thread.EnableRealTimeScheduling()) {
+    LOG(FATAL) << __func__ << ": unable to enable real time scheduling";
+  }
   btif_a2dp_control_init();
   btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateRunning);
 }
diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc
index 8d416c132e2..92abb220b42 100644
--- a/system/btif/src/btif_av.cc
+++ b/system/btif/src/btif_av.cc
@@ -34,7 +34,6 @@
 #include "bt_common.h"
 #include "bt_utils.h"
 #include "bta/include/bta_api.h"
-#include "bta/include/bta_closure_api.h"
 #include "btif/include/btif_a2dp_source.h"
 #include "btif_a2dp.h"
 #include "btif_a2dp_audio_interface.h"
diff --git a/system/btif/src/btif_ble_advertiser.cc b/system/btif/src/btif_ble_advertiser.cc
index e24bcde2b53..d11e7337289 100644
--- a/system/btif/src/btif_ble_advertiser.cc
+++ b/system/btif/src/btif_ble_advertiser.cc
@@ -25,8 +25,8 @@
 #include <vector>
 
 #include "ble_advertiser.h"
-#include "bta_closure_api.h"
 #include "btif_common.h"
+#include "stack/include/btu.h"
 
 using base::Bind;
 using base::Owned;
diff --git a/system/btif/src/btif_ble_scanner.cc b/system/btif/src/btif_ble_scanner.cc
index 2587c8d8301..493bd1c511d 100644
--- a/system/btif/src/btif_ble_scanner.cc
+++ b/system/btif/src/btif_ble_scanner.cc
@@ -35,7 +35,6 @@
 
 #include "advertise_data_parser.h"
 #include "bta_api.h"
-#include "bta_closure_api.h"
 #include "bta_gatt_api.h"
 #include "btif_config.h"
 #include "btif_dm.h"
@@ -43,6 +42,7 @@
 #include "btif_gatt_util.h"
 #include "btif_storage.h"
 #include "osi/include/log.h"
+#include "stack/include/btu.h"
 #include "vendor_api.h"
 
 using base::Bind;
diff --git a/system/btif/src/btif_core.cc b/system/btif/src/btif_core.cc
index 9fa4590cd4e..d2d8865d2f5 100644
--- a/system/btif/src/btif_core.cc
+++ b/system/btif/src/btif_core.cc
@@ -46,7 +46,6 @@
 #include "bt_common.h"
 #include "bt_utils.h"
 #include "bta_api.h"
-#include "bta_closure_api.h"
 #include "bte.h"
 #include "btif_api.h"
 #include "btif_av.h"
@@ -58,17 +57,18 @@
 #include "btif_uid.h"
 #include "btif_util.h"
 #include "btu.h"
+#include "common/message_loop_thread.h"
 #include "device/include/controller.h"
 #include "osi/include/fixed_queue.h"
 #include "osi/include/future.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 #include "osi/include/properties.h"
-#include "osi/include/thread.h"
 #include "stack_manager.h"
 
 using base::PlatformThread;
 using bluetooth::Uuid;
+using bluetooth::common::MessageLoopThread;
 
 /*******************************************************************************
  *  Constants & Macros
@@ -128,12 +128,9 @@ static tBTA_SERVICE_MASK btif_enabled_services = 0;
  */
 static uint8_t btif_dut_mode = 0;
 
-static thread_t* bt_jni_workqueue_thread;
-static const char* BT_JNI_WORKQUEUE_NAME = "bt_jni_workqueue";
-static uid_set_t* uid_set = NULL;
-base::MessageLoop* message_loop_ = NULL;
-base::RunLoop* jni_run_loop = NULL;
-static base::PlatformThreadId btif_thread_id_ = -1;
+static MessageLoopThread bt_jni_workqueue_thread("bt_jni_workqueue");
+static base::AtExitManager* exit_manager;
+static uid_set_t* uid_set;
 
 /*******************************************************************************
  *  Static functions
@@ -224,35 +221,25 @@ bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
  * the JNI message loop.
  **/
 bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
-                             const base::Closure& task) {
-  if (!message_loop_) {
-    BTIF_TRACE_WARNING("%s: Dropped message, message_loop not initialized yet!",
-                       __func__);
+                             base::OnceClosure task) {
+  if (!bt_jni_workqueue_thread.DoInThread(from_here, std::move(task))) {
+    LOG(ERROR) << __func__ << ": Post task to task runner failed!";
     return BT_STATUS_FAIL;
   }
-
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-      message_loop_->task_runner();
-  if (!task_runner.get()) {
-    BTIF_TRACE_WARNING("%s: task runner is dead", __func__);
-    return BT_STATUS_FAIL;
-  }
-
-  if (task_runner->PostTask(from_here, task)) return BT_STATUS_SUCCESS;
-
-  BTIF_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
-  return BT_STATUS_FAIL;
+  return BT_STATUS_SUCCESS;
 }
 
-bt_status_t do_in_jni_thread(const base::Closure& task) {
-  return do_in_jni_thread(FROM_HERE, task);
+bt_status_t do_in_jni_thread(base::OnceClosure task) {
+  return do_in_jni_thread(FROM_HERE, std::move(task));
 }
 
 bool is_on_jni_thread() {
-  return btif_thread_id_ == PlatformThread::CurrentId();
+  return bt_jni_workqueue_thread.GetThreadId() == PlatformThread::CurrentId();
 }
 
-base::MessageLoop* get_jni_message_loop() { return message_loop_; }
+base::MessageLoop* get_jni_message_loop() {
+  return bt_jni_workqueue_thread.message_loop();
+}
 
 /*******************************************************************************
  *
@@ -260,11 +247,11 @@ base::MessageLoop* get_jni_message_loop() { return message_loop_; }
  *
  * Description      checks if BTIF is currently in DUT mode
  *
- * Returns          1 if test mode, otherwize 0
+ * Returns          true if test mode, otherwise false
  *
  ******************************************************************************/
 
-uint8_t btif_is_dut_mode(void) { return (btif_dut_mode == 1); }
+bool btif_is_dut_mode() { return btif_dut_mode == 1; }
 
 /*******************************************************************************
  *
@@ -327,38 +314,6 @@ void btif_sendmsg(void* p_msg) {
   do_in_jni_thread(base::Bind(&bt_jni_msg_ready, p_msg));
 }
 
-void btif_thread_post(thread_fn func, void* context) {
-  do_in_jni_thread(base::Bind(func, context));
-}
-
-void run_message_loop(UNUSED_ATTR void* context) {
-  LOG_INFO(LOG_TAG, "%s entered", __func__);
-  btif_thread_id_ = PlatformThread::CurrentId();
-
-  // TODO(jpawlowski): exit_manager should be defined in main(), but there is no
-  // main method.
-  // It is therefore defined in bt_jni_workqueue_thread, and will be deleted
-  // when we free it.
-  base::AtExitManager exit_manager;
-
-  message_loop_ = new base::MessageLoop(base::MessageLoop::Type::TYPE_DEFAULT);
-
-  // Associate this workqueue thread with JNI.
-  message_loop_->task_runner()->PostTask(FROM_HERE,
-                                         base::Bind(&btif_jni_associate));
-
-  jni_run_loop = new base::RunLoop();
-  jni_run_loop->Run();
-
-  delete message_loop_;
-  message_loop_ = NULL;
-
-  delete jni_run_loop;
-  jni_run_loop = NULL;
-
-  btif_thread_id_ = -1;
-  LOG_INFO(LOG_TAG, "%s finished", __func__);
-}
 /*******************************************************************************
  *
  * Function         btif_init_bluetooth
@@ -370,27 +325,12 @@ void run_message_loop(UNUSED_ATTR void* context) {
  ******************************************************************************/
 bt_status_t btif_init_bluetooth() {
   LOG_INFO(LOG_TAG, "%s entered", __func__);
-
+  exit_manager = new base::AtExitManager();
   bte_main_boot_entry();
-
-  bt_jni_workqueue_thread = thread_new(BT_JNI_WORKQUEUE_NAME);
-  if (bt_jni_workqueue_thread == NULL) {
-    LOG_ERROR(LOG_TAG, "%s Unable to create thread %s", __func__,
-              BT_JNI_WORKQUEUE_NAME);
-    goto error_exit;
-  }
-
-  thread_post(bt_jni_workqueue_thread, run_message_loop, nullptr);
-
+  bt_jni_workqueue_thread.StartUp();
+  bt_jni_workqueue_thread.DoInThread(FROM_HERE, base::Bind(btif_jni_associate));
   LOG_INFO(LOG_TAG, "%s finished", __func__);
   return BT_STATUS_SUCCESS;
-
-error_exit:;
-  thread_free(bt_jni_workqueue_thread);
-
-  bt_jni_workqueue_thread = NULL;
-
-  return BT_STATUS_FAIL;
 }
 
 /*******************************************************************************
@@ -475,7 +415,7 @@ void btif_enable_bluetooth_evt(tBTA_STATUS status) {
  * Returns          void
  *
  ******************************************************************************/
-bt_status_t btif_disable_bluetooth(void) {
+bt_status_t btif_disable_bluetooth() {
   LOG_INFO(LOG_TAG, "%s entered", __func__);
 
   do_in_bta_thread(FROM_HERE, base::Bind(&btm_ble_multi_adv_cleanup));
@@ -505,7 +445,7 @@ bt_status_t btif_disable_bluetooth(void) {
  *
  ******************************************************************************/
 
-void btif_disable_bluetooth_evt(void) {
+void btif_disable_bluetooth_evt() {
   LOG_INFO(LOG_TAG, "%s entered", __func__);
 
   bte_main_disable();
@@ -526,29 +466,19 @@ void btif_disable_bluetooth_evt(void) {
  *
  ******************************************************************************/
 
-bt_status_t btif_cleanup_bluetooth(void) {
+bt_status_t btif_cleanup_bluetooth() {
   LOG_INFO(LOG_TAG, "%s entered", __func__);
-
   do_in_bta_thread(FROM_HERE, base::Bind(&BTA_VendorCleanup));
-
   btif_dm_cleanup();
-  btif_jni_disassociate();
+  bt_jni_workqueue_thread.DoInThread(FROM_HERE,
+                                     base::BindOnce(btif_jni_disassociate));
   btif_queue_release();
-
-  if (jni_run_loop && message_loop_) {
-    message_loop_->task_runner()->PostTask(FROM_HERE,
-                                           jni_run_loop->QuitClosure());
-  }
-
-  thread_free(bt_jni_workqueue_thread);
-  bt_jni_workqueue_thread = NULL;
-
+  bt_jni_workqueue_thread.ShutDown();
   bte_main_cleanup();
-
+  delete exit_manager;
+  exit_manager = nullptr;
   btif_dut_mode = 0;
-
   LOG_INFO(LOG_TAG, "%s finished", __func__);
-
   return BT_STATUS_SUCCESS;
 }
 
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index 91afabfa311..8a8da8514fc 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -47,7 +47,6 @@
 
 #include "advertise_data_parser.h"
 #include "bt_common.h"
-#include "bta_closure_api.h"
 #include "bta_gatt_api.h"
 #include "btif_api.h"
 #include "btif_av.h"
diff --git a/system/btif/src/btif_gatt_client.cc b/system/btif/src/btif_gatt_client.cc
index 0e06bbb9083..f05e7a046b4 100644
--- a/system/btif/src/btif_gatt_client.cc
+++ b/system/btif/src/btif_gatt_client.cc
@@ -41,7 +41,6 @@
 #include <hardware/bt_gatt.h>
 
 #include "bta_api.h"
-#include "bta_closure_api.h"
 #include "bta_gatt_api.h"
 #include "btif_config.h"
 #include "btif_dm.h"
@@ -49,6 +48,7 @@
 #include "btif_gatt_util.h"
 #include "btif_storage.h"
 #include "osi/include/log.h"
+#include "stack/include/btu.h"
 #include "vendor_api.h"
 
 using base::Bind;
diff --git a/system/btif/src/btif_gatt_server.cc b/system/btif/src/btif_gatt_server.cc
index b7fdc8c8608..2c10842d28f 100644
--- a/system/btif/src/btif_gatt_server.cc
+++ b/system/btif/src/btif_gatt_server.cc
@@ -40,7 +40,6 @@
 
 #include "bt_common.h"
 #include "bta_api.h"
-#include "bta_closure_api.h"
 #include "bta_gatt_api.h"
 #include "btif_config.h"
 #include "btif_dm.h"
@@ -48,6 +47,7 @@
 #include "btif_gatt_util.h"
 #include "btif_storage.h"
 #include "osi/include/log.h"
+#include "stack/include/btu.h"
 
 using base::Bind;
 using base::Owned;
diff --git a/system/btif/src/btif_hearing_aid.cc b/system/btif/src/btif_hearing_aid.cc
index 1614a7378e6..7244cf0ad0c 100644
--- a/system/btif/src/btif_hearing_aid.cc
+++ b/system/btif/src/btif_hearing_aid.cc
@@ -18,10 +18,10 @@
 
 /* Hearing Aid Profile Interface */
 
-#include "bta_closure_api.h"
 #include "bta_hearing_aid_api.h"
 #include "btif_common.h"
 #include "btif_storage.h"
+#include "stack/include/btu.h"
 
 #include <base/bind.h>
 #include <base/location.h>
diff --git a/system/btif/src/btif_pan.cc b/system/btif/src/btif_pan.cc
index 9828c4bc886..b210989e782 100644
--- a/system/btif/src/btif_pan.cc
+++ b/system/btif/src/btif_pan.cc
@@ -54,7 +54,6 @@
 
 #include "bt_common.h"
 #include "bta_api.h"
-#include "bta_closure_api.h"
 #include "bta_pan_api.h"
 #include "btif_common.h"
 #include "btif_pan_internal.h"
@@ -65,6 +64,7 @@
 #include "device/include/controller.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
+#include "stack/include/btu.h"
 
 #define FORWARD_IGNORE 1
 #define FORWARD_SUCCESS 0
diff --git a/system/btif/src/btif_profile_queue.cc b/system/btif/src/btif_profile_queue.cc
index 10acaded8e5..02d6ddf0cbb 100644
--- a/system/btif/src/btif_profile_queue.cc
+++ b/system/btif/src/btif_profile_queue.cc
@@ -210,7 +210,6 @@ void btif_queue_release() {
   LOG_INFO(LOG_TAG, "%s", __func__);
   if (do_in_jni_thread(FROM_HERE, base::Bind(&queue_int_release)) !=
       BT_STATUS_SUCCESS) {
-    // Scheduling failed - the thread to schedule on is probably dead
-    queue_int_release();
+    LOG(FATAL) << __func__ << ": Failed to schedule on JNI thread";
   }
 }
diff --git a/system/btif/src/btif_storage.cc b/system/btif/src/btif_storage.cc
index 826244af3db..22689f53717 100644
--- a/system/btif/src/btif_storage.cc
+++ b/system/btif/src/btif_storage.cc
@@ -40,7 +40,6 @@
 #include <time.h>
 
 #include "bt_common.h"
-#include "bta_closure_api.h"
 #include "bta_hd_api.h"
 #include "bta_hearing_aid_api.h"
 #include "bta_hh_api.h"
diff --git a/system/btif/src/stack_manager.cc b/system/btif/src/stack_manager.cc
index e37db87014b..518f1c50c0b 100644
--- a/system/btif/src/stack_manager.cc
+++ b/system/btif/src/stack_manager.cc
@@ -26,18 +26,20 @@
 #include "btcore/include/osi_module.h"
 #include "btif_api.h"
 #include "btif_common.h"
+#include "common/message_loop_thread.h"
 #include "device/include/controller.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 #include "osi/include/semaphore.h"
-#include "osi/include/thread.h"
 
 // Temp includes
 #include "bt_utils.h"
 #include "btif_config.h"
 #include "btif_profile_queue.h"
 
-static thread_t* management_thread;
+using bluetooth::common::MessageLoopThread;
+
+static MessageLoopThread management_thread("stack_manager");
 
 // If initialized, any of the bluetooth API functions can be called.
 // (e.g. turning logging on and off, enabling/disabling the stack, etc)
@@ -56,40 +58,44 @@ static void event_signal_stack_down(void* context);
 // Unvetted includes/imports, etc which should be removed or vetted in the
 // future
 static future_t* hack_future;
-void btif_thread_post(thread_fn func, void* context);
 // End unvetted section
 
 // Interface functions
 
-static void init_stack(void) {
+static void init_stack() {
   // This is a synchronous process. Post it to the thread though, so
   // state modification only happens there. Using the thread to perform
   // all stack operations ensures that the operations are done serially
   // and do not overlap.
   semaphore_t* semaphore = semaphore_new(0);
-  thread_post(management_thread, event_init_stack, semaphore);
+  management_thread.DoInThread(FROM_HERE,
+                               base::Bind(event_init_stack, semaphore));
   semaphore_wait(semaphore);
   semaphore_free(semaphore);
 }
 
-static void start_up_stack_async(void) {
-  thread_post(management_thread, event_start_up_stack, NULL);
+static void start_up_stack_async() {
+  management_thread.DoInThread(FROM_HERE,
+                               base::Bind(event_start_up_stack, nullptr));
 }
 
-static void shut_down_stack_async(void) {
-  thread_post(management_thread, event_shut_down_stack, NULL);
+static void shut_down_stack_async() {
+  management_thread.DoInThread(FROM_HERE,
+                               base::Bind(event_shut_down_stack, nullptr));
 }
 
-static void clean_up_stack(void) {
+static void clean_up_stack() {
   // This is a synchronous process. Post it to the thread though, so
   // state modification only happens there.
   semaphore_t* semaphore = semaphore_new(0);
-  thread_post(management_thread, event_clean_up_stack, semaphore);
+  management_thread.DoInThread(FROM_HERE,
+                               base::Bind(event_clean_up_stack, semaphore));
   semaphore_wait(semaphore);
   semaphore_free(semaphore);
+  management_thread.ShutDown();
 }
 
-static bool get_stack_is_running(void) { return stack_is_running; }
+static bool get_stack_is_running() { return stack_is_running; }
 
 // Internal functions
 
@@ -119,12 +125,12 @@ static void event_init_stack(void* context) {
   if (semaphore) semaphore_post(semaphore);
 }
 
-static void ensure_stack_is_initialized(void) {
+static void ensure_stack_is_initialized() {
   if (!stack_is_initialized) {
     LOG_WARN(LOG_TAG, "%s found the stack was uninitialized. Initializing now.",
              __func__);
     // No semaphore needed since we are calling it directly
-    event_init_stack(NULL);
+    event_init_stack(nullptr);
   }
 }
 
@@ -148,13 +154,13 @@ static void event_start_up_stack(UNUSED_ATTR void* context) {
   if (future_await(local_hack_future) != FUTURE_SUCCESS) {
     LOG_ERROR(LOG_TAG, "%s failed to start up the stack", __func__);
     stack_is_running = true;  // So stack shutdown actually happens
-    event_shut_down_stack(NULL);
+    event_shut_down_stack(nullptr);
     return;
   }
 
   stack_is_running = true;
   LOG_INFO(LOG_TAG, "%s finished", __func__);
-  btif_thread_post(event_signal_stack_up, NULL);
+  do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_up, nullptr));
 }
 
 // Synchronous function to shut down the stack
@@ -178,17 +184,17 @@ static void event_shut_down_stack(UNUSED_ATTR void* context) {
                                                     // state
 
   hack_future = future_new();
-  btif_thread_post(event_signal_stack_down, NULL);
+  do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_down, nullptr));
   future_await(hack_future);
   LOG_INFO(LOG_TAG, "%s finished", __func__);
 }
 
-static void ensure_stack_is_not_running(void) {
+static void ensure_stack_is_not_running() {
   if (stack_is_running) {
     LOG_WARN(LOG_TAG,
              "%s found the stack was still running. Bringing it down now.",
              __func__);
-    event_shut_down_stack(NULL);
+    event_shut_down_stack(nullptr);
   }
 }
 
@@ -228,19 +234,18 @@ static void event_signal_stack_down(UNUSED_ATTR void* context) {
   future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);
 }
 
-static void ensure_manager_initialized(void) {
-  if (management_thread) return;
+static void ensure_manager_initialized() {
+  if (management_thread.IsRunning()) return;
 
-  management_thread = thread_new("stack_manager");
-  if (!management_thread) {
-    LOG_ERROR(LOG_TAG, "%s unable to create stack management thread", __func__);
+  management_thread.StartUp();
+  if (!management_thread.IsRunning()) {
+    LOG_ERROR(LOG_TAG, "%s unable to start stack management thread", __func__);
     return;
   }
 }
 
 static const stack_manager_t interface = {init_stack, start_up_stack_async,
                                           shut_down_stack_async, clean_up_stack,
-
                                           get_stack_is_running};
 
 const stack_manager_t* stack_manager_get_interface() {
diff --git a/system/btif/test/btif_profile_queue_test.cc b/system/btif/test/btif_profile_queue_test.cc
index f7bce86e332..efa9461d051 100644
--- a/system/btif/test/btif_profile_queue_test.cc
+++ b/system/btif/test/btif_profile_queue_test.cc
@@ -34,8 +34,8 @@ static stack_manager_t sStackManager = {nullptr, nullptr, nullptr, nullptr,
                                         get_stack_is_running};
 const stack_manager_t* stack_manager_get_interface() { return &sStackManager; }
 bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
-                             const base::Closure& task) {
-  task.Run();
+                             base::OnceClosure task) {
+  std::move(task).Run();
   return BT_STATUS_SUCCESS;
 }
 bool is_on_jni_thread() { return true; }
diff --git a/system/hci/src/hci_layer.cc b/system/hci/src/hci_layer.cc
index f1e0e7a605e..aa012d6af26 100644
--- a/system/hci/src/hci_layer.cc
+++ b/system/hci/src/hci_layer.cc
@@ -37,6 +37,7 @@
 #include "btcore/include/module.h"
 #include "btsnoop.h"
 #include "buffer_allocator.h"
+#include "common/message_loop_thread.h"
 #include "hci_inject.h"
 #include "hci_internals.h"
 #include "hcidefs.h"
@@ -50,6 +51,8 @@
 
 #define BT_HCI_TIMEOUT_TAG_NUM 1010000
 
+using bluetooth::common::MessageLoopThread;
+
 extern void hci_initialize();
 extern void hci_transmit(BT_HDR* packet);
 extern void hci_close();
@@ -73,9 +76,6 @@ typedef struct {
 #define DEFAULT_STARTUP_TIMEOUT_MS 8000
 #define STRING_VALUE_OF(x) #x
 
-// RT priority for HCI thread
-static const int BT_HCI_RT_PRIORITY = 1;
-
 // Abort if there is no response to an HCI command.
 static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 2000;
 static const uint32_t COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS = 500;
@@ -92,10 +92,7 @@ static const btsnoop_t* btsnoop;
 static const packet_fragmenter_t* packet_fragmenter;
 
 static future_t* startup_future;
-static thread_t* thread;  // We own this
-static std::mutex message_loop_mutex;
-static base::MessageLoop* message_loop_ = nullptr;
-static base::RunLoop* run_loop_ = nullptr;
+static MessageLoopThread thread("hci_thread");  // We own this
 
 static alarm_t* startup_timer;
 
@@ -138,9 +135,7 @@ static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
     transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished};
 
 void initialization_complete() {
-  std::lock_guard<std::mutex> lock(message_loop_mutex);
-  message_loop_->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&event_finish_startup, nullptr));
+  thread.DoInThread(FROM_HERE, base::Bind(&event_finish_startup, nullptr));
 }
 
 void hci_event_received(const tracked_objects::Location& from_here,
@@ -166,26 +161,6 @@ void sco_data_received(BT_HDR* packet) {
 
 static future_t* hci_module_shut_down();
 
-void message_loop_run(UNUSED_ATTR void* context) {
-  {
-    std::lock_guard<std::mutex> lock(message_loop_mutex);
-    message_loop_ = new base::MessageLoop();
-    run_loop_ = new base::RunLoop();
-  }
-
-  message_loop_->task_runner()->PostTask(FROM_HERE,
-                                         base::Bind(&hci_initialize));
-  run_loop_->Run();
-
-  {
-    std::lock_guard<std::mutex> lock(message_loop_mutex);
-    delete message_loop_;
-    message_loop_ = nullptr;
-    delete run_loop_;
-    run_loop_ = nullptr;
-  }
-}
-
 static future_t* hci_module_start_up(void) {
   LOG_INFO(LOG_TAG, "%s", __func__);
 
@@ -217,13 +192,14 @@ static future_t* hci_module_start_up(void) {
     goto error;
   }
 
-  thread = thread_new("hci_thread");
-  if (!thread) {
-    LOG_ERROR(LOG_TAG, "%s unable to create thread.", __func__);
+  thread.StartUp();
+  if (!thread.IsRunning()) {
+    LOG_ERROR(LOG_TAG, "%s unable to start thread.", __func__);
     goto error;
   }
-  if (!thread_set_rt_priority(thread, BT_HCI_RT_PRIORITY)) {
+  if (!thread.EnableRealTimeScheduling()) {
     LOG_ERROR(LOG_TAG, "%s unable to make thread RT.", __func__);
+    goto error;
   }
 
   commands_pending_response = list_new(NULL);
@@ -242,7 +218,7 @@ static future_t* hci_module_start_up(void) {
 
   packet_fragmenter->init(&packet_fragmenter_callbacks);
 
-  thread_post(thread, message_loop_run, NULL);
+  thread.DoInThread(FROM_HERE, base::Bind(&hci_initialize));
 
   LOG_DEBUG(LOG_TAG, "%s starting async portion", __func__);
   return local_startup_future;
@@ -265,16 +241,7 @@ static future_t* hci_module_shut_down() {
     startup_timer = NULL;
   }
 
-  {
-    std::lock_guard<std::mutex> lock(message_loop_mutex);
-    message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitClosure());
-  }
-
-  // Stop the thread to prevent Send() calls.
-  if (thread) {
-    thread_stop(thread);
-    thread_join(thread);
-  }
+  thread.ShutDown();
 
   // Close HCI to prevent callbacks.
   hci_close();
@@ -288,9 +255,6 @@ static future_t* hci_module_shut_down() {
 
   packet_fragmenter->cleanup();
 
-  thread_free(thread);
-  thread = NULL;
-
   // Clean up abort timer, if it exists.
   if (hci_timeout_abort_timer != NULL) {
     alarm_free(hci_timeout_abort_timer);
@@ -405,14 +369,12 @@ static void enqueue_command(waiting_command_t* wait_entry) {
 
   std::lock_guard<std::mutex> command_credits_lock(command_credits_mutex);
   if (command_credits > 0) {
-    std::lock_guard<std::mutex> message_loop_lock(message_loop_mutex);
-    if (message_loop_ == nullptr) {
-      // HCI Layer was shut down
+    if (!thread.DoInThread(FROM_HERE, std::move(callback))) {
+      // HCI Layer was shut down or not running
       buffer_allocator->free(wait_entry->command);
       osi_free(wait_entry);
       return;
     }
-    message_loop_->task_runner()->PostTask(FROM_HERE, std::move(callback));
     command_credits--;
   } else {
     command_queue.push(std::move(callback));
@@ -434,14 +396,11 @@ static void event_command_ready(waiting_command_t* wait_entry) {
 }
 
 static void enqueue_packet(void* packet) {
-  std::lock_guard<std::mutex> lock(message_loop_mutex);
-  if (message_loop_ == nullptr) {
-    // HCI Layer was shut down
+  if (!thread.DoInThread(FROM_HERE, base::Bind(&event_packet_ready, packet))) {
+    // HCI Layer was shut down or not running
     buffer_allocator->free(packet);
     return;
   }
-  message_loop_->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&event_packet_ready, packet));
 }
 
 static void event_packet_ready(void* pkt) {
@@ -576,19 +535,19 @@ static void command_timed_out(void* original_wait_entry) {
 // Event/packet receiving functions
 void process_command_credits(int credits) {
   std::lock_guard<std::mutex> command_credits_lock(command_credits_mutex);
-  std::lock_guard<std::mutex> message_loop_lock(message_loop_mutex);
 
-  if (message_loop_ == nullptr) {
-    // HCI Layer was shut down
+  if (!thread.IsRunning()) {
+    // HCI Layer was shut down or not running
     return;
   }
 
   // Subtract commands in flight.
   command_credits = credits - get_num_waiting_commands();
 
-  while (command_credits > 0 && command_queue.size() > 0) {
-    message_loop_->task_runner()->PostTask(FROM_HERE,
-                                           std::move(command_queue.front()));
+  while (command_credits > 0 && !command_queue.empty()) {
+    if (!thread.DoInThread(FROM_HERE, std::move(command_queue.front()))) {
+      LOG(ERROR) << __func__ << ": failed to enqueue command";
+    }
     command_queue.pop();
     command_credits--;
   }
diff --git a/system/main/Android.bp b/system/main/Android.bp
index 03861996c98..dcd9a0c0bca 100644
--- a/system/main/Android.bp
+++ b/system/main/Android.bp
@@ -61,6 +61,7 @@ cc_library_shared {
     ],
     whole_static_libs: [
         "libbt-bta",
+        "libbt-common",
         "libbtdevice",
         "libbtif",
         "libbt-hci",
diff --git a/system/main/bte_main.cc b/system/main/bte_main.cc
index 7fdeef031db..f3cca3ed98c 100644
--- a/system/main/bte_main.cc
+++ b/system/main/bte_main.cc
@@ -53,7 +53,6 @@
 #include "osi/include/future.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
-#include "osi/include/thread.h"
 #include "stack_config.h"
 
 /*******************************************************************************
diff --git a/system/osi/Android.bp b/system/osi/Android.bp
index 5439b283d95..de33bfa80e1 100644
--- a/system/osi/Android.bp
+++ b/system/osi/Android.bp
@@ -122,6 +122,7 @@ cc_test {
         "libcutils",
     ],
     static_libs: [
+        "libbt-common",
         "libbt-protos-lite",
         "libgmock",
         "libosi",
diff --git a/system/osi/test/alarm_test.cc b/system/osi/test/alarm_test.cc
index f7f473d7d37..df6592a22ce 100644
--- a/system/osi/test/alarm_test.cc
+++ b/system/osi/test/alarm_test.cc
@@ -22,14 +22,15 @@
 
 #include "AlarmTestHarness.h"
 
+#include "common/message_loop_thread.h"
 #include "osi/include/alarm.h"
 #include "osi/include/fixed_queue.h"
 #include "osi/include/osi.h"
 #include "osi/include/semaphore.h"
-#include "osi/include/thread.h"
 
 using base::Closure;
 using base::TimeDelta;
+using bluetooth::common::MessageLoopThread;
 
 static semaphore_t* semaphore;
 static int cb_counter;
@@ -39,23 +40,7 @@ static const uint64_t EPSILON_MS = 50;
 
 static void msleep(uint64_t ms) { usleep(ms * 1000); }
 
-base::MessageLoop* message_loop_;
-base::RunLoop* run_loop_;
-static semaphore_t* msg_loop_ready;
-
-void message_loop_run(UNUSED_ATTR void* context) {
-  message_loop_ = new base::MessageLoop();
-  run_loop_ = new base::RunLoop();
-
-  semaphore_post(msg_loop_ready);
-  run_loop_->Run();
-
-  delete message_loop_;
-  message_loop_ = nullptr;
-
-  delete run_loop_;
-  run_loop_ = nullptr;
-}
+static base::MessageLoop* message_loop_;
 
 base::MessageLoop* get_message_loop() { return message_loop_; }
 
@@ -318,15 +303,12 @@ TEST_F(AlarmTest, test_callback_ordering_on_mloop) {
   alarm_t* alarms[100];
 
   // Initialize MesageLoop, and wait till it's initialized.
-  msg_loop_ready = semaphore_new(0);
-  thread_t* message_loop_thread_ = thread_new("btu message loop");
-  if (!message_loop_thread_) {
+  MessageLoopThread message_loop_thread("btu message loop");
+  message_loop_thread.StartUp();
+  if (!message_loop_thread.IsRunning()) {
     FAIL() << "unable to create btu message loop thread.";
   }
-
-  thread_post(message_loop_thread_, message_loop_run, nullptr);
-  semaphore_wait(msg_loop_ready);
-  semaphore_free(msg_loop_ready);
+  message_loop_ = message_loop_thread.message_loop();
 
   for (int i = 0; i < 100; i++) {
     const std::string alarm_name =
@@ -347,9 +329,7 @@ TEST_F(AlarmTest, test_callback_ordering_on_mloop) {
 
   for (int i = 0; i < 100; i++) alarm_free(alarms[i]);
 
-  message_loop_->task_runner()->PostTask(FROM_HERE,
-                                         run_loop_->QuitWhenIdleClosure());
-  thread_free(message_loop_thread_);
+  message_loop_thread.ShutDown();
   EXPECT_FALSE(WakeLockHeld());
 }
 
diff --git a/system/osi/test/future_test.cc b/system/osi/test/future_test.cc
index 26d319ac6e0..5e787392775 100644
--- a/system/osi/test/future_test.cc
+++ b/system/osi/test/future_test.cc
@@ -20,9 +20,11 @@
 
 #include "AllocationTestHarness.h"
 
+#include "common/message_loop_thread.h"
 #include "osi/include/future.h"
 #include "osi/include/osi.h"
-#include "osi/include/thread.h"
+
+using bluetooth::common::MessageLoopThread;
 
 static const char* pass_back_data0 = "fancy a sandwich? it's a fancy sandwich";
 static const char* pass_back_data1 =
@@ -38,12 +40,13 @@ TEST_F(FutureTest, test_future_non_immediate) {
   future_t* future = future_new();
   ASSERT_TRUE(future != NULL);
 
-  thread_t* worker_thread = thread_new("worker thread");
-  thread_post(worker_thread, post_to_future, future);
+  MessageLoopThread worker_thread("worker_thread");
+  worker_thread.StartUp();
+  worker_thread.DoInThread(FROM_HERE, base::Bind(post_to_future, future));
 
   EXPECT_EQ(pass_back_data0, future_await(future));
 
-  thread_free(worker_thread);
+  worker_thread.ShutDown();
 }
 
 TEST_F(FutureTest, test_future_immediate) {
diff --git a/system/osi/test/semaphore_test.cc b/system/osi/test/semaphore_test.cc
index 44aee8d0d57..54046a85159 100644
--- a/system/osi/test/semaphore_test.cc
+++ b/system/osi/test/semaphore_test.cc
@@ -6,10 +6,12 @@
 #include <sys/select.h>
 #include <unistd.h>
 
+#include "common/message_loop_thread.h"
 #include "osi/include/osi.h"
 #include "osi/include/reactor.h"
 #include "osi/include/semaphore.h"
-#include "osi/include/thread.h"
+
+using bluetooth::common::MessageLoopThread;
 
 struct SemaphoreTestSequenceHelper {
   semaphore_t* semaphore;
@@ -71,16 +73,18 @@ TEST_F(SemaphoreTest, test_wait_after_post) {
 TEST_F(SemaphoreTest, test_ensure_wait) {
   semaphore_t* semaphore = semaphore_new(0);
   ASSERT_TRUE(semaphore != NULL);
-  thread_t* thread = thread_new("semaphore_test_thread");
-  ASSERT_TRUE(thread != NULL);
+  MessageLoopThread thread("semaphore_test_thread");
+  thread.StartUp();
+  ASSERT_TRUE(thread.IsRunning());
 
   EXPECT_FALSE(semaphore_try_wait(semaphore));
   SemaphoreTestSequenceHelper sequence_helper = {semaphore, 0};
-  thread_post(thread, sleep_then_increment_counter, &sequence_helper);
+  thread.DoInThread(FROM_HERE,
+                    base::Bind(sleep_then_increment_counter, &sequence_helper));
   semaphore_wait(semaphore);
   EXPECT_EQ(sequence_helper.counter, 1)
       << "semaphore_wait() did not wait for counter to increment";
 
   semaphore_free(semaphore);
-  thread_free(thread);
+  thread.ShutDown();
 }
diff --git a/system/stack/Android.bp b/system/stack/Android.bp
index f073048cbaf..722a4e5aedf 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -213,6 +213,7 @@ cc_test {
     ],
     static_libs: [
         "libbt-bta",
+        "libbt-common",
         "libbt-stack",
         "libbt-sbc-decoder",
         "libbt-sbc-encoder",
@@ -393,6 +394,7 @@ cc_test {
         "libprotobuf-cpp-lite",
     ],
     static_libs: [
+        "libbt-common",
         "libbluetooth-types",
         "libgmock",
         "libosi",
diff --git a/system/stack/btm/btm_devctl.cc b/system/stack/btm/btm_devctl.cc
index 2e425aa8ae5..f99ee5decee 100644
--- a/system/stack/btm/btm_devctl.cc
+++ b/system/stack/btm/btm_devctl.cc
@@ -34,16 +34,16 @@
 #include "btcore/include/module.h"
 #include "btm_int.h"
 #include "btu.h"
+#include "common/message_loop_thread.h"
 #include "device/include/controller.h"
 #include "hci_layer.h"
 #include "hcimsgs.h"
 #include "l2c_int.h"
 #include "osi/include/osi.h"
-#include "osi/include/thread.h"
 
 #include "gatt_int.h"
 
-extern thread_t* bt_workqueue_thread;
+extern bluetooth::common::MessageLoopThread bt_workqueue_thread;
 
 /******************************************************************************/
 /*               L O C A L    D A T A    D E F I N I T I O N S                */
@@ -76,7 +76,7 @@ static void btm_decode_ext_features_page(uint8_t page_number,
  * Returns          void
  *
  ******************************************************************************/
-void btm_dev_init(void) {
+void btm_dev_init() {
   /* Initialize nonzero defaults */
   memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME));
 
@@ -231,7 +231,7 @@ void BTM_DeviceReset(UNUSED_ATTR tBTM_CMPL_CB* p_cb) {
   btm_db_reset();
 
   module_start_up_callbacked_wrapper(get_module(CONTROLLER_MODULE),
-                                     bt_workqueue_thread, reset_complete);
+                                     &bt_workqueue_thread, reset_complete);
 }
 
 /*******************************************************************************
diff --git a/system/stack/btu/btu_hcif.cc b/system/stack/btu/btu_hcif.cc
index 0f54a69d25d..e2d8a2f7abe 100644
--- a/system/stack/btu/btu_hcif.cc
+++ b/system/stack/btu/btu_hcif.cc
@@ -126,18 +126,6 @@ static void btu_ble_rc_param_req_evt(uint8_t* p);
 static void btu_ble_proc_enhanced_conn_cmpl(uint8_t* p, uint16_t evt_len);
 #endif
 
-static void do_in_hci_thread(const tracked_objects::Location& from_here,
-                             const base::Closure& task) {
-  base::MessageLoop* hci_message_loop = get_message_loop();
-  if (!hci_message_loop || !hci_message_loop->task_runner().get()) {
-    LOG_ERROR(LOG_TAG, "%s: HCI message loop not running, accessed from %s",
-              __func__, from_here.ToString().c_str());
-    return;
-  }
-
-  hci_message_loop->task_runner()->PostTask(from_here, task);
-}
-
 /*******************************************************************************
  *
  * Function         btu_hcif_process_event
@@ -433,7 +421,7 @@ static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event,
 
 static void btu_hcif_command_complete_evt_with_cb(BT_HDR* response,
                                                   void* context) {
-  do_in_hci_thread(FROM_HERE,
+  do_in_bta_thread(FROM_HERE,
                    base::Bind(btu_hcif_command_complete_evt_with_cb_on_task,
                               response, context));
 }
@@ -466,7 +454,7 @@ static void btu_hcif_command_status_evt_with_cb(uint8_t status, BT_HDR* command,
     return;
   }
 
-  do_in_hci_thread(
+  do_in_bta_thread(
       FROM_HERE, base::Bind(btu_hcif_command_status_evt_with_cb_on_task, status,
                             command, context));
 }
@@ -1039,7 +1027,7 @@ static void btu_hcif_command_complete_evt_on_task(BT_HDR* event,
 }
 
 static void btu_hcif_command_complete_evt(BT_HDR* response, void* context) {
-  do_in_hci_thread(FROM_HERE, base::Bind(btu_hcif_command_complete_evt_on_task,
+  do_in_bta_thread(FROM_HERE, base::Bind(btu_hcif_command_complete_evt_on_task,
                                          response, context));
 }
 
@@ -1214,7 +1202,7 @@ static void btu_hcif_command_status_evt_on_task(uint8_t status, BT_HDR* event,
 
 static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command,
                                         void* context) {
-  do_in_hci_thread(FROM_HERE, base::Bind(btu_hcif_command_status_evt_on_task,
+  do_in_bta_thread(FROM_HERE, base::Bind(btu_hcif_command_status_evt_on_task,
                                          status, command, context));
 }
 
diff --git a/system/stack/btu/btu_init.cc b/system/stack/btu/btu_init.cc
index 3f24813c597..7f26fed112a 100644
--- a/system/stack/btu/btu_init.cc
+++ b/system/stack/btu/btu_init.cc
@@ -25,6 +25,7 @@
 #include "bt_target.h"
 #include "btm_int.h"
 #include "btu.h"
+#include "common/message_loop_thread.h"
 #include "device/include/controller.h"
 #include "gatt_api.h"
 #include "gatt_int.h"
@@ -32,20 +33,12 @@
 #include "osi/include/alarm.h"
 #include "osi/include/fixed_queue.h"
 #include "osi/include/log.h"
-#include "osi/include/thread.h"
 #include "sdpint.h"
 #include "smp_int.h"
 
-// RT priority for audio-related tasks
-#define BTU_TASK_RT_PRIORITY 1
+using bluetooth::common::MessageLoopThread;
 
-// Communication queue from hci thread to bt_workqueue.
-extern fixed_queue_t* btu_hci_msg_queue;
-
-thread_t* bt_workqueue_thread;
-static const char* BT_WORKQUEUE_NAME = "bt_workqueue";
-
-extern void PLATFORM_DisableHciTransport(uint8_t bDisable);
+MessageLoopThread bt_workqueue_thread("bt_workqueue");
 
 void btu_task_start_up(void* context);
 void btu_task_shut_down(void* context);
@@ -60,7 +53,7 @@ void btu_task_shut_down(void* context);
  * Returns          void
  *
  *****************************************************************************/
-void btu_init_core(void) {
+void btu_init_core() {
   /* Initialize the mandatory core stack components */
   btm_init();
 
@@ -85,7 +78,7 @@ void btu_init_core(void) {
  * Returns          void
  *
  *****************************************************************************/
-void btu_free_core(void) {
+void btu_free_core() {
   /* Free the mandatory core stack components */
   gatt_free();
 
@@ -106,29 +99,27 @@ void btu_free_core(void) {
  * Returns          void
  *
  *****************************************************************************/
-void BTU_StartUp(void) {
+void BTU_StartUp() {
   btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
-
-  bt_workqueue_thread = thread_new(BT_WORKQUEUE_NAME);
-  if (bt_workqueue_thread == NULL) goto error_exit;
-
-  thread_set_rt_priority(bt_workqueue_thread, BTU_TASK_RT_PRIORITY);
-
-  // Continue startup on bt workqueue thread.
-  thread_post(bt_workqueue_thread, btu_task_start_up, NULL);
-  return;
-
-error_exit:;
-  LOG_ERROR(LOG_TAG, "%s Unable to allocate resources for bt_workqueue",
-            __func__);
-  BTU_ShutDown();
+  bt_workqueue_thread.StartUp();
+  if (!bt_workqueue_thread.EnableRealTimeScheduling()) {
+    LOG(ERROR) << __func__
+               << ": Unable to set real time scheduling policy for"
+                  " bt_workqueue thread";
+    BTU_ShutDown();
+    return;
+  }
+  if (!bt_workqueue_thread.DoInThread(FROM_HERE,
+                                      base::Bind(btu_task_start_up, nullptr))) {
+    LOG(ERROR) << __func__
+               << ": Unable to continue start-up on bt_workqueue"
+                  " thread";
+    BTU_ShutDown();
+    return;
+  }
 }
 
-void BTU_ShutDown(void) {
-  btu_task_shut_down(NULL);
-
-
-  thread_free(bt_workqueue_thread);
-
-  bt_workqueue_thread = NULL;
+void BTU_ShutDown() {
+  btu_task_shut_down(nullptr);
+  bt_workqueue_thread.ShutDown();
 }
diff --git a/system/stack/btu/btu_task.cc b/system/stack/btu/btu_task.cc
index 7d2527a4193..736d30de5ad 100644
--- a/system/stack/btu/btu_task.cc
+++ b/system/stack/btu/btu_task.cc
@@ -32,22 +32,18 @@
 #include "btcore/include/module.h"
 #include "bte.h"
 #include "btif/include/btif_common.h"
+#include "common/message_loop_thread.h"
 #include "osi/include/osi.h"
-#include "osi/include/thread.h"
 #include "stack/btm/btm_int.h"
 #include "stack/include/btu.h"
 #include "stack/l2cap/l2c_int.h"
 
-static const int THREAD_RT_PRIORITY = 1;
+using bluetooth::common::MessageLoopThread;
 
 /* Define BTU storage area */
 uint8_t btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
 
-extern thread_t* bt_workqueue_thread;
-
-static base::MessageLoop* message_loop_ = NULL;
-static base::RunLoop* run_loop_ = NULL;
-static thread_t* message_loop_thread_;
+static MessageLoopThread btu_message_loop_thread("btu_message_loop");
 
 void btu_hci_msg_process(BT_HDR* p_msg) {
   /* Determine the input message type. */
@@ -83,24 +79,16 @@ void btu_hci_msg_process(BT_HDR* p_msg) {
   }
 }
 
-base::MessageLoop* get_message_loop() { return message_loop_; }
-
-void btu_message_loop_run(UNUSED_ATTR void* context) {
-  message_loop_ = new base::MessageLoop();
-  run_loop_ = new base::RunLoop();
-
-  // Inform the bt jni thread initialization is ok.
-  message_loop_->task_runner()->PostTask(
-      FROM_HERE, base::Bind(base::IgnoreResult(&btif_transfer_context),
-                            btif_init_ok, 0, nullptr, 0, nullptr));
-
-  run_loop_->Run();
-
-  delete message_loop_;
-  message_loop_ = NULL;
+base::MessageLoop* get_message_loop() {
+  return btu_message_loop_thread.message_loop();
+}
 
-  delete run_loop_;
-  run_loop_ = NULL;
+bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
+                             base::OnceClosure task) {
+  if (!btu_message_loop_thread.DoInThread(from_here, std::move(task))) {
+    return BT_STATUS_FAIL;
+  }
+  return BT_STATUS_SUCCESS;
 }
 
 void btu_task_start_up(UNUSED_ATTR void* context) {
@@ -123,21 +111,22 @@ void btu_task_start_up(UNUSED_ATTR void* context) {
    */
   module_init(get_module(BTE_LOGMSG_MODULE));
 
-  message_loop_thread_ = thread_new("btu message loop");
-  if (!message_loop_thread_) {
-    LOG(FATAL) << __func__ << " unable to create btu message loop thread.";
+  btu_message_loop_thread.StartUp();
+  if (!btu_message_loop_thread.IsRunning()) {
+    LOG(FATAL) << __func__ << ": unable to start btu message loop thread.";
+  }
+  if (!btu_message_loop_thread.EnableRealTimeScheduling()) {
+    LOG(FATAL) << __func__ << ": unable to enable real time scheduling";
+  }
+  if (do_in_jni_thread(FROM_HERE, base::Bind(btif_init_ok, 0, nullptr)) !=
+      BT_STATUS_SUCCESS) {
+    LOG(FATAL) << __func__ << ": unable to continue starting Bluetooth";
   }
-
-  thread_set_rt_priority(message_loop_thread_, THREAD_RT_PRIORITY);
-  thread_post(message_loop_thread_, btu_message_loop_run, nullptr);
-
 }
 
 void btu_task_shut_down(UNUSED_ATTR void* context) {
   // Shutdown message loop on task completed
-  if (run_loop_ && message_loop_) {
-    message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitClosure());
-  }
+  btu_message_loop_thread.ShutDown();
 
   module_clean_up(get_module(BTE_LOGMSG_MODULE));
 
diff --git a/system/stack/include/btu.h b/system/stack/include/btu.h
index 5841efa5e4c..505df69a369 100644
--- a/system/stack/include/btu.h
+++ b/system/stack/include/btu.h
@@ -32,6 +32,7 @@
 #include <base/threading/thread.h>
 #include "bt_common.h"
 #include "bt_target.h"
+#include "common/message_loop_thread.h"
 #include "osi/include/alarm.h"
 
 /* Global BTU data */
@@ -57,6 +58,8 @@ void btu_free_core(void);
  ***********************************
 */
 base::MessageLoop* get_message_loop();
+bt_status_t do_in_bta_thread(const tracked_objects::Location& from_here,
+                             base::OnceClosure task);
 
 void BTU_StartUp(void);
 void BTU_ShutDown(void);
diff --git a/system/stack/test/stack_btu_test.cc b/system/stack/test/stack_btu_test.cc
index 97e95d2677e..d048b8937f4 100644
--- a/system/stack/test/stack_btu_test.cc
+++ b/system/stack/test/stack_btu_test.cc
@@ -26,9 +26,9 @@
 #include <unistd.h>
 
 #include "btcore/include/module.h"
+#include "common/message_loop_thread.h"
 #include "osi/include/alarm.h"
 #include "osi/include/fixed_queue.h"
-#include "osi/include/thread.h"
 #include "stack/include/btu.h"
 
 class TimeoutHelper {
@@ -67,10 +67,11 @@ void btu_task_shut_down(void* context);
 /* Below are methods and variables that must be implemented if we don't want to
  * compile the whole stack. They will be removed, or changed into mocks one by
  * one in the future, as the refactoring progresses */
-void btif_transfer_context(void (*)(unsigned short, char*), uint16_t, char*,
-                           int, void (*)(unsigned short, char*, char*)) {
+bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
+                             base::OnceClosure task) {
   helper.notify();
-};
+  return BT_STATUS_SUCCESS;
+}
 
 void btu_init_core(){};
 void btif_init_ok(unsigned short, char*){};
@@ -82,7 +83,7 @@ const module_t* get_module(const char*) { return nullptr; };
 bool module_init(module_t const*) { return true; };
 void module_clean_up(module_t const*){};
 
-thread_t* bt_workqueue_thread;
+bluetooth::common::MessageLoopThread bt_workqueue_thread("test alarm thread");
 
 class BtuMessageLoopTest : public testing::Test {
  public:
@@ -92,8 +93,7 @@ class BtuMessageLoopTest : public testing::Test {
   virtual void SetUp() {
     // Initialize alarms to prevent btu_task_shut_down from crashing
     alarm_new("test alarm");
-    bt_workqueue_thread = thread_new("test alarm thread");
-
+    bt_workqueue_thread.StartUp();
     // btu_task_start_up calls btif_transfer_context to let the stack know
     // start up is finished
     btu_task_start_up(nullptr);
@@ -104,6 +104,7 @@ class BtuMessageLoopTest : public testing::Test {
   virtual void TearDown() {
     btu_task_shut_down(nullptr);
     alarm_cleanup();
+    bt_workqueue_thread.ShutDown();
   }
 
   void Fail(std::string message) { FAIL() << message; }
-- 
GitLab