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

Commit 918489e2 authored by William Escande's avatar William Escande
Browse files

MetricsLogger: listen to connection change

AdapterProperties was listening to intent in order to log, this is
exactly the role of the MetricsLogger to listen on event and generates
appropriate logs. The AdapterProperties has nothing to do with that.
So I am moving the code there

Test: atest BluetoothInstrumentationTests
Bug: 311772251
Flag: Exempt refactor moving code without op change
Change-Id: I3ca86dcf0084ebdb39b9be9aefe3466f6f9f5457
parent 483729b9
Loading
Loading
Loading
Loading
+0 −126
Original line number Diff line number Diff line
@@ -23,31 +23,17 @@ import static android.Manifest.permission.BLUETOOTH_SCAN;
import android.annotation.NonNull;
import android.app.BroadcastOptions;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAvrcpController;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothHidDevice;
import android.bluetooth.BluetoothHidHost;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothPbapClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothSap;
import android.bluetooth.BufferConstraint;
import android.bluetooth.BufferConstraints;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -147,70 +133,6 @@ class AdapterProperties {
    private boolean mIsLeIsochronousBroadcasterSupported;
    private boolean mIsLeChannelSoundingSupported;

    private boolean mReceiverRegistered;

    private final BroadcastReceiver mReceiver =
            new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (action == null) {
                        Log.w(TAG, "Received intent with null action");
                        return;
                    }
                    switch (action) {
                        case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HEADSET, intent);
                            break;
                        case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.A2DP, intent);
                            break;
                        case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HEADSET_CLIENT, intent);
                            break;
                        case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HEARING_AID, intent);
                            break;
                        case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.A2DP_SINK, intent);
                            break;
                        case BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HID_DEVICE, intent);
                            break;
                        case BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HID_HOST, intent);
                            break;
                        case BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.AVRCP_CONTROLLER, intent);
                            break;
                        case BluetoothPan.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.PAN, intent);
                            break;
                        case BluetoothMap.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.MAP, intent);
                            break;
                        case BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.MAP_CLIENT, intent);
                            break;
                        case BluetoothSap.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.SAP, intent);
                            break;
                        case BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.PBAP_CLIENT, intent);
                            break;
                        case BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.PBAP, intent);
                            break;
                        case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.LE_AUDIO, intent);
                            break;
                        default:
                            Log.w(TAG, "Received unknown intent " + intent);
                            break;
                    }
                }
            };

    // Lock for all getters and setters.
    // If finer grained locking is needer, more locks
    // can be added here.
@@ -258,34 +180,12 @@ class AdapterProperties {
                SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false)
                        && !SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);

        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
        mService.registerReceiver(mReceiver, filter);
        mReceiverRegistered = true;
        invalidateBluetoothCaches();
    }

    public void cleanup() {
        mProfileConnectionState.clear();

        if (mReceiverRegistered) {
            mService.unregisterReceiver(mReceiver);
            mReceiverRegistered = false;
        }
        mBondedDevices.clear();
        invalidateBluetoothCaches();
    }
@@ -709,32 +609,6 @@ class AdapterProperties {
        return mDiscovering;
    }

    private void logConnectionStateChanges(int profile, Intent connIntent) {
        BluetoothDevice device = connIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        int state = connIntent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
        int metricId = mService.getMetricId(device);
        byte[] remoteDeviceInfoBytes = MetricsLogger.getInstance().getRemoteDeviceInfoProto(device);
        if (state == BluetoothProfile.STATE_CONNECTING) {
            String deviceName = mRemoteDevices.getName(device);
            BluetoothStatsLog.write(
                    BluetoothStatsLog.BLUETOOTH_DEVICE_NAME_REPORTED, metricId, deviceName);
            BluetoothStatsLog.write(
                    BluetoothStatsLog.REMOTE_DEVICE_INFORMATION_WITH_METRIC_ID,
                    metricId,
                    remoteDeviceInfoBytes);

            MetricsLogger.getInstance().logAllowlistedDeviceNameHash(metricId, deviceName, true);
        }
        BluetoothStatsLog.write(
                BluetoothStatsLog.BLUETOOTH_CONNECTION_STATE_CHANGED,
                state,
                0 /* deprecated */,
                profile,
                mService.obfuscateAddress(device),
                metricId,
                0,
                -1);
    }

    void updateOnProfileConnectionChanged(
            BluetoothDevice device, int profile, int newState, int prevState) {
+2 −25
Original line number Diff line number Diff line
@@ -335,8 +335,6 @@ public class AdapterService extends Service {

    private volatile boolean mTestModeEnabled = false;

    private MetricsLogger mMetricsLogger;

    /** Handlers for incoming service calls */
    private AdapterServiceBinder mBinder;

@@ -646,7 +644,6 @@ public class AdapterService extends Service {
    private void init() {
        Log.d(TAG, "init()");
        Config.init(this);
        initMetricsLogger();
        mDeviceConfigListener.start();

        if (!Flags.fastBindToApp()) {
@@ -658,6 +655,7 @@ public class AdapterService extends Service {
            mCompanionDeviceManager = getNonNullSystemService(CompanionDeviceManager.class);
            mRemoteDevices = new RemoteDevices(this, mLooper);
        }
        MetricsLogger.getInstance().init(this, mRemoteDevices);

        clearDiscoveringPackages();
        if (!Flags.fastBindToApp()) {
@@ -822,23 +820,6 @@ public class AdapterService extends Service {
        return mSilenceDeviceManager;
    }

    private boolean initMetricsLogger() {
        if (mMetricsLogger != null) {
            return false;
        }
        mMetricsLogger = MetricsLogger.getInstance();
        return mMetricsLogger.init(this);
    }

    private boolean closeMetricsLogger() {
        if (mMetricsLogger == null) {
            return false;
        }
        boolean result = mMetricsLogger.close();
        mMetricsLogger = null;
        return result;
    }

    /**
     * Log L2CAP CoC Server Connection Metrics
     *
@@ -891,10 +872,6 @@ public class AdapterService extends Service {
                socketAcceptanceLatencyMillis);
    }

    public void setMetricsLogger(MetricsLogger metricsLogger) {
        mMetricsLogger = metricsLogger;
    }

    /**
     * Log L2CAP CoC Client Connection Metrics
     *
@@ -1457,7 +1434,7 @@ public class AdapterService extends Service {
            return;
        }

        closeMetricsLogger();
        MetricsLogger.getInstance().close();

        clearAdapterService(this);

+134 −7
Original line number Diff line number Diff line
@@ -18,9 +18,28 @@ package com.android.bluetooth.btservice;
import static com.android.bluetooth.BtRestrictedStatsLog.RESTRICTED_BLUETOOTH_DEVICE_NAME_REPORTED;

import android.app.AlarmManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothAvrcpController;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothHidDevice;
import android.bluetooth.BluetoothHidHost;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothPbapClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.BluetoothSap;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;
@@ -71,6 +90,7 @@ public class MetricsLogger {
    HashMap<Integer, Long> mCounters = new HashMap<>();
    private static volatile MetricsLogger sInstance = null;
    private AdapterService mAdapterService = null;
    private RemoteDevices mRemoteDevices = null;
    private AlarmManager mAlarmManager = null;
    private boolean mInitialized = false;
    private static final Object sLock = new Object();
@@ -111,7 +131,8 @@ public class MetricsLogger {
        }
    }

    public boolean isInitialized() {
    @VisibleForTesting
    boolean isInitialized() {
        return mInitialized;
    }

@@ -151,12 +172,13 @@ public class MetricsLogger {
        mBloomFilter = bloomfilter;
    }

    public boolean init(AdapterService adapterService) {
    void init(AdapterService adapterService, RemoteDevices remoteDevices) {
        if (mInitialized) {
            return false;
            return;
        }
        mInitialized = true;
        mAdapterService = adapterService;
        mRemoteDevices = remoteDevices;
        scheduleDrains();
        if (!initBloomFilter(BLOOMFILTER_FULL_PATH)) {
            Log.w(TAG, "MetricsLogger can't initialize the bloomfilter");
@@ -164,7 +186,112 @@ public class MetricsLogger {
            // We still want to use this class even if the bloomfilter isn't initialized
            // so still return true here.
        }
        return true;
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
        mAdapterService.registerReceiver(mReceiver, filter);
    }

    private final BroadcastReceiver mReceiver =
            new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (action == null) {
                        Log.w(TAG, "Received intent with null action");
                        return;
                    }
                    switch (action) {
                        case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HEADSET, intent);
                            break;
                        case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.A2DP, intent);
                            break;
                        case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HEADSET_CLIENT, intent);
                            break;
                        case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HEARING_AID, intent);
                            break;
                        case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.A2DP_SINK, intent);
                            break;
                        case BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HID_DEVICE, intent);
                            break;
                        case BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.HID_HOST, intent);
                            break;
                        case BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.AVRCP_CONTROLLER, intent);
                            break;
                        case BluetoothPan.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.PAN, intent);
                            break;
                        case BluetoothMap.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.MAP, intent);
                            break;
                        case BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.MAP_CLIENT, intent);
                            break;
                        case BluetoothSap.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.SAP, intent);
                            break;
                        case BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.PBAP_CLIENT, intent);
                            break;
                        case BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.PBAP, intent);
                            break;
                        case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
                            logConnectionStateChanges(BluetoothProfile.LE_AUDIO, intent);
                            break;
                        default:
                            Log.w(TAG, "Received unknown intent " + intent);
                            break;
                    }
                }
            };

    private void logConnectionStateChanges(int profile, Intent connIntent) {
        BluetoothDevice device = connIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        int state = connIntent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
        int metricId = mAdapterService.getMetricId(device);
        byte[] remoteDeviceInfoBytes = getRemoteDeviceInfoProto(device);
        if (state == BluetoothProfile.STATE_CONNECTING) {
            String deviceName = mRemoteDevices.getName(device);
            BluetoothStatsLog.write(
                    BluetoothStatsLog.BLUETOOTH_DEVICE_NAME_REPORTED, metricId, deviceName);
            BluetoothStatsLog.write(
                    BluetoothStatsLog.REMOTE_DEVICE_INFORMATION_WITH_METRIC_ID,
                    metricId,
                    remoteDeviceInfoBytes);

            logAllowlistedDeviceNameHash(metricId, deviceName, true);
        }
        BluetoothStatsLog.write(
                BluetoothStatsLog.BLUETOOTH_CONNECTION_STATE_CHANGED,
                state,
                0 /* deprecated */,
                profile,
                mAdapterService.obfuscateAddress(device),
                metricId,
                0,
                -1);
    }

    public boolean cacheCount(int key, long count) {
@@ -260,18 +387,18 @@ public class MetricsLogger {
        }
    }

    public boolean close() {
    void close() {
        if (!mInitialized) {
            return false;
            return;
        }
        Log.d(TAG, "close()");
        mAdapterService.unregisterReceiver(mReceiver);
        cancelPendingDrain();
        drainBufferedCounters();
        mAlarmManager = null;
        mAdapterService = null;
        mInitialized = false;
        mBloomFilterInitialized = false;
        return true;
    }

    protected void cancelPendingDrain() {
+5 −7
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -174,7 +173,6 @@ public class BassClientStateMachineTest {
        doNothing()
                .when(mMethodProxy)
                .periodicAdvertisingManagerTransferSync(any(), any(), anyInt(), anyInt());
        MetricsLogger.getInstance();
        MetricsLogger.setInstanceForTesting(mMetricsLogger);

        // Get a device for testing
@@ -2496,7 +2494,7 @@ public class BassClientStateMachineTest {
                BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_CODE_REQUIRED,
                0x0L);
        // Verify broadcast audio session is logged when pa no past
        verify(mMetricsLogger, times(1))
        verify(mMetricsLogger)
                .logLeAudioBroadcastAudioSync(
                        eq(mTestDevice),
                        eq(TEST_BROADCAST_ID),
@@ -2519,7 +2517,7 @@ public class BassClientStateMachineTest {
                BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE,
                0x0L);
        // Verify broadcast audio session is logged when big encryption failed
        verify(mMetricsLogger, times(1))
        verify(mMetricsLogger)
                .logLeAudioBroadcastAudioSync(
                        eq(mTestDevice),
                        eq(TEST_BROADCAST_ID),
@@ -2542,7 +2540,7 @@ public class BassClientStateMachineTest {
                BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING,
                BassConstants.BIS_SYNC_FAILED_SYNC_TO_BIG);
        // Verify broadcast audio session is logged when bis sync failed
        verify(mMetricsLogger, times(1))
        verify(mMetricsLogger)
                .logLeAudioBroadcastAudioSync(
                        eq(mTestDevice),
                        eq(TEST_BROADCAST_ID),
@@ -2579,7 +2577,7 @@ public class BassClientStateMachineTest {
                0x0L);

        // Verify broadcast audio session is logged when source removed
        verify(mMetricsLogger, times(1))
        verify(mMetricsLogger)
                .logLeAudioBroadcastAudioSync(
                        eq(mTestDevice),
                        eq(TEST_BROADCAST_ID),
@@ -2608,7 +2606,7 @@ public class BassClientStateMachineTest {
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());

        // Verify broadcast audio session is logged when source removed
        verify(mMetricsLogger, times(1))
        verify(mMetricsLogger)
                .logLeAudioBroadcastAudioSync(
                        eq(mTestDevice),
                        eq(TEST_BROADCAST_ID),
+2 −4
Original line number Diff line number Diff line
@@ -322,13 +322,10 @@ public class AdapterServiceTest {
        when(mMockService.getName()).thenReturn("Service1");
        when(mMockService2.getName()).thenReturn("Service2");

        when(mMockMetricsLogger.init(any())).thenReturn(true);
        when(mMockMetricsLogger.close()).thenReturn(true);

        configureEnabledProfiles();
        Config.init(mMockContext);

        mAdapterService.setMetricsLogger(mMockMetricsLogger);
        MetricsLogger.setInstanceForTesting(mMockMetricsLogger);

        // Attach a context to the service for permission checks.
        mAdapterService.attach(mMockContext, null, null, null, mApplication, null);
@@ -358,6 +355,7 @@ public class AdapterServiceTest {
        GattNativeInterface.setInstance(null);
        PeriodicScanNativeInterface.setInstance(null);
        ScanNativeInterface.setInstance(null);
        MetricsLogger.setInstanceForTesting(null);
    }

    private void syncHandler(int... what) {
Loading