您好,登錄后才能下訂單哦!
藍牙模塊架構詳解: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
|
這個方法是相當的長啊,這個是組廣播的方法可以確認無疑了。
再看看發送
看看下面這個方法的注釋,發送命令給主機控制器。
其實到這里,廣播包的數據已經拼組完成了。我們就沒有必要往下深究它怎么發出去了。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。