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

Commit 523961bb authored by Aritra Sen's avatar Aritra Sen Committed by Gerrit Code Review
Browse files

Merge "Move Profile connection state changes logic inside the handler to make...

Merge "Move Profile connection state changes logic inside the handler to make sure concurrent counter updates are handled correctly." into main
parents 0a9dd103 d984c29b
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.util.Log;
import com.android.bluetooth.Utils;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.flags.FeatureFlagsImpl;


/**
/**
 * Factory class for object initialization to help with unit testing
 * Factory class for object initialization to help with unit testing
@@ -70,7 +71,8 @@ public class GattObjectsFactory {


    public ScanManager createScanManager(GattService service, AdapterService adapterService,
    public ScanManager createScanManager(GattService service, AdapterService adapterService,
            BluetoothAdapterProxy bluetoothAdapterProxy) {
            BluetoothAdapterProxy bluetoothAdapterProxy) {
        return new ScanManager(service, adapterService, bluetoothAdapterProxy);
        return new ScanManager(
                service, adapterService, bluetoothAdapterProxy, new FeatureFlagsImpl());
    }
    }


    public PeriodicScanManager createPeriodicScanManager(AdapterService adapterService) {
    public PeriodicScanManager createPeriodicScanManager(AdapterService adapterService) {
+52 −3
Original line number Original line Diff line number Diff line
@@ -46,6 +46,7 @@ import android.view.Display;
import com.android.bluetooth.Utils;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.flags.FeatureFlags;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;


@@ -56,6 +57,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Iterator;
import java.util.Map;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Set;
import java.util.UUID;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentHashMap;
@@ -102,6 +104,7 @@ public class ScanManager {
    static final int MSG_REVERT_SCAN_MODE_UPGRADE = 9;
    static final int MSG_REVERT_SCAN_MODE_UPGRADE = 9;
    static final int MSG_START_CONNECTING = 10;
    static final int MSG_START_CONNECTING = 10;
    static final int MSG_STOP_CONNECTING = 11;
    static final int MSG_STOP_CONNECTING = 11;
    private static final int MSG_BT_PROFILE_CONN_STATE_CHANGED = 12;
    private static final String ACTION_REFRESH_BATCHED_SCAN =
    private static final String ACTION_REFRESH_BATCHED_SCAN =
            "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN";
            "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN";


@@ -118,6 +121,7 @@ public class ScanManager {
    private int mCurUsedTrackableAdvertisements = 0;
    private int mCurUsedTrackableAdvertisements = 0;
    private final GattService mService;
    private final GattService mService;
    private final AdapterService mAdapterService;
    private final AdapterService mAdapterService;
    private final FeatureFlags mFeatureFlags;
    private BroadcastReceiver mBatchAlarmReceiver;
    private BroadcastReceiver mBatchAlarmReceiver;
    private boolean mBatchAlarmReceiverRegistered;
    private boolean mBatchAlarmReceiverRegistered;
    private ScanNative mScanNative;
    private ScanNative mScanNative;
@@ -142,7 +146,8 @@ public class ScanManager {
    private final SparseBooleanArray mIsUidForegroundMap = new SparseBooleanArray();
    private final SparseBooleanArray mIsUidForegroundMap = new SparseBooleanArray();
    private boolean mScreenOn = false;
    private boolean mScreenOn = false;
    @VisibleForTesting boolean mIsConnecting;
    @VisibleForTesting boolean mIsConnecting;
    private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
    @VisibleForTesting int mProfilesConnecting;
    private int mProfilesConnected, mProfilesDisconnecting;


    @VisibleForTesting
    @VisibleForTesting
    static class UidImportance {
    static class UidImportance {
@@ -155,8 +160,11 @@ public class ScanManager {
        }
        }
    }
    }


    ScanManager(GattService service, AdapterService adapterService,
    ScanManager(
            BluetoothAdapterProxy bluetoothAdapterProxy) {
            GattService service,
            AdapterService adapterService,
            BluetoothAdapterProxy bluetoothAdapterProxy,
            FeatureFlags featureFlags) {
        mRegularScanClients =
        mRegularScanClients =
                Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
                Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
        mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
        mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
@@ -170,6 +178,7 @@ public class ScanManager {
        mLocationManager = mAdapterService.getSystemService(LocationManager.class);
        mLocationManager = mAdapterService.getSystemService(LocationManager.class);
        mBluetoothAdapterProxy = bluetoothAdapterProxy;
        mBluetoothAdapterProxy = bluetoothAdapterProxy;
        mIsConnecting = false;
        mIsConnecting = false;
        mFeatureFlags = Objects.requireNonNull(featureFlags, "Feature Flags cannot be null");


        mPriorityMap.put(ScanSettings.SCAN_MODE_OPPORTUNISTIC, 0);
        mPriorityMap.put(ScanSettings.SCAN_MODE_OPPORTUNISTIC, 0);
        mPriorityMap.put(ScanSettings.SCAN_MODE_SCREEN_OFF, 1);
        mPriorityMap.put(ScanSettings.SCAN_MODE_SCREEN_OFF, 1);
@@ -374,6 +383,8 @@ public class ScanManager {
                case MSG_STOP_CONNECTING:
                case MSG_STOP_CONNECTING:
                    handleClearConnectingState();
                    handleClearConnectingState();
                    break;
                    break;
                case MSG_BT_PROFILE_CONN_STATE_CHANGED:
                    handleProfileConnectionStateChanged(msg);
                default:
                default:
                    // Shouldn't happen.
                    // Shouldn't happen.
                    Log.e(TAG, "received an unkown message : " + msg.what);
                    Log.e(TAG, "received an unkown message : " + msg.what);
@@ -899,6 +910,31 @@ public class ScanManager {
                mScanNative.configureRegularScanParams();
                mScanNative.configureRegularScanParams();
            }
            }
        }
        }

        private void handleProfileConnectionStateChanged(Message msg) {
            int fromState = msg.arg1, toState = msg.arg2;
            int profile = ((Integer) msg.obj).intValue();
            boolean updatedConnectingState =
                    updateCountersAndCheckForConnectingState(toState, fromState);
            if (DBG) {
                Log.d(
                        TAG,
                        "PROFILE_CONNECTION_STATE_CHANGE:"
                                + (" profile=" + BluetoothProfile.getProfileName(profile))
                                + (" prevState=" + fromState)
                                + (" state=" + toState)
                                + (" updatedConnectingState = " + updatedConnectingState));
            }
            if (updatedConnectingState) {
                if (!mIsConnecting) {
                    handleConnectingState();
                }
            } else {
                if (mIsConnecting) {
                    handleClearConnectingState();
                }
            }
        }
    }
    }


    /**
    /**
@@ -2011,6 +2047,19 @@ public class ScanManager {
     */
     */
    public void handleBluetoothProfileConnectionStateChanged(
    public void handleBluetoothProfileConnectionStateChanged(
            int profile, int fromState, int toState) {
            int profile, int fromState, int toState) {
        if (mFeatureFlags.enableQueuingProfileConnectionChange()) {
            if (mHandler == null) {
                Log.d(TAG, "handleBluetoothProfileConnectionStateChanged: mHandler is null.");
                return;
            }
            mHandler.obtainMessage(
                            MSG_BT_PROFILE_CONN_STATE_CHANGED,
                            fromState,
                            toState,
                            Integer.valueOf(profile))
                    .sendToTarget();
            return;
        }
        boolean updatedConnectingState =
        boolean updatedConnectingState =
                updateCountersAndCheckForConnectingState(toState, fromState);
                updateCountersAndCheckForConnectingState(toState, fromState);
        if (DBG) {
        if (DBG) {
+49 −1
Original line number Original line Diff line number Diff line
@@ -68,11 +68,14 @@ import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.flags.FakeFeatureFlagsImpl;
import com.android.bluetooth.flags.Flags;
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.IBatteryStats;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;


import org.junit.After;
import org.junit.After;
@@ -124,6 +127,7 @@ public class ScanManagerTest {
    @Mock private ScanNativeInterface mScanNativeInterface;
    @Mock private ScanNativeInterface mScanNativeInterface;
    @Mock private MetricsLogger  mMetricsLogger;
    @Mock private MetricsLogger  mMetricsLogger;


    private FakeFeatureFlagsImpl mFakeFlagsImpl;
    private MockContentResolver mMockContentResolver;
    private MockContentResolver mMockContentResolver;
    @Captor ArgumentCaptor<Long> mScanDurationCaptor;
    @Captor ArgumentCaptor<Long> mScanDurationCaptor;


@@ -181,7 +185,10 @@ public class ScanManagerTest {
        doReturn(mTargetContext.getUser()).when(mMockGattService).getUser();
        doReturn(mTargetContext.getUser()).when(mMockGattService).getUser();
        doReturn(mTargetContext.getPackageName()).when(mMockGattService).getPackageName();
        doReturn(mTargetContext.getPackageName()).when(mMockGattService).getPackageName();


        mScanManager = new ScanManager(mMockGattService, mAdapterService, mBluetoothAdapterProxy);
        mFakeFlagsImpl = new FakeFeatureFlagsImpl();
        mScanManager =
                new ScanManager(
                        mMockGattService, mAdapterService, mBluetoothAdapterProxy, mFakeFlagsImpl);


        mHandler = mScanManager.getClientHandler();
        mHandler = mScanManager.getClientHandler();
        assertThat(mHandler).isNotNull();
        assertThat(mHandler).isNotNull();
@@ -1360,6 +1367,10 @@ public class ScanManagerTest {


    @Test
    @Test
    public void profileConnectionStateChanged_sendStartConnectionMessage() {
    public void profileConnectionStateChanged_sendStartConnectionMessage() {
        // This test shouldn't be impacted by this flag. Setting it to false to ensure it passes
        // with the older behavior. Tested flag set to true locally to make sure it doesn't fail
        // when flag is removed.
        mFakeFlagsImpl.setFlag(Flags.FLAG_ENABLE_QUEUING_PROFILE_CONNECTION_CHANGE, false);
        // Set scan downgrade duration through Mock
        // Set scan downgrade duration through Mock
        when(mAdapterService.getScanDowngradeDurationMillis())
        when(mAdapterService.getScanDowngradeDurationMillis())
                .thenReturn((long) DELAY_SCAN_DOWNGRADE_DURATION_MS);
                .thenReturn((long) DELAY_SCAN_DOWNGRADE_DURATION_MS);
@@ -1374,4 +1385,41 @@ public class ScanManagerTest {
        TestUtils.waitForLooperToBeIdle(mHandler.getLooper());
        TestUtils.waitForLooperToBeIdle(mHandler.getLooper());
        assertThat(mScanManager.mIsConnecting).isTrue();
        assertThat(mScanManager.mIsConnecting).isTrue();
    }
    }

    @Test
    public void multipleProfileConnectionStateChanged_updateCountersCorrectly()
            throws ExecutionException, InterruptedException {
        mFakeFlagsImpl.setFlag(Flags.FLAG_ENABLE_QUEUING_PROFILE_CONNECTION_CHANGE, true);
        when(mAdapterService.getScanDowngradeDurationMillis())
                .thenReturn((long) DELAY_SCAN_DOWNGRADE_DURATION_MS);
        assertThat(mScanManager.mIsConnecting).isFalse();

        Thread t1 =
                new Thread(
                        () ->
                                mScanManager.handleBluetoothProfileConnectionStateChanged(
                                        BluetoothProfile.A2DP,
                                        BluetoothProfile.STATE_DISCONNECTED,
                                        BluetoothProfile.STATE_CONNECTING));
        Thread t2 =
                new Thread(
                        () ->
                                mScanManager.handleBluetoothProfileConnectionStateChanged(
                                        BluetoothProfile.HEADSET,
                                        BluetoothProfile.STATE_DISCONNECTED,
                                        BluetoothProfile.STATE_CONNECTING));

        // Connect 3 profiles concurrently.
        t1.start();
        t2.start();
        mScanManager.handleBluetoothProfileConnectionStateChanged(
                BluetoothProfile.HID_HOST,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.STATE_CONNECTING);

        t1.join();
        t2.join();
        TestUtils.waitForLooperToBeIdle(mHandler.getLooper());
        assertThat(mScanManager.mProfilesConnecting).isEqualTo(3);
    }
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@ aconfig_declarations {
    name: "bluetooth_aconfig_flags",
    name: "bluetooth_aconfig_flags",
    package: "com.android.bluetooth.flags",
    package: "com.android.bluetooth.flags",
    srcs: [
    srcs: [
        "gatt.aconfig",
        "hap.aconfig",
        "hap.aconfig",
        "hfp.aconfig",
        "hfp.aconfig",
        "leaudio.aconfig",
        "leaudio.aconfig",

flags/gatt.aconfig

0 → 100644
+8 −0
Original line number Original line Diff line number Diff line
package: "com.android.bluetooth.flags"

flag {
    name: "enable_queuing_profile_connection_change"
    namespace: "bluetooth"
    description: "Queue Profile connection change events on the ClientHandler for Scan Manager"
    bug: "306033108"
}