- 可这么认为,bt协议栈、HDIL-bt都和硬件无关。HDIL-vendor,以及它要打开的linux驱动,和硬件相关。
- Android设备怎么确定蓝牙地址?——为让同一个android镜像能生成不同蓝牙地址,烧写镜像后,是没有确定地址。android第一次启动,执行hci_initialize(),它会执行到BluetoothAddress::get_local_address(local_bda)。第一次get_local_address时,prop变量persist.service.bdroid.bdaddr值是空,于是会生成一个随机地址,然后存入prop变量persist.service.bdroid.bdaddr。这样下次启动时,prop变量persist.service.bdroid.bdaddr不再是空,就取它值为地址,这android设备就一直是这地址了。

一、“DISCOVERY && SRVC_ALL”时发送req、接收resp
这里以“连接进入发现阶段(bta_gattc_start_discover),目的是获取该peripherl有哪些service”为例,看center如何向peripheral发送请求,以及接收应答。
1.1 发送请求
以gatt_act_discovery为分析的起始函数,看它是如何构造请求,并通过之前调用L2CA_ConnectFixedChnl()分配的L2CAP通道,发送请求。
- [stack/gatt/att_protocol.c]attp_send_cl_msg(op_code:GATT_REQ_READ_BY_GRP_TYPE)。调用attp_build_browse_cmd()构造“通用”格式的请求。BT_HDR.offset: 13,BT_HDR.len: 7。
- [stack/gatt/att_protocol.c]attp_cl_send_cmd()。
- [stack/gatt/att_protocol.c]attp_send_msg_to_l2cap()。此时p_tcb->att_lcid == L2CAP_ATT_CID(4)。
- [stack/l2cap/l2c_api.c]L2CA_SendFixedChnlData(L2CAP_ATT_CID, ...)。调用l2c_enqueue_peer_data让数据进入到当前ccb的xmit_hold_q队列中,暂存此数据包。经过l2c_enqueue_peer_data后,BT_HDR.offset: 9,BT_HDR.len: 11。l2c_enqueue_peer_data较为复杂,参考“L2CAP数据发送和接收”。进入到当前ccb的xmit_hold_q队列时调用“fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf)”,但对xmit_hold_q没使用fixed_queue_enqueus机制,下一步就会用fixed_queue_try_dequeue(p_ccb->xmit_hold_q)获取这个新进入的p_buf。
- [stack/l2cap/l2c_link.c]l2c_link_check_send_pkts(tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)。输入参数p_buf是nullptr!内中要调用l2cu_get_next_buffer_to_send(peer_cfg.fcr.mode: L2CAP_FCR_BASIC_MODE,L2CAP_NUM_FIXED_CHNLS: 32),后者通过fixed_queue_try_dequeue(p_ccb->xmit_hold_q),从xmit_hold_q取出BT_HDR赋值给p_buf,紧接调用l2cu_set_acl_hci_header,第三次调整BT_HDR,从BT_HDR.offset: 9,BT_HDR.len: 11改到BT_HDR.offset: 5, BT_HDR.len: 15。
- [stack/l2cap/l2c_link.c]l2c_link_send_to_lower()。
- [main/bte_main.c]bte_main_hci_send()。
- [hci/src/hci_layer.c]transmit_downward()。以BT_HDR结构的请求作为data,把它放入packet_queue队列。
因为packet_queue有新对象进入,触发该队列关联的event_packet_ready。(较老bt协议栈,hci部分有问题。新的参考图1)
- [hci/src/hci_layer.c]event_packet_ready()。
- [hci/src/packet_fragmenter.c]fragment_and_dispatch()。此时BT_HDR.event: 0x2100,BT_HDR.offset: 5, BT_HDR.len: 15。
- [hci/src/hci_hal_h4.c]transmit_fragment()。BT_HDR.event值0x2100(MSG_STACK_TO_HC_HCI_ACL),经过event_to_data_type后,得到type值2(DATA_TYPE_ACL)。send_transmit_finished: true。
- [hci/src/hci_hal_h4.c]transmit_data()。调用write(uart_fd, ...),把15字节的数据写入串口,即发向了蓝牙硬件模块。
1.2 接收应答
hci_thread线程一直poll设备节点,有数据就会调用event_uart_has_bytes来处理。(较老bt协议栈,hci部分有问题。新的参考图1)
- [hci/src/hci_hal_h4.c]event_uart_has_bytes()。从串口read数据。
- [hci/src/hci_layer.c]hal_says_data_ready(serial_data_type_t type:DATA_TYPE_ACL(2))。type值有1、2、3、4,针对每种type,hci_layer.c各开辟一个接收缓冲区incoming_packets[idx]。但由于不会收到DATA_TYPE_COMMAND(1),这个incoming_packets长度(INBOUND_PACKET_TYPE_COUNT)是3,“type - 2”可算出该type在incoming_packets内索引。由于输入参数type值是DATA_TYPE_ACL,回调的是“packet_fragmenter->reassemble_and_dispatch(incoming->buffer)”。
- [hci/src/packet_fragmenter.c]reassemble_and_dispatch()。
- [hci/src/hci_layer.c]dispatch_reassembled()。成员upwards_data_queue指向btu_hci_msg_queue,收到的BT_HDR格式packet放到btu_hci_msg_queue,BT_HDR.event: 0x1100。
因为btu_hci_msg_queue有新对象进入,触发该队列关联的btu_hci_msg_ready。
- [stack/btu/btu_task.c]btu_hci_msg_ready()。
- [stack/btu/btu_task.c]btu_hci_msg_process()。BT_HDR.event值是0x1100(BT_EVT_TO_BTU_HCI_ACL),调用l2c_rcv_acl_data。
- [stack/l2cap/l2c_main.c]l2c_rcv_acl_data()。调用pL2CA_FixedData_Cb,这一个函数指针,指向gatt_le_data_ind。
- [stack/gatt/gatt_main.c]gatt_le_data_ind()。
- [stack/gatt/gatt_main.c]gatt_data_process()。
- [stack/gatt/gatt_cl.c]gatt_client_handle_server_rsp()。op_code值0x11(GATT_RSP_READ_BY_GRP_TYPE),调用gatt_process_read_by_type_rsp。
- [stack/gatt/gatt_cl.c]gatt_process_read_by_type_rsp()。p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_SRVC_ALL && op_code == GATT_RSP_READ_BY_GRP_TYPE。
二、VendorInterface::Open
<aosp>/hardware/interfaces/bluetooth/1.0/default/vendor_interface.cc --- bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb, PacketReadCallback sco_cb, PacketReadCallback iso_cb) { initialize_complete_cb_ = initialize_complete_cb; char vendor_lib_name[32]; // Initialize vendor interface if (wifi_type[0] == 0) check_wifi_chip_type_string(wifi_type); if ((0 == strncmp(wifi_type, "RTL", 3)) || (0 == strncmp(wifi_type, "SSV", 3))) { // for ssv6051 wifi + rtl8761 bt strcpy(vendor_lib_name, VENDOR_REALTEK_LIBRARY_NAME); } else { strcpy(vendor_lib_name, VENDOR_LIBRARY_NAME); } ALOGD("%s: %s", __func__, vendor_lib_name); lib_handle_ = dlopen(vendor_lib_name, RTLD_NOW);
wifi_type: RTL8822CE。vendor_lib_name:libbt-vendor-realtek.so。
调用dlopen加载libbt-vendor-realtek.so
if (!lib_handle_) { ALOGE("%s unable to open %s (%s)", __func__, vendor_lib_name, dlerror()); return false; } lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>( dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME)); if (!lib_interface_) { ALOGE("%s unable to find symbol %s in %s (%s)", __func__, VENDOR_LIBRARY_SYMBOL_NAME, vendor_lib_name, dlerror()); return false; }
VENDOR_LIBRARY_SYMBOL_NAME变量值是“BLUETOOTH_VENDOR_LIB_INTERFACE”。厂商库需定义一个名叫“BLUETOOTH_VENDOR_LIB_INTERFACE”的变量,而且类型需是bt_vendor_interface_t。对rtkbt,这BLUETOOTH_VENDOR_LIB_INTERFACE变量见图1左下角。
// Get the local BD address uint8_t local_bda[BluetoothAddress::kBytes]; if (!BluetoothAddress::get_local_address(local_bda)) { LOG_ALWAYS_FATAL("%s: No Bluetooth Address!", __func__); }
BluetoothAddress::get_local_address用于得到蓝牙地址,输出参数local_bda存储着结果。它是怎么得到地址的?——为让同一个android镜像能生成不同蓝牙地址,烧写镜像后,是没有确定地址。android第一次启动,第一次get_local_address时,prop变量persist.service.bdroid.bdaddr值是空,于是会生成一个随机地址,然后存入prop变量persist.service.bdroid.bdaddr。这样下次启动时,prop变量persist.service.bdroid.bdaddr不再是空,就取它值为地址,这android设备就一直是这地址了。
int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
调用{<aosp>/hardware/realtek/rtkbt/code/libbt-vendor/src/bt_vendor_rtk.c}init()。
if (status) { ALOGE("%s unable to initialize vendor library: %d", __func__, status); return false; } ALOGD("%s vendor library loaded", __func__); // Power on the controller int power_state = BT_VND_PWR_ON; lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
调用{<aosp>/hardware/realtek/rtkbt/code/libbt-vendor/src/bt_vendor_rtk.c}op(),操作id:BT_VND_OP_POWER_CTRL。
// Get the UART socket(s) int fd_list[CH_MAX] = {0}; int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
CH_MAX值是4,表示蓝牙有4类通道,下文引的bt_vendor_hci_channels_t可查看是哪4类通道。操作id:BT_VND_OP_USERIAL_OPEN。让打开4条通道。那这里是不是必须返回4个fd呢?——芯片往往只用一个fd设备,它是怎么做的:fd_list的4个单元都填是fd,返回值fd_count是1。针对minipci插槽的RTL8822ce,深入op(BT_VND_OP_USERIAL_OPEN, ...)。此时rtkbt_transtype:0x22。没有RTKBT_TRANS_UART标记。它依次做两件事。
- userial_vendor_usb_open()。打开一个设备:/dev/rtkbt_dev。变量vnd_userial.port_name存储着这文件名。
- fd = userial_socket_open()。使用socketpair进程间通信机制,两个套接字存储在数组vnd_userial.uart_fd[2],其中uart_fd[0]会做为返回值。
if (fd_count < 1 || fd_count > CH_MAX - 1) { ALOGE("%s: fd_count %d is invalid!", __func__, fd_count); return false; } for (int i = 0; i < fd_count; i++) { if (fd_list[i] == INVALID_FD) { ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]); return false; } } event_cb_ = event_cb; PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) { HandleIncomingEvent(event); }; if (fd_count == 1) { hci::H4Protocol* h4_hci = new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb); fd_watcher_.WatchFdForNonBlockingReads( fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); }); hci_ = h4_hci;
对roc-rk3588s-pc/lubancat4,是进这个入口。依次执行了两个任务,一是创建H4Protocal对象。二是调用WatchFdForNonBlockingReads,它会创建一个线程,该线程的线程函数就是不断调用“h4_hci->OnDataReady(fd)”,后者作用就是从fd读数据,从而实现不断地从蓝牙芯片读出数据,装配成包,向上传去bt协议栈,参考图1“操作:HCI_BLE_EVENT”中底下部分。“NonBlockingReads”指的会用select机制,只有select认为有数据可读了,才会调用read。
} else { hci::MctProtocol* mct_hci = new hci::MctProtocol(fd_list, intercept_events, acl_cb); fd_watcher_.WatchFdForNonBlockingReads( fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); }); fd_watcher_.WatchFdForNonBlockingReads( fd_list[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); }); hci_ = mct_hci; } // Initially, the power management is off. lpm_wake_deasserted = true; // Start configuring the firmware firmware_startup_timer_ = new FirmwareStartupTimer(); lib_interface_->op(BT_VND_OP_FW_CFG, nullptr); return true; }
realtek厂商库定义的名叫“BLUETOOTH_VENDOR_LIB_INTERFACE”的变量,按规则,类型须是bt_vendor_interface_t。
<aosp>/hardware/interfaces/bluetooth/1.0/default/bt_vendor_lib.h typedef enum { CH_CMD, // HCI Command channel CH_EVT, // HCI Event channel CH_ACL_OUT, // HCI ACL downstream channel CH_ACL_IN, // HCI ACL upstream channel CH_MAX // Total channels } bt_vendor_hci_channels_t;
CH_MAX指示蓝牙通道数。