blob: 3a1e2f58c99d1faf221e90ec0639ec2948264dac [file] [log] [blame]
Nick Pelly0b6955a2009-05-26 19:13:43 -07001/*
Zhihai Xufa0fd392012-10-23 17:31:56 -07002 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Nick Pelly0b6955a2009-05-26 19:13:43 -070015 */
16
17package android.bluetooth;
18
Mathew Inwood4dc66d32018-08-01 15:07:20 +010019import android.annotation.UnsupportedAppUsage;
Jack Hea355e5e2017-08-22 16:06:54 -070020import android.net.LocalSocket;
zzy3b147b72012-04-03 19:48:32 -070021import android.os.ParcelFileDescriptor;
Jack Hea355e5e2017-08-22 16:06:54 -070022import android.os.ParcelUuid;
Nick Pelly16fb88a2009-10-07 07:44:03 +020023import android.os.RemoteException;
24import android.util.Log;
25
Nick Pelly0b6955a2009-05-26 19:13:43 -070026import java.io.Closeable;
zzy3b147b72012-04-03 19:48:32 -070027import java.io.FileDescriptor;
Nick Pelly0b6955a2009-05-26 19:13:43 -070028import java.io.IOException;
29import java.io.InputStream;
30import java.io.OutputStream;
Jack Hea355e5e2017-08-22 16:06:54 -070031import java.nio.ByteBuffer;
32import java.nio.ByteOrder;
Andreas Gampee6748ce2015-12-11 18:00:38 -080033import java.util.Arrays;
Jeff Sharkeyfea17de2013-06-11 14:13:09 -070034import java.util.Locale;
zzyb49a8962012-10-11 14:52:43 -070035import java.util.UUID;
Casper Bonde238e0f92015-04-09 09:24:48 +020036
Nick Pelly0b6955a2009-05-26 19:13:43 -070037/**
Nick Pelly45e27042009-08-19 11:00:00 -070038 * A connected or connecting Bluetooth socket.
Nick Pelly0b6955a2009-05-26 19:13:43 -070039 *
Nick Pelly45e27042009-08-19 11:00:00 -070040 * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
41 * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
42 * side, use a {@link BluetoothServerSocket} to create a listening server
Scott Main9fab0ae2009-11-03 18:17:59 -080043 * socket. When a connection is accepted by the {@link BluetoothServerSocket},
44 * it will return a new {@link BluetoothSocket} to manage the connection.
Jake Hambyf51eada2010-09-21 13:39:53 -070045 * On the client side, use a single {@link BluetoothSocket} to both initiate
Scott Main9fab0ae2009-11-03 18:17:59 -080046 * an outgoing connection and to manage the connection.
Nick Pelly0b6955a2009-05-26 19:13:43 -070047 *
Scott Main9fab0ae2009-11-03 18:17:59 -080048 * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
49 * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
50 * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
Nick Pelly0b6955a2009-05-26 19:13:43 -070051 *
Scott Main9fab0ae2009-11-03 18:17:59 -080052 * <p>To create a {@link BluetoothSocket} for connecting to a known device, use
53 * {@link BluetoothDevice#createRfcommSocketToServiceRecord
54 * BluetoothDevice.createRfcommSocketToServiceRecord()}.
55 * Then call {@link #connect()} to attempt a connection to the remote device.
56 * This call will block until a connection is established or the connection
57 * fails.
Nick Pelly45e27042009-08-19 11:00:00 -070058 *
Scott Main9fab0ae2009-11-03 18:17:59 -080059 * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the
60 * {@link BluetoothServerSocket} documentation.
Nick Pelly45e27042009-08-19 11:00:00 -070061 *
Scott Main9fab0ae2009-11-03 18:17:59 -080062 * <p>Once the socket is connected, whether initiated as a client or accepted
63 * as a server, open the IO streams by calling {@link #getInputStream} and
64 * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream}
65 * and {@link java.io.OutputStream} objects, respectively, which are
66 * automatically connected to the socket.
67 *
68 * <p>{@link BluetoothSocket} is thread
Nick Pelly45e27042009-08-19 11:00:00 -070069 * safe. In particular, {@link #close} will always immediately abort ongoing
70 * operations and close the socket.
Nick Pellycf440592009-09-08 10:12:06 -070071 *
Scott Main9fab0ae2009-11-03 18:17:59 -080072 * <p class="note"><strong>Note:</strong>
73 * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
74 *
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080075 * <div class="special reference">
76 * <h3>Developer Guides</h3>
77 * <p>For more information about using Bluetooth, read the
Marie Janssen382871b2016-06-20 10:26:31 -070078 * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080079 * </div>
80 *
Scott Main9fab0ae2009-11-03 18:17:59 -080081 * {@see BluetoothServerSocket}
82 * {@see java.io.InputStream}
83 * {@see java.io.OutputStream}
Nick Pelly0b6955a2009-05-26 19:13:43 -070084 */
85public final class BluetoothSocket implements Closeable {
Nick Pelly16fb88a2009-10-07 07:44:03 +020086 private static final String TAG = "BluetoothSocket";
Joe LaPennaf3de98a2014-05-13 18:17:46 -070087 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
88 private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
Nick Pelly16fb88a2009-10-07 07:44:03 +020089
Nick Pelly24bb9b82009-10-02 20:34:18 -070090 /** @hide */
91 public static final int MAX_RFCOMM_CHANNEL = 30;
Casper Bonde238e0f92015-04-09 09:24:48 +020092 /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF;
Nick Pelly24bb9b82009-10-02 20:34:18 -070093
Andre Eisenbachf4559862015-05-04 13:48:50 -070094 /** RFCOMM socket */
Casper Bonde238e0f92015-04-09 09:24:48 +020095 public static final int TYPE_RFCOMM = 1;
Andre Eisenbachf4559862015-05-04 13:48:50 -070096
97 /** SCO socket */
Casper Bonde238e0f92015-04-09 09:24:48 +020098 public static final int TYPE_SCO = 2;
Andre Eisenbachf4559862015-05-04 13:48:50 -070099
100 /** L2CAP socket */
Casper Bonde238e0f92015-04-09 09:24:48 +0200101 public static final int TYPE_L2CAP = 3;
Nick Pelly6a669fa2009-06-02 15:57:18 -0700102
Stanley Tnge48468d2017-11-22 16:04:40 -0800103 /** L2CAP socket on BR/EDR transport
104 * @hide
105 */
106 public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP;
107
108 /** L2CAP socket on LE transport
109 * @hide
110 */
111 public static final int TYPE_L2CAP_LE = 4;
112
Nick Pelly24bb9b82009-10-02 20:34:18 -0700113 /*package*/ static final int EBADFD = 77;
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100114 @UnsupportedAppUsage
Nick Pelly24bb9b82009-10-02 20:34:18 -0700115 /*package*/ static final int EADDRINUSE = 98;
116
zzy3b147b72012-04-03 19:48:32 -0700117 /*package*/ static final int SEC_FLAG_ENCRYPT = 1;
118 /*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
Jack Hea355e5e2017-08-22 16:06:54 -0700119 /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2;
120 /*package*/ static final int SEC_FLAG_AUTH_MITM = 1 << 3;
121 /*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4;
zzy3b147b72012-04-03 19:48:32 -0700122
Nick Pelly6a669fa2009-06-02 15:57:18 -0700123 private final int mType; /* one of TYPE_RFCOMM etc */
zzy3b147b72012-04-03 19:48:32 -0700124 private BluetoothDevice mDevice; /* remote device */
125 private String mAddress; /* remote address */
Nick Pelly0b6955a2009-05-26 19:13:43 -0700126 private final boolean mAuth;
127 private final boolean mEncrypt;
128 private final BluetoothInputStream mInputStream;
129 private final BluetoothOutputStream mOutputStream;
zzy3b147b72012-04-03 19:48:32 -0700130 private final ParcelUuid mUuid;
Casper Bonde23284232015-04-21 13:12:05 +0200131 private boolean mExcludeSdp = false; /* when true no SPP SDP record will be created */
132 private boolean mAuthMitm = false; /* when true Man-in-the-middle protection will be enabled*/
Casper Bonde3b3d1fe2015-05-08 14:32:24 +0200133 private boolean mMin16DigitPin = false; /* Minimum 16 digit pin for sec mode 2 connections */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100134 @UnsupportedAppUsage
zzy3b147b72012-04-03 19:48:32 -0700135 private ParcelFileDescriptor mPfd;
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100136 @UnsupportedAppUsage
zzy3b147b72012-04-03 19:48:32 -0700137 private LocalSocket mSocket;
138 private InputStream mSocketIS;
139 private OutputStream mSocketOS;
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100140 @UnsupportedAppUsage
Mike Lockwood68c692d2013-10-02 07:56:46 -0700141 private int mPort; /* RFCOMM channel or L2CAP psm */
zzy3b147b72012-04-03 19:48:32 -0700142 private int mFd;
143 private String mServiceName;
Jack He2992cd02017-08-22 21:21:23 -0700144 private static final int PROXY_CONNECTION_TIMEOUT = 5000;
zzy3b147b72012-04-03 19:48:32 -0700145
Jack He2992cd02017-08-22 21:21:23 -0700146 private static final int SOCK_SIGNAL_SIZE = 20;
Casper Bonde238e0f92015-04-09 09:24:48 +0200147
148 private ByteBuffer mL2capBuffer = null;
149 private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
150 private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received.
Nick Pelly0b6955a2009-05-26 19:13:43 -0700151
Matthew Xieceb6c9f2011-05-03 19:50:20 -0700152 private enum SocketState {
153 INIT,
154 CONNECTED,
zzy3b147b72012-04-03 19:48:32 -0700155 LISTENING,
156 CLOSED,
Matthew Xieceb6c9f2011-05-03 19:50:20 -0700157 }
Nick Pelly71c3c782009-09-02 11:51:35 -0700158
Matthew Xieceb6c9f2011-05-03 19:50:20 -0700159 /** prevents all native calls after destroyNative() */
zzy3b147b72012-04-03 19:48:32 -0700160 private volatile SocketState mSocketState;
Matthew Xieceb6c9f2011-05-03 19:50:20 -0700161
162 /** protects mSocketState */
zzy3b147b72012-04-03 19:48:32 -0700163 //private final ReentrantReadWriteLock mLock;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700164
165 /**
Nick Pellybd022f42009-08-14 18:33:38 -0700166 * Construct a BluetoothSocket.
Jack Hea355e5e2017-08-22 16:06:54 -0700167 *
168 * @param type type of socket
169 * @param fd fd to use for connected socket, or -1 for a new socket
170 * @param auth require the remote device to be authenticated
Nick Pelly0b6955a2009-05-26 19:13:43 -0700171 * @param encrypt require the connection to be encrypted
Jack Hea355e5e2017-08-22 16:06:54 -0700172 * @param device remote device that this socket can connect to
173 * @param port remote port
174 * @param uuid SDP uuid
175 * @throws IOException On error, for example Bluetooth not available, or insufficient
176 * privileges
Nick Pelly0b6955a2009-05-26 19:13:43 -0700177 */
Nick Pellybd022f42009-08-14 18:33:38 -0700178 /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
Nick Pelly16fb88a2009-10-07 07:44:03 +0200179 BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
Casper Bonde3b3d1fe2015-05-08 14:32:24 +0200180 this(type, fd, auth, encrypt, device, port, uuid, false, false);
Casper Bonde23284232015-04-21 13:12:05 +0200181 }
182
183 /**
184 * Construct a BluetoothSocket.
Jack Hea355e5e2017-08-22 16:06:54 -0700185 *
186 * @param type type of socket
187 * @param fd fd to use for connected socket, or -1 for a new socket
188 * @param auth require the remote device to be authenticated
Casper Bonde23284232015-04-21 13:12:05 +0200189 * @param encrypt require the connection to be encrypted
Jack Hea355e5e2017-08-22 16:06:54 -0700190 * @param device remote device that this socket can connect to
191 * @param port remote port
192 * @param uuid SDP uuid
193 * @param mitm enforce man-in-the-middle protection.
Casper Bonde3b3d1fe2015-05-08 14:32:24 +0200194 * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
Jack Hea355e5e2017-08-22 16:06:54 -0700195 * @throws IOException On error, for example Bluetooth not available, or insufficient
196 * privileges
Casper Bonde23284232015-04-21 13:12:05 +0200197 */
198 /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
Casper Bonde3b3d1fe2015-05-08 14:32:24 +0200199 BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin)
Jack Hea355e5e2017-08-22 16:06:54 -0700200 throws IOException {
Casper Bonde238e0f92015-04-09 09:24:48 +0200201 if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
202 if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1
203 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
Nick Pelly24bb9b82009-10-02 20:34:18 -0700204 if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
205 throw new IOException("Invalid RFCOMM channel: " + port);
206 }
207 }
Jack Hea355e5e2017-08-22 16:06:54 -0700208 if (uuid != null) {
zzyb49a8962012-10-11 14:52:43 -0700209 mUuid = uuid;
Jack Hea355e5e2017-08-22 16:06:54 -0700210 } else {
211 mUuid = new ParcelUuid(new UUID(0, 0));
212 }
Nick Pelly6a669fa2009-06-02 15:57:18 -0700213 mType = type;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700214 mAuth = auth;
Casper Bonde23284232015-04-21 13:12:05 +0200215 mAuthMitm = mitm;
Casper Bonde3b3d1fe2015-05-08 14:32:24 +0200216 mMin16DigitPin = min16DigitPin;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700217 mEncrypt = encrypt;
Nick Pellybd022f42009-08-14 18:33:38 -0700218 mDevice = device;
zzy3b147b72012-04-03 19:48:32 -0700219 mPort = port;
220 mFd = fd;
221
222 mSocketState = SocketState.INIT;
223
Nick Pellybd022f42009-08-14 18:33:38 -0700224 if (device == null) {
zzy3b147b72012-04-03 19:48:32 -0700225 // Server socket
226 mAddress = BluetoothAdapter.getDefaultAdapter().getAddress();
Nick Pellybd022f42009-08-14 18:33:38 -0700227 } else {
zzy3b147b72012-04-03 19:48:32 -0700228 // Remote socket
Nick Pellybd022f42009-08-14 18:33:38 -0700229 mAddress = device.getAddress();
230 }
Nick Pelly0b6955a2009-05-26 19:13:43 -0700231 mInputStream = new BluetoothInputStream(this);
232 mOutputStream = new BluetoothOutputStream(this);
zzy3b147b72012-04-03 19:48:32 -0700233 }
Jack Hea355e5e2017-08-22 16:06:54 -0700234
zzy3b147b72012-04-03 19:48:32 -0700235 private BluetoothSocket(BluetoothSocket s) {
Casper Bonde238e0f92015-04-09 09:24:48 +0200236 if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType);
zzy3b147b72012-04-03 19:48:32 -0700237 mUuid = s.mUuid;
238 mType = s.mType;
239 mAuth = s.mAuth;
240 mEncrypt = s.mEncrypt;
241 mPort = s.mPort;
242 mInputStream = new BluetoothInputStream(this);
243 mOutputStream = new BluetoothOutputStream(this);
Casper Bonde238e0f92015-04-09 09:24:48 +0200244 mMaxRxPacketSize = s.mMaxRxPacketSize;
245 mMaxTxPacketSize = s.mMaxTxPacketSize;
246
zzy3b147b72012-04-03 19:48:32 -0700247 mServiceName = s.mServiceName;
Casper Bonde238e0f92015-04-09 09:24:48 +0200248 mExcludeSdp = s.mExcludeSdp;
Casper Bonde23284232015-04-21 13:12:05 +0200249 mAuthMitm = s.mAuthMitm;
Casper Bonde3b3d1fe2015-05-08 14:32:24 +0200250 mMin16DigitPin = s.mMin16DigitPin;
zzy3b147b72012-04-03 19:48:32 -0700251 }
Jack Hea355e5e2017-08-22 16:06:54 -0700252
Jack He2992cd02017-08-22 21:21:23 -0700253 private BluetoothSocket acceptSocket(String remoteAddr) throws IOException {
zzy3b147b72012-04-03 19:48:32 -0700254 BluetoothSocket as = new BluetoothSocket(this);
255 as.mSocketState = SocketState.CONNECTED;
256 FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
Andreas Gampee6748ce2015-12-11 18:00:38 -0800257 if (DBG) Log.d(TAG, "socket fd passed by stack fds: " + Arrays.toString(fds));
Jack Hea355e5e2017-08-22 16:06:54 -0700258 if (fds == null || fds.length != 1) {
Andreas Gampee6748ce2015-12-11 18:00:38 -0800259 Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds));
zzy71bfafc2013-04-16 17:17:37 -0700260 as.close();
zzy3b147b72012-04-03 19:48:32 -0700261 throw new IOException("bt socket acept failed");
262 }
Zach Johnson569ff222015-07-13 18:00:35 -0700263
264 as.mPfd = new ParcelFileDescriptor(fds[0]);
Neil Fuller7fd72462017-01-06 11:29:15 +0000265 as.mSocket = LocalSocket.createConnectedLocalSocket(fds[0]);
zzy3b147b72012-04-03 19:48:32 -0700266 as.mSocketIS = as.mSocket.getInputStream();
267 as.mSocketOS = as.mSocket.getOutputStream();
Jack He2992cd02017-08-22 21:21:23 -0700268 as.mAddress = remoteAddr;
269 as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr);
zzy3b147b72012-04-03 19:48:32 -0700270 return as;
271 }
Jack Hea355e5e2017-08-22 16:06:54 -0700272
Nick Pellybd022f42009-08-14 18:33:38 -0700273 /**
Nick Pelly16fb88a2009-10-07 07:44:03 +0200274 * Construct a BluetoothSocket from address. Used by native code.
Jack Hea355e5e2017-08-22 16:06:54 -0700275 *
276 * @param type type of socket
277 * @param fd fd to use for connected socket, or -1 for a new socket
278 * @param auth require the remote device to be authenticated
Nick Pellybd022f42009-08-14 18:33:38 -0700279 * @param encrypt require the connection to be encrypted
280 * @param address remote device that this socket can connect to
Jack Hea355e5e2017-08-22 16:06:54 -0700281 * @param port remote port
282 * @throws IOException On error, for example Bluetooth not available, or insufficient
283 * privileges
Nick Pellybd022f42009-08-14 18:33:38 -0700284 */
285 private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
286 int port) throws IOException {
Casper Bonde3b3d1fe2015-05-08 14:32:24 +0200287 this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null, false, false);
Nick Pellybd022f42009-08-14 18:33:38 -0700288 }
289
Nick Pelly45e27042009-08-19 11:00:00 -0700290 /** @hide */
Nick Pelly0b6955a2009-05-26 19:13:43 -0700291 @Override
292 protected void finalize() throws Throwable {
293 try {
294 close();
295 } finally {
296 super.finalize();
297 }
298 }
Jack Hea355e5e2017-08-22 16:06:54 -0700299
zzy3b147b72012-04-03 19:48:32 -0700300 private int getSecurityFlags() {
301 int flags = 0;
Jack Hea355e5e2017-08-22 16:06:54 -0700302 if (mAuth) {
zzy3b147b72012-04-03 19:48:32 -0700303 flags |= SEC_FLAG_AUTH;
Jack Hea355e5e2017-08-22 16:06:54 -0700304 }
305 if (mEncrypt) {
zzy3b147b72012-04-03 19:48:32 -0700306 flags |= SEC_FLAG_ENCRYPT;
Jack Hea355e5e2017-08-22 16:06:54 -0700307 }
308 if (mExcludeSdp) {
Casper Bonde238e0f92015-04-09 09:24:48 +0200309 flags |= BTSOCK_FLAG_NO_SDP;
Jack Hea355e5e2017-08-22 16:06:54 -0700310 }
311 if (mAuthMitm) {
Casper Bonde23284232015-04-21 13:12:05 +0200312 flags |= SEC_FLAG_AUTH_MITM;
Jack Hea355e5e2017-08-22 16:06:54 -0700313 }
314 if (mMin16DigitPin) {
Casper Bonde3b3d1fe2015-05-08 14:32:24 +0200315 flags |= SEC_FLAG_AUTH_16_DIGIT;
Jack Hea355e5e2017-08-22 16:06:54 -0700316 }
zzy3b147b72012-04-03 19:48:32 -0700317 return flags;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700318 }
319
320 /**
Nick Pelly45e27042009-08-19 11:00:00 -0700321 * Get the remote device this socket is connecting, or connected, to.
Jack Hea355e5e2017-08-22 16:06:54 -0700322 *
Nick Pelly45e27042009-08-19 11:00:00 -0700323 * @return remote device
Nick Pelly0b6955a2009-05-26 19:13:43 -0700324 */
Nick Pellybd022f42009-08-14 18:33:38 -0700325 public BluetoothDevice getRemoteDevice() {
326 return mDevice;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700327 }
328
329 /**
330 * Get the input stream associated with this socket.
Nick Pelly45e27042009-08-19 11:00:00 -0700331 * <p>The input stream will be returned even if the socket is not yet
Nick Pelly0b6955a2009-05-26 19:13:43 -0700332 * connected, but operations on that stream will throw IOException until
333 * the associated socket is connected.
Jack Hea355e5e2017-08-22 16:06:54 -0700334 *
Nick Pelly0b6955a2009-05-26 19:13:43 -0700335 * @return InputStream
336 */
337 public InputStream getInputStream() throws IOException {
338 return mInputStream;
339 }
340
341 /**
342 * Get the output stream associated with this socket.
Nick Pelly45e27042009-08-19 11:00:00 -0700343 * <p>The output stream will be returned even if the socket is not yet
Nick Pelly0b6955a2009-05-26 19:13:43 -0700344 * connected, but operations on that stream will throw IOException until
345 * the associated socket is connected.
Jack Hea355e5e2017-08-22 16:06:54 -0700346 *
Nick Pelly0b6955a2009-05-26 19:13:43 -0700347 * @return OutputStream
348 */
349 public OutputStream getOutputStream() throws IOException {
350 return mOutputStream;
351 }
352
Nick Pelly24bb9b82009-10-02 20:34:18 -0700353 /**
Matthew Xieceb6c9f2011-05-03 19:50:20 -0700354 * Get the connection status of this socket, ie, whether there is an active connection with
355 * remote device.
Jack Hea355e5e2017-08-22 16:06:54 -0700356 *
357 * @return true if connected false if not connected
Matthew Xieceb6c9f2011-05-03 19:50:20 -0700358 */
359 public boolean isConnected() {
zzy3b147b72012-04-03 19:48:32 -0700360 return mSocketState == SocketState.CONNECTED;
361 }
362
363 /*package*/ void setServiceName(String name) {
364 mServiceName = name;
365 }
366
367 /**
368 * Attempt to connect to a remote device.
369 * <p>This method will block until a connection is made or the connection
370 * fails. If this method returns without an exception then this socket
371 * is now connected.
372 * <p>Creating new connections to
373 * remote Bluetooth devices should not be attempted while device discovery
374 * is in progress. Device discovery is a heavyweight procedure on the
375 * Bluetooth adapter and will significantly slow a device connection.
376 * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing
377 * discovery. Discovery is not managed by the Activity,
378 * but is run as a system service, so an application should always call
379 * {@link BluetoothAdapter#cancelDiscovery()} even if it
380 * did not directly request a discovery, just to be sure.
381 * <p>{@link #close} can be used to abort this call from another thread.
Jack Hea355e5e2017-08-22 16:06:54 -0700382 *
zzy3b147b72012-04-03 19:48:32 -0700383 * @throws IOException on error, for example connection failure
384 */
385 public void connect() throws IOException {
386 if (mDevice == null) throw new IOException("Connect is called on null device");
387
388 try {
zzy3b147b72012-04-03 19:48:32 -0700389 if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
Casper Bonde238e0f92015-04-09 09:24:48 +0200390 IBluetooth bluetoothProxy =
391 BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
fredc0f420372012-04-12 00:02:00 -0700392 if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
Jakub Pawlowski04307202017-11-06 12:17:30 -0800393 mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
zzy3b147b72012-04-03 19:48:32 -0700394 mUuid, mPort, getSecurityFlags());
Jack Hea355e5e2017-08-22 16:06:54 -0700395 synchronized (this) {
Matthew Xie563e4142012-10-09 22:10:37 -0700396 if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
zzy3b147b72012-04-03 19:48:32 -0700397 if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
398 if (mPfd == null) throw new IOException("bt socket connect failed");
399 FileDescriptor fd = mPfd.getFileDescriptor();
Neil Fuller7fd72462017-01-06 11:29:15 +0000400 mSocket = LocalSocket.createConnectedLocalSocket(fd);
zzy3b147b72012-04-03 19:48:32 -0700401 mSocketIS = mSocket.getInputStream();
402 mSocketOS = mSocket.getOutputStream();
403 }
404 int channel = readInt(mSocketIS);
Jack Hea355e5e2017-08-22 16:06:54 -0700405 if (channel <= 0) {
zzy3b147b72012-04-03 19:48:32 -0700406 throw new IOException("bt socket connect failed");
Jack Hea355e5e2017-08-22 16:06:54 -0700407 }
zzy3b147b72012-04-03 19:48:32 -0700408 mPort = channel;
409 waitSocketSignal(mSocketIS);
Jack Hea355e5e2017-08-22 16:06:54 -0700410 synchronized (this) {
411 if (mSocketState == SocketState.CLOSED) {
zzy3b147b72012-04-03 19:48:32 -0700412 throw new IOException("bt socket closed");
Jack Hea355e5e2017-08-22 16:06:54 -0700413 }
zzy3b147b72012-04-03 19:48:32 -0700414 mSocketState = SocketState.CONNECTED;
415 }
416 } catch (RemoteException e) {
417 Log.e(TAG, Log.getStackTraceString(new Throwable()));
Sharvil Nanavati3e8eb402014-04-08 14:51:15 -0700418 throw new IOException("unable to send RPC: " + e.getMessage());
zzy3b147b72012-04-03 19:48:32 -0700419 }
Matthew Xieceb6c9f2011-05-03 19:50:20 -0700420 }
421
422 /**
Nick Pelly24bb9b82009-10-02 20:34:18 -0700423 * Currently returns unix errno instead of throwing IOException,
424 * so that BluetoothAdapter can check the error code for EADDRINUSE
425 */
426 /*package*/ int bindListen() {
zzy3b147b72012-04-03 19:48:32 -0700427 int ret;
428 if (mSocketState == SocketState.CLOSED) return EBADFD;
fredc903ac6f2012-04-24 03:59:57 -0700429 IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
fredc0f420372012-04-12 00:02:00 -0700430 if (bluetoothProxy == null) {
431 Log.e(TAG, "bindListen fail, reason: bluetooth is off");
432 return -1;
433 }
Nick Pelly71c3c782009-09-02 11:51:35 -0700434 try {
Stanley Tnge48468d2017-11-22 16:04:40 -0800435 if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType);
Jakub Pawlowskife7e8852017-11-06 12:16:25 -0800436 mPfd = bluetoothProxy.getSocketManager().createSocketChannel(mType, mServiceName,
zzy3b147b72012-04-03 19:48:32 -0700437 mUuid, mPort, getSecurityFlags());
438 } catch (RemoteException e) {
439 Log.e(TAG, Log.getStackTraceString(new Throwable()));
zzy3b147b72012-04-03 19:48:32 -0700440 return -1;
441 }
442
443 // read out port number
444 try {
Jack Hea355e5e2017-08-22 16:06:54 -0700445 synchronized (this) {
446 if (DBG) {
Jack He2992cd02017-08-22 21:21:23 -0700447 Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
Jack Hea355e5e2017-08-22 16:06:54 -0700448 }
449 if (mSocketState != SocketState.INIT) return EBADFD;
450 if (mPfd == null) return -1;
zzy3b147b72012-04-03 19:48:32 -0700451 FileDescriptor fd = mPfd.getFileDescriptor();
Ajay Panickerc2516332017-03-28 14:28:27 -0700452 if (fd == null) {
453 Log.e(TAG, "bindListen(), null file descriptor");
454 return -1;
455 }
456
Neil Fuller7fd72462017-01-06 11:29:15 +0000457 if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket");
458 mSocket = LocalSocket.createConnectedLocalSocket(fd);
459 if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()");
zzy3b147b72012-04-03 19:48:32 -0700460 mSocketIS = mSocket.getInputStream();
461 mSocketOS = mSocket.getOutputStream();
462 }
Joe LaPennaf3de98a2014-05-13 18:17:46 -0700463 if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
zzy3b147b72012-04-03 19:48:32 -0700464 int channel = readInt(mSocketIS);
Jack Hea355e5e2017-08-22 16:06:54 -0700465 synchronized (this) {
466 if (mSocketState == SocketState.INIT) {
zzy3b147b72012-04-03 19:48:32 -0700467 mSocketState = SocketState.LISTENING;
Jack Hea355e5e2017-08-22 16:06:54 -0700468 }
zzy3b147b72012-04-03 19:48:32 -0700469 }
Stanley Tnge48468d2017-11-22 16:04:40 -0800470 if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort);
Casper Bonde238e0f92015-04-09 09:24:48 +0200471 if (mPort <= -1) {
zzy3b147b72012-04-03 19:48:32 -0700472 mPort = channel;
473 } // else ASSERT(mPort == channel)
474 ret = 0;
475 } catch (IOException e) {
Matthew Xie726652e2014-09-03 10:04:00 -0700476 if (mPfd != null) {
477 try {
478 mPfd.close();
479 } catch (IOException e1) {
480 Log.e(TAG, "bindListen, close mPfd: " + e1);
481 }
482 mPfd = null;
483 }
zzy3b147b72012-04-03 19:48:32 -0700484 Log.e(TAG, "bindListen, fail to get port number, exception: " + e);
485 return -1;
486 }
487 return ret;
Nick Pelly71c3c782009-09-02 11:51:35 -0700488 }
489
490 /*package*/ BluetoothSocket accept(int timeout) throws IOException {
zzy3b147b72012-04-03 19:48:32 -0700491 BluetoothSocket acceptedSocket;
Jack Hea355e5e2017-08-22 16:06:54 -0700492 if (mSocketState != SocketState.LISTENING) {
Casper Bonde238e0f92015-04-09 09:24:48 +0200493 throw new IOException("bt socket is not in listen state");
Jack Hea355e5e2017-08-22 16:06:54 -0700494 }
495 if (timeout > 0) {
zzy652678a2012-11-22 11:52:44 -0800496 Log.d(TAG, "accept() set timeout (ms):" + timeout);
Jack Hea355e5e2017-08-22 16:06:54 -0700497 mSocket.setSoTimeout(timeout);
zzy652678a2012-11-22 11:52:44 -0800498 }
zzy3b147b72012-04-03 19:48:32 -0700499 String RemoteAddr = waitSocketSignal(mSocketIS);
Jack Hea355e5e2017-08-22 16:06:54 -0700500 if (timeout > 0) {
zzy652678a2012-11-22 11:52:44 -0800501 mSocket.setSoTimeout(0);
Jack Hea355e5e2017-08-22 16:06:54 -0700502 }
503 synchronized (this) {
504 if (mSocketState != SocketState.LISTENING) {
zzy3b147b72012-04-03 19:48:32 -0700505 throw new IOException("bt socket is not in listen state");
Jack Hea355e5e2017-08-22 16:06:54 -0700506 }
zzy3b147b72012-04-03 19:48:32 -0700507 acceptedSocket = acceptSocket(RemoteAddr);
508 //quick drop the reference of the file handle
Nick Pelly71c3c782009-09-02 11:51:35 -0700509 }
zzy3b147b72012-04-03 19:48:32 -0700510 return acceptedSocket;
Nick Pelly71c3c782009-09-02 11:51:35 -0700511 }
512
513 /*package*/ int available() throws IOException {
Matthew Xie563e4142012-10-09 22:10:37 -0700514 if (VDBG) Log.d(TAG, "available: " + mSocketIS);
zzy3b147b72012-04-03 19:48:32 -0700515 return mSocketIS.available();
Nick Pelly71c3c782009-09-02 11:51:35 -0700516 }
Jack Hea355e5e2017-08-22 16:06:54 -0700517
zzy71bfafc2013-04-16 17:17:37 -0700518 /**
519 * Wait until the data in sending queue is emptied. A polling version
520 * for flush implementation. Used to ensure the writing data afterwards will
521 * be packed in new RFCOMM frame.
Jack Hea355e5e2017-08-22 16:06:54 -0700522 *
523 * @throws IOException if an i/o error occurs.
zzy71bfafc2013-04-16 17:17:37 -0700524 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100525 @UnsupportedAppUsage
zzy71bfafc2013-04-16 17:17:37 -0700526 /*package*/ void flush() throws IOException {
Zhihai Xu610770d2013-12-17 11:39:20 -0800527 if (mSocketOS == null) throw new IOException("flush is called on null OutputStream");
zzy71bfafc2013-04-16 17:17:37 -0700528 if (VDBG) Log.d(TAG, "flush: " + mSocketOS);
529 mSocketOS.flush();
530 }
Nick Pelly71c3c782009-09-02 11:51:35 -0700531
532 /*package*/ int read(byte[] b, int offset, int length) throws IOException {
Casper Bonde238e0f92015-04-09 09:24:48 +0200533 int ret = 0;
Zhihai Xu610770d2013-12-17 11:39:20 -0800534 if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length);
Stanley Tnge48468d2017-11-22 16:04:40 -0800535 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
Casper Bonde238e0f92015-04-09 09:24:48 +0200536 int bytesToRead = length;
Jack Hea355e5e2017-08-22 16:06:54 -0700537 if (VDBG) {
538 Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length
539 + "mL2capBuffer= " + mL2capBuffer);
540 }
Casper Bonde238e0f92015-04-09 09:24:48 +0200541 if (mL2capBuffer == null) {
542 createL2capRxBuffer();
543 }
544 if (mL2capBuffer.remaining() == 0) {
545 if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling...");
546 if (fillL2capRxBuffer() == -1) {
547 return -1;
548 }
549 }
550 if (bytesToRead > mL2capBuffer.remaining()) {
551 bytesToRead = mL2capBuffer.remaining();
552 }
Jack Hea355e5e2017-08-22 16:06:54 -0700553 if (VDBG) {
554 Log.v(TAG, "get(): offset: " + offset
555 + " bytesToRead: " + bytesToRead);
556 }
Casper Bonde238e0f92015-04-09 09:24:48 +0200557 mL2capBuffer.get(b, offset, bytesToRead);
558 ret = bytesToRead;
Jack Hea355e5e2017-08-22 16:06:54 -0700559 } else {
Casper Bonde238e0f92015-04-09 09:24:48 +0200560 if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length);
561 ret = mSocketIS.read(b, offset, length);
562 }
Jack Hea355e5e2017-08-22 16:06:54 -0700563 if (ret < 0) {
Zhihai Xu610770d2013-12-17 11:39:20 -0800564 throw new IOException("bt socket closed, read return: " + ret);
Jack Hea355e5e2017-08-22 16:06:54 -0700565 }
Zhihai Xu610770d2013-12-17 11:39:20 -0800566 if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret);
567 return ret;
Nick Pelly71c3c782009-09-02 11:51:35 -0700568 }
569
570 /*package*/ int write(byte[] b, int offset, int length) throws IOException {
Casper Bonde238e0f92015-04-09 09:24:48 +0200571
572 //TODO: Since bindings can exist between the SDU size and the
573 // protocol, we might need to throw an exception instead of just
574 // splitting the write into multiple smaller writes.
575 // Rfcomm uses dynamic allocation, and should not have any bindings
576 // to the actual message length.
Jack Hea355e5e2017-08-22 16:06:54 -0700577 if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
Stanley Tnge48468d2017-11-22 16:04:40 -0800578 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
Jack Hea355e5e2017-08-22 16:06:54 -0700579 if (length <= mMaxTxPacketSize) {
580 mSocketOS.write(b, offset, length);
581 } else {
582 if (DBG) {
583 Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
Casper Bonde238e0f92015-04-09 09:24:48 +0200584 + "Packet will be divided into SDU packets of size "
585 + mMaxTxPacketSize);
Casper Bonde238e0f92015-04-09 09:24:48 +0200586 }
Jack Hea355e5e2017-08-22 16:06:54 -0700587 int tmpOffset = offset;
588 int bytesToWrite = length;
589 while (bytesToWrite > 0) {
590 int tmpLength = (bytesToWrite > mMaxTxPacketSize)
591 ? mMaxTxPacketSize
592 : bytesToWrite;
593 mSocketOS.write(b, tmpOffset, tmpLength);
594 tmpOffset += tmpLength;
595 bytesToWrite -= tmpLength;
596 }
Casper Bonde238e0f92015-04-09 09:24:48 +0200597 }
Jack Hea355e5e2017-08-22 16:06:54 -0700598 } else {
599 mSocketOS.write(b, offset, length);
600 }
601 // There is no good way to confirm since the entire process is asynchronous anyway
602 if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
603 return length;
Nick Pelly71c3c782009-09-02 11:51:35 -0700604 }
605
zzy3b147b72012-04-03 19:48:32 -0700606 @Override
607 public void close() throws IOException {
Jack He2992cd02017-08-22 21:21:23 -0700608 Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS
609 + ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket + ", mSocketState: "
610 + mSocketState);
Jack Hea355e5e2017-08-22 16:06:54 -0700611 if (mSocketState == SocketState.CLOSED) {
zzy3b147b72012-04-03 19:48:32 -0700612 return;
Jack Hea355e5e2017-08-22 16:06:54 -0700613 } else {
614 synchronized (this) {
615 if (mSocketState == SocketState.CLOSED) {
zzy3b147b72012-04-03 19:48:32 -0700616 return;
Jack Hea355e5e2017-08-22 16:06:54 -0700617 }
618 mSocketState = SocketState.CLOSED;
619 if (mSocket != null) {
Joe LaPennaf3de98a2014-05-13 18:17:46 -0700620 if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
zzy3b147b72012-04-03 19:48:32 -0700621 mSocket.shutdownInput();
622 mSocket.shutdownOutput();
623 mSocket.close();
624 mSocket = null;
625 }
Zhihai Xu01771022014-01-20 12:04:23 -0800626 if (mPfd != null) {
627 mPfd.close();
628 mPfd = null;
629 }
Jack Hea355e5e2017-08-22 16:06:54 -0700630 }
Nick Pelly16fb88a2009-10-07 07:44:03 +0200631 }
zzy3b147b72012-04-03 19:48:32 -0700632 }
Nick Pelly16fb88a2009-10-07 07:44:03 +0200633
zzy3b147b72012-04-03 19:48:32 -0700634 /*package */ void removeChannel() {
635 }
Nick Pelly16fb88a2009-10-07 07:44:03 +0200636
zzy3b147b72012-04-03 19:48:32 -0700637 /*package */ int getPort() {
638 return mPort;
639 }
Casper Bonde238e0f92015-04-09 09:24:48 +0200640
641 /**
642 * Get the maximum supported Transmit packet size for the underlying transport.
643 * Use this to optimize the writes done to the output socket, to avoid sending
644 * half full packets.
Jack Hea355e5e2017-08-22 16:06:54 -0700645 *
Casper Bonde238e0f92015-04-09 09:24:48 +0200646 * @return the maximum supported Transmit packet size for the underlying transport.
647 */
Jack Hea355e5e2017-08-22 16:06:54 -0700648 public int getMaxTransmitPacketSize() {
Casper Bonde238e0f92015-04-09 09:24:48 +0200649 return mMaxTxPacketSize;
650 }
651
652 /**
653 * Get the maximum supported Receive packet size for the underlying transport.
654 * Use this to optimize the reads done on the input stream, as any call to read
655 * will return a maximum of this amount of bytes - or for some transports a
656 * multiple of this value.
Jack Hea355e5e2017-08-22 16:06:54 -0700657 *
Casper Bonde238e0f92015-04-09 09:24:48 +0200658 * @return the maximum supported Receive packet size for the underlying transport.
659 */
Jack Hea355e5e2017-08-22 16:06:54 -0700660 public int getMaxReceivePacketSize() {
Casper Bonde238e0f92015-04-09 09:24:48 +0200661 return mMaxRxPacketSize;
662 }
663
664 /**
Andre Eisenbachf4559862015-05-04 13:48:50 -0700665 * Get the type of the underlying connection.
Jack Hea355e5e2017-08-22 16:06:54 -0700666 *
Andre Eisenbachf4559862015-05-04 13:48:50 -0700667 * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP}
Casper Bonde238e0f92015-04-09 09:24:48 +0200668 */
669 public int getConnectionType() {
Stanley Tng1bff4ba2018-06-29 14:05:04 -0700670 if (mType == TYPE_L2CAP_LE) {
671 // Treat the LE CoC to be the same type as L2CAP.
672 return TYPE_L2CAP;
673 }
Casper Bonde238e0f92015-04-09 09:24:48 +0200674 return mType;
675 }
676
677 /**
678 * Change if a SDP entry should be automatically created.
679 * Must be called before calling .bind, for the call to have any effect.
Jack Hea355e5e2017-08-22 16:06:54 -0700680 *
Jack He2992cd02017-08-22 21:21:23 -0700681 * @param excludeSdp <li>TRUE - do not auto generate SDP record. <li>FALSE - default - auto
Jack Hea355e5e2017-08-22 16:06:54 -0700682 * generate SPP SDP record.
Casper Bonde238e0f92015-04-09 09:24:48 +0200683 * @hide
684 */
685 public void setExcludeSdp(boolean excludeSdp) {
Jack He2992cd02017-08-22 21:21:23 -0700686 mExcludeSdp = excludeSdp;
Casper Bonde238e0f92015-04-09 09:24:48 +0200687 }
688
Stanley Tng918c5242018-01-16 10:39:32 -0800689 /**
690 * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This
691 * parameter is used by the BT Controller to set the maximum transmission packet size on this
692 * connection. This function is currently used for testing only.
693 * @hide
694 */
695 public void requestMaximumTxDataLength() throws IOException {
696 if (mDevice == null) {
697 throw new IOException("requestMaximumTxDataLength is called on null device");
698 }
699
700 try {
701 if (mSocketState == SocketState.CLOSED) {
702 throw new IOException("socket closed");
703 }
704 IBluetooth bluetoothProxy =
705 BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
706 if (bluetoothProxy == null) {
707 throw new IOException("Bluetooth is off");
708 }
709
710 if (DBG) Log.d(TAG, "requestMaximumTxDataLength");
711 bluetoothProxy.getSocketManager().requestMaximumTxDataLength(mDevice);
712 } catch (RemoteException e) {
713 Log.e(TAG, Log.getStackTraceString(new Throwable()));
714 throw new IOException("unable to send RPC: " + e.getMessage());
715 }
716 }
717
Jack Hea355e5e2017-08-22 16:06:54 -0700718 private String convertAddr(final byte[] addr) {
Jeff Sharkeyfea17de2013-06-11 14:13:09 -0700719 return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
Jack Hea355e5e2017-08-22 16:06:54 -0700720 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
zzy3b147b72012-04-03 19:48:32 -0700721 }
Jack Hea355e5e2017-08-22 16:06:54 -0700722
zzy3b147b72012-04-03 19:48:32 -0700723 private String waitSocketSignal(InputStream is) throws IOException {
Jack Hea355e5e2017-08-22 16:06:54 -0700724 byte[] sig = new byte[SOCK_SIGNAL_SIZE];
zzy3b147b72012-04-03 19:48:32 -0700725 int ret = readAll(is, sig);
Jack Hea355e5e2017-08-22 16:06:54 -0700726 if (VDBG) {
Jack He2992cd02017-08-22 21:21:23 -0700727 Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE + " bytes signal ret: " + ret);
Jack Hea355e5e2017-08-22 16:06:54 -0700728 }
zzy3b147b72012-04-03 19:48:32 -0700729 ByteBuffer bb = ByteBuffer.wrap(sig);
Casper Bonde238e0f92015-04-09 09:24:48 +0200730 /* the struct in native is decorated with __attribute__((packed)), hence this is possible */
zzy3b147b72012-04-03 19:48:32 -0700731 bb.order(ByteOrder.nativeOrder());
732 int size = bb.getShort();
Jack Hea355e5e2017-08-22 16:06:54 -0700733 if (size != SOCK_SIGNAL_SIZE) {
zzy652678a2012-11-22 11:52:44 -0800734 throw new IOException("Connection failure, wrong signal size: " + size);
Jack Hea355e5e2017-08-22 16:06:54 -0700735 }
736 byte[] addr = new byte[6];
zzy3b147b72012-04-03 19:48:32 -0700737 bb.get(addr);
738 int channel = bb.getInt();
739 int status = bb.getInt();
Casper Bonde238e0f92015-04-09 09:24:48 +0200740 mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
741 mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
zzy3b147b72012-04-03 19:48:32 -0700742 String RemoteAddr = convertAddr(addr);
Jack Hea355e5e2017-08-22 16:06:54 -0700743 if (VDBG) {
744 Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: "
745 + RemoteAddr + ", channel: " + channel + ", status: " + status
746 + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize);
747 }
748 if (status != 0) {
zzy3b147b72012-04-03 19:48:32 -0700749 throw new IOException("Connection failure, status: " + status);
Jack Hea355e5e2017-08-22 16:06:54 -0700750 }
zzy3b147b72012-04-03 19:48:32 -0700751 return RemoteAddr;
752 }
Casper Bonde238e0f92015-04-09 09:24:48 +0200753
Jack Hea355e5e2017-08-22 16:06:54 -0700754 private void createL2capRxBuffer() {
Stanley Tnge48468d2017-11-22 16:04:40 -0800755 if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
Casper Bonde238e0f92015-04-09 09:24:48 +0200756 // Allocate the buffer to use for reads.
Jack Hea355e5e2017-08-22 16:06:54 -0700757 if (VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize);
Casper Bonde238e0f92015-04-09 09:24:48 +0200758 mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]);
Jack Hea355e5e2017-08-22 16:06:54 -0700759 if (VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining());
Casper Bonde238e0f92015-04-09 09:24:48 +0200760 mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request
Jack Hea355e5e2017-08-22 16:06:54 -0700761 if (VDBG) {
Jack He2992cd02017-08-22 21:21:23 -0700762 Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + mL2capBuffer.remaining());
Jack Hea355e5e2017-08-22 16:06:54 -0700763 }
Casper Bonde238e0f92015-04-09 09:24:48 +0200764 }
765 }
766
zzy3b147b72012-04-03 19:48:32 -0700767 private int readAll(InputStream is, byte[] b) throws IOException {
768 int left = b.length;
Jack Hea355e5e2017-08-22 16:06:54 -0700769 while (left > 0) {
zzy3b147b72012-04-03 19:48:32 -0700770 int ret = is.read(b, b.length - left, left);
Jack Hea355e5e2017-08-22 16:06:54 -0700771 if (ret <= 0) {
772 throw new IOException("read failed, socket might closed or timeout, read ret: "
773 + ret);
774 }
zzy3b147b72012-04-03 19:48:32 -0700775 left -= ret;
Jack Hea355e5e2017-08-22 16:06:54 -0700776 if (left != 0) {
Jack He2992cd02017-08-22 21:21:23 -0700777 Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left)
778 + ", expect size: " + b.length);
Jack Hea355e5e2017-08-22 16:06:54 -0700779 }
Nick Pelly16fb88a2009-10-07 07:44:03 +0200780 }
zzy3b147b72012-04-03 19:48:32 -0700781 return b.length;
782 }
783
784 private int readInt(InputStream is) throws IOException {
785 byte[] ibytes = new byte[4];
786 int ret = readAll(is, ibytes);
Matthew Xie563e4142012-10-09 22:10:37 -0700787 if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret);
zzy3b147b72012-04-03 19:48:32 -0700788 ByteBuffer bb = ByteBuffer.wrap(ibytes);
789 bb.order(ByteOrder.nativeOrder());
790 return bb.getInt();
Nick Pelly16fb88a2009-10-07 07:44:03 +0200791 }
Casper Bonde238e0f92015-04-09 09:24:48 +0200792
793 private int fillL2capRxBuffer() throws IOException {
794 mL2capBuffer.rewind();
795 int ret = mSocketIS.read(mL2capBuffer.array());
Jack Hea355e5e2017-08-22 16:06:54 -0700796 if (ret == -1) {
Casper Bonde238e0f92015-04-09 09:24:48 +0200797 // reached end of stream - return -1
798 mL2capBuffer.limit(0);
799 return -1;
800 }
801 mL2capBuffer.limit(ret);
802 return ret;
803 }
804
805
Nick Pelly0b6955a2009-05-26 19:13:43 -0700806}