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

Commit 7b738d68 authored by Weilin Xu's avatar Weilin Xu
Browse files

Add exception and conversion tests for HIDL client

Unit tests when HAL throws exception and when non-current user calls
methods that modify HAL status were added for broadcast radio HIDL
2.0 HAL client. Also added tests for conversion utlis methods about
converting for program info and program list chunk.

Bug: 262583864
Test: atest com.android.server.broadcastradio.hal2
Change-Id: Ieaff5f54861b2e794d18c283d4740d7e447c52b9
parent 3af3d47f
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -166,6 +166,18 @@ public final class BroadcastRadioServiceHidlTest extends ExtendedRadioMockitoTes
                .that(thrown).hasMessageThat().contains("Cannot open session for non-current user");
    }

    @Test
    public void openSession_withoutAudio_fails() throws Exception {
        createBroadcastRadioService();

        IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
                () -> mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID,
                        /* legacyConfig= */ null, /* withAudio= */ false, mTunerCallbackMock));

        assertWithMessage("Exception for opening session without audio")
                .that(thrown).hasMessageThat().contains("not supported");
    }

    @Test
    public void addAnnouncementListener_addsOnAllRadioModules() throws Exception {
        createBroadcastRadioService();
+11 −7
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.hardware.radio.RadioMetadata;
import android.util.ArrayMap;

import java.util.ArrayList;
import java.util.HashMap;

final class TestUtils {

@@ -43,19 +42,24 @@ final class TestUtils {
                /* dabFrequencyTable= */ null, /* vendorInfo= */ null);
    }

    static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector, int signalQuality) {
    static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector,
            ProgramSelector.Identifier logicallyTunedTo,
            ProgramSelector.Identifier physicallyTunedTo, int signalQuality) {
        return new RadioManager.ProgramInfo(selector,
                selector.getPrimaryId(), selector.getPrimaryId(), /* relatedContents= */ null,
                logicallyTunedTo, physicallyTunedTo, /* relatedContents= */ null,
                /* infoFlags= */ 0, signalQuality,
                new RadioMetadata.Builder().build(), new ArrayMap<>());
    }

    static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector, int signalQuality) {
        return makeProgramInfo(selector, selector.getPrimaryId(), selector.getPrimaryId(),
                signalQuality);
    }

    static RadioManager.ProgramInfo makeProgramInfo(int programType,
            ProgramSelector.Identifier identifier, int signalQuality) {
        // Note: If you set new fields, check if programInfoToHal() needs to be updated as well.
        return new RadioManager.ProgramInfo(makeProgramSelector(programType, identifier), null,
                null, null, 0, signalQuality, new RadioMetadata.Builder().build(),
                new HashMap<String, String>());
        return makeProgramInfo(makeProgramSelector(programType, identifier),
                /* logicallyTunedTo= */ null, /* physicallyTunedTo= */ null, signalQuality);
    }

    static ProgramSelector makeFmSelector(long freq) {
+229 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
@@ -45,6 +46,8 @@ import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioTuner;
import android.os.ParcelableException;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;

@@ -62,6 +65,7 @@ import org.mockito.verification.VerificationWithTimeout;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
@@ -74,10 +78,10 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
            timeout(/* millis= */ 200);
    private static final int SIGNAL_QUALITY = 1;
    private static final long AM_FM_FREQUENCY_SPACING = 500;
    private static final long[] AM_FM_FREQUENCY_LIST = {97500, 98100, 99100};
    private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100};
    private static final RadioManager.FmBandDescriptor FM_BAND_DESCRIPTOR =
            new RadioManager.FmBandDescriptor(RadioManager.REGION_ITU_1, RadioManager.BAND_FM,
                    /* lowerLimit= */ 87500, /* upperLimit= */ 108000, /* spacing= */ 100,
                    /* lowerLimit= */ 87_500, /* upperLimit= */ 108_000, /* spacing= */ 100,
                    /* stereo= */ false, /* rds= */ false, /* ta= */ false, /* af= */ false,
                    /* ea= */ false);
    private static final RadioManager.BandConfig FM_BAND_CONFIG =
@@ -205,6 +209,17 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onConfigurationChanged(FM_BAND_CONFIG);
    }

    @Test
    public void setConfiguration_forNonCurrentUser_doesNotInvokesCallback() throws Exception {
        openAidlClients(/* numClients= */ 1);
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());

        mTunerSessions[0].setConfiguration(FM_BAND_CONFIG);

        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
                .onConfigurationChanged(FM_BAND_CONFIG);
    }

    @Test
    public void getConfiguration() throws Exception {
        openAidlClients(/* numClients= */ 1);
@@ -344,7 +359,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
    }

    @Test
    public void tune_forCurrentUser_doesNotTune() throws Exception {
    public void tune_forNonCurrentUser_doesNotTune() throws Exception {
        openAidlClients(/* numClients= */ 1);
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
@@ -357,6 +372,20 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
                .onCurrentProgramInfoChanged(tuneInfo);
    }

    @Test
    public void tune_withHalHasUnknownError_fails() throws Exception {
        openAidlClients(/* numClients= */ 1);
        ProgramSelector sel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
        doAnswer(invocation -> Result.UNKNOWN_ERROR).when(mHalTunerSessionMock).tune(any());

        ParcelableException thrown = assertThrows(ParcelableException.class, () -> {
            mTunerSessions[0].tune(sel);
        });

        assertWithMessage("Exception for tuning when HAL has unknown error")
                .that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
    }

    @Test
    public void step_withDirectionUp() throws Exception {
        long initFreq = AM_FM_FREQUENCY_LIST[1];
@@ -390,6 +419,34 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
                .onCurrentProgramInfoChanged(stepDownInfo);
    }

    @Test
    public void step_forNonCurrentUser_doesNotStep() throws Exception {
        long initFreq = AM_FM_FREQUENCY_LIST[1];
        ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq);
        openAidlClients(/* numClients= */ 1);
        mHalCurrentInfo = TestUtils.makeHalProgramInfo(
                Convert.programSelectorToHal(initialSel), SIGNAL_QUALITY);
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());

        mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);

        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
                .onCurrentProgramInfoChanged(any());
    }

    @Test
    public void step_withHalInInvalidState_fails() throws Exception {
        openAidlClients(/* numClients= */ 1);
        doAnswer(invocation -> Result.INVALID_STATE).when(mHalTunerSessionMock).step(anyBoolean());

        IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> {
            mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);
        });

        assertWithMessage("Exception for stepping when HAL is in invalid state")
                .that(thrown).hasMessageThat().contains(Result.toString(Result.INVALID_STATE));
    }

    @Test
    public void seek_withDirectionUp() throws Exception {
        long initFreq = AM_FM_FREQUENCY_LIST[2];
@@ -432,10 +489,43 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
                Convert.programSelectorToHal(initialSel), SIGNAL_QUALITY);

        mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);

        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
                .onCurrentProgramInfoChanged(seekUpInfo);
    }

    @Test
    public void seek_forNonCurrentUser_doesNotSeek() throws Exception {
        long initFreq = AM_FM_FREQUENCY_LIST[2];
        ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq);
        RadioManager.ProgramInfo seekUpInfo = TestUtils.makeProgramInfo(
                TestUtils.makeFmSelector(getSeekFrequency(initFreq, /* seekDown= */ true)),
                SIGNAL_QUALITY);
        openAidlClients(/* numClients= */ 1);
        mHalCurrentInfo = TestUtils.makeHalProgramInfo(
                Convert.programSelectorToHal(initialSel), SIGNAL_QUALITY);
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());

        mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);

        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
                .onCurrentProgramInfoChanged(seekUpInfo);
    }

    @Test
    public void seek_withHalHasInternalError_fails() throws Exception {
        openAidlClients(/* numClients= */ 1);
        doAnswer(invocation -> Result.INTERNAL_ERROR).when(mHalTunerSessionMock)
                .scan(anyBoolean(), anyBoolean());

        ParcelableException thrown = assertThrows(ParcelableException.class, () -> {
            mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
        });

        assertWithMessage("Exception for seeking when HAL has internal error")
                .that(thrown).hasMessageThat().contains(Result.toString(Result.INTERNAL_ERROR));
    }

    @Test
    public void cancel() throws Exception {
        openAidlClients(/* numClients= */ 1);
@@ -459,6 +549,32 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
        verify(mHalTunerSessionMock, never()).cancel();
    }

    @Test
    public void cancel_forNonCurrentUser_doesNotCancel() throws Exception {
        openAidlClients(/* numClients= */ 1);
        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
        mTunerSessions[0].tune(initialSel);
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());

        mTunerSessions[0].cancel();

        verify(mHalTunerSessionMock, never()).cancel();
    }

    @Test
    public void cancel_whenHalThrowsRemoteException_fails() throws Exception {
        openAidlClients(/* numClients= */ 1);
        String exceptionMessage = "HAL service died.";
        doThrow(new RemoteException(exceptionMessage)).when(mHalTunerSessionMock).cancel();

        RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
            mTunerSessions[0].cancel();
        });

        assertWithMessage("Exception for canceling when HAL throws remote exception")
                .that(thrown).hasMessageThat().contains(exceptionMessage);
    }

    @Test
    public void getImage_withInvalidId_throwsIllegalArgumentException() throws Exception {
        openAidlClients(/* numClients= */ 1);
@@ -482,6 +598,21 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
        assertWithMessage("Null image").that(imageTest).isEqualTo(null);
    }

    @Test
    public void getImage_whenHalThrowsException_fails() throws Exception {
        openAidlClients(/* numClients= */ 1);
        String exceptionMessage = "HAL service died.";
        when(mBroadcastRadioMock.getImage(anyInt()))
                .thenThrow(new RemoteException(exceptionMessage));

        RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
            mTunerSessions[0].getImage(/* id= */ 1);
        });

        assertWithMessage("Exception for getting image when HAL throws remote exception")
                .that(thrown).hasMessageThat().contains(exceptionMessage);
    }

    @Test
    public void startBackgroundScan() throws Exception {
        openAidlClients(/* numClients= */ 1);
@@ -491,6 +622,16 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onBackgroundScanComplete();
    }

    @Test
    public void startBackgroundScan_forNonCurrentUser_doesNotInvokesCallback() throws Exception {
        openAidlClients(/* numClients= */ 1);
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());

        mTunerSessions[0].startBackgroundScan();

        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete();
    }

    @Test
    public void stopProgramListUpdates() throws Exception {
        openAidlClients(/* numClients= */ 1);
@@ -503,6 +644,19 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
        verify(mHalTunerSessionMock).stopProgramListUpdates();
    }

    @Test
    public void stopProgramListUpdates_forNonCurrentUser_doesNotStopUpdates() throws Exception {
        openAidlClients(/* numClients= */ 1);
        ProgramList.Filter aidlFilter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
                /* includeCategories= */ true, /* excludeModifications= */ false);
        mTunerSessions[0].startProgramListUpdates(aidlFilter);
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());

        mTunerSessions[0].stopProgramListUpdates();

        verify(mHalTunerSessionMock, never()).stopProgramListUpdates();
    }

    @Test
    public void isConfigFlagSupported_withUnsupportedFlag_returnsFalse() throws Exception {
        openAidlClients(/* numClients= */ 1);
@@ -558,6 +712,18 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
        verify(mHalTunerSessionMock).setConfigFlag(flag, /* value= */ false);
    }

    @Test
    public void setConfigFlag_forNonCurrentUser_doesNotSetConfigFlag() throws Exception {
        openAidlClients(/* numClients= */ 1);
        int flag = UNSUPPORTED_CONFIG_FLAG + 1;
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());

        mTunerSessions[0].setConfigFlag(flag, /* value= */ true);

        verify(mHalTunerSessionMock, never()).setConfigFlag(flag, /* value= */ true);
    }


    @Test
    public void isConfigFlagSet_withUnsupportedFlag_throwsRuntimeException()
            throws Exception {
@@ -568,7 +734,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
            mTunerSessions[0].isConfigFlagSet(flag);
        });

        assertWithMessage("Exception for check if unsupported flag %s is set", flag)
        assertWithMessage("Exception for checking if unsupported flag %s is set", flag)
                .that(thrown).hasMessageThat().contains("isConfigFlagSet: NOT_SUPPORTED");
    }

@@ -585,6 +751,20 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
                .that(isSet).isEqualTo(expectedConfigFlagValue);
    }

    @Test
    public void isConfigFlagSet_whenHalThrowsRemoteException_fails() throws Exception {
        openAidlClients(/* numClients= */ 1);
        int flag = UNSUPPORTED_CONFIG_FLAG + 1;
        doThrow(new RemoteException()).when(mHalTunerSessionMock).isConfigFlagSet(anyInt(), any());

        RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
            mTunerSessions[0].isConfigFlagSet(flag);
        });

        assertWithMessage("Exception for checking config flag when HAL throws remote exception")
                .that(thrown).hasMessageThat().contains("Failed to check flag");
    }

    @Test
    public void setParameters_withMockParameters() throws Exception {
        openAidlClients(/* numClients= */ 1);
@@ -596,6 +776,35 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
        verify(mHalTunerSessionMock).setParameters(Convert.vendorInfoToHal(parametersSet));
    }

    @Test
    public void setParameters_forNonCurrentUser_doesNotSetParameters() throws Exception {
        openAidlClients(/* numClients= */ 1);
        Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1",
                "mockParam2", "mockValue2");
        doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());

        mTunerSessions[0].setParameters(parametersSet);

        verify(mHalTunerSessionMock, never()).setParameters(any());
    }

    @Test
    public void setParameters_whenHalThrowsRemoteException_fails() throws Exception {
        openAidlClients(/* numClients= */ 1);
        Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1",
                "mockParam2", "mockValue2");
        String exceptionMessage = "HAL service died.";
        when(mHalTunerSessionMock.setParameters(any()))
                .thenThrow(new RemoteException(exceptionMessage));

        RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
            mTunerSessions[0].setParameters(parametersSet);
        });

        assertWithMessage("Exception for setting parameters when HAL throws remote exception")
                .that(thrown).hasMessageThat().contains(exceptionMessage);
    }

    @Test
    public void getParameters_withMockKeys() throws Exception {
        openAidlClients(/* numClients= */ 1);
@@ -606,6 +815,22 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
        verify(mHalTunerSessionMock).getParameters(parameterKeys);
    }

    @Test
    public void getParameters_whenServiceThrowsRemoteException_fails() throws Exception {
        openAidlClients(/* numClients= */ 1);
        List<String> parameterKeys = List.of("mockKey1", "mockKey2");
        String exceptionMessage = "HAL service died.";
        when(mHalTunerSessionMock.getParameters(any()))
                .thenThrow(new RemoteException(exceptionMessage));

        RuntimeException thrown = assertThrows(RuntimeException.class, () -> {
            mTunerSessions[0].getParameters(parameterKeys);
        });

        assertWithMessage("Exception for getting parameters when HAL throws remote exception")
                .that(thrown).hasMessageThat().contains(exceptionMessage);
    }

    @Test
    public void onConfigFlagUpdated_forTunerCallback() throws Exception {
        int numSessions = 3;
+6 −7
Original line number Diff line number Diff line
@@ -61,21 +61,20 @@ class Convert {
    }

    static void throwOnError(String action, int result) {
        String errorString = action + ": " + Result.toString(result);
        switch (result) {
            case Result.OK:
                return;
            case Result.UNKNOWN_ERROR:
                throw new ParcelableException(new RuntimeException(action + ": UNKNOWN_ERROR"));
            case Result.INTERNAL_ERROR:
                throw new ParcelableException(new RuntimeException(action + ": INTERNAL_ERROR"));
            case Result.TIMEOUT:
                throw new ParcelableException(new RuntimeException(errorString));
            case Result.INVALID_ARGUMENTS:
                throw new IllegalArgumentException(action + ": INVALID_ARGUMENTS");
                throw new IllegalArgumentException(errorString);
            case Result.INVALID_STATE:
                throw new IllegalStateException(action + ": INVALID_STATE");
                throw new IllegalStateException(errorString);
            case Result.NOT_SUPPORTED:
                throw new UnsupportedOperationException(action + ": NOT_SUPPORTED");
            case Result.TIMEOUT:
                throw new ParcelableException(new RuntimeException(action + ": TIMEOUT"));
                throw new UnsupportedOperationException(errorString);
            default:
                throw new ParcelableException(new RuntimeException(
                        action + ": unknown error (" + result + ")"));