Resolve flaky audio routing CUJ tests
Cleans up the flaky audio routing tests which were verifying endpoints
switches. It turned out that the test were flaky from other tests not
properly cleaning up. The audio focus was not being abandoned and the
routing hadn't been processed up to that point. This ended up leaking
into subsequent tests where audio routing requests were piling up from
multiple tests. Asserting MODE_NORMAL here isn't sufficient as it
doesn't account for the audio routing to have been processed so waiting
to process the tests with SystemClock.sleep is sufficient enough to give
the routing enough time to finish processing the end of the call.
Bug: 384101577
Test: atest CtsTelecomCujTestCases:SingleCallingTest
Flag: EXEMPT test fix
Change-Id: I184a713991c450a64f880c9a0dc69fbb38b65fb0
diff --git a/src/com/android/server/telecom/CallAudioRouteController.java b/src/com/android/server/telecom/CallAudioRouteController.java
index 4451a94..d6eedc3 100644
--- a/src/com/android/server/telecom/CallAudioRouteController.java
+++ b/src/com/android/server/telecom/CallAudioRouteController.java
@@ -65,6 +65,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -120,6 +121,8 @@
private boolean mAvailableRoutesUpdated;
private final Object mLock = new Object();
private final TelecomSystem.SyncRoot mTelecomLock;
+ private CountDownLatch mAudioOperationsCompleteLatch;
+ private CountDownLatch mAudioActiveCompleteLatch;
private final BroadcastReceiver mSpeakerPhoneChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -442,6 +445,12 @@
} else {
mCurrentRoute = DUMMY_ROUTE;
}
+ // Audio ops will only ever be completed if there's a call placed and it gains
+ // ACTIVE/RINGING focus, hence why the initial value is 0.
+ mAudioOperationsCompleteLatch = new CountDownLatch(0);
+ // This latch will be count down when ACTIVE/RINGING focus is gained. This is determined
+ // when the routing goes active.
+ mAudioActiveCompleteLatch = new CountDownLatch(1);
mIsActive = false;
mCallAudioState = new CallAudioState(mIsMute, ROUTE_MAP.get(mCurrentRoute.getType()),
supportMask, null, new HashSet<>());
@@ -1118,6 +1127,21 @@
mIsPending = false;
mPendingAudioRoute.clearPendingMessages();
onCurrentRouteChanged();
+ if (mIsActive) {
+ // Reinitialize the audio ops complete latch since the routing went active. We
+ // should always expect operations to complete after this point.
+ if (mAudioOperationsCompleteLatch.getCount() == 0) {
+ mAudioOperationsCompleteLatch = new CountDownLatch(1);
+ }
+ mAudioActiveCompleteLatch.countDown();
+ } else {
+ // Reinitialize the active routing latch when audio ops are complete so that it can
+ // once again be processed when a new call is placed/received.
+ if (mAudioActiveCompleteLatch.getCount() == 0) {
+ mAudioActiveCompleteLatch = new CountDownLatch(1);
+ }
+ mAudioOperationsCompleteLatch.countDown();
+ }
if (mFeatureFlags.telecomMetricsSupport()) {
mMetricsController.getAudioRouteStats().onRouteExit(mPendingAudioRoute, true);
}
@@ -1650,4 +1674,12 @@
sendMessageWithSessionInfo(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE,
btAddressToExclude);
}
+
+ public CountDownLatch getAudioOperationsCompleteLatch() {
+ return mAudioOperationsCompleteLatch;
+ }
+
+ public CountDownLatch getAudioActiveCompleteLatch() {
+ return mAudioActiveCompleteLatch;
+ }
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index dbd33f7..7b99aff 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -379,6 +379,7 @@
Analytics.THIRD_PARTY_PHONE);
}
+ private static final long WAIT_FOR_AUDIO_UPDATE_TIMEOUT = 4000L;
/**
* The main call repository. Keeps an instance of all live calls. New incoming and outgoing
* calls are added to the map and removed when the calls move to the disconnected state.
@@ -513,6 +514,7 @@
private final IncomingCallFilterGraphProvider mIncomingCallFilterGraphProvider;
private final CallAudioWatchdog mCallAudioWatchDog;
+ private final CallAudioRouteAdapter mCallAudioRouteAdapter;
private final ConnectionServiceFocusManager.CallsManagerRequester mRequester =
new ConnectionServiceFocusManager.CallsManagerRequester() {
@@ -691,12 +693,11 @@
mDtmfLocalTonePlayer =
new DtmfLocalTonePlayer(new DtmfLocalTonePlayer.ToneGeneratorProxy());
- CallAudioRouteAdapter callAudioRouteAdapter;
// TODO: add another flag check when
// bluetoothDeviceManager.getBluetoothHeadset().isScoManagedByAudio()
// available and return true
if (!featureFlags.useRefactoredAudioRouteSwitching()) {
- callAudioRouteAdapter = callAudioRouteStateMachineFactory.create(
+ mCallAudioRouteAdapter = callAudioRouteStateMachineFactory.create(
context,
this,
bluetoothManager,
@@ -709,17 +710,17 @@
featureFlags
);
} else {
- callAudioRouteAdapter = new CallAudioRouteController(context, this, audioServiceFactory,
- new AudioRoute.Factory(), wiredHeadsetManager, mBluetoothRouteManager,
- statusBarNotifier, featureFlags, metricsController);
+ mCallAudioRouteAdapter = new CallAudioRouteController(context, this,
+ audioServiceFactory, new AudioRoute.Factory(), wiredHeadsetManager,
+ mBluetoothRouteManager, statusBarNotifier, featureFlags, metricsController);
}
- callAudioRouteAdapter.initialize();
- bluetoothStateReceiver.setCallAudioRouteAdapter(callAudioRouteAdapter);
- bluetoothDeviceManager.setCallAudioRouteAdapter(callAudioRouteAdapter);
+ mCallAudioRouteAdapter.initialize();
+ bluetoothStateReceiver.setCallAudioRouteAdapter(mCallAudioRouteAdapter);
+ bluetoothDeviceManager.setCallAudioRouteAdapter(mCallAudioRouteAdapter);
CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter =
new CallAudioRoutePeripheralAdapter(
- callAudioRouteAdapter,
+ mCallAudioRouteAdapter,
bluetoothManager,
wiredHeadsetManager,
mDockManager,
@@ -755,7 +756,7 @@
mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager,
mTimeoutsAdapter, mLock);
}
- mCallAudioManager = new CallAudioManager(callAudioRouteAdapter,
+ mCallAudioManager = new CallAudioManager(mCallAudioRouteAdapter,
this, callAudioModeStateMachineFactory.create(systemStateHelper,
(AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE),
featureFlags, communicationDeviceTracker),
@@ -7094,4 +7095,23 @@
public CallsManagerCallSequencingAdapter getCallSequencingAdapter() {
return mCallSequencingAdapter;
}
+
+ public void waitForAudioToUpdate(boolean expectActive) {
+ Log.i(this, "waitForAudioToUpdate");
+ if (mFeatureFlags.useRefactoredAudioRouteSwitching()) {
+ try {
+ CallAudioRouteController audioRouteController =
+ (CallAudioRouteController) mCallAudioRouteAdapter;
+ if (expectActive) {
+ audioRouteController.getAudioActiveCompleteLatch().await(
+ WAIT_FOR_AUDIO_UPDATE_TIMEOUT, TimeUnit.MILLISECONDS);
+ } else {
+ audioRouteController.getAudioOperationsCompleteLatch().await(
+ WAIT_FOR_AUDIO_UPDATE_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ } catch (InterruptedException e) {
+ Log.w(this, e.toString());
+ }
+ }
+ }
}
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 72cb297..ef8210d 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -2952,6 +2952,10 @@
}
}
+ @Override
+ public void waitForAudioToUpdate(boolean expectActive) {
+ mCallsManager.waitForAudioToUpdate(expectActive);
+ }
/**
* Determines whether there are any ongoing {@link PhoneAccount#CAPABILITY_SELF_MANAGED}
* calls for a given {@code packageName} and {@code userHandle}.
diff --git a/src/com/android/server/telecom/TelecomShellCommand.java b/src/com/android/server/telecom/TelecomShellCommand.java
index e840b2a..2e955a9 100644
--- a/src/com/android/server/telecom/TelecomShellCommand.java
+++ b/src/com/android/server/telecom/TelecomShellCommand.java
@@ -67,6 +67,10 @@
private static final String COMMAND_RESET_CAR_MODE = "reset-car-mode";
private static final String COMMAND_IS_NON_IN_CALL_SERVICE_BOUND =
"is-non-ui-in-call-service-bound";
+ private static final String COMMAND_WAIT_FOR_AUDIO_OPS_COMPLETION =
+ "wait-for-audio-ops-complete";
+ private static final String COMMAND_WAIT_FOR_AUDIO_ACTIVE_COMPLETION =
+ "wait-for-audio-active";
/**
* Change the system dialer package name if a package name was specified,
@@ -192,6 +196,12 @@
case COMMAND_SET_METRICS_TEST_DISABLED:
mTelecomService.setMetricsTestMode(false);
break;
+ case COMMAND_WAIT_FOR_AUDIO_OPS_COMPLETION:
+ mTelecomService.waitForAudioToUpdate(false);
+ break;
+ case COMMAND_WAIT_FOR_AUDIO_ACTIVE_COMPLETION:
+ mTelecomService.waitForAudioToUpdate(true);
+ break;
default:
return handleDefaultCommands(command);
}