1 UI

蓝牙配对开始于settings设备列表 /packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java中。
DeviceListPreferenceFragment是蓝牙扫描到的设备列表,点击其中一个蓝牙设备,调用onPreferenceTreeClick方法开始蓝牙的配对过程。
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
if (KEY_BT_SCAN.equals(preference.getKey())) {
mLocalAdapter.startScanning(true);
return true;
}

    if (preference instanceof BluetoothDevicePreference) {        BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;        CachedBluetoothDevice device = btPreference.getCachedDevice();        mSelectedDevice = device.getDevice();        //配对连接        onDevicePreferenceClick(btPreference);        return true;    }    return super.onPreferenceTreeClick(preferenceScreen, preference);}

在本地onDevicePreferenceClick方法中调用/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java的onClicked方法:
void onClicked() {
Context context = getContext();
int bondState = mCachedDevice.getBondState();// 获取设备的绑定状态

      final MetricsFeatureProvider metricsFeatureProvider =              FeatureFactory.getFactory(context).getMetricsFeatureProvider();      if (mCachedDevice.isConnected()) {          metricsFeatureProvider.action(context,                  MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);          askDisconnect(); // 已连接,询问是否断开连接      } else if (bondState == BluetoothDevice.BOND_BONDED) {          metricsFeatureProvider.action(context,                  MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT);          mCachedDevice.connect(true);// 已绑定,则进行连接      } else if (bondState == BluetoothDevice.BOND_NONE) {          metricsFeatureProvider.action(context,                  MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);          if (!mCachedDevice.hasHumanReadableName()) {              metricsFeatureProvider.action(context,                  MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);          }          pair();// 如果未绑定,则进行配对      }  }

这里先获取mCachedDevice的绑定状态,如果已经连接,则询问是否断开;如果已经绑定未连接,则开始连接;如果未连接也未绑定,则开始配对。这里我们先看配对。配对调用的是本地的pair方法:
private void pair() {
if (!mCachedDevice.startPairing()) {
Utils.showError(getContext(), mCachedDevice.getName(),
R.string.bluetooth_pairing_error_message);
}
}

pair方法会调用/frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java中的startPairing,启动配对
2 framework
public boolean startPairing() {
// Pairing is unreliable while scanning, so cancel discovery
// 配对时,如果正在扫描,则取消扫描
if (mLocalAdapter.isDiscovering()) {
mLocalAdapter.cancelDiscovery();
}
// 开始配对
if (!mDevice.createBond()) {
return false;
}
// 标识位,配对完成后,自动连接
mConnectAfterPairing = true; // auto-connect after pairing
return true;
}

createBond调用/frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
中的createBond方法:
public boolean createBond(int transport) {
final IBluetooth service = sService;
if (service == null) {
Log.e(TAG, “BT not enabled. Cannot create bond to Remote Device”);
return false;
}
if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE) {
throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport");
}
try {
Log.i(TAG, "createBond() for device " + getAddress()
+ " called by pid: " + Process.myPid()
+ " tid: " + Process.myTid());
return service.createBond(this, transport);
} catch (RemoteException e) {
Log.e(TAG, “”, e);
}
return false;
}

createBond接着调用IBluetooth的createBond方法,通过aidl方式调用蓝牙远程服务。
3 Bluetooth app

和蓝牙扫描一样,实现IBluetooth接口的类是AdapterServiceBinder,AdapterServiceBinder实现IBluetooth.Stub接口,是/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService的私有内部类,AdapterServiceBinder收到的操作,都会转交AdapterService处理,所以会调用AdapterService的createBond方法。
boolean createBond(BluetoothDevice device, int transport) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
“Need BLUETOOTH ADMIN permission”);
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
//属性检查
if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
return false;
}

    // Pairing is unreliable while scanning, so cancel discovery    // Note, remove this when native stack improves    cancelDiscoveryNative();// 配对过程,取消扫描    // 给配对的状态机发消息,创建了BondStateMachine.CREATE_BOND    Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);    msg.obj = device;    msg.arg1 = transport;    mBondStateMachine.sendMessage(msg);    return true;}

createBond 方法会检查一下远程设备属性信息,取消蓝牙扫描任务,将配对任务转交mBondStateMachine,由状态机处理该信息。
@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);                }                result = createBond(dev, msg.arg1, oobData, false);                break;                ........................省略.................................                }        }

BondStateMachine处理服务发送过来的BondStateMachine.CREATE_BOND消息 ,在processMessage 中调用 BondStateMachine的createBond 方法:
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);// 调用到JNI层,进行配对
}

          if (!result) {              sendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);              return false;          } else if (transition) {              transitionTo(mPendingCommandState);          }          return true;      }      return false;  }

createBondNative方法实现在/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp中:
static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address,
jint transport) {
ALOGV("%s", func);

if (!sBluetoothInterface) return JNI_FALSE;jbyte* addr = env->GetByteArrayElements(address, NULL);if (addr == NULL) {  jniThrowIOException(env, EINVAL);  return JNI_FALSE;}// 调用到hal层的配对函数int ret = sBluetoothInterface->create_bond((RawAddress*)addr, transport);env->ReleaseByteArrayElements(address, addr, 0);return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;

}

这里通过create_bond这个方法调用到了蓝牙协议栈里面。
4 蓝牙协议栈

create_bond方法位于/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);

}

create_bond方法调用/system/bt/btif/src/btif_dm.cc的btif_dm_create_bond方法:
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);// 添加了绑定事件// 这里create_bond_cb在上面已经传入了要绑定的蓝牙地址,// 会分别发送给底层两部分,最后会调用btif_dm_generic_evtbtif_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;

}

btif_dm_create_bond方法最终调用了本地的btif_dm_generic_evt方法,传入BTIF_DM_CB_CREATE_BOND事件:
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_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;
…省略…
}
}

这里又调用本地的btif_dm_cb_create_bond方法:
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);
…省略…
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;
}

BTA_DmBondByTransport方法位于\system\bt\bta\dm\bta_dm_api.c:
void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport)
{
// 调用bta的bta_dm_bond方法
do_in_bta_thread(FROM_HERE, base::Bind(bta_dm_bond, bd_addr, transport));
}

这里通过do_in_bta_thread调用/system/bt/bta/dm/bta_dm_act.cc里面的bta_dm_bond方法,进入bta进程:
void bta_dm_bond (tBTA_DM_MSG *p_data)
{
tBTM_STATUS status;
tBTA_DM_SEC sec_event;
char *p_name;

if (p_data->bond.transport == BTA_TRANSPORT_UNKNOWN)    status = BTM_SecBond ( p_data->bond.bd_addr, 0, NULL, 0 );else    status = BTM_SecBondByTransport ( p_data->bond.bd_addr, p_data->bond.transport, 0, NULL, 0 );if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)){    memset(&sec_event, 0, sizeof(tBTA_DM_SEC));    bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr);    p_name = BTM_SecReadDevName(p_data->bond.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(p_data->bond.bd_addr);
}
bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);// 配对事件回调
}
}

然后来到\system\bt\stack\btm\btm_sec.c的BTM_SecBondByTransport 方法:
tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport,
UINT8 pin_len, UINT8 *p_pin, UINT32 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);

}

调用本地btm_sec_bond_by_transport方法,这个方法内容很多,着重看这段代码:
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);// 这里就在和hci层打交道
}
}

这里调用system/bt/stack/hcic/hcicmds.cc的btsnd_hcic_write_pin_type方法通过HCI向底层发送命令进行控制
void btsnd_hcic_write_pin_type (UINT8 type)
{
BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
UINT8 *pp = (UINT8 *)(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);//这里是向hci层发命令,

}

可以看出,这里是通过和hci层的通信,host告诉controlor蓝牙地址、数据、命令等,从而控制其底层硬件发起配对操作。具体btu如何与hci通信,过程也是很繁琐,可以参考《Android BT STACK BTU 和 HCI之间的消息传递》这篇文章。
到此绑定的流程就结束了。有一个遗留问题就是绑定状态是如何返回给上层的呢?
5 配对状态改变的回传

上文我们在bta里面调用/system/bt/bta/dm/bta_dm_act.cc里面的bta_dm_bond方法,进行配对,这个方法里面有这样一段代码:
bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);

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

可以看到是调用这个函数,返回配对完成的事件,这个函数代码很多这里就不引用了,无论配对成功还是失败,这里都会用 bond_state_changed这个方法进行处理:
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);

// Send bonding state only once - based on outgoing/incoming we may receive// duplicatesif ((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);if (state == BT_BOND_STATE_BONDING) {  pairing_cb.state = state;  pairing_cb.bd_addr = bd_addr;} else if ((state == BT_BOND_STATE_NONE) &&    ((bd_addr == pairing_cb.bd_addr) ||    (bd_addr == pairing_cb.static_bdaddr))) {   memset(&pairing_cb, 0, sizeof(pairing_cb));}else{  if ((!pairing_cb.sdp_attempts)&&        ((bd_addr == pairing_cb.bd_addr) ||        (bd_addr == pairing_cb.static_bdaddr)))    memset(&pairing_cb, 0, sizeof(pairing_cb));  else    BTIF_TRACE_DEBUG("%s: BR-EDR service discovery active", __func__);}

}

可以发现也是通过HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);这样的方法进行回调的,bond_state_changed_cb这个函数在bluetooth.h被定义对应的是com_android_bluetooth_btservice_AdapterService.cpp里的bond_state_changed_callback,关键代码如下:
sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback,
(jint)status, addr.get(), (jint)state);

这里将bondStateChangeCallback方法对应到jni的method_bondStateChangeCallback方法
jclass jniCallbackClass =
env->FindClass(“com/android/bluetooth/btservice/JniCallbacks”);
…省略…
method_bondStateChangeCallback =
env->GetMethodID(jniCallbackClass, “bondStateChangeCallback”, “(I[BI)V”);

就找到了JniCallbacks.java里面的bondStateChangeCallback方法
void bondStateChangeCallback(int status, byte[] address, int newState) {
mBondStateMachine.bondStateChangeCallback(status, address, newState);
}

接下来便进入了/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);  }

状态机里面通过sendMessage进行配对状态的变更。
到此,配对流程就分析结束了。

作者:猫疏
链接:https://www.jianshu.com/p/0b748b11fa62
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

更多相关文章

  1. android sdk 下载失败解决方法
  2. android Button字体设置颜色
  3. Android(安卓)IllegalArgumentException: Cannot draw recycled
  4. Android(安卓)签名打包出现的错误的解决方法以及代码中获取应用
  5. Android(安卓)SDK 离线安装方法
  6. 杂乱之android的AlertDialog应用
  7. Android中onTouch方法的执行过程以及和onClick执行发生冲突的解
  8. Android下的数据储存方式
  9. Android(安卓)BlueDroid(三):BlueDroid蓝牙开启过程enable

随机推荐

  1. android获取版本号
  2. Android(安卓)调用相册或相机选择图片
  3. android webview 文字复制
  4. Android:获取网页源代码
  5. Android(安卓)震动示例--心跳效果
  6. Failed to resolve: com.android.support
  7. Android(安卓)中文字符转UTF-8编码
  8. Android(安卓)GridView
  9. android添加联系人(直接添加到联系人数据
  10. Android下拉刷新上拉加载控件的使用