Merge "Revisit logging in MediaRouter and MediaSessionRecord"
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 06dd3db..a84cee8 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -176,7 +176,7 @@
         }
 
         void updateAudioRoutes(AudioRoutesInfo newRoutes) {
-            Log.v(TAG, "Updating audio routes: " + newRoutes);
+            boolean updated = false;
             if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
                 mCurAudioRoutesInfo.mainType = newRoutes.mainType;
                 int name;
@@ -192,6 +192,7 @@
                 }
                 sStatic.mDefaultAudioVideo.mNameResId = name;
                 dispatchRouteChanged(sStatic.mDefaultAudioVideo);
+                updated = true;
             }
 
             final int mainType = mCurAudioRoutesInfo.mainType;
@@ -216,17 +217,23 @@
                     removeRouteStatic(sStatic.mBluetoothA2dpRoute);
                     sStatic.mBluetoothA2dpRoute = null;
                 }
+                updated = true;
             }
 
             if (mBluetoothA2dpRoute != null) {
                 final boolean a2dpEnabled = isBluetoothA2dpOn();
                 if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
                     selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
+                    updated = true;
                 } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
                         a2dpEnabled) {
                     selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false);
+                    updated = true;
                 }
             }
+            if (updated) {
+                Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
+            }
         }
 
         boolean isBluetoothA2dpOn() {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 10ecb86..20663a0 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -92,8 +92,8 @@
     private final MediaSessionService mService;
 
     private final Object mLock = new Object();
-    private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
-            new ArrayList<ISessionControllerCallback>();
+    private final ArrayList<ISessionControllerCallbackHolder> mControllerCallbackHolders =
+            new ArrayList<>();
 
     private long mFlags;
     private PendingIntent mMediaButtonReceiver;
@@ -444,7 +444,7 @@
         pw.println(indent + "active=" + mIsActive);
         pw.println(indent + "flags=" + mFlags);
         pw.println(indent + "rating type=" + mRatingType);
-        pw.println(indent + "controllers: " + mControllerCallbacks.size());
+        pw.println(indent + "controllers: " + mControllerCallbackHolders.size());
         pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
         pw.println(indent + "audioAttrs=" + mAudioAttrs);
         pw.println(indent + "volumeType=" + mVolumeType + ", controlType=" + mVolumeControlType
@@ -489,20 +489,28 @@
         return "size=" + fields + ", description=" + description;
     }
 
+    private void logCallbackException(
+            String msg, ISessionControllerCallbackHolder holder, Exception e) {
+        Log.v(TAG, msg + ", this=" + this + ", callback package=" + holder.mPackageName
+                + ", exception=" + e);
+    }
+
     private void pushPlaybackStateUpdate() {
         synchronized (mLock) {
             if (mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onPlaybackStateChanged(mPlaybackState);
+                    holder.mCallback.onPlaybackStateChanged(mPlaybackState);
                 } catch (DeadObjectException e) {
-                    mControllerCallbacks.remove(i);
-                    Log.w(TAG, "Removed dead callback in pushPlaybackStateUpdate.", e);
+                    mControllerCallbackHolders.remove(i);
+                    logCallbackException("Removed dead callback in pushPlaybackStateUpdate",
+                            holder, e);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushPlaybackStateUpdate.", e);
+                    logCallbackException("unexpected exception in pushPlaybackStateUpdate",
+                            holder, e);
                 }
             }
         }
@@ -513,15 +521,15 @@
             if (mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onMetadataChanged(mMetadata);
+                    holder.mCallback.onMetadataChanged(mMetadata);
                 } catch (DeadObjectException e) {
-                    Log.w(TAG, "Removing dead callback in pushMetadataUpdate. ", e);
-                    mControllerCallbacks.remove(i);
+                    logCallbackException("Removing dead callback in pushMetadataUpdate", holder, e);
+                    mControllerCallbackHolders.remove(i);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushMetadataUpdate. ", e);
+                    logCallbackException("unexpected exception in pushMetadataUpdate", holder, e);
                 }
             }
         }
@@ -532,15 +540,15 @@
             if (mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onQueueChanged(mQueue);
+                    holder.mCallback.onQueueChanged(mQueue);
                 } catch (DeadObjectException e) {
-                    mControllerCallbacks.remove(i);
-                    Log.w(TAG, "Removed dead callback in pushQueueUpdate.", e);
+                    mControllerCallbackHolders.remove(i);
+                    logCallbackException("Removed dead callback in pushQueueUpdate", holder, e);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushQueueUpdate.", e);
+                    logCallbackException("unexpected exception in pushQueueUpdate", holder, e);
                 }
             }
         }
@@ -551,15 +559,17 @@
             if (mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onQueueTitleChanged(mQueueTitle);
+                    holder.mCallback.onQueueTitleChanged(mQueueTitle);
                 } catch (DeadObjectException e) {
-                    mControllerCallbacks.remove(i);
-                    Log.w(TAG, "Removed dead callback in pushQueueTitleUpdate.", e);
+                    mControllerCallbackHolders.remove(i);
+                    logCallbackException("Removed dead callback in pushQueueTitleUpdate",
+                            holder, e);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushQueueTitleUpdate.", e);
+                    logCallbackException("unexpected exception in pushQueueTitleUpdate",
+                            holder, e);
                 }
             }
         }
@@ -570,15 +580,15 @@
             if (mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onExtrasChanged(mExtras);
+                    holder.mCallback.onExtrasChanged(mExtras);
                 } catch (DeadObjectException e) {
-                    mControllerCallbacks.remove(i);
-                    Log.w(TAG, "Removed dead callback in pushExtrasUpdate.", e);
+                    mControllerCallbackHolders.remove(i);
+                    logCallbackException("Removed dead callback in pushExtrasUpdate", holder, e);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushExtrasUpdate.", e);
+                    logCallbackException("unexpected exception in pushExtrasUpdate", holder, e);
                 }
             }
         }
@@ -590,14 +600,14 @@
                 return;
             }
             ParcelableVolumeInfo info = mController.getVolumeAttributes();
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onVolumeInfoChanged(info);
+                    holder.mCallback.onVolumeInfoChanged(info);
                 } catch (DeadObjectException e) {
-                    Log.w(TAG, "Removing dead callback in pushVolumeUpdate. ", e);
+                    logCallbackException("Removing dead callback in pushVolumeUpdate", holder, e);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "Unexpected exception in pushVolumeUpdate. ", e);
+                    logCallbackException("Unexpected exception in pushVolumeUpdate", holder, e);
                 }
             }
         }
@@ -608,15 +618,15 @@
             if (mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onEvent(event, data);
+                    holder.mCallback.onEvent(event, data);
                 } catch (DeadObjectException e) {
-                    Log.w(TAG, "Removing dead callback in pushEvent.", e);
-                    mControllerCallbacks.remove(i);
+                    logCallbackException("Removing dead callback in pushEvent", holder, e);
+                    mControllerCallbackHolders.remove(i);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushEvent.", e);
+                    logCallbackException("unexpected exception in pushEvent", holder, e);
                 }
             }
         }
@@ -627,15 +637,16 @@
             if (mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onRepeatModeChanged(mRepeatMode);
+                    holder.mCallback.onRepeatModeChanged(mRepeatMode);
                 } catch (DeadObjectException e) {
-                    mControllerCallbacks.remove(i);
-                    Log.w(TAG, "Removed dead callback in pushRepeatModeUpdate.", e);
+                    mControllerCallbackHolders.remove(i);
+                    logCallbackException("Removed dead callback in pushRepeatModeUpdate",
+                            holder, e);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushRepeatModeUpdate.", e);
+                    logCallbackException("unexpected exception in pushRepeatModeUpdate", holder, e);
                 }
             }
         }
@@ -646,15 +657,17 @@
             if (mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onShuffleModeChanged(mShuffleModeEnabled);
+                    holder.mCallback.onShuffleModeChanged(mShuffleModeEnabled);
                 } catch (DeadObjectException e) {
-                    mControllerCallbacks.remove(i);
-                    Log.w(TAG, "Removed dead callback in pushShuffleModeUpdate.", e);
+                    mControllerCallbackHolders.remove(i);
+                    logCallbackException("Removed dead callback in pushShuffleModeUpdate",
+                            holder, e);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushShuffleModeUpdate.", e);
+                    logCallbackException("unexpected exception in pushShuffleModeUpdate",
+                            holder, e);
                 }
             }
         }
@@ -667,19 +680,19 @@
             if (!mDestroyed) {
                 return;
             }
-            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    cb.onSessionDestroyed();
+                    holder.mCallback.onSessionDestroyed();
                 } catch (DeadObjectException e) {
-                    Log.w(TAG, "Removing dead callback in pushEvent.", e);
-                    mControllerCallbacks.remove(i);
+                    logCallbackException("Removing dead callback in pushEvent", holder, e);
+                    mControllerCallbackHolders.remove(i);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "unexpected exception in pushEvent.", e);
+                    logCallbackException("unexpected exception in pushEvent", holder, e);
                 }
             }
             // After notifying clear all listeners
-            mControllerCallbacks.clear();
+            mControllerCallbackHolders.clear();
         }
     }
 
@@ -717,10 +730,10 @@
         return result == null ? state : result;
     }
 
-    private int getControllerCbIndexForCb(ISessionControllerCallback cb) {
+    private int getControllerHolderIndexForCb(ISessionControllerCallback cb) {
         IBinder binder = cb.asBinder();
-        for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
-            if (binder.equals(mControllerCallbacks.get(i).asBinder())) {
+        for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
+            if (binder.equals(mControllerCallbackHolders.get(i).mCallback.asBinder())) {
                 return i;
             }
         }
@@ -738,22 +751,23 @@
         synchronized (mLock) {
             if (mCallingUid == UID_NOT_SET || mCallingUid != uid) {
                 mCallingUid = uid;
-                mCallingPackage = packageName;
-                if (mCallingPackage != null) {
-                    return;
-                }
-                Context context = mService.getContext();
-                if (context == null) {
-                    return;
-                }
-                String[] packages = context.getPackageManager().getPackagesForUid(uid);
-                if (packages != null && packages.length > 0) {
-                    mCallingPackage = packages[0];
-                }
+                mCallingPackage = packageName != null ? packageName : getPackageName(uid);
             }
         }
     }
 
+    private String getPackageName(int uid) {
+        Context context = mService.getContext();
+        if (context == null) {
+            return null;
+        }
+        String[] packages = context.getPackageManager().getPackagesForUid(uid);
+        if (packages != null && packages.length > 0) {
+            return packages[0];
+        }
+        return null;
+    }
+
     private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
         @Override
         public void run() {
@@ -1199,8 +1213,9 @@
                     }
                     return;
                 }
-                if (getControllerCbIndexForCb(cb) < 0) {
-                    mControllerCallbacks.add(cb);
+                if (getControllerHolderIndexForCb(cb) < 0) {
+                    mControllerCallbackHolders.add(new ISessionControllerCallbackHolder(cb,
+                          Binder.getCallingUid()));
                     if (DEBUG) {
                         Log.d(TAG, "registering controller callback " + cb);
                     }
@@ -1212,9 +1227,9 @@
         public void unregisterCallbackListener(ISessionControllerCallback cb)
                 throws RemoteException {
             synchronized (mLock) {
-                int index = getControllerCbIndexForCb(cb);
+                int index = getControllerHolderIndexForCb(cb);
                 if (index != -1) {
-                    mControllerCallbacks.remove(index);
+                    mControllerCallbackHolders.remove(index);
                 }
                 if (DEBUG) {
                     Log.d(TAG, "unregistering callback " + cb + ". index=" + index);
@@ -1485,6 +1500,16 @@
         }
     }
 
+    private class ISessionControllerCallbackHolder {
+        private final ISessionControllerCallback mCallback;
+        private final String mPackageName;
+
+        ISessionControllerCallbackHolder(ISessionControllerCallback callback, int uid) {
+            mCallback = callback;
+            mPackageName = getPackageName(uid);
+        }
+    }
+
     private class MessageHandler extends Handler {
         private static final int MSG_UPDATE_METADATA = 1;
         private static final int MSG_UPDATE_PLAYBACK_STATE = 2;