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分支。至此蓝牙配对分析结束。