drm1_jni.c revision 15dd15fd572df6b6f785dff75f66e9b99f40322a
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * @file drm1_jni.c
19 *
20 * This file implement the Java Native Interface
21 * for supporting OMA DRM 1.0
22 */
23
24#include <jni/drm1_jni.h>
25#include <objmng/svc_drm.h>
26#include "log.h"
27#include "JNIHelp.h"
28
29
30#define MS_PER_SECOND 1000                  /* Milliseconds per second */
31#define MS_PER_MINUTE 60 * MS_PER_SECOND    /* Milliseconds per minute */
32#define MS_PER_HOUR   60 * MS_PER_MINUTE    /* Milliseconds per hour */
33#define MS_PER_DAY    24 * MS_PER_HOUR      /* Milliseconds per day */
34
35#define SECONDS_PER_MINUTE 60                       /* Seconds per minute*/
36#define SECONDS_PER_HOUR   60 * SECONDS_PER_MINUTE  /* Seconds per hour */
37#define SECONDS_PER_DAY    24 * SECONDS_PER_HOUR    /* Seconds per day */
38
39#define DAY_PER_MONTH 30                    /* Days per month */
40#define DAY_PER_YEAR  365                   /* Days per year */
41
42/** Nonzero if 'y' is a leap year, else zero. */
43#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
44
45/** Number of leap years from 1970 to 'y' (not including 'y' itself). */
46#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
47
48/** Accumulated number of days from 01-Jan up to start of current month. */
49static const int32_t ydays[] = {
50    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
51};
52
53#define int64_const(s)          (s)
54#define int64_add(dst, s1, s2)  ((void)((dst) = (s1) + (s2)))
55#define int64_mul(dst, s1, s2)  ((void)((dst) = (int64_t)(s1) * (int64_t)(s2)))
56
57/**
58 * DRM data structure
59 */
60typedef struct _DrmData {
61    /**
62     * The id of the DRM content.
63     */
64    int32_t id;
65
66    /**
67     * The pointer of JNI interface.
68     */
69    JNIEnv* env;
70
71    /**
72     * The pointer of DRM raw content InputStream object.
73     */
74    jobject* pInData;
75
76    /**
77     * The len of the InputStream object.
78     */
79    int32_t len;
80
81    /**
82     * The next DRM data.
83     */
84    struct _DrmData *next;
85} DrmData;
86
87/** The table to hold all the DRM data. */
88static DrmData *drmTable = NULL;
89
90/**
91 * Allocate a new item of DrmData.
92 *
93 * \return a pointer to a DrmData item if allocate successfully,
94 *         otherwise return NULL
95 */
96static DrmData * newItem(void)
97{
98    DrmData *d = (DrmData *)malloc(sizeof(DrmData));
99
100    if (d != NULL) {
101        d->id = -1;
102        d->next = NULL;
103    }
104
105    return d;
106}
107
108/**
109 * Free the memory of the specified DrmData item <code>d</code>.
110 *
111 * \param d - a pointer to DrmData
112 */
113static void freeItem(DrmData *d)
114{
115    assert(d != NULL);
116
117    free(d);
118}
119
120/**
121 * Insert a DrmData item with given <code>name</code> into the head of
122 * the DrmData list.
123 *
124 * @param d - the pointer of the JNI interface
125 * @param pInData - the pointer of the DRM content InputStream object.
126 *
127 * @return <code>JNI_DRM_SUCCESS</code> if insert successfully, otherwise
128 *         return <code>JNI_DRM_FAILURE</code>
129 */
130static int32_t addItem(DrmData* d)
131{
132    if (NULL == d)
133        return JNI_DRM_FAILURE;
134
135    if (NULL == drmTable) {
136        drmTable = d;
137        return JNI_DRM_SUCCESS;
138    }
139
140    d->next = drmTable;
141    drmTable = d;
142
143    return JNI_DRM_SUCCESS;
144}
145
146/**
147 * Get the item from the DrmData list by the specified <code>
148 * id</code>.
149 *
150 * @param p - the pointer of the DRM content InputStream object.
151 *
152 * @return a pointer to the DrmData item if find it successfuly,
153 *         otherwise return NULL
154 */
155static DrmData * getItem(int32_t id)
156{
157    DrmData *d;
158
159    if (NULL == drmTable)
160        return NULL;
161
162    for (d = drmTable; d != NULL; d = d->next) {
163        if (id == d->id)
164            return d;
165    }
166
167    return NULL;
168}
169
170/**
171 * Remove the specified DrmData item <code>d</code>.
172 *
173 * @param p - the pointer of the DRM content InputStream object.
174 *
175 * @return <code>JNI_DRM_SUCCESS</code> if remove successfuly,
176 *         otherwise return <code>JNI_DRM_FAILURE</code>
177 */
178static int32_t removeItem(int32_t id)
179{
180    DrmData *curItem, *preItem, *dstItem;
181
182    if (NULL == drmTable)
183        return JNI_DRM_FAILURE;
184
185    preItem = NULL;
186    for (curItem = drmTable; curItem != NULL; curItem = curItem->next) {
187        if (id == curItem->id) {
188            if (curItem == drmTable)
189                drmTable = curItem->next;
190            else
191                preItem->next = curItem->next;
192
193            freeItem(curItem);
194
195            return JNI_DRM_SUCCESS;
196        }
197
198        preItem = curItem;
199    }
200
201    return JNI_DRM_FAILURE;
202}
203
204
205static int32_t getInputStreamDataLength(int32_t handle)
206{
207    JNIEnv* env;
208    jobject* pInputStream;
209    int32_t len;
210    DrmData* p;
211    jclass cls;
212    jmethodID mid;
213
214    p = (DrmData *)handle;
215
216    if (NULL == p)
217        return 0;
218
219    env = p->env;
220    pInputStream = p->pInData;
221    len = p->len;
222
223    if (NULL == env || p->len <= 0 || NULL == pInputStream)
224        return 0;
225
226    /* check the original InputStream is available or not */
227    cls = (*env)->GetObjectClass(env, *pInputStream);
228    mid = (*env)->GetMethodID(env, cls, "available", "()I");
229    (*env)->DeleteLocalRef(env, cls);
230
231    if (NULL == mid)
232        return 0;
233
234    if (0 > (*env)->CallIntMethod(env, *pInputStream, mid))
235        return 0;
236
237    return len;
238}
239
240static int32_t readInputStreamData(int32_t handle, uint8_t* buf, int32_t bufLen)
241{
242    JNIEnv* env;
243    jobject* pInputStream;
244    int32_t len;
245    DrmData* p;
246    jclass cls;
247    jmethodID mid;
248    jbyteArray tmp;
249    int tmpLen;
250    jbyte* pNativeBuf;
251
252    p = (DrmData *)handle;
253
254    if (NULL == p || NULL == buf || bufLen <- 0)
255        return 0;
256
257    env = p->env;
258    pInputStream = p->pInData;
259    len = p->len;
260
261    if (NULL == env || p->len <= 0 || NULL == pInputStream)
262        return 0;
263
264    cls = (*env)->GetObjectClass(env, *pInputStream);
265    mid = (*env)->GetMethodID(env, cls, "read", "([BII)I");
266    tmp = (*env)->NewByteArray(env, bufLen);
267    bufLen = (*env)->CallIntMethod(env, *pInputStream, mid, tmp, 0, bufLen);
268
269    (*env)->DeleteLocalRef(env, cls);
270
271    if (-1 == bufLen)
272        return -1;
273
274    pNativeBuf = (*env)->GetByteArrayElements(env, tmp, NULL);
275    memcpy(buf, pNativeBuf, bufLen);
276    (*env)->ReleaseByteArrayElements(env, tmp, pNativeBuf, 0);
277    (*env)->DeleteLocalRef(env, tmp);
278
279    return bufLen;
280}
281
282static const T_DRM_Rights_Info_Node *searchRightsObject(const jbyte* roId, const T_DRM_Rights_Info_Node* pRightsList)
283{
284    const T_DRM_Rights_Info_Node *pTmp;
285
286    if (NULL == roId || NULL == pRightsList)
287        return NULL;
288
289    pTmp = pRightsList;
290
291    while (NULL != pTmp) {
292        if(0 == strcmp((char *)roId, (char *)pTmp->roInfo.roId))
293            break;
294        pTmp = pTmp->next;
295    }
296
297    return pTmp;
298}
299
300/**
301 * Returns the difference in seconds between the given GMT time
302 * and 1970-01-01 00:00:00 GMT.
303 *
304 * \param year the year (since 1970)
305 * \param month the month (1 - 12)
306 * \param day the day (1 - 31)
307 * \param hour the hour (0 - 23)
308 * \param minute the minute (0 - 59)
309 * \param second the second (0 - 59)
310 *
311 * \return the difference in seconds between the given GMT time
312 *         and 1970-01-01 00:00:00 GMT.
313 */
314static int64_t mkgmtime(
315        uint32_t year, uint32_t month, uint32_t day,
316        uint32_t hour, uint32_t minute, uint32_t second)
317{
318    int64_t result;
319
320    /*
321     * FIXME: It does not check whether the specified days
322     *        is valid based on the specified months.
323     */
324    assert(year >= 1970
325            && month > 0 && month <= 12
326            && day > 0 && day <= 31
327            && hour < 24 && minute < 60
328            && second < 60);
329
330    /* Set 'day' to the number of days into the year. */
331    day += ydays[month - 1] + (month > 2 && leap (year)) - 1;
332
333    /* Now calculate 'day' to the number of days since Jan 1, 1970. */
334    day = day + 365 * (year - 1970) + nleap(year);
335
336    int64_mul(result, int64_const(day), int64_const(SECONDS_PER_DAY));
337    int64_add(result, result, int64_const(
338        SECONDS_PER_HOUR * hour + SECONDS_PER_MINUTE * minute + second));
339
340    return result;
341}
342
343/**
344 * Compute the milliseconds by the specified <code>date</code>
345 * and <code>time</code>.
346 *
347 * @param date - the specified date,
348 *               <code>date = year * 10000 + month * 100 + day</code>
349 * @param time - the specified time,
350 *               <code>time = hour * 10000 + minute * 100 + second</code>
351 *
352 * @return the related milliseconds
353 */
354static int64_t computeTime(int32_t date, int32_t time)
355{
356    int32_t year, month, day, hour, minute, second;
357
358    year = date / 10000;
359    month = (date / 100) % 100;
360    day = date % 100;
361    hour = time / 10000;
362    minute = (time / 100) % 100;
363    second = time % 100;
364
365    /* Adjust the invalid parameters. */
366    if (year < 1970) year = 1970;
367    if (month < 1) month = 1;
368    if (month > 12) month = 12;
369    if (day < 1) day = 1;
370    if (day > 31) day = 31;
371    if (hour < 0) hour = 0;
372    if (hour > 23) hour = 23;
373    if (minute < 0) minute = 0;
374    if (minute > 59) minute = 59;
375    if (second < 0) second = 0;
376    if (second > 59) second = 59;
377
378    return mkgmtime(year, month, day, hour, minute, second) * 1000;
379}
380
381/**
382 * Compute the milliseconds by the specified <code>date</code>
383 * and <code>time</code>.
384 * Note that here we always treat 1 year as 365 days and 1 month as 30 days
385 * that is not precise. But it should not be a problem since OMA DRM 2.0
386 * already restricts the interval representation to be day-based,
387 * i.e. there will not be an interval with year or month any more in the
388 * future.
389 *
390 * @param date - the specified date,
391 *               <code>date = year * 10000 + month * 100 + day</code>
392 * @param time - the specified time,
393 *               <code>time = hour * 10000 + minute * 100 + second</code>
394 *
395 * @return the related milliseconds
396 */
397static int64_t computeInterval(int32_t date, int32_t time)
398{
399    int32_t year, month, day, hour, minute, second;
400    int64_t milliseconds;
401
402    year = date / 10000;
403    month = (date / 100) % 100;
404    day = date % 100;
405    hour = time / 10000;
406    minute = (time / 100) % 100;
407    second = time % 100;
408
409    /* milliseconds = ((((year * 365 + month * 30 + day) * 24
410     *                + hour) * 60 + minute) * 60 + second) * 1000;
411     */
412    int64_mul(milliseconds,
413        int64_const(year * DAY_PER_YEAR + month * DAY_PER_MONTH + day),
414        int64_const(MS_PER_DAY));
415    int64_add(milliseconds, milliseconds,
416        int64_const(hour * MS_PER_HOUR + minute * MS_PER_MINUTE +
417            second * MS_PER_SECOND));
418
419    return milliseconds;
420}
421
422static jint getObjectIntField(JNIEnv * env, jobject obj, const char *name, jint * value)
423{
424    jclass clazz;
425    jfieldID field;
426
427    clazz = (*env)->GetObjectClass(env, obj);
428    if (NULL == clazz)
429        return JNI_DRM_FAILURE;
430
431    field = (*env)->GetFieldID(env, clazz, name, "I");
432    (*env)->DeleteLocalRef(env, clazz);
433
434    if (NULL == field)
435        return JNI_DRM_FAILURE;
436
437    *value = (*env)->GetIntField(env, obj, field);
438
439    return JNI_DRM_SUCCESS;
440}
441
442static jint setObjectIntField(JNIEnv * env, jobject obj, const char *name, jint value)
443{
444    jclass clazz;
445    jfieldID field;
446
447    clazz = (*env)->GetObjectClass(env, obj);
448    if (NULL == clazz)
449        return JNI_DRM_FAILURE;
450
451    field = (*env)->GetFieldID(env, clazz, name, "I");
452    (*env)->DeleteLocalRef(env, clazz);
453
454    if (NULL == field)
455        return JNI_DRM_FAILURE;
456
457    (*env)->SetIntField(env, obj, field, value);
458
459    return JNI_DRM_SUCCESS;
460}
461
462static jint setObjectLongField(JNIEnv * env, jobject obj, const char *name, jlong value)
463{
464    jclass clazz;
465    jfieldID field;
466
467    clazz = (*env)->GetObjectClass(env, obj);
468    if (NULL == clazz)
469        return JNI_DRM_FAILURE;
470
471    field = (*env)->GetFieldID(env, clazz, name, "J");
472    (*env)->DeleteLocalRef(env, clazz);
473
474    if (NULL == field)
475        return JNI_DRM_FAILURE;
476
477    (*env)->SetLongField(env, obj, field, value);
478
479    return JNI_DRM_SUCCESS;
480}
481
482static jint setConstraintFields(JNIEnv * env, jobject constraint, T_DRM_Constraint_Info * pConstraint)
483{
484    /* if no this permission */
485    if (pConstraint->indicator == (uint8_t)DRM_NO_RIGHTS) {
486        if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", 0))
487            return JNI_DRM_FAILURE;
488
489        return JNI_DRM_SUCCESS;
490    }
491
492    /* set count field */
493    if (pConstraint->indicator & DRM_COUNT_CONSTRAINT) {
494        if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", pConstraint->count))
495            return JNI_DRM_FAILURE;
496    }
497
498    /* set start time field */
499    if (pConstraint->indicator & DRM_START_TIME_CONSTRAINT) {
500        int64_t startTime;
501
502        startTime = computeTime(pConstraint->startDate, pConstraint->startTime);
503
504        if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "startDate", startTime))
505            return JNI_DRM_FAILURE;
506    }
507
508    /* set end time field */
509    if (pConstraint->indicator & DRM_END_TIME_CONSTRAINT) {
510        int64_t endTime;
511
512        endTime = computeTime(pConstraint->endDate, pConstraint->endTime);
513
514        if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "endDate", endTime))
515            return JNI_DRM_FAILURE;
516    }
517
518    /* set interval field */
519    if (pConstraint->indicator & DRM_INTERVAL_CONSTRAINT) {
520        int64_t interval;
521
522        interval = computeInterval(pConstraint->intervalDate, pConstraint->intervalTime);
523
524        if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "interval", interval))
525            return JNI_DRM_FAILURE;
526    }
527
528    return JNI_DRM_SUCCESS;
529}
530
531static jint setRightsFields(JNIEnv * env, jobject rights, T_DRM_Rights_Info* pRoInfo)
532{
533    jclass clazz;
534    jfieldID field;
535    jstring str;
536    jint index;
537
538    clazz = (*env)->GetObjectClass(env, rights);
539    if (NULL == clazz)
540        return JNI_DRM_FAILURE;
541
542    /* set roId field */
543    field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;");
544    (*env)->DeleteLocalRef(env, clazz);
545
546    if (NULL == field)
547        return JNI_DRM_FAILURE;
548
549    str = (*env)->NewStringUTF(env, (char *)pRoInfo->roId);
550    if (NULL == str)
551        return JNI_DRM_FAILURE;
552
553    (*env)->SetObjectField(env, rights, field, str);
554    (*env)->DeleteLocalRef(env, str);
555
556    return JNI_DRM_SUCCESS;
557}
558
559/* native interface */
560JNIEXPORT jint JNICALL
561Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent
562  (JNIEnv * env, jobject rawContent, jobject data, jint len, jint mimeType)
563{
564    int32_t id;
565    T_DRM_Input_Data inData;
566    DrmData* drmInData;
567
568    switch (mimeType) {
569    case JNI_DRM_MIMETYPE_MESSAGE:
570        mimeType = TYPE_DRM_MESSAGE;
571        break;
572    case JNI_DRM_MIMETYPE_CONTENT:
573        mimeType = TYPE_DRM_CONTENT;
574        break;
575    default:
576        return JNI_DRM_FAILURE;
577    }
578
579    drmInData = newItem();
580    if (NULL == drmInData)
581        return JNI_DRM_FAILURE;
582
583    drmInData->env = env;
584    drmInData->pInData = &data;
585    drmInData->len = len;
586
587    if (JNI_DRM_FAILURE == addItem(drmInData))
588        return JNI_DRM_FAILURE;
589
590    inData.inputHandle = (int32_t)drmInData;
591    inData.mimeType = mimeType;
592    inData.getInputDataLength = getInputStreamDataLength;
593    inData.readInputData = readInputStreamData;
594
595    id = SVC_drm_openSession(inData);
596    if (id < 0)
597        return JNI_DRM_FAILURE;
598
599    drmInData->id = id;
600
601    return id;
602}
603
604/* native interface */
605JNIEXPORT jstring JNICALL
606Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress
607  (JNIEnv * env, jobject rawContent)
608{
609    jint id;
610    uint8_t rightsIssuer[256] = {0};
611    jstring str = NULL;
612
613    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
614        return NULL;
615
616    if (DRM_SUCCESS == SVC_drm_getRightsIssuer(id, rightsIssuer))
617        str = (*env)->NewStringUTF(env, (char *)rightsIssuer);
618
619    return str;
620}
621
622/* native interface */
623JNIEXPORT jint JNICALL
624Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod
625  (JNIEnv * env, jobject rawContent)
626{
627    jint id;
628    int32_t res;
629
630    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
631        return JNI_DRM_FAILURE;
632
633    res = SVC_drm_getDeliveryMethod(id);
634
635    switch (res) {
636    case FORWARD_LOCK:
637        return JNI_DRM_FORWARD_LOCK;
638    case COMBINED_DELIVERY:
639        return JNI_DRM_COMBINED_DELIVERY;
640    case SEPARATE_DELIVERY:
641        return JNI_DRM_SEPARATE_DELIVERY;
642    case SEPARATE_DELIVERY_FL:
643        return JNI_DRM_SEPARATE_DELIVERY_DM;
644    default:
645        return JNI_DRM_FAILURE;
646    }
647}
648
649/* native interface */
650JNIEXPORT jint JNICALL
651Java_android_drm_mobile1_DrmRawContent_nativeReadContent
652  (JNIEnv * env, jobject rawContent, jbyteArray buf, jint bufOff, jint len, jint mediaOff)
653{
654    jint id;
655    jbyte *nativeBuf;
656    jclass cls;
657    jmethodID mid;
658    DrmData* p;
659    jobject inputStream;
660    jfieldID field;
661
662    if (NULL == buf) {
663        jniThrowNullPointerException(env, "b == null");
664        return JNI_DRM_FAILURE;
665    }
666
667    if (len < 0 || bufOff < 0 || len + bufOff > (*env)->GetArrayLength(env, buf)) {
668        jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
669        return JNI_DRM_FAILURE;
670    }
671
672    if (mediaOff < 0 || len == 0)
673        return JNI_DRM_FAILURE;
674
675    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
676        return JNI_DRM_FAILURE;
677
678    p = getItem(id);
679    if (NULL == p)
680        return JNI_DRM_FAILURE;
681
682    cls = (*env)->GetObjectClass(env, rawContent);
683    if (NULL == cls)
684        return JNI_DRM_FAILURE;
685
686    field = (*env)->GetFieldID(env, cls, "inData", "Ljava/io/BufferedInputStream;");
687    (*env)->DeleteLocalRef(env, cls);
688
689    if (NULL == field)
690        return JNI_DRM_FAILURE;
691
692    inputStream = (*env)->GetObjectField(env, rawContent, field);
693
694    p->env = env;
695    p->pInData = &inputStream;
696
697    nativeBuf = (*env)->GetByteArrayElements(env, buf, NULL);
698
699    len = SVC_drm_getContent(id, mediaOff, (uint8_t *)nativeBuf + bufOff, len);
700
701    (*env)->ReleaseByteArrayElements(env, buf, nativeBuf, 0);
702
703    if (DRM_MEDIA_EOF == len)
704        return JNI_DRM_EOF;
705    if (len <= 0)
706        return JNI_DRM_FAILURE;
707
708    return len;
709}
710
711/* native interface */
712JNIEXPORT jstring JNICALL
713Java_android_drm_mobile1_DrmRawContent_nativeGetContentType
714  (JNIEnv * env, jobject rawContent)
715{
716    jint id;
717    uint8_t contentType[64] = {0};
718    jstring str = NULL;
719
720    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
721        return NULL;
722
723    if (DRM_SUCCESS == SVC_drm_getContentType(id, contentType))
724        str = (*env)->NewStringUTF(env, (char *)contentType);
725
726    return str;
727}
728
729/* native interface */
730JNIEXPORT jint JNICALL
731Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength
732  (JNIEnv * env, jobject rawContent)
733{
734    jint id;
735    int32_t len;
736
737    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
738        return JNI_DRM_FAILURE;
739
740    len = SVC_drm_getContentLength(id);
741
742    if (DRM_UNKNOWN_DATA_LEN == len)
743        return JNI_DRM_UNKNOWN_DATA_LEN;
744
745    if (0 > len)
746        return JNI_DRM_FAILURE;
747
748    return len;
749}
750
751/* native interface */
752JNIEXPORT void JNICALL
753Java_android_drm_mobile1_DrmRawContent_finalize
754  (JNIEnv * env, jobject rawContent)
755{
756    jint id;
757
758    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
759        return;
760
761    removeItem(id);
762
763    SVC_drm_closeSession(id);
764}
765
766/* native interface */
767JNIEXPORT jint JNICALL
768Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo
769  (JNIEnv * env, jobject rights, jint permission, jobject constraint)
770{
771    jclass clazz;
772    jfieldID field;
773    jstring str;
774    uint8_t *nativeStr;
775    T_DRM_Rights_Info_Node *pRightsList;
776    T_DRM_Rights_Info_Node *pCurNode;
777    T_DRM_Constraint_Info *pConstraint;
778
779    clazz = (*env)->GetObjectClass(env, rights);
780    if (NULL == clazz)
781        return JNI_DRM_FAILURE;
782
783    field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;");
784    (*env)->DeleteLocalRef(env, clazz);
785
786    if (NULL == field)
787        return JNI_DRM_FAILURE;
788
789    str = (*env)->GetObjectField(env, rights, field);
790
791    nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL);
792    if (NULL == nativeStr)
793        return JNI_DRM_FAILURE;
794
795    /* this means forward-lock rights */
796    if (0 == strcmp((char *)nativeStr, "ForwardLock")) {
797        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
798        return JNI_DRM_SUCCESS;
799    }
800
801    if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) {
802        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
803        return JNI_DRM_FAILURE;
804    }
805
806    pCurNode = searchRightsObject((jbyte *)nativeStr, pRightsList);
807    if (NULL == pCurNode) {
808        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
809        SVC_drm_freeRightsInfoList(pRightsList);
810        return JNI_DRM_FAILURE;
811    }
812    (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
813
814    switch (permission) {
815    case JNI_DRM_PERMISSION_PLAY:
816        pConstraint = &(pCurNode->roInfo.playRights);
817        break;
818    case JNI_DRM_PERMISSION_DISPLAY:
819        pConstraint = &(pCurNode->roInfo.displayRights);
820        break;
821    case JNI_DRM_PERMISSION_EXECUTE:
822        pConstraint = &(pCurNode->roInfo.executeRights);
823        break;
824    case JNI_DRM_PERMISSION_PRINT:
825        pConstraint = &(pCurNode->roInfo.printRights);
826        break;
827    default:
828        SVC_drm_freeRightsInfoList(pRightsList);
829        return JNI_DRM_FAILURE;
830    }
831
832    /* set constraint field */
833    if (JNI_DRM_FAILURE == setConstraintFields(env, constraint, pConstraint)) {
834        SVC_drm_freeRightsInfoList(pRightsList);
835        return JNI_DRM_FAILURE;
836    }
837
838    SVC_drm_freeRightsInfoList(pRightsList);
839
840    return JNI_DRM_SUCCESS;
841}
842
843/* native interface */
844JNIEXPORT jint JNICALL
845Java_android_drm_mobile1_DrmRights_nativeConsumeRights
846  (JNIEnv * env, jobject rights, jint permission)
847{
848    jclass clazz;
849    jfieldID field;
850    jstring str;
851    uint8_t *nativeStr;
852    int32_t id;
853
854    switch (permission) {
855    case JNI_DRM_PERMISSION_PLAY:
856        permission = DRM_PERMISSION_PLAY;
857        break;
858    case JNI_DRM_PERMISSION_DISPLAY:
859        permission = DRM_PERMISSION_DISPLAY;
860        break;
861    case JNI_DRM_PERMISSION_EXECUTE:
862        permission = DRM_PERMISSION_EXECUTE;
863        break;
864    case JNI_DRM_PERMISSION_PRINT:
865        permission = DRM_PERMISSION_PRINT;
866        break;
867    default:
868        return JNI_DRM_FAILURE;
869    }
870
871    clazz = (*env)->GetObjectClass(env, rights);
872    if (NULL == clazz)
873        return JNI_DRM_FAILURE;
874
875    field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;");
876    (*env)->DeleteLocalRef(env, clazz);
877
878    if (NULL == field)
879        return JNI_DRM_FAILURE;
880
881    str = (*env)->GetObjectField(env, rights, field);
882
883    nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL);
884    if (NULL == nativeStr)
885        return JNI_DRM_FAILURE;
886
887    if (0 == strcmp("ForwardLock", (char *)nativeStr)) {
888        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
889        return JNI_DRM_SUCCESS;
890    }
891
892    if (DRM_SUCCESS != SVC_drm_updateRights(nativeStr, permission)) {
893        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
894        return JNI_DRM_FAILURE;
895    }
896
897    (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
898
899    return JNI_DRM_SUCCESS;
900}
901
902/* native interface */
903JNIEXPORT jint JNICALL
904Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights
905  (JNIEnv * env, jobject rightsManager, jobject data, jint len, jint mimeType, jobject rights)
906{
907    int32_t id;
908    T_DRM_Input_Data inData;
909    DrmData* drmInData;
910    jclass cls;
911    jmethodID mid;
912    T_DRM_Rights_Info rightsInfo;
913
914    switch (mimeType) {
915    case JNI_DRM_MIMETYPE_RIGHTS_XML:
916        mimeType = TYPE_DRM_RIGHTS_XML;
917        break;
918    case JNI_DRM_MIMETYPE_RIGHTS_WBXML:
919        mimeType = TYPE_DRM_RIGHTS_WBXML;
920        break;
921    case JNI_DRM_MIMETYPE_MESSAGE:
922        mimeType = TYPE_DRM_MESSAGE;
923        break;
924    default:
925        return JNI_DRM_FAILURE;
926    }
927
928    drmInData = newItem();
929    if (NULL == drmInData)
930        return JNI_DRM_FAILURE;
931
932    drmInData->env = env;
933    drmInData->pInData = &data;
934    drmInData->len = len;
935
936    inData.inputHandle = (int32_t)drmInData;
937    inData.mimeType = mimeType;
938    inData.getInputDataLength = getInputStreamDataLength;
939    inData.readInputData = readInputStreamData;
940
941    memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info));
942    if (DRM_FAILURE == SVC_drm_installRights(inData, &rightsInfo))
943        return JNI_DRM_FAILURE;
944
945    freeItem(drmInData);
946
947    return setRightsFields(env, rights, &rightsInfo);
948}
949
950/* native interface */
951JNIEXPORT jint JNICALL
952Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights
953  (JNIEnv * env, jobject rightsManager, jobject rawContent, jobject rights)
954{
955    jint id;
956    T_DRM_Rights_Info rightsInfo;
957
958    if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id))
959        return JNI_DRM_FAILURE;
960
961    memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info));
962    if (DRM_SUCCESS != SVC_drm_getRightsInfo(id, &rightsInfo))
963        return JNI_DRM_FAILURE;
964
965    return setRightsFields(env, rights, &rightsInfo);
966}
967
968/* native interface */
969JNIEXPORT jint JNICALL
970Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights
971  (JNIEnv * env, jobject rightsManager)
972{
973    T_DRM_Rights_Info_Node *pRightsList;
974    T_DRM_Rights_Info_Node *pCurNode;
975    int32_t num = 0;
976
977    if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList))
978        return JNI_DRM_FAILURE;
979
980    pCurNode = pRightsList;
981    while (pCurNode != NULL) {
982        num++;
983        pCurNode = pCurNode->next;
984    }
985
986    SVC_drm_freeRightsInfoList(pRightsList);
987
988    return num;
989}
990
991/* native interface */
992JNIEXPORT jint JNICALL
993Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList
994  (JNIEnv * env, jobject rightsManager, jobjectArray rightsArray, jint num)
995{
996    T_DRM_Rights_Info_Node *pRightsList;
997    T_DRM_Rights_Info_Node *pCurNode;
998    int32_t index;
999
1000    if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList))
1001        return JNI_DRM_FAILURE;
1002
1003    pCurNode = pRightsList;
1004    for (index = 0; NULL != pCurNode; index++) {
1005        jobject rights = (*env)->GetObjectArrayElement(env, rightsArray, index);
1006        if (NULL == rights)
1007            break;
1008
1009        if (JNI_DRM_FAILURE == setRightsFields(env, rights, &(pCurNode->roInfo)))
1010            break;
1011
1012        (*env)->SetObjectArrayElement(env, rightsArray, index, rights);
1013
1014        pCurNode = pCurNode->next;
1015    }
1016
1017    SVC_drm_freeRightsInfoList(pRightsList);
1018
1019    return index;
1020}
1021
1022/* native interface */
1023JNIEXPORT jint JNICALL
1024Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights
1025  (JNIEnv * env, jobject rightsManager, jobject rights)
1026{
1027    jclass clazz;
1028    jfieldID field;
1029    jstring str;
1030    uint8_t *nativeStr;
1031
1032    clazz = (*env)->GetObjectClass(env, rights);
1033    if (NULL == clazz)
1034        return JNI_DRM_FAILURE;
1035
1036    field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;");
1037    if (NULL == field)
1038        return JNI_DRM_FAILURE;
1039
1040    str = (*env)->GetObjectField(env, rights, field);
1041
1042    nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL);
1043    if (NULL == nativeStr)
1044        return JNI_DRM_FAILURE;
1045
1046    if (0 == strcmp("ForwardLock", (char *)nativeStr))
1047        return JNI_DRM_SUCCESS;
1048
1049    if (DRM_SUCCESS != SVC_drm_deleteRights(nativeStr)) {
1050        (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
1051        return JNI_DRM_FAILURE;
1052    }
1053
1054    (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr);
1055    return JNI_DRM_SUCCESS;
1056}
1057
1058/*
1059 * Table of methods associated with the DrmRawContent class.
1060 */
1061static JNINativeMethod gDrmRawContentMethods[] = {
1062    /* name, signature, funcPtr */
1063    {"nativeConstructDrmContent", "(Ljava/io/InputStream;II)I",
1064        (void*)Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent},
1065    {"nativeGetRightsAddress", "()Ljava/lang/String;",
1066        (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress},
1067    {"nativeGetDeliveryMethod", "()I",
1068        (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod},
1069    {"nativeReadContent", "([BIII)I",
1070        (void*)Java_android_drm_mobile1_DrmRawContent_nativeReadContent},
1071    {"nativeGetContentType", "()Ljava/lang/String;",
1072        (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentType},
1073    {"nativeGetContentLength", "()I",
1074        (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength},
1075    {"finalize", "()V",
1076        (void*)Java_android_drm_mobile1_DrmRawContent_finalize},
1077};
1078
1079/*
1080 * Table of methods associated with the DrmRights class.
1081 */
1082static JNINativeMethod gDrmRightsMethods[] = {
1083    /* name, signature, funcPtr */
1084    {"nativeGetConstraintInfo", "(ILandroid/drm/mobile1/DrmConstraintInfo;)I",
1085        (void*)Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo},
1086    {"nativeConsumeRights", "(I)I",
1087        (void*)Java_android_drm_mobile1_DrmRights_nativeConsumeRights},
1088};
1089
1090/*
1091 * Table of methods associated with the DrmRightsManager class.
1092 */
1093static JNINativeMethod gDrmRightsManagerMethods[] = {
1094    /* name, signature, funcPtr */
1095    {"nativeInstallDrmRights", "(Ljava/io/InputStream;IILandroid/drm/mobile1/DrmRights;)I",
1096        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights},
1097    {"nativeQueryRights", "(Landroid/drm/mobile1/DrmRawContent;Landroid/drm/mobile1/DrmRights;)I",
1098        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights},
1099    {"nativeGetNumOfRights", "()I",
1100        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights},
1101    {"nativeGetRightsList", "([Landroid/drm/mobile1/DrmRights;I)I",
1102        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList},
1103    {"nativeDeleteRights", "(Landroid/drm/mobile1/DrmRights;)I",
1104        (void*)Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights},
1105};
1106
1107/*
1108 * Register several native methods for one class.
1109 */
1110static int registerNativeMethods(JNIEnv* env, const char* className,
1111    JNINativeMethod* gMethods, int numMethods)
1112{
1113    jclass clazz;
1114
1115    clazz = (*env)->FindClass(env, className);
1116    if (clazz == NULL)
1117        return JNI_FALSE;
1118
1119    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)
1120        return JNI_FALSE;
1121
1122    return JNI_TRUE;
1123}
1124
1125/*
1126 * Register native methods for all classes we know about.
1127 */
1128static int registerNatives(JNIEnv* env)
1129{
1130    if (!registerNativeMethods(env, "android/drm/mobile1/DrmRawContent",
1131            gDrmRawContentMethods, sizeof(gDrmRawContentMethods) / sizeof(gDrmRawContentMethods[0])))
1132        return JNI_FALSE;
1133
1134    if (!registerNativeMethods(env, "android/drm/mobile1/DrmRights",
1135            gDrmRightsMethods, sizeof(gDrmRightsMethods) / sizeof(gDrmRightsMethods[0])))
1136        return JNI_FALSE;
1137
1138    if (!registerNativeMethods(env, "android/drm/mobile1/DrmRightsManager",
1139            gDrmRightsManagerMethods, sizeof(gDrmRightsManagerMethods) / sizeof(gDrmRightsManagerMethods[0])))
1140        return JNI_FALSE;
1141
1142    return JNI_TRUE;
1143}
1144
1145jint JNI_OnLoad(JavaVM* vm, void* reserved)
1146{
1147    JNIEnv* env = NULL;
1148    jint result = -1;
1149
1150    printf("Entering JNI_OnLoad\n");
1151
1152    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK)
1153        goto bail;
1154
1155    assert(env != NULL);
1156
1157    if (!registerNatives(env))
1158        goto bail;
1159
1160    /* success -- return valid version number */
1161    result = JNI_VERSION_1_4;
1162
1163bail:
1164    printf("Leaving JNI_OnLoad (result=0x%x)\n", result);
1165    return result;
1166}
1167