blob: 11353a78bca1dc9ace7c27a8ccb0a117a607d4a3 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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"
Elliott Hughes15dd15f2011-04-08 17:42:34 -070027#include "JNIHelp.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
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) {
Elliott Hughes15dd15f2011-04-08 17:42:34 -0700663 jniThrowNullPointerException(env, "b == null");
664 return JNI_DRM_FAILURE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 }
666
667 if (len < 0 || bufOff < 0 || len + bufOff > (*env)->GetArrayLength(env, buf)) {
Elliott Hughes15dd15f2011-04-08 17:42:34 -0700668 jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
669 return JNI_DRM_FAILURE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 }
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}