| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.bluetooth; |
| |
| import android.os.RemoteException; |
| import android.util.Log; |
| |
| /** Utility class for socket metrics */ |
| class SocketMetrics { |
| private static final String TAG = SocketMetrics.class.getSimpleName(); |
| |
| /*package*/ static final int SOCKET_NO_ERROR = -1; |
| |
| // Defined in BluetoothProtoEnums.L2capCocConnectionResult of proto logging |
| private static final int RESULT_L2CAP_CONN_UNKNOWN = 0; |
| /*package*/ static final int RESULT_L2CAP_CONN_SUCCESS = 1; |
| private static final int RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_FAILED = 1000; |
| private static final int RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED = 1001; |
| private static final int RESULT_L2CAP_CONN_BLUETOOTH_UNABLE_TO_SEND_RPC = 1002; |
| private static final int RESULT_L2CAP_CONN_BLUETOOTH_NULL_BLUETOOTH_DEVICE = 1003; |
| private static final int RESULT_L2CAP_CONN_BLUETOOTH_GET_SOCKET_MANAGER_FAILED = 1004; |
| private static final int RESULT_L2CAP_CONN_BLUETOOTH_NULL_FILE_DESCRIPTOR = 1005; |
| /*package*/ static final int RESULT_L2CAP_CONN_SERVER_FAILURE = 2000; |
| |
| // Defined in BluetoothRfcommProtoEnums.RfcommConnectionResult of proto logging |
| private static final int RFCOMM_CONN_RESULT_FAILURE_UNKNOWN = 0; |
| private static final int RFCOMM_CONN_RESULT_SUCCESS = 1; |
| private static final int RFCOMM_CONN_RESULT_SOCKET_CONNECTION_FAILED = 2; |
| private static final int RFCOMM_CONN_RESULT_SOCKET_CONNECTION_CLOSED = 3; |
| private static final int RFCOMM_CONN_RESULT_UNABLE_TO_SEND_RPC = 4; |
| private static final int RFCOMM_CONN_RESULT_NULL_BLUETOOTH_DEVICE = 5; |
| private static final int RFCOMM_CONN_RESULT_GET_SOCKET_MANAGER_FAILED = 6; |
| private static final int RFCOMM_CONN_RESULT_NULL_FILE_DESCRIPTOR = 7; |
| |
| static void logSocketConnect( |
| int socketExceptionCode, |
| long socketConnectionTimeNanos, |
| int connType, |
| BluetoothDevice device, |
| int port, |
| boolean auth, |
| long socketCreationTimeNanos, |
| long socketCreationLatencyNanos) { |
| IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); |
| if (bluetoothProxy == null) { |
| Log.w(TAG, "logSocketConnect: bluetoothProxy is null"); |
| return; |
| } |
| if (connType == BluetoothSocket.TYPE_L2CAP_LE) { |
| try { |
| bluetoothProxy.logL2capcocClientConnection( |
| device, |
| port, |
| auth, |
| getL2capLeConnectStatusCode(socketExceptionCode), |
| socketCreationTimeNanos, // to calculate end to end latency |
| socketCreationLatencyNanos, // latency of the constructor |
| socketConnectionTimeNanos); // to calculate the latency of connect() |
| } catch (RemoteException e) { |
| Log.w(TAG, "logL2capcocServerConnection failed", e); |
| } |
| } else if (connType == BluetoothSocket.TYPE_RFCOMM) { |
| boolean isSerialPort = true; // BluetoothSocket#connect API always uses serial port uuid |
| try { |
| bluetoothProxy.logRfcommConnectionAttempt( |
| device, |
| auth, |
| getRfcommConnectStatusCode(socketExceptionCode), |
| socketCreationTimeNanos, // to calculate end to end latency |
| isSerialPort); |
| } catch (RemoteException e) { |
| Log.w(TAG, "logL2capcocServerConnection failed", e); |
| } |
| } else { |
| Log.d(TAG, "No metrics for connection type " + connType); |
| } |
| } |
| |
| static void logSocketAccept( |
| BluetoothSocket acceptedSocket, |
| BluetoothSocket socket, |
| int connType, |
| int channel, |
| int timeout, |
| int result, |
| long socketCreationTimeMillis, |
| long socketCreationLatencyMillis, |
| long socketConnectionTimeMillis) { |
| if (connType != BluetoothSocket.TYPE_L2CAP_LE) { |
| return; |
| } |
| IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(); |
| if (bluetoothProxy == null) { |
| Log.w(TAG, "logSocketConnect: bluetoothProxy is null"); |
| return; |
| } |
| try { |
| bluetoothProxy.logL2capcocServerConnection( |
| acceptedSocket == null ? null : acceptedSocket.getRemoteDevice(), |
| channel, |
| socket.isAuth(), |
| result, |
| socketCreationTimeMillis, // pass creation time to calculate end to end latency |
| socketCreationLatencyMillis, // socket creation latency |
| socketConnectionTimeMillis, // send connection start time for connection latency |
| timeout); |
| } catch (RemoteException e) { |
| Log.w(TAG, "logL2capcocServerConnection failed", e); |
| } |
| } |
| |
| private static int getL2capLeConnectStatusCode(int socketExceptionCode) { |
| switch (socketExceptionCode) { |
| case (SOCKET_NO_ERROR): |
| return RESULT_L2CAP_CONN_SUCCESS; |
| case (BluetoothSocketException.NULL_DEVICE): |
| return RESULT_L2CAP_CONN_BLUETOOTH_NULL_BLUETOOTH_DEVICE; |
| case (BluetoothSocketException.SOCKET_MANAGER_FAILURE): |
| return RESULT_L2CAP_CONN_BLUETOOTH_GET_SOCKET_MANAGER_FAILED; |
| case (BluetoothSocketException.SOCKET_CLOSED): |
| return RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_CLOSED; |
| case (BluetoothSocketException.SOCKET_CONNECTION_FAILURE): |
| return RESULT_L2CAP_CONN_BLUETOOTH_SOCKET_CONNECTION_FAILED; |
| case (BluetoothSocketException.RPC_FAILURE): |
| return RESULT_L2CAP_CONN_BLUETOOTH_UNABLE_TO_SEND_RPC; |
| case (BluetoothSocketException.UNIX_FILE_SOCKET_CREATION_FAILURE): |
| return RESULT_L2CAP_CONN_BLUETOOTH_NULL_FILE_DESCRIPTOR; |
| default: |
| return RESULT_L2CAP_CONN_UNKNOWN; |
| } |
| } |
| |
| private static int getRfcommConnectStatusCode(int socketExceptionCode) { |
| switch (socketExceptionCode) { |
| case (SOCKET_NO_ERROR): |
| return RFCOMM_CONN_RESULT_SUCCESS; |
| case (BluetoothSocketException.NULL_DEVICE): |
| return RFCOMM_CONN_RESULT_NULL_BLUETOOTH_DEVICE; |
| case (BluetoothSocketException.SOCKET_MANAGER_FAILURE): |
| return RFCOMM_CONN_RESULT_GET_SOCKET_MANAGER_FAILED; |
| case (BluetoothSocketException.SOCKET_CLOSED): |
| return RFCOMM_CONN_RESULT_SOCKET_CONNECTION_CLOSED; |
| case (BluetoothSocketException.SOCKET_CONNECTION_FAILURE): |
| return RFCOMM_CONN_RESULT_SOCKET_CONNECTION_FAILED; |
| case (BluetoothSocketException.RPC_FAILURE): |
| return RFCOMM_CONN_RESULT_UNABLE_TO_SEND_RPC; |
| case (BluetoothSocketException.UNIX_FILE_SOCKET_CREATION_FAILURE): |
| return RFCOMM_CONN_RESULT_NULL_FILE_DESCRIPTOR; |
| default: |
| return RFCOMM_CONN_RESULT_FAILURE_UNKNOWN; |
| } |
| } |
| } |