Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0a7c938 authored by Casper Bonde's avatar Casper Bonde Committed by Andre Eisenbach
Browse files

OBEX Over L2CAP + SDP search API for BT profiles

- Updated OBEX to support SRM
- Added support for OBEX over l2cap and SRM.
- Minor bugfixes, and reduce CPU load ALOT
- Added support to send responses without body data.
- Extend BluetoothSocket to support L2CAP
- Added functionality to get the channel number
  needed to be able to create an SDP record with the channel number.
- Added interface to get socket type and max packet sizes.
- Added interface to perform SDP search and get the resulting
  SDP record data.

Change-Id: I9d37a00ce73dfffc0e3ce03eab5511ba3a86e5b8
parent 98d25c5f
Loading
Loading
Loading
Loading
+47 −1
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009-2014 The Android Open Source Project
 * Copyright (C) 2009-2015 The Android Open Source Project
 * Copyright (C) 2015 Samsung LSI
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -377,6 +378,18 @@ public final class BluetoothAdapter {
    /** @hide */
    public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";


    /** When creating a ServerSocket using listenUsingRfcommOn() or
     *  listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create
     *  a ServerSocket that auto assigns a channel number to the first
     *  bluetooth socket.
     *  The channel number assigned to this first Bluetooth Socket will
     *  be stored in the ServerSocket, and reused for subsequent Bluetooth
     *  sockets.
     * @hide */
    public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2;


    private static final int ADDRESS_LENGTH = 17;

    private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30;
@@ -1144,6 +1157,9 @@ public final class BluetoothAdapter {
        BluetoothServerSocket socket = new BluetoothServerSocket(
                BluetoothSocket.TYPE_RFCOMM, true, true, channel);
        int errno = socket.mSocket.bindListen();
        if(channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
            socket.setChannel(socket.mSocket.getPort());
        }
        if (errno != 0) {
            //TODO(BT): Throw the same exception error code
            // that the previous code was using.
@@ -1278,6 +1294,9 @@ public final class BluetoothAdapter {
        BluetoothServerSocket socket = new BluetoothServerSocket(
                BluetoothSocket.TYPE_RFCOMM, false, false, port);
        int errno = socket.mSocket.bindListen();
        if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
            socket.setChannel(socket.mSocket.getPort());
        }
        if (errno != 0) {
            //TODO(BT): Throw the same exception error code
            // that the previous code was using.
@@ -1300,6 +1319,9 @@ public final class BluetoothAdapter {
        BluetoothServerSocket socket = new BluetoothServerSocket(
                BluetoothSocket.TYPE_RFCOMM, false, true, port);
        int errno = socket.mSocket.bindListen();
        if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
            socket.setChannel(socket.mSocket.getPort());
        }
        if (errno < 0) {
            //TODO(BT): Throw the same exception error code
            // that the previous code was using.
@@ -1329,6 +1351,30 @@ public final class BluetoothAdapter {
        return socket;
    }

    /**
     * Construct an encrypted, authenticated, L2CAP server socket.
     * Call #accept to retrieve connections to this socket.
     * @return An L2CAP BluetoothServerSocket
     * @throws IOException On error, for example Bluetooth not available, or
     *                     insufficient permissions.
     * @hide
     */
    public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
        BluetoothServerSocket socket = new BluetoothServerSocket(
                BluetoothSocket.TYPE_L2CAP, true, true, port);
        int errno = socket.mSocket.bindListen();
        if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
            socket.setChannel(socket.mSocket.getPort());
        }
        if (errno != 0) {
            //TODO(BT): Throw the same exception error code
            // that the previous code was using.
            //socket.mSocket.throwErrnoNative(errno);
            throw new IOException("Error: " + errno);
        }
        return socket;
    }

    /**
     * Read the local Out of Band Pairing Data
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+66 −3
Original line number Diff line number Diff line
@@ -302,6 +302,12 @@ public final class BluetoothDevice implements Parcelable {
     */
    public static final int DEVICE_TYPE_DUAL = 3;


    /** @hide */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_SDP_RECORD =
            "android.bluetooth.device.action.SDP_RECORD";

    /**
     * Broadcast Action: This intent is used to broadcast the {@link UUID}
     * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
@@ -526,6 +532,13 @@ public final class BluetoothDevice implements Parcelable {
     */
    public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";

    /** @hide */
    public static final String EXTRA_SDP_RECORD =
        "android.bluetooth.device.extra.SDP_RECORD";

    /** @hide */
    public static final String EXTRA_SDP_SEARCH_STATUS =
            "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
    /**
     * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
     * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
@@ -1054,14 +1067,34 @@ public final class BluetoothDevice implements Parcelable {
            return false;
    }

     /**
      * Perform a service discovery on the remote device to get the SDP records associated
      * with the specified UUID.
      *
      * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
      * with the SDP records found on the remote end. If there is an error
      * in getting the SDP records or if the process takes a long time,
      * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
      * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
      * Detailed status error codes can be found by members of the Bluetooth package in
      * the AbstractionLayer class.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
      * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
      * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
      * for.
      *
      * @return False if the sanity check fails, True if the process
      *               of initiating an ACL connection to the remote device
      *               was started.
      */
     /** @hide */
     public boolean fetchMasInstances() {
     public boolean sdpSearch(ParcelUuid uuid) {
         if (sService == null) {
             Log.e(TAG, "BT not enabled. Cannot query remote device for MAS instances");
             Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
             return false;
         }
         try {
             return sService.fetchRemoteMasInstances(this);
             return sService.sdpSearch(this,uuid);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -1260,6 +1293,36 @@ public final class BluetoothDevice implements Parcelable {
                null);
    }

    /**
     * Create an L2cap {@link BluetoothSocket} ready to start a secure
     * outgoing connection to this remote device on given channel.
     * <p>The remote device will be authenticated and communication on this
     * socket will be encrypted.
     * <p> Use this socket only if an authenticated socket link is possible.
     * Authentication refers to the authentication of the link key to
     * prevent man-in-the-middle type of attacks.
     * For example, for Bluetooth 2.1 devices, if any of the devices does not
     * have an input and output capability or just has the ability to
     * display a numeric key, a secure socket connection is not possible.
     * In such a case, use {#link createInsecureRfcommSocket}.
     * For more details, refer to the Security Model section 5.2 (vol 3) of
     * Bluetooth Core Specification version 2.1 + EDR.
     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
     * connection.
     * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
     *
     * @param channel L2cap PSM/channel to connect to
     * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
     * @throws IOException on error, for example Bluetooth not available, or
     *                     insufficient permissions
     * @hide
     */
    public BluetoothSocket createL2capSocket(int channel) throws IOException {
        return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
                null);
    }

    /**
     * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
     * outgoing connection to this remote device using SDP lookup of uuid.
+51 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.bluetooth;

import android.os.Handler;
import android.os.ParcelUuid;
import android.util.Log;

import java.io.Closeable;
import java.io.IOException;
@@ -66,10 +67,11 @@ import java.io.IOException;
 */
public final class BluetoothServerSocket implements Closeable {

    private static final String TAG = "BluetoothServerSocket";
    /*package*/ final BluetoothSocket mSocket;
    private Handler mHandler;
    private int mMessage;
    private final int mChannel;
    private int mChannel;

    /**
     * Construct a socket for incoming connections.
@@ -84,6 +86,9 @@ public final class BluetoothServerSocket implements Closeable {
            throws IOException {
        mChannel = port;
        mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null);
        if(port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
            mSocket.setExcludeSdp(true);
        }
    }

    /**
@@ -98,6 +103,7 @@ public final class BluetoothServerSocket implements Closeable {
    /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid)
            throws IOException {
        mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, -1, uuid);
        // TODO: This is the same as mChannel = -1 - is this intentional?
        mChannel = mSocket.getPort();
    }

@@ -153,6 +159,7 @@ public final class BluetoothServerSocket implements Closeable {
    /*package*/ void setServiceName(String ServiceName) {
        mSocket.setServiceName(ServiceName);
    }

    /**
     * Returns the channel on which this socket is bound.
     * @hide
@@ -160,4 +167,47 @@ public final class BluetoothServerSocket implements Closeable {
    public int getChannel() {
        return mChannel;
    }

    /**
     * Sets the channel on which future sockets are bound.
     * Currently used only when a channel is auto generated.
     */
    /*package*/ void setChannel(int newChannel) {
        /* TODO: From a design/architecture perspective this is wrong.
         *       The bind operation should be conducted through this class
         *       and the resulting port should be kept in mChannel, and
         *       not set from BluetoothAdapter. */
        if(mSocket != null) {
            if(mSocket.getPort() != newChannel) {
                Log.w(TAG,"The port set is different that the underlying port. mSocket.getPort(): "
                            + mSocket.getPort() + " requested newChannel: " + newChannel);
            }
        }
        mChannel = newChannel;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("ServerSocket: Type: ");
        switch(mSocket.getConnectionType()) {
            case BluetoothSocket.TYPE_RFCOMM:
            {
                sb.append("TYPE_RFCOMM");
                break;
            }
            case BluetoothSocket.TYPE_L2CAP:
            {
                sb.append("TYPE_L2CAP");
                break;
            }
            case BluetoothSocket.TYPE_SCO:
            {
                sb.append("TYPE_SCO");
                break;
            }
        }
        sb.append(" Channel: ").append(mChannel);
        return sb.toString();
    }
}
+173 −24
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -29,6 +30,8 @@ import java.io.OutputStream;
import java.util.Locale;
import java.util.UUID;
import android.net.LocalSocket;

import java.nio.Buffer;
import java.nio.ByteOrder;
import java.nio.ByteBuffer;
/**
@@ -86,17 +89,19 @@ public final class BluetoothSocket implements Closeable {

    /** @hide */
    public static final int MAX_RFCOMM_CHANNEL = 30;
    /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF;

    /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
    /*package*/ static final int TYPE_RFCOMM = 1;
    /*package*/ static final int TYPE_SCO = 2;
    /*package*/ static final int TYPE_L2CAP = 3;
    public static final int TYPE_RFCOMM = 1;
    public static final int TYPE_SCO = 2;
    public static final int TYPE_L2CAP = 3;

    /*package*/ static final int EBADFD = 77;
    /*package*/ static final int EADDRINUSE = 98;

    /*package*/ static final int SEC_FLAG_ENCRYPT = 1;
    /*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
    /*package*/ static final int BTSOCK_FLAG_NO_SDP  = 1 << 2;

    private final int mType;  /* one of TYPE_RFCOMM etc */
    private BluetoothDevice mDevice;    /* remote device */
@@ -106,6 +111,7 @@ public final class BluetoothSocket implements Closeable {
    private final BluetoothInputStream mInputStream;
    private final BluetoothOutputStream mOutputStream;
    private final ParcelUuid mUuid;
    private boolean mExcludeSdp = false;
    private ParcelFileDescriptor mPfd;
    private LocalSocket mSocket;
    private InputStream mSocketIS;
@@ -115,7 +121,11 @@ public final class BluetoothSocket implements Closeable {
    private String mServiceName;
    private static int PROXY_CONNECTION_TIMEOUT = 5000;

    private static int SOCK_SIGNAL_SIZE = 16;
    private static int SOCK_SIGNAL_SIZE = 20;

    private ByteBuffer mL2capBuffer = null;
    private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
    private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received.

    private enum SocketState {
        INIT,
@@ -144,7 +154,9 @@ public final class BluetoothSocket implements Closeable {
     */
    /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
            BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) {
        if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1
                && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
            if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
                throw new IOException("Invalid RFCOMM channel: " + port);
            }
@@ -172,6 +184,7 @@ public final class BluetoothSocket implements Closeable {
        mOutputStream = new BluetoothOutputStream(this);
    }
    private BluetoothSocket(BluetoothSocket s) {
        if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType);
        mUuid = s.mUuid;
        mType = s.mType;
        mAuth = s.mAuth;
@@ -179,7 +192,11 @@ public final class BluetoothSocket implements Closeable {
        mPort = s.mPort;
        mInputStream = new BluetoothInputStream(this);
        mOutputStream = new BluetoothOutputStream(this);
        mMaxRxPacketSize = s.mMaxRxPacketSize;
        mMaxTxPacketSize = s.mMaxTxPacketSize;

        mServiceName = s.mServiceName;
        mExcludeSdp = s.mExcludeSdp;
    }
    private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException {
        BluetoothSocket as = new BluetoothSocket(this);
@@ -229,6 +246,8 @@ public final class BluetoothSocket implements Closeable {
            flags |= SEC_FLAG_AUTH;
        if(mEncrypt)
            flags |= SEC_FLAG_ENCRYPT;
        if(mExcludeSdp)
            flags |= BTSOCK_FLAG_NO_SDP;
        return flags;
    }

@@ -298,7 +317,8 @@ public final class BluetoothSocket implements Closeable {

        try {
            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
            IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
            IBluetooth bluetoothProxy =
                    BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
            if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
            mPfd = bluetoothProxy.connectSocket(mDevice, mType,
                    mUuid, mPort, getSecurityFlags());
@@ -370,7 +390,7 @@ public final class BluetoothSocket implements Closeable {
                    mSocketState = SocketState.LISTENING;
            }
            if (DBG) Log.d(TAG, "channel: " + channel);
            if (mPort == -1) {
            if (mPort <= -1) {
                mPort = channel;
            } // else ASSERT(mPort == channel)
            ret = 0;
@@ -391,7 +411,8 @@ public final class BluetoothSocket implements Closeable {

    /*package*/ BluetoothSocket accept(int timeout) throws IOException {
        BluetoothSocket acceptedSocket;
        if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state");
        if (mSocketState != SocketState.LISTENING)
            throw new IOException("bt socket is not in listen state");
        if(timeout > 0) {
            Log.d(TAG, "accept() set timeout (ms):" + timeout);
           mSocket.setSoTimeout(timeout);
@@ -427,9 +448,33 @@ public final class BluetoothSocket implements Closeable {
    }

    /*package*/ int read(byte[] b, int offset, int length) throws IOException {
        if (mSocketIS == null) throw new IOException("read is called on null InputStream");
        int ret = 0;
        if (VDBG) Log.d(TAG, "read in:  " + mSocketIS + " len: " + length);
        int ret = mSocketIS.read(b, offset, length);
        if(mType == TYPE_L2CAP)
        {
            int bytesToRead = length;
            if (VDBG) Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length
                    + "mL2capBuffer= " + mL2capBuffer);
            if (mL2capBuffer == null) {
                createL2capRxBuffer();
            }
            if (mL2capBuffer.remaining() == 0) {
                if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling...");
                if (fillL2capRxBuffer() == -1) {
                    return -1;
                }
            }
            if (bytesToRead > mL2capBuffer.remaining()) {
                bytesToRead = mL2capBuffer.remaining();
            }
            if(VDBG) Log.v(TAG, "get(): offset: " + offset
                    + " bytesToRead: " + bytesToRead);
            mL2capBuffer.get(b, offset, bytesToRead);
            ret = bytesToRead;
        }else {
            if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length);
            ret = mSocketIS.read(b, offset, length);
        }
        if (ret < 0)
            throw new IOException("bt socket closed, read return: " + ret);
        if (VDBG) Log.d(TAG, "read out:  " + mSocketIS + " ret: " + ret);
@@ -437,9 +482,37 @@ public final class BluetoothSocket implements Closeable {
    }

    /*package*/ int write(byte[] b, int offset, int length) throws IOException {
        if (mSocketOS == null) throw new IOException("write is called on null OutputStream");

        //TODO: Since bindings can exist between the SDU size and the
        //      protocol, we might need to throw an exception instead of just
        //      splitting the write into multiple smaller writes.
        //      Rfcomm uses dynamic allocation, and should not have any bindings
        //      to the actual message length.
            if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
            if (mType == TYPE_L2CAP) {
                if(length <= mMaxTxPacketSize) {
                    mSocketOS.write(b, offset, length);
                } else {
                    int tmpOffset = offset;
                    int tmpLength = mMaxTxPacketSize;
                    int endIndex = offset + length;
                    boolean done = false;
                    if(DBG) Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
                            + "Packet will be divided into SDU packets of size "
                            + mMaxTxPacketSize);
                    do{
                        mSocketOS.write(b, tmpOffset, tmpLength);
                        tmpOffset += mMaxTxPacketSize;
                        if((tmpOffset + mMaxTxPacketSize) > endIndex) {
                            tmpLength = endIndex - tmpOffset;
                            done = true;
                        }
                    } while(!done);

                }
            } else {
                mSocketOS.write(b, offset, length);
            }
            // There is no good way to confirm since the entire process is asynchronous anyway
            if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
            return length;
@@ -447,7 +520,8 @@ public final class BluetoothSocket implements Closeable {

    @Override
    public void close() throws IOException {
        if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
        if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: "
                + mSocketState);
        if(mSocketState == SocketState.CLOSED)
            return;
        else
@@ -457,8 +531,9 @@ public final class BluetoothSocket implements Closeable {
                 if(mSocketState == SocketState.CLOSED)
                    return;
                 mSocketState = SocketState.CLOSED;
                 if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
                        ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket);
                 if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort +
                         ", mSocketIS: " + mSocketIS + ", mSocketOS: " + mSocketOS +
                         "mSocket: " + mSocket);
                 if(mSocket != null) {
                    if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
                    mSocket.shutdownInput();
@@ -480,6 +555,47 @@ public final class BluetoothSocket implements Closeable {
    /*package */ int getPort() {
        return mPort;
    }

    /**
     * Get the maximum supported Transmit packet size for the underlying transport.
     * Use this to optimize the writes done to the output socket, to avoid sending
     * half full packets.
     * @return the maximum supported Transmit packet size for the underlying transport.
     */
    public int getMaxTransmitPacketSize(){
        return mMaxTxPacketSize;
    }

    /**
     * Get the maximum supported Receive packet size for the underlying transport.
     * Use this to optimize the reads done on the input stream, as any call to read
     * will return a maximum of this amount of bytes - or for some transports a
     * multiple of this value.
     * @return the maximum supported Receive packet size for the underlying transport.
     */
    public int getMaxReceivePacketSize(){
        return mMaxRxPacketSize;
    }

    /**
     * Get the type of the underlying connection
     * @return one of TYPE_
     */
    public int getConnectionType() {
        return mType;
    }

    /**
     * Change if a SDP entry should be automatically created.
     * Must be called before calling .bind, for the call to have any effect.
     * @param mExcludeSdp <li>TRUE  - do not auto generate SDP record.
     *                    <li>FALSE - default - auto generate SPP SDP record.
     * @hide
     */
    public void setExcludeSdp(boolean excludeSdp) {
        this.mExcludeSdp = excludeSdp;
    }

    private String convertAddr(final byte[] addr)  {
        return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
                addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]);
@@ -487,8 +603,10 @@ public final class BluetoothSocket implements Closeable {
    private String waitSocketSignal(InputStream is) throws IOException {
        byte [] sig = new byte[SOCK_SIGNAL_SIZE];
        int ret = readAll(is, sig);
        if (VDBG) Log.d(TAG, "waitSocketSignal read 16 bytes signal ret: " + ret);
        if (VDBG) Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE +
                " bytes signal ret: " + ret);
        ByteBuffer bb = ByteBuffer.wrap(sig);
        /* the struct in native is decorated with __attribute__((packed)), hence this is possible */
        bb.order(ByteOrder.nativeOrder());
        int size = bb.getShort();
        if(size != SOCK_SIGNAL_SIZE)
@@ -497,19 +615,36 @@ public final class BluetoothSocket implements Closeable {
        bb.get(addr);
        int channel = bb.getInt();
        int status = bb.getInt();
        mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
        mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
        String RemoteAddr = convertAddr(addr);
        if (VDBG) Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: "
                + RemoteAddr + ", channel: " + channel + ", status: " + status);
                + RemoteAddr + ", channel: " + channel + ", status: " + status
                + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize);
        if(status != 0)
            throw new IOException("Connection failure, status: " + status);
        return RemoteAddr;
    }

    private void createL2capRxBuffer(){
        if(mType == TYPE_L2CAP) {
            // Allocate the buffer to use for reads.
            if(VDBG) Log.v(TAG, "  Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize);
            mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]);
            if(VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining());
            mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request
            if(VDBG) Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" +
                    mL2capBuffer.remaining());
        }
    }

    private int readAll(InputStream is, byte[] b) throws IOException {
        int left = b.length;
        while(left > 0) {
            int ret = is.read(b, b.length - left, left);
            if(ret <= 0)
                 throw new IOException("read failed, socket might closed or timeout, read ret: " + ret);
                 throw new IOException("read failed, socket might closed or timeout, read ret: "
                         + ret);
            left -= ret;
            if(left != 0)
                Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) +
@@ -526,4 +661,18 @@ public final class BluetoothSocket implements Closeable {
        bb.order(ByteOrder.nativeOrder());
        return bb.getInt();
    }

    private int fillL2capRxBuffer() throws IOException {
        mL2capBuffer.rewind();
        int ret = mSocketIS.read(mL2capBuffer.array());
        if(ret == -1) {
            // reached end of stream - return -1
            mL2capBuffer.limit(0);
            return -1;
        }
        mL2capBuffer.limit(ret);
        return ret;
    }


}
+1 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading