Android P 蓝牙与PC端连接失败

字符有: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信息提示即可。

猜你喜欢

转载自blog.csdn.net/liuminx/article/details/107717844