这段时间一直在跟一个BLE相关的项目,之前对BLE基本没怎么接触,所以刚好趁这个机会好好把bluedroid好好梳理一遍。要完全分析清楚估计得花老长时间了,先一步步来吧,

  • BlueDroid 代码结构
  • BlueDroid 扫描的调用流程
  • BlueDroid 的一些重要数据结构

BlueDroid 代码结构

先看下Android 里BlueDroid里的代码结构:

很多目录吧,究竟从哪里看起很头疼吧。。

BlueDroid的入口在main目录中的bte_main.c中:

void bte_main_enable()
{APPL_TRACE_DEBUG("%s", __FUNCTION__);module_start_up(get_module(BTSNOOP_MODULE));module_start_up(get_module(HCI_MODULE));BTU_StartUp();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

所有的启动都在后续进行。具体的初始化啥,启动啥,需要自己去研究咯。为了更熟悉bluedroid的代码,一般建议从一些特定的场景开始入手,这次我从BLE常见的扫描到连接这样一个使用场景先来看看bluedroid的代码结构。

BlueDroid 的一般调用流程

如上面所讲的,我们现在从BLE常见的扫描与连接开始这一流程,强调下,我们在这里只关注与bluedroid层面,不关心Android Application 与Android Framework的实现,因为这样的介绍已经有很多了。CSDN上不少博客都有介绍,就不在这里梳理了。

BLE 设备扫描流程

Android Application在上层调用 startLeScan()来启动扫描流程,我们关注下BlueDroid里如何来响应这样一个扫描流程。

BlueDroid里提供给上层的接口:

static const btgatt_interface_t btgattInterface = {sizeof(btgattInterface),btif_gatt_init,btif_gatt_cleanup,&btgattClientInterface,&btgattServerInterface,
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这个btgattInterface的接口就是提供给Android framework使用的,两个接口函数,一个初始化函数,一个清理函数。另外就是两个接口指针,一个给GattClient调用,一个给GattServer调用。 先只关注GattClient的接口吧。

const btgatt_client_interface_t btgattClientInterface = {btif_gattc_register_app,btif_gattc_unregister_app,btif_gattc_scan,btif_gattc_open,btif_gattc_close,。。。。。。。。。。。。。。。。。。}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这个接口里定义函数很多,先只摘录一小部分。btif_gattc_scan 会最终响应上层的startLeScan函数,为什么呢?自己起找对应关系吧,Android里framework分析的基本功哈。
接下来流程会是这样的:

BTIF                                  btif_gattc_scanBTIF_GATTC_SCAN_STARTBTA                                   BTA_DmBleObservebta_dm_ble_observeBTM                                   BTM_BleObservebtm_ble_start_scanHCI                                 btsnd_hcic_ble_set_scan_enable
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

上面左边代表bluedroid里的逻辑分层,右边代表是在每个逻辑层具体走过的函数。等下我们过下具体的函数逻辑。从左边来看逻辑上bluedroid上可以分成BTIF,BTA,BTM,HCI四个层次,但是其实应该还可以加上BTU等层,从字面上看BTIF是接口层,具体应该就是与Android之间的接口,BTA指应用层,BTM指Bluedroid中的管理层,HCI是指HOST Control Interface,即主机与BT控制器之间的接口。

我们来一个个过下这上面提到的函数的一些重要逻辑:
前面的btif_gattc_scan与BTA_DmBleObserve都没啥好说的。都是简单的把事件包装往下发送。
bta_dm_ble_observe:

void bta_dm_ble_observe (tBTA_DM_MSG *p_data)
{tBTM_STATUS status;if (p_data->ble_observe.start){/*Save the  callback to be called when a scan results are available */bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback;if ((status = BTM_BleObserve(TRUE, p_data->ble_observe.duration,bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb))!= BTM_CMD_STARTED){tBTA_DM_SEARCH  data;APPL_TRACE_WARNING(" %s BTM_BleObserve  failed. status %d",__FUNCTION__,status);data.inq_cmpl.num_resps = 0;if (bta_dm_search_cb.p_scan_cback){bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);}}}else{bta_dm_search_cb.p_scan_cback = NULL;BTM_BleObserve(FALSE, 0, NULL,NULL );}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

这里会设置一些callback回调供返回扫描结果。
首先是将从上层设置下来的callback函数指针保存到bta_dm_search_cb这么个全局变量中:

bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback;
  • 1

然后设置BTA的callback函数往下调用:

BTM_BleObserve(TRUE, p_data->ble_observe.duration,bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb)
  • 1
  • 2

bta_dm_observe_results_cb与bta_dm_observe_cmpl_cb这两个回调函数从函数命名上看也知道是一个返回实时扫描结果,一个返回扫描完成。两个回调分别使用BTA_DM_INQ_RES_EVT与BTA_DM_INQ_CMPL_EVT作为参数回调bta_dm_search_cb.p_scan_cback 。
需要注意下bta_dm_search_cb这个全局对象,其是一个名叫tBTA_DM_SEARCH_CB的结构体实例

/* DM search control block */
typedef struct
{tBTA_DM_SEARCH_CBACK * p_search_cback;tBTM_INQ_INFO        * p_btm_inq_info;tBTA_SERVICE_MASK      services;。。。。。。。。。。。。。。。tBTA_TRANSPORT         transport;
#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))tBTA_DM_SEARCH_CBACK * p_scan_cback;
#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))tBTA_GATTC_IF          client_if;UINT8                  num_uuid;tBT_UUID               *p_srvc_uuid;UINT8                  uuid_to_search;。。。。。。。。。TIMER_LIST_ENT         gatt_close_timer; /* GATT channel close delay timer */BD_ADDR                pending_close_bda; /* pending GATT channel remote device address */
#endif
#endif
} tBTA_DM_SEARCH_CB;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

暂时还没用到太多的成员,只有tBTA_DM_SEARCH_CBACK * p_scan_cback;

BTM_BleObserve实现也比较简单:
将上层传递过来的回调函数设置到一个新的结构体实例btm_cb当中。这个结构体非常重要哈,在bluedroid里应用得非常广泛。

   btm_cb.ble_ctr_cb.p_obs_results_cb = p_results_cb;btm_cb.ble_ctr_cb.p_obs_cmpl_cb = p_cmpl_cb;
  • 1
  • 2

配置扫描参数,我自己的nexus 5手机显示不支持extended_scan_support:

            if (cmn_ble_vsc_cb.extended_scan_support == 0){btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval,(UINT16)scan_window,btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,BTM_BLE_DEFAULT_SFP);}else{btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,BTM_BLE_DEFAULT_SFP);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

继续往下走:

status = btm_ble_start_scan();
  • 1

发送HCI命令

    /* start scan, disable duplicate filtering */if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)){status = BTM_NO_RESOURCES;}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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

好了,扫描命令有发送出去了。等着HCI告诉你结果吧。

扫描结果返回

既然我们的扫描命令是通过HCI送进bt 控制器的,那么理所当然扫描的结果也应该是HCI返回回来的。

BTU                           btu_hcif_process_event/HCI_BLE_ADV_PKT_RPT_EVTbtu_ble_process_adv_pktBTM                           btm_ble_process_adv_pktbtm_ble_process_adv_pkt_contBTA                           bta_scan_results_cbBTIF                          BTIF_GATT_OBSERVE_EVT
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

从上面看起来,事件是通过HCI–>BTU—>BTM—->BTA—->BTIF一层层往上抛的,刚好与发送扫描命令相反。

重点看下btm_ble_process_adv_pkt_cont函数:

static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
{tINQ_DB_ENT          *p_i;tBTM_INQUIRY_VAR_ST  *p_inq = &btm_cb.btm_inq_vars;tBTM_INQ_RESULTS_CB  *p_inq_results_cb = p_inq->p_inq_results_cb;tBTM_INQ_RESULTS_CB  *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;tBTM_BLE_INQ_CB      *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;p_i = btm_inq_db_find (bda);/* Check if this address has already been processed for this inquiry */if (btm_inq_find_bdaddr(bda))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

btm_inq_db_find 送数据库里寻找是否已经存在有同样地址的设备。所谓的数据开也就是:btm_cb.btm_inq_vars,前面说过btm_cb基本无处不在哈。

tBTM_INQ_RESULTS_CB  *p_inq_results_cb = p_inq->p_inq_results_cb;tBTM_INQ_RESULTS_CB  *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
  • 1
  • 2

这里拿到的回调就是我们之前看到的呀。

这个函数的最主要逻辑就是将新扫描到的设备放进扫描数据库里,也就是btm_cb.btm_inq_vars中。然后回调通知上层扫描结果。

static void bta_scan_results_cb (tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
{btif_gattc_cb_t btif_cb;uint8_t len;switch (event){case BTA_DM_INQ_RES_EVT:{bdcpy(btif_cb.bd_addr.address, p_data->inq_res.bd_addr);btif_cb.device_type = p_data->inq_res.device_type;btif_cb.rssi = p_data->inq_res.rssi;btif_cb.addr_type = p_data->inq_res.ble_addr_type;btif_cb.flag = p_data->inq_res.flag;if (p_data->inq_res.p_eir){memcpy(btif_cb.value, p_data->inq_res.p_eir, 62);if (BTM_CheckEirData(p_data->inq_res.p_eir, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE,&len)){p_data->inq_res.remt_name_not_required  = TRUE;}}}break;case BTA_DM_INQ_CMPL_EVT:{BTIF_TRACE_DEBUG("%s  BLE observe complete. Num Resp %d",__FUNCTION__,p_data->inq_cmpl.num_resps);return;}default:BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __FUNCTION__, event);return;}btif_transfer_context(btif_gattc_upstreams_evt, BTIF_GATT_OBSERVE_EVT,(char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

这个函数也没干太多事,把结果往BTIF里送:

        case BTIF_GATT_OBSERVE_EVT:{btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*) p_param;uint8_t remote_name_len;uint8_t *p_eir_remote_name=NULL;bt_device_type_t dev_type;bt_property_t properties;p_eir_remote_name = BTM_CheckEirData(p_btif_cb->value,BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);if (p_eir_remote_name == NULL){p_eir_remote_name = BTM_CheckEirData(p_btif_cb->value,BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);}if ((p_btif_cb->addr_type != BLE_ADDR_RANDOM) || (p_eir_remote_name)){if (!btif_gattc_find_bdaddr(p_btif_cb->bd_addr.address)){btif_gattc_add_remote_bdaddr(p_btif_cb->bd_addr.address, p_btif_cb->addr_type);btif_gattc_update_properties(p_btif_cb);}}dev_type =  p_btif_cb->device_type;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);btif_storage_set_remote_addr_type( &p_btif_cb->bd_addr, p_btif_cb->addr_type);HAL_CBACK(bt_gatt_callbacks, client->scan_result_cb,&p_btif_cb->bd_addr, p_btif_cb->rssi, p_btif_cb->value);break;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

BTIF里也没干啥事,就存起来,再通知上层应用。至此一个简单的扫描返回结果的流程就算结束了。

BlueDroid 的一些重要数据结构

在这里,我们就碰到两个结构比较重要:
tBTA_DM_SEARCH_CB 与tBTM_CB btm_cb;一个在BTA层,一个在BTM层,这里虽然带后缀是cb,但应该是control block的意思,不是call back的意思哈。尤其是tBTM_CB btm_cb;后续打交道的日子还多着呢。

一些简单总结

BTIF —> BTA —-> BTM —–> BTU —–> HCI
bluedroid的代码层级基本是这么定义,后续可能再从其他角度来看下这个层级结构。

Android BlueDroid 分析之扫描相关推荐

  1. Android Bluedroid source code analysis

    Android Bluedroid source code analysis 图1:应用层到协议层 Android的bt整体结构如图1所示: 应用层:使用蓝牙协议的各种应用,例如:蓝牙电话.音乐等. ...

  2. (五十四)Android O WiFi 获取扫描结果流程梳理

    前言:之前在(五十) Android O WiFi的扫描流程梳理 已经梳理过扫描流程了,那扫描完的结果会呈现在设置的WiFi界面,那扫描结果是如何获取的呢? 1. wifi扫描结果简介 WiFi的扫描 ...

  3. Android二维码扫描开发(一):实现思路与原理

    2019独角兽企业重金招聘Python工程师标准>>> Android二维码扫描开发(一):实现思路与原理 Android二维码扫描开发(二):YUV图像格式详解 Android二维 ...

  4. Android 如何连续的扫描蓝牙的RSSI来测距离,实现三点定位

    Android 如何连续的扫描蓝牙的RSSI来测距离,实现三点定位 背景: 接到一个小伙伴求助,要实现用蓝牙来测算距离,并用三点计算出蓝牙设备方位,通过以往的经验最终帮这位小伙伴实现了他的需求,下面总 ...

  5. android 蓝牙分析(一)

    android 蓝牙分析(一) 最近公司想要使蓝牙a2dp source和a2dp sink动态切换. 于是决定进行相应的源码调整.现在将一些分析结果整理一下 因为从来没有android 蓝牙的工作经 ...

  6. android逆向分析概述_Android存储概述

    android逆向分析概述 Storage is this thing we are all aware of, but always take for granted. Not long ago, ...

  7. Android JNI入门第五篇——Android.mk分析

    转载请标明出处: http://blog.csdn.net/michael1112/article/details/56671708 江东橘子的博客 Android.mk文件是在使用NDK编译C代码时 ...

  8. Android多线程分析之二:Thread的实现

    Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多线程分析之一:使 ...

  9. Android内存分析和调优(上)

    Android内存分析和调优(上) Android内存分析和调优(上) Android内存分析工具(四):adb命令 posted on 2017-09-25 19:29 时空观察者9号 阅读(... ...

最新文章

  1. There's no Qt version assigned to this project for platform Win32/Win64
  2. 如何将Swift数组转换为字符串?
  3. 特斯拉“自动召唤”有软肋!正面识别很厉害,侧面物体看不见,实测差点碾过行人脚面...
  4. python教程书籍推荐-买Python入门书籍,我推荐这一本
  5. svpwm矢量控制电机相电压波形_如何深入理解SVPWM?
  6. how to improve efficiency of graphic neural network?
  7. java可视化界面视频_java中的可视化界面
  8. Java线程状态分析
  9. 【零基础学Java】—数组(五)
  10. MMO移动游戏性能分析报告:渲染、UI、逻辑代码和内存
  11. 互联网大厂最常见的面试算法题大集合
  12. 素数环java_素数环(java实现)
  13. php 数字转换为货币,php中数字转换成货币格式实现代码
  14. 基于Python的信用评分卡模型建立和分析,万字阐述,收藏
  15. 民谣吉他之新手调音,弦音不对的问题
  16. 计算一个字符串里面特定字符的个数
  17. 浮点数和整数的区别python_浮的部首|浮的拼音|浮的组词|浮的意思 - 查字典
  18. win11登不上微软账号
  19. ASP.Net免费发送短信
  20. 【Graph Neural Network 图神经网络】3.Spatial-based Graph Convolutional Networks 基于空间的图卷积网络

热门文章

  1. docker selenium: Message: unknown error: unable to discover open pages
  2. word文件上传(前后端分离)
  3. 简析广升网配资炒股技巧?
  4. ICN6202 4lane MIPI 转LVDS
  5. 青烟鸿影一盏茶,孤灯小楼听夜雨
  6. glade 使用指南(1)
  7. 杨婷:腾讯云在线教育解决方案分享
  8. 树莓派4B 连接及配置
  9. kali利用MSF对永恒之蓝漏洞入侵windows7
  10. Android中富文本用法包括点击事件处理