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 = ; 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, , 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 = ; 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 = ;
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(, "Callback is NULL", ); \
}

这个宏主要就是执行了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方法

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

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

    BluetoothAdapter.java中有low enery(le)的一些方法,android提供了这些方法,但源码中并未找到这些方法的调用之处.本文档主要分析这类方法的执行流程,来了解下le到底 ...

  2. 【Lua篇】静态代码扫描分析(一)初步介绍

    一.静态代码分析         静态代码分析是一种通过检查代码而不是执行程序来发现源代码中错误的手段.通常可以帮助我们发现常见的编码错误,例如: 语法错误 违反制定的标准编码 未定义的变量 安全性问 ...

  3. 编译原理(六)自底向上分析之LR分析法

    自底向上分析之LR分析法 说明:以老师PPT为标准,借鉴部分教材内容,AlvinZH学习笔记. 基本概念 1. LR分析:从左到右扫描(L)自底向上进行规约(R),是规范规约,也即最右推导(规范推导) ...

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

    常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...

  5. Memcached源代码分析 - Memcached源代码分析之消息回应(3)

    文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析 ...

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

    show variables like '%profiling%';    查看状态  查看时间去哪了``` set  profiling=1;// 打开 show profiles;  查看执行过的 ...

  7. [转载] 常用 Java 静态代码分析工具的分析与比较

    转载自http://www.oschina.net/question/129540_23043 简介: 本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代 ...

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

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  9. x264源代码简单分析:宏块分析(Analysis)部分-帧内宏块(Intra)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

随机推荐

  1. MySQL学习之用户管理

    用户权限管理 用户权限管理:在不同的项目中给不同的角色(开发者)不同的操作权限,为了保证数据库数据的安全. 简单点说:有的用户可以访问并修改这个数据,而有些用户只能去查看数据,而不能修改数据.就如同博 ...

  2. linux 特殊命令(二)

    Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Membershi ...

  3. delphi 2010以上 安装 第三方控件

    delphi-“can't be installed because it is not a design time package. 一定要先装 dcl*.dpk ----------------- ...

  4. EFI分区删除的有效方法

    用Diskpart命令,可以方便的删除EFI系统分区. 一,win + R, 输入cmd,回车. 二,输入 Diskpart ,回车,得到 三,再输入 list disk , 回车,查看磁盘信息 四, ...

  5. Hadoop1.0 与Hadoop2.0

    Hadoop1.0的局限-MapReduce •扩展性 –集群最大节点数–4000 –最大并发任务数–40000 (当 map-reduce job 非常多的时候,会造成很大的内存开销,潜在来说,也增 ...

  6. django使用pycharm为项目选择虚拟环境-3.1

    使用pycharm打开项目 选择右上角的 file - settings - project - project interpreter 选择左上的设置符号,选择 Add 选择红框部分,然后选择之前创 ...

  7. Python3爬虫(十六) pyspider框架

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.pyspider介绍1.基本功能 提供WebUI可视化功能,方便编写和调试爬虫 提供爬取进度监控.爬取结果查看 ...

  8. 洛谷九月月赛T1 思考

    很迷的一道题目,刚开始直接枚举n个1,然后去mod m ,爆0,后来发现一个神奇性质:找到递推公式An=An-1*10+1,枚举n,不断mod m,每递推一次就1的个数加一.居然可行! 听说余数具有可 ...

  9. 【转】odoo装饰器:model

    model装饰器的作用是返回一个集合列表,一般用来定义自动化动作里面,该方法无ids传入. 应用举例: 定义columns langs = fields.Selection(string=" ...

  10. Dinic算法最大流入门

    例题传送门 Dinic算法是网络流最大流的优化算法之一,每一步对原图进行分层,然后用DFS求增广路.时间复杂度是O(n^2*m),Dinic算法最多被分为n个阶段,每个阶段包括建层次网络和寻找增广路两 ...