Merge "Use Tuner Resource Manager to get resource permission"

This commit is contained in:
TreeHugger Robot
2020-02-19 04:42:04 +00:00
committed by Android (Google) Code Review
3 changed files with 123 additions and 28 deletions

View File

@@ -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();

View File

@@ -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,
@PriorityHintUseCaseType int priorityHint) throws UnsupportedCasException {
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

View File

@@ -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;