1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.bluetooth; 18 19 import static android.Manifest.permission.BLUETOOTH_CONNECT; 20 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; 21 import static android.Manifest.permission.LOCAL_MAC_ADDRESS; 22 23 import android.annotation.FlaggedApi; 24 import android.annotation.IntDef; 25 import android.annotation.NonNull; 26 import android.annotation.RequiresNoPermission; 27 import android.annotation.RequiresPermission; 28 import android.annotation.SystemApi; 29 import android.bluetooth.annotations.RequiresBluetoothConnectPermission; 30 import android.compat.annotation.UnsupportedAppUsage; 31 import android.content.AttributionSource; 32 import android.net.LocalSocket; 33 import android.os.Build; 34 import android.os.ParcelFileDescriptor; 35 import android.os.ParcelUuid; 36 import android.os.RemoteException; 37 import android.util.Log; 38 39 import com.android.bluetooth.flags.Flags; 40 41 import java.io.Closeable; 42 import java.io.FileDescriptor; 43 import java.io.IOException; 44 import java.io.InputStream; 45 import java.io.OutputStream; 46 import java.lang.annotation.Retention; 47 import java.lang.annotation.RetentionPolicy; 48 import java.nio.ByteBuffer; 49 import java.nio.ByteOrder; 50 import java.util.Arrays; 51 import java.util.Locale; 52 import java.util.UUID; 53 54 /** 55 * A connected or connecting Bluetooth socket. 56 * 57 * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets: {@link java.net.Socket} 58 * and {@link java.net.ServerSocket}. On the server side, use a {@link BluetoothServerSocket} to 59 * create a listening server socket. When a connection is accepted by the {@link 60 * BluetoothServerSocket}, it will return a new {@link BluetoothSocket} to manage the connection. On 61 * the client side, use a single {@link BluetoothSocket} to both initiate an outgoing connection and 62 * to manage the connection. 63 * 64 * <p>The most common type of Bluetooth socket is RFCOMM, which is the type supported by the Android 65 * APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth. It is also known as 66 * the Serial Port Profile (SPP). 67 * 68 * <p>To create a {@link BluetoothSocket} for connecting to a known device, use {@link 69 * BluetoothDevice#createRfcommSocketToServiceRecord 70 * BluetoothDevice.createRfcommSocketToServiceRecord()}. Then call {@link #connect()} to attempt a 71 * connection to the remote device. This call will block until a connection is established or the 72 * connection fails. 73 * 74 * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the {@link 75 * BluetoothServerSocket} documentation. 76 * 77 * <p>Once the socket is connected, whether initiated as a client or accepted as a server, open the 78 * IO streams by calling {@link #getInputStream} and {@link #getOutputStream} in order to retrieve 79 * {@link java.io.InputStream} and {@link java.io.OutputStream} objects, respectively, which are 80 * automatically connected to the socket. 81 * 82 * <p>{@link BluetoothSocket} is thread safe. In particular, {@link #close} will always immediately 83 * abort ongoing operations and close the socket. 84 * 85 * <p><div class="special reference"> 86 * 87 * <h3>Developer Guides</h3> 88 * 89 * <p>For more information about using Bluetooth, read the <a 90 * href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide. </div> 91 * 92 * @see BluetoothServerSocket 93 * @see java.io.InputStream 94 * @see java.io.OutputStream 95 */ 96 public final class BluetoothSocket implements Closeable { 97 private static final String TAG = BluetoothSocket.class.getSimpleName(); 98 99 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 100 private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE); 101 102 /** @hide */ 103 public static final int MAX_RFCOMM_CHANNEL = 30; 104 105 /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF; 106 107 /** RFCOMM socket */ 108 public static final int TYPE_RFCOMM = 1; 109 110 /** SCO socket */ 111 public static final int TYPE_SCO = 2; 112 113 /** L2CAP socket */ 114 public static final int TYPE_L2CAP = 3; 115 116 /** 117 * L2CAP socket on BR/EDR transport 118 * 119 * <p>To be removed once Flags.FLAG_SOCKET_SETTINGS_API is removed 120 * 121 * @hide 122 */ 123 public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP; 124 125 /** 126 * L2CAP socket on LE transport 127 * 128 * <p>To be removed once Flags.FLAG_SOCKET_SETTINGS_API is removed 129 * 130 * @hide 131 */ 132 public static final int TYPE_L2CAP_LE = 4; 133 134 /** L2CAP socket on LE transport */ 135 @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API) 136 public static final int TYPE_LE = 4; 137 138 /** @hide */ 139 @IntDef( 140 prefix = {"BluetoothSocket.TYPE_"}, 141 value = { 142 BluetoothSocket.TYPE_RFCOMM, 143 BluetoothSocket.TYPE_SCO, 144 BluetoothSocket.TYPE_L2CAP, 145 BluetoothSocket.TYPE_LE, 146 }) 147 @Retention(RetentionPolicy.SOURCE) 148 public @interface SocketType {} 149 150 /*package*/ static final int EBADFD = 77; 151 152 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 153 /*package*/ static final int EADDRINUSE = 98; 154 155 /*package*/ static final int SEC_FLAG_ENCRYPT = 1; 156 /*package*/ static final int SEC_FLAG_AUTH = 1 << 1; 157 /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2; 158 /*package*/ static final int SEC_FLAG_AUTH_PITM = 1 << 3; 159 /*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4; 160 161 /*package*/ static final String DEFAULT_SOCKET_NAME = "default_name"; 162 163 private final int mType; /* one of TYPE_RFCOMM etc */ 164 private BluetoothDevice mDevice; /* remote device */ 165 private String mAddress; /* remote address */ 166 private final boolean mAuth; 167 private final boolean mEncrypt; 168 private final BluetoothInputStream mInputStream; 169 private final BluetoothOutputStream mOutputStream; 170 private final ParcelUuid mUuid; 171 private final int mDataPath; 172 private final String mSocketName; 173 private final long mHubId; 174 private final long mEndpointId; 175 private final int mMaximumPacketSize; 176 177 /** when true no SPP SDP record will be created */ 178 private boolean mExcludeSdp = false; 179 180 /** when true Person-in-the-middle protection will be enabled */ 181 private boolean mAuthPitm = false; 182 183 /** Minimum 16 digit pin for sec mode 2 connections */ 184 private boolean mMin16DigitPin = false; 185 186 @UnsupportedAppUsage(publicAlternatives = "Use {@link BluetoothSocket} public API instead.") 187 private ParcelFileDescriptor mPfd; 188 189 @UnsupportedAppUsage private LocalSocket mSocket; 190 private InputStream mSocketIS; 191 private OutputStream mSocketOS; 192 @UnsupportedAppUsage private int mPort; /* RFCOMM channel or L2CAP psm */ 193 private String mServiceName; 194 195 private static final int SOCK_CONNECTION_SIGNAL_SIZE = 44; 196 private static final long INVALID_SOCKET_ID = 0; 197 private static final int SOCK_ACCEPT_SIGNAL_SIZE = 4; 198 199 private ByteBuffer mL2capBuffer = null; 200 private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer. 201 private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received. 202 private ParcelUuid mConnectionUuid; 203 private long mSocketId; // Socket ID in connected state. 204 205 private long mSocketCreationTimeNanos = 0; 206 private long mSocketCreationLatencyNanos = 0; 207 208 private enum SocketState { 209 INIT, 210 CONNECTED, 211 LISTENING, 212 CLOSED, 213 } 214 215 /** prevents all native calls after destroyNative() */ 216 private volatile SocketState mSocketState; 217 218 /** protects mSocketState */ 219 // private final ReentrantReadWriteLock mLock; 220 221 /** 222 * Construct a BluetoothSocket. 223 * 224 * @param type type of socket 225 * @param auth require the remote device to be authenticated 226 * @param encrypt require the connection to be encrypted 227 * @param port remote port 228 * @param uuid SDP uuid 229 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges 230 */ 231 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS}) BluetoothSocket(int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid)232 /*package*/ BluetoothSocket(int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid) 233 throws IOException { 234 this(type, auth, encrypt, port, uuid, false, false); 235 } 236 237 /** 238 * Construct a BluetoothSocket. 239 * 240 * @param type type of socket 241 * @param auth require the remote device to be authenticated 242 * @param encrypt require the connection to be encrypted 243 * @param port remote port 244 * @param uuid SDP uuid 245 * @param pitm enforce person-in-the-middle protection. 246 * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection 247 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges 248 */ 249 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS}) BluetoothSocket( int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid, boolean pitm, boolean min16DigitPin)250 /*package*/ BluetoothSocket( 251 int type, 252 boolean auth, 253 boolean encrypt, 254 int port, 255 ParcelUuid uuid, 256 boolean pitm, 257 boolean min16DigitPin) 258 throws IOException { 259 this(type, auth, encrypt, port, uuid, pitm, min16DigitPin, 0, DEFAULT_SOCKET_NAME, 0, 0, 0); 260 } 261 262 /** 263 * Construct a BluetoothSocket. 264 * 265 * @param type type of socket 266 * @param auth require the remote device to be authenticated 267 * @param encrypt require the connection to be encrypted 268 * @param port remote port 269 * @param uuid SDP uuid 270 * @param pitm enforce person-in-the-middle protection. 271 * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection 272 * @param dataPath data path used for this socket 273 * @param socketName user-friendly name for this socket 274 * @param hubId ID of the hub to which the end point belongs 275 * @param endpointId ID of the endpoint within the hub that is associated with this socket 276 * @param maximumPacketSize The maximum size (in bytes) of a single data packet 277 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges 278 */ 279 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS}) BluetoothSocket( int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid, boolean pitm, boolean min16DigitPin, int dataPath, @NonNull String socketName, long hubId, long endpointId, int maximumPacketSize)280 /*package*/ BluetoothSocket( 281 int type, 282 boolean auth, 283 boolean encrypt, 284 int port, 285 ParcelUuid uuid, 286 boolean pitm, 287 boolean min16DigitPin, 288 int dataPath, 289 @NonNull String socketName, 290 long hubId, 291 long endpointId, 292 int maximumPacketSize) 293 throws IOException { 294 if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type); 295 mSocketCreationTimeNanos = System.nanoTime(); 296 if (type == BluetoothSocket.TYPE_RFCOMM 297 && uuid == null 298 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 299 if (port < 1 || port > MAX_RFCOMM_CHANNEL) { 300 throw new IOException("Invalid RFCOMM channel: " + port); 301 } 302 } 303 if (uuid != null) { 304 mUuid = uuid; 305 } else { 306 mUuid = new ParcelUuid(new UUID(0, 0)); 307 } 308 mType = type; 309 mAuth = auth; 310 mAuthPitm = pitm; 311 mMin16DigitPin = min16DigitPin; 312 mEncrypt = encrypt; 313 mPort = port; 314 // this constructor to be called only from BluetoothServerSocket 315 mDevice = null; 316 mDataPath = dataPath; 317 mSocketName = socketName; 318 mHubId = hubId; 319 mEndpointId = endpointId; 320 mMaximumPacketSize = maximumPacketSize; 321 322 mSocketState = SocketState.INIT; 323 324 mAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); 325 326 mInputStream = new BluetoothInputStream(this); 327 mOutputStream = new BluetoothOutputStream(this); 328 mSocketCreationLatencyNanos = System.nanoTime() - mSocketCreationTimeNanos; 329 } 330 331 /** 332 * Construct a BluetoothSocket. 333 * 334 * @param device remote device that this socket can connect to 335 * @param type type of socket 336 * @param auth require the remote device to be authenticated 337 * @param encrypt require the connection to be encrypted 338 * @param port remote port 339 * @param uuid SDP uuid 340 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges 341 */ BluetoothSocket( BluetoothDevice device, int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid)342 /*package*/ BluetoothSocket( 343 BluetoothDevice device, 344 int type, 345 boolean auth, 346 boolean encrypt, 347 int port, 348 ParcelUuid uuid) 349 throws IOException { 350 this(device, type, auth, encrypt, port, uuid, false, false); 351 } 352 353 /** 354 * Construct a BluetoothSocket. 355 * 356 * @param device remote device that this socket can connect to 357 * @param type type of socket 358 * @param auth require the remote device to be authenticated 359 * @param encrypt require the connection to be encrypted 360 * @param port remote port 361 * @param uuid SDP uuid 362 * @param pitm enforce person-in-the-middle protection. 363 * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection 364 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges 365 */ BluetoothSocket( @onNull BluetoothDevice device, int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid, boolean pitm, boolean min16DigitPin)366 /*package*/ BluetoothSocket( 367 @NonNull BluetoothDevice device, 368 int type, 369 boolean auth, 370 boolean encrypt, 371 int port, 372 ParcelUuid uuid, 373 boolean pitm, 374 boolean min16DigitPin) 375 throws IOException { 376 this( 377 device, 378 type, 379 auth, 380 encrypt, 381 port, 382 uuid, 383 pitm, 384 min16DigitPin, 385 0, 386 DEFAULT_SOCKET_NAME, 387 0, 388 0, 389 0); 390 } 391 392 /** 393 * Construct a BluetoothSocket. 394 * 395 * @param device remote device that this socket can connect to 396 * @param type type of socket 397 * @param auth require the remote device to be authenticated 398 * @param encrypt require the connection to be encrypted 399 * @param port remote port 400 * @param uuid SDP uuid 401 * @param pitm enforce person-in-the-middle protection. 402 * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection 403 * @param dataPath data path used for this socket 404 * @param socketName user-friendly name for this socket 405 * @param hubId ID of the hub to which the end point belongs 406 * @param endpointId ID of the endpoint within the hub that is associated with this socket 407 * @param maximumPacketSize The maximum size (in bytes) of a single data packet 408 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges 409 */ BluetoothSocket( @onNull BluetoothDevice device, int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid, boolean pitm, boolean min16DigitPin, int dataPath, @NonNull String socketName, long hubId, long endpointId, int maximumPacketSize)410 /*package*/ BluetoothSocket( 411 @NonNull BluetoothDevice device, 412 int type, 413 boolean auth, 414 boolean encrypt, 415 int port, 416 ParcelUuid uuid, 417 boolean pitm, 418 boolean min16DigitPin, 419 int dataPath, 420 @NonNull String socketName, 421 long hubId, 422 long endpointId, 423 int maximumPacketSize) 424 throws IOException { 425 if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type); 426 mSocketCreationTimeNanos = System.nanoTime(); 427 if (type == BluetoothSocket.TYPE_RFCOMM 428 && uuid == null 429 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 430 if (port < 1 || port > MAX_RFCOMM_CHANNEL) { 431 throw new IOException("Invalid RFCOMM channel: " + port); 432 } 433 } 434 if (uuid != null) { 435 mUuid = uuid; 436 } else { 437 mUuid = new ParcelUuid(new UUID(0, 0)); 438 } 439 mType = type; 440 mAuth = auth; 441 mAuthPitm = pitm; 442 mMin16DigitPin = min16DigitPin; 443 mEncrypt = encrypt; 444 mDevice = device; 445 mPort = port; 446 mDataPath = dataPath; 447 mSocketName = socketName; 448 mHubId = hubId; 449 mEndpointId = endpointId; 450 mMaximumPacketSize = maximumPacketSize; 451 452 mSocketState = SocketState.INIT; 453 454 // Remote socket 455 mAddress = device.getAddress(); 456 457 mInputStream = new BluetoothInputStream(this); 458 mOutputStream = new BluetoothOutputStream(this); 459 mSocketCreationLatencyNanos = System.nanoTime() - mSocketCreationTimeNanos; 460 } 461 462 /** 463 * Creates a BluetoothSocket from a {@link ParcelFileDescriptor}. This is used for when the 464 * underlying mPfd is transferred to a separate process (e.g. over a binder), and the socket 465 * must be reconstructed. 466 * 467 * <p>The socket should already be connected in this case, so {@link #connect()} should not be 468 * called. 469 * 470 * @param pfd is the {@link ParcelFileDescriptor} for an already connected BluetoothSocket 471 * @param device is the remote {@link BluetoothDevice} that this socket is connected to 472 * @param uuid is the service ID that this RFCOMM connection is using 473 * @throws IOException if socket creation fails. 474 */ createSocketFromOpenFd( ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid)475 /*package*/ static BluetoothSocket createSocketFromOpenFd( 476 ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid) throws IOException { 477 BluetoothSocket bluetoothSocket = 478 new BluetoothSocket(device, TYPE_RFCOMM, true, true, -1, uuid); 479 480 bluetoothSocket.mPfd = pfd; 481 bluetoothSocket.mSocket = new LocalSocket(pfd.getFileDescriptor()); 482 bluetoothSocket.mSocketIS = bluetoothSocket.mSocket.getInputStream(); 483 bluetoothSocket.mSocketOS = bluetoothSocket.mSocket.getOutputStream(); 484 bluetoothSocket.mSocketState = SocketState.CONNECTED; 485 486 return bluetoothSocket; 487 } 488 BluetoothSocket(BluetoothSocket s)489 private BluetoothSocket(BluetoothSocket s) { 490 if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType); 491 mUuid = s.mUuid; 492 mType = s.mType; 493 mAuth = s.mAuth; 494 mEncrypt = s.mEncrypt; 495 mPort = s.mPort; 496 mInputStream = new BluetoothInputStream(this); 497 mOutputStream = new BluetoothOutputStream(this); 498 mMaxRxPacketSize = s.mMaxRxPacketSize; 499 mMaxTxPacketSize = s.mMaxTxPacketSize; 500 mConnectionUuid = s.mConnectionUuid; 501 mSocketId = s.mSocketId; 502 503 mServiceName = s.mServiceName; 504 mExcludeSdp = s.mExcludeSdp; 505 mAuthPitm = s.mAuthPitm; 506 mMin16DigitPin = s.mMin16DigitPin; 507 mDataPath = s.mDataPath; 508 mSocketName = s.mSocketName; 509 mHubId = s.mHubId; 510 mEndpointId = s.mEndpointId; 511 mMaximumPacketSize = s.mMaximumPacketSize; 512 mSocketCreationTimeNanos = s.mSocketCreationTimeNanos; 513 mSocketCreationLatencyNanos = s.mSocketCreationLatencyNanos; 514 } 515 acceptSocket(String remoteAddr)516 private BluetoothSocket acceptSocket(String remoteAddr) throws IOException { 517 BluetoothSocket as = new BluetoothSocket(this); 518 as.mSocketState = SocketState.CONNECTED; 519 FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors(); 520 if (DBG) Log.d(TAG, "acceptSocket: socket fd passed by stack fds:" + Arrays.toString(fds)); 521 if (fds == null || fds.length != 1) { 522 Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds)); 523 as.close(); 524 throw new IOException("bt socket accept failed"); 525 } 526 527 as.mPfd = ParcelFileDescriptor.dup(fds[0]); 528 as.mSocket = new LocalSocket(fds[0]); 529 as.mSocketIS = as.mSocket.getInputStream(); 530 as.mSocketOS = as.mSocket.getOutputStream(); 531 as.mAddress = remoteAddr; 532 as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr); 533 return as; 534 } 535 536 /** @hide */ 537 @Override 538 @SuppressWarnings("Finalize") // TODO(b/314811467) finalize()539 protected void finalize() throws Throwable { 540 try { 541 close(); 542 } finally { 543 super.finalize(); 544 } 545 } 546 getSecurityFlags()547 private int getSecurityFlags() { 548 int flags = 0; 549 if (mAuth) { 550 flags |= SEC_FLAG_AUTH; 551 } 552 if (mEncrypt) { 553 flags |= SEC_FLAG_ENCRYPT; 554 } 555 if (mExcludeSdp) { 556 flags |= BTSOCK_FLAG_NO_SDP; 557 } 558 if (mAuthPitm) { 559 flags |= SEC_FLAG_AUTH_PITM; 560 } 561 if (mMin16DigitPin) { 562 flags |= SEC_FLAG_AUTH_16_DIGIT; 563 } 564 return flags; 565 } 566 567 /** 568 * Get the remote device this socket is connecting, or connected, to. 569 * 570 * @return remote device 571 */ 572 @RequiresNoPermission getRemoteDevice()573 public BluetoothDevice getRemoteDevice() { 574 return mDevice; 575 } 576 577 /** 578 * Get the input stream associated with this socket. 579 * 580 * <p>The input stream will be returned even if the socket is not yet connected, but operations 581 * on that stream will throw IOException until the associated socket is connected. 582 * 583 * @return InputStream 584 */ 585 @RequiresNoPermission getInputStream()586 public InputStream getInputStream() throws IOException { 587 return mInputStream; 588 } 589 590 /** 591 * Get the output stream associated with this socket. 592 * 593 * <p>The output stream will be returned even if the socket is not yet connected, but operations 594 * on that stream will throw IOException until the associated socket is connected. 595 * 596 * @return OutputStream 597 */ 598 @RequiresNoPermission getOutputStream()599 public OutputStream getOutputStream() throws IOException { 600 return mOutputStream; 601 } 602 603 /** 604 * Get the connection status of this socket, ie, whether there is an active connection with 605 * remote device. 606 * 607 * @return true if connected false if not connected 608 */ 609 @RequiresNoPermission isConnected()610 public boolean isConnected() { 611 return mSocketState == SocketState.CONNECTED; 612 } 613 setServiceName(String name)614 /*package*/ void setServiceName(String name) { 615 mServiceName = name; 616 } 617 isAuth()618 /*package*/ boolean isAuth() { 619 return mAuth; 620 } 621 622 /** 623 * Attempt to connect to a remote device. 624 * 625 * <p>This method will block until a connection is made or the connection fails. If this method 626 * returns without an exception then this socket is now connected. 627 * 628 * <p>Creating new connections to remote Bluetooth devices should not be attempted while device 629 * discovery is in progress. Device discovery is a heavyweight procedure on the Bluetooth 630 * adapter and will significantly slow a device connection. Use {@link 631 * BluetoothAdapter#cancelDiscovery()} to cancel an ongoing discovery. Discovery is not managed 632 * by the Activity, but is run as a system service, so an application should always call {@link 633 * BluetoothAdapter#cancelDiscovery()} even if it did not directly request a discovery, just to 634 * be sure. 635 * 636 * <p>{@link #close} can be used to abort this call from another thread. 637 * 638 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when 639 * {@code mDataPath} is different from {@link BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}. 640 * 641 * @throws BluetoothSocketException in case of failure, with the corresponding error code. 642 * @throws IOException for other errors (eg: InputStream read failures etc.). 643 */ 644 @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API) 645 @RequiresBluetoothConnectPermission 646 @RequiresPermission( 647 allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}, 648 conditional = true) connect()649 public void connect() throws IOException { 650 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 651 long socketConnectionTimeNanos = System.nanoTime(); 652 if (bluetoothProxy == null) { 653 throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE); 654 } 655 try { 656 if (mDevice == null) { 657 throw new BluetoothSocketException(BluetoothSocketException.NULL_DEVICE); 658 } 659 if (mSocketState == SocketState.CLOSED) { 660 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 661 } 662 663 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 664 if (socketManager == null) { 665 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE); 666 } 667 if (Flags.socketSettingsApi()) { 668 if (mDataPath == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) { 669 mPfd = 670 socketManager.connectSocket( 671 mDevice, mType, mUuid, mPort, getSecurityFlags()); 672 } else { 673 mPfd = 674 socketManager.connectSocketWithOffload( 675 mDevice, 676 mType, 677 mUuid, 678 mPort, 679 getSecurityFlags(), 680 mDataPath, 681 mSocketName, 682 mHubId, 683 mEndpointId, 684 mMaximumPacketSize); 685 } 686 } else { 687 mPfd = 688 socketManager.connectSocket( 689 mDevice, mType, mUuid, mPort, getSecurityFlags()); 690 } 691 synchronized (this) { 692 Log.i(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 693 if (mSocketState == SocketState.CLOSED) { 694 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 695 } 696 if (mPfd == null) { 697 throw new BluetoothSocketException( 698 BluetoothSocketException.UNIX_FILE_SOCKET_CREATION_FAILURE); 699 } 700 FileDescriptor fd = mPfd.getFileDescriptor(); 701 mSocket = new LocalSocket(fd); 702 mSocketIS = mSocket.getInputStream(); 703 mSocketOS = mSocket.getOutputStream(); 704 } 705 int channel = readInt(mSocketIS); 706 if (channel == 0) { 707 int errCode = (int) mSocketIS.read(); 708 throw new BluetoothSocketException(errCode); 709 } 710 if (channel < 0) { 711 throw new BluetoothSocketException( 712 BluetoothSocketException.SOCKET_CONNECTION_FAILURE); 713 } 714 mPort = channel; 715 waitSocketSignal(mSocketIS); 716 synchronized (this) { 717 if (mSocketState == SocketState.CLOSED) { 718 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 719 } 720 mSocketState = SocketState.CONNECTED; 721 Log.i(TAG, "connect(), socket connected. mPort=" + mPort); 722 } 723 } catch (BluetoothSocketException e) { 724 SocketMetrics.logSocketConnect( 725 e.getErrorCode(), 726 socketConnectionTimeNanos, 727 mType, 728 mDevice, 729 mPort, 730 mAuth, 731 mSocketCreationTimeNanos, 732 mSocketCreationLatencyNanos); 733 throw e; 734 } catch (RemoteException e) { 735 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 736 SocketMetrics.logSocketConnect( 737 BluetoothSocketException.RPC_FAILURE, 738 socketConnectionTimeNanos, 739 mType, 740 mDevice, 741 mPort, 742 mAuth, 743 mSocketCreationTimeNanos, 744 mSocketCreationLatencyNanos); 745 throw new BluetoothSocketException( 746 BluetoothSocketException.RPC_FAILURE, "unable to send RPC: " + e.getMessage()); 747 } 748 SocketMetrics.logSocketConnect( 749 SocketMetrics.SOCKET_NO_ERROR, 750 socketConnectionTimeNanos, 751 mType, 752 mDevice, 753 mPort, 754 mAuth, 755 mSocketCreationTimeNanos, 756 mSocketCreationLatencyNanos); 757 } 758 759 /** 760 * Currently returns unix errno instead of throwing IOException, so that BluetoothAdapter can 761 * check the error code for EADDRINUSE 762 */ 763 @RequiresBluetoothConnectPermission 764 @RequiresPermission(BLUETOOTH_CONNECT) bindListen()765 /*package*/ int bindListen() { 766 int ret; 767 if (mSocketState == SocketState.CLOSED) return EBADFD; 768 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 769 if (bluetoothProxy == null) { 770 Log.e(TAG, "bindListen fail, reason: bluetooth is off"); 771 return -1; 772 } 773 try { 774 if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType); 775 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 776 if (socketManager == null) { 777 Log.e(TAG, "bindListen() bt get socket manager failed"); 778 return -1; 779 } 780 mPfd = 781 socketManager.createSocketChannel( 782 mType, mServiceName, mUuid, mPort, getSecurityFlags()); 783 } catch (RemoteException e) { 784 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 785 return -1; 786 } 787 788 // read out port number 789 try { 790 synchronized (this) { 791 if (DBG) { 792 Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 793 } 794 if (mSocketState != SocketState.INIT) return EBADFD; 795 if (mPfd == null) return -1; 796 FileDescriptor fd = mPfd.getFileDescriptor(); 797 if (fd == null) { 798 Log.e(TAG, "bindListen(), null file descriptor"); 799 return -1; 800 } 801 802 if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket"); 803 mSocket = new LocalSocket(fd); 804 if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()"); 805 mSocketIS = mSocket.getInputStream(); 806 mSocketOS = mSocket.getOutputStream(); 807 } 808 if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS); 809 int channel = readInt(mSocketIS); 810 synchronized (this) { 811 if (mSocketState == SocketState.INIT) { 812 mSocketState = SocketState.LISTENING; 813 } 814 } 815 if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort); 816 if (mPort <= -1) { 817 mPort = channel; 818 } 819 ret = 0; 820 } catch (IOException e) { 821 if (mPfd != null) { 822 try { 823 mPfd.close(); 824 } catch (IOException e1) { 825 Log.e(TAG, "bindListen, close mPfd: " + e1); 826 } 827 mPfd = null; 828 } 829 Log.e(TAG, "bindListen, fail to get port number, exception: " + e); 830 return -1; 831 } 832 return ret; 833 } 834 835 /** 836 * Currently returns unix errno instead of throwing IOException, so that BluetoothAdapter can 837 * check the error code for EADDRINUSE 838 */ 839 @RequiresBluetoothConnectPermission 840 @RequiresPermission( 841 allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}, 842 conditional = true) bindListenWithOffload()843 /*package*/ int bindListenWithOffload() { 844 int ret; 845 if (mSocketState == SocketState.CLOSED) return EBADFD; 846 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 847 if (bluetoothProxy == null) { 848 Log.e(TAG, "bindListenWithOffload() fail, reason: bluetooth is off"); 849 return -1; 850 } 851 try { 852 if (DBG) Log.d(TAG, "bindListenWithOffload(): mPort=" + mPort + ", mType=" + mType); 853 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 854 if (socketManager == null) { 855 Log.e(TAG, "bindListenWithOffload() bt get socket manager failed"); 856 return -1; 857 } 858 mPfd = 859 socketManager.createSocketChannelWithOffload( 860 mType, 861 mServiceName, 862 mUuid, 863 mPort, 864 getSecurityFlags(), 865 mDataPath, 866 mSocketName, 867 mHubId, 868 mEndpointId, 869 mMaximumPacketSize); 870 } catch (RemoteException e) { 871 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 872 return -1; 873 } 874 875 // read out port number 876 try { 877 synchronized (this) { 878 if (DBG) { 879 Log.d( 880 TAG, 881 "bindListenWithOffload(), SocketState: " 882 + mSocketState 883 + ", mPfd: " 884 + mPfd); 885 } 886 if (mSocketState != SocketState.INIT) return EBADFD; 887 if (mPfd == null) return -1; 888 FileDescriptor fd = mPfd.getFileDescriptor(); 889 if (fd == null) { 890 Log.e(TAG, "bindListenWithOffload(), null file descriptor"); 891 return -1; 892 } 893 894 if (DBG) Log.d(TAG, "bindListenWithOffload(), Create LocalSocket"); 895 mSocket = new LocalSocket(fd); 896 if (DBG) Log.d(TAG, "bindListenWithOffload(), new LocalSocket.getInputStream()"); 897 mSocketIS = mSocket.getInputStream(); 898 mSocketOS = mSocket.getOutputStream(); 899 } 900 if (DBG) Log.d(TAG, "bindListenWithOffload(), readInt mSocketIS: " + mSocketIS); 901 int channel = readInt(mSocketIS); 902 synchronized (this) { 903 if (mSocketState == SocketState.INIT) { 904 mSocketState = SocketState.LISTENING; 905 } 906 } 907 if (DBG) Log.d(TAG, "bindListenWithOffload(): channel=" + channel + ", mPort=" + mPort); 908 if (mPort <= -1) { 909 mPort = channel; 910 } 911 ret = 0; 912 } catch (IOException e) { 913 if (mPfd != null) { 914 try { 915 mPfd.close(); 916 } catch (IOException e1) { 917 Log.e(TAG, "bindListenWithOffload, close mPfd: " + e1); 918 } 919 mPfd = null; 920 } 921 Log.e(TAG, "bindListenWithOffload, fail to get port number, exception: " + e); 922 return -1; 923 } 924 return ret; 925 } 926 accept(int timeout)927 /*package*/ BluetoothSocket accept(int timeout) throws IOException { 928 BluetoothSocket acceptedSocket; 929 if (mSocketState != SocketState.LISTENING) { 930 throw new IOException("bt socket is not in listen state"); 931 } 932 Log.d(TAG, "accept(), timeout (ms):" + timeout); 933 if (timeout > 0) { 934 mSocket.setSoTimeout(timeout); 935 } 936 sendSocketAcceptSignal(mSocketOS, true); 937 String RemoteAddr; 938 try { 939 RemoteAddr = waitSocketSignal(mSocketIS); 940 } finally { 941 sendSocketAcceptSignal(mSocketOS, false); 942 } 943 if (timeout > 0) { 944 mSocket.setSoTimeout(0); 945 } 946 synchronized (this) { 947 if (mSocketState != SocketState.LISTENING) { 948 throw new IOException("bt socket is not in listen state"); 949 } 950 acceptedSocket = acceptSocket(RemoteAddr); 951 // quick drop the reference of the file handle 952 } 953 return acceptedSocket; 954 } 955 available()956 /*package*/ int available() throws IOException { 957 if (VDBG) Log.d(TAG, "available: " + mSocketIS); 958 return mSocketIS.available(); 959 } 960 read(byte[] b, int offset, int length)961 /*package*/ int read(byte[] b, int offset, int length) throws IOException { 962 int ret = 0; 963 if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); 964 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 965 int bytesToRead = length; 966 if (VDBG) { 967 Log.v( 968 TAG, 969 "l2cap: read(): offset: " 970 + offset 971 + " length:" 972 + length 973 + "mL2capBuffer= " 974 + mL2capBuffer); 975 } 976 if (mL2capBuffer == null) { 977 createL2capRxBuffer(); 978 } 979 if (mL2capBuffer.remaining() == 0) { 980 if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling..."); 981 if (fillL2capRxBuffer() == -1) { 982 Log.d(TAG, "socket EOF, returning -1"); 983 mSocketState = SocketState.CLOSED; 984 return -1; 985 } 986 } 987 if (bytesToRead > mL2capBuffer.remaining()) { 988 bytesToRead = mL2capBuffer.remaining(); 989 } 990 if (VDBG) { 991 Log.v(TAG, "get(): offset: " + offset + " bytesToRead: " + bytesToRead); 992 } 993 mL2capBuffer.get(b, offset, bytesToRead); 994 ret = bytesToRead; 995 } else { 996 if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length); 997 ret = mSocketIS.read(b, offset, length); 998 } 999 if (ret < 0) { 1000 mSocketState = SocketState.CLOSED; 1001 throw new IOException("bt socket closed, read return: " + ret); 1002 } 1003 if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); 1004 return ret; 1005 } 1006 write(byte[] b, int offset, int length)1007 /*package*/ int write(byte[] b, int offset, int length) throws IOException { 1008 1009 // TODO: Since bindings can exist between the SDU size and the 1010 // protocol, we might need to throw an exception instead of just 1011 // splitting the write into multiple smaller writes. 1012 // Rfcomm uses dynamic allocation, and should not have any bindings 1013 // to the actual message length. 1014 if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); 1015 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 1016 if (length <= mMaxTxPacketSize) { 1017 mSocketOS.write(b, offset, length); 1018 } else { 1019 if (DBG) { 1020 Log.w( 1021 TAG, 1022 "WARNING: Write buffer larger than L2CAP packet size!\n" 1023 + "Packet will be divided into SDU packets of size " 1024 + mMaxTxPacketSize); 1025 } 1026 int tmpOffset = offset; 1027 int bytesToWrite = length; 1028 while (bytesToWrite > 0) { 1029 int tmpLength = 1030 (bytesToWrite > mMaxTxPacketSize) ? mMaxTxPacketSize : bytesToWrite; 1031 mSocketOS.write(b, tmpOffset, tmpLength); 1032 tmpOffset += tmpLength; 1033 bytesToWrite -= tmpLength; 1034 } 1035 } 1036 } else { 1037 mSocketOS.write(b, offset, length); 1038 } 1039 // There is no good way to confirm since the entire process is asynchronous anyway 1040 if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length); 1041 return length; 1042 } 1043 1044 @Override close()1045 public void close() throws IOException { 1046 Log.d( 1047 TAG, 1048 "close() this: " 1049 + this 1050 + ", channel: " 1051 + mPort 1052 + ", mSocketIS: " 1053 + mSocketIS 1054 + ", mSocketOS: " 1055 + mSocketOS 1056 + ", mSocket: " 1057 + mSocket 1058 + ", mSocketState: " 1059 + mSocketState); 1060 if (mSocketState == SocketState.CLOSED) { 1061 return; 1062 } else { 1063 synchronized (this) { 1064 if (mSocketState == SocketState.CLOSED) { 1065 return; 1066 } 1067 mSocketState = SocketState.CLOSED; 1068 if (mSocket != null) { 1069 if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket); 1070 mSocket.shutdownInput(); 1071 mSocket.shutdownOutput(); 1072 mSocket.close(); 1073 mSocket = null; 1074 } 1075 if (mPfd != null) { 1076 mPfd.close(); 1077 mPfd = null; 1078 } 1079 mConnectionUuid = null; 1080 mSocketId = INVALID_SOCKET_ID; 1081 } 1082 } 1083 } 1084 removeChannel()1085 /*package */ void removeChannel() {} 1086 getPort()1087 /*package */ int getPort() { 1088 return mPort; 1089 } 1090 getSocketCreationTime()1091 /*package */ long getSocketCreationTime() { 1092 return mSocketCreationTimeNanos; 1093 } 1094 1095 /** 1096 * Get the maximum supported Transmit packet size for the underlying transport. Use this to 1097 * optimize the writes done to the output socket, to avoid sending half full packets. 1098 * 1099 * @return the maximum supported Transmit packet size for the underlying transport. 1100 */ 1101 @RequiresNoPermission getMaxTransmitPacketSize()1102 public int getMaxTransmitPacketSize() { 1103 return mMaxTxPacketSize; 1104 } 1105 1106 /** 1107 * Get the maximum supported Receive packet size for the underlying transport. Use this to 1108 * optimize the reads done on the input stream, as any call to read will return a maximum of 1109 * this amount of bytes - or for some transports a multiple of this value. 1110 * 1111 * @return the maximum supported Receive packet size for the underlying transport. 1112 */ 1113 @RequiresNoPermission getMaxReceivePacketSize()1114 public int getMaxReceivePacketSize() { 1115 return mMaxRxPacketSize; 1116 } 1117 1118 /** 1119 * Get the type of the underlying connection. 1120 * 1121 * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP} 1122 */ 1123 @RequiresNoPermission getConnectionType()1124 public int getConnectionType() { 1125 if (mType == TYPE_L2CAP_LE) { 1126 // Treat the LE CoC to be the same type as L2CAP. 1127 return TYPE_L2CAP; 1128 } 1129 return mType; 1130 } 1131 1132 /** 1133 * Change if a SDP entry should be automatically created. Must be called before calling .bind, 1134 * for the call to have any effect. 1135 * 1136 * @param excludeSdp 1137 * <li>TRUE - do not auto generate SDP record. 1138 * <li>FALSE - default - auto generate SPP SDP record. 1139 * @hide 1140 */ 1141 @RequiresNoPermission setExcludeSdp(boolean excludeSdp)1142 public void setExcludeSdp(boolean excludeSdp) { 1143 mExcludeSdp = excludeSdp; 1144 } 1145 1146 /** 1147 * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This 1148 * parameter is used by the BT Controller to set the maximum transmission packet size on this 1149 * connection. This function is currently used for testing only. 1150 * 1151 * @hide 1152 */ 1153 @RequiresBluetoothConnectPermission 1154 @RequiresPermission(BLUETOOTH_CONNECT) requestMaximumTxDataLength()1155 public void requestMaximumTxDataLength() throws IOException { 1156 if (mDevice == null) { 1157 throw new IOException("requestMaximumTxDataLength is called on null device"); 1158 } 1159 1160 try { 1161 if (mSocketState == SocketState.CLOSED) { 1162 throw new IOException("socket closed"); 1163 } 1164 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 1165 if (bluetoothProxy == null) { 1166 throw new IOException("Bluetooth is off"); 1167 } 1168 1169 if (DBG) Log.d(TAG, "requestMaximumTxDataLength"); 1170 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 1171 if (socketManager == null) throw new IOException("bt get socket manager failed"); 1172 socketManager.requestMaximumTxDataLength(mDevice); 1173 } catch (RemoteException e) { 1174 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1175 throw new IOException("unable to send RPC: " + e.getMessage()); 1176 } 1177 } 1178 1179 /** 1180 * Returns the L2CAP local channel ID associated with an open connection to this socket. 1181 * 1182 * @return the L2CAP local channel ID. 1183 * @throws BluetoothSocketException in case of failure, with the corresponding error code. 1184 * @hide 1185 */ 1186 @SystemApi 1187 @FlaggedApi(Flags.FLAG_BT_SOCKET_API_L2CAP_CID) 1188 @RequiresBluetoothConnectPermission 1189 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) getL2capLocalChannelId()1190 public int getL2capLocalChannelId() throws IOException { 1191 if (mType != TYPE_L2CAP_LE) { 1192 throw new BluetoothSocketException(BluetoothSocketException.L2CAP_UNKNOWN); 1193 } 1194 if (mSocketState != SocketState.CONNECTED || mConnectionUuid == null) { 1195 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 1196 } 1197 int cid; 1198 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 1199 if (bluetoothProxy == null) { 1200 throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE); 1201 } 1202 try { 1203 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 1204 if (socketManager == null) { 1205 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE); 1206 } 1207 cid = 1208 socketManager.getL2capLocalChannelId( 1209 mConnectionUuid, AttributionSource.myAttributionSource()); 1210 } catch (RemoteException e) { 1211 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1212 throw new IOException("unable to send RPC: " + e.getMessage()); 1213 } 1214 if (cid == -1) { 1215 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 1216 } 1217 return cid; 1218 } 1219 1220 /** 1221 * Returns the L2CAP remote channel ID associated with an open connection to this socket. 1222 * 1223 * @return the L2CAP remote channel ID. 1224 * @throws BluetoothSocketException in case of failure, with the corresponding error code. 1225 * @hide 1226 */ 1227 @SystemApi 1228 @FlaggedApi(Flags.FLAG_BT_SOCKET_API_L2CAP_CID) 1229 @RequiresBluetoothConnectPermission 1230 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) getL2capRemoteChannelId()1231 public int getL2capRemoteChannelId() throws IOException { 1232 if (mType != TYPE_L2CAP_LE) { 1233 throw new BluetoothSocketException(BluetoothSocketException.L2CAP_UNKNOWN); 1234 } 1235 if (mSocketState != SocketState.CONNECTED || mConnectionUuid == null) { 1236 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 1237 } 1238 int cid; 1239 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 1240 if (bluetoothProxy == null) { 1241 throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE); 1242 } 1243 try { 1244 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 1245 if (socketManager == null) { 1246 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE); 1247 } 1248 cid = 1249 socketManager.getL2capRemoteChannelId( 1250 mConnectionUuid, AttributionSource.myAttributionSource()); 1251 } catch (RemoteException e) { 1252 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1253 throw new IOException("unable to send RPC: " + e.getMessage()); 1254 } 1255 if (cid == -1) { 1256 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 1257 } 1258 return cid; 1259 } 1260 1261 /** 1262 * Returns the socket ID assigned to the open connection on this BluetoothSocket. This socket ID 1263 * is a unique identifier for the socket. It is valid only while the socket is connected. 1264 * 1265 * @return The socket ID in connected state. 1266 * @throws BluetoothSocketException If the socket is not connected or an error occurs while 1267 * retrieving the socket ID. 1268 * @hide 1269 */ 1270 @SystemApi 1271 @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API) 1272 @RequiresNoPermission getSocketId()1273 public long getSocketId() throws IOException { 1274 if (mSocketState != SocketState.CONNECTED || mSocketId == INVALID_SOCKET_ID) { 1275 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 1276 } 1277 return mSocketId; 1278 } 1279 1280 /** @hide */ 1281 @RequiresNoPermission getParcelFileDescriptor()1282 public ParcelFileDescriptor getParcelFileDescriptor() { 1283 return mPfd; 1284 } 1285 convertAddr(final byte[] addr)1286 private static String convertAddr(final byte[] addr) { 1287 return String.format( 1288 Locale.US, 1289 "%02X:%02X:%02X:%02X:%02X:%02X", 1290 addr[0], 1291 addr[1], 1292 addr[2], 1293 addr[3], 1294 addr[4], 1295 addr[5]); 1296 } 1297 1298 /** 1299 * Sends a socket accept signal to the host stack. 1300 * 1301 * <p>This method is used to notify the host stack whether the host application is actively 1302 * accepting a new connection or not. It sends a signal containing the acceptance status to the 1303 * output stream associated with the socket. 1304 * 1305 * <p>This method is only effective when the data path is not {@link 1306 * BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}. 1307 * 1308 * @param os The output stream to write the signal to. 1309 * @param isAccepting {@code true} if the socket connection is being accepted, {@code false} 1310 * otherwise. 1311 * @throws IOException If an I/O error occurs while writing to the output stream. 1312 * @hide 1313 */ sendSocketAcceptSignal(OutputStream os, boolean isAccepting)1314 private void sendSocketAcceptSignal(OutputStream os, boolean isAccepting) throws IOException { 1315 if (Flags.socketSettingsApi()) { 1316 if (mDataPath == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) { 1317 return; 1318 } 1319 Log.d(TAG, "sendSocketAcceptSignal" + " isAccepting " + isAccepting); 1320 byte[] sig = new byte[SOCK_ACCEPT_SIGNAL_SIZE]; 1321 ByteBuffer bb = ByteBuffer.wrap(sig); 1322 bb.order(ByteOrder.nativeOrder()); 1323 bb.putShort((short) SOCK_ACCEPT_SIGNAL_SIZE); 1324 bb.putShort((short) (isAccepting ? 1 : 0)); 1325 os.write(sig, 0, SOCK_ACCEPT_SIGNAL_SIZE); 1326 } 1327 } 1328 waitSocketSignal(InputStream is)1329 private String waitSocketSignal(InputStream is) throws IOException { 1330 byte[] sig = new byte[SOCK_CONNECTION_SIGNAL_SIZE]; 1331 int ret = readAll(is, sig); 1332 if (VDBG) { 1333 Log.d( 1334 TAG, 1335 "waitSocketSignal read " 1336 + SOCK_CONNECTION_SIGNAL_SIZE 1337 + " bytes signal ret: " 1338 + ret); 1339 } 1340 ByteBuffer bb = ByteBuffer.wrap(sig); 1341 /* the struct in native is decorated with __attribute__((packed)), hence this is possible */ 1342 bb.order(ByteOrder.nativeOrder()); 1343 int size = bb.getShort(); 1344 if (size != SOCK_CONNECTION_SIGNAL_SIZE) { 1345 throw new IOException("Connection failure, wrong signal size: " + size); 1346 } 1347 byte[] addr = new byte[6]; 1348 bb.get(addr); 1349 int channel = bb.getInt(); 1350 int status = bb.getInt(); 1351 mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value 1352 mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value 1353 long uuidLsb = bb.getLong(); 1354 long uuidMsb = bb.getLong(); 1355 mConnectionUuid = new ParcelUuid(new UUID(uuidMsb, uuidLsb)); 1356 mSocketId = bb.getLong(); 1357 String RemoteAddr = convertAddr(addr); 1358 if (VDBG) { 1359 Log.d( 1360 TAG, 1361 "waitSocketSignal: sig size: " 1362 + size 1363 + ", remote addr: " 1364 + RemoteAddr 1365 + ", channel: " 1366 + channel 1367 + ", status: " 1368 + status 1369 + " MaxRxPktSize: " 1370 + mMaxRxPacketSize 1371 + " MaxTxPktSize: " 1372 + mMaxTxPacketSize 1373 + " mConnectionUuid: " 1374 + mConnectionUuid.toString() 1375 + " mSocketId: " 1376 + mSocketId); 1377 } 1378 if (status != 0) { 1379 throw new IOException("Connection failure, status: " + status); 1380 } 1381 return RemoteAddr; 1382 } 1383 createL2capRxBuffer()1384 private void createL2capRxBuffer() { 1385 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 1386 // Allocate the buffer to use for reads. 1387 if (VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize); 1388 mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]); 1389 if (VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining()); 1390 mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request 1391 if (VDBG) { 1392 Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + mL2capBuffer.remaining()); 1393 } 1394 } 1395 } 1396 readAll(InputStream is, byte[] b)1397 private static int readAll(InputStream is, byte[] b) throws IOException { 1398 int left = b.length; 1399 while (left > 0) { 1400 int ret = is.read(b, b.length - left, left); 1401 if (ret <= 0) { 1402 throw new IOException( 1403 "read failed, socket might closed or timeout, read ret: " + ret); 1404 } 1405 left -= ret; 1406 if (left != 0) { 1407 Log.w( 1408 TAG, 1409 "readAll() looping, read partial size: " 1410 + (b.length - left) 1411 + ", expect size: " 1412 + b.length); 1413 } 1414 } 1415 return b.length; 1416 } 1417 readInt(InputStream is)1418 private static int readInt(InputStream is) throws IOException { 1419 byte[] ibytes = new byte[4]; 1420 int ret = readAll(is, ibytes); 1421 if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret); 1422 ByteBuffer bb = ByteBuffer.wrap(ibytes); 1423 bb.order(ByteOrder.nativeOrder()); 1424 return bb.getInt(); 1425 } 1426 fillL2capRxBuffer()1427 private int fillL2capRxBuffer() throws IOException { 1428 mL2capBuffer.rewind(); 1429 int ret = mSocketIS.read(mL2capBuffer.array()); 1430 if (ret == -1) { 1431 // reached end of stream - return -1 1432 mL2capBuffer.limit(0); 1433 return -1; 1434 } 1435 mL2capBuffer.limit(ret); 1436 return ret; 1437 } 1438 1439 @Override toString()1440 public String toString() { 1441 return BluetoothUtils.toAnonymizedAddress(mAddress); 1442 } 1443 } 1444