Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45840994 authored by Rahul Sabnis's avatar Rahul Sabnis Committed by Automerger Merge Worker
Browse files

Merge "Address API council feedback on GATT API changes." am: 56ddf94a am: f387f744

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/2030693

Change-Id: Ic3b2ec1db69de2336a11f6d6942afd905652d29d
parents d0569f1f f387f744
Loading
Loading
Loading
Loading
+63 −51
Original line number Original line Diff line number Diff line
@@ -16,7 +16,7 @@


package com.android.bluetooth.gatt;
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.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
@@ -52,6 +52,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.net.MacAddress;
import android.net.MacAddress;
import android.os.Binder;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Message;
import android.os.Message;
@@ -426,40 +427,37 @@ public class GattService extends ProfileService {
        sGattService = instance;
        sGattService = instance;
    }
    }


    // Suppressed since we're not actually enforcing here
    // Suppressed because we are conditionally enforcing
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @SuppressLint("AndroidFrameworkRequiresPermission")
    private boolean permissionCheck(UUID characteristicUuid) {
    private void permissionCheck(UUID characteristicUuid) {
        return !isHidCharUuid(characteristicUuid)
        if (!isHidCharUuid(characteristicUuid)) {
                || (checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED)
            return;
                        == PERMISSION_GRANTED);
        }
        enforceBluetoothPrivilegedPermission(this);
    }
    }


    // Suppressed since we're not actually enforcing here
    // Suppressed because we are conditionally enforcing
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @SuppressLint("AndroidFrameworkRequiresPermission")
    private boolean permissionCheck(int connId, int handle) {
    private void permissionCheck(int connId, int handle) {
        Set<Integer> restrictedHandles = mRestrictedHandles.get(connId);
        if (!isHandleRestricted(connId, handle)) {
        if (restrictedHandles == null || !restrictedHandles.contains(handle)) {
            return;
            return true;
        }
        }

        enforceBluetoothPrivilegedPermission(this);
        return (checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED)
                == PERMISSION_GRANTED);
    }
    }


    // Suppressed since we're not actually enforcing here
    // Suppressed because we are conditionally enforcing
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @SuppressLint("AndroidFrameworkRequiresPermission")
    private boolean permissionCheck(ClientMap.App app, int connId, int handle) {
    private void permissionCheck(ClientMap.App app, int connId, int handle) {
        Set<Integer> restrictedHandles = mRestrictedHandles.get(connId);
        if (!isHandleRestricted(connId, handle) || app.hasBluetoothPrivilegedPermission) {
        if (restrictedHandles == null || !restrictedHandles.contains(handle)) {
            return;
            return true;
        }
        }

        enforceBluetoothPrivilegedPermission(this);
        if (!app.hasBluetoothPrivilegedPermission
                && checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED)== PERMISSION_GRANTED) {
        app.hasBluetoothPrivilegedPermission = true;
        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
    @Override
@@ -2302,7 +2300,13 @@ public class GattService extends ProfileService {


        ClientMap.App app = mClientMap.getByConnId(connId);
        ClientMap.App app = mClientMap.getByConnId(connId);
        if (app != null) {
        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!");
                Log.w(TAG, "onNotify() - permission check failed!");
                return;
                return;
            }
            }
@@ -3255,7 +3259,7 @@ public class GattService extends ProfileService {
                this, attributionSource, "GattService getOwnAddress")) {
                this, attributionSource, "GattService getOwnAddress")) {
            return;
            return;
        }
        }
        enforcePrivilegedPermission();
        enforceBluetoothPrivilegedPermission(this);
        mAdvertiseManager.getOwnAddress(advertiserId);
        mAdvertiseManager.getOwnAddress(advertiserId);
    }
    }


@@ -3539,7 +3543,13 @@ public class GattService extends ProfileService {
            return;
            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!");
            Log.w(TAG, "readCharacteristic() - permission check failed!");
            return;
            return;
        }
        }
@@ -3565,7 +3575,13 @@ public class GattService extends ProfileService {
            return;
            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!");
            Log.w(TAG, "readUsingCharacteristicUuid() - permission check failed!");
            return;
            return;
        }
        }
@@ -3595,11 +3611,7 @@ public class GattService extends ProfileService {
            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
        }
        }

        permissionCheck(connId, handle);
        if (!permissionCheck(connId, handle)) {
            Log.w(TAG, "writeCharacteristic() - permission check failed!");
            return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION;
        }


        Log.d(TAG, "writeCharacteristic() - trying to acquire permit.");
        Log.d(TAG, "writeCharacteristic() - trying to acquire permit.");
        // Lock the thread until onCharacteristicWrite callback comes back.
        // Lock the thread until onCharacteristicWrite callback comes back.
@@ -3640,7 +3652,13 @@ public class GattService extends ProfileService {
            return;
            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!");
            Log.w(TAG, "readDescriptor() - permission check failed!");
            return;
            return;
        }
        }
@@ -3664,11 +3682,7 @@ public class GattService extends ProfileService {
            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
            return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
        }
        }

        permissionCheck(connId, handle);
        if (!permissionCheck(connId, handle)) {
            Log.w(TAG, "writeDescriptor() - permission check failed!");
            return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION;
        }


        gattClientWriteDescriptorNative(connId, handle, authReq, value);
        gattClientWriteDescriptorNative(connId, handle, authReq, value);
        return BluetoothStatusCodes.SUCCESS;
        return BluetoothStatusCodes.SUCCESS;
@@ -3724,7 +3738,13 @@ public class GattService extends ProfileService {
            return;
            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!");
            Log.w(TAG, "registerForNotification() - permission check failed!");
            return;
            return;
        }
        }
@@ -4449,25 +4469,17 @@ public class GattService extends ProfileService {
                            == BluetoothDevice.ADDRESS_TYPE_PUBLIC && filter.getIrk() == null) {
                            == BluetoothDevice.ADDRESS_TYPE_PUBLIC && filter.getIrk() == null) {
                        // Do not enforce
                        // Do not enforce
                    } else {
                    } 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")
    @SuppressLint("AndroidFrameworkRequiresPermission")
    private void enforcePrivilegedPermissionIfNeeded(ScanSettings settings) {
    private void enforcePrivilegedPermissionIfNeeded(ScanSettings settings) {
        if (needsPrivilegedPermissionForScan(settings)) {
        if (needsPrivilegedPermissionForScan(settings)) {
            enforcePrivilegedPermission();
            enforceBluetoothPrivilegedPermission(this);
        }
        }
    }
    }


+0 −1
Original line number Original line Diff line number Diff line
@@ -1056,7 +1056,6 @@ package android.bluetooth {
    field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200; // 0xc8
    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_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_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_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9
    field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff
    field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff
    field public static final int FEATURE_NOT_SUPPORTED = 11; // 0xb
    field public static final int FEATURE_NOT_SUPPORTED = 11; // 0xb
+6 −13
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothGattCharacteristic.WriteType;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
@@ -423,9 +424,6 @@ public final class BluetoothGatt implements BluetoothProfile {
                                if (status == 0) characteristic.setValue(value);
                                if (status == 0) characteristic.setValue(value);
                                callback.onCharacteristicRead(BluetoothGatt.this, characteristic,
                                callback.onCharacteristicRead(BluetoothGatt.this, characteristic,
                                        value, status);
                                        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);
                                characteristic.setValue(value);
                                callback.onCharacteristicChanged(BluetoothGatt.this,
                                callback.onCharacteristicChanged(BluetoothGatt.this,
                                        characteristic, value);
                                        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);
                                if (status == 0) descriptor.setValue(value);
                                callback.onDescriptorRead(BluetoothGatt.this, descriptor, status,
                                callback.onDescriptorRead(BluetoothGatt.this, descriptor, status,
                                        value);
                                        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;
        return true;
    }
    }



    /**
    /**
     * Writes a given characteristic and its values to the associated remote device.
     * 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
     * @throws IllegalArgumentException if characteristic or its value are null
     *
     *
     * @deprecated Use {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[],
     * @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
    @Deprecated
    @RequiresLegacyBluetoothPermission
    @RequiresLegacyBluetoothPermission
@@ -1338,7 +1331,6 @@ public final class BluetoothGatt implements BluetoothProfile {
    @IntDef(value = {
    @IntDef(value = {
            BluetoothStatusCodes.SUCCESS,
            BluetoothStatusCodes.SUCCESS,
            BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
            BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
            BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION,
            BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED,
            BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED,
            BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
            BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
            BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED,
            BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED,
@@ -1362,7 +1354,7 @@ public final class BluetoothGatt implements BluetoothProfile {
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    @WriteOperationReturnValues
    @WriteOperationReturnValues
    public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic,
    public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic,
            @NonNull byte[] value, int writeType) {
            @NonNull byte[] value, @WriteType int writeType) {
        if (characteristic == null) {
        if (characteristic == null) {
            throw new IllegalArgumentException("characteristic must not be 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
     * @throws IllegalArgumentException if descriptor or its value are null
     *
     *
     * @deprecated Use {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} as
     * @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
    @Deprecated
    @RequiresLegacyBluetoothPermission
    @RequiresLegacyBluetoothPermission
+3 −0
Original line number Original line Diff line number Diff line
@@ -105,6 +105,7 @@ public abstract class BluetoothGattCallback {
     */
     */
    public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull
    public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull
            BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) {
            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,
    public void onCharacteristicChanged(@NonNull BluetoothGatt gatt,
            @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
            @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
        onCharacteristicChanged(gatt, characteristic);
    }
    }


    /**
    /**
@@ -184,6 +186,7 @@ public abstract class BluetoothGattCallback {
     */
     */
    public void onDescriptorRead(@NonNull BluetoothGatt gatt,
    public void onDescriptorRead(@NonNull BluetoothGatt gatt,
            @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
            @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
        onDescriptorRead(gatt, descriptor, status);
    }
    }


    /**
    /**
+13 −1
Original line number Original line Diff line number Diff line
@@ -15,11 +15,14 @@
 */
 */
package android.bluetooth;
package android.bluetooth;


import android.annotation.IntDef;
import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcel;
import android.os.ParcelUuid;
import android.os.ParcelUuid;
import android.os.Parcelable;
import android.os.Parcelable;


import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
import java.util.UUID;
import java.util.UUID;
@@ -115,8 +118,17 @@ public class BluetoothGattCharacteristic implements Parcelable {
     */
     */
    public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100;
    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;
    public static final int WRITE_TYPE_DEFAULT = 0x02;


Loading