Limit the number of MediaSessions per uid
This CL makes MediaSessionService counts the number of current MediaSessions per uid, and throw exception to the app if the number exceeds the limit. Bug: 143672815 Test: atest MediaSessionTest Change-Id: Ib3dd0f655d54f9ca436bcc3808e8eba241dfaacc
This commit is contained in:
@@ -146,6 +146,8 @@ public final class MediaSession {
|
||||
* the system but will not be published until {@link #setActive(boolean)
|
||||
* setActive(true)} is called. You must call {@link #release()} when
|
||||
* finished with the session.
|
||||
* <p>
|
||||
* Note that {@link RuntimeException} will be thrown if an app creates too many sessions.
|
||||
*
|
||||
* @param context The context to use to create the session.
|
||||
* @param tag A short name for debugging purposes.
|
||||
@@ -163,6 +165,8 @@ public final class MediaSession {
|
||||
* The {@code sessionInfo} can include additional unchanging information about this session.
|
||||
* For example, it can include the version of the application, or the list of the custom
|
||||
* commands that this session supports.
|
||||
* <p>
|
||||
* Note that {@link RuntimeException} will be thrown if an app creates too many sessions.
|
||||
*
|
||||
* @param context The context to use to create the session.
|
||||
* @param tag A short name for debugging purposes.
|
||||
|
||||
@@ -103,6 +103,7 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
|
||||
private static final int WAKELOCK_TIMEOUT = 5000;
|
||||
private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
|
||||
private static final int SESSION_CREATION_LIMIT_PER_UID = 100;
|
||||
|
||||
private final Context mContext;
|
||||
private final SessionManagerImpl mSessionManagerImpl;
|
||||
@@ -428,6 +429,18 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
Log.d(TAG, "Destroying " + session);
|
||||
}
|
||||
FullUserRecord user = getFullUserRecordLocked(session.getUserId());
|
||||
|
||||
if (user != null) {
|
||||
final int uid = session.getUid();
|
||||
final int sessionCount = user.mUidToSessionCount.get(uid, 0);
|
||||
if (sessionCount <= 0) {
|
||||
Log.w(TAG, "destroySessionLocked: sessionCount should be positive. "
|
||||
+ "sessionCount=" + sessionCount);
|
||||
} else {
|
||||
user.mUidToSessionCount.put(uid, sessionCount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (mGlobalPrioritySession == session) {
|
||||
mGlobalPrioritySession = null;
|
||||
if (session.isActive() && user != null) {
|
||||
@@ -490,6 +503,20 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasMediaControlPermission(int pid, int uid) {
|
||||
// Check if it's system server or has MEDIA_CONTENT_CONTROL.
|
||||
// Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
|
||||
// check here.
|
||||
if (uid == Process.SYSTEM_UID || mContext.checkPermission(
|
||||
android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
} else if (DEBUG) {
|
||||
Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks if the component is an enabled notification listener for the
|
||||
* specified user. Enabled components may only operate on behalf of the user
|
||||
@@ -544,6 +571,14 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
throw new RuntimeException("Media Session owner died prematurely.", e);
|
||||
}
|
||||
|
||||
final int sessionCount = user.mUidToSessionCount.get(callerUid, 0);
|
||||
if (sessionCount >= SESSION_CREATION_LIMIT_PER_UID
|
||||
&& !hasMediaControlPermission(callerPid, callerUid)) {
|
||||
throw new RuntimeException("Created too many sessions. count="
|
||||
+ sessionCount + ")");
|
||||
}
|
||||
user.mUidToSessionCount.put(callerUid, sessionCount + 1);
|
||||
|
||||
user.mPriorityStack.addSession(session);
|
||||
mHandler.postSessionsChanged(session);
|
||||
|
||||
@@ -723,6 +758,7 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
mOnMediaKeyEventDispatchedListeners = new HashMap<>();
|
||||
private final HashMap<IBinder, OnMediaKeyEventSessionChangedListenerRecord>
|
||||
mOnMediaKeyEventSessionChangedListeners = new HashMap<>();
|
||||
private final SparseIntArray mUidToSessionCount = new SparseIntArray();
|
||||
|
||||
private PendingIntent mLastMediaButtonReceiver;
|
||||
private ComponentName mRestoredMediaButtonReceiver;
|
||||
@@ -1954,20 +1990,6 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
return resolvedUserId;
|
||||
}
|
||||
|
||||
private boolean hasMediaControlPermission(int pid, int uid) {
|
||||
// Check if it's system server or has MEDIA_CONTENT_CONTROL.
|
||||
// Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
|
||||
// check here.
|
||||
if (uid == Process.SYSTEM_UID || mContext.checkPermission(
|
||||
android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
} else if (DEBUG) {
|
||||
Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasEnabledNotificationListener(int resolvedUserId, String packageName)
|
||||
throws RemoteException {
|
||||
// You may not access another user's content as an enabled listener.
|
||||
|
||||
Reference in New Issue
Block a user