Loading media/java/android/media/session/MediaSessionManager.java +40 −26 Original line number Diff line number Diff line Loading @@ -180,7 +180,7 @@ public final class MediaSessionManager { * be provided in priority order with the most important controller at index * 0. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} * permission be held by the calling app. You may also retrieve this list if * your app is an enabled notification listener using the * {@link NotificationListenerService} APIs, in which case you must pass the Loading @@ -196,14 +196,18 @@ public final class MediaSessionManager { } /** * Get active sessions for a specific user. To retrieve actions for a user * other than your own you must hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission * in addition to any other requirements. If you are an enabled notification * listener you may only get sessions for the users you are enabled for. * Get active sessions for the given user. * <p> * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be * held by the calling app. You may also retrieve this list if your app is an enabled * notification listener using the {@link NotificationListenerService} APIs, in which case you * must pass the {@link ComponentName} of your enabled listener. * <p> * The calling application needs to hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * retrieve sessions for user ids that do not belong to current process. * * @param notificationListener The enabled notification listener component. * May be null. * @param notificationListener The enabled notification listener component. May be null. * @param userId The user id to fetch sessions for. * @return A list of controllers for ongoing sessions. * @hide Loading Loading @@ -248,8 +252,9 @@ public final class MediaSessionManager { * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the * given user. * <p> * If you want to get tokens for another user, you must hold the * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL permission. * The calling application needs to hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * retrieve session tokens for user ids that do not belong to current process. * * @param userId The user id to fetch sessions for. * @return A list of {@link Session2Token} Loading @@ -267,11 +272,12 @@ public final class MediaSessionManager { } /** * Add a listener to be notified when the list of active sessions changes. This requires the * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling * app. You may also retrieve this list if your app is an enabled notification listener using * the {@link NotificationListenerService} APIs, in which case you must pass the * {@link ComponentName} of your enabled listener. * Add a listener to be notified when the list of active sessions changes. * <p> * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be * held by the calling app. You may also retrieve this list if your app is an enabled * notificationlistener using the {@link NotificationListenerService} APIs, in which case you * must pass the {@link ComponentName} of your enabled listener. * * @param sessionListener The listener to add. * @param notificationListener The enabled notification listener component. May be null. Loading @@ -283,12 +289,13 @@ public final class MediaSessionManager { } /** * Add a listener to be notified when the list of active sessions changes. This requires the * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling * app. You may also retrieve this list if your app is an enabled notification listener using * the {@link NotificationListenerService} APIs, in which case you must pass the * {@link ComponentName} of your enabled listener. Updates will be posted to the handler * specified or to the caller's thread if the handler is null. * Add a listener to be notified when the list of active sessions changes. * <p> * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be * held by the calling app. You may also retrieve this list if your app is an enabled * notification listener using the {@link NotificationListenerService} APIs, in which case you * must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the * handler specified or to the caller's thread if the handler is null. * * @param sessionListener The listener to add. * @param notificationListener The enabled notification listener component. May be null. Loading @@ -302,15 +309,17 @@ public final class MediaSessionManager { } /** * Add a listener to be notified when the list of active sessions changes for the given user. * The calling app must have the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} * permission if it wants to call this method for a user that is not running the app. * Add a listener to be notified when the list of active sessions changes. * <p> * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be * held by the calling app. You may also retrieve this list if your app is an enabled * notification listener using the {@link NotificationListenerService} APIs, in which case you * must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the * handler specified or to the caller's thread if the handler is null. * <p> * The calling application needs to hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * add listeners for user ids that do not belong to current process. * * @param sessionListener The listener to add. * @param notificationListener The enabled notification listener component. May be null. Loading Loading @@ -407,6 +416,10 @@ public final class MediaSessionManager { * Library</a> for consistent behavior across all devices. * <p> * Adds a listener to be notified when the {@link #getSession2Tokens()} changes. * <p> * The calling application needs to hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * add listeners for user ids that do not belong to current process. * * @param userId The userId to listen for changes on * @param listener The listener to add Loading Loading @@ -705,8 +718,9 @@ public final class MediaSessionManager { /** * Checks whether the remote user is a trusted app. * <p> * An app is trusted if the app holds the android.Manifest.permission.MEDIA_CONTENT_CONTROL * permission or has an enabled notification listener. * An app is trusted if the app holds the * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission or has an enabled * notification listener. * * @param userInfo The remote user info from either * {@link MediaSession#getCurrentControllerInfo()} or Loading services/core/java/com/android/server/media/MediaSessionService.java +35 −16 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.media; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.os.UserHandle.ALL; import static android.os.UserHandle.CURRENT; Loading Loading @@ -1115,8 +1116,7 @@ public class MediaSessionService extends SystemService implements Monitor { final long token = Binder.clearCallingIdentity(); try { enforcePackageName(packageName, uid); int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, false /* allowAll */, true /* requireFull */, "createSession", packageName); int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName); if (cb == null) { throw new IllegalArgumentException("Controller callback cannot be null"); } Loading Loading @@ -1191,11 +1191,8 @@ public class MediaSessionService extends SystemService implements Monitor { final long token = Binder.clearCallingIdentity(); try { // Check that they can make calls on behalf of the user and // get the final user id int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, true /* allowAll */, true /* requireFull */, "getSession2Tokens", null /* optional packageName */); // Check that they can make calls on behalf of the user and get the final user id int resolvedUserId = handleIncomingUser(pid, uid, userId, null); List<Session2Token> result; synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(userId); Loading Loading @@ -1262,9 +1259,7 @@ public class MediaSessionService extends SystemService implements Monitor { try { // Check that they can make calls on behalf of the user and get the final user id. int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, true /* allowAll */, true /* requireFull */, "addSession2TokensListener", null /* optional packageName */); int resolvedUserId = handleIncomingUser(pid, uid, userId, null); synchronized (mLock) { int index = findIndexOfSession2TokensListenerLocked(listener); if (index >= 0) { Loading Loading @@ -1981,16 +1976,40 @@ public class MediaSessionService extends SystemService implements Monitor { packageName = componentName.getPackageName(); enforcePackageName(packageName, uid); } // Check that they can make calls on behalf of the user and // get the final user id int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, true /* allowAll */, true /* requireFull */, "getSessions", packageName); // Check if they have the permissions or their component is // enabled for the user they're calling from. // Check that they can make calls on behalf of the user and get the final user id int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName); // Check if they have the permissions or their component is enabled for the user // they're calling from. enforceMediaPermissions(componentName, pid, uid, resolvedUserId); return resolvedUserId; } // Handles incoming user by checking whether the caller has permission to access the // given user id's information or not. Permission is not necessary if the given user id is // equal to the caller's user id, but if not, the caller needs to have the // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown. // The return value will be the given user id, unless the given user id is // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead. private int handleIncomingUser(int pid, int uid, int userId, String packageName) { int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier(); if (userId == callingUserId) { return userId; } boolean canInteractAcrossUsersFull = mContext.checkPermission( INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED; if (canInteractAcrossUsersFull) { if (userId == CURRENT.getIdentifier()) { return ActivityManager.getCurrentUser(); } return userId; } throw new SecurityException("Permission denied while calling from " + packageName + " with user id: " + userId + "; Need to run as either the calling user id (" + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission"); } private boolean hasEnabledNotificationListener(int callingUserId, String controllerPackageName, int controllerUid) { int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier(); Loading Loading
media/java/android/media/session/MediaSessionManager.java +40 −26 Original line number Diff line number Diff line Loading @@ -180,7 +180,7 @@ public final class MediaSessionManager { * be provided in priority order with the most important controller at index * 0. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} * permission be held by the calling app. You may also retrieve this list if * your app is an enabled notification listener using the * {@link NotificationListenerService} APIs, in which case you must pass the Loading @@ -196,14 +196,18 @@ public final class MediaSessionManager { } /** * Get active sessions for a specific user. To retrieve actions for a user * other than your own you must hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission * in addition to any other requirements. If you are an enabled notification * listener you may only get sessions for the users you are enabled for. * Get active sessions for the given user. * <p> * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be * held by the calling app. You may also retrieve this list if your app is an enabled * notification listener using the {@link NotificationListenerService} APIs, in which case you * must pass the {@link ComponentName} of your enabled listener. * <p> * The calling application needs to hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * retrieve sessions for user ids that do not belong to current process. * * @param notificationListener The enabled notification listener component. * May be null. * @param notificationListener The enabled notification listener component. May be null. * @param userId The user id to fetch sessions for. * @return A list of controllers for ongoing sessions. * @hide Loading Loading @@ -248,8 +252,9 @@ public final class MediaSessionManager { * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the * given user. * <p> * If you want to get tokens for another user, you must hold the * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL permission. * The calling application needs to hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * retrieve session tokens for user ids that do not belong to current process. * * @param userId The user id to fetch sessions for. * @return A list of {@link Session2Token} Loading @@ -267,11 +272,12 @@ public final class MediaSessionManager { } /** * Add a listener to be notified when the list of active sessions changes. This requires the * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling * app. You may also retrieve this list if your app is an enabled notification listener using * the {@link NotificationListenerService} APIs, in which case you must pass the * {@link ComponentName} of your enabled listener. * Add a listener to be notified when the list of active sessions changes. * <p> * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be * held by the calling app. You may also retrieve this list if your app is an enabled * notificationlistener using the {@link NotificationListenerService} APIs, in which case you * must pass the {@link ComponentName} of your enabled listener. * * @param sessionListener The listener to add. * @param notificationListener The enabled notification listener component. May be null. Loading @@ -283,12 +289,13 @@ public final class MediaSessionManager { } /** * Add a listener to be notified when the list of active sessions changes. This requires the * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling * app. You may also retrieve this list if your app is an enabled notification listener using * the {@link NotificationListenerService} APIs, in which case you must pass the * {@link ComponentName} of your enabled listener. Updates will be posted to the handler * specified or to the caller's thread if the handler is null. * Add a listener to be notified when the list of active sessions changes. * <p> * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be * held by the calling app. You may also retrieve this list if your app is an enabled * notification listener using the {@link NotificationListenerService} APIs, in which case you * must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the * handler specified or to the caller's thread if the handler is null. * * @param sessionListener The listener to add. * @param notificationListener The enabled notification listener component. May be null. Loading @@ -302,15 +309,17 @@ public final class MediaSessionManager { } /** * Add a listener to be notified when the list of active sessions changes for the given user. * The calling app must have the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} * permission if it wants to call this method for a user that is not running the app. * Add a listener to be notified when the list of active sessions changes. * <p> * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be * held by the calling app. You may also retrieve this list if your app is an enabled * notification listener using the {@link NotificationListenerService} APIs, in which case you * must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the * handler specified or to the caller's thread if the handler is null. * <p> * The calling application needs to hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * add listeners for user ids that do not belong to current process. * * @param sessionListener The listener to add. * @param notificationListener The enabled notification listener component. May be null. Loading Loading @@ -407,6 +416,10 @@ public final class MediaSessionManager { * Library</a> for consistent behavior across all devices. * <p> * Adds a listener to be notified when the {@link #getSession2Tokens()} changes. * <p> * The calling application needs to hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * add listeners for user ids that do not belong to current process. * * @param userId The userId to listen for changes on * @param listener The listener to add Loading Loading @@ -705,8 +718,9 @@ public final class MediaSessionManager { /** * Checks whether the remote user is a trusted app. * <p> * An app is trusted if the app holds the android.Manifest.permission.MEDIA_CONTENT_CONTROL * permission or has an enabled notification listener. * An app is trusted if the app holds the * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission or has an enabled * notification listener. * * @param userInfo The remote user info from either * {@link MediaSession#getCurrentControllerInfo()} or Loading
services/core/java/com/android/server/media/MediaSessionService.java +35 −16 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.media; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.os.UserHandle.ALL; import static android.os.UserHandle.CURRENT; Loading Loading @@ -1115,8 +1116,7 @@ public class MediaSessionService extends SystemService implements Monitor { final long token = Binder.clearCallingIdentity(); try { enforcePackageName(packageName, uid); int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, false /* allowAll */, true /* requireFull */, "createSession", packageName); int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName); if (cb == null) { throw new IllegalArgumentException("Controller callback cannot be null"); } Loading Loading @@ -1191,11 +1191,8 @@ public class MediaSessionService extends SystemService implements Monitor { final long token = Binder.clearCallingIdentity(); try { // Check that they can make calls on behalf of the user and // get the final user id int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, true /* allowAll */, true /* requireFull */, "getSession2Tokens", null /* optional packageName */); // Check that they can make calls on behalf of the user and get the final user id int resolvedUserId = handleIncomingUser(pid, uid, userId, null); List<Session2Token> result; synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(userId); Loading Loading @@ -1262,9 +1259,7 @@ public class MediaSessionService extends SystemService implements Monitor { try { // Check that they can make calls on behalf of the user and get the final user id. int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, true /* allowAll */, true /* requireFull */, "addSession2TokensListener", null /* optional packageName */); int resolvedUserId = handleIncomingUser(pid, uid, userId, null); synchronized (mLock) { int index = findIndexOfSession2TokensListenerLocked(listener); if (index >= 0) { Loading Loading @@ -1981,16 +1976,40 @@ public class MediaSessionService extends SystemService implements Monitor { packageName = componentName.getPackageName(); enforcePackageName(packageName, uid); } // Check that they can make calls on behalf of the user and // get the final user id int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, true /* allowAll */, true /* requireFull */, "getSessions", packageName); // Check if they have the permissions or their component is // enabled for the user they're calling from. // Check that they can make calls on behalf of the user and get the final user id int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName); // Check if they have the permissions or their component is enabled for the user // they're calling from. enforceMediaPermissions(componentName, pid, uid, resolvedUserId); return resolvedUserId; } // Handles incoming user by checking whether the caller has permission to access the // given user id's information or not. Permission is not necessary if the given user id is // equal to the caller's user id, but if not, the caller needs to have the // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown. // The return value will be the given user id, unless the given user id is // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead. private int handleIncomingUser(int pid, int uid, int userId, String packageName) { int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier(); if (userId == callingUserId) { return userId; } boolean canInteractAcrossUsersFull = mContext.checkPermission( INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED; if (canInteractAcrossUsersFull) { if (userId == CURRENT.getIdentifier()) { return ActivityManager.getCurrentUser(); } return userId; } throw new SecurityException("Permission denied while calling from " + packageName + " with user id: " + userId + "; Need to run as either the calling user id (" + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission"); } private boolean hasEnabledNotificationListener(int callingUserId, String controllerPackageName, int controllerUid) { int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier(); Loading