Android GATT 连接过程源码分析
2016-12-21 12:33
453 查看
http://www.race604.com/gatt-connect/
30 JUNE 2015 on Android, Bluetooth
低功耗蓝牙(BLE)设备的通信基本协议是 GATT, 要操作 BLE 设备,第一步就是要连接设备,其实就是连接 BLE 设备上的 GATT service。 结合上一篇文章,我这里结合源码,分析一下
GATT 连接的流程,以及各个模块是怎么相互交互的。注意本文依据的是 Android 4.4 的源代码。
首先,一般应用层都是通过调用如下方法,来创建一个 GATT 连接的:
这里调用了方法
这里通过
Binder 对象,这是一个非常关键的对象,后面会详细讲。然后调用了
如果为
接下来看
这里面关键的一句是
App,底层就知道有 App 在使用蓝牙,有蓝牙消息的时候,就通过回调通知上层的 App。BLE 几乎所有操作都是通过异步回调实现的,就是通过这个你自定义的
可以看到,这里调用了
Binder 机制中,被绑定的 Service 作为称为服务端,发起绑定的一方是客户端。
在继续往下看
BLE 设备,到这一步了,还没有看到连接动作的踪影。这是怎么回事?前面我们说过,蓝牙几乎所有的操作都是依靠回调实现,我们先来看一下这里的
Gatt 回调动作,我们这里主要看
这个回调方法有两个参数
id。 这个回调方法中做的事情比较清晰,特别注意到
接口开始发起连接了。
从代码中可以看到,
在第一段代码的分析中就提到了
Binder。
我们看一下
这里是一个单例模式,通过系统API
会启动一些系统服务并通过
Binder 对象对应的服务是
我们看一下怎么从
Binder 的。注意到
看到
IBluetoothGatt 的类名为 Action Name 的服务,也就是
App 的
我们找到了,原来是绑定到了
如果绑定的类名是
mHandler 怎么处理的:
最终获得
Binder,并赋值给
至此,通过 Binder 机制,完成了应用框架 API 到 Service 的绑定。别忘了我们的目标:分析BLE连接的流程。通过前面的代码分析我们知道,连接的时候,先调用了 'mService.registerClient()',然后在注册成功后,调用了
Service,也就到了蓝牙服务层了。
蓝牙服务的代码在
Bluetooth.apk,安装在
Binder 是
可以看到,实际上这里还是调用了
这里首先是把
uuid 是客户端的唯一标示, uuid 对应了客户端的回调函数
这里可以看出,实际上是客户端的标示 -- UUID 注册到底层去,UUID 是 128 bit, 正好用两个
C/C++ 代码中。
上面的
JNI 的代码在哪里呢?通过查看
是
这里是加载了
jni 目录的
C/C++ 代码在
这是注册 JNI 函数的标准方法,关于 JNI 的详细语法,可以参考这里。可以找到对应的函数实现如下:
这里调用了
UUID 传递下去。这里的
它是一个
注意这里首先通过
看到这里调用了
现在来看
include 的头文件中,最有可能就是在
HAL 头文件都放在
可以看到
我们再来看
在这里我们看到了
Gatt Service、读写 Gatt characteristic/descriptor 等等。 但是这个结构体的具体实现在什么地方呢?我们的直觉应该就在 HAL 的实现 BlueDroid 模块了。
BlueDroid 的代码在
grep 一下:
我们很容易找到
然后在
看到这里定义了一个
在
从代码中可以看出,
JNI 中的
我们来看一下
看到这里调用了
到这里,变量之间的相互关系和初始化就都完全清楚了。还是不要忘记我们的目标:连接 BLE 设备。前面我们分析到了,发起 BLE 设备连接,首先是向底层协议栈注册客户端,也就是调用了
现在我们知道了
这里的
这里面调用了一个很重要的方法
Event,让对应的 handler 函数去处理。 据我的理解,其实就是一个类似于 Android framework 中的
Task 到指定的线程中去运行。 这里
这里的
可以看到,这个函数的参数,都是我们上面那个
UUID 的转换为 BTA 层 UUID 格式。然后真正做事的是
这里首先判断
GATT 客户端事件的处理器。 可见,这个
这是一个结构体,其定义我也贴在上面了,成员类型都是函数指针,其函数的定义我在后面会讲。 我们先往下看,这里的代码是不是看起来有些面熟,其实和
event 给 handler 去处理。 虽然这里调用的是
分析方法类似,我们这里的 event 是
到这里,我们终于看到了最终的真正执行注册客户端的函数
主要流程都在代码的注释中解释了,遍历客户端列表,向 GATT statck 注册客户端,注册成功后发送
因为这里和前面一样,同样是调用了
这里调用了
最终调用了
这个函数的主要作用是,调用刚注册的客户端
我们接着分析
这里是看起来调用了一个回调函数,这里的
回到
其中
其实这个值就是我们在这里创建的,我们看一下
这里又是一个通过 "handler" 机制实现运行上下文的切换,这里来看一下事件处理函数
因为上面传递进来的 event 是
event 的处理代码。
BTA 的 UUID 转换为 BTIF 的格式。 然后,一个宏
这里展开一下,并替换其中实际的变量:
可以看到这里其实就是一个执行回调函数的宏。
现在问题是
也就是初始化的时候,通过传递进来的。在分析 BlueDroid 的最开始我们已经看到了
通过我们前面的分析,
JNI 层的代码:
这里调用了
BlueDroid 层寻找的
通过前面的分析,我们应该能很快知道
HAL 中定义的,然后
在来看
这里的
实际上就是调用了 JNI 中定义的
这里通过 JNI 调用了函数 id 为
这里就对应了 Java class 中的
我们在
可见,上面的
GattService 的成员方法。我们在 GattService 类中找到其实现如下:
哈哈,终于回到我们熟悉的 Java 层代码。还记得我们前面的在分析调用
uuid 对应起来,保存在 mClientMap 中。 这里通过 uuid 找到对应的客户端App,然后调用对应的回调函数
这个
1 节)。到这里,其实就回调了 Android framework 层了。
如果这里注册客户端成功了,回调的
结合文章开始的那个图,回顾一下代码整个调用过程,非常清楚印证流程:framework -> Bluetooth service -> JNI -> HAL -> BlueDroid。
整个分析下来,几乎贯穿了整个 Android 系统,尽管还有很多细节没有展开去了解,但是脉络还是很清晰的。 第一次写分析源代码的文章,不知不觉就写了这么长(其实大部分是代码),花费了很多精力,也不知道说清楚了没有。对我自己来说,还是收获不少。
Android GATT 连接过程源码分析
30 JUNE 2015 on Android, Bluetooth低功耗蓝牙(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 系统,尽管还有很多细节没有展开去了解,但是脉络还是很清晰的。 第一次写分析源代码的文章,不知不觉就写了这么长(其实大部分是代码),花费了很多精力,也不知道说清楚了没有。对我自己来说,还是收获不少。
相关文章推荐
- Android蓝牙源码分析——Gatt连接(一)
- Android Gatt连接流程源码分析之ClientIf注册
- Android 源码分析 -- (一) Android启动过程
- Android-vold源码分析之连接电脑OTG(11)
- Android应用程序与SurfaceFlinger服务的连接过程分析
- Android 源码分析 -- (一) Android启动过程
- smack 源码分析- PacketWriter (android上兑现长连接)
- smack 源码分析一(android上实现长连接)
- Android应用程序与SurfaceFlinger服务的连接过程分析
- android 4.04的应用程序启动过程及与Zygote的交互(基于静态源码分析)
- Android Jamendo源码分析之 网络连接模块
- android之XMPP过程分析(连接、文件监听、登录、异常重连)
- Android Jamendo开源在线音乐播放器源码分析五 网络连接模块的分析
- smack 源码分析- PacketWriter (android上实现长连接)
- 分析Android应用程序与SurfaceFlinger连接过程
- Android-vold源码分析之连接电脑OTG(11)
- Android 4.0 Launcher2源码分析——启动过程分析
- Android 4.0 Launcher2源码分析——Launcher内容加载详细过程
- Android-vold源码分析之连接电脑OTG
- smack 源码分析- PacketReader (android上兑现长连接)