- 依次执行两个函数: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。