diff options
| -rw-r--r-- | services/core/java/com/android/server/media/MediaSessionRecord.java | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 4822d6a62ac7..b482d1869c66 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -62,6 +62,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.NoSuchElementException; /** * This is the system implementation of a Session. Apps will interact with the @@ -792,7 +793,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { try { + holder.mCallback.asBinder().unlinkToDeath(holder.mDeathMonitor, 0); holder.mCallback.onSessionDestroyed(); + } catch (NoSuchElementException e) { + logCallbackException("error unlinking to binder death", holder, e); } catch (DeadObjectException e) { logCallbackException("Removing dead callback in pushSessionDestroyed", holder, e); } catch (RemoteException e) { @@ -1375,12 +1379,22 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR return; } if (getControllerHolderIndexForCb(cb) < 0) { - mControllerCallbackHolders.add(new ISessionControllerCallbackHolder(cb, - packageName, Binder.getCallingUid())); + ISessionControllerCallbackHolder holder = new ISessionControllerCallbackHolder( + cb, packageName, Binder.getCallingUid(), () -> unregisterCallback(cb)); + mControllerCallbackHolders.add(holder); if (DEBUG) { Log.d(TAG, "registering controller callback " + cb + " from controller" + packageName); } + // Avoid callback leaks + try { + // cb is not referenced outside of the MediaSessionRecord, so the death + // handler won't prevent MediaSessionRecord to be garbage collected. + cb.asBinder().linkToDeath(holder.mDeathMonitor, 0); + } catch (RemoteException e) { + unregisterCallback(cb); + Log.w(TAG, "registerCallback failed to linkToDeath", e); + } } } } @@ -1390,6 +1404,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR synchronized (mLock) { int index = getControllerHolderIndexForCb(cb); if (index != -1) { + try { + cb.asBinder().unlinkToDeath( + mControllerCallbackHolders.get(index).mDeathMonitor, 0); + } catch (NoSuchElementException e) { + Log.w(TAG, "error unlinking to binder death", e); + } mControllerCallbackHolders.remove(index); } if (DEBUG) { @@ -1600,12 +1620,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR private final ISessionControllerCallback mCallback; private final String mPackageName; private final int mUid; + private final IBinder.DeathRecipient mDeathMonitor; ISessionControllerCallbackHolder(ISessionControllerCallback callback, String packageName, - int uid) { + int uid, IBinder.DeathRecipient deathMonitor) { mCallback = callback; mPackageName = packageName; mUid = uid; + mDeathMonitor = deathMonitor; } } |