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