mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00: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
(cherry picked from commit 8c262d6c07)
This commit is contained in:
parent
3406334ee8
commit
40ef64ac3a
3 changed files with 24 additions and 6 deletions
|
|
@ -20,6 +20,8 @@
|
||||||
a call from System UI to `Callback.onGetLibraryRoot` with
|
a call from System UI to `Callback.onGetLibraryRoot` with
|
||||||
`params.isRecent == true` on API 30
|
`params.isRecent == true` on API 30
|
||||||
([#355](https://github.com/androidx/media/issues/355)).
|
([#355](https://github.com/androidx/media/issues/355)).
|
||||||
|
* Fix memory leak of `MediaSessionService` or `MediaLibraryService`
|
||||||
|
([#346](https://github.com/androidx/media/issues/346)).
|
||||||
|
|
||||||
### 1.0.1 (2023-04-18)
|
### 1.0.1 (2023-04-18)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import androidx.media3.session.MediaSession.ControllerInfo;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
@ -62,14 +63,14 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
private final ArrayMap<ControllerInfo, ConnectedControllerRecord<T>> controllerRecords =
|
private final ArrayMap<ControllerInfo, ConnectedControllerRecord<T>> controllerRecords =
|
||||||
new ArrayMap<>();
|
new ArrayMap<>();
|
||||||
|
|
||||||
private final MediaSessionImpl sessionImpl;
|
private final WeakReference<MediaSessionImpl> sessionImpl;
|
||||||
|
|
||||||
public ConnectedControllersManager(MediaSessionImpl session) {
|
public ConnectedControllersManager(MediaSessionImpl session) {
|
||||||
// Initialize default values.
|
// Initialize default values.
|
||||||
lock = new Object();
|
lock = new Object();
|
||||||
|
|
||||||
// Initialize members with params.
|
// Initialize members with params.
|
||||||
sessionImpl = session;
|
sessionImpl = new WeakReference<>(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addController(
|
public void addController(
|
||||||
|
|
@ -136,6 +137,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
record.sequencedFutureManager.release();
|
record.sequencedFutureManager.release();
|
||||||
|
@Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
|
||||||
|
if (sessionImpl == null || sessionImpl.isReleased()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
postOrRun(
|
postOrRun(
|
||||||
sessionImpl.getApplicationHandler(),
|
sessionImpl.getApplicationHandler(),
|
||||||
() -> {
|
() -> {
|
||||||
|
|
@ -214,8 +219,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
info = controllerRecords.get(controllerInfo);
|
info = controllerRecords.get(controllerInfo);
|
||||||
}
|
}
|
||||||
|
@Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
|
||||||
return info != null
|
return info != null
|
||||||
&& info.playerCommands.contains(commandCode)
|
&& info.playerCommands.contains(commandCode)
|
||||||
|
&& sessionImpl != null
|
||||||
&& sessionImpl.getPlayerWrapper().getAvailableCommands().contains(commandCode);
|
&& sessionImpl.getPlayerWrapper().getAvailableCommands().contains(commandCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,6 +255,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private void flushCommandQueue(ConnectedControllerRecord<T> info) {
|
private void flushCommandQueue(ConnectedControllerRecord<T> info) {
|
||||||
|
@Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
|
||||||
|
if (sessionImpl == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
AtomicBoolean continueRunning = new AtomicBoolean(true);
|
AtomicBoolean continueRunning = new AtomicBoolean(true);
|
||||||
while (continueRunning.get()) {
|
while (continueRunning.get()) {
|
||||||
continueRunning.set(false);
|
continueRunning.set(false);
|
||||||
|
|
|
||||||
|
|
@ -147,12 +147,13 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
appPackageName = context.getPackageName();
|
appPackageName = context.getPackageName();
|
||||||
sessionManager = MediaSessionManager.getSessionManager(context);
|
sessionManager = MediaSessionManager.getSessionManager(context);
|
||||||
controllerLegacyCbForBroadcast = new ControllerLegacyCbForBroadcast();
|
controllerLegacyCbForBroadcast = new ControllerLegacyCbForBroadcast();
|
||||||
connectionTimeoutHandler =
|
|
||||||
new ConnectionTimeoutHandler(session.getApplicationHandler().getLooper());
|
|
||||||
mediaPlayPauseKeyHandler =
|
mediaPlayPauseKeyHandler =
|
||||||
new MediaPlayPauseKeyHandler(session.getApplicationHandler().getLooper());
|
new MediaPlayPauseKeyHandler(session.getApplicationHandler().getLooper());
|
||||||
connectedControllersManager = new ConnectedControllersManager<>(session);
|
connectedControllersManager = new ConnectedControllersManager<>(session);
|
||||||
connectionTimeoutMs = DEFAULT_CONNECTION_TIMEOUT_MS;
|
connectionTimeoutMs = DEFAULT_CONNECTION_TIMEOUT_MS;
|
||||||
|
connectionTimeoutHandler =
|
||||||
|
new ConnectionTimeoutHandler(
|
||||||
|
session.getApplicationHandler().getLooper(), connectedControllersManager);
|
||||||
|
|
||||||
// Select a media button receiver component.
|
// Select a media button receiver component.
|
||||||
ComponentName receiverComponentName = queryPackageManagerForMediaButtonReceiver(context);
|
ComponentName receiverComponentName = queryPackageManagerForMediaButtonReceiver(context);
|
||||||
|
|
@ -1372,12 +1373,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;
|
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);
|
super(looper);
|
||||||
|
this.connectedControllersManager = connectedControllersManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue