summaryrefslogtreecommitdiff
path: root/framework/java/android/bluetooth/BluetoothAdapter.java
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2022-01-28 01:33:08 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-01-28 01:33:08 +0000
commitd6f8dbbcfe6fe54c90d9deabe60b1644698f9cd0 (patch)
treea481fa36fe2cbac3b412176245d3cfc31e5da640 /framework/java/android/bluetooth/BluetoothAdapter.java
parentcf7c2303d91c61cb2f44f16deb4815e4f377f3a9 (diff)
parent0662f5b93c50096bc2deba7eca9f7828e2d6701b (diff)
Merge "Introduces mechanism for background rfcomm servers" am: 0662f5b93c
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/1885648 Change-Id: I4073bde2f8845d616f5a4a0fa9173db484f5ba92
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java')
-rw-r--r--framework/java/android/bluetooth/BluetoothAdapter.java155
1 files changed, 155 insertions, 0 deletions
diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java
index f420b94db7..ff22c7614a 100644
--- a/framework/java/android/bluetooth/BluetoothAdapter.java
+++ b/framework/java/android/bluetooth/BluetoothAdapter.java
@@ -29,6 +29,7 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache;
+import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice.Transport;
import android.bluetooth.BluetoothProfile.ConnectionPolicy;
import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
@@ -234,6 +235,31 @@ public final class BluetoothAdapter {
UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a");
/**
+ * Used as an optional extra field for the {@link PendingIntent} provided to {@link
+ * #startRfcommServer(String, UUID, PendingIntent)}. This is useful for when an
+ * application registers multiple RFCOMM listeners, and needs a way to determine which service
+ * record the incoming {@link BluetoothSocket} is using.
+ *
+ * @hide
+ */
+ public static final String EXTRA_RFCOMM_LISTENER_ID =
+ "android.bluetooth.adapter.extra.RFCOMM_LISTENER_ID";
+
+ /** @hide */
+ @IntDef(value = {
+ BluetoothStatusCodes.SUCCESS,
+ BluetoothStatusCodes.ERROR_TIMEOUT,
+ BluetoothStatusCodes.RFCOMM_LISTENER_START_FAILED_UUID_IN_USE,
+ BluetoothStatusCodes.RFCOMM_LISTENER_OPERATION_FAILED_NO_MATCHING_SERVICE_RECORD,
+ BluetoothStatusCodes.RFCOMM_LISTENER_OPERATION_FAILED_DIFFERENT_APP,
+ BluetoothStatusCodes.RFCOMM_LISTENER_FAILED_TO_CREATE_SERVER_SOCKET,
+ BluetoothStatusCodes.RFCOMM_LISTENER_FAILED_TO_CLOSE_SERVER_SOCKET,
+ BluetoothStatusCodes.RFCOMM_LISTENER_NO_SOCKET_AVAILABLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RfcommListenerResult {}
+
+ /**
* Human-readable string helper for AdapterState
*
* @hide
@@ -2845,6 +2871,135 @@ public final class BluetoothAdapter {
}
/**
+ * Requests the framework to start an RFCOMM socket server which listens based on the provided
+ * {@code name} and {@code uuid}.
+ * <p>
+ * Incoming connections will cause the system to start the component described in the {@link
+ * PendingIntent}, {@code pendingIntent}. After the component is started, it should obtain a
+ * {@link BluetoothAdapter} and retrieve the {@link BluetoothSocket} via {@link
+ * #retrieveConnectedRfcommSocket(UUID)}.
+ * <p>
+ * An application may register multiple RFCOMM listeners. It is recommended to set the extra
+ * field {@link #EXTRA_RFCOMM_LISTENER_ID} to help determine which service record the incoming
+ * {@link BluetoothSocket} is using.
+ * <p>
+ * The provided {@link PendingIntent} must be created with the {@link
+ * PendingIntent#FLAG_IMMUTABLE} flag.
+ *
+ * @param name service name for SDP record
+ * @param uuid uuid for SDP record
+ * @param pendingIntent component which is called when a new RFCOMM connection is available
+ * @return a status code from {@link BluetoothStatusCodes}
+ * @throws IllegalArgumentException if {@code pendingIntent} is not created with the {@link
+ * PendingIntent#FLAG_IMMUTABLE} flag.
+ * @hide
+ */
+ @SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED
+ })
+ @RfcommListenerResult
+ public int startRfcommServer(@NonNull String name, @NonNull UUID uuid,
+ @NonNull PendingIntent pendingIntent) {
+ if (!pendingIntent.isImmutable()) {
+ throw new IllegalArgumentException("The provided PendingIntent is not immutable");
+ }
+ try {
+ return mService.startRfcommListener(
+ name, new ParcelUuid(uuid), pendingIntent, mAttributionSource);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to transact RFCOMM listener start request", e);
+ return BluetoothStatusCodes.ERROR_TIMEOUT;
+ }
+ }
+
+ /**
+ * Closes the RFCOMM socket server listening on the given SDP record name and UUID. This can be
+ * called by applications after calling {@link #startRfcommServer(String, UUID,
+ * PendingIntent)} to stop listening for incoming RFCOMM connections.
+ *
+ * @param uuid uuid for SDP record
+ * @return a status code from {@link BluetoothStatusCodes}
+ * @hide
+ */
+ @SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
+ @RfcommListenerResult
+ public int closeRfcommServer(@NonNull UUID uuid) {
+ try {
+ return mService.stopRfcommListener(new ParcelUuid(uuid), mAttributionSource);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to transact RFCOMM listener stop request", e);
+ return BluetoothStatusCodes.ERROR_TIMEOUT;
+ }
+ }
+
+ /**
+ * Retrieves a connected {@link BluetoothSocket} for the given service record from a RFCOMM
+ * listener which was registered with {@link #startRfcommServer(String, UUID, PendingIntent)}.
+ * <p>
+ * This method should be called by the component started by the {@link PendingIntent} which was
+ * registered during the call to {@link #startRfcommServer(String, UUID, PendingIntent)} in
+ * order to retrieve the socket.
+ *
+ * @param uuid the same UUID used to register the listener previously
+ * @return a connected {@link BluetoothSocket} or {@code null} if no socket is available
+ * @throws IllegalStateException if the socket could not be retrieved because the application is
+ * trying to obtain a socket for a listener it did not register (incorrect {@code
+ * uuid}).
+ * @hide
+ */
+ @SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
+ public @NonNull BluetoothSocket retrieveConnectedRfcommSocket(@NonNull UUID uuid) {
+ IncomingRfcommSocketInfo socketInfo;
+
+ try {
+ socketInfo =
+ mService.retrievePendingSocketForServiceRecord(
+ new ParcelUuid(uuid), mAttributionSource);
+ } catch (RemoteException e) {
+ return null;
+ }
+
+ switch (socketInfo.status) {
+ case BluetoothStatusCodes.SUCCESS:
+ try {
+ return BluetoothSocket.createSocketFromOpenFd(
+ socketInfo.pfd,
+ socketInfo.bluetoothDevice,
+ new ParcelUuid(uuid));
+ } catch (IOException e) {
+ return null;
+ }
+ case BluetoothStatusCodes.RFCOMM_LISTENER_OPERATION_FAILED_DIFFERENT_APP:
+ throw new IllegalStateException(
+ String.format(
+ "RFCOMM listener for UUID %s was not registered by this app",
+ uuid));
+ case BluetoothStatusCodes.RFCOMM_LISTENER_NO_SOCKET_AVAILABLE:
+ return null;
+ default:
+ Log.e(TAG,
+ String.format(
+ "Unexpected result: (%d), from the adapter service while retrieving"
+ + " an rfcomm socket",
+ socketInfo.status));
+ return null;
+ }
+ }
+
+ /**
* Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
* <p>The link key is not required to be authenticated, i.e the communication may be
* vulnerable to Person In the Middle attacks. For Bluetooth 2.1 devices,