1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth;
18 
19 import android.os.RemoteException;
20 import android.util.Log;
21 
22 /** Utility class for socket metrics */
23 class SocketMetrics {
24     private static final String TAG = SocketMetrics.class.getSimpleName();
25 
26     /*package*/ static final int SOCKET_NO_ERROR = -1;
27 
28     // Defined in BluetoothProtoEnums.L2capCocConnectionResult of proto logging
29     private static final int RESULT_L2CAP_CONN_UNKNOWN = 0;
30     /*package*/ static final int RESULT_L2CAP_CONN_SUCCESS = 1;
31     private static final int RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_FAILED = 1000;
32     private static final int RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED = 1001;
33     private static final int RESULT_L2CAP_CONN_BLUETOOTH_UNABLE_TO_SEND_RPC = 1002;
34     private static final int RESULT_L2CAP_CONN_BLUETOOTH_NULL_BLUETOOTH_DEVICE = 1003;
35     private static final int RESULT_L2CAP_CONN_BLUETOOTH_GET_SOCKET_MANAGER_FAILED = 1004;
36     private static final int RESULT_L2CAP_CONN_BLUETOOTH_NULL_FILE_DESCRIPTOR = 1005;
37     /*package*/ static final int RESULT_L2CAP_CONN_SERVER_FAILURE = 2000;
38 
39     // Defined in BluetoothRfcommProtoEnums.RfcommConnectionResult of proto logging
40     private static final int RFCOMM_CONN_RESULT_FAILURE_UNKNOWN = 0;
41     private static final int RFCOMM_CONN_RESULT_SUCCESS = 1;
42     private static final int RFCOMM_CONN_RESULT_SOCKET_CONNECTION_FAILED = 2;
43     private static final int RFCOMM_CONN_RESULT_SOCKET_CONNECTION_CLOSED = 3;
44     private static final int RFCOMM_CONN_RESULT_UNABLE_TO_SEND_RPC = 4;
45     private static final int RFCOMM_CONN_RESULT_NULL_BLUETOOTH_DEVICE = 5;
46     private static final int RFCOMM_CONN_RESULT_GET_SOCKET_MANAGER_FAILED = 6;
47     private static final int RFCOMM_CONN_RESULT_NULL_FILE_DESCRIPTOR = 7;
48 
logSocketConnect( int socketExceptionCode, long socketConnectionTimeNanos, int connType, BluetoothDevice device, int port, boolean auth, long socketCreationTimeNanos, long socketCreationLatencyNanos)49     static void logSocketConnect(
50             int socketExceptionCode,
51             long socketConnectionTimeNanos,
52             int connType,
53             BluetoothDevice device,
54             int port,
55             boolean auth,
56             long socketCreationTimeNanos,
57             long socketCreationLatencyNanos) {
58         IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
59         if (bluetoothProxy == null) {
60             Log.w(TAG, "logSocketConnect: bluetoothProxy is null");
61             return;
62         }
63         if (connType == BluetoothSocket.TYPE_L2CAP_LE) {
64             try {
65                 bluetoothProxy.logL2capcocClientConnection(
66                         device,
67                         port,
68                         auth,
69                         getL2capLeConnectStatusCode(socketExceptionCode),
70                         socketCreationTimeNanos, // to calculate end to end latency
71                         socketCreationLatencyNanos, // latency of the constructor
72                         socketConnectionTimeNanos); // to calculate the latency of connect()
73             } catch (RemoteException e) {
74                 Log.w(TAG, "logL2capcocServerConnection failed", e);
75             }
76         } else if (connType == BluetoothSocket.TYPE_RFCOMM) {
77             boolean isSerialPort = true; // BluetoothSocket#connect API always uses serial port uuid
78             try {
79                 bluetoothProxy.logRfcommConnectionAttempt(
80                         device,
81                         auth,
82                         getRfcommConnectStatusCode(socketExceptionCode),
83                         socketCreationTimeNanos, // to calculate end to end latency
84                         isSerialPort);
85             } catch (RemoteException e) {
86                 Log.w(TAG, "logL2capcocServerConnection failed", e);
87             }
88         } else {
89             Log.d(TAG, "No metrics for connection type " + connType);
90         }
91     }
92 
logSocketAccept( BluetoothSocket acceptedSocket, BluetoothSocket socket, int connType, int channel, int timeout, int result, long socketCreationTimeMillis, long socketCreationLatencyMillis, long socketConnectionTimeMillis)93     static void logSocketAccept(
94             BluetoothSocket acceptedSocket,
95             BluetoothSocket socket,
96             int connType,
97             int channel,
98             int timeout,
99             int result,
100             long socketCreationTimeMillis,
101             long socketCreationLatencyMillis,
102             long socketConnectionTimeMillis) {
103         if (connType != BluetoothSocket.TYPE_L2CAP_LE) {
104             return;
105         }
106         IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
107         if (bluetoothProxy == null) {
108             Log.w(TAG, "logSocketConnect: bluetoothProxy is null");
109             return;
110         }
111         try {
112             bluetoothProxy.logL2capcocServerConnection(
113                     acceptedSocket == null ? null : acceptedSocket.getRemoteDevice(),
114                     channel,
115                     socket.isAuth(),
116                     result,
117                     socketCreationTimeMillis, // pass creation time to calculate end to end latency
118                     socketCreationLatencyMillis, // socket creation latency
119                     socketConnectionTimeMillis, // send connection start time for connection latency
120                     timeout);
121         } catch (RemoteException e) {
122             Log.w(TAG, "logL2capcocServerConnection failed", e);
123         }
124     }
125 
getL2capLeConnectStatusCode(int socketExceptionCode)126     private static int getL2capLeConnectStatusCode(int socketExceptionCode) {
127         switch (socketExceptionCode) {
128             case (SOCKET_NO_ERROR):
129                 return RESULT_L2CAP_CONN_SUCCESS;
130             case (BluetoothSocketException.NULL_DEVICE):
131                 return RESULT_L2CAP_CONN_BLUETOOTH_NULL_BLUETOOTH_DEVICE;
132             case (BluetoothSocketException.SOCKET_MANAGER_FAILURE):
133                 return RESULT_L2CAP_CONN_BLUETOOTH_GET_SOCKET_MANAGER_FAILED;
134             case (BluetoothSocketException.SOCKET_CLOSED):
135                 return RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED;
136             case (BluetoothSocketException.SOCKET_CONNECTION_FAILURE):
137                 return RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_FAILED;
138             case (BluetoothSocketException.RPC_FAILURE):
139                 return RESULT_L2CAP_CONN_BLUETOOTH_UNABLE_TO_SEND_RPC;
140             case (BluetoothSocketException.UNIX_FILE_SOCKET_CREATION_FAILURE):
141                 return RESULT_L2CAP_CONN_BLUETOOTH_NULL_FILE_DESCRIPTOR;
142             default:
143                 return RESULT_L2CAP_CONN_UNKNOWN;
144         }
145     }
146 
getRfcommConnectStatusCode(int socketExceptionCode)147     private static int getRfcommConnectStatusCode(int socketExceptionCode) {
148         switch (socketExceptionCode) {
149             case (SOCKET_NO_ERROR):
150                 return RFCOMM_CONN_RESULT_SUCCESS;
151             case (BluetoothSocketException.NULL_DEVICE):
152                 return RFCOMM_CONN_RESULT_NULL_BLUETOOTH_DEVICE;
153             case (BluetoothSocketException.SOCKET_MANAGER_FAILURE):
154                 return RFCOMM_CONN_RESULT_GET_SOCKET_MANAGER_FAILED;
155             case (BluetoothSocketException.SOCKET_CLOSED):
156                 return RFCOMM_CONN_RESULT_SOCKET_CONNECTION_CLOSED;
157             case (BluetoothSocketException.SOCKET_CONNECTION_FAILURE):
158                 return RFCOMM_CONN_RESULT_SOCKET_CONNECTION_FAILED;
159             case (BluetoothSocketException.RPC_FAILURE):
160                 return RFCOMM_CONN_RESULT_UNABLE_TO_SEND_RPC;
161             case (BluetoothSocketException.UNIX_FILE_SOCKET_CREATION_FAILURE):
162                 return RFCOMM_CONN_RESULT_NULL_FILE_DESCRIPTOR;
163             default:
164                 return RFCOMM_CONN_RESULT_FAILURE_UNKNOWN;
165         }
166     }
167 }
168