关注我,更多程序猿的日常信息等你哦

1 、UI

DeviceListPreferenceFragment是蓝牙扫描到的设备列表,点击其中一个蓝牙设备,调用onPreferenceTreeClick方法开始蓝牙的配对过程。

/packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java

public boolean onPreferenceTreeClick(Preference preference) {if (KEY_BT_SCAN.equals(preference.getKey())) {mLocalAdapter.startScanning(true);return true;}if (preference instanceof BluetoothDevicePreference) {BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;CachedBluetoothDevice device = btPreference.getCachedDevice();mSelectedDevice = device.getDevice();onDevicePreferenceClick(btPreference);return true;}return super.onPreferenceTreeClick(preference);
}
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {btPreference.onClicked();
}

/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java

void onClicked() {Context context = getContext();int bondState = mCachedDevice.getBondState();final MetricsFeatureProvider metricsFeatureProvider =FeatureFactory.getFactory(context).getMetricsFeatureProvider();if (mCachedDevice.isConnected()) {metricsFeatureProvider.action(context,MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);askDisconnect();} else if (bondState == BluetoothDevice.BOND_BONDED) {metricsFeatureProvider.action(context,MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT);mCachedDevice.connect(true);} else if (bondState == BluetoothDevice.BOND_NONE) {metricsFeatureProvider.action(context,MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);if (!mCachedDevice.hasHumanReadableName()) {metricsFeatureProvider.action(context,MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);}pair();}
}

这里先获取mCachedDevice的绑定状态,如果已经连接,则询问是否断开;如果已经绑定未连接,则开始连接;如果未连接也未绑定,则开始配对。这里我们先看配对。配对调用的是本地的pair方法:

private void pair() {if (!mCachedDevice.startPairing()) {Utils.showError(getContext(), mCachedDevice.getName(),R.string.bluetooth_pairing_error_message);}
}

2 、framework

/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;}return true;
}

/frameworks/base/core/java/android/bluetooth/BluetoothDevice.java

public boolean createBond() {final IBluetooth service = sService;if (service == 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 service.createBond(this, TRANSPORT_AUTO);} catch (RemoteException e) {Log.e(TAG, "", e);}return false;
}

3 、Bluetooth app

和蓝牙扫描一样,实现IBluetooth接口的类是AdapterServiceBinder,AdapterServiceBinder实现IBluetooth.Stub接口,是AdapterService的私有内部类,AdapterServiceBinder收到的操作,都会转交AdapterService处理,所以会调用AdapterService的createBond方法。

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

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;}mRemoteDevices.setBondingInitiatedLocally(Utils.getByteAddress(device));// 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);return true;
}

createBond 方法会检查一下远程设备属性信息,取消蓝牙扫描任务,将配对任务转交mBondStateMachine,由状态机处理该信息。

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

private boolean createBond(BluetoothDevice dev, int transport, OobData oobData,boolean transition) {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);}if (!result) {sendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);return false;} else if (transition) {transitionTo(mPendingCommandState);}return true;}return false;
}

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

native boolean createBondNative(byte[] address, int transport);

/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

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;
}

4 、蓝牙协议栈

/system/bt/btif/src/bluetooth.cc

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

/system/bt/btif/src/btif_dm.cc

bt_status_t btif_dm_create_bond(const RawAddress* bd_addr, int transport) {btif_dm_create_bond_cb_t create_bond_cb;create_bond_cb.transport = transport;create_bond_cb.bdaddr = *bd_addr;BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __func__,bd_addr->ToString().c_str(), 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);return BT_STATUS_SUCCESS;
}
static void btif_dm_generic_evt(uint16_t event, char* p_param) {BTIF_TRACE_EVENT("%s: event=%d", __func__, 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((RawAddress*)p_param);} break;case BTIF_DM_CB_HID_REMOTE_NAME: {btif_dm_cb_hid_remote_name((tBTM_REMOTE_DEV_NAME*)p_param);} break;case BTIF_DM_CB_BOND_STATE_BONDING: {bond_state_changed(BT_STATUS_SUCCESS, *((RawAddress*)p_param),BT_BOND_STATE_BONDING);} break;case BTIF_DM_CB_LE_TX_TEST:case BTIF_DM_CB_LE_RX_TEST: {uint8_t status;STREAM_TO_UINT8(status, p_param);HAL_CBACK(bt_hal_cbacks, le_test_mode_cb,(status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, 0);} break;case BTIF_DM_CB_LE_TEST_END: {uint8_t status;uint16_t count = 0;STREAM_TO_UINT8(status, p_param);if (status == 0) STREAM_TO_UINT16(count, p_param);HAL_CBACK(bt_hal_cbacks, le_test_mode_cb,(status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, count);} break;default: {BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);} break;}
}
static void btif_dm_cb_create_bond(const RawAddress& bd_addr,tBTA_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;int addr_type;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_PUBLICuint8_t tmp_dev_type;uint8_t tmp_addr_type;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_DmBondByTransport(bd_addr, transport);}/*  Track  originator of bond creation  */pairing_cb.is_local_initiated = true;
}

/system/bt/bta/dm/bta_dm_api.cc

void BTA_DmBondByTransport(const RawAddress& bd_addr,tBTA_TRANSPORT transport) {do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_bond, bd_addr, transport));
}

/system/bt/bta/dm/bta_dm_act.cc

void bta_dm_bond(const RawAddress& bd_addr, tBTA_TRANSPORT transport) {tBTM_STATUS status;tBTA_DM_SEC sec_event;char* p_name;if (transport == BTA_TRANSPORT_UNKNOWN)status = BTM_SecBond(bd_addr, 0, NULL, 0);elsestatus = BTM_SecBondByTransport(bd_addr, transport, 0, NULL, 0);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 = BTM_SecReadDevName(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(bd_addr);}bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);}
}

/system/bt/stack/btm/btm_sec.cc

tBTM_STATUS BTM_SecBondByTransport(const RawAddress& bd_addr,tBT_TRANSPORT transport, uint8_t pin_len,uint8_t* p_pin, uint32_t trusted_mask[]) {tBT_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;}return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin,trusted_mask);
}

/system/bt/stack/btm/btm_sec.cc

tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr,tBT_TRANSPORT transport, uint8_t pin_len,uint8_t* p_pin, uint32_t trusted_mask[]) {tBTM_SEC_DEV_REC* p_dev_rec;tBTM_STATUS status;uint8_t* p_features;uint8_t ii;tACL_CONN* p = btm_bda_to_acl(bd_addr, transport);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 != BTM_SEC_INVALID_HANDLE) &&transport == BT_TRANSPORT_BR_EDR &&(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) ||((p_dev_rec->ble_hci_handle != BTM_SEC_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;if (trusted_mask)BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);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) == 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);}}for (ii = 0; ii <= HCI_EXT_FEATURES_PAGE_MAX; ii++) {p_features = p_dev_rec->feature_pages[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 == TRUE)p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN;
#endif/* If connection already exists... */if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE) {btm_sec_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_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);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;
}

/system/bt/stack/hcic/hcicmds.cc

void btsnd_hcic_write_pin_type(uint8_t type) {BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);uint8_t* pp = (uint8_t*)(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);
}

5、 配对状态改变的回传

我们在bta里面调用/system/bt/bta/dm/bta_dm_act.cc里面的bta_dm_bond方法,进行配对,这个方法最后会执行这个函数:
/system/bt/bta/dm/bta_dm_act.cc

bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);

这个就是bta的回调函数,回调事件是BTA_DM_AUTH_CMPL_EVT,根据这个事件标志,我们找到了 /system/bt/btif/src/btif_dm.cc里面的btif_dm_upstreams_evt方法,这个方法就是用于向上层回调消息的,相关代码是:
/system/bt/btif/src/btif_dm.cc

case BTA_DM_AUTH_CMPL_EVT:btif_dm_auth_cmpl_evt(&p_data->auth_cmpl);break;

/system/bt/btif/src/btif_dm.cc

static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {/* Save link key, if not temporary */bt_status_t status = BT_STATUS_FAIL;bt_bond_state_t state = BT_BOND_STATE_NONE;bool skip_sdp = false;BTIF_TRACE_DEBUG("%s: bond state=%d, success=%d, key_present=%d", __func__,pairing_cb.state, p_auth_cmpl->success,p_auth_cmpl->key_present);RawAddress bd_addr = p_auth_cmpl->bd_addr;if ((p_auth_cmpl->success) && (p_auth_cmpl->key_present)) {if ((p_auth_cmpl->key_type < HCI_LKEY_TYPE_DEBUG_COMB) ||(p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) ||(p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) ||(p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB_P_256) ||pairing_cb.bond_type == BOND_TYPE_PERSISTENT) {bt_status_t ret;BTIF_TRACE_DEBUG("%s: Storing link key. key_type=0x%x, bond_type=%d",__func__, p_auth_cmpl->key_type, pairing_cb.bond_type);ret = btif_storage_add_bonded_device(&bd_addr, p_auth_cmpl->key,p_auth_cmpl->key_type,pairing_cb.pin_code_len);ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret);} else {BTIF_TRACE_DEBUG("%s: Temporary key. Not storing. key_type=0x%x, bond_type=%d",__func__, p_auth_cmpl->key_type, pairing_cb.bond_type);if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) {BTIF_TRACE_DEBUG("%s: sending BT_BOND_STATE_NONE for Temp pairing",__func__);btif_storage_remove_bonded_device(&bd_addr);bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_NONE);return;}}}btif_storage_set_remote_addr_type(&bd_addr, p_auth_cmpl->addr_type);btif_update_remote_properties(p_auth_cmpl->bd_addr, p_auth_cmpl->bd_name,NULL, p_auth_cmpl->dev_type);pairing_cb.timeout_retries = 0;status = BT_STATUS_SUCCESS;state = BT_BOND_STATE_BONDED;bd_addr = p_auth_cmpl->bd_addr;if (check_sdp_bl(&bd_addr) && check_cod_hid(&bd_addr)) {LOG_WARN(LOG_TAG, "%s:skip SDP", __func__);skip_sdp = true;}if (!pairing_cb.is_local_initiated && skip_sdp) {bond_state_changed(status, bd_addr, state);LOG_WARN(LOG_TAG, "%s: Incoming HID Connection", __func__);bt_property_t prop;RawAddress bd_addr;Uuid uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);prop.type = BT_PROPERTY_UUIDS;prop.val = &uuid;prop.len = Uuid::kNumBytes128;/* Send the event to the BTIF */HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,&bd_addr, 1, &prop);} else {bool is_crosskey = false;/* If bonded due to cross-key, save the static address too*/if (pairing_cb.state == BT_BOND_STATE_BONDING &&p_auth_cmpl->bd_addr != pairing_cb.bd_addr) {BTIF_TRACE_DEBUG("%s: bonding initiated due to cross key, adding static address",__func__);pairing_cb.static_bdaddr = bd_addr;is_crosskey = true;}if (!is_crosskey ||!(stack_config_get_interface()->get_pts_crosskey_sdp_disable())) {// Ensure inquiry is stopped before attempting service discoverybtif_dm_cancel_discovery();/* Trigger SDP on the device */pairing_cb.sdp_attempts = 1;btif_dm_get_remote_services(bd_addr);}}// Do not call bond_state_changed_cb yet. Wait until remote service// discovery is complete} else {break;default:status = BT_STATUS_FAIL;}/* Special Handling for HID Devices */if (check_cod(&bd_addr, COD_HID_POINTING)) {/* Remove Device as bonded in nvram as authentication failed */BTIF_TRACE_DEBUG("%s(): removing hid pointing device from nvram",__func__);btif_storage_remove_bonded_device(&bd_addr);}bond_state_changed(status, bd_addr, state);}
}

可以发现也是通过HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);这样的方法进行回调的,bond_state_changed_cb这个函数在bluetooth.h被定义对应的是com_android_bluetooth_btservice_AdapterService.cpp里的bond_state_changed_callback,关键代码如下:
/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

static void bond_state_changed_callback(bt_status_t status, RawAddress* bd_addr,bt_bond_state_t state) {CallbackEnv sCallbackEnv(__func__);if (!sCallbackEnv.valid()) return;if (!bd_addr) {ALOGE("Address is null in %s", __func__);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_bondStateChangeCallback,(jint)status, addr.get(), (jint)state);
}

这里将bondStateChangeCallback方法对应到jni的method_bondStateChangeCallback方法

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_bondStateChangeCallback =env->GetMethodID(jniCallbackClass, "bondStateChangeCallback", "(I[BI)V");if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) {ALOGE("No Bluetooth Library found");}
}

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

    void bondStateChangeCallback(int status, byte[] address, int newState) {mBondStateMachine.bondStateChangeCallback(status, address, newState);}

状态机里面通过sendMessage进行配对状态的变更。

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

void bondStateChangeCallback(int status, byte[] address, int newState) {BluetoothDevice device = mRemoteDevices.getDevice(address);if (device == null) {infoLog("No record of the device:" + device);// This device will be added as part of the BONDING_STATE_CHANGE intent processing// in sendIntent abovedevice = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));}infoLog("bondStateChangeCallback: Status: " + status + " Address: " + device + " newState: "+ newState);Message msg = obtainMessage(BONDING_STATE_CHANGE);msg.obj = device;if (newState == BOND_STATE_BONDED) {msg.arg1 = BluetoothDevice.BOND_BONDED;} else if (newState == BOND_STATE_BONDING) {msg.arg1 = BluetoothDevice.BOND_BONDING;} else {msg.arg1 = BluetoothDevice.BOND_NONE;}msg.arg2 = status;sendMessage(msg);
}

Android 9.0 蓝牙配对流程相关推荐

  1. Android 9.0 蓝牙扫描流程

    微信扫码,给个关注吧 昨天梳理了蓝牙的开启流程,今天梳理一遍扫描流程: 1.UI /packages/apps/Settings/src/com/android/settings/bluetooth/ ...

  2. Android 9.0 蓝牙功能之一:蓝牙音乐

    Android 9.0 蓝牙功能之一:蓝牙音乐 本章节记录如何构建蓝牙音乐. 文章目录 Android 9.0 蓝牙功能之一:蓝牙音乐 主要流程 相关代码 其他要点: 蓝牙AG_EVENT广播 (手机 ...

  3. 蓝牙配对码配置错误_安卓系统蓝牙配对流程分析

    安卓系统蓝牙配对流程分析 配对流程基本上始于首次连接一个蓝牙设备的过程中,本端的搜索流程结束获取到该设备的BluetoothDevice信息,就可以开启配对流程. 配对,顾名思义就是将两个设备通过相关 ...

  4. aptx android8,秒杀苹果无线音频!Android 8.0蓝牙音质支持aptxHD/LDAC

    原标题:秒杀苹果无线音频!Android 8.0蓝牙音质支持aptxHD/LDAC [TechWeb报道]8月25日消息,本周将迎来Android 8.0"奥利奥"系统推送,目前已 ...

  5. 安卓application_安卓系统蓝牙配对流程分析

    安卓系统蓝牙配对流程分析 配对流程基本上始于首次连接一个蓝牙设备的过程中,本端的搜索流程结束获取到该设备的BluetoothDevice信息,就可以开启配对流程. 配对,顾名思义就是将两个设备通过相关 ...

  6. android 6.0蓝牙服务开启,Android应用开发之Android 6.0 蓝牙搜索不到设备原因,MIUI权限申请机制方法...

    本文将带你了解Android应用开发Android 6.0 蓝牙搜索不到设备原因,MIUI权限申请机制方法,希望本文对大家学Android有所帮助. 为提供更高的数据保护   Android6.0版本 ...

  7. Android 8.0 p2p搜索流程

    #Android 8.0 p2p搜索流程 8.0 wifi p2p整体流程跟其他Android版本相差不大,主要还是多了HIDL一层转换而已 以下是8.0 p2p的搜索流程

  8. android 4.0 蓝牙分析之一

    原址 SystemServer启动开始讲起,在SystemServer启动的时,会启动一个BluetoothService与BluetoothA2DPService的实例: Code: //     ...

  9. android蓝牙设置名称流程,Android 8 设置蓝牙名称 流程

    记录android 8设置蓝牙名称的流程.java packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDeviceR ...

  10. android 6.0 蓝牙进程,Android6.0-蓝牙权限问题

    在Android 6.0,原来的蓝牙功能,发现扫描蓝牙设备时,无法获取到蓝牙设备:因为在6.0后,蓝牙这块增加一个动态权限:需要在程序中动态申请. 1)        在6.0版本前,使用蓝牙功能,只 ...

最新文章

  1. spark 序列化错误 集群提交时_【问题解决】本地提交任务到Spark集群报错:Initial job has not accepted any resources...
  2. E-learning的现状与未来
  3. 学习新技术的10个建议
  4. 编程软件python怎样开始学-Python 3.7从零开始学
  5. 【DIY】手把手教你 DIY 最便宜的 arduino 温湿度计,详细图文视频教程
  6. MATLAB应用实战系列(五十一)-TXT数据的读取完美教程
  7. biostar handbook: 第一周笔记汇总+第二周任务布置
  8. 20100422.C#.const VS readonly
  9. tomcat7 https 拒绝连接_物与网怎么连接呢?物联网架构及五大通信协议
  10. 遇上放养型导师,论文就业该咋办?
  11. JavaScript 、if else语句判断 、jQurey表单事件
  12. 颠覆QQ,干掉微信?腾讯内测“朋友”,会是下一个国民社交APP吗
  13. 手把手入门三菱PLC FX2N系列(一)安装GX works2 、 连接PLC、基本操作
  14. 小米公司在区块链领域的布局:小米WiFi链也开始种“米”了
  15. EXCEL 图表-双坐标轴
  16. 热评云厂商:网易数帆8.5亿元,企业数字化服务带来差异化
  17. ACM 常用思维技巧
  18. JBoss EAP 7消息系统
  19. JetBrains.ReSharper 字典
  20. pdf转换软件在线转换

热门文章

  1. 湘潭大学信息安全课作业答案1
  2. 【bsauce读论文】 Playing for K(H)eaps: Understanding and Improving Linux Kernel Exploit Reliability
  3. GIS地理信息系统相关整理
  4. Web前端开发-为网页元素添加阴影效果
  5. jsp房屋出租管理系统带合同
  6. Multi-attributed heterogeneous graph convolutional network for bot detection(SCI CCF B)
  7. 1999年秋浙江省计算机等级考试二级c 编程题,2004年秋浙江省计算机等级考试二级C 编程题(2) (C++代码)...
  8. 新巴塞尔资本协议(中英文)
  9. 计算机word加边框,Word2010怎样为段落加上边框
  10. 【新手必看】全网最全平面设计理论基础知识,平面设计重要理论