[Bugfix][Media] Fix ISessionControllerCallback leaks in the system_server when the far side died

When the far side died unexpectedly, it will not call unregisterCallback, resulting in callbacks leak in system_server. Eventually, the system_server will reboot because of too many BinderProxies leaks.

Test: manual

Change-Id: I1d99ea35b8bbbb92db648bbf68c267dce435110c
This commit is contained in:
xi yu
2022-02-09 02:53:57 +00:00
parent ff46fea55c
commit 918eb4f031

View File

@@ -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;
}
}