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 <JNIHelp.h>
23#include <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", "I");
186
187    sp<DrmManagerClientImpl> old = (DrmManagerClientImpl*)env->GetIntField(thiz, fieldId);
188    if (client.get()) {
189        client->incStrong(thiz);
190    }
191    if (old != 0) {
192        old->decStrong(thiz);
193    }
194    env->SetIntField(thiz, fieldId, (int)client.get());
195    return old;
196}
197
198static sp<DrmManagerClientImpl> getDrmManagerClientImpl(JNIEnv* env, jobject thiz) {
199    Mutex::Autolock l(sLock);
200    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
201    jfieldID fieldId = env->GetFieldID(clazz, "mNativeContext", "I");
202
203    DrmManagerClientImpl* const client = (DrmManagerClientImpl*)env->GetIntField(thiz, fieldId);
204    return sp<DrmManagerClientImpl>(client);
205}
206
207static jint android_drm_DrmManagerClient_initialize(
208        JNIEnv* env, jobject thiz) {
209    ALOGV("initialize - Enter");
210
211    int uniqueId = 0;
212    sp<DrmManagerClientImpl> drmManager = DrmManagerClientImpl::create(&uniqueId, false);
213    drmManager->addClient(uniqueId);
214
215    setDrmManagerClientImpl(env, thiz, drmManager);
216    ALOGV("initialize - Exit");
217    return uniqueId;
218}
219
220static void android_drm_DrmManagerClient_setListeners(
221        JNIEnv* env, jobject thiz, jint uniqueId, jobject weak_thiz) {
222    ALOGV("setListeners - Enter");
223
224    // Set the listener to DrmManager
225    sp<DrmManagerClient::OnInfoListener> listener = new JNIOnInfoListener(env, thiz, weak_thiz);
226    getDrmManagerClientImpl(env, thiz)->setOnInfoListener(uniqueId, listener);
227
228    ALOGV("setListeners - Exit");
229}
230
231static void android_drm_DrmManagerClient_release(
232        JNIEnv* env, jobject thiz, jint uniqueId) {
233    ALOGV("release - Enter");
234    DrmManagerClientImpl::remove(uniqueId);
235    getDrmManagerClientImpl(env, thiz)->setOnInfoListener(uniqueId, NULL);
236
237    sp<DrmManagerClientImpl> oldClient = setDrmManagerClientImpl(env, thiz, NULL);
238    if (oldClient != NULL) {
239        oldClient->setOnInfoListener(uniqueId, NULL);
240        oldClient->removeClient(uniqueId);
241    }
242    ALOGV("release - Exit");
243}
244
245static jobject android_drm_DrmManagerClient_getConstraintsFromContent(
246            JNIEnv* env, jobject thiz, jint uniqueId, jstring jpath, jint usage) {
247    ALOGV("GetConstraints - Enter");
248
249    const String8 pathString = Utility::getStringValue(env, jpath);
250    DrmConstraints* pConstraints
251        = getDrmManagerClientImpl(env, thiz)->getConstraints(uniqueId, &pathString, usage);
252
253    jclass localRef = env->FindClass("android/content/ContentValues");
254    jmethodID ContentValues_putByteArray =
255            env->GetMethodID(localRef, "put", "(Ljava/lang/String;[B)V");
256    jmethodID ContentValues_putString =
257            env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/String;)V");
258    jmethodID ContentValues_constructor = env->GetMethodID(localRef, "<init>", "()V");
259    jobject constraints = NULL;
260
261    if (NULL != localRef && NULL != pConstraints) {
262        // create the java DrmConstraints object
263        constraints = env->NewObject(localRef, ContentValues_constructor);
264
265        DrmConstraints::KeyIterator keyIt = pConstraints->keyIterator();
266        while (keyIt.hasNext()) {
267            String8 key = keyIt.next();
268
269            // insert the entry<constraintKey, constraintValue> to newly created java object
270            if (DrmConstraints::EXTENDED_METADATA == key) {
271                const char* value = pConstraints->getAsByteArray(&key);
272                if (NULL != value) {
273                    ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(strlen(value)));
274                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
275                    env->SetByteArrayRegion(dataArray.get(), 0, strlen(value), (jbyte*)value);
276                    env->CallVoidMethod(constraints, ContentValues_putByteArray,
277                                        keyString.get(), dataArray.get());
278                }
279            } else {
280                String8 value = pConstraints->get(key);
281                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
282                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
283                env->CallVoidMethod(constraints, ContentValues_putString,
284                                    keyString.get(), valueString.get());
285            }
286        }
287    }
288
289    delete pConstraints; pConstraints = NULL;
290    ALOGV("GetConstraints - Exit");
291    return constraints;
292}
293
294static jobject android_drm_DrmManagerClient_getMetadataFromContent(
295            JNIEnv* env, jobject thiz, jint uniqueId, jstring jpath) {
296    ALOGV("GetMetadata - Enter");
297    const String8 pathString = Utility::getStringValue(env, jpath);
298    DrmMetadata* pMetadata =
299            getDrmManagerClientImpl(env, thiz)->getMetadata(uniqueId, &pathString);
300
301    jobject metadata = NULL;
302
303    jclass localRef = env->FindClass("android/content/ContentValues");
304    jmethodID ContentValues_putString =
305            env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/String;)V");
306
307    if (NULL != localRef && NULL != pMetadata) {
308        // Get the constructor id
309        jmethodID constructorId = NULL;
310        constructorId = env->GetMethodID(localRef, "<init>", "()V");
311        if (NULL != constructorId) {
312            // create the java DrmMetadata object
313            metadata = env->NewObject(localRef, constructorId);
314            if (NULL != metadata) {
315                DrmMetadata::KeyIterator keyIt = pMetadata->keyIterator();
316                while (keyIt.hasNext()) {
317                    String8 key = keyIt.next();
318                    // insert the entry<constraintKey, constraintValue>
319                    // to newly created java object
320                    String8 value = pMetadata->get(key);
321                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
322                    ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
323                    env->CallVoidMethod(metadata, ContentValues_putString,
324                                        keyString.get(), valueString.get());
325                }
326            }
327        }
328    }
329    delete pMetadata; pMetadata = NULL;
330    ALOGV("GetMetadata - Exit");
331    return metadata;
332}
333
334static jobjectArray android_drm_DrmManagerClient_getAllSupportInfo(
335            JNIEnv* env, jobject thiz, jint uniqueId) {
336    ALOGV("GetAllSupportInfo - Enter");
337    DrmSupportInfo* drmSupportInfoArray = NULL;
338
339    int length = 0;
340    getDrmManagerClientImpl(env, thiz)->getAllSupportInfo(uniqueId, &length, &drmSupportInfoArray);
341
342    jclass clazz = env->FindClass("android/drm/DrmSupportInfo");
343
344    jobjectArray array = (jobjectArray)env->NewObjectArray(length, clazz, NULL);
345
346    for (int i = 0; i < length; i++) {
347        DrmSupportInfo info = drmSupportInfoArray[i];
348
349        jobject drmSupportInfo = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "()V"));
350
351        jmethodID addMimeTypeId
352            = env->GetMethodID(clazz, "addMimeType", "(Ljava/lang/String;)V");
353        jmethodID addFileSuffixId
354            = env->GetMethodID(clazz, "addFileSuffix", "(Ljava/lang/String;)V");
355
356        env->CallVoidMethod(
357            drmSupportInfo, env->GetMethodID(clazz, "setDescription", "(Ljava/lang/String;)V"),
358            env->NewStringUTF(info.getDescription().string()));
359
360        DrmSupportInfo::MimeTypeIterator iterator = info.getMimeTypeIterator();
361        while (iterator.hasNext()) {
362            String8  value = iterator.next();
363            env->CallVoidMethod(drmSupportInfo, addMimeTypeId, env->NewStringUTF(value.string()));
364        }
365
366        DrmSupportInfo::FileSuffixIterator it = info.getFileSuffixIterator();
367        while (it.hasNext()) {
368            String8 value = it.next();
369            env->CallVoidMethod(
370                drmSupportInfo, addFileSuffixId, env->NewStringUTF(value.string()));
371        }
372
373        env->SetObjectArrayElement(array, i, drmSupportInfo);
374    }
375
376    delete [] drmSupportInfoArray; drmSupportInfoArray = NULL;
377    ALOGV("GetAllSupportInfo - Exit");
378    return array;
379}
380
381static void android_drm_DrmManagerClient_installDrmEngine(
382            JNIEnv* env, jobject thiz, jint uniqueId, jstring engineFilePath) {
383    ALOGV("installDrmEngine - Enter");
384    //getDrmManagerClient(env, thiz)
385    //  ->installDrmEngine(uniqueId, Utility::getStringValue(env, engineFilePath));
386    ALOGV("installDrmEngine - Exit");
387}
388
389static jint android_drm_DrmManagerClient_saveRights(
390            JNIEnv* env, jobject thiz, jint uniqueId,
391            jobject drmRights, jstring rightsPath, jstring contentPath) {
392    ALOGV("saveRights - Enter");
393    int result = DRM_ERROR_UNKNOWN;
394    int dataLength = 0;
395    char* mData =  Utility::getByteArrayValue(env, drmRights, "mData", &dataLength);
396
397    if (NULL != mData) {
398        DrmRights rights(DrmBuffer(mData, dataLength),
399                Utility::getStringValue(env, drmRights, "mMimeType"),
400                Utility::getStringValue(env, drmRights, "mAccountId"),
401                Utility::getStringValue(env, drmRights, "mSubscriptionId"));
402        result = getDrmManagerClientImpl(env, thiz)
403            ->saveRights(uniqueId, rights, Utility::getStringValue(env, rightsPath),
404                                Utility::getStringValue(env, contentPath));
405    }
406
407    delete[] mData; mData = NULL;
408    ALOGV("saveRights - Exit");
409    return result;
410}
411
412static jboolean android_drm_DrmManagerClient_canHandle(
413            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jstring mimeType) {
414    ALOGV("canHandle - Enter");
415    jboolean result
416        = getDrmManagerClientImpl(env, thiz)
417            ->canHandle(uniqueId, Utility::getStringValue(env, path),
418                    Utility::getStringValue(env, mimeType));
419    ALOGV("canHandle - Exit");
420    return result;
421}
422
423static jobject android_drm_DrmManagerClient_processDrmInfo(
424            JNIEnv* env, jobject thiz, jint uniqueId, jobject drmInfoObject) {
425    ALOGV("processDrmInfo - Enter");
426    int dataLength = 0;
427    const String8 mMimeType =  Utility::getStringValue(env, drmInfoObject, "mMimeType");
428    char* mData =  Utility::getByteArrayValue(env, drmInfoObject, "mData", &dataLength);
429    int mInfoType = Utility::getIntValue(env, drmInfoObject, "mInfoType");
430
431    const DrmBuffer buffer(mData, dataLength);
432    DrmInfo drmInfo(mInfoType, buffer, mMimeType);
433
434    jclass clazz = env->FindClass("android/drm/DrmInfo");
435    jmethodID DrmInfo_get = env->GetMethodID(clazz, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
436    jobject keyIterator
437        = env->CallObjectMethod(drmInfoObject,
438                env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
439
440    jclass Iterator_class = env->FindClass("java/util/Iterator");
441    jmethodID Iterator_hasNext = env->GetMethodID(Iterator_class, "hasNext", "()Z");
442    jmethodID Iterator_next = env->GetMethodID(Iterator_class, "next", "()Ljava/lang/Object;");
443
444    jclass Object_class = env->FindClass("java/lang/Object");
445    jmethodID Object_toString = env->GetMethodID(Object_class, "toString", "()Ljava/lang/String;");
446
447    while (env->CallBooleanMethod(keyIterator, Iterator_hasNext)) {
448        ScopedLocalRef<jstring> key(env,
449                (jstring) env->CallObjectMethod(keyIterator, Iterator_next));
450        ScopedLocalRef<jobject> valueObject(env,
451                env->CallObjectMethod(drmInfoObject, DrmInfo_get, key.get()));
452        ScopedLocalRef<jstring> valString(env, NULL);
453        if (NULL != valueObject.get()) {
454            valString.reset((jstring) env->CallObjectMethod(valueObject.get(), Object_toString));
455        }
456
457        String8 keyString = Utility::getStringValue(env, key.get());
458        String8 valueString = Utility::getStringValue(env, valString.get());
459        ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
460
461        drmInfo.put(keyString, valueString);
462    }
463
464    DrmInfoStatus* pDrmInfoStatus
465        = getDrmManagerClientImpl(env, thiz)->processDrmInfo(uniqueId, &drmInfo);
466
467    jclass localRef = env->FindClass("android/drm/DrmInfoStatus");
468    jobject drmInfoStatus = NULL;
469
470    if (NULL != localRef && NULL != pDrmInfoStatus) {
471        int statusCode = pDrmInfoStatus->statusCode;
472        int infoType = pDrmInfoStatus->infoType;
473
474        jbyteArray dataArray = NULL;
475        if (NULL != pDrmInfoStatus->drmBuffer) {
476            int length = pDrmInfoStatus->drmBuffer->length;
477            dataArray = env->NewByteArray(length);
478            env->SetByteArrayRegion(
479                dataArray, 0, length, (jbyte*) pDrmInfoStatus->drmBuffer->data);
480
481            delete [] pDrmInfoStatus->drmBuffer->data;
482            delete pDrmInfoStatus->drmBuffer; pDrmInfoStatus->drmBuffer = NULL;
483        }
484        jclass clazz = env->FindClass("android/drm/ProcessedData");
485        jmethodID constructorId
486            = env->GetMethodID(clazz, "<init>", "([BLjava/lang/String;Ljava/lang/String;)V");
487        jobject processedData = env->NewObject(clazz, constructorId, dataArray,
488                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::ACCOUNT_ID)).string()),
489                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::SUBSCRIPTION_ID)).string()));
490
491        constructorId
492            = env->GetMethodID(localRef,
493                "<init>", "(IILandroid/drm/ProcessedData;Ljava/lang/String;)V");
494
495        drmInfoStatus = env->NewObject(localRef, constructorId, statusCode, infoType,
496                processedData, env->NewStringUTF(pDrmInfoStatus->mimeType.string()));
497    }
498
499    delete[] mData; mData = NULL;
500    delete pDrmInfoStatus; pDrmInfoStatus = NULL;
501
502    ALOGV("processDrmInfo - Exit");
503    return drmInfoStatus;
504}
505
506static jobject android_drm_DrmManagerClient_acquireDrmInfo(
507            JNIEnv* env, jobject thiz, jint uniqueId, jobject drmInfoRequest) {
508    ALOGV("acquireDrmInfo Enter");
509    const String8 mMimeType =  Utility::getStringValue(env, drmInfoRequest, "mMimeType");
510    int mInfoType = Utility::getIntValue(env, drmInfoRequest, "mInfoType");
511
512    DrmInfoRequest drmInfoReq(mInfoType, mMimeType);
513
514    jclass clazz = env->FindClass("android/drm/DrmInfoRequest");
515    jobject keyIterator
516        = env->CallObjectMethod(drmInfoRequest,
517                env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
518    jmethodID DrmInfoRequest_get = env->GetMethodID(clazz,
519            "get", "(Ljava/lang/String;)Ljava/lang/Object;");
520
521    jclass Iterator_class = env->FindClass("java/util/Iterator");
522    jmethodID Iterator_hasNext = env->GetMethodID(Iterator_class, "hasNext", "()Z");
523    jmethodID Iterator_next = env->GetMethodID(Iterator_class, "next", "()Ljava/lang/Object;");
524
525    while (env->CallBooleanMethod(keyIterator, Iterator_hasNext)) {
526        ScopedLocalRef<jstring> key(env,
527                (jstring) env->CallObjectMethod(keyIterator, Iterator_next));
528        ScopedLocalRef<jstring> value(env,
529                (jstring) env->CallObjectMethod(drmInfoRequest, DrmInfoRequest_get, key.get()));
530
531        String8 keyString = Utility::getStringValue(env, key.get());
532        String8 valueString = Utility::getStringValue(env, value.get());
533        ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
534
535        drmInfoReq.put(keyString, valueString);
536    }
537
538    DrmInfo* pDrmInfo = getDrmManagerClientImpl(env, thiz)->acquireDrmInfo(uniqueId, &drmInfoReq);
539
540    jobject drmInfoObject = NULL;
541
542    if (NULL != pDrmInfo) {
543        jclass localRef = env->FindClass("android/drm/DrmInfo");
544
545        if (NULL != localRef) {
546            int length = pDrmInfo->getData().length;
547
548            jbyteArray dataArray = env->NewByteArray(length);
549            env->SetByteArrayRegion(dataArray, 0, length, (jbyte*)pDrmInfo->getData().data);
550
551            drmInfoObject
552                = env->NewObject(localRef,
553                    env->GetMethodID(localRef, "<init>", "(I[BLjava/lang/String;)V"),
554                    mInfoType, dataArray, env->NewStringUTF(pDrmInfo->getMimeType().string()));
555
556            DrmInfo::KeyIterator it = pDrmInfo->keyIterator();
557            jmethodID putMethodId
558                = env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/Object;)V");
559
560            while (it.hasNext()) {
561                String8 key = it.next();
562                String8 value = pDrmInfo->get(key);
563                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
564                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
565                env->CallVoidMethod(drmInfoObject, putMethodId,
566                    keyString.get(), valueString.get());
567            }
568        }
569        delete [] pDrmInfo->getData().data;
570    }
571
572    delete pDrmInfo; pDrmInfo = NULL;
573
574    ALOGV("acquireDrmInfo Exit");
575    return drmInfoObject;
576}
577
578static jint android_drm_DrmManagerClient_getDrmObjectType(
579            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jstring mimeType) {
580    ALOGV("getDrmObjectType Enter");
581    int drmObjectType
582        = getDrmManagerClientImpl(env, thiz)
583            ->getDrmObjectType(uniqueId, Utility::getStringValue(env, path),
584                                Utility::getStringValue(env, mimeType));
585    ALOGV("getDrmObjectType Exit");
586    return drmObjectType;
587}
588
589static jstring android_drm_DrmManagerClient_getOriginalMimeType(
590            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jobject fileDescriptor) {
591    ALOGV("getOriginalMimeType Enter");
592
593    int fd = (fileDescriptor == NULL)
594                ? -1
595                : jniGetFDFromFileDescriptor(env, fileDescriptor);
596
597    String8 mimeType
598        = getDrmManagerClientImpl(env, thiz)
599            ->getOriginalMimeType(uniqueId,
600                                  Utility::getStringValue(env, path), fd);
601    ALOGV("getOriginalMimeType Exit");
602    return env->NewStringUTF(mimeType.string());
603}
604
605static jint android_drm_DrmManagerClient_checkRightsStatus(
606            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, int action) {
607    ALOGV("checkRightsStatus Enter");
608    int rightsStatus
609        = getDrmManagerClientImpl(env, thiz)
610            ->checkRightsStatus(uniqueId, Utility::getStringValue(env, path), action);
611    ALOGV("checkRightsStatus Exit");
612    return rightsStatus;
613}
614
615static jint android_drm_DrmManagerClient_removeRights(
616            JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
617    ALOGV("removeRights");
618    return getDrmManagerClientImpl(env, thiz)
619               ->removeRights(uniqueId, Utility::getStringValue(env, path));
620}
621
622static jint android_drm_DrmManagerClient_removeAllRights(
623            JNIEnv* env, jobject thiz, jint uniqueId) {
624    ALOGV("removeAllRights");
625    return getDrmManagerClientImpl(env, thiz)->removeAllRights(uniqueId);
626}
627
628static jint android_drm_DrmManagerClient_openConvertSession(
629            JNIEnv* env, jobject thiz, jint uniqueId, jstring mimeType) {
630    ALOGV("openConvertSession Enter");
631    int convertId
632        = getDrmManagerClientImpl(env, thiz)
633            ->openConvertSession(uniqueId, Utility::getStringValue(env, mimeType));
634    ALOGV("openConvertSession Exit");
635    return convertId;
636}
637
638static jobject GetConvertedStatus(JNIEnv* env, DrmConvertedStatus* pDrmConvertedStatus) {
639    ALOGV("GetConvertedStatus - Enter");
640    jclass localRef = env->FindClass("android/drm/DrmConvertedStatus");
641
642    jobject drmConvertedStatus = NULL;
643
644    if (NULL != localRef && NULL != pDrmConvertedStatus) {
645        int statusCode = pDrmConvertedStatus->statusCode;
646
647        jbyteArray dataArray = NULL;
648        if (NULL != pDrmConvertedStatus->convertedData) {
649            int length = pDrmConvertedStatus->convertedData->length;
650            dataArray = env->NewByteArray(length);
651            env->SetByteArrayRegion(
652                dataArray, 0, length, (jbyte*) pDrmConvertedStatus->convertedData->data);
653
654            delete [] pDrmConvertedStatus->convertedData->data;
655            delete pDrmConvertedStatus->convertedData; pDrmConvertedStatus->convertedData = NULL;
656        }
657        jmethodID constructorId = env->GetMethodID(localRef, "<init>", "(I[BI)V");
658        drmConvertedStatus
659            = env->NewObject(localRef, constructorId,
660                             statusCode, dataArray, pDrmConvertedStatus->offset);
661    }
662
663    delete pDrmConvertedStatus; pDrmConvertedStatus = NULL;
664
665    ALOGV("GetConvertedStatus - Exit");
666    return drmConvertedStatus;
667}
668
669static jobject android_drm_DrmManagerClient_convertData(
670            JNIEnv* env, jobject thiz, jint uniqueId, jint convertId, jbyteArray inputData) {
671    ALOGV("convertData Enter");
672
673    int dataLength = 0;
674    char* mData = Utility::getByteArrayValue(env, inputData, &dataLength);
675    const DrmBuffer buffer(mData, dataLength);
676
677    DrmConvertedStatus* pDrmConvertedStatus
678            = getDrmManagerClientImpl(env, thiz)->convertData(uniqueId, convertId, &buffer);
679    jobject status = GetConvertedStatus(env, pDrmConvertedStatus);
680
681    delete[] mData;
682    mData = NULL;
683
684    ALOGV("convertData - Exit");
685    return status;
686}
687
688static jobject android_drm_DrmManagerClient_closeConvertSession(
689            JNIEnv* env, jobject thiz, int uniqueId, jint convertId) {
690
691    ALOGV("closeConvertSession Enter");
692
693    DrmConvertedStatus* pDrmConvertedStatus
694                = getDrmManagerClientImpl(env, thiz)->closeConvertSession(uniqueId, convertId);
695    jobject status = GetConvertedStatus(env, pDrmConvertedStatus);
696
697    ALOGV("closeConvertSession - Exit");
698    return status;
699}
700
701static JNINativeMethod nativeMethods[] = {
702
703    {"_initialize", "()I",
704                                    (void*)android_drm_DrmManagerClient_initialize},
705
706    {"_setListeners", "(ILjava/lang/Object;)V",
707                                    (void*)android_drm_DrmManagerClient_setListeners},
708
709    {"_release", "(I)V",
710                                    (void*)android_drm_DrmManagerClient_release},
711
712    {"_getConstraints", "(ILjava/lang/String;I)Landroid/content/ContentValues;",
713                                    (void*)android_drm_DrmManagerClient_getConstraintsFromContent},
714
715    {"_getMetadata", "(ILjava/lang/String;)Landroid/content/ContentValues;",
716                                    (void*)android_drm_DrmManagerClient_getMetadataFromContent},
717
718    {"_getAllSupportInfo", "(I)[Landroid/drm/DrmSupportInfo;",
719                                    (void*)android_drm_DrmManagerClient_getAllSupportInfo},
720
721    {"_installDrmEngine", "(ILjava/lang/String;)V",
722                                    (void*)android_drm_DrmManagerClient_installDrmEngine},
723
724    {"_canHandle", "(ILjava/lang/String;Ljava/lang/String;)Z",
725                                    (void*)android_drm_DrmManagerClient_canHandle},
726
727    {"_processDrmInfo", "(ILandroid/drm/DrmInfo;)Landroid/drm/DrmInfoStatus;",
728                                    (void*)android_drm_DrmManagerClient_processDrmInfo},
729
730    {"_acquireDrmInfo", "(ILandroid/drm/DrmInfoRequest;)Landroid/drm/DrmInfo;",
731                                    (void*)android_drm_DrmManagerClient_acquireDrmInfo},
732
733    {"_saveRights", "(ILandroid/drm/DrmRights;Ljava/lang/String;Ljava/lang/String;)I",
734                                    (void*)android_drm_DrmManagerClient_saveRights},
735
736    {"_getDrmObjectType", "(ILjava/lang/String;Ljava/lang/String;)I",
737                                    (void*)android_drm_DrmManagerClient_getDrmObjectType},
738
739    {"_getOriginalMimeType", "(ILjava/lang/String;Ljava/io/FileDescriptor;)Ljava/lang/String;",
740                                    (void*)android_drm_DrmManagerClient_getOriginalMimeType},
741
742    {"_checkRightsStatus", "(ILjava/lang/String;I)I",
743                                    (void*)android_drm_DrmManagerClient_checkRightsStatus},
744
745    {"_removeRights", "(ILjava/lang/String;)I",
746                                    (void*)android_drm_DrmManagerClient_removeRights},
747
748    {"_removeAllRights", "(I)I",
749                                    (void*)android_drm_DrmManagerClient_removeAllRights},
750
751    {"_openConvertSession", "(ILjava/lang/String;)I",
752                                    (void*)android_drm_DrmManagerClient_openConvertSession},
753
754    {"_convertData", "(II[B)Landroid/drm/DrmConvertedStatus;",
755                                    (void*)android_drm_DrmManagerClient_convertData},
756
757    {"_closeConvertSession", "(II)Landroid/drm/DrmConvertedStatus;",
758                                    (void*)android_drm_DrmManagerClient_closeConvertSession},
759};
760
761static int registerNativeMethods(JNIEnv* env) {
762    int result = -1;
763
764    /* look up the class */
765    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
766
767    if (NULL != clazz) {
768        if (env->RegisterNatives(clazz, nativeMethods, sizeof(nativeMethods)
769                / sizeof(nativeMethods[0])) == JNI_OK) {
770            result = 0;
771        }
772    }
773    return result;
774}
775
776jint JNI_OnLoad(JavaVM* vm, void* reserved) {
777    JNIEnv* env = NULL;
778    jint result = -1;
779
780    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {
781        if (NULL != env && registerNativeMethods(env) == 0) {
782            result = JNI_VERSION_1_4;
783        }
784    }
785    return result;
786}
787
788