Add getter for system session overrides

This is necessary in case SysUI crashes and needs to restart while a
mirroring session is already ongoing.

Bug: b/396394220
Test: atest CtsMediaRouterTestCases
Flag: com.android.media.flags.enable_mirroring_in_media_router_2
Change-Id: Ic3866066124f5b4c63dd4569e419a0c1415c702b
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 38c06c0..7ccbc10 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.content.Intent;
+import android.media.AppId;
 import android.media.IMediaRouter2;
 import android.media.IMediaRouter2Manager;
 import android.media.IMediaRouterClient;
@@ -87,6 +88,7 @@
     List<RoutingSessionInfo> getRemoteSessions(IMediaRouter2Manager manager);
     RoutingSessionInfo getSystemSessionInfoForPackage(String callerPackageName,
         String targetPackageName);
+    List<AppId> getSystemSessionOverridesAppIds(IMediaRouter2Manager manager);
     void registerManager(IMediaRouter2Manager manager, String packageName);
     void registerProxyRouter(IMediaRouter2Manager manager, String callingPackageName, String targetPackageName, in UserHandle targetUser);
     void unregisterManager(IMediaRouter2Manager manager);
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 6f816a4..4183be5 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -1318,6 +1318,18 @@
         mImpl.setRouteVolume(route, volume);
     }
 
+    /**
+     * Returns the set of apps currently affected by a system session override.
+     *
+     * <p>This method is only supported by proxy routers.
+     *
+     * @see SystemSessionOverridesListener
+     * @hide
+     */
+    public Set<AppId> getSystemSessionOverridesAppIds() {
+        return mImpl.getSystemSessionOverridesAppIds();
+    }
+
     void syncRoutesOnHandler(
             List<MediaRoute2Info> currentRoutes, RoutingSessionInfo currentSystemSessionInfo) {
         if (currentRoutes == null || currentRoutes.isEmpty() || currentSystemSessionInfo == null) {
@@ -2971,6 +2983,13 @@
          * @param listener The listener to unregister.
          */
         void unregisterSystemSessionOverridesListener(SystemSessionOverridesListener listener);
+
+        /**
+         * Returns the set of apps affected by a system session override.
+         *
+         * @see SystemSessionOverridesListener
+         */
+        Set<AppId> getSystemSessionOverridesAppIds();
     }
 
     /**
@@ -3002,6 +3021,17 @@
         private final List<InstanceInvalidatedCallbackRecord> mInstanceInvalidatedCallbackRecords =
                 new ArrayList<>();
 
+        /**
+         * Holds the last snapshot of ids of apps affected by a system session override.
+         *
+         * <p>Must hold an immutable set to avoid the need for a copy in {@link
+         * #getSystemSessionOverridesAppIds}.
+         *
+         * @see SystemSessionOverridesListener
+         */
+        @GuardedBy("mLock")
+        private Set<AppId> mLastSystemSessionSessionOverridesLocked = Set.of();
+
         ProxyMediaRouter2Impl(
                 @NonNull Context context,
                 @NonNull String clientPackageName,
@@ -3019,11 +3049,22 @@
                         mContext.getApplicationContext().getPackageName(),
                         mClientPackageName,
                         mClientUser);
+                initSystemSessionOverridesSnapshot();
             } catch (RemoteException ex) {
                 throw ex.rethrowFromSystemServer();
             }
         }
 
+        private void initSystemSessionOverridesSnapshot() throws RemoteException {
+            if (!Flags.enableMirroringInMediaRouter2()) {
+                return;
+            }
+            synchronized (mLock) {
+                mLastSystemSessionSessionOverridesLocked =
+                        Set.copyOf(mMediaRouterService.getSystemSessionOverridesAppIds(mClient));
+            }
+        }
+
         public void registerInstanceInvalidatedCallback(
                 @Nullable Executor executor, @Nullable Runnable onInstanceInvalidatedListener) {
             if (executor == null || onInstanceInvalidatedListener == null) {
@@ -3601,6 +3642,13 @@
                             /* executor= */ Runnable::run, listener));
         }
 
+        @Override
+        public Set<AppId> getSystemSessionOverridesAppIds() {
+            synchronized (mLock) {
+                return mLastSystemSessionSessionOverridesLocked;
+            }
+        }
+
         /**
          * Retrieves the system session info for the given package.
          *
@@ -3921,6 +3969,9 @@
 
         private void notifySystemSessionOverridesChangedOnHandler(List<AppId> appsWithOverrides) {
             var appsWithOverridesAsSet = Set.copyOf(appsWithOverrides);
+            synchronized (mLock) {
+                mLastSystemSessionSessionOverridesLocked = appsWithOverridesAsSet;
+            }
             for (var record : mSystemSessionOverridesListenerRecords) {
                 record.mExecutor.execute(
                         () ->
@@ -4436,6 +4487,12 @@
                     "unregisterSystemSessionOverridesListener is only supported on proxy routers.");
         }
 
+        @Override
+        public Set<AppId> getSystemSessionOverridesAppIds() {
+            throw new UnsupportedOperationException(
+                    "getAppsWithSystemSessionOverrides is only supported on proxy routers.");
+        }
+
         @GuardedBy("mLock")
         private void registerRouterStubIfNeededLocked() throws RemoteException {
             if (mStub == null) {
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 31cfb5a..74d4c4b 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -667,6 +667,19 @@
         }
     }
 
+    @NonNull
+    public List<AppId> getSystemSessionOverridesAppIds(@NonNull IMediaRouter2Manager manager) {
+        Objects.requireNonNull(manager, "manager must not be null");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                return getSystemSessionOverridesAppIdsLocked(manager);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
     public void registerManager(@NonNull IMediaRouter2Manager manager,
             @NonNull String callerPackageName) {
@@ -1860,6 +1873,18 @@
         return sessionInfos;
     }
 
+    @GuardedBy("mLock")
+    public List<AppId> getSystemSessionOverridesAppIdsLocked(
+            @NonNull IMediaRouter2Manager manager) {
+        IBinder binder = manager.asBinder();
+        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+        if (managerRecord == null) {
+            Slog.w(TAG, "getSystemSessionOverridesAppIdsLocked: Ignoring unknown manager");
+            return Collections.emptyList();
+        }
+        return managerRecord.mUserRecord.getAppsWithSystemOverridesLocked();
+    }
+
     @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
     @GuardedBy("mLock")
     private void registerManagerLocked(
@@ -2410,7 +2435,8 @@
         private final ArrayList<RouterRecord> mRouterRecords = new ArrayList<>();
         final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
 
-        private final Set<String> mLastPackagesWithSystemOverridesOnHandler = new ArraySet<>();
+        // @GuardedBy("mLock")
+        private final Set<String> mLastPackagesWithSystemOverridesLocked = new ArraySet<>();
 
         // @GuardedBy("mLock")
         private final Map<String, Map<String, List<SuggestedDeviceInfo>>> mDeviceSuggestions =
@@ -2463,6 +2489,19 @@
             return false;
         }
 
+        @GuardedBy("mLock")
+        private List<AppId> getAppsWithSystemOverridesLocked() {
+            return mapPackageNamesToAppIdList(mLastPackagesWithSystemOverridesLocked);
+        }
+
+        /**
+         * Returns a list of {@link AppId app ids} corresponding to the given package names, created
+         * by associating each package name with {@link #mUserHandle}.
+         */
+        private List<AppId> mapPackageNamesToAppIdList(Collection<String> packageNames) {
+            return packageNames.stream().map(it -> new AppId(it, mUserHandle)).toList();
+        }
+
         // @GuardedBy("mLock")
         public void updateDeviceSuggestionsLocked(
                 String packageName,
@@ -3819,19 +3858,19 @@
                 boolean shouldShowVolumeUi) {
             List<ManagerRecord> managers = getManagerRecords();
             List<AppId> appsWithOverridesToReport = null;
-
             boolean isGlobalSession = TextUtils.isEmpty(sessionInfo.getClientPackageName());
-            if (isGlobalSession
-                    && !Objects.equals(
-                            mUserRecord.mLastPackagesWithSystemOverridesOnHandler,
-                            packageNamesWithRoutingSessionOverrides)) {
-                appsWithOverridesToReport =
-                        packageNamesWithRoutingSessionOverrides.stream()
-                                .map(it -> new AppId(it, mUserRecord.mUserHandle))
-                                .toList();
-                mUserRecord.mLastPackagesWithSystemOverridesOnHandler.clear();
-                mUserRecord.mLastPackagesWithSystemOverridesOnHandler.addAll(
-                        packageNamesWithRoutingSessionOverrides);
+            synchronized (mLock) {
+                if (isGlobalSession
+                        && !Objects.equals(
+                                mUserRecord.mLastPackagesWithSystemOverridesLocked,
+                                packageNamesWithRoutingSessionOverrides)) {
+                    appsWithOverridesToReport =
+                            mUserRecord.mapPackageNamesToAppIdList(
+                                    packageNamesWithRoutingSessionOverrides);
+                    mUserRecord.mLastPackagesWithSystemOverridesLocked.clear();
+                    mUserRecord.mLastPackagesWithSystemOverridesLocked.addAll(
+                            packageNamesWithRoutingSessionOverrides);
+                }
             }
             for (ManagerRecord manager : managers) {
                 if (Flags.enableMirroringInMediaRouter2()) {
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 2ec2eda..5533c01 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -31,6 +31,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.media.AppId;
 import android.media.AudioPlaybackConfiguration;
 import android.media.AudioRoutesInfo;
 import android.media.AudioSystem;
@@ -606,6 +607,12 @@
     }
 
     // Binder call
+    @Override
+    public List<AppId> getSystemSessionOverridesAppIds(IMediaRouter2Manager manager) {
+        return mService2.getSystemSessionOverridesAppIds(manager);
+    }
+
+    // Binder call
     @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
     @Override
     public void registerManager(IMediaRouter2Manager manager, String callerPackageName) {