[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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user