博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GATT scan的流程
阅读量:5837 次
发布时间:2019-06-18

本文共 16843 字,大约阅读时间需要 56 分钟。

BLE scan 在bluedroid的实现中,有两个接口:一个是discovery,一个是ble observe,这两者有什么区别呢?

 这里追了一下代码发现,inquiry 是上层调用search 相关的接口的实现函数,ble observe 是调用GATT scan的接口的实现函数,这篇文章分析一下,在调用GATT 接口实现scan的流程。

GATT的服务代码逻辑在哪里实现的呢?其核心代码的实现是bluedroid里面,但是,上层的应用是不可能直接调用协议栈的代码的,其实在bluedroid上面还会进行封装一个GATT的服务,其实现在package/app/Bluetooth下面的GattService.java,这里面实现了关于GATT相关的各种接口,应用层的代码通过binder 调用绑定到这些接口,并完成一系列的调用。

看一下GattService.java的实现:

/**     * Handlers for incoming service calls     */    private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {        private GattService mService;        public BluetoothGattBinder(GattService svc) {            mService = svc;        }        public boolean cleanup()  {            mService = null;            return true;        }...        @Override        public void startScan(int appIf, boolean isServer, ScanSettings settings,                List
filters, List storages, String callingPackage) { GattService service = getService(); if (service == null) return; service.startScan(appIf, isServer, settings, filters, storages, callingPackage); } public void stopScan(int appIf, boolean isServer) { GattService service = getService(); if (service == null) return; service.stopScan(new ScanClient(appIf, isServer)); } ... }

可以看到其代码中实现了一个BluetoothGattBinder,这个上层应用程序在绑定完成的时候,会得到这个binder接口。我们也可以看到,这个binder实现的也是GATT相关的基本的接口。

分析一下startScan接口,发现其是调用到另一个service 的startScan的接口,那这个service 是哪里来的呢?其实这个service就是GATTService本身,在initBinder的时候,将this 指针传入。

protected IProfileServiceBinder initBinder() {        return new BluetoothGattBinder(this);    }

 我们的重点是分析startScan 这个接口的流程,现在我们看GATTService是如何实现这个接口的

void startScan(int appIf, boolean isServer, ScanSettings settings,            List
filters, List
> storages, String callingPackage) {... final ScanClient scanClient = new ScanClient(appIf, isServer, settings, filters, storages); ... mScanManager.startScan(scanClient); }

新建了一个scanClient 类,并将此类传入到mScanManager.startScan中:

void startScan(ScanClient client) {        sendMessage(MSG_START_BLE_SCAN, client);    }

此时的代码走到了ScanManager.java里面,不管上层的代码如何流转,我们知道,最后肯定还是调用到JNI 的接口,然后到达bluedroid里面,接着看:

// Handler class that handles BLE scan operations.    private class ClientHandler extends Handler {...        @Override        public void handleMessage(Message msg) {            ScanClient client = (ScanClient) msg.obj;            switch (msg.what) {                case MSG_START_BLE_SCAN://处理事件                    handleStartScan(client);                    break;                case MSG_STOP_BLE_SCAN:                    handleStopScan(client);                    break;...            }        }        void handleStartScan(ScanClient client) {//处理scan的实现函数            Utils.enforceAdminPermission(mService);...            // Begin scan operations.            if (isBatchClient(client)) {                mBatchClients.add(client);                mScanNative.startBatchScan(client);            } else {                mRegularScanClients.add(client);                mScanNative.startRegularScan(client);                if (!mScanNative.isOpportunisticScanClient(client)) {                    mScanNative.configureRegularScanParams();                }            }        }...    }

这边分析一下startBatchScan是vendor command 相关,那么一般都是调用到mScanNative.startRegularScan,这边已经调用到了native层面,具体看看其实现:

void startRegularScan(ScanClient client) {            if (isFilteringSupported() && mFilterIndexStack.isEmpty()                    && mClientFilterIndexMap.isEmpty()) {                initFilterIndexStack();            }            if (isFilteringSupported()) {                configureScanFilters(client);            }            // Start scan native only for the first client.            if (numRegularScanClients() == 1) {                gattClientScanNative(true);            }        }

这边继续往下调用到gattClientScanNative(true) :这里调用到JNI 层,其实现在文件com_android_bluetooth_gatt.cpp

static void gattClientScanNative(JNIEnv* env, jobject object, jboolean start){    if (!sGattIf) return;    sGattIf->client->scan(start);}

到这里就很明确了,其最终调用的是sGattIf中client 的scan的接口,那其接口是怎么样的呢?

其是在bluetooth.c里面通过get_profile_interface 来获取GATT的interface的,

static const btgatt_interface_t btgattInterface = {    sizeof(btgattInterface),    btif_gatt_init,    btif_gatt_cleanup,    &btgattClientInterface,    &btgattServerInterface,};

中的client 的接口如下:

const btgatt_client_interface_t btgattClientInterface = {    btif_gattc_register_app,    btif_gattc_unregister_app,    btif_gattc_scan,    btif_gattc_open,    btif_gattc_close,    btif_gattc_listen,...}

那其实调用的就是:btif_gattc_scan 

static bt_status_t btif_gattc_scan( bool start ){    CHECK_BTGATT_INIT();    btif_gattc_cb_t btif_cb;    return btif_transfer_context(btgattc_handle_event, start ? BTIF_GATTC_SCAN_START : BTIF_GATTC_SCAN_STOP,                                 (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);}

这里将处理的流程transfer到bt_jni_workqueue_thread线程了,从这个线程的名字来看,主要是处理从JNI 下来的事件。看看具体做了什么:

static void btgattc_handle_event(uint16_t event, char* p_param){...    btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*) p_param;    if (!p_cb) return;    switch (event)    {...        case BTIF_GATTC_SCAN_START:            btif_gattc_init_dev_cb();            BTA_DmBleObserve(TRUE, 0, bta_scan_results_cb);//调用的是这个函数            break;...

继续看BTA_DmBleObserve,注意第一个参数是true,表示开始scan,第二个参数是持续时间,0表示一直持续:

extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration,                             tBTA_DM_SEARCH_CBACK *p_results_cb){    tBTA_DM_API_BLE_OBSERVE   *p_msg;    APPL_TRACE_API("BTA_DmBleObserve:start = %d ", start);    if ((p_msg = (tBTA_DM_API_BLE_OBSERVE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_OBSERVE))) != NULL)    {        memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_OBSERVE));        p_msg->hdr.event = BTA_DM_API_BLE_OBSERVE_EVT;//向bt_workqueue_thread发送BTA_DM_API_BLE_OBSERVE_EVT      p_msg->start = start;
     p_msg->duration = duration;         p_msg->p_cback = p_results_cb;         bta_sys_sendmsg(p_msg);    } }

 看了一下代码发现bt_workqueue_thread 是处理事件的主线程,bta_sys_sendmsg(p_msg); 这个函数是将消息发送到btu_bta_msg_queue,而这个queue是和bt_workqueue_thread绑定的,队列里面的消息都会在这个线程里面处理:

void bta_sys_sendmsg(void *p_msg){    if (btu_bta_msg_queue)        fixed_queue_enqueue(btu_bta_msg_queue, p_msg);}

那现在 关于scan的event 的处理已经来到了另一个线程:bt_workqueue_thread,那么该队列里面有了数据线程如何处理?

fixed_queue_register_dequeue(btu_bta_msg_queue,      thread_get_reactor(bt_workqueue_thread),      btu_bta_msg_ready,      NULL);

根据上面的代码,我们知道会调用到btu_bta_msg_ready:

void btu_bta_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {    BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);//消息出列    bta_sys_event(p_msg);}

也就是先让消息处理,然后再调用bta_sys_event来处理:那至此我们知道,凡是调用到bta_sys_sendmsg,那最终处理的函数都是bta_sys_event来处理,而这个函数的处理方式也是一种dispatch的机制:

void bta_sys_event(BT_HDR *p_msg){...    /* get subsystem id from event */    id = (UINT8) (p_msg->event >> 8);    /* verify id and call subsystem event handler */    if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))    {        freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);    }...}

其思想就是找到该事件对应的处理函数,这些event的高8bit 是属于事件的类型,或者称为主事件,而event的低8 bit是事件的子类,或者称为子事件。处理的过程是先通过主事件找到事件的处理函数handler(当然肯定是事先注册好的),然后在该处理函数中处理子事件。

那该事件的处理函数handler 是什么呢?

/*********************************************************************************** Function         bta_sys_register**** Description      Called by other BTA subsystems to register their event**                  handler.****** Returns          void*********************************************************************************/void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg){    bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg;    bta_sys_cb.is_reg[id] = TRUE;}

这里是注册的地方,根据函数的注释,是BTA 的子系统注册自己的event 的处理函数 时候所调用的。下图很容易看出有哪些模块调用这个注册函数

 对于BTA_DM_API_BLE_OBSERVE_EVT 这个event 可知其主事件是BTA_ID_DM = 1 ,其注册 的地方在BTA_EnableBluetooth:

bta_sys_register (BTA_ID_DM, &bta_dm_reg );

那现在我们知道,其处理的函数的入口就是bta_dm_reg:

static const tBTA_SYS_REG bta_dm_reg ={    bta_dm_sm_execute,    bta_dm_sm_disable};
BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg){    UINT16  event = p_msg->event & 0x00ff;//取出子事件    /* execute action functions */    if(event < BTA_DM_NUM_ACTIONS)    {        (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg);    }    return TRUE;}

这里我们发现,其设计还是比较巧妙,每个event 对应的处理函数,是在一个大的数组中,用事件的子事件(低8bit)来寻址,这有点分页的意味了。

这里该事件真正的处理函数是bta_dm_ble_observe:并调用如下代码:

((status = BTM_BleObserve(TRUE, p_data->ble_observe.duration,                            bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb))!= BTM_CMD_STARTED)

这里我们发现,函数调用已经进入到stack里面了,BTM_BleObserve,看看其具体实现,这里我们应该还记得,这里的第二个参数传进来的时候是0:

tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration,                           tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb){...    UINT32 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;//发现参数是优先使用inquiry的参数    UINT32 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;...    if (start)    {        /* shared inquiry database, do not allow observe if any inquiry is active */        if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))//如果有observe 直接返回        {            BTM_TRACE_ERROR("%s Observe Already Active", __func__);            return status;        }        btm_cb.ble_ctr_cb.p_obs_results_cb = p_results_cb;        btm_cb.ble_ctr_cb.p_obs_cmpl_cb = p_cmpl_cb;        status = BTM_CMD_STARTED;        /* scan is not started */        if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))//没有其他的scan 行为才继续执行        {            /* allow config of scan type */            p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ?                                                    BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type;...            p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;            status = btm_ble_start_scan();//开始scan        }        if (status == BTM_CMD_STARTED)        {            btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_OBSERVE_ACTIVE;            if (duration != 0)                /* start observer timer */                btu_start_timer (&btm_cb.ble_ctr_cb.obs_timer_ent, BTU_TTYPE_BLE_OBSERVE, duration);//这里注意,如果duration设置了,那么经过一定时间就会超时,然后会停止scan,如果没有设置这个值,就会一直scan        }    }

这里注意一下代码中有这样一句注释:shared inquiry database, do not allow observe if any inquiry is active,说明oberve的优先级还是很低的。从代码中也 可以看出只有当没有其他的scan的行为,observe才会继续进行。另外对于scan type 是active还是passive的问题,当p_inq->scan_interval 没有设置的话,就使用active,否则就使用当前的设置值。从这也可以看出,active 是优先被使用的。

最后看看btm_ble_start_scan的实现,这个就很简单了,直接通过HCI 来发送命令了:

 

tBTM_STATUS btm_ble_start_scan(void){    tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;    tBTM_STATUS status = BTM_CMD_STARTED;    /* start scan, disable duplicate filtering */    if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter))//HCI command    {        status = BTM_NO_RESOURCES;    }    else    {        if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI)            btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);//更新拓扑        else            btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT);    }    return status;}

 

scan结果的回报:


前面注册的时候,我们看到

case BTIF_GATTC_SCAN_START:            btif_gattc_init_dev_cb();            BTA_DmBleObserve(TRUE, 0, bta_scan_results_cb);            break;

其回调函数是bta_scan_results_cb,当搜索结果上来的时候,该函数会被调用:

static void bta_scan_results_cb (tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data){...    switch (event)    {        case BTA_DM_INQ_RES_EVT:        {...        }        break;        case BTA_DM_INQ_CMPL_EVT:        {...    }    btif_transfer_context(btif_gattc_upstreams_evt, BTIF_GATT_OBSERVE_EVT,                                 (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);}

代码中针对BTA_DM_INQ_RES_EVT和BTA_DM_INQ_CMPL_EVT 都会有自己的一些处理,但是最后都要经过btif_gattc_upstreams_evt的处理,并且是event = BTIF_GATT_OBSERVE_EVT 

看具体的代码实现:

case BTIF_GATT_OBSERVE_EVT:        {            btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*) p_param;...             BTIF_STORAGE_FILL_PROPERTY(&properties,                        BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type), &dev_type);             btif_storage_set_remote_device_property(&(p_btif_cb->bd_addr), &properties);            HAL_CBACK(bt_gatt_callbacks, client->scan_result_cb,                      &p_btif_cb->bd_addr, p_btif_cb->rssi, p_btif_cb->value);            break;        }

上面做的主要就是保存设备的属性,以及向上层汇报相关的设备信息:使用bt_gatt_callbacks中的 client->scan_result_cb,接口。

那这个接口是哪里来的呢?

static bt_status_t btif_gatt_init( const btgatt_callbacks_t* callbacks ){    bt_gatt_callbacks = callbacks;    return BT_STATUS_SUCCESS;}

发现是gatt 模块init的时候赋值的,那么我们就知道其callback 来源于JNI层面:

static const btgatt_callbacks_t sGattCallbacks = {    sizeof(btgatt_callbacks_t),    &sGattClientCallbacks,    &sGattServerCallbacks};
static const btgatt_client_callbacks_t sGattClientCallbacks = {    btgattc_register_app_cb,    btgattc_scan_result_cb,//此函数    btgattc_open_cb,...

通过JNI方法的回调:

void btgattc_scan_result_cb(bt_bdaddr_t* bda, int rssi, uint8_t* adv_data){...    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onScanResult        , address, rssi, jb);//调用method_onScanResult
... checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); }

这个方法的实现是在java层,那到底对应于哪一个文件呢?

int register_com_android_bluetooth_gatt(JNIEnv* env){    int register_success =        jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/ScanManager$ScanNative",                sScanMethods, NELEM(sScanMethods));    register_success &=        jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/AdvertiseManager$AdvertiseNative",                sAdvertiseMethods, NELEM(sAdvertiseMethods));    return register_success &        jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/GattService",                sMethods, NELEM(sMethods));}

发现sMethods对应于"com/android/bluetooth/gatt/GattService" ,那我们知道其实现是在GattService.java里面。看具体的实现:

void onScanResult(String address, int rssi, byte[] adv_data) {        if (VDBG) Log.d(TAG, "onScanResult() - address=" + address                    + ", rssi=" + rssi);        List
remoteUuids = parseUuids(adv_data); for (ScanClient client : mScanManager.getRegularScanQueue()) { if (client.uuids.length > 0) { int matches = 0; for (UUID search : client.uuids) { for (UUID remote: remoteUuids) { if (remote.equals(search)) { ++matches; break; // Only count 1st match in case of duplicates } } } if (matches < client.uuids.length) continue; } if (!client.isServer) { ClientMap.App app = mClientMap.getById(client.clientIf); if (app != null) { BluetoothDevice device = BluetoothAdapter.getDefaultAdapter() .getRemoteDevice(address); ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(adv_data), rssi, SystemClock.elapsedRealtimeNanos()); // Do no report if location mode is OFF or the client has no location permission // PEERS_MAC_ADDRESS permission holders always get results if (hasScanResultPermission(client) && matchesFilters(client, result)) { try { ScanSettings settings = client.settings; if ((settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_ALL_MATCHES) != 0) { app.callback.onScanResult(result); } } catch (RemoteException e) { Log.e(TAG, "Exception: " + e); mClientMap.remove(client.clientIf); mScanManager.stopScan(client); } } } } else { ServerMap.App app = mServerMap.getById(client.clientIf); if (app != null) { try { app.callback.onScanResult(address, rssi, adv_data); } catch (RemoteException e) { Log.e(TAG, "Exception: " + e); mServerMap.remove(client.clientIf); mScanManager.stopScan(client); } } } } }

到这里呢,协议栈就将关于设备的信息上传到bluetooth.apk了,在这个函数里面,我们可以看到其最终调用到app.callback.onScanResult(address, rssi, adv_data);,这边应该是回调到更上一层应用。

 

转载于:https://www.cnblogs.com/libs-liu/p/9166075.html

你可能感兴趣的文章
那些我们明白却不能完美的
查看>>
Linux Oracle启动SqlPlus无法连接
查看>>
Android中自定义checkbox样式
查看>>
新浪微博模拟登录–HTTPS方式
查看>>
Linux NFS配置小结
查看>>
当用户有登录到的限制时,远程桌面登录报错的解决
查看>>
Java--jvm性能优化课程之基本类型
查看>>
angular的canvas画图例子
查看>>
SELinux
查看>>
我的友情链接
查看>>
从标准输入读取几行输入。每行输入都要打印到标准输出上,前面加上行号。...
查看>>
part 1--入门:
查看>>
Android APK应用安装原理(1)-解析AndroidManifest原理-PackageParser.parserPackage
查看>>
Spark 简介
查看>>
windows 7 下的 XP mode
查看>>
接口规范 13. 文件上传及管理相关接口
查看>>
类与封装的概念(十二)
查看>>
linux服务器crontab定时任务
查看>>
我非软件NSIS
查看>>
Windows server 2012安装.NET 3.5
查看>>