赞
踩
好厚米们,我又来了!
这次分享的是蓝牙设备执行配对动作时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<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();
执行BluetoothDevice.createBond()后,会进入到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中)
- 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
- //其中定义了两个状态
-
- //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>();
-
- @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)方法。
- //承接上面代码中调用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引用,
-
- #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的接口
其中回调部分的代码如下:
- 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:我也是小白,刚看蓝牙源码不久,如果有哪里解释的不对,欢迎各位大神指点!
文章会同步上传到公众号上(二两仙气儿),欢迎同好一起交流学习。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。