Merge "CAS: Add AIDL Support" am: 27530abad7 am: eec8b98fdb
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2314680 Change-Id: I89283c3e8e34f70af08889db9789f388e7d4e906 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user