• android4.3 Bluetooth分析之扫描分析


    android4.3中引入了蓝牙低能耗le(low energy),相应的也有一些方法/类。不过代码里,并没有找到初始调用的地方。所以这里还是先只分析下bt普通的扫描流程(类似android 4.2),先贴出流程图

     

    主要通过“扫描”的流程来分析下

    BluetoothSettings.java::startScanning            ----package
    
    LocalBluetoothAdapter.java::startScanning       ----package
    
    BluetoothAdapter.java::startDiscovery            ----framework
    
    AdapterService.java::startDiscovery              ----package
    
    com_android_bluetooth_btservice_AdapterService.cpp::startDiscoveryNative -jni

    从这里开始分析下用到的一些变量和结构体

    首先看startDiscoveryNative方法:

      static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {                                                   
          ALOGV("%s:",__FUNCTION__); 
    
          jboolean result = JNI_FALSE; 
          if (!sBluetoothInterface) return result; 
                                                                    
          int ret = sBluetoothInterface->start_discovery();         
          result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
          return result;                                            
      }

     分析点: int ret = sBluetoothInterface->start_discovery(); 

    ----------------------------------------------------------------------------

    sBluetoothInterface的来源

    查看com_android_bluetooth_btservice_AdapterService.cpp所在目录的Android.mk文件,

    ......
    LOCAL_SHARED_LIBRARIES := 
        libandroid_runtime 
        libnativehelper 
        libcutils 
        libutils 
        liblog 
        libhardware
    ......

    libhardware是编译时用到的,一般都是在hardware目录中。然后可以在子目录libhardware下找到bluetooth.h。在bluetooth.h中定义了bt_interface_t结构体。继而寻找该结构体对象的创建位置。在external/bluetooth/bluedroid/btif/src/bluetooth.c文件中找到。如下所示:

    static const bt_interface_t bluetoothInterface = {
        sizeof(bluetoothInterface),    
        init,
        enable,
        disable,
        cleanup,
        get_adapter_properties,   
        get_adapter_property,
        set_adapter_property,
        get_remote_device_properties,  
        get_remote_device_property,    
        set_remote_device_property,    
        get_remote_service_record,
        get_remote_services,
        start_discovery,
        cancel_discovery,
        create_bond,
        remove_bond,
        cancel_bond,
        pin_reply,
        ssp_reply,
        get_profile_interface,
        dut_mode_configure,
        dut_mode_send,
    #if BLE_INCLUDED == TRUE
        le_test_mode
    #else
        NULL
    #endif
    };

    sBluetoothInterface对象便是获得了bluetoothInterface对象。

    接下来,打开蓝牙、扫描等功能就会通过sBluetoothInterface调用结构体中声明的相应方法了。

     

    流程:settings界面发起,LocalBluetoothAdapter.java过渡,去framework的转转(BluetoothAdapter.java)后,回到packages的AdapterService.java,再走JNI,接着去external处理。

    ----------------------------------------------------------------------------

    接下来,跟一遍star_discovery

    1.已经找到JNIstartDiscoveryNative函数对应的start_discovery方法(bluetooth.c),分析之。

    static int start_discovery(void)
    {
        /* sanity check */
        if (interface_ready() == FALSE)    
            return BT_STATUS_NOT_READY;
    
        return btif_dm_start_discovery();
    }

    2.分析btif_dm_start_discovery方法(btif_dm.c)

    bt_status_t btif_dm_start_discovery(void)
    {
        tBTA_DM_INQ inq_params;
        tBTA_SERVICE_MASK services = 0;
        
        BTIF_TRACE_EVENT1("%s", __FUNCTION__);
        /* TODO: Do we need to handle multiple inquiries at the same time? */
        
        /* Set inquiry params and call API */
    #if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
        inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;
    #else
        inq_params.mode = BTA_DM_GENERAL_INQUIRY;
    #endif 
        inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
    
        inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
        inq_params.report_dup = TRUE;
    
        inq_params.filter_type = BTA_DM_INQ_CLR;
        /* TODO: Filter device by BDA needs to be implemented here */
        
        /* Will be enabled to TRUE once inquiry busy level has been received */
        btif_dm_inquiry_in_progress = FALSE;
        /* find nearby devices */ //下面是关键语句
        BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
    
        return BT_STATUS_SUCCESS;

    (1) BTA_DmSearch分析

    void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback) 
    {
    
        tBTA_DM_API_SEARCH    *p_msg;  
    
        if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
        {
            memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));
    
            p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
            memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
            p_msg->services = services;    
            p_msg->p_cback = p_cback;      
            p_msg->rs_res  = BTA_DM_RS_NONE;
            bta_sys_sendmsg(p_msg);        
        }  
    
    }

    看来只是发出一个消息,传递参数值。

    (2)bte_search_devices_evt (btif_dm.c)

    这条语句中,bte_search_devices_evt是真正用来搜索的,分析这个方法。贴出代码:

    static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
    {
        UINT16 param_len = 0;
    
        if (p_data)
            param_len += sizeof(tBTA_DM_SEARCH);
        /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
        switch (event)
        {
            case BTA_DM_INQ_RES_EVT:
            {
                if (p_data->inq_res.p_eir)
                    param_len += HCI_EXT_INQ_RESPONSE_LEN;
            }
            break;
    
            case BTA_DM_DISC_RES_EVT:
            {
                if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data)
                    param_len += p_data->disc_res.raw_data_size;
            }
            break;
        }
        BTIF_TRACE_DEBUG3("%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);
    
        /* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
        if (event == BTA_DM_INQ_RES_EVT)
            p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
    
        btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
            (param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
    }

    看注释,这个方法作用就是Switches context from BTE to BTIF for DM search events,即将context从bte传给btif中的dm search事件。所以关键点在于btif_dm_search_devices_evt方法(btif_dm.c文件中定义),继续贴代码:

    static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
    {
        switch (event)
        {
            case BTA_DM_INQ_RES_EVT:
            {
                /* inquiry result */
                UINT32 cod;
                UINT8 *p_eir_remote_name = NULL;
                bt_bdname_t bdname;
                bt_bdaddr_t bdaddr;
                UINT8 remote_name_len;
                UINT8 *p_cached_name = NULL;
                tBTA_SERVICE_MASK services = 0;
                bdstr_t bdstr;
    
                p_search_data = (tBTA_DM_SEARCH *)p_param;
                //解析mac地址
                bdcpy(bdaddr.address, p_search_data->inq_res.bd_addr);
                    
                    /* Callback to notify upper layer of device */
                    //下面是关键语句,回调方法
                    HAL_CBACK(bt_hal_cbacks, device_found_cb,
                                     num_properties, properties);
                }
            }
            break;
    ......

    HAL_CBACK会注册回调方法,这里,会调用结构体对象bt_hal_cbacks中的device_found_cb方法。

     

    继续扩展:

    (a) bt_hal_cbacks对象分析   (根据初始化流程分析从头分析该bt_hal_cback对象的由来)

    (a.1)首先,在AdapterService.java::onCreate方法中,有initNative方法。在相应JNI文件com_android_bluetooth_btservice_AdapterService.cpp中找到该方法,如下:

    static bool initNative(JNIEnv* env, jobject obj) {
        ALOGV("%s:",__FUNCTION__);
        ......
        if (sBluetoothInterface) {
            int ret = sBluetoothInterface->init(&sBluetoothCallbacks);
      ......
    }

    (a.1.1)该JNI文件中定义了sBluetoothCallbacks,如下:

    bt_callbacks_t sBluetoothCallbacks = {
        sizeof(sBluetoothCallbacks),   
        adapter_state_change_callback, 
        adapter_properties_callback,   
        remote_device_properties_callback,
        device_found_callback,
        discovery_state_changed_callback,
        pin_request_callback,
        ssp_request_callback,
        bond_state_changed_callback,   
        acl_state_changed_callback,    
        callback_thread_event,
        dut_mode_recv_callback,
    
        le_test_mode_recv_callback
    };

    bt_callbacks_t结构体的定义在hardware/libhardware/include/hardware/bluetooth.h中,代码如下:

    /** Bluetooth DM callback structure. */
    typedef struct {
        /** set to sizeof(bt_callbacks_t) */
        size_t size;
        adapter_state_changed_callback adapter_state_changed_cb;
        adapter_properties_callback adapter_properties_cb;
        remote_device_properties_callback remote_device_properties_cb;
        device_found_callback device_found_cb;
        discovery_state_changed_callback discovery_state_changed_cb;
        pin_request_callback pin_request_cb;
        ssp_request_callback ssp_request_cb;
        bond_state_changed_callback bond_state_changed_cb;
        acl_state_changed_callback acl_state_changed_cb;
        callback_thread_event thread_evt_cb;
        dut_mode_recv_callback dut_mode_recv_cb;
        le_test_mode_callback le_test_mode_cb;
    } bt_callbacks_t;

    (a.1.2) 分析sBluetoothInterface对象的init方法。

    因为sBluetoothInterface对象的值也是在bluetooth.c文件中定义的bluetoothInterface对象赋值的,所以直接找bluetoothInterface对象的定义处。

    static const bt_interface_t bluetoothInterface = {
        sizeof(bluetoothInterface),    
        init,
        enable,
        disable,
        cleanup,
        get_adapter_properties,
        get_adapter_property,
        set_adapter_property,
        get_remote_device_properties,  
        get_remote_device_property,    
        set_remote_device_property,    
        get_remote_service_record,
        get_remote_services,
        start_discovery,
        cancel_discovery,
        create_bond,
        remove_bond,
        cancel_bond,
        pin_reply,
        ssp_reply,
        get_profile_interface,
        dut_mode_configure,
        dut_mode_send,
    #if BLE_INCLUDED == TRUE
        le_test_mode
    #else
        NULL
    #endif
    };

    在该结构体中找到init方法,然后继续在bluetooth.c中找init方法的定义。

    static int init(bt_callbacks_t* callbacks )
    {
        ALOGI("init");
    
        /* sanity check */
        if (interface_ready() == TRUE)
            return BT_STATUS_DONE;
    
        /* store reference to user callbacks */
        bt_hal_cbacks = callbacks; //这里为bt_hal_cbacks对象赋值
    
        /* add checks for individual callbacks ? */
    
        bt_utils_init();
    
        /* init btif */
        btif_init_bluetooth();
    
        return BT_STATUS_SUCCESS;
    }

    通过上面标注的语句就知道了bt_hal_cback对象的由来,即sBluetoothCallbacks对象。

     

    (b) HAL_CBACK分析

    #define HAL_CBACK(P_CB, P_CBACK, ...)
        if (P_CB && P_CB->P_CBACK) {            
            BTIF_TRACE_API2("HAL %s->%s", #P_CB, #P_CBACK); 
            P_CB->P_CBACK(__VA_ARGS__);         
        }                                       
        else {                                  
            ASSERTC(0, "Callback is NULL", 0);  
        }

    这个宏主要就是执行了P_CB->P_CBACK(__VA_ARGS__); 在这里就是bt_hal_cback-> device_found_cb(...)方法。然后找到 sBluetoothCallbacks对象中对应的方法device_found_callback,继而找到该方法定义处。

    static void device_found_callback(int num_properties, bt_property_t *properties) {
      ......
          callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback, addr);
      ......

    JNI层的method_deviceFoundCallback函数对应java层的deviceFoundCallback方法,在JniCallbacks.java中。该类中又会调用RemoteDevice.java中的deviceFoundCallback方法。

     

    然后,该回调方法中会发出广播,action为BluetoothDevice.ACTION_FOUND。这个广播会在BluetoothEventManager.java中处理。该类中通过addHandler方法,将action的值与相关handler接口类绑定。

    接下来其他方法的处理,基本上也是这个套路。

    总结下扫描的流程:

    1.BluetoothEnabler类中调用startScanning方法,继而会调用LocalBluetoothAdapter,然后进入framework层,调用BluetoothAdapter中的startDiscovery方法,然后调用了AdapterService::startDiscovery(ps:在BluetoothAdapter类中,有mService和mMangerService对象,前一个代表AdapterService,后一个指BluetoothManagerService,比如enable BT的时候,就会调用BluetoothManagerService的方法,这个具体分析的时候要注意)。接着,会调用JNI层com_android_bluetooth_btservice_AdapterService.cpp中的startDiscoveryNative方法。

    这个流程其实还是蛮清晰的,从上层应用执行到中间层再准备到协议栈external中去了。

     

    下面就开始纠结了,各层跳来跳去:即external的分析 

    startDiscoveryNative (JNI层)
     
    ---> sBluetoothInterface->start_discovery() (bluetooth.c中)
    ---> btif_dm_start_discovery方法 (btif_dm.c)
    ---> BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
    ---> bte_search_devices_evt
    ---> btif_dm_search_devices_evt
    ---> HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
                                     status, &bdaddr, 1, properties);
     
    ---> remote_device_properties_callback (JNI层)
    --->callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback, addr, types, props);
     
    --> deviceFoundCallback (packages/apps/Bluetooth..JniCallbacks.java)
     
    --> deviceFoundCallback (packages/apps/Bluetooth..RemoteDevices.java)
     
    --->在RemoteDevices.java中会发出广播,action为BluetoothDevice.ACTION_FOUND。
     
    --->广播接收者(packages/apps/Settings/..../BluetoothEventManager.java)
    在其初始化方法中,为每个action绑定了一个名为XXHander的接口类,即以键值对形式保存。在广播的onReceive方法中,调用相应接口类处理。
     
    --->调用dispatchDeviceAdded方法 (还是在BluetoothEventManager.java中)
    ps:在这个方法中,会调用之前注册的回调类(这个回调类是DeviceListPreferenceFragment.java)的onDeviceAdded方法。
     
    ---> DeviceListPreferenceFragment.java::onDeviceAdded(还是在Settings模块中)
    ---> DeviceListPreferenceFragment.java::createDevicePreference方法
  • 相关阅读:
    谷歌翻译插件
    WordPress资料收集,以后整理
    WordPress不同分类使用不同的文章模板
    禁用/移除WordPress页面的评论功能
    wordpress设置一个特定的页面作为首页
    wordpress主题之后台菜单编辑,小工具
    tinkcmf视频上传大小限制
    转:解决Onethink上传视频的问题 超棒的解决方案
    linux(centos) 下安装phpstudy 如何命令行进入mysql
    在 Mac OS X 10.9 搭建 Python3 科学计算环境
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/6418251.html
Copyright © 2020-2023  润新知