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