1/*
2 * Copyright (C) 2010 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//#define LOG_NDEBUG 0
18#define LOG_TAG "android_drm_DrmManagerClient"
19#include <utils/Log.h>
20
21#include <jni.h>
22#include <nativehelper/JNIHelp.h>
23#include <nativehelper/ScopedLocalRef.h>
24#include <android_runtime/AndroidRuntime.h>
25
26#include <drm/DrmInfo.h>
27#include <drm/DrmRights.h>
28#include <drm/DrmInfoEvent.h>
29#include <drm/DrmInfoStatus.h>
30#include <drm/DrmInfoRequest.h>
31#include <drm/DrmSupportInfo.h>
32#include <drm/DrmConstraints.h>
33#include <drm/DrmMetadata.h>
34#include <drm/DrmConvertedStatus.h>
35#include <drm/drm_framework_common.h>
36
37#include <DrmManagerClientImpl.h>
38
39using namespace android;
40
41/**
42 * Utility class used to extract the value from the provided java object.
43 * May need to add some utility function to create java object.
44 */
45class Utility {
46public:
47    static String8 getStringValue(JNIEnv* env, jobject object, const char* fieldName);
48
49    static char* getByteArrayValue(
50            JNIEnv* env, jobject object, const char* fieldName, int* dataLength);
51
52    static char* getByteArrayValue(
53            JNIEnv* env, jbyteArray byteArray, int* dataLength);
54
55    static String8 getStringValue(JNIEnv* env, jstring string);
56
57    static int getIntValue(JNIEnv* env, jobject object, const char* fieldName);
58};
59
60String8 Utility::getStringValue(JNIEnv* env, jobject object, const char* fieldName) {
61    /* Look for the instance field with the name fieldName */
62    jfieldID fieldID
63        = env->GetFieldID(env->GetObjectClass(object), fieldName , "Ljava/lang/String;");
64
65    if (NULL != fieldID) {
66        jstring valueString = (jstring) env->GetObjectField(object, fieldID);
67        return Utility::getStringValue(env, valueString);
68    }
69
70    String8 dataString("");
71    return dataString;
72}
73
74String8 Utility::getStringValue(JNIEnv* env, jstring string) {
75    String8 dataString("");
76
77    if (NULL != string && string != env->NewStringUTF("")) {
78        char* bytes = const_cast< char* > (env->GetStringUTFChars(string, NULL));
79
80        const int length = strlen(bytes) + 1;
81        char *data = new char[length];
82        strncpy(data, bytes, length);
83        dataString = String8(data);
84
85        env->ReleaseStringUTFChars(string, bytes);
86        delete [] data; data = NULL;
87    }
88    return dataString;
89}
90
91char* Utility::getByteArrayValue(
92            JNIEnv* env, jobject object, const char* fieldName, int* dataLength) {
93
94    *dataLength = 0;
95
96    jfieldID fieldID = env->GetFieldID(env->GetObjectClass(object), fieldName , "[B");
97
98    if (NULL != fieldID) {
99        jbyteArray byteArray = (jbyteArray) env->GetObjectField(object, fieldID);
100        return Utility::getByteArrayValue(env, byteArray, dataLength);
101    }
102    return NULL;
103}
104
105char* Utility::getByteArrayValue(JNIEnv* env, jbyteArray byteArray, int* dataLength) {
106    char* data = NULL;
107    if (NULL != byteArray) {
108        jint length = env->GetArrayLength(byteArray);
109
110        *dataLength = length;
111        if (0 < *dataLength) {
112            data = new char[length];
113            env->GetByteArrayRegion(byteArray, (jint)0, length, (jbyte *) data);
114        }
115    }
116    return data;
117}
118
119int Utility::getIntValue(JNIEnv* env, jobject object, const char* fieldName) {
120    jfieldID fieldID;
121    int intValue = -1;
122
123    /* Get a reference to obj’s class */
124    jclass clazz = env->GetObjectClass(object);
125    /* Look for the instance field with the name fieldName */
126    fieldID = env->GetFieldID(clazz, fieldName , "I");
127
128    if (NULL != fieldID) {
129        intValue = (int) env->GetIntField(object, fieldID);
130    }
131
132    return intValue;
133}
134
135class JNIOnInfoListener : public DrmManagerClient::OnInfoListener {
136public:
137    JNIOnInfoListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
138
139    virtual ~JNIOnInfoListener();
140    void onInfo(const DrmInfoEvent& event);
141
142private:
143    JNIOnInfoListener();
144    jclass mClass;
145    jobject mObject;
146};
147
148JNIOnInfoListener::JNIOnInfoListener(JNIEnv* env, jobject thiz, jobject weak_thiz) {
149    jclass clazz = env->GetObjectClass(thiz);
150
151    if (clazz == NULL) {
152        ALOGE("Can't find android/drm/DrmManagerClient");
153        jniThrowException(env, "java/lang/Exception", NULL);
154        return;
155    }
156    mClass = (jclass)env->NewGlobalRef(clazz);
157    mObject  = env->NewGlobalRef(weak_thiz);
158}
159
160JNIOnInfoListener::~JNIOnInfoListener() {
161    JNIEnv *env = AndroidRuntime::getJNIEnv();
162    env->DeleteGlobalRef(mObject);
163    env->DeleteGlobalRef(mClass);
164}
165
166void JNIOnInfoListener::onInfo(const DrmInfoEvent& event) {
167    jint uniqueId = event.getUniqueId();
168    jint type = event.getType();
169    JNIEnv *env = AndroidRuntime::getJNIEnv();
170    jstring message = env->NewStringUTF(event.getMessage().string());
171    ALOGV("JNIOnInfoListener::onInfo => %d | %d | %s", uniqueId, type, event.getMessage().string());
172
173    env->CallStaticVoidMethod(
174            mClass,
175            env->GetStaticMethodID(mClass, "notify", "(Ljava/lang/Object;IILjava/lang/String;)V"),
176            mObject, uniqueId, type, message);
177}
178
179static Mutex sLock;
180
181static sp<DrmManagerClientImpl> setDrmManagerClientImpl(
182            JNIEnv* env, jobject thiz, const sp<DrmManagerClientImpl>& client) {
183    Mutex::Autolock l(sLock);
184    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
185    jfieldID fieldId = env->GetFieldID(clazz, "mNativeContext", "J");
186
187    jlong oldHandle = env->GetLongField(thiz, fieldId);
188    sp<DrmManagerClientImpl> old = reinterpret_cast<DrmManagerClientImpl*>(oldHandle);
189    if (client.get()) {
190        client->incStrong(thiz);
191    }
192    if (old != 0) {
193        old->decStrong(thiz);
194    }
195    env->SetLongField(thiz, fieldId, reinterpret_cast<jlong>(client.get()));
196    return old;
197}
198
199static sp<DrmManagerClientImpl> getDrmManagerClientImpl(JNIEnv* env, jobject thiz) {
200    Mutex::Autolock l(sLock);
201    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
202    jfieldID fieldId = env->GetFieldID(clazz, "mNativeContext", "J");
203
204    jlong clientHandle = env->GetLongField(thiz, fieldId);
205    DrmManagerClientImpl* const client = reinterpret_cast<DrmManagerClientImpl*>(clientHandle);
206    return sp<DrmManagerClientImpl>(client);
207}
208
209static jint android_drm_DrmManagerClient_initialize(
210        JNIEnv* env, jobject thiz) {
211    ALOGV("initialize - Enter");
212
213    int uniqueId = 0;
214    sp<DrmManagerClientImpl> drmManager = DrmManagerClientImpl::create(&uniqueId, false);
215    drmManager->addClient(uniqueId);
216
217    setDrmManagerClientImpl(env, thiz, drmManager);
218    ALOGV("initialize - Exit");
219    return static_cast<jint>(uniqueId);
220}
221
222static void android_drm_DrmManagerClient_setListeners(
223        JNIEnv* env, jobject thiz, jint uniqueId, jobject weak_thiz) {
224    ALOGV("setListeners - Enter");
225
226    // Set the listener to DrmManager
227    sp<DrmManagerClient::OnInfoListener> listener = new JNIOnInfoListener(env, thiz, weak_thiz);
228    getDrmManagerClientImpl(env, thiz)->setOnInfoListener(uniqueId, listener);
229
230    ALOGV("setListeners - Exit");
231}
232
233static void android_drm_DrmManagerClient_release(
234        JNIEnv* env, jobject thiz, jint uniqueId) {
235    ALOGV("release - Enter");
236    getDrmManagerClientImpl(env, thiz)->remove(uniqueId);
237    getDrmManagerClientImpl(env, thiz)->setOnInfoListener(uniqueId, NULL);
238
239    sp<DrmManagerClientImpl> oldClient = setDrmManagerClientImpl(env, thiz, NULL);
240    if (oldClient != NULL) {
241        oldClient->setOnInfoListener(uniqueId, NULL);
242        oldClient->removeClient(uniqueId);
243    }
244    ALOGV("release - Exit");
245}
246
247static jobject android_drm_DrmManagerClient_getConstraintsFromContent(
248            JNIEnv* env, jobject thiz, jint uniqueId, jstring jpath, jint usage) {
249    ALOGV("GetConstraints - Enter");
250
251    const String8 pathString = Utility::getStringValue(env, jpath);
252    DrmConstraints* pConstraints
253        = getDrmManagerClientImpl(env, thiz)->getConstraints(uniqueId, &pathString, usage);
254
255    jclass localRef = env->FindClass("android/content/ContentValues");
256    jmethodID ContentValues_putByteArray =
257            env->GetMethodID(localRef, "put", "(Ljava/lang/String;[B)V");
258    jmethodID ContentValues_putString =
259            env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/String;)V");
260    jmethodID ContentValues_constructor = env->GetMethodID(localRef, "<init>", "()V");
261    jobject constraints = NULL;
262
263    if (NULL != localRef && NULL != pConstraints) {
264        // create the java DrmConstraints object
265        constraints = env->NewObject(localRef, ContentValues_constructor);
266
267        DrmConstraints::KeyIterator keyIt = pConstraints->keyIterator();
268        while (keyIt.hasNext()) {
269            String8 key = keyIt.next();
270
271            // insert the entry<constraintKey, constraintValue> to newly created java object
272            if (DrmConstraints::EXTENDED_METADATA == key) {
273                const char* value = pConstraints->getAsByteArray(&key);
274                if (NULL != value) {
275                    ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(strlen(value)));
276                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
277                    env->SetByteArrayRegion(dataArray.get(), 0, strlen(value), (jbyte*)value);
278                    env->CallVoidMethod(constraints, ContentValues_putByteArray,
279                                        keyString.get(), dataArray.get());
280                }
281            } else {
282                String8 value = pConstraints->get(key);
283                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
284                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
285                env->CallVoidMethod(constraints, ContentValues_putString,
286                                    keyString.get(), valueString.get());
287            }
288        }
289    }
290
291    delete pConstraints; pConstraints = NULL;
292    ALOGV("GetConstraints - Exit");
293    return constraints;
294}
295
296static jobject android_drm_DrmManagerClient_getMetadataFromContent(
297            JNIEnv* env, jobject thiz, jint uniqueId, jstring jpath) {
298    ALOGV("GetMetadata - Enter");
299    const String8 pathString = Utility::getStringValue(env, jpath);
300    DrmMetadata* pMetadata =
301            getDrmManagerClientImpl(env, thiz)->getMetadata(uniqueId, &pathString);
302
303    jobject metadata = NULL;
304
305    jclass localRef = env->FindClass("android/content/ContentValues");
306    jmethodID ContentValues_putString =
307            env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/String;)V");
308
309    if (NULL != localRef && NULL != pMetadata) {
310        // Get the constructor id
311        jmethodID constructorId = NULL;
312        constructorId = env->GetMethodID(localRef, "<init>", "()V");
313        if (NULL != constructorId) {
314            // create the java DrmMetadata object
315            metadata = env->NewObject(localRef, constructorId);
316            if (NULL != metadata) {
317                DrmMetadata::KeyIterator keyIt = pMetadata->keyIterator();
318                while (keyIt.hasNext()) {
319                    String8 key = keyIt.next();
320                    // insert the entry<constraintKey, constraintValue>
321                    // to newly created java object
322                    String8 value = pMetadata->get(key);
323                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
324                    ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
325                    env->CallVoidMethod(metadata, ContentValues_putString,
326                                        keyString.get(), valueString.get());
327                }
328            }
329        }
330    }
331    delete pMetadata; pMetadata = NULL;
332    ALOGV("GetMetadata - Exit");
333    return metadata;
334}
335
336static jobjectArray android_drm_DrmManagerClient_getAllSupportInfo(
337            JNIEnv* env, jobject thiz, jint uniqueId) {
338    ALOGV("GetAllSupportInfo - Enter");
339    DrmSupportInfo* drmSupportInfoArray = NULL;
340
341    int length = 0;
342    getDrmManagerClientImpl(env, thiz)->getAllSupportInfo(uniqueId, &length, &drmSupportInfoArray);
343
344    jclass clazz = env->FindClass("android/drm/DrmSupportInfo");
345
346    jobjectArray array = (jobjectArray)env->NewObjectArray(length, clazz, NULL);
347
348    for (int i = 0; i < length; i++) {
349        DrmSupportInfo info = drmSupportInfoArray[i];
350
351        jobject drmSupportInfo = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "()V"));
352
353        jmethodID addMimeTypeId
354            = env->GetMethodID(clazz, "addMimeType", "(Ljava/lang/String;)V");
355        jmethodID addFileSuffixId
356            = env->GetMethodID(clazz, "addFileSuffix", "(Ljava/lang/String;)V");
357
358        env->CallVoidMethod(
359            drmSupportInfo, env->GetMethodID(clazz, "setDescription", "(Ljava/lang/String;)V"),
360            env->NewStringUTF(info.getDescription().string()));
361
362        DrmSupportInfo::MimeTypeIterator iterator = info.getMimeTypeIterator();
363        while (iterator.hasNext()) {
364            String8  value = iterator.next();
365            env->CallVoidMethod(drmSupportInfo, addMimeTypeId, env->NewStringUTF(value.string()));
366        }
367
368        DrmSupportInfo::FileSuffixIterator it = info.getFileSuffixIterator();
369        while (it.hasNext()) {
370            String8 value = it.next();
371            env->CallVoidMethod(
372                drmSupportInfo, addFileSuffixId, env->NewStringUTF(value.string()));
373        }
374
375        env->SetObjectArrayElement(array, i, drmSupportInfo);
376    }
377
378    delete [] drmSupportInfoArray; drmSupportInfoArray = NULL;
379    ALOGV("GetAllSupportInfo - Exit");
380    return array;
381}
382
383static void android_drm_DrmManagerClient_installDrmEngine(
384            JNIEnv* /* env */, jobject /* thiz */, jint /* uniqueId */,
385            jstring /* engineFilePath */) {
386    ALOGV("installDrmEngine - Enter");
387    //getDrmManagerClient(env, thiz)
388    //  ->installDrmEngine(uniqueId, Utility::getStringValue(env, engineFilePath));
389    ALOGV("installDrmEngine - Exit");
390}
391
392static jint android_drm_DrmManagerClient_saveRights(
393            JNIEnv* env, jobject thiz, jint uniqueId,
394            jobject drmRights, jstring rightsPath, jstring contentPath) {
395    ALOGV("saveRights - Enter");
396    int result = DRM_ERROR_UNKNOWN;
397    int dataLength = 0;
398    char* mData =  Utility::getByteArrayValue(env, drmRights, "mData", &dataLength);
399
400    if (NULL != mData) {
401        DrmRights rights(DrmBuffer(mData, dataLength),
402                Utility::getStringValue(env, drmRights, "mMimeType"),
403                Utility::getStringValue(env, drmRights, "mAccountId"),
404                Utility::getStringValue(env, drmRights, "mSubscriptionId"));
405        result = getDrmManagerClientImpl(env, thiz)
406            ->saveRights(uniqueId, rights, Utility::getStringValue(env, rightsPath),
407                                Utility::getStringValue(env, contentPath));
408    }
409
410    delete[] mData; mData = NULL;
411    ALOGV("saveRights - Exit");
412    return static_cast<jint>(result);
413}
414
415static jboolean android_drm_DrmManagerClient_canHandle(
416            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jstring mimeType) {
417    ALOGV("canHandle - Enter");
418    jboolean result
419        = getDrmManagerClientImpl(env, thiz)
420            ->canHandle(uniqueId, Utility::getStringValue(env, path),
421                    Utility::getStringValue(env, mimeType));
422    ALOGV("canHandle - Exit");
423    return result;
424}
425
426static jobject android_drm_DrmManagerClient_processDrmInfo(
427            JNIEnv* env, jobject thiz, jint uniqueId, jobject drmInfoObject) {
428    ALOGV("processDrmInfo - Enter");
429    int dataLength = 0;
430    const String8 mMimeType =  Utility::getStringValue(env, drmInfoObject, "mMimeType");
431    char* mData =  Utility::getByteArrayValue(env, drmInfoObject, "mData", &dataLength);
432    int mInfoType = Utility::getIntValue(env, drmInfoObject, "mInfoType");
433
434    const DrmBuffer buffer(mData, dataLength);
435    DrmInfo drmInfo(mInfoType, buffer, mMimeType);
436
437    jclass clazz = env->FindClass("android/drm/DrmInfo");
438    jmethodID DrmInfo_get = env->GetMethodID(clazz, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
439    jobject keyIterator
440        = env->CallObjectMethod(drmInfoObject,
441                env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
442
443    jclass Iterator_class = env->FindClass("java/util/Iterator");
444    jmethodID Iterator_hasNext = env->GetMethodID(Iterator_class, "hasNext", "()Z");
445    jmethodID Iterator_next = env->GetMethodID(Iterator_class, "next", "()Ljava/lang/Object;");
446
447    jclass Object_class = env->FindClass("java/lang/Object");
448    jmethodID Object_toString = env->GetMethodID(Object_class, "toString", "()Ljava/lang/String;");
449
450    while (env->CallBooleanMethod(keyIterator, Iterator_hasNext)) {
451        ScopedLocalRef<jstring> key(env,
452                (jstring) env->CallObjectMethod(keyIterator, Iterator_next));
453        ScopedLocalRef<jobject> valueObject(env,
454                env->CallObjectMethod(drmInfoObject, DrmInfo_get, key.get()));
455        ScopedLocalRef<jstring> valString(env, NULL);
456        if (NULL != valueObject.get()) {
457            valString.reset((jstring) env->CallObjectMethod(valueObject.get(), Object_toString));
458        }
459
460        String8 keyString = Utility::getStringValue(env, key.get());
461        String8 valueString = Utility::getStringValue(env, valString.get());
462        ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
463
464        drmInfo.put(keyString, valueString);
465    }
466
467    DrmInfoStatus* pDrmInfoStatus
468        = getDrmManagerClientImpl(env, thiz)->processDrmInfo(uniqueId, &drmInfo);
469
470    jclass localRef = env->FindClass("android/drm/DrmInfoStatus");
471    jobject drmInfoStatus = NULL;
472
473    if (NULL != localRef && NULL != pDrmInfoStatus) {
474        int statusCode = pDrmInfoStatus->statusCode;
475        int infoType = pDrmInfoStatus->infoType;
476
477        jbyteArray dataArray = NULL;
478        if (NULL != pDrmInfoStatus->drmBuffer) {
479            int length = pDrmInfoStatus->drmBuffer->length;
480            dataArray = env->NewByteArray(length);
481            env->SetByteArrayRegion(
482                dataArray, 0, length, (jbyte*) pDrmInfoStatus->drmBuffer->data);
483
484            delete [] pDrmInfoStatus->drmBuffer->data;
485            delete pDrmInfoStatus->drmBuffer; pDrmInfoStatus->drmBuffer = NULL;
486        }
487        jclass clazz = env->FindClass("android/drm/ProcessedData");
488        jmethodID constructorId
489            = env->GetMethodID(clazz, "<init>", "([BLjava/lang/String;Ljava/lang/String;)V");
490        jobject processedData = env->NewObject(clazz, constructorId, dataArray,
491                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::ACCOUNT_ID)).string()),
492                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::SUBSCRIPTION_ID)).string()));
493
494        constructorId
495            = env->GetMethodID(localRef,
496                "<init>", "(IILandroid/drm/ProcessedData;Ljava/lang/String;)V");
497
498        drmInfoStatus = env->NewObject(localRef, constructorId, statusCode, infoType,
499                processedData, env->NewStringUTF(pDrmInfoStatus->mimeType.string()));
500    }
501
502    delete[] mData; mData = NULL;
503    delete pDrmInfoStatus; pDrmInfoStatus = NULL;
504
505    ALOGV("processDrmInfo - Exit");
506    return drmInfoStatus;
507}
508
509static jobject android_drm_DrmManagerClient_acquireDrmInfo(
510            JNIEnv* env, jobject thiz, jint uniqueId, jobject drmInfoRequest) {
511    ALOGV("acquireDrmInfo Enter");
512    const String8 mMimeType =  Utility::getStringValue(env, drmInfoRequest, "mMimeType");
513    int mInfoType = Utility::getIntValue(env, drmInfoRequest, "mInfoType");
514
515    DrmInfoRequest drmInfoReq(mInfoType, mMimeType);
516
517    jclass clazz = env->FindClass("android/drm/DrmInfoRequest");
518    jobject keyIterator
519        = env->CallObjectMethod(drmInfoRequest,
520                env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
521    jmethodID DrmInfoRequest_get = env->GetMethodID(clazz,
522            "get", "(Ljava/lang/String;)Ljava/lang/Object;");
523
524    jclass Iterator_class = env->FindClass("java/util/Iterator");
525    jmethodID Iterator_hasNext = env->GetMethodID(Iterator_class, "hasNext", "()Z");
526    jmethodID Iterator_next = env->GetMethodID(Iterator_class, "next", "()Ljava/lang/Object;");
527
528    while (env->CallBooleanMethod(keyIterator, Iterator_hasNext)) {
529        ScopedLocalRef<jstring> key(env,
530                (jstring) env->CallObjectMethod(keyIterator, Iterator_next));
531        ScopedLocalRef<jstring> value(env,
532                (jstring) env->CallObjectMethod(drmInfoRequest, DrmInfoRequest_get, key.get()));
533
534        String8 keyString = Utility::getStringValue(env, key.get());
535        String8 valueString = Utility::getStringValue(env, value.get());
536        ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
537
538        drmInfoReq.put(keyString, valueString);
539    }
540
541    DrmInfo* pDrmInfo = getDrmManagerClientImpl(env, thiz)->acquireDrmInfo(uniqueId, &drmInfoReq);
542
543    jobject drmInfoObject = NULL;
544
545    if (NULL != pDrmInfo) {
546        jclass localRef = env->FindClass("android/drm/DrmInfo");
547
548        if (NULL != localRef) {
549            int length = pDrmInfo->getData().length;
550
551            jbyteArray dataArray = env->NewByteArray(length);
552            env->SetByteArrayRegion(dataArray, 0, length, (jbyte*)pDrmInfo->getData().data);
553
554            drmInfoObject
555                = env->NewObject(localRef,
556                    env->GetMethodID(localRef, "<init>", "(I[BLjava/lang/String;)V"),
557                    mInfoType, dataArray, env->NewStringUTF(pDrmInfo->getMimeType().string()));
558
559            DrmInfo::KeyIterator it = pDrmInfo->keyIterator();
560            jmethodID putMethodId
561                = env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/Object;)V");
562
563            while (it.hasNext()) {
564                String8 key = it.next();
565                String8 value = pDrmInfo->get(key);
566                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
567                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
568                env->CallVoidMethod(drmInfoObject, putMethodId,
569                    keyString.get(), valueString.get());
570            }
571        }
572        delete [] pDrmInfo->getData().data;
573    }
574
575    delete pDrmInfo; pDrmInfo = NULL;
576
577    ALOGV("acquireDrmInfo Exit");
578    return drmInfoObject;
579}
580
581static jint android_drm_DrmManagerClient_getDrmObjectType(
582            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jstring mimeType) {
583    ALOGV("getDrmObjectType Enter");
584    int drmObjectType
585        = getDrmManagerClientImpl(env, thiz)
586            ->getDrmObjectType(uniqueId, Utility::getStringValue(env, path),
587                                Utility::getStringValue(env, mimeType));
588    ALOGV("getDrmObjectType Exit");
589    return static_cast<jint>(drmObjectType);
590}
591
592static jstring android_drm_DrmManagerClient_getOriginalMimeType(
593            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jobject fileDescriptor) {
594    ALOGV("getOriginalMimeType Enter");
595
596    int fd = (fileDescriptor == NULL)
597                ? -1
598                : jniGetFDFromFileDescriptor(env, fileDescriptor);
599
600    String8 mimeType
601        = getDrmManagerClientImpl(env, thiz)
602            ->getOriginalMimeType(uniqueId,
603                                  Utility::getStringValue(env, path), fd);
604    ALOGV("getOriginalMimeType Exit");
605    return env->NewStringUTF(mimeType.string());
606}
607
608static jint android_drm_DrmManagerClient_checkRightsStatus(
609            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, int action) {
610    ALOGV("checkRightsStatus Enter");
611    int rightsStatus
612        = getDrmManagerClientImpl(env, thiz)
613            ->checkRightsStatus(uniqueId, Utility::getStringValue(env, path), action);
614    ALOGV("checkRightsStatus Exit");
615    return static_cast<jint>(rightsStatus);
616}
617
618static jint android_drm_DrmManagerClient_removeRights(
619            JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
620    ALOGV("removeRights");
621    return static_cast<jint>(getDrmManagerClientImpl(env, thiz)
622               ->removeRights(uniqueId, Utility::getStringValue(env, path)));
623}
624
625static jint android_drm_DrmManagerClient_removeAllRights(
626            JNIEnv* env, jobject thiz, jint uniqueId) {
627    ALOGV("removeAllRights");
628    return static_cast<jint>(getDrmManagerClientImpl(env, thiz)
629                ->removeAllRights(uniqueId));
630}
631
632static jint android_drm_DrmManagerClient_openConvertSession(
633            JNIEnv* env, jobject thiz, jint uniqueId, jstring mimeType) {
634    ALOGV("openConvertSession Enter");
635    int convertId
636        = getDrmManagerClientImpl(env, thiz)
637            ->openConvertSession(uniqueId, Utility::getStringValue(env, mimeType));
638    ALOGV("openConvertSession Exit");
639    return static_cast<jint>(convertId);
640}
641
642static jobject GetConvertedStatus(JNIEnv* env, DrmConvertedStatus* pDrmConvertedStatus) {
643    ALOGV("GetConvertedStatus - Enter");
644    jclass localRef = env->FindClass("android/drm/DrmConvertedStatus");
645
646    jobject drmConvertedStatus = NULL;
647
648    if (NULL != localRef && NULL != pDrmConvertedStatus) {
649        int statusCode = pDrmConvertedStatus->statusCode;
650
651        jbyteArray dataArray = NULL;
652        if (NULL != pDrmConvertedStatus->convertedData) {
653            int length = pDrmConvertedStatus->convertedData->length;
654            dataArray = env->NewByteArray(length);
655            env->SetByteArrayRegion(
656                dataArray, 0, length, (jbyte*) pDrmConvertedStatus->convertedData->data);
657
658            delete [] pDrmConvertedStatus->convertedData->data;
659            delete pDrmConvertedStatus->convertedData; pDrmConvertedStatus->convertedData = NULL;
660        }
661        jmethodID constructorId = env->GetMethodID(localRef, "<init>", "(I[BI)V");
662        drmConvertedStatus
663            = env->NewObject(localRef, constructorId,
664                             statusCode, dataArray, pDrmConvertedStatus->offset);
665    }
666
667    delete pDrmConvertedStatus; pDrmConvertedStatus = NULL;
668
669    ALOGV("GetConvertedStatus - Exit");
670    return drmConvertedStatus;
671}
672
673static jobject android_drm_DrmManagerClient_convertData(
674            JNIEnv* env, jobject thiz, jint uniqueId, jint convertId, jbyteArray inputData) {
675    ALOGV("convertData Enter");
676
677    int dataLength = 0;
678    char* mData = Utility::getByteArrayValue(env, inputData, &dataLength);
679    const DrmBuffer buffer(mData, dataLength);
680
681    DrmConvertedStatus* pDrmConvertedStatus
682            = getDrmManagerClientImpl(env, thiz)->convertData(uniqueId, convertId, &buffer);
683    jobject status = GetConvertedStatus(env, pDrmConvertedStatus);
684
685    delete[] mData;
686    mData = NULL;
687
688    ALOGV("convertData - Exit");
689    return status;
690}
691
692static jobject android_drm_DrmManagerClient_closeConvertSession(
693            JNIEnv* env, jobject thiz, jint uniqueId, jint convertId) {
694
695    ALOGV("closeConvertSession Enter");
696
697    DrmConvertedStatus* pDrmConvertedStatus
698                = getDrmManagerClientImpl(env, thiz)->closeConvertSession(uniqueId, convertId);
699    jobject status = GetConvertedStatus(env, pDrmConvertedStatus);
700
701    ALOGV("closeConvertSession - Exit");
702    return status;
703}
704
705static const JNINativeMethod nativeMethods[] = {
706
707    {"_initialize", "()I",
708                                    (void*)android_drm_DrmManagerClient_initialize},
709
710    {"_setListeners", "(ILjava/lang/Object;)V",
711                                    (void*)android_drm_DrmManagerClient_setListeners},
712
713    {"_release", "(I)V",
714                                    (void*)android_drm_DrmManagerClient_release},
715
716    {"_getConstraints", "(ILjava/lang/String;I)Landroid/content/ContentValues;",
717                                    (void*)android_drm_DrmManagerClient_getConstraintsFromContent},
718
719    {"_getMetadata", "(ILjava/lang/String;)Landroid/content/ContentValues;",
720                                    (void*)android_drm_DrmManagerClient_getMetadataFromContent},
721
722    {"_getAllSupportInfo", "(I)[Landroid/drm/DrmSupportInfo;",
723                                    (void*)android_drm_DrmManagerClient_getAllSupportInfo},
724
725    {"_installDrmEngine", "(ILjava/lang/String;)V",
726                                    (void*)android_drm_DrmManagerClient_installDrmEngine},
727
728    {"_canHandle", "(ILjava/lang/String;Ljava/lang/String;)Z",
729                                    (void*)android_drm_DrmManagerClient_canHandle},
730
731    {"_processDrmInfo", "(ILandroid/drm/DrmInfo;)Landroid/drm/DrmInfoStatus;",
732                                    (void*)android_drm_DrmManagerClient_processDrmInfo},
733
734    {"_acquireDrmInfo", "(ILandroid/drm/DrmInfoRequest;)Landroid/drm/DrmInfo;",
735                                    (void*)android_drm_DrmManagerClient_acquireDrmInfo},
736
737    {"_saveRights", "(ILandroid/drm/DrmRights;Ljava/lang/String;Ljava/lang/String;)I",
738                                    (void*)android_drm_DrmManagerClient_saveRights},
739
740    {"_getDrmObjectType", "(ILjava/lang/String;Ljava/lang/String;)I",
741                                    (void*)android_drm_DrmManagerClient_getDrmObjectType},
742
743    {"_getOriginalMimeType", "(ILjava/lang/String;Ljava/io/FileDescriptor;)Ljava/lang/String;",
744                                    (void*)android_drm_DrmManagerClient_getOriginalMimeType},
745
746    {"_checkRightsStatus", "(ILjava/lang/String;I)I",
747                                    (void*)android_drm_DrmManagerClient_checkRightsStatus},
748
749    {"_removeRights", "(ILjava/lang/String;)I",
750                                    (void*)android_drm_DrmManagerClient_removeRights},
751
752    {"_removeAllRights", "(I)I",
753                                    (void*)android_drm_DrmManagerClient_removeAllRights},
754
755    {"_openConvertSession", "(ILjava/lang/String;)I",
756                                    (void*)android_drm_DrmManagerClient_openConvertSession},
757
758    {"_convertData", "(II[B)Landroid/drm/DrmConvertedStatus;",
759                                    (void*)android_drm_DrmManagerClient_convertData},
760
761    {"_closeConvertSession", "(II)Landroid/drm/DrmConvertedStatus;",
762                                    (void*)android_drm_DrmManagerClient_closeConvertSession},
763};
764
765static int registerNativeMethods(JNIEnv* env) {
766    int result = -1;
767
768    /* look up the class */
769    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
770
771    if (NULL != clazz) {
772        if (env->RegisterNatives(clazz, nativeMethods, sizeof(nativeMethods)
773                / sizeof(nativeMethods[0])) == JNI_OK) {
774            result = 0;
775        }
776    }
777    return result;
778}
779
780jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
781    JNIEnv* env = NULL;
782    jint result = -1;
783
784    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {
785        if (NULL != env && registerNativeMethods(env) == 0) {
786            result = JNI_VERSION_1_4;
787        }
788    }
789    return result;
790}
791
792