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.已经找到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方法

时间: 2024-08-05 06:58:47

android4.3 Bluetooth分析之扫描分析的相关文章

android4.3 Bluetooth(le)分析之startLeScan分析

BluetoothAdapter.java中有low enery(le)的一些方法,android提供了这些方法,但源码中并未找到这些方法的调用之处.本文档主要分析这类方法的执行流程,来了解下le到底做了些什么. 本文主要就是分析下startLeScan方法(两个重载方法). public boolean startLeScan(LeScanCallback callback) { return startLeScan(null, callback); } public boolean star

Android 上千实例源码分析以及开源分析

Android 上千实例源码分析以及开源分析(百度云分享) 要下载的直接翻到最后吧,项目实例有点多. 首先 介绍几本书籍(下载包中)吧. 01_Android系统概述 02_Android系统的开发综述 03_Android的Linux内核与驱动程序 04_Android的底层库和程序 05_Android的JAVA虚拟机和JAVA环境 06_Android的GUI系统 07_Android的Audio系统 08_Android的Video 输入输出系统 09_Android的多媒体系统 10_

常用 Java 静态代码分析工具的分析与比较

转载自: http://www.oschina.net/question/129540_23043 简介: 本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),最后从功能.特性等方面对它们进行分析和比较,希望能够帮助 Java 软件开发人员了解静态代码分析工具,并选择合适的工具应用到软件开发中. 引言 在 Java 软件开发过程中,开发团队往往要花费大量的时间和精力发现并修改代

Android的Framework分析---5 ActivityManager分析

ActivityManager是android框架的一个重要部分,它负责一新ActivityThread进程创建,Activity生命周期的维护,管理系统中的Acitvity的状态切换. 这边内容还有更多内容,详细请参看ActivityManager.java ,ActivityMangaerNative.java 和SystemServcer.java 文件. 这几个的类的关系如下: 上图很清楚地描述了ActivityManager框架的几个主要类之间的关系,我们做应用开发接触很多的其实就是A

Android开发之蓝牙(Bluetooth)操作(一)--扫描已经配对的蓝牙设备

版权声明:本文为博主原创文章,未经博主允许不得转载. 一. 什么是蓝牙(Bluetooth)? 1.1  BuleTooth是目前使用最广泛的无线通信协议 1.2  主要针对短距离设备通讯(10m) 1.3  常用于连接耳机,鼠标和移动通讯设备等. 二. 与蓝牙相关的API 2.1 BluetoothAdapter: 代表了本地的蓝牙适配器 2.2 BluetoothDevice 代表了一个远程的Bluetooth设备 三. 扫描已经配对的蓝牙设备(1) 注:必须部署在真实手机上,模拟器无法实现

mysql 分析3使用分析sql 性能 show profiles ;

show variables like '%profiling%';    查看状态  查看时间去哪了``` set  profiling=1;// 打开 show profiles;  查看执行过的sql 语句 show profile for query 2;   找到第二条为id为2的sql生成查询计划  分析查询状态 分析sql依据 时间花费在那些地方了 时间浪费在了数据传输. 通过 show profile for query 2;找到问题所在.

Tomcat7.0源码分析——请求原理分析(中)

前言 在<TOMCAT7.0源码分析--请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT7.0源码分析--请求原理分析(上)>一文中的相关知识以及HTTP协议和TCP协议的一些内容.本文重点讲解Tomcat7.0在准备好接受请求后,请求过程的原理分析. 请求处理架构 在正式开始之前,我们先来看看图1中的Tomcat请求处理架构. 图1 Tomcat请求处理架构 图1列出了Tomcat请求处理架构中的主

x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)

本文记录x264的 x264_slice_write()函数中调用的x264_macroblock_analyse()的源代码.x264_macroblock_analyse()对应着x264中的分析模块.分析模块主要完成了下面2个方面的功能: (1)对于帧内宏块,分析帧内预测模式(2)对于帧间宏块,进行运动估计,分析帧间预测模式 上一篇文章记录了帧内宏块预测模式的分析,本文继续记录帧间宏块预测模式的分析. 函数调用关系图 宏块分析(Analysis)部分的源代码在整个x264中的位置如下图所示

Tomcat源码分析——请求原理分析(下)

前言 本文继续讲解TOMCAT的请求原理分析,建议朋友们阅读本文时首先阅读过<TOMCAT源码分析——请求原理分析(上)>和<TOMCAT源码分析——请求原理分析(中)>.在<TOMCAT源码分析——请求原理分析(中)>一文我简单讲到了Pipeline,但并未完全展开,本文将从Pipeline开始讲解请求原理的剩余内容. 管道 在Tomcat中管道Pipeline是一个接口,定义了使得一组阀门Valve按照顺序执行的规范,Pipeline中定义的接口如下: getBas