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

Commit af3a017b authored by Bhakthavatsala Raghavendra's avatar Bhakthavatsala Raghavendra
Browse files

Add socket settings interface

Add socket interface which allows users to control the various
security requirements for the sockets. This also helps in extending
socket for offload socket related parameters

Bug: 366639787
Bug: 374358112
Test: mmm packages/module/Bluetooth

Change-Id: If09796368e76b8375b879b1e3cc7a1c365b67799
parent cf23fb65
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ package android.bluetooth {
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
    method @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingSocketSettings(@NonNull android.bluetooth.BluetoothSocketSettings) throws java.io.IOException;
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setName(String);
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startDiscovery();
    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
@@ -531,6 +532,7 @@ package android.bluetooth {
    method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
    method @NonNull public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
    method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
    method @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") @NonNull public android.bluetooth.BluetoothSocket createUsingSocketSettings(@NonNull android.bluetooth.BluetoothSocketSettings) throws java.io.IOException;
    method public int describeContents();
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean fetchUuidsWithSdp();
    method public String getAddress();
@@ -1080,6 +1082,7 @@ package android.bluetooth {
    method public android.bluetooth.BluetoothDevice getRemoteDevice();
    method public boolean isConnected();
    field public static final int TYPE_L2CAP = 3; // 0x3
    field @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") public static final int TYPE_LE = 4; // 0x4
    field public static final int TYPE_RFCOMM = 1; // 0x1
    field public static final int TYPE_SCO = 2; // 0x2
  }
@@ -1112,6 +1115,26 @@ package android.bluetooth {
    field public static final int UNSPECIFIED = 0; // 0x0
  }

  @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") public final class BluetoothSocketSettings {
    method @IntRange(from=128, to=255) public int getL2capPsm();
    method @Nullable public String getRfcommServiceName();
    method @Nullable public java.util.UUID getRfcommUuid();
    method public int getSocketType();
    method public boolean isAuthenticationRequired();
    method public boolean isEncryptionRequired();
  }

  @FlaggedApi("com.android.bluetooth.flags.socket_settings_api") public static final class BluetoothSocketSettings.Builder {
    ctor public BluetoothSocketSettings.Builder();
    method @NonNull public android.bluetooth.BluetoothSocketSettings build();
    method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setAuthenticationRequired(boolean);
    method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setEncryptionRequired(boolean);
    method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setL2capPsm(@IntRange(from=128, to=255) int);
    method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setRfcommServiceName(@NonNull String);
    method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setRfcommUuid(@NonNull java.util.UUID);
    method @NonNull public android.bluetooth.BluetoothSocketSettings.Builder setSocketType(int);
  }

  public final class BluetoothStatusCodes {
    field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2
    field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1
+78 −4
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static java.util.Objects.requireNonNull;

import android.annotation.BroadcastBehavior;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -4538,8 +4539,7 @@ public final class BluetoothAdapter {
     * another Android device that is given the PSM value.
     *
     * @return an L2CAP CoC BluetoothServerSocket
     * @throws IOException on error, for example Bluetooth not available, or insufficient
     *     permissions, or unable to start this CoC
     * @throws IOException on error, for example Bluetooth not available or unable to start this CoC
     */
    @RequiresLegacyBluetoothPermission
    @RequiresBluetoothConnectPermission
@@ -4594,8 +4594,7 @@ public final class BluetoothAdapter {
     * socket from another Android device that is given the PSM value.
     *
     * @return an L2CAP CoC BluetoothServerSocket
     * @throws IOException on error, for example Bluetooth not available, or insufficient
     *     permissions, or unable to start this CoC
     * @throws IOException on error, for example Bluetooth not available or unable to start this CoC
     */
    @RequiresLegacyBluetoothPermission
    @RequiresBluetoothConnectPermission
@@ -4626,6 +4625,81 @@ public final class BluetoothAdapter {
        return socket;
    }

    /**
     * Creates a listening server channel for Bluetooth connections with the specified socket
     * settings {@link BluetoothSocketSettings}.
     *
     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
     * {@link BluetoothServerSocket}.
     *
     * <p>This API supports {@link BluetoothSocket#TYPE_RFCOMM} and {{@link BluetoothSocket#TYPE_LE}
     * only, which can be set using {@link BluetoothSocketSettings#setSocketType()}.
     * <li>For `BluetoothSocket.TYPE_RFCOMM`: The RFCOMM UUID must be provided using {@link
     *     BluetoothSocketSettings#setRfcommUuid()}.
     * <li>For `BluetoothSocket.TYPE_LE`: The system assigns a dynamic protocol/service multiplexer
     *     (PSM) value. This value can be read from {@link BluetoothServerSocket#getPsm()}. This
     *     value is released when the server socket is closed, Bluetooth is turned off, or the
     *     application exits unexpectedly. The mechanism for disclosing the PSM value to the client
     *     is application-defined.
     *
     *     <p>Use {@link BluetoothDevice#createUsingSocketSettings(BluetoothSocketSettings)} to
     *     connect to this server socket from another Android device using the L2cap
     *     protocol/service multiplexer(PSM) value or the RFCOMM service UUID as input.
     *
     * @param settings Bluetooth socket settings {@link BluetoothSocketSettings}.
     * @return a {@link BluetoothServerSocket}
     * @throws IllegalArgumentException if BluetoothSocket#TYPE_RFCOMM socket is requested with no
     *     UUID.
     * @throws IOException on error, for example Bluetooth not available or unable to start this LE
     *     Connection-oriented Channel (CoC).
     */
    @RequiresBluetoothConnectPermission
    @RequiresPermission(BLUETOOTH_CONNECT)
    @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
    public @NonNull BluetoothServerSocket listenUsingSocketSettings(
            @NonNull BluetoothSocketSettings settings) throws IOException {

        BluetoothServerSocket socket;
        int type = settings.getSocketType();
        if (type == BluetoothSocket.TYPE_RFCOMM) {
            if (settings.getRfcommUuid() == null) {
                throw new IllegalArgumentException("RFCOMM server missing UUID");
            }
            return createNewRfcommSocketAndRecord(
                    settings.getRfcommServiceName(),
                    settings.getRfcommUuid(),
                    settings.isAuthenticationRequired(),
                    settings.isEncryptionRequired());
        } else if (type == BluetoothSocket.TYPE_LE) {
            socket =
                    new BluetoothServerSocket(
                            settings.getSocketType(),
                            settings.isAuthenticationRequired(),
                            settings.isEncryptionRequired(),
                            SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
                            false,
                            false);
        } else {
            throw new IOException("Error: Invalid socket type: " + type);
        }
        int errno = socket.mSocket.bindListen();
        if (errno != 0) {
            throw new IOException("Error: " + errno);
        }
        if (type == BluetoothSocket.TYPE_LE) {
            int assignedPsm = socket.mSocket.getPort();
            if (assignedPsm == 0) {
                throw new IOException("Error: Unable to assign PSM value");
            }
            if (DBG) {
                Log.d(TAG, "listenUsingSocketSettings: set assigned PSM to " + assignedPsm);
            }
            socket.setChannel(assignedPsm);
        }

        return socket;
    }

    /**
     * Register a {@link #OnMetadataChangedListener} to receive update about metadata changes for
     * this {@link BluetoothDevice}. Registration must be done when Bluetooth is ON and will last
+54 −0
Original line number Diff line number Diff line
@@ -3217,6 +3217,60 @@ public final class BluetoothDevice implements Parcelable, Attributable {
        return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP_LE, false, false, psm, null);
    }

    /**
     * Creates a client socket to connect to a remote Bluetooth server with the specified socket
     * settings {@link BluetoothSocketSettings} This API is used to connect to a remote server
     * hosted using {@link BluetoothAdapter#listenUsingSocketSettings}.
     *
     * <ul>
     *   <li>For `BluetoothSocket.TYPE_RFCOMM`: The RFCOMM UUID must be provided using {@link
     *       BluetoothSocketSettings#setRfcommUuid()}.
     *   <li>For `BluetoothSocket.TYPE_LE`: The L2cap protocol/service multiplexer (PSM) value must
     *       be provided using {@link BluetoothSocketSettings#setL2capPsm()}.
     * </ul>
     *
     * <p>Application using this API is responsible for obtaining protocol/service multiplexer (psm)
     * value from remote device.
     *
     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
     *
     * @param settings Bluetooth socket settings {@link BluetoothSocketSettings}.
     * @return a {@link BluetoothSocket} ready for an outgoing connection.
     * @throws IllegalArgumentException if BluetoothSocket#TYPE_RFCOMM socket with no UUID is passed
     *     as input or if BluetoothSocket#TYPE_LE with invalid PSM is passed.
     * @throws IOException on error, for example Bluetooth not available.
     */
    @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
    public @NonNull BluetoothSocket createUsingSocketSettings(
            @NonNull BluetoothSocketSettings settings) throws IOException {
        if (!isBluetoothEnabled()) {
            Log.e(TAG, "createUsingSocketSettings: Bluetooth is not enabled");
            throw new IOException();
        }
        if (DBG) {
            Log.d(TAG, "createUsingSocketSettings: =" + settings.getL2capPsm());
        }
        ParcelUuid uuid = null;
        int psm = settings.getL2capPsm();
        if (settings.getSocketType() == BluetoothSocket.TYPE_RFCOMM) {
            if (settings.getRfcommUuid() == null) {
                throw new IllegalArgumentException("null uuid: " + settings.getRfcommUuid());
            }
            uuid = new ParcelUuid(settings.getRfcommUuid());
        } else if (settings.getSocketType() == BluetoothSocket.TYPE_LE) {
            if (psm < 128 || psm > 255) {
                throw new IllegalArgumentException("Invalid PSM/Channel value: " + psm);
            }
        }
        return new BluetoothSocket(
                this,
                settings.getSocketType(),
                settings.isAuthenticationRequired(),
                settings.isEncryptionRequired(),
                psm,
                uuid);
    }

    /**
     * Set a keyed metadata of this {@link BluetoothDevice} to a {@link String} value. Only bonded
     * devices's metadata will be persisted across Bluetooth restart. Metadata will be removed when
+24 −6
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import static android.Manifest.permission.LOCAL_MAC_ADDRESS;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
@@ -42,6 +43,8 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
@@ -112,6 +115,8 @@ public final class BluetoothSocket implements Closeable {
    /**
     * L2CAP socket on BR/EDR transport
     *
     * <p>To be removed once Flags.FLAG_SOCKET_SETTINGS_API is removed
     *
     * @hide
     */
    public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP;
@@ -119,10 +124,28 @@ public final class BluetoothSocket implements Closeable {
    /**
     * L2CAP socket on LE transport
     *
     * <p>To be removed once Flags.FLAG_SOCKET_SETTINGS_API is removed
     *
     * @hide
     */
    public static final int TYPE_L2CAP_LE = 4;

    /** L2CAP socket on LE transport */
    @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
    public static final int TYPE_LE = 4;

    /** @hide */
    @IntDef(
            prefix = {"BluetoothSocket.TYPE_"},
            value = {
                BluetoothSocket.TYPE_RFCOMM,
                BluetoothSocket.TYPE_SCO,
                BluetoothSocket.TYPE_L2CAP,
                BluetoothSocket.TYPE_LE,
            })
    @Retention(RetentionPolicy.SOURCE)
    public @interface SocketType {}

    /*package*/ static final int EBADFD = 77;

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -195,12 +218,7 @@ public final class BluetoothSocket implements Closeable {
     * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
     */
    @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS})
    /*package*/ BluetoothSocket(
            int type,
            boolean auth,
            boolean encrypt,
            int port,
            ParcelUuid uuid)
    /*package*/ BluetoothSocket(int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid)
            throws IOException {
        this(type, auth, encrypt, port, uuid, false, false);
    }
+349 −0

File added.

Preview size limit exceeded, changes collapsed.