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