[转载]Android GATT 连接过程源码分析

低功耗蓝牙(BLE)设备的通信基本协议是 GATT, 要操作 BLE 设备,第一步就是要连接设备,其实就是连接 BLE 设备上的 GATT service。 结合上一篇文章,我这里结合源码,分析一下 GATT 连接的流程,以及各个模块是怎么相互交互的。注意本文依据的是 Android 4.4 的源代码。

应用框架层
首先,一般应用层都是通过调用如下方法,来创建一个 GATT 连接的:

<code>mBluetoothGatt = device.connectGatt(this, false, mGattCallback); </code>
这里调用了方法 connectGatt(),我们来看一下源码,代码在 /frameworks/base/core/java/android/bluetooth/BluetoothDevice.java:
<code>
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;
}</code>
这里通过 BluetoothAdapter 获取 managerService ,这是通过 Binder 机制绑定的一个远程蓝牙管理服务,进而获得 iGatt,同样,这也是一个远程的 Binder 对象,这是一个非常关键的对象,后面会详细讲。然后调用了 BluetoothGatt 的 connect() 方法,需要注意这里有一个参数 autoConnect, 如果为 false,则表示直接连接,true 表示自动连接,意思是等到设备可用,则会自动连接上。

接下来看 gatt.connect() 的实现,代码在/frameworks/base/core/java/android/bluetooth/BluetoothGatt.java:
<code>
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;

}</code>
这里面关键的一句是 registerApp(callback),这是向底层注册 App,底层就知道有 App 在使用蓝牙,有蓝牙消息的时候,就通过回调通知上层的 App。BLE 几乎所有操作都是通过异步回调实现的,就是通过这个你自定义的 BluetoothGattCallback 来通知你的应用的。接下来我们继续看 registerApp():
<code>
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;

}</code>
可以看到,这里调用了 mService.registerClient(),这里的 mService 就是第一步创建的 BluetoothGatt 对象的时候传入的 IBluetoothGatt 类型的 Binder 对象。对于这个函数的名字为什么叫 registerClient,这是因为,在 Binder 机制中,被绑定的 Service 作为称为服务端,发起绑定的一方是客户端。

在继续往下看 registerClient() 这个函数之前,我们回忆一下,我们的目标是连接 BLE 设备,到这一步了,还没有看到连接动作的踪影。这是怎么回事?前面我们说过,蓝牙几乎所有的操作都是依靠回调实现,我们先来看一下这里的 mBluetoothGatt 的实现,看源代码中,这个回调对象非常大,包含所有的 Gatt 回调动作,我们这里主要看 onClientRegistered() 方法:
<code>
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);
}
}

...

};</code>
这个回调方法有两个参数 status 和 clientIf,前者很好理解,就是表示注册客户端是否成功。clientIf 表示从底层返回的一个 id,用来唯一标示这个客户端,接下来的所有客户端的操作请求,都需要带上这个 id。 这个回调方法中做的事情比较清晰,特别注意到 mService.clientConnect(...),这里开始调用 Service 接口开始发起连接了。

从代码中可以看到,mService 是一个很关键的对象,但是这个对象是从哪里来的呢?

应用框架和蓝牙服务的衔接: Binder
在第一段代码的分析中就提到了 iGatt 对象,从 BluetoothGatt 的构造函数可以看出,其实 mService = iGatt,iGatt 是 IBluetoothGatt 接口的 Binder。

我们看一下 BluetoothAdapter 是怎么获得的,BluetoothAdapter.getDefaultAdapter():
<code>
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;
}</code>
这里是一个单例模式,通过系统API ServiceManager.getService() 获得的,这里大致逻辑就是,在系统那个启动的时候,Android 会启动一些系统服务并通过 ServiceManager 管理,具体我就不往下深究了,可以具体看一下老罗的这篇文章。这里直接给出结论,这里 Binder 对象对应的服务是 BluetoothManagerService,代码在 /frameworks/base/services/java/com/android/server/BluetoothManagerService.java。

我们看一下怎么从 BluetoothManagerService 中获取到 IBluetoothGatt 的 Binder 的。注意到 BluetoothManagerService 中有一个方法 bluetoothStateChangeHandler(),冲方法名就大概可以知道这个方法是在蓝牙状态变化的时候,做一些处理的。跟踪以下这个函数的调用的地方,就能验证我们的猜想是对的。这一块和本文的关系不大,我们现在来看一下 bluetoothStateChangeHandler() 的具体实现:
<code>
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);
}

}</code>
看到 if (isUp) 这个分支中,会绑定到以 IBluetoothGatt 的类名为 Action Name 的服务,也就是 action="android.bluetooth.IBluetoothGatt"。我们在 /packages/apps/Bluetooth 这个 App 的 AndroidManifest.xml 中找到如下的声明:
<code>
<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> </code>
我们找到了,原来是绑定到了 com.android.bluetooth.gatt.GattService 上了。如果绑定成功,会回调 mConnection 的 onServiceConnected(),其实现如下:
<code>
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);
}</code>
如果绑定的类名是 GattService,就会发送MESSAGE_BLUETOOTH_SERVICE_CONNECTED 消息给 mHandler,消息的第一个参数为 SERVICE_IBLUETOOTHGATT,我们接下来看 mHandler 怎么处理的:
<ocde>
@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;
}
...
}
}
}
}</code>
最终获得 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 的一个内部类:
<code>
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);
}
}</code>
可以看到,实际上这里还是调用了 GattService 的 registerClient 方法:
<code>
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());

}</code>
这里首先是把 uuid 以及对应的 callback 保存到一个 mClientMap 中去,这里从名字上我们就能大概清楚这里的作用,这里的 uuid 是客户端的唯一标示, uuid 对应了客户端的回调函数 callback。接下来,调用了 gattClientRegisterAppNative() 接口向底层协议栈注册客户端,看一下函数定义:
<code>
private native void gattClientRegisterAppNative(long app_uuid_lsb, long app_uuid_msb); </code>
这里可以看出,实际上是客户端的标示 -- UUID 注册到底层去,UUID 是 128 bit, 正好用两个 long 型的参数表示。这个函数是 JNI 的申明,具体的实现就在对应的 C/C++ 代码中。

蓝牙服务和 HAL 的调用:JNI
上面的 gattClientRegisterAppNative() 对应的 JNI 的代码在哪里呢?通过查看 AndroidManifest.xml,我们知道 Bluetooth 的自定义 Application 是 AdapterApp,里面有这样的代码:
<code>
static {
if (DBG) Log.d(TAG,"Loading JNI Library");
System.loadLibrary("bluetooth_jni");
}</code>
这里是加载了 libbluetooth_jni.so 动态库。我们再看 jni 目录的 Android.mk,这里正好是生成 libbluetooth_jni 的编译脚本。这样我们就知道了对应的 C/C++ 代码在 com_android_bluetooth_gatt.cpp:
<code>
static JNINativeMethod sMethods[] = {
...
{"gattClientRegisterAppNative", "(JJ)V", (void ) gattClientRegisterAppNative},
...
}</code>
这是注册 JNI 函数的标准方法,关于 JNI 的详细语法,可以参考这里。可以找到对应的函数实现如下:
<code>
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);

}</code>
这里调用了 sGattIf 的 client 的 register_client() 方法,这里还是把客户端的标示 UUID 传递下去。这里的 sGattIf 是什么呢?

static const btgatt_interface_t *sGattIf = NULL;
它是一个 btgatt_interface_t 类型的变量,sGattIf 的初始化在 initializeNative() 中,这个函数在 GattService.start() 方法中被调用了,这个函数定义如下:
<code>
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;
}
...
}</code>
注意这里首先通过 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 的定义如下:
<code>
/** 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;</code>
可以看到 btgatt_interface_t 有一个成员 client,类型是 btgatt_client_interface_t。 我们再来看 btgatt_client_interface_t 的定义,在 bt_gatt_client.h 中:
<code>
/** 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;</code>
在这里我们看到了 register_client 这个函数指针。这个结构体的定义很长,我这里只截取了本文相关的内容。这里定义了所有 GATT 客户端操作相关的接口,例如连接、扫描、获取 Gatt Service、读写 Gatt characteristic/descriptor 等等。 但是这个结构体的具体实现在什么地方呢?我们的直觉应该就在 HAL 的实现 BlueDroid 模块了。

蓝牙协议栈:BlueDroid
BlueDroid 的代码在 external/bluetooth/bluedroid。我们在这个目录下 grep 一下:
<code>
$ cd external/bluetooth/bluedroid
$ grep -nr 'btgatt_interface_t' .</code>
我们很容易找到 btgatt_interface_t 的实现:
<code>
// btif/src/btif_gatt.c
static const btgatt_interface_t btgattInterface = {
sizeof(btgattInterface),

btif_gatt_init,
btif_gatt_cleanup,

&btgattClientInterface,
&btgattServerInterface,

};</code>
然后在 btif/src/btif_gatt_client.c,找到 btgattClientInterface 具体的实现如下:
<code>
const btgatt_client_interface_t btgattClientInterface = {
btif_gattc_register_app,
btif_gattc_unregister_app,
btif_gattc_open,
btif_gattc_close,
...
}</code>
看到这里定义了一个 btgatt_client_interface_t 的实例 btgattClientInterface,内部都是函数指针,所有的函数的实现都这这个文件中能找到。其实这个变量就是前面的代码中提到的 sGattIf->client,我们下面来看看这是是怎么关联上的。 在 btif/src/btif_gatt.c 中又如下定义:
<code>
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;
}</code>
从代码中可以看出,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 中:
<code>
static const void
get_profile_interface (const char *profile_id)
{
...
if (is_profile(profile_id, BT_PROFILE_GATT_ID))
return btif_gatt_get_interface();
...
}</code>
看到这里调用了 btif_gatt_get_interface(),实际上就是把 btgattInterface 返回赋值给了 sGattIf。

到这里,变量之间的相互关系和初始化就都完全清楚了。还是不要忘记我们的目标:连接 BLE 设备。前面我们分析到了,发起 BLE 设备连接,首先是向底层协议栈注册客户端,也就是调用了 sGattIf->client->register_client(&uuid);。 现在我们知道了 register_client() 的实现就在 btif/src/btif_gatt_client.c,对应的实现如下:
<code>
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);
}</code>
这里的 btif_transfer_context() 是一个工具方法,代码如下:
<code>
// 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;
}

}</code>
这里面调用了一个很重要的方法 btif_sendmsg(...),实际上是调用了 GKI_send_msg(...),接着往下看代码就会发现,实际上就是发送一个 Event,让对应的 handler 函数去处理。 据我的理解,其实就是一个类似于 Android framework 中的 Handler,你可以提交你的 Task 到指定的线程中去运行。 这里 btif_transfer_context(...) 的作用就是把代码运行的上下文(context)转为蓝牙协议栈,这部分的代码和本文关系不大,这里就不深入讨论了。 这里的 btgattc_handle_event 相当于我们要运行的 Task, 后面就是这个 Task 运行需要的一些参数。我们接下来看 btgattc_handle_event 的实现:
<code>
// 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;
            ...
    }

}</code>
可以看到,这个函数的参数,都是我们上面那个 btif_transfer_context(...) 传递进来的,这里 event = BTIF_GATTC_REGISTER_APP,看一下对应的 switch 分支代码。 btif_to_bta_uuid() 非常简单,这是把 UUID 的转换为 BTA 层 UUID 格式。然后真正做事的是 BTA_GATTC_AppRegister(...):
<code>
// 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;

}</code>
这里首先判断 BTA_ID_GATTC 事件处理器是否注册了,如果没有注册就注册一个 bta_gattc_reg。这里表示 bta_gattc_reg 所有的 GATT 客户端事件的处理器。 可见,这个 bta_gattc_reg 是非常重要的,我们来看它的定义:
<code>
// 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
};</code>
这是一个结构体,其定义我也贴在上面了,成员类型都是函数指针,其函数的定义我在后面会讲。 我们先往下看,这里的代码是不是看起来有些面熟,其实和 btif_transfer_context() 的逻辑非常类似,这里也是发送一个 event 给 handler 去处理。 虽然这里调用的是 bta_sys_sendmsg(...),实际上它的实现就是调用 GKI_send_msg(...)。 分析方法类似,我们这里的 event 是 BTA_GATTC_API_REG_EVT,这个事件的处理函数就是上面的 bta_gattc_reg 的 bta_gattc_hdl_event:
<code>
// 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;
...
}
...
}</code>
到这里,我们终于看到了最终的真正执行注册客户端的函数 bta_gattc_register(...) 了:
<code>
// 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);
}  

}</code>
主要流程都在代码的注释中解释了,遍历客户端列表,向 GATT statck 注册客户端,注册成功后发送 BTA_GATTC_INT_START_IF_EVT 事件。 因为这里和前面一样,同样是调用了 bta_sys_sendmsg(...),所以处理函数是 bta_gattc_hdl_event(...),我们再来看这个分支:
<code>
// 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;
...
}
}</code>
这里调用了 bta_gattc_start_if(...):
<code>
// 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 );
}
}</code>
最终调用了 GATT_StartIf(...):
<code>
// 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;
    }
}

}</code>
这个函数的主要作用是,调用刚注册的客户端 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):
<code>
// bta/gatt/bta_gattc_int.h
typedef union
{
BT_HDR hdr;
tBTA_GATTC_API_REG api_reg;
...
} tBTA_GATTC_DATA;</code>
其中 (p_data->api_reg) 成员是一个 tBTA_GATTC_API_REG,这个类型我们在 BTA_GATTC_AppRegister(...) 函数中见过。 其实这个值就是我们在这里创建的,我们看一下 p_cback 是谁,我们在往回找到 btgattc_handle_event(...) 函数,发现就是 bta_gattc_cback:其定义如下:
</code>
// 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);
}</code>
这里又是一个通过 "handler" 机制实现运行上下文的切换,这里来看一下事件处理函数 btif_gattc_upstreams_evt:
</code>
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);

}</code>
因为上面传递进来的 event 是 BTA_GATTC_REG_EVT,我们就来看这个 event 的处理代码。 bta_to_btif_uuid() 和上面的 btif_to_bta_uuid() 相反,把 BTA 的 UUID 转换为 BTIF 的格式。 然后,一个宏 HAL_CBACK,其定义如下:
<code>

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);  \
}</code>

这里展开一下,并替换其中实际的变量:

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 层的代码:
<code>
// /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);

}</code>
这里调用了 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);。具体的流程和上面整个分析类似。 有了上面的整个分析经验,这次应该就驾轻就熟了。所以我这里也不再往下继续说了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容