From 21da483832629c57b7015edd59adf74e80a668fe Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Thu, 26 Jan 2023 18:26:06 +0000 Subject: [PATCH] Use CompatChanges to radio app version check Instead of comparing SDK version of application directly in broadcast radio service, used CompatChanges methods with UID of application, to check whether it meets the SDK version requirement for program info and program list from broadcast radio HAL. Bug: 261770108 Test: atest android.hardware.radio Test: atest com.android.server.broadcastradio.aidl Change-Id: I7fe6d22bdb80a654cdd918114ff26d7faaf2e879 --- .../android/hardware/radio/IRadioService.aidl | 2 +- .../android/hardware/radio/RadioManager.java | 4 +- .../BroadcastRadioTests/AndroidManifest.xml | 2 + .../hardware/radio/ProgramListTest.java | 2 +- .../hardware/radio/RadioManagerTest.java | 9 +--- .../hardware/radio/TunerAdapterTest.java | 2 +- .../IRadioServiceAidlImplTest.java | 9 ++-- .../IRadioServiceHidlImplTest.java | 8 ++-- .../RadioServiceUserControllerTest.java | 5 ++- .../aidl/BroadcastRadioServiceImplTest.java | 18 +++----- .../aidl/ConversionUtilsTest.java | 42 ++++++++++++++----- .../broadcastradio/aidl/TunerSessionTest.java | 19 ++++----- .../broadcastradio/IRadioServiceAidlImpl.java | 5 +-- .../broadcastradio/IRadioServiceHidlImpl.java | 3 +- .../aidl/BroadcastRadioServiceImpl.java | 5 +-- .../broadcastradio/aidl/ConversionUtils.java | 39 ++++++++++------- .../broadcastradio/aidl/RadioModule.java | 22 +++++----- .../broadcastradio/aidl/TunerSession.java | 20 ++++----- 18 files changed, 113 insertions(+), 103 deletions(-) diff --git a/core/java/android/hardware/radio/IRadioService.aidl b/core/java/android/hardware/radio/IRadioService.aidl index c7131a7fe9c95..9349cf7d0c327 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, int targetSdkVersion); + in ITunerCallback callback); 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 f072e3b43b4ad..8c6083ce49b63 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, mTargetSdkVersion); + tuner = mService.openTuner(moduleId, config, withAudio, halCallback); } catch (RemoteException | IllegalArgumentException | IllegalStateException ex) { Log.e(TAG, "Failed to open tuner", ex); return null; @@ -1873,7 +1873,6 @@ public class RadioManager { @NonNull private final Context mContext; @NonNull private final IRadioService mService; - private final int mTargetSdkVersion; /** * @hide @@ -1890,6 +1889,5 @@ public class RadioManager { public RadioManager(Context context, IRadioService service) { mContext = context; mService = service; - mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion; } } diff --git a/core/tests/BroadcastRadioTests/AndroidManifest.xml b/core/tests/BroadcastRadioTests/AndroidManifest.xml index 8f655efe4f07d..fef3d16a183b9 100644 --- a/core/tests/BroadcastRadioTests/AndroidManifest.xml +++ b/core/tests/BroadcastRadioTests/AndroidManifest.xml @@ -18,6 +18,8 @@ package="com.android.frameworks.broadcastradiotests"> + + diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java index 75f8c954be5ec..7c3d2f2138a40 100644 --- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/ProgramListTest.java @@ -580,7 +580,7 @@ public final class ProgramListTest { doAnswer(invocation -> { mTunerCallback = (ITunerCallback) invocation.getArguments()[3]; return mTunerMock; - }).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any(), anyInt()); + }).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any()); mRadioTuner = radioManager.openTuner(/* moduleId= */ 0, band, /* withAudio= */ true, mTunerCallbackMock, /* handler= */ null); diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java index ce3e019520c84..b9f4c3fa0a779 100644 --- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java @@ -30,7 +30,6 @@ import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.os.Build; import android.os.Parcel; import android.os.RemoteException; import android.util.ArrayMap; @@ -50,8 +49,6 @@ 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; @@ -1043,14 +1040,13 @@ 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(), - anyInt()); + verify(mRadioServiceMock).openTuner(eq(moduleId), eq(FM_BAND_CONFIG), eq(withAudio), any()); } @Test public void openTuner_whenServiceDied_returnsNull() throws Exception { createRadioManager(); - when(mRadioServiceMock.openTuner(anyInt(), any(), anyBoolean(), any(), anyInt())) + when(mRadioServiceMock.openTuner(anyInt(), any(), anyBoolean(), any())) .thenThrow(new RemoteException()); RadioTuner nullTuner = mRadioManager.openTuner(/* moduleId= */ 0, FM_BAND_CONFIG, @@ -1166,7 +1162,6 @@ 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/TunerAdapterTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java index 8b257e832e436..c7b82b1caca64 100644 --- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java @@ -86,7 +86,7 @@ public final class TunerAdapterTest { doAnswer(invocation -> { mTunerCallback = (ITunerCallback) invocation.getArguments()[3]; return mTunerMock; - }).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any(), anyInt()); + }).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any()); 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 16c1499a2775a..da51ba45174cc 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceAidlImplTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceAidlImplTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertThrows; 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; @@ -35,7 +34,6 @@ 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; @@ -58,7 +56,6 @@ 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; @@ -86,7 +83,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(), eq(TARGET_SDK_VERSION))) + when(mHalMock.openSession(anyInt(), any(), anyBoolean(), any())) .thenReturn(mTunerMock); when(mHalMock.addAnnouncementListener(any(), any())).thenReturn(mICloseHandle); @@ -118,7 +115,7 @@ public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCas @Test public void openTuner_forAidlImpl() throws Exception { ITuner tuner = mAidlImpl.openTuner(/* moduleId= */ 0, mBandConfigMock, - /* withAudio= */ true, mTunerCallbackMock, TARGET_SDK_VERSION); + /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Tuner opened in AIDL HAL") .that(tuner).isEqualTo(mTunerMock); @@ -128,7 +125,7 @@ public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCas public void openTuner_withNullCallbackForAidlImpl_fails() throws Exception { IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> mAidlImpl.openTuner(/* moduleId= */ 0, mBandConfigMock, - /* withAudio= */ true, /* callback= */ null, TARGET_SDK_VERSION)); + /* withAudio= */ true, /* callback= */ null)); assertWithMessage("Exception for opening tuner with null callback") .that(thrown).hasMessageThat().contains("Callback must not be null"); 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 164c9aff127a7..20bc8d404d760 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceHidlImplTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceHidlImplTest.java @@ -33,7 +33,6 @@ 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; @@ -51,7 +50,6 @@ 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; @@ -106,7 +104,7 @@ public final class IRadioServiceHidlImplTest { @Test public void openTuner_withHal1ModuleId_forHidlImpl() throws Exception { ITuner tuner = mHidlImpl.openTuner(HAL1_MODULE_ID, mBandConfigMock, - /* withAudio= */ true, mTunerCallbackMock, TARGET_SDK_VERSION); + /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Tuner opened in HAL 1") .that(tuner).isEqualTo(mHal1TunerMock); @@ -115,7 +113,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, TARGET_SDK_VERSION); + /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Tuner opened in HAL 2") .that(tuner).isEqualTo(mHal2TunerMock); @@ -125,7 +123,7 @@ public final class IRadioServiceHidlImplTest { public void openTuner_withNullCallbackForHidlImpl_fails() throws Exception { NullPointerException thrown = assertThrows(NullPointerException.class, () -> mHidlImpl.openTuner(/* moduleId= */ 0, mBandConfigMock, - /* withAudio= */ true, /* callback= */ null, TARGET_SDK_VERSION)); + /* withAudio= */ true, /* callback= */ null)); assertWithMessage("Exception for opening tuner with null callback") .that(thrown).hasMessageThat().contains("Callback must not be null"); diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java index 161ac2dc6aa03..3e9e9922431bb 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java @@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.app.compat.CompatChanges; import android.os.Binder; import android.os.UserHandle; @@ -46,8 +47,8 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(ActivityManager.class) - .spyStatic(Binder.class); + builder.spyStatic(ActivityManager.class).spyStatic(Binder.class) + .spyStatic(CompatChanges.class); } @Before 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 98103f6eddd39..22f3bd4abe113 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,7 +36,6 @@ 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; @@ -55,8 +54,6 @@ 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 = @@ -140,8 +137,7 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes createBroadcastRadioService(); ITuner session = mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID, - /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock, - TARGET_SDK_VERSION); + /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Session opened in FM radio module") .that(session).isEqualTo(mFmTunerSessionMock); @@ -152,8 +148,7 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes createBroadcastRadioService(); ITuner session = mBroadcastRadioService.openSession(DAB_RADIO_MODULE_ID + 1, - /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock, - TARGET_SDK_VERSION); + /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Session opened with id not found").that(session).isNull(); } @@ -165,8 +160,7 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID, - /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock, - TARGET_SDK_VERSION)); + /* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock)); assertWithMessage("Exception for opening session by non-current user") .that(thrown).hasMessageThat().contains("Cannot open session for non-current user"); @@ -178,8 +172,7 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID, - /* legacyConfig= */ null, /* withAudio= */ false, mTunerCallbackMock, - TARGET_SDK_VERSION)); + /* legacyConfig= */ null, /* withAudio= */ false, mTunerCallbackMock)); assertWithMessage("Exception for opening session without audio") .that(thrown).hasMessageThat().contains("not supported"); @@ -247,7 +240,6 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes return null; }).when(mFmBinderMock).linkToDeath(any(), anyInt()); - when(mFmRadioModuleMock.openSession(eq(mTunerCallbackMock), eq(TARGET_SDK_VERSION))) - .thenReturn(mFmTunerSessionMock); + when(mFmRadioModuleMock.openSession(mTunerCallbackMock)).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 5d0e07613a98f..ba0579171c435 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 @@ -16,6 +16,9 @@ package com.android.server.broadcastradio.aidl; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; + +import android.app.compat.CompatChanges; import android.hardware.broadcastradio.AmFmBandRange; import android.hardware.broadcastradio.AmFmRegionConfig; import android.hardware.broadcastradio.DabTableEntry; @@ -29,17 +32,23 @@ import android.hardware.radio.Announcement; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; -import android.os.Build; + +import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; +import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; import com.google.common.truth.Expect; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import java.util.Map; import java.util.Set; -public final class ConversionUtilsTest { +public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { + + private static final int U_APP_UID = 1001; + private static final int T_APP_UID = 1002; private static final int FM_LOWER_LIMIT = 87_500; private static final int FM_UPPER_LIMIT = 108_000; @@ -118,16 +127,29 @@ public final class ConversionUtilsTest { @Rule public final Expect expect = Expect.create(); + @Override + protected void initializeSession(StaticMockitoSessionBuilder builder) { + builder.spyStatic(CompatChanges.class); + } + + @Before + public void setUp() { + doReturn(true).when(() -> CompatChanges.isChangeEnabled( + ConversionUtils.RADIO_U_VERSION_REQUIRED, U_APP_UID)); + doReturn(false).when(() -> CompatChanges.isChangeEnabled( + ConversionUtils.RADIO_U_VERSION_REQUIRED, T_APP_UID)); + } + @Test public void isAtLeastU_withTSdkVersion_returnsFalse() { expect.withMessage("Target SDK version of T") - .that(ConversionUtils.isAtLeastU(Build.VERSION_CODES.TIRAMISU)).isFalse(); + .that(ConversionUtils.isAtLeastU(T_APP_UID)).isFalse(); } @Test public void isAtLeastU_withCurrentSdkVersion_returnsTrue() { expect.withMessage("Target SDK version of U") - .that(ConversionUtils.isAtLeastU(Build.VERSION_CODES.CUR_DEVELOPMENT)).isTrue(); + .that(ConversionUtils.isAtLeastU(U_APP_UID)).isTrue(); } @Test @@ -372,14 +394,14 @@ public final class ConversionUtilsTest { 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(); + T_APP_UID)).isFalse(); } @Test public void programSelectorMeetsSdkVersionRequirement_withRequiredVersionId_returnsTrue() { expect.withMessage("Selector %s with required SDK version", TEST_FM_SELECTOR) .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(TEST_FM_SELECTOR, - Build.VERSION_CODES.TIRAMISU)).isTrue(); + T_APP_UID)).isTrue(); } @Test @@ -389,7 +411,7 @@ public final class ConversionUtilsTest { expect.withMessage("Program info %s without required SDK version", dabProgramInfo) .that(ConversionUtils.programInfoMeetsSdkVersionRequirement(dabProgramInfo, - Build.VERSION_CODES.TIRAMISU)).isFalse(); + T_APP_UID)).isFalse(); } @Test @@ -399,7 +421,7 @@ public final class ConversionUtilsTest { expect.withMessage("Program info %s with required SDK version", fmProgramInfo) .that(ConversionUtils.programInfoMeetsSdkVersionRequirement(fmProgramInfo, - Build.VERSION_CODES.TIRAMISU)).isTrue(); + T_APP_UID)).isTrue(); } @Test @@ -413,7 +435,7 @@ public final class ConversionUtilsTest { Set.of(TEST_DAB_SID_EXT_ID, TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID)); ProgramList.Chunk convertedChunk = ConversionUtils.convertChunkToTargetSdkVersion(chunk, - Build.VERSION_CODES.TIRAMISU); + T_APP_UID); expect.withMessage( "Purged state of the converted program list chunk with lower SDK version") @@ -441,7 +463,7 @@ public final class ConversionUtilsTest { 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); + U_APP_UID); expect.withMessage("Converted program list chunk with required SDK version") .that(convertedChunk).isEqualTo(chunk); 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 464ecb2b50a11..78b5a4ad71de8 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 @@ -33,6 +33,7 @@ import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.compat.CompatChanges; import android.graphics.Bitmap; import android.hardware.broadcastradio.IBroadcastRadio; import android.hardware.broadcastradio.ITunerCallback; @@ -46,7 +47,6 @@ 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.ParcelableException; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -73,7 +73,6 @@ import java.util.Set; */ 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 = 90; @@ -125,11 +124,13 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(RadioServiceUserController.class); + builder.spyStatic(RadioServiceUserController.class).spyStatic(CompatChanges.class); } @Before public void setup() throws Exception { + doReturn(true).when(() -> CompatChanges.isChangeEnabled( + eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt())); doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); mRadioModule = new RadioModule(mBroadcastRadioMock, @@ -341,7 +342,9 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { @Test public void tune_withLowerSdkVersion() throws Exception { - openAidlClients(/* numClients= */ 1, Build.VERSION_CODES.TIRAMISU); + doReturn(false).when(() -> CompatChanges.isChangeEnabled( + eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt())); + openAidlClients(/* numClients= */ 1); ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); RadioManager.ProgramInfo tuneInfo = AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); @@ -1175,17 +1178,13 @@ 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 { + private void openAidlClients(int numClients) 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], - targetSdkVersion); + mTunerSessions[index] = mRadioModule.openSession(mAidlTunerCallbackMocks[index]); } } diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java index b66120d428c3f..6a010424db139 100644 --- a/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java +++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java @@ -86,8 +86,7 @@ final class IRadioServiceAidlImpl extends IRadioService.Stub { @Override public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, - boolean withAudio, ITunerCallback callback, int targetSdkVersion) - throws RemoteException { + boolean withAudio, ITunerCallback callback) throws RemoteException { if (isDebugEnabled()) { Slogf.d(TAG, "Opening module %d", moduleId); } @@ -95,7 +94,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, targetSdkVersion); + return mHalAidl.openSession(moduleId, bandConfig, withAudio, callback); } @Override diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java index 8a1ba19e24ab7..408fba1bff3b1 100644 --- a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java +++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java @@ -92,8 +92,7 @@ final class IRadioServiceHidlImpl extends IRadioService.Stub { @Override public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, - boolean withAudio, ITunerCallback callback, int targetSdkVersion) - throws RemoteException { + boolean withAudio, ITunerCallback callback) 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 772cd4144f11b..03acf72725e7d 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java @@ -199,8 +199,7 @@ public final class BroadcastRadioServiceImpl { */ @Nullable public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig, - boolean withAudio, ITunerCallback callback, int targetSdkVersion) - throws RemoteException { + boolean withAudio, ITunerCallback callback) throws RemoteException { if (DEBUG) { Slogf.d(TAG, "Open AIDL radio session"); } @@ -223,7 +222,7 @@ public final class BroadcastRadioServiceImpl { } } - TunerSession tunerSession = radioModule.openSession(callback, targetSdkVersion); + TunerSession tunerSession = radioModule.openSession(callback); 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 c0a238feb9b55..4f2bfd1c1e520 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java @@ -17,6 +17,10 @@ package com.android.server.broadcastradio.aidl; import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.hardware.broadcastradio.AmFmRegionConfig; import android.hardware.broadcastradio.Announcement; import android.hardware.broadcastradio.DabTableEntry; @@ -57,16 +61,24 @@ import java.util.Set; * {@link android.hardware.radio} */ final class ConversionUtils { - // TODO(b/241118988): Add unit test for ConversionUtils class private static final String TAG = "BcRadioAidlSrv.convert"; + /** + * With RADIO_U_VERSION_REQUIRED enabled, 44-bit DAB identifier + * {@link IdentifierType#DAB_SID_EXT} from broadcast radio HAL can be passed as + * {@link ProgramSelector#IDENTIFIER_TYPE_DAB_DMB_SID_EXT} to {@link RadioTuner}. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public static final long RADIO_U_VERSION_REQUIRED = 261770108L; + private 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; + @SuppressLint("AndroidFrameworkRequiresPermission") + static boolean isAtLeastU(int uid) { + return CompatChanges.isChangeEnabled(RADIO_U_VERSION_REQUIRED, uid); } static RuntimeException throwOnError(RuntimeException halException, String action) { @@ -584,9 +596,8 @@ final class ConversionUtils { return id.getType() == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT; } - static boolean programSelectorMeetsSdkVersionRequirement(ProgramSelector sel, - int targetSdkVersion) { - if (isAtLeastU(targetSdkVersion)) { + static boolean programSelectorMeetsSdkVersionRequirement(ProgramSelector sel, int uid) { + if (isAtLeastU(uid)) { return true; } if (sel.getPrimaryId().getType() == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT) { @@ -601,12 +612,11 @@ final class ConversionUtils { return true; } - static boolean programInfoMeetsSdkVersionRequirement(RadioManager.ProgramInfo info, - int targetSdkVersion) { - if (isAtLeastU(targetSdkVersion)) { + static boolean programInfoMeetsSdkVersionRequirement(RadioManager.ProgramInfo info, int uid) { + if (isAtLeastU(uid)) { return true; } - if (!programSelectorMeetsSdkVersionRequirement(info.getSelector(), targetSdkVersion)) { + if (!programSelectorMeetsSdkVersionRequirement(info.getSelector(), uid)) { return false; } if (isNewIdentifierInU(info.getLogicallyTunedTo()) @@ -622,16 +632,15 @@ final class ConversionUtils { return true; } - static ProgramList.Chunk convertChunkToTargetSdkVersion(ProgramList.Chunk chunk, - int targetSdkVersion) { - if (isAtLeastU(targetSdkVersion)) { + static ProgramList.Chunk convertChunkToTargetSdkVersion(ProgramList.Chunk chunk, int uid) { + if (isAtLeastU(uid)) { return chunk; } Set modified = new ArraySet<>(); Iterator modifiedIterator = chunk.getModified().iterator(); while (modifiedIterator.hasNext()) { RadioManager.ProgramInfo info = modifiedIterator.next(); - if (programInfoMeetsSdkVersionRequirement(info, targetSdkVersion)) { + if (programInfoMeetsSdkVersionRequirement(info, uid)) { modified.add(info); } } 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 f8c19ae2b8f18..132fb8ef8a952 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java @@ -101,9 +101,9 @@ final class RadioModule { ConversionUtils.programSelectorFromHalProgramSelector(programSelector); int tunerResult = ConversionUtils.halResultToTunerResult(result); synchronized (mLock) { - fanoutAidlCallbackLocked((cb, sdkVersion) -> { + fanoutAidlCallbackLocked((cb, uid) -> { if (csel != null && !ConversionUtils - .programSelectorMeetsSdkVersionRequirement(csel, sdkVersion)) { + .programSelectorMeetsSdkVersionRequirement(csel, uid)) { Slogf.e(TAG, "onTuneFailed: cannot send program selector " + "requiring higher target SDK version"); return; @@ -123,9 +123,9 @@ final class RadioModule { "Program info from AIDL HAL is invalid"); synchronized (mLock) { mCurrentProgramInfo = currentProgramInfo; - fanoutAidlCallbackLocked((cb, sdkVersion) -> { + fanoutAidlCallbackLocked((cb, uid) -> { if (!ConversionUtils.programInfoMeetsSdkVersionRequirement( - currentProgramInfo, sdkVersion)) { + currentProgramInfo, uid)) { Slogf.e(TAG, "onCurrentProgramInfoChanged: cannot send " + "program info requiring higher target SDK version"); return; @@ -156,7 +156,7 @@ final class RadioModule { fireLater(() -> { synchronized (mLock) { mAntennaConnected = connected; - fanoutAidlCallbackLocked((cb, sdkVersion) -> cb.onAntennaState(connected)); + fanoutAidlCallbackLocked((cb, uid) -> cb.onAntennaState(connected)); } }); } @@ -165,7 +165,7 @@ final class RadioModule { public void onConfigFlagUpdated(int flag, boolean value) { fireLater(() -> { synchronized (mLock) { - fanoutAidlCallbackLocked((cb, sdkVersion) -> { + fanoutAidlCallbackLocked((cb, uid) -> { cb.onConfigFlagUpdated(flag, value); }); } @@ -178,7 +178,7 @@ final class RadioModule { synchronized (mLock) { Map cparam = ConversionUtils.vendorInfoFromHalVendorKeyValues(parameters); - fanoutAidlCallbackLocked((cb, sdkVersion) -> { + fanoutAidlCallbackLocked((cb, uid) -> { cb.onParametersUpdated(cparam); }); } @@ -244,14 +244,14 @@ final class RadioModule { mService.setTunerCallback(mHalTunerCallback); } - TunerSession openSession(android.hardware.radio.ITunerCallback userCb, int targetSdkVersion) + TunerSession openSession(android.hardware.radio.ITunerCallback userCb) throws RemoteException { mLogger.logRadioEvent("Open TunerSession"); TunerSession tunerSession; Boolean antennaConnected; RadioManager.ProgramInfo currentProgramInfo; synchronized (mLock) { - tunerSession = new TunerSession(this, mService, userCb, targetSdkVersion); + tunerSession = new TunerSession(this, mService, userCb); mAidlTunerSessions.add(tunerSession); antennaConnected = mAntennaConnected; currentProgramInfo = mCurrentProgramInfo; @@ -404,7 +404,7 @@ final class RadioModule { } interface AidlCallbackRunnable { - void run(android.hardware.radio.ITunerCallback callback, int targetSdkVersion) + void run(android.hardware.radio.ITunerCallback callback, int uid) throws RemoteException; } @@ -423,7 +423,7 @@ final class RadioModule { for (int i = 0; i < mAidlTunerSessions.size(); i++) { try { runnable.run(mAidlTunerSessions.valueAt(i).mCallback, - mAidlTunerSessions.valueAt(i).getTargetSdkVersion()); + mAidlTunerSessions.valueAt(i).getUid()); } 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 fe8c23845d2ab..0a3823f038fa9 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java @@ -24,6 +24,7 @@ import android.hardware.radio.ITuner; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; +import android.os.Binder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.ArraySet; @@ -46,7 +47,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 int mUid; private final IBroadcastRadio mService; @GuardedBy("mLock") @@ -61,11 +62,11 @@ final class TunerSession extends ITuner.Stub { private RadioManager.BandConfig mPlaceHolderConfig; TunerSession(RadioModule radioModule, IBroadcastRadio service, - android.hardware.radio.ITunerCallback callback, int targetSdkVersion) { + android.hardware.radio.ITunerCallback callback) { 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; + mUid = Binder.getCallingUid(); mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE); } @@ -130,7 +131,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, sdkVersion) -> cb.onConfigurationChanged(config)); + mModule.fanoutAidlCallback((cb, mUid) -> cb.onConfigurationChanged(config)); } @Override @@ -254,7 +255,7 @@ 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((cb, sdkVersion) -> { + mModule.fanoutAidlCallback((cb, mUid) -> { cb.onBackgroundScanComplete(); }); return true; @@ -284,8 +285,8 @@ final class TunerSession extends ITuner.Stub { mModule.onTunerSessionProgramListFilterChanged(this); } - int getTargetSdkVersion() { - return mTargetSdkVersion; + int getUid() { + return mUid; } ProgramList.Filter getProgramListFilter() { @@ -323,10 +324,9 @@ final class TunerSession extends ITuner.Stub { } for (int i = 0; i < chunks.size(); i++) { try { - if (!ConversionUtils.isAtLeastU(getTargetSdkVersion())) { + if (!ConversionUtils.isAtLeastU(getUid())) { ProgramList.Chunk downgradedChunk = - ConversionUtils.convertChunkToTargetSdkVersion(chunks.get(i), - getTargetSdkVersion()); + ConversionUtils.convertChunkToTargetSdkVersion(chunks.get(i), getUid()); mCallback.onProgramListUpdated(downgradedChunk); } else { mCallback.onProgramListUpdated(chunks.get(i));