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

Commit f1145b8e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use Tuner Resource Manager to get resource permission"

parents f2392c6f 5cba7b11
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -25094,7 +25094,7 @@ package android.media {
  public final class MediaCas implements java.lang.AutoCloseable {
    ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
    ctor public MediaCas(int, @Nullable String, int) throws android.media.MediaCasException.UnsupportedCasException;
    ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int) throws android.media.MediaCasException.UnsupportedCasException;
    method public void close();
    method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
    method protected void finalize();
+112 −12
Original line number Diff line number Diff line
@@ -19,14 +19,20 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
import android.hardware.cas.V1_0.ICas;
import android.hardware.cas.V1_0.IMediaCasService;
import android.hardware.cas.V1_2.ICasListener;
import android.hardware.cas.V1_2.Status;
import android.media.MediaCasException.*;
import android.media.tv.TvInputService.PriorityHintUseCaseType;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IHwBinder;
import android.os.Looper;
@@ -39,6 +45,9 @@ import android.util.Singleton;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * MediaCas can be used to obtain keys for descrambling protected media streams, in
@@ -110,6 +119,10 @@ public final class MediaCas implements AutoCloseable {
    private EventHandler mEventHandler;
    private @PriorityHintUseCaseType int mPriorityHint;
    private String mTvInputServiceSessionId;
    private int mClientId;
    private int mCasSystemId;
    private TunerResourceManager mTunerResourceManager = null;
    private final Map<Session, Integer> mSessionMap = new HashMap<>();

    /**
     * Scrambling modes used to open cas sessions.
@@ -329,6 +342,10 @@ public final class MediaCas implements AutoCloseable {
                        createFromSessionId(sessionId), msg.arg1, msg.arg2,
                        bundle.getByteArray(DATA_KEY));
            } else if (msg.what == MSG_CAS_STATUS_EVENT) {
                if ((msg.arg1 == PLUGIN_STATUS_SESSION_NUMBER_CHANGED)
                        && (mTunerResourceManager != null)) {
                    mTunerResourceManager.updateCasInfo(mCasSystemId, msg.arg2);
                }
                mListener.onPluginStatusUpdate(MediaCas.this, msg.arg1, msg.arg2);
            } else if (msg.what == MSG_CAS_RESOURCE_LOST) {
                mListener.onResourceLost(MediaCas.this);
@@ -364,6 +381,19 @@ public final class MediaCas implements AutoCloseable {
                    EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
        }
    };

    private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
            new TunerResourceManager.ResourcesReclaimListener() {
            @Override
            public void onReclaimResources() {
                synchronized (mSessionMap) {
                    mSessionMap.forEach((casSession, sessionResourceId) -> casSession.close());
                }
                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                        EventHandler.MSG_CAS_RESOURCE_LOST));
            }
        };

    /**
     * Describe a CAS plugin with its CA_system_ID and string name.
     *
@@ -429,11 +459,21 @@ public final class MediaCas implements AutoCloseable {
     */
    public final class Session implements AutoCloseable {
        final ArrayList<Byte> mSessionId;
        boolean mIsClosed = false;

        Session(@NonNull ArrayList<Byte> sessionId) {
            mSessionId = new ArrayList<Byte>(sessionId);
        }

        private void validateSessionInternalStates() {
            if (mICas == null) {
                throw new IllegalStateException();
            }
            if (mIsClosed) {
                MediaCasStateException.throwExceptionIfNeeded(Status.ERROR_CAS_SESSION_NOT_OPENED);
            }
        }

        /**
         * Query if an object equal current Session object.
         *
@@ -459,7 +499,7 @@ public final class MediaCas implements AutoCloseable {
         */
        public void setPrivateData(@NonNull byte[] data)
                throws MediaCasException {
            validateInternalStates();
            validateSessionInternalStates();

            try {
                MediaCasException.throwExceptionIfNeeded(
@@ -483,7 +523,7 @@ public final class MediaCas implements AutoCloseable {
         */
        public void processEcm(@NonNull byte[] data, int offset, int length)
                throws MediaCasException {
            validateInternalStates();
            validateSessionInternalStates();

            try {
                MediaCasException.throwExceptionIfNeeded(
@@ -522,7 +562,7 @@ public final class MediaCas implements AutoCloseable {
         */
        public void sendSessionEvent(int event, int arg, @Nullable byte[] data)
                throws MediaCasException {
            validateInternalStates();
            validateSessionInternalStates();

            if (mICasV11 == null) {
                Log.d(TAG, "Send Session Event isn't supported by cas@1.0 interface");
@@ -546,7 +586,7 @@ public final class MediaCas implements AutoCloseable {
         */
        @NonNull
        public byte[] getSessionId() {
            validateInternalStates();
            validateSessionInternalStates();
            return toBytes(mSessionId);
        }

@@ -558,11 +598,12 @@ public final class MediaCas implements AutoCloseable {
         */
        @Override
        public void close() {
            validateInternalStates();

            validateSessionInternalStates();
            try {
                MediaCasStateException.throwExceptionIfNeeded(
                        mICas.closeSession(mSessionId));
                mIsClosed = true;
                removeSessionFromResourceMap(this);
            } catch (RemoteException e) {
                cleanupAndRethrowIllegalState();
            }
@@ -664,6 +705,7 @@ public final class MediaCas implements AutoCloseable {
    /**
     * Instantiate a CA system of the specified system id.
     *
     * @param context the context of the caller.
     * @param casSystemId The system id of the CA system.
     * @param tvInputServiceSessionId The Id of the session opened in TV Input Service (TIS)
     *        {@link android.media.tv.TvInputService#onCreateSession(String, String)}
@@ -672,11 +714,23 @@ public final class MediaCas implements AutoCloseable {
     * @throws UnsupportedCasException if the device does not support the
     * specified CA system.
     */
    public MediaCas(int casSystemId, @Nullable String tvInputServiceSessionId,
    public MediaCas(@NonNull Context context, int casSystemId,
            @Nullable String tvInputServiceSessionId,
            @PriorityHintUseCaseType int priorityHint) throws UnsupportedCasException {
        this(casSystemId);
        mPriorityHint = priorityHint;
        mTvInputServiceSessionId = tvInputServiceSessionId;

        Objects.requireNonNull(context, "context must not be null");
        mCasSystemId = casSystemId;
        mTunerResourceManager = (TunerResourceManager)
                context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
        if (mTunerResourceManager != null) {
            int[] clientId = new int[1];
            ResourceClientProfile profile =
                    new ResourceClientProfile(tvInputServiceSessionId, priorityHint);
            mTunerResourceManager.registerClientProfile(
                    profile, new HandlerExecutor(mEventHandler), mResourceListener, clientId);
            mClientId = clientId[0];
        }
    }

    IHwBinder getBinder() {
@@ -813,6 +867,40 @@ public final class MediaCas implements AutoCloseable {
        }
    }

    private int getSessionResourceId() throws MediaCasException {
        validateInternalStates();

        int[] sessionResourceId = new int[1];
        sessionResourceId[0] = -1;
        if (mTunerResourceManager != null) {
            CasSessionRequest casSessionRequest = new CasSessionRequest(mClientId, mCasSystemId);
            if (!mTunerResourceManager.requestCasSession(casSessionRequest, sessionResourceId)) {
                throw new MediaCasException.ResourceBusyException(
                    "insufficient resource to Open Session");
            }
        }
        return  sessionResourceId[0];
    }

    private void addSessionToResourceMap(Session session, int sessionResourceId) {

        if (sessionResourceId != -1) {
            synchronized (mSessionMap) {
                mSessionMap.put(session, sessionResourceId);
            }
        }
    }

    private void removeSessionFromResourceMap(Session session) {

        synchronized (mSessionMap) {
            if (mSessionMap.get(session) != null) {
                mTunerResourceManager.releaseCasSession(mSessionMap.get(session));
                mSessionMap.remove(session);
            }
        }
    }

    /**
     * Open a session to descramble one or more streams scrambled by the
     * conditional access system.
@@ -824,12 +912,13 @@ public final class MediaCas implements AutoCloseable {
     * @throws MediaCasStateException for CAS-specific state exceptions.
     */
    public Session openSession() throws MediaCasException {
        validateInternalStates();
        int sessionResourceId = getSessionResourceId();

        try {
            OpenSessionCallback cb = new OpenSessionCallback();
            mICas.openSession(cb);
            MediaCasException.throwExceptionIfNeeded(cb.mStatus);
            addSessionToResourceMap(cb.mSession, sessionResourceId);
            return cb.mSession;
        } catch (RemoteException e) {
            cleanupAndRethrowIllegalState();
@@ -853,7 +942,7 @@ public final class MediaCas implements AutoCloseable {
    @Nullable
    public Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode)
            throws MediaCasException {
        validateInternalStates();
        int sessionResourceId = getSessionResourceId();

        if (mICasV12 == null) {
            Log.d(TAG, "Open Session with scrambling mode is only supported by cas@1.2+ interface");
@@ -864,6 +953,7 @@ public final class MediaCas implements AutoCloseable {
            OpenSession_1_2_Callback cb = new OpenSession_1_2_Callback();
            mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
            MediaCasException.throwExceptionIfNeeded(cb.mStatus);
            addSessionToResourceMap(cb.mSession, sessionResourceId);
            return cb.mSession;
        } catch (RemoteException e) {
            cleanupAndRethrowIllegalState();
@@ -987,6 +1077,16 @@ public final class MediaCas implements AutoCloseable {
                mICas = null;
            }
        }

        if (mTunerResourceManager != null) {
            mTunerResourceManager.unregisterClientProfile(mClientId);
            mTunerResourceManager = null;
        }

        if (mHandlerThread != null) {
            mHandlerThread.quit();
            mHandlerThread = null;
        }
    }

    @Override
+10 −15
Original line number Diff line number Diff line
@@ -111,37 +111,32 @@ public abstract class TvInputService extends Service {
    public @interface PriorityHintUseCaseType {}

    /**
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
     * Background.
     * TODO Link: Tuner#Tuner(Context, string, int).
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(Context, int, String,
     * int)}: Background. TODO Link: Tuner#Tuner(Context, string, int).
     */
    public static final int PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND = 100;

    /**
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
     * Scan.
     * TODO Link: Tuner#Tuner(Context, string, int).
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(Context, int, String,
     * int)}: Scan. TODO Link: Tuner#Tuner(Context, string, int).
     */
    public static final int PRIORITY_HINT_USE_CASE_TYPE_SCAN = 200;

    /**
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
     * Playback.
     * TODO Link: Tuner#Tuner(Context, string, int).
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(Context, int, String,
     * int)}: Playback. TODO Link: Tuner#Tuner(Context, string, int).
     */
    public static final int PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK = 300;

    /**
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
     * Live.
     * TODO Link: Tuner#Tuner(Context, string, int).
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(Context, int, String,
     * int)}: Live. TODO Link: Tuner#Tuner(Context, string, int).
     */
    public static final int PRIORITY_HINT_USE_CASE_TYPE_LIVE = 400;

    /**
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
     * Record.
     * TODO Link: Tuner#Tuner(Context, string, int).
     * Use case of priority hint for {@link android.media.MediaCas#MediaCas(Context, int, String,
     * int)}: Record. TODO Link: Tuner#Tuner(Context, string, int).
     */
    public static final int PRIORITY_HINT_USE_CASE_TYPE_RECORD = 500;