Android源碼個個擊破之6.0藍牙廣播開啓源碼

藍牙模塊架構詳解:https://blog.csdn.net/tronteng/article/details/53435217 html


藍牙鏈接過程分析:http://mcu.szdahao.com/info/info_218.html java





因爲公司想節約成本,將藍牙盒子的功能由android來實現,可是發現android廣播包的數據的拼組順序與藍牙盒子的不一致。因此須要看看源碼是如何組包的,是否能夠去修改。android


  1. 開啓廣播的源碼
    數組

  》》註冊客戶端架構

image.png

app

  AdvertiseCallbackWrapper是BluetoothAdvertiser的內部類ide

 image.png  

    |
oop

    上面的mBluetoothGatt其實就是GattService的BluetoothGattBinder對象,可是注意廣播的數據advertiseData並無往下傳遞。ui

    image.png

      |
this

      Binder又調用了外部類GattService的方法

        image.png

          而後調用了Native的方法,調用到這裏忽然發現TMD的廣播包數據沒有傳遞過來。因此往回看,搜索廣播包存儲的變量mAdertisment.

      》》客戶端註冊成功,真正的開啓廣播

         

         image.png

        先調用binder的方法startMultiAdvertising

        image.png

        而後binder再調用service裏的方法

        image.png

         能夠看到廣播的數據被封進了AdvertiseClient對象

             service而後再調用AdvertiseManager的方法

         image.png    

        |

            image.png

            |

            調用AdvertiseNative方法,注意這個類是AdvertiseManager的內部類

            image.png

            先看單個廣播的方法startSingleAdvertising:

              image.png

             第一步,先使能廣播 。

             第二步,設置廣播的數據 。

             image.png

       看看JNI方法,注意是JNI,不是C。

        image.png

          注意上面的JNI方法env->GetByteArrayElements和ReleaseByteArrayElements,獲取數組而後又釋放了數組。因此主要看sGattIf->client->set_adv_data這個方法

          搜索到這個方法的定義的h文件:

         image.png

            那麼sGattIf是什麼,client又是什麼?這個方法的實如今哪裏呢?

            追溯sGattIf

            image.png

          追溯btIf

          image.png    

         |

        image.png

        |

         image.png

            這個方法是在classInitNative方法裏被調用的

            image.png

          那麼classInitNative確定有個地方被用,咱們找找,注意這是jni類的方法,那麼它確定是要被上層代碼所調用的 :

         image.png

            |

            image.png

            |

            image.png

            能夠發現classInitNative正好是GattService的本地方法,而且在GattService類加載時就調用了。觀察GattService和com_android_bluetooth_btservice_AdapterService.cpp兩個類,

    發現它們也是在同一個應用下。因此上面方法調用推理是沒有毛病的。

            因此咱們接着上面的源碼提及

            image.png

            上面引用調用十分複雜:

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已經在和硬件打交道了

        image.png

         上面方法的調用就不去具體深究了,下面看看看     sBluetoothInterface這個變量的類型

          image.png

          它是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是由那個類實現的

        搜索這個方法的調用是很繞的

        image.png

         只能搜索一個bt_gatt_client.h文件,那麼繼續搜索bt_gatt_client.h文件

        image.png

            繼續搜索bt_gatt.h文件

         image.png

           而後一個一個文件點進去搜索set_adv_data方法,發現只有/system/bt/btif/src/btif_gatt_client.c這個類裏包涵這個方法,可是名字不是徹底如出一轍。

           image.png

            image.png

            那麼這個模塊是怎麼和外部模塊創建關聯的?用的什麼機制?

            搜索btgattClientInterface這個變量

            image.png

               |    

            image.png

            搜索btif_gatt_get_interface方法

           image.png

                  

            image.png

            看看調用的方法:

             image.png

              這個好像就是藍牙架構裏的Profile層??

                

              在bluetooth.c又將上面的get_profile_interface封裝到bluetoothInterface

                image.png

                 

         image.png

           image.png  |

         看看id image.png    

         這不正是打開藍牙棧嗎?可是死活沒有搜索到HAL_MODULE_INFO_SYM在哪裏被調用。

         看了這個博客https://blog.csdn.net/myarrow/article/details/7175204,應該就能明白。HAL如何向上層提供接口

        

        回顧前面的源碼

        image.png

            看看id image.png

               

         2個module的id如出一轍,這不正好與上面的HAL_MODULE_INFO_SYM這個Module不謀而合??????MD,分析源碼,終於有一次合上了。

         至此,咱們找到了方法的調用棧,但這不是個人目的。個人目的,還在set_adv_data那裏。因此繼續前面的源碼接着說:

         image.png

           

         第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步:標題待定

            image.png

            

            image.png

            fixed_queue_enqueue是否是似曾相識

            分析上面的回調方法應該是:

            image.png

            

            image.png

            

           image.png

            可知數據又發給了bta模塊

             可是bta又是在哪裏接受這個消息的呢?

            搜索BTA_DM_API_BLE_SET_ADV_CONFIG_EVT

            image.png

            搜索bta_dm_ble_set_adv_config

            image.png

            |

          image.png   

             

            image.png

             這個方法是至關的長啊,這個是組廣播的方法能夠確認無疑了。

             再看看發送

             image.png

               看看下面這個方法的註釋,發送命令給主機控制器。
                image.png

                 其實到這裏,廣播包的數據已經拼組完成了。咱們就沒有必要往下深究它怎麼發出去了。

相關文章
相關標籤/搜索