summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattService.java114
-rw-r--r--framework/api/current.txt1
-rw-r--r--framework/java/android/bluetooth/BluetoothGatt.java19
-rw-r--r--framework/java/android/bluetooth/BluetoothGattCallback.java3
-rw-r--r--framework/java/android/bluetooth/BluetoothGattCharacteristic.java14
-rw-r--r--framework/java/android/bluetooth/BluetoothGattServer.java3
-rw-r--r--framework/java/android/bluetooth/BluetoothStatusCodes.java14
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}.
*/