Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3db9592 authored by Pomai Ahlo's avatar Pomai Ahlo
Browse files

Add RFCOMM Metrics Implementation

Add logic necessary to log RfcommConnectionAttempt as described in
go/rfcomm_metrics_design

Bug: 306760576
Flag: EXEMPT the metrics implementation doesn't affect bt behavior
Test: m Bluetooth
Change-Id: I3c086bdd8a914895449080944d1dc3674ca49f5a
parent bc19c025
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -176,6 +176,8 @@ interface IBluetooth

    @JavaPassthrough(annotation="@android.annotation.RequiresNoPermission")
    oneway void logL2capcocClientConnection(in BluetoothDevice device, int port, boolean isSecured, int result, long socketCreationTimeNanos, long socketCreationLatencyNanos, long socketConnectionTimeNanos, in SynchronousResultReceiver receiver);
    @JavaPassthrough(annotation="@android.annotation.RequiresNoPermission")
    oneway void logRfcommConnectionAttempt(in BluetoothDevice device, boolean isSecured, int resultCode, long socketCreationTimeNanos, boolean isSerialPort, in SynchronousResultReceiver receiver);

    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
    oneway void factoryReset(in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+58 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import android.bluetooth.IBluetoothSocketManager;
import android.bluetooth.IncomingRfcommSocketInfo;
import android.bluetooth.OobData;
import android.bluetooth.UidTraffic;
import android.bluetooth.rfcomm.BluetoothRfcommProtoEnums;
import android.companion.CompanionDeviceManager;
import android.content.AttributionSource;
import android.content.Context;
@@ -909,6 +910,37 @@ public class AdapterService extends Service {
                socketConnectionLatencyMillis);
    }

    /**
     * Log RFCOMM Connection Metrics
     *
     * @param device Bluetooth device
     * @param isSecured if secured API is called
     * @param resultCode transaction result of the connection
     * @param isSerialPort true if service class UUID is 0x1101
     */
    public void logRfcommConnectionAttempt(
            BluetoothDevice device,
            boolean isSecured,
            int resultCode,
            long socketCreationTimeNanos,
            boolean isSerialPort,
            int appUid) {

        int metricId = getMetricId(device);
        long currentTime = System.nanoTime();
        long endToEndLatencyNanos = currentTime - socketCreationTimeNanos;
        BluetoothStatsLog.write(
                BluetoothStatsLog.BLUETOOTH_RFCOMM_CONNECTION_ATTEMPTED,
                metricId,
                endToEndLatencyNanos,
                isSecured
                        ? BluetoothRfcommProtoEnums.SOCKET_SECURITY_SECURE
                        : BluetoothRfcommProtoEnums.SOCKET_SECURITY_INSECURE,
                resultCode,
                isSerialPort,
                appUid);
    }

    @RequiresPermission(
            allOf = {
                android.Manifest.permission.BLUETOOTH_CONNECT,
@@ -3958,6 +3990,32 @@ public class AdapterService extends Service {
            }
        }

        @Override
        public void logRfcommConnectionAttempt(
                BluetoothDevice device,
                boolean isSecured,
                int resultCode,
                long socketCreationTimeNanos,
                boolean isSerialPort,
                SynchronousResultReceiver receiver) {
            AdapterService service = getService();
            if (service == null) {
                return;
            }
            try {
                service.logRfcommConnectionAttempt(
                        device,
                        isSecured,
                        resultCode,
                        socketCreationTimeNanos,
                        isSerialPort,
                        Binder.getCallingUid());
                receiver.send(null);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }

        @Override
        public void sdpSearch(
                BluetoothDevice device,
+64 −18
Original line number Diff line number Diff line
@@ -42,6 +42,16 @@ class SocketMetrics {
    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,
@@ -51,29 +61,44 @@ class SocketMetrics {
            boolean auth,
            long socketCreationTimeNanos,
            long socketCreationLatencyNanos) {
        if (connType != BluetoothSocket.TYPE_L2CAP_LE) {
            return;
        }
        IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
        if (bluetoothProxy == null) {
            Log.w(TAG, "logSocketConnect: bluetoothProxy is null");
            return;
        }
        int errCode = getL2capLeConnectStatusCode(socketExceptionCode);
        if (connType == BluetoothSocket.TYPE_L2CAP_LE) {
            try {
                final SynchronousResultReceiver recv = SynchronousResultReceiver.get();
                bluetoothProxy.logL2capcocClientConnection(
                        device,
                        port,
                        auth,
                    errCode,
                        getL2capLeConnectStatusCode(socketExceptionCode),
                        socketCreationTimeNanos, // to calculate end to end latency
                        socketCreationLatencyNanos, // latency of the constructor
                        socketConnectionTimeNanos, // to calculate the latency of connect()
                        recv);
                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
            } catch (RemoteException | TimeoutException e) {
            Log.w(TAG, "logL2capcocClientConnection failed", 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 {
                final SynchronousResultReceiver recv = SynchronousResultReceiver.get();
                bluetoothProxy.logRfcommConnectionAttempt(
                        device,
                        auth,
                        getRfcommConnectStatusCode(socketExceptionCode),
                        socketCreationTimeNanos, // to calculate end to end latency
                        isSerialPort,
                        recv);
                recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
            } catch (RemoteException | TimeoutException e) {
                Log.w(TAG, "logL2capcocServerConnection failed", e);
            }
        } else {
            Log.d(TAG, "No metrics for connection type " + connType);
        }
    }

@@ -134,4 +159,25 @@ class SocketMetrics {
                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;
        }
    }
}