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