Merge "Bind provider services when necessary" into sc-dev

This commit is contained in:
Kyunglyul Hyun
2021-06-08 16:12:15 +00:00
committed by Android (Google) Code Review
5 changed files with 115 additions and 51 deletions

View File

@@ -26,9 +26,9 @@ import android.os.Bundle;
*/ */
oneway interface IMediaRoute2ProviderServiceCallback { oneway interface IMediaRoute2ProviderServiceCallback {
// TODO: Change it to updateRoutes? // TODO: Change it to updateRoutes?
void updateState(in MediaRoute2ProviderInfo providerInfo); void notifyProviderUpdated(in MediaRoute2ProviderInfo providerInfo);
void notifySessionCreated(long requestId, in RoutingSessionInfo sessionInfo); void notifySessionCreated(long requestId, in RoutingSessionInfo sessionInfo);
void notifySessionUpdated(in RoutingSessionInfo sessionInfo); void notifySessionsUpdated(in List<RoutingSessionInfo> sessionInfo);
void notifySessionReleased(in RoutingSessionInfo sessionInfo); void notifySessionReleased(in RoutingSessionInfo sessionInfo);
void notifyRequestFailed(long requestId, int reason); void notifyRequestFailed(long requestId, int reason);
} }

View File

@@ -141,6 +141,7 @@ public abstract class MediaRoute2ProviderService extends Service {
private final Object mSessionLock = new Object(); private final Object mSessionLock = new Object();
private final Object mRequestIdsLock = new Object(); private final Object mRequestIdsLock = new Object();
private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false); private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false);
private final AtomicBoolean mSessionUpdateScheduled = new AtomicBoolean(false);
private MediaRoute2ProviderServiceStub mStub; private MediaRoute2ProviderServiceStub mStub;
private IMediaRoute2ProviderServiceCallback mRemoteCallback; private IMediaRoute2ProviderServiceCallback mRemoteCallback;
private volatile MediaRoute2ProviderInfo mProviderInfo; private volatile MediaRoute2ProviderInfo mProviderInfo;
@@ -287,16 +288,8 @@ public abstract class MediaRoute2ProviderService extends Service {
Log.w(TAG, "notifySessionUpdated: Ignoring unknown session info."); Log.w(TAG, "notifySessionUpdated: Ignoring unknown session info.");
return; 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) { void setCallback(IMediaRoute2ProviderServiceCallback callback) {
mRemoteCallback = callback; mRemoteCallback = callback;
schedulePublishState(); schedulePublishState();
scheduleUpdateSessions();
} }
void schedulePublishState() { void schedulePublishState() {
@@ -497,12 +491,40 @@ public abstract class MediaRoute2ProviderService extends Service {
} }
try { try {
mRemoteCallback.updateState(mProviderInfo); mRemoteCallback.notifyProviderUpdated(mProviderInfo);
} catch (RemoteException ex) { } catch (RemoteException ex) {
Log.w(TAG, "Failed to publish provider state.", 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}. * 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). * When the max size is reached, the first element is removed (FIFO).

View File

@@ -47,7 +47,7 @@ abstract class MediaRoute2Provider {
mUniqueId = componentName.flattenToShortString(); mUniqueId = componentName.flattenToShortString();
} }
public void setCallback(MediaRoute2ProviderServiceProxy.Callback callback) { public void setCallback(Callback callback) {
mCallback = callback; mCallback = callback;
} }

View File

@@ -16,6 +16,10 @@
package com.android.server.media; 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.annotation.NonNull;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@@ -43,6 +47,7 @@ import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -64,6 +69,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
private Connection mActiveConnection; private Connection mActiveConnection;
private boolean mConnectionReady; private boolean mConnectionReady;
private boolean mIsManagerScanning;
private RouteDiscoveryPreference mLastDiscoveryPreference = null; private RouteDiscoveryPreference mLastDiscoveryPreference = null;
@GuardedBy("mLock") @GuardedBy("mLock")
@@ -86,6 +92,13 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
pw.println(prefix + " mConnectionReady=" + mConnectionReady); pw.println(prefix + " mConnectionReady=" + mConnectionReady);
} }
public void setManagerScanning(boolean managerScanning) {
if (mIsManagerScanning != managerScanning) {
mIsManagerScanning = managerScanning;
updateBinding();
}
}
@Override @Override
public void requestCreateSession(long requestId, String packageName, String routeId, public void requestCreateSession(long requestId, String packageName, String routeId,
Bundle sessionHints) { Bundle sessionHints) {
@@ -209,7 +222,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
// Bind when there is a discovery preference or an active route session. // Bind when there is a discovery preference or an active route session.
return (mLastDiscoveryPreference != null return (mLastDiscoveryPreference != null
&& !mLastDiscoveryPreference.getPreferredFeatures().isEmpty()) && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty())
|| !getSessionInfos().isEmpty(); || !getSessionInfos().isEmpty()
|| mIsManagerScanning;
} }
return false; return false;
} }
@@ -311,13 +325,12 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
} }
} }
private void onProviderStateUpdated(Connection connection, private void onProviderUpdated(Connection connection, MediaRoute2ProviderInfo providerInfo) {
MediaRoute2ProviderInfo providerInfo) {
if (mActiveConnection != connection) { if (mActiveConnection != connection) {
return; return;
} }
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, this + ": State changed "); Slog.d(TAG, this + ": updated");
} }
setAndNotifyProviderState(providerInfo); setAndNotifyProviderState(providerInfo);
} }
@@ -350,40 +363,44 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
mCallback.onSessionCreated(this, requestId, newSession); 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) { if (mActiveConnection != connection) {
return; return;
} }
if (updatedSession == null) {
Slog.w(TAG, "onSessionUpdated: Ignoring null session sent from "
+ mComponentName);
return;
}
updatedSession = assignProviderIdForSession(updatedSession); int targetIndex = 0;
boolean found = false;
synchronized (mLock) { synchronized (mLock) {
for (int i = 0; i < mSessionInfos.size(); i++) { for (RoutingSessionInfo session : sessions) {
if (mSessionInfos.get(i).getId().equals(updatedSession.getId())) { if (session == null) continue;
mSessionInfos.set(i, updatedSession); session = assignProviderIdForSession(session);
found = true;
break;
}
}
if (!found) { int sourceIndex = findSessionByIdLocked(session);
for (RoutingSessionInfo releasingSession : mReleasingSessions) { if (sourceIndex < 0) {
if (TextUtils.equals(releasingSession.getId(), updatedSession.getId())) { mSessionInfos.add(targetIndex++, session);
return; 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);
} }
} }
Slog.w(TAG, "onSessionUpdated: Matching session info not found"); for (int i = mSessionInfos.size() - 1; i >= targetIndex; i--) {
return; RoutingSessionInfo releasedSession = mSessionInfos.remove(i);
dispatchSessionReleased(releasedSession);
} }
} }
mCallback.onSessionUpdated(this, updatedSession);
} }
private void onSessionReleased(Connection connection, RoutingSessionInfo releaedSession) { private void onSessionReleased(Connection connection, RoutingSessionInfo releaedSession) {
@@ -424,6 +441,21 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
mCallback.onSessionReleased(this, releaedSession); 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) { private RoutingSessionInfo assignProviderIdForSession(RoutingSessionInfo sessionInfo) {
return new RoutingSessionInfo.Builder(sessionInfo) return new RoutingSessionInfo.Builder(sessionInfo)
.setOwnerPackageName(mComponentName.getPackageName()) .setOwnerPackageName(mComponentName.getPackageName())
@@ -436,7 +468,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
return; return;
} }
if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) { if (requestId == REQUEST_ID_NONE) {
Slog.w(TAG, "onRequestFailed: Ignoring requestId REQUEST_ID_NONE"); Slog.w(TAG, "onRequestFailed: Ignoring requestId REQUEST_ID_NONE");
return; return;
} }
@@ -561,16 +593,16 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
mHandler.post(() -> onConnectionDied(Connection.this)); mHandler.post(() -> onConnectionDied(Connection.this));
} }
void postProviderStateUpdated(MediaRoute2ProviderInfo providerInfo) { void postProviderUpdated(MediaRoute2ProviderInfo providerInfo) {
mHandler.post(() -> onProviderStateUpdated(Connection.this, providerInfo)); mHandler.post(() -> onProviderUpdated(Connection.this, providerInfo));
} }
void postSessionCreated(long requestId, RoutingSessionInfo sessionInfo) { void postSessionCreated(long requestId, RoutingSessionInfo sessionInfo) {
mHandler.post(() -> onSessionCreated(Connection.this, requestId, sessionInfo)); mHandler.post(() -> onSessionCreated(Connection.this, requestId, sessionInfo));
} }
void postSessionUpdated(RoutingSessionInfo sessionInfo) { void postSessionsUpdated(List<RoutingSessionInfo> sessionInfo) {
mHandler.post(() -> onSessionUpdated(Connection.this, sessionInfo)); mHandler.post(() -> onSessionsUpdated(Connection.this, sessionInfo));
} }
void postSessionReleased(RoutingSessionInfo sessionInfo) { void postSessionReleased(RoutingSessionInfo sessionInfo) {
@@ -595,10 +627,10 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
} }
@Override @Override
public void updateState(MediaRoute2ProviderInfo providerInfo) { public void notifyProviderUpdated(MediaRoute2ProviderInfo providerInfo) {
Connection connection = mConnectionRef.get(); Connection connection = mConnectionRef.get();
if (connection != null) { if (connection != null) {
connection.postProviderStateUpdated(providerInfo); connection.postProviderUpdated(providerInfo);
} }
} }
@@ -611,10 +643,10 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
} }
@Override @Override
public void notifySessionUpdated(RoutingSessionInfo sessionInfo) { public void notifySessionsUpdated(List<RoutingSessionInfo> sessionInfo) {
Connection connection = mConnectionRef.get(); Connection connection = mConnectionRef.get();
if (connection != null) { if (connection != null) {
connection.postSessionUpdated(sessionInfo); connection.postSessionsUpdated(sessionInfo);
} }
} }

View File

@@ -2156,6 +2156,8 @@ class MediaRouter2ServiceImpl {
List<RouterRecord> routerRecords = getRouterRecords(); List<RouterRecord> routerRecords = getRouterRecords();
List<ManagerRecord> managerRecords = getManagerRecords(); List<ManagerRecord> managerRecords = getManagerRecords();
boolean shouldBindProviders = false;
if (service.mPowerManager.isInteractive()) { if (service.mPowerManager.isInteractive()) {
boolean isManagerScanning = managerRecords.stream().anyMatch(manager -> boolean isManagerScanning = managerRecords.stream().anyMatch(manager ->
manager.mIsScanning && service.mActivityManager manager.mIsScanning && service.mActivityManager
@@ -2166,6 +2168,7 @@ class MediaRouter2ServiceImpl {
discoveryPreferences = routerRecords.stream() discoveryPreferences = routerRecords.stream()
.map(record -> record.mDiscoveryPreference) .map(record -> record.mDiscoveryPreference)
.collect(Collectors.toList()); .collect(Collectors.toList());
shouldBindProviders = true;
} else { } else {
discoveryPreferences = routerRecords.stream().filter(record -> discoveryPreferences = routerRecords.stream().filter(record ->
service.mActivityManager.getPackageImportance(record.mPackageName) 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) { synchronized (service.mLock) {
RouteDiscoveryPreference newPreference = RouteDiscoveryPreference newPreference =
new RouteDiscoveryPreference.Builder(discoveryPreferences).build(); new RouteDiscoveryPreference.Builder(discoveryPreferences).build();