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 android.annotation.FlaggedApi; 20 import android.annotation.RequiresNoPermission; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SystemApi; 23 import android.bluetooth.annotations.RequiresBluetoothConnectPermission; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.content.AttributionSource; 26 import android.net.LocalSocket; 27 import android.os.Build; 28 import android.os.ParcelFileDescriptor; 29 import android.os.ParcelUuid; 30 import android.os.RemoteException; 31 import android.util.Log; 32 33 import com.android.bluetooth.flags.Flags; 34 35 import java.io.Closeable; 36 import java.io.FileDescriptor; 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.io.OutputStream; 40 import java.nio.ByteBuffer; 41 import java.nio.ByteOrder; 42 import java.util.Arrays; 43 import java.util.Locale; 44 import java.util.UUID; 45 46 /** 47 * A connected or connecting Bluetooth socket. 48 * 49 * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets: {@link java.net.Socket} 50 * and {@link java.net.ServerSocket}. On the server side, use a {@link BluetoothServerSocket} to 51 * create a listening server socket. When a connection is accepted by the {@link 52 * BluetoothServerSocket}, it will return a new {@link BluetoothSocket} to manage the connection. On 53 * the client side, use a single {@link BluetoothSocket} to both initiate an outgoing connection and 54 * to manage the connection. 55 * 56 * <p>The most common type of Bluetooth socket is RFCOMM, which is the type supported by the Android 57 * APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth. It is also known as 58 * the Serial Port Profile (SPP). 59 * 60 * <p>To create a {@link BluetoothSocket} for connecting to a known device, use {@link 61 * BluetoothDevice#createRfcommSocketToServiceRecord 62 * BluetoothDevice.createRfcommSocketToServiceRecord()}. Then call {@link #connect()} to attempt a 63 * connection to the remote device. This call will block until a connection is established or the 64 * connection fails. 65 * 66 * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the {@link 67 * BluetoothServerSocket} documentation. 68 * 69 * <p>Once the socket is connected, whether initiated as a client or accepted as a server, open the 70 * IO streams by calling {@link #getInputStream} and {@link #getOutputStream} in order to retrieve 71 * {@link java.io.InputStream} and {@link java.io.OutputStream} objects, respectively, which are 72 * automatically connected to the socket. 73 * 74 * <p>{@link BluetoothSocket} is thread safe. In particular, {@link #close} will always immediately 75 * abort ongoing operations and close the socket. 76 * 77 * <p><div class="special reference"> 78 * 79 * <h3>Developer Guides</h3> 80 * 81 * <p>For more information about using Bluetooth, read the <a 82 * href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide. </div> 83 * 84 * @see BluetoothServerSocket 85 * @see java.io.InputStream 86 * @see java.io.OutputStream 87 */ 88 public final class BluetoothSocket implements Closeable { 89 private static final String TAG = "BluetoothSocket"; 90 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 91 private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE); 92 93 /** @hide */ 94 public static final int MAX_RFCOMM_CHANNEL = 30; 95 96 /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF; 97 98 /** RFCOMM socket */ 99 public static final int TYPE_RFCOMM = 1; 100 101 /** SCO socket */ 102 public static final int TYPE_SCO = 2; 103 104 /** L2CAP socket */ 105 public static final int TYPE_L2CAP = 3; 106 107 /** 108 * L2CAP socket on BR/EDR transport 109 * 110 * @hide 111 */ 112 public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP; 113 114 /** 115 * L2CAP socket on LE transport 116 * 117 * @hide 118 */ 119 public static final int TYPE_L2CAP_LE = 4; 120 121 /*package*/ static final int EBADFD = 77; 122 123 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 124 /*package*/ static final int EADDRINUSE = 98; 125 126 /*package*/ static final int SEC_FLAG_ENCRYPT = 1; 127 /*package*/ static final int SEC_FLAG_AUTH = 1 << 1; 128 /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2; 129 /*package*/ static final int SEC_FLAG_AUTH_MITM = 1 << 3; 130 /*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4; 131 132 private final int mType; /* one of TYPE_RFCOMM etc */ 133 private BluetoothDevice mDevice; /* remote device */ 134 private String mAddress; /* remote address */ 135 private final boolean mAuth; 136 private final boolean mEncrypt; 137 private final BluetoothInputStream mInputStream; 138 private final BluetoothOutputStream mOutputStream; 139 private final ParcelUuid mUuid; 140 141 /** when true no SPP SDP record will be created */ 142 private boolean mExcludeSdp = false; 143 144 /** when true Person-in-the-middle protection will be enabled */ 145 private boolean mAuthMitm = false; 146 147 /** Minimum 16 digit pin for sec mode 2 connections */ 148 private boolean mMin16DigitPin = false; 149 150 @UnsupportedAppUsage(publicAlternatives = "Use {@link BluetoothSocket} public API instead.") 151 private ParcelFileDescriptor mPfd; 152 153 @UnsupportedAppUsage private LocalSocket mSocket; 154 private InputStream mSocketIS; 155 private OutputStream mSocketOS; 156 @UnsupportedAppUsage private int mPort; /* RFCOMM channel or L2CAP psm */ 157 private String mServiceName; 158 159 private static final int SOCK_SIGNAL_SIZE = 36; 160 161 private ByteBuffer mL2capBuffer = null; 162 private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer. 163 private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received. 164 private ParcelUuid mConnectionUuid; 165 166 private long mSocketCreationTimeNanos = 0; 167 private long mSocketCreationLatencyNanos = 0; 168 169 private enum SocketState { 170 INIT, 171 CONNECTED, 172 LISTENING, 173 CLOSED, 174 } 175 176 /** prevents all native calls after destroyNative() */ 177 private volatile SocketState mSocketState; 178 179 /** protects mSocketState */ 180 // private final ReentrantReadWriteLock mLock; 181 182 /** 183 * Construct a BluetoothSocket. 184 * 185 * @param type type of socket 186 * @param auth require the remote device to be authenticated 187 * @param encrypt require the connection to be encrypted 188 * @param device remote device that this socket can connect to 189 * @param port remote port 190 * @param uuid SDP uuid 191 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges 192 */ BluetoothSocket( int type, boolean auth, boolean encrypt, BluetoothDevice device, int port, ParcelUuid uuid)193 /*package*/ BluetoothSocket( 194 int type, 195 boolean auth, 196 boolean encrypt, 197 BluetoothDevice device, 198 int port, 199 ParcelUuid uuid) 200 throws IOException { 201 this(type, auth, encrypt, device, port, uuid, false, false); 202 } 203 204 /** 205 * Construct a BluetoothSocket. 206 * 207 * @param type type of socket 208 * @param auth require the remote device to be authenticated 209 * @param encrypt require the connection to be encrypted 210 * @param device remote device that this socket can connect to 211 * @param port remote port 212 * @param uuid SDP uuid 213 * @param mitm enforce person-in-the-middle protection. 214 * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection 215 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges 216 */ BluetoothSocket( int type, boolean auth, boolean encrypt, BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin)217 /*package*/ BluetoothSocket( 218 int type, 219 boolean auth, 220 boolean encrypt, 221 BluetoothDevice device, 222 int port, 223 ParcelUuid uuid, 224 boolean mitm, 225 boolean min16DigitPin) 226 throws IOException { 227 if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type); 228 mSocketCreationTimeNanos = System.nanoTime(); 229 if (type == BluetoothSocket.TYPE_RFCOMM 230 && uuid == null 231 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 232 if (port < 1 || port > MAX_RFCOMM_CHANNEL) { 233 throw new IOException("Invalid RFCOMM channel: " + port); 234 } 235 } 236 if (uuid != null) { 237 mUuid = uuid; 238 } else { 239 mUuid = new ParcelUuid(new UUID(0, 0)); 240 } 241 mType = type; 242 mAuth = auth; 243 mAuthMitm = mitm; 244 mMin16DigitPin = min16DigitPin; 245 mEncrypt = encrypt; 246 mDevice = device; 247 mPort = port; 248 249 mSocketState = SocketState.INIT; 250 251 if (device == null) { 252 // Server socket 253 mAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); 254 } else { 255 // Remote socket 256 mAddress = device.getAddress(); 257 } 258 mInputStream = new BluetoothInputStream(this); 259 mOutputStream = new BluetoothOutputStream(this); 260 mSocketCreationLatencyNanos = System.nanoTime() - mSocketCreationTimeNanos; 261 } 262 263 /** 264 * Creates a BluetoothSocket from a {@link ParcelFileDescriptor}. This is used for when the 265 * underlying mPfd is transferred to a separate process (e.g. over a binder), and the socket 266 * must be reconstructed. 267 * 268 * <p>The socket should already be connected in this case, so {@link #connect()} should not be 269 * called. 270 * 271 * @param pfd is the {@link ParcelFileDescriptor} for an already connected BluetoothSocket 272 * @param device is the remote {@link BluetoothDevice} that this socket is connected to 273 * @param uuid is the service ID that this RFCOMM connection is using 274 * @throws IOException if socket creation fails. 275 */ createSocketFromOpenFd( ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid)276 /*package*/ static BluetoothSocket createSocketFromOpenFd( 277 ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid) throws IOException { 278 BluetoothSocket bluetoothSocket = 279 new BluetoothSocket(TYPE_RFCOMM, true, true, device, -1, uuid); 280 281 bluetoothSocket.mPfd = pfd; 282 bluetoothSocket.mSocket = new LocalSocket(pfd.getFileDescriptor()); 283 bluetoothSocket.mSocketIS = bluetoothSocket.mSocket.getInputStream(); 284 bluetoothSocket.mSocketOS = bluetoothSocket.mSocket.getOutputStream(); 285 bluetoothSocket.mSocketState = SocketState.CONNECTED; 286 287 return bluetoothSocket; 288 } 289 BluetoothSocket(BluetoothSocket s)290 private BluetoothSocket(BluetoothSocket s) { 291 if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType); 292 mUuid = s.mUuid; 293 mType = s.mType; 294 mAuth = s.mAuth; 295 mEncrypt = s.mEncrypt; 296 mPort = s.mPort; 297 mInputStream = new BluetoothInputStream(this); 298 mOutputStream = new BluetoothOutputStream(this); 299 mMaxRxPacketSize = s.mMaxRxPacketSize; 300 mMaxTxPacketSize = s.mMaxTxPacketSize; 301 mConnectionUuid = s.mConnectionUuid; 302 303 mServiceName = s.mServiceName; 304 mExcludeSdp = s.mExcludeSdp; 305 mAuthMitm = s.mAuthMitm; 306 mMin16DigitPin = s.mMin16DigitPin; 307 mSocketCreationTimeNanos = s.mSocketCreationTimeNanos; 308 mSocketCreationLatencyNanos = s.mSocketCreationLatencyNanos; 309 } 310 acceptSocket(String remoteAddr)311 private BluetoothSocket acceptSocket(String remoteAddr) throws IOException { 312 BluetoothSocket as = new BluetoothSocket(this); 313 as.mSocketState = SocketState.CONNECTED; 314 FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors(); 315 if (DBG) Log.d(TAG, "acceptSocket: socket fd passed by stack fds:" + Arrays.toString(fds)); 316 if (fds == null || fds.length != 1) { 317 Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds)); 318 as.close(); 319 throw new IOException("bt socket accept failed"); 320 } 321 322 as.mPfd = ParcelFileDescriptor.dup(fds[0]); 323 as.mSocket = new LocalSocket(fds[0]); 324 as.mSocketIS = as.mSocket.getInputStream(); 325 as.mSocketOS = as.mSocket.getOutputStream(); 326 as.mAddress = remoteAddr; 327 as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr); 328 return as; 329 } 330 331 /** @hide */ 332 @Override 333 @SuppressWarnings("Finalize") // TODO(b/314811467) finalize()334 protected void finalize() throws Throwable { 335 try { 336 close(); 337 } finally { 338 super.finalize(); 339 } 340 } 341 getSecurityFlags()342 private int getSecurityFlags() { 343 int flags = 0; 344 if (mAuth) { 345 flags |= SEC_FLAG_AUTH; 346 } 347 if (mEncrypt) { 348 flags |= SEC_FLAG_ENCRYPT; 349 } 350 if (mExcludeSdp) { 351 flags |= BTSOCK_FLAG_NO_SDP; 352 } 353 if (mAuthMitm) { 354 flags |= SEC_FLAG_AUTH_MITM; 355 } 356 if (mMin16DigitPin) { 357 flags |= SEC_FLAG_AUTH_16_DIGIT; 358 } 359 return flags; 360 } 361 362 /** 363 * Get the remote device this socket is connecting, or connected, to. 364 * 365 * @return remote device 366 */ 367 @RequiresNoPermission getRemoteDevice()368 public BluetoothDevice getRemoteDevice() { 369 return mDevice; 370 } 371 372 /** 373 * Get the input stream associated with this socket. 374 * 375 * <p>The input stream will be returned even if the socket is not yet connected, but operations 376 * on that stream will throw IOException until the associated socket is connected. 377 * 378 * @return InputStream 379 */ 380 @RequiresNoPermission getInputStream()381 public InputStream getInputStream() throws IOException { 382 return mInputStream; 383 } 384 385 /** 386 * Get the output stream associated with this socket. 387 * 388 * <p>The output stream will be returned even if the socket is not yet connected, but operations 389 * on that stream will throw IOException until the associated socket is connected. 390 * 391 * @return OutputStream 392 */ 393 @RequiresNoPermission getOutputStream()394 public OutputStream getOutputStream() throws IOException { 395 return mOutputStream; 396 } 397 398 /** 399 * Get the connection status of this socket, ie, whether there is an active connection with 400 * remote device. 401 * 402 * @return true if connected false if not connected 403 */ 404 @RequiresNoPermission isConnected()405 public boolean isConnected() { 406 return mSocketState == SocketState.CONNECTED; 407 } 408 setServiceName(String name)409 /*package*/ void setServiceName(String name) { 410 mServiceName = name; 411 } 412 isAuth()413 /*package*/ boolean isAuth() { 414 return mAuth; 415 } 416 417 /** 418 * Attempt to connect to a remote device. 419 * 420 * <p>This method will block until a connection is made or the connection fails. If this method 421 * returns without an exception then this socket is now connected. 422 * 423 * <p>Creating new connections to remote Bluetooth devices should not be attempted while device 424 * discovery is in progress. Device discovery is a heavyweight procedure on the Bluetooth 425 * adapter and will significantly slow a device connection. Use {@link 426 * BluetoothAdapter#cancelDiscovery()} to cancel an ongoing discovery. Discovery is not managed 427 * by the Activity, but is run as a system service, so an application should always call {@link 428 * BluetoothAdapter#cancelDiscovery()} even if it did not directly request a discovery, just to 429 * be sure. 430 * 431 * <p>{@link #close} can be used to abort this call from another thread. 432 * 433 * @throws BluetoothSocketException in case of failure, with the corresponding error code. 434 * @throws IOException for other errors (eg: InputStream read failures etc.). 435 */ 436 @RequiresBluetoothConnectPermission 437 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connect()438 public void connect() throws IOException { 439 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 440 long socketConnectionTimeNanos = System.nanoTime(); 441 if (bluetoothProxy == null) { 442 throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE); 443 } 444 try { 445 if (mDevice == null) { 446 throw new BluetoothSocketException(BluetoothSocketException.NULL_DEVICE); 447 } 448 if (mSocketState == SocketState.CLOSED) { 449 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 450 } 451 452 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 453 if (socketManager == null) { 454 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE); 455 } 456 mPfd = socketManager.connectSocket(mDevice, mType, mUuid, mPort, getSecurityFlags()); 457 synchronized (this) { 458 Log.i(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 459 if (mSocketState == SocketState.CLOSED) { 460 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 461 } 462 if (mPfd == null) { 463 throw new BluetoothSocketException( 464 BluetoothSocketException.UNIX_FILE_SOCKET_CREATION_FAILURE); 465 } 466 FileDescriptor fd = mPfd.getFileDescriptor(); 467 mSocket = new LocalSocket(fd); 468 mSocketIS = mSocket.getInputStream(); 469 mSocketOS = mSocket.getOutputStream(); 470 } 471 int channel = readInt(mSocketIS); 472 if (channel == 0) { 473 int errCode = (int) mSocketIS.read(); 474 throw new BluetoothSocketException(errCode); 475 } 476 if (channel < 0) { 477 throw new BluetoothSocketException( 478 BluetoothSocketException.SOCKET_CONNECTION_FAILURE); 479 } 480 mPort = channel; 481 waitSocketSignal(mSocketIS); 482 synchronized (this) { 483 if (mSocketState == SocketState.CLOSED) { 484 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 485 } 486 mSocketState = SocketState.CONNECTED; 487 Log.i(TAG, "connect(), socket connected. mPort=" + mPort); 488 } 489 } catch (BluetoothSocketException e) { 490 SocketMetrics.logSocketConnect( 491 e.getErrorCode(), 492 socketConnectionTimeNanos, 493 mType, 494 mDevice, 495 mPort, 496 mAuth, 497 mSocketCreationTimeNanos, 498 mSocketCreationLatencyNanos); 499 throw e; 500 } catch (RemoteException e) { 501 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 502 SocketMetrics.logSocketConnect( 503 BluetoothSocketException.RPC_FAILURE, 504 socketConnectionTimeNanos, 505 mType, 506 mDevice, 507 mPort, 508 mAuth, 509 mSocketCreationTimeNanos, 510 mSocketCreationLatencyNanos); 511 throw new BluetoothSocketException( 512 BluetoothSocketException.RPC_FAILURE, "unable to send RPC: " + e.getMessage()); 513 } 514 SocketMetrics.logSocketConnect( 515 SocketMetrics.SOCKET_NO_ERROR, 516 socketConnectionTimeNanos, 517 mType, 518 mDevice, 519 mPort, 520 mAuth, 521 mSocketCreationTimeNanos, 522 mSocketCreationLatencyNanos); 523 } 524 525 /** 526 * Currently returns unix errno instead of throwing IOException, so that BluetoothAdapter can 527 * check the error code for EADDRINUSE 528 */ 529 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) bindListen()530 /*package*/ int bindListen() { 531 int ret; 532 if (mSocketState == SocketState.CLOSED) return EBADFD; 533 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 534 if (bluetoothProxy == null) { 535 Log.e(TAG, "bindListen fail, reason: bluetooth is off"); 536 return -1; 537 } 538 try { 539 if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType); 540 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 541 if (socketManager == null) { 542 Log.e(TAG, "bindListen() bt get socket manager failed"); 543 return -1; 544 } 545 mPfd = 546 socketManager.createSocketChannel( 547 mType, mServiceName, mUuid, mPort, getSecurityFlags()); 548 } catch (RemoteException e) { 549 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 550 return -1; 551 } 552 553 // read out port number 554 try { 555 synchronized (this) { 556 if (DBG) { 557 Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 558 } 559 if (mSocketState != SocketState.INIT) return EBADFD; 560 if (mPfd == null) return -1; 561 FileDescriptor fd = mPfd.getFileDescriptor(); 562 if (fd == null) { 563 Log.e(TAG, "bindListen(), null file descriptor"); 564 return -1; 565 } 566 567 if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket"); 568 mSocket = new LocalSocket(fd); 569 if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()"); 570 mSocketIS = mSocket.getInputStream(); 571 mSocketOS = mSocket.getOutputStream(); 572 } 573 if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS); 574 int channel = readInt(mSocketIS); 575 synchronized (this) { 576 if (mSocketState == SocketState.INIT) { 577 mSocketState = SocketState.LISTENING; 578 } 579 } 580 if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort); 581 if (mPort <= -1) { 582 mPort = channel; 583 } // else ASSERT(mPort == channel) 584 ret = 0; 585 } catch (IOException e) { 586 if (mPfd != null) { 587 try { 588 mPfd.close(); 589 } catch (IOException e1) { 590 Log.e(TAG, "bindListen, close mPfd: " + e1); 591 } 592 mPfd = null; 593 } 594 Log.e(TAG, "bindListen, fail to get port number, exception: " + e); 595 return -1; 596 } 597 return ret; 598 } 599 accept(int timeout)600 /*package*/ BluetoothSocket accept(int timeout) throws IOException { 601 BluetoothSocket acceptedSocket; 602 if (mSocketState != SocketState.LISTENING) { 603 throw new IOException("bt socket is not in listen state"); 604 } 605 Log.d(TAG, "accept(), timeout (ms):" + timeout); 606 if (timeout > 0) { 607 mSocket.setSoTimeout(timeout); 608 } 609 String RemoteAddr = waitSocketSignal(mSocketIS); 610 if (timeout > 0) { 611 mSocket.setSoTimeout(0); 612 } 613 synchronized (this) { 614 if (mSocketState != SocketState.LISTENING) { 615 throw new IOException("bt socket is not in listen state"); 616 } 617 acceptedSocket = acceptSocket(RemoteAddr); 618 // quick drop the reference of the file handle 619 } 620 return acceptedSocket; 621 } 622 available()623 /*package*/ int available() throws IOException { 624 if (VDBG) Log.d(TAG, "available: " + mSocketIS); 625 return mSocketIS.available(); 626 } 627 read(byte[] b, int offset, int length)628 /*package*/ int read(byte[] b, int offset, int length) throws IOException { 629 int ret = 0; 630 if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); 631 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 632 int bytesToRead = length; 633 if (VDBG) { 634 Log.v( 635 TAG, 636 "l2cap: read(): offset: " 637 + offset 638 + " length:" 639 + length 640 + "mL2capBuffer= " 641 + mL2capBuffer); 642 } 643 if (mL2capBuffer == null) { 644 createL2capRxBuffer(); 645 } 646 if (mL2capBuffer.remaining() == 0) { 647 if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling..."); 648 if (fillL2capRxBuffer() == -1) { 649 return -1; 650 } 651 } 652 if (bytesToRead > mL2capBuffer.remaining()) { 653 bytesToRead = mL2capBuffer.remaining(); 654 } 655 if (VDBG) { 656 Log.v(TAG, "get(): offset: " + offset + " bytesToRead: " + bytesToRead); 657 } 658 mL2capBuffer.get(b, offset, bytesToRead); 659 ret = bytesToRead; 660 } else { 661 if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length); 662 ret = mSocketIS.read(b, offset, length); 663 } 664 if (ret < 0) { 665 throw new IOException("bt socket closed, read return: " + ret); 666 } 667 if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); 668 return ret; 669 } 670 write(byte[] b, int offset, int length)671 /*package*/ int write(byte[] b, int offset, int length) throws IOException { 672 673 // TODO: Since bindings can exist between the SDU size and the 674 // protocol, we might need to throw an exception instead of just 675 // splitting the write into multiple smaller writes. 676 // Rfcomm uses dynamic allocation, and should not have any bindings 677 // to the actual message length. 678 if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); 679 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 680 if (length <= mMaxTxPacketSize) { 681 mSocketOS.write(b, offset, length); 682 } else { 683 if (DBG) { 684 Log.w( 685 TAG, 686 "WARNING: Write buffer larger than L2CAP packet size!\n" 687 + "Packet will be divided into SDU packets of size " 688 + mMaxTxPacketSize); 689 } 690 int tmpOffset = offset; 691 int bytesToWrite = length; 692 while (bytesToWrite > 0) { 693 int tmpLength = 694 (bytesToWrite > mMaxTxPacketSize) ? mMaxTxPacketSize : bytesToWrite; 695 mSocketOS.write(b, tmpOffset, tmpLength); 696 tmpOffset += tmpLength; 697 bytesToWrite -= tmpLength; 698 } 699 } 700 } else { 701 mSocketOS.write(b, offset, length); 702 } 703 // There is no good way to confirm since the entire process is asynchronous anyway 704 if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length); 705 return length; 706 } 707 708 @Override close()709 public void close() throws IOException { 710 Log.d( 711 TAG, 712 "close() this: " 713 + this 714 + ", channel: " 715 + mPort 716 + ", mSocketIS: " 717 + mSocketIS 718 + ", mSocketOS: " 719 + mSocketOS 720 + ", mSocket: " 721 + mSocket 722 + ", mSocketState: " 723 + mSocketState); 724 if (mSocketState == SocketState.CLOSED) { 725 return; 726 } else { 727 synchronized (this) { 728 if (mSocketState == SocketState.CLOSED) { 729 return; 730 } 731 mSocketState = SocketState.CLOSED; 732 if (mSocket != null) { 733 if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket); 734 mSocket.shutdownInput(); 735 mSocket.shutdownOutput(); 736 mSocket.close(); 737 mSocket = null; 738 } 739 if (mPfd != null) { 740 mPfd.close(); 741 mPfd = null; 742 } 743 mConnectionUuid = null; 744 } 745 } 746 } 747 removeChannel()748 /*package */ void removeChannel() {} 749 getPort()750 /*package */ int getPort() { 751 return mPort; 752 } 753 getSocketCreationTime()754 /*package */ long getSocketCreationTime() { 755 return mSocketCreationTimeNanos; 756 } 757 758 /** 759 * Get the maximum supported Transmit packet size for the underlying transport. Use this to 760 * optimize the writes done to the output socket, to avoid sending half full packets. 761 * 762 * @return the maximum supported Transmit packet size for the underlying transport. 763 */ 764 @RequiresNoPermission getMaxTransmitPacketSize()765 public int getMaxTransmitPacketSize() { 766 return mMaxTxPacketSize; 767 } 768 769 /** 770 * Get the maximum supported Receive packet size for the underlying transport. Use this to 771 * optimize the reads done on the input stream, as any call to read will return a maximum of 772 * this amount of bytes - or for some transports a multiple of this value. 773 * 774 * @return the maximum supported Receive packet size for the underlying transport. 775 */ 776 @RequiresNoPermission getMaxReceivePacketSize()777 public int getMaxReceivePacketSize() { 778 return mMaxRxPacketSize; 779 } 780 781 /** 782 * Get the type of the underlying connection. 783 * 784 * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP} 785 */ 786 @RequiresNoPermission getConnectionType()787 public int getConnectionType() { 788 if (mType == TYPE_L2CAP_LE) { 789 // Treat the LE CoC to be the same type as L2CAP. 790 return TYPE_L2CAP; 791 } 792 return mType; 793 } 794 795 /** 796 * Change if a SDP entry should be automatically created. Must be called before calling .bind, 797 * for the call to have any effect. 798 * 799 * @param excludeSdp 800 * <li>TRUE - do not auto generate SDP record. 801 * <li>FALSE - default - auto generate SPP SDP record. 802 * @hide 803 */ 804 @RequiresNoPermission setExcludeSdp(boolean excludeSdp)805 public void setExcludeSdp(boolean excludeSdp) { 806 mExcludeSdp = excludeSdp; 807 } 808 809 /** 810 * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This 811 * parameter is used by the BT Controller to set the maximum transmission packet size on this 812 * connection. This function is currently used for testing only. 813 * 814 * @hide 815 */ 816 @RequiresBluetoothConnectPermission 817 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) requestMaximumTxDataLength()818 public void requestMaximumTxDataLength() throws IOException { 819 if (mDevice == null) { 820 throw new IOException("requestMaximumTxDataLength is called on null device"); 821 } 822 823 try { 824 if (mSocketState == SocketState.CLOSED) { 825 throw new IOException("socket closed"); 826 } 827 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 828 if (bluetoothProxy == null) { 829 throw new IOException("Bluetooth is off"); 830 } 831 832 if (DBG) Log.d(TAG, "requestMaximumTxDataLength"); 833 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 834 if (socketManager == null) throw new IOException("bt get socket manager failed"); 835 socketManager.requestMaximumTxDataLength(mDevice); 836 } catch (RemoteException e) { 837 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 838 throw new IOException("unable to send RPC: " + e.getMessage()); 839 } 840 } 841 842 /** 843 * Returns the L2CAP local channel ID associated with an open connection to this socket. 844 * 845 * @return the L2CAP local channel ID. 846 * @throws BluetoothSocketException in case of failure, with the corresponding error code. 847 * @hide 848 */ 849 @SystemApi 850 @FlaggedApi(Flags.FLAG_BT_SOCKET_API_L2CAP_CID) 851 @RequiresPermission( 852 allOf = { 853 android.Manifest.permission.BLUETOOTH_CONNECT, 854 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 855 }) getL2capLocalChannelId()856 public int getL2capLocalChannelId() throws IOException { 857 if (mType != TYPE_L2CAP_LE) { 858 throw new BluetoothSocketException(BluetoothSocketException.L2CAP_UNKNOWN); 859 } 860 if (mSocketState != SocketState.CONNECTED || mConnectionUuid == null) { 861 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 862 } 863 int cid; 864 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 865 if (bluetoothProxy == null) { 866 throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE); 867 } 868 try { 869 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 870 if (socketManager == null) { 871 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE); 872 } 873 cid = 874 socketManager.getL2capLocalChannelId( 875 mConnectionUuid, AttributionSource.myAttributionSource()); 876 } catch (RemoteException e) { 877 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 878 throw new IOException("unable to send RPC: " + e.getMessage()); 879 } 880 if (cid == -1) { 881 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 882 } 883 return cid; 884 } 885 886 /** 887 * Returns the L2CAP remote channel ID associated with an open connection to this socket. 888 * 889 * @return the L2CAP remote channel ID. 890 * @throws BluetoothSocketException in case of failure, with the corresponding error code. 891 * @hide 892 */ 893 @SystemApi 894 @FlaggedApi(Flags.FLAG_BT_SOCKET_API_L2CAP_CID) 895 @RequiresPermission( 896 allOf = { 897 android.Manifest.permission.BLUETOOTH_CONNECT, 898 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 899 }) getL2capRemoteChannelId()900 public int getL2capRemoteChannelId() throws IOException { 901 if (mType != TYPE_L2CAP_LE) { 902 throw new BluetoothSocketException(BluetoothSocketException.L2CAP_UNKNOWN); 903 } 904 if (mSocketState != SocketState.CONNECTED || mConnectionUuid == null) { 905 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 906 } 907 int cid; 908 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 909 if (bluetoothProxy == null) { 910 throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE); 911 } 912 try { 913 IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager(); 914 if (socketManager == null) { 915 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE); 916 } 917 cid = 918 socketManager.getL2capRemoteChannelId( 919 mConnectionUuid, AttributionSource.myAttributionSource()); 920 } catch (RemoteException e) { 921 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 922 throw new IOException("unable to send RPC: " + e.getMessage()); 923 } 924 if (cid == -1) { 925 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED); 926 } 927 return cid; 928 } 929 930 /** @hide */ getParcelFileDescriptor()931 public ParcelFileDescriptor getParcelFileDescriptor() { 932 return mPfd; 933 } 934 convertAddr(final byte[] addr)935 private String convertAddr(final byte[] addr) { 936 return String.format( 937 Locale.US, 938 "%02X:%02X:%02X:%02X:%02X:%02X", 939 addr[0], 940 addr[1], 941 addr[2], 942 addr[3], 943 addr[4], 944 addr[5]); 945 } 946 waitSocketSignal(InputStream is)947 private String waitSocketSignal(InputStream is) throws IOException { 948 byte[] sig = new byte[SOCK_SIGNAL_SIZE]; 949 int ret = readAll(is, sig); 950 if (VDBG) { 951 Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE + " bytes signal ret: " + ret); 952 } 953 ByteBuffer bb = ByteBuffer.wrap(sig); 954 /* the struct in native is decorated with __attribute__((packed)), hence this is possible */ 955 bb.order(ByteOrder.nativeOrder()); 956 int size = bb.getShort(); 957 if (size != SOCK_SIGNAL_SIZE) { 958 throw new IOException("Connection failure, wrong signal size: " + size); 959 } 960 byte[] addr = new byte[6]; 961 bb.get(addr); 962 int channel = bb.getInt(); 963 int status = bb.getInt(); 964 mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value 965 mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value 966 long uuidLsb = bb.getLong(); 967 long uuidMsb = bb.getLong(); 968 mConnectionUuid = new ParcelUuid(new UUID(uuidMsb, uuidLsb)); 969 String RemoteAddr = convertAddr(addr); 970 if (VDBG) { 971 Log.d( 972 TAG, 973 "waitSocketSignal: sig size: " 974 + size 975 + ", remote addr: " 976 + RemoteAddr 977 + ", channel: " 978 + channel 979 + ", status: " 980 + status 981 + " MaxRxPktSize: " 982 + mMaxRxPacketSize 983 + " MaxTxPktSize: " 984 + mMaxTxPacketSize 985 + " mConnectionUuid: " 986 + mConnectionUuid.toString()); 987 } 988 if (status != 0) { 989 throw new IOException("Connection failure, status: " + status); 990 } 991 return RemoteAddr; 992 } 993 createL2capRxBuffer()994 private void createL2capRxBuffer() { 995 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 996 // Allocate the buffer to use for reads. 997 if (VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize); 998 mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]); 999 if (VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining()); 1000 mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request 1001 if (VDBG) { 1002 Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + mL2capBuffer.remaining()); 1003 } 1004 } 1005 } 1006 readAll(InputStream is, byte[] b)1007 private int readAll(InputStream is, byte[] b) throws IOException { 1008 int left = b.length; 1009 while (left > 0) { 1010 int ret = is.read(b, b.length - left, left); 1011 if (ret <= 0) { 1012 throw new IOException( 1013 "read failed, socket might closed or timeout, read ret: " + ret); 1014 } 1015 left -= ret; 1016 if (left != 0) { 1017 Log.w( 1018 TAG, 1019 "readAll() looping, read partial size: " 1020 + (b.length - left) 1021 + ", expect size: " 1022 + b.length); 1023 } 1024 } 1025 return b.length; 1026 } 1027 readInt(InputStream is)1028 private int readInt(InputStream is) throws IOException { 1029 byte[] ibytes = new byte[4]; 1030 int ret = readAll(is, ibytes); 1031 if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret); 1032 ByteBuffer bb = ByteBuffer.wrap(ibytes); 1033 bb.order(ByteOrder.nativeOrder()); 1034 return bb.getInt(); 1035 } 1036 fillL2capRxBuffer()1037 private int fillL2capRxBuffer() throws IOException { 1038 mL2capBuffer.rewind(); 1039 int ret = mSocketIS.read(mL2capBuffer.array()); 1040 if (ret == -1) { 1041 // reached end of stream - return -1 1042 mL2capBuffer.limit(0); 1043 return -1; 1044 } 1045 mL2capBuffer.limit(ret); 1046 return ret; 1047 } 1048 1049 @Override toString()1050 public String toString() { 1051 return BluetoothUtils.toAnonymizedAddress(mAddress); 1052 } 1053 } 1054