- 依次执行两个函数:mService.registerClient()和mService.clientConnect()。对mService.registerClient(),主要两个操作。1)向GATT协议栈注册,并获得新的client_if。此过程只是在gatt_cb.cl_rcb得到一个可用位置,不会触发蓝牙数据传输。2)调用JNI注册的回调函数:btgattc_register_app_cb,进而回调BluetoothGatt.mBluetoothGattCallback.onClientRegistered。onClientRegistered不会回调到app,而是“向下”执行connectGatt的第二个函数:mService.clientConnect()。
不要忘记我们的目标:连接BLE设备。前面我们分析到了,发起 BLE 设备连接,首先是向底层协议栈注册客户端,也就是调用了“sGattIf->client->register_client(&uuid)”,现在知道了register_client()的实现是btif_gattc_register_app。
<aosp>/system/bt/btif/src/btif_gatt_client.cc
------
static bt_status_t btif_gattc_register_app(const Uuid& uuid,
bool eatt_support) {
CHECK_BTGATT_INIT();
return do_in_jni_thread(Bind(
[](const Uuid& uuid, bool eatt_support) {
BTA_GATTC_AppRegister(
bta_gattc_cback,
base::Bind(
[](const Uuid& uuid, uint8_t client_id, uint8_t status) {
do_in_jni_thread(Bind(
[](const Uuid& uuid, uint8_t client_id, uint8_t status) {
HAL_CBACK(bt_gatt_callbacks, client->register_client_cb,
status, client_id, uuid);
},
uuid, client_id, status));
},
uuid),
eatt_support);
},
uuid, eatt_support));
}do_in_jni_thread使用了MessageLoopThread机制,这类似chormium线程模型,实现了可向线程a的message_loop_投递一个函数f,然后在将来某个时刻,线程a就会以f()方法调用函数f。do_in_jni_thread是将f发向了bt_jin_thread线程,除它外,do_in_main_thread也在使用MessageLoopThread机制,只是改发向bt_main_thread线程。
将函数f发向bt_jni_thread,意味着这些操作将在bt_jni_thread被依次序列化执行,这大大减少多线程并发,这自然就提高了bt协议栈稳定性、以及简化编程模型。
虽然btif_gattc_register_app内只有一条语句,但从外到内实现了三个函数。
- Bind([](const Uuid& uuid, bool eatt_support){...}, uuid, eatt_support)。
最外层函数,最先执行。bt_jni_thread调用时是以不带参数的f(),可这函数需要两个参数,第二个参数uuid给uuid传值,第三个eatt_support则传给eatt_support。 - base::Bind([](const Uuid& uuid, uint8_t client_id, uint8_t status){...}, uuid)。
它的结果将传给BTA_GATTC_AppRegister的第二个参数cb(类型BtaAppRegisterCallback)。外面调用时会f(client_id, status)进行调用,base::Bind的第二个参数uuid给lambda函数的第一个参数传值。 - Bind([](const Uuid& uuid, uint8_t client_id, uint8_t status){...}, uuid, client_id, status)。
上面的base::Bind实现的数就一个操作,在bt_jni_thread线程执行这个lambad函数。简单来说,就是让在bt_jni_thread执行HAL_CBACK。
总之,btif_gattc_register_app就一个逻辑,在bt_jni_thread执行BTA_GATTC_AppRegiste。
<aosp>/system/bt/bta/gatt/bta_gattc_api.cc
------
void BTA_GATTC_AppRegister(tBTA_GATTC_CBACK* p_client_cb,
BtaAppRegisterCallback cb, bool eatt_support) {
if (!bta_sys_is_register(BTA_ID_GATTC))
bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
do_in_main_thread(
FROM_HERE, base::Bind(&bta_gattc_register, Uuid::GetRandom(), p_client_cb,
std::move(cb), eatt_support));
}BTA_GATTC_AppRegister依次执行两个操作。
- 如果没有注册过BTA_ID_GATTC事件类处理函数,调用bta_sys_register执行注册。
- 生成一个随机uuid,在bt_main_thread执行bta_gattc_register。
第一个操作bta_sys_register,后面一并说。看第二个操作,bta_gattc_register,这函数真正执行着注册客户端。
<aosp>/system/bt/bta/gatt/bta_gattc_act.cc
------
/** Register a GATT client application with BTA */
void bta_gattc_register(const Uuid& app_uuid, tBTA_GATTC_CBACK* p_cback,
BtaAppRegisterCallback cb, bool eatt_suppport) {
tGATT_STATUS status = GATT_NO_RESOURCES;
uint8_t client_if = 0;
// 检查 GATTC 模块是否开启;如果没有,就开启
if (bta_gattc_cb.state == BTA_GATTC_STATE_DISABLED) {
bta_gattc_enable();
}
// 这里遍历cl_rcb数组,cl_rcb存储着app的注册信息
for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i++) {
if (!bta_gattc_cb.cl_rcb[i].in_use) {
// 找到一个未使用(in_use==false)插槽,该插槽将被用于此次访问。
// 注意,client_if和插槽索引i无关。
if ((bta_gattc_cb.cl_rcb[i].client_if = GATT_Register(
app_uuid, "GattClient", &bta_gattc_cl_cback, eatt_suppport)) ==
0) {
LOG(ERROR) << "Register with GATT stack failed.";
status = GATT_ERROR;
} else {
bta_gattc_cb.cl_rcb[i].in_use = true;
// p_cback是传给BTA_GATTC_AppRegister的第一个参数,即bta_gattc_cback
bta_gattc_cb.cl_rcb[i].p_cback = p_cback;
bta_gattc_cb.cl_rcb[i].app_uuid = app_uuid;
/* BTA use the same client interface as BTE GATT statck */
client_if = bta_gattc_cb.cl_rcb[i].client_if;
// 注册成功,发送 BTA_GATTC_INT_START_IF_EVT 事件
do_in_main_thread(FROM_HERE,
base::Bind(&bta_gattc_start_if, client_if));
status = GATT_SUCCESS;
break;
}
}
}
// cb是传给BTA_GATTC_AppRegister的第二个参数,
// 即btif_gattc_register_app内3个lambad的第二个
// 通过发送 BTA_GATTC_REG_EVT 事件,把注册结果回调给上层
if (!cb.is_null()) cb.Run(client_if, status);
}bta_gattc_register依次执行四个操作。
- 遍历cl_rcb列表,找到一个未使用(in_use==false)插槽,然后调用GATT_Register算出client_if,告知我这个app使用这个插槽了。注意,client_if值是占用单元在一个数组内从1开始的索引,但这个数组不是插槽所在的cl_rcb,而是全局数组gatt_cb.cl_rcb[GATT_MAX_APPS]。因为GATT_MAX_APPS值是32,所以client_if范围是[1, 32]。
- 给bta_gattc_cb.cl_rcb[i]各字段赋值。client_if、in_use、p_cback、app_uuid。额外说下p_cback,它的值来自传给BTA_GATTC_AppRegister的第一个参数,即bta_gattc_cback。后面多个地方会发现,bt协议栈向回调bt-JNI中函数靠的就是它。
- 在bt_main_thread执行bta_gattc_start_if。
- cb.Run(client_if, status)。把此次注册结果返回给bt-JNI,返回说来就是回调bt-JNI注册的回调函数。
一、调用GATT_Register找到一个可用插槽,调用GATT_Register计算client_if
typedef struct {
tGATT_TCB tcb[GATT_MAX_PHY_CHANNEL];
...
tGATT_REG cl_rcb[GATT_MAX_APPS];
tGATT_CLCB clcb[GATT_CL_MAX_LCB]; /* connection link control block*/
...
} tGATT_CB;
tGATT_CB gatt_cb;
<apsp>/system/bt/stack/gatt/gatt_api.cc
------
tGATT_IF GATT_Register(const Uuid& app_uuid128, std::string name,
tGATT_CBACK* p_cb_info, bool eatt_support) {
tGATT_REG* p_reg;
uint8_t i_gatt_if = 0;
tGATT_IF gatt_if = 0;
for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
i_gatt_if++, p_reg++) {
if (p_reg->in_use && p_reg->app_uuid128 == app_uuid128) {
// 不允许重复注册同一个app_uuid128
return 0;
}
}
for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
i_gatt_if++, p_reg++) {
if (!p_reg->in_use) {
*p_reg = {};
i_gatt_if++; /* one based number */
p_reg->app_uuid128 = app_uuid128;
gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if;
p_reg->app_cb = *p_cb_info;
p_reg->in_use = true;
p_reg->eatt_support = eatt_support;
p_reg->name = name;
LOG_INFO("Allocated name:%s uuid:%s gatt_if:%hhu eatt_support:%u",
name.c_str(), app_uuid128.ToString().c_str(), gatt_if,
eatt_support);
return gatt_if;
}
}
return 0;
}gatt_cb是个全局变量,注册到gatt_cb.cl_rcb的用户有若干种,bta_gattc_register只是当中一种,作为易记,可认为name="GattClient"这这类用户的标识。一个用户占用一个单元后,GATT_Register会向logcat输出类似“Allocated name: ...”,让看一次android设备从开机开始的日志。
前面4个是在android启动阶阶段时输出的 ----------------- GATT_Register: Allocated name:GattProfileDb uuid:81818181-8181-8181-8181-818181818181 gatt_if:1 eatt_support:0 GATT_Register: Allocated name:Gap uuid:82828282-8282-8282-8282-828282828282 gatt_if:2 eatt_support:0 GATT_Register: Allocated name:GattClient uuid:7adebf0e-b4b7-c41b-4027-bd5e234ca56c gatt_if:3 eatt_support:0 GATT_Register: Allocated name:GattClient uuid:c88155b2-89e4-952e-1ee8-7bc03ba9f870 gatt_if:4 eatt_support:0 进入桌面,运行一个ble cenger app。开始扫描 GATT_Register: Allocated name:GattClient uuid:b8a12676-459f-3a5e-d747-e98a888002b4 gatt_if:5 eatt_support:0 在该app结束扫描,连接一个peripheral GATT_Register: Allocated name:GattClient uuid:ba40e20a-c435-285b-d455-37205d56e962 gatt_if:5 eatt_support:0 在该app断开连接,再次开始扫描 GATT_Register: Allocated name:GattClient uuid:719a97b9-7291-207a-0e02-0d9cdfe3aec2 gatt_if:6 eatt_support:0
从上面logcat可得出几个结论
- client_if/gatt_if是从1开始赋值。
- android启动阶段会占用数个单元,这些可认为是bt协议栈系统占用。
- 由于有bt协议栈系统占用,第一个ble cenger app得到的client_if不是1。
二、给bta_gattc_cb.cl_rcb[i]各字段赋值
client_if、in_use、p_cback、app_uuid。额外说下p_cback,它的值来自传给BTA_GATTC_AppRegister的第一个参数,即bta_gattc_cback。后面多个地方会发现,bt协议栈向回调bt-JNI中函数靠的就是它。
三、在bt_main_thread执行bta_gattc_start_if
<aosp>/system/bt/bta/gatt/bta_gattc_act.cc
------
void bta_gattc_start_if(uint8_t client_if) {
GATT_StartIf(client_if);
}
<aosp>/system/bt/stack/gatt/gatt_api.cc
------
void GATT_StartIf(tGATT_IF gatt_if) {
tGATT_REG* p_reg;
tGATT_TCB* p_tcb;
RawAddress bda;
uint8_t start_idx, found_idx;
uint16_t conn_id;
tBT_TRANSPORT transport;
LOG_DEBUG("Starting GATT interface gatt_if_:%hu", gatt_if);
p_reg = gatt_get_regcb(gatt_if);
if (p_reg != NULL) {
start_idx = 0;
while (
gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
p_tcb = gatt_find_tcb_by_addr(bda, transport);
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,
GATT_CONN_UNKNOWN, transport);
}
start_idx = ++found_idx;
}
}
}这个函数的主要作用是,调用刚注册的客户端 gatt_if 的连接回调函数,上报所有的设备的连接状态。
四、cb.Run(client_if, status),回调bt-JNI注册的回调函数
cb是传给BTA_GATTC_AppRegister的第二个参数,即btif_gattc_register_app内3个lambad的第二个。
do_in_jni_thread(Bind(
[](const Uuid& uuid, uint8_t client_id, uint8_t status) {
HAL_CBACK(bt_gatt_callbacks, client->register_client_cb, status, client_id, uuid);
},
uuid, client_id, status));以上代码将在bt_jni_thread线程调用位在bt-JNI内btgattc_register_app_cb(status, client_id, uuid)。
<aosp>/packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
------
void btgattc_register_app_cb(int status, int clientIf, const Uuid& app_uuid) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientRegistered, status,
clientIf, UUID_PARAMS(app_uuid));
}这里通过JNI 调用了函数id为method_onClientRegistered函数。
<aosp>/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 是谁呢?
<aosp>/packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
------
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void *) classInitNative},
...
}我们在 GattService.java 中看到:
<aosp>/packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
------
public class GattService extends ProfileService {
static {
classInitNative();
}
}可见,上面的 clazz 就是 GattService,onClientRegistered 就是 GattService 的成员方法。我们在 GattService 类中找到其实现如下:
<aosp>/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) {
if (status == 0) {
app.id = clientIf;
app.linkToDeath(new ClientDeathRecipient(clientIf));
} else {
mClientMap.remove(uuid);
}
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 层了。
如果mService.registerClient成功,会以参数status=GATT_SUCCESS回调BluetoothGatt的onClientRegistered,当中会发起连接请求:mService.clientConnect(mClientIf, mDevice.getAddress(), !mAutoConnect)。clientConnect会调用JNI函数gattClientConnectNative,后者进一步调用BLE HAL中的btif_gattc_open。