diff options
7 files changed, 85 insertions, 83 deletions
diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java index 2f32315d27..42dbe0997f 100644 --- a/android/app/src/com/android/bluetooth/gatt/GattService.java +++ b/android/app/src/com/android/bluetooth/gatt/GattService.java @@ -16,7 +16,7 @@ package com.android.bluetooth.gatt; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; @@ -52,6 +52,7 @@ import android.content.Context; import android.content.Intent; import android.net.MacAddress; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Message; @@ -425,40 +426,37 @@ public class GattService extends ProfileService { sGattService = instance; } - // Suppressed since we're not actually enforcing here + // Suppressed because we are conditionally enforcing @SuppressLint("AndroidFrameworkRequiresPermission") - private boolean permissionCheck(UUID characteristicUuid) { - return !isHidCharUuid(characteristicUuid) - || (checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) - == PERMISSION_GRANTED); + private void permissionCheck(UUID characteristicUuid) { + if (!isHidCharUuid(characteristicUuid)) { + return; + } + enforceBluetoothPrivilegedPermission(this); } - // Suppressed since we're not actually enforcing here + // Suppressed because we are conditionally enforcing @SuppressLint("AndroidFrameworkRequiresPermission") - private boolean permissionCheck(int connId, int handle) { - Set<Integer> restrictedHandles = mRestrictedHandles.get(connId); - if (restrictedHandles == null || !restrictedHandles.contains(handle)) { - return true; + private void permissionCheck(int connId, int handle) { + if (!isHandleRestricted(connId, handle)) { + return; } - - return (checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) - == PERMISSION_GRANTED); + enforceBluetoothPrivilegedPermission(this); } - // Suppressed since we're not actually enforcing here + // Suppressed because we are conditionally enforcing @SuppressLint("AndroidFrameworkRequiresPermission") - private boolean permissionCheck(ClientMap.App app, int connId, int handle) { - Set<Integer> restrictedHandles = mRestrictedHandles.get(connId); - if (restrictedHandles == null || !restrictedHandles.contains(handle)) { - return true; - } - - if (!app.hasBluetoothPrivilegedPermission - && checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED)== PERMISSION_GRANTED) { - app.hasBluetoothPrivilegedPermission = true; + private void permissionCheck(ClientMap.App app, int connId, int handle) { + if (!isHandleRestricted(connId, handle) || app.hasBluetoothPrivilegedPermission) { + return; } + enforceBluetoothPrivilegedPermission(this); + app.hasBluetoothPrivilegedPermission = true; + } - return app.hasBluetoothPrivilegedPermission; + private boolean isHandleRestricted(int connId, int handle) { + Set<Integer> restrictedHandles = mRestrictedHandles.get(connId); + return restrictedHandles != null && restrictedHandles.contains(handle); } @Override @@ -2293,7 +2291,13 @@ public class GattService extends ProfileService { ClientMap.App app = mClientMap.getByConnId(connId); if (app != null) { - if (!permissionCheck(app, connId, handle)) { + try { + permissionCheck(connId, handle); + } catch (SecurityException ex) { + // Only throws on T+ as this is an older API and did not throw prior to T + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + throw ex; + } Log.w(TAG, "onNotify() - permission check failed!"); return; } @@ -3246,7 +3250,7 @@ public class GattService extends ProfileService { this, attributionSource, "GattService getOwnAddress")) { return; } - enforcePrivilegedPermission(); + enforceBluetoothPrivilegedPermission(this); mAdvertiseManager.getOwnAddress(advertiserId); } @@ -3530,7 +3534,13 @@ public class GattService extends ProfileService { return; } - if (!permissionCheck(connId, handle)) { + try { + permissionCheck(connId, handle); + } catch (SecurityException ex) { + // Only throws on T+ as this is an older API and did not throw prior to T + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + throw ex; + } Log.w(TAG, "readCharacteristic() - permission check failed!"); return; } @@ -3556,7 +3566,13 @@ public class GattService extends ProfileService { return; } - if (!permissionCheck(uuid)) { + try { + permissionCheck(uuid); + } catch (SecurityException ex) { + // Only throws on T+ as this is an older API and did not throw prior to T + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + throw ex; + } Log.w(TAG, "readUsingCharacteristicUuid() - permission check failed!"); return; } @@ -3586,11 +3602,7 @@ public class GattService extends ProfileService { Log.e(TAG, "writeCharacteristic() - No connection for " + address + "..."); return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED; } - - if (!permissionCheck(connId, handle)) { - Log.w(TAG, "writeCharacteristic() - permission check failed!"); - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION; - } + permissionCheck(connId, handle); Log.d(TAG, "writeCharacteristic() - trying to acquire permit."); // Lock the thread until onCharacteristicWrite callback comes back. @@ -3631,7 +3643,13 @@ public class GattService extends ProfileService { return; } - if (!permissionCheck(connId, handle)) { + try { + permissionCheck(connId, handle); + } catch (SecurityException ex) { + // Only throws on T+ as this is an older API and did not throw prior to T + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + throw ex; + } Log.w(TAG, "readDescriptor() - permission check failed!"); return; } @@ -3655,11 +3673,7 @@ public class GattService extends ProfileService { Log.e(TAG, "writeDescriptor() - No connection for " + address + "..."); return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED; } - - if (!permissionCheck(connId, handle)) { - Log.w(TAG, "writeDescriptor() - permission check failed!"); - return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION; - } + permissionCheck(connId, handle); gattClientWriteDescriptorNative(connId, handle, authReq, value); return BluetoothStatusCodes.SUCCESS; @@ -3715,7 +3729,13 @@ public class GattService extends ProfileService { return; } - if (!permissionCheck(connId, handle)) { + try { + permissionCheck(connId, handle); + } catch (SecurityException ex) { + // Only throws on T+ as this is an older API and did not throw prior to T + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + throw ex; + } Log.w(TAG, "registerForNotification() - permission check failed!"); return; } @@ -4440,25 +4460,17 @@ public class GattService extends ProfileService { == BluetoothDevice.ADDRESS_TYPE_PUBLIC && filter.getIrk() == null) { // Do not enforce } else { - enforcePrivilegedPermission(); + enforceBluetoothPrivilegedPermission(this); } } } } } - // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be - // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission. - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) - private void enforcePrivilegedPermission() { - enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, - "Need BLUETOOTH_PRIVILEGED permission"); - } - @SuppressLint("AndroidFrameworkRequiresPermission") private void enforcePrivilegedPermissionIfNeeded(ScanSettings settings) { if (needsPrivilegedPermissionForScan(settings)) { - enforcePrivilegedPermission(); + enforceBluetoothPrivilegedPermission(this); } } diff --git a/framework/api/current.txt b/framework/api/current.txt index 23739cbbc7..47dd751218 100644 --- a/framework/api/current.txt +++ b/framework/api/current.txt @@ -1037,7 +1037,6 @@ package android.bluetooth { field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200; // 0xc8 field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 201; // 0xc9 field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6 - field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8 field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9 field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff field public static final int FEATURE_NOT_SUPPORTED = 11; // 0xb diff --git a/framework/java/android/bluetooth/BluetoothGatt.java b/framework/java/android/bluetooth/BluetoothGatt.java index 70266741ad..ee9c691134 100644 --- a/framework/java/android/bluetooth/BluetoothGatt.java +++ b/framework/java/android/bluetooth/BluetoothGatt.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; +import android.bluetooth.BluetoothGattCharacteristic.WriteType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; @@ -423,9 +424,6 @@ public final class BluetoothGatt implements BluetoothProfile { if (status == 0) characteristic.setValue(value); callback.onCharacteristicRead(BluetoothGatt.this, characteristic, value, status); - // Keep calling deprecated callback to maintain app compatibility - callback.onCharacteristicRead(BluetoothGatt.this, characteristic, - status); } } }); @@ -526,9 +524,6 @@ public final class BluetoothGatt implements BluetoothProfile { characteristic.setValue(value); callback.onCharacteristicChanged(BluetoothGatt.this, characteristic, value); - // Keep calling deprecated callback to maintain app compatibility - callback.onCharacteristicChanged(BluetoothGatt.this, - characteristic); } } }); @@ -585,8 +580,6 @@ public final class BluetoothGatt implements BluetoothProfile { if (status == 0) descriptor.setValue(value); callback.onDescriptorRead(BluetoothGatt.this, descriptor, status, value); - // Keep calling deprecated callback to maintain app compatibility - callback.onDescriptorRead(BluetoothGatt.this, descriptor, status); } } }); @@ -1305,7 +1298,6 @@ public final class BluetoothGatt implements BluetoothProfile { return true; } - /** * Writes a given characteristic and its values to the associated remote device. * @@ -1318,7 +1310,8 @@ public final class BluetoothGatt implements BluetoothProfile { * @throws IllegalArgumentException if characteristic or its value are null * * @deprecated Use {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], - * int)} as this is not memory safe. + * int)} as this is not memory safe because it relies on a {@link BluetoothGattCharacteristic} + * object whose underlying fields are subject to change outside this method. */ @Deprecated @RequiresLegacyBluetoothPermission @@ -1338,7 +1331,6 @@ public final class BluetoothGatt implements BluetoothProfile { @IntDef(value = { BluetoothStatusCodes.SUCCESS, BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION, BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED, BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED, @@ -1362,7 +1354,7 @@ public final class BluetoothGatt implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @WriteOperationReturnValues public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic, - @NonNull byte[] value, int writeType) { + @NonNull byte[] value, @WriteType int writeType) { if (characteristic == null) { throw new IllegalArgumentException("characteristic must not be null"); } @@ -1487,7 +1479,8 @@ public final class BluetoothGatt implements BluetoothProfile { * @throws IllegalArgumentException if descriptor or its value are null * * @deprecated Use {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} as - * this is not memory safe. + * this is not memory safe because it relies on a {@link BluetoothGattDescriptor} object + * whose underlying fields are subject to change outside this method. */ @Deprecated @RequiresLegacyBluetoothPermission diff --git a/framework/java/android/bluetooth/BluetoothGattCallback.java b/framework/java/android/bluetooth/BluetoothGattCallback.java index d0a5a1e729..3852d508c0 100644 --- a/framework/java/android/bluetooth/BluetoothGattCallback.java +++ b/framework/java/android/bluetooth/BluetoothGattCallback.java @@ -105,6 +105,7 @@ public abstract class BluetoothGattCallback { */ public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) { + onCharacteristicRead(gatt, characteristic, status); } /** @@ -155,6 +156,7 @@ public abstract class BluetoothGattCallback { */ public void onCharacteristicChanged(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) { + onCharacteristicChanged(gatt, characteristic); } /** @@ -184,6 +186,7 @@ public abstract class BluetoothGattCallback { */ public void onDescriptorRead(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) { + onDescriptorRead(gatt, descriptor, status); } /** diff --git a/framework/java/android/bluetooth/BluetoothGattCharacteristic.java b/framework/java/android/bluetooth/BluetoothGattCharacteristic.java index c5e986e895..92bbfcefaf 100644 --- a/framework/java/android/bluetooth/BluetoothGattCharacteristic.java +++ b/framework/java/android/bluetooth/BluetoothGattCharacteristic.java @@ -15,11 +15,14 @@ */ package android.bluetooth; +import android.annotation.IntDef; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.ParcelUuid; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -115,8 +118,17 @@ public class BluetoothGattCharacteristic implements Parcelable { */ public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "WRITE_TYPE_", value = { + WRITE_TYPE_DEFAULT, + WRITE_TYPE_NO_RESPONSE, + WRITE_TYPE_SIGNED + }) + public @interface WriteType{} + /** - * Write characteristic, requesting acknoledgement by the remote device + * Write characteristic, requesting acknowledgement by the remote device */ public static final int WRITE_TYPE_DEFAULT = 0x02; diff --git a/framework/java/android/bluetooth/BluetoothGattServer.java b/framework/java/android/bluetooth/BluetoothGattServer.java index 27d78475a3..8b84505e36 100644 --- a/framework/java/android/bluetooth/BluetoothGattServer.java +++ b/framework/java/android/bluetooth/BluetoothGattServer.java @@ -751,11 +751,8 @@ public final class BluetoothGattServer implements BluetoothProfile { @IntDef(value = { BluetoothStatusCodes.SUCCESS, BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, - BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION, BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED, BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND, - BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED, - BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY, BluetoothStatusCodes.ERROR_UNKNOWN }) public @interface NotifyCharacteristicReturnValues{} diff --git a/framework/java/android/bluetooth/BluetoothStatusCodes.java b/framework/java/android/bluetooth/BluetoothStatusCodes.java index 49b0578f8c..c81c6830eb 100644 --- a/framework/java/android/bluetooth/BluetoothStatusCodes.java +++ b/framework/java/android/bluetooth/BluetoothStatusCodes.java @@ -58,14 +58,6 @@ public final class BluetoothStatusCodes { /** * Error code indicating that the caller does not have the - * {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission. - * - * @hide - */ - public static final int ERROR_MISSING_BLUETOOTH_ADVERTISE_PERMISSION = 5; - - /** - * Error code indicating that the caller does not have the * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. */ public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; @@ -79,12 +71,6 @@ public final class BluetoothStatusCodes { public static final int ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION = 7; /** - * Error code indicating that the caller does not have the - * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission. - */ - public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; - - /** * Error code indicating that the profile service is not bound. You can bind a profile service * by calling {@link BluetoothAdapter#getProfileProxy}. */ |