好厚米们,我又来了!
这次分享的是蓝牙设备执行配对动作时Android源码的执行流程。
( ps:大多数业务逻辑,都是扫描到可用设备后,点击可用设备 -> 发起配对。)
这里我直接略过点击可用设备的步骤哈,扫描到第一个可用设备后,我直接通过扫描信息进行配对。
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter;
private BluetoothDevice mBluetoothDevice;
private BluetoothLeScanner scanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ScanCallback scanCallback = new ScanCallback() {
@SuppressLint("MissingPermission")
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
//将扫描到的设备信息取出来,为蓝牙设备赋值
mBluetoothDevice = result.getDevice();
//通过蓝牙设备,调用配对方法
mBluetoothDevice.createBond();
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
// 扫描失败处理
}
};
// 开始扫描
if (scanner != null) {
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
// 添加过滤条件
List 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();
执行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接口调用蓝牙远程服务。
而这个接口的实现类,在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.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;
}
//调用蓝牙服务中的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) {
//如果当前设备已经配对或者设备属性为空那么返回false
return 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);
}
//将消息发送给配对相关的状态机,并返回true
mBondStateMachine.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 mDevices = new ArrayList();
@Override
public void enter() {
infoLog("Entering PendingCommandState State");
BluetoothDevice dev = (BluetoothDevice) getCurrentMessage().obj;
}
@Override
public 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,则开始执行配对,否则直接返回false
if (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);
//如果建立成功 配对状态写入StatsLog
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;
}
根据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.cc - OpenGrok cross reference for /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;
//返回btif_dm_create_bond方法的配对结果
return btif_dm_create_bond(bd_addr, transport);
}
而执行create_bond方法后会返回btif_dm_create_bond方法的配对结果,btif_dm_create_bond方法的部分代码如下:
btif_dm.cc - OpenGrok cross reference for /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);
//如果配对状态不为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:主要是二两也不太会,怕说错了误人子弟)
回调的位置还是在http://aospxref.com/android-10.0.0_r47/xref/system/bt/btif/src/btif_dm.cc
方法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 address
if (!pairing_cb.static_bdaddr.IsEmpty()) {
auto tmp = bd_addr;
//回调bond_state_changed_cb
HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);
}
return;
}
//判断是否为临时配对 如果是state设置为BT_BOND_STATE_NONE
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_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
//引用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 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 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);
}
至此,整个配对的流程就梳理完了。
整个配对流程较冗长,但是我也实在不想分两篇来写,各位厚米多担待。
而且从JNI到蓝牙协议栈的处理梳理的并不到位,如果有懂行的大佬欢迎交流~
ps:我也是小白,刚看蓝牙源码不久,如果有哪里解释的不对,欢迎各位大神指点!
文章会同步上传到公众号上(二两仙气儿),欢迎同好一起交流学习。