Android GATT 連接過程源碼分析
低功耗藍牙(BLE)設備的通信基本協議是 GATT, 要操作 BLE 設備,第一步就是要連接設備,其實就是連接 BLE 設備上的 GATT service。
結合上一篇文章,我這裏結合源碼,分析一下 GATT 連接的流程,以及各個模塊是怎麼相互交互的。注意本文依據的是 Android 4.4 的源代碼。
應用框架層
首先,一般應用層都是通過調用如下方法,來創建一個 GATT 連接的:
|
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
|
這裏調用了方法 connectGatt()
,我們來看一下源碼,代碼在 /frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
:
|
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager managerService = adapter.getBluetoothManager();
try {
IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) {
// BLE is not supported
return null;
}
// 創建一個 BluetoothGatt 對象
BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
// 發起連接
gatt.connect(autoConnect, callback);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
|
這裏通過 BluetoothAdapter
獲取 managerService
,這是通過 Binder
機制綁定的一個遠程藍牙管理服務,進而獲得 iGatt
,同樣,這也是一個遠程的 Binder 對象,這是一個非常關鍵的對象,後面會詳細講。然後調用了 BluetoothGatt
的 connect()
方法,需要注意這裏有一個參數 autoConnect
, 如果爲 false
,則表示直接連接,true
表示自動連接,意思是等到設備可用,則會自動連接上。
接下來看 gatt.connect()
的實現,代碼在/frameworks/base/core/java/android/bluetooth/BluetoothGatt.java
:
|
boolean connect(Boolean autoConnect, BluetoothGattCallback callback) {
if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
synchronized(mStateLock) {
// 判斷當前連接狀態
if (mConnState != CONN_STATE_IDLE) {
throw new IllegalStateException("Not idle");
}
mConnState = CONN_STATE_CONNECTING;
}
// 這裏向底層註冊上層的應用
if (!registerApp(callback)) {
synchronized(mStateLock) {
mConnState = CONN_STATE_IDLE;
}
Log.e(TAG, "Failed to register callback");
return false;
}
// the connection will continue after successful callback registration
mAutoConnect = autoConnect;
return true;
}
|
這裏面關鍵的一句是 registerApp(callback)
,這是向底層註冊 App,底層就知道有 App 在使用藍牙,有藍牙消息的時候,就通過回調通知上層的 App。BLE 幾乎所有操作都是通過異步回調實現的,就是通過這個你自定義的 BluetoothGattCallback
來通知你的應用的。接下來我們繼續看 registerApp()
:
|
private boolean registerApp(BluetoothGattCallback callback) {
if (DBG) Log.d(TAG, "registerApp()");
if (mService == null) return false;
mCallback = callback;
UUID uuid = UUID.randomUUID();
if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
try {
mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
|
可以看到,這裏調用了 mService.registerClient()
,這裏的 mService
就是第一步創建的 BluetoothGatt
對象的時候傳入的 IBluetoothGatt
類型的 Binder
對象。對於這個函數的名字爲什麼叫 registerClient
,這是因爲,在 Binder 機制中,被綁定的 Service 作爲稱爲服務端,發起綁定的一方是客戶端。
在繼續往下看 registerClient()
這個函數之前,我們回憶一下,我們的目標是連接 BLE 設備,到這一步了,還沒有看到連接動作的蹤影。這是怎麼回事?前面我們說過,藍牙幾乎所有的操作都是依靠回調實現,我們先來看一下這裏的 mBluetoothGatt
的實現,看源代碼中,這個回調對象非常大,包含所有的 Gatt 回調動作,我們這裏主要看 onClientRegistered()
方法:
|
private final IBluetoothGattCallback mBluetoothGattCallback =
new IBluetoothGattCallback.Stub() {
/**
* Application interface registered - app is ready to go
* @hide
*/
public void onClientRegistered(int status, int clientIf) {
if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
+ " clientIf=" + clientIf);
if (VDBG) {
synchronized(mStateLock) {
// 這裏判斷狀態是不是 CONN_STATE_CONNECTING,
// 注意到前面的 `connect()` 方法中已經把 mConnState = CONN_STATE_CONNECTING;
if (mConnState != CONN_STATE_CONNECTING) {
Log.e(TAG, "Bad connection state: " + mConnState);
}
}
}
mClientIf = clientIf;
// 註冊客戶端失敗,通知到應用的 callback
if (status != GATT_SUCCESS) {
mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
BluetoothProfile.STATE_DISCONNECTED);
synchronized(mStateLock) {
mConnState = CONN_STATE_IDLE;
}
return;
}
try {
// 這裏開始做真正的連接操作了
mService.clientConnect(mClientIf, mDevice.getAddress(),
!mAutoConnect); // autoConnect is inverse of "isDirect"
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
}
...
};
|
這個回調方法有兩個參數 status
和 clientIf
,前者很好理解,就是表示註冊客戶端是否成功。clientIf
表示從底層返回的一個 id,用來唯一標示這個客戶端,接下來的所有客戶端的操作請求,都需要帶上這個 id。
這個回調方法中做的事情比較清晰,特別注意到 mService.clientConnect(...)
,這裏開始調用 Service 接口開始發起連接了。
從代碼中可以看到,mService
是一個很關鍵的對象,但是這個對象是從哪裏來的呢?
應用框架和藍牙服務的銜接: Binder
在第一段代碼的分析中就提到了 iGatt
對象,從 BluetoothGatt
的構造函數可以看出,其實 mService = iGatt
,iGatt
是 IBluetoothGatt
接口的 Binder。
我們看一下 BluetoothAdapter
是怎麼獲得的,BluetoothAdapter.getDefaultAdapter()
:
|
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
if (b != null) {
IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
sAdapter = new BluetoothAdapter(managerService);
} else {
Log.e(TAG, "Bluetooth binder is null");
}
}
return sAdapter;
}
|
這裏是一個單例模式,通過系統API ServiceManager.getService()
獲得的,這裏大致邏輯就是,在系統那個啓動的時候,Android 會啓動一些系統服務並通過 ServiceManager
管理,具體我就不往下深究了,可以具體看一下老羅的這篇文章。這裏直接給出結論,這裏 Binder 對象對應的服務是 BluetoothManagerService
,代碼在 /frameworks/base/services/java/com/android/server/BluetoothManagerService.java
。
我們看一下怎麼從 BluetoothManagerService
中獲取到 IBluetoothGatt
的 Binder 的。注意到 BluetoothManagerService
中有一個方法 bluetoothStateChangeHandler()
,衝方法名就大概可以知道這個方法是在藍牙狀態變化的時候,做一些處理的。跟蹤以下這個函數的調用的地方,就能驗證我們的猜想是對的。這一塊和本文的關係不大,我們現在來看一下 bluetoothStateChangeHandler()
的具體實現:
|
private void bluetoothStateChangeHandler(int prevState, int newState) {
if (prevState != newState) {
//Notify all proxy objects first of adapter state change
if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
boolean isUp = (newState==BluetoothAdapter.STATE_ON);
sendBluetoothStateCallback(isUp);
if (isUp) {
// connect to GattService
if (mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_BLUETOOTH_LE)) {
Intent i = new Intent(IBluetoothGatt.class.getName());
doBind(i, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
Intent iqc = new Intent(IQBluetooth.class.getName());
doBind(iqc, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
}
} else {
//If Bluetooth is off, send service down event to proxy objects, and unbind
if (!isUp && canUnbindBluetoothService()) {
sendBluetoothServiceDownCallback();
sendQBluetoothServiceDownCallback();
unbindAndFinish();
}
}
}
//Send broadcast message to everyone else
Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
BLUETOOTH_PERM);
}
}
|
看到 if (isUp)
這個分支中,會綁定到以 IBluetoothGatt 的類名爲 Action Name 的服務,也就是 action="android.bluetooth.IBluetoothGatt"
。我們在 /packages/apps/Bluetooth
這個 App 的 AndroidManifest.xml
中找到如下的聲明:
|
<service
android:process="@string/process"
android:name = ".gatt.GattService"
android:enabled="@bool/profile_supported_gatt">
<intent-filter>
<action android:name="android.bluetooth.IBluetoothGatt" />
</intent-filter>
</service>
|
我們找到了,原來是綁定到了 com.android.bluetooth.gatt.GattService
上了。如果綁定成功,會回調 mConnection
的 onServiceConnected()
,其實現如下:
|
public void onServiceConnected(ComponentName className, IBinder service) {
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
...
} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
}
...
msg.obj = service;
mHandler.sendMessage(msg);
}
|
如果綁定的類名是 GattService
,就會發送MESSAGE_BLUETOOTH_SERVICE_CONNECTED
消息給 mHandler
,消息的第一個參數爲 SERVICE_IBLUETOOTHGATT
,我們接下來看 mHandler 怎麼處理的:
|
@Override
public void handleMessage(Message msg) {
if (DBG) Log.d (TAG, "Message: " + msg.what);
switch (msg.what) {
...
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
{
IBinder service = (IBinder) msg.obj;
synchronized(mConnection) {
if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
break;
}
...
}
}
}
}
|
最終獲得 IBluetoothGatt
的 Binder,並賦值給 mBluetoothGatt
,最後通過如下接口,返回給前面的 BluetoothGatt
。
至此,通過 Binder 機制,完成了應用框架 API 到 Service 的綁定。別忘了我們的目標:分析BLE連接的流程。通過前面的代碼分析我們知道,連接的時候,先調用了 ‘mService.registerClient()’,然後在註冊成功後,調用了 mService.clientConnect()
真正發起連接。我們知道了,這個 mService
實際上就是 com.android.bluetooth.gatt.GattService
。我們接下來分析這個 Service,也就到了藍牙服務層了。
藍牙服務
藍牙服務的代碼在 packages/app/Bluetooth
,編譯以後成 Bluetooth.apk,安裝在 /system/app/
目錄下面,GattService
運行在 com.android.bluetooth
進程中。我們接着來看 Binder
的 registerClient()
接口,這個 Binder 是 GattService
的一個內部類:
|
private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {
public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) {
GattService service = getService();
if (service == null) return;
service.registerClient(uuid.getUuid(), callback);
}
}
|
可以看到,實際上這裏還是調用了 GattService
的 registerClient
方法:
|
void registerClient(UUID uuid, IBluetoothGattCallback callback) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
mClientMap.add(uuid, callback);
// 調用 native 接口
gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
uuid.getMostSignificantBits());
}
|
這裏首先是把 uuid
以及對應的 callback
保存到一個 mClientMap
中去,這裏從名字上我們就能大概清楚這裏的作用,這裏的 uuid 是客戶端的唯一標示, uuid 對應了客戶端的回調函數 callback
。接下來,調用了 gattClientRegisterAppNative()
接口向底層協議棧註冊客戶端,看一下函數定義:
|
private native void gattClientRegisterAppNative(long app_uuid_lsb, long app_uuid_msb);
|
這裏可以看出,實際上是客戶端的標示 – UUID 註冊到底層去,UUID 是 128 bit, 正好用兩個 long
型的參數表示。這個函數是 JNI 的申明,具體的實現就在對應的 C/C++ 代碼中。
藍牙服務和 HAL 的調用:JNI
上面的 gattClientRegisterAppNative()
對應的 JNI 的代碼在哪裏呢?通過查看 AndroidManifest.xml
,我們知道 Bluetooth 的自定義 Application 是 AdapterApp
,裏面有這樣的代碼:
|
static {
if (DBG) Log.d(TAG,"Loading JNI Library");
System.loadLibrary("bluetooth_jni");
}
|
這裏是加載了 libbluetooth_jni.so
動態庫。我們再看 jni 目錄的 Android.mk
,這裏正好是生成 libbluetooth_jni
的編譯腳本。這樣我們就知道了對應的 C/C++ 代碼在 com_android_bluetooth_gatt.cpp
:
|
static JNINativeMethod sMethods[] = {
...
{"gattClientRegisterAppNative", "(JJ)V", (void *) gattClientRegisterAppNative},
...
}
|
這是註冊 JNI 函數的標準方法,關於 JNI 的詳細語法,可以參考這裏。可以找到對應的函數實現如下:
|
static void gattClientRegisterAppNative(JNIEnv* env, jobject object,
jlong app_uuid_lsb, jlong app_uuid_msb )
{
bt_uuid_t uuid;
if (!sGattIf) return;
set_uuid(uuid.uu, app_uuid_msb, app_uuid_lsb);
sGattIf->client->register_client(&uuid);
}
|
這裏調用了 sGattIf
的 client
的 register_client()
方法,這裏還是把客戶端的標示 UUID 傳遞下去。這裏的 sGattIf
是什麼呢?
|
static const btgatt_interface_t *sGattIf = NULL;
|
它是一個 btgatt_interface_t
類型的變量,sGattIf
的初始化在 initializeNative()
中,這個函數在 GattService.start()
方法中被調用了,這個函數定義如下:
|
static void initializeNative(JNIEnv *env, jobject object) {
if(btIf)
return;
if ( (btIf = getBluetoothInterface()) == NULL) {
error("Bluetooth module is not loaded");
return;
}
...
if ( (sGattIf = (btgatt_interface_t *)
btIf->get_profile_interface(BT_PROFILE_GATT_ID)) == NULL) {
error("Failed to get Bluetooth GATT Interface");
return;
}
...
}
|
注意這裏首先通過 getBluetoothInterface()
獲得整個底層的藍牙接口。我們重點來關注以下 sGattIf
是怎麼來的?
看到這裏調用了 btIf->get_profile_interface(BT_PROFILE_GATT_ID))
來獲取 sGattIf
實例。
現在來看 btgatt_interface_t
是在哪裏定義的,我們看一下這個文件 include 的頭文件中,最有可能就是在 #include "hardware/bt_gatt.h"
,這就是 HAL 接口定義的地方。
硬件抽象層 HAL
HAL 頭文件都放在 hardware/libhardware/include/hardware/
,我們在這裏找到了 bt_gatt.h
,並找到了 btgatt_interface_t
的定義如下:
|
/** Represents the standard Bluetooth GATT interface. */
typedef struct {
/** Set to sizeof(btgatt_interface_t) */
size_t size;
/**
* Initializes the interface and provides callback routines
*/
bt_status_t (*init)( const btgatt_callbacks_t* callbacks );
/** Closes the interface */
void (*cleanup)( void );
/** Pointer to the GATT client interface methods.*/
const btgatt_client_interface_t* client;
/** Pointer to the GATT server interface methods.*/
const btgatt_server_interface_t* server;
} btgatt_interface_t;
|
可以看到 btgatt_interface_t
有一個成員 client
,類型是 btgatt_client_interface_t
。
我們再來看 btgatt_client_interface_t
的定義,在 bt_gatt_client.h
中:
|
/** Represents the standard BT-GATT client interface. */
typedef struct {
/** Registers a GATT client application with the stack */
bt_status_t (*register_client)( bt_uuid_t *uuid );
/** Unregister a client application from the stack */
bt_status_t (*unregister_client)(int client_if );
/** Create a connection to a remote LE or dual-mode device */
bt_status_t (*connect)( int client_if, const bt_bdaddr_t *bd_addr,
bool is_direct, int transport );
/** Disconnect a remote device or cancel a pending connection */
bt_status_t (*disconnect)( int client_if, const bt_bdaddr_t *bd_addr,
int conn_id);
...
} btgatt_client_interface_t;
|
在這裏我們看到了 register_client
這個函數指針。這個結構體的定義很長,我這裏只截取了本文相關的內容。這裏定義了所有 GATT
客戶端操作相關的接口,例如連接、掃描、獲取 Gatt Service、讀寫 Gatt characteristic/descriptor 等等。
但是這個結構體的具體實現在什麼地方呢?我們的直覺應該就在 HAL 的實現 BlueDroid 模塊了。
藍牙協議棧:BlueDroid
BlueDroid 的代碼在 external/bluetooth/bluedroid
。我們在這個目錄下 grep 一下:
|
$ cd external/bluetooth/bluedroid
$ grep -nr 'btgatt_interface_t' .
|
我們很容易找到 btgatt_interface_t
的實現:
|
// btif/src/btif_gatt.c
static const btgatt_interface_t btgattInterface = {
sizeof(btgattInterface),
btif_gatt_init,
btif_gatt_cleanup,
&btgattClientInterface,
&btgattServerInterface,
};
|
然後在 btif/src/btif_gatt_client.c
,找到 btgattClientInterface
具體的實現如下:
|
const btgatt_client_interface_t btgattClientInterface = {
btif_gattc_register_app,
btif_gattc_unregister_app,
btif_gattc_open,
btif_gattc_close,
...
}
|
看到這裏定義了一個 btgatt_client_interface_t
的實例 btgattClientInterface
,內部都是函數指針,所有的函數的實現都這這個文件中能找到。其實這個變量就是前面的代碼中提到的 sGattIf->client
,我們下面來看看這是是怎麼關聯上的。
在 btif/src/btif_gatt.c
中又如下定義:
|
extern btgatt_client_interface_t btgattClientInterface;
static const btgatt_interface_t btgattInterface = {
sizeof(btgattInterface),
btif_gatt_init,
btif_gatt_cleanup,
&btgattClientInterface,
&btgattServerInterface,
};
const btgatt_interface_t *btif_gatt_get_interface()
{
return &btgattInterface;
}
|
從代碼中可以看出,btgattClientInterface
賦值給了 btgattInterface
的 client
成員(還記得前面的 btgatt_interface_t
的定義吧)。難道這裏的 btgattInterface
就是 JNI 中的 sGattIf
嗎?
確實是這樣的,還記的前面的說的 sGattIf
的初始化,調用瞭如下接口:
|
sGattIf = (btgatt_interface_t *)btIf->get_profile_interface(BT_PROFILE_GATT_ID)
|
我們來看一下 get_profile_interface()
的定義,在 btif/src/bluetooth.c
中:
|
static const void* get_profile_interface (const char *profile_id)
{
...
if (is_profile(profile_id, BT_PROFILE_GATT_ID))
return btif_gatt_get_interface();
...
}
|
看到這裏調用了 btif_gatt_get_interface()
,實際上就是把 btgattInterface
返回賦值給了 sGattIf
。
到這裏,變量之間的相互關係和初始化就都完全清楚了。還是不要忘記我們的目標:連接 BLE 設備。前面我們分析到了,發起 BLE 設備連接,首先是向底層協議棧註冊客戶端,也就是調用了 sGattIf->client->register_client(&uuid);
。
現在我們知道了 register_client()
的實現就在 btif/src/btif_gatt_client.c
,對應的實現如下:
|
static bt_status_t btif_gattc_register_app(bt_uuid_t *uuid)
{
CHECK_BTGATT_INIT();
btif_gattc_cb_t btif_cb;
memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t));
return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REGISTER_APP,
(char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL);
}
|
這裏的 btif_transfer_context()
是一個工具方法,代碼如下:
|
// btif/src/btif_core.c
bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTIF_COPY_CBACK *p_copy_cback)
{
tBTIF_CONTEXT_SWITCH_CBACK *p_msg;
BTIF_TRACE_VERBOSE2("btif_transfer_context event %d, len %d", event, param_len);
/* allocate and send message that will be executed in btif context */
if ((p_msg = (tBTIF_CONTEXT_SWITCH_CBACK *) GKI_getbuf(sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len)) != NULL)
{
// 給 p_msg 賦值
...
// 注意這裏
btif_sendmsg(p_msg);
return BT_STATUS_SUCCESS;
}
else
{
/* let caller deal with a failed allocation */
return BT_STATUS_NOMEM;
}
}
|
這裏面調用了一個很重要的方法 btif_sendmsg(...)
,實際上是調用了 GKI_send_msg(...)
,接着往下看代碼就會發現,實際上就是發送一個 Event,讓對應的 handler 函數去處理。
據我的理解,其實就是一個類似於 Android framework 中的 Handler
,你可以提交你的 Task 到指定的線程中去運行。
這裏 btif_transfer_context(...)
的作用就是把代碼運行的上下文(context)轉爲藍牙協議棧,這部分的代碼和本文關係不大,這裏就不深入討論了。
這裏的 btgattc_handle_event
相當於我們要運行的 Task, 後面就是這個 Task 運行需要的一些參數。我們接下來看 btgattc_handle_event
的實現:
|
// btif/src/btif_gatt_client.c
static void btgattc_handle_event(uint16_t event, char* p_param)
{
tBTA_GATT_STATUS status;
tBT_UUID uuid;
...
btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*)p_param;
if (!p_cb) return;
ALOGD("%s: Event %d", __FUNCTION__, event);
switch (event)
{
case BTIF_GATTC_REGISTER_APP:
// UUID 的格式轉換
btif_to_bta_uuid(&uuid, &p_cb->uuid);
BTA_GATTC_AppRegister(&uuid, bta_gattc_cback);
break;
...
}
}
|
可以看到,這個函數的參數,都是我們上面那個 btif_transfer_context(...)
傳遞進來的,這裏 event = BTIF_GATTC_REGISTER_APP
,看一下對應的 switch
分支代碼。
btif_to_bta_uuid()
非常簡單,這是把 UUID 的轉換爲 BTA 層 UUID 格式。然後真正做事的是 BTA_GATTC_AppRegister(...)
:
|
// bta/gatt/bta_gattc_api.c
void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb)
{
tBTA_GATTC_API_REG *p_buf;
if (bta_sys_is_register(BTA_ID_GATTC) == FALSE)
{
GKI_sched_lock();
// 註冊事件處理函數
bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
GKI_sched_unlock();
}
if ((p_buf = (tBTA_GATTC_API_REG *) GKI_getbuf(sizeof(tBTA_GATTC_API_REG))) != NULL)
{
p_buf->hdr.event = BTA_GATTC_API_REG_EVT;
if (p_app_uuid != NULL)
memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
p_buf->p_cback = p_client_cb;
bta_sys_sendmsg(p_buf);
}
return;
}
|
這裏首先判斷 BTA_ID_GATTC
事件處理器是否註冊了,如果沒有註冊就註冊一個 bta_gattc_reg
。這裏表示 bta_gattc_reg
所有的 GATT 客戶端事件的處理器。
可見,這個 bta_gattc_reg
是非常重要的,我們來看它的定義:
|
// bta/sys/bta_sys.h
/* registration structure */
typedef struct
{
// 事件處理函數
tBTA_SYS_EVT_HDLR *evt_hdlr;
// 關閉事件處理
tBTA_SYS_DISABLE *disable;
} tBTA_SYS_REG;
// bta/gatt/bta_gattc_api.c
static const tBTA_SYS_REG bta_gattc_reg =
{
bta_gattc_hdl_event,
BTA_GATTC_Disable
};
|
這是一個結構體,其定義我也貼在上面了,成員類型都是函數指針,其函數的定義我在後面會講。
我們先往下看,這裏的代碼是不是看起來有些面熟,其實和 btif_transfer_context()
的邏輯非常類似,這裏也是發送一個 event 給 handler 去處理。
雖然這裏調用的是 bta_sys_sendmsg(...)
,實際上它的實現就是調用 GKI_send_msg(...)
。
分析方法類似,我們這裏的 event 是 BTA_GATTC_API_REG_EVT
,這個事件的處理函數就是上面的 bta_gattc_reg
的 bta_gattc_hdl_event
:
|
// bta/gatt/bta_gattc_main.c
BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
...
switch (p_msg->event)
{
case BTA_GATTC_API_REG_EVT:
bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
...
}
...
}
|
到這裏,我們終於看到了最終的真正執行註冊客戶端的函數 bta_gattc_register(...)
了:
|
// bta/gatt/bta_gattc_act.c
void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data;
UINT8 i;
tBT_UUID *p_app_uuid = &p_data->api_reg.app_uuid;
tBTA_GATTC_INT_START_IF *p_buf;
tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
APPL_TRACE_DEBUG1("bta_gattc_register state %d",p_cb->state);
memset(&cb_data, 0, sizeof(cb_data));
cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES;
// 檢查 GATTC 模塊是否開啓;如果沒有,就開啓
if (p_cb->state == BTA_GATTC_STATE_DISABLED)
{
bta_gattc_enable (p_cb);
}
// 這裏遍歷客戶端列表
for (i = 0; i < BTA_GATTC_CL_MAX; i ++)
{
// 檢查是否被佔用
if (!p_cb->cl_rcb[i].in_use)
{
// 如果沒有被佔用,就向 GATT 協議棧註冊,並獲得新的 client_if
if ((p_app_uuid == NULL) || (p_cb->cl_rcb[i].client_if = GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0)
{
APPL_TRACE_ERROR0("Register with GATT stack failed.");
status = BTA_GATT_ERROR;
}
else
{
// GATT協議棧註冊成功,就在 BTA 層也中保存下來,完成註冊
p_cb->cl_rcb[i].in_use = TRUE;
p_cb->cl_rcb[i].p_cback = p_data->api_reg.p_cback;
memcpy(&p_cb->cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID));
/* BTA use the same client interface as BTE GATT statck */
cb_data.reg_oper.client_if = p_cb->cl_rcb[i].client_if;
if ((p_buf = (tBTA_GATTC_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTC_INT_START_IF))) != NULL)
{
p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT;
p_buf->client_if = p_cb->cl_rcb[i].client_if;
// 註冊成功,發送 BTA_GATTC_INT_START_IF_EVT 事件
bta_sys_sendmsg(p_buf);
status = BTA_GATT_OK;
}
else
{
GATT_Deregister(p_cb->cl_rcb[i].client_if);
status = BTA_GATT_NO_RESOURCES;
memset( &p_cb->cl_rcb[i], 0 , sizeof(tBTA_GATTC_RCB));
}
break;
}
}
}
/* callback with register event */
if (p_data->api_reg.p_cback)
{
if (p_app_uuid != NULL)
memcpy(&(cb_data.reg_oper.app_uuid),p_app_uuid,sizeof(tBT_UUID));
cb_data.reg_oper.status = status;
// 通過發送 BTA_GATTC_REG_EVT 事件,把註冊結果回調給上層
(*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data);
}
}
|
主要流程都在代碼的註釋中解釋了,遍歷客戶端列表,向 GATT statck 註冊客戶端,註冊成功後發送 BTA_GATTC_INT_START_IF_EVT
事件。
因爲這裏和前面一樣,同樣是調用了 bta_sys_sendmsg(...)
,所以處理函數是 bta_gattc_hdl_event(...)
,我們再來看這個分支:
|
// bta/gatt/bta_gattc_main.c
BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
{
tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
...
switch (p_msg->event)
{
...
case BTA_GATTC_INT_START_IF_EVT:
bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
break;
...
}
}
|
這裏調用了 bta_gattc_start_if(...)
:
|
// bta/gatt/bta_gattc_act.c
void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)
{
if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) !=NULL )
{
GATT_StartIf(p_msg->int_start_if.client_if);
}
else
{
APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.client_if );
}
}
|
最終調用了 GATT_StartIf(...)
:
|
// stack/gatt/gatt_api.c
void GATT_StartIf (tGATT_IF gatt_if)
{
tGATT_REG *p_reg;
tGATT_TCB *p_tcb;
BD_ADDR bda;
UINT8 start_idx, found_idx;
UINT16 conn_id;
GATT_TRACE_API1 ("GATT_StartIf gatt_if=%d", gatt_if);
if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
{
p_reg = &gatt_cb.cl_rcb[gatt_if - 1];
start_idx = 0;
while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
{
p_tcb = gatt_find_tcb_by_addr(bda);
if (p_reg->app_cb.p_conn_cb && p_tcb)
{
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
(*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0);
}
start_idx = ++found_idx;
}
}
}
|
這個函數的主要作用是,調用剛註冊的客戶端 gatt_if
的連接回調函數,上報所有的設備的連接狀態。
我們接着分析 bta_gattc_register(...)
函數,重點是這一行:
|
(*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data);
|
這裏是看起來調用了一個回調函數,這裏的 (*p_data->api_reg.p_cback)
是誰,我們這裏回溯以下。
回到 bta_gattc_hdl_event(...)
,這個 p_data
是這裏傳進來的 tBTA_GATTC_DATA
類型的數據,它是一個聯合體(union):
|
// bta/gatt/bta_gattc_int.h
typedef union
{
BT_HDR hdr;
tBTA_GATTC_API_REG api_reg;
...
} tBTA_GATTC_DATA;
|
其中 (p_data->api_reg)
成員是一個 tBTA_GATTC_API_REG
,這個類型我們在 BTA_GATTC_AppRegister(...)
函數中見過。
其實這個值就是我們在這裏創建的,我們看一下 p_cback
是誰,我們在往回找到 btgattc_handle_event(...)
函數,發現就是 bta_gattc_cback
:其定義如下:
|
// btif/src/btif_gatt_client.c
static void bta_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
{
bt_status_t status = btif_transfer_context(btif_gattc_upstreams_evt,
(uint16_t) event, (void*)p_data, sizeof(tBTA_GATTC), btapp_gattc_req_data);
ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
}
|
這裏又是一個通過 “handler” 機制實現運行上下文的切換,這裏來看一下事件處理函數 btif_gattc_upstreams_evt
:
|
static void btif_gattc_upstreams_evt(uint16_t event, char* p_param)
{
ALOGD("%s: Event %d", __FUNCTION__, event);
tBTA_GATTC *p_data = (tBTA_GATTC*)p_param;
switch (event)
{
case BTA_GATTC_REG_EVT:
{
bt_uuid_t app_uuid;
bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.app_uuid);
HAL_CBACK(bt_gatt_callbacks, client->register_client_cb
, p_data->reg_oper.status
, p_data->reg_oper.client_if
, &app_uuid
);
break;
}
...
}
btapp_gattc_free_req_data(event, p_data);
}
|
因爲上面傳遞進來的 event 是 BTA_GATTC_REG_EVT
,我們就來看這個 event 的處理代碼。
bta_to_btif_uuid()
和上面的 btif_to_bta_uuid()
相反,把 BTA 的 UUID 轉換爲 BTIF 的格式。
然後,一個宏 HAL_CBACK
,其定義如下:
|
#define HAL_CBACK(P_CB, P_CBACK, ...)\
if (P_CB && P_CB->P_CBACK) { \
BTIF_TRACE_API2("HAL %s->%s", #P_CB, #P_CBACK); \
P_CB->P_CBACK(__VA_ARGS__); \
} \
else { \
ASSERTC(0, "Callback is NULL", 0); \
}
|
這裏展開一下,並替換其中實際的變量:
|
bt_gatt_callbacks->client->register_client_cb(p_data->reg_oper.status, p_data->reg_oper.client_if, &app_uuid);
|
可以看到這裏其實就是一個執行回調函數的宏。
現在問題是 bt_gatt_callbacks
是從誰?我們可以看到是在這裏初始化的:
|
static bt_status_t btif_gatt_init( const btgatt_callbacks_t* callbacks )
{
bt_gatt_callbacks = callbacks;
return BT_STATUS_SUCCESS;
}
|
也就是初始化的時候,通過傳遞進來的。在分析 BlueDroid 的最開始我們已經看到了 btgattInterface
的初始化了,這裏的 btif_gatt_init
函數就賦值給了它的 init
成員。
通過我們前面的分析,btgattInterface
實際上就是 JNI 層的 sGattIf
對象。我們回到 JNI 層的代碼:
|
// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static void initializeNative(JNIEnv *env, jobject object) {
...
// 這裏我們前面分析過
if ( (sGattIf = (btgatt_interface_t *)
btIf->get_profile_interface(BT_PROFILE_GATT_ID)) == NULL) {
error("Failed to get Bluetooth GATT Interface");
return;
}
// 注意這裏調用初始化方法 init(...)
bt_status_t status;
if ( (status = sGattIf->init(&sGattCallbacks)) != BT_STATUS_SUCCESS) {
error("Failed to initialize Bluetooth GATT, status: %d", status);
sGattIf = NULL;
return;
}
mCallbacksObj = env->NewGlobalRef(object);
}
|
這裏調用了 sGattIf->init(...)
方法,實際上就是前面的 btif_gatt_init(...)
函數。看到這裏傳入的 sGattCallbacks
就是我們在 BlueDroid 層尋找的 bt_gatt_callbacks
。
我們來看 sGattCallbacks
的定義:
|
// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static const btgatt_callbacks_t sGattCallbacks = {
sizeof(btgatt_callbacks_t),
&sGattClientCallbacks,
&sGattServerCallbacks
};
|
通過前面的分析,我們應該能很快知道 btgatt_callbacks_t
應該在 HAL 中定義的,然後 sGattClientCallbacks
就是對應的 client
成員。
在來看 sGattClientCallbacks
的定義:
|
// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static const btgatt_client_callbacks_t sGattClientCallbacks = {
btgattc_register_app_cb,
...
};
|
這裏的 btgattc_register_app_cb
對應的就是 btgatt_client_callbacks_t
的 register_client_cb
成員。所以我們再來看一下那個展開的宏,這裏再貼一下:
|
bt_gatt_callbacks->client->register_client_cb(p_data->reg_oper.status, p_data->reg_oper.client_if, &app_uuid);
|
實際上就是調用了 JNI 中定義的 btgattc_register_app_cb
函數:
|
// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
void btgattc_register_app_cb(int status, int clientIf, bt_uuid_t *app_uuid)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientRegistered, status,
clientIf, UUID_PARAMS(app_uuid));
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
|
這裏通過 JNI 調用了函數 id 爲 method_onClientRegistered
函數,
|
// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static void classInitNative(JNIEnv* env, jclass clazz) {
// Client callbacks
method_onClientRegistered = env->GetMethodID(clazz, "onClientRegistered", "(IIJJ)V");
...
}
|
這裏就對應了 Java class 中的 onClientRegistered(...)
方法,這裏 clazz
是誰呢?
|
// /packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void *) classInitNative},
...
}
|
我們在 GattService.java
中看到:
|
// /packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
public class GattService extends ProfileService {
static {
classInitNative();
}
}
|
可見,上面的 clazz
就是 GattService
,onClientRegistered
就是 GattService 的成員方法。我們在 GattService 類中找到其實現如下:
|
// /packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
throws RemoteException {
UUID uuid = new UUID(uuidMsb, uuidLsb);
if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
ClientMap.App app = mClientMap.getByUuid(uuid);
if (app != null) {
app.id = clientIf;
app.linkToDeath(new ClientDeathRecipient(clientIf));
app.callback.onClientRegistered(status, clientIf);
}
}
|
哈哈,終於回到我們熟悉的 Java 層代碼。還記得我們前面的在分析調用 registerClient(...)
的時候,把上層客戶端與 uuid 對應起來,保存在 mClientMap 中。
這裏通過 uuid 找到對應的客戶端App,然後調用對應的回調函數 app.callback.onClientRegistered(status, clientIf);
。
如果你還記得前面的分析的話,應該知道這個 callback
就是 BluetoothGatt
在調用 registerApp(...)
的時候傳遞的 mBluetoothGattCallback
,所以這裏就調用了 mBluetoothGattCallback.onClientRegistered(...)
方法。
這個 onClientRegistered()
回調我們在之前就提到過,如果註冊客戶端完成,就會回調這裏。如果成功,就會發起真正的連接請求(見第 1 節)。到這裏,其實就回調了 Android framework 層了。
如果這裏註冊客戶端成功了,回調的 status
就是 GATT_SUCCESS
,在 BluetoothGatt
中就會發起連接請求 mService.clientConnect(mClientIf, mDevice.getAddress(), !mAutoConnect);
。具體的流程和上面整個分析類似。
有了上面的整個分析經驗,這次應該就駕輕就熟了。所以我這裏也不再往下繼續說了。
總結
結合文章開始的那個圖,回顧一下代碼整個調用過程,非常清楚印證流程:framework -> Bluetooth service -> JNI -> HAL -> BlueDroid。
整個分析下來,幾乎貫穿了整個 Android 系統,儘管還有很多細節沒有展開去了解,但是脈絡還是很清晰的。
第一次寫分析源代碼的文章,不知不覺就寫了這麼長(其實大部分是代碼),花費了很多精力,也不知道說清楚了沒有。對我自己來說,還是收穫不少。