From 2fd4aac310787d1a57207b5142a0ab08d5e1a2a5 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 21 Nov 2022 09:31:15 +0000 Subject: [PATCH] Do not require package visibility when connecting to a Media3 session When we currently call SessionToken.createSessionToken with a legacy token, we call the package manager to get the process UID. This requires visiblity to the target package, which may not be available unless the target runs a service known to the controller app. However, when connecting to a Media3, this UID doesn't have to be known, so we can move the call closer to where it's needed to avoid the unncessary visibility check. In addition, a legacy session may reply with unknown result code to the session token request, which we should handle as well. One of the constructor can be removed since it was only used from a test. PiperOrigin-RevId: 489917706 --- .../androidx/media3/session/SessionToken.java | 59 +++++++++---------- ...CompatCallbackWithMediaControllerTest.java | 3 +- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/libraries/session/src/main/java/androidx/media3/session/SessionToken.java b/libraries/session/src/main/java/androidx/media3/session/SessionToken.java index 5b0e76b817..e9eba03445 100644 --- a/libraries/session/src/main/java/androidx/media3/session/SessionToken.java +++ b/libraries/session/src/main/java/androidx/media3/session/SessionToken.java @@ -130,6 +130,7 @@ public final class SessionToken implements Bundleable { } } + /** Creates a session token connected to a Media3 session. */ /* package */ SessionToken( int uid, int type, @@ -143,21 +144,9 @@ public final class SessionToken implements Bundleable { uid, type, libraryVersion, interfaceVersion, packageName, iSession, tokenExtras); } - /* package */ SessionToken(Context context, MediaSessionCompat.Token compatToken) { - checkNotNull(context, "context must not be null"); - checkNotNull(compatToken, "compatToken must not be null"); - - MediaControllerCompat controller = createMediaControllerCompat(context, compatToken); - - String packageName = controller.getPackageName(); - int uid = getUid(context.getPackageManager(), packageName); - Bundle extras = controller.getSessionInfo(); - - impl = new SessionTokenImplLegacy(compatToken, packageName, uid, extras); - } - - /* package */ SessionToken(SessionTokenImpl impl) { - this.impl = impl; + /** Creates a session token connected to a legacy media session. */ + private SessionToken(MediaSessionCompat.Token token, String packageName, int uid, Bundle extras) { + this.impl = new SessionTokenImplLegacy(token, packageName, uid, extras); } private SessionToken(Bundle bundle) { @@ -283,32 +272,37 @@ public final class SessionToken implements Bundleable { MediaControllerCompat controller = createMediaControllerCompat(context, (MediaSessionCompat.Token) compatToken); String packageName = controller.getPackageName(); - int uid = getUid(context.getPackageManager(), packageName); Handler handler = new Handler(thread.getLooper()); + Runnable createFallbackLegacyToken = + () -> { + int uid = getUid(context.getPackageManager(), packageName); + SessionToken resultToken = + new SessionToken( + (MediaSessionCompat.Token) compatToken, + packageName, + uid, + controller.getSessionInfo()); + future.set(resultToken); + }; controller.sendCommand( MediaConstants.SESSION_COMMAND_REQUEST_SESSION3_TOKEN, /* params= */ null, new ResultReceiver(handler) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { + // Remove timeout callback. handler.removeCallbacksAndMessages(null); - future.set(SessionToken.CREATOR.fromBundle(resultData)); + try { + future.set(SessionToken.CREATOR.fromBundle(resultData)); + } catch (RuntimeException e) { + // Fallback to a legacy token if we receive an unexpected result, e.g. a legacy + // session acknowledging commands by a success callback. + createFallbackLegacyToken.run(); + } } }); - - handler.postDelayed( - () -> { - // Timed out getting session3 token. Handle this as a legacy token. - SessionToken resultToken = - new SessionToken( - new SessionTokenImplLegacy( - (MediaSessionCompat.Token) compatToken, - packageName, - uid, - controller.getSessionInfo())); - future.set(resultToken); - }, - WAIT_TIME_MS_FOR_SESSION3_TOKEN); + // Post creating a fallback token if the command receives no result after a timeout. + handler.postDelayed(createFallbackLegacyToken, WAIT_TIME_MS_FOR_SESSION3_TOKEN); future.addListener(() -> thread.quit(), MoreExecutors.directExecutor()); return future; } @@ -399,7 +393,8 @@ public final class SessionToken implements Bundleable { try { return manager.getApplicationInfo(packageName, 0).uid; } catch (PackageManager.NameNotFoundException e) { - throw new IllegalArgumentException("Cannot find package " + packageName, e); + throw new IllegalArgumentException( + "Cannot find package " + packageName + " or package is not visible", e); } } diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCompatCallbackWithMediaControllerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCompatCallbackWithMediaControllerTest.java index ca25291cf4..45ee44b3af 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCompatCallbackWithMediaControllerTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCompatCallbackWithMediaControllerTest.java @@ -112,7 +112,8 @@ public class MediaSessionCompatCallbackWithMediaControllerTest { } private RemoteMediaController createControllerAndWaitConnection() throws Exception { - SessionToken sessionToken = new SessionToken(context, session.getSessionToken()); + SessionToken sessionToken = + SessionToken.createSessionToken(context, session.getSessionToken()).get(); return controllerTestRule.createRemoteController(sessionToken); }