android_frameworks_base/media/jni/android_media_MediaDrm.cpp
Jeff Tinker eb13c764c6 Fix exception on MediaDrm invalid property access
Accessing an invalid MediaDrm property would result in
an IllegalStateException.  This change causes
IllegalArgumentException to be thrown instead, which
is more appropriate.

Test: android.media.cts.ClearKeySystemTest passes
  and it fails prior to this CL.

bug:68765217
Change-Id: I858575dc8fe643a88381da49b543c5cc0d266e02
2017-11-02 18:13:02 +00:00

1540 lines
49 KiB
C++

/*
* Copyright 2013, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaDrm-JNI"
#include <utils/Log.h>
#include "android_media_MediaDrm.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include "android_os_Parcel.h"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <cutils/properties.h>
#include <media/IDrm.h>
#include <media/IMediaDrmService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! (var), "Unable to find class " className);
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find method " fieldName);
#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find static method " fieldName);
struct RequestFields {
jfieldID data;
jfieldID defaultUrl;
jfieldID requestType;
};
struct ArrayListFields {
jmethodID init;
jmethodID add;
};
struct HashmapFields {
jmethodID init;
jmethodID get;
jmethodID put;
jmethodID entrySet;
};
struct SetFields {
jmethodID iterator;
};
struct IteratorFields {
jmethodID next;
jmethodID hasNext;
};
struct EntryFields {
jmethodID getKey;
jmethodID getValue;
};
struct EventTypes {
jint kEventProvisionRequired;
jint kEventKeyRequired;
jint kEventKeyExpired;
jint kEventVendorDefined;
jint kEventSessionReclaimed;
} gEventTypes;
struct EventWhat {
jint kWhatDrmEvent;
jint kWhatExpirationUpdate;
jint kWhatKeyStatusChange;
} gEventWhat;
struct KeyTypes {
jint kKeyTypeStreaming;
jint kKeyTypeOffline;
jint kKeyTypeRelease;
} gKeyTypes;
struct KeyRequestTypes {
jint kKeyRequestTypeInitial;
jint kKeyRequestTypeRenewal;
jint kKeyRequestTypeRelease;
} gKeyRequestTypes;
struct CertificateTypes {
jint kCertificateTypeNone;
jint kCertificateTypeX509;
} gCertificateTypes;
struct CertificateFields {
jfieldID wrappedPrivateKey;
jfieldID certificateData;
};
struct StateExceptionFields {
jmethodID init;
jclass classId;
};
struct fields_t {
jfieldID context;
jmethodID post_event;
RequestFields keyRequest;
RequestFields provisionRequest;
ArrayListFields arraylist;
HashmapFields hashmap;
SetFields set;
IteratorFields iterator;
EntryFields entry;
CertificateFields certificate;
StateExceptionFields stateException;
jclass certificateClassId;
jclass hashmapClassId;
jclass arraylistClassId;
jclass stringClassId;
};
static fields_t gFields;
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class JNIDrmListener: public DrmListener
{
public:
JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
~JNIDrmListener();
virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
private:
JNIDrmListener();
jclass mClass; // Reference to MediaDrm class
jobject mObject; // Weak ref to MediaDrm Java object to call on
};
JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
{
// Hold onto the MediaDrm class for use in calling the static method
// that posts events to the application thread.
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
ALOGE("Can't find android/media/MediaDrm");
jniThrowException(env, "java/lang/Exception",
"Can't find android/media/MediaDrm");
return;
}
mClass = (jclass)env->NewGlobalRef(clazz);
// We use a weak reference so the MediaDrm object can be garbage collected.
// The reference is only used as a proxy for callbacks.
mObject = env->NewGlobalRef(weak_thiz);
}
JNIDrmListener::~JNIDrmListener()
{
// remove global references
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mObject);
env->DeleteGlobalRef(mClass);
}
void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
const Parcel *obj)
{
jint jwhat;
jint jeventType = 0;
// translate DrmPlugin event types into their java equivalents
switch (eventType) {
case DrmPlugin::kDrmPluginEventProvisionRequired:
jwhat = gEventWhat.kWhatDrmEvent;
jeventType = gEventTypes.kEventProvisionRequired;
break;
case DrmPlugin::kDrmPluginEventKeyNeeded:
jwhat = gEventWhat.kWhatDrmEvent;
jeventType = gEventTypes.kEventKeyRequired;
break;
case DrmPlugin::kDrmPluginEventKeyExpired:
jwhat = gEventWhat.kWhatDrmEvent;
jeventType = gEventTypes.kEventKeyExpired;
break;
case DrmPlugin::kDrmPluginEventVendorDefined:
jwhat = gEventWhat.kWhatDrmEvent;
jeventType = gEventTypes.kEventVendorDefined;
break;
case DrmPlugin::kDrmPluginEventSessionReclaimed:
jwhat = gEventWhat.kWhatDrmEvent;
jeventType = gEventTypes.kEventSessionReclaimed;
break;
case DrmPlugin::kDrmPluginEventExpirationUpdate:
jwhat = gEventWhat.kWhatExpirationUpdate;
break;
case DrmPlugin::kDrmPluginEventKeysChange:
jwhat = gEventWhat.kWhatKeyStatusChange;
break;
default:
ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
return;
}
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (obj && obj->dataSize() > 0) {
jobject jParcel = createJavaParcelObject(env);
if (jParcel != NULL) {
Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
nativeParcel->setData(obj->data(), obj->dataSize());
env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
jwhat, jeventType, extra, jParcel);
env->DeleteLocalRef(jParcel);
}
}
if (env->ExceptionCheck()) {
ALOGW("An exception occurred while notifying an event.");
LOGW_EX(env);
env->ExceptionClear();
}
}
static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
ALOGE("Illegal state exception: %s (%d)", msg, err);
jobject exception = env->NewObject(gFields.stateException.classId,
gFields.stateException.init, static_cast<int>(err),
env->NewStringUTF(msg));
env->Throw(static_cast<jthrowable>(exception));
}
static bool throwExceptionAsNecessary(
JNIEnv *env, status_t err, const char *msg = NULL) {
const char *drmMessage = NULL;
switch (err) {
case ERROR_DRM_UNKNOWN:
drmMessage = "General DRM error";
break;
case ERROR_DRM_NO_LICENSE:
drmMessage = "No license";
break;
case ERROR_DRM_LICENSE_EXPIRED:
drmMessage = "License expired";
break;
case ERROR_DRM_SESSION_NOT_OPENED:
drmMessage = "Session not opened";
break;
case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
drmMessage = "Not initialized";
break;
case ERROR_DRM_DECRYPT:
drmMessage = "Decrypt error";
break;
case ERROR_DRM_CANNOT_HANDLE:
drmMessage = "Invalid parameter or data format";
break;
case ERROR_DRM_TAMPER_DETECTED:
drmMessage = "Invalid state";
break;
default:
break;
}
String8 vendorMessage;
if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
vendorMessage = String8::format("DRM vendor-defined error: %d", err);
drmMessage = vendorMessage.string();
}
if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
jniThrowException(env, "java/lang/IllegalArgumentException", msg);
return true;
} else if (err == ERROR_DRM_NOT_PROVISIONED) {
jniThrowException(env, "android/media/NotProvisionedException", msg);
return true;
} else if (err == ERROR_DRM_RESOURCE_BUSY) {
jniThrowException(env, "android/media/ResourceBusyException", msg);
return true;
} else if (err == ERROR_DRM_DEVICE_REVOKED) {
jniThrowException(env, "android/media/DeniedByServerException", msg);
return true;
} else if (err == DEAD_OBJECT) {
jniThrowException(env, "android/media/MediaDrmResetException",
"mediaserver died");
return true;
} else if (err != OK) {
String8 errbuf;
if (drmMessage != NULL) {
if (msg == NULL) {
msg = drmMessage;
} else {
errbuf = String8::format("%s: %s", msg, drmMessage);
msg = errbuf.string();
}
}
throwStateException(env, msg, err);
return true;
}
return false;
}
static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
return jdrm ? jdrm->getDrm() : NULL;
}
JDrm::JDrm(
JNIEnv *env, jobject thiz, const uint8_t uuid[16],
const String8 &appPackageName) {
mObject = env->NewWeakGlobalRef(thiz);
mDrm = MakeDrm(uuid, appPackageName);
if (mDrm != NULL) {
mDrm->setListener(this);
}
}
JDrm::~JDrm() {
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->DeleteWeakGlobalRef(mObject);
mObject = NULL;
}
// static
sp<IDrm> JDrm::MakeDrm() {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.drm"));
sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
if (service == NULL) {
return NULL;
}
sp<IDrm> drm = service->makeDrm();
if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
return NULL;
}
return drm;
}
// static
sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
sp<IDrm> drm = MakeDrm();
if (drm == NULL) {
return NULL;
}
status_t err = drm->createPlugin(uuid, appPackageName);
if (err != OK) {
return NULL;
}
return drm;
}
status_t JDrm::setListener(const sp<DrmListener>& listener) {
Mutex::Autolock lock(mLock);
mListener = listener;
return OK;
}
void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
sp<DrmListener> listener;
mLock.lock();
listener = mListener;
mLock.unlock();
if (listener != NULL) {
Mutex::Autolock lock(mNotifyLock);
listener->notify(eventType, extra, obj);
}
}
void JDrm::disconnect() {
if (mDrm != NULL) {
mDrm->destroyPlugin();
mDrm.clear();
}
}
// static
bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
sp<IDrm> drm = MakeDrm();
if (drm == NULL) {
return false;
}
return drm->isCryptoSchemeSupported(uuid, mimeType);
}
status_t JDrm::initCheck() const {
return mDrm == NULL ? NO_INIT : OK;
}
// 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;
}
static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
size_t length = vector.size();
jbyteArray result = env->NewByteArray(length);
if (result != NULL) {
env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
}
return result;
}
static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
String8 result;
const char *s = env->GetStringUTFChars(jstr, NULL);
if (s) {
result = s;
env->ReleaseStringUTFChars(jstr, s);
}
return result;
}
/*
import java.util.HashMap;
import java.util.Set;
import java.Map.Entry;
import jav.util.Iterator;
HashMap<k, v> hm;
Set<Entry<k, v> > s = hm.entrySet();
Iterator i = s.iterator();
Entry e = s.next();
*/
static KeyedVector<String8, String8> HashMapToKeyedVector(
JNIEnv *env, jobject &hashMap, bool* pIsOK) {
jclass clazz = gFields.stringClassId;
KeyedVector<String8, String8> keyedVector;
*pIsOK = true;
jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
if (entrySet) {
jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
if (iterator) {
jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
while (hasNext) {
jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
if (entry) {
jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"HashMap key is not a String");
env->DeleteLocalRef(entry);
*pIsOK = false;
break;
}
jstring jkey = static_cast<jstring>(obj);
obj = env->CallObjectMethod(entry, gFields.entry.getValue);
if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"HashMap value is not a String");
env->DeleteLocalRef(entry);
*pIsOK = false;
break;
}
jstring jvalue = static_cast<jstring>(obj);
String8 key = JStringToString8(env, jkey);
String8 value = JStringToString8(env, jvalue);
keyedVector.add(key, value);
env->DeleteLocalRef(jkey);
env->DeleteLocalRef(jvalue);
hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
}
env->DeleteLocalRef(entry);
}
env->DeleteLocalRef(iterator);
}
env->DeleteLocalRef(entrySet);
}
return keyedVector;
}
static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
jclass clazz = gFields.hashmapClassId;
jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
for (size_t i = 0; i < map.size(); ++i) {
jstring jkey = env->NewStringUTF(map.keyAt(i).string());
jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
env->DeleteLocalRef(jkey);
env->DeleteLocalRef(jvalue);
}
return hashMap;
}
static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
List<Vector<uint8_t> > list) {
jclass clazz = gFields.arraylistClassId;
jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
List<Vector<uint8_t> >::iterator iter = list.begin();
while (iter != list.end()) {
jbyteArray byteArray = VectorToJByteArray(env, *iter);
env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
env->DeleteLocalRef(byteArray);
iter++;
}
return arrayList;
}
} // namespace android
using namespace android;
static sp<JDrm> setDrm(
JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
if (drm != NULL) {
drm->incStrong(thiz);
}
if (old != NULL) {
old->decStrong(thiz);
}
env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
return old;
}
static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
{
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
return false;
}
if (jsessionId == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
return false;
}
return true;
}
static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
sp<JDrm> drm = setDrm(env, thiz, NULL);
if (drm != NULL) {
drm->setListener(NULL);
drm->disconnect();
}
}
static void android_media_MediaDrm_native_init(JNIEnv *env) {
jclass clazz;
FIND_CLASS(clazz, "android/media/MediaDrm");
GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
jfieldID field;
GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
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");
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.requestType, clazz, "mRequestType", "I");
GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
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 = static_cast<jclass>(env->NewGlobalRef(clazz));
FIND_CLASS(clazz, "java/util/ArrayList");
GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
FIND_CLASS(clazz, "java/util/HashMap");
GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
FIND_CLASS(clazz, "java/util/Set");
GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
FIND_CLASS(clazz, "java/util/Iterator");
GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
FIND_CLASS(clazz, "java/util/Map$Entry");
GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
FIND_CLASS(clazz, "java/util/HashMap");
gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
FIND_CLASS(clazz, "java/lang/String");
gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
FIND_CLASS(clazz, "java/util/ArrayList");
gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
}
static void android_media_MediaDrm_native_setup(
JNIEnv *env, jobject thiz,
jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
if (uuidObj == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
return;
}
Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
if (uuid.size() != 16) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"invalid UUID size, expected 16 bytes");
return;
}
String8 packageName;
if (jappPackageName == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"application package name cannot be null");
return;
}
packageName = JStringToString8(env, jappPackageName);
sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
status_t err = drm->initCheck();
if (err != OK) {
jniThrowException(
env,
"android/media/UnsupportedSchemeException",
"Failed to instantiate drm object.");
return;
}
sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
drm->setListener(listener);
setDrm(env, thiz, drm);
}
static void android_media_MediaDrm_native_finalize(
JNIEnv *env, jobject thiz) {
android_media_MediaDrm_release(env, thiz);
}
static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
if (uuidObj == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return false;
}
Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
if (uuid.size() != 16) {
jniThrowException(
env,
"java/lang/IllegalArgumentException",
"invalid UUID size, expected 16 bytes");
return false;
}
String8 mimeType;
if (jmimeType != NULL) {
mimeType = JStringToString8(env, jmimeType);
}
return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
}
static jbyteArray android_media_MediaDrm_openSession(
JNIEnv *env, jobject thiz) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return NULL;
}
Vector<uint8_t> sessionId;
status_t err = drm->openSession(sessionId);
if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
return NULL;
}
return VectorToJByteArray(env, sessionId);
}
static void android_media_MediaDrm_closeSession(
JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
sp<IDrm> drm = GetDrm(env, thiz);
if (!CheckSession(env, drm, jsessionId)) {
return;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
status_t err = drm->closeSession(sessionId);
throwExceptionAsNecessary(env, err, "Failed to close session");
}
static jobject android_media_MediaDrm_getKeyRequest(
JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
jstring jmimeType, jint jkeyType, jobject joptParams) {
sp<IDrm> drm = GetDrm(env, thiz);
if (!CheckSession(env, drm, jsessionId)) {
return NULL;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Vector<uint8_t> initData;
if (jinitData != NULL) {
initData = JByteArrayToVector(env, jinitData);
}
String8 mimeType;
if (jmimeType != NULL) {
mimeType = JStringToString8(env, jmimeType);
}
DrmPlugin::KeyType keyType;
if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
keyType = DrmPlugin::kKeyType_Streaming;
} else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
keyType = DrmPlugin::kKeyType_Offline;
} else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
keyType = DrmPlugin::kKeyType_Release;
} else {
jniThrowException(env, "java/lang/IllegalArgumentException",
"invalid keyType");
return NULL;
}
KeyedVector<String8, String8> optParams;
if (joptParams != NULL) {
bool isOK;
optParams = HashMapToKeyedVector(env, joptParams, &isOK);
if (!isOK) {
return NULL;
}
}
Vector<uint8_t> request;
String8 defaultUrl;
DrmPlugin::KeyRequestType keyRequestType;
status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
keyType, optParams, request, defaultUrl, &keyRequestType);
if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
return NULL;
}
// Fill out return obj
jclass clazz;
FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
jobject keyObj = NULL;
if (clazz) {
keyObj = env->AllocObject(clazz);
jbyteArray jrequest = VectorToJByteArray(env, request);
env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
switch (keyRequestType) {
case DrmPlugin::kKeyRequestType_Initial:
env->SetIntField(keyObj, gFields.keyRequest.requestType,
gKeyRequestTypes.kKeyRequestTypeInitial);
break;
case DrmPlugin::kKeyRequestType_Renewal:
env->SetIntField(keyObj, gFields.keyRequest.requestType,
gKeyRequestTypes.kKeyRequestTypeRenewal);
break;
case DrmPlugin::kKeyRequestType_Release:
env->SetIntField(keyObj, gFields.keyRequest.requestType,
gKeyRequestTypes.kKeyRequestTypeRelease);
break;
default:
throwStateException(env, "DRM plugin failure: unknown key request type",
ERROR_DRM_UNKNOWN);
break;
}
}
return keyObj;
}
static jbyteArray android_media_MediaDrm_provideKeyResponse(
JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
sp<IDrm> drm = GetDrm(env, thiz);
if (!CheckSession(env, drm, jsessionId)) {
return NULL;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
if (jresponse == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"key response is null");
return NULL;
}
Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
Vector<uint8_t> keySetId;
status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
return NULL;
}
return VectorToJByteArray(env, keySetId);
}
static void android_media_MediaDrm_removeKeys(
JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
sp<IDrm> drm = GetDrm(env, thiz);
if (jkeysetId == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"keySetId is null");
return;
}
Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
status_t err = drm->removeKeys(keySetId);
throwExceptionAsNecessary(env, err, "Failed to remove keys");
}
static void android_media_MediaDrm_restoreKeys(
JNIEnv *env, jobject thiz, jbyteArray jsessionId,
jbyteArray jkeysetId) {
sp<IDrm> drm = GetDrm(env, thiz);
if (!CheckSession(env, drm, jsessionId)) {
return;
}
if (jkeysetId == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
status_t err = drm->restoreKeys(sessionId, keySetId);
throwExceptionAsNecessary(env, err, "Failed to restore keys");
}
static jobject android_media_MediaDrm_queryKeyStatus(
JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
sp<IDrm> drm = GetDrm(env, thiz);
if (!CheckSession(env, drm, jsessionId)) {
return NULL;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
KeyedVector<String8, String8> infoMap;
status_t err = drm->queryKeyStatus(sessionId, infoMap);
if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
return NULL;
}
return KeyedVectorToHashMap(env, infoMap);
}
static jobject android_media_MediaDrm_getProvisionRequestNative(
JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return NULL;
}
Vector<uint8_t> request;
String8 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")) {
return NULL;
}
// Fill out return obj
jclass clazz;
FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
jobject provisionObj = NULL;
if (clazz) {
provisionObj = env->AllocObject(clazz);
jbyteArray jrequest = VectorToJByteArray(env, request);
env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
}
return provisionObj;
}
static jobject android_media_MediaDrm_provideProvisionResponseNative(
JNIEnv *env, jobject thiz, jbyteArray jresponse) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return NULL;
}
if (jresponse == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"provision response is null");
return NULL;
}
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);
jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
}
throwExceptionAsNecessary(env, err, "Failed to handle provision response");
return certificateObj;
}
static jobject android_media_MediaDrm_getSecureStops(
JNIEnv *env, jobject thiz) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return NULL;
}
List<Vector<uint8_t> > secureStops;
status_t err = drm->getSecureStops(secureStops);
if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
return NULL;
}
return ListOfVectorsToArrayListOfByteArray(env, secureStops);
}
static jbyteArray android_media_MediaDrm_getSecureStop(
JNIEnv *env, jobject thiz, jbyteArray ssid) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return NULL;
}
Vector<uint8_t> secureStop;
status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
return NULL;
}
return VectorToJByteArray(env, secureStop);
}
static void android_media_MediaDrm_releaseSecureStops(
JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return;
}
Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
status_t err = drm->releaseSecureStops(ssRelease);
throwExceptionAsNecessary(env, err, "Failed to release secure stops");
}
static void android_media_MediaDrm_releaseAllSecureStops(
JNIEnv *env, jobject thiz) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return;
}
status_t err = drm->releaseAllSecureStops();
throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
}
static jstring android_media_MediaDrm_getPropertyString(
JNIEnv *env, jobject thiz, jstring jname) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return NULL;
}
if (jname == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"property name String is null");
return NULL;
}
String8 name = JStringToString8(env, jname);
String8 value;
status_t err = drm->getPropertyString(name, value);
if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
return NULL;
}
return env->NewStringUTF(value.string());
}
static jbyteArray android_media_MediaDrm_getPropertyByteArray(
JNIEnv *env, jobject thiz, jstring jname) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return NULL;
}
if (jname == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"property name String is null");
return NULL;
}
String8 name = JStringToString8(env, jname);
Vector<uint8_t> value;
status_t err = drm->getPropertyByteArray(name, value);
if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
return NULL;
}
return VectorToJByteArray(env, value);
}
static void android_media_MediaDrm_setPropertyString(
JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return;
}
if (jname == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"property name String is null");
return;
}
if (jvalue == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"property value String is null");
return;
}
String8 name = JStringToString8(env, jname);
String8 value = JStringToString8(env, jvalue);
status_t err = drm->setPropertyString(name, value);
throwExceptionAsNecessary(env, err, "Failed to set property");
}
static void android_media_MediaDrm_setPropertyByteArray(
JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
return;
}
if (jname == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"property name String is null");
return;
}
if (jvalue == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"property value byte array is null");
return;
}
String8 name = JStringToString8(env, jname);
Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
status_t err = drm->setPropertyByteArray(name, value);
throwExceptionAsNecessary(env, err, "Failed to set property");
}
static void android_media_MediaDrm_setCipherAlgorithmNative(
JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
jstring jalgorithm) {
sp<IDrm> drm = GetDrm(env, jdrm);
if (!CheckSession(env, drm, jsessionId)) {
return;
}
if (jalgorithm == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"algorithm String is null");
return;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
String8 algorithm = JStringToString8(env, jalgorithm);
status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
}
static void android_media_MediaDrm_setMacAlgorithmNative(
JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
jstring jalgorithm) {
sp<IDrm> drm = GetDrm(env, jdrm);
if (!CheckSession(env, drm, jsessionId)) {
return;
}
if (jalgorithm == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"algorithm String is null");
return;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
String8 algorithm = JStringToString8(env, jalgorithm);
status_t err = drm->setMacAlgorithm(sessionId, algorithm);
throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
}
static jbyteArray android_media_MediaDrm_encryptNative(
JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
sp<IDrm> drm = GetDrm(env, jdrm);
if (!CheckSession(env, drm, jsessionId)) {
return NULL;
}
if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"required argument is null");
return NULL;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
Vector<uint8_t> input(JByteArrayToVector(env, jinput));
Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
Vector<uint8_t> output;
status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
return NULL;
}
return VectorToJByteArray(env, output);
}
static jbyteArray android_media_MediaDrm_decryptNative(
JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
sp<IDrm> drm = GetDrm(env, jdrm);
if (!CheckSession(env, drm, jsessionId)) {
return NULL;
}
if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"required argument is null");
return NULL;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
Vector<uint8_t> input(JByteArrayToVector(env, jinput));
Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
Vector<uint8_t> output;
status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
return NULL;
}
return VectorToJByteArray(env, output);
}
static jbyteArray android_media_MediaDrm_signNative(
JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
jbyteArray jkeyId, jbyteArray jmessage) {
sp<IDrm> drm = GetDrm(env, jdrm);
if (!CheckSession(env, drm, jsessionId)) {
return NULL;
}
if (jkeyId == NULL || jmessage == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"required argument is null");
return NULL;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
Vector<uint8_t> signature;
status_t err = drm->sign(sessionId, keyId, message, signature);
if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
return NULL;
}
return VectorToJByteArray(env, signature);
}
static jboolean android_media_MediaDrm_verifyNative(
JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
sp<IDrm> drm = GetDrm(env, jdrm);
if (!CheckSession(env, drm, jsessionId)) {
return false;
}
if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"required argument is null");
return false;
}
Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
bool match;
status_t err = drm->verify(sessionId, keyId, message, signature, match);
throwExceptionAsNecessary(env, err, "Failed to verify");
return match;
}
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 const JNINativeMethod gMethods[] = {
{ "release", "()V", (void *)android_media_MediaDrm_release },
{ "native_init", "()V", (void *)android_media_MediaDrm_native_init },
{ "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
(void *)android_media_MediaDrm_native_setup },
{ "native_finalize", "()V",
(void *)android_media_MediaDrm_native_finalize },
{ "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
(void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
{ "openSession", "()[B",
(void *)android_media_MediaDrm_openSession },
{ "closeSession", "([B)V",
(void *)android_media_MediaDrm_closeSession },
{ "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
"Landroid/media/MediaDrm$KeyRequest;",
(void *)android_media_MediaDrm_getKeyRequest },
{ "provideKeyResponse", "([B[B)[B",
(void *)android_media_MediaDrm_provideKeyResponse },
{ "removeKeys", "([B)V",
(void *)android_media_MediaDrm_removeKeys },
{ "restoreKeys", "([B[B)V",
(void *)android_media_MediaDrm_restoreKeys },
{ "queryKeyStatus", "([B)Ljava/util/HashMap;",
(void *)android_media_MediaDrm_queryKeyStatus },
{ "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
(void *)android_media_MediaDrm_getProvisionRequestNative },
{ "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
(void *)android_media_MediaDrm_provideProvisionResponseNative },
{ "getSecureStops", "()Ljava/util/List;",
(void *)android_media_MediaDrm_getSecureStops },
{ "getSecureStop", "([B)[B",
(void *)android_media_MediaDrm_getSecureStop },
{ "releaseSecureStops", "([B)V",
(void *)android_media_MediaDrm_releaseSecureStops },
{ "releaseAllSecureStops", "()V",
(void *)android_media_MediaDrm_releaseAllSecureStops },
{ "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
(void *)android_media_MediaDrm_getPropertyString },
{ "getPropertyByteArray", "(Ljava/lang/String;)[B",
(void *)android_media_MediaDrm_getPropertyByteArray },
{ "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
(void *)android_media_MediaDrm_setPropertyString },
{ "setPropertyByteArray", "(Ljava/lang/String;[B)V",
(void *)android_media_MediaDrm_setPropertyByteArray },
{ "setCipherAlgorithmNative",
"(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
(void *)android_media_MediaDrm_setCipherAlgorithmNative },
{ "setMacAlgorithmNative",
"(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
(void *)android_media_MediaDrm_setMacAlgorithmNative },
{ "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
(void *)android_media_MediaDrm_encryptNative },
{ "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
(void *)android_media_MediaDrm_decryptNative },
{ "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
(void *)android_media_MediaDrm_signNative },
{ "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
(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) {
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaDrm", gMethods, NELEM(gMethods));
}