其他分享
首页 > 其他分享> > Android Bluetooth蓝牙scan过程

Android Bluetooth蓝牙scan过程

作者:互联网

Android Bluetooth框架

在这里插入图片描述

一、Settings界面下scan

进入到android设置界面并打开蓝牙,扫描会自动开始。
下面我们从android蓝牙设置界面开始分析:

蓝牙开关按钮
BluetoothSettings.java (packages\apps\settings\src\com\android\settings\bluetooth)

public final class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable 
	private BluetoothEnabler mBluetoothEnabler;
	public void onActivityCreated(Bundle savedInstanceState)
		mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);
        mBluetoothEnabler.setupSwitchBar();
        	mSwitchBar.show(); // 显示蓝牙开关按钮

    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

打开蓝牙
BluetoothEnabler.java (packages\apps\settings\src\com\android\settings\bluetooth)

onSwitchChanged()
     mLocalAdapter.setBluetoothEnabled(isChecked);

    
    
  • 1
  • 2

打开蓝牙过程请参考我前面文章Android BlueDroid蓝牙enable过程,这里不做描述。蓝牙打开成功的状态会从协议栈回调上来,调用onBluetoothStateChanged,最终调用startScanning。

    public void onBluetoothStateChanged(int bluetoothState) {
        super.onBluetoothStateChanged(bluetoothState);
        updateContent(bluetoothState);
    }
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">updateContent</span><span class="token punctuation">(</span><span class="token keyword">int</span> bluetoothState<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">final</span> PreferenceScreen preferenceScreen <span class="token operator">=</span> <span class="token function">getPreferenceScreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> messageId <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token keyword">switch</span> <span class="token punctuation">(</span>bluetoothState<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">case</span> BluetoothAdapter<span class="token punctuation">.</span>STATE_ON<span class="token operator">:</span>
            preferenceScreen<span class="token punctuation">.</span><span class="token function">removeAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            preferenceScreen<span class="token punctuation">.</span><span class="token function">setOrderingAsAdded</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            mDevicePreferenceMap<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            mPairedDevicesCategory<span class="token punctuation">.</span><span class="token function">removeAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			mAvailableDevicesCategory<span class="token punctuation">.</span><span class="token function">removeAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mInitialScanStarted<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                <span class="token function">startScanning</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//启动扫描</span>
                	mLocalAdapter<span class="token punctuation">.</span><span class="token function">startScanning</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
	<span class="token punctuation">}</span>

}

LocalBluetoothAdapter.java (packages\apps\settings\src\com\android\settings\bluetooth)

    void startScanning(boolean force) {
        if (!mAdapter.isDiscovering()) {
            if (mAdapter.startDiscovery()) {
                mLastScan = System.currentTimeMillis();
            }
        }
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

BluetoothAdapter.java (frameworks\base\core\java\android\bluetooth)

    public boolean startDiscovery() {
        if (getState() != STATE_ON) return false;
        try {
            synchronized(mManagerCallback) {
                if (mService != null) return mService.startDiscovery();
            }
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        return false;
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

查看mService的定义:

    private IBluetooth mService;

 
 
  • 1

mService通过binder调用startDiscovery。
AdapterService.java(packages\apps\bluetooth\src\com\android\bluetooth\btservice)

public class AdapterService extends Service {
    boolean startDiscovery() {
       enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                      "Need BLUETOOTH ADMIN permission");
       return startDiscoveryNative();
   }

private static class AdapterServiceBinder extends IBluetooth.Stub {
public boolean startDiscovery() {
AdapterService service = getService();
if (service == null) return false;
return service.startDiscovery();
}
}
}

查看startDiscoveryNative的定义,可以看到它是一个native方法:

private native boolean startDiscoveryNative();

 
 
  • 1

com_android_bluetooth_btservice_AdapterService.cpp (packages\apps\bluetooth\jni)

static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
   int ret = sBluetoothInterface->start_discovery();
}

 
 
  • 1
  • 2
  • 3

查看定义

static const bt_interface_t *sBluetoothInterface = NULL;

 
 
  • 1

查找sBluetoothInterface的赋值,发现它加载了一个bluetooth.defualt.so模块:

#define BT_HARDWARE_MODULE_ID "bluetooth"
#define BT_STACK_MODULE_ID "bluetooth"
#define BT_STACK_TEST_MODULE_ID "bluetooth_test"
static void classInitNative(JNIEnv* env, jclass clazz)
{
   hw_module_t* module;
   const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID :  
   		BT_STACK_TEST_MODULE_ID);
   // 加载btStack模块 bluetooth.defualt.so
   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) {
   		//最终转换为btStack结构体
           bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction;
           // sBluetoothInterface 赋值
           sBluetoothInterface = btStack->get_bluetooth_interface();
       } else {
          ALOGE("Error while opening Bluetooth library");
       }
   } else {
       ALOGE("No Bluetooth Library found");
   } 
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

查看hw_get_module的定义:
Hardware.c (hardware\libhardware)

 /** Base path of the hal modules */
#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#endif

/*

int hw_get_module(const char id, const struct hw_module_t module)
hw_get_module_by_class(id, NULL, module);
int hw_get_module_by_class(const char class_id, const char inst,
const struct hw_module_t *module)
{
char path[PATH_MAX];
char name[PATH_MAX];

strlcpy(name, class_id, PATH_MAX);

/* Nothing found, try the default */
// 查找模块 bluetooth.default.so
if (hw_module_exists(path, sizeof(path), name, “default”) == 0) {
goto found;
}

found:
return load(class_id, path, module);
void handle;
struct hw_module_t hmi;
handle = dlopen(path, RTLD_NOW);
/* Get the address of the struct hal_module_info. /
const char sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym);
}

Bluetooth.c (external\bluetooth\bluedroid\btif\src)
我们知道BlueDroid协议栈代码编译会 生成bluetooth.defualt.so模块,代码在external\bluetooth\bluedroid目录。

static const bt_interface_t bluetoothInterface
   start_discovery,
   	btif_dm_start_discovery();

 
 
  • 1
  • 2
  • 3

Btif_dm.c (external\bluetooth\bluedroid\btif\src)

  bt_status_t btif_dm_start_discovery(void)
   	inq_params.mode = BTA_DM_GENERAL_INQUIRY;
   	inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION; // 扫描时间10*1.28 s
   	inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS; 
   	inq_params.report_dup = TRUE;
   	inq_params.filter_type = BTA_DM_INQ_CLR;
   	BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
   		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);

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

btif_dm_start_discovery调用BTA_DmSearch,发送一个BTA_DM_API_SEARCH_EVT的消息,发出去的消息最后会在btu_task处理。

Bta_sys_main.c (external\bluetooth\bluedroid\bta\sys)

void bta_sys_sendmsg(void *p_msg)
{
   GKI_send_msg(bta_sys_cb.task_id, p_bta_sys_cfg->mbox, p_msg);
   	 GKI_send_event(task_id, (UINT16)EVENT_MASK(mbox));
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

查看bta_sys_cb.task_id的赋值:

BTA_API void bta_sys_init(void)
    bta_sys_cb.task_id = GKI_get_taskid();

 
 
  • 1
  • 2

bta_sys_init在btu_task中被调用,因此task_id 等于btu_task的task id,消息在btu_task中接收处理。

查看p_bta_sys_cfg->mbox的赋值:

// gki.h (external\bluetooth\bluedroid\gki\common)
/************************************************************************
** Mailbox definitions. Each task has 4 mailboxes that are used to
** send buffers to the task.
*/
#define TASK_MBOX_0    0
#define TASK_MBOX_1    1
#define TASK_MBOX_2    2
#define TASK_MBOX_3    3

#define NUM_TASK_MBOX 4

/************************************************************************
** Event definitions.
**
** There are 4 reserved events used to signal messages rcvd in task mailboxes.
** There are 4 reserved events used to signal timeout events.
** There are 8 general purpose events available for applications.
*/
#define MAX_EVENTS 16

#define TASK_MBOX_0_EVT_MASK 0x0001
#define TASK_MBOX_1_EVT_MASK 0x0002
#define TASK_MBOX_2_EVT_MASK 0x0004
#define TASK_MBOX_3_EVT_MASK 0x0008

//bta_sys.h (external\bluetooth\bluedroid\bta\sys)
/* system manager configuration structure /
typedef struct
{
UINT16 mbox_evt; / GKI mailbox event /
UINT8 mbox; / GKI mailbox id /
UINT8 timer; / GKI timer id /
UINT8 trace_level; / initial trace level */
} tBTA_SYS_CFG;

// bta_sys_cfg.c (external\bluetooth\bluedroid\bta\sys)
/* GKI task mailbox event for BTA. */
#define BTA_MBOX_EVT TASK_MBOX_2_EVT_MASK

/* GKI task mailbox for BTA. */
#define BTA_MBOX TASK_MBOX_2

const tBTA_SYS_CFG bta_sys_cfg =
{
BTA_MBOX_EVT, /* GKI mailbox event /
BTA_MBOX, / GKI mailbox id /
BTA_TIMER, / GKI timer id /
APPL_INITIAL_TRACE_LEVEL / initial trace level */
};

tBTA_SYS_CFG p_bta_sys_cfg = (tBTA_SYS_CFG )&bta_sys_cfg;

所以p_bta_sys_cfg->mbox等于TASK_MBOX_2, EVENT_MASK(mbox)则等于TASK_MBOX_2_EVT_MASK。

btu_task.c (external\bluetooth\bluedroid\stack\btu)


/*******************************************************************************
**
** Function         btu_task
**
** Description      This is the main task of the Bluetooth Upper Layers unit.
**                  It sits in a loop waiting for messages, and dispatches them
**                  to the appropiate handlers.
**
** Returns          should never return
**
*******************************************************************************/
BTU_API UINT32 btu_task (UINT32 param)
{
    UINT16           event;
    BT_HDR          *p_msg;
    UINT8            i;
    UINT16           mask;
    BOOLEAN          handled;
<span class="token comment">/* Initialize the mandatory core stack control blocks
   (BTU, BTM, L2CAP, and SDP)
 */</span>
<span class="token function">btu_init_core</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/* Initialize any optional stack components */</span>
<span class="token function">BTE_InitStack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
bta_sys_init(); // bta init
#endif

<span class="token comment">/* Send a startup evt message to BTIF_TASK to kickstart the init procedure */</span>
<span class="token function">GKI_send_event</span><span class="token punctuation">(</span>BTIF_TASK<span class="token punctuation">,</span> BT_EVT_TRIGGER_STACK_INIT<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/* Wait for, and process, events */</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    event <span class="token operator">=</span> GKI_wait <span class="token punctuation">(</span><span class="token number">0xFFFF</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">&amp;</span> TASK_MBOX_0_EVT_MASK<span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token comment">/* Process all messages in the queue */</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">&amp;</span> TIMER_0_EVT_MASK<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>

    <span class="token punctuation">}</span>

#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
if (event & TASK_MBOX_2_EVT_MASK)
{
while ((p_msg = (BT_HDR ) GKI_read_mbox(TASK_MBOX_2)) != NULL)
{
bta_sys_event(p_msg);
UINT8 id;
BOOLEAN freebuf = TRUE;
//event等于BTA_DM_API_SEARCH_EVT,id等于BTA_ID_DM_SEARCH,对应的cb函数bta_dm_search_reg(在btif_task->BTA_EnableBluetooth注册)
id = (UINT8) (p_msg->event >> 8);
//调用bta_dm_search_reg的bta_dm_search_sm_execute函数
freebuf = (bta_sys_cb.reg[id]->evt_hdlr)(p_msg);

    <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">&amp;</span> TIMER_1_EVT_MASK<span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token function">bta_sys_timer_update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

#endif
if (event & TIMER_3_EVT_MASK) {

    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">&amp;</span> <span class="token function">EVENT_MASK</span><span class="token punctuation">(</span>APPL_EVT_7<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

bta_dm_main.c (external\bluetooth\bluedroid\bta\dm)
bta_dm_search_sm_execute在bta_dm_search_action函数列表中取出BTA_DM_API_SEARCH对应的函数bta_dm_search_start并调用。

/* action function list */
const tBTA_DM_ACTION bta_dm_search_action[] =
{

bta_dm_search_start, /* 0 BTA_DM_API_SEARCH /
bta_dm_search_cancel, / 1 BTA_DM_API_SEARCH_CANCEL /
bta_dm_discover, / 2 BTA_DM_API_DISCOVER /
bta_dm_inq_cmpl, / 3 BTA_DM_INQUIRY_CMPL /
bta_dm_rmt_name, / 4 BTA_DM_REMT_NAME /
bta_dm_sdp_result, / 5 BTA_DM_SDP_RESULT /
bta_dm_search_cmpl, / 6 BTA_DM_SEARCH_CMPL /
bta_dm_free_sdp_db, / 7 BTA_DM_FREE_SDP_DB /
bta_dm_disc_result, / 8 BTA_DM_DISC_RESULT /
bta_dm_search_result, / 9 BTA_DM_SEARCH_RESULT /
bta_dm_queue_search, / 10 BTA_DM_QUEUE_SEARCH /
bta_dm_queue_disc, / 11 BTA_DM_QUEUE_DISC /
bta_dm_search_clear_queue, / 12 BTA_DM_SEARCH_CLEAR_QUEUE /
bta_dm_search_cancel_cmpl, / 13 BTA_DM_SEARCH_CANCEL_CMPL /
bta_dm_search_cancel_notify, / 14 BTA_DM_SEARCH_CANCEL_NOTIFY /
bta_dm_search_cancel_transac_cmpl, / 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL /
bta_dm_disc_rmt_name, / 16 BTA_DM_DISC_RMT_NAME /
bta_dm_di_disc / 17 BTA_DM_API_DI_DISCOVER */
#if BLE_INCLUDED == TRUE
,bta_dm_close_gatt_conn
#endif
};

BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg)
{
tBTA_DM_ST_TBL state_table;
UINT8 action;
int i;

<span class="token comment">/* look up the state table for the current state */</span>
state_table <span class="token operator">=</span> bta_dm_search_st_tbl<span class="token punctuation">[</span>bta_dm_search_cb<span class="token punctuation">.</span>state<span class="token punctuation">]</span><span class="token punctuation">;</span>
bta_dm_search_cb<span class="token punctuation">.</span>state <span class="token operator">=</span> state_table<span class="token punctuation">[</span>p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>event <span class="token operator">&amp;</span> <span class="token number">0x00ff</span><span class="token punctuation">]</span><span class="token punctuation">[</span>BTA_DM_SEARCH_NEXT_STATE<span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token comment">/* execute action functions */</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> BTA_DM_SEARCH_ACTIONS<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>action <span class="token operator">=</span> state_table<span class="token punctuation">[</span>p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>event <span class="token operator">&amp;</span> <span class="token number">0x00ff</span><span class="token punctuation">]</span><span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">!=</span> BTA_DM_SEARCH_IGNORE<span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token punctuation">(</span><span class="token operator">*</span>bta_dm_search_action<span class="token punctuation">[</span>action<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">(</span> <span class="token punctuation">(</span>tBTA_DM_MSG<span class="token operator">*</span><span class="token punctuation">)</span> p_msg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> TRUE<span class="token punctuation">;</span>

}

Bta_dm_act.c (external\bluetooth\bluedroid\bta\dm)

void bta_dm_search_start (tBTA_DM_MSG *p_data)
{
    result.status = BTM_StartInquiry(   (tBTM_INQ_PARMS*)&p_data->search.inq_params,
                        bta_dm_inq_results_cb,
                        (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb);
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Btm_inq.c (external\bluetooth\bluedroid\stack\btm)
BTM_StartInquiry函数的查询过程包括BLE和BR/EDR两种模式的查询,我们这里只关注BLE模式。p_inq->p_inq_results_cb是扫描回调指向bta_dm_inq_results_cb,扫描到广播后bta_dm_inq_results_cb将被调用。

tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb)
{
    /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
    p_inq->inqparms = *p_inqparms;
<span class="token comment">/* Initialize the inquiry variables */</span>
p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>state <span class="token operator">=</span> BTM_INQ_ACTIVE_STATE<span class="token punctuation">;</span>
p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>p_inq_cmpl_cb <span class="token operator">=</span> p_cmpl_cb<span class="token punctuation">;</span>
p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>p_inq_results_cb <span class="token operator">=</span> p_results_cb<span class="token punctuation">;</span>
p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>inq_cmpl_info<span class="token punctuation">.</span>num_resp <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>         <span class="token comment">/* Clear the results counter */</span>
p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>inq_active <span class="token operator">=</span> p_inqparms<span class="token operator">-</span><span class="token operator">&gt;</span>mode<span class="token punctuation">;</span>

#if BLE_INCLUDED == TRUE
/* start LE inquiry */
status = btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK), p_inqparms->duration)) != BTM_CMD_STARTED):

    <span class="token keyword">return</span> status<span class="token punctuation">;</span>

#endif
/* start br/edr inquiry */
if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type,
&p_inqparms->filter_cond)) != BTM_CMD_STARTED)
p_inq->state = BTM_INQ_INACTIVE_STATE;
}

Btm_ble_gap.c (external\bluetooth\bluedroid\stack\btm)

tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8   duration)
{
    if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
    {
        btm_update_scanner_filter_policy(SP_ADV_ALL);
        status = btm_ble_start_scan(BTM_BLE_DUPLICATE_DISABLE);
    }
<span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">==</span> BTM_CMD_STARTED<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>inq_active <span class="token operator">|</span><span class="token operator">=</span> mode<span class="token punctuation">;</span>
    p_ble_cb<span class="token operator">-</span><span class="token operator">&gt;</span>scan_activity <span class="token operator">|</span><span class="token operator">=</span> mode<span class="token punctuation">;</span>

    <span class="token function">BTM_TRACE_DEBUG</span><span class="token punctuation">(</span><span class="token string">"btm_ble_start_inquiry inq_active = 0x%02x"</span><span class="token punctuation">,</span> p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>inq_active<span class="token punctuation">)</span><span class="token punctuation">;</span>
	
    <span class="token keyword">if</span> <span class="token punctuation">(</span>duration <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token comment">/* 启动inquiry timer */</span>
        btu_start_timer <span class="token punctuation">(</span><span class="token operator">&amp;</span>p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>inq_timer_ent<span class="token punctuation">,</span> BTU_TTYPE_BLE_INQUIRY<span class="token punctuation">,</span> duration<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

btm_ble_start_inquiry主要做了三件事:
1)设置扫描参数: btm_update_scanner_filter_policy(SP_ADV_ALL)
2)启动扫描: btm_ble_start_scan(BTM_BLE_DUPLICATE_DISABLE);
3)启动扫描定时器,定时器超时后在btu_task中关闭扫描:
btu_start_timer (&p_inq->inq_timer_ent, BTU_TTYPE_BLE_INQUIRY, duration)

下面分别对这三件事进行跟踪:

1) 设置扫描参数

Btm_ble_bgconn.c (external\bluetooth\bluedroid\stack\btm)

void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy)
{
    p_inq->sfp = scan_policy;
    p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type;
btsnd_hcic_ble_set_scan_params <span class="token punctuation">(</span>p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>scan_type<span class="token punctuation">,</span>
                                <span class="token punctuation">(</span>UINT16<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token operator">!</span>p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>scan_interval <span class="token operator">?</span> BTM_BLE_GAP_DISC_SCAN_INT <span class="token operator">:</span> p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>scan_interval<span class="token punctuation">)</span><span class="token punctuation">,</span>
                                <span class="token punctuation">(</span>UINT16<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token operator">!</span>p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>scan_window <span class="token operator">?</span> BTM_BLE_GAP_DISC_SCAN_WIN <span class="token operator">:</span> p_inq<span class="token operator">-</span><span class="token operator">&gt;</span>scan_window<span class="token punctuation">)</span><span class="token punctuation">,</span>
                                 btm_cb<span class="token punctuation">.</span>ble_ctr_cb<span class="token punctuation">.</span>addr_mgnt_cb<span class="token punctuation">.</span>own_addr_type<span class="token punctuation">,</span>
                                 scan_policy<span class="token punctuation">)</span><span class="token punctuation">;</span>                             

}

Hciblecmds.c (external\bluetooth\bluedroid\stack\hcic)

BOOLEAN btsnd_hcic_ble_set_scan_params (UINT8 scan_type,
                                          UINT16 scan_int, UINT16 scan_win,
                                          UINT8 addr_type_own, UINT8 scan_filter_policy)
{
    BT_HDR *p;
    UINT8 *pp;
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>p <span class="token operator">=</span> <span class="token function">HCI_GET_CMD_BUF</span><span class="token punctuation">(</span>HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>FALSE<span class="token punctuation">)</span><span class="token punctuation">;</span>

pp <span class="token operator">=</span> <span class="token punctuation">(</span>UINT8 <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">(</span>p <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 指向 data[]</span>

p<span class="token operator">-</span><span class="token operator">&gt;</span>len    <span class="token operator">=</span> HCIC_PREAMBLE_SIZE <span class="token operator">+</span> HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM<span class="token punctuation">;</span>
p<span class="token operator">-</span><span class="token operator">&gt;</span>offset <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

UINT16_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> HCI_BLE_WRITE_SCAN_PARAMS<span class="token punctuation">)</span><span class="token punctuation">;</span>
UINT8_TO_STREAM  <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM<span class="token punctuation">)</span><span class="token punctuation">;</span>

UINT8_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> scan_type<span class="token punctuation">)</span><span class="token punctuation">;</span>
UINT16_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> scan_int<span class="token punctuation">)</span><span class="token punctuation">;</span>
UINT16_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> scan_win<span class="token punctuation">)</span><span class="token punctuation">;</span>
UINT8_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> addr_type_own<span class="token punctuation">)</span><span class="token punctuation">;</span>
UINT8_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> scan_filter_policy<span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token comment">/* 发送hci命令 */</span>
 btu_hcif_send_cmd <span class="token punctuation">(</span>LOCAL_BR_EDR_CONTROLLER_ID<span class="token punctuation">,</span>  p<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span><span class="token punctuation">;</span>

}

2) 启动扫描

Btm_ble_gap.c (external\bluetooth\bluedroid\stack\btm)

tBTM_STATUS btm_ble_start_scan (UINT8 filter_enable)
{
    tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
    tBTM_STATUS status = BTM_CMD_STARTED;
<span class="token comment">/* start scan, disable duplicate filtering */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>btsnd_hcic_ble_set_scan_enable <span class="token punctuation">(</span>BTM_BLE_SCAN_ENABLE<span class="token punctuation">,</span> filter_enable<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    status <span class="token operator">=</span> BTM_NO_RESOURCES<span class="token punctuation">;</span>
    btm_cb<span class="token punctuation">.</span>ble_ctr_cb<span class="token punctuation">.</span>wl_state <span class="token operator">&amp;</span><span class="token operator">=</span> <span class="token operator">~</span>BTM_BLE_WL_SCAN<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> status<span class="token punctuation">;</span>

}

Hciblecmds.c (external\bluetooth\bluedroid\stack\hcic)

BOOLEAN btsnd_hcic_ble_set_scan_enable (UINT8 scan_enable, UINT8 duplicate)
{
    BT_HDR *p;
    UINT8 *pp;
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>p <span class="token operator">=</span> <span class="token function">HCI_GET_CMD_BUF</span><span class="token punctuation">(</span>HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>FALSE<span class="token punctuation">)</span><span class="token punctuation">;</span>

pp <span class="token operator">=</span> <span class="token punctuation">(</span>UINT8 <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">(</span>p <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 指向 data[]</span>

p<span class="token operator">-</span><span class="token operator">&gt;</span>len    <span class="token operator">=</span> HCIC_PREAMBLE_SIZE <span class="token operator">+</span> HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE<span class="token punctuation">;</span>
p<span class="token operator">-</span><span class="token operator">&gt;</span>offset <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

UINT16_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> HCI_BLE_WRITE_SCAN_ENABLE<span class="token punctuation">)</span><span class="token punctuation">;</span>
UINT8_TO_STREAM  <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE<span class="token punctuation">)</span><span class="token punctuation">;</span>

UINT8_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> scan_enable<span class="token punctuation">)</span><span class="token punctuation">;</span>
UINT8_TO_STREAM <span class="token punctuation">(</span>pp<span class="token punctuation">,</span> duplicate<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/* 发送hci命令 */</span>
btu_hcif_send_cmd <span class="token punctuation">(</span>LOCAL_BR_EDR_CONTROLLER_ID<span class="token punctuation">,</span>  p<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span><span class="token punctuation">;</span>

}

3) 启动扫描定时器
void btu_start_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout)
{
    BT_HDR *p_msg;
    GKI_disable();
<span class="token comment">//如果btu定时器轮询停止,则重新启动计数轮询,轮询周期是1s</span>
<span class="token comment">/* if timer list is currently empty, start periodic GKI timer */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>btu_cb<span class="token punctuation">.</span>timer_queue<span class="token punctuation">.</span>p_first <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token comment">/* if timer starts on other than BTU task */</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">GKI_get_taskid</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> BTU_TASK<span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token comment">/* post event to start timer in BTU task */</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>p_msg <span class="token operator">=</span> <span class="token punctuation">(</span>BT_HDR <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">GKI_getbuf</span><span class="token punctuation">(</span>BT_HDR_SIZE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
        <span class="token punctuation">{<!-- --></span>
            p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>event <span class="token operator">=</span> BT_EVT_TO_START_TIMER<span class="token punctuation">;</span>
            GKI_send_msg <span class="token punctuation">(</span>BTU_TASK<span class="token punctuation">,</span> TASK_MBOX_0<span class="token punctuation">,</span> p_msg<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token comment">/* Start free running 1 second timer for list management */</span>
        GKI_start_timer <span class="token punctuation">(</span>TIMER_0<span class="token punctuation">,</span> GKI_SECS_TO_TICKS <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> TRUE<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

GKI_remove_from_timer_list <span class="token punctuation">(</span><span class="token operator">&amp;</span>btu_cb<span class="token punctuation">.</span>timer_queue<span class="token punctuation">,</span> p_tle<span class="token punctuation">)</span><span class="token punctuation">;</span>

p_tle<span class="token operator">-</span><span class="token operator">&gt;</span>event <span class="token operator">=</span> type<span class="token punctuation">;</span>
p_tle<span class="token operator">-</span><span class="token operator">&gt;</span>ticks <span class="token operator">=</span> timeout<span class="token punctuation">;</span>
p_tle<span class="token operator">-</span><span class="token operator">&gt;</span>ticks_initial <span class="token operator">=</span> timeout<span class="token punctuation">;</span>

<span class="token comment">//将定时器添加到GKI定时器列表</span>
GKI_add_to_timer_list <span class="token punctuation">(</span><span class="token operator">&amp;</span>btu_cb<span class="token punctuation">.</span>timer_queue<span class="token punctuation">,</span> p_tle<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">GKI_enable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

如果btu task的定时器队列为空,说明当前btu task的计时轮询已经停止,所以要启动btu task的计时轮询,轮询周期是1s。最后将定时器添加到GKI定时器列表。
那么定时器超时在哪里执行? 我们找到了GKI_init函数:
Gki_ulinux.c (external\bluetooth\bluedroid\gki\ulinux)
从下面的代码可以看出定时器到期执行函数为bt_alarm_cb:

void GKI_init(void)
{
    pthread_mutexattr_t attr;
    tGKI_OS             *p_os;
memset <span class="token punctuation">(</span><span class="token operator">&amp;</span>gki_cb<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span> <span class="token punctuation">(</span>gki_cb<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">gki_buffer_init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">gki_timers_init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">alarm_service_init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTicks <span class="token operator">=</span> <span class="token punctuation">(</span>UINT32<span class="token punctuation">)</span> <span class="token function">times</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">pthread_mutexattr_init</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>attr<span class="token punctuation">)</span><span class="token punctuation">;</span>
p_os <span class="token operator">=</span> <span class="token operator">&amp;</span>gki_cb<span class="token punctuation">.</span>os<span class="token punctuation">;</span>
<span class="token function">pthread_mutex_init</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>p_os<span class="token operator">-</span><span class="token operator">&gt;</span>GKI_mutex<span class="token punctuation">,</span> <span class="token operator">&amp;</span>attr<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">struct</span> sigevent sigevent<span class="token punctuation">;</span>
<span class="token function">memset</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>sigevent<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>sigevent<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
sigevent<span class="token punctuation">.</span>sigev_notify <span class="token operator">=</span> SIGEV_THREAD<span class="token punctuation">;</span>
sigevent<span class="token punctuation">.</span>sigev_notify_function <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">union</span> sigval<span class="token punctuation">)</span><span class="token punctuation">)</span>bt_alarm_cb<span class="token punctuation">;</span>
sigevent<span class="token punctuation">.</span>sigev_value<span class="token punctuation">.</span>sival_ptr <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">timer_create</span><span class="token punctuation">(</span>CLOCK_REALTIME<span class="token punctuation">,</span> <span class="token operator">&amp;</span>sigevent<span class="token punctuation">,</span> <span class="token operator">&amp;</span>posix_timer<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token function">ALOGE</span><span class="token punctuation">(</span><span class="token string">"%s unable to create POSIX timer: %s"</span><span class="token punctuation">,</span> <span class="token constant">__func__</span><span class="token punctuation">,</span> <span class="token function">strerror</span><span class="token punctuation">(</span>errno<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    timer_created <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
    timer_created <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

/** Callback from Java thread after alarm from AlarmService fires. /
static void bt_alarm_cb(void data)
{
GKI_timer_update(ticks_taken > alarm_service.ticks_scheduled
? ticks_taken : alarm_service.ticks_scheduled);
}

Gki_time.c (external\bluetooth\bluedroid\gki\common) 25288 2017/12/14

void GKI_timer_update (INT32 ticks_since_last_update)
{
    UINT8   task_id;
    long    next_expiration; 
gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTicks <span class="token operator">+</span><span class="token operator">=</span> ticks_since_last_update<span class="token punctuation">;</span>
gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTicksTilExp <span class="token operator">-</span><span class="token operator">=</span> ticks_since_last_update<span class="token punctuation">;</span>

<span class="token comment">/* Don't allow timer interrupt nesting */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>timer_nesting<span class="token punctuation">)</span>
    <span class="token keyword">return</span><span class="token punctuation">;</span>

gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>timer_nesting <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
next_expiration <span class="token operator">=</span> GKI_NO_NEW_TMRS_STARTED<span class="token punctuation">;</span>
gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSNumOrigTicks <span class="token operator">-</span><span class="token operator">=</span> gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTicksTilExp<span class="token punctuation">;</span>
<span class="token function">GKI_disable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/* Check for OS Task Timers */</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>task_id <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> task_id <span class="token operator">&lt;</span> GKI_MAX_TASKS<span class="token punctuation">;</span> task_id<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSWaitTmr<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment">/* If timer is running */</span>
    <span class="token punctuation">{<!-- --></span>
        gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSWaitTmr<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span> <span class="token operator">-</span><span class="token operator">=</span> gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSNumOrigTicks<span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSWaitTmr<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span> <span class="token operator">&lt;=</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token punctuation">{<!-- --></span>
            <span class="token comment">/* Timer Expired */</span>
            gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSRdyTbl<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span> <span class="token operator">=</span> TASK_READY<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

#if (GKI_NUM_TIMERS > 0)
/* If any timer is running, decrement */
if (gki_cb.com.OSTaskTmr0[task_id] > 0)
{
gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks;

        <span class="token keyword">if</span> <span class="token punctuation">(</span>gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTaskTmr0<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span> <span class="token operator">&lt;=</span> <span class="token number">0</span><span class="token punctuation">)</span>
        <span class="token punctuation">{<!-- --></span>
            <span class="token comment">/* Reload timer and set Timer 0 Expired event mask */</span>
            gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTaskTmr0<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span> <span class="token operator">=</span> gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTaskTmr0R<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span><span class="token punctuation">;</span>
            GKI_send_event <span class="token punctuation">(</span>task_id<span class="token punctuation">,</span> TIMER_0_EVT_MASK<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/* Check to see if this timer is the next one to expire */</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTaskTmr0<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span> <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTaskTmr0<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span> <span class="token operator">&lt;</span> next_expiration<span class="token punctuation">)</span>
        next_expiration <span class="token operator">=</span> gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>OSTaskTmr0<span class="token punctuation">[</span>task_id<span class="token punctuation">]</span><span class="token punctuation">;</span>

#endif
// 此处省略TIMER_1,TIMER_2,TIMER_3相关处理
}
/* Set the next timer experation value if there is one to start */
if (next_expiration < GKI_NO_NEW_TMRS_STARTED)
{
gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = next_expiration;
}
else
{
gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = 0;
}

<span class="token comment">// Set alarm service for next alarm.</span>
<span class="token function">alarm_service_reschedule</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">GKI_enable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gki_cb<span class="token punctuation">.</span>com<span class="token punctuation">.</span>timer_nesting <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>

}

如果OSTaskTmr小于0,表示定时器已经超时,这里调用GKI_send_event发送了一个event出去。

Btu_task.c (external\bluetooth\bluedroid\stack\btu)

BTU_API UINT32 btu_task (UINT32 param)
{
    /* Wait for, and process, events */
    for (;;)
    {
        event = GKI_wait (0xFFFF, 0);
    <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">&amp;</span> TIMER_0_EVT_MASK<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        GKI_update_timer_list <span class="token punctuation">(</span><span class="token operator">&amp;</span>btu_cb<span class="token punctuation">.</span>timer_queue<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">GKI_timer_queue_is_empty</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>btu_cb<span class="token punctuation">.</span>timer_queue<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            TIMER_LIST_ENT <span class="token operator">*</span>p_tle <span class="token operator">=</span> <span class="token function">GKI_timer_getfirst</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>btu_cb<span class="token punctuation">.</span>timer_queue<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>p_tle<span class="token operator">-</span><span class="token operator">&gt;</span>ticks <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>

            <span class="token function">GKI_remove_from_timer_list</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>btu_cb<span class="token punctuation">.</span>timer_queue<span class="token punctuation">,</span> p_tle<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">switch</span> <span class="token punctuation">(</span>p_tle<span class="token operator">-</span><span class="token operator">&gt;</span>event<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>

#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
case BTU_TTYPE_BLE_INQUIRY:
case BTU_TTYPE_BLE_GAP_LIM_DISC:
case BTU_TTYPE_BLE_GAP_FAST_ADV:
case BTU_TTYPE_BLE_OBSERVE:
btm_ble_timeout(p_tle);
break;

                <span class="token keyword">case</span> BTU_TTYPE_ATT_WAIT_FOR_RSP<span class="token operator">:</span>
                    <span class="token function">gatt_rsp_timeout</span><span class="token punctuation">(</span>p_tle<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
if (event & TIMER_2_EVT_MASK)
{
btu_process_quick_timer_evt();
}
#endif

#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
if (event & TIMER_1_EVT_MASK)
{
bta_sys_timer_update();
}
#endif

    <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">&amp;</span> TIMER_3_EVT_MASK<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token function">BTM_TRACE_API</span><span class="token punctuation">(</span><span class="token string">"Received oneshot timer event complete"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

启动扫描的定时器event类型是BTU_TTYPE_BLE_INQUIRY,btm_ble_timeout被调用,最终调用btm_ble_stop_scan停止扫描。
Btm_ble_gap.c (external\bluetooth\bluedroid\stack\btm)

void btm_ble_timeout(TIMER_LIST_ENT *p_tle)
{
    switch (p_tle->event)
    {
            case BTU_TTYPE_BLE_INQUIRY:
            btm_ble_stop_inquiry();
            	btm_ble_stop_scan(); // 停止扫描
            break;
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

至此启动扫描的三件事都已跟踪完成,现在我们继续分析。
设置扫描参数和启动扫描最后都是调用btu_hcif_send_cmd发送hci命令,
下面我们就对这个函数进行跟踪。
Btu_hcif.c (external\bluetooth\bluedroid\stack\btu)

/*******************************************************************************
**
** Function         btu_hcif_send_cmd
**
** Description      This function is called to check if it can send commands
**                  to the Host Controller. It may be passed the address of
**                  a packet to send.
**
** Returns          void
**
*******************************************************************************/
void btu_hcif_send_cmd (UINT8 controller_id, BT_HDR *p_buf)
{
    tHCI_CMD_CB * p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]);
<span class="token comment">/* If there are already commands in the queue, then enqueue this command */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>p_buf<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_xmit_q<span class="token punctuation">.</span>count<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    GKI_enqueue <span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token punctuation">(</span>p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_xmit_q<span class="token punctuation">)</span><span class="token punctuation">,</span> p_buf<span class="token punctuation">)</span><span class="token punctuation">;</span>
    p_buf <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Allow for startup case, where no acks may be received */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>controller_id <span class="token operator">==</span> LOCAL_BR_EDR_CONTROLLER_ID<span class="token punctuation">)</span>
     <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_window <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
     <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>btm_cb<span class="token punctuation">.</span>devcb<span class="token punctuation">.</span>state <span class="token operator">==</span> BTM_DEV_STATE_WAIT_RESET_CMPLT<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_window <span class="token operator">=</span> p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_xmit_q<span class="token punctuation">.</span>count <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* See if we can send anything */</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_window <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>p_buf<span class="token punctuation">)</span>
        p_buf <span class="token operator">=</span> <span class="token punctuation">(</span>BT_HDR <span class="token operator">*</span><span class="token punctuation">)</span>GKI_dequeue <span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token punctuation">(</span>p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_xmit_q<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>p_buf<span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token function">btu_hcif_store_cmd</span><span class="token punctuation">(</span>controller_id<span class="token punctuation">,</span> p_buf<span class="token punctuation">)</span><span class="token punctuation">;</span>
        p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_window<span class="token operator">--</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>controller_id <span class="token operator">==</span> LOCAL_BR_EDR_CONTROLLER_ID<span class="token punctuation">)</span>
        <span class="token punctuation">{<!-- --></span>
            <span class="token function">HCI_CMD_TO_LOWER</span><span class="token punctuation">(</span>p_buf<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span>
        <span class="token punctuation">{<!-- --></span>
            <span class="token function">GKI_freebuf</span><span class="token punctuation">(</span>p_buf<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        p_buf <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>p_buf<span class="token punctuation">)</span>
    GKI_enqueue <span class="token punctuation">(</span><span class="token operator">&amp;</span><span class="token punctuation">(</span>p_hci_cmd_cb<span class="token operator">-</span><span class="token operator">&gt;</span>cmd_xmit_q<span class="token punctuation">)</span><span class="token punctuation">,</span> p_buf<span class="token punctuation">)</span><span class="token punctuation">;</span>

}

查看HCI_CMD_TO_LOWER定义:

/* Sends an HCI command received from the upper stack to the BD/EDR HCI transport. */
#ifndef HCI_CMD_TO_LOWER
#define HCI_CMD_TO_LOWER(p)         bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_HCI_CMD);
#endif

 
 
  • 1
  • 2
  • 3
  • 4

Bte_main.c (external\bluetooth\bluedroid\main)

void bte_main_hci_send (BT_HDR *p_msg, UINT16 event)
{
    UINT16 sub_event = event & BT_SUB_EVT_MASK;  /* local controller ID */
p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>event <span class="token operator">=</span> event<span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token punctuation">(</span>sub_event <span class="token operator">==</span> LOCAL_BR_EDR_CONTROLLER_ID<span class="token punctuation">)</span> <span class="token operator">||</span> \
   <span class="token punctuation">(</span>sub_event <span class="token operator">==</span> LOCAL_BLE_CONTROLLER_ID<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>bt_hc_if<span class="token punctuation">)</span>
        bt_hc_if<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">transmit_buf</span><span class="token punctuation">(</span><span class="token punctuation">(</span>TRANSAC<span class="token punctuation">)</span>p_msg<span class="token punctuation">,</span> \
                                   <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span> <span class="token punctuation">(</span>p_msg <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> \
                                    p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>len<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">else</span>
        <span class="token function">GKI_freebuf</span><span class="token punctuation">(</span>p_msg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

查看bt_hc_if的赋值:

static void bte_main_in_hw_init(void)
{
	// bt_hci_bdroid.c中的 bluetoothHCLibInterface
    if ( (bt_hc_if = (bt_hc_interface_t *) bt_hc_get_interface()) \
         == NULL)
    {
        APPL_TRACE_ERROR("!!! Failed to get BtHostControllerInterface !!!");
    }
<span class="token function">memset</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>preload_retry_cb<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>bt_preload_retry_cb_t<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

Bt_hci_bdroid.c (external/bluetooth/bluedroid/hci/src)

void bthc_tx(HC_BT_HDR *buf) {
  pthread_mutex_lock(&hc_cb.worker_thread_lock);
  if (hc_cb.worker_thread) {
    if (buf)
      utils_enqueue(&tx_q, buf); // 将buf放入队列tx_q,给到event_tx处理
    // 构造一个work_item_t并放入thread->work_queue,
    // worker_thread的线程处理函数run_thread会从thread->work_queue中取出这个item,
    // 并调用回调函数event_tx
    thread_post(hc_cb.worker_thread, event_tx, NULL); 
  }

pthread_mutex_unlock(&hc_cb.worker_thread_lock);
}
/** Transmit frame /
static int transmit_buf(TRANSAC transac, UNUSED_ATTR char p_buf, UNUSED_ATTR int len) {
bthc_tx((HC_BT_HDR *)transac);
return BT_HC_STATUS_SUCCESS;
}

static const bt_hc_interface_t bluetoothHCLibInterface = {
sizeof(bt_hc_interface_t),
init,
set_power,
lpm,
preload,
postload,
transmit_buf,
logging,
cleanup,
tx_hc_cmd,
};

const bt_hc_interface_t *bt_hc_get_interface(void)
{
return &bluetoothHCLibInterface;
}

下面主要看下实际的发送函数event_tx:
event_tx里面有个while循环,通过utils_getnext从tx_q获取所有消息并保存到sending_msg_que,消息的个数为sending_msg_count。消息取完后跳出while,使用一个for循环取出所有要发送的消息并调用 p_hci_if->send发送出去。
注意: 如果我们已用完控制器的未用HCI命令信用(通常为1),则跳过队列中的所有HCI命令数据包。

static void event_tx(UNUSED_ATTR void *context) {
  /*
   *  We will go through every packets in the tx queue.
   *  Fine to clear tx_cmd_pkts_pending.
   */
  tx_cmd_pkts_pending = false;
  HC_BT_HDR *sending_msg_que[64];
  size_t sending_msg_count = 0;
  int sending_hci_cmd_pkts_count = 0;
  utils_lock();
  HC_BT_HDR *p_next_msg = tx_q.p_first;
  while (p_next_msg && sending_msg_count < ARRAY_SIZE(sending_msg_que))
  {
  	// 注意: 如果我们已用完控制器的未用HCI命令信用(通常为1),
  	// 则跳过队列中的所有HCI命令数据包。
    if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
    {
      if (tx_cmd_pkts_pending ||
          (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts))
      {
        tx_cmd_pkts_pending = true;
        p_next_msg = utils_getnext(p_next_msg); // 取出消息
        continue;
      }
      sending_hci_cmd_pkts_count++; //增加消息计数sending_msg_count
    }
HC_BT_HDR <span class="token operator">*</span>p_msg <span class="token operator">=</span> p_next_msg<span class="token punctuation">;</span>
p_next_msg <span class="token operator">=</span> <span class="token function">utils_getnext</span><span class="token punctuation">(</span>p_msg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 取出消息</span>
<span class="token function">utils_remove_from_queue_unlocked</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>tx_q<span class="token punctuation">,</span> p_msg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//把消息放入sending_msg_que,并增加消息计数sending_msg_count</span>
sending_msg_que<span class="token punctuation">[</span>sending_msg_count<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> p_msg<span class="token punctuation">;</span> 

}
utils_unlock();
for(size_t i = 0; i < sending_msg_count; i++)
p_hci_if->send(sending_msg_que[i]);
if (tx_cmd_pkts_pending)
BTHCDBG(“Used up Tx Cmd credits”);
}

p_hci_if在init函数中被赋值:

static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
	extern tHCI_IF hci_mct_func_table;
	p_hci_if = &hci_h4_func_table

 
 
  • 1
  • 2
  • 3

Hci_h4.c (external\bluetooth\bluedroid\hci\src)

/******************************************************************************
**  HCI H4 Services interface table
******************************************************************************/
const tHCI_IF hci_h4_func_table =
{
    hci_h4_init,
    hci_h4_cleanup,
    hci_h4_send_msg,
    hci_h4_send_int_cmd,
    hci_h4_get_acl_data_length,
    hci_h4_receive_msg
};

/*******************************************************************************
** Function hci_h4_send_msg
** Description Determine message type, set HCI H4 packet indicator, and
** send message through USERIAL driver
****************************************************************************/
void hci_h4_send_msg(HC_BT_HDR p_msg)
{
uint8_t type = 0;
uint16_t handle;
uint16_t bytes_to_send, lay_spec;
uint8_t p = ((uint8_t )(p_msg + 1)) + p_msg->offset;
uint16_t event = p_msg->event & MSG_EVT_MASK;//event类型
uint16_t sub_event = p_msg->event & MSG_SUB_EVT_MASK; // sub_event类型
uint16_t acl_pkt_size = 0, acl_data_size = 0;
uint16_t bytes_sent;

<span class="token comment">/* wake up BT device if its in sleep mode */</span>
<span class="token function">lpm_wake_assert</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">==</span> MSG_STACK_TO_HC_HCI_ACL<span class="token punctuation">)</span>
    type <span class="token operator">=</span> H4_TYPE_ACL_DATA<span class="token punctuation">;</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">==</span> MSG_STACK_TO_HC_HCI_SCO<span class="token punctuation">)</span>
    type <span class="token operator">=</span> H4_TYPE_SCO_DATA<span class="token punctuation">;</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event <span class="token operator">==</span> MSG_STACK_TO_HC_HCI_CMD<span class="token punctuation">)</span>
    type <span class="token operator">=</span> H4_TYPE_COMMAND<span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>sub_event <span class="token operator">==</span> LOCAL_BR_EDR_CONTROLLER_ID<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    acl_data_size <span class="token operator">=</span> h4_cb<span class="token punctuation">.</span>hc_acl_data_size<span class="token punctuation">;</span>
    acl_pkt_size <span class="token operator">=</span> h4_cb<span class="token punctuation">.</span>hc_acl_data_size <span class="token operator">+</span> HCI_ACL_PREAMBLE_SIZE<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
<span class="token punctuation">{<!-- --></span>
    acl_data_size <span class="token operator">=</span> h4_cb<span class="token punctuation">.</span>hc_ble_acl_data_size<span class="token punctuation">;</span>
    acl_pkt_size <span class="token operator">=</span> h4_cb<span class="token punctuation">.</span>hc_ble_acl_data_size <span class="token operator">+</span> HCI_ACL_PREAMBLE_SIZE<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

  <span class="token comment">/* Do all the first chunks */</span>
  <span class="token keyword">while</span> <span class="token punctuation">(</span>p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>len <span class="token operator">&gt;</span> acl_pkt_size<span class="token punctuation">)</span>
  <span class="token punctuation">{<!-- --></span> 
    <span class="token comment">/* Check if sending ACL data that needs fragmenting */</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>event <span class="token operator">==</span> MSG_STACK_TO_HC_HCI_ACL<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>len <span class="token operator">&gt;</span> acl_pkt_size<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
            bytes_to_send <span class="token operator">=</span> acl_pkt_size <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> 
            <span class="token comment">/* 通过uart发送命令/数据 */</span>
            bytes_sent <span class="token operator">=</span> <span class="token function">userial_write</span><span class="token punctuation">(</span>event<span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token keyword">uint8_t</span> <span class="token operator">*</span><span class="token punctuation">)</span> p<span class="token punctuation">,</span>bytes_to_send<span class="token punctuation">)</span><span class="token punctuation">;</span>
            	<span class="token function">write</span><span class="token punctuation">(</span>userial_cb<span class="token punctuation">.</span>fd<span class="token punctuation">,</span> p_data <span class="token operator">+</span> total<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">/* 生成btsnoop追踪消息 */</span>
            <span class="token function">btsnoop_capture</span><span class="token punctuation">(</span>p_msg<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
p <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">uint8_t</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">(</span>p_msg <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>offset <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token operator">*</span>p <span class="token operator">=</span> type<span class="token punctuation">;</span>
bytes_to_send <span class="token operator">=</span> p_msg<span class="token operator">-</span><span class="token operator">&gt;</span>len <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> 
<span class="token comment">/* 通过uart发送命令/数据 */</span>
bytes_sent <span class="token operator">=</span> <span class="token function">userial_write</span><span class="token punctuation">(</span>event<span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token keyword">uint8_t</span> <span class="token operator">*</span><span class="token punctuation">)</span> p<span class="token punctuation">,</span> bytes_to_send<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">write</span><span class="token punctuation">(</span>userial_cb<span class="token punctuation">.</span>fd<span class="token punctuation">,</span> p_data <span class="token operator">+</span> total<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/* 生成btsnoop追踪消息 */</span>
<span class="token function">btsnoop_capture</span><span class="token punctuation">(</span>p_msg<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>bt_hc_cbacks<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
	<span class="token comment">// 回调bte_main.c中的hc_cbacks-&gt;tx_result</span>
    bt_hc_cbacks<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">tx_result</span><span class="token punctuation">(</span><span class="token punctuation">(</span>TRANSAC<span class="token punctuation">)</span> p_msg<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span> <span class="token punctuation">(</span>p_msg <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> \
                                BT_HC_TX_SUCCESS<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span><span class="token punctuation">;</span>

}

hci_h4_send_msg主要以下工作:
1)根据消息的event得到event和sub_event
2)根据event得到hci类型,根据sub_event得到acl_data_size和acl_packet_size
3)通过uart发送消息
4)生成btsnoop追踪数据
5)回调uart写成功状态,实际命令发送状态由userial_read_thread来完成。

Userial.c (external\bluetooth\bluedroid\hci\src)

uint16_t userial_write(uint16_t msg_id, const uint8_t *p_data, uint16_t len) {
    UNUSED(msg_id);
    uint16_t total = 0;
    while (len) {
        ssize_t ret = write(userial_cb.fd, p_data + total, len);
        switch (ret) {
            case -1:
                ALOGE("%s error writing to serial port: %s", __func__, strerror(errno));
                return total;
            case 0:  // don't loop forever in case write returns 0.
                return total;
            default:
                total += ret;
                len -= ret;
                break;
        }
    	send_byte_total+=total;    
    }
<span class="token keyword">return</span> total<span class="token punctuation">;</span>

}

查看userial_cb.fd的赋值:

bool userial_open(userial_port_t port) {
    // Call in to the vendor-specific library to open the serial port.
    int fd_array[CH_MAX];
    int num_ports = vendor_send_command(BT_VND_OP_USERIAL_OPEN, &fd_array);
    userial_cb.fd = fd_array[0];
    userial_cb.port = port;
    if (pthread_create(&userial_cb.read_thread, NULL, userial_read_thread, NULL)) {
        ALOGE("%s unable to spawn read thread.", __func__);
        goto error;
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Vendor.c (external\bluetooth\bluedroid\hci\src)

int vendor_send_command(bt_vendor_opcode_t opcode, void *param) {
  return vendor_interface->op(opcode, param);
}

 
 
  • 1
  • 2
  • 3
VENDOR_LIBRARY_NAME = "libbt-vendor.so";
vendor_open(const uint8_t *local_bdaddr) 
    lib_handle = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
    vendor_interface = (bt_vendor_interface_t *)dlsym(lib_handle, VENDOR_LIBRARY_SYMBOL_NAME);

 
 
  • 1
  • 2
  • 3
  • 4

dlsym根据动态链接库操作句柄与符号,返回符号对应的地址。
可以得到vendor_interface的实现代码在libbt-vendor.so这个动态链接库中。

Bt_vendor_brcm.c (hardware\broadcom\libbt\src)
全局抓取一下libbt-vendor.so,我们在hardware\broadcom\libbt下的Android.mk中找到了libbt-vendor.so的包含的源文件。
抓取一下bt_vendor_interface_t,发现在Bt_vendor_brcm.c找到了它的实现:

// Entry point of DLib
const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
    sizeof(bt_vendor_interface_t),
    init,
    op,
    	     case BT_VND_OP_USERIAL_OPEN:
                int (*fd_array)[] = (int (*)[]) param;
                int fd, idx;
                fd = userial_vendor_open((tUSERIAL_CFG *) &userial_init_cfg);
                	/* Device port name where Bluetooth controller attached */
					#ifndef BLUETOOTH_UART_DEVICE_PORT // bt_vendor_brcm.h
					#define BLUETOOTH_UART_DEVICE_PORT   "/dev/ttyO1"  // maguro 
					#endif
                	// void userial_vendor_init中赋值:
    				// 		snprintf(vnd_userial.port_name, VND_PORT_NAME_MAXLEN, "%s", BLUETOOTH_UART_DEVICE_PORT);
                	vnd_userial.fd = open(vnd_userial.port_name, O_RDWR);//userial_vendor.c
                	return vnd_userial.fd;
                if (fd != -1)
                {
                    for (idx=0; idx < CH_MAX; idx++)
                        (*fd_array)[idx] = fd;
                retval <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
cleanup

};

再回到hci_h4_send_msg查看bt_hc_cbacks的赋值:
Bt_hci_bdroid.c (external\bluetooth\bluedroid\hci\src)

static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
    /* store reference to user callbacks */
    bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb;

static const bt_hc_interface_t bluetoothHCLibInterface = {
sizeof(bt_hc_interface_t),
init,
set_power,
lpm,
preload,
postload,
transmit_buf,
logging,
cleanup,
tx_hc_cmd,
};

bluetoothHCLibInterface的init函数在蓝牙enable的时候被调用:

Bte_main.c (external\bluetooth\bluedroid\main)

bt_hc_callbacks_t *bt_hc_cbacks = NULL;
static const bt_hc_callbacks_t hc_callbacks = {
    sizeof(bt_hc_callbacks_t),
    preload_cb,
    postload_cb,
    lpm_cb,
    hostwake_ind,
    alloc,
    dealloc,
    data_ind,
    tx_result
};

static void bte_main_in_hw_init(void)
{
bt_hc_if = (bt_hc_interface_t *) bt_hc_get_interface() // Bt_hci_bdroid.c
return &bluetoothHCLibInterface;
}

bte_main_enable
bte_hci_enable
//调用bluetoothHCLibInterface的init函数,将bt_hc_cbacks赋值为hc_callbacks
int result = bt_hc_if->init(&hc_callbacks, btif_local_bd_addr.address);
bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb; // Bt_hci_bdroid.c

最终将bt_hc_cbacks赋值为hc_callbacks。

二、APK scan

apk scan发生在蓝牙打开以后,分为经典蓝牙扫描和BLE扫描。
1)经典蓝牙扫描

private BluetoothAdapter mBluetoothAdapter;

// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();

// 启动扫描
mBluetoothAdapter.startDiscovery();

剩下的内容和settings里面开启扫描流程相同。
扫描到的设备在JniCallbacks.java的deviceFoundCallback方法通过广播发送出来。
JniCallbacks.java (packages\apps\bluetooth\src\com\android\bluetooth\btservice)

void deviceFoundCallback(byte[] address) 
    mRemoteDevices.deviceFoundCallback(address);
        // The device properties are already registered - we can send the intent
        BluetoothDevice device = getDevice(address); // RemoteDevices.java
        DeviceProperties deviceProp = getDeviceProperties(device);
        Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothDevice.EXTRA_CLASS,
                new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass)));
        intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
        intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
        mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

应用广播接收代码:

       // Broadcast Register
       private SingBroadcastReceiver mReceiver;
       mReceiver = new SingBroadcastReceiver();
       IntentFilter intentFilter = new IntentFilter();
       intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
       intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
       intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
       registerReceiver(mReceiver, intentFilter);
   <span class="token comment">// Broadcast Receiver</span>
   <span class="token keyword">class</span> <span class="token class-name">SingBroadcastReceiver</span> <span class="token keyword">extends</span> <span class="token class-name">BroadcastReceiver</span> <span class="token punctuation">{<!-- --></span>
       <span class="token annotation punctuation">@Override</span>
       <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onReceive</span><span class="token punctuation">(</span>Context context<span class="token punctuation">,</span> Intent intent<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
           String action <span class="token operator">=</span> intent<span class="token punctuation">.</span><span class="token function">getAction</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
           <span class="token keyword">if</span> <span class="token punctuation">(</span>BluetoothDevice<span class="token punctuation">.</span>ACTION_FOUND<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>action<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
               BluetoothDevice device <span class="token operator">=</span> intent<span class="token punctuation">.</span><span class="token function">getParcelableExtra</span><span class="token punctuation">(</span>BluetoothDevice<span class="token punctuation">.</span>EXTRA_DEVICE<span class="token punctuation">)</span><span class="token punctuation">;</span>
               Log<span class="token punctuation">.</span><span class="token function">i</span><span class="token punctuation">(</span><span class="token string">"MainActivity"</span><span class="token punctuation">,</span> <span class="token string">""</span> <span class="token operator">+</span> device<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" "</span> <span class="token operator">+</span> device<span class="token punctuation">.</span><span class="token function">getAddress</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
           <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>BluetoothDevice<span class="token punctuation">.</span>ACTION_DISCOVERY_STARTED<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>action<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
               Log<span class="token punctuation">.</span><span class="token function">i</span><span class="token punctuation">(</span><span class="token string">"MainActivity"</span><span class="token punctuation">,</span> <span class="token string">"Discovery started."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
           <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>BluetoothDevice<span class="token punctuation">.</span>ACTION_DISCOVERY_FINISHED<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>action<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> 
               Log<span class="token punctuation">.</span><span class="token function">i</span><span class="token punctuation">(</span><span class="token string">"MainActivity"</span><span class="token punctuation">,</span> <span class="token string">"Discovery finished."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
           <span class="token punctuation">}</span>
       <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>

2)BLE扫描

private BluetoothAdapter mBluetoothAdapter;

// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();

BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
Log.i(TAG, "mLeScanCallback device: " + device.getName() + " "+ device.getAddress());
}
};

// 启动扫描
mBluetoothAdapter.startLeScan(mLeScanCallback);

BluetoothAdapter.java (frameworks\base\core\java\android\bluetooth)

    /**
     * Starts a scan for Bluetooth LE devices.
     * @param callback the callback LE scan results are delivered
     */
    @Deprecated
    public boolean startLeScan(LeScanCallback callback) {
        return startLeScan(null, callback);
    }
<span class="token comment">/**
 * Starts a scan for Bluetooth LE devices, looking for devices that
 * advertise given services.
 * @param serviceUuids Array of services to look for
 * @param callback the callback LE scan results are delivered
 */</span>
<span class="token annotation punctuation">@Deprecated</span>
<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">startLeScan</span><span class="token punctuation">(</span><span class="token keyword">final</span> UUID<span class="token punctuation">[</span><span class="token punctuation">]</span> serviceUuids<span class="token punctuation">,</span> <span class="token keyword">final</span> LeScanCallback callback<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>DBG<span class="token punctuation">)</span> Log<span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"startLeScan(): "</span> <span class="token operator">+</span> serviceUuids<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>callback <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>DBG<span class="token punctuation">)</span> Log<span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"startLeScan: null callback"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 获得一个BluetoothLeScanner 对象</span>
    BluetoothLeScanner scanner <span class="token operator">=</span> <span class="token function">getBluetoothLeScanner</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>scanner <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>DBG<span class="token punctuation">)</span> Log<span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"startLeScan: cannot get BluetoothLeScanner"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
	<span class="token comment">// 判断mLeScanClients里面是否已有当前扫描的callback,有则表示扫描已开始</span>
    <span class="token keyword">synchronized</span><span class="token punctuation">(</span>mLeScanClients<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mLeScanClients<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>callback<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>DBG<span class="token punctuation">)</span> Log<span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"LE Scan has already started"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
       		<span class="token comment">//获取BluetoothGatt Binder类的实例,该类的定义在GattService.java中</span>
       		 <span class="token comment">//GattService内部类private static class BluetoothGattBinder extends IBluetoothGatt.Stub</span>
            IBluetoothGatt iGatt <span class="token operator">=</span> mManagerService<span class="token punctuation">.</span><span class="token function">getBluetoothGatt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>iGatt <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                <span class="token comment">// BLE is not supported</span>
                <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
			<span class="token comment">// 扫描回调</span>
            ScanCallback scanCallback <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ScanCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                <span class="token annotation punctuation">@Override</span>
                <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onScanResult</span><span class="token punctuation">(</span><span class="token keyword">int</span> callbackType<span class="token punctuation">,</span> ScanResult result<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>

标签:gt,scan,cb,Bluetooth,bta,msg,Android,bluetooth,event
来源: https://blog.csdn.net/mingchong2005/article/details/121615594