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