android10 蓝牙(二)配对源码解析

news2024/11/7 21:59:11

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

void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
    btPreference.onClicked();
}

        点击preference的时候会执行onDevicePreferenceClick方法,调用BluetoothDevicePreference.java中的onClieck方法。

xref: /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,
                SettingsEnums.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);
        askDisconnect();
    } else if (bondState == BluetoothDevice.BOND_BONDED) {
        metricsFeatureProvider.action(context,
                SettingsEnums.ACTION_SETTINGS_BLUETOOTH_CONNECT);
        mCachedDevice.connect(true);
    } 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);
    }
}

        判断蓝牙有没有配对,如果bondState是BluetoothDevice.BOND_NONE则配对蓝牙,走pair方法。在pair方法中会调用CachedBluetoothDevice.java中的startPairing方法。

xref: /frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java

public boolean startPairing() {
    // Pairing is unreliable while scanning, so cancel discovery
    if (mLocalAdapter.isDiscovering()) {
        mLocalAdapter.cancelDiscovery();
    }

    if (!mDevice.createBond()) {
        return false;
    }

    return true;
}

        扫描的时候是不能配对的,所以要先取消扫描。然后调用BluetoothDevice.java中的createBond方法配对。

xref: /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;
}

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

/**
 * The Binder implementation must be declared to be a static class, with
 * the AdapterService instance passed in the constructor. Furthermore,
 * when the AdapterService shuts down, the reference to the AdapterService
 * must be explicitly removed.
 *
 * Otherwise, a memory leak can occur from repeated starting/stopping the
 * service...Please refer to android.os.Binder for further details on
 * why an inner instance class should be avoided.
 *
 */
private static class AdapterServiceBinder extends IBluetooth.Stub {
    private AdapterService mService;

    AdapterServiceBinder(AdapterService svc) {
        mService = svc;
    }

    public void cleanup() {
        mService = null;
    }

    public AdapterService getService() {
        if (mService != null && mService.isAvailable()) {
            return mService;
        }
        return null;
    }

........................................................................................
   
     @Override
     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);
     }

     .........................................................................................
 }



.........................................................................................


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 improves
   cancelDiscoveryNative();

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


        AdapterServiceBinder 继承自IBluetooth.Stub,AdapterServiceBinder定义在AdapterService.java类中。通过mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND)往BondStateMachine.java中发送消息。

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

private class StableState extends State {
    @Override
    public void enter() {
        infoLog("StableState(): Entering Off State");
    }

    @Override
    public boolean processMessage(Message msg) {

        BluetoothDevice dev = (BluetoothDevice) msg.obj;

        switch (msg.what) {

            case CREATE_BOND:
                OobData oobData = null;
                if (msg.getData() != null) {
                    oobData = msg.getData().getParcelable(OOBDATA);
                }

                createBond(dev, msg.arg1, oobData, true);
                break;
            case REMOVE_BOND:
                removeBond(dev, true);
                break;
            case BONDING_STATE_CHANGE:
                int newState = msg.arg1;
            /* if incoming pairing, transition to pending state */
                if (newState == BluetoothDevice.BOND_BONDING) {
                    sendIntent(dev, newState, 0);
                    transitionTo(mPendingCommandState);
                } else if (newState == BluetoothDevice.BOND_NONE) {
                /* if the link key was deleted by the stack */
                    sendIntent(dev, newState, 0);
                } else {
                    Log.e(TAG, "In stable state, received invalid newState: "
                            + state2str(newState));
                }
                break;
            case UUID_UPDATE:
                if (mPendingBondedDevices.contains(dev)) {
                    sendIntent(dev, BluetoothDevice.BOND_BONDED, 0);
                }
                break;
            case CANCEL_BOND:
            default:
                Log.e(TAG, "Received unhandled state: " + msg.what);
                return false;
        }
        return true;
    }
}


...................................................................................................................


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);
        }
        StatsLog.write(StatsLog.BLUETOOTH_BOND_STATE_CHANGED,
                mAdapterService.obfuscateAddress(dev), transport, dev.getType(),
                BluetoothDevice.BOND_BONDING,
                oobData == null ? BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN
                        : BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED,
                BluetoothProtoEnums.UNBOND_REASON_UNKNOWN);
        if (!result) {
            StatsLog.write(StatsLog.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);
            return false;
        } else if (transition) {
            transitionTo(mPendingCommandState);
        }
        return true;
    }
    return false;
}

        StableState中接收消息的处理,走case CREATE_BOND分支。在createBond方法中调用mAdapterService.createBondNative,createBondNative定义在AdapterService.java类中,是一个native方法。

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

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

        实现类在com_android_bluetooth_btservice_AdapterService.cpp中国

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

static const bt_interface_t* sBluetoothInterface = NULL;


...........................................................................................


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

        执行sBluetoothInterface->create_bond((RawAddress*)addr, transport)方法,后续就是调用蓝牙协议栈内容。

xref: /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);
}

        调用btif_dm.cc中的btif_dm_create_bond方法

xref: /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_PUBLIC
      uint8_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;
}

        在btif_dm_create_bond方法调用btif_dm_generic_evt方法,走BTIF_DM_CB_CREATE_BOND分支,调用btif_dm_cb_create_bond方法。在btif_dm_cb_create_bond方法中调用BTA_DmBondByTransport(bd_addr, transport)方法。

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

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

        在bta_dm_bond线程中执行操作

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

        

  tBTM_STATUS status;
  tBTA_DM_SEC sec_event;
  char* p_name;

  if (transport == BTA_TRANSPORT_UNKNOWN)
    status = BTM_SecBond(bd_addr, 0, NULL, 0);
  else
    status = 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);
  }
}

        调用BTM_SecBondByTransport(bd_addr, transport, 0, NULL, 0)方法。

xref: /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);
}


........................................................................................



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

        执行btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED)方法

xref: /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);
}

        btu_hcif_send_cmd发送cmd命令。接下来的分析我们回到bta_dm_act.cc中的bta_dm_bond方法中

xref: /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);
  else
    status = 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);
  }
}

        bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event),根据回调事件BTA_DM_AUTH_CMPL_EVT

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

static void btif_dm_upstreams_evt(uint16_t event, char* p_param) {
  tBTA_DM_SEC* p_data = (tBTA_DM_SEC*)p_param;
  tBTA_SERVICE_MASK service_mask;
  uint32_t i;
  RawAddress bd_addr;

  BTIF_TRACE_EVENT("%s: ev: %s", __func__, dump_dm_event(event));

  switch (event) {
    
	
	.........................................................................................
	
	
    case BTA_DM_AUTH_CMPL_EVT:
      btif_dm_auth_cmpl_evt(&p_data->auth_cmpl);
      break;


    .........................................................................................
	
	
  }

  btif_dm_data_free(event, p_data);
}

 .........................................................................................


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

  if (p_auth_cmpl->success) {
    // We could have received a new link key without going through the pairing
    // flow.  If so, we don't want to perform SDP or any other operations on the
    // authenticated device. Also, make sure that the link key is not derived
    // from secure LTK, because we will need to perform SDP in case of link key
    // derivation to allow bond state change notification for the BR/EDR
    // transport so that the subsequent BR/EDR connections to the remote can use
    // the derived link key.
    if (p_auth_cmpl->bd_addr != pairing_cb.bd_addr &&
        (!pairing_cb.ble.is_penc_key_rcvd)) {
      LOG(INFO) << __func__
                << " skipping SDP since we did not initiate pairing to "
                << p_auth_cmpl->bd_addr;
      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 discovery
        btif_dm_cancel_discovery();

        /* Trigger SDP on the device */
        pairing_cb.sdp_attempts = 1;

        if (is_crosskey) {
          // If bonding occurred due to cross-key pairing, send bonding callback
          // for static address now
          LOG_INFO(LOG_TAG,
                   "%s: send bonding state update for static address %s",
                   __func__, bd_addr.ToString().c_str());
          bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
        }
        bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDED);

        btif_dm_get_remote_services(bd_addr);
      }
    }
    // 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 (interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &bd_addr) &&
            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;
        }
        FALLTHROUGH_INTENDED; /* FALLTHROUGH */
      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;

      /* map the auth failure codes, so we can retry pairing if necessary */
      case HCI_ERR_AUTH_FAILURE:
      case HCI_ERR_KEY_MISSING:
        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:
        BTIF_TRACE_DEBUG(" %s() Authentication fail reason %d", __func__,
                         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;
    }
    /* 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);
  }
}


........................................................................................


static void bond_state_changed(bt_status_t status, const RawAddress& bd_addr,
                               bt_bond_state_t state) {
  btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_BOND_STATE_CHANGED, state);

  if ((pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING)) {
    // Cross key pairing so send callback for static address
    if (!pairing_cb.static_bdaddr.IsEmpty()) {
      auto tmp = bd_addr;
      HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);
    }
    return;
  }

  if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) state = BT_BOND_STATE_NONE;

  BTIF_TRACE_DEBUG("%s: state=%d, prev_state=%d, sdp_attempts = %d", __func__,
                   state, pairing_cb.state, pairing_cb.sdp_attempts);

  auto tmp = bd_addr;
  HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);

  int dev_type;
  if (!btif_get_device_type(bd_addr, &dev_type)) {
    dev_type = BT_DEVICE_TYPE_BREDR;
  }

  if (state == BT_BOND_STATE_BONDING ||
      (state == BT_BOND_STATE_BONDED && pairing_cb.sdp_attempts > 0)) {
    // Save state for the device is bonding or SDP.
    pairing_cb.state = state;
    pairing_cb.bd_addr = bd_addr;
  } else {
    pairing_cb = {};
  }
}

         调用bond_state_changed方法,在bond_state_changed方法中会调用HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state)方法,

xref: /system/bt/include/hardware/bluetooth.h

typedef struct {
  /** set to sizeof(bt_callbacks_t) */
  size_t size;
  adapter_state_changed_callback adapter_state_changed_cb;
  adapter_properties_callback adapter_properties_cb;
  remote_device_properties_callback remote_device_properties_cb;
  device_found_callback device_found_cb;
  discovery_state_changed_callback discovery_state_changed_cb;
  pin_request_callback pin_request_cb;
  ssp_request_callback ssp_request_cb;
  bond_state_changed_callback bond_state_changed_cb;
  acl_state_changed_callback acl_state_changed_cb;
  callback_thread_event thread_evt_cb;
  dut_mode_recv_callback dut_mode_recv_cb;
  le_test_mode_callback le_test_mode_cb;
  energy_info_callback energy_info_cb;
} bt_callbacks_t;

        bond_state_changed_cb的实现方法在com_android_bluetooth_btservice_AdapterService.cpp中

xref: /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);
}


..........................................................................................


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_stateChangeCallback =
      env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V");

  method_adapterPropertyChangedCallback = env->GetMethodID(
      jniCallbackClass, "adapterPropertyChangedCallback", "([I[[B)V");
  method_discoveryStateChangeCallback = env->GetMethodID(
      jniCallbackClass, "discoveryStateChangeCallback", "(I)V");

  method_devicePropertyChangedCallback = env->GetMethodID(
      jniCallbackClass, "devicePropertyChangedCallback", "([B[I[[B)V");
  method_deviceFoundCallback =
      env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
  method_pinRequestCallback =
      env->GetMethodID(jniCallbackClass, "pinRequestCallback", "([B[BIZ)V");
  method_sspRequestCallback =
      env->GetMethodID(jniCallbackClass, "sspRequestCallback", "([B[BIII)V");

  method_bondStateChangeCallback =
      env->GetMethodID(jniCallbackClass, "bondStateChangeCallback", "(I[BI)V");

  method_aclStateChangeCallback =
      env->GetMethodID(jniCallbackClass, "aclStateChangeCallback", "(I[BI)V");

  method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z");
  method_acquireWakeLock =
      env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z");
  method_releaseWakeLock =
      env->GetMethodID(clazz, "releaseWakeLock", "(Ljava/lang/String;)Z");
  method_energyInfo = env->GetMethodID(
      clazz, "energyInfoCallback", "(IIJJJJ[Landroid/bluetooth/UidTraffic;)V");

  if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) {
    ALOGE("No Bluetooth Library found");
  }
}

        调用method_bondStateChangeCallback方法。method_bondStateChangeCallback对应bondStateChangeCallback方法。

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

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

        调用mBondStateMachine的bondStateChangeCallback方法。

xref: /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 above
        device = 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);
}


........................................................................................


private class StableState extends State {
    @Override
    public void enter() {
        infoLog("StableState(): Entering Off State");
    }

    @Override
    public boolean processMessage(Message msg) {

        BluetoothDevice dev = (BluetoothDevice) msg.obj;

        switch (msg.what) {

            case CREATE_BOND:
                OobData oobData = null;
                if (msg.getData() != null) {
                    oobData = msg.getData().getParcelable(OOBDATA);
                }

                createBond(dev, msg.arg1, oobData, true);
                break;
            case REMOVE_BOND:
                removeBond(dev, true);
                break;
            case BONDING_STATE_CHANGE:
                int newState = msg.arg1;
            /* if incoming pairing, transition to pending state */
                if (newState == BluetoothDevice.BOND_BONDING) {
                    sendIntent(dev, newState, 0);
                    transitionTo(mPendingCommandState);
                } else if (newState == BluetoothDevice.BOND_NONE) {
                /* if the link key was deleted by the stack */
                    sendIntent(dev, newState, 0);
                } else {
                    Log.e(TAG, "In stable state, received invalid newState: "
                            + state2str(newState));
                }
                break;
            case UUID_UPDATE:
                if (mPendingBondedDevices.contains(dev)) {
                    sendIntent(dev, BluetoothDevice.BOND_BONDED, 0);
                }
                break;
            case CANCEL_BOND:
            default:
                Log.e(TAG, "Received unhandled state: " + msg.what);
                return false;
        }
        return true;
    }
}	

        通过sendMessage往StableState中发送消息,走BONDING_STATE_CHANGE分支。至此蓝牙配对分析结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2235312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

可重入函数 volatile SIGCHLD

目录 1. 可重入函数2. volatile3. SIGCHLD 信号 1. 可重入函数 场景&#xff1a;当我们在全局区定义一个链表&#xff08;不带头结点&#xff09;&#xff0c;然后对链表做头插结点的操作&#xff0c;即插入 node1 结点&#xff08;如上图所示&#xff09;。在插入 node1 时需要…

『VUE』20. 组件嵌套关系page(详细图文注释)

目录 VUE的自带组件结构新建文件搭建结构app与Main Header Aside结构App.vueHeader.vueMain.vueAside.vue Main 与Article.Aside与Item结构Article.vueItem.vue 总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 因为前面已经有…

【Hive sql面试题】找出连续活跃3天及以上的用户

表数据如下&#xff1a; 要求&#xff1a;求出连续活跃三天及以上的用户 建表语句和插入数据如下&#xff1a; create table t_useractive(uid string,dt string );insert into t_useractive values(A,2023-10-01 10:10:20),(A,2023-10-02 10:10:20),(A,2023-10-03 10:16…

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-16

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…

Vulnhub靶机——DC-3

#环境准备 dc-3 虚拟机&#xff1a;网卡NAT模式 kali攻击机&#xff1a;网卡NAT模式 #信息收集 nmap轻车熟路扫一下dc3的地址&#xff0c;识别出joomla系统 面向百度渗透&#xff0c;得知有一个joomla的扫描器&#xff0c;直接安排上&#xff0c;这下有版本号和后台登录地址…

数据结构:七种排序及总结

文章目录 排序一插入排序1直接插入排序2希尔排序二选择排序3直接选择排序4堆排序三 交换排序5冒泡排序6快速排序四 归并排序7归并排序源码 排序 我们数据结构常见的排序有四大种&#xff0c;四大种又分为七小种&#xff0c;如图所示 排序&#xff1a;所谓排序&#xff0c;就是…

基于STM32H7XX的Bootloader启动与FOTA

1. Bootloader是如何工作的: 2.正常情况下,程序从flash启动时的启动流程,如下图所示: 首先程序从flash启动,根据中断向量表找到复位中断处理函数的地址(0x0800 0004处是中断向量表的起始地址,记录了复位中断处理函数的地址)。执行复位中断处理函数,初始化系统环境之后…

语音 AI 迎来爆发期,也仍然隐藏着被低估的机会丨RTE2024 音频技术和 Voice AI 专场

在人工智能快速发展的今天&#xff0c;语音交互技术正经历一场革命性的变革。从语音识别到语音合成&#xff0c;再到端到端的语音对话系统&#xff0c;这一领域的创新正以前所未有的速度推进。这些进步不仅提升了技术指标&#xff0c;更为实时翻译、虚拟数字人、智能客服等实时…

【自学笔记】神经网络(1)

文章目录 介绍模型结构层&#xff08;Layer&#xff09;神经元 前向传播反向传播Q1: 为什么要用向量Q2: 不用激活函数会发生什么 介绍 我们已经学习了简单的分类任务和回归任务&#xff0c;也认识了逻辑回归和正则化等技巧&#xff0c;已经可以搭建一个简单的神经网络模型了。 …

在内蒙考驾照需要注意什么呢?

一、报名条件 年满18周岁&#xff0c;具有完全民事行为能力的中国公民。持有有效的身份证明文件。身体健康&#xff0c;无妨碍驾驶机动车的疾病&#xff0c;并需要通过体检。 二、选择驾校 可以先向身边已经拿到驾照的朋友咨询&#xff0c;了解驾校的距离、位置、口碑等信息。…

C++builder中的人工智能(8)什么是神经网络中的恒等激活函数?

在这篇文章中&#xff0c;我们将回答以下问题&#xff1a; 你想了解神经网络中最简单的激活函数是什么吗&#xff1f;什么是恒等函数&#xff1f;作为AI术语&#xff0c;我们需要了解激活函数和转移函数的哪些知识&#xff1f;激活函数与净输入函数是一回事吗&#xff1f;是否…

django图书管理系统-计算机毕业设计源码00648

摘要 图书管理系统在数字化阅读趋势、图书馆自动化管理、用户体验需求和信息技术应用等方面具有重要的研究意义。图书馆自动化管理系统的引入和应用提高了图书借阅过程的效率和准确性&#xff0c;减少了对手工操作和纸质记录的需求。用户对系统的易用性、查询速度、借还流程有更…

文件系统和日志管理

文件系统 文件系统&#xff1a; 文件系统提供了一个接口&#xff0c;用户用来访问硬件设备硬件设备上对文件的管理 存储单位 文件存储在硬盘上&#xff0c;硬盘最小的存储单位是512字节 扇区&#xff0c;文件在硬盘上的最小存储单位&#xff1a;块block&#xff0c;一个块的…

【代码转换】如何用 GPT 将 Python2代码 转换为 Python3代码 :实战教程

文章目录 1. 为什么要将 Python 2 代码迁移到 Python 3&#xff1f;2. 使用 ChatGPT 进行代码转换的步骤步骤1&#xff1a;打开CodeMoss步骤2&#xff1a;在输入框输入符号&#xff0c;选择代码转换步骤3&#xff1a;在这里选择你要更改的具体代码步骤4&#xff1a;准备 Python…

「Mac畅玩鸿蒙与硬件27」UI互动应用篇4 - 猫与灯的互动应用

本篇将带领你实现一个趣味十足的互动应用&#xff0c;用户点击按钮时猫会在一排灯之间移动&#xff0c;猫所在的位置灯会亮起&#xff08;on&#xff09;&#xff0c;其余灯会熄灭&#xff08;off&#xff09;。应用会根据用户的操作动态更新灯光状态和文本提示当前亮灯的位置&…

ES海量数据插入如何优化性能?

2024年10月NJSD技术盛典暨第十届NJSD软件开发者大会、第八届IAS互联网架构大会在南京召开。百度文心快码总经理臧志分享了《AI原生研发新范式的实践与思考》&#xff0c;探讨了大模型赋能下的研发变革及如何在公司和行业中落地&#xff0c;AI原生研发新范式的内涵和推动经验。 …

OTFS基带通信系统(脉冲导频,信道估计,MP解调算法)

Embedded Pilot-Aided Channel Estimation for OTFS in Delay–Doppler Channels | IEEE Journals & Magazine | IEEE Xplore 一、OTFS通信系统 如下图简要概括了OTFS基带通信系统过程&#xff0c;废话不多说给出完整系统详细代码。 以下仿真结果基于四抽头信道 估计信道…

理解Web登录机制:会话管理与跟踪技术解析(二)-JWT令牌

JWT令牌是一种用于安全地在各方之间传递信息的开放标准&#xff0c;它不仅能够验证用户的身份&#xff0c;还可以安全地传递有用的信息。由于其结构简单且基于JSON&#xff0c;JWT可以在不同的系统、平台和语言间无缝传递&#xff0c;成为现代Web开发中不可或缺的一部分。 文章…

微积分复习笔记 Calculus Volume 1 - 4.8 L’Hôpital’s Rule

4.8 L’Hpital’s Rule - Calculus Volume 1 | OpenStax

用户流定义:绘制产品交互流程图

产品经理在进行产品设计时&#xff0c;经常利用交互流程图来提升团队的工作效率。这种流程图适用于传达方案、评审目标等需要团队协作的场景&#xff0c;使得视觉设计师、产品开发等团队成员能够迅速理解图示内容&#xff0c;节省了理解时间&#xff0c;有效提高了沟通效率。 …