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

Commit 73e5f173 authored by hughchen's avatar hughchen
Browse files

Fix deadlock in CachedBluetoothDeviceManager

Following deadlock exist in previous code:

1. Main thread:
Device.refresh() -> Device.dispatchCallback() -> Lock callback
-> (handle callback in systemui) -> DeviceManager.getDevicesCopy()
-> try lock deviceManager

2. Bg thread:
DeviceManager.onActiveDeviceChanged() -> Lock deviceManager ->
Device.dispatchCallback() -> try lock callback

This CL remove sychnorized method in DeviceManager to unblock this
deadlock.

Fixes: 143373496
Test: Manual
Change-Id: Ib17d99a8d797e4e514e965541a04a520f89edad5
parent ff671494
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -212,15 +212,21 @@ public class BluetoothEventManager {
    }

    private void dispatchAudioModeChanged() {
        mDeviceManager.dispatchAudioModeChanged();
        for (CachedBluetoothDevice cachedDevice : mDeviceManager.getCachedDevicesCopy()) {
            cachedDevice.onAudioModeChanged();
        }
        for (BluetoothCallback callback : mCallbacks) {
            callback.onAudioModeChanged();
        }
    }

    private void dispatchActiveDeviceChanged(CachedBluetoothDevice activeDevice,
    @VisibleForTesting
    void dispatchActiveDeviceChanged(CachedBluetoothDevice activeDevice,
            int bluetoothProfile) {
        mDeviceManager.onActiveDeviceChanged(activeDevice, bluetoothProfile);
        for (CachedBluetoothDevice cachedDevice : mDeviceManager.getCachedDevicesCopy()) {
            boolean isActive = Objects.equals(cachedDevice, activeDevice);
            cachedDevice.onActiveDeviceChanged(isActive, bluetoothProfile);
        }
        for (BluetoothCallback callback : mCallbacks) {
            callback.onActiveDeviceChanged(activeDevice, bluetoothProfile);
        }
+0 −15
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
@@ -229,14 +228,6 @@ public class CachedBluetoothDeviceManager {
        }
    }

    public synchronized void onActiveDeviceChanged(CachedBluetoothDevice activeDevice,
            int bluetoothProfile) {
        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
            boolean isActive = Objects.equals(cachedDevice, activeDevice);
            cachedDevice.onActiveDeviceChanged(isActive, bluetoothProfile);
        }
    }

    public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
            cachedDevice, int state) {
        return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
@@ -257,12 +248,6 @@ public class CachedBluetoothDeviceManager {
        }
    }

    public synchronized void dispatchAudioModeChanged() {
        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
            cachedDevice.onAudioModeChanged();
        }
    }

    private void log(String msg) {
        if (DEBUG) {
            Log.d(TAG, msg);
+150 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
package com.android.settingslib.bluetooth;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -41,6 +43,9 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

import java.util.ArrayList;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
public class BluetoothEventManagerTest {

@@ -54,10 +59,24 @@ public class BluetoothEventManagerTest {
    private CachedBluetoothDevice mCachedBluetoothDevice;
    @Mock
    private BluetoothDevice mBluetoothDevice;
    @Mock
    private HeadsetProfile mHfpProfile;
    @Mock
    private A2dpProfile mA2dpProfile;
    @Mock
    private HearingAidProfile mHearingAidProfile;
    @Mock
    private BluetoothDevice mDevice1;
    @Mock
    private BluetoothDevice mDevice2;
    @Mock
    private LocalBluetoothProfileManager mLocalProfileManager;

    private Context mContext;
    private Intent mIntent;
    private BluetoothEventManager mBluetoothEventManager;
    private CachedBluetoothDevice mCachedDevice1;
    private CachedBluetoothDevice mCachedDevice2;

    @Before
    public void setUp() {
@@ -67,6 +86,12 @@ public class BluetoothEventManagerTest {
        mBluetoothEventManager = new BluetoothEventManager(mLocalAdapter,
                mCachedDeviceManager, mContext, /* handler= */ null, /* userHandle= */ null);
        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
        when(mHfpProfile.isProfileReady()).thenReturn(true);
        when(mA2dpProfile.isProfileReady()).thenReturn(true);
        when(mHearingAidProfile.isProfileReady()).thenReturn(true);

        mCachedDevice1 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1);
        mCachedDevice2 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2);
    }

    @Test
@@ -194,4 +219,129 @@ public class BluetoothEventManagerTest {
        verify(mBluetoothCallback, never()).onAclConnectionStateChanged(mCachedBluetoothDevice,
                BluetoothAdapter.STATE_CONNECTED);
    }

    /**
     * Test to verify onActiveDeviceChanged().
     */
    @Test
    public void dispatchActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
        final List<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
        cachedDevices.add(mCachedDevice1);
        cachedDevices.add(mCachedDevice2);

        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);

        // Connect both devices for A2DP and HFP
        mCachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
        mCachedDevice2.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
        mCachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
        mCachedDevice2.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);

        // Verify that both devices are connected and none is Active
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();

        // The first device is active for A2DP, the second device is active for HFP
        mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.A2DP);
        mBluetoothEventManager
                .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET);
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();

        // The first device is active for A2DP and HFP
        mBluetoothEventManager
                .dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.HEADSET);
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();

        // The second device is active for A2DP and HFP
        mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.A2DP);
        mBluetoothEventManager
                .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET);
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();

        // No active device for A2DP
        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.A2DP);
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();

        // No active device for HFP
        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEADSET);
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
    }

    /**
     * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.
     */
    @Test
    public void dispatchActiveDeviceChanged_withA2dpAndHearingAid() {
        final List<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
        cachedDevices.add(mCachedDevice1);
        cachedDevices.add(mCachedDevice2);

        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);

        // Connect device1 for A2DP and HFP and device2 for Hearing Aid
        mCachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
        mCachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
        mCachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);

        // Verify that both devices are connected and none is Active
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();

        // The first device is active for A2DP and HFP
        mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.A2DP);
        mBluetoothEventManager
                .dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.HEADSET);
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();

        // The second device is active for Hearing Aid and the first device is not active
        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.A2DP);
        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEADSET);
        mBluetoothEventManager
                .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEARING_AID);
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isTrue();

        // No active device for Hearing Aid
        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEARING_AID);
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
    }
}
+0 −123
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;

import org.junit.Before;
@@ -50,8 +49,6 @@ public class CachedBluetoothDeviceManagerTest {
    private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11";
    private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
    private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33";
    private final static String DEVICE_SUMMARY_1 = "summary 1";
    private final static String DEVICE_SUMMARY_2 = "summary 2";
    private final static long HISYNCID1 = 10;
    private final static long HISYNCID2 = 11;
    private final BluetoothClass DEVICE_CLASS_1 =
@@ -401,124 +398,4 @@ public class CachedBluetoothDeviceManagerTest {
        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
        assertThat(mCachedDeviceManager.onDeviceDisappeared(cachedDevice1)).isTrue();
    }

    /**
     * Test to verify onActiveDeviceChanged().
     */
    @Test
    public void onActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        assertThat(cachedDevice1).isNotNull();
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
        assertThat(cachedDevice2).isNotNull();

        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);

        // Connect both devices for A2DP and HFP
        cachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
        cachedDevice2.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
        cachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
        cachedDevice2.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);

        // Verify that both devices are connected and none is Active
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();

        // The first device is active for A2DP, the second device is active for HFP
        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.A2DP);
        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEADSET);
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();

        // The first device is active for A2DP and HFP
        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.HEADSET);
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();

        // The second device is active for A2DP and HFP
        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.A2DP);
        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEADSET);
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();

        // No active device for A2DP
        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.A2DP);
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();

        // No active device for HFP
        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEADSET);
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
    }

    /**
     * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.
     */
    @Test
    public void onActiveDeviceChanged_withA2dpAndHearingAid() {
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        assertThat(cachedDevice1).isNotNull();
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
        assertThat(cachedDevice2).isNotNull();

        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);

        // Connect device1 for A2DP and HFP and device2 for Hearing Aid
        cachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
        cachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
        cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);

        // Verify that both devices are connected and none is Active
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();

        // The first device is active for A2DP and HFP
        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.A2DP);
        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.HEADSET);
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();

        // The second device is active for Hearing Aid and the first device is not active
        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.A2DP);
        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEADSET);
        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEARING_AID);
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isTrue();

        // No active device for Hearing Aid
        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEARING_AID);
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
    }
}