Merge "MediaRouterService binds services when necessary"
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 068f968..4b8a8ad 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -73,6 +73,8 @@
void unregisterManager(IMediaRouter2Manager manager);
void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
in MediaRoute2Info route, int volume);
+ void startScan(IMediaRouter2Manager manager);
+ void stopScan(IMediaRouter2Manager manager);
void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route);
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 4b09a5f..68237de 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -147,6 +147,36 @@
}
/**
+ * Starts scanning remote routes.
+ * @see #stopScan(String)
+ */
+ public void startScan() {
+ Client client = getOrCreateClient();
+ if (client != null) {
+ try {
+ mMediaRouterService.startScan(client);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+ }
+ }
+ }
+
+ /**
+ * Stops scanning remote routes to reduce resource consumption.
+ * @see #startScan(String)
+ */
+ public void stopScan() {
+ Client client = getOrCreateClient();
+ if (client != null) {
+ try {
+ mMediaRouterService.stopScan(client);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+ }
+ }
+ }
+
+ /**
* Gets a {@link android.media.session.MediaController} associated with the
* given routing session.
* If there is no matching media session, {@code null} is returned.
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 68f2964..2f95247 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -153,6 +153,7 @@
return false;
}
RouteDiscoveryPreference other = (RouteDiscoveryPreference) o;
+ //TODO: Make this order-free
return Objects.equals(mPreferredFeatures, other.mPreferredFeatures)
&& mShouldPerformActiveScan == other.mShouldPerformActiveScan;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index eb86128..9e25389 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -24,6 +24,7 @@
import android.graphics.drawable.Icon;
import android.media.MediaMetadata;
import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
import android.media.RoutingSessionInfo;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
@@ -76,6 +77,7 @@
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final boolean mAboveStatusbar;
private final NotificationEntryManager mNotificationEntryManager;
+ private final MediaRouter2Manager mRouterManager;
@VisibleForTesting
final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
@@ -104,6 +106,7 @@
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mUiEventLogger = uiEventLogger;
+ mRouterManager = MediaRouter2Manager.getInstance(mContext);
}
void start(@NonNull Callback cb) {
@@ -134,6 +137,7 @@
mLocalMediaManager.stopScan();
mLocalMediaManager.registerCallback(this);
mLocalMediaManager.startScan();
+ mRouterManager.startScan();
}
void stop() {
@@ -144,6 +148,9 @@
mLocalMediaManager.unregisterCallback(this);
mLocalMediaManager.stopScan();
}
+ if (mRouterManager != null) {
+ mRouterManager.stopScan();
+ }
mMediaDevices.clear();
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index f882c57..edc9d7c 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -77,7 +77,7 @@
@NonNull
public List<RoutingSessionInfo> getSessionInfos() {
synchronized (mLock) {
- return mSessionInfos;
+ return new ArrayList<>(mSessionInfos);
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 85af346..ab38dca 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -108,8 +108,8 @@
mLastDiscoveryPreference = discoveryPreference;
if (mConnectionReady) {
mActiveConnection.updateDiscoveryPreference(discoveryPreference);
- updateBinding();
}
+ updateBinding();
}
@Override
@@ -205,9 +205,11 @@
}
private boolean shouldBind() {
- //TODO: Binding could be delayed until it's necessary.
if (mRunning) {
- return true;
+ // Bind when there is a discovery preference or an active route session.
+ return (mLastDiscoveryPreference != null
+ && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty())
+ || !getSessionInfos().isEmpty();
}
return false;
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 1114fe0..31edf43 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getProviderId;
@@ -73,10 +74,12 @@
// TODO: (In Android S or later) if we add callback methods for generic failures
// in MediaRouter2, remove this constant and replace the usages with the real request IDs.
private static final long DUMMY_REQUEST_ID = -1;
+ private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND;
private final Context mContext;
private final Object mLock = new Object();
final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
+ final ActivityManager mActivityManager;
@GuardedBy("mLock")
private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
@@ -87,8 +90,21 @@
@GuardedBy("mLock")
private int mCurrentUserId = -1;
+ private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
+ (uid, importance) -> {
+ synchronized (mLock) {
+ final int count = mUserRecords.size();
+ for (int i = 0; i < count; i++) {
+ mUserRecords.valueAt(i).mHandler.maybeUpdateDiscoveryPreferenceForUid(uid);
+ }
+ }
+ };
+
MediaRouter2ServiceImpl(Context context) {
mContext = context;
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
+ mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener,
+ PACKAGE_IMPORTANCE_FOR_DISCOVERY);
}
////////////////////////////////////////////////////////////////
@@ -388,6 +404,30 @@
}
}
+ public void startScan(IMediaRouter2Manager manager) {
+ Objects.requireNonNull(manager, "manager must not be null");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ startScanLocked(manager);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ public void stopScan(IMediaRouter2Manager manager) {
+ Objects.requireNonNull(manager, "manager must not be null");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ stopScanLocked(manager);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
MediaRoute2Info route, int volume) {
Objects.requireNonNull(manager, "manager must not be null");
@@ -839,6 +879,24 @@
disposeUserIfNeededLocked(userRecord); // since manager removed from user
}
+ private void startScanLocked(@NonNull IMediaRouter2Manager manager) {
+ final IBinder binder = manager.asBinder();
+ ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+ if (managerRecord == null) {
+ return;
+ }
+ managerRecord.startScan();
+ }
+
+ private void stopScanLocked(@NonNull IMediaRouter2Manager manager) {
+ final IBinder binder = manager.asBinder();
+ ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+ if (managerRecord == null) {
+ return;
+ }
+ managerRecord.stopScan();
+ }
+
private void setRouteVolumeWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull MediaRoute2Info route, int volume) {
@@ -1122,6 +1180,7 @@
public final String mPackageName;
public final int mManagerId;
public SessionCreationRequest mLastSessionCreationRequest;
+ public boolean mIsScanning;
ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
int uid, int pid, String packageName) {
@@ -1146,6 +1205,24 @@
pw.println(prefix + this);
}
+ public void startScan() {
+ if (mIsScanning) {
+ return;
+ }
+ mIsScanning = true;
+ mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage(
+ UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
+ }
+
+ public void stopScan() {
+ if (!mIsScanning) {
+ return;
+ }
+ mIsScanning = false;
+ mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage(
+ UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
+ }
+
@Override
public String toString() {
return "Manager " + mPackageName + " (pid " + mPid + ")";
@@ -1262,6 +1339,24 @@
return null;
}
+ public void maybeUpdateDiscoveryPreferenceForUid(int uid) {
+ MediaRouter2ServiceImpl service = mServiceRef.get();
+ if (service == null) {
+ return;
+ }
+ boolean isUidRelevant;
+ synchronized (service.mLock) {
+ isUidRelevant = mUserRecord.mRouterRecords.stream().anyMatch(
+ router -> router.mUid == uid)
+ | mUserRecord.mManagerRecords.stream().anyMatch(
+ manager -> manager.mUid == uid);
+ }
+ if (isUidRelevant) {
+ sendMessage(PooledLambda.obtainMessage(
+ UserHandler::updateDiscoveryPreferenceOnHandler, this));
+ }
+ }
+
private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
@@ -1767,6 +1862,16 @@
return managers;
}
+ private List<RouterRecord> getRouterRecords() {
+ MediaRouter2ServiceImpl service = mServiceRef.get();
+ if (service == null) {
+ return Collections.emptyList();
+ }
+ synchronized (service.mLock) {
+ return new ArrayList<>(mUserRecord.mRouterRecords);
+ }
+ }
+
private List<ManagerRecord> getManagerRecords() {
MediaRouter2ServiceImpl service = mServiceRef.get();
if (service == null) {
@@ -2001,13 +2106,28 @@
return;
}
List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>();
- synchronized (service.mLock) {
- for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
+ List<RouterRecord> routerRecords = getRouterRecords();
+ List<ManagerRecord> managerRecords = getManagerRecords();
+ boolean isAnyManagerScanning =
+ managerRecords.stream().anyMatch(manager -> manager.mIsScanning
+ && service.mActivityManager.getPackageImportance(manager.mPackageName)
+ <= PACKAGE_IMPORTANCE_FOR_DISCOVERY);
+
+ for (RouterRecord routerRecord : routerRecords) {
+ if (isAnyManagerScanning
+ || service.mActivityManager.getPackageImportance(routerRecord.mPackageName)
+ <= PACKAGE_IMPORTANCE_FOR_DISCOVERY) {
discoveryPreferences.add(routerRecord.mDiscoveryPreference);
}
- mUserRecord.mCompositeDiscoveryPreference =
- new RouteDiscoveryPreference.Builder(discoveryPreferences)
- .build();
+ }
+
+ synchronized (service.mLock) {
+ RouteDiscoveryPreference newPreference =
+ new RouteDiscoveryPreference.Builder(discoveryPreferences).build();
+ if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) {
+ return;
+ }
+ mUserRecord.mCompositeDiscoveryPreference = newPreference;
}
for (MediaRoute2Provider provider : mRouteProviders) {
provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 0e52a67..b6d6cc4 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -544,6 +544,18 @@
// Binder call
@Override
+ public void startScan(IMediaRouter2Manager manager) {
+ mService2.startScan(manager);
+ }
+
+ // Binder call
+ @Override
+ public void stopScan(IMediaRouter2Manager manager) {
+ mService2.stopScan(manager);
+ }
+
+ // Binder call
+ @Override
public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
MediaRoute2Info route, int volume) {
mService2.setRouteVolumeWithManager(manager, requestId, route, volume);