Fix missing notification of session service release

PiperOrigin-RevId: 422352302
This commit is contained in:
jaewan 2022-01-17 14:23:48 +00:00 committed by Ian Baker
parent 3cfd24a912
commit 9f2f33657f

View File

@ -45,8 +45,11 @@ import androidx.media3.common.util.Log;
import androidx.media3.session.MediaSession.ControllerInfo; import androidx.media3.session.MediaSession.ControllerInfo;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Superclass to be extended by services hosting {@link MediaSession media sessions}. * Superclass to be extended by services hosting {@link MediaSession media sessions}.
@ -417,30 +420,42 @@ public abstract class MediaSessionService extends Service {
private final WeakReference<MediaSessionService> serviceReference; private final WeakReference<MediaSessionService> serviceReference;
private final Handler handler; private final Handler handler;
private final MediaSessionManager mediaSessionManager; private final MediaSessionManager mediaSessionManager;
private final Set<IMediaController> pendingControllers;
public MediaSessionServiceStub(MediaSessionService serviceReference) { public MediaSessionServiceStub(MediaSessionService serviceReference) {
this.serviceReference = new WeakReference<>(serviceReference); this.serviceReference = new WeakReference<>(serviceReference);
Context context = serviceReference.getApplicationContext(); Context context = serviceReference.getApplicationContext();
handler = new Handler(context.getMainLooper()); handler = new Handler(context.getMainLooper());
mediaSessionManager = MediaSessionManager.getSessionManager(context); mediaSessionManager = MediaSessionManager.getSessionManager(context);
pendingControllers = Collections.newSetFromMap(new ConcurrentHashMap<>());
} }
@Override @Override
public void connect( public void connect(
@Nullable IMediaController caller, @Nullable Bundle connectionRequestBundle) { @Nullable IMediaController caller, @Nullable Bundle connectionRequestBundle) {
if (caller == null || connectionRequestBundle == null) { if (caller == null || connectionRequestBundle == null) {
return; // Malformed call from potentially malicious controller.
} // No need to notify that we're ignoring call.
if (serviceReference.get() == null) {
return; return;
} }
ConnectionRequest request; ConnectionRequest request;
try { try {
request = ConnectionRequest.CREATOR.fromBundle(connectionRequestBundle); request = ConnectionRequest.CREATOR.fromBundle(connectionRequestBundle);
} catch (RuntimeException e) { } catch (RuntimeException e) {
// Malformed call from potentially malicious controller.
// No need to notify that we're ignoring call.
Log.w(TAG, "Ignoring malformed Bundle for ConnectionRequest", e); Log.w(TAG, "Ignoring malformed Bundle for ConnectionRequest", e);
return; return;
} }
if (serviceReference.get() == null) {
try {
caller.onDisconnected(/* seq= */ 0);
} catch (RemoteException e) {
// Controller may be died prematurely.
// Not an issue because we'll ignore it anyway.
}
return;
}
int callingPid = Binder.getCallingPid(); int callingPid = Binder.getCallingPid();
int uid = Binder.getCallingUid(); int uid = Binder.getCallingUid();
long token = Binder.clearCallingIdentity(); long token = Binder.clearCallingIdentity();
@ -448,19 +463,17 @@ public abstract class MediaSessionService extends Service {
MediaSessionManager.RemoteUserInfo remoteUserInfo = MediaSessionManager.RemoteUserInfo remoteUserInfo =
new MediaSessionManager.RemoteUserInfo(request.packageName, pid, uid); new MediaSessionManager.RemoteUserInfo(request.packageName, pid, uid);
boolean isTrusted = mediaSessionManager.isTrustedForMediaControl(remoteUserInfo); boolean isTrusted = mediaSessionManager.isTrustedForMediaControl(remoteUserInfo);
pendingControllers.add(caller);
try { try {
handler.post( handler.post(
() -> { () -> {
pendingControllers.remove(caller);
boolean shouldNotifyDisconnected = true; boolean shouldNotifyDisconnected = true;
try { try {
@Nullable MediaSessionService service = serviceReference.get(); @Nullable MediaSessionService service = serviceReference.get();
if (service == null) { if (service == null) {
return; return;
} }
if (service == null) {
return;
}
ControllerInfo controllerInfo = ControllerInfo controllerInfo =
new ControllerInfo( new ControllerInfo(
remoteUserInfo, remoteUserInfo,
@ -510,6 +523,13 @@ public abstract class MediaSessionService extends Service {
public void release() { public void release() {
serviceReference.clear(); serviceReference.clear();
handler.removeCallbacksAndMessages(null); handler.removeCallbacksAndMessages(null);
for (IMediaController controller : pendingControllers) {
try {
controller.onDisconnected(/* seq= */ 0);
} catch (RemoteException e) {
// Ignore. We're releasing.
}
}
} }
} }
} }