• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth;
18 
19 import static android.bluetooth.BluetoothUtils.getSyncTimeout;
20 
21 import android.annotation.RequiresNoPermission;
22 import android.annotation.RequiresPermission;
23 import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
24 import android.compat.annotation.UnsupportedAppUsage;
25 import android.net.LocalSocket;
26 import android.os.Build;
27 import android.os.ParcelFileDescriptor;
28 import android.os.ParcelUuid;
29 import android.os.RemoteException;
30 import android.util.Log;
31 
32 import com.android.modules.utils.SynchronousResultReceiver;
33 
34 import java.io.Closeable;
35 import java.io.FileDescriptor;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.OutputStream;
39 import java.nio.ByteBuffer;
40 import java.nio.ByteOrder;
41 import java.util.Arrays;
42 import java.util.Locale;
43 import java.util.UUID;
44 import java.util.concurrent.TimeoutException;
45 
46 /**
47  * A connected or connecting Bluetooth socket.
48  *
49  * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
50  * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
51  * side, use a {@link BluetoothServerSocket} to create a listening server
52  * socket. When a connection is accepted by the {@link BluetoothServerSocket},
53  * it will return a new {@link BluetoothSocket} to manage the connection.
54  * On the client side, use a single {@link BluetoothSocket} to both initiate
55  * an outgoing connection and to manage the connection.
56  *
57  * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
58  * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
59  * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
60  *
61  * <p>To create a {@link BluetoothSocket} for connecting to a known device, use
62  * {@link BluetoothDevice#createRfcommSocketToServiceRecord
63  * BluetoothDevice.createRfcommSocketToServiceRecord()}.
64  * Then call {@link #connect()} to attempt a connection to the remote device.
65  * This call will block until a connection is established or the connection
66  * fails.
67  *
68  * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the
69  * {@link BluetoothServerSocket} documentation.
70  *
71  * <p>Once the socket is connected, whether initiated as a client or accepted
72  * as a server, open the IO streams by calling {@link #getInputStream} and
73  * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream}
74  * and {@link java.io.OutputStream} objects, respectively, which are
75  * automatically connected to the socket.
76  *
77  * <p>{@link BluetoothSocket} is thread
78  * safe. In particular, {@link #close} will always immediately abort ongoing
79  * operations and close the socket.
80  *
81  * <div class="special reference">
82  * <h3>Developer Guides</h3>
83  * <p>For more information about using Bluetooth, read the
84  * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
85  * </div>
86  *
87  * {@see BluetoothServerSocket}
88  * {@see java.io.InputStream}
89  * {@see java.io.OutputStream}
90  */
91 public final class BluetoothSocket implements Closeable {
92     private static final String TAG = "BluetoothSocket";
93     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
94     private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
95 
96     /** @hide */
97     public static final int MAX_RFCOMM_CHANNEL = 30;
98     /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF;
99 
100     /** RFCOMM socket */
101     public static final int TYPE_RFCOMM = 1;
102 
103     /** SCO socket */
104     public static final int TYPE_SCO = 2;
105 
106     /** L2CAP socket */
107     public static final int TYPE_L2CAP = 3;
108 
109     /** L2CAP socket on BR/EDR transport
110      * @hide
111      */
112     public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP;
113 
114     /** L2CAP socket on LE transport
115      * @hide
116      */
117     public static final int TYPE_L2CAP_LE = 4;
118 
119     /*package*/ static final int EBADFD = 77;
120     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
121     /*package*/ static final int EADDRINUSE = 98;
122 
123     /*package*/ static final int SEC_FLAG_ENCRYPT = 1;
124     /*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
125     /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2;
126     /*package*/ static final int SEC_FLAG_AUTH_MITM = 1 << 3;
127     /*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4;
128 
129     // Defined in BluetoothProtoEnums.L2capCocConnectionResult of proto logging
130     private static final int RESULT_L2CAP_CONN_UNKNOWN = 0;
131     /*package*/ static final int RESULT_L2CAP_CONN_SUCCESS = 1;
132     private static final int RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_FAILED = 1000;
133     private static final int RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED = 1001;
134     private static final int RESULT_L2CAP_CONN_BLUETOOTH_UNABLE_TO_SEND_RPC = 1002;
135     private static final int RESULT_L2CAP_CONN_BLUETOOTH_NULL_BLUETOOTH_DEVICE = 1003;
136     private static final int RESULT_L2CAP_CONN_BLUETOOTH_GET_SOCKET_MANAGER_FAILED = 1004;
137     private static final int RESULT_L2CAP_CONN_BLUETOOTH_NULL_FILE_DESCRIPTOR = 1005;
138     /*package*/ static final int RESULT_L2CAP_CONN_SERVER_FAILURE = 2000;
139 
140     private final int mType;  /* one of TYPE_RFCOMM etc */
141     private BluetoothDevice mDevice;    /* remote device */
142     private String mAddress;    /* remote address */
143     private final boolean mAuth;
144     private final boolean mEncrypt;
145     private final BluetoothInputStream mInputStream;
146     private final BluetoothOutputStream mOutputStream;
147     private final ParcelUuid mUuid;
148     /** when true no SPP SDP record will be created */
149     private boolean mExcludeSdp = false;
150     /** when true Person-in-the-middle protection will be enabled */
151     private boolean mAuthMitm = false;
152     /** Minimum 16 digit pin for sec mode 2 connections */
153     private boolean mMin16DigitPin = false;
154     @UnsupportedAppUsage(publicAlternatives = "Use {@link BluetoothSocket} public API instead.")
155     private ParcelFileDescriptor mPfd;
156     @UnsupportedAppUsage
157     private LocalSocket mSocket;
158     private InputStream mSocketIS;
159     private OutputStream mSocketOS;
160     @UnsupportedAppUsage
161     private int mPort;  /* RFCOMM channel or L2CAP psm */
162     private int mFd;
163     private String mServiceName;
164     private static final int PROXY_CONNECTION_TIMEOUT = 5000;
165 
166     private static final int SOCK_SIGNAL_SIZE = 20;
167 
168     private ByteBuffer mL2capBuffer = null;
169     private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
170     private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received.
171 
172     private long mSocketCreationTimeMillis = 0;
173     private long mSocketCreationLatencyMillis = 0;
174 
175     private enum SocketState {
176         INIT,
177         CONNECTED,
178         LISTENING,
179         CLOSED,
180     }
181 
182     /** prevents all native calls after destroyNative() */
183     private volatile SocketState mSocketState;
184 
185     /** protects mSocketState */
186     //private final ReentrantReadWriteLock mLock;
187 
188     /**
189      * Construct a BluetoothSocket.
190      *
191      * @param type type of socket
192      * @param fd fd to use for connected socket, or -1 for a new socket
193      * @param auth require the remote device to be authenticated
194      * @param encrypt require the connection to be encrypted
195      * @param device remote device that this socket can connect to
196      * @param port remote port
197      * @param uuid SDP uuid
198      * @throws IOException On error, for example Bluetooth not available, or insufficient
199      * privileges
200      */
BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, BluetoothDevice device, int port, ParcelUuid uuid)201     /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
202             BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
203         this(type, fd, auth, encrypt, device, port, uuid, false, false);
204     }
205 
206     /**
207      * Construct a BluetoothSocket.
208      *
209      * @param type type of socket
210      * @param fd fd to use for connected socket, or -1 for a new socket
211      * @param auth require the remote device to be authenticated
212      * @param encrypt require the connection to be encrypted
213      * @param device remote device that this socket can connect to
214      * @param port remote port
215      * @param uuid SDP uuid
216      * @param mitm enforce person-in-the-middle protection.
217      * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
218      * @throws IOException On error, for example Bluetooth not available, or insufficient
219      * privileges
220      */
BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin)221     /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
222             BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin)
223             throws IOException {
224         if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
225         mSocketCreationTimeMillis = System.currentTimeMillis();
226         if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1
227                 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
228             if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
229                 throw new IOException("Invalid RFCOMM channel: " + port);
230             }
231         }
232         if (uuid != null) {
233             mUuid = uuid;
234         } else {
235             mUuid = new ParcelUuid(new UUID(0, 0));
236         }
237         mType = type;
238         mAuth = auth;
239         mAuthMitm = mitm;
240         mMin16DigitPin = min16DigitPin;
241         mEncrypt = encrypt;
242         mDevice = device;
243         mPort = port;
244         mFd = fd;
245 
246         mSocketState = SocketState.INIT;
247 
248         if (device == null) {
249             // Server socket
250             mAddress = BluetoothAdapter.getDefaultAdapter().getAddress();
251         } else {
252             // Remote socket
253             mAddress = device.getAddress();
254         }
255         mInputStream = new BluetoothInputStream(this);
256         mOutputStream = new BluetoothOutputStream(this);
257         mSocketCreationLatencyMillis = System.currentTimeMillis() - mSocketCreationTimeMillis;
258     }
259 
260     /**
261      * Creates a BluetoothSocket from a {@link ParcelFileDescriptor}. This is used for when the
262      * underlying mPfd is transferred to a separate process (e.g. over a binder), and the socket
263      * must be reconstructed.
264      * <p>
265      * The socket should already be connected in this case, so {@link #connect()} should not be
266      * called.
267      *
268      * @param pfd is the {@link ParcelFileDescriptor} for an already connected BluetoothSocket
269      * @param device is the remote {@link BluetoothDevice} that this socket is connected to
270      * @param uuid is the service ID that this RFCOMM connection is using
271      * @throws IOException if socket creation fails.
272      */
createSocketFromOpenFd( ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid)273     /*package*/ static BluetoothSocket createSocketFromOpenFd(
274             ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid) throws IOException {
275         BluetoothSocket bluetoothSocket =
276                 new BluetoothSocket(TYPE_RFCOMM, pfd.getFd(), true, true, device, -1, uuid);
277 
278         bluetoothSocket.mPfd = pfd;
279         bluetoothSocket.mSocket = new LocalSocket(pfd.getFileDescriptor());
280         bluetoothSocket.mSocketIS = bluetoothSocket.mSocket.getInputStream();
281         bluetoothSocket.mSocketOS = bluetoothSocket.mSocket.getOutputStream();
282         bluetoothSocket.mSocketState = SocketState.CONNECTED;
283 
284         return bluetoothSocket;
285     }
286 
BluetoothSocket(BluetoothSocket s)287     private BluetoothSocket(BluetoothSocket s) {
288         if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType);
289         mUuid = s.mUuid;
290         mType = s.mType;
291         mAuth = s.mAuth;
292         mEncrypt = s.mEncrypt;
293         mPort = s.mPort;
294         mInputStream = new BluetoothInputStream(this);
295         mOutputStream = new BluetoothOutputStream(this);
296         mMaxRxPacketSize = s.mMaxRxPacketSize;
297         mMaxTxPacketSize = s.mMaxTxPacketSize;
298 
299         mServiceName = s.mServiceName;
300         mExcludeSdp = s.mExcludeSdp;
301         mAuthMitm = s.mAuthMitm;
302         mMin16DigitPin = s.mMin16DigitPin;
303         mSocketCreationTimeMillis = s.mSocketCreationTimeMillis;
304         mSocketCreationLatencyMillis = s.mSocketCreationLatencyMillis;
305     }
306 
acceptSocket(String remoteAddr)307     private BluetoothSocket acceptSocket(String remoteAddr) throws IOException {
308         BluetoothSocket as = new BluetoothSocket(this);
309         as.mSocketState = SocketState.CONNECTED;
310         FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
311         if (DBG) Log.d(TAG, "acceptSocket: socket fd passed by stack fds:" + Arrays.toString(fds));
312         if (fds == null || fds.length != 1) {
313             Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds));
314             as.close();
315             throw new IOException("bt socket acept failed");
316         }
317 
318         as.mPfd = ParcelFileDescriptor.dup(fds[0]);
319         as.mSocket = new LocalSocket(fds[0]);
320         as.mSocketIS = as.mSocket.getInputStream();
321         as.mSocketOS = as.mSocket.getOutputStream();
322         as.mAddress = remoteAddr;
323         as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr);
324         return as;
325     }
326 
327     /**
328      * Construct a BluetoothSocket from address. Used by native code.
329      *
330      * @param type type of socket
331      * @param fd fd to use for connected socket, or -1 for a new socket
332      * @param auth require the remote device to be authenticated
333      * @param encrypt require the connection to be encrypted
334      * @param address remote device that this socket can connect to
335      * @param port remote port
336      * @throws IOException On error, for example Bluetooth not available, or insufficient
337      * privileges
338      */
BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, int port)339     private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
340             int port) throws IOException {
341         this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null, false, false);
342     }
343 
344     /** @hide */
345     @Override
finalize()346     protected void finalize() throws Throwable {
347         try {
348             close();
349         } finally {
350             super.finalize();
351         }
352     }
353 
getSecurityFlags()354     private int getSecurityFlags() {
355         int flags = 0;
356         if (mAuth) {
357             flags |= SEC_FLAG_AUTH;
358         }
359         if (mEncrypt) {
360             flags |= SEC_FLAG_ENCRYPT;
361         }
362         if (mExcludeSdp) {
363             flags |= BTSOCK_FLAG_NO_SDP;
364         }
365         if (mAuthMitm) {
366             flags |= SEC_FLAG_AUTH_MITM;
367         }
368         if (mMin16DigitPin) {
369             flags |= SEC_FLAG_AUTH_16_DIGIT;
370         }
371         return flags;
372     }
373 
374     /**
375      * Get the remote device this socket is connecting, or connected, to.
376      *
377      * @return remote device
378      */
379     @RequiresNoPermission
getRemoteDevice()380     public BluetoothDevice getRemoteDevice() {
381         return mDevice;
382     }
383 
384     /**
385      * Get the input stream associated with this socket.
386      * <p>The input stream will be returned even if the socket is not yet
387      * connected, but operations on that stream will throw IOException until
388      * the associated socket is connected.
389      *
390      * @return InputStream
391      */
392     @RequiresNoPermission
getInputStream()393     public InputStream getInputStream() throws IOException {
394         return mInputStream;
395     }
396 
397     /**
398      * Get the output stream associated with this socket.
399      * <p>The output stream will be returned even if the socket is not yet
400      * connected, but operations on that stream will throw IOException until
401      * the associated socket is connected.
402      *
403      * @return OutputStream
404      */
405     @RequiresNoPermission
getOutputStream()406     public OutputStream getOutputStream() throws IOException {
407         return mOutputStream;
408     }
409 
410     /**
411      * Get the connection status of this socket, ie, whether there is an active connection with
412      * remote device.
413      *
414      * @return true if connected false if not connected
415      */
416     @RequiresNoPermission
isConnected()417     public boolean isConnected() {
418         return mSocketState == SocketState.CONNECTED;
419     }
420 
setServiceName(String name)421     /*package*/ void setServiceName(String name) {
422         mServiceName = name;
423     }
424 
isAuth()425     /*package*/ boolean isAuth() {
426         return mAuth;
427     }
428     /**
429      * Attempt to connect to a remote device.
430      * <p>This method will block until a connection is made or the connection fails. If this method
431      * returns without an exception then this socket is now connected.
432      * <p>Creating new connections to remote Bluetooth devices should not be attempted while device
433      * discovery is in progress. Device discovery is a heavyweight procedure on the Bluetooth
434      * adapter and will significantly slow a device connection. Use
435      * {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing discovery. Discovery is not
436      * managed by the Activity, but is run as a system service, so an application should always call
437      * {@link BluetoothAdapter#cancelDiscovery()} even if it did not directly request a discovery,
438      * just to be sure.
439      * <p>{@link #close} can be used to abort this call from another thread.
440      *
441      * @throws BluetoothSocketException in case of failure, with the corresponding
442      * {@link BluetoothSocketException#ErrorCode}.
443      * @throws IOException for other errors (eg: InputStream read failures etc.).
444      */
445     @RequiresBluetoothConnectPermission
446     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
connect()447     public void connect() throws IOException {
448         IBluetooth bluetoothProxy =
449                 BluetoothAdapter.getDefaultAdapter().getBluetoothService();
450         long socketConnectionTimeMillis = System.currentTimeMillis();
451         if (bluetoothProxy == null) {
452             throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE);
453         }
454         if (mDevice == null) {
455             logL2capcocClientConnection(
456                     bluetoothProxy,
457                     RESULT_L2CAP_CONN_BLUETOOTH_NULL_BLUETOOTH_DEVICE,
458                     socketConnectionTimeMillis);
459             throw new BluetoothSocketException(BluetoothSocketException.NULL_DEVICE);
460         }
461         try {
462             if (mSocketState == SocketState.CLOSED) {
463                 logL2capcocClientConnection(
464                         bluetoothProxy,
465                         RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED,
466                         socketConnectionTimeMillis);
467                 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
468             }
469 
470             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
471             if (socketManager == null) {
472                 logL2capcocClientConnection(
473                         bluetoothProxy,
474                         RESULT_L2CAP_CONN_BLUETOOTH_GET_SOCKET_MANAGER_FAILED,
475                         socketConnectionTimeMillis);
476                 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE);
477             }
478             mPfd = socketManager.connectSocket(mDevice, mType, mUuid, mPort, getSecurityFlags());
479             synchronized (this) {
480                 if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
481                 if (mSocketState == SocketState.CLOSED) {
482                     logL2capcocClientConnection(
483                             bluetoothProxy,
484                             RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED,
485                             socketConnectionTimeMillis);
486                     throw new BluetoothSocketException(
487                             BluetoothSocketException.SOCKET_CONNECTION_FAILURE);
488                 }
489                 if (mPfd == null) {
490                     logL2capcocClientConnection(
491                             bluetoothProxy,
492                             RESULT_L2CAP_CONN_BLUETOOTH_NULL_FILE_DESCRIPTOR,
493                             socketConnectionTimeMillis);
494                     throw new BluetoothSocketException(
495                             BluetoothSocketException.SOCKET_CONNECTION_FAILURE);
496                 }
497                 FileDescriptor fd = mPfd.getFileDescriptor();
498                 mSocket = new LocalSocket(fd);
499                 mSocketIS = mSocket.getInputStream();
500                 mSocketOS = mSocket.getOutputStream();
501             }
502             int channel = readInt(mSocketIS);
503             if (channel == 0) {
504                 int errCode = (int) mSocketIS.read();
505                 logL2capcocClientConnection(bluetoothProxy, errCode, socketConnectionTimeMillis);
506                 throw new BluetoothSocketException(errCode);
507             }
508             if (channel < 0) {
509                 logL2capcocClientConnection(
510                         bluetoothProxy,
511                         RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_FAILED,
512                         socketConnectionTimeMillis);
513                 throw new BluetoothSocketException(
514                         BluetoothSocketException.SOCKET_CONNECTION_FAILURE);
515             }
516             mPort = channel;
517             waitSocketSignal(mSocketIS);
518             synchronized (this) {
519                 if (mSocketState == SocketState.CLOSED) {
520                     logL2capcocClientConnection(
521                             bluetoothProxy,
522                             RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED,
523                             socketConnectionTimeMillis);
524                     throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
525                 }
526                 mSocketState = SocketState.CONNECTED;
527                 if (DBG) Log.d(TAG, "connect(), socket connected");
528             }
529             logL2capcocClientConnection(bluetoothProxy,
530                     RESULT_L2CAP_CONN_SUCCESS,
531                     socketConnectionTimeMillis);
532         } catch (RemoteException e) {
533             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
534             logL2capcocClientConnection(
535                     bluetoothProxy,
536                     RESULT_L2CAP_CONN_BLUETOOTH_UNABLE_TO_SEND_RPC,
537                     socketConnectionTimeMillis);
538             throw new BluetoothSocketException(BluetoothSocketException.RPC_FAILURE,
539                     "unable to send RPC: " + e.getMessage());
540         }
541     }
542 
543     /**
544      * Currently returns unix errno instead of throwing IOException,
545      * so that BluetoothAdapter can check the error code for EADDRINUSE
546      */
547     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
bindListen()548     /*package*/ int bindListen() {
549         int ret;
550         if (mSocketState == SocketState.CLOSED) return EBADFD;
551         IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
552         if (bluetoothProxy == null) {
553             Log.e(TAG, "bindListen fail, reason: bluetooth is off");
554             return -1;
555         }
556         try {
557             if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType);
558             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
559             if (socketManager == null) {
560                 Log.e(TAG, "bindListen() bt get socket manager failed");
561                 return -1;
562             }
563             mPfd = socketManager
564                 .createSocketChannel(mType, mServiceName, mUuid, mPort, getSecurityFlags());
565         } catch (RemoteException e) {
566             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
567             return -1;
568         }
569 
570         // read out port number
571         try {
572             synchronized (this) {
573                 if (DBG) {
574                     Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
575                 }
576                 if (mSocketState != SocketState.INIT) return EBADFD;
577                 if (mPfd == null) return -1;
578                 FileDescriptor fd = mPfd.getFileDescriptor();
579                 if (fd == null) {
580                     Log.e(TAG, "bindListen(), null file descriptor");
581                     return -1;
582                 }
583 
584                 if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket");
585                 mSocket = new LocalSocket(fd);
586                 if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()");
587                 mSocketIS = mSocket.getInputStream();
588                 mSocketOS = mSocket.getOutputStream();
589             }
590             if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
591             int channel = readInt(mSocketIS);
592             synchronized (this) {
593                 if (mSocketState == SocketState.INIT) {
594                     mSocketState = SocketState.LISTENING;
595                 }
596             }
597             if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort);
598             if (mPort <= -1) {
599                 mPort = channel;
600             } // else ASSERT(mPort == channel)
601             ret = 0;
602         } catch (IOException e) {
603             if (mPfd != null) {
604                 try {
605                     mPfd.close();
606                 } catch (IOException e1) {
607                     Log.e(TAG, "bindListen, close mPfd: " + e1);
608                 }
609                 mPfd = null;
610             }
611             Log.e(TAG, "bindListen, fail to get port number, exception: " + e);
612             return -1;
613         }
614         return ret;
615     }
616 
accept(int timeout)617     /*package*/ BluetoothSocket accept(int timeout) throws IOException {
618         BluetoothSocket acceptedSocket;
619         if (mSocketState != SocketState.LISTENING) {
620             throw new IOException("bt socket is not in listen state");
621         }
622         Log.d(TAG, "accept(), timeout (ms):" + timeout);
623         if (timeout > 0) {
624             mSocket.setSoTimeout(timeout);
625         }
626         String RemoteAddr = waitSocketSignal(mSocketIS);
627         if (timeout > 0) {
628             mSocket.setSoTimeout(0);
629         }
630         synchronized (this) {
631             if (mSocketState != SocketState.LISTENING) {
632                 throw new IOException("bt socket is not in listen state");
633             }
634             acceptedSocket = acceptSocket(RemoteAddr);
635             //quick drop the reference of the file handle
636         }
637         return acceptedSocket;
638     }
639 
available()640     /*package*/ int available() throws IOException {
641         if (VDBG) Log.d(TAG, "available: " + mSocketIS);
642         return mSocketIS.available();
643     }
644 
read(byte[] b, int offset, int length)645     /*package*/ int read(byte[] b, int offset, int length) throws IOException {
646         int ret = 0;
647         if (VDBG) Log.d(TAG, "read in:  " + mSocketIS + " len: " + length);
648         if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
649             int bytesToRead = length;
650             if (VDBG) {
651                 Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length
652                         + "mL2capBuffer= " + mL2capBuffer);
653             }
654             if (mL2capBuffer == null) {
655                 createL2capRxBuffer();
656             }
657             if (mL2capBuffer.remaining() == 0) {
658                 if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling...");
659                 if (fillL2capRxBuffer() == -1) {
660                     return -1;
661                 }
662             }
663             if (bytesToRead > mL2capBuffer.remaining()) {
664                 bytesToRead = mL2capBuffer.remaining();
665             }
666             if (VDBG) {
667                 Log.v(TAG, "get(): offset: " + offset
668                         + " bytesToRead: " + bytesToRead);
669             }
670             mL2capBuffer.get(b, offset, bytesToRead);
671             ret = bytesToRead;
672         } else {
673             if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length);
674             ret = mSocketIS.read(b, offset, length);
675         }
676         if (ret < 0) {
677             throw new IOException("bt socket closed, read return: " + ret);
678         }
679         if (VDBG) Log.d(TAG, "read out:  " + mSocketIS + " ret: " + ret);
680         return ret;
681     }
682 
write(byte[] b, int offset, int length)683     /*package*/ int write(byte[] b, int offset, int length) throws IOException {
684 
685         //TODO: Since bindings can exist between the SDU size and the
686         //      protocol, we might need to throw an exception instead of just
687         //      splitting the write into multiple smaller writes.
688         //      Rfcomm uses dynamic allocation, and should not have any bindings
689         //      to the actual message length.
690         if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
691         if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
692             if (length <= mMaxTxPacketSize) {
693                 mSocketOS.write(b, offset, length);
694             } else {
695                 if (DBG) {
696                     Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
697                             + "Packet will be divided into SDU packets of size "
698                             + mMaxTxPacketSize);
699                 }
700                 int tmpOffset = offset;
701                 int bytesToWrite = length;
702                 while (bytesToWrite > 0) {
703                     int tmpLength = (bytesToWrite > mMaxTxPacketSize)
704                             ? mMaxTxPacketSize
705                             : bytesToWrite;
706                     mSocketOS.write(b, tmpOffset, tmpLength);
707                     tmpOffset += tmpLength;
708                     bytesToWrite -= tmpLength;
709                 }
710             }
711         } else {
712             mSocketOS.write(b, offset, length);
713         }
714         // There is no good way to confirm since the entire process is asynchronous anyway
715         if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
716         return length;
717     }
718 
719     @Override
close()720     public void close() throws IOException {
721         Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS
722                 + ", mSocketOS: " + mSocketOS + ", mSocket: " + mSocket + ", mSocketState: "
723                 + mSocketState);
724         if (mSocketState == SocketState.CLOSED) {
725             return;
726         } else {
727             synchronized (this) {
728                 if (mSocketState == SocketState.CLOSED) {
729                     return;
730                 }
731                 mSocketState = SocketState.CLOSED;
732                 if (mSocket != null) {
733                     if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
734                     mSocket.shutdownInput();
735                     mSocket.shutdownOutput();
736                     mSocket.close();
737                     mSocket = null;
738                 }
739                 if (mPfd != null) {
740                     mPfd.close();
741                     mPfd = null;
742                 }
743             }
744         }
745     }
746 
logL2capcocClientConnection( IBluetooth bluetoothProxy, int errCode, long socketConnectionTimeMillis)747     private void logL2capcocClientConnection(
748             IBluetooth bluetoothProxy, int errCode, long socketConnectionTimeMillis) {
749         if (mType != TYPE_L2CAP_LE) {
750             return;
751         }
752         try {
753             final SynchronousResultReceiver recv = SynchronousResultReceiver.get();
754             bluetoothProxy.logL2capcocClientConnection(
755                     mDevice,
756                     mPort,
757                     mAuth,
758                     errCode,
759                     mSocketCreationTimeMillis, // to calculate end to end latency
760                     mSocketCreationLatencyMillis, // latency of the constructor
761                     socketConnectionTimeMillis, // to calculate the latency of connect()
762                     recv);
763             recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
764         } catch (RemoteException | TimeoutException e) {
765             Log.w(TAG, "logL2capcocClientConnection failed due to remote exception");
766         }
767     }
768 
removeChannel()769     /*package */ void removeChannel() {
770     }
771 
getPort()772     /*package */ int getPort() {
773         return mPort;
774     }
775 
getSocketCreationTime()776     /*package */ long getSocketCreationTime() {
777         return mSocketCreationTimeMillis;
778     }
779 
780     /**
781      * Get the maximum supported Transmit packet size for the underlying transport.
782      * Use this to optimize the writes done to the output socket, to avoid sending
783      * half full packets.
784      *
785      * @return the maximum supported Transmit packet size for the underlying transport.
786      */
787     @RequiresNoPermission
getMaxTransmitPacketSize()788     public int getMaxTransmitPacketSize() {
789         return mMaxTxPacketSize;
790     }
791 
792     /**
793      * Get the maximum supported Receive packet size for the underlying transport.
794      * Use this to optimize the reads done on the input stream, as any call to read
795      * will return a maximum of this amount of bytes - or for some transports a
796      * multiple of this value.
797      *
798      * @return the maximum supported Receive packet size for the underlying transport.
799      */
800     @RequiresNoPermission
getMaxReceivePacketSize()801     public int getMaxReceivePacketSize() {
802         return mMaxRxPacketSize;
803     }
804 
805     /**
806      * Get the type of the underlying connection.
807      *
808      * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP}
809      */
810     @RequiresNoPermission
getConnectionType()811     public int getConnectionType() {
812         if (mType == TYPE_L2CAP_LE) {
813             // Treat the LE CoC to be the same type as L2CAP.
814             return TYPE_L2CAP;
815         }
816         return mType;
817     }
818 
819     /**
820      * Change if a SDP entry should be automatically created.
821      * Must be called before calling .bind, for the call to have any effect.
822      *
823      * @param excludeSdp <li>TRUE - do not auto generate SDP record. <li>FALSE - default - auto
824      * generate SPP SDP record.
825      * @hide
826      */
827     @RequiresNoPermission
setExcludeSdp(boolean excludeSdp)828     public void setExcludeSdp(boolean excludeSdp) {
829         mExcludeSdp = excludeSdp;
830     }
831 
832     /**
833      * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This
834      * parameter is used by the BT Controller to set the maximum transmission packet size on this
835      * connection. This function is currently used for testing only.
836      * @hide
837      */
838     @RequiresBluetoothConnectPermission
839     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
requestMaximumTxDataLength()840     public void requestMaximumTxDataLength() throws IOException {
841         if (mDevice == null) {
842             throw new IOException("requestMaximumTxDataLength is called on null device");
843         }
844 
845         try {
846             if (mSocketState == SocketState.CLOSED) {
847                 throw new IOException("socket closed");
848             }
849             IBluetooth bluetoothProxy =
850                     BluetoothAdapter.getDefaultAdapter().getBluetoothService();
851             if (bluetoothProxy == null) {
852                 throw new IOException("Bluetooth is off");
853             }
854 
855             if (DBG) Log.d(TAG, "requestMaximumTxDataLength");
856             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
857             if (socketManager == null) throw new IOException("bt get socket manager failed");
858             socketManager.requestMaximumTxDataLength(mDevice);
859         } catch (RemoteException e) {
860             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
861             throw new IOException("unable to send RPC: " + e.getMessage());
862         }
863     }
864 
865     /** @hide */
getParcelFileDescriptor()866     public ParcelFileDescriptor getParcelFileDescriptor() {
867         return mPfd;
868     }
869 
convertAddr(final byte[] addr)870     private String convertAddr(final byte[] addr) {
871         return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
872                 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
873     }
874 
waitSocketSignal(InputStream is)875     private String waitSocketSignal(InputStream is) throws IOException {
876         byte[] sig = new byte[SOCK_SIGNAL_SIZE];
877         int ret = readAll(is, sig);
878         if (VDBG) {
879             Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE + " bytes signal ret: " + ret);
880         }
881         ByteBuffer bb = ByteBuffer.wrap(sig);
882         /* the struct in native is decorated with __attribute__((packed)), hence this is possible */
883         bb.order(ByteOrder.nativeOrder());
884         int size = bb.getShort();
885         if (size != SOCK_SIGNAL_SIZE) {
886             throw new IOException("Connection failure, wrong signal size: " + size);
887         }
888         byte[] addr = new byte[6];
889         bb.get(addr);
890         int channel = bb.getInt();
891         int status = bb.getInt();
892         mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
893         mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
894         String RemoteAddr = convertAddr(addr);
895         if (VDBG) {
896             Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: "
897                     + RemoteAddr + ", channel: " + channel + ", status: " + status
898                     + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize);
899         }
900         if (status != 0) {
901             throw new IOException("Connection failure, status: " + status);
902         }
903         return RemoteAddr;
904     }
905 
createL2capRxBuffer()906     private void createL2capRxBuffer() {
907         if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
908             // Allocate the buffer to use for reads.
909             if (VDBG) Log.v(TAG, "  Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize);
910             mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]);
911             if (VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining());
912             mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request
913             if (VDBG) {
914                 Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + mL2capBuffer.remaining());
915             }
916         }
917     }
918 
readAll(InputStream is, byte[] b)919     private int readAll(InputStream is, byte[] b) throws IOException {
920         int left = b.length;
921         while (left > 0) {
922             int ret = is.read(b, b.length - left, left);
923             if (ret <= 0) {
924                 throw new IOException("read failed, socket might closed or timeout, read ret: "
925                         + ret);
926             }
927             left -= ret;
928             if (left != 0) {
929                 Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left)
930                         + ", expect size: " + b.length);
931             }
932         }
933         return b.length;
934     }
935 
readInt(InputStream is)936     private int readInt(InputStream is) throws IOException {
937         byte[] ibytes = new byte[4];
938         int ret = readAll(is, ibytes);
939         if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret);
940         ByteBuffer bb = ByteBuffer.wrap(ibytes);
941         bb.order(ByteOrder.nativeOrder());
942         return bb.getInt();
943     }
944 
fillL2capRxBuffer()945     private int fillL2capRxBuffer() throws IOException {
946         mL2capBuffer.rewind();
947         int ret = mSocketIS.read(mL2capBuffer.array());
948         if (ret == -1) {
949             // reached end of stream - return -1
950             mL2capBuffer.limit(0);
951             return -1;
952         }
953         mL2capBuffer.limit(ret);
954         return ret;
955     }
956 
957     @Override
toString()958     public String toString() {
959         return BluetoothUtils.toAnonymizedAddress(mAddress);
960     }
961 }
962