赞
踩
参考:
https://evilpan.com/2021/07/11/android-bt/
https://source.android.com/docs/core/connect/bluetooth?hl=zh-cn
https://developer.android.com/guide/topics/connectivity/bluetooth?hl=zh-cn
https://developer.android.com/guide/components/intents-filters?hl=zh-cn
对于BlueDroid而言,协议栈是在用户层实现的,内核只暴露出HCI(USB/UART)的接口。因此,我们可以从HCI出发,自底向上进行分析,也可以参考上面的框架图,从用户应用程序开始,自顶向下进行分析
bool SetScanMode(int scan_mode) system/bt/service/adapter.cc
SetAdapterProperty
hal::BluetoothInterface::Get()->GetHALInterface()->set_adapter_property
set_adapter_property system/bt/btif/src/bluetooth.cc
do_in_main_thread
btif_set_adapter_property system/bt/btif/src/btif_core.cc
BTA_DmSetVisibility system/bt/bta/dm/bta_dm_act.cc
android12/system/bt/stack/btm/btm_inq.cc
这其中涉及了几个API:
btm_ble_set_discoverability
btsnd_hcic_write_cur_iac_lap
btsnd_hcic_write_inqscan_cfg
btsnd_hcic_write_scan_enable
第一个API是BLE相关,内部实际上最终也调用了btsnd_hcic_xxx
的类似接口。IAC
意为Inquiry Access Code,蓝牙baseband定义了几个固定IAC,分别是LIAC和GIAC(见baseband)。LAP是蓝牙地址的一部分,如下图所示:
// system/bt/stack/hcic/hcicmds.cc void btsnd_hcic_write_cur_iac_lap(uint8_t num_cur_iac, LAP* const iac_lap) { btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); } /UINTx_TO_STREAM(pp, n)的作用是将整数以小端的形式写入p->data中,最终调用btu_hcif_send_cmd函数发送数据 // system/btstack/btu/btu_hcif.cc void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_buf) { uint8_t* stream = p_buf->data + p_buf->offset; stream++; btu_hcif_log_command_metrics(opcode, stream, android::bluetooth::hci::STATUS_UNKNOWN, false); hci_layer_get_interface()->transmit_command( p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt, vsc_callback); } //可见p_buf->data中保存的就是HCI数据,前16位为opcode,其中高6字节为ogf,低10字节为ocf,也就是我们平时使用hcitool cmd时的前两个参数
继续跟踪transmit_command
,就来到了HCI子系统中
transmit_command system/bt/hci/src/hci_layer.cc
enqueue_command
process_command_credits
其调用链路为:
BluetoothHciCallbacks::hciEventReceived system/bt/hci/src/hci_layer_android.cc
hci_event_received system/bt/hci/src/hci_layer.cc
filter_incoming_event
process_command_credits
BluetoothHciCallbacks::hciEventReceived 这个函数回调是在HCI初始化的时候调用的
BluetoothHci::initialize
(system/bt/vendor_libs/linux/interface/bluetooth_hci.cc):
Return<void> BluetoothHci::initialize system/bt/vendor_libs/linux/interface/bluetooth_hci.cc
openBtHci
fd_watcher_
本质上是针对hci_fd
文件句柄的读端事件监控,后者由openBtHci
函数产生,该函数由厂商实现,接口文件是hardware/interfaces/bluetooth/1.0/IBluetoothHci.hal
。在Linux中的参考实现如下:
继续回头接着上节之前的内容讲,我们的任务队列是在process_command_credits
中被消费的,取出来之后需要进入到hci_thread
线程中执行。从接收数据一节中也能看出,hci接口本身使用的是串行总线,因此不能并发地发送数据,所有命令都是在之前的命令响应后再发送。
值得一提的是,enqueue_command实际上绑定的是函数event_command_ready
,以包含我们命令内容和对应回调的类型waiting_command_t
为参数:
static void enqueue_command(waiting_command_t* wait_entry) {
base::Closure callback = base::Bind(&event_command_ready, wait_entry);
//...
command_queue.push(std::move(callback));
}
因此,负责执行HCI发送命令的是event_command_ready函数:
static void event_command_ready(waiting_command_t* wait_entry) {
{
/// Move it to the list of commands awaiting response
std::lock_guard<std::recursive_timed_mutex> lock(
commands_pending_response_mutex);
wait_entry->timestamp = std::chrono::steady_clock::now();
list_append(commands_pending_response, wait_entry);
}
// Send it off
packet_fragmenter->fragment_and_dispatch(wait_entry->command);
update_command_response_timer();
}
首先将command放到一个等待响应的队列里,然后分片发送:
static void fragment_and_dispatch(BT_HDR* packet) {
CHECK(packet != NULL);
uint16_t event = packet->event & MSG_EVT_MASK;
uint8_t* stream = packet->data + packet->offset;
// We only fragment ACL packets
if (event != MSG_STACK_TO_HC_HCI_ACL) {
callbacks->fragmented(packet, true);
return;
}
// ACL/L2CAP fragment...
}
实现中只对ACL类型的HCI数据进行分片发送,不管是不是分片,都对最后一个packet调用callbacks->fragmented()
,callbacks的类型是packet_fragmenter_callbacks_t
,在packet_fragmenter_t->init
中初始化并设置。而packet_fragmenter的初始化发生在hci_module_start_up()
中,HCI层定义的回调如下:
static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = { transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished };
fragmented即对应transmit_fragment,对应定义如下:
// Callback for the fragmenter to send a fragment static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) { btsnoop->capture(packet, false); // HCI command packets are freed on a different thread when the matching // event is received. Check packet->event before sending to avoid a race. bool free_after_transmit = (packet->event & MSG_EVT_MASK) != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished; hci_transmit(packet); if (free_after_transmit) { buffer_allocator->free(packet); } }
hci_transmit
有不同平台的实现,分别在:
前者是通过write
直接向HCI socket的fd写入,后者是调用IBluetoothHci::sendHciCommand
去实现,接口定义同样是在hardware/interfaces/bluetooth/1.0/IBluetoothHci.hal
文件中。
因为不同手机厂商的SoC中集成蓝牙芯片的接口不同,有的是使用USB连接,有的是使用UART连接,因此需要给安卓提供一个统一的操作接口,这个接口就很适合由HAL(HIDL)来进行抽象。这部分实现通常是使用Linux中已有的UART/USB驱动进行操作,以提高代码的复用性。
在ITX-3588J 中,通过/dev/ttyS6与蓝牙芯片进行通信,通过rfkill控制蓝牙开关
蓝牙协议栈、HIDL interface、 libbt-vendor
Bluetooth Native Stack
HIDL Interfaces
Vendor Implementation
相关源码路径
system/bt
hardware/interfaces/bluetooth/1.0/default
hardware/broadcom/libbt/src
net/rfkill/rfkill-bt.c
drivers/tty
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。