Bind provider services when necessary
The media router service bound media route provider services only when there was a discovery request. This prevented output switcher to work when there are only legacy media router clients (i.e. apps that didn't enable MR2) This CL makes the media router service binds media route provider services when the MediaRouter2Manager#startScan is called so that the output switcher can show cast sessions created by the providers. This CL also changes communication between the media router service and the provider services as cast sessions can be created/released even when the media router service is disconnected from media route provider. Bug: 176774510 Test: manually Change-Id: I481e1aa8f9dcc136cbf5788b9f66540708665af2
This commit is contained in:
@@ -26,9 +26,9 @@ import android.os.Bundle;
|
||||
*/
|
||||
oneway interface IMediaRoute2ProviderServiceCallback {
|
||||
// TODO: Change it to updateRoutes?
|
||||
void updateState(in MediaRoute2ProviderInfo providerInfo);
|
||||
void notifyProviderUpdated(in MediaRoute2ProviderInfo providerInfo);
|
||||
void notifySessionCreated(long requestId, in RoutingSessionInfo sessionInfo);
|
||||
void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
|
||||
void notifySessionsUpdated(in List<RoutingSessionInfo> sessionInfo);
|
||||
void notifySessionReleased(in RoutingSessionInfo sessionInfo);
|
||||
void notifyRequestFailed(long requestId, int reason);
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ public abstract class MediaRoute2ProviderService extends Service {
|
||||
private final Object mSessionLock = new Object();
|
||||
private final Object mRequestIdsLock = new Object();
|
||||
private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false);
|
||||
private final AtomicBoolean mSessionUpdateScheduled = new AtomicBoolean(false);
|
||||
private MediaRoute2ProviderServiceStub mStub;
|
||||
private IMediaRoute2ProviderServiceCallback mRemoteCallback;
|
||||
private volatile MediaRoute2ProviderInfo mProviderInfo;
|
||||
@@ -287,16 +288,8 @@ public abstract class MediaRoute2ProviderService extends Service {
|
||||
Log.w(TAG, "notifySessionUpdated: Ignoring unknown session info.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRemoteCallback == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mRemoteCallback.notifySessionUpdated(sessionInfo);
|
||||
} catch (RemoteException ex) {
|
||||
Log.w(TAG, "Failed to notify session info changed.");
|
||||
}
|
||||
}
|
||||
scheduleUpdateSessions();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -479,6 +472,7 @@ public abstract class MediaRoute2ProviderService extends Service {
|
||||
void setCallback(IMediaRoute2ProviderServiceCallback callback) {
|
||||
mRemoteCallback = callback;
|
||||
schedulePublishState();
|
||||
scheduleUpdateSessions();
|
||||
}
|
||||
|
||||
void schedulePublishState() {
|
||||
@@ -497,12 +491,40 @@ public abstract class MediaRoute2ProviderService extends Service {
|
||||
}
|
||||
|
||||
try {
|
||||
mRemoteCallback.updateState(mProviderInfo);
|
||||
mRemoteCallback.notifyProviderUpdated(mProviderInfo);
|
||||
} catch (RemoteException ex) {
|
||||
Log.w(TAG, "Failed to publish provider state.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
void scheduleUpdateSessions() {
|
||||
if (mSessionUpdateScheduled.compareAndSet(false, true)) {
|
||||
mHandler.post(this::updateSessions);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSessions() {
|
||||
if (!mSessionUpdateScheduled.compareAndSet(true, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRemoteCallback == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<RoutingSessionInfo> sessions;
|
||||
synchronized (mSessionLock) {
|
||||
sessions = new ArrayList<>(mSessionInfo.values());
|
||||
}
|
||||
|
||||
try {
|
||||
mRemoteCallback.notifySessionsUpdated(sessions);
|
||||
} catch (RemoteException ex) {
|
||||
Log.w(TAG, "Failed to notify session info changed.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a requestId in the request ID list whose max size is {@link #MAX_REQUEST_IDS_SIZE}.
|
||||
* When the max size is reached, the first element is removed (FIFO).
|
||||
|
||||
@@ -47,7 +47,7 @@ abstract class MediaRoute2Provider {
|
||||
mUniqueId = componentName.flattenToShortString();
|
||||
}
|
||||
|
||||
public void setCallback(MediaRoute2ProviderServiceProxy.Callback callback) {
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.server.media;
|
||||
|
||||
import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
|
||||
|
||||
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -43,6 +47,7 @@ import com.android.internal.annotations.GuardedBy;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -64,6 +69,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
private Connection mActiveConnection;
|
||||
private boolean mConnectionReady;
|
||||
|
||||
private boolean mIsManagerScanning;
|
||||
private RouteDiscoveryPreference mLastDiscoveryPreference = null;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@@ -86,6 +92,13 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
pw.println(prefix + " mConnectionReady=" + mConnectionReady);
|
||||
}
|
||||
|
||||
public void setManagerScanning(boolean managerScanning) {
|
||||
if (mIsManagerScanning != managerScanning) {
|
||||
mIsManagerScanning = managerScanning;
|
||||
updateBinding();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestCreateSession(long requestId, String packageName, String routeId,
|
||||
Bundle sessionHints) {
|
||||
@@ -209,7 +222,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
// Bind when there is a discovery preference or an active route session.
|
||||
return (mLastDiscoveryPreference != null
|
||||
&& !mLastDiscoveryPreference.getPreferredFeatures().isEmpty())
|
||||
|| !getSessionInfos().isEmpty();
|
||||
|| !getSessionInfos().isEmpty()
|
||||
|| mIsManagerScanning;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -311,13 +325,12 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
}
|
||||
}
|
||||
|
||||
private void onProviderStateUpdated(Connection connection,
|
||||
MediaRoute2ProviderInfo providerInfo) {
|
||||
private void onProviderUpdated(Connection connection, MediaRoute2ProviderInfo providerInfo) {
|
||||
if (mActiveConnection != connection) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, this + ": State changed ");
|
||||
Slog.d(TAG, this + ": updated");
|
||||
}
|
||||
setAndNotifyProviderState(providerInfo);
|
||||
}
|
||||
@@ -350,40 +363,44 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
mCallback.onSessionCreated(this, requestId, newSession);
|
||||
}
|
||||
|
||||
private void onSessionUpdated(Connection connection, RoutingSessionInfo updatedSession) {
|
||||
private int findSessionByIdLocked(RoutingSessionInfo session) {
|
||||
for (int i = 0; i < mSessionInfos.size(); i++) {
|
||||
if (TextUtils.equals(mSessionInfos.get(i).getId(), session.getId())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private void onSessionsUpdated(Connection connection, List<RoutingSessionInfo> sessions) {
|
||||
if (mActiveConnection != connection) {
|
||||
return;
|
||||
}
|
||||
if (updatedSession == null) {
|
||||
Slog.w(TAG, "onSessionUpdated: Ignoring null session sent from "
|
||||
+ mComponentName);
|
||||
return;
|
||||
}
|
||||
|
||||
updatedSession = assignProviderIdForSession(updatedSession);
|
||||
|
||||
boolean found = false;
|
||||
int targetIndex = 0;
|
||||
synchronized (mLock) {
|
||||
for (int i = 0; i < mSessionInfos.size(); i++) {
|
||||
if (mSessionInfos.get(i).getId().equals(updatedSession.getId())) {
|
||||
mSessionInfos.set(i, updatedSession);
|
||||
found = true;
|
||||
break;
|
||||
for (RoutingSessionInfo session : sessions) {
|
||||
if (session == null) continue;
|
||||
session = assignProviderIdForSession(session);
|
||||
|
||||
int sourceIndex = findSessionByIdLocked(session);
|
||||
if (sourceIndex < 0) {
|
||||
mSessionInfos.add(targetIndex++, session);
|
||||
dispatchSessionCreated(REQUEST_ID_NONE, session);
|
||||
} else if (sourceIndex < targetIndex) {
|
||||
Slog.w(TAG, "Ignoring duplicate session ID: " + session.getId());
|
||||
} else {
|
||||
mSessionInfos.set(sourceIndex, session);
|
||||
Collections.swap(mSessionInfos, sourceIndex, targetIndex++);
|
||||
dispatchSessionUpdated(session);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (RoutingSessionInfo releasingSession : mReleasingSessions) {
|
||||
if (TextUtils.equals(releasingSession.getId(), updatedSession.getId())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Slog.w(TAG, "onSessionUpdated: Matching session info not found");
|
||||
return;
|
||||
for (int i = mSessionInfos.size() - 1; i >= targetIndex; i--) {
|
||||
RoutingSessionInfo releasedSession = mSessionInfos.remove(i);
|
||||
dispatchSessionReleased(releasedSession);
|
||||
}
|
||||
}
|
||||
|
||||
mCallback.onSessionUpdated(this, updatedSession);
|
||||
}
|
||||
|
||||
private void onSessionReleased(Connection connection, RoutingSessionInfo releaedSession) {
|
||||
@@ -424,6 +441,21 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
mCallback.onSessionReleased(this, releaedSession);
|
||||
}
|
||||
|
||||
private void dispatchSessionCreated(long requestId, RoutingSessionInfo session) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(mCallback::onSessionCreated, this, requestId, session));
|
||||
}
|
||||
|
||||
private void dispatchSessionUpdated(RoutingSessionInfo session) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(mCallback::onSessionUpdated, this, session));
|
||||
}
|
||||
|
||||
private void dispatchSessionReleased(RoutingSessionInfo session) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(mCallback::onSessionReleased, this, session));
|
||||
}
|
||||
|
||||
private RoutingSessionInfo assignProviderIdForSession(RoutingSessionInfo sessionInfo) {
|
||||
return new RoutingSessionInfo.Builder(sessionInfo)
|
||||
.setOwnerPackageName(mComponentName.getPackageName())
|
||||
@@ -436,7 +468,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
|
||||
if (requestId == REQUEST_ID_NONE) {
|
||||
Slog.w(TAG, "onRequestFailed: Ignoring requestId REQUEST_ID_NONE");
|
||||
return;
|
||||
}
|
||||
@@ -561,16 +593,16 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
mHandler.post(() -> onConnectionDied(Connection.this));
|
||||
}
|
||||
|
||||
void postProviderStateUpdated(MediaRoute2ProviderInfo providerInfo) {
|
||||
mHandler.post(() -> onProviderStateUpdated(Connection.this, providerInfo));
|
||||
void postProviderUpdated(MediaRoute2ProviderInfo providerInfo) {
|
||||
mHandler.post(() -> onProviderUpdated(Connection.this, providerInfo));
|
||||
}
|
||||
|
||||
void postSessionCreated(long requestId, RoutingSessionInfo sessionInfo) {
|
||||
mHandler.post(() -> onSessionCreated(Connection.this, requestId, sessionInfo));
|
||||
}
|
||||
|
||||
void postSessionUpdated(RoutingSessionInfo sessionInfo) {
|
||||
mHandler.post(() -> onSessionUpdated(Connection.this, sessionInfo));
|
||||
void postSessionsUpdated(List<RoutingSessionInfo> sessionInfo) {
|
||||
mHandler.post(() -> onSessionsUpdated(Connection.this, sessionInfo));
|
||||
}
|
||||
|
||||
void postSessionReleased(RoutingSessionInfo sessionInfo) {
|
||||
@@ -595,10 +627,10 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(MediaRoute2ProviderInfo providerInfo) {
|
||||
public void notifyProviderUpdated(MediaRoute2ProviderInfo providerInfo) {
|
||||
Connection connection = mConnectionRef.get();
|
||||
if (connection != null) {
|
||||
connection.postProviderStateUpdated(providerInfo);
|
||||
connection.postProviderUpdated(providerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,10 +643,10 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
|
||||
public void notifySessionsUpdated(List<RoutingSessionInfo> sessionInfo) {
|
||||
Connection connection = mConnectionRef.get();
|
||||
if (connection != null) {
|
||||
connection.postSessionUpdated(sessionInfo);
|
||||
connection.postSessionsUpdated(sessionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2156,6 +2156,8 @@ class MediaRouter2ServiceImpl {
|
||||
List<RouterRecord> routerRecords = getRouterRecords();
|
||||
List<ManagerRecord> managerRecords = getManagerRecords();
|
||||
|
||||
boolean shouldBindProviders = false;
|
||||
|
||||
if (service.mPowerManager.isInteractive()) {
|
||||
boolean isManagerScanning = managerRecords.stream().anyMatch(manager ->
|
||||
manager.mIsScanning && service.mActivityManager
|
||||
@@ -2166,6 +2168,7 @@ class MediaRouter2ServiceImpl {
|
||||
discoveryPreferences = routerRecords.stream()
|
||||
.map(record -> record.mDiscoveryPreference)
|
||||
.collect(Collectors.toList());
|
||||
shouldBindProviders = true;
|
||||
} else {
|
||||
discoveryPreferences = routerRecords.stream().filter(record ->
|
||||
service.mActivityManager.getPackageImportance(record.mPackageName)
|
||||
@@ -2175,6 +2178,13 @@ class MediaRouter2ServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
for (MediaRoute2Provider provider : mRouteProviders) {
|
||||
if (provider instanceof MediaRoute2ProviderServiceProxy) {
|
||||
((MediaRoute2ProviderServiceProxy) provider)
|
||||
.setManagerScanning(shouldBindProviders);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (service.mLock) {
|
||||
RouteDiscoveryPreference newPreference =
|
||||
new RouteDiscoveryPreference.Builder(discoveryPreferences).build();
|
||||
|
||||
Reference in New Issue
Block a user