Android Bluetooth

好厚米们,我又来了!

这次分享的是蓝牙设备执行配对动作时Android源码的执行流程。

下面先来说下,应用层是如何发起蓝牙配对的:

( ps:大多数业务逻辑,都是扫描到可用设备后,点击可用设备 -> 发起配对。)

这里我直接略过点击可用设备的步骤哈,扫描到第一个可用设备后,我直接通过扫描信息进行配对。

public class MainActivity extends AppCompatActivity {private BluetoothAdapter mBluetoothAdapter;private BluetoothDevice mBluetoothDevice;private BluetoothLeScanner scanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ScanCallback scanCallback = new ScanCallback() {@SuppressLint("MissingPermission")@Overridepublic void onScanResult(int callbackType, ScanResult result) {super.onScanResult(callbackType, result);//将扫描到的设备信息取出来,为蓝牙设备赋值mBluetoothDevice = result.getDevice();//通过蓝牙设备,调用配对方法mBluetoothDevice.createBond();}@Overridepublic void onScanFailed(int errorCode) {super.onScanFailed(errorCode);// 扫描失败处理}};// 开始扫描if (scanner != null) {ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();// 添加过滤条件List<ScanFilter> filters = new ArrayList<>();//权限检查if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {// TODO: Consider calling//    ActivityCompat#requestPermissions// here to request the missing permissions, and then overriding//   public void onRequestPermissionsResult(int requestCode, String[] permissions,//                                          int[] grantResults)// to handle the case where the user grants the permission. See the documentation// for ActivityCompat#requestPermissions for more details.return;}scanner.startScan(filters, settings, scanCallback);}// 停止扫描if (scanner != null) {scanner.stopScan(scanCallback);}mBluetoothAdapter.startDiscovery();}
}

由上面的代码可以看出,配对动作的执行依赖

 //通过蓝牙设备,调用配对方法BluetoothDevice.createBond();

下面就进入到了FWK层

执行BluetoothDevice.createBond()后,会进入到BluetoothDevice.java中执行

BluetoothDevice.java - OpenGrok cross reference for /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());//通过service接口执行配对动作return service.createBond(this, TRANSPORT_AUTO);} catch (RemoteException e) {Log.e(TAG, "", e);}return false;}

而这个service,我们来看下其声明

private static volatile IBluetooth sService;//后来在上面的配对方法中,为此接口赋值
final IBluetooth service = sService;

本质上就是IBluetooth接口,不过在Android 10中,IBluetooth接口一共有两个。

应用层下发配对动作时,所用的IBludetooth接口是/system/bt/service/common/android/bluetooth/

此接口的具体代码如下(太多了,各位厚米自己点连接看下就行):

IBluetooth.aidl - OpenGrok cross reference for /system/bt/binder/android/bluetooth/IBluetooth.aidl

即通过这个AIDL接口调用蓝牙远程服务。

下面进入了Bluetooth 服务层

而这个接口的实现类,在AdaperServiceBinder中,部分代码如下:

PS:AdaperServiceBinder写在AdapterService.java中

AdapterService.java - OpenGrok cross reference for /packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

private static class AdapterServiceBinder extends IBluetooth.Stub {//在Binder类中继承了IBluetooth.Stubprivate AdapterService mService;AdapterServiceBinder(AdapterService svc) {mService = svc;}public void cleanup() {mService = null;}public AdapterService getService() {if (mService != null && mService.isAvailable()) {return mService;}return null;}//发起配对@Overridepublic 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;}//调用蓝牙服务中的createBond方法return service.createBond(device, transport, null);}
}

 即,应用层触发的配对动作,最后会通过AIDL接口以及AIDL实现类,最终传递到蓝牙服务层的AdapterService.java中,下面看下AdapterService.java中是如何进行配对的,部分代码如下:

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) {//如果当前设备已经配对或者设备属性为空那么返回falsereturn false;}//设置本地设备的绑定状态mRemoteDevices.setBondingInitiatedLocally(Utils.getByteAddress(device));// Pairing is unreliable while scanning, so cancel discovery// Note, remove this when native stack improves//取消扫描,具体参见上边的英文。cancelDiscoveryNative();//构建一个含有配对动作的MSG消息Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);//并将设备以及transport传入消息中msg.obj = device;msg.arg1 = transport;if (oobData != null) {Bundle oobDataBundle = new Bundle();oobDataBundle.putParcelable(BondStateMachine.OOBDATA, oobData);msg.setData(oobDataBundle);}//将消息发送给配对相关的状态机,并返回truemBondStateMachine.sendMessage(msg);return true;}

到这里,就开始进入BondStateMachine.java中进行消息的处理了~ ,先来看下这个状态机中的状态:

BondStateMachine.java - OpenGrok cross reference for /packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java

  //该状态机名为BondStateMachine.java//其中定义了两个状态//PendingCommandState是等待蓝牙配对命令的状态private PendingCommandState mPendingCommandState = new PendingCommandState();//StableState是指已经完成蓝牙配对的状态private StableState mStableState = new StableState();

综上所述,发送配对msg后,会进入PendingCommandState状态下进行处理,部分代码如下:

  private class PendingCommandState extends State {private final ArrayList<BluetoothDevice> mDevices = new ArrayList<BluetoothDevice>();@Overridepublic void enter() {infoLog("Entering PendingCommandState State");BluetoothDevice dev = (BluetoothDevice) getCurrentMessage().obj;}@Overridepublic boolean processMessage(Message msg) {BluetoothDevice dev = (BluetoothDevice) msg.obj;DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev);boolean result = false;if (mDevices.contains(dev) && msg.what != CANCEL_BOND&& msg.what != BONDING_STATE_CHANGE && msg.what != SSP_REQUEST&& msg.what != PIN_REQUEST) {deferMessage(msg);return true;}switch (msg.what) {case CREATE_BOND://接到建立连接消息后OobData oobData = null;if (msg.getData() != null) {//为oob数据赋值oobData = msg.getData().getParcelable(OOBDATA);}//调用createBond方法,建立配对result = createBond(dev, msg.arg1, oobData, false);break;//其余代码已省略...
}

        可以看到,接收到含有CREATE_BOND的msg之后,会调用createBond方法,部分代码如下:

private boolean createBond(BluetoothDevice dev, int transport, OobData oobData,boolean transition) {//如果当前的配对状态为NONE,则开始执行配对,否则直接返回falseif (dev.getBondState() == BluetoothDevice.BOND_NONE) {infoLog("Bond address is:" + dev);//将设备的地址转换为addr的数组byte[] addr = Utils.getBytesFromAddress(dev.getAddress());boolean result;//根据是否有oobData来选择对应的协议栈接口方法建立配对关系if (oobData != null) {result = mAdapterService.createBondOutOfBandNative(addr, transport, oobData);} else {//先看无oobdata的建立配对,此处直接调用了协议栈提供的接口,也就是调用到JNI层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);//如果建立成功 配对状态写入StatsLogif (!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 reasonsendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);return false;} else if (transition) {//如果传入了需要转换的状态,则进行转换transitionTo(mPendingCommandState);}return true;}return false;}

       根据oobData分别调用不同的协议栈接口,我们主要先分析下createBondNative(addr, transport)方法。

com_android_bluetooth_btservice_AdapterService.cpp - OpenGrok cross reference for /packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

//承接上面代码中调用JNI层接口的动作  result = mAdapterService.createBondNative(addr, transport);//最终会传递到一个.cpp文件中 -> 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方法,部分代码如下

bluetooth - OpenGrok cross reference for /system/bt/btif/src/bluetooth

static int create_bond(const RawAddress* bd_addr, int transport) {/* sanity check */if (!interface_ready()) return BT_STATUS_NOT_READY;//返回btif_dm_create_bond方法的配对结果return btif_dm_create_bond(bd_addr, transport);
}

而执行create_bond方法后会返回btif_dm_create_bond方法的配对结果,btif_dm_create_bond方法的部分代码如下:

btif_dm - OpenGrok cross reference for /system/bt/btif/src/btif_dm

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);//如果配对状态不为NONE,则返回一个BUSY状态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_DM_CB_CREATE_BOND事件发送到btif_dm_generic_evt方法中进行处理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;
}

事件传入 btif_dm_generic_evt后,btif_dm_generic_evt会根据不同的事件进行处理,当case到配对事件时,会执行如下代码:

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方法btif_dm_cb_create_bond(create_bond_cb->bdaddr, create_bond_cb->transport);} break;//省略部分代码
}

而调用btif_dm_cb_create_bond方法时,会回调配对状态的变化,部分代码如下:

tatic 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去向下传递进而完成配对动作的向下传递,这部分代码偏向硬件,我就不过多叙述了,主要还是看下状态如何回调到应用层的。(PS:主要是二两也不太会,怕说错了误人子弟)

配对状态是如何回调到应用层的呢?

回调的位置还是在.0.0_r47/xref/system/bt/btif/src/btif_dm

 方法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);//检查设备的配对是否在进行中if ((pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING)) {// Cross key pairing so send callback for static addressif (!pairing_cb.static_bdaddr.IsEmpty()) {auto tmp = bd_addr;//回调bond_state_changed_cbHAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);}return;}//判断是否为临时配对 如果是state设置为BT_BOND_STATE_NONEif (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_cb要通知到应用层,就需要从下往上,通过JNI然后再通过蓝牙服务最终传递到应用层。

而bond_state_changed_cb是如何通知到JNI的呢?这就需要了解另一个文件

bluetooth.h - OpenGrok cross reference for /system/bt/include/hardware/bluetooth.h

在bluetooth.h中,bond_state_changed_cb方法被声明成bond_state_changed_callback,如下:

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;

而最终这个bluetooth.h会被com_android_bluetooth_btservice_AdapterService.cpp引用,

com_android_bluetooth_btservice_AdapterService.cpp - OpenGrok cross reference for /packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp部分代码如下:


#include <hardware/bluetooth.h>
//引用bluetooth.h//配对状态改变回调
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);//调用Java层的回调函数,将对应状态以及地址和绑定状态作为参数传递sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback,(jint)status, addr.get(), (jint)state);
}

顺便看下,它是如何映射到JNI的回调方法的,代码如下:

jclass jniCallbackClass =env->FindClass("com/android/bluetooth/btservice/JniCallbacks");method_bondStateChangeCallback =env->GetMethodID(jniCallbackClass, "bondStateChangeCallback", "(I[BI)V");

通过此回调就算是通知到了JNI的接口

JniCallbacks.java - OpenGrok cross reference for /packages/apps/Bluetooth/src/com/android/bluetooth/btservice/JniCallbacks.java

 其中回调部分的代码如下:

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

可以看到,这个状态的回调会再次通知到配对的状态机,而状态发生更新后,状态机通过接收对应的msg,来进行相应状态的转换或者其他代码的执行,代码如下:

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 abovedevice = 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);}

至此,整个配对的流程就梳理完了。

整个配对流程较冗长,但是我也实在不想分两篇来写,各位厚米多担待。

而且从JNI到蓝牙协议栈的处理梳理的并不到位,如果有懂行的大佬欢迎交流~

ps:我也是小白,刚看蓝牙源码不久,如果有哪里解释的不对,欢迎各位大神指点!

文章会同步上传到公众号上(二两仙气儿),欢迎同好一起交流学习。

Android Bluetooth

好厚米们,我又来了!

这次分享的是蓝牙设备执行配对动作时Android源码的执行流程。

下面先来说下,应用层是如何发起蓝牙配对的:

( ps:大多数业务逻辑,都是扫描到可用设备后,点击可用设备 -> 发起配对。)

这里我直接略过点击可用设备的步骤哈,扫描到第一个可用设备后,我直接通过扫描信息进行配对。

public class MainActivity extends AppCompatActivity {private BluetoothAdapter mBluetoothAdapter;private BluetoothDevice mBluetoothDevice;private BluetoothLeScanner scanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ScanCallback scanCallback = new ScanCallback() {@SuppressLint("MissingPermission")@Overridepublic void onScanResult(int callbackType, ScanResult result) {super.onScanResult(callbackType, result);//将扫描到的设备信息取出来,为蓝牙设备赋值mBluetoothDevice = result.getDevice();//通过蓝牙设备,调用配对方法mBluetoothDevice.createBond();}@Overridepublic void onScanFailed(int errorCode) {super.onScanFailed(errorCode);// 扫描失败处理}};// 开始扫描if (scanner != null) {ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();// 添加过滤条件List<ScanFilter> filters = new ArrayList<>();//权限检查if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {// TODO: Consider calling//    ActivityCompat#requestPermissions// here to request the missing permissions, and then overriding//   public void onRequestPermissionsResult(int requestCode, String[] permissions,//                                          int[] grantResults)// to handle the case where the user grants the permission. See the documentation// for ActivityCompat#requestPermissions for more details.return;}scanner.startScan(filters, settings, scanCallback);}// 停止扫描if (scanner != null) {scanner.stopScan(scanCallback);}mBluetoothAdapter.startDiscovery();}
}

由上面的代码可以看出,配对动作的执行依赖

 //通过蓝牙设备,调用配对方法BluetoothDevice.createBond();

下面就进入到了FWK层

执行BluetoothDevice.createBond()后,会进入到BluetoothDevice.java中执行

BluetoothDevice.java - OpenGrok cross reference for /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());//通过service接口执行配对动作return service.createBond(this, TRANSPORT_AUTO);} catch (RemoteException e) {Log.e(TAG, "", e);}return false;}

而这个service,我们来看下其声明

private static volatile IBluetooth sService;//后来在上面的配对方法中,为此接口赋值
final IBluetooth service = sService;

本质上就是IBluetooth接口,不过在Android 10中,IBluetooth接口一共有两个。

应用层下发配对动作时,所用的IBludetooth接口是/system/bt/service/common/android/bluetooth/

此接口的具体代码如下(太多了,各位厚米自己点连接看下就行):

IBluetooth.aidl - OpenGrok cross reference for /system/bt/binder/android/bluetooth/IBluetooth.aidl

即通过这个AIDL接口调用蓝牙远程服务。

下面进入了Bluetooth 服务层

而这个接口的实现类,在AdaperServiceBinder中,部分代码如下:

PS:AdaperServiceBinder写在AdapterService.java中

AdapterService.java - OpenGrok cross reference for /packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

private static class AdapterServiceBinder extends IBluetooth.Stub {//在Binder类中继承了IBluetooth.Stubprivate AdapterService mService;AdapterServiceBinder(AdapterService svc) {mService = svc;}public void cleanup() {mService = null;}public AdapterService getService() {if (mService != null && mService.isAvailable()) {return mService;}return null;}//发起配对@Overridepublic 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;}//调用蓝牙服务中的createBond方法return service.createBond(device, transport, null);}
}

 即,应用层触发的配对动作,最后会通过AIDL接口以及AIDL实现类,最终传递到蓝牙服务层的AdapterService.java中,下面看下AdapterService.java中是如何进行配对的,部分代码如下:

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) {//如果当前设备已经配对或者设备属性为空那么返回falsereturn false;}//设置本地设备的绑定状态mRemoteDevices.setBondingInitiatedLocally(Utils.getByteAddress(device));// Pairing is unreliable while scanning, so cancel discovery// Note, remove this when native stack improves//取消扫描,具体参见上边的英文。cancelDiscoveryNative();//构建一个含有配对动作的MSG消息Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);//并将设备以及transport传入消息中msg.obj = device;msg.arg1 = transport;if (oobData != null) {Bundle oobDataBundle = new Bundle();oobDataBundle.putParcelable(BondStateMachine.OOBDATA, oobData);msg.setData(oobDataBundle);}//将消息发送给配对相关的状态机,并返回truemBondStateMachine.sendMessage(msg);return true;}

到这里,就开始进入BondStateMachine.java中进行消息的处理了~ ,先来看下这个状态机中的状态:

BondStateMachine.java - OpenGrok cross reference for /packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java

  //该状态机名为BondStateMachine.java//其中定义了两个状态//PendingCommandState是等待蓝牙配对命令的状态private PendingCommandState mPendingCommandState = new PendingCommandState();//StableState是指已经完成蓝牙配对的状态private StableState mStableState = new StableState();

综上所述,发送配对msg后,会进入PendingCommandState状态下进行处理,部分代码如下:

  private class PendingCommandState extends State {private final ArrayList<BluetoothDevice> mDevices = new ArrayList<BluetoothDevice>();@Overridepublic void enter() {infoLog("Entering PendingCommandState State");BluetoothDevice dev = (BluetoothDevice) getCurrentMessage().obj;}@Overridepublic boolean processMessage(Message msg) {BluetoothDevice dev = (BluetoothDevice) msg.obj;DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev);boolean result = false;if (mDevices.contains(dev) && msg.what != CANCEL_BOND&& msg.what != BONDING_STATE_CHANGE && msg.what != SSP_REQUEST&& msg.what != PIN_REQUEST) {deferMessage(msg);return true;}switch (msg.what) {case CREATE_BOND://接到建立连接消息后OobData oobData = null;if (msg.getData() != null) {//为oob数据赋值oobData = msg.getData().getParcelable(OOBDATA);}//调用createBond方法,建立配对result = createBond(dev, msg.arg1, oobData, false);break;//其余代码已省略...
}

        可以看到,接收到含有CREATE_BOND的msg之后,会调用createBond方法,部分代码如下:

private boolean createBond(BluetoothDevice dev, int transport, OobData oobData,boolean transition) {//如果当前的配对状态为NONE,则开始执行配对,否则直接返回falseif (dev.getBondState() == BluetoothDevice.BOND_NONE) {infoLog("Bond address is:" + dev);//将设备的地址转换为addr的数组byte[] addr = Utils.getBytesFromAddress(dev.getAddress());boolean result;//根据是否有oobData来选择对应的协议栈接口方法建立配对关系if (oobData != null) {result = mAdapterService.createBondOutOfBandNative(addr, transport, oobData);} else {//先看无oobdata的建立配对,此处直接调用了协议栈提供的接口,也就是调用到JNI层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);//如果建立成功 配对状态写入StatsLogif (!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 reasonsendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);return false;} else if (transition) {//如果传入了需要转换的状态,则进行转换transitionTo(mPendingCommandState);}return true;}return false;}

       根据oobData分别调用不同的协议栈接口,我们主要先分析下createBondNative(addr, transport)方法。

com_android_bluetooth_btservice_AdapterService.cpp - OpenGrok cross reference for /packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

//承接上面代码中调用JNI层接口的动作  result = mAdapterService.createBondNative(addr, transport);//最终会传递到一个.cpp文件中 -> 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方法,部分代码如下

bluetooth - OpenGrok cross reference for /system/bt/btif/src/bluetooth

static int create_bond(const RawAddress* bd_addr, int transport) {/* sanity check */if (!interface_ready()) return BT_STATUS_NOT_READY;//返回btif_dm_create_bond方法的配对结果return btif_dm_create_bond(bd_addr, transport);
}

而执行create_bond方法后会返回btif_dm_create_bond方法的配对结果,btif_dm_create_bond方法的部分代码如下:

btif_dm - OpenGrok cross reference for /system/bt/btif/src/btif_dm

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);//如果配对状态不为NONE,则返回一个BUSY状态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_DM_CB_CREATE_BOND事件发送到btif_dm_generic_evt方法中进行处理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;
}

事件传入 btif_dm_generic_evt后,btif_dm_generic_evt会根据不同的事件进行处理,当case到配对事件时,会执行如下代码:

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方法btif_dm_cb_create_bond(create_bond_cb->bdaddr, create_bond_cb->transport);} break;//省略部分代码
}

而调用btif_dm_cb_create_bond方法时,会回调配对状态的变化,部分代码如下:

tatic 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去向下传递进而完成配对动作的向下传递,这部分代码偏向硬件,我就不过多叙述了,主要还是看下状态如何回调到应用层的。(PS:主要是二两也不太会,怕说错了误人子弟)

配对状态是如何回调到应用层的呢?

回调的位置还是在.0.0_r47/xref/system/bt/btif/src/btif_dm

 方法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);//检查设备的配对是否在进行中if ((pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING)) {// Cross key pairing so send callback for static addressif (!pairing_cb.static_bdaddr.IsEmpty()) {auto tmp = bd_addr;//回调bond_state_changed_cbHAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);}return;}//判断是否为临时配对 如果是state设置为BT_BOND_STATE_NONEif (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_cb要通知到应用层,就需要从下往上,通过JNI然后再通过蓝牙服务最终传递到应用层。

而bond_state_changed_cb是如何通知到JNI的呢?这就需要了解另一个文件

bluetooth.h - OpenGrok cross reference for /system/bt/include/hardware/bluetooth.h

在bluetooth.h中,bond_state_changed_cb方法被声明成bond_state_changed_callback,如下:

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;

而最终这个bluetooth.h会被com_android_bluetooth_btservice_AdapterService.cpp引用,

com_android_bluetooth_btservice_AdapterService.cpp - OpenGrok cross reference for /packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp部分代码如下:


#include <hardware/bluetooth.h>
//引用bluetooth.h//配对状态改变回调
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);//调用Java层的回调函数,将对应状态以及地址和绑定状态作为参数传递sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback,(jint)status, addr.get(), (jint)state);
}

顺便看下,它是如何映射到JNI的回调方法的,代码如下:

jclass jniCallbackClass =env->FindClass("com/android/bluetooth/btservice/JniCallbacks");method_bondStateChangeCallback =env->GetMethodID(jniCallbackClass, "bondStateChangeCallback", "(I[BI)V");

通过此回调就算是通知到了JNI的接口

JniCallbacks.java - OpenGrok cross reference for /packages/apps/Bluetooth/src/com/android/bluetooth/btservice/JniCallbacks.java

 其中回调部分的代码如下:

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

可以看到,这个状态的回调会再次通知到配对的状态机,而状态发生更新后,状态机通过接收对应的msg,来进行相应状态的转换或者其他代码的执行,代码如下:

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 abovedevice = 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);}

至此,整个配对的流程就梳理完了。

整个配对流程较冗长,但是我也实在不想分两篇来写,各位厚米多担待。

而且从JNI到蓝牙协议栈的处理梳理的并不到位,如果有懂行的大佬欢迎交流~

ps:我也是小白,刚看蓝牙源码不久,如果有哪里解释的不对,欢迎各位大神指点!

文章会同步上传到公众号上(二两仙气儿),欢迎同好一起交流学习。