• 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.Manifest.permission.BLUETOOTH_CONNECT;
20 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
21 import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
22 
23 import android.annotation.FlaggedApi;
24 import android.annotation.IntDef;
25 import android.annotation.NonNull;
26 import android.annotation.RequiresNoPermission;
27 import android.annotation.RequiresPermission;
28 import android.annotation.SystemApi;
29 import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
30 import android.compat.annotation.UnsupportedAppUsage;
31 import android.content.AttributionSource;
32 import android.net.LocalSocket;
33 import android.os.Build;
34 import android.os.ParcelFileDescriptor;
35 import android.os.ParcelUuid;
36 import android.os.RemoteException;
37 import android.util.Log;
38 
39 import com.android.bluetooth.flags.Flags;
40 
41 import java.io.Closeable;
42 import java.io.FileDescriptor;
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.io.OutputStream;
46 import java.lang.annotation.Retention;
47 import java.lang.annotation.RetentionPolicy;
48 import java.nio.ByteBuffer;
49 import java.nio.ByteOrder;
50 import java.util.Arrays;
51 import java.util.Locale;
52 import java.util.UUID;
53 
54 /**
55  * A connected or connecting Bluetooth socket.
56  *
57  * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets: {@link java.net.Socket}
58  * and {@link java.net.ServerSocket}. On the server side, use a {@link BluetoothServerSocket} to
59  * create a listening server socket. When a connection is accepted by the {@link
60  * BluetoothServerSocket}, it will return a new {@link BluetoothSocket} to manage the connection. On
61  * the client side, use a single {@link BluetoothSocket} to both initiate an outgoing connection and
62  * to manage the connection.
63  *
64  * <p>The most common type of Bluetooth socket is RFCOMM, which is the type supported by the Android
65  * APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth. It is also known as
66  * the Serial Port Profile (SPP).
67  *
68  * <p>To create a {@link BluetoothSocket} for connecting to a known device, use {@link
69  * BluetoothDevice#createRfcommSocketToServiceRecord
70  * BluetoothDevice.createRfcommSocketToServiceRecord()}. Then call {@link #connect()} to attempt a
71  * connection to the remote device. This call will block until a connection is established or the
72  * connection fails.
73  *
74  * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the {@link
75  * BluetoothServerSocket} documentation.
76  *
77  * <p>Once the socket is connected, whether initiated as a client or accepted as a server, open the
78  * IO streams by calling {@link #getInputStream} and {@link #getOutputStream} in order to retrieve
79  * {@link java.io.InputStream} and {@link java.io.OutputStream} objects, respectively, which are
80  * automatically connected to the socket.
81  *
82  * <p>{@link BluetoothSocket} is thread safe. In particular, {@link #close} will always immediately
83  * abort ongoing operations and close the socket.
84  *
85  * <p><div class="special reference">
86  *
87  * <h3>Developer Guides</h3>
88  *
89  * <p>For more information about using Bluetooth, read the <a
90  * href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide. </div>
91  *
92  * @see BluetoothServerSocket
93  * @see java.io.InputStream
94  * @see java.io.OutputStream
95  */
96 public final class BluetoothSocket implements Closeable {
97     private static final String TAG = BluetoothSocket.class.getSimpleName();
98 
99     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
100     private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
101 
102     /** @hide */
103     public static final int MAX_RFCOMM_CHANNEL = 30;
104 
105     /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF;
106 
107     /** RFCOMM socket */
108     public static final int TYPE_RFCOMM = 1;
109 
110     /** SCO socket */
111     public static final int TYPE_SCO = 2;
112 
113     /** L2CAP socket */
114     public static final int TYPE_L2CAP = 3;
115 
116     /**
117      * L2CAP socket on BR/EDR transport
118      *
119      * <p>To be removed once Flags.FLAG_SOCKET_SETTINGS_API is removed
120      *
121      * @hide
122      */
123     public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP;
124 
125     /**
126      * L2CAP socket on LE transport
127      *
128      * <p>To be removed once Flags.FLAG_SOCKET_SETTINGS_API is removed
129      *
130      * @hide
131      */
132     public static final int TYPE_L2CAP_LE = 4;
133 
134     /** L2CAP socket on LE transport */
135     @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
136     public static final int TYPE_LE = 4;
137 
138     /** @hide */
139     @IntDef(
140             prefix = {"BluetoothSocket.TYPE_"},
141             value = {
142                 BluetoothSocket.TYPE_RFCOMM,
143                 BluetoothSocket.TYPE_SCO,
144                 BluetoothSocket.TYPE_L2CAP,
145                 BluetoothSocket.TYPE_LE,
146             })
147     @Retention(RetentionPolicy.SOURCE)
148     public @interface SocketType {}
149 
150     /*package*/ static final int EBADFD = 77;
151 
152     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
153     /*package*/ static final int EADDRINUSE = 98;
154 
155     /*package*/ static final int SEC_FLAG_ENCRYPT = 1;
156     /*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
157     /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2;
158     /*package*/ static final int SEC_FLAG_AUTH_PITM = 1 << 3;
159     /*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4;
160 
161     /*package*/ static final String DEFAULT_SOCKET_NAME = "default_name";
162 
163     private final int mType; /* one of TYPE_RFCOMM etc */
164     private BluetoothDevice mDevice; /* remote device */
165     private String mAddress; /* remote address */
166     private final boolean mAuth;
167     private final boolean mEncrypt;
168     private final BluetoothInputStream mInputStream;
169     private final BluetoothOutputStream mOutputStream;
170     private final ParcelUuid mUuid;
171     private final int mDataPath;
172     private final String mSocketName;
173     private final long mHubId;
174     private final long mEndpointId;
175     private final int mMaximumPacketSize;
176 
177     /** when true no SPP SDP record will be created */
178     private boolean mExcludeSdp = false;
179 
180     /** when true Person-in-the-middle protection will be enabled */
181     private boolean mAuthPitm = false;
182 
183     /** Minimum 16 digit pin for sec mode 2 connections */
184     private boolean mMin16DigitPin = false;
185 
186     @UnsupportedAppUsage(publicAlternatives = "Use {@link BluetoothSocket} public API instead.")
187     private ParcelFileDescriptor mPfd;
188 
189     @UnsupportedAppUsage private LocalSocket mSocket;
190     private InputStream mSocketIS;
191     private OutputStream mSocketOS;
192     @UnsupportedAppUsage private int mPort; /* RFCOMM channel or L2CAP psm */
193     private String mServiceName;
194 
195     private static final int SOCK_CONNECTION_SIGNAL_SIZE = 44;
196     private static final long INVALID_SOCKET_ID = 0;
197     private static final int SOCK_ACCEPT_SIGNAL_SIZE = 4;
198 
199     private ByteBuffer mL2capBuffer = null;
200     private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
201     private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received.
202     private ParcelUuid mConnectionUuid;
203     private long mSocketId; // Socket ID in connected state.
204 
205     private long mSocketCreationTimeNanos = 0;
206     private long mSocketCreationLatencyNanos = 0;
207 
208     private enum SocketState {
209         INIT,
210         CONNECTED,
211         LISTENING,
212         CLOSED,
213     }
214 
215     /** prevents all native calls after destroyNative() */
216     private volatile SocketState mSocketState;
217 
218     /** protects mSocketState */
219     // private final ReentrantReadWriteLock mLock;
220 
221     /**
222      * Construct a BluetoothSocket.
223      *
224      * @param type type of socket
225      * @param auth require the remote device to be authenticated
226      * @param encrypt require the connection to be encrypted
227      * @param port remote port
228      * @param uuid SDP uuid
229      * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
230      */
231     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS})
BluetoothSocket(int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid)232     /*package*/ BluetoothSocket(int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid)
233             throws IOException {
234         this(type, auth, encrypt, port, uuid, false, false);
235     }
236 
237     /**
238      * Construct a BluetoothSocket.
239      *
240      * @param type type of socket
241      * @param auth require the remote device to be authenticated
242      * @param encrypt require the connection to be encrypted
243      * @param port remote port
244      * @param uuid SDP uuid
245      * @param pitm enforce person-in-the-middle protection.
246      * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
247      * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
248      */
249     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS})
BluetoothSocket( int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid, boolean pitm, boolean min16DigitPin)250     /*package*/ BluetoothSocket(
251             int type,
252             boolean auth,
253             boolean encrypt,
254             int port,
255             ParcelUuid uuid,
256             boolean pitm,
257             boolean min16DigitPin)
258             throws IOException {
259         this(type, auth, encrypt, port, uuid, pitm, min16DigitPin, 0, DEFAULT_SOCKET_NAME, 0, 0, 0);
260     }
261 
262     /**
263      * Construct a BluetoothSocket.
264      *
265      * @param type type of socket
266      * @param auth require the remote device to be authenticated
267      * @param encrypt require the connection to be encrypted
268      * @param port remote port
269      * @param uuid SDP uuid
270      * @param pitm enforce person-in-the-middle protection.
271      * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
272      * @param dataPath data path used for this socket
273      * @param socketName user-friendly name for this socket
274      * @param hubId ID of the hub to which the end point belongs
275      * @param endpointId ID of the endpoint within the hub that is associated with this socket
276      * @param maximumPacketSize The maximum size (in bytes) of a single data packet
277      * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
278      */
279     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS})
BluetoothSocket( int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid, boolean pitm, boolean min16DigitPin, int dataPath, @NonNull String socketName, long hubId, long endpointId, int maximumPacketSize)280     /*package*/ BluetoothSocket(
281             int type,
282             boolean auth,
283             boolean encrypt,
284             int port,
285             ParcelUuid uuid,
286             boolean pitm,
287             boolean min16DigitPin,
288             int dataPath,
289             @NonNull String socketName,
290             long hubId,
291             long endpointId,
292             int maximumPacketSize)
293             throws IOException {
294         if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
295         mSocketCreationTimeNanos = System.nanoTime();
296         if (type == BluetoothSocket.TYPE_RFCOMM
297                 && uuid == null
298                 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
299             if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
300                 throw new IOException("Invalid RFCOMM channel: " + port);
301             }
302         }
303         if (uuid != null) {
304             mUuid = uuid;
305         } else {
306             mUuid = new ParcelUuid(new UUID(0, 0));
307         }
308         mType = type;
309         mAuth = auth;
310         mAuthPitm = pitm;
311         mMin16DigitPin = min16DigitPin;
312         mEncrypt = encrypt;
313         mPort = port;
314         // this constructor to be called only from BluetoothServerSocket
315         mDevice = null;
316         mDataPath = dataPath;
317         mSocketName = socketName;
318         mHubId = hubId;
319         mEndpointId = endpointId;
320         mMaximumPacketSize = maximumPacketSize;
321 
322         mSocketState = SocketState.INIT;
323 
324         mAddress = BluetoothAdapter.getDefaultAdapter().getAddress();
325 
326         mInputStream = new BluetoothInputStream(this);
327         mOutputStream = new BluetoothOutputStream(this);
328         mSocketCreationLatencyNanos = System.nanoTime() - mSocketCreationTimeNanos;
329     }
330 
331     /**
332      * Construct a BluetoothSocket.
333      *
334      * @param device remote device that this socket can connect to
335      * @param type type of socket
336      * @param auth require the remote device to be authenticated
337      * @param encrypt require the connection to be encrypted
338      * @param port remote port
339      * @param uuid SDP uuid
340      * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
341      */
BluetoothSocket( BluetoothDevice device, int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid)342     /*package*/ BluetoothSocket(
343             BluetoothDevice device,
344             int type,
345             boolean auth,
346             boolean encrypt,
347             int port,
348             ParcelUuid uuid)
349             throws IOException {
350         this(device, type, auth, encrypt, port, uuid, false, false);
351     }
352 
353     /**
354      * Construct a BluetoothSocket.
355      *
356      * @param device remote device that this socket can connect to
357      * @param type type of socket
358      * @param auth require the remote device to be authenticated
359      * @param encrypt require the connection to be encrypted
360      * @param port remote port
361      * @param uuid SDP uuid
362      * @param pitm enforce person-in-the-middle protection.
363      * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
364      * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
365      */
BluetoothSocket( @onNull BluetoothDevice device, int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid, boolean pitm, boolean min16DigitPin)366     /*package*/ BluetoothSocket(
367             @NonNull BluetoothDevice device,
368             int type,
369             boolean auth,
370             boolean encrypt,
371             int port,
372             ParcelUuid uuid,
373             boolean pitm,
374             boolean min16DigitPin)
375             throws IOException {
376         this(
377                 device,
378                 type,
379                 auth,
380                 encrypt,
381                 port,
382                 uuid,
383                 pitm,
384                 min16DigitPin,
385                 0,
386                 DEFAULT_SOCKET_NAME,
387                 0,
388                 0,
389                 0);
390     }
391 
392     /**
393      * Construct a BluetoothSocket.
394      *
395      * @param device remote device that this socket can connect to
396      * @param type type of socket
397      * @param auth require the remote device to be authenticated
398      * @param encrypt require the connection to be encrypted
399      * @param port remote port
400      * @param uuid SDP uuid
401      * @param pitm enforce person-in-the-middle protection.
402      * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
403      * @param dataPath data path used for this socket
404      * @param socketName user-friendly name for this socket
405      * @param hubId ID of the hub to which the end point belongs
406      * @param endpointId ID of the endpoint within the hub that is associated with this socket
407      * @param maximumPacketSize The maximum size (in bytes) of a single data packet
408      * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
409      */
BluetoothSocket( @onNull BluetoothDevice device, int type, boolean auth, boolean encrypt, int port, ParcelUuid uuid, boolean pitm, boolean min16DigitPin, int dataPath, @NonNull String socketName, long hubId, long endpointId, int maximumPacketSize)410     /*package*/ BluetoothSocket(
411             @NonNull BluetoothDevice device,
412             int type,
413             boolean auth,
414             boolean encrypt,
415             int port,
416             ParcelUuid uuid,
417             boolean pitm,
418             boolean min16DigitPin,
419             int dataPath,
420             @NonNull String socketName,
421             long hubId,
422             long endpointId,
423             int maximumPacketSize)
424             throws IOException {
425         if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
426         mSocketCreationTimeNanos = System.nanoTime();
427         if (type == BluetoothSocket.TYPE_RFCOMM
428                 && uuid == null
429                 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
430             if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
431                 throw new IOException("Invalid RFCOMM channel: " + port);
432             }
433         }
434         if (uuid != null) {
435             mUuid = uuid;
436         } else {
437             mUuid = new ParcelUuid(new UUID(0, 0));
438         }
439         mType = type;
440         mAuth = auth;
441         mAuthPitm = pitm;
442         mMin16DigitPin = min16DigitPin;
443         mEncrypt = encrypt;
444         mDevice = device;
445         mPort = port;
446         mDataPath = dataPath;
447         mSocketName = socketName;
448         mHubId = hubId;
449         mEndpointId = endpointId;
450         mMaximumPacketSize = maximumPacketSize;
451 
452         mSocketState = SocketState.INIT;
453 
454         // Remote socket
455         mAddress = device.getAddress();
456 
457         mInputStream = new BluetoothInputStream(this);
458         mOutputStream = new BluetoothOutputStream(this);
459         mSocketCreationLatencyNanos = System.nanoTime() - mSocketCreationTimeNanos;
460     }
461 
462     /**
463      * Creates a BluetoothSocket from a {@link ParcelFileDescriptor}. This is used for when the
464      * underlying mPfd is transferred to a separate process (e.g. over a binder), and the socket
465      * must be reconstructed.
466      *
467      * <p>The socket should already be connected in this case, so {@link #connect()} should not be
468      * called.
469      *
470      * @param pfd is the {@link ParcelFileDescriptor} for an already connected BluetoothSocket
471      * @param device is the remote {@link BluetoothDevice} that this socket is connected to
472      * @param uuid is the service ID that this RFCOMM connection is using
473      * @throws IOException if socket creation fails.
474      */
createSocketFromOpenFd( ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid)475     /*package*/ static BluetoothSocket createSocketFromOpenFd(
476             ParcelFileDescriptor pfd, BluetoothDevice device, ParcelUuid uuid) throws IOException {
477         BluetoothSocket bluetoothSocket =
478                 new BluetoothSocket(device, TYPE_RFCOMM, true, true, -1, uuid);
479 
480         bluetoothSocket.mPfd = pfd;
481         bluetoothSocket.mSocket = new LocalSocket(pfd.getFileDescriptor());
482         bluetoothSocket.mSocketIS = bluetoothSocket.mSocket.getInputStream();
483         bluetoothSocket.mSocketOS = bluetoothSocket.mSocket.getOutputStream();
484         bluetoothSocket.mSocketState = SocketState.CONNECTED;
485 
486         return bluetoothSocket;
487     }
488 
BluetoothSocket(BluetoothSocket s)489     private BluetoothSocket(BluetoothSocket s) {
490         if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType);
491         mUuid = s.mUuid;
492         mType = s.mType;
493         mAuth = s.mAuth;
494         mEncrypt = s.mEncrypt;
495         mPort = s.mPort;
496         mInputStream = new BluetoothInputStream(this);
497         mOutputStream = new BluetoothOutputStream(this);
498         mMaxRxPacketSize = s.mMaxRxPacketSize;
499         mMaxTxPacketSize = s.mMaxTxPacketSize;
500         mConnectionUuid = s.mConnectionUuid;
501         mSocketId = s.mSocketId;
502 
503         mServiceName = s.mServiceName;
504         mExcludeSdp = s.mExcludeSdp;
505         mAuthPitm = s.mAuthPitm;
506         mMin16DigitPin = s.mMin16DigitPin;
507         mDataPath = s.mDataPath;
508         mSocketName = s.mSocketName;
509         mHubId = s.mHubId;
510         mEndpointId = s.mEndpointId;
511         mMaximumPacketSize = s.mMaximumPacketSize;
512         mSocketCreationTimeNanos = s.mSocketCreationTimeNanos;
513         mSocketCreationLatencyNanos = s.mSocketCreationLatencyNanos;
514     }
515 
acceptSocket(String remoteAddr)516     private BluetoothSocket acceptSocket(String remoteAddr) throws IOException {
517         BluetoothSocket as = new BluetoothSocket(this);
518         as.mSocketState = SocketState.CONNECTED;
519         FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
520         if (DBG) Log.d(TAG, "acceptSocket: socket fd passed by stack fds:" + Arrays.toString(fds));
521         if (fds == null || fds.length != 1) {
522             Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds));
523             as.close();
524             throw new IOException("bt socket accept failed");
525         }
526 
527         as.mPfd = ParcelFileDescriptor.dup(fds[0]);
528         as.mSocket = new LocalSocket(fds[0]);
529         as.mSocketIS = as.mSocket.getInputStream();
530         as.mSocketOS = as.mSocket.getOutputStream();
531         as.mAddress = remoteAddr;
532         as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr);
533         return as;
534     }
535 
536     /** @hide */
537     @Override
538     @SuppressWarnings("Finalize") // TODO(b/314811467)
finalize()539     protected void finalize() throws Throwable {
540         try {
541             close();
542         } finally {
543             super.finalize();
544         }
545     }
546 
getSecurityFlags()547     private int getSecurityFlags() {
548         int flags = 0;
549         if (mAuth) {
550             flags |= SEC_FLAG_AUTH;
551         }
552         if (mEncrypt) {
553             flags |= SEC_FLAG_ENCRYPT;
554         }
555         if (mExcludeSdp) {
556             flags |= BTSOCK_FLAG_NO_SDP;
557         }
558         if (mAuthPitm) {
559             flags |= SEC_FLAG_AUTH_PITM;
560         }
561         if (mMin16DigitPin) {
562             flags |= SEC_FLAG_AUTH_16_DIGIT;
563         }
564         return flags;
565     }
566 
567     /**
568      * Get the remote device this socket is connecting, or connected, to.
569      *
570      * @return remote device
571      */
572     @RequiresNoPermission
getRemoteDevice()573     public BluetoothDevice getRemoteDevice() {
574         return mDevice;
575     }
576 
577     /**
578      * Get the input stream associated with this socket.
579      *
580      * <p>The input stream will be returned even if the socket is not yet connected, but operations
581      * on that stream will throw IOException until the associated socket is connected.
582      *
583      * @return InputStream
584      */
585     @RequiresNoPermission
getInputStream()586     public InputStream getInputStream() throws IOException {
587         return mInputStream;
588     }
589 
590     /**
591      * Get the output stream associated with this socket.
592      *
593      * <p>The output stream will be returned even if the socket is not yet connected, but operations
594      * on that stream will throw IOException until the associated socket is connected.
595      *
596      * @return OutputStream
597      */
598     @RequiresNoPermission
getOutputStream()599     public OutputStream getOutputStream() throws IOException {
600         return mOutputStream;
601     }
602 
603     /**
604      * Get the connection status of this socket, ie, whether there is an active connection with
605      * remote device.
606      *
607      * @return true if connected false if not connected
608      */
609     @RequiresNoPermission
isConnected()610     public boolean isConnected() {
611         return mSocketState == SocketState.CONNECTED;
612     }
613 
setServiceName(String name)614     /*package*/ void setServiceName(String name) {
615         mServiceName = name;
616     }
617 
isAuth()618     /*package*/ boolean isAuth() {
619         return mAuth;
620     }
621 
622     /**
623      * Attempt to connect to a remote device.
624      *
625      * <p>This method will block until a connection is made or the connection fails. If this method
626      * returns without an exception then this socket is now connected.
627      *
628      * <p>Creating new connections to remote Bluetooth devices should not be attempted while device
629      * discovery is in progress. Device discovery is a heavyweight procedure on the Bluetooth
630      * adapter and will significantly slow a device connection. Use {@link
631      * BluetoothAdapter#cancelDiscovery()} to cancel an ongoing discovery. Discovery is not managed
632      * by the Activity, but is run as a system service, so an application should always call {@link
633      * BluetoothAdapter#cancelDiscovery()} even if it did not directly request a discovery, just to
634      * be sure.
635      *
636      * <p>{@link #close} can be used to abort this call from another thread.
637      *
638      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
639      * {@code mDataPath} is different from {@link BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}.
640      *
641      * @throws BluetoothSocketException in case of failure, with the corresponding error code.
642      * @throws IOException for other errors (eg: InputStream read failures etc.).
643      */
644     @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
645     @RequiresBluetoothConnectPermission
646     @RequiresPermission(
647             allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
648             conditional = true)
connect()649     public void connect() throws IOException {
650         IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
651         long socketConnectionTimeNanos = System.nanoTime();
652         if (bluetoothProxy == null) {
653             throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE);
654         }
655         try {
656             if (mDevice == null) {
657                 throw new BluetoothSocketException(BluetoothSocketException.NULL_DEVICE);
658             }
659             if (mSocketState == SocketState.CLOSED) {
660                 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
661             }
662 
663             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
664             if (socketManager == null) {
665                 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE);
666             }
667             if (Flags.socketSettingsApi()) {
668                 if (mDataPath == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
669                     mPfd =
670                             socketManager.connectSocket(
671                                     mDevice, mType, mUuid, mPort, getSecurityFlags());
672                 } else {
673                     mPfd =
674                             socketManager.connectSocketWithOffload(
675                                     mDevice,
676                                     mType,
677                                     mUuid,
678                                     mPort,
679                                     getSecurityFlags(),
680                                     mDataPath,
681                                     mSocketName,
682                                     mHubId,
683                                     mEndpointId,
684                                     mMaximumPacketSize);
685                 }
686             } else {
687                 mPfd =
688                         socketManager.connectSocket(
689                                 mDevice, mType, mUuid, mPort, getSecurityFlags());
690             }
691             synchronized (this) {
692                 Log.i(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
693                 if (mSocketState == SocketState.CLOSED) {
694                     throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
695                 }
696                 if (mPfd == null) {
697                     throw new BluetoothSocketException(
698                             BluetoothSocketException.UNIX_FILE_SOCKET_CREATION_FAILURE);
699                 }
700                 FileDescriptor fd = mPfd.getFileDescriptor();
701                 mSocket = new LocalSocket(fd);
702                 mSocketIS = mSocket.getInputStream();
703                 mSocketOS = mSocket.getOutputStream();
704             }
705             int channel = readInt(mSocketIS);
706             if (channel == 0) {
707                 int errCode = (int) mSocketIS.read();
708                 throw new BluetoothSocketException(errCode);
709             }
710             if (channel < 0) {
711                 throw new BluetoothSocketException(
712                         BluetoothSocketException.SOCKET_CONNECTION_FAILURE);
713             }
714             mPort = channel;
715             waitSocketSignal(mSocketIS);
716             synchronized (this) {
717                 if (mSocketState == SocketState.CLOSED) {
718                     throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
719                 }
720                 mSocketState = SocketState.CONNECTED;
721                 Log.i(TAG, "connect(), socket connected. mPort=" + mPort);
722             }
723         } catch (BluetoothSocketException e) {
724             SocketMetrics.logSocketConnect(
725                     e.getErrorCode(),
726                     socketConnectionTimeNanos,
727                     mType,
728                     mDevice,
729                     mPort,
730                     mAuth,
731                     mSocketCreationTimeNanos,
732                     mSocketCreationLatencyNanos);
733             throw e;
734         } catch (RemoteException e) {
735             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
736             SocketMetrics.logSocketConnect(
737                     BluetoothSocketException.RPC_FAILURE,
738                     socketConnectionTimeNanos,
739                     mType,
740                     mDevice,
741                     mPort,
742                     mAuth,
743                     mSocketCreationTimeNanos,
744                     mSocketCreationLatencyNanos);
745             throw new BluetoothSocketException(
746                     BluetoothSocketException.RPC_FAILURE, "unable to send RPC: " + e.getMessage());
747         }
748         SocketMetrics.logSocketConnect(
749                 SocketMetrics.SOCKET_NO_ERROR,
750                 socketConnectionTimeNanos,
751                 mType,
752                 mDevice,
753                 mPort,
754                 mAuth,
755                 mSocketCreationTimeNanos,
756                 mSocketCreationLatencyNanos);
757     }
758 
759     /**
760      * Currently returns unix errno instead of throwing IOException, so that BluetoothAdapter can
761      * check the error code for EADDRINUSE
762      */
763     @RequiresBluetoothConnectPermission
764     @RequiresPermission(BLUETOOTH_CONNECT)
bindListen()765     /*package*/ int bindListen() {
766         int ret;
767         if (mSocketState == SocketState.CLOSED) return EBADFD;
768         IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
769         if (bluetoothProxy == null) {
770             Log.e(TAG, "bindListen fail, reason: bluetooth is off");
771             return -1;
772         }
773         try {
774             if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType);
775             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
776             if (socketManager == null) {
777                 Log.e(TAG, "bindListen() bt get socket manager failed");
778                 return -1;
779             }
780             mPfd =
781                     socketManager.createSocketChannel(
782                             mType, mServiceName, mUuid, mPort, getSecurityFlags());
783         } catch (RemoteException e) {
784             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
785             return -1;
786         }
787 
788         // read out port number
789         try {
790             synchronized (this) {
791                 if (DBG) {
792                     Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
793                 }
794                 if (mSocketState != SocketState.INIT) return EBADFD;
795                 if (mPfd == null) return -1;
796                 FileDescriptor fd = mPfd.getFileDescriptor();
797                 if (fd == null) {
798                     Log.e(TAG, "bindListen(), null file descriptor");
799                     return -1;
800                 }
801 
802                 if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket");
803                 mSocket = new LocalSocket(fd);
804                 if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()");
805                 mSocketIS = mSocket.getInputStream();
806                 mSocketOS = mSocket.getOutputStream();
807             }
808             if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
809             int channel = readInt(mSocketIS);
810             synchronized (this) {
811                 if (mSocketState == SocketState.INIT) {
812                     mSocketState = SocketState.LISTENING;
813                 }
814             }
815             if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort);
816             if (mPort <= -1) {
817                 mPort = channel;
818             }
819             ret = 0;
820         } catch (IOException e) {
821             if (mPfd != null) {
822                 try {
823                     mPfd.close();
824                 } catch (IOException e1) {
825                     Log.e(TAG, "bindListen, close mPfd: " + e1);
826                 }
827                 mPfd = null;
828             }
829             Log.e(TAG, "bindListen, fail to get port number, exception: " + e);
830             return -1;
831         }
832         return ret;
833     }
834 
835     /**
836      * Currently returns unix errno instead of throwing IOException, so that BluetoothAdapter can
837      * check the error code for EADDRINUSE
838      */
839     @RequiresBluetoothConnectPermission
840     @RequiresPermission(
841             allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
842             conditional = true)
bindListenWithOffload()843     /*package*/ int bindListenWithOffload() {
844         int ret;
845         if (mSocketState == SocketState.CLOSED) return EBADFD;
846         IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
847         if (bluetoothProxy == null) {
848             Log.e(TAG, "bindListenWithOffload() fail, reason: bluetooth is off");
849             return -1;
850         }
851         try {
852             if (DBG) Log.d(TAG, "bindListenWithOffload(): mPort=" + mPort + ", mType=" + mType);
853             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
854             if (socketManager == null) {
855                 Log.e(TAG, "bindListenWithOffload() bt get socket manager failed");
856                 return -1;
857             }
858             mPfd =
859                     socketManager.createSocketChannelWithOffload(
860                             mType,
861                             mServiceName,
862                             mUuid,
863                             mPort,
864                             getSecurityFlags(),
865                             mDataPath,
866                             mSocketName,
867                             mHubId,
868                             mEndpointId,
869                             mMaximumPacketSize);
870         } catch (RemoteException e) {
871             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
872             return -1;
873         }
874 
875         // read out port number
876         try {
877             synchronized (this) {
878                 if (DBG) {
879                     Log.d(
880                             TAG,
881                             "bindListenWithOffload(), SocketState: "
882                                     + mSocketState
883                                     + ", mPfd: "
884                                     + mPfd);
885                 }
886                 if (mSocketState != SocketState.INIT) return EBADFD;
887                 if (mPfd == null) return -1;
888                 FileDescriptor fd = mPfd.getFileDescriptor();
889                 if (fd == null) {
890                     Log.e(TAG, "bindListenWithOffload(), null file descriptor");
891                     return -1;
892                 }
893 
894                 if (DBG) Log.d(TAG, "bindListenWithOffload(), Create LocalSocket");
895                 mSocket = new LocalSocket(fd);
896                 if (DBG) Log.d(TAG, "bindListenWithOffload(), new LocalSocket.getInputStream()");
897                 mSocketIS = mSocket.getInputStream();
898                 mSocketOS = mSocket.getOutputStream();
899             }
900             if (DBG) Log.d(TAG, "bindListenWithOffload(), readInt mSocketIS: " + mSocketIS);
901             int channel = readInt(mSocketIS);
902             synchronized (this) {
903                 if (mSocketState == SocketState.INIT) {
904                     mSocketState = SocketState.LISTENING;
905                 }
906             }
907             if (DBG) Log.d(TAG, "bindListenWithOffload(): channel=" + channel + ", mPort=" + mPort);
908             if (mPort <= -1) {
909                 mPort = channel;
910             }
911             ret = 0;
912         } catch (IOException e) {
913             if (mPfd != null) {
914                 try {
915                     mPfd.close();
916                 } catch (IOException e1) {
917                     Log.e(TAG, "bindListenWithOffload, close mPfd: " + e1);
918                 }
919                 mPfd = null;
920             }
921             Log.e(TAG, "bindListenWithOffload, fail to get port number, exception: " + e);
922             return -1;
923         }
924         return ret;
925     }
926 
accept(int timeout)927     /*package*/ BluetoothSocket accept(int timeout) throws IOException {
928         BluetoothSocket acceptedSocket;
929         if (mSocketState != SocketState.LISTENING) {
930             throw new IOException("bt socket is not in listen state");
931         }
932         Log.d(TAG, "accept(), timeout (ms):" + timeout);
933         if (timeout > 0) {
934             mSocket.setSoTimeout(timeout);
935         }
936         sendSocketAcceptSignal(mSocketOS, true);
937         String RemoteAddr;
938         try {
939             RemoteAddr = waitSocketSignal(mSocketIS);
940         } finally {
941             sendSocketAcceptSignal(mSocketOS, false);
942         }
943         if (timeout > 0) {
944             mSocket.setSoTimeout(0);
945         }
946         synchronized (this) {
947             if (mSocketState != SocketState.LISTENING) {
948                 throw new IOException("bt socket is not in listen state");
949             }
950             acceptedSocket = acceptSocket(RemoteAddr);
951             // quick drop the reference of the file handle
952         }
953         return acceptedSocket;
954     }
955 
available()956     /*package*/ int available() throws IOException {
957         if (VDBG) Log.d(TAG, "available: " + mSocketIS);
958         return mSocketIS.available();
959     }
960 
read(byte[] b, int offset, int length)961     /*package*/ int read(byte[] b, int offset, int length) throws IOException {
962         int ret = 0;
963         if (VDBG) Log.d(TAG, "read in:  " + mSocketIS + " len: " + length);
964         if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
965             int bytesToRead = length;
966             if (VDBG) {
967                 Log.v(
968                         TAG,
969                         "l2cap: read(): offset: "
970                                 + offset
971                                 + " length:"
972                                 + length
973                                 + "mL2capBuffer= "
974                                 + mL2capBuffer);
975             }
976             if (mL2capBuffer == null) {
977                 createL2capRxBuffer();
978             }
979             if (mL2capBuffer.remaining() == 0) {
980                 if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling...");
981                 if (fillL2capRxBuffer() == -1) {
982                     Log.d(TAG, "socket EOF, returning -1");
983                     mSocketState = SocketState.CLOSED;
984                     return -1;
985                 }
986             }
987             if (bytesToRead > mL2capBuffer.remaining()) {
988                 bytesToRead = mL2capBuffer.remaining();
989             }
990             if (VDBG) {
991                 Log.v(TAG, "get(): offset: " + offset + " bytesToRead: " + bytesToRead);
992             }
993             mL2capBuffer.get(b, offset, bytesToRead);
994             ret = bytesToRead;
995         } else {
996             if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length);
997             ret = mSocketIS.read(b, offset, length);
998         }
999         if (ret < 0) {
1000             mSocketState = SocketState.CLOSED;
1001             throw new IOException("bt socket closed, read return: " + ret);
1002         }
1003         if (VDBG) Log.d(TAG, "read out:  " + mSocketIS + " ret: " + ret);
1004         return ret;
1005     }
1006 
write(byte[] b, int offset, int length)1007     /*package*/ int write(byte[] b, int offset, int length) throws IOException {
1008 
1009         // TODO: Since bindings can exist between the SDU size and the
1010         //      protocol, we might need to throw an exception instead of just
1011         //      splitting the write into multiple smaller writes.
1012         //      Rfcomm uses dynamic allocation, and should not have any bindings
1013         //      to the actual message length.
1014         if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
1015         if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
1016             if (length <= mMaxTxPacketSize) {
1017                 mSocketOS.write(b, offset, length);
1018             } else {
1019                 if (DBG) {
1020                     Log.w(
1021                             TAG,
1022                             "WARNING: Write buffer larger than L2CAP packet size!\n"
1023                                     + "Packet will be divided into SDU packets of size "
1024                                     + mMaxTxPacketSize);
1025                 }
1026                 int tmpOffset = offset;
1027                 int bytesToWrite = length;
1028                 while (bytesToWrite > 0) {
1029                     int tmpLength =
1030                             (bytesToWrite > mMaxTxPacketSize) ? mMaxTxPacketSize : bytesToWrite;
1031                     mSocketOS.write(b, tmpOffset, tmpLength);
1032                     tmpOffset += tmpLength;
1033                     bytesToWrite -= tmpLength;
1034                 }
1035             }
1036         } else {
1037             mSocketOS.write(b, offset, length);
1038         }
1039         // There is no good way to confirm since the entire process is asynchronous anyway
1040         if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
1041         return length;
1042     }
1043 
1044     @Override
close()1045     public void close() throws IOException {
1046         Log.d(
1047                 TAG,
1048                 "close() this: "
1049                         + this
1050                         + ", channel: "
1051                         + mPort
1052                         + ", mSocketIS: "
1053                         + mSocketIS
1054                         + ", mSocketOS: "
1055                         + mSocketOS
1056                         + ", mSocket: "
1057                         + mSocket
1058                         + ", mSocketState: "
1059                         + mSocketState);
1060         if (mSocketState == SocketState.CLOSED) {
1061             return;
1062         } else {
1063             synchronized (this) {
1064                 if (mSocketState == SocketState.CLOSED) {
1065                     return;
1066                 }
1067                 mSocketState = SocketState.CLOSED;
1068                 if (mSocket != null) {
1069                     if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
1070                     mSocket.shutdownInput();
1071                     mSocket.shutdownOutput();
1072                     mSocket.close();
1073                     mSocket = null;
1074                 }
1075                 if (mPfd != null) {
1076                     mPfd.close();
1077                     mPfd = null;
1078                 }
1079                 mConnectionUuid = null;
1080                 mSocketId = INVALID_SOCKET_ID;
1081             }
1082         }
1083     }
1084 
removeChannel()1085     /*package */ void removeChannel() {}
1086 
getPort()1087     /*package */ int getPort() {
1088         return mPort;
1089     }
1090 
getSocketCreationTime()1091     /*package */ long getSocketCreationTime() {
1092         return mSocketCreationTimeNanos;
1093     }
1094 
1095     /**
1096      * Get the maximum supported Transmit packet size for the underlying transport. Use this to
1097      * optimize the writes done to the output socket, to avoid sending half full packets.
1098      *
1099      * @return the maximum supported Transmit packet size for the underlying transport.
1100      */
1101     @RequiresNoPermission
getMaxTransmitPacketSize()1102     public int getMaxTransmitPacketSize() {
1103         return mMaxTxPacketSize;
1104     }
1105 
1106     /**
1107      * Get the maximum supported Receive packet size for the underlying transport. Use this to
1108      * optimize the reads done on the input stream, as any call to read will return a maximum of
1109      * this amount of bytes - or for some transports a multiple of this value.
1110      *
1111      * @return the maximum supported Receive packet size for the underlying transport.
1112      */
1113     @RequiresNoPermission
getMaxReceivePacketSize()1114     public int getMaxReceivePacketSize() {
1115         return mMaxRxPacketSize;
1116     }
1117 
1118     /**
1119      * Get the type of the underlying connection.
1120      *
1121      * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP}
1122      */
1123     @RequiresNoPermission
getConnectionType()1124     public int getConnectionType() {
1125         if (mType == TYPE_L2CAP_LE) {
1126             // Treat the LE CoC to be the same type as L2CAP.
1127             return TYPE_L2CAP;
1128         }
1129         return mType;
1130     }
1131 
1132     /**
1133      * Change if a SDP entry should be automatically created. Must be called before calling .bind,
1134      * for the call to have any effect.
1135      *
1136      * @param excludeSdp
1137      *     <li>TRUE - do not auto generate SDP record.
1138      *     <li>FALSE - default - auto generate SPP SDP record.
1139      * @hide
1140      */
1141     @RequiresNoPermission
setExcludeSdp(boolean excludeSdp)1142     public void setExcludeSdp(boolean excludeSdp) {
1143         mExcludeSdp = excludeSdp;
1144     }
1145 
1146     /**
1147      * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This
1148      * parameter is used by the BT Controller to set the maximum transmission packet size on this
1149      * connection. This function is currently used for testing only.
1150      *
1151      * @hide
1152      */
1153     @RequiresBluetoothConnectPermission
1154     @RequiresPermission(BLUETOOTH_CONNECT)
requestMaximumTxDataLength()1155     public void requestMaximumTxDataLength() throws IOException {
1156         if (mDevice == null) {
1157             throw new IOException("requestMaximumTxDataLength is called on null device");
1158         }
1159 
1160         try {
1161             if (mSocketState == SocketState.CLOSED) {
1162                 throw new IOException("socket closed");
1163             }
1164             IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
1165             if (bluetoothProxy == null) {
1166                 throw new IOException("Bluetooth is off");
1167             }
1168 
1169             if (DBG) Log.d(TAG, "requestMaximumTxDataLength");
1170             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
1171             if (socketManager == null) throw new IOException("bt get socket manager failed");
1172             socketManager.requestMaximumTxDataLength(mDevice);
1173         } catch (RemoteException e) {
1174             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1175             throw new IOException("unable to send RPC: " + e.getMessage());
1176         }
1177     }
1178 
1179     /**
1180      * Returns the L2CAP local channel ID associated with an open connection to this socket.
1181      *
1182      * @return the L2CAP local channel ID.
1183      * @throws BluetoothSocketException in case of failure, with the corresponding error code.
1184      * @hide
1185      */
1186     @SystemApi
1187     @FlaggedApi(Flags.FLAG_BT_SOCKET_API_L2CAP_CID)
1188     @RequiresBluetoothConnectPermission
1189     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getL2capLocalChannelId()1190     public int getL2capLocalChannelId() throws IOException {
1191         if (mType != TYPE_L2CAP_LE) {
1192             throw new BluetoothSocketException(BluetoothSocketException.L2CAP_UNKNOWN);
1193         }
1194         if (mSocketState != SocketState.CONNECTED || mConnectionUuid == null) {
1195             throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
1196         }
1197         int cid;
1198         IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
1199         if (bluetoothProxy == null) {
1200             throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE);
1201         }
1202         try {
1203             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
1204             if (socketManager == null) {
1205                 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE);
1206             }
1207             cid =
1208                     socketManager.getL2capLocalChannelId(
1209                             mConnectionUuid, AttributionSource.myAttributionSource());
1210         } catch (RemoteException e) {
1211             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1212             throw new IOException("unable to send RPC: " + e.getMessage());
1213         }
1214         if (cid == -1) {
1215             throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
1216         }
1217         return cid;
1218     }
1219 
1220     /**
1221      * Returns the L2CAP remote channel ID associated with an open connection to this socket.
1222      *
1223      * @return the L2CAP remote channel ID.
1224      * @throws BluetoothSocketException in case of failure, with the corresponding error code.
1225      * @hide
1226      */
1227     @SystemApi
1228     @FlaggedApi(Flags.FLAG_BT_SOCKET_API_L2CAP_CID)
1229     @RequiresBluetoothConnectPermission
1230     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getL2capRemoteChannelId()1231     public int getL2capRemoteChannelId() throws IOException {
1232         if (mType != TYPE_L2CAP_LE) {
1233             throw new BluetoothSocketException(BluetoothSocketException.L2CAP_UNKNOWN);
1234         }
1235         if (mSocketState != SocketState.CONNECTED || mConnectionUuid == null) {
1236             throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
1237         }
1238         int cid;
1239         IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
1240         if (bluetoothProxy == null) {
1241             throw new BluetoothSocketException(BluetoothSocketException.BLUETOOTH_OFF_FAILURE);
1242         }
1243         try {
1244             IBluetoothSocketManager socketManager = bluetoothProxy.getSocketManager();
1245             if (socketManager == null) {
1246                 throw new BluetoothSocketException(BluetoothSocketException.SOCKET_MANAGER_FAILURE);
1247             }
1248             cid =
1249                     socketManager.getL2capRemoteChannelId(
1250                             mConnectionUuid, AttributionSource.myAttributionSource());
1251         } catch (RemoteException e) {
1252             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1253             throw new IOException("unable to send RPC: " + e.getMessage());
1254         }
1255         if (cid == -1) {
1256             throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
1257         }
1258         return cid;
1259     }
1260 
1261     /**
1262      * Returns the socket ID assigned to the open connection on this BluetoothSocket. This socket ID
1263      * is a unique identifier for the socket. It is valid only while the socket is connected.
1264      *
1265      * @return The socket ID in connected state.
1266      * @throws BluetoothSocketException If the socket is not connected or an error occurs while
1267      *     retrieving the socket ID.
1268      * @hide
1269      */
1270     @SystemApi
1271     @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
1272     @RequiresNoPermission
getSocketId()1273     public long getSocketId() throws IOException {
1274         if (mSocketState != SocketState.CONNECTED || mSocketId == INVALID_SOCKET_ID) {
1275             throw new BluetoothSocketException(BluetoothSocketException.SOCKET_CLOSED);
1276         }
1277         return mSocketId;
1278     }
1279 
1280     /** @hide */
1281     @RequiresNoPermission
getParcelFileDescriptor()1282     public ParcelFileDescriptor getParcelFileDescriptor() {
1283         return mPfd;
1284     }
1285 
convertAddr(final byte[] addr)1286     private static String convertAddr(final byte[] addr) {
1287         return String.format(
1288                 Locale.US,
1289                 "%02X:%02X:%02X:%02X:%02X:%02X",
1290                 addr[0],
1291                 addr[1],
1292                 addr[2],
1293                 addr[3],
1294                 addr[4],
1295                 addr[5]);
1296     }
1297 
1298     /**
1299      * Sends a socket accept signal to the host stack.
1300      *
1301      * <p>This method is used to notify the host stack whether the host application is actively
1302      * accepting a new connection or not. It sends a signal containing the acceptance status to the
1303      * output stream associated with the socket.
1304      *
1305      * <p>This method is only effective when the data path is not {@link
1306      * BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}.
1307      *
1308      * @param os The output stream to write the signal to.
1309      * @param isAccepting {@code true} if the socket connection is being accepted, {@code false}
1310      *     otherwise.
1311      * @throws IOException If an I/O error occurs while writing to the output stream.
1312      * @hide
1313      */
sendSocketAcceptSignal(OutputStream os, boolean isAccepting)1314     private void sendSocketAcceptSignal(OutputStream os, boolean isAccepting) throws IOException {
1315         if (Flags.socketSettingsApi()) {
1316             if (mDataPath == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
1317                 return;
1318             }
1319             Log.d(TAG, "sendSocketAcceptSignal" + " isAccepting " + isAccepting);
1320             byte[] sig = new byte[SOCK_ACCEPT_SIGNAL_SIZE];
1321             ByteBuffer bb = ByteBuffer.wrap(sig);
1322             bb.order(ByteOrder.nativeOrder());
1323             bb.putShort((short) SOCK_ACCEPT_SIGNAL_SIZE);
1324             bb.putShort((short) (isAccepting ? 1 : 0));
1325             os.write(sig, 0, SOCK_ACCEPT_SIGNAL_SIZE);
1326         }
1327     }
1328 
waitSocketSignal(InputStream is)1329     private String waitSocketSignal(InputStream is) throws IOException {
1330         byte[] sig = new byte[SOCK_CONNECTION_SIGNAL_SIZE];
1331         int ret = readAll(is, sig);
1332         if (VDBG) {
1333             Log.d(
1334                     TAG,
1335                     "waitSocketSignal read "
1336                             + SOCK_CONNECTION_SIGNAL_SIZE
1337                             + " bytes signal ret: "
1338                             + ret);
1339         }
1340         ByteBuffer bb = ByteBuffer.wrap(sig);
1341         /* the struct in native is decorated with __attribute__((packed)), hence this is possible */
1342         bb.order(ByteOrder.nativeOrder());
1343         int size = bb.getShort();
1344         if (size != SOCK_CONNECTION_SIGNAL_SIZE) {
1345             throw new IOException("Connection failure, wrong signal size: " + size);
1346         }
1347         byte[] addr = new byte[6];
1348         bb.get(addr);
1349         int channel = bb.getInt();
1350         int status = bb.getInt();
1351         mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
1352         mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
1353         long uuidLsb = bb.getLong();
1354         long uuidMsb = bb.getLong();
1355         mConnectionUuid = new ParcelUuid(new UUID(uuidMsb, uuidLsb));
1356         mSocketId = bb.getLong();
1357         String RemoteAddr = convertAddr(addr);
1358         if (VDBG) {
1359             Log.d(
1360                     TAG,
1361                     "waitSocketSignal: sig size: "
1362                             + size
1363                             + ", remote addr: "
1364                             + RemoteAddr
1365                             + ", channel: "
1366                             + channel
1367                             + ", status: "
1368                             + status
1369                             + " MaxRxPktSize: "
1370                             + mMaxRxPacketSize
1371                             + " MaxTxPktSize: "
1372                             + mMaxTxPacketSize
1373                             + " mConnectionUuid: "
1374                             + mConnectionUuid.toString()
1375                             + " mSocketId: "
1376                             + mSocketId);
1377         }
1378         if (status != 0) {
1379             throw new IOException("Connection failure, status: " + status);
1380         }
1381         return RemoteAddr;
1382     }
1383 
createL2capRxBuffer()1384     private void createL2capRxBuffer() {
1385         if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
1386             // Allocate the buffer to use for reads.
1387             if (VDBG) Log.v(TAG, "  Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize);
1388             mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]);
1389             if (VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining());
1390             mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request
1391             if (VDBG) {
1392                 Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + mL2capBuffer.remaining());
1393             }
1394         }
1395     }
1396 
readAll(InputStream is, byte[] b)1397     private static int readAll(InputStream is, byte[] b) throws IOException {
1398         int left = b.length;
1399         while (left > 0) {
1400             int ret = is.read(b, b.length - left, left);
1401             if (ret <= 0) {
1402                 throw new IOException(
1403                         "read failed, socket might closed or timeout, read ret: " + ret);
1404             }
1405             left -= ret;
1406             if (left != 0) {
1407                 Log.w(
1408                         TAG,
1409                         "readAll() looping, read partial size: "
1410                                 + (b.length - left)
1411                                 + ", expect size: "
1412                                 + b.length);
1413             }
1414         }
1415         return b.length;
1416     }
1417 
readInt(InputStream is)1418     private static int readInt(InputStream is) throws IOException {
1419         byte[] ibytes = new byte[4];
1420         int ret = readAll(is, ibytes);
1421         if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret);
1422         ByteBuffer bb = ByteBuffer.wrap(ibytes);
1423         bb.order(ByteOrder.nativeOrder());
1424         return bb.getInt();
1425     }
1426 
fillL2capRxBuffer()1427     private int fillL2capRxBuffer() throws IOException {
1428         mL2capBuffer.rewind();
1429         int ret = mSocketIS.read(mL2capBuffer.array());
1430         if (ret == -1) {
1431             // reached end of stream - return -1
1432             mL2capBuffer.limit(0);
1433             return -1;
1434         }
1435         mL2capBuffer.limit(ret);
1436         return ret;
1437     }
1438 
1439     @Override
toString()1440     public String toString() {
1441         return BluetoothUtils.toAnonymizedAddress(mAddress);
1442     }
1443 }
1444