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

Commit 6f6ef118 authored by Jeff Tinker's avatar Jeff Tinker
Browse files

Add a method to associate MediaDrm session with MediaCrypto

Previously, to associate a MediaDrm session with MediaCrypto,
the MediaDrm sessionId was passed as initData to the MediaCrypto
constructor.  This is not ideal for two reasons: it's pretty
obscure and you can't change the association without tearing
down the MediaCodec/MediaCrypto and starting all over.  Use
cases like key rotation require being able to update the
MediaDrm session post-construction.  This CL addresses both of
these issues.

bug: 19570317
Change-Id: Ie3d3eda16651b598cdd41f2180074a43cb6c0884
parent 74797f84
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15275,6 +15275,7 @@ package android.media {
    method public static final boolean isCryptoSchemeSupported(java.util.UUID);
    method public final void release();
    method public final boolean requiresSecureDecoderComponent(java.lang.String);
    method public final void setMediaDrmSession(byte[]) throws android.media.MediaCryptoException;
  }
  public final class MediaCryptoException extends java.lang.Exception {
+1 −0
Original line number Diff line number Diff line
@@ -16484,6 +16484,7 @@ package android.media {
    method public static final boolean isCryptoSchemeSupported(java.util.UUID);
    method public final void release();
    method public final boolean requiresSecureDecoderComponent(java.lang.String);
    method public final void setMediaDrmSession(byte[]) throws android.media.MediaCryptoException;
  }
  public final class MediaCryptoException extends java.lang.Exception {
+14 −0
Original line number Diff line number Diff line
@@ -70,6 +70,20 @@ public final class MediaCrypto {
     */
    public final native boolean requiresSecureDecoderComponent(String mime);

    /**
     * Associate a MediaDrm session with this MediaCrypto instance.  The
     * MediaDrm session is used to securely load decryption keys for a
     * crypto scheme.  The crypto keys loaded through the MediaDrm session
     * may be selected for use during the decryption operation performed
     * by {@link android.media.MediaCodec#queueSecureInputBuffer} by specifying
     * their key ids in the {@link android.media.MediaCodec.CryptoInfo#key} field.
     * @param sessionId the MediaDrm sessionId to associate with this
     * MediaCrypto instance
     * @throws MediaCryptoException on failure to set the sessionId
     */
    public final native void setMediaDrmSession(byte[] sessionId)
        throws MediaCryptoException;

    @Override
    protected void finalize() {
        native_finalize();
+2 −2
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@
package android.media;

/**
 * Exception thrown if MediaCrypto object could not be instantiated for
 * whatever reason.
 * Exception thrown if MediaCrypto object could not be instantiated or
 * if unable to perform an operation on the MediaCrypto object.
 */
public final class MediaCryptoException extends Exception {
    public MediaCryptoException(String detailMessage) {
+43 −0
Original line number Diff line number Diff line
@@ -140,6 +140,15 @@ sp<ICrypto> JCrypto::GetCrypto(JNIEnv *env, jobject obj) {
    return jcrypto->mCrypto;
}

// JNI conversion utilities
static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
    Vector<uint8_t> vector;
    size_t length = env->GetArrayLength(byteArray);
    vector.insertAt((size_t)0, length);
    env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
    return vector;
}

}  // namespace android

using namespace android;
@@ -274,6 +283,37 @@ static jboolean android_media_MediaCrypto_requiresSecureDecoderComponent(
    return result ? JNI_TRUE : JNI_FALSE;
}

static void android_media_MediaCrypto_setMediaDrmSession(
        JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
    if (jsessionId == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return;
    }

    sp<ICrypto> crypto = JCrypto::GetCrypto(env, thiz);

    if (crypto == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return;
    }

    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));

    status_t err = crypto->setMediaDrmSession(sessionId);

    String8 msg("setMediaDrmSession failed");
    if (err == ERROR_DRM_SESSION_NOT_OPENED) {
        msg += ": session not opened";
    } else if (err == ERROR_UNSUPPORTED) {
        msg += ": not supported by this crypto scheme";
    } else if (err == NO_INIT) {
        msg += ": crypto plugin not initialized";
    } else if (err != OK) {
        msg.appendFormat(": general failure (%d)", err);
    }
    jniThrowException(env, "android/media/MediaCryptoException", msg.string());
}

static JNINativeMethod gMethods[] = {
    { "release", "()V", (void *)android_media_MediaCrypto_release },
    { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
@@ -289,6 +329,9 @@ static JNINativeMethod gMethods[] = {

    { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z",
      (void *)android_media_MediaCrypto_requiresSecureDecoderComponent },

    { "setMediaDrmSession", "([B)V",
      (void *)android_media_MediaCrypto_setMediaDrmSession },
};

int register_android_media_Crypto(JNIEnv *env) {