AOSP开发C/C++应用向CSR8510蓝牙芯片发送自定义命令的问题
我之前在AOSP环境下折腾过类似的蓝牙底层命令发送需求,给你梳理几个关键步骤和踩过的坑,应该能帮你顺利推进:
1. 先确认目标函数的符号可见性
首先得确保btu_hcif_send_cmd和osi_malloc是bluetooth.default.so对外导出的符号——毕竟如果符号没导出,就算链接了库也调用不了。你可以用nm命令在AOSP编译产物里检查:
nm -D out/target/product/[你的开发板型号]/system/lib64/bluetooth.default.so | grep -E "btu_hcif_send_cmd|osi_malloc"
如果输出里的符号前是T(全局导出)或者t(局部导出),说明没问题;如果是U,那意味着这个符号没被导出,你需要修改bluedroid的源码:
- 在对应的头文件(比如
btu_hcif.h)里给函数声明加上__attribute__((visibility("default"))),比如:__attribute__((visibility("default"))) int btu_hcif_send_cmd(uint16_t opcode, uint8_t param_len, uint8_t *param); - 或者在bluedroid模块的编译配置(比如
Android.mk或Android.bp)里添加-fvisibility=default编译参数,强制导出符号。
2. 配置应用的编译脚本(Android.mk/Android.bp)
不管你用哪种编译方式,都要正确链接bluetooth.default.so并引入bluedroid的头文件路径,不然编译会报错找不到函数声明。
用Android.mk的例子:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # 你的应用名称 LOCAL_MODULE := custom_bt_cmd_app # 你的源文件 LOCAL_SRC_FILES := main.c # 依赖的共享库,必须包含bluetooth.default LOCAL_SHARED_LIBRARIES := bluetooth.default libcutils liblog # 引入bluedroid的头文件路径,确保能找到btu_hcif.h和osi/memory.h LOCAL_C_INCLUDES := \ $(TOP)/system/bt/include \ $(TOP)/system/bt/osi/include \ $(TOP)/system/bt/hci/include # 编译成可执行程序 include $(BUILD_EXECUTABLE)
用Android.bp的例子:
cc_binary { name: "custom_bt_cmd_app", srcs: ["main.c"], shared_libs: [ "bluetooth.default", "libcutils", "liblog", ], includes: [ "system/bt/include", "system/bt/osi/include", "system/bt/hci/include", ], }
3. 函数调用的关键注意事项
- 内存管理要统一:
osi_malloc是bluedroid自己的内存分配函数,对应的释放必须用osi_free,绝对不能混用标准库的free,否则会触发内存崩溃。 - 命令参数要合规:
btu_hcif_send_cmd的三个参数分别是HCI命令的opcode、参数长度、参数缓冲区,必须严格符合HCI命令规范。给你一个简单的调用示例:#include <stdio.h> #include "btu_hcif.h" #include "osi/memory.h" int main() { // 示例:发送HCI_Read_Local_Version_Information命令,opcode为0x0401,无参数 uint16_t opcode = 0x0401; uint8_t param_len = 0; uint8_t* params = osi_malloc(param_len); int ret = btu_hcif_send_cmd(opcode, param_len, params); if (ret == 0) { printf("自定义蓝牙命令发送成功\n"); } else { printf("命令发送失败,返回值:%d\n", ret); } osi_free(params); return 0; } - 权限和初始化问题:
btu_hcif_send_cmd必须在蓝牙栈初始化完成后才能调用,而且需要蓝牙相关的权限:- 如果是纯Native可执行程序,建议以root身份运行,或者将程序的UID切换为蓝牙进程的UID(通常是1002);
- 如果是带APK的应用,需要在
AndroidManifest.xml中添加<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />权限,并且确保蓝牙服务已经启动。
4. 常见问题排查
- 链接报错:undefined reference:要么是没正确链接
bluetooth.default.so,要么是函数符号没导出——回头再用nm检查符号,确认编译脚本里的shared_libs配置正确。 - 运行时崩溃:大概率是蓝牙栈没初始化就调用了
btu_hcif_send_cmd。如果你的应用是独立进程,可能需要修改bluedroid源码导出初始化相关函数(比如btu_init),或者把你的代码集成到蓝牙守护进程(bluetoothd)里。 - 权限不足导致调用失败:尝试用
su切换到root后运行程序,或者给程序添加系统签名,确保能获取蓝牙底层操作权限。
内容的提问来源于stack exchange,提问作者Tijo Thomas John
相关产品推荐
相关产品推荐

