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.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 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 518 /** 519 * Wait until the data in sending queue is emptied. A polling version 520 * for flush implementation. Used to ensure the writing data afterwards will 521 * be packed in new RFCOMM frame. 522 * 523 * @throws IOException if an i/o error occurs. 524 */ 525 @UnsupportedAppUsage flush()526 /*package*/ void flush() throws IOException { 527 if (mSocketOS == null) throw new IOException("flush is called on null OutputStream"); 528 if (VDBG) Log.d(TAG, "flush: " + mSocketOS); 529 mSocketOS.flush(); 530 } 531 read(byte[] b, int offset, int length)532 /*package*/ int read(byte[] b, int offset, int length) throws IOException { 533 int ret = 0; 534 if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); 535 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 536 int bytesToRead = length; 537 if (VDBG) { 538 Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length 539 + "mL2capBuffer= " + mL2capBuffer); 540 } 541 if (mL2capBuffer == null) { 542 createL2capRxBuffer(); 543 } 544 if (mL2capBuffer.remaining() == 0) { 545 if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling..."); 546 if (fillL2capRxBuffer() == -1) { 547 return -1; 548 } 549 } 550 if (bytesToRead > mL2capBuffer.remaining()) { 551 bytesToRead = mL2capBuffer.remaining(); 552 } 553 if (VDBG) { 554 Log.v(TAG, "get(): offset: " + offset 555 + " bytesToRead: " + bytesToRead); 556 } 557 mL2capBuffer.get(b, offset, bytesToRead); 558 ret = bytesToRead; 559 } else { 560 if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length); 561 ret = mSocketIS.read(b, offset, length); 562 } 563 if (ret < 0) { 564 throw new IOException("bt socket closed, read return: " + ret); 565 } 566 if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); 567 return ret; 568 } 569 write(byte[] b, int offset, int length)570 /*package*/ int write(byte[] b, int offset, int length) throws IOException { 571 572 //TODO: Since bindings can exist between the SDU size and the 573 // protocol, we might need to throw an exception instead of just 574 // splitting the write into multiple smaller writes. 575 // Rfcomm uses dynamic allocation, and should not have any bindings 576 // to the actual message length. 577 if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); 578 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 579 if (length <= mMaxTxPacketSize) { 580 mSocketOS.write(b, offset, length); 581 } else { 582 if (DBG) { 583 Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n" 584 + "Packet will be divided into SDU packets of size " 585 + mMaxTxPacketSize); 586 } 587 int tmpOffset = offset; 588 int bytesToWrite = length; 589 while (bytesToWrite > 0) { 590 int tmpLength = (bytesToWrite > mMaxTxPacketSize) 591 ? mMaxTxPacketSize 592 : bytesToWrite; 593 mSocketOS.write(b, tmpOffset, tmpLength); 594 tmpOffset += tmpLength; 595 bytesToWrite -= tmpLength; 596 } 597 } 598 } else { 599 mSocketOS.write(b, offset, length); 600 } 601 // There is no good way to confirm since the entire process is asynchronous anyway 602 if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length); 603 return length; 604 } 605 606 @Override close()607 public void close() throws IOException { 608 Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS 609 + ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket + ", mSocketState: " 610 + mSocketState); 611 if (mSocketState == SocketState.CLOSED) { 612 return; 613 } else { 614 synchronized (this) { 615 if (mSocketState == SocketState.CLOSED) { 616 return; 617 } 618 mSocketState = SocketState.CLOSED; 619 if (mSocket != null) { 620 if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket); 621 mSocket.shutdownInput(); 622 mSocket.shutdownOutput(); 623 mSocket.close(); 624 mSocket = null; 625 } 626 if (mPfd != null) { 627 mPfd.close(); 628 mPfd = null; 629 } 630 } 631 } 632 } 633 removeChannel()634 /*package */ void removeChannel() { 635 } 636 getPort()637 /*package */ int getPort() { 638 return mPort; 639 } 640 641 /** 642 * Get the maximum supported Transmit packet size for the underlying transport. 643 * Use this to optimize the writes done to the output socket, to avoid sending 644 * half full packets. 645 * 646 * @return the maximum supported Transmit packet size for the underlying transport. 647 */ getMaxTransmitPacketSize()648 public int getMaxTransmitPacketSize() { 649 return mMaxTxPacketSize; 650 } 651 652 /** 653 * Get the maximum supported Receive packet size for the underlying transport. 654 * Use this to optimize the reads done on the input stream, as any call to read 655 * will return a maximum of this amount of bytes - or for some transports a 656 * multiple of this value. 657 * 658 * @return the maximum supported Receive packet size for the underlying transport. 659 */ getMaxReceivePacketSize()660 public int getMaxReceivePacketSize() { 661 return mMaxRxPacketSize; 662 } 663 664 /** 665 * Get the type of the underlying connection. 666 * 667 * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP} 668 */ getConnectionType()669 public int getConnectionType() { 670 if (mType == TYPE_L2CAP_LE) { 671 // Treat the LE CoC to be the same type as L2CAP. 672 return TYPE_L2CAP; 673 } 674 return mType; 675 } 676 677 /** 678 * Change if a SDP entry should be automatically created. 679 * Must be called before calling .bind, for the call to have any effect. 680 * 681 * @param excludeSdp <li>TRUE - do not auto generate SDP record. <li>FALSE - default - auto 682 * generate SPP SDP record. 683 * @hide 684 */ setExcludeSdp(boolean excludeSdp)685 public void setExcludeSdp(boolean excludeSdp) { 686 mExcludeSdp = excludeSdp; 687 } 688 689 /** 690 * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This 691 * parameter is used by the BT Controller to set the maximum transmission packet size on this 692 * connection. This function is currently used for testing only. 693 * @hide 694 */ requestMaximumTxDataLength()695 public void requestMaximumTxDataLength() throws IOException { 696 if (mDevice == null) { 697 throw new IOException("requestMaximumTxDataLength is called on null device"); 698 } 699 700 try { 701 if (mSocketState == SocketState.CLOSED) { 702 throw new IOException("socket closed"); 703 } 704 IBluetooth bluetoothProxy = 705 BluetoothAdapter.getDefaultAdapter().getBluetoothService(null); 706 if (bluetoothProxy == null) { 707 throw new IOException("Bluetooth is off"); 708 } 709 710 if (DBG) Log.d(TAG, "requestMaximumTxDataLength"); 711 bluetoothProxy.getSocketManager().requestMaximumTxDataLength(mDevice); 712 } catch (RemoteException e) { 713 Log.e(TAG, Log.getStackTraceString(new Throwable())); 714 throw new IOException("unable to send RPC: " + e.getMessage()); 715 } 716 } 717 convertAddr(final byte[] addr)718 private String convertAddr(final byte[] addr) { 719 return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", 720 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 721 } 722 waitSocketSignal(InputStream is)723 private String waitSocketSignal(InputStream is) throws IOException { 724 byte[] sig = new byte[SOCK_SIGNAL_SIZE]; 725 int ret = readAll(is, sig); 726 if (VDBG) { 727 Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE + " bytes signal ret: " + ret); 728 } 729 ByteBuffer bb = ByteBuffer.wrap(sig); 730 /* the struct in native is decorated with __attribute__((packed)), hence this is possible */ 731 bb.order(ByteOrder.nativeOrder()); 732 int size = bb.getShort(); 733 if (size != SOCK_SIGNAL_SIZE) { 734 throw new IOException("Connection failure, wrong signal size: " + size); 735 } 736 byte[] addr = new byte[6]; 737 bb.get(addr); 738 int channel = bb.getInt(); 739 int status = bb.getInt(); 740 mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value 741 mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value 742 String RemoteAddr = convertAddr(addr); 743 if (VDBG) { 744 Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: " 745 + RemoteAddr + ", channel: " + channel + ", status: " + status 746 + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize); 747 } 748 if (status != 0) { 749 throw new IOException("Connection failure, status: " + status); 750 } 751 return RemoteAddr; 752 } 753 createL2capRxBuffer()754 private void createL2capRxBuffer() { 755 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { 756 // Allocate the buffer to use for reads. 757 if (VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize); 758 mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]); 759 if (VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining()); 760 mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request 761 if (VDBG) { 762 Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + mL2capBuffer.remaining()); 763 } 764 } 765 } 766 readAll(InputStream is, byte[] b)767 private int readAll(InputStream is, byte[] b) throws IOException { 768 int left = b.length; 769 while (left > 0) { 770 int ret = is.read(b, b.length - left, left); 771 if (ret <= 0) { 772 throw new IOException("read failed, socket might closed or timeout, read ret: " 773 + ret); 774 } 775 left -= ret; 776 if (left != 0) { 777 Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) 778 + ", expect size: " + b.length); 779 } 780 } 781 return b.length; 782 } 783 readInt(InputStream is)784 private int readInt(InputStream is) throws IOException { 785 byte[] ibytes = new byte[4]; 786 int ret = readAll(is, ibytes); 787 if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret); 788 ByteBuffer bb = ByteBuffer.wrap(ibytes); 789 bb.order(ByteOrder.nativeOrder()); 790 return bb.getInt(); 791 } 792 fillL2capRxBuffer()793 private int fillL2capRxBuffer() throws IOException { 794 mL2capBuffer.rewind(); 795 int ret = mSocketIS.read(mL2capBuffer.array()); 796 if (ret == -1) { 797 // reached end of stream - return -1 798 mL2capBuffer.limit(0); 799 return -1; 800 } 801 mL2capBuffer.limit(ret); 802 return ret; 803 } 804 805 806 } 807