mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Deflake MediaSessionServiceTest
`onConnect_controllerInfo_sameInstanceFromServiceToConnectedControllerManager` was flaky because `onDestroy()` of `MockMediaSessionService` was cleaning up the `TestServiceRegistry`. This includes releasing the session of the service after which no further `MediaSession.Callback` methods are called. This created a race between `Callback.onDisconnected` and the `Mediasession.release()` being called. `onDestroy()` is called unexpectedly early because the controller unbinds as the last controller from the service that never was started (`onStartCommand` never called). In such a case the service is immediately terminated by the system after the last client unbinds from the service, which called `onDestroy()` on the mock service. This change making `MockMediaSessionService` optionally not clean up the registry in `onDestroy()` prevents the session from being released too early. Alternatively, starting playback and hence starting the service into the foreground would prevent the problem as well for the purpose of the test. Another alternative to fix the test would be removing the session from the service before releasing the controller. PiperOrigin-RevId: 730361199 (cherry picked from commit fbe186a70ccb588889d0909ccfc07affaf49ec51)
This commit is contained in:
parent
4d50e8a815
commit
8ee2532db3
@ -101,6 +101,7 @@ public class MediaSessionServiceTest {
|
||||
List<ControllerInfo> playbackCommandControllerInfos = new ArrayList<>();
|
||||
List<ControllerInfo> onDisconnectedCommandControllerInfos = new ArrayList<>();
|
||||
AtomicReference<MediaSession> session = new AtomicReference<>();
|
||||
ConditionVariable disconnected = new ConditionVariable();
|
||||
testServiceRegistry.setOnGetSessionHandler(
|
||||
controllerInfo -> {
|
||||
// The controllerInfo passed to the onGetSession of the service.
|
||||
@ -136,8 +137,8 @@ public class MediaSessionServiceTest {
|
||||
if (!session.isMediaNotificationController(controller)) {
|
||||
// The controllerInfo when disconnecting.
|
||||
onDisconnectedCommandControllerInfos.add(controller);
|
||||
disconnected.open();
|
||||
}
|
||||
MediaSession.Callback.super.onDisconnected(session, controller);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
@ -150,6 +151,8 @@ public class MediaSessionServiceTest {
|
||||
// Get the started service instance after creation.
|
||||
MockMediaSessionService service =
|
||||
(MockMediaSessionService) testServiceRegistry.getServiceInstance();
|
||||
// TestServiceRegistry is taken care of and cleaned up @After the test.
|
||||
service.setCleanupServiceRegistryOnDestroy(false);
|
||||
controller.setRepeatMode(Player.REPEAT_MODE_ONE);
|
||||
List<ControllerInfo> connectedControllerManagerControllerInfos = new ArrayList<>();
|
||||
for (ControllerInfo controllerInfo : session.get().getConnectedControllers()) {
|
||||
@ -159,9 +162,12 @@ public class MediaSessionServiceTest {
|
||||
}
|
||||
}
|
||||
|
||||
// The controller that was bound to the service unbinds when released. Because the service was
|
||||
// never started (as in `onStartCommand()` was never called), the service is immediately
|
||||
// terminated by the system when the last bound client unbinds.
|
||||
controller.release();
|
||||
|
||||
service.blockUntilAllControllersUnbind(TIMEOUT_MS);
|
||||
assertThat(disconnected.block(TIMEOUT_MS)).isTrue();
|
||||
assertThat(onGetSessionControllerInfos).hasSize(1);
|
||||
assertThat(onGetSessionControllerInfos).isEqualTo(onConnectControllerInfos);
|
||||
assertThat(onGetSessionControllerInfos).isEqualTo(playbackCommandControllerInfos);
|
||||
|
@ -38,11 +38,24 @@ public class MockMediaSessionService extends MediaSessionService {
|
||||
|
||||
@Nullable public MediaSession session;
|
||||
@Nullable private HandlerThread handlerThread;
|
||||
private boolean cleanupServiceRegistryOnDestroy;
|
||||
|
||||
public MockMediaSessionService() {
|
||||
boundControllerCount = new AtomicInteger(/* initialValue= */ 0);
|
||||
allControllersUnbound = new ConditionVariable();
|
||||
allControllersUnbound.open();
|
||||
cleanupServiceRegistryOnDestroy = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the service should clean up the service registry {@link #onDestroy()} by calling {@link
|
||||
* TestServiceRegistry#cleanUp()} on {@link TestServiceRegistry#getInstance()}.
|
||||
*
|
||||
* <p>The cleanup will release all sessions of the service. A test can clean up when tearing down
|
||||
* the test, to prevent the sessions to be released by the service.
|
||||
*/
|
||||
public void setCleanupServiceRegistryOnDestroy(boolean cleanupServiceRegistryOnDestroy) {
|
||||
this.cleanupServiceRegistryOnDestroy = cleanupServiceRegistryOnDestroy;
|
||||
}
|
||||
|
||||
/** Returns whether at least one controller is bound to this service. */
|
||||
@ -90,7 +103,9 @@ public class MockMediaSessionService extends MediaSessionService {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
TestServiceRegistry.getInstance().cleanUp();
|
||||
if (cleanupServiceRegistryOnDestroy) {
|
||||
TestServiceRegistry.getInstance().cleanUp();
|
||||
}
|
||||
handlerThread.quitSafely();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user