BluetoothSocket.java revision 6d95fc0a2ca910212a43c4547c0ef000659b72dc
10b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/*
20b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Copyright (C) 2009 The Android Open Source Project
30b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
40b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
50b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * you may not use this file except in compliance with the License.
60b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * You may obtain a copy of the License at
70b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
80b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
90b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Unless required by applicable law or agreed to in writing, software
110b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
120b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * See the License for the specific language governing permissions and
140b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * limitations under the License.
150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */
160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypackage android.bluetooth;
180b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
2016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.ParcelUuid;
2116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.RemoteException;
2216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.util.Log;
2316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
240b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.Closeable;
250b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.IOException;
260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.InputStream;
270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.OutputStream;
2871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pellyimport java.util.concurrent.locks.ReentrantReadWriteLock;
2971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
300b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/**
3145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * A connected or connecting Bluetooth socket.
320b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
3345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
3445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
3545e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * side, use a {@link BluetoothServerSocket} to create a listening server
369fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * socket. When a connection is accepted by the {@link BluetoothServerSocket},
379fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * it will return a new {@link BluetoothSocket} to manage the connection.
389fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * On the client side, use a single {@link BluetoothSocket} to both intiate
399fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * an outgoing connection and to manage the connection.
400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
419fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
429fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
439fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
459fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} for connecting to a known device, use
469fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothDevice#createRfcommSocketToServiceRecord
479fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * BluetoothDevice.createRfcommSocketToServiceRecord()}.
489fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Then call {@link #connect()} to attempt a connection to the remote device.
499fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * This call will block until a connection is established or the connection
509fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * fails.
5145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly *
529fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the
539fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothServerSocket} documentation.
5445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly *
559fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>Once the socket is connected, whether initiated as a client or accepted
569fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * as a server, open the IO streams by calling {@link #getInputStream} and
579fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream}
589fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * and {@link java.io.OutputStream} objects, respectively, which are
599fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * automatically connected to the socket.
609fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main *
619fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>{@link BluetoothSocket} is thread
6245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * safe. In particular, {@link #close} will always immediately abort ongoing
6345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * operations and close the socket.
64cf44059813539bf7f36dabd278cef93ba3122c56Nick Pelly *
659fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p class="note"><strong>Note:</strong>
669fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
679fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main *
689fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see BluetoothServerSocket}
699fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.InputStream}
709fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.OutputStream}
710b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */
720b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypublic final class BluetoothSocket implements Closeable {
7316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final String TAG = "BluetoothSocket";
7416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
7524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /** @hide */
7624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public static final int MAX_RFCOMM_CHANNEL = 30;
7724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
7845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
796a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_RFCOMM = 1;
806a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_SCO = 2;
816a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_L2CAP = 3;
826a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly
8324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ static final int EBADFD = 77;
8424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ static final int EADDRINUSE = 98;
8524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
866a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private final int mType;  /* one of TYPE_RFCOMM etc */
87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final BluetoothDevice mDevice;    /* remote device */
880b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final String mAddress;    /* remote address */
890b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final boolean mAuth;
900b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final boolean mEncrypt;
910b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final BluetoothInputStream mInputStream;
920b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final BluetoothOutputStream mOutputStream;
9316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final SdpHelper mSdp;
9416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
9516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private int mPort;  /* RFCOMM channel or L2CAP psm */
960b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
9771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** prevents all native calls after destroyNative() */
9871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private boolean mClosed;
9971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
10071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** protects mClosed */
10171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private final ReentrantReadWriteLock mLock;
10271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
10371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** used by native code only */
10471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private int mSocketData;
1050b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1060b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
107bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * Construct a BluetoothSocket.
1086a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly     * @param type    type of socket
1090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
1100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param auth    require the remote device to be authenticated
1110b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param encrypt require the connection to be encrypted
112bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param device  remote device that this socket can connect to
1130b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param port    remote port
11416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * @param uuid    SDP uuid
1150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @throws IOException On error, for example Bluetooth not available, or
1160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     *                     insufficient priveleges
1170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
118bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
11916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) {
12124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
12224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                throw new IOException("Invalid RFCOMM channel: " + port);
12324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
12424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
12516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid == null) {
12616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mPort = port;
12716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mSdp = null;
12816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        } else {
12916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mSdp = new SdpHelper(device, uuid);
13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mPort = -1;
13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1326a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly        mType = type;
1330b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mAuth = auth;
1340b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mEncrypt = encrypt;
135bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDevice = device;
136bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (device == null) {
137bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = null;
138bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        } else {
139bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = device.getAddress();
140bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        }
1410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        if (fd == -1) {
1420b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            initSocketNative();
1430b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } else {
1440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            initSocketFromFdNative(fd);
1450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
1460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mInputStream = new BluetoothInputStream(this);
1470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mOutputStream = new BluetoothOutputStream(this);
14871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mClosed = false;
14971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock = new ReentrantReadWriteLock();
1500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
1510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
152bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /**
15316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Construct a BluetoothSocket from address. Used by native code.
154bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param type    type of socket
155bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
156bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param auth    require the remote device to be authenticated
157bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param encrypt require the connection to be encrypted
158bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param address remote device that this socket can connect to
159bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param port    remote port
160bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @throws IOException On error, for example Bluetooth not available, or
161bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     *                     insufficient priveleges
162bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     */
163bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
164bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            int port) throws IOException {
16516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null);
166bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
167bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
16845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** @hide */
1690b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    @Override
1700b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    protected void finalize() throws Throwable {
1710b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        try {
1720b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            close();
1730b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } finally {
1740b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            super.finalize();
1750b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
1760b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
1770b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1780b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
1790b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Attempt to connect to a remote device.
18045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>This method will block until a connection is made or the connection
1810b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * fails. If this method returns without an exception then this socket
18245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * is now connected.
1836d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * <p>Creating new connections to
1846d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * remote Bluetooth devices should not be attempted while device discovery
1856d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * is in progress. Device discovery is a heavyweight procedure on the
1866d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * Bluetooth adapter and will significantly slow a device connection.
1876d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing
1886d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * discovery. Discovery is not managed by the Activity,
1896d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * but is run as a system service, so an application should always call
1906d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * {@link BluetoothAdapter#cancelDiscovery()} even if it
1916d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * did not directly request a discovery, just to be sure.
19245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>{@link #close} can be used to abort this call from another thread.
19345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @throws IOException on error, for example connection failure
1940b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
1950b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public void connect() throws IOException {
19671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
19771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
19871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
19916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
20016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (mSdp != null) {
20116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mPort = mSdp.doSdp();  // blocks
20216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
20316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
20416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            connectNative();  // blocks
20571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
20671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
20771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
2080b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
21145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Immediately close this socket, and release all associated resources.
21245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>Causes blocked calls on this socket in other threads to immediately
2130b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * throw an IOException.
2140b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public void close() throws IOException {
21671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        // abort blocking operations on the socket
21771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
21871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
21971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) return;
22016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (mSdp != null) {
22116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mSdp.cancel();
22216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
22371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            abortNative();
22471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
22571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
22671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
22771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
22816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // all native calls are guaranteed to immediately return after
22971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        // abortNative(), so this lock should immediatley acquire
23071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.writeLock().lock();
23171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
23271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mClosed = true;
23371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            destroyNative();
23471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
23571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.writeLock().unlock();
23671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
2370b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2380b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2390b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
24045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Get the remote device this socket is connecting, or connected, to.
24145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @return remote device
2420b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
243bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothDevice getRemoteDevice() {
244bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mDevice;
2450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the input stream associated with this socket.
24945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The input stream will be returned even if the socket is not yet
2500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return InputStream
2530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2540b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public InputStream getInputStream() throws IOException {
2550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mInputStream;
2560b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2590b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the output stream associated with this socket.
26045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The output stream will be returned even if the socket is not yet
2610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2620b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2630b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return OutputStream
2640b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2650b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public OutputStream getOutputStream() throws IOException {
2660b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mOutputStream;
2670b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2680b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
26924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
27024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Currently returns unix errno instead of throwing IOException,
27124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * so that BluetoothAdapter can check the error code for EADDRINUSE
27224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
27324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ int bindListen() {
27471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
27571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
27624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (mClosed) return EBADFD;
27724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return bindListenNative();
27871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
27971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
28071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
28171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
28271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
28371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ BluetoothSocket accept(int timeout) throws IOException {
28471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
28571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
28671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
28771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return acceptNative(timeout);
28871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
28971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
29071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
29171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
29271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
29371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int available() throws IOException {
29471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
29571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
29671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
29771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return availableNative();
29871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
29971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
30071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
30171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
30271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
30371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int read(byte[] b, int offset, int length) throws IOException {
30471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
30571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
30671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
30771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return readNative(b, offset, length);
30871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
30971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
31071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
31171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
31271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
31371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int write(byte[] b, int offset, int length) throws IOException {
31471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
31571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
31671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
31771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return writeNative(b, offset, length);
31871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
31971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
32071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
32171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
32271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
3236a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void initSocketNative() throws IOException;
3246a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void initSocketFromFdNative(int fd) throws IOException;
3256a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void connectNative() throws IOException;
32624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int bindListenNative();
32771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native BluetoothSocket acceptNative(int timeout) throws IOException;
32871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int availableNative() throws IOException;
32971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int readNative(byte[] b, int offset, int length) throws IOException;
33071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int writeNative(byte[] b, int offset, int length) throws IOException;
33171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native void abortNative() throws IOException;
3326a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void destroyNative() throws IOException;
33324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
33424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Throws an IOException for given posix errno. Done natively so we can
33524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * use strerr to convert to string error.
33624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
33724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ native void throwErrnoNative(int errno) throws IOException;
33816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
33916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
34016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Helper to perform blocking SDP lookup.
34116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
34216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class SdpHelper extends IBluetoothCallback.Stub {
34316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final IBluetooth service;
34416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final ParcelUuid uuid;
34516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final BluetoothDevice device;
34616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private int channel;
34716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private boolean canceled;
34816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public SdpHelper(BluetoothDevice device, ParcelUuid uuid) {
34916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            service = BluetoothDevice.getService();
35016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.device = device;
35116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
35216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            canceled = false;
35316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
35416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        /**
35516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         * Returns the RFCOMM channel for the UUID, or throws IOException
35616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         * on failure.
35716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         */
35816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized int doSdp() throws IOException {
35916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (canceled) throw new IOException("Service discovery canceled");
36016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            channel = -1;
36116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
36216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            boolean inProgress = false;
36316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            try {
36416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                inProgress = service.fetchRemoteUuids(device.getAddress(), uuid, this);
36516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            } catch (RemoteException e) {Log.e(TAG, "", e);}
36616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
36716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!inProgress) throw new IOException("Unable to start Service Discovery");
36816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
36916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            try {
37016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                /* 12 second timeout as a precaution - onRfcommChannelFound
37116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                 * should always occur before the timeout */
37216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                wait(12000);   // block
37316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
37416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            } catch (InterruptedException e) {}
37516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
37616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (canceled) throw new IOException("Service discovery canceled");
37716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (channel < 1) throw new IOException("Service discovery failed");
37816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
37916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return channel;
38016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
38116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        /** Object cannot be re-used after calling cancel() */
38216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized void cancel() {
38316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!canceled) {
38416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                canceled = true;
38516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = -1;
38616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                notifyAll();  // unblock
38716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
38816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
38916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized void onRfcommChannelFound(int channel) {
39016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!canceled) {
39116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                this.channel = channel;
39216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                notifyAll();  // unblock
39316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
39416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
39516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
3960b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly}
397