Loading api/current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -24208,6 +24208,8 @@ package android.media { method public static int getMaxSecurityLevel(); method public int getMaxSessionCount(); method public android.os.PersistableBundle getMetrics(); method public java.util.List<byte[]> getOfflineLicenseKeySetIds(); method public int getOfflineLicenseState(byte[]); method public int getOpenSessionCount(); method public byte[] getPropertyByteArray(java.lang.String); method public java.lang.String getPropertyString(java.lang.String); Loading @@ -24228,6 +24230,7 @@ package android.media { method public void releaseSecureStops(byte[]); method public void removeAllSecureStops(); method public void removeKeys(byte[]); method public void removeOfflineLicense(byte[]); method public void removeSecureStop(byte[]); method public void restoreKeys(byte[], byte[]); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); Loading @@ -24250,6 +24253,9 @@ package android.media { field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 field public static final int OFFLINE_LICENSE_INACTIVE = 2; // 0x2 field public static final int OFFLINE_LICENSE_STATE_UNKNOWN = 0; // 0x0 field public static final int OFFLINE_LICENSE_USABLE = 1; // 0x1 field public static final java.lang.String PROPERTY_ALGORITHMS = "algorithms"; field public static final java.lang.String PROPERTY_DESCRIPTION = "description"; field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId"; media/java/android/media/MediaDrm.java +81 −0 Original line number Diff line number Diff line Loading @@ -978,6 +978,87 @@ public final class MediaDrm implements AutoCloseable { private native Certificate provideProvisionResponseNative(@NonNull byte[] response) throws DeniedByServerException; /** * The keys in an offline license allow protected content to be played even * if the device is not connected to a network. Offline licenses are stored * on the device after a key request/response exchange when the key request * KeyType is OFFLINE. Normally each app is responsible for keeping track of * the keySetIds it has created. If an app loses the keySetId for any stored * licenses that it created, however, it must be able to recover the stored * keySetIds so those licenses can be removed when they expire or when the * app is uninstalled. * <p> * This method returns a list of the keySetIds for all offline licenses. * The offline license keySetId may be used to query the status of an * offline license with {@link #getOfflineLicenseState} or remove it with * {@link #removeOfflineLicense}. * * @return a list of offline license keySetIds */ @NonNull public native List<byte[]> getOfflineLicenseKeySetIds(); /** * Normally offline licenses are released using a key request/response * exchange using {@link #getKeyRequest} where the key type is * KEY_TYPE_RELEASE, followed by {@link #provideKeyResponse}. This allows * the server to cryptographically confirm that the license has been removed * and then adjust the count of offline licenses allocated to the device. * <p> * In some exceptional situations it may be necessary to directly remove * offline licenses without notifying the server, which may be performed * using this method. * * @param keySetId the id of the offline license to remove * @throws IllegalArgumentException if the keySetId does not refer to an * offline license. */ public native void removeOfflineLicense(@NonNull byte[] keySetId); /** * Offline license state is unknown, an error occurred while trying * to access it. */ public static final int OFFLINE_LICENSE_STATE_UNKNOWN = 0; /** * Offline license state is usable, the keys may be used for decryption. */ public static final int OFFLINE_LICENSE_USABLE = 1; /** * Offline license state is inactive, the keys have been marked for * release using {@link #getKeyRequest} with KEY_TYPE_RELEASE but the * key response has not been received. */ public static final int OFFLINE_LICENSE_INACTIVE = 2; /** @hide */ @IntDef({ OFFLINE_LICENSE_STATE_UNKNOWN, OFFLINE_LICENSE_USABLE, OFFLINE_LICENSE_INACTIVE, }) @Retention(RetentionPolicy.SOURCE) public @interface OfflineLicenseState {} /** * Request the state of an offline license. An offline license may be usable * or inactive. The keys in a usable offline license are available for * decryption. When the offline license state is inactive, the keys have * been marked for release using {@link #getKeyRequest} with * KEY_TYPE_RELEASE but the key response has not been received. The keys in * an inactive offline license are not usable for decryption. * * @param keySetId selects the offline license * @return the offline license state, one of {@link #OFFLINE_LICENSE_USABLE}, * {@link #OFFLINE_LICENSE_INACTIVE} or {@link #OFFLINE_LICENSE_STATE_UNKNOWN}. * @throws IllegalArgumentException if the keySetId does not refer to an * offline license. */ @OfflineLicenseState public native int getOfflineLicenseState(@NonNull byte[] keySetId); /** * Secure stops are a way to enforce limits on the number of concurrent * streams per subscriber across devices. They provide secure monitoring of Loading media/jni/android_media_MediaDrm.cpp +92 −12 Original line number Diff line number Diff line Loading @@ -161,6 +161,12 @@ struct SecurityLevels { jint kSecurityLevelHwSecureAll; } gSecurityLevels; struct OfflineLicenseState { jint kOfflineLicenseStateUsable; jint kOfflineLicenseStateInactive; jint kOfflineLicenseStateUnknown; } gOfflineLicenseStates; struct fields_t { jfieldID context; Loading Loading @@ -740,6 +746,15 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I"); gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_USABLE", "I"); gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_INACTIVE", "I"); gOfflineLicenseStates.kOfflineLicenseStateInactive = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I"); gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I"); jmethodID getMaxSecurityLevel; GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I"); gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel); Loading Loading @@ -890,9 +905,7 @@ static jbyteArray android_media_MediaDrm_openSession( JNIEnv *env, jobject thiz, jint jlevel) { sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); if (!CheckDrm(env, drm)) { return NULL; } Loading Loading @@ -1070,6 +1083,10 @@ static void android_media_MediaDrm_removeKeys( JNIEnv *env, jobject thiz, jbyteArray jkeysetId) { sp<IDrm> drm = GetDrm(env, thiz); if (!CheckDrm(env, drm)) { return; } if (jkeysetId == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", "keySetId is null"); Loading Loading @@ -1231,9 +1248,7 @@ static jobject android_media_MediaDrm_getSecureStopIds( JNIEnv *env, jobject thiz) { sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); if (!CheckDrm(env, drm)) { return NULL; } Loading Loading @@ -1286,9 +1301,7 @@ static void android_media_MediaDrm_removeSecureStop( JNIEnv *env, jobject thiz, jbyteArray ssid) { sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); if (!CheckDrm(env, drm)) { return; } Loading Loading @@ -1437,6 +1450,65 @@ static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env, } } static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds( JNIEnv *env, jobject thiz) { sp<IDrm> drm = GetDrm(env, thiz); if (!CheckDrm(env, drm)) { return NULL; } List<Vector<uint8_t> > keySetIds; status_t err = drm->getOfflineLicenseKeySetIds(keySetIds); if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) { return NULL; } return ListOfVectorsToArrayListOfByteArray(env, keySetIds); } static void android_media_MediaDrm_removeOfflineLicense( JNIEnv *env, jobject thiz, jbyteArray keySetId) { sp<IDrm> drm = GetDrm(env, thiz); if (!CheckDrm(env, drm)) { return; } status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId)); throwExceptionAsNecessary(env, err, "Failed to remove offline license"); } static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env, jobject thiz, jbyteArray jkeySetId) { sp<IDrm> drm = GetDrm(env, thiz); if (!CheckDrm(env, drm)) { return gOfflineLicenseStates.kOfflineLicenseStateUnknown; } Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId)); DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown; status_t err = drm->getOfflineLicenseState(keySetId, &state); if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) { return gOfflineLicenseStates.kOfflineLicenseStateUnknown; } switch(state) { case DrmPlugin::kOfflineLicenseStateUsable: return gOfflineLicenseStates.kOfflineLicenseStateUsable; case DrmPlugin::kOfflineLicenseStateInactive: return gOfflineLicenseStates.kOfflineLicenseStateInactive; default: return gOfflineLicenseStates.kOfflineLicenseStateUnknown; } } static jstring android_media_MediaDrm_getPropertyString( JNIEnv *env, jobject thiz, jstring jname) { Loading Loading @@ -1718,9 +1790,8 @@ static jobject android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz) { sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); if (!CheckDrm(env, drm)) { return NULL; } Loading Loading @@ -1839,6 +1910,15 @@ static const JNINativeMethod gMethods[] = { { "getSecurityLevel", "([B)I", (void *)android_media_MediaDrm_getSecurityLevel }, { "removeOfflineLicense", "([B)V", (void *)android_media_MediaDrm_removeOfflineLicense }, { "getOfflineLicenseKeySetIds", "()Ljava/util/List;", (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds }, { "getOfflineLicenseState", "([B)I", (void *)android_media_MediaDrm_getOfflineLicenseState }, { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_MediaDrm_getPropertyString }, Loading Loading
api/current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -24208,6 +24208,8 @@ package android.media { method public static int getMaxSecurityLevel(); method public int getMaxSessionCount(); method public android.os.PersistableBundle getMetrics(); method public java.util.List<byte[]> getOfflineLicenseKeySetIds(); method public int getOfflineLicenseState(byte[]); method public int getOpenSessionCount(); method public byte[] getPropertyByteArray(java.lang.String); method public java.lang.String getPropertyString(java.lang.String); Loading @@ -24228,6 +24230,7 @@ package android.media { method public void releaseSecureStops(byte[]); method public void removeAllSecureStops(); method public void removeKeys(byte[]); method public void removeOfflineLicense(byte[]); method public void removeSecureStop(byte[]); method public void restoreKeys(byte[], byte[]); method public void setOnEventListener(android.media.MediaDrm.OnEventListener); Loading @@ -24250,6 +24253,9 @@ package android.media { field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 field public static final int OFFLINE_LICENSE_INACTIVE = 2; // 0x2 field public static final int OFFLINE_LICENSE_STATE_UNKNOWN = 0; // 0x0 field public static final int OFFLINE_LICENSE_USABLE = 1; // 0x1 field public static final java.lang.String PROPERTY_ALGORITHMS = "algorithms"; field public static final java.lang.String PROPERTY_DESCRIPTION = "description"; field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
media/java/android/media/MediaDrm.java +81 −0 Original line number Diff line number Diff line Loading @@ -978,6 +978,87 @@ public final class MediaDrm implements AutoCloseable { private native Certificate provideProvisionResponseNative(@NonNull byte[] response) throws DeniedByServerException; /** * The keys in an offline license allow protected content to be played even * if the device is not connected to a network. Offline licenses are stored * on the device after a key request/response exchange when the key request * KeyType is OFFLINE. Normally each app is responsible for keeping track of * the keySetIds it has created. If an app loses the keySetId for any stored * licenses that it created, however, it must be able to recover the stored * keySetIds so those licenses can be removed when they expire or when the * app is uninstalled. * <p> * This method returns a list of the keySetIds for all offline licenses. * The offline license keySetId may be used to query the status of an * offline license with {@link #getOfflineLicenseState} or remove it with * {@link #removeOfflineLicense}. * * @return a list of offline license keySetIds */ @NonNull public native List<byte[]> getOfflineLicenseKeySetIds(); /** * Normally offline licenses are released using a key request/response * exchange using {@link #getKeyRequest} where the key type is * KEY_TYPE_RELEASE, followed by {@link #provideKeyResponse}. This allows * the server to cryptographically confirm that the license has been removed * and then adjust the count of offline licenses allocated to the device. * <p> * In some exceptional situations it may be necessary to directly remove * offline licenses without notifying the server, which may be performed * using this method. * * @param keySetId the id of the offline license to remove * @throws IllegalArgumentException if the keySetId does not refer to an * offline license. */ public native void removeOfflineLicense(@NonNull byte[] keySetId); /** * Offline license state is unknown, an error occurred while trying * to access it. */ public static final int OFFLINE_LICENSE_STATE_UNKNOWN = 0; /** * Offline license state is usable, the keys may be used for decryption. */ public static final int OFFLINE_LICENSE_USABLE = 1; /** * Offline license state is inactive, the keys have been marked for * release using {@link #getKeyRequest} with KEY_TYPE_RELEASE but the * key response has not been received. */ public static final int OFFLINE_LICENSE_INACTIVE = 2; /** @hide */ @IntDef({ OFFLINE_LICENSE_STATE_UNKNOWN, OFFLINE_LICENSE_USABLE, OFFLINE_LICENSE_INACTIVE, }) @Retention(RetentionPolicy.SOURCE) public @interface OfflineLicenseState {} /** * Request the state of an offline license. An offline license may be usable * or inactive. The keys in a usable offline license are available for * decryption. When the offline license state is inactive, the keys have * been marked for release using {@link #getKeyRequest} with * KEY_TYPE_RELEASE but the key response has not been received. The keys in * an inactive offline license are not usable for decryption. * * @param keySetId selects the offline license * @return the offline license state, one of {@link #OFFLINE_LICENSE_USABLE}, * {@link #OFFLINE_LICENSE_INACTIVE} or {@link #OFFLINE_LICENSE_STATE_UNKNOWN}. * @throws IllegalArgumentException if the keySetId does not refer to an * offline license. */ @OfflineLicenseState public native int getOfflineLicenseState(@NonNull byte[] keySetId); /** * Secure stops are a way to enforce limits on the number of concurrent * streams per subscriber across devices. They provide secure monitoring of Loading
media/jni/android_media_MediaDrm.cpp +92 −12 Original line number Diff line number Diff line Loading @@ -161,6 +161,12 @@ struct SecurityLevels { jint kSecurityLevelHwSecureAll; } gSecurityLevels; struct OfflineLicenseState { jint kOfflineLicenseStateUsable; jint kOfflineLicenseStateInactive; jint kOfflineLicenseStateUnknown; } gOfflineLicenseStates; struct fields_t { jfieldID context; Loading Loading @@ -740,6 +746,15 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I"); gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_USABLE", "I"); gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_INACTIVE", "I"); gOfflineLicenseStates.kOfflineLicenseStateInactive = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I"); gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I"); jmethodID getMaxSecurityLevel; GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I"); gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel); Loading Loading @@ -890,9 +905,7 @@ static jbyteArray android_media_MediaDrm_openSession( JNIEnv *env, jobject thiz, jint jlevel) { sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); if (!CheckDrm(env, drm)) { return NULL; } Loading Loading @@ -1070,6 +1083,10 @@ static void android_media_MediaDrm_removeKeys( JNIEnv *env, jobject thiz, jbyteArray jkeysetId) { sp<IDrm> drm = GetDrm(env, thiz); if (!CheckDrm(env, drm)) { return; } if (jkeysetId == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", "keySetId is null"); Loading Loading @@ -1231,9 +1248,7 @@ static jobject android_media_MediaDrm_getSecureStopIds( JNIEnv *env, jobject thiz) { sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); if (!CheckDrm(env, drm)) { return NULL; } Loading Loading @@ -1286,9 +1301,7 @@ static void android_media_MediaDrm_removeSecureStop( JNIEnv *env, jobject thiz, jbyteArray ssid) { sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); if (!CheckDrm(env, drm)) { return; } Loading Loading @@ -1437,6 +1450,65 @@ static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env, } } static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds( JNIEnv *env, jobject thiz) { sp<IDrm> drm = GetDrm(env, thiz); if (!CheckDrm(env, drm)) { return NULL; } List<Vector<uint8_t> > keySetIds; status_t err = drm->getOfflineLicenseKeySetIds(keySetIds); if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) { return NULL; } return ListOfVectorsToArrayListOfByteArray(env, keySetIds); } static void android_media_MediaDrm_removeOfflineLicense( JNIEnv *env, jobject thiz, jbyteArray keySetId) { sp<IDrm> drm = GetDrm(env, thiz); if (!CheckDrm(env, drm)) { return; } status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId)); throwExceptionAsNecessary(env, err, "Failed to remove offline license"); } static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env, jobject thiz, jbyteArray jkeySetId) { sp<IDrm> drm = GetDrm(env, thiz); if (!CheckDrm(env, drm)) { return gOfflineLicenseStates.kOfflineLicenseStateUnknown; } Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId)); DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown; status_t err = drm->getOfflineLicenseState(keySetId, &state); if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) { return gOfflineLicenseStates.kOfflineLicenseStateUnknown; } switch(state) { case DrmPlugin::kOfflineLicenseStateUsable: return gOfflineLicenseStates.kOfflineLicenseStateUsable; case DrmPlugin::kOfflineLicenseStateInactive: return gOfflineLicenseStates.kOfflineLicenseStateInactive; default: return gOfflineLicenseStates.kOfflineLicenseStateUnknown; } } static jstring android_media_MediaDrm_getPropertyString( JNIEnv *env, jobject thiz, jstring jname) { Loading Loading @@ -1718,9 +1790,8 @@ static jobject android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz) { sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); if (!CheckDrm(env, drm)) { return NULL; } Loading Loading @@ -1839,6 +1910,15 @@ static const JNINativeMethod gMethods[] = { { "getSecurityLevel", "([B)I", (void *)android_media_MediaDrm_getSecurityLevel }, { "removeOfflineLicense", "([B)V", (void *)android_media_MediaDrm_removeOfflineLicense }, { "getOfflineLicenseKeySetIds", "()Ljava/util/List;", (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds }, { "getOfflineLicenseState", "([B)I", (void *)android_media_MediaDrm_getOfflineLicenseState }, { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_MediaDrm_getPropertyString }, Loading