/* * 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; } } }