mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Fix leaks of media session service.
References to the service are kept from MediaSessionStub and from a long-delayed Handler messages in ConnectionTimeoutHandler. Remove strong references from these places by making the timeout handler static and ensuring ConnectedControllersManager only keeps a weak reference to the service (as it's part of MediaSessionStub). Issue: androidx/media#346 PiperOrigin-RevId: 527543396
This commit is contained in:
parent
e2bae0c50d
commit
8c262d6c07
@ -66,6 +66,9 @@
|
||||
`handlePlayPauseButtonAction` to write custom UI elements with a
|
||||
play/pause button.
|
||||
|
||||
* Fix memory leak of `MediaSessionService` or `MediaLibraryService`
|
||||
([#346](https://github.com/androidx/media/issues/346)).
|
||||
|
||||
* Audio:
|
||||
|
||||
* Fix bug where some playbacks fail when tunneling is enabled and
|
||||
|
@ -26,6 +26,7 @@ import androidx.media3.session.MediaSession.ControllerInfo;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@ -62,14 +63,14 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
private final ArrayMap<ControllerInfo, ConnectedControllerRecord<T>> controllerRecords =
|
||||
new ArrayMap<>();
|
||||
|
||||
private final MediaSessionImpl sessionImpl;
|
||||
private final WeakReference<MediaSessionImpl> sessionImpl;
|
||||
|
||||
public ConnectedControllersManager(MediaSessionImpl session) {
|
||||
// Initialize default values.
|
||||
lock = new Object();
|
||||
|
||||
// Initialize members with params.
|
||||
sessionImpl = session;
|
||||
sessionImpl = new WeakReference<>(session);
|
||||
}
|
||||
|
||||
public void addController(
|
||||
@ -136,6 +137,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
}
|
||||
|
||||
record.sequencedFutureManager.release();
|
||||
@Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
|
||||
if (sessionImpl == null || sessionImpl.isReleased()) {
|
||||
return;
|
||||
}
|
||||
postOrRun(
|
||||
sessionImpl.getApplicationHandler(),
|
||||
() -> {
|
||||
@ -214,8 +219,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
synchronized (lock) {
|
||||
info = controllerRecords.get(controllerInfo);
|
||||
}
|
||||
@Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
|
||||
return info != null
|
||||
&& info.playerCommands.contains(commandCode)
|
||||
&& sessionImpl != null
|
||||
&& sessionImpl.getPlayerWrapper().getAvailableCommands().contains(commandCode);
|
||||
}
|
||||
|
||||
@ -248,6 +255,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@GuardedBy("lock")
|
||||
private void flushCommandQueue(ConnectedControllerRecord<T> info) {
|
||||
@Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
|
||||
if (sessionImpl == null) {
|
||||
return;
|
||||
}
|
||||
AtomicBoolean continueRunning = new AtomicBoolean(true);
|
||||
while (continueRunning.get()) {
|
||||
continueRunning.set(false);
|
||||
|
@ -145,12 +145,13 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
appPackageName = context.getPackageName();
|
||||
sessionManager = MediaSessionManager.getSessionManager(context);
|
||||
controllerLegacyCbForBroadcast = new ControllerLegacyCbForBroadcast();
|
||||
connectionTimeoutHandler =
|
||||
new ConnectionTimeoutHandler(session.getApplicationHandler().getLooper());
|
||||
mediaPlayPauseKeyHandler =
|
||||
new MediaPlayPauseKeyHandler(session.getApplicationHandler().getLooper());
|
||||
connectedControllersManager = new ConnectedControllersManager<>(session);
|
||||
connectionTimeoutMs = DEFAULT_CONNECTION_TIMEOUT_MS;
|
||||
connectionTimeoutHandler =
|
||||
new ConnectionTimeoutHandler(
|
||||
session.getApplicationHandler().getLooper(), connectedControllersManager);
|
||||
|
||||
// Select a media button receiver component.
|
||||
ComponentName receiverComponentName = queryPackageManagerForMediaButtonReceiver(context);
|
||||
@ -1359,12 +1360,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
}
|
||||
}
|
||||
|
||||
private class ConnectionTimeoutHandler extends Handler {
|
||||
private static class ConnectionTimeoutHandler extends Handler {
|
||||
|
||||
private static final int MSG_CONNECTION_TIMED_OUT = 1001;
|
||||
|
||||
public ConnectionTimeoutHandler(Looper looper) {
|
||||
private final ConnectedControllersManager<RemoteUserInfo> connectedControllersManager;
|
||||
|
||||
public ConnectionTimeoutHandler(
|
||||
Looper looper, ConnectedControllersManager<RemoteUserInfo> connectedControllersManager) {
|
||||
super(looper);
|
||||
this.connectedControllersManager = connectedControllersManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user