温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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