Android Bluetooth | 蓝牙配对源码分析

好厚米们,我又来了!

这次分享的是蓝牙设备执行配对动作时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();

下面就进入到了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.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<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)方法。

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 <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 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:我也是小白,刚看蓝牙源码不久,如果有哪里解释的不对,欢迎各位大神指点!

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

猜你喜欢

转载自blog.csdn.net/ezsxrtghjmk/article/details/131311668