Bluedroid协议栈BTU线程处理HCI数据流程分析

在蓝牙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, 0, NULL, 0, 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, 1, false) != 0) {
    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, 0, PREAMBLE_BUFFER_SIZE);
        incoming->index = 0;
        incoming->state = PREAMBLE;
        // INTENTIONAL FALLTHROUGH
      case PREAMBLE:
        incoming->preamble[incoming->index] = byte;
        incoming->index++;
        incoming->bytes_remaining--;

        if (incoming->bytes_remaining == 0) {
          // 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 == 0 ? BRAND_NEW : IGNORE;
            break;
          }

          // Initialize the buffer
          incoming->buffer->offset = 0;
          incoming->buffer->layer_specific = 0;
          incoming->buffer->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)];
          memcpy(incoming->buffer->data, incoming->preamble, incoming->index);

          incoming->state = incoming->bytes_remaining > 0 ? 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 == 0 ? FINISHED : incoming->state;
        break;
      case IGNORE:
        incoming->bytes_remaining--;
        if (incoming->bytes_remaining == 0) {
          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 = 0;
        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来等待处理,

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

 

posted @ 2018-06-21 22:42  雪山飞燕  阅读(1218)  评论(0编辑  收藏  举报