Check if getSystemSessionInfo requested by a Proxy Router

ProxyRouter (inside MediaRouter2) calls getSystemSessionInfoForPackage
to request the initial RoutingSessionInfo. The method was designed for
LocalRouter and does not take into account calls from proxy routers,
therefore returns DEFAULT_ROUTE when requested by system router but
without bluetooth or modify audio routing permissions.

Bug: b/325755852
Test: N/A
Change-Id: I9fa38fb731c17e06927e1a927d6acc030ebb2135
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 7727078..63cb945 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -50,7 +50,7 @@
     // MediaRouterService.java for readability.
 
     // Methods for MediaRouter2
-    List<MediaRoute2Info> getSystemRoutes();
+    List<MediaRoute2Info> getSystemRoutes(String callerPackageName, boolean isProxyRouter);
     RoutingSessionInfo getSystemSessionInfo();
 
     void registerRouter2(IMediaRouter2 router, String packageName);
@@ -75,7 +75,8 @@
 
     // Methods for MediaRouter2Manager
     List<RoutingSessionInfo> getRemoteSessions(IMediaRouter2Manager manager);
-    RoutingSessionInfo getSystemSessionInfoForPackage(String packageName);
+    RoutingSessionInfo getSystemSessionInfoForPackage(String callerPackageName,
+        String targetPackageName);
     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 e0258ba..3f9440b 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -613,7 +613,7 @@
         mImpl = new LocalMediaRouter2Impl(mContext.getPackageName());
         mHandler = new Handler(Looper.getMainLooper());
 
-        loadSystemRoutes();
+        loadSystemRoutes(/* isProxyRouter */ false);
 
         RoutingSessionInfo currentSystemSessionInfo = mImpl.getSystemSessionInfo();
         if (currentSystemSessionInfo == null) {
@@ -631,21 +631,22 @@
                 IMediaRouterService.Stub.asInterface(
                         ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
 
-        loadSystemRoutes();
+        loadSystemRoutes(/* isProxyRouter */ true);
 
         mSystemController =
                 new SystemRoutingController(
                         ProxyMediaRouter2Impl.getSystemSessionInfoImpl(
-                                mMediaRouterService, clientPackageName));
+                                mMediaRouterService, mContext.getPackageName(), clientPackageName));
 
         mImpl = new ProxyMediaRouter2Impl(context, clientPackageName, user);
     }
 
     @GuardedBy("mLock")
-    private void loadSystemRoutes() {
+    private void loadSystemRoutes(boolean isProxyRouter) {
         List<MediaRoute2Info> currentSystemRoutes = null;
         try {
-            currentSystemRoutes = mMediaRouterService.getSystemRoutes();
+            currentSystemRoutes = mMediaRouterService.getSystemRoutes(mContext.getPackageName(),
+                    isProxyRouter);
         } catch (RemoteException ex) {
             ex.rethrowFromSystemServer();
         }
@@ -2644,7 +2645,8 @@
 
         @Override
         public RoutingSessionInfo getSystemSessionInfo() {
-            return getSystemSessionInfoImpl(mMediaRouterService, mClientPackageName);
+            return getSystemSessionInfoImpl(
+                    mMediaRouterService, mContext.getPackageName(), mClientPackageName);
         }
 
         /**
@@ -3049,9 +3051,11 @@
          * <p>Extracted into a static method to allow calling this from the constructor.
          */
         /* package */ static RoutingSessionInfo getSystemSessionInfoImpl(
-                @NonNull IMediaRouterService service, @NonNull String clientPackageName) {
+                @NonNull IMediaRouterService service,
+                @NonNull String callerPackageName,
+                @NonNull String clientPackageName) {
             try {
-                return service.getSystemSessionInfoForPackage(clientPackageName);
+                return service.getSystemSessionInfoForPackage(callerPackageName, clientPackageName);
             } catch (RemoteException ex) {
                 throw ex.rethrowFromSystemServer();
             }
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 7756d93..e62d112 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -81,6 +81,7 @@
     @GuardedBy("sLock")
     private static MediaRouter2Manager sInstance;
 
+    private final Context mContext;
     private final MediaSessionManager mMediaSessionManager;
     private final Client mClient;
     private final IMediaRouterService mMediaRouterService;
@@ -120,6 +121,7 @@
     }
 
     private MediaRouter2Manager(Context context) {
+        mContext = context.getApplicationContext();
         mMediaRouterService = IMediaRouterService.Stub.asInterface(
                 ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
         mMediaSessionManager = (MediaSessionManager) context
@@ -374,16 +376,17 @@
     }
 
     /**
-     * Gets the system routing session for the given {@code packageName}.
-     * Apps can select a route that is not the global route. (e.g. an app can select the device
-     * route while BT route is available.)
+     * Gets the system routing session for the given {@code targetPackageName}. Apps can select a
+     * route that is not the global route. (e.g. an app can select the device route while BT route
+     * is available.)
      *
-     * @param packageName the package name of the application.
+     * @param targetPackageName the package name of the application.
      */
     @Nullable
-    public RoutingSessionInfo getSystemRoutingSession(@Nullable String packageName) {
+    public RoutingSessionInfo getSystemRoutingSession(@Nullable String targetPackageName) {
         try {
-            return mMediaRouterService.getSystemSessionInfoForPackage(packageName);
+            return mMediaRouterService.getSystemSessionInfoForPackage(
+                    mContext.getPackageName(), targetPackageName);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 51a8aef..624cab8 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -221,18 +221,27 @@
     // Start of methods that implement MediaRouter2 operations.
 
     @NonNull
-    public List<MediaRoute2Info> getSystemRoutes() {
+    public List<MediaRoute2Info> getSystemRoutes(@NonNull String callerPackageName,
+            boolean isProxyRouter) {
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
         final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
-        final boolean hasSystemRoutingPermission = checkCallerHasSystemRoutingPermissions(pid, uid);
+
+        boolean hasSystemRoutingPermissions;
+        if (!isProxyRouter) {
+            hasSystemRoutingPermissions = checkCallerHasSystemRoutingPermissions(pid, uid);
+        } else {
+            // Request from ProxyRouter.
+            hasSystemRoutingPermissions =
+                    checkCallerHasPrivilegedRoutingPermissions(pid, uid, callerPackageName);
+        }
 
         final long token = Binder.clearCallingIdentity();
         try {
             Collection<MediaRoute2Info> systemRoutes;
             synchronized (mLock) {
                 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
-                if (hasSystemRoutingPermission) {
+                if (hasSystemRoutingPermissions) {
                     MediaRoute2ProviderInfo providerInfo =
                             userRecord.mHandler.mSystemProvider.getProviderInfo();
                     if (providerInfo != null) {
@@ -795,12 +804,21 @@
 
     @Nullable
     public RoutingSessionInfo getSystemSessionInfo(
-            @Nullable String packageName, boolean setDeviceRouteSelected) {
+            @NonNull String callerPackageName,
+            @Nullable String targetPackageName,
+            boolean setDeviceRouteSelected) {
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
         final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
-        final boolean hasSystemRoutingPermissions =
-                checkCallerHasSystemRoutingPermissions(pid, uid);
+
+        boolean hasSystemRoutingPermissions;
+        if (targetPackageName == null) {
+            hasSystemRoutingPermissions = checkCallerHasSystemRoutingPermissions(pid, uid);
+        } else {
+            // Request from ProxyRouter.
+            hasSystemRoutingPermissions =
+                    checkCallerHasPrivilegedRoutingPermissions(pid, uid, callerPackageName);
+        }
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -812,14 +830,14 @@
                         // Return a fake system session that shows the device route as selected and
                         // available bluetooth routes as transferable.
                         return userRecord.mHandler.mSystemProvider
-                                .generateDeviceRouteSelectedSessionInfo(packageName);
+                                .generateDeviceRouteSelectedSessionInfo(targetPackageName);
                     } else {
                         sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
                         if (!sessionInfos.isEmpty()) {
                             // Return a copy of the current system session with no modification,
                             // except setting the client package name.
                             return new RoutingSessionInfo.Builder(sessionInfos.get(0))
-                                    .setClientPackageName(packageName)
+                                    .setClientPackageName(targetPackageName)
                                     .build();
                         } else {
                             Slog.w(TAG, "System provider does not have any session info.");
@@ -828,7 +846,7 @@
                 } else {
                     return new RoutingSessionInfo.Builder(
                                     userRecord.mHandler.mSystemProvider.getDefaultSessionInfo())
-                            .setClientPackageName(packageName)
+                            .setClientPackageName(targetPackageName)
                             .build();
                 }
             }
@@ -843,6 +861,12 @@
                 || checkCallerHasBluetoothPermissions(pid, uid);
     }
 
+    private boolean checkCallerHasPrivilegedRoutingPermissions(
+            int pid, int uid, @NonNull String callerPackageName) {
+        return checkMediaContentControlPermission(uid, pid)
+                || checkMediaRoutingControlPermission(uid, pid, callerPackageName);
+    }
+
     private boolean checkCallerHasModifyAudioRoutingPermission(int pid, int uid) {
         return mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_ROUTING, pid, uid)
                 == PackageManager.PERMISSION_GRANTED;
@@ -864,30 +888,29 @@
                 Manifest.permission.MEDIA_CONTENT_CONTROL
             })
     private void enforcePrivilegedRoutingPermissions(
-            int callerUid, int callerPid, @Nullable String callerPackageName) {
-        if (hasMediaContentControlPermission(callerUid, callerPid)) {
+            int callerUid, int callerPid, @NonNull String callerPackageName) {
+        if (checkMediaContentControlPermission(callerUid, callerPid)) {
             return;
         }
 
-        if (!Flags.enablePrivilegedRoutingForMediaRoutingControl()) {
-            throw new SecurityException("Must hold MEDIA_CONTENT_CONTROL");
-        }
-
         if (!checkMediaRoutingControlPermission(callerUid, callerPid, callerPackageName)) {
             throw new SecurityException(
                     "Must hold MEDIA_CONTENT_CONTROL or MEDIA_ROUTING_CONTROL permissions.");
         }
     }
 
-    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
-    private boolean hasMediaContentControlPermission(int callerUid, int callerPid) {
+    private boolean checkMediaContentControlPermission(int callerUid, int callerPid) {
         return mContext.checkPermission(
                         Manifest.permission.MEDIA_CONTENT_CONTROL, callerPid, callerUid)
                 == PackageManager.PERMISSION_GRANTED;
     }
 
     private boolean checkMediaRoutingControlPermission(
-            int callerUid, int callerPid, @Nullable String callerPackageName) {
+            int callerUid, int callerPid, @NonNull String callerPackageName) {
+        if (!Flags.enablePrivilegedRoutingForMediaRoutingControl()) {
+            return false;
+        }
+
         return PermissionChecker.checkPermissionForDataDelivery(
                         mContext,
                         Manifest.permission.MEDIA_ROUTING_CONTROL,
@@ -1520,7 +1543,7 @@
         boolean hasMediaRoutingControl =
                 checkMediaRoutingControlPermission(callerUid, callerPid, callerPackageName);
 
-        boolean hasMediaContentControl = hasMediaContentControlPermission(callerUid, callerPid);
+        boolean hasMediaContentControl = checkMediaContentControlPermission(callerUid, callerPid);
 
         Slog.i(
                 TAG,
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 6af3480..76b8db6 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -411,15 +411,21 @@
 
     // Binder call
     @Override
-    public List<MediaRoute2Info> getSystemRoutes() {
-        return mService2.getSystemRoutes();
+    public List<MediaRoute2Info> getSystemRoutes(@NonNull String callerPackageName,
+            boolean isProxyRouter) {
+        if (!validatePackageName(Binder.getCallingUid(), callerPackageName)) {
+            throw new SecurityException("callerPackageName does not match calling uid.");
+        }
+        return mService2.getSystemRoutes(callerPackageName, isProxyRouter);
     }
 
     // Binder call
     @Override
     public RoutingSessionInfo getSystemSessionInfo() {
         return mService2.getSystemSessionInfo(
-                null /* packageName */, false /* setDeviceRouteSelected */);
+                /* callerPackageName */ null,
+                /* targetPackageName */ null, /* setDeviceRouteSelected */
+                false);
     }
 
     // Binder call
@@ -530,16 +536,22 @@
 
     // Binder call
     @Override
-    public RoutingSessionInfo getSystemSessionInfoForPackage(@Nullable String packageName) {
+    public RoutingSessionInfo getSystemSessionInfoForPackage(
+            @NonNull String callerPackageName, @Nullable String targetPackageName) {
         final int uid = Binder.getCallingUid();
         final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+
+        if (!validatePackageName(uid, callerPackageName)) {
+            throw new SecurityException("callerPackageName does not match calling uid.");
+        }
+
         boolean setDeviceRouteSelected = false;
         synchronized (mLock) {
             UserRecord userRecord = mUserRecords.get(userId);
             List<ClientRecord> userClientRecords =
                     userRecord != null ? userRecord.mClientRecords : Collections.emptyList();
             for (ClientRecord clientRecord : userClientRecords) {
-                if (TextUtils.equals(clientRecord.mPackageName, packageName)) {
+                if (TextUtils.equals(clientRecord.mPackageName, targetPackageName)) {
                     if (mDefaultAudioRouteId.equals(clientRecord.mSelectedRouteId)) {
                         setDeviceRouteSelected = true;
                         break;
@@ -547,7 +559,8 @@
                 }
             }
         }
-        return mService2.getSystemSessionInfo(packageName, setDeviceRouteSelected);
+        return mService2.getSystemSessionInfo(
+                callerPackageName, targetPackageName, setDeviceRouteSelected);
     }
 
     // Binder call