在蓝牙enable的过程中会进行多个线程的创建以及将线程与队列进行绑定的工作。该篇文章主要分析一下处理hci数据这个 线程。

void BTU_StartUp(void)
{
...
btu_bta_msg_queue = fixed_queue_new(SIZE_MAX); btu_general_alarm_hash_map = hash_map_new(BTU_GENERAL_ALARM_HASH_MAP_SIZE,
hash_function_pointer, NULL, (data_free_fn)alarm_free, NULL); btu_general_alarm_queue = fixed_queue_new(SIZE_MAX);
btu_oneshot_alarm_hash_map = hash_map_new(BTU_ONESHOT_ALARM_HASH_MAP_SIZE,
hash_function_pointer, NULL, (data_free_fn)alarm_free, NULL); btu_oneshot_alarm_queue = fixed_queue_new(SIZE_MAX); btu_l2cap_alarm_hash_map = hash_map_new(BTU_L2CAP_ALARM_HASH_MAP_SIZE,
hash_function_pointer, NULL, (data_free_fn)alarm_free, NULL); btu_l2cap_alarm_queue = fixed_queue_new(SIZE_MAX); bt_workqueue_thread = thread_new(BT_WORKQUEUE_NAME);//该线程为处理各个task 的线程,之后会与多个队列绑定
// Continue startup on bt workqueue thread.
thread_post(bt_workqueue_thread, btu_task_start_up, NULL);//在bt_workqueue_thread中继续startup的工作
return; 
}

剩下的enable 的工作会在这个函数中btu_task_start_up继续做:

void btu_task_start_up(UNUSED_ATTR void *context) {
...
/* Initialize the mandatory core stack control blocks
(BTU, BTM, L2CAP, and SDP)
*/
btu_init_core();
/* Initialize any optional stack components */
BTE_InitStack();
bta_sys_init();
// Inform the bt jni thread initialization is ok.
btif_transfer_context(btif_init_ok, , NULL, , NULL); fixed_queue_register_dequeue(btu_bta_msg_queue,//绑定btu_bta_msg_queue
thread_get_reactor(bt_workqueue_thread),
btu_bta_msg_ready,
NULL); fixed_queue_register_dequeue(btu_hci_msg_queue,//绑定btu_hci_msg_queue
thread_get_reactor(bt_workqueue_thread),
btu_hci_msg_ready,
NULL); fixed_queue_register_dequeue(btu_general_alarm_queue,//绑定btu_general_alarm_queue
thread_get_reactor(bt_workqueue_thread),
btu_general_alarm_ready,
NULL); fixed_queue_register_dequeue(btu_oneshot_alarm_queue,//绑定btu_oneshot_alarm_queue
thread_get_reactor(bt_workqueue_thread),
btu_oneshot_alarm_ready,
NULL); fixed_queue_register_dequeue(btu_l2cap_alarm_queue,//绑定btu_l2cap_alarm_queue
thread_get_reactor(bt_workqueue_thread),
btu_l2cap_alarm_ready,
NULL);
}

这里绑定的含义就是当被绑定的队列里面有数据可以读写的时候,就会在该线程中处理,处理的函数就是fixed_queue_register_dequeue函数的第三个参数和第四个参数,分别对应于读和写的函数。

从上面的注册信息来看,都是当队列里面有数据的时候,调用函数来处理这些队列中的消息。

现在具体分析一下btu_hci_msg_queue 这个队列的处理流程。

稍微思考一下,可以想到从controller 传上来的消息都会塞到这个队列里面。现在具体的分析,controller传上来的数据 都是通过bt driver来上传的,上传上来的数据有event以及acl data,这两者应该都是放置到这个队列进行处理的。

在协议栈中,当底层有数据的时候,会调用该函数:

hci_layer.c中:

static void hal_says_data_ready(serial_data_type_t type) {
packet_receive_data_t *incoming = &incoming_packets[PACKET_TYPE_TO_INBOUND_INDEX(type)]; uint8_t byte;
while (hal->read_data(type, &byte, , false) != ) {
switch (incoming->state) {
case BRAND_NEW:
// Initialize and prepare to jump to the preamble reading state
incoming->bytes_remaining = preamble_sizes[PACKET_TYPE_TO_INDEX(type)];
memset(incoming->preamble, , PREAMBLE_BUFFER_SIZE);
incoming->index = ;
incoming->state = PREAMBLE;
// INTENTIONAL FALLTHROUGH
case PREAMBLE:
incoming->preamble[incoming->index] = byte;
incoming->index++;
incoming->bytes_remaining--; if (incoming->bytes_remaining == ) {
// For event and sco preambles, the last byte we read is the length
incoming->bytes_remaining = (type == DATA_TYPE_ACL) ? RETRIEVE_ACL_LENGTH(incoming->preamble) : byte; size_t buffer_size = BT_HDR_SIZE + incoming->index + incoming->bytes_remaining;
incoming->buffer = (BT_HDR *)buffer_allocator->alloc(buffer_size); if (!incoming->buffer) {
LOG_ERROR("%s error getting buffer for incoming packet of type %d and size %zd", __func__, type, buffer_size);
// Can't read any more of this current packet, so jump out
incoming->state = incoming->bytes_remaining == ? BRAND_NEW : IGNORE;
break;
} // Initialize the buffer
incoming->buffer->offset = ;
incoming->buffer->layer_specific = ;
incoming->buffer->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)];
memcpy(incoming->buffer->data, incoming->preamble, incoming->index); incoming->state = incoming->bytes_remaining > ? BODY : FINISHED;
} break;
case BODY:
incoming->buffer->data[incoming->index] = byte;
incoming->index++;
incoming->bytes_remaining--; size_t bytes_read = hal->read_data(type, (incoming->buffer->data + incoming->index), incoming->bytes_remaining, false);
incoming->index += bytes_read;
incoming->bytes_remaining -= bytes_read; incoming->state = incoming->bytes_remaining == ? FINISHED : incoming->state;
break;
case IGNORE:
incoming->bytes_remaining--;
if (incoming->bytes_remaining == ) {
incoming->state = BRAND_NEW;
// Don't forget to let the hal know we finished the packet we were ignoring.
// Otherwise we'll get out of sync with hals that embed extra information
// in the uart stream (like H4). #badnewsbears
hal->packet_finished(type);
return;
} break;
case FINISHED:
LOG_ERROR("%s the state machine should not have been left in the finished state.", __func__);
break;
} if (incoming->state == FINISHED) {
incoming->buffer->len = incoming->index;
btsnoop->capture(incoming->buffer, true);//capture btsnoop if (type != DATA_TYPE_EVENT) {
packet_fragmenter->reassemble_and_dispatch(incoming->buffer);//acl data的处理
} else if (!filter_incoming_event(incoming->buffer)) {//event 的处理
// Dispatch the event by event code
uint8_t *stream = incoming->buffer->data;
uint8_t event_code;
STREAM_TO_UINT8(event_code, stream); data_dispatcher_dispatch(
interface.event_dispatcher,
event_code,
incoming->buffer
);
} // We don't control the buffer anymore
incoming->buffer = NULL;
incoming->state = BRAND_NEW;
hal->packet_finished(type); // We return after a packet is finished for two reasons:
// 1. The type of the next packet could be different.
// 2. We don't want to hog cpu time.
return;
}
}
}

从上面的函数可以看出,如果封包接收没有结束会继续接收,直到incoming->state == FINISHED ,这个时候说明封包完整的接收到了。对于封包的处理,做了如下的事情:

  1. 录制btsnoop
  2. 根据不同数据类型分别路由到不同的处理函数,acl data 以及其他的封包由packet_fragmenter->reassemble_and_dispatch(incoming->buffer) 来处理。event事件由

    data_dispatcher_dispatch(interface.event_dispatcher,event_code,incoming->buffer)

这里分别看看两个函数的具体处理流程:

packet_fragmenter->reassemble_and_dispatch


先看看这个packet_fragmenter_t结构:

static const packet_fragmenter_t interface = {
init,
cleanup,
fragment_and_dispatch,
reassemble_and_dispatch
};

其中的具体实现,我这里

static void reassemble_and_dispatch(UNUSED_ATTR BT_HDR *packet) {
if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) {
...
STREAM_TO_UINT16(handle, stream);
STREAM_TO_UINT16(acl_length, stream);
STREAM_TO_UINT16(l2cap_length, stream); BT_HDR *partial_packet = (BT_HDR *)hash_map_get(partial_packets, (void *)(uintptr_t)handle);
memcpy(partial_packet->data, packet->data, packet->len);
...
packet->offset = HCI_ACL_PREAMBLE_SIZE;
...
memcpy(
partial_packet->data + partial_packet->offset,
packet->data + packet->offset,
packet->len - packet->offset
);
...
if (partial_packet->offset == partial_packet->len) {
hash_map_erase(partial_packets, (void *)(uintptr_t)handle);
partial_packet->offset = ;
callbacks->reassembled(partial_packet);//最终调用hci_hal_callbacks_t的
}
}
} else {
callbacks->reassembled(packet);
}
}

上面看到最终调用callbacks->reassembled(partial_packet);来处理,实现在hci_layer.c

static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
transmit_fragment,
dispatch_reassembled,//实际调用的是这个函数
fragmenter_transmit_finished,
filter_incoming_event
fragmenter_transmit_finished
#endif
};

看具体实现:

// Callback for the fragmenter to dispatch up a completely reassembled packet
static void dispatch_reassembled(BT_HDR *packet) {
// Events should already have been dispatched before this point
assert(upwards_data_queue != NULL); if (upwards_data_queue) {//放置都这个queue
fixed_queue_enqueue(upwards_data_queue, packet);
} else {
LOG_ERROR("%s had no queue to place upwards data packet in. Dropping it on the floor.", __func__);
buffer_allocator->free(packet);
}
}
static void set_data_queue(fixed_queue_t *queue) { //这个函数对该队列赋值
upwards_data_queue = queue;
}
static void init_layer_interface() {
if (!interface_created) {
interface.send_low_power_command = low_power_manager->post_command;
interface.do_postload = do_postload;
interface.event_dispatcher = data_dispatcher_new("hci_layer"); interface.set_data_queue = set_data_queue;//肯定是别的地方调用hci 的interface来设置这个队列的 interface.transmit_command = transmit_command;
interface.transmit_command_futured = transmit_command_futured;
interface.transmit_downward = transmit_downward;
interface_created = true;
}
}

这里其实是在蓝牙初始化的时候就已经做了,

void bte_main_boot_entry(void)
{
module_init(get_module(GKI_MODULE));
module_init(get_module(COUNTER_MODULE)); hci = hci_layer_get_interface();//获取hci的interface btu_hci_msg_queue = fixed_queue_new(SIZE_MAX);
if (btu_hci_msg_queue == NULL) {
LOG_ERROR("%s unable to allocate hci message queue.", __func__);
return;
}
data_dispatcher_register_default(hci->event_dispatcher, btu_hci_msg_queue);
hci->set_data_queue(btu_hci_msg_queue);//将btu_hci_msg_queue传入,也就是后来的upwards_data_queue
...
}

到这里,我们知道了,其实acl的数据都最终会放置到这个btu_hci_msg_queue 队列来处理。


现在我们看看

data_dispatcher_dispatch(interface.event_dispatcher,event_code,incoming->buffer) 的处理流程:

我们先看看data_dispatcher_dispatch的实现:

bool data_dispatcher_dispatch(data_dispatcher_t *dispatcher, data_dispatcher_type_t type, void *data) {
fixed_queue_t *queue = hash_map_get(dispatcher->dispatch_table, (void *)type);
if (!queue)
queue = dispatcher->default_queue;//如果没有获取到专用的队列,就用默认的队列 if (queue)
fixed_queue_enqueue(queue, data);//将数据加入到队列里面
return queue != NULL;
}

当前不清楚 dispatcher->dispatch_table 的队列的情况,在init_layer_interface中:

 interface.event_dispatcher = data_dispatcher_new("hci_layer");

这里没有设置专用的队列,那在哪里有设置呢?其实还是在上面的蓝牙init的时候:

void bte_main_boot_entry(void)
{
module_init(get_module(GKI_MODULE));
module_init(get_module(COUNTER_MODULE)); hci = hci_layer_get_interface();//获取hci的interface btu_hci_msg_queue = fixed_queue_new(SIZE_MAX);
if (btu_hci_msg_queue == NULL) {
LOG_ERROR("%s unable to allocate hci message queue.", __func__);
return;
}
data_dispatcher_register_default(hci->event_dispatcher, btu_hci_msg_queue);//将btu_hci_msg_queue 注册给hci的event_dispatcher,
hci->set_data_queue(btu_hci_msg_queue);//将btu_hci_msg_queue传入,也就是后来的upwards_data_queue
...
}
void data_dispatcher_register_default(data_dispatcher_t *dispatcher, fixed_queue_t *queue) {
assert(dispatcher != NULL);
dispatcher->default_queue = queue;
}

到这里,我们发现,的确是所有的controller上来的数据都是放置到btu_hci_msg_queue来等待处理,

后续的具体的处理流程很简单,根据不同的数据类型,发配给不同的函数来处理。

Bluedroid协议栈BTU线程处理HCI数据流程分析的更多相关文章

  1. android Camera 数据流程分析

    这篇文章主要针对其数据流程进行分析.Camera一般用于图像浏览.拍照和视频录制.这里先对图像浏览和拍照的数据流进行分析,后面再对视频电话部分进行分析. 1.针对HAL层对摄像头数据处理补充一下 Li ...

  2. Android多媒体框架总结(1) - 利用MediaMuxer合成音视频数据流程分析

    场景介绍: 设备端通过服务器传向客户端(Android手机)实时发送视频数据(H.264)和音频数据(g711a或g711u), 需要在客户端将音视频数据保存为MP4文件存放在本地,用户可以通过APP ...

  3. Java版 QQ空间自动登录无需拷贝cookie一天抓取30WQQ说说数据&流程分析

    QQ空间说说抓取难度比较大,花了一个星期才研究清楚! 代码请移步到GitHub GitHub地址:https://github.com/20100507/Qzone [没有加入多线程,希望你可以参与进 ...

  4. live555从RTSP服务器读取数据到使用接收到的数据流程分析

    本文在linux环境下编译live555工程,并用cgdb调试工具对live555工程中的testProgs目录下的openRTSP的执行过程进行了跟踪分析,直到将从socket端读取视频数据并保存为 ...

  5. (转)live555从RTSP服务器读取数据到使用接收到的数据流程分析

    本文在linux环境下编译live555工程,并用cgdb调试工具对live555工程中的testProgs目录下的openRTSP的执行过程进行了跟踪分析,直到将从socket端读取视频数据并保存为 ...

  6. [HDFS_add_2] SecondaryNameNode 滚动 NameNode 数据流程

    0. 说明 在 将 SecondaryNameNode 配置到 s105 节点上 的基础上进行 SecondaryNameNode 滚动 NameNode 数据流程 分析 1. SecondaryNa ...

  7. S3C6410 SPI全双工读写流程分析(原创)【转】

    转自:http://blog.csdn.net/hustyangju/article/details/21165721 原创博文,知识共享!转载请注明出处:http://blog.csdn.net/h ...

  8. Bluedroid协议栈HCI线程分析

    蓝牙进程中有多个线程,其中HCI 线程是负责处理蓝牙主机端和控制器的数据处理和收发的工作. 本篇文章就是分析一下该线程的数据处理流程. 1.跟HCI相关的接口 首先看看hci的相关的接口:在hci_l ...

  9. Java--Exchanger用于进行线程间的数据交换

    package com; import java.util.concurrent.Exchanger; /** * Created by yangyu on 16/11/28. */ /** * Ex ...

随机推荐

  1. 学习dbms_parallel_execute包

    一.简介 ORACLE11g R2版本的新特性之一就是引进了DBMS_PARALLEL_EXECUTE包,使用DBMS_PARALLEL_EXECUTE包批量并行递增式的更新表. 更多ORACLE11 ...

  2. 迁移MSSQL实例的所有login(包含密码)

    迁移数据库的时候肯定会涉及到login的迁移(包含数据库除外). 而一般我们迁移login的时候,可能会使用在某个login上右键生成脚本这样的做法.但是这样生成的脚本不能把密码也生成出来. 而且你只 ...

  3. 基于CNN网络的汉字图像字体识别及其原理

    现代办公要将纸质文档转换为电子文档的需求越来越多,目前针对这种应用场景的系统为OCR系统,也就是光学字符识别系统,例如对于古老出版物的数字化.但是目前OCR系统主要针对文字的识别上,对于出版物的版面以 ...

  4. Beta阶段第一次冲刺

    Beta阶段第一次冲刺 以后严格按照Git标准来,组员有上传Git的才有贡献分没有的为0 代码签入图 1.part1 -站立式会议照片 2.part2 -项目燃尽图 3.part3 -项目进展 1.正 ...

  5. AnyHashable类型擦除的原因:set和dictory需要指定一个确定的类型

    AnyHashable 属于无关联类型的擦除. 将具体类型的类型信息擦除掉了,只剩下协议类型的信息暴露出来. 类型擦除实践:将相同协议的不同实现屏蔽起来,暴露出类型的共同特征(协议接口). A typ ...

  6. AtCoder Regular Contest

    一句话题解 因为上篇AGC的写的有点长……估计这篇也短不了所以放个一句话题解方便查阅啥的吧QwQ 具体的题意代码题解还是往下翻…… ARC 058 D:简单容斥计数. E:用二进制表示放的数字,然后状 ...

  7. 洛谷 P1144 最短路计数

    传送门:https://www.luogu.org/problemnew/show/P1144 这虽然是一道普及+的题,然而我发现我现在还没做过,这也就直接导致我今天模拟T2只杠了个暴力分…… 那这道 ...

  8. FastJson遇见的问题或项目实战中优化的问题,看源码都可以解决

    1:感觉见鬼了一般存储JSONObject中的字段竟然不见了? JSONObject object=new JSONObject(); Map fields = new HashMap(); fiel ...

  9. Python高级知识点总结

    一.可迭代对象.迭代器对象和生成器 像list, tuple等这些序列是可以使用for...in ...语句来进行遍历输出的.这是为什么呢?这就需要知道可迭代对象(Iterable).迭代器对象(It ...

  10. VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误

    1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...