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