【android bluetooth 框架分析 01】【关键线程 4】【native <-> java 上下行必须要跑在bt_jni_thread 线程中吗?】

所有的 jni 层的 无论上下行 调用都必须加入 bt_jni_thread 线程中执行吗?

  • java <-> native 必须要加入到 bt_jni_thread 线程执行?

1. 简明结论:

不是所有 JNI 层的调用都必须走 bt_jni_thread

上下行处理分工明确

  • 上行(native → Java):统一通过 bt_jni_thread

  • 下行(Java → native)

    • 核心控制命令 → bt_main_thread
    • 轻量级 profile 操作 → 可以走 bt_jni_thread

2. bt_jni_thread 的作用(一定走的场景):

用于所有 从 native 层回调 Java 层的场景(上行通信)。

这些回调大多数通过 bt_callbacks_t 和各个 profile 的回调结构体实现:

回调类型 说明 示例函数
adapter_state_changed_cb 适配器状态变化 onAdapterStateChanged()
device_found_cb 扫描到新设备 onDeviceFound()
bond_state_changed_cb 配对状态变化 onBondStateChanged()
acl_state_changed_cb 连接状态变化 onConnectionStateChanged()

这些回调一般通过:

btif_transfer_context(...) → do_in_jni_thread(...) → jni_thread

必须走 bt_jni_thread 的原因:

  • 回调线程可能不是 attach 过 JVM 的线程,不能直接调用 Java。

  • bt_jni_thread 是 attach 了 JVM 的,线程安全、可调度。

  • 避免 JNI 层逻辑散落在多个 native 线程里。


3. 下行(Java 调 native)走哪个线程?

3.1 下行控制类操作 → 一般走 bt_main_thread

用于控制整个蓝牙栈行为的操作,必须保证执行顺序一致性。

操作 示例函数 线程
开关蓝牙 enable(), disable() bt_main_thread
开始/停止扫描 startDiscovery() bt_main_thread
配对、取消配对 createBond(), removeBond() bt_main_thread
获取/设置属性 getAdapterProperty(), setAdapterProperty() bt_main_thread

路径通常是:

do_in_main_thread(base::Bind(...)); // 使用 bt_main_thread


3.2 profile 中的轻量操作(部分) → 走 bt_jni_thread

例如:

模块 操作 使用线程
HFP Client connect_audio() bt_jni_thread
GATT client readCharacteristic(), writeDescriptor() bt_jni_thread
AVRCP sendPassThroughCmd() bt_jni_thread
BluetoothSocket connect()(通过线程池执行) 非 bt_main,非 jni,独立线程

这些调用往往是异步、快速、不改变蓝牙主状态机的,设计者为了简洁和性能,允许它们在 bt_jni_thread 执行


4. 汇总表:JNI 上下行操作走哪儿?

调用方向 模块/场景 示例函数 使用线程
上行 native → Java adapter、bonding、scan、profile回调 onDeviceFound() bt_jni_thread
下行 Java → native enable/disable, discovery, bonding enable()createBond() bt_main_thread
下行 Java → native 轻量 profile(HFP、AVRCP、GATT) connect_audio(), readChar() bt_jni_thread
下行 Java → native BluetoothSocket connect() 独立线程池

4.1 为啥不是统一线程调度?

原因 说明
控制流程需要顺序 bt_main_thread 保证主流程有序执行
轻量操作异步无依赖 可走 bt_jni_thread 提高响应速度
各模块历史演进独立 profiles 各自定义处理逻辑
回调必须 JVM attach bt_jni_thread 保证 JVM 可调用

4.2 总结:

所有 native → Java 的回调都必须走 bt_jni_thread
但 Java → native 的“控制命令”一般走 bt_main_thread,而轻量 profile 操作可以走 bt_jni_thread具体视模块而定

常见误区澄清

误解 正确理解
“所有 JNI 层调用都要走 bt_jni_thread” ❌,只有native → Java 回调必须走;Java 调 native 不是必须
“connect_audio() 这类控制调用也要走 main_thread” ❌,HFP client 中是例外,它走的是 bt_jni_thread,因为它是轻量 profile 自定义调度
“主控操作也走 jni_thread” ❌,如 enable()startDiscovery() 是典型的主控行为,走的是 bt_main_thread

对比其他线程

线程名 职责 举例
bt_main_thread 控制蓝牙主流程,统一顺序调度 enable(), createBond(), startDiscovery()
bt_jni_thread 回调 Java 层、执行轻量异步操作 onDeviceFound(), connect_audio()
其他 profile 自定义线程 GATT、AVRCP 等模块内部调度 socket_thread, gatt_cmd_thread(与 bt_jni_thread 配合)

你可能感兴趣的:(android,15,蓝牙协议栈分析,android,aosp13,bluetooth,bluedroid,bt,aosp15)