【android bluetooth 框架分析 01】【关键线程 3】【bt_jni_thread 线程介绍】

发布于:2025-04-11 ⋅ 阅读:(36) ⋅ 点赞:(0)

1. bt_jni_thread 职责介绍

bt_jni_thread 这个线程的作用是专门负责处理蓝牙 JNI 层的消息循环,也可以说是 C++ 层和 Java 层交互的桥梁线程。


1.1 什么是 JNI 层?为什么需要这个线程?

JNI(Java Native Interface)是 Android 用来让 Java 和 C/C++ 代码通信的机制。在蓝牙协议栈中:

  • Java 层(APP 或框架)发送蓝牙指令。
  • C++ 层(Native 蓝牙协议栈)负责底层逻辑,比如连接蓝牙设备、传输数据等。
  • 中间就是 JNI 层,它用来做“翻译官” —— 把 Java 的指令转成 C++ 能理解的函数调用,反之也一样。

1.2 职责总结

  1. 消息分发器(Message Dispatcher)
    所有 JNI 相关的调用(比如设备连接状态回调、扫描结果等),都通过这个线程发送回 Java 层。

  2. 避免阻塞主线程(Non-blocking)
    蓝牙操作可能会耗时,比如搜索设备、建立连接等。如果不单独开线程处理,会拖慢系统,甚至 ANR(应用无响应)。

  3. 保证线程安全(Thread Safety)
    蓝牙操作涉及很多共享资源(socket、状态等),用一个专门的线程可以避免多线程访问冲突。

  4. 事件循环(Message Loop)
    这个线程运行的是一个“消息循环”,就是不断读取事件队列中的消息,然后按顺序处理。


1.3 为什么这样设计很重要?

  • 安全性(Safe)
    如果所有 JNI 回调都在主线程或者随便哪个线程跑,容易出现崩溃或者状态错乱。

  • 效率(Efficient)
    用单独线程做专门的事,可以提高系统响应速度,用户操作不会被蓝牙事件卡住。

  • 解耦(Decoupled)
    Java 层、JNI 层、Native 层之间职责分明,出了问题更容易排查和维护。


1.4 总结一句话:

bt_jni_thread 就像是蓝牙 JNI 层的“接线员”,负责有序、高效、安全地处理 Java 与 C++ 层的消息传递,是整个 Android 蓝牙系统稳定运行的重要一环。

2. 如何工作的?

既然 bt_jni_thread 职责已经很清晰了, 那我们就探索一下, bt_jni_thread 是如何启动 , 如何接收事件, 以及处理事件的?

  • system/btif/src/btif_core.cc

2.1 线程何时启动


static MessageLoopThread jni_thread("bt_jni_thread");

bt_status_t btif_init_bluetooth() {
  LOG_INFO("%s entered", __func__);
  exit_manager = new base::AtExitManager();
  jni_thread.StartUp(); // 创建 bt_jni_thread 线程
  invoke_thread_evt_cb(ASSOCIATE_JVM);
  LOG_INFO("%s finished", __func__);
  return BT_STATUS_SUCCESS;
}

调用流程

[stack_manager.cc:event_init_stack] ->

[btif_init_bluetooth]
  • 是在 调用 stack_manager 的 event_init_stack 函数阶段触发的, event_init_stack的调用流程, 请参考 之前的文章 介绍 bt_stack_manager_thread

2.2 如何下发任务到 该线程

bt_jni_thread 线程已经启动, 那我们如何下发任务给 该线程去处理呢?
答案是通过 do_in_jni_thread 函数

1. do_in_jni_thread

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

这个函数的目的是:

把你传进来的任务 task 安排到 bt_jni_thread 线程里去执行。

参数解释:

  • from_here:记录任务来源,用于调试(比如你从哪个文件、哪一行调用的这个函数)。
  • task:要在线程中执行的逻辑(闭包或 lambda 表达式)。

实现逻辑:

  • 它调用了:jni_thread.DoInThread(from_here, std::move(task));

  • bt_jni_thread 来执行这个任务。如果失败(比如线程未启动),就返回 BT_STATUS_FAIL

  • 那些场景会用到 do_in_jni_thread
    在这里插入图片描述

  • 从搜素结果来看, 凡是设计到 jni 交互的场景都 在使用。 这个也验证了 本章已开始就介绍的 bt_jni_thread 职责。

这个函数主要用途:

  • 线程切换:你可能当前在蓝牙主线程、HAL 线程、APP 线程,但 JNI 的东西要在 bt_jni_thread 里跑,必须切过去。

  • 线程安全:统一通过 bt_jni_thread 来操作 JNI,避免多线程同时调用 JNI 导致 crash。

  • 任务封装:代码结构更清晰,异步任务都包成一个 Closure 任务发送。

2. btif_transfer_context

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 */
  }

  do_in_jni_thread(base::Bind(&bt_jni_msg_ready, p_msg));
  return BT_STATUS_SUCCESS;
}


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

btif_transfer_context(...),它的作用是:

把来自 HAL 或 Stack 的事件,转移(transfer)到 JNI 线程(bt_jni_thread)中执行,并调用对应的回调函数。

这个函数起到了核心的“线程桥梁”和“事件分发器”的作用。
函数入参解释

参数 类型 作用
p_cback tBTIF_CBACK* 你希望在 bt_jni_thread 中被调用的回调函数
event uint16_t 表示是什么事件,通常用枚举,如 BTIF_DM_CB_DISCOVERY_STARTED
p_params char* 回调函数要用的参数
param_len int 参数长度
p_copy_cback tBTIF_COPY_CBACK* 自定义的“深拷贝”函数,用于复杂结构的复制(可选)
  1. 分配内存

    tBTIF_CONTEXT_SWITCH_CBACK* p_msg = (tBTIF_CONTEXT_SWITCH_CBACK*)osi_malloc(...);

    创建一个消息对象 p_msg,用来封装要执行的任务。

  2. 设置元数据

    p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; p_msg->p_cb = p_cback; p_msg->event = event;

    标记这个是“上下文切换事件”,并把事件编号和要执行的回调函数绑定进来。

  3. 拷贝参数
    如果参数非空,尝试用 p_copy_cback() 深拷贝参数;否则直接用 memcpy() 复制。

  4. 投递给 JNI 线程执行

    do_in_jni_thread(base::Bind(&bt_jni_msg_ready, p_msg));

    把这个封装好的消息送到 bt_jni_thread 中,由 bt_jni_msg_ready() 函数去调度并执行真正的回调。

  5. 返回成功

    return BT_STATUS_SUCCESS;

这样设计意义是什么?

设计点 意义
线程安全 所有 JNI 回调都在同一个线程中执行,避免多线程问题
可扩展 不同事件、不同回调都能统一走这个机制
解耦 HAL 层不用关心 JNI 层线程情况,只管调用 transfer
支持复杂数据 可通过 p_copy_cback 自定义深拷贝参数结构体

总结

  • btif_transfer_context() 是一个线程切换和任务派发的机制

  • 不是 Java 调 Native 的唯一通道,但在需要切换到 bt_jni_thread 执行的下行任务中非常关键。

  • 它和 do_in_jni_thread() 一起构成了 Android 蓝牙协议栈中线程调度和事件派发的基础工具。

3. 使用举例

1. 上行 native -> java
01-10 06:48:39.160  2024  3120 I bluetooth: packages/modules/Bluetooth/system/bta/dm/bta_dm_main.cc:65 bta_dm_search_sm_execute: bta_dm_search_sm_execute state:1, event:0x205

01-10 06:48:39.160  2024  3120 I bt_btif : packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: btif_dm_search_devices_evt event=BTA_DM_DISC_CMPL_EVT

01-10 06:48:39.161  2024  2493 I bt_btif : packages/modules/Bluetooth/system/main/bte_logmsg.cc:198 LogMsg: operator(): HAL bt_hal_cbacks->discovery_state_changed_cb

01-10 06:48:39.161  2024  2493 I AdapterProperties: Callback:discoveryStateChangeCallback with state:0

当我们发起扫描, 扫描结束后, 会上报一个状态给 java 层。

我们来梳理一下这个调用流程:

  • system/btif/src/btif_dm.cc
static int start_discovery(void) {
  if (!interface_ready()) return BT_STATUS_NOT_READY;
  // 当我们触发 扫描时, 是跑在 main_thread 中的
  do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_start_discovery));
  return BT_STATUS_SUCCESS;
}


void btif_dm_start_discovery(void) {
  BTIF_TRACE_EVENT("%s", __func__);

  /* no race here because we're guaranteed to be in the main thread */
  if (bta_dm_is_search_request_queued()) {
    LOG_INFO("%s skipping start discovery because a request is queued",
             __func__);
    return;
  }

  /* Will be enabled to true once inquiry busy level has been received */
  btif_dm_inquiry_in_progress = false;
  /* find nearby devices */
  BTA_DmSearch(btif_dm_search_devices_evt);
}
  • app 侧发起扫描, 就会触发 btif_dm_start_discovery 调用,
  • 在触发扫描时,我们注册了 btif_dm_search_devices_evt 回调函数

当芯片上报扫描 结束时,就会 回调 btif_dm_search_devices_evt 。 这个过程怎么回调到的,暂时不表, 后面有机会,专门单独表述,这种机制。

  • system/btif/src/btif_dm.cc
static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event,
                                       tBTA_DM_SEARCH* p_search_data) {
                               
  // 此时发现收到了 扫描结束事件
    case BTA_DM_DISC_CMPL_EVT: {
      // 这里会触发
      invoke_discovery_state_changed_cb(BT_DISCOVERY_STOPPED);
    } break;                       

}
  • 触发调用 invoke_discovery_state_changed_cb

  • system/btif/src/bluetooth.cc

void invoke_discovery_state_changed_cb(bt_discovery_state_t state) {
  do_in_jni_thread(FROM_HERE, base::BindOnce(
                                  [](bt_discovery_state_t state) {
                                    HAL_CBACK(bt_hal_cbacks,
                                              discovery_state_changed_cb,
                                              state);
                                  },
                                  state));
}
  • HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,…)
    • 上述的 调用会打印如下log
    • HAL bt_hal_cbacks->discovery_state_changed_cb
  • 此时就会调用到 discovery_state_changed_cb
  • 从这里开始 回调 hal 层, 将 discovery_state_changed_cb 回调放置到 bt_jni_thread 线程中去处理, 从这里往下都是跑在 bt_jni_thread 中。

  • android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp

static bt_callbacks_t sBluetoothCallbacks = {
...
                                             discovery_state_changed_callback, // 这里会被回调到
                                             ...
};



static void discovery_state_changed_callback(bt_discovery_state_t state) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  ALOGV("%s: DiscoveryState:%d ", __func__, state);

  sCallbackEnv->CallVoidMethod(
      sJniCallbacksObj, method_discoveryStateChangeCallback, (jint)state);
}


static void classInitNative(JNIEnv* env, jclass clazz) {
...
	  method_discoveryStateChangeCallback = env->GetMethodID(
      jniCallbackClass, "discoveryStateChangeCallback", "(I)V");
}
  • 此时回调到 discovery_state_changed_callback 他最终回调到 java 侧的 AdapterProperties::discoveryStateChangeCallback

  • android/app/src/com/android/bluetooth/btservice/AdapterProperties.java

    void discoveryStateChangeCallback(int state) {
        infoLog("Callback:discoveryStateChangeCallback with state:" + state);
        synchronized (mObject) {
            Intent intent;
            if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) {
                mDiscovering = false;
                mService.clearDiscoveringPackages();
                mDiscoveryEndMs = System.currentTimeMillis();
                intent = newIntent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
                        BluetoothAdapterExt.ACTION_DISCOVERY_FINISHED);
                mService.sendBroadcast(intent, BLUETOOTH_SCAN,
                        Utils.getTempAllowlistBroadcastOptions());
            } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) {
                mDiscovering = true;
                mDiscoveryEndMs = System.currentTimeMillis() + DEFAULT_DISCOVERY_TIMEOUT_MS;
                intent = newIntent(BluetoothAdapter.ACTION_DISCOVERY_STARTED,
                        BluetoothAdapterExt.ACTION_DISCOVERY_STARTED);
                mService.sendBroadcast(intent, BLUETOOTH_SCAN,
                        Utils.getTempAllowlistBroadcastOptions());
            }
        }
    }
2. 下行 java -> native

在车机的蓝牙电话通话过程中, 我们可以随意在 车机上切换当前来电是在手机接听,还是车机接听。 也就是 hfp 中 SCO 的建立和断开。 这里我们看一下 主动去建立 SCO的流程。

  • android/app/jni/com_android_bluetooth_hfpclient.cpp
static jboolean connectAudioNative(JNIEnv* env, jobject object,
                                   jbyteArray address) {
	...

  bt_status_t status =
      sBluetoothHfpClientInterface->connect_audio((const RawAddress*)addr);
	...
}
  • system/btif/src/btif_hf_client.cc

static bt_status_t connect_audio(const RawAddress* bd_addr) {
  btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(*bd_addr);
  if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;

  CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);

  if ((get_default_hf_client_features() & BTA_HF_CLIENT_FEAT_CODEC) &&
      (cb->peer_feat & BTA_HF_CLIENT_PEER_CODEC)) {
    BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BCC, 0, 0, NULL);
  } else {
    BTA_HfClientAudioOpen(cb->handle);
  }

  /* Inform the application that the audio connection has been initiated
   * successfully */
  // 之间加入到 bt_jni_thread 中去执行
  btif_transfer_context(btif_in_hf_client_generic_evt,
                        BTIF_HF_CLIENT_CB_AUDIO_CONNECTING, (char*)bd_addr,
                        sizeof(RawAddress), NULL);
  return BT_STATUS_SUCCESS;
}
  • 这里通过 btif_transfer_context 将建立 sco 的操作放置到 bt_jni_thread 线程中去执行了。

2.3 线程何时终止


bt_status_t btif_cleanup_bluetooth() {
  LOG_INFO("%s entered", __func__);
  btif_dm_cleanup();
  invoke_thread_evt_cb(DISASSOCIATE_JVM);
  btif_queue_release();
  jni_thread.ShutDown();
  delete exit_manager;
  exit_manager = nullptr;
  btif_dut_mode = 0;
  LOG_INFO("%s finished", __func__);
  return BT_STATUS_SUCCESS;
}
  • system/btif/src/stack_manager.cc
static void event_clean_up_stack(std::promise<void> promise) {
	...

  btif_cleanup_bluetooth();

  ...
}
  • 当我们点击关闭蓝牙时 bt_stack_manager_thread 线程会去触发 event_clean_up_stack 调用, 在这个里面,会去讲我们的 bt_jni_thread 线程终止的。

3. bt_hal_cbacks 介绍

3.1 HAL_CBACK

在上面 2.2.2.1 小结介绍上行 流时, 我们看到了 HAL_CBACK 的调用,本节就来看看 这部分是如何 做到的。

void invoke_discovery_state_changed_cb(bt_discovery_state_t state) {
  do_in_jni_thread(FROM_HERE, base::BindOnce(
                                  [](bt_discovery_state_t state) {
                                    HAL_CBACK(bt_hal_cbacks,
                                              discovery_state_changed_cb,
                                              state);
                                  },
                                  state));
}
#define HAL_CBACK(P_CB, P_CBACK, ...)                              \
  do {                                                             \
    if ((P_CB) && (P_CB)->P_CBACK) {                               \
      BTIF_TRACE_API("%s: HAL %s->%s", __func__, #P_CB, #P_CBACK); \
      (P_CB)->P_CBACK(__VA_ARGS__);                                \
    } else {                                                       \
      ASSERTC(0, "Callback is NULL", 0);                           \
    }                                                              \
  } while (0)
  • 这里是一个宏函数,
  • 可以直接把 HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb 调用替换为:
    • bt_hal_cbacks->discovery_state_changed_cb(state)

但是这不是重点, 重点是 bt_hal_cbacks 初始化以及 这些回调函数的含义

3.2 bt_callbacks_t

  • system/btif/src/bluetooth.cc
static bt_callbacks_t* bt_hal_cbacks = NULL;
typedef struct {
    /** set to sizeof(bt_callbacks_t) */
    size_t size;
    adapter_state_changed_callback adapter_state_changed_cb;
    adapter_properties_callback adapter_properties_cb;
    remote_device_properties_callback remote_device_properties_cb;
    device_found_callback device_found_cb;
    discovery_state_changed_callback discovery_state_changed_cb; // 会调用到这里
    pin_request_callback pin_request_cb;
    ssp_request_callback ssp_request_cb;
    bond_state_changed_callback bond_state_changed_cb;
    acl_state_changed_callback acl_state_changed_cb;
    callback_thread_event thread_evt_cb;
    dut_mode_recv_callback dut_mode_recv_cb;
    le_test_mode_callback le_test_mode_cb;
    energy_info_callback energy_info_cb;
} bt_callbacks_t;

bt_callbacks_t 结构体是 Bluetooth HAL(硬件抽象层) 定义的一组回调接口,用于 Native 层通过回调与上层框架通信,比如 Java 层或者 JNI 层。

回调函数名 作用说明 触发时机 / 事件说明
adapter_state_changed_cb 通知适配器状态变化(开/关) BluetoothAdapter.enable()disable() 被调用后,适配器状态变化时触发,如 BT_STATE_ONBT_STATE_OFF
adapter_properties_cb 返回适配器属性(如名称、地址) 当上层请求读取或设置蓝牙本地适配器属性,如调用 getAdapterProperty()setAdapterProperty()
remote_device_properties_cb 返回远程设备的属性(如名称、class) 上层请求远程设备属性,或发现设备时获取其属性后触发
device_found_cb 通知发现了新的远程设备 调用 startDiscovery() 后,在扫描过程中每发现一个新设备就会触发
discovery_state_changed_cb 扫描状态变化 调用 startDiscovery()cancelDiscovery() 后,通知开始或结束扫描
pin_request_cb 要求输入 PIN 码配对 当连接传统蓝牙设备(BR/EDR)时需要输入 PIN 码进行配对时触发
ssp_request_cb 要求进行安全简单配对(SSP) 设备配对时支持 SSP 模式,进行确认、比较、输入密钥等操作时触发
bond_state_changed_cb 配对状态变化 设备配对成功或失败时调用,如从 BOND_BONDINGBOND_BONDED
acl_state_changed_cb ACL 连接状态变化 蓝牙链路层连接或断开时调用(所有设备连接都会有 ACL 层)
thread_evt_cb 通知线程附加或分离 JNI 层使用,用于线程绑定和解绑当前线程到 JVM(Attach/Detach)
dut_mode_recv_cb DUT 模式接收数据 当设备处于 DUT 模式(测试模式)下收到测试数据时触发(调试使用)
le_test_mode_cb LE 测试模式回调 BLE 专用的 TX/RX 测试事件的结果回调(蓝牙 SIG 测试场景)
energy_info_cb 蓝牙能耗信息回调 请求能耗信息时(比如上层调用 requestControllerEnergyInfo())触发,回调耗电数据

3.3 bt_hal_cbacks 如何初始化的

  • system/btif/src/bluetooth.cc
static bt_callbacks_t* bt_hal_cbacks = NULL;

那这里的 bt_hal_cbacks 是如何初始化的?

  • android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
static bool initNative(JNIEnv* env, jobject obj, jboolean isGuest,
                       jboolean isCommonCriteriaMode, int configCompareResult,
                       jobjectArray initFlags, jboolean isAtvDevice,
                       jstring userDataDirectory) {


// 将 sBluetoothCallbacks 传递出去
int ret = sBluetoothInterface->init(
      &sBluetoothCallbacks, isGuest == JNI_TRUE ? 1 : 0,
      isCommonCriteriaMode == JNI_TRUE ? 1 : 0, configCompareResult, flags,
      isAtvDevice == JNI_TRUE ? 1 : 0, user_data_directory);


}


static bt_callbacks_t sBluetoothCallbacks = {sizeof(sBluetoothCallbacks),
                                             adapter_state_change_callback,
                                             adapter_properties_callback,
                                             remote_device_properties_callback,
                                             device_found_callback,
                                             discovery_state_changed_callback,
                                             pin_request_callback,
                                             ssp_request_callback,
                                             bond_state_changed_callback,
                                             address_consolidate_callback,
                                             le_address_associate_callback,
                                             acl_state_changed_callback,
                                             callback_thread_event,
                                             dut_mode_recv_callback,
                                             le_test_mode_recv_callback,
                                             energy_info_recv_callback,
                                             link_quality_report_callback,
                                             generate_local_oob_data_callback,
                                             switch_buffer_size_callback,
                                             switch_codec_callback};
  • 当我们拉起我们的 蓝牙进程服务时, 将触发 initNative 调用

  • 此时通过 sBluetoothInterface->init( &sBluetoothCallbacks

    • 将我们的 sBluetoothCallbacks 传递出去。
  • system/btif/src/bluetooth.cc


static int init(bt_callbacks_t* callbacks, bool start_restricted,
                bool is_common_criteria_mode, int config_compare_result,
                const char** init_flags, bool is_atv,
                const char* user_data_directory) {


  set_hal_cbacks(callbacks); // 直接将 callbacks 给了 bt_hal_cbacks

}



void set_hal_cbacks(bt_callbacks_t* callbacks) { bt_hal_cbacks = callbacks; }
  • 这里所有的 hal 回调都将回调到 sBluetoothCallbacks 中。

4. 小结

bt_jni_thread 是 AOSP 蓝牙系统中 native → Java 方向的专用线程桥梁,同时也承担部分 profile 层轻量控制任务的执行职责。它不是全能线程,但在 JNI 回调中不可或缺。

为什么要有 bt_jni_thread

原因 解释
保证 JVM attach 不同 native 回调线程不一定 attach 了 JVM
避免跨线程调用 Java Android 不允许非 JVM 线程直接访问 Java
提高模块解耦 各个 profile 回调逻辑统一封装、集中调度
提升线程安全 所有 JNI 回调集中在一个线程处理,避免竞态

核心职责

类别 说明
上行事件调度 负责 native → Java 的事件回调,例如设备发现、配对状态变化等
JVM 安全桥梁 由于 native 回调来自蓝牙堆栈中的多个线程,bt_jni_thread 保证在 JVM 附着线程中调用 Java
profile 模块轻量任务 某些模块(如 HFP client、AVRCP、GATT)内部异步任务也在此线程中执行

使用场景举例

上行事件来源 对应 Java 回调函数
adapter_state_changed_cb onAdapterStateChanged()
device_found_cb onDeviceFound()
bond_state_changed_cb onBondStateChanged()
acl_state_changed_cb onConnectionStateChanged()
btif_gatt_client_* 回调 GATT 连接、通知、读写特征值等
hfp_client_callbacks HFP 状态变化、音频连接事件

看到这里大家可以思考一下问题:

  • native <-> java 上下行的事件, 一定都要 放在 bt_jni_thread 线程中执行吗?
  • 答案

网站公告

今日签到

点亮在社区的每一天
去签到