2014年12月17日 星期三

BT_一般掃描流程(轉)

原作者 平淡

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.已經找到JNI層startDiscoveryNative函數對應的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方法

沒有留言:

張貼留言