十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
蓝牙模块架构详解:https://blog.csdn.net/tronteng/article/details/53435217
创新互联建站服务项目包括右玉网站建设、右玉网站制作、右玉网页制作以及右玉网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,右玉网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到右玉省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
蓝牙连接过程分析:http://mcu.szdahao.com/info/info_218.html
由于公司想节约成本,将蓝牙盒子的功能由android来实现,但是发现android广播包的数据的拼组顺序与蓝牙盒子的不一致。所以需要看看源码是如何组包的,是否可以去修改。
开启广播的源码
》》注册客户端
|
AdvertiseCallbackWrapper是BluetoothAdvertiser的内部类
|
上面的mBluetoothGatt其实就是GattService的BluetoothGattBinder对象,但是注意广播的数据advertiseData并没有往下传递。
|
Binder又调用了外部类GattService的方法
然后调用了Native的方法,调用到这里突然发现TMD的广播包数据没有传递过来。所以往回看,搜索广播包存储的变量mAdertisment.
》》客户端注册成功,真正的开启广播
先调用binder的方法startMultiAdvertising
然后binder再调用service里的方法
可以看到广播的数据被封进了AdvertiseClient对象
service然后再调用AdvertiseManager的方法
|
|
调用AdvertiseNative方法,注意这个类是AdvertiseManager的内部类
先看单个广播的方法startSingleAdvertising:
第一步,先使能广播 。
第二步,设置广播的数据 。
看看JNI方法,注意是JNI,不是C。
注意上面的JNI方法env->GetByteArrayElements和ReleaseByteArrayElements,获取数组然后又释放了数组。所以主要看sGattIf->client->set_adv_data这个方法
搜索到这个方法的定义的h文件:
那么sGattIf是什么,client又是什么?这个方法的实现在哪里呢?
追溯sGattIf
追溯btIf
|
|
这个方法是在classInitNative方法里被调用的
那么classInitNative肯定有个地方被用,我们找找,注意这是jni类的方法,那么它肯定是要被上层代码所调用的 :
|
|
可以发现classInitNative正好是GattService的本地方法,并且在GattService类加载时就调用了。观察GattService和com_android_bluetooth_btservice_AdapterService.cpp两个类,
发现它们也是在同一个应用下。所以上面方法调用推理是没有毛病的。
所以我们接着上面的源码说起
上面引用调用十分复杂:
static void classInitNative(JNIEnv* env, jclass clazz) { int err; hw_module_t* module; char value[PROPERTY_VALUE_MAX]; //从配置文件里获取key = "bluetooth.mock_stack"的值 property_get("bluetooth.mock_stack", value, ""); //得到module的ID const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID); //给module赋值 err = hw_get_module(id, (hw_module_t const**)&module); if (err == 0) { hw_device_t* abstraction; err = module->methods->open(module, id, &abstraction); if (err == 0) { bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction; sBluetoothInterface = btStack->get_bluetooth_interface(); } else { ALOGE("Error while opening Bluetooth library"); } } else { ALOGE("No Bluetooth Library found"); } }
上面的hw_get_module已经在和硬件打交道了
上面方法的调用就不去具体深究了,下面看看看 sBluetoothInterface这个变量的类型
它是bt_interface_t的指针类型,bt_interface_t的定义:
/** Represents the standard Bluetooth DM interface. */ typedef struct { /** set to sizeof(bt_interface_t) */ size_t size; /** * Opens the interface and provides the callback routines * to the implemenation of this interface. */ int (*init)(bt_callbacks_t* callbacks ); /** Enable Bluetooth. */ int (*enable)(void); /** Disable Bluetooth. */ int (*disable)(void); /** Closes the interface. */ void (*cleanup)(void); /** Get all Bluetooth Adapter properties at init */ int (*get_adapter_properties)(void); /** Get Bluetooth Adapter property of 'type' */ int (*get_adapter_property)(bt_property_type_t type); /** Set Bluetooth Adapter property of 'type' */ /* Based on the type, val shall be one of * bt_bdaddr_t or bt_bdname_t or bt_scanmode_t etc */ int (*set_adapter_property)(const bt_property_t *property); /** Get all Remote Device properties */ int (*get_remote_device_properties)(bt_bdaddr_t *remote_addr); /** Get Remote Device property of 'type' */ int (*get_remote_device_property)(bt_bdaddr_t *remote_addr, bt_property_type_t type); /** Set Remote Device property of 'type' */ int (*set_remote_device_property)(bt_bdaddr_t *remote_addr, const bt_property_t *property); /** Get Remote Device's service record for the given UUID */ int (*get_remote_service_record)(bt_bdaddr_t *remote_addr, bt_uuid_t *uuid); /** Start SDP to get remote services */ int (*get_remote_services)(bt_bdaddr_t *remote_addr); /** Start Discovery */ int (*start_discovery)(void); /** Cancel Discovery */ int (*cancel_discovery)(void); /** Create Bluetooth Bonding */ int (*create_bond)(const bt_bdaddr_t *bd_addr, int transport); /** Remove Bond */ int (*remove_bond)(const bt_bdaddr_t *bd_addr); /** Cancel Bond */ int (*cancel_bond)(const bt_bdaddr_t *bd_addr); /** * Get the connection status for a given remote device. * return value of 0 means the device is not connected, * non-zero return status indicates an active connection. */ int (*get_connection_state)(const bt_bdaddr_t *bd_addr); /** BT Legacy PinKey Reply */ /** If accept==FALSE, then pin_len and pin_code shall be 0x0 */ int (*pin_reply)(const bt_bdaddr_t *bd_addr, uint8_t accept, uint8_t pin_len, bt_pin_code_t *pin_code); /** BT SSP Reply - Just Works, Numeric Comparison and Passkey * passkey shall be zero for BT_SSP_VARIANT_PASSKEY_COMPARISON & * BT_SSP_VARIANT_CONSENT * For BT_SSP_VARIANT_PASSKEY_ENTRY, if accept==FALSE, then passkey * shall be zero */ int (*ssp_reply)(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant, uint8_t accept, uint32_t passkey); /** Get Bluetooth profile interface */ const void* (*get_profile_interface) (const char *profile_id); /** Bluetooth Test Mode APIs - Bluetooth must be enabled for these APIs */ /* Configure DUT Mode - Use this mode to enter/exit DUT mode */ int (*dut_mode_configure)(uint8_t enable); /* Send any test HCI (vendor-specific) command to the controller. Must be in DUT Mode */ int (*dut_mode_send)(uint16_t opcode, uint8_t *buf, uint8_t len); /** BLE Test Mode APIs */ /* opcode MUST be one of: LE_Receiver_Test, LE_Transmitter_Test, LE_Test_End */ int (*le_test_mode)(uint16_t opcode, uint8_t *buf, uint8_t len); /* enable or disable bluetooth HCI snoop log */ int (*config_hci_snoop_log)(uint8_t enable); /** Sets the OS call-out functions that bluedroid needs for alarms and wake locks. * This should be called immediately after a successful |init|. */ int (*set_os_callouts)(bt_os_callouts_t *callouts); /** Read Energy info details - return value indicates BT_STATUS_SUCCESS or BT_STATUS_NOT_READY * Success indicates that the VSC command was sent to controller */ int (*read_energy_info)(); /** * Native support for dumpsys function * Function is synchronous and |fd| is owned by caller. */ void (*dump)(int fd); /** * Clear /data/misc/bt_config.conf and erase all stored connections */ int (*config_clear)(void); } bt_interface_t;
可以知道bt_interface_t是个结构体类型
其实吧,源码看到这儿我又走偏了,我们主要是分析set_adv_data是由那个类实现的
搜索这个方法的调用是很绕的
只能搜索一个bt_gatt_client.h文件,那么继续搜索bt_gatt_client.h文件
继续搜索bt_gatt.h文件
然后一个一个文件点进去搜索set_adv_data方法,发现只有/system/bt/btif/src/btif_gatt_client.c这个类里包涵这个方法,但是名字不是完全一模一样。
那么这个模块是怎么和外部模块建立关联的?用的什么机制?
搜索btgattClientInterface这个变量
|
搜索btif_gatt_get_interface方法
看看调用的方法:
这个好像就是蓝牙架构里的Profile层??
在bluetooth.c又将上面的get_profile_interface封装到bluetoothInterface
|
看看id
这不正是打开蓝牙栈吗?但是死活没有搜索到HAL_MODULE_INFO_SYM在哪里被调用。
看了这个博客https://blog.csdn.net/myarrow/article/details/7175204,应该就能明白。HAL如何向上层提供接口
回顾前面的源码
看看id
2个module的id一模一样,这不正好与上面的HAL_MODULE_INFO_SYM这个Module不谋而合??????MD,分析源码,终于有一次合上了。
至此,我们找到了方法的调用栈,但这不是我的目的。我的目的,还在set_adv_data那里。所以继续前面的源码接着说:
第1步:打包数据
就是把数据封装到adv_data这个变量里。
(client_ifbool set_scan_rspbool include_namebool include_txpowermin_intervalmax_intervalappearancemanufacturer_len* manufacturer_dataservice_data_len* service_dataservice_uuid_len* service_uuidbtif_adv_data_t *p_multi_adv_inst) { memset(p_multi_adv_instsizeof(btif_adv_data_t))p_multi_adv_inst->= (uint8_t) p_multi_adv_inst->= p_multi_adv_inst->= p_multi_adv_inst->= p_multi_adv_inst->= p_multi_adv_inst->= p_multi_adv_inst->= p_multi_adv_inst->= (manufacturer_len > ) { p_multi_adv_inst->p_manufacturer_data = GKI_getbuf()memcpy(p_multi_adv_inst->p_manufacturer_datamanufacturer_datamanufacturer_len)} p_multi_adv_inst->= (service_data_len > ) { p_multi_adv_inst->p_service_data = GKI_getbuf()memcpy(p_multi_adv_inst->p_service_dataservice_dataservice_data_len)} p_multi_adv_inst->= (service_uuid_len > ) { p_multi_adv_inst->p_service_uuid = GKI_getbuf()memcpy(p_multi_adv_inst->p_service_uuidservice_uuidservice_uuid_len)} }
第2步:标题待定
fixed_queue_enqueue是不是似曾相识
分析上面的回调方法应该是:
可知数据又发给了bta模块
但是bta又是在哪里接受这个消息的呢?
搜索BTA_DM_API_BLE_SET_ADV_CONFIG_EVT
搜索bta_dm_ble_set_adv_config
|
这个方法是相当的长啊,这个是组广播的方法可以确认无疑了。
再看看发送
看看下面这个方法的注释,发送命令给主机控制器。
其实到这里,广播包的数据已经拼组完成了。我们就没有必要往下深究它怎么发出去了。