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

Commit ac91c6eb authored by Jeff Tinker's avatar Jeff Tinker Committed by Android (Google) Code Review
Browse files

Merge "Add new offline management APIs to MediaDrm"

parents 140aaada 55d26249
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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);
@@ -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";
+81 −0
Original line number Diff line number Diff line
@@ -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
+92 −12
Original line number Diff line number Diff line
@@ -161,6 +161,12 @@ struct SecurityLevels {
    jint kSecurityLevelHwSecureAll;
} gSecurityLevels;

struct OfflineLicenseState {
    jint kOfflineLicenseStateUsable;
    jint kOfflineLicenseStateInactive;
    jint kOfflineLicenseStateUnknown;
} gOfflineLicenseStates;


struct fields_t {
    jfieldID context;
@@ -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);
@@ -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;
    }

@@ -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");
@@ -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;
    }

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

@@ -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) {
@@ -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;
    }

@@ -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 },