1. 程式人生 > >Android GATT 連線過程原始碼分析

Android GATT 連線過程原始碼分析

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 = iGattiGatt 是 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 就是 GattServiceonClientRegistered 就是 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 系統,儘管還有很多細節沒有展開去了解,但是脈絡還是很清晰的。
第一次寫分析原始碼的文章,不知不覺就寫了這麼長(其實大部分是程式碼),花費了很多精力,也不知道說清楚了沒有。對我自己來說,還是收穫不少。

 

轉自: http://mcu.szdahao.com/info/info_218.html