Bluedroid中的线程介绍

本文深入分析了Bluedroid在Android O中的线程使用,包括线程创建、线程详解、主要线程(jni_thread、bta_btu_thread、hci_thread)的功能和交互,以及如何在调试时跟踪协议栈代码流程。通过文章,读者能理解Bluedroid的线程结构和蓝牙协议栈架构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Bluedroid中的线程介绍 

版权所有,转载时请注明出处
luowh0822@outlook.com

本文基于android O的代码进行分析。通过本文档,能够了解bluedroid的线程结构和协议栈架构。

线程的基本用法

osi/src/thread.cc
对posix的线程函数进行了封装

thread_t* thread_new(const char* name);
bool thread_post(thread_t* thread, thread_fn func, void* context);

使用thread_new()创建一个线程,参数为线程名字的字符串。
使用thread_post()把子线程的处理函数传递给子线程。
Bluedroid封装的后的thread函数与POSIX的thread有点不同。
- thread_new不需要传入子线程的入口函数,内部会创建一个默认的入口函数,等待用户传入任务。
- thread_post传递用户真正需要的执行函数给子线程。

线程详解

struct thread_t {
  std::atomic_bool is_joined{
  false}; //是否joined
  pthread_t pthread; //pthread的handle
  pid_t tid; //线程id
  char name[THREAD_NAME_MAX + 1]; //线程名
  reactor_t* reactor; //很重要的一个参数,循环epoll所有注册的queue,当queue中有数据就会调用相应的函数处理
  fixed_queue_t* work_queue; //处理函数队列,用户调用thread_post()把处理函数及参数放到这个队列中,在reactor中处理。
}; 

thread_t* thread_new_sized(const char* name, size_t work_queue_capacity) {

  thread_t* ret = static_cast<thread_t*>(osi_calloc(sizeof(thread_t)));
  ret->reactor = reactor_new();
  ret->work_queue = fixed_queue_new(work_queue_capacity);

  // Start is on the stack, but we use a semaphore, so it's safe
  struct start_arg start;
  start.start_sem = semaphore_new(0);

  strncpy(ret->name, name, THREAD_NAME_MAX);
  start.thread = ret;
  start.error = 0;
  pthread_create(&ret->pthread, NULL, run_thread, &start);
  semaphore_wait(start.start_sem);
  semaphore_free(start.start_sem);
}

static void* run_thread(void* start_arg) {
  struct start_arg* start = static_cast<struct start_arg*>(start_arg);
  thread_t* thread = start->thread;

  thread->tid = gettid();

  semaphore_post(start->start_sem);

  int fd = fixed_queue_get_dequeue_fd(thread->work_queue);
  void* context = thread->work_queue;

  reactor_object_t* work_queue_object =
    reactor_register(thread->reactor, fd, context, work_queue_read_cb, NULL);
  reactor_start(thread->reactor);
  ...
}
  1. 当用户调用thread_new后,内部首先创建线程的reactor和work_queue,semaphore用来创建线程时跟父线程同步用的。
  2. 然后调用pthread_create(&ret->pthread, NULL, run_thread, &start)函数,创建并执行run_thread()接口函数。
  3. 在run_thread()函数里,调用reactor_register(),把work_queue加入到epoll的集合里。具体细节是work_queue有semaphore,而semaphore是使用eventfd实现的,eventfd可以使用epoll来监听。当有数据放到queue里面,semaphore就会改变,epoll就可以被唤醒。
  4. reactor_start(thread->reactor),函数里面有死循环,通过epoll,监听所有)通过reactor_register()传入的queue。当queue有数据传入,执行fixed_queue_register_dequeue()传入的对应处理函数。

创建线程后,线程会把自己内部的work_queue注册到reactor,当用户调用thread_post,传入函数指针和参数后,子线程就会处理。当创建线程后,至少会调用一次thread_post。我们可以看到btif_a2dp_sink.cc和btif_a2dp_source.cc中多次调用thread_post()的情况。以btif_a2dp_source.cc为例,当创建线程时,会把cmd_msg_queue注册到reactor中,用来接收a2dp的控制命令,另外当a2dp工作时,会设置一个周期的定时器,当超时,会调用thread_post,做音频数据编码再发送的工作,另外a2dp停止时,也会调用thread_post去停止。
thread还有另一种工作方式。用户调用fixed_queue_register_dequeue(),把外部的queue传给thread。这时候,向queue里添加元素(Event),就可以处理。后面bta_btu_thread会有详解的讲解。

bluedroid中的线程列表

在/system/bt/目录下”grep -rns thread_new *”就可以列出所有的thread。
下面列出的的是去掉测试代码中的线程后的线程列表:

thread description
thread_new(“module_wrapper”) module manager
thread_new(“stack_manager”) stack manager, enable other thread
thread_new(“btif_sock”) btif socket
thread_new(“btif_a2dp_sink_worker_thread”) a2dp sink
thread_new_sized(“media_worker”, MAX_MEDIA_WORKQUEUE_SEM_COUNT) a2dp source
thread_new(BT_JNI_WORKQUEUE_NAME) jni thread
thread_new(“hci_thread”) hci thread
thread_new(“hci_inject”) send hci raw data
thread_new_sized(“alarm_default_callbacks”, SIZE_MAX) alarm callback execution
thread_new(“alarm_dispatcher”) alarm management
thread_new(BT_WORKQUEUE_NAME) bta_btu thread, core stack thread.

另外,Android N及之前的版本有bt transport layer的线程,用来读uart的数据。在Android O的时候,这部分的工作在hidl里完成了。

主要线程分析

接下来分析bluedroid流程分析时最重要的三个线程,从下往上分别是:hci_thread, bta_btu_thread, jni_thread。
hci_thread:靠近底层传输层,完成HCI的拆包和组包工作,处理HCI命令,事件及数据包。
bta_btu_thread:实现协议栈的核心功能
jni_thread:衔接协议栈及上层JNI

jni_thread

  • 上层的java service调用bluredroid接口时,切换到这个线程执行调用程序,并跟下层(协议栈核心模块,bta_btu_thread)交互
  • bta_btu_thread向上发送的event,切换到这个线程处理event。
btif_core.cc
bt_status_t btif_init_bluetooth() {
    bt_jni_workqueue_thread = thread_new(BT_JNI_WORKQUEUE_NAME);
    thread_post(bt_jni_workqueue_thread, run_message_loop, nullptr);
}

bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event, ...)

创建线程后,会执行run_messag

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值