BluetoothSocket.java revision f455986a45328614c8dd07a4d60a30b9ddc3d994
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 17package android.bluetooth; 18 19import android.os.ParcelUuid; 20import android.os.ParcelFileDescriptor; 21import android.os.RemoteException; 22import android.util.Log; 23 24import java.io.BufferedInputStream; 25import java.io.Closeable; 26import java.io.FileDescriptor; 27import java.io.IOException; 28import java.io.InputStream; 29import java.io.OutputStream; 30import java.util.Locale; 31import java.util.UUID; 32import android.net.LocalSocket; 33 34import java.nio.Buffer; 35import java.nio.ByteOrder; 36import java.nio.ByteBuffer; 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/wireless/bluetooth.html">Bluetooth</a> developer guide.</p> 79 * </div> 80 * 81 * {@see BluetoothServerSocket} 82 * {@see java.io.InputStream} 83 * {@see java.io.OutputStream} 84 */ 85public 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 /*package*/ static final int EBADFD = 77; 104 /*package*/ static final int EADDRINUSE = 98; 105 106 /*package*/ static final int SEC_FLAG_ENCRYPT = 1; 107 /*package*/ static final int SEC_FLAG_AUTH = 1 << 1; 108 /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2; 109 110 private final int mType; /* one of TYPE_RFCOMM etc */ 111 private BluetoothDevice mDevice; /* remote device */ 112 private String mAddress; /* remote address */ 113 private final boolean mAuth; 114 private final boolean mEncrypt; 115 private final BluetoothInputStream mInputStream; 116 private final BluetoothOutputStream mOutputStream; 117 private final ParcelUuid mUuid; 118 private boolean mExcludeSdp = false; 119 private ParcelFileDescriptor mPfd; 120 private LocalSocket mSocket; 121 private InputStream mSocketIS; 122 private OutputStream mSocketOS; 123 private int mPort; /* RFCOMM channel or L2CAP psm */ 124 private int mFd; 125 private String mServiceName; 126 private static int PROXY_CONNECTION_TIMEOUT = 5000; 127 128 private static int SOCK_SIGNAL_SIZE = 20; 129 130 private ByteBuffer mL2capBuffer = null; 131 private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer. 132 private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received. 133 134 private enum SocketState { 135 INIT, 136 CONNECTED, 137 LISTENING, 138 CLOSED, 139 } 140 141 /** prevents all native calls after destroyNative() */ 142 private volatile SocketState mSocketState; 143 144 /** protects mSocketState */ 145 //private final ReentrantReadWriteLock mLock; 146 147 /** 148 * Construct a BluetoothSocket. 149 * @param type type of socket 150 * @param fd fd to use for connected socket, or -1 for a new socket 151 * @param auth require the remote device to be authenticated 152 * @param encrypt require the connection to be encrypted 153 * @param device remote device that this socket can connect to 154 * @param port remote port 155 * @param uuid SDP uuid 156 * @throws IOException On error, for example Bluetooth not available, or 157 * insufficient privileges 158 */ 159 /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, 160 BluetoothDevice device, int port, ParcelUuid uuid) throws IOException { 161 if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type); 162 if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1 163 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 164 if (port < 1 || port > MAX_RFCOMM_CHANNEL) { 165 throw new IOException("Invalid RFCOMM channel: " + port); 166 } 167 } 168 if (uuid != null) 169 mUuid = uuid; 170 else mUuid = new ParcelUuid(new UUID(0, 0)); 171 mType = type; 172 mAuth = auth; 173 mEncrypt = encrypt; 174 mDevice = device; 175 mPort = port; 176 mFd = fd; 177 178 mSocketState = SocketState.INIT; 179 180 if (device == null) { 181 // Server socket 182 mAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); 183 } else { 184 // Remote socket 185 mAddress = device.getAddress(); 186 } 187 mInputStream = new BluetoothInputStream(this); 188 mOutputStream = new BluetoothOutputStream(this); 189 } 190 private BluetoothSocket(BluetoothSocket s) { 191 if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType); 192 mUuid = s.mUuid; 193 mType = s.mType; 194 mAuth = s.mAuth; 195 mEncrypt = s.mEncrypt; 196 mPort = s.mPort; 197 mInputStream = new BluetoothInputStream(this); 198 mOutputStream = new BluetoothOutputStream(this); 199 mMaxRxPacketSize = s.mMaxRxPacketSize; 200 mMaxTxPacketSize = s.mMaxTxPacketSize; 201 202 mServiceName = s.mServiceName; 203 mExcludeSdp = s.mExcludeSdp; 204 } 205 private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException { 206 BluetoothSocket as = new BluetoothSocket(this); 207 as.mSocketState = SocketState.CONNECTED; 208 FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors(); 209 if (DBG) Log.d(TAG, "socket fd passed by stack fds: " + fds); 210 if(fds == null || fds.length != 1) { 211 Log.e(TAG, "socket fd passed from stack failed, fds: " + fds); 212 as.close(); 213 throw new IOException("bt socket acept failed"); 214 } 215 as.mSocket = new LocalSocket(fds[0]); 216 as.mSocketIS = as.mSocket.getInputStream(); 217 as.mSocketOS = as.mSocket.getOutputStream(); 218 as.mAddress = RemoteAddr; 219 as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(RemoteAddr); 220 return as; 221 } 222 /** 223 * Construct a BluetoothSocket from address. Used by native code. 224 * @param type type of socket 225 * @param fd fd to use for connected socket, or -1 for a new socket 226 * @param auth require the remote device to be authenticated 227 * @param encrypt require the connection to be encrypted 228 * @param address remote device that this socket can connect to 229 * @param port remote port 230 * @throws IOException On error, for example Bluetooth not available, or 231 * insufficient privileges 232 */ 233 private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, 234 int port) throws IOException { 235 this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null); 236 } 237 238 /** @hide */ 239 @Override 240 protected void finalize() throws Throwable { 241 try { 242 close(); 243 } finally { 244 super.finalize(); 245 } 246 } 247 private int getSecurityFlags() { 248 int flags = 0; 249 if(mAuth) 250 flags |= SEC_FLAG_AUTH; 251 if(mEncrypt) 252 flags |= SEC_FLAG_ENCRYPT; 253 if(mExcludeSdp) 254 flags |= BTSOCK_FLAG_NO_SDP; 255 return flags; 256 } 257 258 /** 259 * Get the remote device this socket is connecting, or connected, to. 260 * @return remote device 261 */ 262 public BluetoothDevice getRemoteDevice() { 263 return mDevice; 264 } 265 266 /** 267 * Get the input stream associated with this socket. 268 * <p>The input stream will be returned even if the socket is not yet 269 * connected, but operations on that stream will throw IOException until 270 * the associated socket is connected. 271 * @return InputStream 272 */ 273 public InputStream getInputStream() throws IOException { 274 return mInputStream; 275 } 276 277 /** 278 * Get the output stream associated with this socket. 279 * <p>The output stream will be returned even if the socket is not yet 280 * connected, but operations on that stream will throw IOException until 281 * the associated socket is connected. 282 * @return OutputStream 283 */ 284 public OutputStream getOutputStream() throws IOException { 285 return mOutputStream; 286 } 287 288 /** 289 * Get the connection status of this socket, ie, whether there is an active connection with 290 * remote device. 291 * @return true if connected 292 * false if not connected 293 */ 294 public boolean isConnected() { 295 return mSocketState == SocketState.CONNECTED; 296 } 297 298 /*package*/ void setServiceName(String name) { 299 mServiceName = name; 300 } 301 302 /** 303 * Attempt to connect to a remote device. 304 * <p>This method will block until a connection is made or the connection 305 * fails. If this method returns without an exception then this socket 306 * is now connected. 307 * <p>Creating new connections to 308 * remote Bluetooth devices should not be attempted while device discovery 309 * is in progress. Device discovery is a heavyweight procedure on the 310 * Bluetooth adapter and will significantly slow a device connection. 311 * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing 312 * discovery. Discovery is not managed by the Activity, 313 * but is run as a system service, so an application should always call 314 * {@link BluetoothAdapter#cancelDiscovery()} even if it 315 * did not directly request a discovery, just to be sure. 316 * <p>{@link #close} can be used to abort this call from another thread. 317 * @throws IOException on error, for example connection failure 318 */ 319 public void connect() throws IOException { 320 if (mDevice == null) throw new IOException("Connect is called on null device"); 321 322 try { 323 if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); 324 IBluetooth bluetoothProxy = 325 BluetoothAdapter.getDefaultAdapter().getBluetoothService(null); 326 if (bluetoothProxy == null) throw new IOException("Bluetooth is off"); 327 mPfd = bluetoothProxy.connectSocket(mDevice, mType, 328 mUuid, mPort, getSecurityFlags()); 329 synchronized(this) 330 { 331 if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 332 if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); 333 if (mPfd == null) throw new IOException("bt socket connect failed"); 334 FileDescriptor fd = mPfd.getFileDescriptor(); 335 mSocket = new LocalSocket(fd); 336 mSocketIS = mSocket.getInputStream(); 337 mSocketOS = mSocket.getOutputStream(); 338 } 339 int channel = readInt(mSocketIS); 340 if (channel <= 0) 341 throw new IOException("bt socket connect failed"); 342 mPort = channel; 343 waitSocketSignal(mSocketIS); 344 synchronized(this) 345 { 346 if (mSocketState == SocketState.CLOSED) 347 throw new IOException("bt socket closed"); 348 mSocketState = SocketState.CONNECTED; 349 } 350 } catch (RemoteException e) { 351 Log.e(TAG, Log.getStackTraceString(new Throwable())); 352 throw new IOException("unable to send RPC: " + e.getMessage()); 353 } 354 } 355 356 /** 357 * Currently returns unix errno instead of throwing IOException, 358 * so that BluetoothAdapter can check the error code for EADDRINUSE 359 */ 360 /*package*/ int bindListen() { 361 int ret; 362 if (mSocketState == SocketState.CLOSED) return EBADFD; 363 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null); 364 if (bluetoothProxy == null) { 365 Log.e(TAG, "bindListen fail, reason: bluetooth is off"); 366 return -1; 367 } 368 try { 369 mPfd = bluetoothProxy.createSocketChannel(mType, mServiceName, 370 mUuid, mPort, getSecurityFlags()); 371 } catch (RemoteException e) { 372 Log.e(TAG, Log.getStackTraceString(new Throwable())); 373 return -1; 374 } 375 376 // read out port number 377 try { 378 synchronized(this) { 379 if (DBG) Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + 380 mPfd); 381 if(mSocketState != SocketState.INIT) return EBADFD; 382 if(mPfd == null) return -1; 383 FileDescriptor fd = mPfd.getFileDescriptor(); 384 if (DBG) Log.d(TAG, "bindListen(), new LocalSocket "); 385 mSocket = new LocalSocket(fd); 386 if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() "); 387 mSocketIS = mSocket.getInputStream(); 388 mSocketOS = mSocket.getOutputStream(); 389 } 390 if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS); 391 int channel = readInt(mSocketIS); 392 synchronized(this) { 393 if(mSocketState == SocketState.INIT) 394 mSocketState = SocketState.LISTENING; 395 } 396 if (DBG) Log.d(TAG, "channel: " + channel); 397 if (mPort <= -1) { 398 mPort = channel; 399 } // else ASSERT(mPort == channel) 400 ret = 0; 401 } catch (IOException e) { 402 if (mPfd != null) { 403 try { 404 mPfd.close(); 405 } catch (IOException e1) { 406 Log.e(TAG, "bindListen, close mPfd: " + e1); 407 } 408 mPfd = null; 409 } 410 Log.e(TAG, "bindListen, fail to get port number, exception: " + e); 411 return -1; 412 } 413 return ret; 414 } 415 416 /*package*/ BluetoothSocket accept(int timeout) throws IOException { 417 BluetoothSocket acceptedSocket; 418 if (mSocketState != SocketState.LISTENING) 419 throw new IOException("bt socket is not in listen state"); 420 if(timeout > 0) { 421 Log.d(TAG, "accept() set timeout (ms):" + timeout); 422 mSocket.setSoTimeout(timeout); 423 } 424 String RemoteAddr = waitSocketSignal(mSocketIS); 425 if(timeout > 0) 426 mSocket.setSoTimeout(0); 427 synchronized(this) 428 { 429 if (mSocketState != SocketState.LISTENING) 430 throw new IOException("bt socket is not in listen state"); 431 acceptedSocket = acceptSocket(RemoteAddr); 432 //quick drop the reference of the file handle 433 } 434 return acceptedSocket; 435 } 436 437 /*package*/ int available() throws IOException { 438 if (VDBG) Log.d(TAG, "available: " + mSocketIS); 439 return mSocketIS.available(); 440 } 441 /** 442 * Wait until the data in sending queue is emptied. A polling version 443 * for flush implementation. Used to ensure the writing data afterwards will 444 * be packed in new RFCOMM frame. 445 * @throws IOException 446 * if an i/o error occurs. 447 */ 448 /*package*/ void flush() throws IOException { 449 if (mSocketOS == null) throw new IOException("flush is called on null OutputStream"); 450 if (VDBG) Log.d(TAG, "flush: " + mSocketOS); 451 mSocketOS.flush(); 452 } 453 454 /*package*/ int read(byte[] b, int offset, int length) throws IOException { 455 int ret = 0; 456 if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); 457 if(mType == TYPE_L2CAP) 458 { 459 int bytesToRead = length; 460 if (VDBG) Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length 461 + "mL2capBuffer= " + mL2capBuffer); 462 if (mL2capBuffer == null) { 463 createL2capRxBuffer(); 464 } 465 if (mL2capBuffer.remaining() == 0) { 466 if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling..."); 467 if (fillL2capRxBuffer() == -1) { 468 return -1; 469 } 470 } 471 if (bytesToRead > mL2capBuffer.remaining()) { 472 bytesToRead = mL2capBuffer.remaining(); 473 } 474 if(VDBG) Log.v(TAG, "get(): offset: " + offset 475 + " bytesToRead: " + bytesToRead); 476 mL2capBuffer.get(b, offset, bytesToRead); 477 ret = bytesToRead; 478 }else { 479 if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length); 480 ret = mSocketIS.read(b, offset, length); 481 } 482 if (ret < 0) 483 throw new IOException("bt socket closed, read return: " + ret); 484 if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); 485 return ret; 486 } 487 488 /*package*/ int write(byte[] b, int offset, int length) throws IOException { 489 490 //TODO: Since bindings can exist between the SDU size and the 491 // protocol, we might need to throw an exception instead of just 492 // splitting the write into multiple smaller writes. 493 // Rfcomm uses dynamic allocation, and should not have any bindings 494 // to the actual message length. 495 if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); 496 if (mType == TYPE_L2CAP) { 497 if(length <= mMaxTxPacketSize) { 498 mSocketOS.write(b, offset, length); 499 } else { 500 int tmpOffset = offset; 501 int tmpLength = mMaxTxPacketSize; 502 int endIndex = offset + length; 503 boolean done = false; 504 if(DBG) Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n" 505 + "Packet will be divided into SDU packets of size " 506 + mMaxTxPacketSize); 507 do{ 508 mSocketOS.write(b, tmpOffset, tmpLength); 509 tmpOffset += mMaxTxPacketSize; 510 if((tmpOffset + mMaxTxPacketSize) > endIndex) { 511 tmpLength = endIndex - tmpOffset; 512 done = true; 513 } 514 } while(!done); 515 516 } 517 } else { 518 mSocketOS.write(b, offset, length); 519 } 520 // There is no good way to confirm since the entire process is asynchronous anyway 521 if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length); 522 return length; 523 } 524 525 @Override 526 public void close() throws IOException { 527 if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " 528 + mSocketState); 529 if(mSocketState == SocketState.CLOSED) 530 return; 531 else 532 { 533 synchronized(this) 534 { 535 if(mSocketState == SocketState.CLOSED) 536 return; 537 mSocketState = SocketState.CLOSED; 538 if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + 539 ", mSocketIS: " + mSocketIS + ", mSocketOS: " + mSocketOS + 540 "mSocket: " + mSocket); 541 if(mSocket != null) { 542 if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket); 543 mSocket.shutdownInput(); 544 mSocket.shutdownOutput(); 545 mSocket.close(); 546 mSocket = null; 547 } 548 if (mPfd != null) { 549 mPfd.close(); 550 mPfd = null; 551 } 552 } 553 } 554 } 555 556 /*package */ void removeChannel() { 557 } 558 559 /*package */ int getPort() { 560 return mPort; 561 } 562 563 /** 564 * Get the maximum supported Transmit packet size for the underlying transport. 565 * Use this to optimize the writes done to the output socket, to avoid sending 566 * half full packets. 567 * @return the maximum supported Transmit packet size for the underlying transport. 568 */ 569 public int getMaxTransmitPacketSize(){ 570 return mMaxTxPacketSize; 571 } 572 573 /** 574 * Get the maximum supported Receive packet size for the underlying transport. 575 * Use this to optimize the reads done on the input stream, as any call to read 576 * will return a maximum of this amount of bytes - or for some transports a 577 * multiple of this value. 578 * @return the maximum supported Receive packet size for the underlying transport. 579 */ 580 public int getMaxReceivePacketSize(){ 581 return mMaxRxPacketSize; 582 } 583 584 /** 585 * Get the type of the underlying connection. 586 * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP} 587 */ 588 public int getConnectionType() { 589 return mType; 590 } 591 592 /** 593 * Change if a SDP entry should be automatically created. 594 * Must be called before calling .bind, for the call to have any effect. 595 * @param mExcludeSdp <li>TRUE - do not auto generate SDP record. 596 * <li>FALSE - default - auto generate SPP SDP record. 597 * @hide 598 */ 599 public void setExcludeSdp(boolean excludeSdp) { 600 this.mExcludeSdp = excludeSdp; 601 } 602 603 private String convertAddr(final byte[] addr) { 604 return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", 605 addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]); 606 } 607 private String waitSocketSignal(InputStream is) throws IOException { 608 byte [] sig = new byte[SOCK_SIGNAL_SIZE]; 609 int ret = readAll(is, sig); 610 if (VDBG) Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE + 611 " bytes signal ret: " + ret); 612 ByteBuffer bb = ByteBuffer.wrap(sig); 613 /* the struct in native is decorated with __attribute__((packed)), hence this is possible */ 614 bb.order(ByteOrder.nativeOrder()); 615 int size = bb.getShort(); 616 if(size != SOCK_SIGNAL_SIZE) 617 throw new IOException("Connection failure, wrong signal size: " + size); 618 byte [] addr = new byte[6]; 619 bb.get(addr); 620 int channel = bb.getInt(); 621 int status = bb.getInt(); 622 mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value 623 mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value 624 String RemoteAddr = convertAddr(addr); 625 if (VDBG) Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: " 626 + RemoteAddr + ", channel: " + channel + ", status: " + status 627 + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize); 628 if(status != 0) 629 throw new IOException("Connection failure, status: " + status); 630 return RemoteAddr; 631 } 632 633 private void createL2capRxBuffer(){ 634 if(mType == TYPE_L2CAP) { 635 // Allocate the buffer to use for reads. 636 if(VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize); 637 mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]); 638 if(VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining()); 639 mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request 640 if(VDBG) Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + 641 mL2capBuffer.remaining()); 642 } 643 } 644 645 private int readAll(InputStream is, byte[] b) throws IOException { 646 int left = b.length; 647 while(left > 0) { 648 int ret = is.read(b, b.length - left, left); 649 if(ret <= 0) 650 throw new IOException("read failed, socket might closed or timeout, read ret: " 651 + ret); 652 left -= ret; 653 if(left != 0) 654 Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) + 655 ", expect size: " + b.length); 656 } 657 return b.length; 658 } 659 660 private int readInt(InputStream is) throws IOException { 661 byte[] ibytes = new byte[4]; 662 int ret = readAll(is, ibytes); 663 if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret); 664 ByteBuffer bb = ByteBuffer.wrap(ibytes); 665 bb.order(ByteOrder.nativeOrder()); 666 return bb.getInt(); 667 } 668 669 private int fillL2capRxBuffer() throws IOException { 670 mL2capBuffer.rewind(); 671 int ret = mSocketIS.read(mL2capBuffer.array()); 672 if(ret == -1) { 673 // reached end of stream - return -1 674 mL2capBuffer.limit(0); 675 return -1; 676 } 677 mL2capBuffer.limit(ret); 678 return ret; 679 } 680 681 682} 683