Merge changes I63b1ee6b,I8de3afa2
* changes: Refactor locks in radio client for HIDL HAL Refactor locks in radio client for AIDL HAL
This commit is contained in:
committed by
Android (Google) Code Review
commit
eeafd7358f
@@ -210,9 +210,9 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes
|
||||
any(IServiceCallback.class)));
|
||||
|
||||
doReturn(mFmRadioModuleMock).when(() -> RadioModule.tryLoadingModule(
|
||||
eq(FM_RADIO_MODULE_ID), anyString(), any(IBinder.class), any(Object.class)));
|
||||
eq(FM_RADIO_MODULE_ID), anyString(), any(IBinder.class)));
|
||||
doReturn(mDabRadioModuleMock).when(() -> RadioModule.tryLoadingModule(
|
||||
eq(DAB_RADIO_MODULE_ID), anyString(), any(IBinder.class), any(Object.class)));
|
||||
eq(DAB_RADIO_MODULE_ID), anyString(), any(IBinder.class)));
|
||||
|
||||
when(mFmRadioModuleMock.getProperties()).thenReturn(mFmModuleMock);
|
||||
when(mDabRadioModuleMock.getProperties()).thenReturn(mDabModuleMock);
|
||||
|
||||
@@ -58,14 +58,13 @@ public final class RadioModuleTest {
|
||||
@Mock
|
||||
private android.hardware.broadcastradio.ICloseHandle mHalCloseHandleMock;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
// RadioModule under test
|
||||
private RadioModule mRadioModule;
|
||||
private android.hardware.broadcastradio.IAnnouncementListener mHalListener;
|
||||
|
||||
@Before
|
||||
public void setup() throws RemoteException {
|
||||
mRadioModule = new RadioModule(mBroadcastRadioMock, TEST_MODULE_PROPERTIES, mLock);
|
||||
mRadioModule = new RadioModule(mBroadcastRadioMock, TEST_MODULE_PROPERTIES);
|
||||
|
||||
// TODO(b/241118988): test non-null image for getImage method
|
||||
when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(null);
|
||||
|
||||
@@ -83,7 +83,6 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
|
||||
@Mock private IBroadcastRadio mBroadcastRadioMock;
|
||||
private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
// RadioModule under test
|
||||
private RadioModule mRadioModule;
|
||||
|
||||
@@ -104,7 +103,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
|
||||
doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
|
||||
|
||||
mRadioModule = new RadioModule(mBroadcastRadioMock,
|
||||
AidlTestUtils.makeDefaultModuleProperties(), mLock);
|
||||
AidlTestUtils.makeDefaultModuleProperties());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
|
||||
|
||||
@@ -59,8 +59,6 @@ public final class BroadcastRadioServiceHidlTest extends ExtendedRadioMockitoTes
|
||||
new ArrayList<>(Arrays.asList("FmService", "DabService"));
|
||||
private static final int[] TEST_ENABLED_TYPES = new int[]{Announcement.TYPE_TRAFFIC};
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private BroadcastRadioService mBroadcastRadioService;
|
||||
private DeathRecipient mFmDeathRecipient;
|
||||
|
||||
@@ -200,7 +198,7 @@ public final class BroadcastRadioServiceHidlTest extends ExtendedRadioMockitoTes
|
||||
|
||||
mockServiceManager();
|
||||
mBroadcastRadioService = new BroadcastRadioService(/* nextModuleId= */ FM_RADIO_MODULE_ID,
|
||||
mLock, mServiceManagerMock);
|
||||
mServiceManagerMock);
|
||||
}
|
||||
|
||||
private void mockServiceManager() throws RemoteException {
|
||||
@@ -221,9 +219,9 @@ public final class BroadcastRadioServiceHidlTest extends ExtendedRadioMockitoTes
|
||||
}).thenReturn(true);
|
||||
|
||||
doReturn(mFmRadioModuleMock).when(() -> RadioModule.tryLoadingModule(
|
||||
eq(FM_RADIO_MODULE_ID), anyString(), any(Object.class)));
|
||||
eq(FM_RADIO_MODULE_ID), anyString()));
|
||||
doReturn(mDabRadioModuleMock).when(() -> RadioModule.tryLoadingModule(
|
||||
eq(DAB_RADIO_MODULE_ID), anyString(), any(Object.class)));
|
||||
eq(DAB_RADIO_MODULE_ID), anyString()));
|
||||
|
||||
when(mFmRadioModuleMock.getProperties()).thenReturn(mFmModuleMock);
|
||||
when(mDabRadioModuleMock.getProperties()).thenReturn(mDabModuleMock);
|
||||
|
||||
@@ -62,13 +62,12 @@ public final class RadioModuleHidlTest {
|
||||
@Mock
|
||||
private android.hardware.broadcastradio.V2_0.ICloseHandle mHalCloseHandleMock;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private RadioModule mRadioModule;
|
||||
private android.hardware.broadcastradio.V2_0.IAnnouncementListener mHalListener;
|
||||
|
||||
@Before
|
||||
public void setup() throws RemoteException {
|
||||
mRadioModule = new RadioModule(mBroadcastRadioMock, TEST_MODULE_PROPERTIES, mLock);
|
||||
mRadioModule = new RadioModule(mBroadcastRadioMock, TEST_MODULE_PROPERTIES);
|
||||
|
||||
when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(new ArrayList<Byte>(0));
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ public class StartProgramListUpdatesFanoutTest extends ExtendedRadioMockitoTestC
|
||||
@Mock ITunerSession mHalTunerSessionMock;
|
||||
private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
// RadioModule under test
|
||||
private RadioModule mRadioModule;
|
||||
|
||||
@@ -100,7 +99,7 @@ public class StartProgramListUpdatesFanoutTest extends ExtendedRadioMockitoTestC
|
||||
doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
|
||||
|
||||
mRadioModule = new RadioModule(mBroadcastRadioMock,
|
||||
TestUtils.makeDefaultModuleProperties(), mLock);
|
||||
TestUtils.makeDefaultModuleProperties());
|
||||
|
||||
doAnswer((Answer) invocation -> {
|
||||
mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
|
||||
|
||||
@@ -84,7 +84,6 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
|
||||
new RadioManager.FmBandConfig(FM_BAND_DESCRIPTOR);
|
||||
private static final int UNSUPPORTED_CONFIG_FLAG = 0;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final ArrayMap<Integer, Boolean> mHalConfigMap = new ArrayMap<>();
|
||||
private RadioModule mRadioModule;
|
||||
private ITunerCallback mHalTunerCallback;
|
||||
@@ -105,7 +104,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
|
||||
doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
|
||||
|
||||
mRadioModule = new RadioModule(mBroadcastRadioMock,
|
||||
TestUtils.makeDefaultModuleProperties(), mLock);
|
||||
TestUtils.makeDefaultModuleProperties());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.broadcastradio.hal2.AnnouncementAggregator;
|
||||
|
||||
@@ -51,15 +52,17 @@ final class IRadioServiceHidlImpl extends IRadioService.Stub {
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private final BroadcastRadioService mService;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final List<RadioManager.ModuleProperties> mV1Modules;
|
||||
|
||||
IRadioServiceHidlImpl(BroadcastRadioService service) {
|
||||
mService = Objects.requireNonNull(service, "broadcast radio service cannot be null");
|
||||
mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService(mLock);
|
||||
mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService();
|
||||
mV1Modules = mHal1.loadModules();
|
||||
OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max();
|
||||
mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(
|
||||
max.isPresent() ? max.getAsInt() + 1 : 0, mLock);
|
||||
max.isPresent() ? max.getAsInt() + 1 : 0);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -78,9 +81,11 @@ final class IRadioServiceHidlImpl extends IRadioService.Stub {
|
||||
public List<RadioManager.ModuleProperties> listModules() {
|
||||
mService.enforcePolicyAccess();
|
||||
Collection<RadioManager.ModuleProperties> v2Modules = mHal2.listModules();
|
||||
List<RadioManager.ModuleProperties> modules = new ArrayList<>(
|
||||
mV1Modules.size() + v2Modules.size());
|
||||
modules.addAll(mV1Modules);
|
||||
List<RadioManager.ModuleProperties> modules;
|
||||
synchronized (mLock) {
|
||||
modules = new ArrayList<>(mV1Modules.size() + v2Modules.size());
|
||||
modules.addAll(mV1Modules);
|
||||
}
|
||||
modules.addAll(v2Modules);
|
||||
return modules;
|
||||
}
|
||||
@@ -131,7 +136,9 @@ final class IRadioServiceHidlImpl extends IRadioService.Stub {
|
||||
radioPw.printf("HAL1: %s\n", mHal1);
|
||||
|
||||
radioPw.increaseIndent();
|
||||
radioPw.printf("Modules of HAL1: %s\n", mV1Modules);
|
||||
synchronized (mLock) {
|
||||
radioPw.printf("Modules of HAL1: %s\n", mV1Modules);
|
||||
}
|
||||
radioPw.decreaseIndent();
|
||||
|
||||
radioPw.printf("HAL2:\n");
|
||||
|
||||
@@ -77,7 +77,7 @@ public final class BroadcastRadioServiceImpl {
|
||||
}
|
||||
|
||||
RadioModule radioModule =
|
||||
RadioModule.tryLoadingModule(moduleId, name, newBinder, mLock);
|
||||
RadioModule.tryLoadingModule(moduleId, name, newBinder);
|
||||
if (radioModule == null) {
|
||||
Slogf.w(TAG, "No module %s with id %d (HAL AIDL)", name, moduleId);
|
||||
return;
|
||||
|
||||
@@ -55,7 +55,7 @@ final class RadioModule {
|
||||
|
||||
private final IBroadcastRadio mService;
|
||||
|
||||
private final Object mLock;
|
||||
private final Object mLock = new Object();
|
||||
private final Handler mHandler;
|
||||
private final RadioLogger mLogger;
|
||||
private final RadioManager.ModuleProperties mProperties;
|
||||
@@ -165,18 +165,15 @@ final class RadioModule {
|
||||
};
|
||||
|
||||
@VisibleForTesting
|
||||
RadioModule(IBroadcastRadio service,
|
||||
RadioManager.ModuleProperties properties, Object lock) {
|
||||
RadioModule(IBroadcastRadio service, RadioManager.ModuleProperties properties) {
|
||||
mProperties = Objects.requireNonNull(properties, "properties cannot be null");
|
||||
mService = Objects.requireNonNull(service, "service cannot be null");
|
||||
mLock = Objects.requireNonNull(lock, "lock cannot be null");
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mLogger = new RadioLogger(TAG, RADIO_EVENT_LOGGER_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static RadioModule tryLoadingModule(int moduleId, String moduleName,
|
||||
IBinder serviceBinder, Object lock) {
|
||||
static RadioModule tryLoadingModule(int moduleId, String moduleName, IBinder serviceBinder) {
|
||||
try {
|
||||
Slogf.i(TAG, "Try loading module for module id = %d, module name = %s",
|
||||
moduleId, moduleName);
|
||||
@@ -206,7 +203,7 @@ final class RadioModule {
|
||||
RadioManager.ModuleProperties prop = ConversionUtils.propertiesFromHalProperties(
|
||||
moduleId, moduleName, service.getProperties(), amfmConfig, dabConfig);
|
||||
|
||||
return new RadioModule(service, prop, lock);
|
||||
return new RadioModule(service, prop);
|
||||
} catch (RemoteException ex) {
|
||||
Slogf.e(TAG, ex, "Failed to load module %s", moduleName);
|
||||
return null;
|
||||
@@ -222,9 +219,7 @@ final class RadioModule {
|
||||
}
|
||||
|
||||
void setInternalHalCallback() throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
mService.setTunerCallback(mHalTunerCallback);
|
||||
}
|
||||
mService.setTunerCallback(mHalTunerCallback);
|
||||
}
|
||||
|
||||
TunerSession openSession(android.hardware.radio.ITunerCallback userCb)
|
||||
@@ -234,7 +229,7 @@ final class RadioModule {
|
||||
Boolean antennaConnected;
|
||||
RadioManager.ProgramInfo currentProgramInfo;
|
||||
synchronized (mLock) {
|
||||
tunerSession = new TunerSession(this, mService, userCb, mLock);
|
||||
tunerSession = new TunerSession(this, mService, userCb);
|
||||
mAidlTunerSessions.add(tunerSession);
|
||||
antennaConnected = mAntennaConnected;
|
||||
currentProgramInfo = mCurrentProgramInfo;
|
||||
@@ -356,14 +351,14 @@ final class RadioModule {
|
||||
// Otherwise, update the HAL's filter, and AIDL clients will be updated when
|
||||
// mHalTunerCallback.onProgramListUpdated() is called.
|
||||
mUnionOfAidlProgramFilters = newFilter;
|
||||
try {
|
||||
mService.startProgramListUpdates(
|
||||
ConversionUtils.filterToHalProgramFilter(newFilter));
|
||||
} catch (RuntimeException ex) {
|
||||
throw ConversionUtils.throwOnError(ex, /* action= */ "Start Program ListUpdates");
|
||||
} catch (RemoteException ex) {
|
||||
Slogf.e(TAG, ex, "mHalTunerSession.startProgramListUpdates() failed");
|
||||
}
|
||||
}
|
||||
try {
|
||||
mService.startProgramListUpdates(
|
||||
ConversionUtils.filterToHalProgramFilter(newFilter));
|
||||
} catch (RuntimeException ex) {
|
||||
throw ConversionUtils.throwOnError(ex, /* action= */ "Start Program ListUpdates");
|
||||
} catch (RemoteException ex) {
|
||||
Slogf.e(TAG, ex, "mHalTunerSession.startProgramListUpdates() failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,12 +448,10 @@ final class RadioModule {
|
||||
}
|
||||
};
|
||||
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
hwCloseHandle[0] = mService.registerAnnouncementListener(hwListener, enabledList);
|
||||
} catch (RuntimeException ex) {
|
||||
throw ConversionUtils.throwOnError(ex, /* action= */ "AnnouncementListener");
|
||||
}
|
||||
try {
|
||||
hwCloseHandle[0] = mService.registerAnnouncementListener(hwListener, enabledList);
|
||||
} catch (RuntimeException ex) {
|
||||
throw ConversionUtils.throwOnError(ex, /* action= */ "AnnouncementListener");
|
||||
}
|
||||
|
||||
return new android.hardware.radio.ICloseHandle.Stub() {
|
||||
@@ -478,12 +471,10 @@ final class RadioModule {
|
||||
if (id == 0) throw new IllegalArgumentException("Image ID is missing");
|
||||
|
||||
byte[] rawImage;
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
rawImage = mService.getImage(id);
|
||||
} catch (RemoteException ex) {
|
||||
throw ex.rethrowFromSystemServer();
|
||||
}
|
||||
try {
|
||||
rawImage = mService.getImage(id);
|
||||
} catch (RemoteException ex) {
|
||||
throw ex.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
if (rawImage == null || rawImage.length == 0) return null;
|
||||
|
||||
@@ -42,7 +42,7 @@ final class TunerSession extends ITuner.Stub {
|
||||
private static final String TAG = "BcRadioAidlSrv.session";
|
||||
private static final int TUNER_EVENT_LOGGER_QUEUE_SIZE = 25;
|
||||
|
||||
private final Object mLock;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private final RadioLogger mLogger;
|
||||
private final RadioModule mModule;
|
||||
@@ -61,12 +61,10 @@ final class TunerSession extends ITuner.Stub {
|
||||
private RadioManager.BandConfig mPlaceHolderConfig;
|
||||
|
||||
TunerSession(RadioModule radioModule, IBroadcastRadio service,
|
||||
android.hardware.radio.ITunerCallback callback,
|
||||
Object lock) {
|
||||
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");
|
||||
mLock = Objects.requireNonNull(lock, "lock cannot be null");
|
||||
mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
@@ -91,17 +89,19 @@ final class TunerSession extends ITuner.Stub {
|
||||
mLogger.logRadioEvent("Close tuner session on error %d", error);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (mIsClosed) return;
|
||||
if (error != null) {
|
||||
try {
|
||||
mCallback.onError(error);
|
||||
} catch (RemoteException ex) {
|
||||
Slogf.w(TAG, ex, "mCallback.onError(%s) failed", error);
|
||||
}
|
||||
if (mIsClosed) {
|
||||
return;
|
||||
}
|
||||
mIsClosed = true;
|
||||
mModule.onTunerSessionClosed(this);
|
||||
}
|
||||
if (error != null) {
|
||||
try {
|
||||
mCallback.onError(error);
|
||||
} catch (RemoteException ex) {
|
||||
Slogf.w(TAG, ex, "mCallback.onError(%s) failed", error);
|
||||
}
|
||||
}
|
||||
mModule.onTunerSessionClosed(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -36,7 +36,7 @@ public class BroadcastRadioService {
|
||||
*/
|
||||
private final long mNativeContext = nativeInit();
|
||||
|
||||
private final Object mLock;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
@@ -50,14 +50,6 @@ public class BroadcastRadioService {
|
||||
private native Tuner nativeOpenTuner(long nativeContext, int moduleId,
|
||||
RadioManager.BandConfig config, boolean withAudio, ITunerCallback callback);
|
||||
|
||||
/**
|
||||
* Constructor. should pass
|
||||
* {@code com.android.server.broadcastradio.BroadcastRadioService#mLock} for lock.
|
||||
*/
|
||||
public BroadcastRadioService(Object lock) {
|
||||
mLock = lock;
|
||||
}
|
||||
|
||||
public @NonNull List<RadioManager.ModuleProperties> loadModules() {
|
||||
synchronized (mLock) {
|
||||
return Objects.requireNonNull(nativeLoadModules(mNativeContext));
|
||||
|
||||
@@ -43,13 +43,16 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BroadcastRadioService {
|
||||
/**
|
||||
* Broadcast radio service using BroadcastRadio HIDL 2.0 HAL
|
||||
*/
|
||||
public final class BroadcastRadioService {
|
||||
private static final String TAG = "BcRadio2Srv";
|
||||
|
||||
private final Object mLock;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private int mNextModuleId = 0;
|
||||
private int mNextModuleId;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final Map<String, Integer> mServiceNameToModuleIdMap = new HashMap<>();
|
||||
@@ -72,7 +75,7 @@ public class BroadcastRadioService {
|
||||
moduleId = mNextModuleId;
|
||||
}
|
||||
|
||||
RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName, mLock);
|
||||
RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName);
|
||||
if (module == null) {
|
||||
return;
|
||||
}
|
||||
@@ -120,9 +123,8 @@ public class BroadcastRadioService {
|
||||
}
|
||||
};
|
||||
|
||||
public BroadcastRadioService(int nextModuleId, Object lock) {
|
||||
public BroadcastRadioService(int nextModuleId) {
|
||||
mNextModuleId = nextModuleId;
|
||||
mLock = lock;
|
||||
try {
|
||||
IServiceManager manager = IServiceManager.getService();
|
||||
if (manager == null) {
|
||||
@@ -136,9 +138,8 @@ public class BroadcastRadioService {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BroadcastRadioService(int nextModuleId, Object lock, IServiceManager manager) {
|
||||
BroadcastRadioService(int nextModuleId, IServiceManager manager) {
|
||||
mNextModuleId = nextModuleId;
|
||||
mLock = lock;
|
||||
Objects.requireNonNull(manager, "Service manager cannot be null");
|
||||
try {
|
||||
manager.registerForNotifications(IBroadcastRadio.kInterfaceName, "", mServiceListener);
|
||||
@@ -180,7 +181,7 @@ public class BroadcastRadioService {
|
||||
throw new IllegalArgumentException("Non-audio sessions not supported with HAL 2.0");
|
||||
}
|
||||
|
||||
RadioModule module = null;
|
||||
RadioModule module;
|
||||
synchronized (mLock) {
|
||||
module = mModules.get(moduleId);
|
||||
if (module == null) {
|
||||
|
||||
@@ -60,7 +60,7 @@ final class RadioModule {
|
||||
@NonNull private final IBroadcastRadio mService;
|
||||
@NonNull private final RadioManager.ModuleProperties mProperties;
|
||||
|
||||
private final Object mLock;
|
||||
private final Object mLock = new Object();
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final RadioEventLogger mEventLogger;
|
||||
|
||||
@@ -75,7 +75,7 @@ final class RadioModule {
|
||||
private RadioManager.ProgramInfo mCurrentProgramInfo = null;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final ProgramInfoCache mProgramInfoCache = new ProgramInfoCache(null);
|
||||
private final ProgramInfoCache mProgramInfoCache = new ProgramInfoCache(/* filter= */ null);
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private android.hardware.radio.ProgramList.Filter mUnionOfAidlProgramFilters = null;
|
||||
@@ -84,47 +84,59 @@ final class RadioModule {
|
||||
private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
|
||||
@Override
|
||||
public void onTuneFailed(int result, ProgramSelector programSelector) {
|
||||
lockAndFireLater(() -> {
|
||||
fireLater(() -> {
|
||||
android.hardware.radio.ProgramSelector csel =
|
||||
Convert.programSelectorFromHal(programSelector);
|
||||
fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
|
||||
synchronized (mLock) {
|
||||
fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
|
||||
lockAndFireLater(() -> {
|
||||
mCurrentProgramInfo = Convert.programInfoFromHal(halProgramInfo);
|
||||
fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(mCurrentProgramInfo));
|
||||
fireLater(() -> {
|
||||
synchronized (mLock) {
|
||||
mCurrentProgramInfo = Convert.programInfoFromHal(halProgramInfo);
|
||||
RadioManager.ProgramInfo currentProgramInfo = mCurrentProgramInfo;
|
||||
fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(
|
||||
currentProgramInfo));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgramListUpdated(ProgramListChunk programListChunk) {
|
||||
lockAndFireLater(() -> {
|
||||
fireLater(() -> {
|
||||
android.hardware.radio.ProgramList.Chunk chunk =
|
||||
Convert.programListChunkFromHal(programListChunk);
|
||||
mProgramInfoCache.filterAndApplyChunk(chunk);
|
||||
synchronized (mLock) {
|
||||
mProgramInfoCache.filterAndApplyChunk(chunk);
|
||||
|
||||
for (TunerSession tunerSession : mAidlTunerSessions) {
|
||||
tunerSession.onMergedProgramListUpdateFromHal(chunk);
|
||||
for (TunerSession tunerSession : mAidlTunerSessions) {
|
||||
tunerSession.onMergedProgramListUpdateFromHal(chunk);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAntennaStateChange(boolean connected) {
|
||||
lockAndFireLater(() -> {
|
||||
mAntennaConnected = connected;
|
||||
fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
|
||||
fireLater(() -> {
|
||||
synchronized (mLock) {
|
||||
mAntennaConnected = connected;
|
||||
fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
|
||||
lockAndFireLater(() -> {
|
||||
fireLater(() -> {
|
||||
Map<String, String> cparam = Convert.vendorInfoFromHal(parameters);
|
||||
fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
|
||||
synchronized (mLock) {
|
||||
fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -135,17 +147,15 @@ final class RadioModule {
|
||||
|
||||
@VisibleForTesting
|
||||
RadioModule(@NonNull IBroadcastRadio service,
|
||||
@NonNull RadioManager.ModuleProperties properties, @NonNull Object lock) {
|
||||
@NonNull RadioManager.ModuleProperties properties) {
|
||||
mProperties = Objects.requireNonNull(properties);
|
||||
mService = Objects.requireNonNull(service);
|
||||
mLock = Objects.requireNonNull(lock);
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mEventLogger = new RadioEventLogger(TAG, RADIO_EVENT_LOGGER_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static RadioModule tryLoadingModule(int idx, @NonNull String fqName,
|
||||
Object lock) {
|
||||
static RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
|
||||
try {
|
||||
Slog.i(TAG, "Try loading module for idx " + idx + ", fqName " + fqName);
|
||||
IBroadcastRadio service = IBroadcastRadio.getService(fqName);
|
||||
@@ -167,7 +177,7 @@ final class RadioModule {
|
||||
RadioManager.ModuleProperties prop = Convert.propertiesFromHal(idx, fqName,
|
||||
service.getProperties(), amfmConfig.value, dabConfig.value);
|
||||
|
||||
return new RadioModule(service, prop, lock);
|
||||
return new RadioModule(service, prop);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.e(TAG, "Failed to load module " + fqName, ex);
|
||||
return null;
|
||||
@@ -196,8 +206,7 @@ final class RadioModule {
|
||||
});
|
||||
mHalTunerSession = Objects.requireNonNull(hwSession.value);
|
||||
}
|
||||
TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb,
|
||||
mLock);
|
||||
TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb);
|
||||
mAidlTunerSessions.add(tunerSession);
|
||||
|
||||
// Propagate state to new client. Note: These callbacks are invoked while holding mLock
|
||||
@@ -229,6 +238,7 @@ final class RadioModule {
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private android.hardware.radio.ProgramList.Filter
|
||||
buildUnionOfTunerSessionFiltersLocked() {
|
||||
@@ -281,6 +291,7 @@ final class RadioModule {
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onTunerSessionProgramListFilterChangedLocked(@Nullable TunerSession session) {
|
||||
android.hardware.radio.ProgramList.Filter newFilter =
|
||||
buildUnionOfTunerSessionFiltersLocked();
|
||||
@@ -325,6 +336,7 @@ final class RadioModule {
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onTunerSessionsClosedLocked(TunerSession... tunerSessions) {
|
||||
for (TunerSession tunerSession : tunerSessions) {
|
||||
mAidlTunerSessions.remove(tunerSession);
|
||||
@@ -342,12 +354,8 @@ final class RadioModule {
|
||||
}
|
||||
|
||||
// add to mHandler queue, but ensure the runnable holds mLock when it gets executed
|
||||
private void lockAndFireLater(Runnable r) {
|
||||
mHandler.post(() -> {
|
||||
synchronized (mLock) {
|
||||
r.run();
|
||||
}
|
||||
});
|
||||
private void fireLater(Runnable r) {
|
||||
mHandler.post(() -> r.run());
|
||||
}
|
||||
|
||||
interface AidlCallbackRunnable {
|
||||
@@ -356,9 +364,14 @@ final class RadioModule {
|
||||
|
||||
// Invokes runnable with each TunerSession currently open.
|
||||
void fanoutAidlCallback(AidlCallbackRunnable runnable) {
|
||||
lockAndFireLater(() -> fanoutAidlCallbackLocked(runnable));
|
||||
fireLater(() -> {
|
||||
synchronized (mLock) {
|
||||
fanoutAidlCallbackLocked(runnable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
|
||||
List<TunerSession> deadSessions = null;
|
||||
for (TunerSession tunerSession : mAidlTunerSessions) {
|
||||
@@ -399,12 +412,10 @@ final class RadioModule {
|
||||
}
|
||||
};
|
||||
|
||||
synchronized (mLock) {
|
||||
mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHnd) -> {
|
||||
halResult.value = result;
|
||||
hwCloseHandle.value = closeHnd;
|
||||
});
|
||||
}
|
||||
mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHandle) -> {
|
||||
halResult.value = result;
|
||||
hwCloseHandle.value = closeHandle;
|
||||
});
|
||||
Convert.throwOnError("addAnnouncementListener", halResult.value);
|
||||
|
||||
return new android.hardware.radio.ICloseHandle.Stub() {
|
||||
@@ -424,12 +435,10 @@ final class RadioModule {
|
||||
if (id == 0) throw new IllegalArgumentException("Image ID is missing");
|
||||
|
||||
byte[] rawImage;
|
||||
synchronized (mLock) {
|
||||
List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
|
||||
rawImage = new byte[rawList.size()];
|
||||
for (int i = 0; i < rawList.size(); i++) {
|
||||
rawImage[i] = rawList.get(i);
|
||||
}
|
||||
List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
|
||||
rawImage = new byte[rawList.size()];
|
||||
for (int i = 0; i < rawList.size(); i++) {
|
||||
rawImage[i] = rawList.get(i);
|
||||
}
|
||||
|
||||
if (rawImage == null || rawImage.length == 0) return null;
|
||||
@@ -440,17 +449,17 @@ final class RadioModule {
|
||||
void dumpInfo(IndentingPrintWriter pw) {
|
||||
pw.printf("RadioModule\n");
|
||||
pw.increaseIndent();
|
||||
pw.printf("BroadcastRadioService: %s\n", mService);
|
||||
pw.printf("Properties: %s\n", mProperties);
|
||||
synchronized (mLock) {
|
||||
pw.printf("BroadcastRadioService: %s\n", mService);
|
||||
pw.printf("Properties: %s\n", mProperties);
|
||||
pw.printf("HIDL2.0 HAL TunerSession: %s\n", mHalTunerSession);
|
||||
pw.printf("HIDL 2.0 HAL TunerSession: %s\n", mHalTunerSession);
|
||||
pw.printf("Is antenna connected? ");
|
||||
if (mAntennaConnected == null) {
|
||||
pw.printf("null\n");
|
||||
} else {
|
||||
pw.printf("%s\n", mAntennaConnected ? "Yes" : "No");
|
||||
}
|
||||
pw.printf("current ProgramInfo: %s\n", mCurrentProgramInfo);
|
||||
pw.printf("Current ProgramInfo: %s\n", mCurrentProgramInfo);
|
||||
pw.printf("ProgramInfoCache: %s\n", mProgramInfoCache);
|
||||
pw.printf("Union of AIDL ProgramFilters: %s\n", mUnionOfAidlProgramFilters);
|
||||
pw.printf("AIDL TunerSessions:\n");
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.util.MutableBoolean;
|
||||
import android.util.MutableInt;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.broadcastradio.RadioServiceUserController;
|
||||
import com.android.server.utils.Slogf;
|
||||
|
||||
@@ -46,26 +47,28 @@ class TunerSession extends ITuner.Stub {
|
||||
private static final String kAudioDeviceName = "Radio tuner source";
|
||||
private static final int TUNER_EVENT_LOGGER_QUEUE_SIZE = 25;
|
||||
|
||||
private final Object mLock;
|
||||
private final Object mLock = new Object();
|
||||
@NonNull private final RadioEventLogger mEventLogger;
|
||||
|
||||
private final RadioModule mModule;
|
||||
private final ITunerSession mHwSession;
|
||||
final android.hardware.radio.ITunerCallback mCallback;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean mIsClosed = false;
|
||||
@GuardedBy("mLock")
|
||||
private boolean mIsMuted = false;
|
||||
@GuardedBy("mLock")
|
||||
private ProgramInfoCache mProgramInfoCache = null;
|
||||
|
||||
// necessary only for older APIs compatibility
|
||||
private RadioManager.BandConfig mDummyConfig = null;
|
||||
|
||||
TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession,
|
||||
@NonNull android.hardware.radio.ITunerCallback callback,
|
||||
@NonNull Object lock) {
|
||||
@NonNull android.hardware.radio.ITunerCallback callback) {
|
||||
mModule = Objects.requireNonNull(module);
|
||||
mHwSession = Objects.requireNonNull(hwSession);
|
||||
mCallback = Objects.requireNonNull(callback);
|
||||
mLock = Objects.requireNonNull(lock);
|
||||
mEventLogger = new RadioEventLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
@@ -86,23 +89,26 @@ class TunerSession extends ITuner.Stub {
|
||||
mEventLogger.logRadioEvent("Close on error %d", error);
|
||||
synchronized (mLock) {
|
||||
if (mIsClosed) return;
|
||||
if (error != null) {
|
||||
try {
|
||||
mCallback.onError(error);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "mCallback.onError() failed: ", ex);
|
||||
}
|
||||
}
|
||||
mIsClosed = true;
|
||||
mModule.onTunerSessionClosed(this);
|
||||
}
|
||||
if (error != null) {
|
||||
try {
|
||||
mCallback.onError(error);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "mCallback.onError() failed: ", ex);
|
||||
}
|
||||
}
|
||||
mModule.onTunerSessionClosed(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return mIsClosed;
|
||||
synchronized (mLock) {
|
||||
return mIsClosed;
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void checkNotClosedLocked() {
|
||||
if (mIsClosed) {
|
||||
throw new IllegalStateException("Tuner is closed, no further operations are allowed");
|
||||
@@ -118,9 +124,9 @@ class TunerSession extends ITuner.Stub {
|
||||
synchronized (mLock) {
|
||||
checkNotClosedLocked();
|
||||
mDummyConfig = Objects.requireNonNull(config);
|
||||
Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.0");
|
||||
mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config));
|
||||
}
|
||||
Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.0");
|
||||
mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,8 +143,8 @@ class TunerSession extends ITuner.Stub {
|
||||
checkNotClosedLocked();
|
||||
if (mIsMuted == mute) return;
|
||||
mIsMuted = mute;
|
||||
Slog.w(TAG, "Mute via RadioService is not implemented - please handle it via app");
|
||||
}
|
||||
Slog.w(TAG, "Mute via RadioService is not implemented - please handle it via app");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -383,8 +389,8 @@ class TunerSession extends ITuner.Stub {
|
||||
void dumpInfo(IndentingPrintWriter pw) {
|
||||
pw.printf("TunerSession\n");
|
||||
pw.increaseIndent();
|
||||
pw.printf("HIDL HAL Session: %s\n", mHwSession);
|
||||
synchronized (mLock) {
|
||||
pw.printf("HIDL HAL Session: %s\n", mHwSession);
|
||||
pw.printf("Is session closed? %s\n", mIsClosed ? "Yes" : "No");
|
||||
pw.printf("Is muted? %s\n", mIsMuted ? "Yes" : "No");
|
||||
pw.printf("ProgramInfoCache: %s\n", mProgramInfoCache);
|
||||
|
||||
Reference in New Issue
Block a user