Merge "[Bugfix][Media] Fix ISessionControllerCallback leaks in the system_server when the far side died"
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 4822d6a..b482d18 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.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 @@
}
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 @@
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 @@
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 @@
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;
}
}