亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2020-07-04 01:58:09 來源:網絡 閱讀:5290 作者:屠夫章哥 欄目:移動開發

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


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





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


  1. 開啟廣播的源碼

  》》注冊客戶端

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

  AdvertiseCallbackWrapper是BluetoothAdvertiser的內部類

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

    |

    上面的mBluetoothGatt其實就是GattService的BluetoothGattBinder對象,但是注意廣播的數據advertiseData并沒有往下傳遞。

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

      |

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

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

          然后調用了Native的方法,調用到這里突然發現TMD的廣播包數據沒有傳遞過來。所以往回看,搜索廣播包存儲的變量mAdertisment.

      》》客戶端注冊成功,真正的開啟廣播

         

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

        先調用binder的方法startMultiAdvertising

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

        然后binder再調用service里的方法

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

         可以看到廣播的數據被封進了AdvertiseClient對象

             service然后再調用AdvertiseManager的方法

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

        |

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

            |

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

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

            先看單個廣播的方法startSingleAdvertising:

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

             第一步,先使能廣播 。

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

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

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

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

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

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

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

            那么sGattIf是什么,client又是什么?這個方法的實現在哪里呢?

            追溯sGattIf

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

          追溯btIf

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

         |

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

        |

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

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

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

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

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

            |

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

            |

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

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

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

            所以我們接著上面的源碼說起

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

            上面引用調用十分復雜:

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

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

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

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

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

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

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

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

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

            繼續搜索bt_gatt.h文件

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

           然后一個一個文件點進去搜索set_adv_data方法,發現只有/system/bt/btif/src/btif_gatt_client.c這個類里包涵這個方法,但是名字不是完全一模一樣。

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

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

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

            搜索btgattClientInterface這個變量

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

               |    

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

            搜索btif_gatt_get_interface方法

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

                  

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

            看看調用的方法:

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

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

                

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

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

                 

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

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

         看看id Android源碼個個擊破之6.0藍牙廣播開啟源碼    

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

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

        

        回顧前面的源碼

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

            看看id Android源碼個個擊破之6.0藍牙廣播開啟源碼

               

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

         至此,我們找到了方法的調用棧,但這不是我的目的。我的目的,還在set_adv_data那里。所以繼續前面的源碼接著說:

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

           

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

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

            

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

            fixed_queue_enqueue是不是似曾相識

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

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

            

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

            

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

            可知數據又發給了bta模塊

             但是bta又是在哪里接受這個消息的呢?

            搜索BTA_DM_API_BLE_SET_ADV_CONFIG_EVT

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

            搜索bta_dm_ble_set_adv_config

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

            |

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

             

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

             這個方法是相當的長啊,這個是組廣播的方法可以確認無疑了。

             再看看發送

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

               看看下面這個方法的注釋,發送命令給主機控制器。
                Android源碼個個擊破之6.0藍牙廣播開啟源碼

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

    

                    

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

古蔺县| 景谷| 九江市| 唐海县| 德惠市| 舞钢市| 文登市| 青浦区| 安新县| 门源| 慈利县| 蒙城县| 武强县| 拉孜县| 台州市| 潞西市| 松原市| 安陆市| 开鲁县| 民权县| 马尔康县| 栾城县| 湖北省| 登封市| 贵州省| 新丰县| 定陶县| 泊头市| 手机| 门源| 墨江| 怀集县| 都昌县| 延寿县| 玛多县| 辰溪县| 巴林右旗| 阳江市| 永丰县| 中宁县| 佳木斯市|