summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/radio/TunerCallbackAdapter.java10
-rw-r--r--core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java16
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java47
3 files changed, 48 insertions, 25 deletions
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index 0fb93e532cd3..beff0f7607f8 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -211,10 +211,12 @@ class TunerCallbackAdapter extends ITunerCallback.Stub {
@Override
public void onProgramListUpdated(ProgramList.Chunk chunk) {
- synchronized (mLock) {
- if (mProgramList == null) return;
- mProgramList.apply(Objects.requireNonNull(chunk));
- }
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ if (mProgramList == null) return;
+ mProgramList.apply(Objects.requireNonNull(chunk));
+ }
+ });
}
@Override
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index 3d9a1d9398c5..7c6271cbdf61 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,6 +44,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import org.mockito.verification.VerificationWithTimeout;
import java.util.Arrays;
import java.util.HashSet;
@@ -56,6 +58,8 @@ import java.util.List;
public class StartProgramListUpdatesFanoutTest {
private static final String TAG = "BroadcastRadioTests.hal2.StartProgramListUpdatesFanout";
+ private static final VerificationWithTimeout CB_TIMEOUT = timeout(100);
+
// Mocks
@Mock IBroadcastRadio mBroadcastRadioMock;
@Mock ITunerSession mHalTunerSessionMock;
@@ -200,10 +204,10 @@ public class StartProgramListUpdatesFanoutTest {
// Adding mDabEnsembleInfo should not update any client.
updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
- verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
- verify(mAidlTunerCallbackMocks[1], times(2)).onProgramListUpdated(any());
- verify(mAidlTunerCallbackMocks[2], times(1)).onProgramListUpdated(any());
- verify(mAidlTunerCallbackMocks[3], times(2)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[1], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[2], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[3], CB_TIMEOUT.times(2)).onProgramListUpdated(any());
}
@Test
@@ -240,7 +244,7 @@ public class StartProgramListUpdatesFanoutTest {
// Update the HAL with mModifiedAmFmInfo, and verify only the remaining client is updated.
updateHalProgramInfo(true, Arrays.asList(mModifiedAmFmInfo), null);
- verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any());
verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true,
Arrays.asList(mModifiedAmFmInfo), null);
@@ -313,6 +317,6 @@ public class StartProgramListUpdatesFanoutTest {
}
ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet,
removedSet);
- verify(clientMock).onProgramListUpdated(expectedChunk);
+ verify(clientMock, CB_TIMEOUT).onProgramListUpdated(expectedChunk);
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 53890a48a674..a0eafb4fc93f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -35,6 +35,8 @@ import android.hardware.broadcastradio.V2_0.Result;
import android.hardware.broadcastradio.V2_0.VendorKeyValue;
import android.hardware.radio.RadioManager;
import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.util.MutableInt;
import android.util.Slog;
@@ -45,6 +47,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -56,6 +59,7 @@ class RadioModule {
@NonNull public final RadioManager.ModuleProperties mProperties;
private final Object mLock = new Object();
+ @NonNull private final Handler mHandler;
@GuardedBy("mLock")
private ITunerSession mHalTunerSession;
@@ -77,22 +81,24 @@ class RadioModule {
private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
@Override
public void onTuneFailed(int result, ProgramSelector programSelector) {
- fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal(
- programSelector)));
+ lockAndFireLater(() -> {
+ android.hardware.radio.ProgramSelector csel =
+ Convert.programSelectorFromHal(programSelector);
+ fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
+ });
}
@Override
public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
- RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo);
- synchronized (mLock) {
- mCurrentProgramInfo = programInfo;
- fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo));
- }
+ lockAndFireLater(() -> {
+ mCurrentProgramInfo = Convert.programInfoFromHal(halProgramInfo);
+ fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(mCurrentProgramInfo));
+ });
}
@Override
public void onProgramListUpdated(ProgramListChunk programListChunk) {
- synchronized (mLock) {
+ lockAndFireLater(() -> {
android.hardware.radio.ProgramList.Chunk chunk =
Convert.programListChunkFromHal(programListChunk);
mProgramInfoCache.filterAndApplyChunk(chunk);
@@ -100,20 +106,23 @@ class RadioModule {
for (TunerSession tunerSession : mAidlTunerSessions) {
tunerSession.onMergedProgramListUpdateFromHal(chunk);
}
- }
+ });
}
@Override
public void onAntennaStateChange(boolean connected) {
- synchronized (mLock) {
+ lockAndFireLater(() -> {
mAntennaConnected = connected;
fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
- }
+ });
}
@Override
public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
- fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters)));
+ lockAndFireLater(() -> {
+ Map<String, String> cparam = Convert.vendorInfoFromHal(parameters);
+ fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
+ });
}
};
@@ -126,6 +135,7 @@ class RadioModule {
@NonNull RadioManager.ModuleProperties properties) {
mProperties = Objects.requireNonNull(properties);
mService = Objects.requireNonNull(service);
+ mHandler = new Handler(Looper.getMainLooper());
}
public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
@@ -310,15 +320,22 @@ 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();
+ }
+ });
+ }
+
interface AidlCallbackRunnable {
void run(android.hardware.radio.ITunerCallback callback) throws RemoteException;
}
// Invokes runnable with each TunerSession currently open.
void fanoutAidlCallback(AidlCallbackRunnable runnable) {
- synchronized (mLock) {
- fanoutAidlCallbackLocked(runnable);
- }
+ lockAndFireLater(() -> fanoutAidlCallbackLocked(runnable));
}
private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {