打开手机/手表的蓝牙,就能在列表中看到扫描到的蓝牙,点击就可以实现配对功能。目前手表支持与所有设备的配对,但是仅支持与耳机类型的设备进行连接

安全简易配对SSP(Secure simple pairing),蓝牙2.0之后配对方式,简易安全配对一共有四种,其中Out of Band很少使用到,具体如下:
Numeric Comparison
配对双方都显示一个6位的数字,由用户来核对数字是否一致,并输入Yes/No,两端Yes表示一致即可配对,可以防止中间人攻击。
使用场景:两端设备可以弹出6位十进制数,并且有yes和no按钮。

Passkey Entry
配对目标输入一个在本地设备上显示的6位数字,输入正确即可配对,并可以防止中间人攻击。
使用场景:一端设备可以显示,另一端设备可以输入。

Just Works
不会进行鉴权,不能防止中间人攻击用于配对没有显示没有输入的设备,主动发起连接即可配对,用户看不到配对过程,不可以防止中间人攻击,例如连接蓝牙耳机。
使用场景:用于即不能显示6位随机数,也不能输入的设备。

Out of Band
两设备的通过别的途径交换配对信息,例如一些NFC蓝牙音箱。

一、原生应用设置界面的packages\Settings

目录:android\packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothDevicePreference.java

void onClicked() {int bondState = mCachedDevice.getBondState();if (mCachedDevice.isConnected()) {askDisconnect();//断开连接} else if (bondState == BluetoothDevice.BOND_BONDED) {mCachedDevice.connect(true);//已经配对了就连接} else if (bondState == BluetoothDevice.BOND_NONE) {pair();//没有配对的话就去配对}
}
private void pair() {if (!mCachedDevice.startPairing()) {Utils.showError(getContext(), mCachedDevice.getName(),R.string.bluetooth_pairing_error_message);} else {final Context context = getContext();SearchIndexableRaw data = new SearchIndexableRaw(context);data.className = BluetoothSettings.class.getName();data.title = mCachedDevice.getName();data.screenTitle = context.getResources().getString(R.string.bluetooth_settings);data.iconResId = R.drawable.ic_settings_bluetooth;data.enabled = true;Index.getInstance(context).updateFromSearchIndexableData(data);}
}

Y:\HLOS\frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth\CachedBluetoothDevice.java

public boolean startPairing() {// Pairing is unreliable while scanning, so cancel discoveryif (mLocalAdapter.isDiscovering()) {mLocalAdapter.cancelDiscovery();//如果设备正在搜索,就取消搜索}if (!mDevice.createBond()) {//配对return false;}mConnectAfterPairing = true;  // auto-connect after pairingreturn true;}

二、framework层配对逻辑

Y:\HLOS\frameworks\base\core\java\android\bluetooth\BluetoothDevice.java

public boolean createBond() {if (sService == null) {Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");return false;}try {Log.i(TAG, "createBond() for device " + getAddress() +" called by pid: " + Process.myPid() +" tid: " + Process.myTid());return sService.createBond(this, TRANSPORT_AUTO);//跨进程调用到AdapterService中的方法} catch (RemoteException e) {Log.e(TAG, "", e);}return false;}

三、frameworks的aidl文件

private static IBluetooth sService;

HLOS\frameworks\base\core\java\android\bluetooth\IBluetooth.aidl
boolean createBond(in BluetoothDevice device);
这个是属于跨进程通信的方法,通过IBluetooth.aidl文件,调用到AdapterService.java中的createBond方法

四、从framework跨进程调到packages\Bluetooth

Y:\HLOS\packages\apps\Bluetooth\src\com\android\bluetooth\btservice\AdapterService.java

public boolean createBond(BluetoothDevice device, int transport) {if (!Utils.checkCallerAllowManagedProfiles(mService)) {Log.w(TAG, "createBond() - Not allowed for non-active user");return false;}AdapterService service = getService();if (service == null) return false;return service.createBond(device, transport, null);//调用本服务的createBond}

同在AdapterService文件下

boolean createBond(BluetoothDevice device, int transport, OobData oobData) {enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,"Need BLUETOOTH ADMIN permission");DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {return false;}// Multicast: Do not allow bonding while multcastA2dpService a2dpService = A2dpService.getA2dpService();if (a2dpService != null &&a2dpService.isMulticastFeatureEnabled() &&a2dpService.isMulticastOngoing(null)) {Log.i(TAG,"A2dp Multicast is ongoing, ignore bonding");return false;}// Pairing is unreliable while scanning, so cancel discovery// Note, remove this when native stack improvescancelDiscoveryNative();//配对过程,取消扫描Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);msg.obj = device;msg.arg1 = transport;if (oobData != null) {Bundle oobDataBundle = new Bundle();oobDataBundle.putParcelable(BondStateMachine.OOBDATA, oobData);msg.setData(oobDataBundle);}mBondStateMachine.sendMessage(msg);//给配对的状态机发消息,创建创建了BondStateMachine.CREATE_BONDreturn true;}

在Y:\HLOS\packages\apps\Bluetooth\src\com\android\bluetooth\btservice\BondStateMachine.java
处理服务发送过来的消息

@Overridepublic boolean processMessage(Message msg) {BluetoothDevice dev = (BluetoothDevice)msg.obj;DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev);boolean result = false;if (mDevices.contains(dev) && msg.what != CANCEL_BOND &&msg.what != BONDING_STATE_CHANGE && msg.what != SSP_REQUEST &&msg.what != PIN_REQUEST) {deferMessage(msg);return true;}Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);switch (msg.what) {case CREATE_BOND:OobData oobData = null;if (msg.getData() != null)oobData = msg.getData().getParcelable(OOBDATA);result = createBond(dev, msg.arg1, oobData, false);break;、、、}}
private boolean createBond(BluetoothDevice dev, int transport, OobData oobData,boolean transition) {if(mAdapterService == null) return false;if (dev.getBondState() == BluetoothDevice.BOND_NONE) {infoLog("Bond address is:" + dev);byte[] addr = Utils.getBytesFromAddress(dev.getAddress());boolean result;if (oobData != null) {//判读是否借助其他硬件进行无绑定配对result = mAdapterService.createBondOutOfBandNative(addr, transport, oobData);} else {result = mAdapterService.createBondNative(addr, transport);//调用到JNI层,进行配对}if (!result) {sendIntent(dev, BluetoothDevice.BOND_NONE,BluetoothDevice.UNBOND_REASON_REMOVED);return false;} else if (transition) {transitionTo(mPendingCommandState);}return true;}return false;}

五、packages\Bluetooth的java层调到jini层的cpp文件

Y:\HLOS\packages\apps\Bluetooth\jni\com_android_bluetooth_btservice_AdapterService.cpp

static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address, jint transport) {ALOGV("%s:",__FUNCTION__);jbyte *addr;jboolean result = JNI_FALSE;if (!sBluetoothInterface) return result;addr = env->GetByteArrayElements(address, NULL);if (addr == NULL) {jniThrowIOException(env, EINVAL);return result;}int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr, transport);//该接口调用到hal层的配对函数env->ReleaseByteArrayElements(address, addr, 0);result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;return result;
}

六、hal层createBond的调用

Y:\HLOS\system\bt\btif\src\bluetooth.c

static int create_bond(const bt_bdaddr_t *bd_addr, int transport)
{/* sanity check */if (interface_ready() == FALSE)return BT_STATUS_NOT_READY;return btif_dm_create_bond(bd_addr, transport);
}

Y:\HLOS\system\bt\btif\src\btif_dm.c

bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr, int transport)
{btif_dm_create_bond_cb_t create_bond_cb;create_bond_cb.transport = transport;bdcpy(create_bond_cb.bdaddr.address, bd_addr->address);bdstr_t bdstr;BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __FUNCTION__, bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);if (pairing_cb.state != BT_BOND_STATE_NONE)return BT_STATUS_BUSY;btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND, pairing_cb.state);//添加了绑定事件btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_CREATE_BOND,(char *)&create_bond_cb, sizeof(btif_dm_create_bond_cb_t), NULL);//cotext是开辟了上下文的意思,这里create_bond_cb已经包含了要绑定的蓝牙地址,会分别发送给底层两部分,最后会调用btif_dm_generic_evtreturn BT_STATUS_SUCCESS;
}

Y:\HLOS\system\bt\btif\src\btif_dm.c

static void btif_dm_generic_evt(UINT16 event, char* p_param)
{BTIF_TRACE_EVENT("%s: event=%d", __FUNCTION__, event);switch(event){case BTIF_DM_CB_DISCOVERY_STARTED:{HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STARTED);}break;case BTIF_DM_CB_CREATE_BOND://走这一路去配对{pairing_cb.timeout_retries = NUM_TIMEOUT_RETRIES;btif_dm_create_bond_cb_t *create_bond_cb = (btif_dm_create_bond_cb_t*)p_param;btif_dm_cb_create_bond(&create_bond_cb->bdaddr, create_bond_cb->transport);}break;case BTIF_DM_CB_REMOVE_BOND:{btif_dm_cb_remove_bond((bt_bdaddr_t *)p_param);}break;、、、}、、、
}
static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr, tBTA_TRANSPORT transport)
{BOOLEAN is_hid = check_cod(bd_addr, COD_HID_POINTING);bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);#if BLE_INCLUDED == TRUEint device_type;int addr_type;bdstr_t bdstr;bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr));if (transport == BT_TRANSPORT_LE){if (!btif_config_get_int((char const *)&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){btif_storage_set_remote_addr_type(bd_addr, BLE_ADDR_PUBLIC);}}if((btif_config_get_int((char const *)&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->address, addr_type, device_type);}
#endif#if BLE_INCLUDED == TRUEif(is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0)
#elseif(is_hid)
#endif{int status;status = btif_hh_connect(bd_addr);//连接?if(status != BT_STATUS_SUCCESS)bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);//绑定状态发生变化时,这里开始回调}else{BTA_DmBondByTransport((UINT8 *)bd_addr->address, transport);//第一次调用会走这里}/*  Track  originator of bond creation  */pairing_cb.is_local_initiated = TRUE;}

Y:\HLOS\system\bt\bta\dm\bta_dm_api.c

void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport)
{tBTA_DM_API_BOND *p_msg =(tBTA_DM_API_BOND *)osi_malloc(sizeof(tBTA_DM_API_BOND));p_msg->hdr.event = BTA_DM_API_BOND_EVT;bdcpy(p_msg->bd_addr, bd_addr);p_msg->transport = transport;//消息包装bta_sys_sendmsg(p_msg);//发送到另一个线程
}

七、蓝牙协议栈给线程间消息的收发

bta_sys_sendmsg这是蓝牙协议栈的进程间收发消息的机制,不是三言两语能说清楚的,若想了解,可以参考android bluedroid协议栈里面的各个组件之间的消息处理机制
根据BTA_DM_API_BOND_EVT这个类型,可以找到消息接收的地方
Y:\HLOS\system\bt\bta\dm\bta_dm_main.c

const tBTA_DM_ACTION bta_dm_action[] =
{/* device manager local device API events */bta_dm_enable,            /* 0  BTA_DM_API_ENABLE_EVT */bta_dm_disable,           /* 1  BTA_DM_API_DISABLE_EVT */bta_dm_set_dev_name,      /* 2  BTA_DM_API_SET_NAME_EVT */bta_dm_set_visibility,    /* 3  BTA_DM_API_SET_VISIBILITY_EVT */bta_dm_acl_change,        /* 8  BTA_DM_ACL_CHANGE_EVT */bta_dm_add_device,        /* 9  BTA_DM_API_ADD_DEVICE_EVT */bta_dm_close_acl,        /* 10  BTA_DM_API_ADD_DEVICE_EVT *//* security API events */bta_dm_bond,              /* 11  BTA_DM_API_BOND_EVT */bta_dm_bond_cancel,       /* 12  BTA_DM_API_BOND_CANCEL_EVT */bta_dm_pin_reply,         /* 13 BTA_DM_API_PIN_REPLY_EVT *//* power manger events */bta_dm_pm_btm_status,     /* 16 BTA_DM_PM_BTM_STATUS_EVT */bta_dm_pm_timer,          /* 17 BTA_DM_PM_TIMER_EVT*//* simple pairing events */bta_dm_confirm,           /* 18 BTA_DM_API_CONFIRM_EVT */bta_dm_set_encryption,    /* BTA_DM_API_SET_ENCRYPTION_EVT *//* out of band pairing events */bta_dm_loc_oob,           /* 20 BTA_DM_API_LOC_OOB_EVT */bta_dm_ci_io_req_act,     /* 21 BTA_DM_CI_IO_REQ_EVT */bta_dm_ci_rmt_oob_act,    /* 22 BTA_DM_CI_RMT_OOB_EVT */
、、、
}

Y:\HLOS\system\bt\bta\dm\bta_dm_act.c

void bta_dm_bond (tBTA_DM_MSG *p_data)
{tBTM_STATUS status;tBTA_DM_SEC sec_event;char        *p_name;if (p_data->bond.transport == BTA_TRANSPORT_UNKNOWN)//这里看transport类型,走不通渠道status = BTM_SecBond ( p_data->bond.bd_addr, 0, NULL, 0 );elsestatus = BTM_SecBondByTransport ( p_data->bond.bd_addr, p_data->bond.transport, 0, NULL, 0 );if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)){memset(&sec_event, 0, sizeof(tBTA_DM_SEC));bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr);p_name = BTM_SecReadDevName(p_data->bond.bd_addr);if (p_name != NULL){memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN-1));sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 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(p_data->bond.bd_addr);}bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);}}

Y:\HLOS\system\bt\stack\btm\btm_sec.c

tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport,UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
{
#if SMP_INCLUDED == TRUEtBT_DEVICE_TYPE     dev_type;tBLE_ADDR_TYPE      addr_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;}
#endifreturn btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask);
}

Y:\HLOS\system\bt\stack\btm\btm_sec.c

tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport,UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
{tBTM_SEC_DEV_REC *p_dev_rec;tBTM_STATUS      status;UINT8            *p_features;UINT8            ii;tACL_CONN        *p= btm_bda_to_acl(bd_addr, transport);BTM_TRACE_API ("btm_sec_bond_by_transport BDA: %02x:%02x:%02x:%02x:%02x:%02x",bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);BTM_TRACE_DEBUG("btm_sec_bond_by_transport: Transport used %d" , transport);/* 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);}if ((p_dev_rec = btm_find_or_alloc_dev (bd_addr)) == 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 != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_BR_EDR&&  (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
#if (BLE_INCLUDED == TRUE)||((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_LE&&  (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))
#endif){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);}memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);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;if (trusted_mask)BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUEif (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) == 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);}
#endifp_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);}}for (ii = 0; ii <= HCI_EXT_FEATURES_PAGE_MAX; ii++){p_features = p_dev_rec->features[ii];BTM_TRACE_EVENT("  remote_features page[%1d] = %02x-%02x-%02x-%02x",ii, p_features[0], p_features[1], p_features[2], p_features[3]);BTM_TRACE_EVENT("                              %02x-%02x-%02x-%02x",p_features[4], p_features[5], p_features[6], p_features[7]);}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 == TRUEp_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN;
#endif/* If connection already exists... */if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE){if (!btm_sec_start_authentication (p_dev_rec))return(BTM_NO_RESOURCES);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_SP_DEBUG ||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);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);}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);return BTM_CMD_STARTED;}/* both local and peer are 2.1  */status = btm_sec_dd_create_conn(p_dev_rec);if (status != BTM_CMD_STARTED){btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);//改变配对的状态}return status;
}

这里代码很多,每一句都看懂不现实,现摘出重要的一段看

 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);//这里就可以看到在和hci层打交道了}}

八、通过HCI向底层发送命令进行控制

BOOLEAN btsnd_hcic_write_pin_type (UINT8 type)
{BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);UINT8 *pp = (UINT8 *)(p + 1);p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;p->offset = 0;UINT16_TO_STREAM (pp, HCI_WRITE_PIN_TYPE);UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);UINT8_TO_STREAM (pp, type);btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);//这里是向hci层发命令,return (TRUE);
}

可以看出,这里是通过和hci层的通信,host告诉controlor蓝牙地址、数据、命令等,从而控制其底层硬件发起配对操作

蓝牙配对过程分析(经典蓝牙)相关推荐

  1. 蓝牙le和经典蓝牙区别_Android上的蓝牙LE数据包捕获

    蓝牙le和经典蓝牙区别 At Propeller Health we develop products that help people with asthma or COPD manage thei ...

  2. android 取消蓝牙配对框,android - 蓝牙配对 - 如何显示简单的取消/配对对话框? - 堆栈内存溢出...

    我在GitHub为这个问题准备了一个简单的测试项目 . 我正在尝试创建一个Android应用程序,它将从计算机屏幕扫描QR代码,然后使用数据(MAC地址和PIN或哈希)与蓝牙设备轻松配对(绑定). 类 ...

  3. 蓝牙配对,解决蓝牙多次连接不上的问题

    文章目录 nRF52832 配对和绑定 1.在连接时,nRF52832向蓝牙主机发送配对请求 2.主机收到配对请求后,向nRF52832发送安全参数请求,nRF52832收到后回复请求 3.判断配对是 ...

  4. 蓝牙 配对 android,Android蓝牙工具类:连接、配对、传输

    /** * Created by XingAijian * Date: 2019/6/12_17:23 * * 蓝牙工具类 */ public class BTUtils extends Activi ...

  5. Qt经典蓝牙系列四(经典蓝牙客户端的设计 纯Qt代码) android/windows10

    Qt for Bluetooth 蓝牙开发系列文章总纲 文章目录 前言 效果动态图 bluetoothClient定义与构造函数 控制本地开关,并扫描蓝牙设备 与服务器端建立socket连接 与Blu ...

  6. 【Android】蓝牙开发——经典蓝牙配对介绍(通过手机系统蓝牙演示)

    目录 一.蓝牙配对介绍 二.蓝牙配对过程 三.蓝牙配对方式展示 一.蓝牙配对介绍 蓝牙规范定义了两种标准配对过程,LMP配对(也称为基于PIN码)和SSP安全简易配对. LMP(Link Manage ...

  7. 蓝牙配对模式 java_【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码...

    目录 前言 一.连接&配对方法介绍 二.演示:第一次连接蓝牙设备  &  直接与蓝牙设备建立配对 三.总结 四.补充 五.Demo案例源码地址: 前言 前面两篇文章[Android]蓝 ...

  8. 【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码

    目录 前言 一.连接&配对方法介绍 二.演示:第一次连接蓝牙设备  &  直接与蓝牙设备建立配对 三.总结 四.补充 五.Demo案例源码地址: 前言 前面两篇文章[Android]蓝 ...

  9. 关于经典蓝牙和低功耗蓝牙的区别

    刚开发蓝牙的小伙伴在开发的时候,或许会看到经典蓝牙和低功耗蓝牙这两种,不知道它们之间的区别与联系,今天给大家介绍一下经典蓝牙和低功耗蓝牙(BLE)的区别. 文章转载自: http://www.love ...

最新文章

  1. 虚拟摄像头 安卓版_林俊杰 ft. M.E.,联同视效大厂数字王国加码虚拟偶像
  2. 类DefaultWsdl 11定义中英文对比API文档
  3. 【Nginx-20180108】Nginx的搭建文件服务器问题一则
  4. 为PHP5.4开启Zend OPCode缓存
  5. find -exec 批量使用方法
  6. uva 674 Coin Change 换钱币【完全背包】
  7. linux救援模式使用、自制linux系统和linux内核编译
  8. 不错的学习博客,有时间看看
  9. matlab进行mppt控制仿真,光伏发电系统MPPT控制仿真模型
  10. 提取swf素材_SWF素材采集软件(SWF Decompiler Magic)V5.2.2.21 免费版
  11. i7 8750h支持linux,i7-9750H和i7-8750H性能对比:差距仅5%,日常使用无区别
  12. 固态硬盘与机械硬盘读取速度实测
  13. 别傻傻分不清docker run 和 start 的区别了
  14. 点击识别元素位置、生成显示二维码、下载二维码
  15. Java Pair类的使用
  16. web自动登录方法汇总(转自老大指导)
  17. 合宙Air105|CRYPTO|加密与解密|算法|RSA|HASH函数| BASE64|MD5|SHA1|SHA256|CRC|官方demo|学习(4):CRYPTO(加密与解密)
  18. ready 和 onload 的区别
  19. OpenWrt分区扩容
  20. SAP-CDS+Odata+BOPF 创建与使用介绍,fiori一体化测试

热门文章

  1. 根据年月以及月中周次,获取该周开始,结束日期
  2. kali入门到入狱之Nmap扫描端口
  3. HTTP和FTP的区别
  4. Linux下安装SVN工具和连接svn
  5. 网页版终端webssh2配置
  6. go mysql delete_Go实现对MySQL的增删改查
  7. 解决电脑自动安装软件
  8. 解决谷歌浏览器自动添加书签问题
  9. 计算机网络教室财产登记册,一般计算机室、网络教室管理员岗位职责有哪些
  10. John the Ripper 安装