MediaRouter: Release RoutingSession for died clients.
This CL makes MediaRouteProviderServiceImplApi30 override dispose
to release RoutingSessionInfo of died clients.
A new test that fails w/o this change is added to ensure the behavior
as well.
Bug: 168161584
Test: ./gradlew mediarouter:mediarouter:connectedCheck and
manually using GMSCore built with this.
Change-Id: I042dac2bb5954be1ca1e68ace0d778fae97720fd
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
index f64a65b..8747820 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
@@ -25,6 +25,7 @@
import android.media.MediaRoute2ProviderService;
import android.media.RoutingSessionInfo;
import android.os.Build;
+import android.os.Messenger;
import android.support.mediacompat.testlib.util.PollingCheck;
import android.text.TextUtils;
@@ -58,7 +59,9 @@
Context mContext;
MediaRouter mRouter;
+ StubMediaRouteProviderService mService;
StubMediaRouteProviderService.StubMediaRouteProvider mProvider;
+ MediaRouteProviderService.MediaRouteProviderServiceImplApi30 mServiceImpl;
MediaRoute2ProviderServiceAdapter mMr2ProviderServiceAdapter;
List<MediaRouter.Callback> mCallbacks;
@@ -81,12 +84,13 @@
new PollingCheck(TIMEOUT_MS) {
@Override
protected boolean check() {
- StubMediaRouteProviderService.StubMediaRouteProvider provider =
- StubMediaRouteProviderService.getProvider();
- if (provider != null) {
- mProvider = provider;
- mMr2ProviderServiceAdapter =
- StubMediaRouteProviderService.getMr2ProviderServiceAdapter();
+ mService = StubMediaRouteProviderService.getInstance();
+ if (mService != null && mService.getMediaRouteProvider() != null) {
+ mProvider = (StubMediaRouteProviderService.StubMediaRouteProvider)
+ mService.getMediaRouteProvider();
+ mServiceImpl = (MediaRouteProviderService.MediaRouteProviderServiceImplApi30)
+ mService.mImpl;
+ mMr2ProviderServiceAdapter = mServiceImpl.mMR2ProviderServiceAdapter;
return true;
}
return false;
@@ -154,6 +158,42 @@
assertTrue(onRouteUnselectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
+ @SmallTest
+ @Test
+ public void onBinderDied_releaseRoutingSessions() throws Exception {
+ String descriptorId = StubMediaRouteProviderService.ROUTE_ID1;
+
+ waitForRoutesAdded();
+ assertNotNull(mRoutes);
+
+ RouteInfo routeToSelect = mRoutes.get(descriptorId);
+ assertNotNull(routeToSelect);
+
+ getInstrumentation().runOnMainSync(() -> mRouter.selectRoute(routeToSelect));
+
+ // Wait for a session being created.
+ PollingCheck.waitFor(TIMEOUT_MS,
+ () -> !mMr2ProviderServiceAdapter.getAllSessionInfo().isEmpty());
+
+ try {
+ List<Messenger> messengers =
+ mServiceImpl.mClients.stream().map(client -> client.mMessenger)
+ .collect(Collectors.toList());
+ getInstrumentation().runOnMainSync(() ->
+ messengers.forEach(mServiceImpl::onBinderDied));
+ // It should have no session info.
+ PollingCheck.waitFor(TIMEOUT_MS,
+ () -> mMr2ProviderServiceAdapter.getAllSessionInfo().isEmpty());
+ } finally {
+ // Rebind for future tests
+ getInstrumentation().runOnMainSync(
+ () -> {
+ MediaRouter.sGlobal.mRegisteredProviderWatcher.stop();
+ MediaRouter.sGlobal.mRegisteredProviderWatcher.start();
+ });
+ }
+ }
+
void addCallback(MediaRouter.Callback callback) {
getInstrumentation().runOnMainSync(() -> {
mRouter.addCallback(mSelector, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
index f742900..540fee8 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
@@ -51,26 +51,9 @@
CONTROL_FILTERS_TEST.add(f1);
}
- public static StubMediaRouteProvider getProvider() {
+ public static StubMediaRouteProviderService getInstance() {
synchronized (sLock) {
- if (sInstance == null) {
- return null;
- }
- MediaRouteProvider provider = sInstance.getMediaRouteProvider();
- return (provider == null) ? null : (StubMediaRouteProvider) provider;
- }
- }
-
- public static MediaRoute2ProviderServiceAdapter getMr2ProviderServiceAdapter() {
- synchronized (sLock) {
- if (sInstance == null) {
- return null;
- }
- if (!(sInstance.mImpl instanceof MediaRouteProviderServiceImplApi30)) {
- return null;
- }
- return ((MediaRouteProviderServiceImplApi30) sInstance.mImpl)
- .mMR2ProviderServiceAdapter;
+ return sInstance;
}
}
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
index 9ff3b77..0d8dac9 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
@@ -1185,6 +1185,17 @@
}
@Override
+ public void dispose() {
+ int count = mControllers.size();
+ for (int i = 0; i < count; i++) {
+ int controllerId = mControllers.keyAt(i);
+ mMR2ProviderServiceAdapter.notifyRouteControllerRemoved(controllerId);
+ }
+ mRouteIdToControllerMap.clear();
+ super.dispose();
+ }
+
+ @Override
public boolean createRouteController(String routeId, String routeGroupId,
int controllerId) {
RouteController controller = mRouteIdToControllerMap.get(routeId);
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
index b5dcd5d..bf82d6f 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
@@ -44,6 +44,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap;
import androidx.core.app.ActivityManagerCompat;
import androidx.core.content.ContextCompat;
@@ -2311,7 +2312,7 @@
* state and the bulk of the media router implementation lives here.
* </p>
*/
- private static final class GlobalMediaRouter
+ static final class GlobalMediaRouter
implements SystemMediaRouteProvider.SyncCallback,
RegisteredMediaRouteProviderWatcher.Callback {
final Context mApplicationContext;
@@ -2332,7 +2333,8 @@
private final boolean mLowRam;
private MediaRouterParams mRouterParams;
- private RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher;
+ @VisibleForTesting
+ RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher;
private RouteInfo mDefaultRoute;
private RouteInfo mBluetoothRoute;
RouteInfo mSelectedRoute;