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