blob: 867180dd8d939c47ec6da3a78f4269435d0747b9 [file] [log] [blame]
Nick Pelly53f441b2009-05-26 19:13:43 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.bluetooth;
18
Chen Chen874e7b02023-03-07 17:37:43 -080019
Jeff Sharkey5ba8bfc2021-04-16 09:53:23 -060020import android.annotation.SuppressLint;
Artur Satayevd8fe38c2019-12-10 17:47:52 +000021import android.compat.annotation.UnsupportedAppUsage;
Nick Pellyee1402d2009-10-02 20:34:18 -070022import android.os.Handler;
zzyfab62db2012-04-03 19:48:32 -070023import android.os.ParcelUuid;
Casper Bondec0a7c932015-04-09 09:24:48 +020024import android.util.Log;
Nick Pellyee1402d2009-10-02 20:34:18 -070025
Chen Chen874e7b02023-03-07 17:37:43 -080026
Nick Pelly53f441b2009-05-26 19:13:43 -070027import java.io.Closeable;
28import java.io.IOException;
29
30/**
Nick Pelly753da532009-08-19 11:00:00 -070031 * A listening Bluetooth socket.
Nick Pelly53f441b2009-05-26 19:13:43 -070032 *
David Duarteee52b7e2023-12-02 01:32:11 +000033 * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets: {@link java.net.Socket}
34 * and {@link java.net.ServerSocket}. On the server side, use a {@link BluetoothServerSocket} to
35 * create a listening server socket. When a connection is accepted by the {@link
36 * BluetoothServerSocket}, it will return a new {@link BluetoothSocket} to manage the connection. On
37 * the client side, use a single {@link BluetoothSocket} to both initiate an outgoing connection and
38 * to manage the connection.
Nick Pelly53f441b2009-05-26 19:13:43 -070039 *
Stanley Tng3b285452019-04-19 14:27:09 -070040 * <p>For Bluetooth BR/EDR, the most common type of socket is RFCOMM, which is the type supported by
41 * the Android APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth BR/EDR. It
David Duarteee52b7e2023-12-02 01:32:11 +000042 * is also known as the Serial Port Profile (SPP). To create a listening {@link
43 * BluetoothServerSocket} that's ready for incoming Bluetooth BR/EDR connections, use {@link
Stanley Tng3b285452019-04-19 14:27:09 -070044 * BluetoothAdapter#listenUsingRfcommWithServiceRecord
45 * BluetoothAdapter.listenUsingRfcommWithServiceRecord()}.
Nick Pelly53f441b2009-05-26 19:13:43 -070046 *
Stanley Tng3b285452019-04-19 14:27:09 -070047 * <p>For Bluetooth LE, the socket uses LE Connection-oriented Channel (CoC). LE CoC is a
48 * connection-oriented, streaming transport over Bluetooth LE and has a credit-based flow control.
49 * Correspondingly, use {@link BluetoothAdapter#listenUsingL2capChannel
50 * BluetoothAdapter.listenUsingL2capChannel()} to create a listening {@link BluetoothServerSocket}
51 * that's ready for incoming Bluetooth LE CoC connections. For LE CoC, you can use {@link #getPsm()}
52 * to get the protocol/service multiplexer (PSM) value that the peer needs to use to connect to your
53 * socket.
54 *
David Duarteee52b7e2023-12-02 01:32:11 +000055 * <p>After the listening {@link BluetoothServerSocket} is created, call {@link #accept()} to listen
56 * for incoming connection requests. This call will block until a connection is established, at
57 * which point, it will return a {@link BluetoothSocket} to manage the connection. Once the {@link
58 * BluetoothSocket} is acquired, it's a good idea to call {@link #close()} on the {@link
59 * BluetoothServerSocket} when it's no longer needed for accepting connections. Closing the {@link
60 * BluetoothServerSocket} will <em>not</em> close the returned {@link BluetoothSocket}.
Nick Pelly753da532009-08-19 11:00:00 -070061 *
David Duarteee52b7e2023-12-02 01:32:11 +000062 * <p>{@link BluetoothServerSocket} is thread safe. In particular, {@link #close} will always
63 * immediately abort ongoing operations and close the server socket.
Nick Pellyed6f2ce2009-09-08 10:12:06 -070064 *
David Duarteee52b7e2023-12-02 01:32:11 +000065 * <p><div class="special reference">
66 *
Joe Fernandezda4e2ab2011-12-20 10:38:34 -080067 * <h3>Developer Guides</h3>
Joe Fernandezda4e2ab2011-12-20 10:38:34 -080068 *
David Duarteee52b7e2023-12-02 01:32:11 +000069 * <p>For more information about using Bluetooth, read the <a
70 * href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide. </div>
71 *
David Duarte5a02bb42023-12-04 23:07:42 +000072 * @see BluetoothSocket
Nick Pelly53f441b2009-05-26 19:13:43 -070073 */
Jeff Sharkey5ba8bfc2021-04-16 09:53:23 -060074@SuppressLint("AndroidFrameworkBluetoothPermission")
Nick Pelly53f441b2009-05-26 19:13:43 -070075public final class BluetoothServerSocket implements Closeable {
Nick Pelly4cd2cd92009-09-02 11:51:35 -070076
Casper Bondec0a7c932015-04-09 09:24:48 +020077 private static final String TAG = "BluetoothServerSocket";
Ugo Yub6dc15a2022-12-28 20:18:00 +080078 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
David Duarteee52b7e2023-12-02 01:32:11 +000079
80 @UnsupportedAppUsage(
81 publicAlternatives = "Use public {@link BluetoothServerSocket} API " + "instead.")
Nick Pelly2d664882009-08-14 18:33:38 -070082 /*package*/ final BluetoothSocket mSocket;
David Duarteee52b7e2023-12-02 01:32:11 +000083
Nick Pellyee1402d2009-10-02 20:34:18 -070084 private Handler mHandler;
85 private int mMessage;
Casper Bondec0a7c932015-04-09 09:24:48 +020086 private int mChannel;
Chen Chen61174be2023-03-16 17:42:36 -070087 private long mSocketCreationTimeMillis = 0;
88 private long mSocketCreationLatencyMillis = 0;
Chen Chen874e7b02023-03-07 17:37:43 -080089
90 // BluetoothSocket.getConnectionType() will hide L2CAP_LE.
91 // Therefore a new variable need to be maintained here.
92 private int mType;
Nick Pelly53f441b2009-05-26 19:13:43 -070093
94 /**
95 * Construct a socket for incoming connections.
Jack He910201b2017-08-22 16:06:54 -070096 *
97 * @param type type of socket
98 * @param auth require the remote device to be authenticated
Nick Pellycb32d7c2009-06-02 15:57:18 -070099 * @param encrypt require the connection to be encrypted
Jack He910201b2017-08-22 16:06:54 -0700100 * @param port remote port
David Duarteee52b7e2023-12-02 01:32:11 +0000101 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
Nick Pelly53f441b2009-05-26 19:13:43 -0700102 */
Nick Pelly2d664882009-08-14 18:33:38 -0700103 /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
Nick Pellycb32d7c2009-06-02 15:57:18 -0700104 throws IOException {
Chen Chen61174be2023-03-16 17:42:36 -0700105 mSocketCreationTimeMillis = System.currentTimeMillis();
Chen Chen874e7b02023-03-07 17:37:43 -0800106 mType = type;
Ben Dodson48d0cca2011-07-08 14:36:42 -0700107 mChannel = port;
David Duarte5a02bb42023-12-04 23:07:42 +0000108 mSocket = new BluetoothSocket(type, auth, encrypt, null, port, null);
Casper Bonde60d77c22015-04-21 13:12:05 +0200109 if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
110 mSocket.setExcludeSdp(true);
111 }
Chen Chen61174be2023-03-16 17:42:36 -0700112 mSocketCreationLatencyMillis = System.currentTimeMillis() - mSocketCreationTimeMillis;
Casper Bonde60d77c22015-04-21 13:12:05 +0200113 }
114
115 /**
116 * Construct a socket for incoming connections.
Jack He910201b2017-08-22 16:06:54 -0700117 *
118 * @param type type of socket
119 * @param auth require the remote device to be authenticated
Casper Bonde60d77c22015-04-21 13:12:05 +0200120 * @param encrypt require the connection to be encrypted
Jack He910201b2017-08-22 16:06:54 -0700121 * @param port remote port
Jeff Sharkeyc5386af2020-09-11 14:57:21 -0600122 * @param mitm enforce person-in-the-middle protection for authentication.
Casper Bonde91276012015-05-08 14:32:24 +0200123 * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
David Duarteee52b7e2023-12-02 01:32:11 +0000124 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
Casper Bonde60d77c22015-04-21 13:12:05 +0200125 */
David Duarteee52b7e2023-12-02 01:32:11 +0000126 /*package*/ BluetoothServerSocket(
127 int type, boolean auth, boolean encrypt, int port, boolean mitm, boolean min16DigitPin)
Casper Bonde60d77c22015-04-21 13:12:05 +0200128 throws IOException {
Chen Chen61174be2023-03-16 17:42:36 -0700129 mSocketCreationTimeMillis = System.currentTimeMillis();
Chen Chen874e7b02023-03-07 17:37:43 -0800130 mType = type;
Casper Bonde60d77c22015-04-21 13:12:05 +0200131 mChannel = port;
David Duarte5a02bb42023-12-04 23:07:42 +0000132 mSocket = new BluetoothSocket(type, auth, encrypt, null, port, null, mitm, min16DigitPin);
Jack He910201b2017-08-22 16:06:54 -0700133 if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
Casper Bondec0a7c932015-04-09 09:24:48 +0200134 mSocket.setExcludeSdp(true);
135 }
Chen Chen61174be2023-03-16 17:42:36 -0700136 mSocketCreationLatencyMillis = System.currentTimeMillis() - mSocketCreationTimeMillis;
Nick Pelly53f441b2009-05-26 19:13:43 -0700137 }
138
139 /**
zzyfab62db2012-04-03 19:48:32 -0700140 * Construct a socket for incoming connections.
Jack He910201b2017-08-22 16:06:54 -0700141 *
142 * @param type type of socket
143 * @param auth require the remote device to be authenticated
zzyfab62db2012-04-03 19:48:32 -0700144 * @param encrypt require the connection to be encrypted
Jack He910201b2017-08-22 16:06:54 -0700145 * @param uuid uuid
David Duarteee52b7e2023-12-02 01:32:11 +0000146 * @throws IOException On error, for example Bluetooth not available, or insufficient privileges
zzyfab62db2012-04-03 19:48:32 -0700147 */
148 /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid)
149 throws IOException {
Chen Chen61174be2023-03-16 17:42:36 -0700150 mSocketCreationTimeMillis = System.currentTimeMillis();
Chen Chen874e7b02023-03-07 17:37:43 -0800151 mType = type;
David Duarte5a02bb42023-12-04 23:07:42 +0000152 mSocket = new BluetoothSocket(type, auth, encrypt, null, -1, uuid);
Casper Bondec0a7c932015-04-09 09:24:48 +0200153 // TODO: This is the same as mChannel = -1 - is this intentional?
zzyfab62db2012-04-03 19:48:32 -0700154 mChannel = mSocket.getPort();
Chen Chen61174be2023-03-16 17:42:36 -0700155 mSocketCreationLatencyMillis = System.currentTimeMillis() - mSocketCreationTimeMillis;
zzyfab62db2012-04-03 19:48:32 -0700156 }
157
zzyfab62db2012-04-03 19:48:32 -0700158 /**
Nick Pelly53f441b2009-05-26 19:13:43 -0700159 * Block until a connection is established.
David Duarteee52b7e2023-12-02 01:32:11 +0000160 *
Nick Pelly753da532009-08-19 11:00:00 -0700161 * <p>Returns a connected {@link BluetoothSocket} on successful connection.
David Duarteee52b7e2023-12-02 01:32:11 +0000162 *
163 * <p>Once this call returns, it can be called again to accept subsequent incoming connections.
164 *
Nick Pelly753da532009-08-19 11:00:00 -0700165 * <p>{@link #close} can be used to abort this call from another thread.
Jack He910201b2017-08-22 16:06:54 -0700166 *
Nick Pelly753da532009-08-19 11:00:00 -0700167 * @return a connected {@link BluetoothSocket}
Jack He910201b2017-08-22 16:06:54 -0700168 * @throws IOException on error, for example this call was aborted, or timeout
Nick Pelly53f441b2009-05-26 19:13:43 -0700169 */
170 public BluetoothSocket accept() throws IOException {
171 return accept(-1);
172 }
173
174 /**
175 * Block until a connection is established, with timeout.
David Duarteee52b7e2023-12-02 01:32:11 +0000176 *
Nick Pelly753da532009-08-19 11:00:00 -0700177 * <p>Returns a connected {@link BluetoothSocket} on successful connection.
David Duarteee52b7e2023-12-02 01:32:11 +0000178 *
179 * <p>Once this call returns, it can be called again to accept subsequent incoming connections.
180 *
Nick Pelly753da532009-08-19 11:00:00 -0700181 * <p>{@link #close} can be used to abort this call from another thread.
Jack He910201b2017-08-22 16:06:54 -0700182 *
Nick Pelly753da532009-08-19 11:00:00 -0700183 * @return a connected {@link BluetoothSocket}
Jack He910201b2017-08-22 16:06:54 -0700184 * @throws IOException on error, for example this call was aborted, or timeout
Nick Pelly53f441b2009-05-26 19:13:43 -0700185 */
186 public BluetoothSocket accept(int timeout) throws IOException {
Chen Chen61174be2023-03-16 17:42:36 -0700187 long socketConnectionTime = System.currentTimeMillis();
Chen Chen874e7b02023-03-07 17:37:43 -0800188 BluetoothSocket acceptedSocket = null;
189 try {
190 acceptedSocket = mSocket.accept(timeout);
Pomai Ahloe28d3cb2023-11-02 17:19:30 -0700191 SocketMetrics.logSocketAccept(
Chen Chen61174be2023-03-16 17:42:36 -0700192 acceptedSocket,
Pomai Ahloe28d3cb2023-11-02 17:19:30 -0700193 mSocket,
194 mType,
195 mChannel,
Chen Chen61174be2023-03-16 17:42:36 -0700196 timeout,
Pomai Ahloe28d3cb2023-11-02 17:19:30 -0700197 SocketMetrics.RESULT_L2CAP_CONN_SUCCESS,
198 mSocketCreationTimeMillis,
199 mSocketCreationLatencyMillis,
Chen Chen61174be2023-03-16 17:42:36 -0700200 socketConnectionTime);
Chen Chen874e7b02023-03-07 17:37:43 -0800201 return acceptedSocket;
202 } catch (IOException e) {
Pomai Ahloe28d3cb2023-11-02 17:19:30 -0700203 SocketMetrics.logSocketAccept(
Chen Chen61174be2023-03-16 17:42:36 -0700204 acceptedSocket,
Pomai Ahloe28d3cb2023-11-02 17:19:30 -0700205 mSocket,
206 mType,
207 mChannel,
Chen Chen61174be2023-03-16 17:42:36 -0700208 timeout,
Pomai Ahloe28d3cb2023-11-02 17:19:30 -0700209 SocketMetrics.RESULT_L2CAP_CONN_SERVER_FAILURE,
210 mSocketCreationTimeMillis,
211 mSocketCreationLatencyMillis,
Chen Chen61174be2023-03-16 17:42:36 -0700212 socketConnectionTime);
Chen Chen874e7b02023-03-07 17:37:43 -0800213 throw e;
214 }
Nick Pelly53f441b2009-05-26 19:13:43 -0700215 }
216
217 /**
Nick Pelly753da532009-08-19 11:00:00 -0700218 * Immediately close this socket, and release all associated resources.
David Duarteee52b7e2023-12-02 01:32:11 +0000219 *
220 * <p>Causes blocked calls on this socket in other threads to immediately throw an IOException.
221 *
222 * <p>Closing the {@link BluetoothServerSocket} will <em>not</em> close any {@link
223 * BluetoothSocket} received from {@link #accept()}.
Nick Pelly53f441b2009-05-26 19:13:43 -0700224 */
225 public void close() throws IOException {
Stanley Tngd67d5e42017-11-22 16:04:40 -0800226 if (DBG) Log.d(TAG, "BluetoothServerSocket:close() called. mChannel=" + mChannel);
Nick Pellyee1402d2009-10-02 20:34:18 -0700227 synchronized (this) {
228 if (mHandler != null) {
229 mHandler.obtainMessage(mMessage).sendToTarget();
230 }
231 }
Nick Pelly4cd2cd92009-09-02 11:51:35 -0700232 mSocket.close();
Nick Pelly53f441b2009-05-26 19:13:43 -0700233 }
Nick Pellyee1402d2009-10-02 20:34:18 -0700234
Jack He910201b2017-08-22 16:06:54 -0700235 /*package*/
236 synchronized void setCloseHandler(Handler handler, int message) {
Nick Pellyee1402d2009-10-02 20:34:18 -0700237 mHandler = handler;
238 mMessage = message;
239 }
Jack He910201b2017-08-22 16:06:54 -0700240
Jack He9e045d22017-08-22 21:21:23 -0700241 /*package*/ void setServiceName(String serviceName) {
242 mSocket.setServiceName(serviceName);
zzyfab62db2012-04-03 19:48:32 -0700243 }
Casper Bondec0a7c932015-04-09 09:24:48 +0200244
Ben Dodson48d0cca2011-07-08 14:36:42 -0700245 /**
246 * Returns the channel on which this socket is bound.
Jack He910201b2017-08-22 16:06:54 -0700247 *
Ben Dodson48d0cca2011-07-08 14:36:42 -0700248 * @hide
249 */
250 public int getChannel() {
251 return mChannel;
252 }
Casper Bondec0a7c932015-04-09 09:24:48 +0200253
254 /**
Stanley Tngd67d5e42017-11-22 16:04:40 -0800255 * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
256 * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
Xin Li10802fb2019-02-13 22:36:25 -0800257 * {@link BluetoothAdapter#listenUsingL2capChannel()} or {@link
258 * BluetoothAdapter#listenUsingInsecureL2capChannel()}. The returned value is undefined if this
Stanley Tngd67d5e42017-11-22 16:04:40 -0800259 * method is called on non-L2CAP server sockets.
260 *
261 * @return the assigned PSM or LE_PSM value depending on transport
Stanley Tngd67d5e42017-11-22 16:04:40 -0800262 */
263 public int getPsm() {
264 return mChannel;
265 }
266
267 /**
David Duarteee52b7e2023-12-02 01:32:11 +0000268 * Sets the channel on which future sockets are bound. Currently used only when a channel is
269 * auto generated.
Casper Bondec0a7c932015-04-09 09:24:48 +0200270 */
271 /*package*/ void setChannel(int newChannel) {
272 /* TODO: From a design/architecture perspective this is wrong.
273 * The bind operation should be conducted through this class
274 * and the resulting port should be kept in mChannel, and
275 * not set from BluetoothAdapter. */
Jack He910201b2017-08-22 16:06:54 -0700276 if (mSocket != null) {
277 if (mSocket.getPort() != newChannel) {
David Duarteee52b7e2023-12-02 01:32:11 +0000278 Log.w(
279 TAG,
280 "The port set is different that the underlying port. mSocket.getPort(): "
281 + mSocket.getPort()
282 + " requested newChannel: "
283 + newChannel);
Casper Bondec0a7c932015-04-09 09:24:48 +0200284 }
285 }
286 mChannel = newChannel;
287 }
288
289 @Override
290 public String toString() {
291 StringBuilder sb = new StringBuilder();
292 sb.append("ServerSocket: Type: ");
Jack He910201b2017-08-22 16:06:54 -0700293 switch (mSocket.getConnectionType()) {
David Duarteee52b7e2023-12-02 01:32:11 +0000294 case BluetoothSocket.TYPE_RFCOMM:
295 {
296 sb.append("TYPE_RFCOMM");
297 break;
298 }
299 case BluetoothSocket.TYPE_L2CAP:
300 {
301 sb.append("TYPE_L2CAP");
302 break;
303 }
304 case BluetoothSocket.TYPE_L2CAP_LE:
305 {
306 sb.append("TYPE_L2CAP_LE");
307 break;
308 }
309 case BluetoothSocket.TYPE_SCO:
310 {
311 sb.append("TYPE_SCO");
312 break;
313 }
Casper Bondec0a7c932015-04-09 09:24:48 +0200314 }
315 sb.append(" Channel: ").append(mChannel);
316 return sb.toString();
317 }
Nick Pelly53f441b2009-05-26 19:13:43 -0700318}