公司做了一个多连的ble应用,其他设备正常使用,但是在oppoAX7上出现了连上后过一会就断开的情况,这种情况只有在多连的时候才会出现,查了下日志发现断开的都是onClientConnectionState() - status=8 状态为8,查了好久才找到一个博主给了答案,搬运内容:
GATT_SUCCESS和GATT_FAILURE(不常见)在BluetoothGatt源码中可以找到外,其他8、22、133等status状态值不知道其意义,对于断开连接的原因就不好判断了。
下面我们从framework源码追查这几个状态
_bluetoothGatt = device.connectGatt(_context, false, mGattCallback);
BluetoothDevice connectGatt方法将mGattCallback传入
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport) {
// TODO(Bluetooth) check whether platform support BLE
// Do the check here or in GattServer?
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager managerService = adapter.getBluetoothManager();
try {
IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) {
// BLE is not supported
return null;
}
BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport);
gatt.connect(autoConnect, callback);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
connect方法中创建了BluetoothGatt对象,gatt connect方法将callback导入,我们继续看BluetoothGatt源码
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;
}
mAutoConnect = autoConnect;
if (!registerApp(callback)) {
synchronized(mStateLock) {
mConnState = CONN_STATE_IDLE;
}
Log.e(TAG, "Failed to register callback");
return false;
}
// The connection will continue in the onClientRegistered callback
return true;
}
继续看reigsterApp方法
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是IBluetoothGatt接口的Proxy端
查找源码发现IBluetoothGatt的Stub端在GattService中实现,我们看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, this);
gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
uuid.getMostSignificantBits());
}
mClientMap管理各个APP的callback对象
void onConnected(int clientIf, int connId, int status, String address)
throws RemoteException {
if (DBG) Log.d(TAG, "onConnected() - clientIf=" + clientIf
+ ", connId=" + connId + ", address=" + address);
if (status == 0) mClientMap.addConnection(clientIf, connId, address);
ClientMap.App app = mClientMap.getById(clientIf);
if (app != null) {
app.callback.onClientConnectionState(status, clientIf,
(status==BluetoothGatt.GATT_SUCCESS), address);
}
}
void onDisconnected(int clientIf, int connId, int status, String address)
throws RemoteException {
if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf
+ ", connId=" + connId + ", address=" + address);
mClientMap.removeConnection(clientIf, connId);
ClientMap.App app = mClientMap.getById(clientIf);
if (app != null) {
app.callback.onClientConnectionState(status, clientIf, false, address);
}
}
在GattService的onConnected和onDisconnected方法中我们找到了callback.onClientConnectionState的调用,那么这两个方法是谁调用的,很显然这个调用者来自jni底层
method_onConnected = env->GetMethodID(clazz, "onConnected", "(IIILjava/lang/String;)V");
method_onDisconnected = env->GetMethodID(clazz, "onDisconnected", "(IIILjava/lang/String;)V");
com_android_bluetooth_gatt.cpp中有关于这两个方法的反射调用
void btgattc_close_cb(int conn_id, int status, int clientIf, bt_bdaddr_t* bda)
{
CHECK_CALLBACK_ENV
char c_address[32];
snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X",
bda->address[0], bda->address[1], bda->address[2],
bda->address[3], bda->address[4], bda->address[5]);
jstring address = sCallbackEnv->NewStringUTF(c_address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDisconnected,
clientIf, conn_id, status, address);
sCallbackEnv->DeleteLocalRef(address);
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
com_android_bluetooth_gatt的btgattc_close_cb方法中调用了onDisconnected,但是status依然是外部导入的,我们继续追。
btgattc_close_cb是BTA client callback,所以答案应该在BTA
BTA就是Bluetooth Application,所有蓝牙请求都必须进过它,我们看bta目录下的h文件,目录是system/bt/bta
最终,我们在bta_gatt_api.h中找到了status 8, 22, 133等错误
#define BTA_GATT_OK GATT_SUCCESS #define BTA_GATT_INVALID_HANDLE GATT_INVALID_HANDLE #define BTA_GATT_READ_NOT_PERMIT GATT_READ_NOT_PERMIT #define BTA_GATT_WRITE_NOT_PERMIT GATT_WRITE_NOT_PERMIT #define BTA_GATT_INVALID_PDU GATT_INVALID_PDU #define BTA_GATT_INSUF_AUTHENTICATION GATT_INSUF_AUTHENTICATION #define BTA_GATT_REQ_NOT_SUPPORTED GATT_REQ_NOT_SUPPORTED #define BTA_GATT_INVALID_OFFSET GATT_INVALID_OFFSET #define BTA_GATT_INSUF_AUTHORIZATION GATT_INSUF_AUTHORIZATION #define BTA_GATT_PREPARE_Q_FULL GATT_PREPARE_Q_FULL #define BTA_GATT_NOT_FOUND GATT_NOT_FOUND #define BTA_GATT_NOT_LONG GATT_NOT_LONG #define BTA_GATT_INSUF_KEY_SIZE GATT_INSUF_KEY_SIZE #define BTA_GATT_INVALID_ATTR_LEN GATT_INVALID_ATTR_LEN #define BTA_GATT_ERR_UNLIKELY GATT_ERR_UNLIKELY #define BTA_GATT_INSUF_ENCRYPTION GATT_INSUF_ENCRYPTION #define BTA_GATT_UNSUPPORT_GRP_TYPE GATT_UNSUPPORT_GRP_TYPE #define BTA_GATT_INSUF_RESOURCE GATT_INSUF_RESOURCE #define BTA_GATT_NO_RESOURCES GATT_NO_RESOURCES #define BTA_GATT_INTERNAL_ERROR GATT_INTERNAL_ERROR #define BTA_GATT_WRONG_STATE GATT_WRONG_STATE #define BTA_GATT_DB_FULL GATT_DB_FULL #define BTA_GATT_BUSY GATT_BUSY #define BTA_GATT_ERROR GATT_ERROR #define BTA_GATT_CMD_STARTED GATT_CMD_STARTED #define BTA_GATT_ILLEGAL_PARAMETER GATT_ILLEGAL_PARAMETER #define BTA_GATT_PENDING GATT_PENDING #define BTA_GATT_AUTH_FAIL GATT_AUTH_FAIL #define BTA_GATT_MORE GATT_MORE #define BTA_GATT_INVALID_CFG GATT_INVALID_CFG #define BTA_GATT_SERVICE_STARTED GATT_SERVICE_STARTED #define BTA_GATT_ENCRYPED_MITM GATT_ENCRYPED_MITM #define BTA_GATT_ENCRYPED_NO_MITM GATT_ENCRYPED_NO_MITM #define BTA_GATT_NOT_ENCRYPTED GATT_NOT_ENCRYPTED #define BTA_GATT_CONGESTED GATT_CONGESTED #define BTA_GATT_DUP_REG 0x90 #define BTA_GATT_ALREADY_OPEN 0x91 #define BTA_GATT_CANCEL 0x92
#define BTA_GATT_CONN_UNKNOWN 0 #define BTA_GATT_CONN_L2C_FAILURE GATT_CONN_L2C_FAILURE #define BTA_GATT_CONN_TIMEOUT GATT_CONN_TIMEOUT #define BTA_GATT_CONN_TERMINATE_PEER_USER GATT_CONN_TERMINATE_PEER_USER #define BTA_GATT_CONN_TERMINATE_LOCAL_HOST GATT_CONN_TERMINATE_LOCAL_HOST #define BTA_GATT_CONN_FAIL_ESTABLISH GATT_CONN_FAIL_ESTABLISH #define BTA_GATT_CONN_LMP_TIMEOUT GATT_CONN_LMP_TIMEOUT #define BTA_GATT_CONN_CANCEL GATT_CONN_CANCEL #define BTA_GATT_CONN_NONE 0x0101
status 133 GATT_ERROR,这个错误是Android源码的问题
bluetooth lowenergy - Every connection request is being treated as direct connect request + android ble - Stack Overflow
status 22 GATT_CONN_TERMINATE_LOCAL_HOST
https://stackoverflow.com/questions/40966104/how-to-solve-the-error-onclientconnectionstate-status-22-clientif-7-in-ble?noredirect=1
status 8 GATT_CONN_TIMEOUT
参考博客地址:Android 从源码分析BLE连接错误分析_疾风细语的博客-CSDN博客
非常感谢这位大哥的分享



