/*
* 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"
#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) {
jclass newExcCls = (*env)->FindClass(env, "java/lang/NullPointerException");
if (newExcCls == NULL)
/* Unable to find the exception class, give up. */
return JNI_DRM_FAILURE;
(*env)->ThrowNew(env, newExcCls, "b is null");
}
if (len < 0 || bufOff < 0 || len + bufOff > (*env)->GetArrayLength(env, buf)) {
jclass newExcCls = (*env)->FindClass(env, "java/lang/IndexOutOfBoundsException");
if (newExcCls == NULL)
/* Unable to find the exception class, give up. */
return JNI_DRM_FAILURE;
(*env)->ThrowNew(env, newExcCls, NULL);
}
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;
}