10b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/*
2fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Copyright (C) 2012 The Android Open Source Project
3fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu *
4fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Licensed under the Apache License, Version 2.0 (the "License");
5fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * you may not use this file except in compliance with the License.
6fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * You may obtain a copy of the License at
7fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu *
8fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu *      http://www.apache.org/licenses/LICENSE-2.0
9fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu *
10fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Unless required by applicable law or agreed to in writing, software
11fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * distributed under the License is distributed on an "AS IS" BASIS,
12fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * See the License for the specific language governing permissions and
14fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * limitations under the License.
150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */
160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypackage android.bluetooth;
180b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
193b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.IBinder;
2016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.ParcelUuid;
213b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.ParcelFileDescriptor;
2216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.RemoteException;
233b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.ServiceManager;
2416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.util.Log;
2516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.Closeable;
273b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileDescriptor;
283b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileInputStream;
293b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileOutputStream;
300b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.IOException;
310b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.InputStream;
320b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.OutputStream;
333b147b770269173d5d711d6c33f142dc5e723824zzyimport java.util.List;
34b49a89635906e0901637a4a4c1c2f5bb263b6595zzyimport java.util.UUID;
353b147b770269173d5d711d6c33f142dc5e723824zzyimport android.net.LocalSocket;
363b147b770269173d5d711d6c33f142dc5e723824zzyimport java.nio.ByteOrder;
373b147b770269173d5d711d6c33f142dc5e723824zzyimport java.nio.ByteBuffer;
380b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/**
3945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * A connected or connecting Bluetooth socket.
400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
4145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
4245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
4345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * side, use a {@link BluetoothServerSocket} to create a listening server
449fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * socket. When a connection is accepted by the {@link BluetoothServerSocket},
459fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * it will return a new {@link BluetoothSocket} to manage the connection.
46f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * On the client side, use a single {@link BluetoothSocket} to both initiate
479fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * an outgoing connection and to manage the connection.
480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
499fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
509fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
519fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
539fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} for connecting to a known device, use
549fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothDevice#createRfcommSocketToServiceRecord
559fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * BluetoothDevice.createRfcommSocketToServiceRecord()}.
569fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Then call {@link #connect()} to attempt a connection to the remote device.
579fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * This call will block until a connection is established or the connection
589fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * fails.
5945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly *
609fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the
619fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothServerSocket} documentation.
6245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly *
639fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>Once the socket is connected, whether initiated as a client or accepted
649fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * as a server, open the IO streams by calling {@link #getInputStream} and
659fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream}
669fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * and {@link java.io.OutputStream} objects, respectively, which are
679fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * automatically connected to the socket.
689fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main *
699fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>{@link BluetoothSocket} is thread
7045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * safe. In particular, {@link #close} will always immediately abort ongoing
7145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * operations and close the socket.
72cf44059813539bf7f36dabd278cef93ba3122c56Nick Pelly *
739fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p class="note"><strong>Note:</strong>
749fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
759fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main *
763aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <div class="special reference">
773aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <h3>Developer Guides</h3>
783aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <p>For more information about using Bluetooth, read the
793aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p>
803aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * </div>
813aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez *
829fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see BluetoothServerSocket}
839fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.InputStream}
849fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.OutputStream}
850b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */
860b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypublic final class BluetoothSocket implements Closeable {
8716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final String TAG = "BluetoothSocket";
88563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie    private static final boolean DBG = true;
89563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie    private static final boolean VDBG = false;
9016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
9124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /** @hide */
9224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public static final int MAX_RFCOMM_CHANNEL = 30;
9324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
9445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
956a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_RFCOMM = 1;
966a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_SCO = 2;
976a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_L2CAP = 3;
986a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly
9924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ static final int EBADFD = 77;
10024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ static final int EADDRINUSE = 98;
10124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
1023b147b770269173d5d711d6c33f142dc5e723824zzy    /*package*/ static final int SEC_FLAG_ENCRYPT = 1;
1033b147b770269173d5d711d6c33f142dc5e723824zzy    /*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
1043b147b770269173d5d711d6c33f142dc5e723824zzy
1056a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private final int mType;  /* one of TYPE_RFCOMM etc */
1063b147b770269173d5d711d6c33f142dc5e723824zzy    private BluetoothDevice mDevice;    /* remote device */
1073b147b770269173d5d711d6c33f142dc5e723824zzy    private String mAddress;    /* remote address */
1080b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final boolean mAuth;
1090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final boolean mEncrypt;
1100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final BluetoothInputStream mInputStream;
1110b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final BluetoothOutputStream mOutputStream;
1123b147b770269173d5d711d6c33f142dc5e723824zzy    private final ParcelUuid mUuid;
1133b147b770269173d5d711d6c33f142dc5e723824zzy    private ParcelFileDescriptor mPfd;
1143b147b770269173d5d711d6c33f142dc5e723824zzy    private LocalSocket mSocket;
1153b147b770269173d5d711d6c33f142dc5e723824zzy    private InputStream mSocketIS;
1163b147b770269173d5d711d6c33f142dc5e723824zzy    private OutputStream mSocketOS;
11716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private int mPort;  /* RFCOMM channel or L2CAP psm */
1183b147b770269173d5d711d6c33f142dc5e723824zzy    private int mFd;
1193b147b770269173d5d711d6c33f142dc5e723824zzy    private String mServiceName;
1203b147b770269173d5d711d6c33f142dc5e723824zzy    private static int PROXY_CONNECTION_TIMEOUT = 5000;
1213b147b770269173d5d711d6c33f142dc5e723824zzy
1223b147b770269173d5d711d6c33f142dc5e723824zzy    private static int SOCK_SIGNAL_SIZE = 16;
1230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
124ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    private enum SocketState {
125ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        INIT,
126ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        CONNECTED,
1273b147b770269173d5d711d6c33f142dc5e723824zzy        LISTENING,
1283b147b770269173d5d711d6c33f142dc5e723824zzy        CLOSED,
129ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    }
130ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
13171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** prevents all native calls after destroyNative() */
1323b147b770269173d5d711d6c33f142dc5e723824zzy    private volatile SocketState mSocketState;
13371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
134ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    /** protects mSocketState */
1353b147b770269173d5d711d6c33f142dc5e723824zzy    //private final ReentrantReadWriteLock mLock;
1360b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1370b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
138bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * Construct a BluetoothSocket.
1396a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly     * @param type    type of socket
1400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
1410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param auth    require the remote device to be authenticated
1420b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param encrypt require the connection to be encrypted
143bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param device  remote device that this socket can connect to
1440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param port    remote port
14516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * @param uuid    SDP uuid
1460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @throws IOException On error, for example Bluetooth not available, or
147f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     *                     insufficient privileges
1480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
149bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
15016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) {
15224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
15324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                throw new IOException("Invalid RFCOMM channel: " + port);
15424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
15524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
156b49a89635906e0901637a4a4c1c2f5bb263b6595zzy        if(uuid != null)
157b49a89635906e0901637a4a4c1c2f5bb263b6595zzy            mUuid = uuid;
158b49a89635906e0901637a4a4c1c2f5bb263b6595zzy        else mUuid = new ParcelUuid(new UUID(0, 0));
1596a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly        mType = type;
1600b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mAuth = auth;
1610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mEncrypt = encrypt;
162bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDevice = device;
1633b147b770269173d5d711d6c33f142dc5e723824zzy        mPort = port;
1643b147b770269173d5d711d6c33f142dc5e723824zzy        mFd = fd;
1653b147b770269173d5d711d6c33f142dc5e723824zzy
1663b147b770269173d5d711d6c33f142dc5e723824zzy        mSocketState = SocketState.INIT;
1673b147b770269173d5d711d6c33f142dc5e723824zzy
168bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (device == null) {
1693b147b770269173d5d711d6c33f142dc5e723824zzy            // Server socket
1703b147b770269173d5d711d6c33f142dc5e723824zzy            mAddress = BluetoothAdapter.getDefaultAdapter().getAddress();
171bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        } else {
1723b147b770269173d5d711d6c33f142dc5e723824zzy            // Remote socket
173bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = device.getAddress();
174bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        }
1753b147b770269173d5d711d6c33f142dc5e723824zzy        mInputStream = new BluetoothInputStream(this);
1763b147b770269173d5d711d6c33f142dc5e723824zzy        mOutputStream = new BluetoothOutputStream(this);
1773b147b770269173d5d711d6c33f142dc5e723824zzy    }
1783b147b770269173d5d711d6c33f142dc5e723824zzy    private BluetoothSocket(BluetoothSocket s) {
1793b147b770269173d5d711d6c33f142dc5e723824zzy        mUuid = s.mUuid;
1803b147b770269173d5d711d6c33f142dc5e723824zzy        mType = s.mType;
1813b147b770269173d5d711d6c33f142dc5e723824zzy        mAuth = s.mAuth;
1823b147b770269173d5d711d6c33f142dc5e723824zzy        mEncrypt = s.mEncrypt;
1833b147b770269173d5d711d6c33f142dc5e723824zzy        mPort = s.mPort;
1840b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mInputStream = new BluetoothInputStream(this);
1850b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mOutputStream = new BluetoothOutputStream(this);
1863b147b770269173d5d711d6c33f142dc5e723824zzy        mServiceName = s.mServiceName;
1873b147b770269173d5d711d6c33f142dc5e723824zzy    }
1883b147b770269173d5d711d6c33f142dc5e723824zzy    private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException {
1893b147b770269173d5d711d6c33f142dc5e723824zzy        BluetoothSocket as = new BluetoothSocket(this);
1903b147b770269173d5d711d6c33f142dc5e723824zzy        as.mSocketState = SocketState.CONNECTED;
1913b147b770269173d5d711d6c33f142dc5e723824zzy        FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
192563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) Log.d(TAG, "socket fd passed by stack  fds: " + fds);
1933b147b770269173d5d711d6c33f142dc5e723824zzy        if(fds == null || fds.length != 1) {
1943b147b770269173d5d711d6c33f142dc5e723824zzy            Log.e(TAG, "socket fd passed from stack failed, fds: " + fds);
1953b147b770269173d5d711d6c33f142dc5e723824zzy            throw new IOException("bt socket acept failed");
1963b147b770269173d5d711d6c33f142dc5e723824zzy        }
1973b147b770269173d5d711d6c33f142dc5e723824zzy        as.mSocket = new LocalSocket(fds[0]);
1983b147b770269173d5d711d6c33f142dc5e723824zzy        as.mSocketIS = as.mSocket.getInputStream();
1993b147b770269173d5d711d6c33f142dc5e723824zzy        as.mSocketOS = as.mSocket.getOutputStream();
2003b147b770269173d5d711d6c33f142dc5e723824zzy        as.mAddress = RemoteAddr;
2013b147b770269173d5d711d6c33f142dc5e723824zzy        as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(RemoteAddr);
2023b147b770269173d5d711d6c33f142dc5e723824zzy        return as;
2030b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
204bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /**
20516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Construct a BluetoothSocket from address. Used by native code.
206bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param type    type of socket
207bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
208bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param auth    require the remote device to be authenticated
209bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param encrypt require the connection to be encrypted
210bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param address remote device that this socket can connect to
211bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param port    remote port
212bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @throws IOException On error, for example Bluetooth not available, or
213f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     *                     insufficient privileges
214bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     */
215bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
216bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            int port) throws IOException {
21716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null);
218bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
219bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
22045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** @hide */
2210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    @Override
2220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    protected void finalize() throws Throwable {
2230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        try {
2240b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            close();
2250b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } finally {
2260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            super.finalize();
2270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
2280b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2293b147b770269173d5d711d6c33f142dc5e723824zzy    private int getSecurityFlags() {
2303b147b770269173d5d711d6c33f142dc5e723824zzy        int flags = 0;
2313b147b770269173d5d711d6c33f142dc5e723824zzy        if(mAuth)
2323b147b770269173d5d711d6c33f142dc5e723824zzy            flags |= SEC_FLAG_AUTH;
2333b147b770269173d5d711d6c33f142dc5e723824zzy        if(mEncrypt)
2343b147b770269173d5d711d6c33f142dc5e723824zzy            flags |= SEC_FLAG_ENCRYPT;
2353b147b770269173d5d711d6c33f142dc5e723824zzy        return flags;
2360b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2370b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2380b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
23945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Get the remote device this socket is connecting, or connected, to.
24045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @return remote device
2410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
242bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothDevice getRemoteDevice() {
243bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mDevice;
2440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the input stream associated with this socket.
24845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The input stream will be returned even if the socket is not yet
2490b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return InputStream
2520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public InputStream getInputStream() throws IOException {
2540b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mInputStream;
2550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2560b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the output stream associated with this socket.
25945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The output stream will be returned even if the socket is not yet
2600b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2620b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return OutputStream
2630b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2640b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public OutputStream getOutputStream() throws IOException {
2650b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mOutputStream;
2660b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2670b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
26824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
269ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * Get the connection status of this socket, ie, whether there is an active connection with
270ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * remote device.
271ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * @return true if connected
272ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     *         false if not connected
273ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     */
274ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    public boolean isConnected() {
2753b147b770269173d5d711d6c33f142dc5e723824zzy        return mSocketState == SocketState.CONNECTED;
2763b147b770269173d5d711d6c33f142dc5e723824zzy    }
2773b147b770269173d5d711d6c33f142dc5e723824zzy
2783b147b770269173d5d711d6c33f142dc5e723824zzy    /*package*/ void setServiceName(String name) {
2793b147b770269173d5d711d6c33f142dc5e723824zzy        mServiceName = name;
2803b147b770269173d5d711d6c33f142dc5e723824zzy    }
2813b147b770269173d5d711d6c33f142dc5e723824zzy
2823b147b770269173d5d711d6c33f142dc5e723824zzy    /**
2833b147b770269173d5d711d6c33f142dc5e723824zzy     * Attempt to connect to a remote device.
2843b147b770269173d5d711d6c33f142dc5e723824zzy     * <p>This method will block until a connection is made or the connection
2853b147b770269173d5d711d6c33f142dc5e723824zzy     * fails. If this method returns without an exception then this socket
2863b147b770269173d5d711d6c33f142dc5e723824zzy     * is now connected.
2873b147b770269173d5d711d6c33f142dc5e723824zzy     * <p>Creating new connections to
2883b147b770269173d5d711d6c33f142dc5e723824zzy     * remote Bluetooth devices should not be attempted while device discovery
2893b147b770269173d5d711d6c33f142dc5e723824zzy     * is in progress. Device discovery is a heavyweight procedure on the
2903b147b770269173d5d711d6c33f142dc5e723824zzy     * Bluetooth adapter and will significantly slow a device connection.
2913b147b770269173d5d711d6c33f142dc5e723824zzy     * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing
2923b147b770269173d5d711d6c33f142dc5e723824zzy     * discovery. Discovery is not managed by the Activity,
2933b147b770269173d5d711d6c33f142dc5e723824zzy     * but is run as a system service, so an application should always call
2943b147b770269173d5d711d6c33f142dc5e723824zzy     * {@link BluetoothAdapter#cancelDiscovery()} even if it
2953b147b770269173d5d711d6c33f142dc5e723824zzy     * did not directly request a discovery, just to be sure.
2963b147b770269173d5d711d6c33f142dc5e723824zzy     * <p>{@link #close} can be used to abort this call from another thread.
2973b147b770269173d5d711d6c33f142dc5e723824zzy     * @throws IOException on error, for example connection failure
2983b147b770269173d5d711d6c33f142dc5e723824zzy     */
2993b147b770269173d5d711d6c33f142dc5e723824zzy    public void connect() throws IOException {
3003b147b770269173d5d711d6c33f142dc5e723824zzy        if (mDevice == null) throw new IOException("Connect is called on null device");
3013b147b770269173d5d711d6c33f142dc5e723824zzy
3023b147b770269173d5d711d6c33f142dc5e723824zzy        try {
3033b147b770269173d5d711d6c33f142dc5e723824zzy            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
304903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc            IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
3050f42037eb7b5118015c2caca635538324ccf0ccffredc            if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
3060f42037eb7b5118015c2caca635538324ccf0ccffredc            mPfd = bluetoothProxy.connectSocket(mDevice, mType,
3073b147b770269173d5d711d6c33f142dc5e723824zzy                    mUuid, mPort, getSecurityFlags());
3083b147b770269173d5d711d6c33f142dc5e723824zzy            synchronized(this)
3093b147b770269173d5d711d6c33f142dc5e723824zzy            {
310563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
3113b147b770269173d5d711d6c33f142dc5e723824zzy                if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
3123b147b770269173d5d711d6c33f142dc5e723824zzy                if (mPfd == null) throw new IOException("bt socket connect failed");
3133b147b770269173d5d711d6c33f142dc5e723824zzy                FileDescriptor fd = mPfd.getFileDescriptor();
3143b147b770269173d5d711d6c33f142dc5e723824zzy                mSocket = new LocalSocket(fd);
3153b147b770269173d5d711d6c33f142dc5e723824zzy                mSocketIS = mSocket.getInputStream();
3163b147b770269173d5d711d6c33f142dc5e723824zzy                mSocketOS = mSocket.getOutputStream();
3173b147b770269173d5d711d6c33f142dc5e723824zzy            }
3183b147b770269173d5d711d6c33f142dc5e723824zzy            int channel = readInt(mSocketIS);
3193b147b770269173d5d711d6c33f142dc5e723824zzy            if (channel <= 0)
3203b147b770269173d5d711d6c33f142dc5e723824zzy                throw new IOException("bt socket connect failed");
3213b147b770269173d5d711d6c33f142dc5e723824zzy            mPort = channel;
3223b147b770269173d5d711d6c33f142dc5e723824zzy            waitSocketSignal(mSocketIS);
3233b147b770269173d5d711d6c33f142dc5e723824zzy            synchronized(this)
3243b147b770269173d5d711d6c33f142dc5e723824zzy            {
3253b147b770269173d5d711d6c33f142dc5e723824zzy                if (mSocketState == SocketState.CLOSED)
3263b147b770269173d5d711d6c33f142dc5e723824zzy                    throw new IOException("bt socket closed");
3273b147b770269173d5d711d6c33f142dc5e723824zzy                mSocketState = SocketState.CONNECTED;
3283b147b770269173d5d711d6c33f142dc5e723824zzy            }
3293b147b770269173d5d711d6c33f142dc5e723824zzy        } catch (RemoteException e) {
3303b147b770269173d5d711d6c33f142dc5e723824zzy            Log.e(TAG, Log.getStackTraceString(new Throwable()));
3313b147b770269173d5d711d6c33f142dc5e723824zzy        }
332ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    }
333ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
334ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    /**
33524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Currently returns unix errno instead of throwing IOException,
33624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * so that BluetoothAdapter can check the error code for EADDRINUSE
33724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
33824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ int bindListen() {
3393b147b770269173d5d711d6c33f142dc5e723824zzy        int ret;
3403b147b770269173d5d711d6c33f142dc5e723824zzy        if (mSocketState == SocketState.CLOSED) return EBADFD;
341903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc        IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
3420f42037eb7b5118015c2caca635538324ccf0ccffredc        if (bluetoothProxy == null) {
3430f42037eb7b5118015c2caca635538324ccf0ccffredc            Log.e(TAG, "bindListen fail, reason: bluetooth is off");
3440f42037eb7b5118015c2caca635538324ccf0ccffredc            return -1;
3450f42037eb7b5118015c2caca635538324ccf0ccffredc        }
34671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
3470f42037eb7b5118015c2caca635538324ccf0ccffredc            mPfd = bluetoothProxy.createSocketChannel(mType, mServiceName,
3483b147b770269173d5d711d6c33f142dc5e723824zzy                    mUuid, mPort, getSecurityFlags());
3493b147b770269173d5d711d6c33f142dc5e723824zzy        } catch (RemoteException e) {
3503b147b770269173d5d711d6c33f142dc5e723824zzy            Log.e(TAG, Log.getStackTraceString(new Throwable()));
3513b147b770269173d5d711d6c33f142dc5e723824zzy            return -1;
3523b147b770269173d5d711d6c33f142dc5e723824zzy        }
35371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
3543b147b770269173d5d711d6c33f142dc5e723824zzy        // read out port number
35571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
3563b147b770269173d5d711d6c33f142dc5e723824zzy            synchronized(this) {
357563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                if (VDBG) Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " +
358563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                                mPfd);
3593b147b770269173d5d711d6c33f142dc5e723824zzy                if(mSocketState != SocketState.INIT) return EBADFD;
3603b147b770269173d5d711d6c33f142dc5e723824zzy                if(mPfd == null) return -1;
3613b147b770269173d5d711d6c33f142dc5e723824zzy                FileDescriptor fd = mPfd.getFileDescriptor();
362563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                if (VDBG) Log.d(TAG, "bindListen(), new LocalSocket ");
3633b147b770269173d5d711d6c33f142dc5e723824zzy                mSocket = new LocalSocket(fd);
364563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                if (VDBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() ");
3653b147b770269173d5d711d6c33f142dc5e723824zzy                mSocketIS = mSocket.getInputStream();
3663b147b770269173d5d711d6c33f142dc5e723824zzy                mSocketOS = mSocket.getOutputStream();
3673b147b770269173d5d711d6c33f142dc5e723824zzy            }
368563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie            if (VDBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
3693b147b770269173d5d711d6c33f142dc5e723824zzy            int channel = readInt(mSocketIS);
3703b147b770269173d5d711d6c33f142dc5e723824zzy            synchronized(this) {
3713b147b770269173d5d711d6c33f142dc5e723824zzy                if(mSocketState == SocketState.INIT)
3723b147b770269173d5d711d6c33f142dc5e723824zzy                    mSocketState = SocketState.LISTENING;
3733b147b770269173d5d711d6c33f142dc5e723824zzy            }
374563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie            if (VDBG) Log.d(TAG, "channel: " + channel);
3753b147b770269173d5d711d6c33f142dc5e723824zzy            if (mPort == -1) {
3763b147b770269173d5d711d6c33f142dc5e723824zzy                mPort = channel;
3773b147b770269173d5d711d6c33f142dc5e723824zzy            } // else ASSERT(mPort == channel)
3783b147b770269173d5d711d6c33f142dc5e723824zzy            ret = 0;
3793b147b770269173d5d711d6c33f142dc5e723824zzy        } catch (IOException e) {
3803b147b770269173d5d711d6c33f142dc5e723824zzy            Log.e(TAG, "bindListen, fail to get port number, exception: " + e);
3813b147b770269173d5d711d6c33f142dc5e723824zzy            return -1;
3823b147b770269173d5d711d6c33f142dc5e723824zzy        }
3833b147b770269173d5d711d6c33f142dc5e723824zzy        return ret;
3843b147b770269173d5d711d6c33f142dc5e723824zzy    }
385ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
3863b147b770269173d5d711d6c33f142dc5e723824zzy    /*package*/ BluetoothSocket accept(int timeout) throws IOException {
3873b147b770269173d5d711d6c33f142dc5e723824zzy        BluetoothSocket acceptedSocket;
3883b147b770269173d5d711d6c33f142dc5e723824zzy        if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state");
389652678af4d18b9a6c18ce6a860de01d958bc82fezzy        if(timeout > 0) {
390652678af4d18b9a6c18ce6a860de01d958bc82fezzy            Log.d(TAG, "accept() set timeout (ms):" + timeout);
391652678af4d18b9a6c18ce6a860de01d958bc82fezzy           mSocket.setSoTimeout(timeout);
392652678af4d18b9a6c18ce6a860de01d958bc82fezzy        }
3933b147b770269173d5d711d6c33f142dc5e723824zzy        String RemoteAddr = waitSocketSignal(mSocketIS);
394652678af4d18b9a6c18ce6a860de01d958bc82fezzy        if(timeout > 0)
395652678af4d18b9a6c18ce6a860de01d958bc82fezzy            mSocket.setSoTimeout(0);
3963b147b770269173d5d711d6c33f142dc5e723824zzy        synchronized(this)
3973b147b770269173d5d711d6c33f142dc5e723824zzy        {
3983b147b770269173d5d711d6c33f142dc5e723824zzy            if (mSocketState != SocketState.LISTENING)
3993b147b770269173d5d711d6c33f142dc5e723824zzy                throw new IOException("bt socket is not in listen state");
4003b147b770269173d5d711d6c33f142dc5e723824zzy            acceptedSocket = acceptSocket(RemoteAddr);
4013b147b770269173d5d711d6c33f142dc5e723824zzy            //quick drop the reference of the file handle
40271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
4033b147b770269173d5d711d6c33f142dc5e723824zzy        return acceptedSocket;
40471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
40571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
40671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int available() throws IOException {
407563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) Log.d(TAG, "available: " + mSocketIS);
4083b147b770269173d5d711d6c33f142dc5e723824zzy        return mSocketIS.available();
40971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
41071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
41171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int read(byte[] b, int offset, int length) throws IOException {
4123b147b770269173d5d711d6c33f142dc5e723824zzy
413563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie            if (VDBG) Log.d(TAG, "read in:  " + mSocketIS + " len: " + length);
4143b147b770269173d5d711d6c33f142dc5e723824zzy            int ret = mSocketIS.read(b, offset, length);
4153b147b770269173d5d711d6c33f142dc5e723824zzy            if(ret < 0)
4163b147b770269173d5d711d6c33f142dc5e723824zzy                throw new IOException("bt socket closed, read return: " + ret);
417563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie            if (VDBG) Log.d(TAG, "read out:  " + mSocketIS + " ret: " + ret);
4183b147b770269173d5d711d6c33f142dc5e723824zzy            return ret;
41971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
42071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
42171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int write(byte[] b, int offset, int length) throws IOException {
4223b147b770269173d5d711d6c33f142dc5e723824zzy
423563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie            if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
4243b147b770269173d5d711d6c33f142dc5e723824zzy            mSocketOS.write(b, offset, length);
4253b147b770269173d5d711d6c33f142dc5e723824zzy            // There is no good way to confirm since the entire process is asynchronous anyway
426563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie            if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
4273b147b770269173d5d711d6c33f142dc5e723824zzy            return length;
4283b147b770269173d5d711d6c33f142dc5e723824zzy    }
4293b147b770269173d5d711d6c33f142dc5e723824zzy
4303b147b770269173d5d711d6c33f142dc5e723824zzy    @Override
4313b147b770269173d5d711d6c33f142dc5e723824zzy    public void close() throws IOException {
432d77982ef29b2d3b5de42846ba308fc9f880938a2Matthew Xie        if (VDBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
4333b147b770269173d5d711d6c33f142dc5e723824zzy        if(mSocketState == SocketState.CLOSED)
4343b147b770269173d5d711d6c33f142dc5e723824zzy            return;
4353b147b770269173d5d711d6c33f142dc5e723824zzy        else
4363b147b770269173d5d711d6c33f142dc5e723824zzy        {
4373b147b770269173d5d711d6c33f142dc5e723824zzy            synchronized(this)
4383b147b770269173d5d711d6c33f142dc5e723824zzy            {
4393b147b770269173d5d711d6c33f142dc5e723824zzy                 if(mSocketState == SocketState.CLOSED)
4403b147b770269173d5d711d6c33f142dc5e723824zzy                    return;
4413b147b770269173d5d711d6c33f142dc5e723824zzy                 mSocketState = SocketState.CLOSED;
442563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                 if (VDBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
4433b147b770269173d5d711d6c33f142dc5e723824zzy                        ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket);
4443b147b770269173d5d711d6c33f142dc5e723824zzy                 if(mSocket != null) {
445563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                    if (VDBG) Log.d(TAG, "Closing mSocket: " + mSocket);
4463b147b770269173d5d711d6c33f142dc5e723824zzy                    mSocket.shutdownInput();
4473b147b770269173d5d711d6c33f142dc5e723824zzy                    mSocket.shutdownOutput();
4483b147b770269173d5d711d6c33f142dc5e723824zzy                    mSocket.close();
4493b147b770269173d5d711d6c33f142dc5e723824zzy                    mSocket = null;
4503b147b770269173d5d711d6c33f142dc5e723824zzy                }
4513b147b770269173d5d711d6c33f142dc5e723824zzy                if(mPfd != null)
4523b147b770269173d5d711d6c33f142dc5e723824zzy                    mPfd.detachFd();
4533b147b770269173d5d711d6c33f142dc5e723824zzy           }
45471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
45571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
45671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
4573b147b770269173d5d711d6c33f142dc5e723824zzy    /*package */ void removeChannel() {
4583b147b770269173d5d711d6c33f142dc5e723824zzy    }
45916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
4603b147b770269173d5d711d6c33f142dc5e723824zzy    /*package */ int getPort() {
4613b147b770269173d5d711d6c33f142dc5e723824zzy        return mPort;
4623b147b770269173d5d711d6c33f142dc5e723824zzy    }
4633b147b770269173d5d711d6c33f142dc5e723824zzy    private String convertAddr(final byte[] addr)  {
4643b147b770269173d5d711d6c33f142dc5e723824zzy        return String.format("%02X:%02X:%02X:%02X:%02X:%02X",
4653b147b770269173d5d711d6c33f142dc5e723824zzy                addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]);
4663b147b770269173d5d711d6c33f142dc5e723824zzy    }
4673b147b770269173d5d711d6c33f142dc5e723824zzy    private String waitSocketSignal(InputStream is) throws IOException {
4683b147b770269173d5d711d6c33f142dc5e723824zzy        byte [] sig = new byte[SOCK_SIGNAL_SIZE];
4693b147b770269173d5d711d6c33f142dc5e723824zzy        int ret = readAll(is, sig);
470563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) Log.d(TAG, "waitSocketSignal read 16 bytes signal ret: " + ret);
4713b147b770269173d5d711d6c33f142dc5e723824zzy        ByteBuffer bb = ByteBuffer.wrap(sig);
4723b147b770269173d5d711d6c33f142dc5e723824zzy        bb.order(ByteOrder.nativeOrder());
4733b147b770269173d5d711d6c33f142dc5e723824zzy        int size = bb.getShort();
474652678af4d18b9a6c18ce6a860de01d958bc82fezzy        if(size != SOCK_SIGNAL_SIZE)
475652678af4d18b9a6c18ce6a860de01d958bc82fezzy            throw new IOException("Connection failure, wrong signal size: " + size);
4763b147b770269173d5d711d6c33f142dc5e723824zzy        byte [] addr = new byte[6];
4773b147b770269173d5d711d6c33f142dc5e723824zzy        bb.get(addr);
4783b147b770269173d5d711d6c33f142dc5e723824zzy        int channel = bb.getInt();
4793b147b770269173d5d711d6c33f142dc5e723824zzy        int status = bb.getInt();
4803b147b770269173d5d711d6c33f142dc5e723824zzy        String RemoteAddr = convertAddr(addr);
481563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: "
4823b147b770269173d5d711d6c33f142dc5e723824zzy                + RemoteAddr + ", channel: " + channel + ", status: " + status);
4833b147b770269173d5d711d6c33f142dc5e723824zzy        if(status != 0)
4843b147b770269173d5d711d6c33f142dc5e723824zzy            throw new IOException("Connection failure, status: " + status);
4853b147b770269173d5d711d6c33f142dc5e723824zzy        return RemoteAddr;
4863b147b770269173d5d711d6c33f142dc5e723824zzy    }
4873b147b770269173d5d711d6c33f142dc5e723824zzy    private int readAll(InputStream is, byte[] b) throws IOException {
4883b147b770269173d5d711d6c33f142dc5e723824zzy        int left = b.length;
4893b147b770269173d5d711d6c33f142dc5e723824zzy        while(left > 0) {
4903b147b770269173d5d711d6c33f142dc5e723824zzy            int ret = is.read(b, b.length - left, left);
491d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc            if(ret <= 0)
492652678af4d18b9a6c18ce6a860de01d958bc82fezzy                 throw new IOException("read failed, socket might closed or timeout, read ret: " + ret);
4933b147b770269173d5d711d6c33f142dc5e723824zzy            left -= ret;
4943b147b770269173d5d711d6c33f142dc5e723824zzy            if(left != 0)
4953b147b770269173d5d711d6c33f142dc5e723824zzy                Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) +
4963b147b770269173d5d711d6c33f142dc5e723824zzy                            ", expect size: " + b.length);
49716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
4983b147b770269173d5d711d6c33f142dc5e723824zzy        return b.length;
4993b147b770269173d5d711d6c33f142dc5e723824zzy    }
5003b147b770269173d5d711d6c33f142dc5e723824zzy
5013b147b770269173d5d711d6c33f142dc5e723824zzy    private int readInt(InputStream is) throws IOException {
5023b147b770269173d5d711d6c33f142dc5e723824zzy        byte[] ibytes = new byte[4];
5033b147b770269173d5d711d6c33f142dc5e723824zzy        int ret = readAll(is, ibytes);
504563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret);
5053b147b770269173d5d711d6c33f142dc5e723824zzy        ByteBuffer bb = ByteBuffer.wrap(ibytes);
5063b147b770269173d5d711d6c33f142dc5e723824zzy        bb.order(ByteOrder.nativeOrder());
5073b147b770269173d5d711d6c33f142dc5e723824zzy        return bb.getInt();
50816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
5090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly}
510