Loading media/java/android/media/session/ISessionManager.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,6 @@ import android.os.Bundle; * @hide */ interface ISessionManager { ISession createSession(String packageName, in ISessionCallback cb, String tag); List<IBinder> getSessions(in ComponentName compName); ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId); List<IBinder> getSessions(in ComponentName compName, int userId); } No newline at end of file media/java/android/media/session/SessionManager.java +36 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.media.session.ISessionManager; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.util.Log; Loading Loading @@ -65,10 +66,25 @@ public final class SessionManager { * @return a {@link Session} for the new session */ public Session createSession(String tag) { return createSessionAsUser(tag, UserHandle.myUserId()); } /** * Creates a new session as the specified user. To create a session as a * user other than your own you must hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} * permission. * * @param tag A short name for debugging purposes * @param userId The user id to create the session as. * @return a {@link Session} for the new session * @hide */ public Session createSessionAsUser(String tag, int userId) { try { Session.CallbackStub cbStub = new Session.CallbackStub(); Session session = new Session(mService .createSession(mContext.getPackageName(), cbStub, tag), cbStub); .createSession(mContext.getPackageName(), cbStub, tag, userId), cbStub); cbStub.setMediaSession(session); return session; Loading @@ -91,9 +107,27 @@ public final class SessionManager { * @return A list of controllers for ongoing sessions */ public List<SessionController> getActiveSessions(ComponentName notificationListener) { return getActiveSessionsForUser(notificationListener, UserHandle.myUserId()); } /** * 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. * * @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 */ public List<SessionController> getActiveSessionsForUser(ComponentName notificationListener, int userId) { ArrayList<SessionController> controllers = new ArrayList<SessionController>(); try { List<IBinder> binders = mService.getSessions(notificationListener); List<IBinder> binders = mService.getSessions(notificationListener, userId); for (int i = binders.size() - 1; i >= 0; i--) { SessionController controller = SessionController.fromBinder(ISessionController.Stub .asInterface(binders.get(i))); Loading services/core/java/com/android/server/media/MediaSessionRecord.java +22 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.media; import android.app.ActivityManager; import android.content.Intent; import android.content.pm.PackageManager; import android.media.routeprovider.RouteRequest; Loading @@ -42,6 +43,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.util.Pair; Loading Loading @@ -80,7 +82,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private final MessageHandler mHandler; private final int mPid; private final int mOwnerPid; private final int mOwnerUid; private final int mUserId; private final SessionInfo mSessionInfo; private final String mTag; private final ControllerStub mController; Loading Loading @@ -110,10 +114,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private boolean mIsActive = false; public MediaSessionRecord(int pid, String packageName, ISessionCallback cb, String tag, MediaSessionService service, Handler handler) { mPid = pid; mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), packageName); public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName, ISessionCallback cb, String tag, MediaSessionService service, Handler handler) { mOwnerPid = ownerPid; mOwnerUid = ownerUid; mUserId = userId; mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), ownerPackageName); mTag = tag; mController = new ControllerStub(); mSession = new SessionStub(); Loading Loading @@ -186,6 +192,15 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { return (mFlags & flag) != 0; } /** * Get the user id this session was created for. * * @return The user id for this session. */ public int getUserId() { return mUserId; } /** * Check if this session has system priorty and should receive media buttons * before any other sessions. Loading Loading @@ -305,7 +320,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { pw.println(prefix + mTag + " " + this); final String indent = prefix + " "; pw.println(indent + "pid=" + mPid); pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid + ", userId=" + mUserId); pw.println(indent + "info=" + mSessionInfo.toString()); pw.println(indent + "published=" + mIsActive); pw.println(indent + "flags=" + mFlags); Loading services/core/java/com/android/server/media/MediaSessionService.java +53 −28 Original line number Diff line number Diff line Loading @@ -63,7 +63,6 @@ public class MediaSessionService extends SystemService implements Monitor { private final ArrayList<MediaRouteProviderProxy> mProviders = new ArrayList<MediaRouteProviderProxy>(); private final Object mLock = new Object(); // TODO do we want a separate thread for handling mediasession messages? private final Handler mHandler = new Handler(); private MediaSessionRecord mPrioritySession; Loading @@ -72,8 +71,8 @@ public class MediaSessionService extends SystemService implements Monitor { // session so we drop late callbacks properly. private int mShowRoutesRequestId = 0; // TODO refactor to have per user state. See MediaRouterService for an // example // TODO refactor to have per user state for providers. See // MediaRouterService for an example public MediaSessionService(Context context) { super(context); Loading Loading @@ -211,25 +210,42 @@ public class MediaSessionService extends SystemService implements Monitor { * <ul> * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL * permission</li> * <li>the caller's listener is one of the enabled notification listeners</li> * <li>the caller's listener is one of the enabled notification listeners * for the caller's user</li> * </ul> */ private void enforceMediaPermissions(ComponentName compName, int pid, int uid) { private void enforceMediaPermissions(ComponentName compName, int pid, int uid, int resolvedUserId) { if (getContext() .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid) != PackageManager.PERMISSION_GRANTED && !isEnabledNotificationListener(compName)) { && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid), resolvedUserId)) { throw new SecurityException("Missing permission to control media."); } } private boolean isEnabledNotificationListener(ComponentName compName) { /** * This checks if the component is an enabled notification listener for the * specified user. Enabled components may only operate on behalf of the user * they're running as. * * @param compName The component that is enabled. * @param userId The user id of the caller. * @param forUserId The user id they're making the request on behalf of. * @return True if the component is enabled, false otherwise */ private boolean isEnabledNotificationListener(ComponentName compName, int userId, int forUserId) { if (userId != forUserId) { // You may not access another user's content as an enabled listener. return false; } if (compName != null) { final int currentUser = ActivityManager.getCurrentUser(); final String enabledNotifListeners = Settings.Secure.getStringForUser( getContext().getContentResolver(), Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, currentUser); userId); if (enabledNotifListeners != null) { final String[] components = enabledNotifListeners.split(":"); for (int i = 0; i < components.length; i++) { Loading @@ -248,23 +264,23 @@ public class MediaSessionService extends SystemService implements Monitor { } if (DEBUG) { Log.d(TAG, "not ok to get sessions, " + compName + " is not in list of ENABLED_NOTIFICATION_LISTENERS"); " is not in list of ENABLED_NOTIFICATION_LISTENERS for user " + userId); } } return false; } private MediaSessionRecord createSessionInternal(int pid, String packageName, ISessionCallback cb, String tag, boolean forCalls) { private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId, String callerPackageName, ISessionCallback cb, String tag) { synchronized (mLock) { return createSessionLocked(pid, packageName, cb, tag); return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag); } } private MediaSessionRecord createSessionLocked(int pid, String packageName, ISessionCallback cb, String tag) { final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this, mHandler); private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId, String callerPackageName, ISessionCallback cb, String tag) { final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId, callerPackageName, cb, tag, this, mHandler); try { cb.asBinder().linkToDeath(session, 0); } catch (RemoteException e) { Loading @@ -273,7 +289,7 @@ public class MediaSessionService extends SystemService implements Monitor { mRecords.add(session); mPriorityStack.addSession(session); if (DEBUG) { Log.d(TAG, "Created session for package " + packageName + " with tag " + tag); Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag); } return session; } Loading Loading @@ -358,41 +374,50 @@ public class MediaSessionService extends SystemService implements Monitor { // ActivityManagerNative.handleIncomingUser and stash result for use // when starting services on that session's behalf. @Override public ISession createSession(String packageName, ISessionCallback cb, String tag) throws RemoteException { public ISession createSession(String packageName, ISessionCallback cb, String tag, int userId) throws RemoteException { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { enforcePackageName(packageName, uid); int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, false /* allowAll */, true /* requireFull */, "createSession", packageName); if (cb == null) { throw new IllegalArgumentException("Controller callback cannot be null"); } return createSessionInternal(pid, packageName, cb, tag, false).getSessionBinder(); return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag) .getSessionBinder(); } finally { Binder.restoreCallingIdentity(token); } } @Override public List<IBinder> getSessions(ComponentName componentName) { public List<IBinder> getSessions(ComponentName componentName, int userId) { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { String packageName = null; if (componentName != null) { // If they gave us a component name verify they own the // package enforcePackageName(componentName.getPackageName(), uid); packageName = componentName.getPackageName(); enforcePackageName(packageName, uid); } // Then check if they have the permissions or their component is // allowed enforceMediaPermissions(componentName, pid, 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. enforceMediaPermissions(componentName, pid, uid, resolvedUserId); ArrayList<IBinder> binders = new ArrayList<IBinder>(); synchronized (mLock) { ArrayList<MediaSessionRecord> records = mPriorityStack .getActiveSessions(); .getActiveSessions(resolvedUserId); int size = records.size(); for (int i = 0; i < size; i++) { binders.add(records.get(i).getControllerBinder().asBinder()); Loading Loading @@ -428,7 +453,7 @@ public class MediaSessionService extends SystemService implements Monitor { mRecords.get(i).dump(pw, ""); pw.println(); } mPriorityStack.dumpLocked(pw, ""); mPriorityStack.dump(pw, ""); pw.println("Providers:"); count = mProviders.size(); Loading services/core/java/com/android/server/media/MediaSessionStack.java +25 −11 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.media; import android.media.session.PlaybackState; import android.media.session.Session; import android.os.UserHandle; import android.text.TextUtils; import java.io.PrintWriter; Loading Loading @@ -104,11 +105,12 @@ public class MediaSessionStack { * Get the current priority sorted list of active sessions. The most * important session is at index 0 and the least important at size - 1. * * @param userId The user to check. * @return All the active sessions in priority order. */ public ArrayList<MediaSessionRecord> getActiveSessions() { public ArrayList<MediaSessionRecord> getActiveSessions(int userId) { if (mCachedActiveList == null) { mCachedActiveList = getPriorityListLocked(true, 0); mCachedActiveList = getPriorityListLocked(true, 0, userId); } return mCachedActiveList; } Loading @@ -118,13 +120,14 @@ public class MediaSessionStack { * transport controls. The most important session is at index 0 and the * least important at size -1. * * @param userId The user to check. * @return All the active sessions that handle transport controls in * priority order. */ public ArrayList<MediaSessionRecord> getTransportControlSessions() { public ArrayList<MediaSessionRecord> getTransportControlSessions(int userId) { if (mCachedTransportControlList == null) { mCachedTransportControlList = getPriorityListLocked(true, Session.FLAG_HANDLES_TRANSPORT_CONTROLS); Session.FLAG_HANDLES_TRANSPORT_CONTROLS, userId); } return mCachedTransportControlList; } Loading @@ -132,13 +135,14 @@ public class MediaSessionStack { /** * Get the highest priority active session. * * @param userId The user to check. * @return The current highest priority session or null. */ public MediaSessionRecord getDefaultSession() { public MediaSessionRecord getDefaultSession(int userId) { if (mCachedDefault != null) { return mCachedDefault; } ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0); ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId); if (records.size() > 0) { return records.get(0); } Loading @@ -148,22 +152,24 @@ public class MediaSessionStack { /** * Get the highest priority session that can handle media buttons. * * @param userId The user to check. * @return The default media button session or null. */ public MediaSessionRecord getDefaultMediaButtonSession() { public MediaSessionRecord getDefaultMediaButtonSession(int userId) { if (mCachedButtonReceiver != null) { return mCachedButtonReceiver; } ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, Session.FLAG_HANDLES_MEDIA_BUTTONS); Session.FLAG_HANDLES_MEDIA_BUTTONS, userId); if (records.size() > 0) { mCachedButtonReceiver = records.get(0); } return mCachedButtonReceiver; } public void dumpLocked(PrintWriter pw, String prefix) { ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0); public void dump(PrintWriter pw, String prefix) { ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0, UserHandle.USER_ALL); int count = sortedSessions.size(); pw.println(prefix + "Sessions Stack - have " + count + " sessions:"); String indent = prefix + " "; Loading @@ -182,9 +188,12 @@ public class MediaSessionStack { * all sessions. * @param withFlags Only return sessions with all the specified flags set. 0 * returns all sessions. * @param userId The user to get sessions for. {@link UserHandle#USER_ALL} * will return sessions for all users. * @return The priority sorted list of sessions. */ private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags) { private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags, int userId) { ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>(); int lastLocalIndex = 0; int lastActiveIndex = 0; Loading @@ -194,7 +203,12 @@ public class MediaSessionStack { for (int i = 0; i < size; i++) { final MediaSessionRecord session = mSessions.get(i); if (userId != UserHandle.USER_ALL && userId != session.getUserId()) { // Filter out sessions for the wrong user continue; } if ((session.getFlags() & withFlags) != withFlags) { // Filter out sessions with the wrong flags continue; } if (!session.isActive()) { Loading Loading
media/java/android/media/session/ISessionManager.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,6 @@ import android.os.Bundle; * @hide */ interface ISessionManager { ISession createSession(String packageName, in ISessionCallback cb, String tag); List<IBinder> getSessions(in ComponentName compName); ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId); List<IBinder> getSessions(in ComponentName compName, int userId); } No newline at end of file
media/java/android/media/session/SessionManager.java +36 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.media.session.ISessionManager; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.util.Log; Loading Loading @@ -65,10 +66,25 @@ public final class SessionManager { * @return a {@link Session} for the new session */ public Session createSession(String tag) { return createSessionAsUser(tag, UserHandle.myUserId()); } /** * Creates a new session as the specified user. To create a session as a * user other than your own you must hold the * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} * permission. * * @param tag A short name for debugging purposes * @param userId The user id to create the session as. * @return a {@link Session} for the new session * @hide */ public Session createSessionAsUser(String tag, int userId) { try { Session.CallbackStub cbStub = new Session.CallbackStub(); Session session = new Session(mService .createSession(mContext.getPackageName(), cbStub, tag), cbStub); .createSession(mContext.getPackageName(), cbStub, tag, userId), cbStub); cbStub.setMediaSession(session); return session; Loading @@ -91,9 +107,27 @@ public final class SessionManager { * @return A list of controllers for ongoing sessions */ public List<SessionController> getActiveSessions(ComponentName notificationListener) { return getActiveSessionsForUser(notificationListener, UserHandle.myUserId()); } /** * 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. * * @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 */ public List<SessionController> getActiveSessionsForUser(ComponentName notificationListener, int userId) { ArrayList<SessionController> controllers = new ArrayList<SessionController>(); try { List<IBinder> binders = mService.getSessions(notificationListener); List<IBinder> binders = mService.getSessions(notificationListener, userId); for (int i = binders.size() - 1; i >= 0; i--) { SessionController controller = SessionController.fromBinder(ISessionController.Stub .asInterface(binders.get(i))); Loading
services/core/java/com/android/server/media/MediaSessionRecord.java +22 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.media; import android.app.ActivityManager; import android.content.Intent; import android.content.pm.PackageManager; import android.media.routeprovider.RouteRequest; Loading @@ -42,6 +43,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.util.Pair; Loading Loading @@ -80,7 +82,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private final MessageHandler mHandler; private final int mPid; private final int mOwnerPid; private final int mOwnerUid; private final int mUserId; private final SessionInfo mSessionInfo; private final String mTag; private final ControllerStub mController; Loading Loading @@ -110,10 +114,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private boolean mIsActive = false; public MediaSessionRecord(int pid, String packageName, ISessionCallback cb, String tag, MediaSessionService service, Handler handler) { mPid = pid; mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), packageName); public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName, ISessionCallback cb, String tag, MediaSessionService service, Handler handler) { mOwnerPid = ownerPid; mOwnerUid = ownerUid; mUserId = userId; mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), ownerPackageName); mTag = tag; mController = new ControllerStub(); mSession = new SessionStub(); Loading Loading @@ -186,6 +192,15 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { return (mFlags & flag) != 0; } /** * Get the user id this session was created for. * * @return The user id for this session. */ public int getUserId() { return mUserId; } /** * Check if this session has system priorty and should receive media buttons * before any other sessions. Loading Loading @@ -305,7 +320,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { pw.println(prefix + mTag + " " + this); final String indent = prefix + " "; pw.println(indent + "pid=" + mPid); pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid + ", userId=" + mUserId); pw.println(indent + "info=" + mSessionInfo.toString()); pw.println(indent + "published=" + mIsActive); pw.println(indent + "flags=" + mFlags); Loading
services/core/java/com/android/server/media/MediaSessionService.java +53 −28 Original line number Diff line number Diff line Loading @@ -63,7 +63,6 @@ public class MediaSessionService extends SystemService implements Monitor { private final ArrayList<MediaRouteProviderProxy> mProviders = new ArrayList<MediaRouteProviderProxy>(); private final Object mLock = new Object(); // TODO do we want a separate thread for handling mediasession messages? private final Handler mHandler = new Handler(); private MediaSessionRecord mPrioritySession; Loading @@ -72,8 +71,8 @@ public class MediaSessionService extends SystemService implements Monitor { // session so we drop late callbacks properly. private int mShowRoutesRequestId = 0; // TODO refactor to have per user state. See MediaRouterService for an // example // TODO refactor to have per user state for providers. See // MediaRouterService for an example public MediaSessionService(Context context) { super(context); Loading Loading @@ -211,25 +210,42 @@ public class MediaSessionService extends SystemService implements Monitor { * <ul> * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL * permission</li> * <li>the caller's listener is one of the enabled notification listeners</li> * <li>the caller's listener is one of the enabled notification listeners * for the caller's user</li> * </ul> */ private void enforceMediaPermissions(ComponentName compName, int pid, int uid) { private void enforceMediaPermissions(ComponentName compName, int pid, int uid, int resolvedUserId) { if (getContext() .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid) != PackageManager.PERMISSION_GRANTED && !isEnabledNotificationListener(compName)) { && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid), resolvedUserId)) { throw new SecurityException("Missing permission to control media."); } } private boolean isEnabledNotificationListener(ComponentName compName) { /** * This checks if the component is an enabled notification listener for the * specified user. Enabled components may only operate on behalf of the user * they're running as. * * @param compName The component that is enabled. * @param userId The user id of the caller. * @param forUserId The user id they're making the request on behalf of. * @return True if the component is enabled, false otherwise */ private boolean isEnabledNotificationListener(ComponentName compName, int userId, int forUserId) { if (userId != forUserId) { // You may not access another user's content as an enabled listener. return false; } if (compName != null) { final int currentUser = ActivityManager.getCurrentUser(); final String enabledNotifListeners = Settings.Secure.getStringForUser( getContext().getContentResolver(), Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, currentUser); userId); if (enabledNotifListeners != null) { final String[] components = enabledNotifListeners.split(":"); for (int i = 0; i < components.length; i++) { Loading @@ -248,23 +264,23 @@ public class MediaSessionService extends SystemService implements Monitor { } if (DEBUG) { Log.d(TAG, "not ok to get sessions, " + compName + " is not in list of ENABLED_NOTIFICATION_LISTENERS"); " is not in list of ENABLED_NOTIFICATION_LISTENERS for user " + userId); } } return false; } private MediaSessionRecord createSessionInternal(int pid, String packageName, ISessionCallback cb, String tag, boolean forCalls) { private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId, String callerPackageName, ISessionCallback cb, String tag) { synchronized (mLock) { return createSessionLocked(pid, packageName, cb, tag); return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag); } } private MediaSessionRecord createSessionLocked(int pid, String packageName, ISessionCallback cb, String tag) { final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this, mHandler); private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId, String callerPackageName, ISessionCallback cb, String tag) { final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId, callerPackageName, cb, tag, this, mHandler); try { cb.asBinder().linkToDeath(session, 0); } catch (RemoteException e) { Loading @@ -273,7 +289,7 @@ public class MediaSessionService extends SystemService implements Monitor { mRecords.add(session); mPriorityStack.addSession(session); if (DEBUG) { Log.d(TAG, "Created session for package " + packageName + " with tag " + tag); Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag); } return session; } Loading Loading @@ -358,41 +374,50 @@ public class MediaSessionService extends SystemService implements Monitor { // ActivityManagerNative.handleIncomingUser and stash result for use // when starting services on that session's behalf. @Override public ISession createSession(String packageName, ISessionCallback cb, String tag) throws RemoteException { public ISession createSession(String packageName, ISessionCallback cb, String tag, int userId) throws RemoteException { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { enforcePackageName(packageName, uid); int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, false /* allowAll */, true /* requireFull */, "createSession", packageName); if (cb == null) { throw new IllegalArgumentException("Controller callback cannot be null"); } return createSessionInternal(pid, packageName, cb, tag, false).getSessionBinder(); return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag) .getSessionBinder(); } finally { Binder.restoreCallingIdentity(token); } } @Override public List<IBinder> getSessions(ComponentName componentName) { public List<IBinder> getSessions(ComponentName componentName, int userId) { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { String packageName = null; if (componentName != null) { // If they gave us a component name verify they own the // package enforcePackageName(componentName.getPackageName(), uid); packageName = componentName.getPackageName(); enforcePackageName(packageName, uid); } // Then check if they have the permissions or their component is // allowed enforceMediaPermissions(componentName, pid, 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. enforceMediaPermissions(componentName, pid, uid, resolvedUserId); ArrayList<IBinder> binders = new ArrayList<IBinder>(); synchronized (mLock) { ArrayList<MediaSessionRecord> records = mPriorityStack .getActiveSessions(); .getActiveSessions(resolvedUserId); int size = records.size(); for (int i = 0; i < size; i++) { binders.add(records.get(i).getControllerBinder().asBinder()); Loading Loading @@ -428,7 +453,7 @@ public class MediaSessionService extends SystemService implements Monitor { mRecords.get(i).dump(pw, ""); pw.println(); } mPriorityStack.dumpLocked(pw, ""); mPriorityStack.dump(pw, ""); pw.println("Providers:"); count = mProviders.size(); Loading
services/core/java/com/android/server/media/MediaSessionStack.java +25 −11 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.media; import android.media.session.PlaybackState; import android.media.session.Session; import android.os.UserHandle; import android.text.TextUtils; import java.io.PrintWriter; Loading Loading @@ -104,11 +105,12 @@ public class MediaSessionStack { * Get the current priority sorted list of active sessions. The most * important session is at index 0 and the least important at size - 1. * * @param userId The user to check. * @return All the active sessions in priority order. */ public ArrayList<MediaSessionRecord> getActiveSessions() { public ArrayList<MediaSessionRecord> getActiveSessions(int userId) { if (mCachedActiveList == null) { mCachedActiveList = getPriorityListLocked(true, 0); mCachedActiveList = getPriorityListLocked(true, 0, userId); } return mCachedActiveList; } Loading @@ -118,13 +120,14 @@ public class MediaSessionStack { * transport controls. The most important session is at index 0 and the * least important at size -1. * * @param userId The user to check. * @return All the active sessions that handle transport controls in * priority order. */ public ArrayList<MediaSessionRecord> getTransportControlSessions() { public ArrayList<MediaSessionRecord> getTransportControlSessions(int userId) { if (mCachedTransportControlList == null) { mCachedTransportControlList = getPriorityListLocked(true, Session.FLAG_HANDLES_TRANSPORT_CONTROLS); Session.FLAG_HANDLES_TRANSPORT_CONTROLS, userId); } return mCachedTransportControlList; } Loading @@ -132,13 +135,14 @@ public class MediaSessionStack { /** * Get the highest priority active session. * * @param userId The user to check. * @return The current highest priority session or null. */ public MediaSessionRecord getDefaultSession() { public MediaSessionRecord getDefaultSession(int userId) { if (mCachedDefault != null) { return mCachedDefault; } ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0); ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId); if (records.size() > 0) { return records.get(0); } Loading @@ -148,22 +152,24 @@ public class MediaSessionStack { /** * Get the highest priority session that can handle media buttons. * * @param userId The user to check. * @return The default media button session or null. */ public MediaSessionRecord getDefaultMediaButtonSession() { public MediaSessionRecord getDefaultMediaButtonSession(int userId) { if (mCachedButtonReceiver != null) { return mCachedButtonReceiver; } ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, Session.FLAG_HANDLES_MEDIA_BUTTONS); Session.FLAG_HANDLES_MEDIA_BUTTONS, userId); if (records.size() > 0) { mCachedButtonReceiver = records.get(0); } return mCachedButtonReceiver; } public void dumpLocked(PrintWriter pw, String prefix) { ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0); public void dump(PrintWriter pw, String prefix) { ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0, UserHandle.USER_ALL); int count = sortedSessions.size(); pw.println(prefix + "Sessions Stack - have " + count + " sessions:"); String indent = prefix + " "; Loading @@ -182,9 +188,12 @@ public class MediaSessionStack { * all sessions. * @param withFlags Only return sessions with all the specified flags set. 0 * returns all sessions. * @param userId The user to get sessions for. {@link UserHandle#USER_ALL} * will return sessions for all users. * @return The priority sorted list of sessions. */ private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags) { private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags, int userId) { ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>(); int lastLocalIndex = 0; int lastActiveIndex = 0; Loading @@ -194,7 +203,12 @@ public class MediaSessionStack { for (int i = 0; i < size; i++) { final MediaSessionRecord session = mSessions.get(i); if (userId != UserHandle.USER_ALL && userId != session.getUserId()) { // Filter out sessions for the wrong user continue; } if ((session.getFlags() & withFlags) != withFlags) { // Filter out sessions with the wrong flags continue; } if (!session.isActive()) { Loading