diff --git a/core/java/android/hardware/radio/IRadioService.aidl b/core/java/android/hardware/radio/IRadioService.aidl index 9349cf7d0c327..c7131a7fe9c95 100644 --- a/core/java/android/hardware/radio/IRadioService.aidl +++ b/core/java/android/hardware/radio/IRadioService.aidl @@ -31,7 +31,7 @@ interface IRadioService { List listModules(); ITuner openTuner(int moduleId, in RadioManager.BandConfig bandConfig, boolean withAudio, - in ITunerCallback callback); + in ITunerCallback callback, int targetSdkVersion); ICloseHandle addAnnouncementListener(in int[] enabledTypes, in IAnnouncementListener listener); diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index 8c6083ce49b63..f072e3b43b4ad 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -1796,7 +1796,7 @@ public class RadioManager { ITuner tuner; TunerCallbackAdapter halCallback = new TunerCallbackAdapter(callback, handler); try { - tuner = mService.openTuner(moduleId, config, withAudio, halCallback); + tuner = mService.openTuner(moduleId, config, withAudio, halCallback, mTargetSdkVersion); } catch (RemoteException | IllegalArgumentException | IllegalStateException ex) { Log.e(TAG, "Failed to open tuner", ex); return null; @@ -1873,6 +1873,7 @@ public class RadioManager { @NonNull private final Context mContext; @NonNull private final IRadioService mService; + private final int mTargetSdkVersion; /** * @hide @@ -1889,5 +1890,6 @@ public class RadioManager { public RadioManager(Context context, IRadioService service) { mContext = context; mService = service; + mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion; } } diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramListTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramListTest.java index 2b9de18701e2e..87f91fa436ed3 100644 --- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramListTest.java +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramListTest.java @@ -41,6 +41,8 @@ import android.os.Parcel; import android.os.RemoteException; import android.util.ArraySet; +import androidx.test.InstrumentationRegistry; + import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -54,6 +56,8 @@ import java.util.concurrent.Executor; @RunWith(MockitoJUnitRunner.class) public final class ProgramListTest { + public final Context mContext = InstrumentationRegistry.getContext(); + private static final int CREATOR_ARRAY_SIZE = 3; private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 500); @@ -109,8 +113,6 @@ public final class ProgramListTest { @Mock private IRadioService mRadioServiceMock; @Mock - private Context mContextMock; - @Mock private ITuner mTunerMock; @Mock private RadioTuner.Callback mTunerCallbackMock; @@ -477,7 +479,7 @@ public final class ProgramListTest { } private void createRadioTuner() throws Exception { - RadioManager radioManager = new RadioManager(mContextMock, mRadioServiceMock); + RadioManager radioManager = new RadioManager(mContext, mRadioServiceMock); RadioManager.BandConfig band = new RadioManager.FmBandConfig( new RadioManager.FmBandDescriptor(RadioManager.REGION_ITU_1, RadioManager.BAND_FM, /* lowerLimit= */ 87500, /* upperLimit= */ 108000, /* spacing= */ 200, @@ -487,7 +489,7 @@ public final class ProgramListTest { doAnswer(invocation -> { mTunerCallback = (ITunerCallback) invocation.getArguments()[3]; return mTunerMock; - }).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any()); + }).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any(), anyInt()); mRadioTuner = radioManager.openTuner(/* moduleId= */ 0, band, /* withAudio= */ true, mTunerCallbackMock, /* handler= */ null); diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java index 44aa6d19cb0a2..03742eb93a3bb 100644 --- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java @@ -18,14 +18,16 @@ package android.hardware.radio.tests.unittests; import static com.google.common.truth.Truth.assertWithMessage; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.hardware.radio.Announcement; import android.hardware.radio.IAnnouncementListener; import android.hardware.radio.ICloseHandle; @@ -34,6 +36,7 @@ import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; import android.hardware.radio.RadioTuner; +import android.os.Build; import android.os.Parcel; import android.os.RemoteException; import android.util.ArrayMap; @@ -53,6 +56,8 @@ import java.util.Set; @RunWith(MockitoJUnitRunner.class) public final class RadioManagerTest { + private static final int TEST_TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT; + private static final int REGION = RadioManager.REGION_ITU_2; private static final int FM_LOWER_LIMIT = 87500; private static final int FM_UPPER_LIMIT = 108000; @@ -126,6 +131,7 @@ public final class RadioManagerTest { /* vendorInfo= */ new ArrayMap<>())); private RadioManager mRadioManager; + private final ApplicationInfo mApplicationInfo = new ApplicationInfo(); @Mock private IRadioService mRadioServiceMock; @@ -1008,7 +1014,8 @@ public final class RadioManagerTest { mRadioManager.openTuner(moduleId, FM_BAND_CONFIG, withAudio, mCallbackMock, /* handler= */ null); - verify(mRadioServiceMock).openTuner(eq(moduleId), eq(FM_BAND_CONFIG), eq(withAudio), any()); + verify(mRadioServiceMock).openTuner(eq(moduleId), eq(FM_BAND_CONFIG), eq(withAudio), any(), + anyInt()); } @Test @@ -1103,6 +1110,8 @@ public final class RadioManagerTest { } private void createRadioManager() throws RemoteException { + mApplicationInfo.targetSdkVersion = TEST_TARGET_SDK_VERSION; + when(mContextMock.getApplicationInfo()).thenReturn(mApplicationInfo); when(mRadioServiceMock.listModules()).thenReturn(Arrays.asList(AMFM_PROPERTIES)); when(mRadioServiceMock.addAnnouncementListener(any(), any())).thenReturn(mCloseHandleMock); diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/TunerAdapterTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/TunerAdapterTest.java index 6d77f99361964..7a9976779df9f 100644 --- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/TunerAdapterTest.java +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/TunerAdapterTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.graphics.Bitmap; import android.hardware.radio.IRadioService; import android.hardware.radio.ITuner; @@ -35,6 +36,7 @@ import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; import android.hardware.radio.RadioTuner; +import android.os.Build; import org.junit.After; import org.junit.Before; @@ -51,6 +53,8 @@ import java.util.Map; @RunWith(MockitoJUnitRunner.class) public final class TunerAdapterTest { + private static final int TEST_TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT; + private static final int CALLBACK_TIMEOUT_MS = 30_000; private static final int AM_LOWER_LIMIT_KHZ = 150; @@ -65,6 +69,7 @@ public final class TunerAdapterTest { private RadioTuner mRadioTuner; private ITunerCallback mTunerCallback; + private final ApplicationInfo mApplicationInfo = new ApplicationInfo(); @Mock private IRadioService mRadioServiceMock; @@ -77,12 +82,14 @@ public final class TunerAdapterTest { @Before public void setUp() throws Exception { + mApplicationInfo.targetSdkVersion = TEST_TARGET_SDK_VERSION; + when(mContextMock.getApplicationInfo()).thenReturn(mApplicationInfo); RadioManager radioManager = new RadioManager(mContextMock, mRadioServiceMock); doAnswer(invocation -> { mTunerCallback = (ITunerCallback) invocation.getArguments()[3]; return mTunerMock; - }).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any()); + }).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any(), anyInt()); doAnswer(invocation -> { ProgramSelector program = (ProgramSelector) invocation.getArguments()[0]; diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceAidlImplTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceAidlImplTest.java index a2df426c315c8..9803474566fbf 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceAidlImplTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceAidlImplTest.java @@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -33,6 +34,7 @@ import android.hardware.radio.ICloseHandle; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; +import android.os.Build; import android.os.IBinder; import android.os.ServiceManager; @@ -55,6 +57,7 @@ public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCas "android.hardware.broadcastradio.IBroadcastRadio/amfm"; private static final String DAB_SERVICE_NAME = "android.hardware.broadcastradio.IBroadcastRadio/dab"; + private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT; private IRadioServiceAidlImpl mAidlImpl; @@ -82,7 +85,7 @@ public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCas doNothing().when(mServiceMock).enforcePolicyAccess(); when(mHalMock.listModules()).thenReturn(List.of(mModuleMock)); - when(mHalMock.openSession(anyInt(), any(), anyBoolean(), any())) + when(mHalMock.openSession(anyInt(), any(), anyBoolean(), any(), eq(TARGET_SDK_VERSION))) .thenReturn(mTunerMock); when(mHalMock.addAnnouncementListener(any(), any())).thenReturn(mICloseHandle); @@ -114,7 +117,7 @@ public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCas @Test public void openTuner_forAidlImpl() throws Exception { ITuner tuner = mAidlImpl.openTuner(/* moduleId= */ 0, mBandConfigMock, - /* withAudio= */ true, mTunerCallbackMock); + /* withAudio= */ true, mTunerCallbackMock, TARGET_SDK_VERSION); assertWithMessage("Tuner opened in AIDL HAL") .that(tuner).isEqualTo(mTunerMock); diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceHidlImplTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceHidlImplTest.java index 5ab943542f81d..cfff477362400 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceHidlImplTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceHidlImplTest.java @@ -32,6 +32,7 @@ import android.hardware.radio.ICloseHandle; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; +import android.os.Build; import org.junit.Before; import org.junit.Test; @@ -49,6 +50,7 @@ public final class IRadioServiceHidlImplTest { private static final int HAL1_MODULE_ID = 0; private static final int[] ENABLE_TYPES = new int[]{Announcement.TYPE_TRAFFIC}; + private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT; private IRadioServiceHidlImpl mHidlImpl; @@ -103,7 +105,7 @@ public final class IRadioServiceHidlImplTest { @Test public void openTuner_withHal1ModuleId_forHidlImpl() throws Exception { ITuner tuner = mHidlImpl.openTuner(HAL1_MODULE_ID, mBandConfigMock, - /* withAudio= */ true, mTunerCallbackMock); + /* withAudio= */ true, mTunerCallbackMock, TARGET_SDK_VERSION); assertWithMessage("Tuner opened in HAL 1") .that(tuner).isEqualTo(mHal1TunerMock); @@ -112,7 +114,7 @@ public final class IRadioServiceHidlImplTest { @Test public void openTuner_withHal2ModuleId_forHidlImpl() throws Exception { ITuner tuner = mHidlImpl.openTuner(HAL1_MODULE_ID + 1, mBandConfigMock, - /* withAudio= */ true, mTunerCallbackMock); + /* withAudio= */ true, mTunerCallbackMock, TARGET_SDK_VERSION); assertWithMessage("Tuner opened in HAL 2") .that(tuner).isEqualTo(mHal2TunerMock); 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 1cc0a98512bf5..f4040825e9a74 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 @@ -36,6 +36,7 @@ import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; +import android.os.Build; import android.os.IBinder; import android.os.IServiceCallback; import android.os.RemoteException; @@ -54,6 +55,8 @@ import java.util.Arrays; public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTestCase { + private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT; + private static final int FM_RADIO_MODULE_ID = 0; private static final int DAB_RADIO_MODULE_ID = 1; private static final ArrayList SERVICE_LIST = @@ -137,7 +140,8 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes createBroadcastRadioService(); ITuner session = mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID, - /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock); + /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock, + TARGET_SDK_VERSION); assertWithMessage("Session opened in FM radio module") .that(session).isEqualTo(mFmTunerSessionMock); @@ -148,7 +152,8 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes createBroadcastRadioService(); ITuner session = mBroadcastRadioService.openSession(DAB_RADIO_MODULE_ID + 1, - /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock); + /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock, + TARGET_SDK_VERSION); assertWithMessage("Session opened with id not found").that(session).isNull(); } @@ -160,7 +165,8 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID, - /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock)); + /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock, + TARGET_SDK_VERSION)); assertWithMessage("Exception for opening session by non-current user") .that(thrown).hasMessageThat().contains("Cannot open session for non-current user"); @@ -228,7 +234,7 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes return null; }).when(mFmBinderMock).linkToDeath(any(), anyInt()); - when(mFmRadioModuleMock.openSession(eq(mTunerCallbackMock))) + when(mFmRadioModuleMock.openSession(eq(mTunerCallbackMock), eq(TARGET_SDK_VERSION))) .thenReturn(mFmTunerSessionMock); } } 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 31195548c9685..a1cebb630aac3 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 @@ -25,6 +25,7 @@ import android.hardware.broadcastradio.VendorKeyValue; import android.hardware.radio.Announcement; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; +import android.os.Build; import com.google.common.truth.Expect; @@ -68,6 +69,18 @@ public final class ConversionUtilsTest { @Rule public final Expect expect = Expect.create(); + @Test + public void isAtLeastU_withTSdkVersion_returnsFalse() { + expect.withMessage("Target SDK version of T") + .that(ConversionUtils.isAtLeastU(Build.VERSION_CODES.TIRAMISU)).isFalse(); + } + + @Test + public void isAtLeastU_withCurrentSdkVersion_returnsTrue() { + expect.withMessage("Target SDK version of U") + .that(ConversionUtils.isAtLeastU(Build.VERSION_CODES.CUR_DEVELOPMENT)).isTrue(); + } + @Test public void propertiesFromHalProperties_idsMatch() { expect.withMessage("Properties id") 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 b76171aef4663..36c96260ae8f2 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 @@ -42,6 +42,7 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; +import android.os.Build; import android.os.ServiceSpecificException; import android.util.ArrayMap; import android.util.ArraySet; @@ -65,6 +66,7 @@ import java.util.Map; */ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { + private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT; private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 200); private static final int SIGNAL_QUALITY = 1; @@ -298,6 +300,18 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); } + @Test + public void tune_withLowerSdkVersion() throws Exception { + openAidlClients(/* numClients= */ 1, Build.VERSION_CODES.TIRAMISU); + ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + RadioManager.ProgramInfo tuneInfo = + AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); + + mTunerSessions[0].tune(initialSel); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); + } + @Test public void tune_withMultipleSessions() throws Exception { int numSessions = 3; @@ -627,13 +641,17 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { .onParametersUpdated(parametersExpected); } } - private void openAidlClients(int numClients) throws Exception { + openAidlClients(numClients, TARGET_SDK_VERSION); + } + + private void openAidlClients(int numClients, int targetSdkVersion) throws Exception { mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients]; mTunerSessions = new TunerSession[numClients]; for (int index = 0; index < numClients; index++) { mAidlTunerCallbackMocks[index] = mock(android.hardware.radio.ITunerCallback.class); - mTunerSessions[index] = mRadioModule.openSession(mAidlTunerCallbackMocks[index]); + mTunerSessions[index] = mRadioModule.openSession(mAidlTunerCallbackMocks[index], + targetSdkVersion); } } diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java index 6a010424db139..b66120d428c3f 100644 --- a/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java +++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java @@ -86,7 +86,8 @@ final class IRadioServiceAidlImpl extends IRadioService.Stub { @Override public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, - boolean withAudio, ITunerCallback callback) throws RemoteException { + boolean withAudio, ITunerCallback callback, int targetSdkVersion) + throws RemoteException { if (isDebugEnabled()) { Slogf.d(TAG, "Opening module %d", moduleId); } @@ -94,7 +95,7 @@ final class IRadioServiceAidlImpl extends IRadioService.Stub { if (callback == null) { throw new IllegalArgumentException("Callback must not be null"); } - return mHalAidl.openSession(moduleId, bandConfig, withAudio, callback); + return mHalAidl.openSession(moduleId, bandConfig, withAudio, callback, targetSdkVersion); } @Override diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java index 408fba1bff3b1..8a1ba19e24ab7 100644 --- a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java +++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java @@ -92,7 +92,8 @@ final class IRadioServiceHidlImpl extends IRadioService.Stub { @Override public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, - boolean withAudio, ITunerCallback callback) throws RemoteException { + boolean withAudio, ITunerCallback callback, int targetSdkVersion) + throws RemoteException { if (isDebugEnabled()) { Slog.d(TAG, "Opening module " + moduleId); } diff --git a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java index 03acf72725e7d..772cd4144f11b 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java @@ -199,7 +199,8 @@ public final class BroadcastRadioServiceImpl { */ @Nullable public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig, - boolean withAudio, ITunerCallback callback) throws RemoteException { + boolean withAudio, ITunerCallback callback, int targetSdkVersion) + throws RemoteException { if (DEBUG) { Slogf.d(TAG, "Open AIDL radio session"); } @@ -222,7 +223,7 @@ public final class BroadcastRadioServiceImpl { } } - TunerSession tunerSession = radioModule.openSession(callback); + TunerSession tunerSession = radioModule.openSession(callback, targetSdkVersion); if (legacyConfig != null) { tunerSession.setConfiguration(legacyConfig); } 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 09ee99659afca..9a7a3b5e18706 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java @@ -33,6 +33,7 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; +import android.os.Build; import android.os.ParcelableException; import android.os.ServiceSpecificException; import android.util.ArrayMap; @@ -62,6 +63,11 @@ final class ConversionUtils { throw new UnsupportedOperationException("ConversionUtils class is noninstantiable"); } + static boolean isAtLeastU(int targetSdkVersion) { + // TODO(b/261770108): Use version code for U. + return targetSdkVersion >= Build.VERSION_CODES.CUR_DEVELOPMENT; + } + static RuntimeException throwOnError(RuntimeException halException, String action) { if (!(halException instanceof ServiceSpecificException)) { return new ParcelableException(new RuntimeException( @@ -472,6 +478,60 @@ final class ConversionUtils { return new ProgramList.Chunk(chunk.purge, chunk.complete, modified, removed); } + private static boolean isNewIdentifierInU(ProgramSelector.Identifier id) { + return id.getType() == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT; + } + + static boolean programSelectorMeetsSdkVersionRequirement(ProgramSelector sel, + int targetSdkVersion) { + if (isAtLeastU(targetSdkVersion)) { + return true; + } + if (sel.getPrimaryId().getType() == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT) { + return false; + } + ProgramSelector.Identifier[] secondaryIds = sel.getSecondaryIds(); + for (int i = 0; i < secondaryIds.length; i++) { + if (isNewIdentifierInU(secondaryIds[i])) { + return false; + } + } + return true; + } + + static boolean programInfoMeetsSdkVersionRequirement(RadioManager.ProgramInfo info, + int targetSdkVersion) { + if (isAtLeastU(targetSdkVersion)) { + return true; + } + if (!programSelectorMeetsSdkVersionRequirement(info.getSelector(), targetSdkVersion)) { + return false; + } + if (isNewIdentifierInU(info.getLogicallyTunedTo()) + || isNewIdentifierInU(info.getPhysicallyTunedTo())) { + return false; + } + Iterator relatedContentIt = info.getRelatedContent().iterator(); + while (relatedContentIt.hasNext()) { + if (isNewIdentifierInU(relatedContentIt.next())) { + return false; + } + } + return true; + } + + static ProgramList.Chunk convertChunkToTargetSdkVersion(ProgramList.Chunk chunk, + int targetSdkVersion) { + if (isAtLeastU(targetSdkVersion)) { + return chunk; + } + Set modified = chunk.getModified(); + modified.removeIf(info -> !programInfoMeetsSdkVersionRequirement(info, targetSdkVersion)); + Set removed = chunk.getRemoved(); + removed.removeIf(id -> isNewIdentifierInU(id)); + return new ProgramList.Chunk(chunk.isPurge(), chunk.isComplete(), modified, removed); + } + public static android.hardware.radio.Announcement announcementFromHalAnnouncement( Announcement hwAnnouncement) { return new android.hardware.radio.Announcement( diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java index 5a3bd28cb7047..47203c8854a3a 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java @@ -100,7 +100,15 @@ final class RadioModule { synchronized (mLock) { android.hardware.radio.ProgramSelector csel = ConversionUtils.programSelectorFromHalProgramSelector(programSelector); - fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel)); + fanoutAidlCallbackLocked((cb, sdkVersion) -> { + if (csel != null && !ConversionUtils + .programSelectorMeetsSdkVersionRequirement(csel, sdkVersion)) { + Slogf.e(TAG, "onTuneFailed: cannot send program selector " + + "requiring higher target SDK version"); + return; + } + cb.onTuneFailed(result, csel); + }); } }); } @@ -112,7 +120,13 @@ final class RadioModule { mCurrentProgramInfo = ConversionUtils.programInfoFromHalProgramInfo(halProgramInfo); RadioManager.ProgramInfo currentProgramInfo = mCurrentProgramInfo; - fanoutAidlCallbackLocked(cb -> { + fanoutAidlCallbackLocked((cb, sdkVersion) -> { + if (!ConversionUtils.programInfoMeetsSdkVersionRequirement( + currentProgramInfo, sdkVersion)) { + Slogf.e(TAG, "onCurrentProgramInfoChanged: cannot send " + + "program info requiring higher target SDK version"); + return; + } cb.onCurrentProgramInfoChanged(currentProgramInfo); }); } @@ -139,7 +153,7 @@ final class RadioModule { fireLater(() -> { synchronized (mLock) { mAntennaConnected = connected; - fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected)); + fanoutAidlCallbackLocked((cb, sdkVersion) -> cb.onAntennaState(connected)); } }); } @@ -148,7 +162,9 @@ final class RadioModule { public void onConfigFlagUpdated(int flag, boolean value) { fireLater(() -> { synchronized (mLock) { - fanoutAidlCallbackLocked(cb -> cb.onConfigFlagUpdated(flag, value)); + fanoutAidlCallbackLocked((cb, sdkVersion) -> { + cb.onConfigFlagUpdated(flag, value); + }); } }); } @@ -159,7 +175,9 @@ final class RadioModule { synchronized (mLock) { Map cparam = ConversionUtils.vendorInfoFromHalVendorKeyValues(parameters); - fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam)); + fanoutAidlCallbackLocked((cb, sdkVersion) -> { + cb.onParametersUpdated(cparam); + }); } }); } @@ -223,14 +241,14 @@ final class RadioModule { mService.setTunerCallback(mHalTunerCallback); } - TunerSession openSession(android.hardware.radio.ITunerCallback userCb) + TunerSession openSession(android.hardware.radio.ITunerCallback userCb, int targetSdkVersion) throws RemoteException { mLogger.logRadioEvent("Open TunerSession"); TunerSession tunerSession; Boolean antennaConnected; RadioManager.ProgramInfo currentProgramInfo; synchronized (mLock) { - tunerSession = new TunerSession(this, mService, userCb); + tunerSession = new TunerSession(this, mService, userCb, targetSdkVersion); mAidlTunerSessions.add(tunerSession); antennaConnected = mAntennaConnected; currentProgramInfo = mCurrentProgramInfo; @@ -383,7 +401,8 @@ final class RadioModule { } interface AidlCallbackRunnable { - void run(android.hardware.radio.ITunerCallback callback) throws RemoteException; + void run(android.hardware.radio.ITunerCallback callback, int targetSdkVersion) + throws RemoteException; } // Invokes runnable with each TunerSession currently open. @@ -400,7 +419,8 @@ final class RadioModule { List deadSessions = null; for (int i = 0; i < mAidlTunerSessions.size(); i++) { try { - runnable.run(mAidlTunerSessions.valueAt(i).mCallback); + runnable.run(mAidlTunerSessions.valueAt(i).mCallback, + mAidlTunerSessions.valueAt(i).getTargetSdkVersion()); } catch (DeadObjectException ex) { // The other side died without calling close(), so just purge it from our records. Slogf.e(TAG, "Removing dead TunerSession"); diff --git a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java index 66e1be183a0f2..d700ed01b3c35 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java @@ -21,7 +21,6 @@ import android.graphics.Bitmap; import android.hardware.broadcastradio.ConfigFlag; import android.hardware.broadcastradio.IBroadcastRadio; import android.hardware.radio.ITuner; -import android.hardware.radio.ITunerCallback; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; @@ -47,6 +46,7 @@ final class TunerSession extends ITuner.Stub { private final RadioLogger mLogger; private final RadioModule mModule; final android.hardware.radio.ITunerCallback mCallback; + private final int mTargetSdkVersion; private final IBroadcastRadio mService; @GuardedBy("mLock") @@ -61,10 +61,11 @@ final class TunerSession extends ITuner.Stub { private RadioManager.BandConfig mPlaceHolderConfig; TunerSession(RadioModule radioModule, IBroadcastRadio service, - android.hardware.radio.ITunerCallback callback) { + android.hardware.radio.ITunerCallback callback, int targetSdkVersion) { mModule = Objects.requireNonNull(radioModule, "radioModule cannot be null"); mService = Objects.requireNonNull(service, "service cannot be null"); mCallback = Objects.requireNonNull(callback, "callback cannot be null"); + mTargetSdkVersion = targetSdkVersion; mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE); } @@ -129,7 +130,7 @@ final class TunerSession extends ITuner.Stub { mPlaceHolderConfig = Objects.requireNonNull(config, "config cannot be null"); } Slogf.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL AIDL"); - mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config)); + mModule.fanoutAidlCallback((cb, sdkVersion) -> cb.onConfigurationChanged(config)); } @Override @@ -248,7 +249,9 @@ final class TunerSession extends ITuner.Stub { Slogf.w(TAG, "Cannot start background scan on AIDL HAL client from non-current user"); return false; } - mModule.fanoutAidlCallback(ITunerCallback::onBackgroundScanComplete); + mModule.fanoutAidlCallback((cb, sdkVersion) -> { + cb.onBackgroundScanComplete(); + }); return true; } @@ -276,6 +279,10 @@ final class TunerSession extends ITuner.Stub { mModule.onTunerSessionProgramListFilterChanged(this); } + int getTargetSdkVersion() { + return mTargetSdkVersion; + } + ProgramList.Filter getProgramListFilter() { synchronized (mLock) { return mProgramInfoCache == null ? null : mProgramInfoCache.getFilter(); @@ -311,7 +318,14 @@ final class TunerSession extends ITuner.Stub { } for (int i = 0; i < chunks.size(); i++) { try { - mCallback.onProgramListUpdated(chunks.get(i)); + if (!ConversionUtils.isAtLeastU(getTargetSdkVersion())) { + ProgramList.Chunk downgradedChunk = + ConversionUtils.convertChunkToTargetSdkVersion(chunks.get(i), + getTargetSdkVersion()); + mCallback.onProgramListUpdated(downgradedChunk); + } else { + mCallback.onProgramListUpdated(chunks.get(i)); + } } catch (RemoteException ex) { Slogf.w(TAG, ex, "mCallback.onProgramListUpdated() failed"); } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java index 984bf5125582e..1e31f200fd47d 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java @@ -169,7 +169,7 @@ public final class BroadcastRadioService { } public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig, - boolean withAudio, @NonNull ITunerCallback callback) throws RemoteException { + boolean withAudio, @NonNull ITunerCallback callback) throws RemoteException { Slog.v(TAG, "Open HIDL 2.0 session with module id " + moduleId); if (!RadioServiceUserController.isCurrentOrSystemUser()) { Slogf.e(TAG, "Cannot open tuner on HAL 2.0 client for non-current user");