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