Merge "Add a method to associate MediaDrm session with MediaCrypto"
diff --git a/api/current.txt b/api/current.txt
index e2c6596..75a8df9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15323,6 +15323,7 @@
     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 {
diff --git a/api/system-current.txt b/api/system-current.txt
index 22187da..d272c20 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -16532,6 +16532,7 @@
     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 {
diff --git a/media/java/android/media/MediaCrypto.java b/media/java/android/media/MediaCrypto.java
index c7c3fc2..da81b37 100644
--- a/media/java/android/media/MediaCrypto.java
+++ b/media/java/android/media/MediaCrypto.java
@@ -70,6 +70,20 @@
      */
     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();
diff --git a/media/java/android/media/MediaCryptoException.java b/media/java/android/media/MediaCryptoException.java
index 44c5222..703e96f 100644
--- a/media/java/android/media/MediaCryptoException.java
+++ b/media/java/android/media/MediaCryptoException.java
@@ -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) {
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index d2216fb..a9accb02 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -140,6 +140,15 @@
     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 @@
     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 @@
 
     { "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) {