Android 12 Bluetooth源码分析蓝牙配对

本文主要是列出一些蓝牙配对重要的类和方法/函数,遇到相关问题时方便查找添加log排查。

蓝牙扫描列表页面:packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java点击其中一个设备会调用:onPreferenceTreeClick()

java 复制代码
    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        if (KEY_BT_SCAN.equals(preference.getKey())) {
            startScanning();
            return true;
        }

        if (preference instanceof BluetoothDevicePreference) {
            BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;
            CachedBluetoothDevice device = btPreference.getCachedDevice();
            mSelectedDevice = device.getDevice();
            mSelectedList.add(mSelectedDevice);
            //配对
            onDevicePreferenceClick(btPreference);
            return true;
        }

        return super.onPreferenceTreeClick(preference);
    }

接着调用 packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java

java 复制代码
void onClicked() {
        Context context = getContext();
        int bondState = mCachedDevice.getBondState();

        final MetricsFeatureProvider metricsFeatureProvider =
                FeatureFactory.getFactory(context).getMetricsFeatureProvider();

        if (mCachedDevice.isConnected()) {
            metricsFeatureProvider.action(context,
                    SettingsEnums.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);
            askDisconnect();
        } else if (bondState == BluetoothDevice.BOND_BONDED) {
            metricsFeatureProvider.action(context,
                    SettingsEnums.ACTION_SETTINGS_BLUETOOTH_CONNECT);
            mCachedDevice.connect();
        } else if (bondState == BluetoothDevice.BOND_NONE) {
            metricsFeatureProvider.action(context,
                    SettingsEnums.ACTION_SETTINGS_BLUETOOTH_PAIR);
            if (!mCachedDevice.hasHumanReadableName()) {
                metricsFeatureProvider.action(context,
                        SettingsEnums.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
            }
            pair();//配对
        }
    }

继续调用

java 复制代码
public boolean startPairing() {
        // Pairing is unreliable while scanning, so cancel discovery
        if (mLocalAdapter.isDiscovering()) {
            mLocalAdapter.cancelDiscovery();
        }
        //创建配对
        if (!mDevice.createBond()) {
            return false;
        }

        return true;
    }

一直往下会到BluetoothDevice.java,在里面调用了IBuletooth.aidl

复制代码
frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
java 复制代码
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,
            @Nullable OobData remoteP256Data) {
        final IBluetooth service = sService;
        if (service == null) {
            Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
            return false;
        }
        try {
            return service.createBond(
                    this, transport, remoteP192Data, remoteP256Data, mAttributionSource);
        } catch (RemoteException e) {
            Log.e(TAG, "", e);
        }
        return false;
    }

在AdapterService.java里实现了IBluetooth.Stub

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

java 复制代码
@VisibleForTesting
    public static class AdapterServiceBinder extends IBluetooth.Stub {
        private AdapterService mService;

        AdapterServiceBinder(AdapterService svc) {
            mService = svc;
            mService.invalidateBluetoothGetStateCache();
            BluetoothAdapter.getDefaultAdapter().disableBluetoothGetStateCache();
        }
        .....省略


        @Override
        public boolean createBond(BluetoothDevice device, int transport, OobData remoteP192Data,
                OobData remoteP256Data, AttributionSource attributionSource) {
            Attributable.setAttributionSource(device, attributionSource);
            AdapterService service = getService();
            if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG, "createBond")
                    || !Utils.checkConnectPermissionForDataDelivery(
                            service, attributionSource, "AdapterService createBond")) {
                return false;
            }

            // This conditional is required to satisfy permission dependencies
            // since createBond calls createBondOutOfBand with null value passed as data.
            // BluetoothDevice#createBond requires BLUETOOTH_ADMIN only.
            service.enforceBluetoothPrivilegedPermissionIfNeeded(remoteP192Data, remoteP256Data);
            //进入createBond
            return service.createBond(device, transport, remoteP192Data, remoteP256Data,
                    attributionSource.getPackageName());
        }
    }
java 复制代码
boolean createBond(BluetoothDevice device, int transport, OobData remoteP192Data,
            OobData remoteP256Data, String callingPackage) {
        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
        if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
            return false;
        }

        if (!isPackageNameAccurate(this, callingPackage, Binder.getCallingUid())) {
            return false;
        }

        CallerInfo createBondCaller = new CallerInfo();
        createBondCaller.callerPackageName = callingPackage;
        createBondCaller.user = UserHandle.of(UserHandle.getCallingUserId());
        mBondAttemptCallerInfo.put(device.getAddress(), createBondCaller);

        mRemoteDevices.setBondingInitiatedLocally(Utils.getByteAddress(device));

        // Pairing is unreliable while scanning, so cancel discovery
        // Note, remove this when native stack improves
        cancelDiscoveryNative();

        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
        msg.obj = device;
        msg.arg1 = transport;

        Bundle remoteOobDatasBundle = new Bundle();
        boolean setData = false;
        if (remoteP192Data != null) {
            remoteOobDatasBundle.putParcelable(BondStateMachine.OOBDATAP192, remoteP192Data);
            setData = true;
        }
        if (remoteP256Data != null) {
            remoteOobDatasBundle.putParcelable(BondStateMachine.OOBDATAP256, remoteP256Data);
            setData = true;
        }
        if (setData) {
            msg.setData(remoteOobDatasBundle);
        }
        //发送配对message
        mBondStateMachine.sendMessage(msg);
        return true;
    }

接着进入packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java

java 复制代码
private boolean createBond(BluetoothDevice dev, int transport, OobData remoteP192Data,
            OobData remoteP256Data, boolean transition) {
        if (dev.getBondState() == BluetoothDevice.BOND_NONE) {
            infoLog("Bond address is:" + dev);
            byte[] addr = Utils.getBytesFromAddress(dev.getAddress());
            boolean result;
            // If we have some data
            if (remoteP192Data != null || remoteP256Data != null) {
                result = mAdapterService.createBondOutOfBandNative(addr, transport,
                    remoteP192Data, remoteP256Data);
            } else {
                //调用了native的代码
                result = mAdapterService.createBondNative(addr, transport);
            }
            BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED,
                    mAdapterService.obfuscateAddress(dev), transport, dev.getType(),
                    BluetoothDevice.BOND_BONDING,
                    remoteP192Data == null && remoteP256Data == null
                            ? BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN
                            : BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED,
                    BluetoothProtoEnums.UNBOND_REASON_UNKNOWN);

            if (!result) {
                BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED,
                        mAdapterService.obfuscateAddress(dev), transport, dev.getType(),
                        BluetoothDevice.BOND_NONE, BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN,
                        BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS);
                // Using UNBOND_REASON_REMOVED for legacy reason
                sendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);
                return false;
            } else if (transition) {
                transitionTo(mPendingCommandState);
            }
            return true;
        }
        return false;
    }

这里调到了JNI层的代码,进入packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

java 复制代码
static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address,
                                 jint transport) {
  ALOGV("%s", __func__);

  if (!sBluetoothInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
  if (addr == NULL) {
    jniThrowIOException(env, EINVAL);
    return JNI_FALSE;
  }
  //调用hal层的配对函数
  int ret = sBluetoothInterface->create_bond((RawAddress*)addr, transport);
  env->ReleaseByteArrayElements(address, addr, 0);
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

调用到了hal层的代码,在蓝牙协议栈里 system/bt/btif/src/bluetooth.cc

cpp 复制代码
static int create_bond(const RawAddress* bd_addr, int transport) {
  if (!interface_ready()) return BT_STATUS_NOT_READY;
  if (btif_dm_pairing_is_busy()) return BT_STATUS_BUSY;

    //调用了btif_dm_create_bond
  do_in_main_thread(FROM_HERE,
                    base::BindOnce(btif_dm_create_bond, *bd_addr, transport));
  return BT_STATUS_SUCCESS;
}

调用到了system/bt/btif/src/btif_dm.cc

cpp 复制代码
/*******************************************************************************
 *
 * Function         btif_dm_create_bond
 *
 * Description      Initiate bonding with the specified device
 *
 ******************************************************************************/
void btif_dm_create_bond(const RawAddress bd_addr, int transport) {
  BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __func__,
                   bd_addr.ToString().c_str(), transport);
  btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND,
                            pairing_cb.state);

  pairing_cb.timeout_retries = NUM_TIMEOUT_RETRIES;
  btif_dm_cb_create_bond(bd_addr, transport);
}
cpp 复制代码
static void btif_dm_cb_create_bond(const RawAddress bd_addr,
                                   tBT_TRANSPORT transport) {
  bool is_hid = check_cod(&bd_addr, COD_HID_POINTING);
  bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);

  int device_type = 0;
  tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC;
  std::string addrstr = bd_addr.ToString();
  const char* bdstr = addrstr.c_str();
  if (transport == BT_TRANSPORT_LE) {
    if (!btif_config_get_int(bdstr, "DevType", &device_type)) {
      btif_config_set_int(bdstr, "DevType", BT_DEVICE_TYPE_BLE);
    }
    if (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) !=
        BT_STATUS_SUCCESS) {
      // Try to read address type. OOB pairing might have set it earlier, but
      // didn't store it, it defaults to BLE_ADDR_PUBLIC
      uint8_t tmp_dev_type;
      tBLE_ADDR_TYPE tmp_addr_type = BLE_ADDR_PUBLIC;
      BTM_ReadDevInfo(bd_addr, &tmp_dev_type, &tmp_addr_type);
      addr_type = tmp_addr_type;

      btif_storage_set_remote_addr_type(&bd_addr, addr_type);
    }
  }
  if ((btif_config_get_int(bdstr, "DevType", &device_type) &&
       (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) ==
        BT_STATUS_SUCCESS) &&
       (device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) ||
      (transport == BT_TRANSPORT_LE)) {
    BTA_DmAddBleDevice(bd_addr, addr_type, device_type);
  }

  if (is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0) {
    bt_status_t status;
    status = (bt_status_t)btif_hh_connect(&bd_addr);
    if (status != BT_STATUS_SUCCESS)
      bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);
  } else {
    //执行到这个方法
    BTA_DmBond(bd_addr, addr_type, transport, device_type);
  }
  /*  Track  originator of bond creation  */
  pairing_cb.is_local_initiated = true;
}

这个函数BTA_DmBond里调用到了system/bt/bta/dm/bta_dm_act.cc

cpp 复制代码
/** Bonds with peer device */
void bta_dm_bond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
                 tBT_TRANSPORT transport, int device_type) {
  tBTA_DM_SEC sec_event;
  char* p_name;
  
  //在BTM_SecBond函数发送配对信息,蓝牙地址、数据、命令等信息
  tBTM_STATUS status =
      (bluetooth::shim::is_gd_security_enabled())
          ? bluetooth::shim::BTM_SecBond(bd_addr, addr_type, transport,
                                         device_type)
          : BTM_SecBond(bd_addr, addr_type, transport, device_type, 0, NULL);

  if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)) {
    memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
    sec_event.auth_cmpl.bd_addr = bd_addr;
    p_name = (bluetooth::shim::is_gd_security_enabled())
                 ? bluetooth::shim::BTM_SecReadDevName(bd_addr)
                 : BTM_SecReadDevName(bd_addr);
    if (p_name != NULL) {
      memcpy(sec_event.auth_cmpl.bd_name, p_name, BD_NAME_LEN);
      sec_event.auth_cmpl.bd_name[BD_NAME_LEN] = 0;
    }

    /*      taken care of by memset [above]
            sec_event.auth_cmpl.key_present = false;
            sec_event.auth_cmpl.success = false;
    */
    sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND;
    if (status == BTM_SUCCESS) {
      sec_event.auth_cmpl.success = true;
    } else {
      /* delete this device entry from Sec Dev DB */
      bta_dm_remove_sec_dev_entry(bd_addr);
    }
    bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
  }
}

来到system/bt/stack/btm/btm_sec.cc,最终在这里发送命令给HCI与硬件打交道

cpp 复制代码
/*******************************************************************************
 *
 * Function         BTM_SecBond
 *
 * Description      This function is called to perform bonding with peer device.
 *                  If the connection is already up, but not secure, pairing
 *                  is attempted.  If already paired BTM_SUCCESS is returned.
 *
 * Parameters:      bd_addr      - Address of the device to bond
 *                  transport    - doing SSP over BR/EDR or SMP over LE
 *                  pin_len      - length in bytes of the PIN Code
 *                  p_pin        - pointer to array with the PIN Code
 *
 *  Note: After 2.1 parameters are not used and preserved here not to change API
 ******************************************************************************/
tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
                        tBT_TRANSPORT transport, int device_type,
                        uint8_t pin_len, uint8_t* p_pin) {
  if (bluetooth::shim::is_gd_shim_enabled()) {
    return bluetooth::shim::BTM_SecBond(bd_addr, addr_type, transport,
                                        device_type);
  }

  if (transport == BT_TRANSPORT_INVALID)
    transport = BTM_UseLeLink(bd_addr) ? BT_TRANSPORT_LE : BT_TRANSPORT_BR_EDR;

  tBT_DEVICE_TYPE dev_type;

  BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
  /* LE device, do SMP pairing */
  if ((transport == BT_TRANSPORT_LE && (dev_type & BT_DEVICE_TYPE_BLE) == 0) ||
      (transport == BT_TRANSPORT_BR_EDR &&
       (dev_type & BT_DEVICE_TYPE_BREDR) == 0)) {
    return BTM_ILLEGAL_ACTION;
  }
  //执行btm_sec_bond_by_transport函数
  return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin);
}


/*******************************************************************************
 *
 * Function         btm_sec_bond_by_transport
 *
 * Description      this is the bond function that will start either SSP or SMP.
 *
 * Parameters:      bd_addr      - Address of the device to bond
 *                  pin_len      - length in bytes of the PIN Code
 *                  p_pin        - pointer to array with the PIN Code
 *
 *  Note: After 2.1 parameters are not used and preserved here not to change API
 ******************************************************************************/
tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr,
                                      tBT_TRANSPORT transport, uint8_t pin_len,
                                      uint8_t* p_pin) {

  //....代码太多,最底层就是发送控制命令

  if (!controller_get_interface()->supports_simple_pairing()) {
    /* The special case when we authenticate keyboard.  Set pin type to fixed */
    /* It would be probably better to do it from the application, but it is */
    /* complicated */
    if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
         BTM_COD_MAJOR_PERIPHERAL) &&
        (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD) &&
        (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) {
      btm_cb.pin_type_changed = true;
      
      //通过HCI向底层发送命令
      btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED);
    }
  }
  return status;
}

到这里就结束了,后面就是控制硬件发起配对操作。

相关推荐
愤怒的代码7 分钟前
Spring Boot对访问密钥加密解密——RSA
java·spring boot·后端
美美的海顿8 分钟前
springboot基于Java的校园导航微信小程序的设计与实现
java·数据库·spring boot·后端·spring·微信小程序·毕业设计
愤怒的代码10 分钟前
Spring Boot中幂等性的应用
java·spring boot·后端
silver68711 分钟前
JAVA8 Stream API 使用详解
java
武子康13 分钟前
大数据-259 离线数仓 - Griffin架构 修改配置 pom.xml sparkProperties 编译启动
xml·java·大数据·hive·hadoop·架构
IT 古月方源24 分钟前
ensp 关于ARRP 的讲解 配置
运维·开发语言·网络·tcp/ip·智能路由器
西猫雷婶29 分钟前
python学opencv|读取图像(二十二)使用cv2.polylines()绘制多边形
开发语言·python·opencv
温轻舟32 分钟前
前端开发 -- 自定义鼠标指针样式
开发语言·前端·javascript·css·html·温轻舟
xiaocaibao7771 小时前
编程语言的软件工程
开发语言·后端·golang
天天打码1 小时前
ThinkPHP项目如何关闭runtime下Log日志文件记录
android·java·javascript