蓝牙协议栈 jni回调java流程

这篇博客详细解析了Android系统中蓝牙连接状态变化的处理流程,从btif_dm.cc开始,经过jni层的转换,到Java层的回调函数aclStateChangeCallback,最后在RemoteDevices.java中进行设备状态更新。过程中涉及到蓝牙库的加载、接口调用以及不同层级的回调函数交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

step.1:
btif_dm.cc

static void btif_dm_upstreams_evt(uint16_t event, char* p_param) {
  tBTA_DM_SEC* p_data = (tBTA_DM_SEC*)p_param;
  tBTA_SERVICE_MASK service_mask;
  uint32_t i;
  RawAddress bd_addr;

  BTIF_TRACE_EVENT("%s: ev: %s", __func__, dump_dm_event(event));


  //android::CallStack    stack;     
  //stack.update();    
  //stack.log("callstack");
  //libutilscallstack
  //debug_stamp


   LOG_INFO(LOG_TAG, "%s: ev: %s", __func__, dump_dm_event(event));

  HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
                &bd_addr, BT_ACL_STATE_CONNECTED);
                


step.2:                
packages/apps/bluetooth/jni
com_android_bluetooth_btservice_AdapterService.cpp
static void acl_state_changed_callback(bt_status_t status, RawAddress* bd_addr,
                                       bt_acl_state_t state) {
  if (!bd_addr) {
    ALOGE("Address is null in %s", __func__);
    return;
  }


  ALOGE( "in %s", __func__ );
  

  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  ScopedLocalRef<jbyteArray> addr(
      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
  if (!addr.get()) {
    ALOGE("Address allocation failed in %s", __func__);
    return;
  }
  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                   (jbyte*)bd_addr);

  sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_aclStateChangeCallback,
                               (jint)status, addr.get(), (jint)state);
}


step.3:
static void classInitNative(JNIEnv* env, jclass clazz) {
  jclass jniUidTrafficClass = env->FindClass("android/bluetooth/UidTraffic");
  android_bluetooth_UidTraffic.constructor =
      env->GetMethodID(jniUidTrafficClass, "<init>", "(IJJ)V");

  jclass jniCallbackClass = env->FindClass("com/android/bluetooth/btservice/JniCallbacks");
  sJniCallbacksField = env->GetFieldID(
      clazz, "mJniCallbacks", "Lcom/android/bluetooth/btservice/JniCallbacks;");

  method_stateChangeCallback =
      env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V");

  method_adapterPropertyChangedCallback = env->GetMethodID(
      jniCallbackClass, "adapterPropertyChangedCallback", "([I[[B)V");
  method_discoveryStateChangeCallback = env->GetMethodID(
      jniCallbackClass, "discoveryStateChangeCallback", "(I)V");

  method_devicePropertyChangedCallback = env->GetMethodID(
      jniCallbackClass, "devicePropertyChangedCallback", "([B[I[[B)V");
  method_deviceFoundCallback =
      env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
  method_pinRequestCallback =
      env->GetMethodID(jniCallbackClass, "pinRequestCallback", "([B[BIZ)V");

  
  method_sspRequestCallback =
      env->GetMethodID(jniCallbackClass, "sspRequestCallback", "([B[BIII)V");

  //void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, int passkey) {

  

  method_bondStateChangeCallback =
      env->GetMethodID(jniCallbackClass, "bondStateChangeCallback", "(I[BI)V");

  method_aclStateChangeCallback =
      env->GetMethodID(jniCallbackClass, "aclStateChangeCallback", "(I[BI)V");

  method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z");
  method_acquireWakeLock =
      env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z");
  method_releaseWakeLock =
      env->GetMethodID(clazz, "releaseWakeLock", "(Ljava/lang/String;)Z");
  method_energyInfo = env->GetMethodID(
      clazz, "energyInfoCallback", "(IIJJJJ[Landroid/bluetooth/UidTraffic;)V");

  if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) {
    ALOGE("No Bluetooth Library found");
  }
}

step.4:
JniCallbacks.java

void aclStateChangeCallback(int status, byte[] address, int newState) {
        mRemoteDevices.aclStateChangeCallback(status, address, newState);
    }


step.5:
RemoteDevices.java
 void aclStateChangeCallback(int status, byte[] address, int newState) {
        BluetoothDevice device = getDevice(address);

        if (device == null) {
            errorLog("aclStateChangeCallback: device is NULL, address="
                    + Utils.getAddressStringFromByte(address) + ", newState=" + newState + "\n\n\n");
            return;
        }
        int state = sAdapterService.getState();
        

一些疑点捋一捋:
acl_state_changed_cb  怎么到下一步的?
static const bt_interface_t* sBluetoothInterface = NULL;
if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) {
    ALOGE("No Bluetooth Library found");
  }


int hal_util_load_bt_library(const bt_interface_t** interface) {
  const char* sym = BLUETOOTH_INTERFACE_STRING;
  #define BLUETOOTH_INTERFACE_STRING "bluetoothInterface"

  bt_interface_t* itf = nullptr;

  // The library name is not set by default, so the preset library name is used.
  char path[PROPERTY_VALUE_MAX] = "";
  property_get(PROPERTY_BT_LIBRARY_NAME, path, DEFAULT_BT_LIBRARY_NAME);
  void* handle = dlopen(path, RTLD_NOW);
  #define DEFAULT_BT_LIBRARY_NAME "libbluetooth.so"
  //打开蓝牙库

  if (!handle) {
    const char* err_str = dlerror();
    LOG(ERROR) << __func__ << ": failed to load Bluetooth library, error="
               << (err_str ? err_str : "error unknown");
    goto error;
  }

  // Get the address of the bt_interface_t.
  itf = (bt_interface_t*)dlsym(handle, sym);
  //加载其中的 bluetoothInterface
  if (!itf) {
    LOG(ERROR) << __func__ << ": failed to load symbol from Bluetooth library "
               << sym;
    goto error;
  }

  // Success.
  LOG(INFO) << __func__ << " loaded HAL: btinterface=" << itf
            << ", handle=" << handle;
  *interface = itf;
  return 0;

error:
  *interface = NULL;
  if (handle) dlclose(handle);

  return -EINVAL;
}


bt/btif/src/Bluetooth.cc
EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
    sizeof(bluetoothInterface),
    init,
    enable,
    disable,
    cleanup,
    get_adapter_properties,
    get_adapter_property,
    set_adapter_property,
    get_remote_device_properties,
    get_remote_device_property,
    set_remote_device_property,
    get_remote_service_record,
    get_remote_services,
    start_discovery,
    cancel_discovery,
    create_bond,
    create_bond_out_of_band,
    remove_bond,
    cancel_bond,
    get_connection_state,
    pin_reply,
    ssp_reply,
    get_profile_interface,
    dut_mode_configure,
    dut_mode_send,
    le_test_mode,
    set_os_callouts,
    read_energy_info,
    dump,
    dumpMetrics,
    config_clear,
    interop_database_clear,
    interop_database_add,
    get_avrcp_service,
};


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, acl_state_changed_callback,
    callback_thread_event,       dut_mode_recv_callback,
    le_test_mode_recv_callback,  energy_info_recv_callback};
    
static bool initNative(JNIEnv* env, jobject obj) {
  ALOGV("%s", __func__);

  android_bluetooth_UidTraffic.clazz =
      (jclass)env->NewGlobalRef(env->FindClass("android/bluetooth/UidTraffic"));

  sJniAdapterServiceObj = env->NewGlobalRef(obj);
  sJniCallbacksObj =
      env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));

  if (!sBluetoothInterface) {
    return JNI_FALSE;
  }

  int ret = sBluetoothInterface->init(&sBluetoothCallbacks);
  
  
  
  bt/btif/src/Bluetooth.cc
static int init(bt_callbacks_t* callbacks) {
 // LOG_INFO(LOG_TAG, "%s", __func__);

  if (interface_ready()) return BT_STATUS_DONE;

#ifdef BLUEDROID_DEBUG
  allocation_tracker_init();
#endif

  bt_hal_cbacks = callbacks;
  stack_manager_get_interface()->init_stack();
  btif_debug_init();
  return BT_STATUS_SUCCESS;
}

  HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
                &bd_addr, BT_ACL_STATE_CONNECTED);
终于将上下联系起来了!
  
       

<think>好的,我现在需要解决用户的问题:“如何根据 method_onParamsUpdated找出真正回调的实现”。首先,我要理解用户的问题。用户可能是在分析或调试JNI代码时遇到了困难,特别是在处理异步回调时。用户提到的method_onParamsUpdated看起来是一个JNI方法,可能用于回调Java层,但用户想知道如何追踪到具体的Java实现。 首先,我应该回顾之前提供的执行链示例。在阶段4.2中,提到了base::Bind(&callJniCallback, method_onParamsUpdated, advertiser_id)。这里的method_onParamsUpdated应该是一个JNI方法ID,用于在C++层调用Java层的回调方法。用户想知道如何通过这个methodID找到对应的Java实现。 接下来,我需要思考用户可能的场景。用户可能是在查看JNI代码时,发现了method_onParamsUpdated的使用,但不知道对应的Java方法在哪里定义。或者可能是在调试时遇到回调未触发的问题,需要确认回调是否正确绑定。 用户可能的身份是Android开发人员,或者是正在进行蓝牙相关模块开发的工程师。他们可能对JNI和Android的蓝牙协议栈有一定了解,但在处理JNI回调时遇到了困难。 用户的需求不仅仅是找到方法的位置,还可能包括如何调试回调问题,比如回调未触发或参数错误。深层需求可能包括理解整个JNI回调机制,确保回调正确绑定,或者解决实际开发中的问题。 接下来,我需要整理解决这个问题的步骤。首先,确定methodID是如何获取的。通常,在JNI中,方法ID是通过GetMethodID函数获取的,需要类名、方法名和签名。因此,用户需要找到获取method_onParamsUpdated的地方,查看对应的类名和方法签名。 然后,根据类名和方法签名,在Java代码中查找对应的回调方法。例如,如果method_onParamsUpdated对应的类是com.example.BluetoothLeAdvertiser,方法名为onParamsUpdated,签名是(II)V,那么可以在对应的Java类中找到该方法。 此外,还需要考虑动态注册和静态注册的区别。如果使用动态注册,JNI方法可能通过RegisterNatives绑定,此时需要查看注册时的参数。如果是静态注册,方法名需要遵循特定的命名规则。 还可能涉及线程问题,比如回调是否在主线程执行,是否需要使用JNIEnv的正确实例。此外,全局引用和局部引用的管理也可能影响回调是否被正确调用。 总结可能的解决步骤: 1. 在JNI代码中查找method_onParamsUpdated的获取位置,确定类名、方法名和签名。 2. 根据类名在Java代码中找到对应的类。 3. 在Java类中查找符合方法名和签名的方法。 4. 检查回调的注册和触发逻辑,确保正确绑定。 5. 调试时检查JNI调用是否成功,是否有异常抛出。 同时,需要提醒用户注意JNI的常见问题,比如方法签名错误、类名错误、线程问题等,这些可能导致无法找到回调方法或回调未被正确触发。</think>--- ### **逐步解析:如何追踪 `method_onParamsUpdated` 对应的 Java 回调实现** --- #### **步骤 1:定位 JNI 层 `method_onParamsUpdated` 的获取位置** 在 JNI 代码中搜索 `method_onParamsUpdated` 的定义和初始化位置,通常出现在以下场景: ```cpp // 示例:JNI 层获取 methodID jmethodID method_onParamsUpdated = env->GetMethodID( clazz, // Java 类对象 "onPeriodicAdvertisingParametersUpdated", // 方法名 "(II)V" // 方法签名(参数:int advertiserId, int status) ); ``` **关键点**: - **类对象 `clazz`**:通过 `FindClass` 或已缓存的类引用确定 Java 类路径(如 `com/android/bluetooth/le/BluetoothLeAdvertiser`) - **方法签名 `(II)V`**:表示该方法接受两个 `int` 参数,返回 `void` --- #### **步骤 2:根据类路径定位 Java 实现** 假设 `clazz` 对应的类路径为 `com.android.bluetooth.le.BluetoothLeAdvertiser`,在 Java 代码中查找该类: ```java // Java 类路径:frameworks/base/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java public class BluetoothLeAdvertiser { // 回调方法声明(需匹配方法名和签名) private void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) { // 处理参数更新结果 } } ``` **验证点**: 1. 方法名是否与 JNI 中的 `"onPeriodicAdvertisingParametersUpdated"` 一致 2. 方法签名是否匹配 `(II)V`(两个 `int` 参数,无返回值) --- #### **步骤 3:调试确认回调触发路径** 若无法直接定位代码,可通过以下调试手段验证: ##### **3.1 注入日志** 在 JNI 调用回调前添加日志: ```cpp // JNI 层调用 Java 回调 env->CallVoidMethod(callbackObj, method_onParamsUpdated, advertiserId, status); __android_log_print(ANDROID_LOG_DEBUG, "JNI", "Called method_onParamsUpdated"); ``` 在 Java 回调方法中添加日志: ```java private void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) { Log.d("JavaCallback", "onParamsUpdated: advertiserId=" + advertiserId + ", status=" + status); } ``` ##### **3.2 检查异常** 在 JNI 调用后检查是否抛异常: ```cpp if (env->ExceptionCheck()) { env->ExceptionDescribe(); // 打印异常信息 env->ExceptionClear(); } ``` --- #### **步骤 4:逆向工程辅助(无源码场景)** 若需分析预编译的 SDK 或系统库,可通过以下方式: ##### **4.1 反编译 Java 类** 使用工具(如 `jadx`)反编译 APK 或系统 JAR 包,搜索方法名 `onPeriodicAdvertisingParametersUpdated`。 ##### **4.2 分析 JNI 符号表** 从原生库(`.so` 文件)中提取符号信息: ```bash nm -D libbluetooth_jni.so | grep method_onParamsUpdated ``` 若符号未剥离,可能显示关联的 JNI 函数名。 --- #### **典型问题排查表** | 问题现象 | 可能原因 | 解决方案 | |---------------------------|-----------------------------|-----------------------------| | 回调未触发 | 方法名/签名不匹配 | 检查 JNI `GetMethodID` 参数 | | 崩溃在 `CallVoidMethod` | 未正确获取 `jmethodID` | 确保类已加载且方法存在 | | 参数值错误 | JNIJava 参数顺序不一致 | 对比方法签名与实际参数 | --- ### **总结** 1. **核心链路**:`JNI 获取 methodID → Java 类中匹配方法名和签名 → 触发回调` 2. **调试工具**:日志注入、异常检查、反编译工具 3. **关键验证**:方法名、签名、类路径三者的严格一致性 通过以上步骤,可精准定位 `method_onParamsUpdated` 对应的 Java 回调实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值