From 0555ea12e3346527db1f1593885a55b81a658ab8 Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Fri, 16 Dec 2022 23:42:19 +0000 Subject: [PATCH] Add exception and conversion tests for AIDL client Unit tests when HAL throws exception and when non-current user calls methods that modify HAL status were added for broadcast radio AIDL HAL client. Also added tests for conversion utlis methods about converting and checking SDK versions for program info and program list chunk. Bug: 241118988 Test: atest com.android.server.broadcastradio.aidl Change-Id: I94c85f6bc4da374326530e46683c5375aa686c3b --- .../broadcastradio/aidl/AidlTestUtils.java | 39 ++- .../aidl/BroadcastRadioServiceImplTest.java | 13 + .../aidl/ConversionUtilsTest.java | 176 +++++++++++-- .../broadcastradio/aidl/TunerSessionTest.java | 242 +++++++++++++++++- .../broadcastradio/aidl/ConversionUtils.java | 20 +- 5 files changed, 432 insertions(+), 58 deletions(-) diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java index 3037f345b5a36..82db716fcdc24 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java @@ -19,6 +19,7 @@ import android.hardware.broadcastradio.IdentifierType; import android.hardware.broadcastradio.Metadata; import android.hardware.broadcastradio.ProgramIdentifier; import android.hardware.broadcastradio.ProgramInfo; +import android.hardware.broadcastradio.ProgramListChunk; import android.hardware.broadcastradio.VendorKeyValue; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; @@ -41,17 +42,18 @@ final class AidlTestUtils { /* 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(int programType, - ProgramSelector.Identifier identifier, int signalQuality) { - ProgramSelector selector = makeProgramSelector(programType, identifier); - return makeProgramInfo(selector, signalQuality); + static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector, int signalQuality) { + return makeProgramInfo(selector, selector.getPrimaryId(), selector.getPrimaryId(), + signalQuality); } static ProgramIdentifier makeHalIdentifier(@IdentifierType int type, long value) { @@ -87,21 +89,6 @@ final class AidlTestUtils { return hwSelector; } - static ProgramInfo programInfoToHalProgramInfo(RadioManager.ProgramInfo info) { - // Note that because ConversionUtils does not by design provide functions for all - // conversions, this function only copies fields that are set by makeProgramInfo(). - ProgramInfo hwInfo = new ProgramInfo(); - hwInfo.selector = ConversionUtils.programSelectorToHalProgramSelector(info.getSelector()); - hwInfo.logicallyTunedTo = - ConversionUtils.identifierToHalProgramIdentifier(info.getLogicallyTunedTo()); - hwInfo.physicallyTunedTo = - ConversionUtils.identifierToHalProgramIdentifier(info.getPhysicallyTunedTo()); - hwInfo.signalQuality = info.getSignalStrength(); - hwInfo.relatedContent = new ProgramIdentifier[]{}; - hwInfo.metadata = new Metadata[]{}; - return hwInfo; - } - static ProgramInfo makeHalProgramInfo( android.hardware.broadcastradio.ProgramSelector hwSel, int hwSignalQuality) { return makeHalProgramInfo(hwSel, hwSel.primaryId, hwSel.primaryId, hwSignalQuality); @@ -121,6 +108,16 @@ final class AidlTestUtils { return hwInfo; } + static ProgramListChunk makeProgramListChunk(boolean purge, boolean complete, + ProgramInfo[] modified, ProgramIdentifier[] removed) { + ProgramListChunk halChunk = new ProgramListChunk(); + halChunk.purge = purge; + halChunk.complete = complete; + halChunk.modified = modified; + halChunk.removed = removed; + return halChunk; + } + static VendorKeyValue makeVendorKeyValue(String vendorKey, String vendorValue) { VendorKeyValue vendorKeyValue = new VendorKeyValue(); vendorKeyValue.key = vendorKey; diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java index f4040825e9a74..98103f6eddd39 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java @@ -172,6 +172,19 @@ public final class BroadcastRadioServiceImplTest 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, + TARGET_SDK_VERSION)); + + assertWithMessage("Exception for opening session without audio") + .that(thrown).hasMessageThat().contains("not supported"); + } + @Test public void binderDied_forDeathRecipient() throws Exception { createBroadcastRadioService(); diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java index 6604d2aea7c17..710c150c006cf 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java @@ -22,9 +22,11 @@ import android.hardware.broadcastradio.DabTableEntry; import android.hardware.broadcastradio.IdentifierType; import android.hardware.broadcastradio.ProgramIdentifier; import android.hardware.broadcastradio.ProgramInfo; +import android.hardware.broadcastradio.ProgramListChunk; import android.hardware.broadcastradio.Properties; import android.hardware.broadcastradio.VendorKeyValue; import android.hardware.radio.Announcement; +import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.os.Build; @@ -35,19 +37,20 @@ import org.junit.Rule; import org.junit.Test; import java.util.Map; +import java.util.Set; public final class ConversionUtilsTest { - private static final int FM_LOWER_LIMIT = 87500; - private static final int FM_UPPER_LIMIT = 108000; + private static final int FM_LOWER_LIMIT = 87_500; + private static final int FM_UPPER_LIMIT = 108_000; private static final int FM_SPACING = 200; private static final int AM_LOWER_LIMIT = 540; - private static final int AM_UPPER_LIMIT = 1700; + private static final int AM_UPPER_LIMIT = 1_700; private static final int AM_SPACING = 10; private static final String DAB_ENTRY_LABEL_1 = "5A"; - private static final int DAB_ENTRY_FREQUENCY_1 = 174928; + private static final int DAB_ENTRY_FREQUENCY_1 = 174_928; private static final String DAB_ENTRY_LABEL_2 = "12D"; - private static final int DAB_ENTRY_FREQUENCY_2 = 229072; + private static final int DAB_ENTRY_FREQUENCY_2 = 229_072; private static final String VENDOR_INFO_KEY_1 = "vendorKey1"; private static final String VENDOR_INFO_VALUE_1 = "vendorValue1"; private static final String VENDOR_INFO_KEY_2 = "vendorKey2"; @@ -62,7 +65,10 @@ public final class ConversionUtilsTest { private static final int TEST_SIGNAL_QUALITY = 1; private static final long TEST_DAB_DMB_SID_EXT_VALUE = 0xA000000111L; private static final long TEST_DAB_ENSEMBLE_VALUE = 0x1001; - private static final long TEST_DAB_FREQUENCY_VALUE = 220352; + private static final long TEST_DAB_FREQUENCY_VALUE = 220_352; + private static final long TEST_FM_FREQUENCY_VALUE = 92_100; + private static final long TEST_VENDOR_ID_VALUE = 9_901; + private static final ProgramSelector.Identifier TEST_DAB_SID_EXT_ID = new ProgramSelector.Identifier( ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT, TEST_DAB_DMB_SID_EXT_VALUE); @@ -72,6 +78,13 @@ public final class ConversionUtilsTest { private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID = new ProgramSelector.Identifier( ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, TEST_DAB_FREQUENCY_VALUE); + private static final ProgramSelector.Identifier TEST_FM_FREQUENCY_ID = + new ProgramSelector.Identifier( + ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, TEST_FM_FREQUENCY_VALUE); + private static final ProgramSelector.Identifier TEST_VENDOR_ID = + new ProgramSelector.Identifier( + ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, TEST_VENDOR_ID_VALUE); + private static final ProgramIdentifier TEST_HAL_DAB_SID_EXT_ID = AidlTestUtils.makeHalIdentifier(IdentifierType.DAB_SID_EXT, TEST_DAB_DMB_SID_EXT_VALUE); private static final ProgramIdentifier TEST_HAL_DAB_ENSEMBLE_ID = @@ -79,6 +92,19 @@ public final class ConversionUtilsTest { private static final ProgramIdentifier TEST_HAL_DAB_FREQUENCY_ID = AidlTestUtils.makeHalIdentifier(IdentifierType.DAB_FREQUENCY_KHZ, TEST_DAB_FREQUENCY_VALUE); + private static final ProgramIdentifier TEST_HAL_FM_FREQUENCY_ID = + AidlTestUtils.makeHalIdentifier(IdentifierType.AMFM_FREQUENCY_KHZ, + TEST_FM_FREQUENCY_VALUE); + private static final ProgramIdentifier TEST_HAL_VENDOR_ID = + AidlTestUtils.makeHalIdentifier(IdentifierType.VENDOR_START, + TEST_VENDOR_ID_VALUE); + + private static final ProgramSelector TEST_DAB_SELECTOR = new ProgramSelector( + ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID, + new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID}, + /* vendorIds= */ null); + private static final ProgramSelector TEST_FM_SELECTOR = + AidlTestUtils.makeFmSelector(TEST_FM_FREQUENCY_VALUE); private static final int TEST_ENABLED_TYPE = Announcement.TYPE_EMERGENCY; private static final int TEST_ANNOUNCEMENT_FREQUENCY = FM_LOWER_LIMIT + FM_SPACING; @@ -200,13 +226,8 @@ public final class ConversionUtilsTest { @Test public void programSelectorToHalProgramSelector_withValidSelector() { - ProgramSelector dabSelector = new ProgramSelector( - ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID, - new ProgramSelector.Identifier[]{TEST_DAB_ENSEMBLE_ID, TEST_DAB_FREQUENCY_ID}, - new long[0]); - android.hardware.broadcastradio.ProgramSelector halDabSelector = - ConversionUtils.programSelectorToHalProgramSelector(dabSelector); + ConversionUtils.programSelectorToHalProgramSelector(TEST_DAB_SELECTOR); expect.withMessage("Primary identifier of converted HAL DAB selector") .that(halDabSelector.primaryId).isEqualTo(TEST_HAL_DAB_SID_EXT_ID); @@ -297,26 +318,135 @@ public final class ConversionUtilsTest { } @Test - public void programSelectorMeetsSdkVersionRequirement_withLowerVersionId_returnsFalse() { - ProgramSelector dabSelector = new ProgramSelector( - ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID, - new ProgramSelector.Identifier[]{TEST_DAB_ENSEMBLE_ID, TEST_DAB_FREQUENCY_ID}, - new long[0]); + public void chunkFromHalProgramListChunk_withValidChunk() { + boolean purge = false; + boolean complete = true; + android.hardware.broadcastradio.ProgramSelector halDabSelector = + AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{ + TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID}); + ProgramInfo halDabInfo = AidlTestUtils.makeHalProgramInfo(halDabSelector, + TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY); + RadioManager.ProgramInfo dabInfo = + ConversionUtils.programInfoFromHalProgramInfo(halDabInfo); + ProgramListChunk halChunk = AidlTestUtils.makeProgramListChunk(purge, complete, + new ProgramInfo[]{halDabInfo}, + new ProgramIdentifier[]{TEST_HAL_VENDOR_ID, TEST_HAL_FM_FREQUENCY_ID}); - expect.withMessage("Selector %s not meeting required SDK version", dabSelector) - .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(dabSelector, + ProgramList.Chunk chunk = ConversionUtils.chunkFromHalProgramListChunk(halChunk); + + expect.withMessage("Purged state of the converted valid program list chunk") + .that(chunk.isPurge()).isEqualTo(purge); + expect.withMessage("Completion state of the converted valid program list chunk") + .that(chunk.isComplete()).isEqualTo(complete); + expect.withMessage("Modified program info in the converted valid program list chunk") + .that(chunk.getModified()).containsExactly(dabInfo); + expect.withMessage("Removed program ides in the converted valid program list chunk") + .that(chunk.getRemoved()).containsExactly(TEST_VENDOR_ID, TEST_FM_FREQUENCY_ID); + } + + @Test + public void chunkFromHalProgramListChunk_withInvalidModifiedProgramInfo() { + boolean purge = true; + boolean complete = false; + android.hardware.broadcastradio.ProgramSelector halDabSelector = + AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{ + TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID}); + ProgramInfo halDabInfo = AidlTestUtils.makeHalProgramInfo(halDabSelector, + TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_ENSEMBLE_ID, TEST_SIGNAL_QUALITY); + ProgramListChunk halChunk = AidlTestUtils.makeProgramListChunk(purge, complete, + new ProgramInfo[]{halDabInfo}, new ProgramIdentifier[]{TEST_HAL_FM_FREQUENCY_ID}); + + ProgramList.Chunk chunk = ConversionUtils.chunkFromHalProgramListChunk(halChunk); + + expect.withMessage("Purged state of the converted invalid program list chunk") + .that(chunk.isPurge()).isEqualTo(purge); + expect.withMessage("Completion state of the converted invalid program list chunk") + .that(chunk.isComplete()).isEqualTo(complete); + expect.withMessage("Modified program info in the converted invalid program list chunk") + .that(chunk.getModified()).isEmpty(); + expect.withMessage("Removed program ids in the converted invalid program list chunk") + .that(chunk.getRemoved()).containsExactly(TEST_FM_FREQUENCY_ID); + } + + @Test + public void programSelectorMeetsSdkVersionRequirement_withLowerVersionId_returnsFalse() { + expect.withMessage("Selector %s without required SDK version", TEST_DAB_SELECTOR) + .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(TEST_DAB_SELECTOR, Build.VERSION_CODES.TIRAMISU)).isFalse(); } @Test public void programSelectorMeetsSdkVersionRequirement_withRequiredVersionId_returnsTrue() { - ProgramSelector fmSelector = AidlTestUtils.makeFmSelector(/* freq= */ 97100); - - expect.withMessage("Selector %s meeting required SDK version", fmSelector) - .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(fmSelector, + expect.withMessage("Selector %s with required SDK version", TEST_FM_SELECTOR) + .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(TEST_FM_SELECTOR, Build.VERSION_CODES.TIRAMISU)).isTrue(); } + @Test + public void programInfoMeetsSdkVersionRequirement_withLowerVersionId_returnsFalse() { + RadioManager.ProgramInfo dabProgramInfo = AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR, + TEST_DAB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY); + + expect.withMessage("Program info %s without required SDK version", dabProgramInfo) + .that(ConversionUtils.programInfoMeetsSdkVersionRequirement(dabProgramInfo, + Build.VERSION_CODES.TIRAMISU)).isFalse(); + } + + @Test + public void programInfoMeetsSdkVersionRequirement_withRequiredVersionId_returnsTrue() { + RadioManager.ProgramInfo fmProgramInfo = AidlTestUtils.makeProgramInfo(TEST_FM_SELECTOR, + TEST_SIGNAL_QUALITY); + + expect.withMessage("Program info %s with required SDK version", fmProgramInfo) + .that(ConversionUtils.programInfoMeetsSdkVersionRequirement(fmProgramInfo, + Build.VERSION_CODES.TIRAMISU)).isTrue(); + } + + @Test + public void convertChunkToTargetSdkVersion_withLowerSdkVersion() { + RadioManager.ProgramInfo dabProgramInfo = AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR, + TEST_DAB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY); + RadioManager.ProgramInfo fmProgramInfo = AidlTestUtils.makeProgramInfo(TEST_FM_SELECTOR, + TEST_SIGNAL_QUALITY); + ProgramList.Chunk chunk = new ProgramList.Chunk(/* purge= */ true, + /* complete= */ true, Set.of(dabProgramInfo, fmProgramInfo), + Set.of(TEST_DAB_SID_EXT_ID, TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID)); + + ProgramList.Chunk convertedChunk = ConversionUtils.convertChunkToTargetSdkVersion(chunk, + Build.VERSION_CODES.TIRAMISU); + + expect.withMessage( + "Purged state of the converted program list chunk with lower SDK version") + .that(convertedChunk.isPurge()).isEqualTo(chunk.isPurge()); + expect.withMessage( + "Completion state of the converted program list chunk with lower SDK version") + .that(convertedChunk.isComplete()).isEqualTo(chunk.isComplete()); + expect.withMessage( + "Modified program info in the converted program list chunk with lower SDK version") + .that(convertedChunk.getModified()).containsExactly(fmProgramInfo); + expect.withMessage( + "Removed program ids in the converted program list chunk with lower SDK version") + .that(convertedChunk.getRemoved()) + .containsExactly(TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID); + } + + @Test + public void convertChunkToTargetSdkVersion_withRequiredSdkVersion() { + RadioManager.ProgramInfo dabProgramInfo = AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR, + TEST_DAB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY); + RadioManager.ProgramInfo fmProgramInfo = AidlTestUtils.makeProgramInfo(TEST_FM_SELECTOR, + TEST_SIGNAL_QUALITY); + ProgramList.Chunk chunk = new ProgramList.Chunk(/* purge= */ true, + /* complete= */ true, Set.of(dabProgramInfo, fmProgramInfo), + Set.of(TEST_DAB_SID_EXT_ID, TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID)); + + ProgramList.Chunk convertedChunk = ConversionUtils.convertChunkToTargetSdkVersion(chunk, + Build.VERSION_CODES.CUR_DEVELOPMENT); + + expect.withMessage("Converted program list chunk with required SDK version") + .that(convertedChunk).isEqualTo(chunk); + } + @Test public void announcementFromHalAnnouncement_typesMatch() { expect.withMessage("Announcement type") diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java index 201a50f49f881..d7723acf6f05f 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java @@ -26,7 +26,9 @@ 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; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -43,6 +45,8 @@ import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; import android.os.Build; +import android.os.ParcelableException; +import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.ArrayMap; import android.util.ArraySet; @@ -57,7 +61,6 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.verification.VerificationWithTimeout; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -71,10 +74,10 @@ public final class TunerSessionTest 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 = @@ -199,6 +202,17 @@ public final class TunerSessionTest 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); @@ -365,7 +379,7 @@ public final class TunerSessionTest 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 = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); @@ -378,6 +392,21 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { .onCurrentProgramInfoChanged(tuneInfo); } + @Test + public void tune_withHalHasUnknownError_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + doThrow(new ServiceSpecificException(Result.UNKNOWN_ERROR)) + .when(mBroadcastRadioMock).tune(any()); + + ParcelableException thrown = assertThrows(ParcelableException.class, () -> { + mTunerSessions[0].tune(sel); + }); + + assertWithMessage("Exception for tuning when HAL has unknown error") + .that(thrown).hasMessageThat().contains("UNKNOWN_ERROR"); + } + @Test public void step_withDirectionUp() throws Exception { long initFreq = AM_FM_FREQUENCY_LIST[1]; @@ -412,6 +441,35 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { .onCurrentProgramInfoChanged(stepDownInfo); } + @Test + public void step_forNonCurrentUser_doesNotStep() throws Exception { + long initFreq = AM_FM_FREQUENCY_LIST[1]; + ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq); + openAidlClients(/* numClients= */ 1); + mHalCurrentInfo = AidlTestUtils.makeHalProgramInfo( + ConversionUtils.programSelectorToHalProgramSelector(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); + doThrow(new ServiceSpecificException(Result.INVALID_STATE)) + .when(mBroadcastRadioMock).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("INVALID_STATE"); + } + @Test public void seek_withDirectionUp() throws Exception { long initFreq = AM_FM_FREQUENCY_LIST[2]; @@ -454,10 +512,43 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { ConversionUtils.programSelectorToHalProgramSelector(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 = AidlTestUtils.makeFmSelector(initFreq); + RadioManager.ProgramInfo seekUpInfo = AidlTestUtils.makeProgramInfo( + AidlTestUtils.makeFmSelector(getSeekFrequency(initFreq, /* seekDown= */ true)), + SIGNAL_QUALITY); + openAidlClients(/* numClients= */ 1); + mHalCurrentInfo = AidlTestUtils.makeHalProgramInfo( + ConversionUtils.programSelectorToHalProgramSelector(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); + doThrow(new ServiceSpecificException(Result.INTERNAL_ERROR)) + .when(mBroadcastRadioMock).seek(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("INTERNAL_ERROR"); + } + @Test public void cancel() throws Exception { openAidlClients(/* numClients= */ 1); @@ -469,6 +560,32 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { verify(mBroadcastRadioMock).cancel(); } + @Test + public void cancel_forNonCurrentUser_doesNotCancel() throws Exception { + openAidlClients(/* numClients= */ 1); + ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + mTunerSessions[0].tune(initialSel); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].cancel(); + + verify(mBroadcastRadioMock, never()).cancel(); + } + + @Test + public void cancel_whenHalThrowsRemoteException_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + String exceptionMessage = "HAL service died."; + doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock).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); @@ -492,6 +609,21 @@ public final class TunerSessionTest 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); @@ -501,6 +633,16 @@ public final class TunerSessionTest 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); @@ -513,6 +655,19 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { verify(mBroadcastRadioMock).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(mBroadcastRadioMock, never()).stopProgramListUpdates(); + } + @Test public void isConfigFlagSupported_withUnsupportedFlag_returnsFalse() throws Exception { openAidlClients(/* numClients= */ 1); @@ -568,6 +723,17 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { verify(mBroadcastRadioMock).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(mBroadcastRadioMock, never()).setConfigFlag(flag, /* value= */ true); + } + @Test public void isConfigFlagSet_withUnsupportedFlag_throwsRuntimeException() throws Exception { @@ -578,7 +744,7 @@ public final class TunerSessionTest 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"); } @@ -595,6 +761,20 @@ public final class TunerSessionTest 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(mBroadcastRadioMock).isConfigFlagSet(anyInt()); + + 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); @@ -607,17 +787,59 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { ConversionUtils.vendorInfoToHalVendorKeyValues(parametersSet)); } + @Test + public void setParameters_forNonCurrentUser_doesNotSetParameters() throws Exception { + openAidlClients(/* numClients= */ 1); + Map parametersSet = Map.of("mockParam1", "mockValue1", + "mockParam2", "mockValue2"); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].setParameters(parametersSet); + + verify(mBroadcastRadioMock, never()).setParameters(any()); + } + + @Test + public void setParameters_whenHalThrowsRemoteException_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + Map parametersSet = Map.of("mockParam1", "mockValue1", + "mockParam2", "mockValue2"); + String exceptionMessage = "HAL service died."; + when(mBroadcastRadioMock.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); - List parameterKeys = new ArrayList<>(2); - parameterKeys.add("mockKey1"); - parameterKeys.add("mockKey2"); + List parameterKeys = List.of("mockKey1", "mockKey2"); mTunerSessions[0].getParameters(parameterKeys); - verify(mBroadcastRadioMock).getParameters( - parameterKeys.toArray(new String[0])); + verify(mBroadcastRadioMock).getParameters(parameterKeys.toArray(new String[0])); + } + + @Test + public void getParameters_whenServiceThrowsRemoteException_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + List parameterKeys = List.of("mockKey1", "mockKey2"); + String exceptionMessage = "HAL service died."; + when(mBroadcastRadioMock.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 diff --git a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java index d580d5ce8fa66..c0a238feb9b55 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java @@ -627,10 +627,22 @@ final class ConversionUtils { if (isAtLeastU(targetSdkVersion)) { return chunk; } - Set modified = chunk.getModified(); - modified.removeIf(info -> !programInfoMeetsSdkVersionRequirement(info, targetSdkVersion)); - Set removed = chunk.getRemoved(); - removed.removeIf(id -> isNewIdentifierInU(id)); + Set modified = new ArraySet<>(); + Iterator modifiedIterator = chunk.getModified().iterator(); + while (modifiedIterator.hasNext()) { + RadioManager.ProgramInfo info = modifiedIterator.next(); + if (programInfoMeetsSdkVersionRequirement(info, targetSdkVersion)) { + modified.add(info); + } + } + Set removed = new ArraySet<>(); + Iterator removedIterator = chunk.getRemoved().iterator(); + while (removedIterator.hasNext()) { + ProgramSelector.Identifier id = removedIterator.next(); + if (!isNewIdentifierInU(id)) { + removed.add(id); + } + } return new ProgramList.Chunk(chunk.isPurge(), chunk.isComplete(), modified, removed); }