欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android P 蓝牙与PC端连接失败(error错误分析与解决方法)

程序员文章站 2022-05-01 19:18:49
字符有:PIN码或配对密钥不正确,无法与对应的字符串为:bluetooth_pairing_pin_error_messageframeworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java /** * Called when we have reached the unbonded state. * * @pa...

字符有:PIN码或配对密钥不正确,无法与
对应的字符串为:bluetooth_pairing_pin_error_message

frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java

 /**
         * Called when we have reached the unbonded state.
         *
         * @param reason one of the error reasons from
         *            BluetoothDevice.UNBOND_REASON_*
         */ private void showUnbondMessage(Context context, String name, int reason) { int errorMsg; switch(reason) { case BluetoothDevice.UNBOND_REASON_AUTH_FAILED: errorMsg = R.string.bluetooth_pairing_pin_error_message; break; case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED: errorMsg = R.string.bluetooth_pairing_rejected_error_message; break; case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN: errorMsg = R.string.bluetooth_pairing_device_down_error_message; break; case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS: case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT: case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS: case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED: errorMsg = R.string.bluetooth_pairing_error_message; break; default: Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason); return; } Utils.showError(context, name, errorMsg); } } 

继续查看调用showUnbondMessage的位置:

private class BondStateChangedHandler implements Handler { public void onReceive(Context context, Intent intent, BluetoothDevice device) { if (device == null) { Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE"); return; } int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); if (cachedDevice == null) { Log.w(TAG, "CachedBluetoothDevice for device " + device + " not found, calling readPairedDevices()."); if (readPairedDevices()) { cachedDevice = mDeviceManager.findDevice(device); } if (cachedDevice == null) { Log.w(TAG, "Got bonding state changed for " + device + ", but we have no record of that device."); cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device); dispatchDeviceAdded(cachedDevice); } } synchronized (mCallbacks) { for (BluetoothCallback callback : mCallbacks) { callback.onDeviceBondStateChanged(cachedDevice, bondState); } } cachedDevice.onBondingStateChanged(bondState); if (bondState == BluetoothDevice.BOND_NONE) { /* Check if we need to remove other Hearing Aid devices */ if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) { mDeviceManager.onDeviceUnpaired(cachedDevice); } int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.ERROR); showUnbondMessage(context, cachedDevice.getName(), reason); } } 

该错误的提示已异常为:BluetoothDevice.UNBOND_REASON_AUTH_FAILED
找到蓝牙服务的位置, 根据蓝牙状态机的显示有:
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java

 private int getUnbondReasonFromHALCode(int reason) { if (reason == AbstractionLayer.BT_STATUS_SUCCESS) { return BluetoothDevice.BOND_SUCCESS; } else if (reason == AbstractionLayer.BT_STATUS_RMT_DEV_DOWN) { return BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN; } else if (reason == AbstractionLayer.BT_STATUS_AUTH_FAILURE) { return BluetoothDevice.UNBOND_REASON_AUTH_FAILED; } else if (reason == AbstractionLayer.BT_STATUS_AUTH_REJECTED) { return BluetoothDevice.UNBOND_REASON_AUTH_REJECTED; } else if (reason == AbstractionLayer.BT_STATUS_AUTH_TIMEOUT) { return BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT; } /* default */ return BluetoothDevice.UNBOND_REASON_REMOVED; } 

可以知道是:AbstractionLayer.BT_STATUS_AUTH_FAILURE这个异常导致;
此处有蓝牙状态变化的处理函数:

 private class PendingCommandState extends State { @Override public void enter() { infoLog("Entering PendingCommandState State"); BluetoothDevice dev = (BluetoothDevice) getCurrentMessage().obj; } @Override public synchronized 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; } 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; case REMOVE_BOND: result = removeBond(dev, false); break; case CANCEL_BOND: result = cancelBond(dev); break; case BONDING_STATE_CHANGE: int newState = msg.arg1; int reason = getUnbondReasonFromHALCode(msg.arg2); sendIntent(dev, newState, reason); if (newState != BluetoothDevice.BOND_BONDING) { // check if bond none is received from device which // was in pairing state otherwise don't transition to // stable state. if (newState == BluetoothDevice.BOND_NONE && !mDevices.contains(dev) && mDevices.size() != 0) { infoLog("not transitioning to stable state"); break; } /* this is either none/bonded, remove and transition */ result = !mDevices.remove(dev); if (mDevices.isEmpty()) { // Whenever mDevices is empty, then we need to // set result=false. Else, we will end up adding // the device to the list again. This prevents us // from pairing with a device that we just unpaired result = false; transitionTo(mStableState); } if (newState == BluetoothDevice.BOND_NONE) { mAdapterService.setPhonebookAccessPermission(dev, BluetoothDevice.ACCESS_UNKNOWN); mAdapterService.setMessageAccessPermission(dev, BluetoothDevice.ACCESS_UNKNOWN); mAdapterService.setSimAccessPermission(dev, BluetoothDevice.ACCESS_UNKNOWN); // Set the profile Priorities to undefined clearProfilePriority(dev); } } else if (!mDevices.contains(dev)) { result = true; } break; case SSP_REQUEST: int passkey = msg.arg1; int variant = msg.arg2; if (devProp == null) { Log.e(TAG,"Received msg from an unknown device"); return false; } sendDisplayPinIntent(devProp.getAddress(), passkey, variant); break; case PIN_REQUEST: BluetoothClass btClass = dev.getBluetoothClass(); int btDeviceClass = btClass.getDeviceClass(); if (devProp == null) { Log.e(TAG,"Received msg from an unknown device"); return false; } if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD || btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { // Its a keyboard. Follow the HID spec recommendation of creating the // passkey and displaying it to the user. If the keyboard doesn't follow // the spec recommendation, check if the keyboard has a fixed PIN zero // and pair. //TODO: Maintain list of devices that have fixed pin // Generate a variable 6-digit PIN in range of 100000-999999 // This is not truly random but good enough. int pin = 100000 + (int) Math.floor((Math.random() * (999999 - 100000))); sendDisplayPinIntent(devProp.getAddress(), pin, BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN); break; } if (msg.arg2 == 1) { // Minimum 16 digit pin required here sendDisplayPinIntent(devProp.getAddress(), 0, BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS); } else { // In PIN_REQUEST, there is no passkey to display.So do not send the // EXTRA_PAIRING_KEY type in the intent( 0 in SendDisplayPinIntent() ) sendDisplayPinIntent(devProp.getAddress(), 0, BluetoothDevice.PAIRING_VARIANT_PIN); } break; default: Log.e(TAG, "Received unhandled event:" + msg.what); return false; } if (result) { mDevices.add(dev); } return true; } } 

根据该函数的调用位置可以知道是BONDING_STATE_CHANGE变化时候的提示;
继续追踪可以找到是蓝牙协议调用层:
vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_dm.cc

/*******************************************************************************
 *
 * Function         btif_dm_auth_cmpl_evt
 *
 * Description      Executes authentication complete event in btif context
 *
 * Returns          void
 *
 ******************************************************************************/ 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; if (p_auth_cmpl->success) { // Do not call bond_state_changed_cb yet. Wait until remote service // discovery is complete } else { // Map the HCI fail reason  to  bt status switch (p_auth_cmpl->fail_reason) { case HCI_ERR_PAGE_TIMEOUT: case HCI_ERR_LMP_RESPONSE_TIMEOUT: if (pairing_cb.timeout_retries) { BTIF_TRACE_WARNING("%s() - Pairing timeout; retrying (%d) ...", __func__, pairing_cb.timeout_retries); --pairing_cb.timeout_retries; btif_dm_cb_create_bond(bd_addr, BTA_TRANSPORT_UNKNOWN); return; } /* Fall-through */ case HCI_ERR_CONNECTION_TOUT: status = BT_STATUS_RMT_DEV_DOWN; break; case HCI_ERR_PAIRING_NOT_ALLOWED: btif_storage_remove_bonded_device(&bd_addr); status = BT_STATUS_AUTH_REJECTED; break; /* Dont fail the bonding for key missing error as stack retry security */ case HCI_ERR_KEY_MISSING: btif_storage_remove_bonded_device(&bd_addr); if (p_auth_cmpl->is_sm4_dev) { return; } else { BTIF_TRACE_WARNING("%s() legacy remote ,move bond state to none", __FUNCTION__); } /* map the auth failure codes, so we can retry pairing if necessary */ case HCI_ERR_AUTH_FAILURE: btif_storage_remove_bonded_device(&bd_addr); case HCI_ERR_HOST_REJECT_SECURITY: case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE: case HCI_ERR_UNIT_KEY_USED: case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED: case HCI_ERR_INSUFFCIENT_SECURITY: case HCI_ERR_PEER_USER: case HCI_ERR_UNSPECIFIED: case HCI_ERR_REPEATED_ATTEMPTS: BTIF_TRACE_DEBUG(" %s() Authentication fail reason %d", __FUNCTION__, p_auth_cmpl->fail_reason); if (pairing_cb.autopair_attempts == 1) { /* Create the Bond once again */ BTIF_TRACE_WARNING("%s() auto pair failed. Reinitiate Bond", __func__); btif_dm_cb_create_bond(bd_addr, BTA_TRANSPORT_UNKNOWN); return; } else { /* if autopair attempts are more than 1, or not attempted */ status = BT_STATUS_AUTH_FAILURE; } break; default: status = BT_STATUS_FAIL; } 

查看注释上写明:

 /* if autopair attempts are more than 1, or not attempted */ status = BT_STATUS_AUTH_FAILURE; 

另外还有一处调用:

/*******************************************************************************
 *
 * Function         btif_dm_ble_auth_cmpl_evt
 *
 * Description      Executes authentication complete event in btif context
 *
 * Returns          void
 *
 ******************************************************************************/ static void btif_dm_ble_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; RawAddress bd_addr = p_auth_cmpl->bd_addr; /* Clear OOB data */ memset(&oob_cb, 0, sizeof(oob_cb)); if ((p_auth_cmpl->success == true) && (p_auth_cmpl->key_present)) { /* store keys */ } if (p_auth_cmpl->success) { status = BT_STATUS_SUCCESS; state = BT_BOND_STATE_BONDED; int addr_type; RawAddress bdaddr = p_auth_cmpl->bd_addr; if (btif_storage_get_remote_addr_type(&bdaddr, &addr_type) != BT_STATUS_SUCCESS) btif_storage_set_remote_addr_type(&bdaddr, p_auth_cmpl->addr_type); /* Test for temporary bonding */ if (btm_get_bond_type_dev(p_auth_cmpl->bd_addr) == BOND_TYPE_TEMPORARY) { BTIF_TRACE_DEBUG("%s: sending BT_BOND_STATE_NONE for Temp pairing", __func__); btif_storage_remove_bonded_device(&bdaddr); state = BT_BOND_STATE_NONE; } else { btif_dm_save_ble_bonding_keys(); BTA_GATTC_Refresh(bd_addr); if(!p_auth_cmpl->smp_over_br) btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE); else btif_dm_get_remote_services(bd_addr); } } else { /*Map the HCI fail reason  to  bt status  */ switch (p_auth_cmpl->fail_reason) { case BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL: case BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL: case BTA_DM_AUTH_SMP_UNKNOWN_ERR: case BTA_DM_AUTH_SMP_CONN_TOUT: btif_dm_remove_ble_bonding_keys(); status = BT_STATUS_AUTH_FAILURE; break; case BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT: status = BT_STATUS_AUTH_REJECTED; break; default: btif_dm_remove_ble_bonding_keys(); status = BT_STATUS_FAIL; break; } } bond_state_changed(status, bd_addr, state); } 

以上两种方式,我们初步可以判断是BLE协议和传统蓝牙协议;
而PC端与设备端调用我们初步判断是传统蓝牙协议,故执行btif_dm_auth_cmpl_evt

 case BTA_DM_AUTH_CMPL_EVT: btif_dm_auth_cmpl_evt(&p_data->auth_cmpl); break; case BTA_DM_BLE_AUTH_CMPL_EVT: BTIF_TRACE_DEBUG("BTA_DM_BLE_AUTH_CMPL_EVT. "); btif_dm_ble_auth_cmpl_evt(&p_data->auth_cmpl); break; 

后续可以抓取log一步步跟踪尝试。
临时修改方案,当Auth异常时候,不显示其Toast显示,直接以log信息提示即可。

本文地址:https://blog.csdn.net/liuminx/article/details/107717844