GattCallback: memory safe onDescriptorRead

Change the method signature of GattCallback.onDescriptorRead to be memory safe. See Android 13 (Tiramisu, API 33) documentation for background.

To be memory safe onDescriptorRead should always evaluate the `value` parameter, potential in combination with BLETypeConversions, and not use:
- BluetoothGattDescriptor.getValue
- BluetoothGattDescriptor.getIntValue
- BluetoothGattDescriptor.getFloatValue
- BluetoothGattDescriptor.getStringValue
This commit is contained in:
Thomas Kuehne
2025-05-13 19:36:17 +00:00
committed by José Rebelo
parent e1de7efa55
commit 7733f7ed28
6 changed files with 28 additions and 10 deletions
@@ -403,9 +403,9 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im
}
@Override
public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status, byte[] value) {
for (AbstractBleProfile<?> profile : mSupportedProfiles) {
if (profile.onDescriptorRead(gatt, descriptor, status)) {
if (profile.onDescriptorRead(gatt, descriptor, status, value)) {
return true;
}
}
@@ -489,9 +489,9 @@ public abstract class AbstractBTLEMultiDeviceSupport extends AbstractDeviceSuppo
@Override
public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
int status, byte[] value) {
for (AbstractBleProfile<?> profile : mSupportedProfiles) {
if (profile.onDescriptorRead(gatt, descriptor, status)) {
if (profile.onDescriptorRead(gatt, descriptor, status, value)) {
return true;
}
}
@@ -197,8 +197,8 @@ public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport>
}
@Override
public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
return mSupport.onDescriptorRead(gatt, descriptor, status);
public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status, byte[] value) {
return mSupport.onDescriptorRead(gatt, descriptor, status, value);
}
@Override
@@ -48,7 +48,7 @@ public abstract class AbstractGattCallback implements GattCallback {
}
@Override
public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status, byte[] value) {
return false;
}
@@ -644,13 +644,19 @@ public final class BtLEQueue {
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
byte[] value = emulateMemorySafeValue(descriptor, status);
onDescriptorRead(gatt, descriptor, status, value);
}
@Override
public void onDescriptorRead(@NonNull BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
LOG.debug("descriptor read: {} {}", descriptor.getUuid(), BleNamesResolver.getStatusString(status));
if (!checkCorrectGattInstance(gatt, "descriptor read")) {
return;
}
if (getCallbackToUse() != null) {
try {
getCallbackToUse().onDescriptorRead(gatt, descriptor, status);
getCallbackToUse().onDescriptorRead(gatt, descriptor, status, value);
} catch (Throwable ex) {
LOG.error("onDescriptorRead failed", ex);
}
@@ -757,6 +763,18 @@ public final class BtLEQueue {
}
return EMPTY;
}
/// helper to emulate Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU on older APIs
private byte[] emulateMemorySafeValue(BluetoothGattDescriptor descriptor,
int status){
if(status == BluetoothGatt.GATT_SUCCESS) {
byte[] value = descriptor.getValue();
if (value != null) {
return value.clone();
}
}
return EMPTY;
}
}
// Implements callback methods for GATT server events that the app cares about. For example,
@@ -78,10 +78,10 @@ public interface GattCallback {
* @param gatt
* @param descriptor
* @param status
* @see BluetoothGattCallback#onDescriptorRead(BluetoothGatt, BluetoothGattDescriptor, int)
* @see BluetoothGattCallback#onDescriptorRead(BluetoothGatt, BluetoothGattDescriptor, int, byte[])
*/
boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status);
int status, byte[] value);
/**
* @param gatt