BLE scan 在bluedroid的實現中,有兩個接口:一個是discovery,一個是ble observe,這兩者有什么區別呢?
這里追了一下代碼發現,inquiry 是上層調用search 相關的接口的實現函數,ble observe 是調用GATT scan的接口的實現函數,這篇文章分析一下,在調用GATT 接口實現scan的流程。
GATT的服務代碼邏輯在哪里實現的呢?其核心代碼的實現是bluedroid里面,但是,上層的應用是不可能直接調用協議棧的代碼的,其實在bluedroid上面還會進行封裝一個GATT的服務,其實現在package/app/Bluetooth下面的GattService.java,這里面實現了關於GATT相關的各種接口,應用層的代碼通過binder 調用綁定到這些接口,並完成一系列的調用。
看一下GattService.java的實現:
/** * Handlers for incoming service calls */ private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder { private GattService mService; public BluetoothGattBinder(GattService svc) { mService = svc; } public boolean cleanup() { mService = null; return true; } ... @Override public void startScan(int appIf, boolean isServer, ScanSettings settings, List<ScanFilter> filters, List storages, String callingPackage) { GattService service = getService(); if (service == null) return; service.startScan(appIf, isServer, settings, filters, storages, callingPackage); } public void stopScan(int appIf, boolean isServer) { GattService service = getService(); if (service == null) return; service.stopScan(new ScanClient(appIf, isServer)); } ... }
可以看到其代碼中實現了一個BluetoothGattBinder,這個上層應用程序在綁定完成的時候,會得到這個binder接口。我們也可以看到,這個binder實現的也是GATT相關的基本的接口。
分析一下startScan接口,發現其是調用到另一個service 的startScan的接口,那這個service 是哪里來的呢?其實這個service就是GATTService本身,在initBinder的時候,將this 指針傳入。
protected IProfileServiceBinder initBinder() { return new BluetoothGattBinder(this); }
我們的重點是分析startScan 這個接口的流程,現在我們看GATTService是如何實現這個接口的
void startScan(int appIf, boolean isServer, ScanSettings settings, List<ScanFilter> filters, List<List<ResultStorageDescriptor>> storages, String callingPackage) { ... final ScanClient scanClient = new ScanClient(appIf, isServer, settings, filters, storages);
... mScanManager.startScan(scanClient); }
新建了一個scanClient 類,並將此類傳入到mScanManager.startScan中:
void startScan(ScanClient client) { sendMessage(MSG_START_BLE_SCAN, client); }
此時的代碼走到了ScanManager.java里面,不管上層的代碼如何流轉,我們知道,最后肯定還是調用到JNI 的接口,然后到達bluedroid里面,接着看:
// Handler class that handles BLE scan operations. private class ClientHandler extends Handler { ... @Override public void handleMessage(Message msg) { ScanClient client = (ScanClient) msg.obj; switch (msg.what) { case MSG_START_BLE_SCAN://處理事件 handleStartScan(client); break; case MSG_STOP_BLE_SCAN: handleStopScan(client); break; ... } } void handleStartScan(ScanClient client) {//處理scan的實現函數 Utils.enforceAdminPermission(mService);... // Begin scan operations. if (isBatchClient(client)) { mBatchClients.add(client); mScanNative.startBatchScan(client); } else { mRegularScanClients.add(client); mScanNative.startRegularScan(client); if (!mScanNative.isOpportunisticScanClient(client)) { mScanNative.configureRegularScanParams(); } } } ... }
這邊分析一下startBatchScan是vendor command 相關,那么一般都是調用到mScanNative.startRegularScan,這邊已經調用到了native層面,具體看看其實現:
void startRegularScan(ScanClient client) { if (isFilteringSupported() && mFilterIndexStack.isEmpty() && mClientFilterIndexMap.isEmpty()) { initFilterIndexStack(); } if (isFilteringSupported()) { configureScanFilters(client); } // Start scan native only for the first client. if (numRegularScanClients() == 1) { gattClientScanNative(true); } }
這邊繼續往下調用到gattClientScanNative(true) :這里調用到JNI 層,其實現在文件com_android_bluetooth_gatt.cpp
static void gattClientScanNative(JNIEnv* env, jobject object, jboolean start) { if (!sGattIf) return; sGattIf->client->scan(start); }
到這里就很明確了,其最終調用的是sGattIf中client 的scan的接口,那其接口是怎么樣的呢?
其是在bluetooth.c里面通過get_profile_interface 來獲取GATT的interface的,
static const btgatt_interface_t btgattInterface = { sizeof(btgattInterface), btif_gatt_init, btif_gatt_cleanup, &btgattClientInterface, &btgattServerInterface, };
中的client 的接口如下:
const btgatt_client_interface_t btgattClientInterface = { btif_gattc_register_app, btif_gattc_unregister_app, btif_gattc_scan, btif_gattc_open, btif_gattc_close, btif_gattc_listen, ... }
那其實調用的就是:btif_gattc_scan
static bt_status_t btif_gattc_scan( bool start ) { CHECK_BTGATT_INIT(); btif_gattc_cb_t btif_cb; return btif_transfer_context(btgattc_handle_event, start ? BTIF_GATTC_SCAN_START : BTIF_GATTC_SCAN_STOP, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); }
這里將處理的流程transfer到bt_jni_workqueue_thread線程了,從這個線程的名字來看,主要是處理從JNI 下來的事件。看看具體做了什么:
static void btgattc_handle_event(uint16_t event, char* p_param) { ... btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*) p_param; if (!p_cb) return; switch (event) { ... case BTIF_GATTC_SCAN_START: btif_gattc_init_dev_cb(); BTA_DmBleObserve(TRUE, 0, bta_scan_results_cb);//調用的是這個函數 break; ...
繼續看BTA_DmBleObserve,注意第一個參數是true,表示開始scan,第二個參數是持續時間,0表示一直持續:
extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration, tBTA_DM_SEARCH_CBACK *p_results_cb) { tBTA_DM_API_BLE_OBSERVE *p_msg; APPL_TRACE_API("BTA_DmBleObserve:start = %d ", start); if ((p_msg = (tBTA_DM_API_BLE_OBSERVE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_OBSERVE))) != NULL) { memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_OBSERVE)); p_msg->hdr.event = BTA_DM_API_BLE_OBSERVE_EVT;//向bt_workqueue_thread發送BTA_DM_API_BLE_OBSERVE_EVT
p_msg->start = start;
p_msg->duration = duration;
p_msg->p_cback = p_results_cb;
bta_sys_sendmsg(p_msg);
}
}
看了一下代碼發現bt_workqueue_thread 是處理事件的主線程,bta_sys_sendmsg(p_msg); 這個函數是將消息發送到btu_bta_msg_queue,而這個queue是和bt_workqueue_thread綁定的,隊列里面的消息都會在這個線程里面處理:
void bta_sys_sendmsg(void *p_msg) { if (btu_bta_msg_queue) fixed_queue_enqueue(btu_bta_msg_queue, p_msg); }
那現在 關於scan的event 的處理已經來到了另一個線程:bt_workqueue_thread,那么該隊列里面有了數據線程如何處理?
fixed_queue_register_dequeue(btu_bta_msg_queue,
thread_get_reactor(bt_workqueue_thread),
btu_bta_msg_ready,
NULL);
根據上面的代碼,我們知道會調用到btu_bta_msg_ready:
void btu_bta_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) { BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);//消息出列 bta_sys_event(p_msg); }
也就是先讓消息處理,然后再調用bta_sys_event來處理:那至此我們知道,凡是調用到bta_sys_sendmsg,那最終處理的函數都是bta_sys_event來處理,而這個函數的處理方式也是一種dispatch的機制:
void bta_sys_event(BT_HDR *p_msg) { ... /* get subsystem id from event */ id = (UINT8) (p_msg->event >> 8); /* verify id and call subsystem event handler */ if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) { freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg); } ... }
其思想就是找到該事件對應的處理函數,這些event的高8bit 是屬於事件的類型,或者稱為主事件,而event的低8 bit是事件的子類,或者稱為子事件。處理的過程是先通過主事件找到事件的處理函數handler(當然肯定是事先注冊好的),然后在該處理函數中處理子事件。
那該事件的處理函數handler 是什么呢?
/******************************************************************************* ** ** Function bta_sys_register ** ** Description Called by other BTA subsystems to register their event ** handler. ** ** ** Returns void ** *******************************************************************************/ void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg) { bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg; bta_sys_cb.is_reg[id] = TRUE; }
這里是注冊的地方,根據函數的注釋,是BTA 的子系統注冊自己的event 的處理函數 時候所調用的。下圖很容易看出有哪些模塊調用這個注冊函數

對於BTA_DM_API_BLE_OBSERVE_EVT 這個event 可知其主事件是BTA_ID_DM = 1 ,其注冊 的地方在BTA_EnableBluetooth:
bta_sys_register (BTA_ID_DM, &bta_dm_reg );
那現在我們知道,其處理的函數的入口就是bta_dm_reg:
static const tBTA_SYS_REG bta_dm_reg = { bta_dm_sm_execute, bta_dm_sm_disable };
BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg) { UINT16 event = p_msg->event & 0x00ff;//取出子事件 /* execute action functions */ if(event < BTA_DM_NUM_ACTIONS) { (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg); } return TRUE; }
這里我們發現,其設計還是比較巧妙,每個event 對應的處理函數,是在一個大的數組中,用事件的子事件(低8bit)來尋址,這有點分頁的意味了。
這里該事件真正的處理函數是bta_dm_ble_observe:並調用如下代碼:
((status = BTM_BleObserve(TRUE, p_data->ble_observe.duration,
bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb))!= BTM_CMD_STARTED)
這里我們發現,函數調用已經進入到stack里面了,BTM_BleObserve,看看其具體實現,這里我們應該還記得,這里的第二個參數傳進來的時候是0:
tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration, tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb) { ... UINT32 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;//發現參數是優先使用inquiry的參數 UINT32 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window; ... if (start) { /* shared inquiry database, do not allow observe if any inquiry is active */ if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))//如果有observe 直接返回 { BTM_TRACE_ERROR("%s Observe Already Active", __func__); return status; } btm_cb.ble_ctr_cb.p_obs_results_cb = p_results_cb; btm_cb.ble_ctr_cb.p_obs_cmpl_cb = p_cmpl_cb; status = BTM_CMD_STARTED; /* scan is not started */ if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))//沒有其他的scan 行為才繼續執行 { /* allow config of scan type */ p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type; ... p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE; status = btm_ble_start_scan();//開始scan } if (status == BTM_CMD_STARTED) { btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_OBSERVE_ACTIVE; if (duration != 0) /* start observer timer */ btu_start_timer (&btm_cb.ble_ctr_cb.obs_timer_ent, BTU_TTYPE_BLE_OBSERVE, duration);//這里注意,如果duration設置了,那么經過一定時間就會超時,然后會停止scan,如果沒有設置這個值,就會一直scan } }
這里注意一下代碼中有這樣一句注釋:shared inquiry database, do not allow observe if any inquiry is active,說明oberve的優先級還是很低的。從代碼中也 可以看出只有當沒有其他的scan的行為,observe才會繼續進行。另外對於scan type 是active還是passive的問題,當p_inq->scan_interval 沒有設置的話,就使用active,否則就使用當前的設置值。從這也可以看出,active 是優先被使用的。
最后看看btm_ble_start_scan的實現,這個就很簡單了,直接通過HCI 來發送命令了:
tBTM_STATUS btm_ble_start_scan(void) { tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var; tBTM_STATUS status = BTM_CMD_STARTED; /* start scan, disable duplicate filtering */ if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter))//HCI command { status = BTM_NO_RESOURCES; } else { if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI) btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);//更新拓撲 else btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT); } return status; }
scan結果的回報:
前面注冊的時候,我們看到
case BTIF_GATTC_SCAN_START: btif_gattc_init_dev_cb(); BTA_DmBleObserve(TRUE, 0, bta_scan_results_cb); break;
其回調函數是bta_scan_results_cb,當搜索結果上來的時候,該函數會被調用:
static void bta_scan_results_cb (tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) { ... switch (event) { case BTA_DM_INQ_RES_EVT: { ... } break; case BTA_DM_INQ_CMPL_EVT: { ... } btif_transfer_context(btif_gattc_upstreams_evt, BTIF_GATT_OBSERVE_EVT, (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); }
代碼中針對BTA_DM_INQ_RES_EVT和BTA_DM_INQ_CMPL_EVT 都會有自己的一些處理,但是最后都要經過btif_gattc_upstreams_evt的處理,並且是event = BTIF_GATT_OBSERVE_EVT
看具體的代碼實現:
case BTIF_GATT_OBSERVE_EVT: { btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*) p_param; ... BTIF_STORAGE_FILL_PROPERTY(&properties, BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type), &dev_type); btif_storage_set_remote_device_property(&(p_btif_cb->bd_addr), &properties); HAL_CBACK(bt_gatt_callbacks, client->scan_result_cb, &p_btif_cb->bd_addr, p_btif_cb->rssi, p_btif_cb->value); break; }
上面做的主要就是保存設備的屬性,以及向上層匯報相關的設備信息:使用bt_gatt_callbacks中的 client->scan_result_cb,接口。
那這個接口是哪里來的呢?
static bt_status_t btif_gatt_init( const btgatt_callbacks_t* callbacks ) { bt_gatt_callbacks = callbacks; return BT_STATUS_SUCCESS; }
發現是gatt 模塊init的時候賦值的,那么我們就知道其callback 來源於JNI層面:
static const btgatt_callbacks_t sGattCallbacks = { sizeof(btgatt_callbacks_t), &sGattClientCallbacks, &sGattServerCallbacks };
static const btgatt_client_callbacks_t sGattClientCallbacks = { btgattc_register_app_cb, btgattc_scan_result_cb,//此函數 btgattc_open_cb, ...
通過JNI方法的回調:
void btgattc_scan_result_cb(bt_bdaddr_t* bda, int rssi, uint8_t* adv_data) { ... sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onScanResult , address, rssi, jb);//調用method_onScanResult
... checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); }
這個方法的實現是在java層,那到底對應於哪一個文件呢?
int register_com_android_bluetooth_gatt(JNIEnv* env) { int register_success = jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/ScanManager$ScanNative", sScanMethods, NELEM(sScanMethods)); register_success &= jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/AdvertiseManager$AdvertiseNative", sAdvertiseMethods, NELEM(sAdvertiseMethods)); return register_success & jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/GattService", sMethods, NELEM(sMethods)); }
發現sMethods對應於"com/android/bluetooth/gatt/GattService" ,那我們知道其實現是在GattService.java里面。看具體的實現:
void onScanResult(String address, int rssi, byte[] adv_data) { if (VDBG) Log.d(TAG, "onScanResult() - address=" + address + ", rssi=" + rssi); List<UUID> remoteUuids = parseUuids(adv_data); for (ScanClient client : mScanManager.getRegularScanQueue()) { if (client.uuids.length > 0) { int matches = 0; for (UUID search : client.uuids) { for (UUID remote: remoteUuids) { if (remote.equals(search)) { ++matches; break; // Only count 1st match in case of duplicates } } } if (matches < client.uuids.length) continue; } if (!client.isServer) { ClientMap.App app = mClientMap.getById(client.clientIf); if (app != null) { BluetoothDevice device = BluetoothAdapter.getDefaultAdapter() .getRemoteDevice(address); ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(adv_data), rssi, SystemClock.elapsedRealtimeNanos()); // Do no report if location mode is OFF or the client has no location permission // PEERS_MAC_ADDRESS permission holders always get results if (hasScanResultPermission(client) && matchesFilters(client, result)) { try { ScanSettings settings = client.settings; if ((settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_ALL_MATCHES) != 0) { app.callback.onScanResult(result); } } catch (RemoteException e) { Log.e(TAG, "Exception: " + e); mClientMap.remove(client.clientIf); mScanManager.stopScan(client); } } } } else { ServerMap.App app = mServerMap.getById(client.clientIf); if (app != null) { try { app.callback.onScanResult(address, rssi, adv_data); } catch (RemoteException e) { Log.e(TAG, "Exception: " + e); mServerMap.remove(client.clientIf); mScanManager.stopScan(client); } } } } }
到這里呢,協議棧就將關於設備的信息上傳到bluetooth.apk了,在這個函數里面,我們可以看到其最終調用到app.callback.onScanResult(address, rssi, adv_data);,這邊應該是回調到更上一層應用。
