Loading media/java/android/media/MediaDrm.java +147 −6 Original line number Original line Diff line number Diff line Loading @@ -20,11 +20,14 @@ import java.lang.ref.WeakReference; import java.util.UUID; import java.util.UUID; import java.util.HashMap; import java.util.HashMap; import java.util.List; import java.util.List; import android.os.Binder; import android.os.Debug; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.Parcel; import android.os.Parcel; import android.util.Log; import android.util.Log; import android.content.Context; /** /** * MediaDrm can be used to obtain keys for decrypting protected media streams, in * MediaDrm can be used to obtain keys for decrypting protected media streams, in Loading Loading @@ -100,6 +103,20 @@ public final class MediaDrm { private long mNativeContext; private long mNativeContext; /** * Specify no certificate type * * @hide - not part of the public API at this time */ public static final int CERTIFICATE_TYPE_NONE = 0; /** * Specify X.509 certificate type * * @hide - not part of the public API at this time */ public static final int CERTIFICATE_TYPE_X509 = 1; /** /** * Query if the given scheme identified by its UUID is supported on * Query if the given scheme identified by its UUID is supported on * this device. * this device. Loading Loading @@ -316,6 +333,9 @@ public final class MediaDrm { * Contains the opaque data an app uses to request keys from a license server * Contains the opaque data an app uses to request keys from a license server */ */ public final static class KeyRequest { public final static class KeyRequest { private byte[] mData; private String mDefaultUrl; KeyRequest() {} KeyRequest() {} /** /** Loading @@ -329,9 +349,6 @@ public final class MediaDrm { * server URL from other sources. * server URL from other sources. */ */ public String getDefaultUrl() { return mDefaultUrl; } public String getDefaultUrl() { return mDefaultUrl; } private byte[] mData; private String mDefaultUrl; }; }; /** /** Loading Loading @@ -456,7 +473,12 @@ public final class MediaDrm { * is returned in ProvisionRequest.data. The recommended URL to deliver the provision * is returned in ProvisionRequest.data. The recommended URL to deliver the provision * request to is returned in ProvisionRequest.defaultUrl. * request to is returned in ProvisionRequest.defaultUrl. */ */ public native ProvisionRequest getProvisionRequest(); public ProvisionRequest getProvisionRequest() { return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, ""); } private native ProvisionRequest getProvisionRequestNative(int certType, String certAuthority); /** /** * After a provision response is received by the app, it is provided to the DRM * After a provision response is received by the app, it is provided to the DRM Loading @@ -468,7 +490,12 @@ public final class MediaDrm { * @throws DeniedByServerException if the response indicates that the * @throws DeniedByServerException if the response indicates that the * server rejected the request * server rejected the request */ */ public native void provideProvisionResponse(byte[] response) public void provideProvisionResponse(byte[] response) throws DeniedByServerException { provideProvisionResponseNative(response); } private native Certificate provideProvisionResponseNative(byte[] response) throws DeniedByServerException; throws DeniedByServerException; /** /** Loading Loading @@ -683,6 +710,120 @@ public final class MediaDrm { return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm); return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm); } } /** * Contains the opaque data an app uses to request a certificate from a provisioning * server * * @hide - not part of the public API at this time */ public final static class CertificateRequest { private byte[] mData; private String mDefaultUrl; CertificateRequest(byte[] data, String defaultUrl) { mData = data; mDefaultUrl = defaultUrl; } /** * Get the opaque message data */ public byte[] getData() { return mData; } /** * Get the default URL to use when sending the certificate request * message to a server, if known. The app may prefer to use a different * certificate server URL obtained from other sources. */ public String getDefaultUrl() { return mDefaultUrl; } } /** * Generate a certificate request, specifying the certificate type * and authority. The response received should be passed to * provideCertificateResponse. * * @param certType Specifies the certificate type. * * @param certAuthority is passed to the certificate server to specify * the chain of authority. * * @hide - not part of the public API at this time */ public CertificateRequest getCertificateRequest(int certType, String certAuthority) { ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority); return new CertificateRequest(provisionRequest.getData(), provisionRequest.getDefaultUrl()); } /** * Contains the wrapped private key and public certificate data associated * with a certificate. * * @hide - not part of the public API at this time */ public final static class Certificate { Certificate() {} /** * Get the wrapped private key data */ public byte[] getWrappedPrivateKey() { return mWrappedKey; } /** * Get the PEM-encoded certificate chain */ public byte[] getContent() { return mCertificateData; } private byte[] mWrappedKey; private byte[] mCertificateData; } /** * Process a response from the certificate server. The response * is obtained from an HTTP Post to the url provided by getCertificateRequest. * <p> * The public X509 certificate chain and wrapped private key are returned * in the returned Certificate objec. The certificate chain is in PEM format. * The wrapped private key should be stored in application private * storage, and used when invoking the signRSA method. * * @param response the opaque certificate response byte array to provide to the * DRM engine plugin. * * @throws DeniedByServerException if the response indicates that the * server rejected the request * * @hide - not part of the public API at this time */ public Certificate provideCertificateResponse(byte[] response) throws DeniedByServerException { return provideProvisionResponseNative(response); } private static final native byte[] signRSANative(MediaDrm drm, byte[] sessionId, String algorithm, byte[] wrappedKey, byte[] message); /** * Sign data using an RSA key * * @param context the app context * @param sessionId a sessionId obtained from openSession on the MediaDrm object * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1" * @param wrappedKey - the wrapped (encrypted) RSA private key obtained * from provideCertificateResponse * @param message the data for which a signature is to be computed * * @hide - not part of the public API at this time */ public byte[] signRSA(Context context, byte[] sessionId, String algorithm, byte[] wrappedKey, byte[] message) { return signRSANative(this, sessionId, algorithm, wrappedKey, message); } @Override @Override protected void finalize() { protected void finalize() { native_finalize(); native_finalize(); Loading media/jni/android_media_MediaDrm.cpp +109 −17 Original line number Original line Diff line number Diff line Loading @@ -100,6 +100,16 @@ struct KeyTypes { jint kKeyTypeRelease; jint kKeyTypeRelease; } gKeyTypes; } gKeyTypes; struct CertificateTypes { jint kCertificateTypeNone; jint kCertificateTypeX509; } gCertificateTypes; struct CertificateFields { jfieldID wrappedPrivateKey; jfieldID certificateData; }; struct fields_t { struct fields_t { jfieldID context; jfieldID context; jmethodID post_event; jmethodID post_event; Loading @@ -110,6 +120,11 @@ struct fields_t { SetFields set; SetFields set; IteratorFields iterator; IteratorFields iterator; EntryFields entry; EntryFields entry; CertificateFields certificate; jclass certificateClassId; jclass hashmapClassId; jclass arraylistClassId; jclass stringClassId; }; }; static fields_t gFields; static fields_t gFields; Loading Loading @@ -406,8 +421,7 @@ static String8 JStringToString8(JNIEnv *env, jstring const &jstr) { */ */ static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) { static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) { jclass clazz; jclass clazz = gFields.stringClassId; FIND_CLASS(clazz, "java/lang/String"); KeyedVector<String8, String8> keyedVector; KeyedVector<String8, String8> keyedVector; jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet); jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet); Loading Loading @@ -450,8 +464,7 @@ static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject & } } static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) { static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) { jclass clazz; jclass clazz = gFields.hashmapClassId; FIND_CLASS(clazz, "java/util/HashMap"); jobject hashMap = env->NewObject(clazz, gFields.hashmap.init); jobject hashMap = env->NewObject(clazz, gFields.hashmap.init); for (size_t i = 0; i < map.size(); ++i) { for (size_t i = 0; i < map.size(); ++i) { jstring jkey = env->NewStringUTF(map.keyAt(i).string()); jstring jkey = env->NewStringUTF(map.keyAt(i).string()); Loading @@ -465,8 +478,7 @@ static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env, static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env, List<Vector<uint8_t> > list) { List<Vector<uint8_t> > list) { jclass clazz; jclass clazz = gFields.arraylistClassId; FIND_CLASS(clazz, "java/util/ArrayList"); jobject arrayList = env->NewObject(clazz, gFields.arraylist.init); jobject arrayList = env->NewObject(clazz, gFields.arraylist.init); List<Vector<uint8_t> >::iterator iter = list.begin(); List<Vector<uint8_t> >::iterator iter = list.begin(); while (iter != list.end()) { while (iter != list.end()) { Loading Loading @@ -542,6 +554,11 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I"); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I"); gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field); gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I"); gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I"); gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field); FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); Loading @@ -550,6 +567,11 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); FIND_CLASS(clazz, "android/media/MediaDrm$Certificate"); GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B"); GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B"); gFields.certificateClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); FIND_CLASS(clazz, "java/util/ArrayList"); FIND_CLASS(clazz, "java/util/ArrayList"); GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V"); GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V"); GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z"); GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z"); Loading @@ -571,6 +593,15 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { FIND_CLASS(clazz, "java/util/Map$Entry"); FIND_CLASS(clazz, "java/util/Map$Entry"); GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;"); GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;"); GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;"); GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;"); FIND_CLASS(clazz, "java/util/HashMap"); gFields.hashmapClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); FIND_CLASS(clazz, "java/lang/String"); gFields.stringClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); FIND_CLASS(clazz, "java/util/ArrayList"); gFields.arraylistClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); } } static void android_media_MediaDrm_native_setup( static void android_media_MediaDrm_native_setup( Loading Loading @@ -826,8 +857,8 @@ static jobject android_media_MediaDrm_queryKeyStatus( return KeyedVectorToHashMap(env, infoMap); return KeyedVectorToHashMap(env, infoMap); } } static jobject android_media_MediaDrm_getProvisionRequest( static jobject android_media_MediaDrm_getProvisionRequestNative( JNIEnv *env, jobject thiz) { JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) { sp<IDrm> drm = GetDrm(env, thiz); sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { if (drm == NULL) { Loading @@ -839,7 +870,17 @@ static jobject android_media_MediaDrm_getProvisionRequest( Vector<uint8_t> request; Vector<uint8_t> request; String8 defaultUrl; String8 defaultUrl; status_t err = drm->getProvisionRequest(request, defaultUrl); String8 certType; if (jcertType == gCertificateTypes.kCertificateTypeX509) { certType = "X.509"; } else if (jcertType == gCertificateTypes.kCertificateTypeNone) { certType = "none"; } else { certType = "invalid"; } String8 certAuthority = JStringToString8(env, jcertAuthority); status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl); if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) { if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) { return NULL; return NULL; Loading @@ -863,27 +904,43 @@ static jobject android_media_MediaDrm_getProvisionRequest( return provisionObj; return provisionObj; } } static void android_media_MediaDrm_provideProvisionResponse( static jobject android_media_MediaDrm_provideProvisionResponseNative( JNIEnv *env, jobject thiz, jbyteArray jresponse) { JNIEnv *env, jobject thiz, jbyteArray jresponse) { sp<IDrm> drm = GetDrm(env, thiz); sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); "MediaDrm obj is null"); return; return NULL; } } if (jresponse == NULL) { if (jresponse == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", jniThrowException(env, "java/lang/IllegalArgumentException", "provision response is null"); "provision response is null"); return; return NULL; } } Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); Vector<uint8_t> certificate, wrappedKey; status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey); // Fill out return obj jclass clazz = gFields.certificateClassId; jobject certificateObj = NULL; if (clazz && certificate.size() && wrappedKey.size()) { certificateObj = env->AllocObject(clazz); jbyteArray jcertificate = VectorToJByteArray(env, certificate); env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate); status_t err = drm->provideProvisionResponse(response); jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey); env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey); } throwExceptionAsNecessary(env, err, "Failed to handle provision response"); throwExceptionAsNecessary(env, err, "Failed to handle provision response"); return certificateObj; } } static jobject android_media_MediaDrm_getSecureStops( static jobject android_media_MediaDrm_getSecureStops( Loading Loading @@ -1209,6 +1266,38 @@ static jboolean android_media_MediaDrm_verifyNative( } } static jbyteArray android_media_MediaDrm_signRSANative( JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) { sp<IDrm> drm = GetDrm(env, jdrm); if (!CheckSession(env, drm, jsessionId)) { return NULL; } if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", "required argument is null"); return NULL; } Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); String8 algorithm = JStringToString8(env, jalgorithm); Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey)); Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); Vector<uint8_t> signature; status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature); if (throwExceptionAsNecessary(env, err, "Failed to sign")) { return NULL; } return VectorToJByteArray(env, signature); } static JNINativeMethod gMethods[] = { static JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaDrm_release }, { "release", "()V", (void *)android_media_MediaDrm_release }, { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, Loading Loading @@ -1244,11 +1333,11 @@ static JNINativeMethod gMethods[] = { { "queryKeyStatus", "([B)Ljava/util/HashMap;", { "queryKeyStatus", "([B)Ljava/util/HashMap;", (void *)android_media_MediaDrm_queryKeyStatus }, (void *)android_media_MediaDrm_queryKeyStatus }, { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;", { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;", (void *)android_media_MediaDrm_getProvisionRequest }, (void *)android_media_MediaDrm_getProvisionRequestNative }, { "provideProvisionResponse", "([B)V", { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;", (void *)android_media_MediaDrm_provideProvisionResponse }, (void *)android_media_MediaDrm_provideProvisionResponseNative }, { "getSecureStops", "()Ljava/util/List;", { "getSecureStops", "()Ljava/util/List;", (void *)android_media_MediaDrm_getSecureStops }, (void *)android_media_MediaDrm_getSecureStops }, Loading Loading @@ -1287,6 +1376,9 @@ static JNINativeMethod gMethods[] = { { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z", { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z", (void *)android_media_MediaDrm_verifyNative }, (void *)android_media_MediaDrm_verifyNative }, { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B", (void *)android_media_MediaDrm_signRSANative }, }; }; int register_android_media_Drm(JNIEnv *env) { int register_android_media_Drm(JNIEnv *env) { Loading media/lib/Android.mk→media/lib/remotedisplay/Android.mk +2 −2 Original line number Original line Diff line number Diff line Loading @@ -15,7 +15,7 @@ # # LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir) # the library # the remotedisplay library # ============================================================ # ============================================================ include $(CLEAR_VARS) include $(CLEAR_VARS) Loading @@ -23,7 +23,7 @@ LOCAL_MODULE:= com.android.media.remotedisplay LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \ $(call all-subdir-java-files) \ $(call all-java-files-under, java) \ $(call all-aidl-files-under, java) $(call all-aidl-files-under, java) include $(BUILD_JAVA_LIBRARY) include $(BUILD_JAVA_LIBRARY) Loading media/lib/README.txt→media/lib/remotedisplay/README.txt +0 −1 Original line number Original line Diff line number Diff line Loading @@ -25,4 +25,3 @@ with the framework in a new API. That API isn't ready yet so this library is a compromise to make new capabilities available to the system library is a compromise to make new capabilities available to the system without exposing the full surface area of the support library media without exposing the full surface area of the support library media route provider protocol. route provider protocol. media/lib/com.android.media.remotedisplay.xml→media/lib/remotedisplay/com.android.media.remotedisplay.xml +0 −0 File moved. View file Loading
media/java/android/media/MediaDrm.java +147 −6 Original line number Original line Diff line number Diff line Loading @@ -20,11 +20,14 @@ import java.lang.ref.WeakReference; import java.util.UUID; import java.util.UUID; import java.util.HashMap; import java.util.HashMap; import java.util.List; import java.util.List; import android.os.Binder; import android.os.Debug; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.Looper; import android.os.Message; import android.os.Message; import android.os.Parcel; import android.os.Parcel; import android.util.Log; import android.util.Log; import android.content.Context; /** /** * MediaDrm can be used to obtain keys for decrypting protected media streams, in * MediaDrm can be used to obtain keys for decrypting protected media streams, in Loading Loading @@ -100,6 +103,20 @@ public final class MediaDrm { private long mNativeContext; private long mNativeContext; /** * Specify no certificate type * * @hide - not part of the public API at this time */ public static final int CERTIFICATE_TYPE_NONE = 0; /** * Specify X.509 certificate type * * @hide - not part of the public API at this time */ public static final int CERTIFICATE_TYPE_X509 = 1; /** /** * Query if the given scheme identified by its UUID is supported on * Query if the given scheme identified by its UUID is supported on * this device. * this device. Loading Loading @@ -316,6 +333,9 @@ public final class MediaDrm { * Contains the opaque data an app uses to request keys from a license server * Contains the opaque data an app uses to request keys from a license server */ */ public final static class KeyRequest { public final static class KeyRequest { private byte[] mData; private String mDefaultUrl; KeyRequest() {} KeyRequest() {} /** /** Loading @@ -329,9 +349,6 @@ public final class MediaDrm { * server URL from other sources. * server URL from other sources. */ */ public String getDefaultUrl() { return mDefaultUrl; } public String getDefaultUrl() { return mDefaultUrl; } private byte[] mData; private String mDefaultUrl; }; }; /** /** Loading Loading @@ -456,7 +473,12 @@ public final class MediaDrm { * is returned in ProvisionRequest.data. The recommended URL to deliver the provision * is returned in ProvisionRequest.data. The recommended URL to deliver the provision * request to is returned in ProvisionRequest.defaultUrl. * request to is returned in ProvisionRequest.defaultUrl. */ */ public native ProvisionRequest getProvisionRequest(); public ProvisionRequest getProvisionRequest() { return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, ""); } private native ProvisionRequest getProvisionRequestNative(int certType, String certAuthority); /** /** * After a provision response is received by the app, it is provided to the DRM * After a provision response is received by the app, it is provided to the DRM Loading @@ -468,7 +490,12 @@ public final class MediaDrm { * @throws DeniedByServerException if the response indicates that the * @throws DeniedByServerException if the response indicates that the * server rejected the request * server rejected the request */ */ public native void provideProvisionResponse(byte[] response) public void provideProvisionResponse(byte[] response) throws DeniedByServerException { provideProvisionResponseNative(response); } private native Certificate provideProvisionResponseNative(byte[] response) throws DeniedByServerException; throws DeniedByServerException; /** /** Loading Loading @@ -683,6 +710,120 @@ public final class MediaDrm { return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm); return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm); } } /** * Contains the opaque data an app uses to request a certificate from a provisioning * server * * @hide - not part of the public API at this time */ public final static class CertificateRequest { private byte[] mData; private String mDefaultUrl; CertificateRequest(byte[] data, String defaultUrl) { mData = data; mDefaultUrl = defaultUrl; } /** * Get the opaque message data */ public byte[] getData() { return mData; } /** * Get the default URL to use when sending the certificate request * message to a server, if known. The app may prefer to use a different * certificate server URL obtained from other sources. */ public String getDefaultUrl() { return mDefaultUrl; } } /** * Generate a certificate request, specifying the certificate type * and authority. The response received should be passed to * provideCertificateResponse. * * @param certType Specifies the certificate type. * * @param certAuthority is passed to the certificate server to specify * the chain of authority. * * @hide - not part of the public API at this time */ public CertificateRequest getCertificateRequest(int certType, String certAuthority) { ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority); return new CertificateRequest(provisionRequest.getData(), provisionRequest.getDefaultUrl()); } /** * Contains the wrapped private key and public certificate data associated * with a certificate. * * @hide - not part of the public API at this time */ public final static class Certificate { Certificate() {} /** * Get the wrapped private key data */ public byte[] getWrappedPrivateKey() { return mWrappedKey; } /** * Get the PEM-encoded certificate chain */ public byte[] getContent() { return mCertificateData; } private byte[] mWrappedKey; private byte[] mCertificateData; } /** * Process a response from the certificate server. The response * is obtained from an HTTP Post to the url provided by getCertificateRequest. * <p> * The public X509 certificate chain and wrapped private key are returned * in the returned Certificate objec. The certificate chain is in PEM format. * The wrapped private key should be stored in application private * storage, and used when invoking the signRSA method. * * @param response the opaque certificate response byte array to provide to the * DRM engine plugin. * * @throws DeniedByServerException if the response indicates that the * server rejected the request * * @hide - not part of the public API at this time */ public Certificate provideCertificateResponse(byte[] response) throws DeniedByServerException { return provideProvisionResponseNative(response); } private static final native byte[] signRSANative(MediaDrm drm, byte[] sessionId, String algorithm, byte[] wrappedKey, byte[] message); /** * Sign data using an RSA key * * @param context the app context * @param sessionId a sessionId obtained from openSession on the MediaDrm object * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1" * @param wrappedKey - the wrapped (encrypted) RSA private key obtained * from provideCertificateResponse * @param message the data for which a signature is to be computed * * @hide - not part of the public API at this time */ public byte[] signRSA(Context context, byte[] sessionId, String algorithm, byte[] wrappedKey, byte[] message) { return signRSANative(this, sessionId, algorithm, wrappedKey, message); } @Override @Override protected void finalize() { protected void finalize() { native_finalize(); native_finalize(); Loading
media/jni/android_media_MediaDrm.cpp +109 −17 Original line number Original line Diff line number Diff line Loading @@ -100,6 +100,16 @@ struct KeyTypes { jint kKeyTypeRelease; jint kKeyTypeRelease; } gKeyTypes; } gKeyTypes; struct CertificateTypes { jint kCertificateTypeNone; jint kCertificateTypeX509; } gCertificateTypes; struct CertificateFields { jfieldID wrappedPrivateKey; jfieldID certificateData; }; struct fields_t { struct fields_t { jfieldID context; jfieldID context; jmethodID post_event; jmethodID post_event; Loading @@ -110,6 +120,11 @@ struct fields_t { SetFields set; SetFields set; IteratorFields iterator; IteratorFields iterator; EntryFields entry; EntryFields entry; CertificateFields certificate; jclass certificateClassId; jclass hashmapClassId; jclass arraylistClassId; jclass stringClassId; }; }; static fields_t gFields; static fields_t gFields; Loading Loading @@ -406,8 +421,7 @@ static String8 JStringToString8(JNIEnv *env, jstring const &jstr) { */ */ static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) { static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) { jclass clazz; jclass clazz = gFields.stringClassId; FIND_CLASS(clazz, "java/lang/String"); KeyedVector<String8, String8> keyedVector; KeyedVector<String8, String8> keyedVector; jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet); jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet); Loading Loading @@ -450,8 +464,7 @@ static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject & } } static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) { static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) { jclass clazz; jclass clazz = gFields.hashmapClassId; FIND_CLASS(clazz, "java/util/HashMap"); jobject hashMap = env->NewObject(clazz, gFields.hashmap.init); jobject hashMap = env->NewObject(clazz, gFields.hashmap.init); for (size_t i = 0; i < map.size(); ++i) { for (size_t i = 0; i < map.size(); ++i) { jstring jkey = env->NewStringUTF(map.keyAt(i).string()); jstring jkey = env->NewStringUTF(map.keyAt(i).string()); Loading @@ -465,8 +478,7 @@ static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env, static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env, List<Vector<uint8_t> > list) { List<Vector<uint8_t> > list) { jclass clazz; jclass clazz = gFields.arraylistClassId; FIND_CLASS(clazz, "java/util/ArrayList"); jobject arrayList = env->NewObject(clazz, gFields.arraylist.init); jobject arrayList = env->NewObject(clazz, gFields.arraylist.init); List<Vector<uint8_t> >::iterator iter = list.begin(); List<Vector<uint8_t> >::iterator iter = list.begin(); while (iter != list.end()) { while (iter != list.end()) { Loading Loading @@ -542,6 +554,11 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I"); GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I"); gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field); gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I"); gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field); GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I"); gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field); FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); Loading @@ -550,6 +567,11 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); FIND_CLASS(clazz, "android/media/MediaDrm$Certificate"); GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B"); GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B"); gFields.certificateClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); FIND_CLASS(clazz, "java/util/ArrayList"); FIND_CLASS(clazz, "java/util/ArrayList"); GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V"); GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V"); GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z"); GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z"); Loading @@ -571,6 +593,15 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { FIND_CLASS(clazz, "java/util/Map$Entry"); FIND_CLASS(clazz, "java/util/Map$Entry"); GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;"); GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;"); GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;"); GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;"); FIND_CLASS(clazz, "java/util/HashMap"); gFields.hashmapClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); FIND_CLASS(clazz, "java/lang/String"); gFields.stringClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); FIND_CLASS(clazz, "java/util/ArrayList"); gFields.arraylistClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); } } static void android_media_MediaDrm_native_setup( static void android_media_MediaDrm_native_setup( Loading Loading @@ -826,8 +857,8 @@ static jobject android_media_MediaDrm_queryKeyStatus( return KeyedVectorToHashMap(env, infoMap); return KeyedVectorToHashMap(env, infoMap); } } static jobject android_media_MediaDrm_getProvisionRequest( static jobject android_media_MediaDrm_getProvisionRequestNative( JNIEnv *env, jobject thiz) { JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) { sp<IDrm> drm = GetDrm(env, thiz); sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { if (drm == NULL) { Loading @@ -839,7 +870,17 @@ static jobject android_media_MediaDrm_getProvisionRequest( Vector<uint8_t> request; Vector<uint8_t> request; String8 defaultUrl; String8 defaultUrl; status_t err = drm->getProvisionRequest(request, defaultUrl); String8 certType; if (jcertType == gCertificateTypes.kCertificateTypeX509) { certType = "X.509"; } else if (jcertType == gCertificateTypes.kCertificateTypeNone) { certType = "none"; } else { certType = "invalid"; } String8 certAuthority = JStringToString8(env, jcertAuthority); status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl); if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) { if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) { return NULL; return NULL; Loading @@ -863,27 +904,43 @@ static jobject android_media_MediaDrm_getProvisionRequest( return provisionObj; return provisionObj; } } static void android_media_MediaDrm_provideProvisionResponse( static jobject android_media_MediaDrm_provideProvisionResponseNative( JNIEnv *env, jobject thiz, jbyteArray jresponse) { JNIEnv *env, jobject thiz, jbyteArray jresponse) { sp<IDrm> drm = GetDrm(env, thiz); sp<IDrm> drm = GetDrm(env, thiz); if (drm == NULL) { if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); "MediaDrm obj is null"); return; return NULL; } } if (jresponse == NULL) { if (jresponse == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", jniThrowException(env, "java/lang/IllegalArgumentException", "provision response is null"); "provision response is null"); return; return NULL; } } Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); Vector<uint8_t> certificate, wrappedKey; status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey); // Fill out return obj jclass clazz = gFields.certificateClassId; jobject certificateObj = NULL; if (clazz && certificate.size() && wrappedKey.size()) { certificateObj = env->AllocObject(clazz); jbyteArray jcertificate = VectorToJByteArray(env, certificate); env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate); status_t err = drm->provideProvisionResponse(response); jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey); env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey); } throwExceptionAsNecessary(env, err, "Failed to handle provision response"); throwExceptionAsNecessary(env, err, "Failed to handle provision response"); return certificateObj; } } static jobject android_media_MediaDrm_getSecureStops( static jobject android_media_MediaDrm_getSecureStops( Loading Loading @@ -1209,6 +1266,38 @@ static jboolean android_media_MediaDrm_verifyNative( } } static jbyteArray android_media_MediaDrm_signRSANative( JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId, jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) { sp<IDrm> drm = GetDrm(env, jdrm); if (!CheckSession(env, drm, jsessionId)) { return NULL; } if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", "required argument is null"); return NULL; } Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); String8 algorithm = JStringToString8(env, jalgorithm); Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey)); Vector<uint8_t> message(JByteArrayToVector(env, jmessage)); Vector<uint8_t> signature; status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature); if (throwExceptionAsNecessary(env, err, "Failed to sign")) { return NULL; } return VectorToJByteArray(env, signature); } static JNINativeMethod gMethods[] = { static JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaDrm_release }, { "release", "()V", (void *)android_media_MediaDrm_release }, { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, Loading Loading @@ -1244,11 +1333,11 @@ static JNINativeMethod gMethods[] = { { "queryKeyStatus", "([B)Ljava/util/HashMap;", { "queryKeyStatus", "([B)Ljava/util/HashMap;", (void *)android_media_MediaDrm_queryKeyStatus }, (void *)android_media_MediaDrm_queryKeyStatus }, { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;", { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;", (void *)android_media_MediaDrm_getProvisionRequest }, (void *)android_media_MediaDrm_getProvisionRequestNative }, { "provideProvisionResponse", "([B)V", { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;", (void *)android_media_MediaDrm_provideProvisionResponse }, (void *)android_media_MediaDrm_provideProvisionResponseNative }, { "getSecureStops", "()Ljava/util/List;", { "getSecureStops", "()Ljava/util/List;", (void *)android_media_MediaDrm_getSecureStops }, (void *)android_media_MediaDrm_getSecureStops }, Loading Loading @@ -1287,6 +1376,9 @@ static JNINativeMethod gMethods[] = { { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z", { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z", (void *)android_media_MediaDrm_verifyNative }, (void *)android_media_MediaDrm_verifyNative }, { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B", (void *)android_media_MediaDrm_signRSANative }, }; }; int register_android_media_Drm(JNIEnv *env) { int register_android_media_Drm(JNIEnv *env) { Loading
media/lib/Android.mk→media/lib/remotedisplay/Android.mk +2 −2 Original line number Original line Diff line number Diff line Loading @@ -15,7 +15,7 @@ # # LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir) # the library # the remotedisplay library # ============================================================ # ============================================================ include $(CLEAR_VARS) include $(CLEAR_VARS) Loading @@ -23,7 +23,7 @@ LOCAL_MODULE:= com.android.media.remotedisplay LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \ $(call all-subdir-java-files) \ $(call all-java-files-under, java) \ $(call all-aidl-files-under, java) $(call all-aidl-files-under, java) include $(BUILD_JAVA_LIBRARY) include $(BUILD_JAVA_LIBRARY) Loading
media/lib/README.txt→media/lib/remotedisplay/README.txt +0 −1 Original line number Original line Diff line number Diff line Loading @@ -25,4 +25,3 @@ with the framework in a new API. That API isn't ready yet so this library is a compromise to make new capabilities available to the system library is a compromise to make new capabilities available to the system without exposing the full surface area of the support library media without exposing the full surface area of the support library media route provider protocol. route provider protocol.
media/lib/com.android.media.remotedisplay.xml→media/lib/remotedisplay/com.android.media.remotedisplay.xml +0 −0 File moved. View file