Merge "CAS: Add AIDL Support"

This commit is contained in:
Yixiao Luo
2023-01-10 20:04:04 +00:00
committed by Gerrit Code Review
5 changed files with 649 additions and 254 deletions

View File

@@ -106,6 +106,7 @@ filegroup {
":android.security.maintenance-java-source", ":android.security.maintenance-java-source",
":android.security.metrics-java-source", ":android.security.metrics-java-source",
":android.system.keystore2-V3-java-source", ":android.system.keystore2-V3-java-source",
":android.hardware.cas-V1-java-source",
":credstore_aidl", ":credstore_aidl",
":dumpstate_aidl", ":dumpstate_aidl",
":framework_native_aidl", ":framework_native_aidl",
@@ -196,6 +197,7 @@ java_library {
"updatable-driver-protos", "updatable-driver-protos",
"ota_metadata_proto_java", "ota_metadata_proto_java",
"android.hidl.base-V1.0-java", "android.hidl.base-V1.0-java",
"android.hardware.cas-V1-java", // AIDL
"android.hardware.cas-V1.0-java", "android.hardware.cas-V1.0-java",
"android.hardware.cas-V1.1-java", "android.hardware.cas-V1.1-java",
"android.hardware.cas-V1.2-java", "android.hardware.cas-V1.2-java",

View File

@@ -21142,6 +21142,7 @@ package android.media {
field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0 field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0
field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1 field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1
field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9 field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9
field public static final int SCRAMBLING_MODE_AES_CBC = 14; // 0xe
field public static final int SCRAMBLING_MODE_AES_ECB = 10; // 0xa field public static final int SCRAMBLING_MODE_AES_ECB = 10; // 0xa
field public static final int SCRAMBLING_MODE_AES_SCTE52 = 11; // 0xb field public static final int SCRAMBLING_MODE_AES_SCTE52 = 11; // 0xb
field public static final int SCRAMBLING_MODE_DVB_CISSA_V1 = 6; // 0x6 field public static final int SCRAMBLING_MODE_DVB_CISSA_V1 = 6; // 0x6

View File

@@ -21,11 +21,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.TestApi; import android.annotation.TestApi;
import android.content.Context; import android.content.Context;
import android.hardware.cas.AidlCasPluginDescriptor;
import android.hardware.cas.ICas;
import android.hardware.cas.ICasListener;
import android.hardware.cas.IMediaCasService;
import android.hardware.cas.Status;
import android.hardware.cas.V1_0.HidlCasPluginDescriptor; 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.MediaCasException.*;
import android.media.tv.TvInputService.PriorityHintUseCaseType; import android.media.tv.TvInputService.PriorityHintUseCaseType;
import android.media.tv.tunerresourcemanager.CasSessionRequest; import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -39,6 +40,7 @@ import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.Process; import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log; import android.util.Log;
import android.util.Singleton; import android.util.Singleton;
@@ -47,6 +49,7 @@ import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -114,9 +117,10 @@ import java.util.Objects;
*/ */
public final class MediaCas implements AutoCloseable { public final class MediaCas implements AutoCloseable {
private static final String TAG = "MediaCas"; private static final String TAG = "MediaCas";
private ICas mICas; private ICas mICas = null;
private android.hardware.cas.V1_1.ICas mICasV11; private android.hardware.cas.V1_0.ICas mICasHidl = null;
private android.hardware.cas.V1_2.ICas mICasV12; private android.hardware.cas.V1_1.ICas mICasHidl11 = null;
private android.hardware.cas.V1_2.ICas mICasHidl12 = null;
private EventListener mListener; private EventListener mListener;
private HandlerThread mHandlerThread; private HandlerThread mHandlerThread;
private EventHandler mEventHandler; private EventHandler mEventHandler;
@@ -133,88 +137,84 @@ public final class MediaCas implements AutoCloseable {
* *
* @hide * @hide
*/ */
@IntDef(prefix = "SCRAMBLING_MODE_", @IntDef(
value = {SCRAMBLING_MODE_RESERVED, SCRAMBLING_MODE_DVB_CSA1, SCRAMBLING_MODE_DVB_CSA2, prefix = "SCRAMBLING_MODE_",
SCRAMBLING_MODE_DVB_CSA3_STANDARD, value = {
SCRAMBLING_MODE_DVB_CSA3_MINIMAL, SCRAMBLING_MODE_DVB_CSA3_ENHANCE, SCRAMBLING_MODE_RESERVED,
SCRAMBLING_MODE_DVB_CISSA_V1, SCRAMBLING_MODE_DVB_IDSA, SCRAMBLING_MODE_DVB_CSA1,
SCRAMBLING_MODE_MULTI2, SCRAMBLING_MODE_AES128, SCRAMBLING_MODE_AES_ECB, SCRAMBLING_MODE_DVB_CSA2,
SCRAMBLING_MODE_AES_SCTE52, SCRAMBLING_MODE_TDES_ECB, SCRAMBLING_MODE_TDES_SCTE52}) SCRAMBLING_MODE_DVB_CSA3_STANDARD,
SCRAMBLING_MODE_DVB_CSA3_MINIMAL,
SCRAMBLING_MODE_DVB_CSA3_ENHANCE,
SCRAMBLING_MODE_DVB_CISSA_V1,
SCRAMBLING_MODE_DVB_IDSA,
SCRAMBLING_MODE_MULTI2,
SCRAMBLING_MODE_AES128,
SCRAMBLING_MODE_AES_CBC,
SCRAMBLING_MODE_AES_ECB,
SCRAMBLING_MODE_AES_SCTE52,
SCRAMBLING_MODE_TDES_ECB,
SCRAMBLING_MODE_TDES_SCTE52
})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface ScramblingMode {} public @interface ScramblingMode {}
/** /** DVB (Digital Video Broadcasting) reserved mode. */
* DVB (Digital Video Broadcasting) reserved mode. public static final int SCRAMBLING_MODE_RESERVED = android.hardware.cas.ScramblingMode.RESERVED;
*/
public static final int SCRAMBLING_MODE_RESERVED = /** DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1. */
android.hardware.cas.V1_2.ScramblingMode.RESERVED; public static final int SCRAMBLING_MODE_DVB_CSA1 = android.hardware.cas.ScramblingMode.DVB_CSA1;
/**
* DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1. /** DVB CSA 2. */
*/ public static final int SCRAMBLING_MODE_DVB_CSA2 = android.hardware.cas.ScramblingMode.DVB_CSA2;
public static final int SCRAMBLING_MODE_DVB_CSA1 =
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA1; /** DVB CSA 3 in standard mode. */
/**
* DVB CSA 2.
*/
public static final int SCRAMBLING_MODE_DVB_CSA2 =
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA2;
/**
* DVB CSA 3 in standard mode.
*/
public static final int SCRAMBLING_MODE_DVB_CSA3_STANDARD = public static final int SCRAMBLING_MODE_DVB_CSA3_STANDARD =
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_STANDARD; android.hardware.cas.ScramblingMode.DVB_CSA3_STANDARD;
/**
* DVB CSA 3 in minimally enhanced mode. /** DVB CSA 3 in minimally enhanced mode. */
*/
public static final int SCRAMBLING_MODE_DVB_CSA3_MINIMAL = public static final int SCRAMBLING_MODE_DVB_CSA3_MINIMAL =
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_MINIMAL; android.hardware.cas.ScramblingMode.DVB_CSA3_MINIMAL;
/**
* DVB CSA 3 in fully enhanced mode. /** DVB CSA 3 in fully enhanced mode. */
*/
public static final int SCRAMBLING_MODE_DVB_CSA3_ENHANCE = public static final int SCRAMBLING_MODE_DVB_CSA3_ENHANCE =
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_ENHANCE; android.hardware.cas.ScramblingMode.DVB_CSA3_ENHANCE;
/**
* DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1. /** DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1. */
*/
public static final int SCRAMBLING_MODE_DVB_CISSA_V1 = public static final int SCRAMBLING_MODE_DVB_CISSA_V1 =
android.hardware.cas.V1_2.ScramblingMode.DVB_CISSA_V1; android.hardware.cas.ScramblingMode.DVB_CISSA_V1;
/**
* ATIS-0800006 IIF Default Scrambling Algorithm (IDSA). /** ATIS-0800006 IIF Default Scrambling Algorithm (IDSA). */
*/ public static final int SCRAMBLING_MODE_DVB_IDSA = android.hardware.cas.ScramblingMode.DVB_IDSA;
public static final int SCRAMBLING_MODE_DVB_IDSA =
android.hardware.cas.V1_2.ScramblingMode.DVB_IDSA; /** A symmetric key algorithm. */
/** public static final int SCRAMBLING_MODE_MULTI2 = android.hardware.cas.ScramblingMode.MULTI2;
* A symmetric key algorithm.
*/ /** Advanced Encryption System (AES) 128-bit Encryption mode. */
public static final int SCRAMBLING_MODE_MULTI2 = public static final int SCRAMBLING_MODE_AES128 = android.hardware.cas.ScramblingMode.AES128;
android.hardware.cas.V1_2.ScramblingMode.MULTI2;
/** /** Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode. */
* Advanced Encryption System (AES) 128-bit Encryption mode. public static final int SCRAMBLING_MODE_AES_CBC = android.hardware.cas.ScramblingMode.AES_CBC;
*/
public static final int SCRAMBLING_MODE_AES128 = /** Advanced Encryption System (AES) Electronic Code Book (ECB) mode. */
android.hardware.cas.V1_2.ScramblingMode.AES128; public static final int SCRAMBLING_MODE_AES_ECB = android.hardware.cas.ScramblingMode.AES_ECB;
/**
* Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
*/
public static final int SCRAMBLING_MODE_AES_ECB =
android.hardware.cas.V1_2.ScramblingMode.AES_ECB;
/** /**
* Advanced Encryption System (AES) Society of Cable Telecommunications Engineers (SCTE) 52 * Advanced Encryption System (AES) Society of Cable Telecommunications Engineers (SCTE) 52
* mode. * mode.
*/ */
public static final int SCRAMBLING_MODE_AES_SCTE52 = public static final int SCRAMBLING_MODE_AES_SCTE52 =
android.hardware.cas.V1_2.ScramblingMode.AES_SCTE52; android.hardware.cas.ScramblingMode.AES_SCTE52;
/**
* Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode. /** Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode. */
*/ public static final int SCRAMBLING_MODE_TDES_ECB = android.hardware.cas.ScramblingMode.TDES_ECB;
public static final int SCRAMBLING_MODE_TDES_ECB =
android.hardware.cas.V1_2.ScramblingMode.TDES_ECB;
/** /**
* Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications Engineers (SCTE) * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications Engineers (SCTE)
* 52 mode. * 52 mode.
*/ */
public static final int SCRAMBLING_MODE_TDES_SCTE52 = public static final int SCRAMBLING_MODE_TDES_SCTE52 =
android.hardware.cas.V1_2.ScramblingMode.TDES_SCTE52; android.hardware.cas.ScramblingMode.TDES_SCTE52;
/** /**
* Usages used to open cas sessions. * Usages used to open cas sessions.
@@ -226,25 +226,21 @@ public final class MediaCas implements AutoCloseable {
SESSION_USAGE_TIMESHIFT}) SESSION_USAGE_TIMESHIFT})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface SessionUsage {} public @interface SessionUsage {}
/**
* Cas session is used to descramble live streams. /** Cas session is used to descramble live streams. */
*/ public static final int SESSION_USAGE_LIVE = android.hardware.cas.SessionIntent.LIVE;
public static final int SESSION_USAGE_LIVE = android.hardware.cas.V1_2.SessionIntent.LIVE;
/** /** Cas session is used to descramble recoreded streams. */
* Cas session is used to descramble recoreded streams. public static final int SESSION_USAGE_PLAYBACK = android.hardware.cas.SessionIntent.PLAYBACK;
*/
public static final int SESSION_USAGE_PLAYBACK = /** Cas session is used to descramble live streams and encrypt local recorded content */
android.hardware.cas.V1_2.SessionIntent.PLAYBACK; public static final int SESSION_USAGE_RECORD = android.hardware.cas.SessionIntent.RECORD;
/**
* Cas session is used to descramble live streams and encrypt local recorded content
*/
public static final int SESSION_USAGE_RECORD = android.hardware.cas.V1_2.SessionIntent.RECORD;
/** /**
* Cas session is used to descramble live streams , encrypt local recorded content and playback * Cas session is used to descramble live streams , encrypt local recorded content and playback
* local encrypted content. * local encrypted content.
*/ */
public static final int SESSION_USAGE_TIMESHIFT = public static final int SESSION_USAGE_TIMESHIFT = android.hardware.cas.SessionIntent.TIMESHIFT;
android.hardware.cas.V1_2.SessionIntent.TIMESHIFT;
/** /**
* Plugin status events sent from cas system. * Plugin status events sent from cas system.
@@ -261,63 +257,90 @@ public final class MediaCas implements AutoCloseable {
* physical CAS modules. * physical CAS modules.
*/ */
public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED =
android.hardware.cas.V1_2.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED; android.hardware.cas.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED;
/**
* The event to indicate that the number of CAS system's session is changed. /** The event to indicate that the number of CAS system's session is changed. */
*/
public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED =
android.hardware.cas.V1_2.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED; android.hardware.cas.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
private static final Singleton<IMediaCasService> sService = new Singleton<IMediaCasService>() { private static final Singleton<IMediaCasService> sService =
@Override new Singleton<IMediaCasService>() {
protected IMediaCasService create() { @Override
try { protected IMediaCasService create() {
Log.d(TAG, "Trying to get cas@1.2 service"); try {
android.hardware.cas.V1_2.IMediaCasService serviceV12 = Log.d(TAG, "Trying to get AIDL service");
android.hardware.cas.V1_2.IMediaCasService.getService(true /*wait*/); IMediaCasService serviceAidl =
if (serviceV12 != null) { IMediaCasService.Stub.asInterface(
return serviceV12; ServiceManager.getService(
} IMediaCasService.DESCRIPTOR + "/default"));
} catch (Exception eV1_2) { if (serviceAidl != null) {
Log.d(TAG, "Failed to get cas@1.2 service"); return serviceAidl;
} }
} catch (Exception eAidl) {
try { Log.d(TAG, "Failed to get cas AIDL service");
Log.d(TAG, "Trying to get cas@1.1 service");
android.hardware.cas.V1_1.IMediaCasService serviceV11 =
android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
if (serviceV11 != null) {
return serviceV11;
} }
} catch (Exception eV1_1) { return null;
Log.d(TAG, "Failed to get cas@1.1 service"); }
} };
try { private static final Singleton<android.hardware.cas.V1_0.IMediaCasService> sServiceHidl =
Log.d(TAG, "Trying to get cas@1.0 service"); new Singleton<android.hardware.cas.V1_0.IMediaCasService>() {
return IMediaCasService.getService(true /*wait*/); @Override
} catch (Exception eV1_0) { protected android.hardware.cas.V1_0.IMediaCasService create() {
Log.d(TAG, "Failed to get cas@1.0 service"); try {
} Log.d(TAG, "Trying to get cas@1.2 service");
android.hardware.cas.V1_2.IMediaCasService serviceV12 =
android.hardware.cas.V1_2.IMediaCasService.getService(
true /*wait*/);
if (serviceV12 != null) {
return serviceV12;
}
} catch (Exception eV1_2) {
Log.d(TAG, "Failed to get cas@1.2 service");
}
return null; try {
} Log.d(TAG, "Trying to get cas@1.1 service");
}; android.hardware.cas.V1_1.IMediaCasService serviceV11 =
android.hardware.cas.V1_1.IMediaCasService.getService(
true /*wait*/);
if (serviceV11 != null) {
return serviceV11;
}
} catch (Exception eV1_1) {
Log.d(TAG, "Failed to get cas@1.1 service");
}
try {
Log.d(TAG, "Trying to get cas@1.0 service");
return android.hardware.cas.V1_0.IMediaCasService.getService(true /*wait*/);
} catch (Exception eV1_0) {
Log.d(TAG, "Failed to get cas@1.0 service");
}
return null;
}
};
static IMediaCasService getService() { static IMediaCasService getService() {
return sService.get(); return sService.get();
} }
static android.hardware.cas.V1_0.IMediaCasService getServiceHidl() {
return sServiceHidl.get();
}
private void validateInternalStates() { private void validateInternalStates() {
if (mICas == null) { if (mICas == null && mICasHidl == null) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }
private void cleanupAndRethrowIllegalState() { private void cleanupAndRethrowIllegalState() {
mICas = null; mICas = null;
mICasV11 = null; mICasHidl = null;
mICasV12 = null; mICasHidl11 = null;
mICasHidl12 = null;
throw new IllegalStateException(); throw new IllegalStateException();
} }
@@ -341,7 +364,7 @@ public final class MediaCas implements AutoCloseable {
toBytes((ArrayList<Byte>) msg.obj)); toBytes((ArrayList<Byte>) msg.obj));
} else if (msg.what == MSG_CAS_SESSION_EVENT) { } else if (msg.what == MSG_CAS_SESSION_EVENT) {
Bundle bundle = msg.getData(); Bundle bundle = msg.getData();
ArrayList<Byte> sessionId = toByteArray(bundle.getByteArray(SESSION_KEY)); byte[] sessionId = bundle.getByteArray(SESSION_KEY);
mListener.onSessionEvent(MediaCas.this, mListener.onSessionEvent(MediaCas.this,
createFromSessionId(sessionId), msg.arg1, msg.arg2, createFromSessionId(sessionId), msg.arg1, msg.arg2,
bundle.getByteArray(DATA_KEY)); bundle.getByteArray(DATA_KEY));
@@ -357,40 +380,94 @@ public final class MediaCas implements AutoCloseable {
} }
} }
private final ICasListener.Stub mBinder = new ICasListener.Stub() { private final ICasListener.Stub mBinder =
@Override new ICasListener.Stub() {
public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data) @Override
throws RemoteException { public void onEvent(int event, int arg, byte[] data) throws RemoteException {
if (mEventHandler != null) { if (mEventHandler != null) {
mEventHandler.sendMessage(mEventHandler.obtainMessage( mEventHandler.sendMessage(
EventHandler.MSG_CAS_EVENT, event, arg, data)); mEventHandler.obtainMessage(
} EventHandler.MSG_CAS_EVENT, event, arg, data));
} }
@Override }
public void onSessionEvent(@NonNull ArrayList<Byte> sessionId,
int event, int arg, @Nullable ArrayList<Byte> data) @Override
throws RemoteException { public void onSessionEvent(byte[] sessionId, int event, int arg, byte[] data)
if (mEventHandler != null) { throws RemoteException {
Message msg = mEventHandler.obtainMessage(); if (mEventHandler != null) {
msg.what = EventHandler.MSG_CAS_SESSION_EVENT; Message msg = mEventHandler.obtainMessage();
msg.arg1 = event; msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
msg.arg2 = arg; msg.arg1 = event;
Bundle bundle = new Bundle(); msg.arg2 = arg;
bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId)); Bundle bundle = new Bundle();
bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data)); bundle.putByteArray(EventHandler.SESSION_KEY, sessionId);
msg.setData(bundle); bundle.putByteArray(EventHandler.DATA_KEY, data);
mEventHandler.sendMessage(msg); msg.setData(bundle);
} mEventHandler.sendMessage(msg);
} }
@Override }
public void onStatusUpdate(byte status, int arg)
throws RemoteException { @Override
if (mEventHandler != null) { public void onStatusUpdate(byte status, int arg) throws RemoteException {
mEventHandler.sendMessage(mEventHandler.obtainMessage( if (mEventHandler != null) {
EventHandler.MSG_CAS_STATUS_EVENT, status, arg)); mEventHandler.sendMessage(
} mEventHandler.obtainMessage(
} EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
}; }
}
@Override
public synchronized String getInterfaceHash() throws android.os.RemoteException {
return ICasListener.Stub.HASH;
}
@Override
public int getInterfaceVersion() throws android.os.RemoteException {
return ICasListener.Stub.VERSION;
}
};
private final android.hardware.cas.V1_2.ICasListener.Stub mBinderHidl =
new android.hardware.cas.V1_2.ICasListener.Stub() {
@Override
public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data)
throws RemoteException {
if (mEventHandler != null) {
mEventHandler.sendMessage(
mEventHandler.obtainMessage(
EventHandler.MSG_CAS_EVENT, event, arg, data));
}
}
@Override
public void onSessionEvent(
@NonNull ArrayList<Byte> sessionId,
int event,
int arg,
@Nullable ArrayList<Byte> data)
throws RemoteException {
if (mEventHandler != null) {
Message msg = mEventHandler.obtainMessage();
msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
msg.arg1 = event;
msg.arg2 = arg;
Bundle bundle = new Bundle();
bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId));
bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data));
msg.setData(bundle);
mEventHandler.sendMessage(msg);
}
}
@Override
public void onStatusUpdate(byte status, int arg) throws RemoteException {
if (mEventHandler != null) {
mEventHandler.sendMessage(
mEventHandler.obtainMessage(
EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
}
}
};
private final TunerResourceManager.ResourcesReclaimListener mResourceListener = private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
new TunerResourceManager.ResourcesReclaimListener() { new TunerResourceManager.ResourcesReclaimListener() {
@@ -422,6 +499,11 @@ public final class MediaCas implements AutoCloseable {
mName = null; mName = null;
} }
PluginDescriptor(@NonNull AidlCasPluginDescriptor descriptor) {
mCASystemId = descriptor.caSystemId;
mName = descriptor.name;
}
PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) { PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) {
mCASystemId = descriptor.caSystemId; mCASystemId = descriptor.caSystemId;
mName = descriptor.name; mName = descriptor.name;
@@ -467,19 +549,20 @@ public final class MediaCas implements AutoCloseable {
} }
return data; return data;
} }
/** /**
* Class for an open session with the CA system. * Class for an open session with the CA system.
*/ */
public final class Session implements AutoCloseable { public final class Session implements AutoCloseable {
final ArrayList<Byte> mSessionId; final byte[] mSessionId;
boolean mIsClosed = false; boolean mIsClosed = false;
Session(@NonNull ArrayList<Byte> sessionId) { Session(@NonNull byte[] sessionId) {
mSessionId = new ArrayList<Byte>(sessionId); mSessionId = sessionId;
} }
private void validateSessionInternalStates() { private void validateSessionInternalStates() {
if (mICas == null) { if (mICas == null && mICasHidl == null) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
if (mIsClosed) { if (mIsClosed) {
@@ -496,7 +579,7 @@ public final class MediaCas implements AutoCloseable {
*/ */
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj instanceof Session) { if (obj instanceof Session) {
return mSessionId.equals(((Session) obj).mSessionId); return Arrays.equals(mSessionId, ((Session) obj).mSessionId);
} }
return false; return false;
} }
@@ -515,8 +598,13 @@ public final class MediaCas implements AutoCloseable {
validateSessionInternalStates(); validateSessionInternalStates();
try { try {
MediaCasException.throwExceptionIfNeeded( if (mICas != null) {
mICas.setSessionPrivateData(mSessionId, toByteArray(data, 0, data.length))); mICas.setSessionPrivateData(mSessionId, data);
} else {
MediaCasException.throwExceptionIfNeeded(
mICasHidl.setSessionPrivateData(
toByteArray(mSessionId), toByteArray(data, 0, data.length)));
}
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -539,8 +627,13 @@ public final class MediaCas implements AutoCloseable {
validateSessionInternalStates(); validateSessionInternalStates();
try { try {
MediaCasException.throwExceptionIfNeeded( if (mICas != null) {
mICas.processEcm(mSessionId, toByteArray(data, offset, length))); mICas.processEcm(mSessionId, data);
} else {
MediaCasException.throwExceptionIfNeeded(
mICasHidl.processEcm(
toByteArray(mSessionId), toByteArray(data, offset, length)));
}
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -576,15 +669,23 @@ public final class MediaCas implements AutoCloseable {
public void sendSessionEvent(int event, int arg, @Nullable byte[] data) public void sendSessionEvent(int event, int arg, @Nullable byte[] data)
throws MediaCasException { throws MediaCasException {
validateSessionInternalStates(); validateSessionInternalStates();
if (mICas != null) {
try {
mICas.sendSessionEvent(mSessionId, event, arg, data);
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
}
if (mICasV11 == null) { if (mICasHidl11 == null) {
Log.d(TAG, "Send Session Event isn't supported by cas@1.0 interface"); Log.d(TAG, "Send Session Event isn't supported by cas@1.0 interface");
throw new UnsupportedCasException("Send Session Event is not supported"); throw new UnsupportedCasException("Send Session Event is not supported");
} }
try { try {
MediaCasException.throwExceptionIfNeeded( MediaCasException.throwExceptionIfNeeded(
mICasV11.sendSessionEvent(mSessionId, event, arg, toByteArray(data))); mICasHidl11.sendSessionEvent(
toByteArray(mSessionId), event, arg, toByteArray(data)));
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -600,7 +701,7 @@ public final class MediaCas implements AutoCloseable {
@NonNull @NonNull
public byte[] getSessionId() { public byte[] getSessionId() {
validateSessionInternalStates(); validateSessionInternalStates();
return toBytes(mSessionId); return mSessionId;
} }
/** /**
@@ -613,8 +714,12 @@ public final class MediaCas implements AutoCloseable {
public void close() { public void close() {
validateSessionInternalStates(); validateSessionInternalStates();
try { try {
MediaCasStateException.throwExceptionIfNeeded( if (mICas != null) {
mICas.closeSession(mSessionId)); mICas.closeSession(mSessionId);
} else {
MediaCasStateException.throwExceptionIfNeeded(
mICasHidl.closeSession(toByteArray(mSessionId)));
}
mIsClosed = true; mIsClosed = true;
removeSessionFromResourceMap(this); removeSessionFromResourceMap(this);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -623,8 +728,8 @@ public final class MediaCas implements AutoCloseable {
} }
} }
Session createFromSessionId(@NonNull ArrayList<Byte> sessionId) { Session createFromSessionId(byte[] sessionId) {
if (sessionId == null || sessionId.size() == 0) { if (sessionId == null || sessionId.length == 0) {
return null; return null;
} }
return new Session(sessionId); return new Session(sessionId);
@@ -638,11 +743,19 @@ public final class MediaCas implements AutoCloseable {
* @return Whether the specified CA system is supported on this device. * @return Whether the specified CA system is supported on this device.
*/ */
public static boolean isSystemIdSupported(int CA_system_id) { public static boolean isSystemIdSupported(int CA_system_id) {
IMediaCasService service = getService(); IMediaCasService service = sService.get();
if (service != null) { if (service != null) {
try { try {
return service.isSystemIdSupported(CA_system_id); return service.isSystemIdSupported(CA_system_id);
} catch (RemoteException e) {
return false;
}
}
android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
if (serviceHidl != null) {
try {
return serviceHidl.isSystemIdSupported(CA_system_id);
} catch (RemoteException e) { } catch (RemoteException e) {
} }
} }
@@ -655,12 +768,26 @@ public final class MediaCas implements AutoCloseable {
* @return an array of descriptors for the available CA plugins. * @return an array of descriptors for the available CA plugins.
*/ */
public static PluginDescriptor[] enumeratePlugins() { public static PluginDescriptor[] enumeratePlugins() {
IMediaCasService service = getService(); IMediaCasService service = sService.get();
if (service != null) { if (service != null) {
try { try {
ArrayList<HidlCasPluginDescriptor> descriptors = AidlCasPluginDescriptor[] descriptors = service.enumeratePlugins();
service.enumeratePlugins(); if (descriptors.length == 0) {
return null;
}
PluginDescriptor[] results = new PluginDescriptor[descriptors.length];
for (int i = 0; i < results.length; i++) {
results[i] = new PluginDescriptor(descriptors[i]);
}
return results;
} catch (RemoteException e) {
}
}
android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
if (serviceHidl != null) {
try {
ArrayList<HidlCasPluginDescriptor> descriptors = serviceHidl.enumeratePlugins();
if (descriptors.size() == 0) { if (descriptors.size() == 0) {
return null; return null;
} }
@@ -680,29 +807,40 @@ public final class MediaCas implements AutoCloseable {
mCasSystemId = casSystemId; mCasSystemId = casSystemId;
mUserId = Process.myUid(); mUserId = Process.myUid();
IMediaCasService service = getService(); IMediaCasService service = getService();
android.hardware.cas.V1_2.IMediaCasService serviceV12 = if (service != null) {
android.hardware.cas.V1_2.IMediaCasService.castFrom(service); Log.d(TAG, "Use CAS AIDL interface to create plugin");
if (serviceV12 == null) { mICas = service.createPlugin(casSystemId, mBinder);
android.hardware.cas.V1_1.IMediaCasService serviceV11 =
android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
if (serviceV11 == null) {
Log.d(TAG, "Used cas@1_0 interface to create plugin");
mICas = service.createPlugin(casSystemId, mBinder);
} else {
Log.d(TAG, "Used cas@1.1 interface to create plugin");
mICas = mICasV11 = serviceV11.createPluginExt(casSystemId, mBinder);
}
} else { } else {
Log.d(TAG, "Used cas@1.2 interface to create plugin"); android.hardware.cas.V1_0.IMediaCasService serviceV10 = getServiceHidl();
mICas = mICasV11 = mICasV12 = android.hardware.cas.V1_2.IMediaCasService serviceV12 =
android.hardware.cas.V1_2.ICas android.hardware.cas.V1_2.IMediaCasService.castFrom(serviceV10);
.castFrom(serviceV12.createPluginExt(casSystemId, mBinder)); if (serviceV12 == null) {
android.hardware.cas.V1_1.IMediaCasService serviceV11 =
android.hardware.cas.V1_1.IMediaCasService.castFrom(serviceV10);
if (serviceV11 == null) {
Log.d(TAG, "Used cas@1_0 interface to create plugin");
mICasHidl = serviceV10.createPlugin(casSystemId, mBinderHidl);
} else {
Log.d(TAG, "Used cas@1.1 interface to create plugin");
mICasHidl =
mICasHidl11 = serviceV11.createPluginExt(casSystemId, mBinderHidl);
}
} else {
Log.d(TAG, "Used cas@1.2 interface to create plugin");
mICasHidl =
mICasHidl11 =
mICasHidl12 =
android.hardware.cas.V1_2.ICas.castFrom(
serviceV12.createPluginExt(
casSystemId, mBinderHidl));
}
} }
} catch(Exception e) { } catch(Exception e) {
Log.e(TAG, "Failed to create plugin: " + e); Log.e(TAG, "Failed to create plugin: " + e);
mICas = null; mICas = null;
mICasHidl = null;
} finally { } finally {
if (mICas == null) { if (mICas == null && mICasHidl == null) {
throw new UnsupportedCasException( throw new UnsupportedCasException(
"Unsupported casSystemId " + casSystemId); "Unsupported casSystemId " + casSystemId);
} }
@@ -783,9 +921,22 @@ public final class MediaCas implements AutoCloseable {
} }
IHwBinder getBinder() { IHwBinder getBinder() {
if (mICas != null) {
return null; // Return IHwBinder only for HIDL
}
validateInternalStates(); validateInternalStates();
return mICas.asBinder(); return mICasHidl.asBinder();
}
/**
* Check if the HAL is an AIDL implementation
*
* @hide
*/
public boolean isAidlHal() {
return mICas != null;
} }
/** /**
@@ -886,8 +1037,12 @@ public final class MediaCas implements AutoCloseable {
validateInternalStates(); validateInternalStates();
try { try {
MediaCasException.throwExceptionIfNeeded( if (mICas != null) {
mICas.setPrivateData(toByteArray(data, 0, data.length))); mICas.setPrivateData(data);
} else {
MediaCasException.throwExceptionIfNeeded(
mICasHidl.setPrivateData(toByteArray(data, 0, data.length)));
}
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -899,7 +1054,7 @@ public final class MediaCas implements AutoCloseable {
@Override @Override
public void onValues(int status, ArrayList<Byte> sessionId) { public void onValues(int status, ArrayList<Byte> sessionId) {
mStatus = status; mStatus = status;
mSession = createFromSessionId(sessionId); mSession = createFromSessionId(toBytes(sessionId));
} }
} }
@@ -912,7 +1067,7 @@ public final class MediaCas implements AutoCloseable {
@Override @Override
public void onValues(int status, ArrayList<Byte> sessionId) { public void onValues(int status, ArrayList<Byte> sessionId) {
mStatus = status; mStatus = status;
mSession = createFromSessionId(sessionId); mSession = createFromSessionId(toBytes(sessionId));
} }
} }
@@ -971,15 +1126,19 @@ public final class MediaCas implements AutoCloseable {
int sessionResourceHandle = getSessionResourceHandle(); int sessionResourceHandle = getSessionResourceHandle();
try { try {
OpenSessionCallback cb = new OpenSessionCallback(); if (mICasHidl != null) {
mICas.openSession(cb); OpenSessionCallback cb = new OpenSessionCallback();
MediaCasException.throwExceptionIfNeeded(cb.mStatus); mICasHidl.openSession(cb);
addSessionToResourceMap(cb.mSession, sessionResourceHandle); MediaCasException.throwExceptionIfNeeded(cb.mStatus);
Log.d(TAG, "Write Stats Log for succeed to Open Session."); addSessionToResourceMap(cb.mSession, sessionResourceHandle);
FrameworkStatsLog Log.d(TAG, "Write Stats Log for succeed to Open Session.");
.write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId, FrameworkStatsLog.write(
FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
mUserId,
mCasSystemId,
FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED); FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
return cb.mSession; return cb.mSession;
}
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -1012,14 +1171,30 @@ public final class MediaCas implements AutoCloseable {
throws MediaCasException { throws MediaCasException {
int sessionResourceHandle = getSessionResourceHandle(); int sessionResourceHandle = getSessionResourceHandle();
if (mICasV12 == null) { if (mICas != null) {
try {
byte[] sessionId = mICas.openSession(sessionUsage, scramblingMode);
Session session = createFromSessionId(sessionId);
addSessionToResourceMap(session, sessionResourceHandle);
Log.d(TAG, "Write Stats Log for succeed to Open Session.");
FrameworkStatsLog.write(
FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
mUserId,
mCasSystemId,
FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
return session;
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
}
if (mICasHidl12 == null) {
Log.d(TAG, "Open Session with scrambling mode is only supported by cas@1.2+ interface"); Log.d(TAG, "Open Session with scrambling mode is only supported by cas@1.2+ interface");
throw new UnsupportedCasException("Open Session with scrambling mode is not supported"); throw new UnsupportedCasException("Open Session with scrambling mode is not supported");
} }
try { try {
OpenSession_1_2_Callback cb = new OpenSession_1_2_Callback(); OpenSession_1_2_Callback cb = new OpenSession_1_2_Callback();
mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb); mICasHidl12.openSession_1_2(sessionUsage, scramblingMode, cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus); MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceHandle); addSessionToResourceMap(cb.mSession, sessionResourceHandle);
Log.d(TAG, "Write Stats Log for succeed to Open Session."); Log.d(TAG, "Write Stats Log for succeed to Open Session.");
@@ -1053,8 +1228,12 @@ public final class MediaCas implements AutoCloseable {
validateInternalStates(); validateInternalStates();
try { try {
MediaCasException.throwExceptionIfNeeded( if (mICas != null) {
mICas.processEmm(toByteArray(data, offset, length))); mICas.processEmm(Arrays.copyOfRange(data, offset, length));
} else {
MediaCasException.throwExceptionIfNeeded(
mICasHidl.processEmm(toByteArray(data, offset, length)));
}
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -1092,8 +1271,12 @@ public final class MediaCas implements AutoCloseable {
validateInternalStates(); validateInternalStates();
try { try {
MediaCasException.throwExceptionIfNeeded( if (mICas != null) {
mICas.sendEvent(event, arg, toByteArray(data))); mICas.sendEvent(event, arg, data);
} else {
MediaCasException.throwExceptionIfNeeded(
mICasHidl.sendEvent(event, arg, toByteArray(data)));
}
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -1114,8 +1297,11 @@ public final class MediaCas implements AutoCloseable {
validateInternalStates(); validateInternalStates();
try { try {
MediaCasException.throwExceptionIfNeeded( if (mICas != null) {
mICas.provision(provisionString)); mICas.provision(provisionString);
} else {
MediaCasException.throwExceptionIfNeeded(mICasHidl.provision(provisionString));
}
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -1136,8 +1322,12 @@ public final class MediaCas implements AutoCloseable {
validateInternalStates(); validateInternalStates();
try { try {
MediaCasException.throwExceptionIfNeeded( if (mICas != null) {
mICas.refreshEntitlements(refreshType, toByteArray(refreshData))); mICas.refreshEntitlements(refreshType, refreshData);
} else {
MediaCasException.throwExceptionIfNeeded(
mICasHidl.refreshEntitlements(refreshType, toByteArray(refreshData)));
}
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -1163,6 +1353,13 @@ public final class MediaCas implements AutoCloseable {
} finally { } finally {
mICas = null; mICas = null;
} }
} else if (mICasHidl != null) {
try {
mICasHidl.release();
} catch (RemoteException e) {
} finally {
mICasHidl = mICasHidl11 = mICasHidl12 = null;
}
} }
if (mTunerResourceManager != null) { if (mTunerResourceManager != null) {

View File

@@ -17,14 +17,26 @@
package android.media; package android.media;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.hardware.cas.V1_0.*; import android.hardware.cas.DestinationBuffer;
import android.hardware.cas.IDescrambler;
import android.hardware.cas.ScramblingControl;
import android.hardware.cas.SharedBuffer;
import android.hardware.cas.SubSample;
import android.hardware.cas.V1_0.IDescramblerBase;
import android.hardware.common.Ashmem;
import android.hardware.common.NativeHandle;
import android.media.MediaCasException.UnsupportedCasException; import android.media.MediaCasException.UnsupportedCasException;
import android.os.IHwBinder; import android.os.IHwBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceSpecificException; import android.os.ServiceSpecificException;
import android.os.SharedMemory;
import android.system.ErrnoException;
import android.util.Log; import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
/** /**
* MediaDescrambler class can be used in conjunction with {@link android.media.MediaCodec} * MediaDescrambler class can be used in conjunction with {@link android.media.MediaCodec}
@@ -39,7 +51,198 @@ import java.nio.ByteBuffer;
*/ */
public final class MediaDescrambler implements AutoCloseable { public final class MediaDescrambler implements AutoCloseable {
private static final String TAG = "MediaDescrambler"; private static final String TAG = "MediaDescrambler";
private IDescramblerBase mIDescrambler; private DescramblerWrapper mIDescrambler;
private interface DescramblerWrapper {
IHwBinder asBinder();
int descramble(
@NonNull ByteBuffer srcBuf,
@NonNull ByteBuffer dstBuf,
@NonNull MediaCodec.CryptoInfo cryptoInfo)
throws RemoteException;
boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException;
void setMediaCasSession(byte[] sessionId) throws RemoteException;
void release() throws RemoteException;
}
;
private long getSubsampleInfo(
int numSubSamples,
int[] numBytesOfClearData,
int[] numBytesOfEncryptedData,
SubSample[] subSamples) {
long totalSize = 0;
for (int i = 0; i < numSubSamples; i++) {
totalSize += numBytesOfClearData[i];
subSamples[i].numBytesOfClearData = numBytesOfClearData[i];
totalSize += numBytesOfEncryptedData[i];
subSamples[i].numBytesOfEncryptedData = numBytesOfEncryptedData[i];
}
return totalSize;
}
private ParcelFileDescriptor createSharedMemory(ByteBuffer buffer, String name)
throws RemoteException {
byte[] source = buffer.array();
if (source.length == 0) {
return null;
}
ParcelFileDescriptor fd = null;
try {
SharedMemory ashmem = SharedMemory.create(name == null ? "" : name, source.length);
ByteBuffer ptr = ashmem.mapReadWrite();
ptr.put(buffer);
ashmem.unmap(ptr);
fd = ashmem.getFdDup();
return fd;
} catch (ErrnoException | IOException e) {
throw new RemoteException(e);
}
}
private class AidlDescrambler implements DescramblerWrapper {
IDescrambler mAidlDescrambler;
AidlDescrambler(IDescrambler aidlDescrambler) {
mAidlDescrambler = aidlDescrambler;
}
@Override
public IHwBinder asBinder() {
return null;
}
@Override
public int descramble(
@NonNull ByteBuffer src,
@NonNull ByteBuffer dst,
@NonNull MediaCodec.CryptoInfo cryptoInfo)
throws RemoteException {
SubSample[] subSamples = new SubSample[cryptoInfo.numSubSamples];
long totalLength =
getSubsampleInfo(
cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData,
cryptoInfo.numBytesOfEncryptedData,
subSamples);
SharedBuffer srcBuffer = new SharedBuffer();
DestinationBuffer dstBuffer;
srcBuffer.heapBase = new Ashmem();
srcBuffer.heapBase.fd = createSharedMemory(src, "Descrambler Source Buffer");
srcBuffer.heapBase.size = src.array().length;
if (dst == null) {
dstBuffer = DestinationBuffer.nonsecureMemory(srcBuffer);
} else {
ParcelFileDescriptor pfd =
createSharedMemory(dst, "Descrambler Destination Buffer");
NativeHandle nh = new NativeHandle();
nh.fds = new ParcelFileDescriptor[] {pfd};
nh.ints = new int[] {1}; // Mark 1 since source buffer also uses it?
dstBuffer = DestinationBuffer.secureMemory(nh);
}
@ScramblingControl int control = cryptoInfo.key[0];
return mAidlDescrambler.descramble(
(byte) control,
subSamples,
srcBuffer,
src.position(),
dstBuffer,
dst.position());
}
@Override
public boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException {
return mAidlDescrambler.requiresSecureDecoderComponent(mime);
}
@Override
public void setMediaCasSession(byte[] sessionId) throws RemoteException {
mAidlDescrambler.setMediaCasSession(sessionId);
}
@Override
public void release() throws RemoteException {
mAidlDescrambler.release();
}
}
private class HidlDescrambler implements DescramblerWrapper {
IDescramblerBase mHidlDescrambler;
HidlDescrambler(IDescramblerBase hidlDescrambler) {
mHidlDescrambler = hidlDescrambler;
native_setup(hidlDescrambler.asBinder());
}
@Override
public IHwBinder asBinder() {
return mHidlDescrambler.asBinder();
}
@Override
public int descramble(
@NonNull ByteBuffer srcBuf,
@NonNull ByteBuffer dstBuf,
@NonNull MediaCodec.CryptoInfo cryptoInfo)
throws RemoteException {
try {
return native_descramble(
cryptoInfo.key[0],
cryptoInfo.key[1],
cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData,
cryptoInfo.numBytesOfEncryptedData,
srcBuf,
srcBuf.position(),
srcBuf.limit(),
dstBuf,
dstBuf.position(),
dstBuf.limit());
} catch (ServiceSpecificException e) {
MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
return -1;
}
@Override
public boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException {
return mHidlDescrambler.requiresSecureDecoderComponent(mime);
}
@Override
public void setMediaCasSession(byte[] sessionId) throws RemoteException {
ArrayList<Byte> byteArray = new ArrayList<>();
if (sessionId != null) {
int length = sessionId.length;
byteArray = new ArrayList<Byte>(length);
for (int i = 0; i < length; i++) {
byteArray.add(Byte.valueOf(sessionId[i]));
}
}
MediaCasStateException.throwExceptionIfNeeded(
mHidlDescrambler.setMediaCasSession(byteArray));
}
@Override
public void release() throws RemoteException {
mHidlDescrambler.release();
native_release();
}
}
private final void validateInternalStates() { private final void validateInternalStates() {
if (mIDescrambler == null) { if (mIDescrambler == null) {
@@ -61,7 +264,14 @@ public final class MediaDescrambler implements AutoCloseable {
*/ */
public MediaDescrambler(int CA_system_id) throws UnsupportedCasException { public MediaDescrambler(int CA_system_id) throws UnsupportedCasException {
try { try {
mIDescrambler = MediaCas.getService().createDescrambler(CA_system_id); if (MediaCas.getService() != null) {
mIDescrambler =
new AidlDescrambler(MediaCas.getService().createDescrambler(CA_system_id));
} else if (MediaCas.getServiceHidl() != null) {
mIDescrambler =
new HidlDescrambler(
MediaCas.getServiceHidl().createDescrambler(CA_system_id));
}
} catch(Exception e) { } catch(Exception e) {
Log.e(TAG, "Failed to create descrambler: " + e); Log.e(TAG, "Failed to create descrambler: " + e);
mIDescrambler = null; mIDescrambler = null;
@@ -70,7 +280,6 @@ public final class MediaDescrambler implements AutoCloseable {
throw new UnsupportedCasException("Unsupported CA_system_id " + CA_system_id); throw new UnsupportedCasException("Unsupported CA_system_id " + CA_system_id);
} }
} }
native_setup(mIDescrambler.asBinder());
} }
IHwBinder getBinder() { IHwBinder getBinder() {
@@ -117,8 +326,7 @@ public final class MediaDescrambler implements AutoCloseable {
validateInternalStates(); validateInternalStates();
try { try {
MediaCasStateException.throwExceptionIfNeeded( mIDescrambler.setMediaCasSession(session.mSessionId);
mIDescrambler.setMediaCasSession(session.mSessionId));
} catch (RemoteException e) { } catch (RemoteException e) {
cleanupAndRethrowIllegalState(); cleanupAndRethrowIllegalState();
} }
@@ -126,27 +334,31 @@ public final class MediaDescrambler implements AutoCloseable {
/** /**
* Scramble control value indicating that the samples are not scrambled. * Scramble control value indicating that the samples are not scrambled.
*
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/ */
public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0; public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = (byte) ScramblingControl.UNSCRAMBLED;
/** /**
* Scramble control value reserved and shouldn't be used currently. * Scramble control value reserved and shouldn't be used currently.
*
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/ */
public static final byte SCRAMBLE_CONTROL_RESERVED = 1; public static final byte SCRAMBLE_CONTROL_RESERVED = (byte) ScramblingControl.RESERVED;
/** /**
* Scramble control value indicating that the even key is used. * Scramble control value indicating that the even key is used.
*
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/ */
public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2; public static final byte SCRAMBLE_CONTROL_EVEN_KEY = (byte) ScramblingControl.EVENKEY;
/** /**
* Scramble control value indicating that the odd key is used. * Scramble control value indicating that the odd key is used.
*
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/ */
public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3; public static final byte SCRAMBLE_CONTROL_ODD_KEY = (byte) ScramblingControl.ODDKEY;
/** /**
* Scramble flag for a hint indicating that the descrambling request is for * Scramble flag for a hint indicating that the descrambling request is for
@@ -207,14 +419,7 @@ public final class MediaDescrambler implements AutoCloseable {
} }
try { try {
return native_descramble( return mIDescrambler.descramble(srcBuf, dstBuf, cryptoInfo);
cryptoInfo.key[0],
cryptoInfo.key[1],
cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData,
cryptoInfo.numBytesOfEncryptedData,
srcBuf, srcBuf.position(), srcBuf.limit(),
dstBuf, dstBuf.position(), dstBuf.limit());
} catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) {
MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage()); MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -233,7 +438,6 @@ public final class MediaDescrambler implements AutoCloseable {
mIDescrambler = null; mIDescrambler = null;
} }
} }
native_release();
} }
@Override @Override

View File

@@ -36,7 +36,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -325,14 +324,6 @@ public final class MediaExtractor {
} }
} }
private ArrayList<Byte> toByteArray(@NonNull byte[] data) {
ArrayList<Byte> byteArray = new ArrayList<Byte>(data.length);
for (int i = 0; i < data.length; i++) {
byteArray.add(i, Byte.valueOf(data[i]));
}
return byteArray;
}
/** /**
* Retrieves the information about the conditional access system used to scramble * Retrieves the information about the conditional access system used to scramble
* a track. * a track.
@@ -357,7 +348,7 @@ public final class MediaExtractor {
buf.rewind(); buf.rewind();
final byte[] sessionId = new byte[buf.remaining()]; final byte[] sessionId = new byte[buf.remaining()];
buf.get(sessionId); buf.get(sessionId);
session = mMediaCas.createFromSessionId(toByteArray(sessionId)); session = mMediaCas.createFromSessionId(sessionId);
} }
return new CasInfo(systemId, session, privateData); return new CasInfo(systemId, session, privateData);
} }