| /* |
| * Copyright (C) 2007 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. |
| */ |
| |
| /** |
| * @file drm1_jni.c |
| * |
| * This file implement the Java Native Interface |
| * for supporting OMA DRM 1.0 |
| */ |
| |
| #include <jni/drm1_jni.h> |
| #include <objmng/svc_drm.h> |
| #include "log.h" |
| #include "JNIHelp.h" |
| |
| |
| #define MS_PER_SECOND 1000 /* Milliseconds per second */ |
| #define MS_PER_MINUTE 60 * MS_PER_SECOND /* Milliseconds per minute */ |
| #define MS_PER_HOUR 60 * MS_PER_MINUTE /* Milliseconds per hour */ |
| #define MS_PER_DAY 24 * MS_PER_HOUR /* Milliseconds per day */ |
| |
| #define SECONDS_PER_MINUTE 60 /* Seconds per minute*/ |
| #define SECONDS_PER_HOUR 60 * SECONDS_PER_MINUTE /* Seconds per hour */ |
| #define SECONDS_PER_DAY 24 * SECONDS_PER_HOUR /* Seconds per day */ |
| |
| #define DAY_PER_MONTH 30 /* Days per month */ |
| #define DAY_PER_YEAR 365 /* Days per year */ |
| |
| /** Nonzero if 'y' is a leap year, else zero. */ |
| #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) |
| |
| /** Number of leap years from 1970 to 'y' (not including 'y' itself). */ |
| #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400) |
| |
| /** Accumulated number of days from 01-Jan up to start of current month. */ |
| static const int32_t ydays[] = { |
| 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 |
| }; |
| |
| #define int64_const(s) (s) |
| #define int64_add(dst, s1, s2) ((void)((dst) = (s1) + (s2))) |
| #define int64_mul(dst, s1, s2) ((void)((dst) = (int64_t)(s1) * (int64_t)(s2))) |
| |
| /** |
| * DRM data structure |
| */ |
| typedef struct _DrmData { |
| /** |
| * The id of the DRM content. |
| */ |
| int32_t id; |
| |
| /** |
| * The pointer of JNI interface. |
| */ |
| JNIEnv* env; |
| |
| /** |
| * The pointer of DRM raw content InputStream object. |
| */ |
| jobject* pInData; |
| |
| /** |
| * The len of the InputStream object. |
| */ |
| int32_t len; |
| |
| /** |
| * The next DRM data. |
| */ |
| struct _DrmData *next; |
| } DrmData; |
| |
| /** The table to hold all the DRM data. */ |
| static DrmData *drmTable = NULL; |
| |
| /** |
| * Allocate a new item of DrmData. |
| * |
| * \return a pointer to a DrmData item if allocate successfully, |
| * otherwise return NULL |
| */ |
| static DrmData * newItem(void) |
| { |
| DrmData *d = (DrmData *)malloc(sizeof(DrmData)); |
| |
| if (d != NULL) { |
| d->id = -1; |
| d->next = NULL; |
| } |
| |
| return d; |
| } |
| |
| /** |
| * Free the memory of the specified DrmData item <code>d</code>. |
| * |
| * \param d - a pointer to DrmData |
| */ |
| static void freeItem(DrmData *d) |
| { |
| assert(d != NULL); |
| |
| free(d); |
| } |
| |
| /** |
| * Insert a DrmData item with given <code>name</code> into the head of |
| * the DrmData list. |
| * |
| * @param d - the pointer of the JNI interface |
| * @param pInData - the pointer of the DRM content InputStream object. |
| * |
| * @return <code>JNI_DRM_SUCCESS</code> if insert successfully, otherwise |
| * return <code>JNI_DRM_FAILURE</code> |
| */ |
| static int32_t addItem(DrmData* d) |
| { |
| if (NULL == d) |
| return JNI_DRM_FAILURE; |
| |
| if (NULL == drmTable) { |
| drmTable = d; |
| return JNI_DRM_SUCCESS; |
| } |
| |
| d->next = drmTable; |
| drmTable = d; |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| /** |
| * Get the item from the DrmData list by the specified <code> |
| * id</code>. |
| * |
| * @param p - the pointer of the DRM content InputStream object. |
| * |
| * @return a pointer to the DrmData item if find it successfuly, |
| * otherwise return NULL |
| */ |
| static DrmData * getItem(int32_t id) |
| { |
| DrmData *d; |
| |
| if (NULL == drmTable) |
| return NULL; |
| |
| for (d = drmTable; d != NULL; d = d->next) { |
| if (id == d->id) |
| return d; |
| } |
| |
| return NULL; |
| } |
| |
| /** |
| * Remove the specified DrmData item <code>d</code>. |
| * |
| * @param p - the pointer of the DRM content InputStream object. |
| * |
| * @return <code>JNI_DRM_SUCCESS</code> if remove successfuly, |
| * otherwise return <code>JNI_DRM_FAILURE</code> |
| */ |
| static int32_t removeItem(int32_t id) |
| { |
| DrmData *curItem, *preItem, *dstItem; |
| |
| if (NULL == drmTable) |
| return JNI_DRM_FAILURE; |
| |
| preItem = NULL; |
| for (curItem = drmTable; curItem != NULL; curItem = curItem->next) { |
| if (id == curItem->id) { |
| if (curItem == drmTable) |
| drmTable = curItem->next; |
| else |
| preItem->next = curItem->next; |
| |
| freeItem(curItem); |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| preItem = curItem; |
| } |
| |
| return JNI_DRM_FAILURE; |
| } |
| |
| |
| static int32_t getInputStreamDataLength(int32_t handle) |
| { |
| JNIEnv* env; |
| jobject* pInputStream; |
| int32_t len; |
| DrmData* p; |
| jclass cls; |
| jmethodID mid; |
| |
| p = (DrmData *)handle; |
| |
| if (NULL == p) |
| return 0; |
| |
| env = p->env; |
| pInputStream = p->pInData; |
| len = p->len; |
| |
| if (NULL == env || p->len <= 0 || NULL == pInputStream) |
| return 0; |
| |
| /* check the original InputStream is available or not */ |
| cls = (*env)->GetObjectClass(env, *pInputStream); |
| mid = (*env)->GetMethodID(env, cls, "available", "()I"); |
| (*env)->DeleteLocalRef(env, cls); |
| |
| if (NULL == mid) |
| return 0; |
| |
| if (0 > (*env)->CallIntMethod(env, *pInputStream, mid)) |
| return 0; |
| |
| return len; |
| } |
| |
| static int32_t readInputStreamData(int32_t handle, uint8_t* buf, int32_t bufLen) |
| { |
| JNIEnv* env; |
| jobject* pInputStream; |
| int32_t len; |
| DrmData* p; |
| jclass cls; |
| jmethodID mid; |
| jbyteArray tmp; |
| int tmpLen; |
| jbyte* pNativeBuf; |
| |
| p = (DrmData *)handle; |
| |
| if (NULL == p || NULL == buf || bufLen <- 0) |
| return 0; |
| |
| env = p->env; |
| pInputStream = p->pInData; |
| len = p->len; |
| |
| if (NULL == env || p->len <= 0 || NULL == pInputStream) |
| return 0; |
| |
| cls = (*env)->GetObjectClass(env, *pInputStream); |
| mid = (*env)->GetMethodID(env, cls, "read", "([BII)I"); |
| tmp = (*env)->NewByteArray(env, bufLen); |
| bufLen = (*env)->CallIntMethod(env, *pInputStream, mid, tmp, 0, bufLen); |
| |
| (*env)->DeleteLocalRef(env, cls); |
| |
| if (-1 == bufLen) |
| return -1; |
| |
| pNativeBuf = (*env)->GetByteArrayElements(env, tmp, NULL); |
| memcpy(buf, pNativeBuf, bufLen); |
| (*env)->ReleaseByteArrayElements(env, tmp, pNativeBuf, 0); |
| (*env)->DeleteLocalRef(env, tmp); |
| |
| return bufLen; |
| } |
| |
| static const T_DRM_Rights_Info_Node *searchRightsObject(const jbyte* roId, const T_DRM_Rights_Info_Node* pRightsList) |
| { |
| const T_DRM_Rights_Info_Node *pTmp; |
| |
| if (NULL == roId || NULL == pRightsList) |
| return NULL; |
| |
| pTmp = pRightsList; |
| |
| while (NULL != pTmp) { |
| if(0 == strcmp((char *)roId, (char *)pTmp->roInfo.roId)) |
| break; |
| pTmp = pTmp->next; |
| } |
| |
| return pTmp; |
| } |
| |
| /** |
| * Returns the difference in seconds between the given GMT time |
| * and 1970-01-01 00:00:00 GMT. |
| * |
| * \param year the year (since 1970) |
| * \param month the month (1 - 12) |
| * \param day the day (1 - 31) |
| * \param hour the hour (0 - 23) |
| * \param minute the minute (0 - 59) |
| * \param second the second (0 - 59) |
| * |
| * \return the difference in seconds between the given GMT time |
| * and 1970-01-01 00:00:00 GMT. |
| */ |
| static int64_t mkgmtime( |
| uint32_t year, uint32_t month, uint32_t day, |
| uint32_t hour, uint32_t minute, uint32_t second) |
| { |
| int64_t result; |
| |
| /* |
| * FIXME: It does not check whether the specified days |
| * is valid based on the specified months. |
| */ |
| assert(year >= 1970 |
| && month > 0 && month <= 12 |
| && day > 0 && day <= 31 |
| && hour < 24 && minute < 60 |
| && second < 60); |
| |
| /* Set 'day' to the number of days into the year. */ |
| day += ydays[month - 1] + (month > 2 && leap (year)) - 1; |
| |
| /* Now calculate 'day' to the number of days since Jan 1, 1970. */ |
| day = day + 365 * (year - 1970) + nleap(year); |
| |
| int64_mul(result, int64_const(day), int64_const(SECONDS_PER_DAY)); |
| int64_add(result, result, int64_const( |
| SECONDS_PER_HOUR * hour + SECONDS_PER_MINUTE * minute + second)); |
| |
| return result; |
| } |
| |
| /** |
| * Compute the milliseconds by the specified <code>date</code> |
| * and <code>time</code>. |
| * |
| * @param date - the specified date, |
| * <code>date = year * 10000 + month * 100 + day</code> |
| * @param time - the specified time, |
| * <code>time = hour * 10000 + minute * 100 + second</code> |
| * |
| * @return the related milliseconds |
| */ |
| static int64_t computeTime(int32_t date, int32_t time) |
| { |
| int32_t year, month, day, hour, minute, second; |
| |
| year = date / 10000; |
| month = (date / 100) % 100; |
| day = date % 100; |
| hour = time / 10000; |
| minute = (time / 100) % 100; |
| second = time % 100; |
| |
| /* Adjust the invalid parameters. */ |
| if (year < 1970) year = 1970; |
| if (month < 1) month = 1; |
| if (month > 12) month = 12; |
| if (day < 1) day = 1; |
| if (day > 31) day = 31; |
| if (hour < 0) hour = 0; |
| if (hour > 23) hour = 23; |
| if (minute < 0) minute = 0; |
| if (minute > 59) minute = 59; |
| if (second < 0) second = 0; |
| if (second > 59) second = 59; |
| |
| return mkgmtime(year, month, day, hour, minute, second) * 1000; |
| } |
| |
| /** |
| * Compute the milliseconds by the specified <code>date</code> |
| * and <code>time</code>. |
| * Note that here we always treat 1 year as 365 days and 1 month as 30 days |
| * that is not precise. But it should not be a problem since OMA DRM 2.0 |
| * already restricts the interval representation to be day-based, |
| * i.e. there will not be an interval with year or month any more in the |
| * future. |
| * |
| * @param date - the specified date, |
| * <code>date = year * 10000 + month * 100 + day</code> |
| * @param time - the specified time, |
| * <code>time = hour * 10000 + minute * 100 + second</code> |
| * |
| * @return the related milliseconds |
| */ |
| static int64_t computeInterval(int32_t date, int32_t time) |
| { |
| int32_t year, month, day, hour, minute, second; |
| int64_t milliseconds; |
| |
| year = date / 10000; |
| month = (date / 100) % 100; |
| day = date % 100; |
| hour = time / 10000; |
| minute = (time / 100) % 100; |
| second = time % 100; |
| |
| /* milliseconds = ((((year * 365 + month * 30 + day) * 24 |
| * + hour) * 60 + minute) * 60 + second) * 1000; |
| */ |
| int64_mul(milliseconds, |
| int64_const(year * DAY_PER_YEAR + month * DAY_PER_MONTH + day), |
| int64_const(MS_PER_DAY)); |
| int64_add(milliseconds, milliseconds, |
| int64_const(hour * MS_PER_HOUR + minute * MS_PER_MINUTE + |
| second * MS_PER_SECOND)); |
| |
| return milliseconds; |
| } |
| |
| static jint getObjectIntField(JNIEnv * env, jobject obj, const char *name, jint * value) |
| { |
| jclass clazz; |
| jfieldID field; |
| |
| clazz = (*env)->GetObjectClass(env, obj); |
| if (NULL == clazz) |
| return JNI_DRM_FAILURE; |
| |
| field = (*env)->GetFieldID(env, clazz, name, "I"); |
| (*env)->DeleteLocalRef(env, clazz); |
| |
| if (NULL == field) |
| return JNI_DRM_FAILURE; |
| |
| *value = (*env)->GetIntField(env, obj, field); |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| static jint setObjectIntField(JNIEnv * env, jobject obj, const char *name, jint value) |
| { |
| jclass clazz; |
| jfieldID field; |
| |
| clazz = (*env)->GetObjectClass(env, obj); |
| if (NULL == clazz) |
| return JNI_DRM_FAILURE; |
| |
| field = (*env)->GetFieldID(env, clazz, name, "I"); |
| (*env)->DeleteLocalRef(env, clazz); |
| |
| if (NULL == field) |
| return JNI_DRM_FAILURE; |
| |
| (*env)->SetIntField(env, obj, field, value); |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| static jint setObjectLongField(JNIEnv * env, jobject obj, const char *name, jlong value) |
| { |
| jclass clazz; |
| jfieldID field; |
| |
| clazz = (*env)->GetObjectClass(env, obj); |
| if (NULL == clazz) |
| return JNI_DRM_FAILURE; |
| |
| field = (*env)->GetFieldID(env, clazz, name, "J"); |
| (*env)->DeleteLocalRef(env, clazz); |
| |
| if (NULL == field) |
| return JNI_DRM_FAILURE; |
| |
| (*env)->SetLongField(env, obj, field, value); |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| static jint setConstraintFields(JNIEnv * env, jobject constraint, T_DRM_Constraint_Info * pConstraint) |
| { |
| /* if no this permission */ |
| if (pConstraint->indicator == (uint8_t)DRM_NO_RIGHTS) { |
| if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", 0)) |
| return JNI_DRM_FAILURE; |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| /* set count field */ |
| if (pConstraint->indicator & DRM_COUNT_CONSTRAINT) { |
| if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", pConstraint->count)) |
| return JNI_DRM_FAILURE; |
| } |
| |
| /* set start time field */ |
| if (pConstraint->indicator & DRM_START_TIME_CONSTRAINT) { |
| int64_t startTime; |
| |
| startTime = computeTime(pConstraint->startDate, pConstraint->startTime); |
| |
| if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "startDate", startTime)) |
| return JNI_DRM_FAILURE; |
| } |
| |
| /* set end time field */ |
| if (pConstraint->indicator & DRM_END_TIME_CONSTRAINT) { |
| int64_t endTime; |
| |
| endTime = computeTime(pConstraint->endDate, pConstraint->endTime); |
| |
| if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "endDate", endTime)) |
| return JNI_DRM_FAILURE; |
| } |
| |
| /* set interval field */ |
| if (pConstraint->indicator & DRM_INTERVAL_CONSTRAINT) { |
| int64_t interval; |
| |
| interval = computeInterval(pConstraint->intervalDate, pConstraint->intervalTime); |
| |
| if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "interval", interval)) |
| return JNI_DRM_FAILURE; |
| } |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| static jint setRightsFields(JNIEnv * env, jobject rights, T_DRM_Rights_Info* pRoInfo) |
| { |
| jclass clazz; |
| jfieldID field; |
| jstring str; |
| jint index; |
| |
| clazz = (*env)->GetObjectClass(env, rights); |
| if (NULL == clazz) |
| return JNI_DRM_FAILURE; |
| |
| /* set roId field */ |
| field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); |
| (*env)->DeleteLocalRef(env, clazz); |
| |
| if (NULL == field) |
| return JNI_DRM_FAILURE; |
| |
| str = (*env)->NewStringUTF(env, (char *)pRoInfo->roId); |
| if (NULL == str) |
| return JNI_DRM_FAILURE; |
| |
| (*env)->SetObjectField(env, rights, field, str); |
| (*env)->DeleteLocalRef(env, str); |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent |
| (JNIEnv * env, jobject rawContent, jobject data, jint len, jint mimeType) |
| { |
| int32_t id; |
| T_DRM_Input_Data inData; |
| DrmData* drmInData; |
| |
| switch (mimeType) { |
| case JNI_DRM_MIMETYPE_MESSAGE: |
| mimeType = TYPE_DRM_MESSAGE; |
| break; |
| case JNI_DRM_MIMETYPE_CONTENT: |
| mimeType = TYPE_DRM_CONTENT; |
| break; |
| default: |
| return JNI_DRM_FAILURE; |
| } |
| |
| drmInData = newItem(); |
| if (NULL == drmInData) |
| return JNI_DRM_FAILURE; |
| |
| drmInData->env = env; |
| drmInData->pInData = &data; |
| drmInData->len = len; |
| |
| if (JNI_DRM_FAILURE == addItem(drmInData)) |
| return JNI_DRM_FAILURE; |
| |
| inData.inputHandle = (int32_t)drmInData; |
| inData.mimeType = mimeType; |
| inData.getInputDataLength = getInputStreamDataLength; |
| inData.readInputData = readInputStreamData; |
| |
| id = SVC_drm_openSession(inData); |
| if (id < 0) |
| return JNI_DRM_FAILURE; |
| |
| drmInData->id = id; |
| |
| return id; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jstring JNICALL |
| Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress |
| (JNIEnv * env, jobject rawContent) |
| { |
| jint id; |
| uint8_t rightsIssuer[256] = {0}; |
| jstring str = NULL; |
| |
| if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) |
| return NULL; |
| |
| if (DRM_SUCCESS == SVC_drm_getRightsIssuer(id, rightsIssuer)) |
| str = (*env)->NewStringUTF(env, (char *)rightsIssuer); |
| |
| return str; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod |
| (JNIEnv * env, jobject rawContent) |
| { |
| jint id; |
| int32_t res; |
| |
| if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) |
| return JNI_DRM_FAILURE; |
| |
| res = SVC_drm_getDeliveryMethod(id); |
| |
| switch (res) { |
| case FORWARD_LOCK: |
| return JNI_DRM_FORWARD_LOCK; |
| case COMBINED_DELIVERY: |
| return JNI_DRM_COMBINED_DELIVERY; |
| case SEPARATE_DELIVERY: |
| return JNI_DRM_SEPARATE_DELIVERY; |
| case SEPARATE_DELIVERY_FL: |
| return JNI_DRM_SEPARATE_DELIVERY_DM; |
| default: |
| return JNI_DRM_FAILURE; |
| } |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRawContent_nativeReadContent |
| (JNIEnv * env, jobject rawContent, jbyteArray buf, jint bufOff, jint len, jint mediaOff) |
| { |
| jint id; |
| jbyte *nativeBuf; |
| jclass cls; |
| jmethodID mid; |
| DrmData* p; |
| jobject inputStream; |
| jfieldID field; |
| |
| if (NULL == buf) { |
| jniThrowNullPointerException(env, "b == null"); |
| return JNI_DRM_FAILURE; |
| } |
| |
| if (len < 0 || bufOff < 0 || len + bufOff > (*env)->GetArrayLength(env, buf)) { |
| jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL); |
| return JNI_DRM_FAILURE; |
| } |
| |
| if (mediaOff < 0 || len == 0) |
| return JNI_DRM_FAILURE; |
| |
| if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) |
| return JNI_DRM_FAILURE; |
| |
| p = getItem(id); |
| if (NULL == p) |
| return JNI_DRM_FAILURE; |
| |
| cls = (*env)->GetObjectClass(env, rawContent); |
| if (NULL == cls) |
| return JNI_DRM_FAILURE; |
| |
| field = (*env)->GetFieldID(env, cls, "inData", "Ljava/io/BufferedInputStream;"); |
| (*env)->DeleteLocalRef(env, cls); |
| |
| if (NULL == field) |
| return JNI_DRM_FAILURE; |
| |
| inputStream = (*env)->GetObjectField(env, rawContent, field); |
| |
| p->env = env; |
| p->pInData = &inputStream; |
| |
| nativeBuf = (*env)->GetByteArrayElements(env, buf, NULL); |
| |
| len = SVC_drm_getContent(id, mediaOff, (uint8_t *)nativeBuf + bufOff, len); |
| |
| (*env)->ReleaseByteArrayElements(env, buf, nativeBuf, 0); |
| |
| if (DRM_MEDIA_EOF == len) |
| return JNI_DRM_EOF; |
| if (len <= 0) |
| return JNI_DRM_FAILURE; |
| |
| return len; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jstring JNICALL |
| Java_android_drm_mobile1_DrmRawContent_nativeGetContentType |
| (JNIEnv * env, jobject rawContent) |
| { |
| jint id; |
| uint8_t contentType[64] = {0}; |
| jstring str = NULL; |
| |
| if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) |
| return NULL; |
| |
| if (DRM_SUCCESS == SVC_drm_getContentType(id, contentType)) |
| str = (*env)->NewStringUTF(env, (char *)contentType); |
| |
| return str; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength |
| (JNIEnv * env, jobject rawContent) |
| { |
| jint id; |
| int32_t len; |
| |
| if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) |
| return JNI_DRM_FAILURE; |
| |
| len = SVC_drm_getContentLength(id); |
| |
| if (DRM_UNKNOWN_DATA_LEN == len) |
| return JNI_DRM_UNKNOWN_DATA_LEN; |
| |
| if (0 > len) |
| return JNI_DRM_FAILURE; |
| |
| return len; |
| } |
| |
| /* native interface */ |
| JNIEXPORT void JNICALL |
| Java_android_drm_mobile1_DrmRawContent_finalize |
| (JNIEnv * env, jobject rawContent) |
| { |
| jint id; |
| |
| if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) |
| return; |
| |
| removeItem(id); |
| |
| SVC_drm_closeSession(id); |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo |
| (JNIEnv * env, jobject rights, jint permission, jobject constraint) |
| { |
| jclass clazz; |
| jfieldID field; |
| jstring str; |
| uint8_t *nativeStr; |
| T_DRM_Rights_Info_Node *pRightsList; |
| T_DRM_Rights_Info_Node *pCurNode; |
| T_DRM_Constraint_Info *pConstraint; |
| |
| clazz = (*env)->GetObjectClass(env, rights); |
| if (NULL == clazz) |
| return JNI_DRM_FAILURE; |
| |
| field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); |
| (*env)->DeleteLocalRef(env, clazz); |
| |
| if (NULL == field) |
| return JNI_DRM_FAILURE; |
| |
| str = (*env)->GetObjectField(env, rights, field); |
| |
| nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); |
| if (NULL == nativeStr) |
| return JNI_DRM_FAILURE; |
| |
| /* this means forward-lock rights */ |
| if (0 == strcmp((char *)nativeStr, "ForwardLock")) { |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| return JNI_DRM_SUCCESS; |
| } |
| |
| if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) { |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| return JNI_DRM_FAILURE; |
| } |
| |
| pCurNode = searchRightsObject((jbyte *)nativeStr, pRightsList); |
| if (NULL == pCurNode) { |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| SVC_drm_freeRightsInfoList(pRightsList); |
| return JNI_DRM_FAILURE; |
| } |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| |
| switch (permission) { |
| case JNI_DRM_PERMISSION_PLAY: |
| pConstraint = &(pCurNode->roInfo.playRights); |
| break; |
| case JNI_DRM_PERMISSION_DISPLAY: |
| pConstraint = &(pCurNode->roInfo.displayRights); |
| break; |
| case JNI_DRM_PERMISSION_EXECUTE: |
| pConstraint = &(pCurNode->roInfo.executeRights); |
| break; |
| case JNI_DRM_PERMISSION_PRINT: |
| pConstraint = &(pCurNode->roInfo.printRights); |
| break; |
| default: |
| SVC_drm_freeRightsInfoList(pRightsList); |
| return JNI_DRM_FAILURE; |
| } |
| |
| /* set constraint field */ |
| if (JNI_DRM_FAILURE == setConstraintFields(env, constraint, pConstraint)) { |
| SVC_drm_freeRightsInfoList(pRightsList); |
| return JNI_DRM_FAILURE; |
| } |
| |
| SVC_drm_freeRightsInfoList(pRightsList); |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRights_nativeConsumeRights |
| (JNIEnv * env, jobject rights, jint permission) |
| { |
| jclass clazz; |
| jfieldID field; |
| jstring str; |
| uint8_t *nativeStr; |
| int32_t id; |
| |
| switch (permission) { |
| case JNI_DRM_PERMISSION_PLAY: |
| permission = DRM_PERMISSION_PLAY; |
| break; |
| case JNI_DRM_PERMISSION_DISPLAY: |
| permission = DRM_PERMISSION_DISPLAY; |
| break; |
| case JNI_DRM_PERMISSION_EXECUTE: |
| permission = DRM_PERMISSION_EXECUTE; |
| break; |
| case JNI_DRM_PERMISSION_PRINT: |
| permission = DRM_PERMISSION_PRINT; |
| break; |
| default: |
| return JNI_DRM_FAILURE; |
| } |
| |
| clazz = (*env)->GetObjectClass(env, rights); |
| if (NULL == clazz) |
| return JNI_DRM_FAILURE; |
| |
| field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); |
| (*env)->DeleteLocalRef(env, clazz); |
| |
| if (NULL == field) |
| return JNI_DRM_FAILURE; |
| |
| str = (*env)->GetObjectField(env, rights, field); |
| |
| nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); |
| if (NULL == nativeStr) |
| return JNI_DRM_FAILURE; |
| |
| if (0 == strcmp("ForwardLock", (char *)nativeStr)) { |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| return JNI_DRM_SUCCESS; |
| } |
| |
| if (DRM_SUCCESS != SVC_drm_updateRights(nativeStr, permission)) { |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| return JNI_DRM_FAILURE; |
| } |
| |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| |
| return JNI_DRM_SUCCESS; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights |
| (JNIEnv * env, jobject rightsManager, jobject data, jint len, jint mimeType, jobject rights) |
| { |
| int32_t id; |
| T_DRM_Input_Data inData; |
| DrmData* drmInData; |
| jclass cls; |
| jmethodID mid; |
| T_DRM_Rights_Info rightsInfo; |
| |
| switch (mimeType) { |
| case JNI_DRM_MIMETYPE_RIGHTS_XML: |
| mimeType = TYPE_DRM_RIGHTS_XML; |
| break; |
| case JNI_DRM_MIMETYPE_RIGHTS_WBXML: |
| mimeType = TYPE_DRM_RIGHTS_WBXML; |
| break; |
| case JNI_DRM_MIMETYPE_MESSAGE: |
| mimeType = TYPE_DRM_MESSAGE; |
| break; |
| default: |
| return JNI_DRM_FAILURE; |
| } |
| |
| drmInData = newItem(); |
| if (NULL == drmInData) |
| return JNI_DRM_FAILURE; |
| |
| drmInData->env = env; |
| drmInData->pInData = &data; |
| drmInData->len = len; |
| |
| inData.inputHandle = (int32_t)drmInData; |
| inData.mimeType = mimeType; |
| inData.getInputDataLength = getInputStreamDataLength; |
| inData.readInputData = readInputStreamData; |
| |
| memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info)); |
| if (DRM_FAILURE == SVC_drm_installRights(inData, &rightsInfo)) |
| return JNI_DRM_FAILURE; |
| |
| freeItem(drmInData); |
| |
| return setRightsFields(env, rights, &rightsInfo); |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights |
| (JNIEnv * env, jobject rightsManager, jobject rawContent, jobject rights) |
| { |
| jint id; |
| T_DRM_Rights_Info rightsInfo; |
| |
| if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) |
| return JNI_DRM_FAILURE; |
| |
| memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info)); |
| if (DRM_SUCCESS != SVC_drm_getRightsInfo(id, &rightsInfo)) |
| return JNI_DRM_FAILURE; |
| |
| return setRightsFields(env, rights, &rightsInfo); |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights |
| (JNIEnv * env, jobject rightsManager) |
| { |
| T_DRM_Rights_Info_Node *pRightsList; |
| T_DRM_Rights_Info_Node *pCurNode; |
| int32_t num = 0; |
| |
| if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) |
| return JNI_DRM_FAILURE; |
| |
| pCurNode = pRightsList; |
| while (pCurNode != NULL) { |
| num++; |
| pCurNode = pCurNode->next; |
| } |
| |
| SVC_drm_freeRightsInfoList(pRightsList); |
| |
| return num; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList |
| (JNIEnv * env, jobject rightsManager, jobjectArray rightsArray, jint num) |
| { |
| T_DRM_Rights_Info_Node *pRightsList; |
| T_DRM_Rights_Info_Node *pCurNode; |
| int32_t index; |
| |
| if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) |
| return JNI_DRM_FAILURE; |
| |
| pCurNode = pRightsList; |
| for (index = 0; NULL != pCurNode; index++) { |
| jobject rights = (*env)->GetObjectArrayElement(env, rightsArray, index); |
| if (NULL == rights) |
| break; |
| |
| if (JNI_DRM_FAILURE == setRightsFields(env, rights, &(pCurNode->roInfo))) |
| break; |
| |
| (*env)->SetObjectArrayElement(env, rightsArray, index, rights); |
| |
| pCurNode = pCurNode->next; |
| } |
| |
| SVC_drm_freeRightsInfoList(pRightsList); |
| |
| return index; |
| } |
| |
| /* native interface */ |
| JNIEXPORT jint JNICALL |
| Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights |
| (JNIEnv * env, jobject rightsManager, jobject rights) |
| { |
| jclass clazz; |
| jfieldID field; |
| jstring str; |
| uint8_t *nativeStr; |
| |
| clazz = (*env)->GetObjectClass(env, rights); |
| if (NULL == clazz) |
| return JNI_DRM_FAILURE; |
| |
| field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); |
| if (NULL == field) |
| return JNI_DRM_FAILURE; |
| |
| str = (*env)->GetObjectField(env, rights, field); |
| |
| nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); |
| if (NULL == nativeStr) |
| return JNI_DRM_FAILURE; |
| |
| if (0 == strcmp("ForwardLock", (char *)nativeStr)) |
| return JNI_DRM_SUCCESS; |
| |
| if (DRM_SUCCESS != SVC_drm_deleteRights(nativeStr)) { |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| return JNI_DRM_FAILURE; |
| } |
| |
| (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); |
| return JNI_DRM_SUCCESS; |
| } |
| |
| /* |
| * Table of methods associated with the DrmRawContent class. |
| */ |
| static JNINativeMethod gDrmRawContentMethods[] = { |
| /* name, signature, funcPtr */ |
| {"nativeConstructDrmContent", "(Ljava/io/InputStream;II)I", |
| (void*)Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent}, |
| {"nativeGetRightsAddress", "()Ljava/lang/String;", |
| (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress}, |
| {"nativeGetDeliveryMethod", "()I", |
| (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod}, |
| {"nativeReadContent", "([BIII)I", |
| (void*)Java_android_drm_mobile1_DrmRawContent_nativeReadContent}, |
| {"nativeGetContentType", "()Ljava/lang/String;", |
| (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentType}, |
| {"nativeGetContentLength", "()I", |
| (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength}, |
| {"finalize", "()V", |
| (void*)Java_android_drm_mobile1_DrmRawContent_finalize}, |
| }; |
| |
| /* |
| * Table of methods associated with the DrmRights class. |
| */ |
| static JNINativeMethod gDrmRightsMethods[] = { |
| /* name, signature, funcPtr */ |
| {"nativeGetConstraintInfo", "(ILandroid/drm/mobile1/DrmConstraintInfo;)I", |
| (void*)Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo}, |
| {"nativeConsumeRights", "(I)I", |
| (void*)Java_android_drm_mobile1_DrmRights_nativeConsumeRights}, |
| }; |
| |
| /* |
| * Table of methods associated with the DrmRightsManager class. |
| */ |
| static JNINativeMethod gDrmRightsManagerMethods[] = { |
| /* name, signature, funcPtr */ |
| {"nativeInstallDrmRights", "(Ljava/io/InputStream;IILandroid/drm/mobile1/DrmRights;)I", |
| (void*)Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights}, |
| {"nativeQueryRights", "(Landroid/drm/mobile1/DrmRawContent;Landroid/drm/mobile1/DrmRights;)I", |
| (void*)Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights}, |
| {"nativeGetNumOfRights", "()I", |
| (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights}, |
| {"nativeGetRightsList", "([Landroid/drm/mobile1/DrmRights;I)I", |
| (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList}, |
| {"nativeDeleteRights", "(Landroid/drm/mobile1/DrmRights;)I", |
| (void*)Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights}, |
| }; |
| |
| /* |
| * Register several native methods for one class. |
| */ |
| static int registerNativeMethods(JNIEnv* env, const char* className, |
| JNINativeMethod* gMethods, int numMethods) |
| { |
| jclass clazz; |
| |
| clazz = (*env)->FindClass(env, className); |
| if (clazz == NULL) |
| return JNI_FALSE; |
| |
| if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) |
| return JNI_FALSE; |
| |
| return JNI_TRUE; |
| } |
| |
| /* |
| * Register native methods for all classes we know about. |
| */ |
| static int registerNatives(JNIEnv* env) |
| { |
| if (!registerNativeMethods(env, "android/drm/mobile1/DrmRawContent", |
| gDrmRawContentMethods, sizeof(gDrmRawContentMethods) / sizeof(gDrmRawContentMethods[0]))) |
| return JNI_FALSE; |
| |
| if (!registerNativeMethods(env, "android/drm/mobile1/DrmRights", |
| gDrmRightsMethods, sizeof(gDrmRightsMethods) / sizeof(gDrmRightsMethods[0]))) |
| return JNI_FALSE; |
| |
| if (!registerNativeMethods(env, "android/drm/mobile1/DrmRightsManager", |
| gDrmRightsManagerMethods, sizeof(gDrmRightsManagerMethods) / sizeof(gDrmRightsManagerMethods[0]))) |
| return JNI_FALSE; |
| |
| return JNI_TRUE; |
| } |
| |
| jint JNI_OnLoad(JavaVM* vm, void* reserved) |
| { |
| JNIEnv* env = NULL; |
| jint result = -1; |
| |
| printf("Entering JNI_OnLoad\n"); |
| |
| if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) |
| goto bail; |
| |
| assert(env != NULL); |
| |
| if (!registerNatives(env)) |
| goto bail; |
| |
| /* success -- return valid version number */ |
| result = JNI_VERSION_1_4; |
| |
| bail: |
| printf("Leaving JNI_OnLoad (result=0x%x)\n", result); |
| return result; |
| } |