现象描述
调用 readCharacteristic
或者 writeCharacteristic
出现permission check failed! 时, 后面便一直无法读写 characteristic
了。
原因分析
调用
readCharacteristic
方法后mDeviceBusy
被设置为true
/**
* Reads the requested characteristic from the associated remote device.
*
* This is an asynchronous operation. The result of the read operation
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
* callback.
*
*
Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic Characteristic to read from the remote device
* @return true, if the read operation was initiated successfully
*/
public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) {
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) == 0) {
return false;
}
if (VDBG) Log.d(TAG, "readCharacteristic() - uuid: " + characteristic.getUuid());
if (mService == null || mClientIf == 0) return false;
BluetoothGattService service = characteristic.getService();
if (service == null) return false;
BluetoothDevice device = service.getDevice();
if (device == null) return false;
synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
try {
mService.readCharacteristic(mClientIf, device.getAddress(),
characteristic.getInstanceId(), AUTHENTICATION_NONE);
} catch (RemoteException e) {
Log.e(TAG, "", e);
mDeviceBusy = false;
return false;
}
return true;
}
正常情况,成功发完数据后会有
onCharacteristicWrite
返回,并将mDeviceBusy
设置成false
。
/**
* Characteristic has been written to the remote device.
* Let the app know how we did...
* @hide
*/
@Override
public void onCharacteristicWrite(String address, int status, int handle) {
if (VDBG) {
Log.d(TAG, "onCharacteristicWrite() - Device=" + address
+ " handle=" + handle + " Status=" + status);
}
if (!address.equals(mDevice.getAddress())) {
return;
}
synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice,
handle);
if (characteristic == null) return;
if ((status == GATT_INSUFFICIENT_AUTHENTICATION
|| status == GATT_INSUFFICIENT_ENCRYPTION)
&& (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
try {
final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
mService.writeCharacteristic(mClientIf, address, handle,
characteristic.getWriteType(), authReq,
characteristic.getValue());
mAuthRetryState++;
return;
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
mAuthRetryState = AUTH_RETRY_STATE_IDLE;
runOrQueueCallback(new Runnable() {
@Override
public void run() {
final BluetoothGattCallback callback = mCallback;
if (callback != null) {
callback.onCharacteristicWrite(BluetoothGatt.this, characteristic,
status);
}
}
});
}
但是异常情况,当
连接断开
或者permissionCheck
失败,不会去写characteristic
,所以也就不会有onCharacteristicWrite
void writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq,
byte[] value) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (VDBG) {
Log.d(TAG, "writeCharacteristic() - address=" + address);
}
if (mReliableQueue.contains(address)) {
writeType = 3; // Prepared write
}
Integer connId = mClientMap.connIdByAddress(clientIf, address);
if (connId == null) {
Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
return;
}
if (!permissionCheck(connId, handle)) {
Log.w(TAG, "writeCharacteristic() - permission check failed!");
return;
}
gattClientWriteCharacteristicNative(connId, handle, writeType, authReq, value);
}
由于没有收到
onCharacteristicWrite
导致mDeviceBusy
一直是true
,后面再发送其他请求,都会报错。