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