Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ddc2096 authored by Jaewan Kim's avatar Jaewan Kim
Browse files

MediaSession2: Fix bug in SessionToken2 constructor

There's a bug in SessionToken2 constructor that session service is
misunderstood as library service. It's because
PackageManager.resolveService(Intent, int) ignores action in the intent
if the class name is specified, and there's no way for getting the
action from the ResolvedInfo.

Use PackageManager.queryIntentServices(Intent, int) instead to query
services with the action.

Also added tests and fixed ID mismatch issue in test service.

Test: Run all MediaComponents tests once
Change-Id: I5df2f36eae8100be268629881122f47e44eb41d1
parent 31832c60
Loading
Loading
Loading
Loading
+39 −15
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import android.os.Bundle;
import android.os.IBinder;
import android.text.TextUtils;

import java.util.List;

public class SessionToken2Impl implements SessionToken2Provider {
    private static final String KEY_UID = "android.media.token.uid";
    private static final String KEY_TYPE = "android.media.token.type";
@@ -73,25 +75,24 @@ public class SessionToken2Impl implements SessionToken2Provider {
            }
        }
        mUid = uid;
        // calculate id and type
        Intent serviceIntent = new Intent(MediaLibraryService2.SERVICE_INTERFACE);
        serviceIntent.setClassName(packageName, serviceName);
        String id = getSessionId(manager.resolveService(serviceIntent,
                PackageManager.GET_META_DATA));
        int type = TYPE_LIBRARY_SERVICE;
        if (id == null) {

        // Infer id and type from package name and service name
        // TODO(jaewan): Handle multi-user.
        String id = getSessionIdFromService(manager, MediaLibraryService2.SERVICE_INTERFACE,
                packageName, serviceName);
        if (id != null) {
            mId = id;
            mType = TYPE_LIBRARY_SERVICE;
        } else {
            // retry with session service
            serviceIntent.setClassName(packageName, serviceName);
            id = getSessionId(manager.resolveService(serviceIntent,
                    PackageManager.GET_META_DATA));
            type = TYPE_SESSION_SERVICE;
            mId = getSessionIdFromService(manager, MediaSessionService2.SERVICE_INTERFACE,
                    packageName, serviceName);
            mType = TYPE_SESSION_SERVICE;
        }
        if (id == null) {
        if (mId == null) {
            throw new IllegalArgumentException("service " + serviceName + " doesn't implement"
                    + " session service nor library service");
                    + " session service nor library service. Use service's full name.");
        }
        mId = id;
        mType = type;
        mPackageName = packageName;
        mServiceName = serviceName;
        mSessionBinder = null;
@@ -109,6 +110,29 @@ public class SessionToken2Impl implements SessionToken2Provider {
        mInstance = new SessionToken2(this);
    }

    private static String getSessionIdFromService(PackageManager manager, String serviceInterface,
            String packageName, String serviceName) {
        Intent serviceIntent = new Intent(serviceInterface);
        serviceIntent.setPackage(packageName);
        // Use queryIntentServices to find services with MediaLibraryService2.SERVICE_INTERFACE.
        // We cannot use resolveService with intent specified class name, because resolveService
        // ignores actions if Intent.setClassName() is specified.
        List<ResolveInfo> list = manager.queryIntentServices(
                serviceIntent, PackageManager.GET_META_DATA);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                ResolveInfo resolveInfo = list.get(i);
                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
                    continue;
                }
                if (TextUtils.equals(resolveInfo.serviceInfo.name, serviceName)) {
                    return getSessionId(resolveInfo);
                }
            }
        }
        return null;
    }

    public static String getSessionId(ResolveInfo resolveInfo) {
        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
            return null;
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@
            <intent-filter>
                <action android:name="android.media.MediaLibraryService2" />
            </intent-filter>
            <meta-data android:name="android.media.session" android:value="TestBrowser" />
            <meta-data android:name="android.media.session" android:value="TestLibrary" />
        </service>
    </application>

+63 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import static junit.framework.Assert.assertEquals;

import android.content.Context;
import android.os.Process;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.InstrumentationRegistry;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Tests {@link SessionToken2}.
 */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SessionToken2Test {
    private Context mContext;

    @Before
    public void setUp() throws Exception {
        mContext = InstrumentationRegistry.getTargetContext();
    }

    @Test
    public void testConstructor_sessionService() {
        SessionToken2 token = new SessionToken2(mContext, mContext.getPackageName(),
                MockMediaSessionService2.class.getCanonicalName());
        assertEquals(MockMediaSessionService2.ID, token.getId());
        assertEquals(mContext.getPackageName(), token.getPackageName());
        assertEquals(Process.myUid(), token.getUid());
        assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
    }

    @Test
    public void testConstructor_libraryService() {
        SessionToken2 token = new SessionToken2(mContext, mContext.getPackageName(),
                MockMediaLibraryService2.class.getCanonicalName());
        assertEquals(MockMediaLibraryService2.ID, token.getId());
        assertEquals(mContext.getPackageName(), token.getPackageName());
        assertEquals(Process.myUid(), token.getUid());
        assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, token.getType());
    }
}
 No newline at end of file