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

Commit a2249444 authored by Amy Zhang's avatar Amy Zhang
Browse files

Complete the acquireHardware API implementation in the TvInputHardwareManager

This CL:
1. Finish the logic in TIHM to utilize the TRM for a client priority check.
2. FInish the TRM isHigherPriority API to allow the TIHM to compare the
client priority.
3. Finish the TRM isForeground method to check if a process is
foreground or not.
3. Add unit test for TRM isHigherPriority.

Test: atest com.android.server.tv.tunerresourcemanager
Bug: 155339425
Change-Id: I3887ccad31195d3386f1fc6b3de3e641df91092f
parent df554bb5
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -1805,7 +1805,7 @@ public final class TvInputManager {
            String tvInputSessionId, int priorityHint,
            Executor executor, final HardwareCallback callback) {
        try {
            return new Hardware(
            ITvInputHardware hardware =
                    mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
                @Override
                public void onReleased() {
@@ -1826,7 +1826,11 @@ public final class TvInputManager {
                                Binder.restoreCallingIdentity(identity);
                            }
                }
                    }, info, mUserId, tvInputSessionId, priorityHint));
                    }, info, mUserId, tvInputSessionId, priorityHint);
            if (hardware == null) {
                return null;
            }
            return new Hardware(hardware);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+3 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media.tv.tunerresourcemanager;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -81,7 +82,7 @@ public final class ResourceClientProfile implements Parcelable {
     *                OEM. The id of the useCaseVendor should be passed through this parameter. Any
     *                undefined use case would cause IllegalArgumentException.
     */
    public ResourceClientProfile(@NonNull String tvInputSessionId,
    public ResourceClientProfile(@Nullable String tvInputSessionId,
                                 int useCase) {
        mTvInputSessionId = tvInputSessionId;
        mUseCase = useCase;
@@ -92,7 +93,7 @@ public final class ResourceClientProfile implements Parcelable {
     *
     * @return the value of the tv input session id.
     */
    @NonNull
    @Nullable
    public String getTvInputSessionId() {
        return mTvInputSessionId;
    }
+35 −16
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ import android.media.tv.TvInputHardwareInfo;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputService.PriorityHintUseCaseType;
import android.media.tv.TvStreamConfig;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -179,7 +181,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
                Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId);
                return;
            }
            connection.resetLocked(null, null, null, null, null);
            connection.resetLocked(null, null, null, null, null, null);
            mConnections.remove(deviceId);
            buildHardwareListLocked();
            TvInputHardwareInfo info = connection.getHardwareInfoLocked();
@@ -369,15 +371,24 @@ class TvInputHardwareManager implements TvInputHal.Callback {
        if (callback == null) {
            throw new NullPointerException();
        }
        TunerResourceManager trm = (TunerResourceManager) mContext.getSystemService(
                Context.TV_TUNER_RESOURCE_MGR_SERVICE);
        synchronized (mLock) {
            Connection connection = mConnections.get(deviceId);
            if (connection == null) {
                Slog.e(TAG, "Invalid deviceId : " + deviceId);
                return null;
            }
            // TODO: check with TRM to compare the client's priority with the current holder's
            // priority. If lower, do nothing.
            if (checkUidChangedLocked(connection, callingUid, resolvedUserId)) {

            ResourceClientProfile profile =
                    new ResourceClientProfile(tvInputSessionId, priorityHint);
            ResourceClientProfile holderProfile = connection.getResourceClientProfileLocked();
            if (holderProfile != null && trm != null
                    && !trm.isHigherPriority(profile, holderProfile)) {
                Slog.d(TAG, "Acquiring does not show higher priority than the current holder."
                        + " Device id:" + deviceId);
                return null;
            }
            TvInputHardwareImpl hardware =
                    new TvInputHardwareImpl(connection.getHardwareInfoLocked());
            try {
@@ -386,8 +397,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
                hardware.release();
                return null;
            }
                connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId);
            }
            connection.resetLocked(hardware, callback, info, callingUid, resolvedUserId,
                    profile);
            return connection.getHardwareLocked();
        }
    }
@@ -411,7 +422,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            if (callback != null) {
                callback.asBinder().unlinkToDeath(connection, 0);
            }
            connection.resetLocked(null, null, null, null, null);
            connection.resetLocked(null, null, null, null, null, null);
        }
    }

@@ -621,6 +632,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
        private Integer mCallingUid = null;
        private Integer mResolvedUserId = null;
        private Runnable mOnFirstFrameCaptured;
        private ResourceClientProfile mResourceClientProfile = null;

        public Connection(TvInputHardwareInfo hardwareInfo) {
            mHardwareInfo = hardwareInfo;
@@ -629,7 +641,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
        // *Locked methods assume TvInputHardwareManager.mLock is held.

        public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback,
                TvInputInfo info, Integer callingUid, Integer resolvedUserId) {
                TvInputInfo info, Integer callingUid, Integer resolvedUserId,
                ResourceClientProfile profile) {
            if (mHardware != null) {
                try {
                    mCallback.onReleased();
@@ -644,6 +657,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            mCallingUid = callingUid;
            mResolvedUserId = resolvedUserId;
            mOnFirstFrameCaptured = null;
            mResourceClientProfile = profile;

            if (mHardware != null && mCallback != null) {
                try {
@@ -698,10 +712,14 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            return mOnFirstFrameCaptured;
        }

        public ResourceClientProfile getResourceClientProfileLocked() {
            return mResourceClientProfile;
        }

        @Override
        public void binderDied() {
            synchronized (mLock) {
                resetLocked(null, null, null, null, null);
                resetLocked(null, null, null, null, null, null);
            }
        }

@@ -713,6 +731,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
                    + ", mConfigs: " + Arrays.toString(mConfigs)
                    + ", mCallingUid: " + mCallingUid
                    + ", mResolvedUserId: " + mResolvedUserId
                    + ", mResourceClientProfile: " + mResourceClientProfile
                    + " }";
        }

+60 −14
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.server.tv.tunerresourcemanager;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.media.tv.TvInputManager;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -42,6 +44,7 @@ import com.android.server.SystemService;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@@ -71,7 +74,8 @@ public class TunerResourceManagerService extends SystemService {
    @GuardedBy("mLock")
    private Map<Integer, ResourcesReclaimListenerRecord> mListeners = new HashMap<>();

    private TvInputManager mManager;
    private TvInputManager mTvInputManager;
    private ActivityManager mActivityManager;
    private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();

    // An internal resource request count to help generate resource handle.
@@ -94,7 +98,9 @@ public class TunerResourceManagerService extends SystemService {
        if (!isForTesting) {
            publishBinderService(Context.TV_TUNER_RESOURCE_MGR_SERVICE, new BinderService());
        }
        mManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
        mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
        mActivityManager =
                (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
        mPriorityCongfig.parse();
    }

@@ -362,14 +368,15 @@ public class TunerResourceManagerService extends SystemService {

        @Override
        public boolean isHigherPriority(
                ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile) {
                ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile)
                throws RemoteException {
            enforceTrmAccessPermission("isHigherPriority");
            if (DEBUG) {
                Slog.d(TAG,
                        "isHigherPriority(challengerProfile=" + challengerProfile
                                + ", holderProfile=" + challengerProfile + ")");
            if (challengerProfile == null || holderProfile == null) {
                throw new RemoteException("Client profiles can't be null.");
            }
            synchronized (mLock) {
                return isHigherPriorityInternal(challengerProfile, holderProfile);
            }
            return true;
        }
    }

@@ -381,7 +388,7 @@ public class TunerResourceManagerService extends SystemService {
        }

        clientId[0] = INVALID_CLIENT_ID;
        if (mManager == null) {
        if (mTvInputManager == null) {
            Slog.e(TAG, "TvInputManager is null. Can't register client profile.");
            return;
        }
@@ -390,7 +397,7 @@ public class TunerResourceManagerService extends SystemService {

        int pid = profile.getTvInputSessionId() == null
                ? Binder.getCallingPid() /*callingPid*/
                : mManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/
                : mTvInputManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/

        ClientProfile clientProfile = new ClientProfile.Builder(clientId[0])
                                              .tvInputSessionId(profile.getTvInputSessionId())
@@ -692,6 +699,33 @@ public class TunerResourceManagerService extends SystemService {
        return false;
    }

    @VisibleForTesting
    protected boolean isHigherPriorityInternal(ResourceClientProfile challengerProfile,
            ResourceClientProfile holderProfile) {
        if (DEBUG) {
            Slog.d(TAG,
                    "isHigherPriority(challengerProfile=" + challengerProfile
                            + ", holderProfile=" + challengerProfile + ")");
        }
        if (mTvInputManager == null) {
            Slog.e(TAG, "TvInputManager is null. Can't compare the priority.");
            // Allow the client to acquire the hardware interface
            // when the TRM is not able to compare the priority.
            return true;
        }

        int challengerPid = challengerProfile.getTvInputSessionId() == null
                ? Binder.getCallingPid() /*callingPid*/
                : mTvInputManager.getClientPid(challengerProfile.getTvInputSessionId()); /*tvAppId*/
        int holderPid = holderProfile.getTvInputSessionId() == null
                ? Binder.getCallingPid() /*callingPid*/
                : mTvInputManager.getClientPid(holderProfile.getTvInputSessionId()); /*tvAppId*/

        int challengerPriority = getClientPriority(challengerProfile.getUseCase(), challengerPid);
        int holderPriority = getClientPriority(holderProfile.getUseCase(), holderPid);
        return challengerPriority > holderPriority;
    }

    @VisibleForTesting
    protected void releaseFrontendInternal(FrontendResource fe) {
        if (DEBUG) {
@@ -818,9 +852,21 @@ public class TunerResourceManagerService extends SystemService {

    @VisibleForTesting
    protected boolean isForeground(int pid) {
        // TODO: how to get fg/bg information from pid
        if (mActivityManager == null) {
            return false;
        }
        List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses();
        if (appProcesses == null) {
            return false;
        }
        for (RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.pid == pid
                    && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return true;
            }
        }
        return false;
    }

    private void updateFrontendClientMappingOnNewGrant(int grantingId, int ownerClientId) {
        FrontendResource grantingFrontend = getFrontendResource(grantingId);
@@ -1044,7 +1090,7 @@ public class TunerResourceManagerService extends SystemService {
    }

    private void enforceTrmAccessPermission(String apiName) {
        getContext().enforceCallingPermission("android.permission.TUNER_RESOURCE_ACCESS",
        getContext().enforceCallingOrSelfPermission("android.permission.TUNER_RESOURCE_ACCESS",
                TAG + ": " + apiName);
    }

+25 −1
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ public class TunerResourceManagerServiceTest {
    private Context mContextSpy;
    @Mock private ITvInputManager mITvInputManagerMock;
    private TunerResourceManagerService mTunerResourceManagerService;
    private boolean mIsForeground;

    private static final class TestResourcesReclaimListener extends IResourcesReclaimListener.Stub {
        boolean mReclaimed;
@@ -104,7 +105,12 @@ public class TunerResourceManagerServiceTest {
        TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0);
        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
        when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager);
        mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy);
        mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) {
            @Override
            protected boolean isForeground(int pid) {
                return mIsForeground;
            }
        };
        mTunerResourceManagerService.onStart(true /*isForTesting*/);
    }

@@ -737,4 +743,22 @@ public class TunerResourceManagerServiceTest {
                .isTrue();
        assertThat(mTunerResourceManagerService.getResourceIdFromHandle(desHandle[0])).isEqualTo(0);
    }

    @Test
    public void isHigherPriorityTest() {
        mIsForeground = false;
        ResourceClientProfile backgroundPlaybackProfile =
                new ResourceClientProfile(null /*sessionId*/,
                        TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
        ResourceClientProfile backgroundRecordProfile =
                new ResourceClientProfile(null /*sessionId*/,
                        TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD);
        int backgroundPlaybackPriority = mTunerResourceManagerService.getClientPriority(
                TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 0);
        int backgroundRecordPriority = mTunerResourceManagerService.getClientPriority(
                TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD, 0);
        assertThat(mTunerResourceManagerService.isHigherPriorityInternal(backgroundPlaybackProfile,
                backgroundRecordProfile)).isEqualTo(
                        (backgroundPlaybackPriority > backgroundRecordPriority));
    }
}