diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index fb80afc44fd4999bcaa05f16faa9e691766b65c2..ad64e866eb81f94ec1c40e8ecf5da3744559e439 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -188,6 +188,7 @@ cc_library_static {
         "src/btif_gatt_test.cc",
         "src/btif_gatt_util.cc",
         "src/btif_iot_config.cc",
+        "src/btif_jni_task.cc",
         "src/btif_keystore.cc",
         "src/btif_metrics_logging.cc",
         "src/btif_profile_queue.cc",
diff --git a/system/btif/BUILD.gn b/system/btif/BUILD.gn
index 155dc28234e5efb090eec5d7da282ef7f8bde7be..87d19502cd4059724228bfecabb384aa124fc0b8 100644
--- a/system/btif/BUILD.gn
+++ b/system/btif/BUILD.gn
@@ -69,6 +69,7 @@ static_library("btif") {
     "src/btif_hf_client.cc",
     "src/btif_hh.cc",
     "src/btif_iot_config.cc",
+    "src/btif_jni_task.cc",
     "src/btif_keystore.cc",
     "src/btif_le_audio.cc",
     "src/btif_metrics_logging.cc",
diff --git a/system/btif/include/btif_jni_task.h b/system/btif/include/btif_jni_task.h
new file mode 100644
index 0000000000000000000000000000000000000000..e2771db2a4f04cbff5ddba3794ab3fe98a9423cf
--- /dev/null
+++ b/system/btif/include/btif_jni_task.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#pragma once
+
+#include "btif/include/btif_common.h"
+#include "include/hardware/bluetooth.h"
+
+void jni_thread_startup();
+void jni_thread_shutdown();
+
+/*******************************************************************************
+ *
+ * Function         btif_transfer_context
+ *
+ * Description      This function switches context to btif task
+ *
+ *                  p_cback   : callback used to process message in btif context
+ *                  event     : event id of message
+ *                  p_params  : parameter area passed to callback (copied)
+ *                  param_len : length of parameter area
+ *                  p_copy_cback : If set this function will be invoked for deep
+ *                                 copy
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+                                  char* p_params, int param_len,
+                                  tBTIF_COPY_CBACK* p_copy_cback);
+
+/**
+ * This function posts a task into the btif message loop, that executes it in
+ * the JNI message loop.
+ **/
+bt_status_t do_in_jni_thread(const base::Location& from_here,
+                             base::OnceClosure task);
+
+bt_status_t do_in_jni_thread(base::OnceClosure task);
+
+bool is_on_jni_thread();
+
+void post_on_bt_jni(BtJniClosure closure);
diff --git a/system/btif/src/btif_core.cc b/system/btif/src/btif_core.cc
index 55532bdc73a14ff6c357a91d424bfe1b13cb6736..9327194e608a7d2a80f2095bb0cd5bc2efe8d3fa 100644
--- a/system/btif/src/btif_core.cc
+++ b/system/btif/src/btif_core.cc
@@ -42,6 +42,7 @@
 #include "btif/include/btif_common.h"
 #include "btif/include/btif_config.h"
 #include "btif/include/btif_dm.h"
+#include "btif/include/btif_jni_task.h"
 #include "btif/include/btif_pan.h"
 #include "btif/include/btif_profile_queue.h"
 #include "btif/include/btif_sock.h"
@@ -65,8 +66,6 @@ using base::PlatformThread;
 using bluetooth::Uuid;
 using bluetooth::common::MessageLoopThread;
 
-static void bt_jni_msg_ready(void* context);
-
 /*******************************************************************************
  *  Constants & Macros
  ******************************************************************************/
@@ -102,7 +101,6 @@ static tBTA_SERVICE_MASK btif_enabled_services = 0;
  */
 static uint8_t btif_dut_mode = 0;
 
-static MessageLoopThread jni_thread("bt_jni_thread");
 static base::AtExitManager* exit_manager;
 static uid_set_t* uid_set;
 
@@ -114,77 +112,6 @@ void btif_dm_enable_service(tBTA_SERVICE_ID service_id, bool enable);
 void btif_dm_load_local_oob(void);
 #endif
 
-/*******************************************************************************
- *
- * Function         btif_transfer_context
- *
- * Description      This function switches context to btif task
- *
- *                  p_cback   : callback used to process message in btif context
- *                  event     : event id of message
- *                  p_params  : parameter area passed to callback (copied)
- *                  param_len : length of parameter area
- *                  p_copy_cback : If set this function will be invoked for deep
- *                                 copy
- *
- * Returns          void
- *
- ******************************************************************************/
-
-bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
-                                  char* p_params, int param_len,
-                                  tBTIF_COPY_CBACK* p_copy_cback) {
-  tBTIF_CONTEXT_SWITCH_CBACK* p_msg = (tBTIF_CONTEXT_SWITCH_CBACK*)osi_malloc(
-      sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len);
-
-  BTIF_TRACE_VERBOSE("btif_transfer_context event %d, len %d", event,
-                     param_len);
-
-  /* allocate and send message that will be executed in btif context */
-  p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */
-  p_msg->p_cb = p_cback;
-
-  p_msg->event = event; /* callback event */
-
-  /* check if caller has provided a copy callback to do the deep copy */
-  if (p_copy_cback) {
-    p_copy_cback(event, p_msg->p_param, p_params);
-  } else if (p_params) {
-    memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */
-  }
-
-  return do_in_jni_thread(base::BindOnce(&bt_jni_msg_ready, p_msg));
-}
-
-/**
- * This function posts a task into the btif message loop, that executes it in
- * the JNI message loop.
- **/
-bt_status_t do_in_jni_thread(const base::Location& from_here,
-                             base::OnceClosure task) {
-  if (!jni_thread.DoInThread(from_here, std::move(task))) {
-    LOG(ERROR) << __func__ << ": Post task to task runner failed!";
-    return BT_STATUS_FAIL;
-  }
-  return BT_STATUS_SUCCESS;
-}
-
-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 jni_thread.GetThreadId() == PlatformThread::CurrentId();
-}
-
-static void do_post_on_bt_jni(BtJniClosure closure) { closure(); }
-
-void post_on_bt_jni(BtJniClosure closure) {
-  ASSERT(do_in_jni_thread(FROM_HERE, base::BindOnce(do_post_on_bt_jni,
-                                                    std::move(closure))) ==
-         BT_STATUS_SUCCESS);
-}
-
 /*******************************************************************************
  *
  * Function         btif_is_dut_mode
@@ -216,22 +143,6 @@ void btif_init_ok() {
   btif_dm_load_ble_local_keys();
 }
 
-/*******************************************************************************
- *
- * Function         btif_task
- *
- * Description      BTIF task handler managing all messages being passed
- *                  Bluetooth HAL and BTA.
- *
- * Returns          void
- *
- ******************************************************************************/
-static void bt_jni_msg_ready(void* context) {
-  tBTIF_CONTEXT_SWITCH_CBACK* p = (tBTIF_CONTEXT_SWITCH_CBACK*)context;
-  if (p->p_cb) p->p_cb(p->event, p->p_param);
-  osi_free(p);
-}
-
 /*******************************************************************************
  *
  * Function         btif_init_bluetooth
@@ -244,7 +155,7 @@ static void bt_jni_msg_ready(void* context) {
 bt_status_t btif_init_bluetooth() {
   LOG_INFO("%s entered", __func__);
   exit_manager = new base::AtExitManager();
-  jni_thread.StartUp();
+  jni_thread_startup();
   GetInterfaceToProfiles()->events->invoke_thread_evt_cb(ASSOCIATE_JVM);
   LOG_INFO("%s finished", __func__);
   return BT_STATUS_SUCCESS;
@@ -326,7 +237,7 @@ bt_status_t btif_cleanup_bluetooth() {
   btif_dm_cleanup();
   GetInterfaceToProfiles()->events->invoke_thread_evt_cb(DISASSOCIATE_JVM);
   btif_queue_release();
-  jni_thread.ShutDown();
+  jni_thread_shutdown();
   delete exit_manager;
   exit_manager = nullptr;
   btif_dut_mode = 0;
diff --git a/system/btif/src/btif_jni_task.cc b/system/btif/src/btif_jni_task.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3e83c877979befc3da3f07b0d26443ce8f329d80
--- /dev/null
+++ b/system/btif/src/btif_jni_task.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#include "btif/include/btif_jni_task.h"
+
+#include <base/logging.h>
+#include <base/threading/platform_thread.h>
+
+#include "common/message_loop_thread.h"
+#include "include/hardware/bluetooth.h"
+#include "osi/include/allocator.h"
+
+using base::PlatformThread;
+
+static bluetooth::common::MessageLoopThread jni_thread("bt_jni_thread");
+
+void jni_thread_startup() { jni_thread.StartUp(); }
+
+void jni_thread_shutdown() { jni_thread.ShutDown(); }
+
+/*******************************************************************************
+ *
+ * Function         btif_task
+ *
+ * Description      BTIF task handler managing all messages being passed
+ *                  Bluetooth HAL and BTA.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bt_jni_msg_ready(void* context) {
+  tBTIF_CONTEXT_SWITCH_CBACK* p = (tBTIF_CONTEXT_SWITCH_CBACK*)context;
+  if (p->p_cb) p->p_cb(p->event, p->p_param);
+  osi_free(p);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_transfer_context
+ *
+ * Description      This function switches context to btif task
+ *
+ *                  p_cback   : callback used to process message in btif context
+ *                  event     : event id of message
+ *                  p_params  : parameter area passed to callback (copied)
+ *                  param_len : length of parameter area
+ *                  p_copy_cback : If set this function will be invoked for deep
+ *                                 copy
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+                                  char* p_params, int param_len,
+                                  tBTIF_COPY_CBACK* p_copy_cback) {
+  tBTIF_CONTEXT_SWITCH_CBACK* p_msg = (tBTIF_CONTEXT_SWITCH_CBACK*)osi_malloc(
+      sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len);
+
+  BTIF_TRACE_VERBOSE("btif_transfer_context event %d, len %d", event,
+                     param_len);
+
+  /* allocate and send message that will be executed in btif context */
+  p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */
+  p_msg->p_cb = p_cback;
+
+  p_msg->event = event; /* callback event */
+
+  /* check if caller has provided a copy callback to do the deep copy */
+  if (p_copy_cback) {
+    p_copy_cback(event, p_msg->p_param, p_params);
+  } else if (p_params) {
+    memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */
+  }
+
+  return do_in_jni_thread(base::BindOnce(&bt_jni_msg_ready, p_msg));
+}
+
+/**
+ * This function posts a task into the btif message loop, that executes it in
+ * the JNI message loop.
+ **/
+bt_status_t do_in_jni_thread(const base::Location& from_here,
+                             base::OnceClosure task) {
+  if (!jni_thread.DoInThread(from_here, std::move(task))) {
+    LOG(ERROR) << __func__ << ": Post task to task runner failed!";
+    return BT_STATUS_FAIL;
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+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 jni_thread.GetThreadId() == PlatformThread::CurrentId();
+}
+
+static void do_post_on_bt_jni(BtJniClosure closure) { closure(); }
+
+void post_on_bt_jni(BtJniClosure closure) {
+  ASSERT(do_in_jni_thread(FROM_HERE, base::BindOnce(do_post_on_bt_jni,
+                                                    std::move(closure))) ==
+         BT_STATUS_SUCCESS);
+}