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
This commit is contained in:
Weilin Xu
2023-01-26 18:26:06 +00:00
parent 99e9394054
commit 21da483832
18 changed files with 113 additions and 103 deletions

View File

@@ -31,7 +31,7 @@ interface IRadioService {
List<RadioManager.ModuleProperties> 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);

View File

@@ -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;
}
}

View File

@@ -18,6 +18,8 @@
package="com.android.frameworks.broadcastradiotests">
<uses-permission android:name="android.permission.ACCESS_BROADCAST_RADIO" />
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />

View File

@@ -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);

View File

@@ -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);

View File

@@ -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];

View File

@@ -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");

View File

@@ -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");

View File

@@ -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

View File

@@ -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<String> 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);
}
}

View File

@@ -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);

View File

@@ -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]);
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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<RadioManager.ProgramInfo> modified = new ArraySet<>();
Iterator<RadioManager.ProgramInfo> modifiedIterator = chunk.getModified().iterator();
while (modifiedIterator.hasNext()) {
RadioManager.ProgramInfo info = modifiedIterator.next();
if (programInfoMeetsSdkVersionRequirement(info, targetSdkVersion)) {
if (programInfoMeetsSdkVersionRequirement(info, uid)) {
modified.add(info);
}
}

View File

@@ -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<String, String> 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");

View File

@@ -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));