Remove sessions listeners that are disabled

Removes sessions listeners when their notification listener is
disabled. Also updates the dump for media sessions.

bug:15549450

Change-Id: Ibe51a4a42ef333e75a09f0fffa0f2b9b8939b85c
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 92644ce..277344e 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.database.ContentObserver;
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.media.IRemoteVolumeController;
@@ -37,6 +38,7 @@
 import android.media.session.ISessionCallback;
 import android.media.session.ISessionManager;
 import android.media.session.MediaSession;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -86,6 +88,7 @@
     private KeyguardManager mKeyguardManager;
     private IAudioService mAudioService;
     private ContentResolver mContentResolver;
+    private SettingsObserver mSettingsObserver;
 
     private MediaSessionRecord mPrioritySession;
     private int mCurrentUserId = -1;
@@ -111,6 +114,8 @@
                 (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
         mAudioService = getAudioService();
         mContentResolver = getContext().getContentResolver();
+        mSettingsObserver = new SettingsObserver();
+        mSettingsObserver.observe();
     }
 
     private IAudioService getAudioService() {
@@ -229,6 +234,28 @@
         }
     }
 
+    private void updateActiveSessionListeners() {
+        synchronized (mLock) {
+            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+                SessionsListenerRecord listener = mSessionsListeners.get(i);
+                try {
+                    enforceMediaPermissions(listener.mComponentName, listener.mPid, listener.mUid,
+                            listener.mUserId);
+                } catch (SecurityException e) {
+                    Log.i(TAG, "ActiveSessionsListener " + listener.mComponentName
+                            + " is no longer authorized. Disconnecting.");
+                    mSessionsListeners.remove(i);
+                    try {
+                        listener.mListener
+                                .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
+                    } catch (Exception e1) {
+                        // ignore
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Stop the user and unbind from everything.
      *
@@ -525,11 +552,19 @@
 
     final class SessionsListenerRecord implements IBinder.DeathRecipient {
         private final IActiveSessionsListener mListener;
+        private final ComponentName mComponentName;
         private final int mUserId;
+        private final int mPid;
+        private final int mUid;
 
-        public SessionsListenerRecord(IActiveSessionsListener listener, int userId) {
+        public SessionsListenerRecord(IActiveSessionsListener listener,
+                ComponentName componentName,
+                int userId, int pid, int uid) {
             mListener = listener;
+            mComponentName = componentName;
             mUserId = userId;
+            mPid = pid;
+            mUid = uid;
         }
 
         @Override
@@ -540,6 +575,25 @@
         }
     }
 
+    final class SettingsObserver extends ContentObserver {
+        private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+        private SettingsObserver() {
+            super(null);
+        }
+
+        private void observe() {
+            mContentResolver.registerContentObserver(mSecureSettingsUri,
+                    false, this, UserHandle.USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateActiveSessionListeners();
+        }
+    }
+
     class SessionManagerImpl extends ISessionManager.Stub {
         private static final String EXTRA_WAKELOCK_ACQUIRED =
                 "android.media.AudioService.WAKELOCK_ACQUIRED";
@@ -607,7 +661,7 @@
                         return;
                     }
                     SessionsListenerRecord record = new SessionsListenerRecord(listener,
-                            resolvedUserId);
+                            componentName, resolvedUserId, pid, uid);
                     try {
                         listener.asBinder().linkToDeath(record, 0);
                     } catch (RemoteException e) {