蓝牙基本概念以及Android中蓝牙enable/discover流程分析

蓝牙基本概念

两种蓝牙技术:Basic Rate (BR)和Low Energy(LE)
这两种技术是不能互通的,也就是不能相互兼容。如果要确保和所有的蓝牙设备互通,只能同时实现这两种技术。

BR

Basic Rage是正宗的蓝牙技术,包括可选的(optional)的EDR(Enhanced Data Rate)技术,以及Alternate(交替使用的)MAC层和PHY层扩展(简称AMP)。

LE

BR技术的进化路线,就是传输速率的加快。能量是守恒的,想要加快传输速率,代价就是要消耗更多的能量。再有些应用场景下,并不关心传输速率,反而关心功耗,这就是BLE产生的背景。

物理层

物理层负责提供数据传输的物理信道,蓝牙的物理层分未Physical Channel 和Physiccal Links

Physical Channel

频率范围:2.400-2.4835GHz
BR/EDR物理信道定义:
1.ISM频率范围被分成79个Channel,每个Channel占用1M的带宽。在0 Channel和78 Channel设立gurad band(保护带宽,Lower Guard Band为2MHz,Upper Guard Band为3.5MHz)
2.采用跳频技术(hopping),也就是说摸一个物理信道并不是固定的占用79个channel中的某一个,而是以一定的规律在跳动(该规律在技术上叫做“伪随机码”,就是假的随机码)。因此蓝牙的物理信道也可以称作跳频信道(hopping channel);
3. BR/EDR技术定义了5种物理信道(跳频信道),BR/EDR Basic Piconet Physical Channel(用于连接状态的蓝牙设备之间的通讯,使用全部79个频点);BR/EDR Adapted Piconet Physical Channel(用于连接状态下蓝牙设备之间的通讯,使用79个跳频点种的子集,但是跳频数目不能少于20个);BR/EDR Page Scan Physical Channel(用于发现蓝牙设备的发现操作Discovery);BR/EDR Inquriy Scan Physical Channel(用于蓝牙设备的连接操作Connect);BR/EDR synchronization Scan Channel(用于无连接的广播通讯).
4. 同一时刻,BT设备只能在其中一个物理信道上通信,为了支持多个并行的操作,蓝牙系统采用分时方式,即不同的时间点采用不同的信道
LE的物理信道定义:
1.ISM频率范围被分成40个channel,每个channel占用2M的带宽,在0channel和39channel之外设立guradband(保护带宽,Lower Guard为2MHz,Upper Guard Band为3.5MHz)
2.LE技术定义了2种物理信道,LE Piconet channed(用于连接状态的蓝牙设备件的通讯,和BR/EDR一样,采用调频技术,但是只会在40个频点种的37个中进行跳频)和LE advertisement Broadcast Channel(用于在设备间进行无连接的广播通讯,这些广播通信用于蓝牙设备的返现,连接操作,亦可用于无连接的数据传输)
AMP为高速数据传输设计的技术,其物理规范直接采用802.11的PHY规范,主要有如下特点:AMP物理信道只有一种,即AMP Physical Channel,主要用于已连接设备之间的数据通讯。

Physical Links(物理链路)
由上面的描述可知,蓝牙协议为BR/EDR, LE和AMP三种技术定义了8种类型的物理信道。物理链路是对这些物理信道的进一步封装。

AMP Physical Channel /LE Piconet Channel/LE Advertisement Broadcast Channel均有一个对应的Physical Link,分别是Amp Physical Link/LE Active Physical Link/LE Advertising Physical Channel。

逻辑层

逻辑层的主要功能是再已连接的蓝牙设备之间,基于物理链路,建立逻辑信道。
蓝牙逻辑信道的划分依据是传输类型,主要包含下面三类:
1.用于管理底层物理链路的控制类传输,包括AMP-C,ACL-C,PSB-C,LE-C,ADVB-C
2.传输用户数据的用户类传输,包括AMP-U,ACL-U,PSB-U,LE-U,ADVB-U
3.其他比较特殊的传输类型,包括流式传输stream,PBD(Profile Broadcast Data)
以上每种Logic Link都会在下层对应一个Logical Transport,这些Logical Transport具有一些属性,如流控,应答,重传机制等。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TTgSQloV-1587893425132)(./images/1573809760433.png)]

Android Bluetooth系统框图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mTyIIFJH-1587893425133)(./images/Bluetooth.png)]
com_android_bluetooth_btservice_AdapterService.cpp中的sBluetoothInterface对应下面文件
hardware/realtek/bluetooth/rtkbt/code/bluedroid/btif/src/bluetooth.c

蓝牙源码分析
typedef struct {
    int cmd_fdr, cmd_fdw;//通过socketpair获得
    int poll_count;//记录加入到poll中的fd个数,或者说是pollslot的个数
    poll_slot_t ps[MAX_POLL];//最大值为8,
    int psi[MAX_POLL]; //index of poll slot
    volatile pid_t thread_id;
    btsock_signaled_cb callback;
    btsock_cmd_cb cmd_callback;
    int used; //标志着这个thread slot有没有被使用,最大值为8
} thread_slot_t;
蓝牙的构成

在android系统里面,个人感觉是比较复杂的,起码比无线复杂。下面就以amlogic sdk为例来进行分析。总体来说,android中蓝牙由以下部分组成:
1.libbt-vendor.so。这部分应该是由硬件决定的。比如说这个蓝牙芯片是通过usb接入到主芯片还是通过uart接入到主芯片。这次代码阅读时通过uart的方式接入到主芯片的。代码位置为:hardware/realtek/bluetooth/rtkbt/code/libbt-vendor
2.bluetooth.default。这部分包含了蓝牙协议部分;代码位置为:hardware/realtek/bluetooth/rtkbt/
3.Bluetooth.apk,通过jni与bluetooth.default进行数据的交换。代码位置为:packages/apps/Bluetooth。
4.Android System中蓝牙有关的service & adapter。在打开蓝牙时,将会通过AIDL(IBluetooth)连接上步中的Service。同时提供统一的api接口供apk进行调用;
5.Settings,也就是设置。在这部分主要是提供一个界面,供用户进行操作。

随手笔记

在设置中的蓝牙部分的入口为:BluetoothSettings.java.这部分主要就是对系统中的BluetoothAdapter进行了封装,然后监听蓝牙的状态进行更新以及负责ui部分的逻辑。这部分比较简单就不进行源码分析了

1.打开蓝牙过程:

sequenceDiagram
BluetoothManagerService.java ->>BluetoothManagerService.java:handler send MESSAGE_ENABLE msg
BluetoothManagerService.java ->>BluetoothManagerService.java:handleEnable.bind service and call enable 
BluetoothManagerService.java ->>AdapterService.java:enable()
AdapterService.java ->>AdapterState.java:handler send USER_TURN_ON msg
AdapterState.java ->> AdapterService.java:OffState call processStart
Note right of AdapterService.java:processStart 这个函数里面启动profile对应的service并且发送广播,init jnicallback回调函数,
JniCallbacks.java ->> AdapterService.java:processProfileServiceStateChanged,
Note right of AdapterService.java:更新profile状态,如果都启动的话,启动native 层
AdapterService.java ->> AdapterState.java:Handler 发送STARTED消息
AdapterState.java ->> AdapterService.java:enableNative
AdapterService.java->>com_android_bluetooth_btservice_AdapterService.cpp:JNI调用 enableNative
com_android_bluetooth_btservice_AdapterService.cpp ->> bluetooth.c:调用enable()
bluetooth.c ->> btif_core.c:btif_enable_bluetooth
btif_core.c ->> bte_main.c:bte_main_enable
Note right of bte_main.c:初始化hci,创建一个线程运行btu_task,这个task有两个作用:1.初始话底层的一些协议:2.创建一个循环,读取mbox中的消息进行处理

在这里面需要注意的是,底层产生的信息是通过JniCallbacks这个java类进行反馈上来的。
关于蓝牙硬件初始化的逻辑结构参考如下图所示:
在这里插入图片描述

蓝牙Discovery流程分析
BluetoothAdapter初始化分析

1.在Android中,对蓝牙进行操作都是通过BluetoothAdapter进行的。那么先看一下它的初始化函数

BluetoothAdapter.java
    public static synchronized BluetoothAdapter getDefaultAdapter() {
        if (sAdapter == null) {
            IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);//获得系统中的Bluetooth Manager Service
            if (b != null) {
                IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
                sAdapter = new BluetoothAdapter(managerService);
            } else {
                Log.e(TAG, "Bluetooth binder is null");
            }
        }
        return sAdapter;
    }

    /**
     * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
     */
    BluetoothAdapter(IBluetoothManager managerService) {

        if (managerService == null) {
            throw new IllegalArgumentException("bluetooth manager service is null");
        }
        try {
            mService = managerService.registerAdapter(mManagerCallback);//注册callback函数,这里需要注意的是返回的实际上是AdapterService代理。对蓝牙的操作都是使用这个代理进行的。
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        mManagerService = managerService;
        mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
        mHandler = new Handler(Looper.getMainLooper());
    }

BluetoothManagerService.java
    public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
        //Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
        //msg.obj = callback;
        //mHandler.sendMessage(msg);
        synchronized(mConnection) {
            boolean added = mCallbacks.register(callback);
            return mBluetooth;
        }
    }
	
private class BluetoothHandler extends Handler {
···
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
                      mBluetooth = IBluetooth.Stub.asInterface(service);
···
}

之前在介绍打开蓝牙的分析中提到过,打开蓝牙的时候Bind了AdapterService。从上面可以看出,BluetoothAdapter实际上是使用Bluetooth.apk中的AdapterService进行蓝牙操作的。
下面言归正传,在Settings中的Bluetooth设置界面点击搜索按键时就会按照下面的顺序进行调用:
LocalBluetoothAdapter ->BluetoothAdapter ->AdapterService.下面就是调用native层中的startDiscoveryNative函数。
在JNI中 对应函数包含在文件:com_android_bluetooth_btservice_AdapterService.cpp中。

static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
   ALOGV("%s:",__FUNCTION__);

   jboolean result = JNI_FALSE;
   if (!sBluetoothInterface) return result;

   int ret = sBluetoothInterface->start_discovery();
   result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
   return result;
}

在这个函数中涉及到的sBluetoothInterface就是蓝牙构成里面介绍的bluetooth.default的入口。
那么bluetooth.default是如何加载的呢?

static void classInitNative(JNIEnv* env, jclass clazz) {
···
   char value[PROPERTY_VALUE_MAX];
   property_get("bluetooth.mock_stack", value, "");

   const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID);

   err = hw_get_module(id, (hw_module_t const**)&module);//只是加载对应的库文件

   if (err == 0) {
       hw_device_t* abstraction;
   	//实际上调的是Bluetooth.c中的open_bluetooth_stack
       err = module->methods->open(module, id, &abstraction);
       if (err == 0) {
           bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction;
           sBluetoothInterface = btStack->get_bluetooth_interface();
       } else {
          ALOGE("Error while opening Bluetooth library");
       }
   } else {
       ALOGE("No Bluetooth Library found");
   }
···
}

具体的是根据什么去加载的细节问题这里就不在详细介绍了,就是根据name进行加载的。
那么sBluetoothInterface对应的实现文件是bluetooth.c
继续分析discovery流程

bluetooth.c
static int start_discovery(void)
{
    /* sanity check */
    if (interface_ready() == FALSE)
        return BT_STATUS_NOT_READY;

    return btif_dm_start_discovery();
}
bt_status_t btif_dm_start_discovery(void){

···
BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
···
}
void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{

    tBTA_DM_API_SEARCH    *p_msg;

    if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
    {
        memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));

        p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
        memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
        p_msg->services = services;
        p_msg->p_cback = p_cback;
        p_msg->rs_res  = BTA_DM_RS_NONE;
        bta_sys_sendmsg(p_msg);
    }

}

看到就是填充一个信息相关的机构,表明事件类型为BTA_DM_API_SEARCH_EVT,之后发送这个消息。
这里面就涉及到了蓝牙中的消息是如何循环处理的问题了。这部分还是有点复杂,后面有时间再写出来分析。
总之会根据调用到bta_dm_act.c中的bta_dm_search_start函数。

void bta_dm_search_start (tBTA_DM_MSG *p_data){
···
    result.status = BTM_StartInquiry(   (tBTM_INQ_PARMS*)&p_data->search.inq_params,
                        bta_dm_inq_results_cb,
                        (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb);
···
}
btm_inq.c
tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
                              tBTM_CMPL_CB *p_cmpl_cb){
···
        else if ((status = btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
                                            p_inqparms->duration)) != BTM_CMD_STARTED)
        {
···
}
btm_ble_gap.c
tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8   duration){
···
	if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE))
···
}
hciblecmds.c
BOOLEAN btsnd_hcic_ble_set_scan_enable (UINT8 scan_enable, UINT8 duplicate)
{
    BT_HDR *p;
    UINT8 *pp;

    if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE)) == NULL)
        return (FALSE);

    pp = (UINT8 *)(p + 1);

    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE;
    p->offset = 0;

    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_ENABLE);
    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE);

    UINT8_TO_STREAM (pp, scan_enable);
    UINT8_TO_STREAM (pp, duplicate);

    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
    return (TRUE);
}
void btu_hcif_send_cmd (UINT8 controller_id, BT_HDR *p_buf){
···
HCI_CMD_TO_LOWER(p_buf);
···
}

这个宏定义为:

#define HCI_CMD_TO_LOWER(p)         bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_HCI_CMD)
bte_main.c
void bte_main_hci_send (BT_HDR *p_msg, UINT16 event){
···
        if (bt_hc_if)
            bt_hc_if->transmit_buf((TRANSAC)p_msg, \
                                       (char *) (p_msg + 1), \
                                        p_msg->len);
···
}

transmit_buf这个函数实际上就是动用了uart的写入函数,将数据写入到节点中。至此discover命令的发送就结束了。

欢迎使用 {小书匠}(xiaoshujiang)编辑器,您可以通过 小书匠主按钮>模板 里的模板管理来改变新建文章的内容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章