diff options
| author | 2024-11-22 10:57:05 -0800 | |
|---|---|---|
| committer | 2024-11-25 14:35:13 -0800 | |
| commit | 8b52b29be13412f8eafc29575f09e5e36fa96b61 (patch) | |
| tree | f4e6dfaabdc3edc8558cfc6804d96a3d0b329edf | |
| parent | 28c7df2479b777b1b90b826c4ad57a589b8cbb31 (diff) | |
Add a new API to let media routes have visibility restricted by permissions
Bug: 367799834
Flag: com.android.media.flags.enable_route_visibility_control_api
Test: MediaRoute2InfoTest and MediaRouter2HostSideTest
Change-Id: I61b89b11b7eb6cb05d9d237134af566ed289bb8c
| -rw-r--r-- | core/api/current.txt | 2 | ||||
| -rw-r--r-- | media/java/android/media/MediaRoute2Info.java | 36 | ||||
| -rw-r--r-- | services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java | 26 |
3 files changed, 61 insertions, 3 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 3af8e7e17dbd..8d1c244758fc 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -24852,6 +24852,7 @@ package android.media { method @Nullable public android.net.Uri getIconUri(); method @NonNull public String getId(); method @NonNull public CharSequence getName(); + method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public java.util.Set<java.lang.String> getRequiredPermissions(); method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public int getSuitabilityStatus(); method public int getType(); method public int getVolume(); @@ -24917,6 +24918,7 @@ package android.media { method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence); method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle); method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri); + method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public android.media.MediaRoute2Info.Builder setRequiredPermissions(@NonNull java.util.Set<java.lang.String>); method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") @NonNull public android.media.MediaRoute2Info.Builder setSuitabilityStatus(int); method @NonNull public android.media.MediaRoute2Info.Builder setType(int); method @NonNull public android.media.MediaRoute2Info.Builder setVisibilityPublic(); diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index 09022782e6c3..b1a31eb09181 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -23,6 +23,7 @@ import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AN import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES; import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES; import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES; +import static com.android.media.flags.Flags.FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -569,6 +570,7 @@ public final class MediaRoute2Info implements Parcelable { private final String mProviderId; private final boolean mIsVisibilityRestricted; private final Set<String> mAllowedPackages; + private final Set<String> mRequiredPermissions; @SuitabilityStatus private final int mSuitabilityStatus; MediaRoute2Info(@NonNull Builder builder) { @@ -592,6 +594,7 @@ public final class MediaRoute2Info implements Parcelable { mIsVisibilityRestricted = builder.mIsVisibilityRestricted; mAllowedPackages = builder.mAllowedPackages; mSuitabilityStatus = builder.mSuitabilityStatus; + mRequiredPermissions = Set.copyOf(builder.mRequiredPermissions); } MediaRoute2Info(@NonNull Parcel in) { @@ -615,6 +618,7 @@ public final class MediaRoute2Info implements Parcelable { mProviderId = in.readString(); mIsVisibilityRestricted = in.readBoolean(); mAllowedPackages = Set.of(in.createString8Array()); + mRequiredPermissions = Set.of(in.createString8Array()); mSuitabilityStatus = in.readInt(); } @@ -851,6 +855,15 @@ public final class MediaRoute2Info implements Parcelable { } /** + * @return the set of permissions which must be held to see this route + */ + @NonNull + @FlaggedApi(FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API) + public Set<String> getRequiredPermissions() { + return mRequiredPermissions; + } + + /** * Returns whether this route's type can only be published by the system route provider. * * @see #isSystemRoute() @@ -920,6 +933,7 @@ public final class MediaRoute2Info implements Parcelable { pw.println(indent + "mIsVisibilityRestricted=" + mIsVisibilityRestricted); pw.println(indent + "mAllowedPackages=" + mAllowedPackages); pw.println(indent + "mSuitabilityStatus=" + mSuitabilityStatus); + pw.println(indent + "mRequiredPermissions=" + mRequiredPermissions); } private void dumpVolume(@NonNull PrintWriter pw, @NonNull String prefix) { @@ -955,6 +969,7 @@ public final class MediaRoute2Info implements Parcelable { && Objects.equals(mProviderId, other.mProviderId) && (mIsVisibilityRestricted == other.mIsVisibilityRestricted) && Objects.equals(mAllowedPackages, other.mAllowedPackages) + && Objects.equals(mRequiredPermissions, other.mRequiredPermissions) && mSuitabilityStatus == other.mSuitabilityStatus; } @@ -980,6 +995,7 @@ public final class MediaRoute2Info implements Parcelable { mProviderId, mIsVisibilityRestricted, mAllowedPackages, + mRequiredPermissions, mSuitabilityStatus); } @@ -1018,6 +1034,8 @@ public final class MediaRoute2Info implements Parcelable { .append(mIsVisibilityRestricted) .append(", allowedPackages=") .append(String.join(",", mAllowedPackages)) + .append(", mRequiredPermissions=") + .append(String.join(",", mRequiredPermissions)) .append(", suitabilityStatus=") .append(mSuitabilityStatus) .append(" }") @@ -1050,6 +1068,7 @@ public final class MediaRoute2Info implements Parcelable { dest.writeString(mProviderId); dest.writeBoolean(mIsVisibilityRestricted); dest.writeString8Array(mAllowedPackages.toArray(new String[0])); + dest.writeString8Array(mRequiredPermissions.toArray(new String[0])); dest.writeInt(mSuitabilityStatus); } @@ -1169,6 +1188,7 @@ public final class MediaRoute2Info implements Parcelable { private String mProviderId; private boolean mIsVisibilityRestricted; private Set<String> mAllowedPackages; + private Set<String> mRequiredPermissions; @SuitabilityStatus private int mSuitabilityStatus; /** @@ -1194,6 +1214,7 @@ public final class MediaRoute2Info implements Parcelable { mDeduplicationIds = Set.of(); mAllowedPackages = Set.of(); mSuitabilityStatus = SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER; + mRequiredPermissions = Set.of(); } /** @@ -1242,6 +1263,7 @@ public final class MediaRoute2Info implements Parcelable { mIsVisibilityRestricted = routeInfo.mIsVisibilityRestricted; mAllowedPackages = routeInfo.mAllowedPackages; mSuitabilityStatus = routeInfo.mSuitabilityStatus; + mRequiredPermissions = routeInfo.mRequiredPermissions; } /** @@ -1461,6 +1483,7 @@ public final class MediaRoute2Info implements Parcelable { public Builder setVisibilityPublic() { mIsVisibilityRestricted = false; mAllowedPackages = Set.of(); + mRequiredPermissions = Set.of(); return this; } @@ -1485,6 +1508,19 @@ public final class MediaRoute2Info implements Parcelable { } /** + * Limits the visibility of this route to holders of a set of permissions. + * + * @param requiredPermissions the list of all permissions which must be held in order to + * see this route. + */ + @NonNull + @FlaggedApi(FLAG_ENABLE_ROUTE_VISIBILITY_CONTROL_API) + public Builder setRequiredPermissions(@NonNull Set<String> requiredPermissions) { + mRequiredPermissions = Set.copyOf(requiredPermissions); + return this; + } + + /** * Sets route suitability status. * * <p>The default value is {@link diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 27bc1cf3e631..f9fa73b27304 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -1136,6 +1136,7 @@ class MediaRouter2ServiceImpl { UserRecord userRecord = getOrCreateUserRecordLocked(userId); RouterRecord routerRecord = new RouterRecord( + mContext, userRecord, router, uid, @@ -2055,6 +2056,7 @@ class MediaRouter2ServiceImpl { } final class RouterRecord implements IBinder.DeathRecipient { + public final Context mContext; public final UserRecord mUserRecord; public final String mPackageName; public final List<Integer> mSelectRouteSequenceNumbers; @@ -2073,6 +2075,7 @@ class MediaRouter2ServiceImpl { @Nullable public RouteListingPreference mRouteListingPreference; RouterRecord( + Context context, UserRecord userRecord, IMediaRouter2 router, int uid, @@ -2082,6 +2085,7 @@ class MediaRouter2ServiceImpl { boolean hasModifyAudioRoutingPermission, boolean hasMediaContentControlPermission, boolean hasMediaRoutingControl) { + mContext = context; mUserRecord = userRecord; mPackageName = packageName; mSelectRouteSequenceNumbers = new ArrayList<>(); @@ -2322,18 +2326,34 @@ class MediaRouter2ServiceImpl { } /** - * Returns a filtered copy of {@code routes} that contains only the routes that are {@link - * MediaRoute2Info#isVisibleTo visible} to the router corresponding to this record. + * Returns a filtered copy of {@code routes} that contains only the routes that are visible + * to this RouterRecord. */ private List<MediaRoute2Info> getVisibleRoutes(@NonNull List<MediaRoute2Info> routes) { List<MediaRoute2Info> filteredRoutes = new ArrayList<>(); for (MediaRoute2Info route : routes) { - if (route.isVisibleTo(mPackageName)) { + if (route.isVisibleTo(mPackageName) && hasPermissionsToSeeRoute(route)) { filteredRoutes.add(route); } } return filteredRoutes; } + + /** + * @return whether this RouterRecord has the required permissions to see the given route. + */ + private boolean hasPermissionsToSeeRoute(MediaRoute2Info route) { + if (!Flags.enableRouteVisibilityControlApi()) { + return true; + } + for (String permission : route.getRequiredPermissions()) { + if (mContext.checkPermission(permission, mPid, mUid) + != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } } final class ManagerRecord implements IBinder.DeathRecipient { |