Refactor locks in radio client for HIDL HAL
Seperate locks were used for radio service implementation, radio module, and tuner session in HIDL 2.0 and 1.x HAL clients to minimize performance issue. Potential dead lock issue in TunerSession#close was also fixed. Bug: 258688572 Test: atest com.android.server.broadcastradio.hal2 Test: atest android.broadcastradio.cts Change-Id: I63b1ee6b2d22c424133e7f208148e2863078cc40
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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