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

Commit a2b755de authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Gerrit Code Review
Browse files

Merge "leaudio: Fix authorization on MCS/TBS after unbonding" into main

parents 02e0b61e d46d54a7
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -2875,6 +2875,7 @@ public class LeAudioService extends ProfileService {
                return;
            }
            removeStateMachine(device);
            removeAuthorizationInfoForRelatedProfiles(device);
        }
    }

@@ -2962,6 +2963,7 @@ public class LeAudioService extends ProfileService {
                Log.d(TAG, device + " is unbond. Remove state machine");
            }
            removeStateMachine(device);
            removeAuthorizationInfoForRelatedProfiles(device);
        }

        if (!isScannerNeeded()) {
@@ -3341,6 +3343,23 @@ public class LeAudioService extends ProfileService {
        }
    }

    void removeAuthorizationInfoForRelatedProfiles(BluetoothDevice device) {
        if (!mFeatureFlags.leaudioMcsTbsAuthorizationRebondFix()) {
            Log.i(TAG, "leaudio_mcs_tbs_authorization_rebond_fix is disabled");
            return;
        }

        McpService mcpService = getMcpService();
        if (mcpService != null) {
            mcpService.removeDeviceAuthorizationInfo(device);
        }

        TbsService tbsService = getTbsService();
        if (tbsService != null) {
            tbsService.removeDeviceAuthorizationInfo(device);
        }
    }

    /**
     * This function is called when the framework registers a callback with the service for this
     * first time. This is used as an indication that Bluetooth has been enabled.
@@ -3499,6 +3518,7 @@ public class LeAudioService extends ProfileService {
        }

        setAuthorizationForRelatedProfiles(device, false);
        removeAuthorizationInfoForRelatedProfiles(device);
    }

    private void notifyGroupNodeRemoved(BluetoothDevice device, int groupId) {
+11 −0
Original line number Diff line number Diff line
@@ -200,6 +200,17 @@ public class McpService extends ProfileService {
        setDeviceAuthorized(device, false);
    }

    /**
     * Remove authorization information for the device.
     *
     * @param device device to remove from the service information
     * @hide
     */
    public void removeDeviceAuthorizationInfo(BluetoothDevice device) {
        Log.i(TAG, "removeDeviceAuthorizationInfo(): device: " + device);
        mDeviceAuthorizations.remove(device);
    }

    public void setDeviceAuthorized(BluetoothDevice device, boolean isAuthorized) {
        Log.i(TAG, "\tsetDeviceAuthorized(): device: " + device + ", isAuthorized: "
                + isAuthorized);
+11 −0
Original line number Diff line number Diff line
@@ -143,6 +143,17 @@ public class TbsService extends ProfileService {
        setDeviceAuthorized(device, false);
    }

    /**
     * Remove authorization information for the device.
     *
     * @param device device to remove from the service information
     * @hide
     */
    public void removeDeviceAuthorizationInfo(BluetoothDevice device) {
        Log.i(TAG, "removeDeviceAuthorizationInfo(): device: " + device);
        mDeviceAuthorizations.remove(device);
    }

    /**
     * Sets device authorization for TBS.
     *
+134 −0
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ public class LeAudioServiceTest {
        mFakeFlagsImpl.setFlag(Flags.FLAG_LEAUDIO_UNICAST_INACTIVATE_DEVICE_BASED_ON_CONTEXT, false);
        mFakeFlagsImpl.setFlag(Flags.FLAG_AUDIO_ROUTING_CENTRALIZATION, false);
        mFakeFlagsImpl.setFlag(Flags.FLAG_LEAUDIO_BROADCAST_AUDIO_HANDOVER_POLICIES, false);
        mFakeFlagsImpl.setFlag(Flags.FLAG_LEAUDIO_MCS_TBS_AUTHORIZATION_REBOND_FIX, false);
        mService.setFeatureFlags(mFakeFlagsImpl);

        mService.mAudioManager = mAudioManager;
@@ -804,6 +805,139 @@ public class LeAudioServiceTest {
        assertThat(mService.getDevices().contains(mLeftDevice)).isFalse();
    }

    /** Test that authorization info is removed from TBS and MCS after the device is unbond. */
    @Test
    public void testAuthorizationInfoRemovedFromTbsMcsOnUnbondEvents() {
        mFakeFlagsImpl.setFlag(Flags.FLAG_AUDIO_ROUTING_CENTRALIZATION, true);
        mFakeFlagsImpl.setFlag(Flags.FLAG_LEAUDIO_MCS_TBS_AUTHORIZATION_REBOND_FIX, true);

        // Update the device priority so okToConnect() returns true
        when(mDatabaseManager.getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.LE_AUDIO))
                .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        when(mDatabaseManager.getProfileConnectionPolicy(mRightDevice, BluetoothProfile.LE_AUDIO))
                .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
        when(mDatabaseManager.getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.LE_AUDIO))
                .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
        doReturn(true).when(mNativeInterface).disconnectLeAudio(any(BluetoothDevice.class));

        // Create device descriptor with connect request
        assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();

        // Unbond received in CONNECTION_STATE_CONNECTING state
        generateConnectionMessageFromNative(
                mLeftDevice,
                BluetoothProfile.STATE_CONNECTING,
                BluetoothProfile.STATE_DISCONNECTED);
        assertThat(mService.getConnectionState(mLeftDevice))
                .isEqualTo(BluetoothProfile.STATE_CONNECTING);
        assertThat(mService.getDevices().contains(mLeftDevice)).isTrue();

        // Device unbond
        doReturn(BluetoothDevice.BOND_NONE)
                .when(mAdapterService)
                .getBondState(any(BluetoothDevice.class));
        mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE);
        assertThat(mService.getDevices().contains(mLeftDevice)).isTrue();
        verifyConnectionStateIntent(
                TIMEOUT_MS,
                mLeftDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.STATE_CONNECTING);
        verify(mTbsService, times(1)).removeDeviceAuthorizationInfo(mLeftDevice);
        verify(mMcpService, times(1)).removeDeviceAuthorizationInfo(mLeftDevice);

        reset(mTbsService);
        reset(mMcpService);

        // Unbond received in CONNECTION_STATE_CONNECTED
        // Create device descriptor with connect request. To connect service,
        // device needs to be bonded
        doReturn(BluetoothDevice.BOND_BONDED)
                .when(mAdapterService)
                .getBondState(any(BluetoothDevice.class));
        assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();

        generateConnectionMessageFromNative(
                mLeftDevice,
                BluetoothProfile.STATE_CONNECTING,
                BluetoothProfile.STATE_DISCONNECTED);
        generateConnectionMessageFromNative(
                mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING);
        assertThat(mService.getConnectionState(mLeftDevice))
                .isEqualTo(BluetoothProfile.STATE_CONNECTED);

        assertThat(mService.getDevices().contains(mLeftDevice)).isTrue();

        // Device unbond
        doReturn(BluetoothDevice.BOND_NONE)
                .when(mAdapterService)
                .getBondState(any(BluetoothDevice.class));
        mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE);

        assertThat(mService.getDevices().contains(mLeftDevice)).isTrue();
        verifyConnectionStateIntent(
                TIMEOUT_MS,
                mLeftDevice,
                BluetoothProfile.STATE_DISCONNECTING,
                BluetoothProfile.STATE_CONNECTED);
        assertThat(mService.getConnectionState(mLeftDevice))
                .isEqualTo(BluetoothProfile.STATE_DISCONNECTING);
        assertThat(mService.getDevices().contains(mLeftDevice)).isTrue();
        verify(mTbsService, times(0)).removeDeviceAuthorizationInfo(mLeftDevice);
        verify(mMcpService, times(0)).removeDeviceAuthorizationInfo(mLeftDevice);

        reset(mTbsService);
        reset(mMcpService);

        // Inject CONNECTION_STATE_DISCONNECTED
        generateConnectionMessageFromNative(
                mLeftDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.STATE_DISCONNECTING);

        verify(mTbsService, times(1)).removeDeviceAuthorizationInfo(mLeftDevice);
        verify(mMcpService, times(1)).removeDeviceAuthorizationInfo(mLeftDevice);

        reset(mTbsService);
        reset(mMcpService);

        // Unbond received in CONNECTION_STATE_DISCONNECTED
        // Create device descriptor with connect request. To connect service,
        // device needs to be bonded
        doReturn(BluetoothDevice.BOND_BONDED)
                .when(mAdapterService)
                .getBondState(any(BluetoothDevice.class));
        assertWithMessage("Connect failed").that(mService.connect(mLeftDevice)).isTrue();

        generateConnectionMessageFromNative(
                mLeftDevice,
                BluetoothProfile.STATE_CONNECTING,
                BluetoothProfile.STATE_DISCONNECTED);
        generateConnectionMessageFromNative(
                mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING);
        assertThat(mService.getConnectionState(mLeftDevice))
                .isEqualTo(BluetoothProfile.STATE_CONNECTED);

        assertThat(mService.getDevices().contains(mLeftDevice)).isTrue();
        injectAndVerifyDeviceDisconnected(mLeftDevice);

        verify(mTbsService, times(0)).removeDeviceAuthorizationInfo(mLeftDevice);
        verify(mMcpService, times(0)).removeDeviceAuthorizationInfo(mLeftDevice);

        reset(mTbsService);
        reset(mMcpService);

        // Device unbond
        doReturn(BluetoothDevice.BOND_NONE)
                .when(mAdapterService)
                .getBondState(any(BluetoothDevice.class));
        mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE);

        verify(mTbsService, times(1)).removeDeviceAuthorizationInfo(mLeftDevice);
        verify(mMcpService, times(1)).removeDeviceAuthorizationInfo(mLeftDevice);
    }

    /**
     * Test that a CONNECTION_STATE_DISCONNECTED Le Audio stack event will remove the state
     * machine only if the device is unbond.