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", "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, jstring engineFilePath) {
385    ALOGV("installDrmEngine - Enter");
386    //getDrmManagerClient(env, thiz)
387    //  ->installDrmEngine(uniqueId, Utility::getStringValue(env, engineFilePath));
388    ALOGV("installDrmEngine - Exit");
389}
390
391static jint android_drm_DrmManagerClient_saveRights(
392            JNIEnv* env, jobject thiz, jint uniqueId,
393            jobject drmRights, jstring rightsPath, jstring contentPath) {
394    ALOGV("saveRights - Enter");
395    int result = DRM_ERROR_UNKNOWN;
396    int dataLength = 0;
397    char* mData =  Utility::getByteArrayValue(env, drmRights, "mData", &dataLength);
398
399    if (NULL != mData) {
400        DrmRights rights(DrmBuffer(mData, dataLength),
401                Utility::getStringValue(env, drmRights, "mMimeType"),
402                Utility::getStringValue(env, drmRights, "mAccountId"),
403                Utility::getStringValue(env, drmRights, "mSubscriptionId"));
404        result = getDrmManagerClientImpl(env, thiz)
405            ->saveRights(uniqueId, rights, Utility::getStringValue(env, rightsPath),
406                                Utility::getStringValue(env, contentPath));
407    }
408
409    delete[] mData; mData = NULL;
410    ALOGV("saveRights - Exit");
411    return static_cast<jint>(result);
412}
413
414static jboolean android_drm_DrmManagerClient_canHandle(
415            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jstring mimeType) {
416    ALOGV("canHandle - Enter");
417    jboolean result
418        = getDrmManagerClientImpl(env, thiz)
419            ->canHandle(uniqueId, Utility::getStringValue(env, path),
420                    Utility::getStringValue(env, mimeType));
421    ALOGV("canHandle - Exit");
422    return result;
423}
424
425static jobject android_drm_DrmManagerClient_processDrmInfo(
426            JNIEnv* env, jobject thiz, jint uniqueId, jobject drmInfoObject) {
427    ALOGV("processDrmInfo - Enter");
428    int dataLength = 0;
429    const String8 mMimeType =  Utility::getStringValue(env, drmInfoObject, "mMimeType");
430    char* mData =  Utility::getByteArrayValue(env, drmInfoObject, "mData", &dataLength);
431    int mInfoType = Utility::getIntValue(env, drmInfoObject, "mInfoType");
432
433    const DrmBuffer buffer(mData, dataLength);
434    DrmInfo drmInfo(mInfoType, buffer, mMimeType);
435
436    jclass clazz = env->FindClass("android/drm/DrmInfo");
437    jmethodID DrmInfo_get = env->GetMethodID(clazz, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
438    jobject keyIterator
439        = env->CallObjectMethod(drmInfoObject,
440                env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
441
442    jclass Iterator_class = env->FindClass("java/util/Iterator");
443    jmethodID Iterator_hasNext = env->GetMethodID(Iterator_class, "hasNext", "()Z");
444    jmethodID Iterator_next = env->GetMethodID(Iterator_class, "next", "()Ljava/lang/Object;");
445
446    jclass Object_class = env->FindClass("java/lang/Object");
447    jmethodID Object_toString = env->GetMethodID(Object_class, "toString", "()Ljava/lang/String;");
448
449    while (env->CallBooleanMethod(keyIterator, Iterator_hasNext)) {
450        ScopedLocalRef<jstring> key(env,
451                (jstring) env->CallObjectMethod(keyIterator, Iterator_next));
452        ScopedLocalRef<jobject> valueObject(env,
453                env->CallObjectMethod(drmInfoObject, DrmInfo_get, key.get()));
454        ScopedLocalRef<jstring> valString(env, NULL);
455        if (NULL != valueObject.get()) {
456            valString.reset((jstring) env->CallObjectMethod(valueObject.get(), Object_toString));
457        }
458
459        String8 keyString = Utility::getStringValue(env, key.get());
460        String8 valueString = Utility::getStringValue(env, valString.get());
461        ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
462
463        drmInfo.put(keyString, valueString);
464    }
465
466    DrmInfoStatus* pDrmInfoStatus
467        = getDrmManagerClientImpl(env, thiz)->processDrmInfo(uniqueId, &drmInfo);
468
469    jclass localRef = env->FindClass("android/drm/DrmInfoStatus");
470    jobject drmInfoStatus = NULL;
471
472    if (NULL != localRef && NULL != pDrmInfoStatus) {
473        int statusCode = pDrmInfoStatus->statusCode;
474        int infoType = pDrmInfoStatus->infoType;
475
476        jbyteArray dataArray = NULL;
477        if (NULL != pDrmInfoStatus->drmBuffer) {
478            int length = pDrmInfoStatus->drmBuffer->length;
479            dataArray = env->NewByteArray(length);
480            env->SetByteArrayRegion(
481                dataArray, 0, length, (jbyte*) pDrmInfoStatus->drmBuffer->data);
482
483            delete [] pDrmInfoStatus->drmBuffer->data;
484            delete pDrmInfoStatus->drmBuffer; pDrmInfoStatus->drmBuffer = NULL;
485        }
486        jclass clazz = env->FindClass("android/drm/ProcessedData");
487        jmethodID constructorId
488            = env->GetMethodID(clazz, "<init>", "([BLjava/lang/String;Ljava/lang/String;)V");
489        jobject processedData = env->NewObject(clazz, constructorId, dataArray,
490                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::ACCOUNT_ID)).string()),
491                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::SUBSCRIPTION_ID)).string()));
492
493        constructorId
494            = env->GetMethodID(localRef,
495                "<init>", "(IILandroid/drm/ProcessedData;Ljava/lang/String;)V");
496
497        drmInfoStatus = env->NewObject(localRef, constructorId, statusCode, infoType,
498                processedData, env->NewStringUTF(pDrmInfoStatus->mimeType.string()));
499    }
500
501    delete[] mData; mData = NULL;
502    delete pDrmInfoStatus; pDrmInfoStatus = NULL;
503
504    ALOGV("processDrmInfo - Exit");
505    return drmInfoStatus;
506}
507
508static jobject android_drm_DrmManagerClient_acquireDrmInfo(
509            JNIEnv* env, jobject thiz, jint uniqueId, jobject drmInfoRequest) {
510    ALOGV("acquireDrmInfo Enter");
511    const String8 mMimeType =  Utility::getStringValue(env, drmInfoRequest, "mMimeType");
512    int mInfoType = Utility::getIntValue(env, drmInfoRequest, "mInfoType");
513
514    DrmInfoRequest drmInfoReq(mInfoType, mMimeType);
515
516    jclass clazz = env->FindClass("android/drm/DrmInfoRequest");
517    jobject keyIterator
518        = env->CallObjectMethod(drmInfoRequest,
519                env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
520    jmethodID DrmInfoRequest_get = env->GetMethodID(clazz,
521            "get", "(Ljava/lang/String;)Ljava/lang/Object;");
522
523    jclass Iterator_class = env->FindClass("java/util/Iterator");
524    jmethodID Iterator_hasNext = env->GetMethodID(Iterator_class, "hasNext", "()Z");
525    jmethodID Iterator_next = env->GetMethodID(Iterator_class, "next", "()Ljava/lang/Object;");
526
527    while (env->CallBooleanMethod(keyIterator, Iterator_hasNext)) {
528        ScopedLocalRef<jstring> key(env,
529                (jstring) env->CallObjectMethod(keyIterator, Iterator_next));
530        ScopedLocalRef<jstring> value(env,
531                (jstring) env->CallObjectMethod(drmInfoRequest, DrmInfoRequest_get, key.get()));
532
533        String8 keyString = Utility::getStringValue(env, key.get());
534        String8 valueString = Utility::getStringValue(env, value.get());
535        ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
536
537        drmInfoReq.put(keyString, valueString);
538    }
539
540    DrmInfo* pDrmInfo = getDrmManagerClientImpl(env, thiz)->acquireDrmInfo(uniqueId, &drmInfoReq);
541
542    jobject drmInfoObject = NULL;
543
544    if (NULL != pDrmInfo) {
545        jclass localRef = env->FindClass("android/drm/DrmInfo");
546
547        if (NULL != localRef) {
548            int length = pDrmInfo->getData().length;
549
550            jbyteArray dataArray = env->NewByteArray(length);
551            env->SetByteArrayRegion(dataArray, 0, length, (jbyte*)pDrmInfo->getData().data);
552
553            drmInfoObject
554                = env->NewObject(localRef,
555                    env->GetMethodID(localRef, "<init>", "(I[BLjava/lang/String;)V"),
556                    mInfoType, dataArray, env->NewStringUTF(pDrmInfo->getMimeType().string()));
557
558            DrmInfo::KeyIterator it = pDrmInfo->keyIterator();
559            jmethodID putMethodId
560                = env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/Object;)V");
561
562            while (it.hasNext()) {
563                String8 key = it.next();
564                String8 value = pDrmInfo->get(key);
565                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
566                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
567                env->CallVoidMethod(drmInfoObject, putMethodId,
568                    keyString.get(), valueString.get());
569            }
570        }
571        delete [] pDrmInfo->getData().data;
572    }
573
574    delete pDrmInfo; pDrmInfo = NULL;
575
576    ALOGV("acquireDrmInfo Exit");
577    return drmInfoObject;
578}
579
580static jint android_drm_DrmManagerClient_getDrmObjectType(
581            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jstring mimeType) {
582    ALOGV("getDrmObjectType Enter");
583    int drmObjectType
584        = getDrmManagerClientImpl(env, thiz)
585            ->getDrmObjectType(uniqueId, Utility::getStringValue(env, path),
586                                Utility::getStringValue(env, mimeType));
587    ALOGV("getDrmObjectType Exit");
588    return static_cast<jint>(drmObjectType);
589}
590
591static jstring android_drm_DrmManagerClient_getOriginalMimeType(
592            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jobject fileDescriptor) {
593    ALOGV("getOriginalMimeType Enter");
594
595    int fd = (fileDescriptor == NULL)
596                ? -1
597                : jniGetFDFromFileDescriptor(env, fileDescriptor);
598
599    String8 mimeType
600        = getDrmManagerClientImpl(env, thiz)
601            ->getOriginalMimeType(uniqueId,
602                                  Utility::getStringValue(env, path), fd);
603    ALOGV("getOriginalMimeType Exit");
604    return env->NewStringUTF(mimeType.string());
605}
606
607static jint android_drm_DrmManagerClient_checkRightsStatus(
608            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, int action) {
609    ALOGV("checkRightsStatus Enter");
610    int rightsStatus
611        = getDrmManagerClientImpl(env, thiz)
612            ->checkRightsStatus(uniqueId, Utility::getStringValue(env, path), action);
613    ALOGV("checkRightsStatus Exit");
614    return static_cast<jint>(rightsStatus);
615}
616
617static jint android_drm_DrmManagerClient_removeRights(
618            JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
619    ALOGV("removeRights");
620    return static_cast<jint>(getDrmManagerClientImpl(env, thiz)
621               ->removeRights(uniqueId, Utility::getStringValue(env, path)));
622}
623
624static jint android_drm_DrmManagerClient_removeAllRights(
625            JNIEnv* env, jobject thiz, jint uniqueId) {
626    ALOGV("removeAllRights");
627    return static_cast<jint>(getDrmManagerClientImpl(env, thiz)
628                ->removeAllRights(uniqueId));
629}
630
631static jint android_drm_DrmManagerClient_openConvertSession(
632            JNIEnv* env, jobject thiz, jint uniqueId, jstring mimeType) {
633    ALOGV("openConvertSession Enter");
634    int convertId
635        = getDrmManagerClientImpl(env, thiz)
636            ->openConvertSession(uniqueId, Utility::getStringValue(env, mimeType));
637    ALOGV("openConvertSession Exit");
638    return static_cast<jint>(convertId);
639}
640
641static jobject GetConvertedStatus(JNIEnv* env, DrmConvertedStatus* pDrmConvertedStatus) {
642    ALOGV("GetConvertedStatus - Enter");
643    jclass localRef = env->FindClass("android/drm/DrmConvertedStatus");
644
645    jobject drmConvertedStatus = NULL;
646
647    if (NULL != localRef && NULL != pDrmConvertedStatus) {
648        int statusCode = pDrmConvertedStatus->statusCode;
649
650        jbyteArray dataArray = NULL;
651        if (NULL != pDrmConvertedStatus->convertedData) {
652            int length = pDrmConvertedStatus->convertedData->length;
653            dataArray = env->NewByteArray(length);
654            env->SetByteArrayRegion(
655                dataArray, 0, length, (jbyte*) pDrmConvertedStatus->convertedData->data);
656
657            delete [] pDrmConvertedStatus->convertedData->data;
658            delete pDrmConvertedStatus->convertedData; pDrmConvertedStatus->convertedData = NULL;
659        }
660        jmethodID constructorId = env->GetMethodID(localRef, "<init>", "(I[BI)V");
661        drmConvertedStatus
662            = env->NewObject(localRef, constructorId,
663                             statusCode, dataArray, pDrmConvertedStatus->offset);
664    }
665
666    delete pDrmConvertedStatus; pDrmConvertedStatus = NULL;
667
668    ALOGV("GetConvertedStatus - Exit");
669    return drmConvertedStatus;
670}
671
672static jobject android_drm_DrmManagerClient_convertData(
673            JNIEnv* env, jobject thiz, jint uniqueId, jint convertId, jbyteArray inputData) {
674    ALOGV("convertData Enter");
675
676    int dataLength = 0;
677    char* mData = Utility::getByteArrayValue(env, inputData, &dataLength);
678    const DrmBuffer buffer(mData, dataLength);
679
680    DrmConvertedStatus* pDrmConvertedStatus
681            = getDrmManagerClientImpl(env, thiz)->convertData(uniqueId, convertId, &buffer);
682    jobject status = GetConvertedStatus(env, pDrmConvertedStatus);
683
684    delete[] mData;
685    mData = NULL;
686
687    ALOGV("convertData - Exit");
688    return status;
689}
690
691static jobject android_drm_DrmManagerClient_closeConvertSession(
692            JNIEnv* env, jobject thiz, jint uniqueId, jint convertId) {
693
694    ALOGV("closeConvertSession Enter");
695
696    DrmConvertedStatus* pDrmConvertedStatus
697                = getDrmManagerClientImpl(env, thiz)->closeConvertSession(uniqueId, convertId);
698    jobject status = GetConvertedStatus(env, pDrmConvertedStatus);
699
700    ALOGV("closeConvertSession - Exit");
701    return status;
702}
703
704static JNINativeMethod nativeMethods[] = {
705
706    {"_initialize", "()I",
707                                    (void*)android_drm_DrmManagerClient_initialize},
708
709    {"_setListeners", "(ILjava/lang/Object;)V",
710                                    (void*)android_drm_DrmManagerClient_setListeners},
711
712    {"_release", "(I)V",
713                                    (void*)android_drm_DrmManagerClient_release},
714
715    {"_getConstraints", "(ILjava/lang/String;I)Landroid/content/ContentValues;",
716                                    (void*)android_drm_DrmManagerClient_getConstraintsFromContent},
717
718    {"_getMetadata", "(ILjava/lang/String;)Landroid/content/ContentValues;",
719                                    (void*)android_drm_DrmManagerClient_getMetadataFromContent},
720
721    {"_getAllSupportInfo", "(I)[Landroid/drm/DrmSupportInfo;",
722                                    (void*)android_drm_DrmManagerClient_getAllSupportInfo},
723
724    {"_installDrmEngine", "(ILjava/lang/String;)V",
725                                    (void*)android_drm_DrmManagerClient_installDrmEngine},
726
727    {"_canHandle", "(ILjava/lang/String;Ljava/lang/String;)Z",
728                                    (void*)android_drm_DrmManagerClient_canHandle},
729
730    {"_processDrmInfo", "(ILandroid/drm/DrmInfo;)Landroid/drm/DrmInfoStatus;",
731                                    (void*)android_drm_DrmManagerClient_processDrmInfo},
732
733    {"_acquireDrmInfo", "(ILandroid/drm/DrmInfoRequest;)Landroid/drm/DrmInfo;",
734                                    (void*)android_drm_DrmManagerClient_acquireDrmInfo},
735
736    {"_saveRights", "(ILandroid/drm/DrmRights;Ljava/lang/String;Ljava/lang/String;)I",
737                                    (void*)android_drm_DrmManagerClient_saveRights},
738
739    {"_getDrmObjectType", "(ILjava/lang/String;Ljava/lang/String;)I",
740                                    (void*)android_drm_DrmManagerClient_getDrmObjectType},
741
742    {"_getOriginalMimeType", "(ILjava/lang/String;Ljava/io/FileDescriptor;)Ljava/lang/String;",
743                                    (void*)android_drm_DrmManagerClient_getOriginalMimeType},
744
745    {"_checkRightsStatus", "(ILjava/lang/String;I)I",
746                                    (void*)android_drm_DrmManagerClient_checkRightsStatus},
747
748    {"_removeRights", "(ILjava/lang/String;)I",
749                                    (void*)android_drm_DrmManagerClient_removeRights},
750
751    {"_removeAllRights", "(I)I",
752                                    (void*)android_drm_DrmManagerClient_removeAllRights},
753
754    {"_openConvertSession", "(ILjava/lang/String;)I",
755                                    (void*)android_drm_DrmManagerClient_openConvertSession},
756
757    {"_convertData", "(II[B)Landroid/drm/DrmConvertedStatus;",
758                                    (void*)android_drm_DrmManagerClient_convertData},
759
760    {"_closeConvertSession", "(II)Landroid/drm/DrmConvertedStatus;",
761                                    (void*)android_drm_DrmManagerClient_closeConvertSession},
762};
763
764static int registerNativeMethods(JNIEnv* env) {
765    int result = -1;
766
767    /* look up the class */
768    jclass clazz = env->FindClass("android/drm/DrmManagerClient");
769
770    if (NULL != clazz) {
771        if (env->RegisterNatives(clazz, nativeMethods, sizeof(nativeMethods)
772                / sizeof(nativeMethods[0])) == JNI_OK) {
773            result = 0;
774        }
775    }
776    return result;
777}
778
779jint JNI_OnLoad(JavaVM* vm, void* reserved) {
780    JNIEnv* env = NULL;
781    jint result = -1;
782
783    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {
784        if (NULL != env && registerNativeMethods(env) == 0) {
785            result = JNI_VERSION_1_4;
786        }
787    }
788    return result;
789}
790
791