首先我们需要大致知道下HID( The Human Interface Device )是啥,手机和鼠标分别扮演什么角色,这里我们大致了解下即可,然后又在看代码。HID 定义了蓝牙在人机接口设备中的协议、特征和使用规程。典型的应用包括蓝牙鼠标、蓝牙键盘、蓝牙游戏手柄等。该协议改编自USB HID Protocol。所以和USB类似,分为host和device,host这里指手机端,device就是指鼠标、键盘这些HID设备。
蓝牙HID report分为三种:
- Input report:从hid device发送给hid host的封包
- Output report:从hid host发送给hid device的封包
总结就是以host为参考,进入host的包就是 Input report,出host的包就是 Output report - Feature report:特性封包,是双向的
HID有两条逻辑链路:
- HID Control:这个通道主要用于传输控制封包,在这个通道传输的封包称为同步封包(synchronous reports)
- HID Interrupt:在这个通道传输的封包不需要确认,所以称为异步封包(asynchronous reports)
Ok知道这些大致就差不多了,直接看代码流程吧,这里代码选取:Android 13
这里我们比如使用蓝牙鼠标连接手机,在手机界面已经搜索到蓝牙鼠标mac,点击发起连接,我们从这里去看代码,都知道蓝牙显示的界面在这里 http://aospxref.com/android-13.0.0_r3/xref/packages/apps/Settings/src/com/android/settings/bluetooth/
DeviceListPreferenceFragment.java
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);
}
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
btPreference.onClicked(); ---> 其实就是调用 BluetoothDevicePreference.onClicked()
}
http://aospxref.com/android-13.0.0_r3/xref/packages/apps/Settings/src/com/android/settings/bluetooth/
BluetoothDevicePreference.java#onClicked()
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(); // 如果未绑定,则进行配对
}
}
private void pair() {
if (!mCachedDevice.startPairing()) { ---> 配对失败提示无法配对
Utils.showError(getContext(), mCachedDevice.getName(), R.string.bluetooth_pairing_error_message);
}
}
这时候就到了Settinglib里面的代码了,
http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/
CachedBluetoothDevice.java#startPairing
public boolean startPairing() {
// 扫描时配对是不可靠的,因此取消
if (mLocalAdapter.isDiscovering()) {
mLocalAdapter.cancelDiscovery();
}
if (!mDevice.createBond()) { ---> 就是调用BluetoothDevice里面的createBond()方法
return false;
}
return true;
}
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Bluetooth/framework/java/android/bluetooth/
BluetoothDevice.java#createBond
// 在BluetoothDevice里面经过调用流程转换,最终到这里
private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,
@Nullable OobData remoteP256Data) {
if (DBG) log("createBondOutOfBand()");
final IBluetooth service = sService;
final boolean defaultValue = false;
if (service == null || !isBluetoothEnabled()) {
Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (NULL_MAC_ADDRESS.equals(mAddress)) {
Log.e(TAG, "Unable to create bond, invalid address " + mAddress);
} else {
try {
final SynchronousResultReceiver<Boolean> recv = SynchronousResultReceiver.get();
// 这里的service 就是Adaptservice,下面看这里调用的方法
service.createBond(this, transport, remoteP192Data, remoteP256Data, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
} catch (RemoteException | TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
}
}
return defaultValue;
}
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/
AdapterService.java#createBond
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 = Binder.getCallingUserHandle();
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);
}
mBondStateMachine.sendMessage(msg); ---> 其实就是到BondStateMachine里面处理 CREATE_BOND
return true;
}
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/
BondStateMachine.java#StableState
// 初始状态 setInitialState(mStableState)
private class StableState extends State {
@Override
public void enter() {
infoLog("StableState(): Entering Off State");
}
@Override
public synchronized boolean processMessage(Message msg) {
BluetoothDevice dev = (BluetoothDevice) msg.obj;
switch (msg.what) {
case CREATE_BOND:
OobData p192Data = (msg.getData() != null)
? msg.getData().getParcelable(OOBDATAP192) : null;
OobData p256Data = (msg.getData() != null)
? msg.getData().getParcelable(OOBDATAP256) : null;
createBond(dev, msg.arg1, p192Data, p256Data, true);
break;
// 继续跟下 createBond 方法
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) { ---> 可以看前面,传下来的是null,那现在就应该走下面这个分支
result = mAdapterService.createBondOutOfBandNative(addr, transport, remoteP192Data, remoteP256Data);
} else {
result = mAdapterService.createBondNative(addr, transport); ---> 看这个
}
BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_DEVICE_NAME_REPORTED,
mAdapterService.getMetricId(dev), dev.getName());
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, false);
return false;
} else if (transition) {
transitionTo(mPendingCommandState);
}
return true;
}
return false;
}
// mAdapterService.createBondNative(addr, transport)
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Bluetooth/android/app/jni/
com_android_bluetooth_btservice_AdapterService.cpp#createBondNative
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;
}
int ret = sBluetoothInterface->create_bond((RawAddress*)addr, transport); ---> 看这个
env->ReleaseByteArrayElements(address, addr, 0);
return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
// /packages/modules/Bluetooth/system/btif/src/bluetooth.cc
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;
do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_create_bond, *bd_addr, transport));
return BT_STATUS_SUCCESS;
}
继续追下 btif_dm_create_bond //packages/modules/Bluetooth/system/btif/src/btif_dm.cc
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); ---> 看这个
}
//
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,
static_cast<tBT_DEVICE_TYPE>(device_type));
}
if (is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0) {
const bt_status_t status = 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;
}
void BTA_DmBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) {
do_in_main_thread(FROM_HERE, base::Bind(bta_dm_bond, bd_addr, addr_type, transport, device_type));
}
继续看 bta_dm_bond
/** Bonds with peer device */
void bta_dm_bond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
tBT_TRANSPORT transport, tBT_DEVICE_TYPE device_type) {
LOG_DEBUG("Bonding with peer device:%s type:%s transport:%s type:%s",
PRIVATE_ADDRESS(bd_addr), AddressTypeText(addr_type).c_str(),
bt_transport_text(transport).c_str(),
DeviceTypeText(device_type).c_str());
tBTA_DM_SEC sec_event;
char* p_name;
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);
}
}
tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
tBT_TRANSPORT transport, tBT_DEVICE_TYPE 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_AUTO) {
if (addr_type == BLE_ADDR_PUBLIC) {
transport =
BTM_UseLeLink(bd_addr) ? BT_TRANSPORT_LE : BT_TRANSPORT_BR_EDR;
} else {
LOG_INFO("Forcing transport LE (was auto) because of the address type");
transport = BT_TRANSPORT_LE;
}
}
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;
}
return btm_sec_bond_by_transport(bd_addr, addr_type, 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,
tBLE_ADDR_TYPE addr_type,
tBT_TRANSPORT transport, uint8_t pin_len,
uint8_t* p_pin) {
tBTM_SEC_DEV_REC* p_dev_rec;
tBTM_STATUS status;
VLOG(1) << __func__ << " BDA: " << bd_addr;
BTM_TRACE_DEBUG("%s: Transport used %d, bd_addr=%s", __func__, transport,
bd_addr.ToString().c_str());
/* Other security process is in progress */
if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) {
BTM_TRACE_ERROR("BTM_SecBond: already busy in state: %s",
btm_pair_state_descr(btm_cb.pairing_state));
return (BTM_WRONG_MODE);
}
p_dev_rec = btm_find_or_alloc_dev(bd_addr);
if (p_dev_rec == NULL) {
return (BTM_NO_RESOURCES);
}
if (!controller_get_interface()->get_is_ready()) {
BTM_TRACE_ERROR("%s controller module is not ready", __func__);
return (BTM_NO_RESOURCES);
}
BTM_TRACE_DEBUG("before update sec_flags=0x%x", p_dev_rec->sec_flags);
/* Finished if connection is active and already paired */
if (((p_dev_rec->hci_handle != HCI_INVALID_HANDLE) &&
transport == BT_TRANSPORT_BR_EDR &&
(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) ||
((p_dev_rec->ble_hci_handle != HCI_INVALID_HANDLE) &&
transport == BT_TRANSPORT_LE &&
(p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))) {
BTM_TRACE_WARNING("BTM_SecBond -> Already Paired");
return (BTM_SUCCESS);
}
/* Tell controller to get rid of the link key if it has one stored */
if ((BTM_DeleteStoredLinkKey(&bd_addr, NULL)) != BTM_SUCCESS)
return (BTM_NO_RESOURCES);
/* Save the PIN code if we got a valid one */
if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0)) {
btm_cb.pin_code_len = pin_len;
p_dev_rec->pin_code_length = pin_len;
memcpy(btm_cb.pin_code, p_pin, PIN_CODE_LEN);
}
btm_cb.pairing_bda = bd_addr;
btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD;
p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE;
p_dev_rec->is_originator = true;
BTM_LogHistory(kBtmLogTag, bd_addr, "Bonding initiated", bt_transport_text(transport));
if (transport == BT_TRANSPORT_LE) {
btm_ble_init_pseudo_addr(p_dev_rec, bd_addr);
p_dev_rec->sec_flags &= ~BTM_SEC_LE_MASK;
if (SMP_Pair(bd_addr, addr_type) == SMP_STARTED) { ---> 配对
btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
return BTM_CMD_STARTED;
}
btm_cb.pairing_flags = 0;
return (BTM_NO_RESOURCES);
}
p_dev_rec->sec_flags &=
~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED |
BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED);
BTM_TRACE_DEBUG("after update sec_flags=0x%x", p_dev_rec->sec_flags);
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;
btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED);
}
}
BTM_TRACE_EVENT("BTM_SecBond: Remote sm4: 0x%x HCI Handle: 0x%04x",
p_dev_rec->sm4, p_dev_rec->hci_handle);
#if (BTM_SEC_FORCE_RNR_FOR_DBOND == TRUE)
p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN;
#endif
/* If connection already exists... */
if (BTM_IsAclConnectionUpAndHandleValid(bd_addr, transport)) {
btm_sec_wait_and_start_authentication(p_dev_rec);
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
/* Mark lcb as bonding */
l2cu_update_lcb_4_bonding(bd_addr, true);
return (BTM_CMD_STARTED);
}
BTM_TRACE_DEBUG("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4);
if (!controller_get_interface()->supports_simple_pairing() ||
(p_dev_rec->sm4 == BTM_SM4_KNOWN)) {
if (btm_sec_check_prefetch_pin(p_dev_rec)) return (BTM_CMD_STARTED);
}
if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
btm_cb.security_mode == BTM_SEC_MODE_SC) &&
BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
/* local is 2.1 and peer is unknown */
if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) {
/* we are not accepting connection request from peer
* -> RNR (to learn if peer is 2.1)
* RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME);
status = BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR);
} else {
/* We are accepting connection request from peer */
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
status = BTM_CMD_STARTED;
}
BTM_TRACE_DEBUG("State:%s sm4: 0x%x sec_state:%d",
btm_pair_state_descr(btm_cb.pairing_state), p_dev_rec->sm4,
p_dev_rec->sec_state);
} else {
/* both local and peer are 2.1 */
status = btm_sec_dd_create_conn(p_dev_rec);
}
if (status != BTM_CMD_STARTED) {
BTM_TRACE_ERROR(
"%s BTM_ReadRemoteDeviceName or btm_sec_dd_create_conn error: 0x%x",
__func__, (int)status);
btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
}
return status;
}
这块代码有点多,细节找个时间再细细追下,先为了流程我们可以大致知道这个如果配对上就会回调状态给上层,比如这样的log打印:
09-19 14:49:07.917 17238 17294 I BluetoothBondStateMachine: bondStateChangeCallback: Status: 0 Address: FC:25:4B:6B:40:D0 newState: 1 hciReason: 0 —> 1 表示 BOND_STATE_BONDING
09-19 14:49:11.532 17238 17294 I BluetoothBondStateMachine: bondStateChangeCallback: Status: 0 Address: FC:25:4B:6B:40:D0 newState: 2 hciReason: 0 —> 2 表示 BOND_STATE_BONDED
所以只要我们看到回调的结果是 BOND_STATE_BONDED,就表示连接成功了
看下连接成功后代码:http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Bluetooth/android/app/src/
com/android/bluetooth/btservice/BondStateMachine.java#455文章来源:https://www.toymoban.com/news/detail-845407.html
455 void bondStateChangeCallback(int status, byte[] address, int newState, int hciReason) {
456 BluetoothDevice device = mRemoteDevices.getDevice(address);
457 // 配对成功的device
458 if (device == null) {
459 infoLog("No record of the device:" + device);
460 // This device will be added as part of the BONDING_STATE_CHANGE intent processing
461 // in sendIntent above
462 device = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
463 }
464 // hciReason 表示原因,看这里的说明 AdapterService.java#4473
465 infoLog("bondStateChangeCallback: Status: " + status + " Address: " + device + " newState: "
466 + newState + " hciReason: " + hciReason);
467
468 Message msg = obtainMessage(BONDING_STATE_CHANGE);
469 msg.obj = device;
470
471 if (newState == BOND_STATE_BONDED) {
472 msg.arg1 = BluetoothDevice.BOND_BONDED;
473 } else if (newState == BOND_STATE_BONDING) {
474 msg.arg1 = BluetoothDevice.BOND_BONDING;
475 } else {
476 msg.arg1 = BluetoothDevice.BOND_NONE;
477 }
478 msg.arg2 = status;
479
480 sendMessage(msg); --->发送这个消息 BONDING_STATE_CHANGE
481 }
// PendingCommandState 状态里面处理
218 case BONDING_STATE_CHANGE:
219 int newState = msg.arg1;
220 int reason = getUnbondReasonFromHALCode(msg.arg2);
221 // Bond is explicitly removed if we are in pending command state
222 if (newState == BluetoothDevice.BOND_NONE
223 && reason == BluetoothDevice.BOND_SUCCESS) {
224 reason = BluetoothDevice.UNBOND_REASON_REMOVED;
225 }
226 sendIntent(dev, newState, reason, false); ---> 做些判断,然后发送ACTION_BOND_STATE_CHANGED广播
227 if (newState != BluetoothDevice.BOND_BONDING) {
228 // This is either none/bonded, remove and transition, and also set
229 // result=false to avoid adding the device to mDevices.
230 mDevices.remove(dev);
231 result = false;
232 if (mDevices.isEmpty()) {
233 transitionTo(mStableState); ---> 切换到这个状态
234 }
235 if (newState == BluetoothDevice.BOND_NONE) {
236 mAdapterService.setPhonebookAccessPermission(dev,
237 BluetoothDevice.ACCESS_UNKNOWN);
238 mAdapterService.setMessageAccessPermission(dev,
239 BluetoothDevice.ACCESS_UNKNOWN);
240 mAdapterService.setSimAccessPermission(dev,
241 BluetoothDevice.ACCESS_UNKNOWN);
242 // Set the profile Priorities to undefined
243 clearProfilePriority(dev);
244 }
245 } else if (!mDevices.contains(dev)) {
246 result = true;
247 }
248 break;
收到 ACTION_BOND_STATE_CHANGED 广播的地方就会做一些逻辑处理,支持,连接流程大致梳理完毕。文章来源地址https://www.toymoban.com/news/detail-845407.html
到了这里,关于蓝牙鼠标HID设备连接流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!