android_media_MediaDrm.cpp revision 8a0c80fdcc46faa8cb8c9f4dda06f4b63ec2f906
1/*
2 * Copyright 2013, 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 "MediaDrm-JNI"
19#include <utils/Log.h>
20
21#include "android_media_MediaDrm.h"
22
23#include "android_runtime/AndroidRuntime.h"
24#include "jni.h"
25#include "JNIHelp.h"
26
27#include <binder/IServiceManager.h>
28#include <media/IDrm.h>
29#include <media/IMediaPlayerService.h>
30#include <media/stagefright/foundation/ADebug.h>
31
32namespace android {
33
34#define FIND_CLASS(var, className) \
35    var = env->FindClass(className); \
36    LOG_FATAL_IF(! var, "Unable to find class " className);
37
38#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
39    var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
40    LOG_FATAL_IF(! var, "Unable to find field " fieldName);
41
42#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
43    var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
44    LOG_FATAL_IF(! var, "Unable to find method " fieldName);
45
46struct RequestFields {
47    jfieldID data;
48    jfieldID defaultUrl;
49};
50
51struct ArrayListFields {
52    jmethodID init;
53    jmethodID add;
54};
55
56struct HashmapFields {
57    jmethodID init;
58    jmethodID get;
59    jmethodID put;
60    jmethodID entrySet;
61};
62
63struct SetFields {
64    jmethodID iterator;
65};
66
67struct IteratorFields {
68    jmethodID next;
69    jmethodID hasNext;
70};
71
72struct EntryFields {
73    jmethodID getKey;
74    jmethodID getValue;
75};
76
77struct fields_t {
78    jfieldID context;
79    RequestFields licenseRequest;
80    RequestFields provisionRequest;
81    ArrayListFields arraylist;
82    HashmapFields hashmap;
83    SetFields set;
84    IteratorFields iterator;
85    EntryFields entry;
86};
87
88static fields_t gFields;
89
90static bool throwExceptionAsNecessary(
91        JNIEnv *env, status_t err, const char *msg = NULL) {
92
93    if (err == BAD_VALUE) {
94        jniThrowException(env, "java/lang/IllegalArgumentException", msg);
95        return true;
96    } else if (err != OK) {
97        jniThrowException(env, "java/lang/IllegalStateException", msg);
98        return true;
99    }
100    return false;
101}
102
103static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
104    JDrm *jdrm = (JDrm *)env->GetIntField(thiz, gFields.context);
105    return jdrm ? jdrm->getDrm() : NULL;
106}
107
108JDrm::JDrm(
109        JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
110    mObject = env->NewWeakGlobalRef(thiz);
111    mDrm = MakeDrm(uuid);
112}
113
114JDrm::~JDrm() {
115    mDrm.clear();
116
117    JNIEnv *env = AndroidRuntime::getJNIEnv();
118
119    env->DeleteWeakGlobalRef(mObject);
120    mObject = NULL;
121}
122
123// static
124sp<IDrm> JDrm::MakeDrm() {
125    sp<IServiceManager> sm = defaultServiceManager();
126
127    sp<IBinder> binder =
128        sm->getService(String16("media.player"));
129
130    sp<IMediaPlayerService> service =
131        interface_cast<IMediaPlayerService>(binder);
132
133    if (service == NULL) {
134        return NULL;
135    }
136
137    sp<IDrm> drm = service->makeDrm();
138
139    if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
140        return NULL;
141    }
142
143    return drm;
144}
145
146// static
147sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
148    sp<IDrm> drm = MakeDrm();
149
150    if (drm == NULL) {
151        return NULL;
152    }
153
154    status_t err = drm->createPlugin(uuid);
155
156    if (err != OK) {
157        return NULL;
158    }
159
160    return drm;
161}
162
163// static
164bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
165    sp<IDrm> drm = MakeDrm();
166
167    if (drm == NULL) {
168        return false;
169    }
170
171    return drm->isCryptoSchemeSupported(uuid);
172}
173
174status_t JDrm::initCheck() const {
175    return mDrm == NULL ? NO_INIT : OK;
176}
177
178// JNI conversion utilities
179static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
180    Vector<uint8_t> vector;
181    size_t length = env->GetArrayLength(byteArray);
182    vector.insertAt((size_t)0, length);
183    env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
184    return vector;
185}
186
187static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
188    size_t length = vector.size();
189    jbyteArray result = env->NewByteArray(length);
190    if (result != NULL) {
191        env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
192    }
193    return result;
194}
195
196static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
197    jboolean isCopy;
198    String8 result;
199
200    const char *s = env->GetStringUTFChars(jstr, &isCopy);
201    if (s) {
202        result = s;
203        env->ReleaseStringUTFChars(jstr, s);
204    }
205    return result;
206}
207/*
208    import java.util.HashMap;
209    import java.util.Set;
210    import java.Map.Entry;
211    import jav.util.Iterator;
212
213    HashMap<k, v> hm;
214    Set<Entry<k, v> > s = hm.entrySet();
215    Iterator i = s.iterator();
216    Entry e = s.next();
217*/
218
219static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
220    jclass clazz;
221    FIND_CLASS(clazz, "java/lang/String");
222    KeyedVector<String8, String8> keyedVector;
223
224    jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
225    if (entrySet) {
226        jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
227        if (iterator) {
228            jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
229            while (hasNext) {
230                jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
231                if (entry) {
232                    jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
233                    if (!env->IsInstanceOf(obj, clazz)) {
234                        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
235                    }
236                    jstring jkey = static_cast<jstring>(obj);
237
238                    obj = env->CallObjectMethod(entry, gFields.entry.getValue);
239                    if (!env->IsInstanceOf(obj, clazz)) {
240                        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
241                    }
242                    jstring jvalue = static_cast<jstring>(obj);
243
244                    String8 key = JStringToString8(env, jkey);
245                    String8 value = JStringToString8(env, jvalue);
246                    keyedVector.add(key, value);
247
248                    env->DeleteLocalRef(jkey);
249                    env->DeleteLocalRef(jvalue);
250                    hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
251                }
252                env->DeleteLocalRef(entry);
253            }
254            env->DeleteLocalRef(iterator);
255        }
256        env->DeleteLocalRef(entrySet);
257    }
258    return keyedVector;
259}
260
261static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
262    jclass clazz;
263    FIND_CLASS(clazz, "java/util/HashMap");
264    jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
265    for (size_t i = 0; i < map.size(); ++i) {
266        jstring jkey = env->NewStringUTF(map.keyAt(i).string());
267        jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
268        env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
269        env->DeleteLocalRef(jkey);
270        env->DeleteLocalRef(jvalue);
271    }
272    return hashMap;
273}
274
275static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
276                                                   List<Vector<uint8_t> > list) {
277    jclass clazz;
278    FIND_CLASS(clazz, "java/util/ArrayList");
279    jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
280    List<Vector<uint8_t> >::iterator iter = list.begin();
281    while (iter != list.end()) {
282        jbyteArray byteArray = VectorToJByteArray(env, *iter);
283        env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
284        env->DeleteLocalRef(byteArray);
285        iter++;
286    }
287
288    return arrayList;
289}
290
291}  // namespace android
292
293using namespace android;
294
295static sp<JDrm> setDrm(
296        JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
297    sp<JDrm> old = (JDrm *)env->GetIntField(thiz, gFields.context);
298    if (drm != NULL) {
299        drm->incStrong(thiz);
300    }
301    if (old != NULL) {
302        old->decStrong(thiz);
303    }
304    env->SetIntField(thiz, gFields.context, (int)drm.get());
305
306    return old;
307}
308
309static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
310{
311    if (drm == NULL) {
312        jniThrowException(env, "java/lang/IllegalStateException", NULL);
313        return false;
314    }
315
316    if (jsessionId == NULL) {
317        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
318        return false;
319    }
320    return true;
321}
322
323static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
324    setDrm(env, thiz, NULL);
325}
326
327static void android_media_MediaDrm_native_init(JNIEnv *env) {
328    jclass clazz;
329    FIND_CLASS(clazz, "android/media/MediaDrm");
330    GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
331
332    FIND_CLASS(clazz, "android/media/MediaDrm$LicenseRequest");
333    GET_FIELD_ID(gFields.licenseRequest.data, clazz, "data", "[B");
334    GET_FIELD_ID(gFields.licenseRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
335
336    FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
337    GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B");
338    GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
339
340    FIND_CLASS(clazz, "java/util/ArrayList");
341    GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
342    GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
343
344    FIND_CLASS(clazz, "java/util/HashMap");
345    GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
346    GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
347    GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
348                  "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
349    GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
350
351    FIND_CLASS(clazz, "java/util/Set");
352    GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
353
354    FIND_CLASS(clazz, "java/util/Iterator");
355    GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
356    GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
357
358    FIND_CLASS(clazz, "java/util/Map$Entry");
359    GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
360    GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
361}
362
363static void android_media_MediaDrm_native_setup(
364        JNIEnv *env, jobject thiz,
365        jobject weak_this, jbyteArray uuidObj) {
366
367    if (uuidObj == NULL) {
368        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
369        return;
370    }
371
372    Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
373
374    if (uuid.size() != 16) {
375        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
376        return;
377    }
378
379    sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
380
381    status_t err = drm->initCheck();
382
383    if (err != OK) {
384        jniThrowException(
385                env,
386                "android/media/MediaDrmException",
387                "Failed to instantiate drm object.");
388        return;
389    }
390
391    setDrm(env, thiz, drm);
392}
393
394static void android_media_MediaDrm_native_finalize(
395        JNIEnv *env, jobject thiz) {
396    android_media_MediaDrm_release(env, thiz);
397}
398
399static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
400        JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
401
402    if (uuidObj == NULL) {
403        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
404        return false;
405    }
406
407    Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
408
409    if (uuid.size() != 16) {
410        jniThrowException(
411                env,
412                "java/lang/IllegalArgumentException",
413                NULL);
414        return false;
415    }
416
417    return JDrm::IsCryptoSchemeSupported(uuid.array());
418}
419
420static jbyteArray android_media_MediaDrm_openSession(
421    JNIEnv *env, jobject thiz) {
422    sp<IDrm> drm = GetDrm(env, thiz);
423
424    if (drm == NULL) {
425        jniThrowException(env, "java/lang/IllegalStateException", NULL);
426        return NULL;
427    }
428
429    Vector<uint8_t> sessionId;
430    status_t err = drm->openSession(sessionId);
431
432    if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
433        return NULL;
434    }
435
436    return VectorToJByteArray(env, sessionId);
437}
438
439static void android_media_MediaDrm_closeSession(
440    JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
441    sp<IDrm> drm = GetDrm(env, thiz);
442
443    if (!CheckSession(env, drm, jsessionId)) {
444        return;
445    }
446
447    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
448
449    status_t err = drm->closeSession(sessionId);
450
451    throwExceptionAsNecessary(env, err, "Failed to close session");
452}
453
454static jobject android_media_MediaDrm_getLicenseRequest(
455    JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
456    jstring jmimeType, jint jlicenseType, jobject joptParams) {
457    sp<IDrm> drm = GetDrm(env, thiz);
458
459    if (!CheckSession(env, drm, jsessionId)) {
460        return NULL;
461    }
462
463    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
464
465    Vector<uint8_t> initData;
466    if (jinitData != NULL) {
467        initData = JByteArrayToVector(env, jinitData);
468    }
469
470    String8 mimeType;
471    if (jmimeType != NULL) {
472        mimeType = JStringToString8(env, jmimeType);
473    }
474
475    DrmPlugin::LicenseType licenseType = (DrmPlugin::LicenseType)jlicenseType;
476
477    KeyedVector<String8, String8> optParams;
478    if (joptParams != NULL) {
479        optParams = HashMapToKeyedVector(env, joptParams);
480    }
481
482    Vector<uint8_t> request;
483    String8 defaultUrl;
484
485    status_t err = drm->getLicenseRequest(sessionId, initData, mimeType,
486                                          licenseType, optParams, request, defaultUrl);
487
488    if (throwExceptionAsNecessary(env, err, "Failed to get license request")) {
489        return NULL;
490    }
491
492    // Fill out return obj
493    jclass clazz;
494    FIND_CLASS(clazz, "android/media/MediaDrm$LicenseRequest");
495
496    jobject licenseObj = NULL;
497
498    if (clazz) {
499        licenseObj = env->AllocObject(clazz);
500        jbyteArray jrequest = VectorToJByteArray(env, request);
501        env->SetObjectField(licenseObj, gFields.licenseRequest.data, jrequest);
502
503        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
504        env->SetObjectField(licenseObj, gFields.licenseRequest.defaultUrl, jdefaultUrl);
505    }
506
507    return licenseObj;
508}
509
510static void android_media_MediaDrm_provideLicenseResponse(
511    JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
512    sp<IDrm> drm = GetDrm(env, thiz);
513
514    if (!CheckSession(env, drm, jsessionId)) {
515        return;
516    }
517
518    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
519
520    if (jresponse == NULL) {
521        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
522        return;
523    }
524    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
525
526    status_t err = drm->provideLicenseResponse(sessionId, response);
527
528    throwExceptionAsNecessary(env, err, "Failed to handle license response");
529}
530
531static void android_media_MediaDrm_removeLicense(
532    JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
533    sp<IDrm> drm = GetDrm(env, thiz);
534
535    if (!CheckSession(env, drm, jsessionId)) {
536        return;
537    }
538
539    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
540
541    status_t err = drm->removeLicense(sessionId);
542
543    throwExceptionAsNecessary(env, err, "Failed to remove license");
544}
545
546static jobject android_media_MediaDrm_queryLicenseStatus(
547    JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
548    sp<IDrm> drm = GetDrm(env, thiz);
549
550    if (!CheckSession(env, drm, jsessionId)) {
551        return NULL;
552    }
553    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
554
555    KeyedVector<String8, String8> infoMap;
556
557    status_t err = drm->queryLicenseStatus(sessionId, infoMap);
558
559    if (throwExceptionAsNecessary(env, err, "Failed to query license")) {
560        return NULL;
561    }
562
563    return KeyedVectorToHashMap(env, infoMap);
564}
565
566static jobject android_media_MediaDrm_getProvisionRequest(
567    JNIEnv *env, jobject thiz) {
568    sp<IDrm> drm = GetDrm(env, thiz);
569
570    if (drm == NULL) {
571        jniThrowException(env, "java/lang/IllegalStateException", NULL);
572        return NULL;
573    }
574
575    Vector<uint8_t> request;
576    String8 defaultUrl;
577
578    status_t err = drm->getProvisionRequest(request, defaultUrl);
579
580    if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
581        return NULL;
582    }
583
584    // Fill out return obj
585    jclass clazz;
586    FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
587
588    jobject provisionObj = NULL;
589
590    if (clazz) {
591        provisionObj = env->AllocObject(clazz);
592        jbyteArray jrequest = VectorToJByteArray(env, request);
593        env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
594
595        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
596        env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
597    }
598
599    return provisionObj;
600}
601
602static void android_media_MediaDrm_provideProvisionResponse(
603    JNIEnv *env, jobject thiz, jbyteArray jresponse) {
604    sp<IDrm> drm = GetDrm(env, thiz);
605
606    if (drm == NULL) {
607        jniThrowException(env, "java/lang/IllegalStateException", NULL);
608        return;
609    }
610
611    if (jresponse == NULL) {
612        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
613        return;
614    }
615
616    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
617
618    status_t err = drm->provideProvisionResponse(response);
619
620    throwExceptionAsNecessary(env, err, "Failed to handle provision response");
621}
622
623static jobject android_media_MediaDrm_getSecureStops(
624    JNIEnv *env, jobject thiz) {
625    sp<IDrm> drm = GetDrm(env, thiz);
626
627    if (drm == NULL) {
628        jniThrowException(env, "java/lang/IllegalStateException", NULL);
629        return NULL;
630    }
631
632    List<Vector<uint8_t> > secureStops;
633
634    status_t err = drm->getSecureStops(secureStops);
635
636    if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
637        return NULL;
638    }
639
640    return ListOfVectorsToArrayListOfByteArray(env, secureStops);
641}
642
643static void android_media_MediaDrm_releaseSecureStops(
644    JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
645    sp<IDrm> drm = GetDrm(env, thiz);
646
647    if (drm == NULL) {
648        jniThrowException(env, "java/lang/IllegalStateException", NULL);
649        return;
650    }
651
652    Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
653
654    status_t err = drm->releaseSecureStops(ssRelease);
655
656    throwExceptionAsNecessary(env, err, "Failed to release secure stops");
657}
658
659static jstring android_media_MediaDrm_getPropertyString(
660    JNIEnv *env, jobject thiz, jstring jname) {
661    sp<IDrm> drm = GetDrm(env, thiz);
662
663    if (drm == NULL) {
664        jniThrowException(env, "java/lang/IllegalStateException", NULL);
665        return NULL;
666    }
667
668    if (jname == NULL) {
669        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
670        return NULL;
671    }
672
673    String8 name = JStringToString8(env, jname);
674    String8 value;
675
676    status_t err = drm->getPropertyString(name, value);
677
678    if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
679        return NULL;
680    }
681
682    return env->NewStringUTF(value.string());
683}
684
685static jbyteArray android_media_MediaDrm_getPropertyByteArray(
686    JNIEnv *env, jobject thiz, jstring jname) {
687    sp<IDrm> drm = GetDrm(env, thiz);
688
689    if (drm == NULL) {
690        jniThrowException(env, "java/lang/IllegalStateException", NULL);
691        return NULL;
692    }
693
694    if (jname == NULL) {
695        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
696        return NULL;
697    }
698
699    String8 name = JStringToString8(env, jname);
700    Vector<uint8_t> value;
701
702    status_t err = drm->getPropertyByteArray(name, value);
703
704    if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
705        return NULL;
706    }
707
708    return VectorToJByteArray(env, value);
709}
710
711static void android_media_MediaDrm_setPropertyString(
712    JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
713    sp<IDrm> drm = GetDrm(env, thiz);
714
715    if (drm == NULL) {
716        jniThrowException(env, "java/lang/IllegalStateException", NULL);
717        return;
718    }
719
720    if (jname == NULL || jvalue == NULL) {
721        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
722        return;
723    }
724
725    String8 name = JStringToString8(env, jname);
726    String8 value = JStringToString8(env, jvalue);
727
728    status_t err = drm->setPropertyString(name, value);
729
730    throwExceptionAsNecessary(env, err, "Failed to set property");
731}
732
733static void android_media_MediaDrm_setPropertyByteArray(
734    JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
735    sp<IDrm> drm = GetDrm(env, thiz);
736
737    if (drm == NULL) {
738        jniThrowException(env, "java/lang/IllegalStateException", NULL);
739        return;
740    }
741
742    if (jname == NULL || jvalue == NULL) {
743        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
744        return;
745    }
746
747    String8 name = JStringToString8(env, jname);
748    Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
749
750    status_t err = drm->setPropertyByteArray(name, value);
751
752    throwExceptionAsNecessary(env, err, "Failed to set property");
753}
754
755
756static JNINativeMethod gMethods[] = {
757    { "release", "()V", (void *)android_media_MediaDrm_release },
758    { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
759
760    { "native_setup", "(Ljava/lang/Object;[B)V",
761      (void *)android_media_MediaDrm_native_setup },
762
763    { "native_finalize", "()V",
764      (void *)android_media_MediaDrm_native_finalize },
765
766    { "isCryptoSchemeSupportedNative", "([B)Z",
767      (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
768
769    { "openSession", "()[B",
770      (void *)android_media_MediaDrm_openSession },
771
772    { "closeSession", "([B)V",
773      (void *)android_media_MediaDrm_closeSession },
774
775    { "getLicenseRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
776      "Landroid/media/MediaDrm$LicenseRequest;",
777      (void *)android_media_MediaDrm_getLicenseRequest },
778
779    { "provideLicenseResponse", "([B[B)V",
780      (void *)android_media_MediaDrm_provideLicenseResponse },
781
782    { "removeLicense", "([B)V",
783      (void *)android_media_MediaDrm_removeLicense },
784
785    { "queryLicenseStatus", "([B)Ljava/util/HashMap;",
786      (void *)android_media_MediaDrm_queryLicenseStatus },
787
788    { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
789      (void *)android_media_MediaDrm_getProvisionRequest },
790
791    { "provideProvisionResponse", "([B)V",
792      (void *)android_media_MediaDrm_provideProvisionResponse },
793
794    { "getSecureStops", "()Ljava/util/List;",
795      (void *)android_media_MediaDrm_getSecureStops },
796
797    { "releaseSecureStops", "([B)V",
798      (void *)android_media_MediaDrm_releaseSecureStops },
799
800    { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
801      (void *)android_media_MediaDrm_getPropertyString },
802
803    { "getPropertyByteArray", "(Ljava/lang/String;)[B",
804      (void *)android_media_MediaDrm_getPropertyByteArray },
805
806    { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
807      (void *)android_media_MediaDrm_setPropertyString },
808
809    { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
810      (void *)android_media_MediaDrm_setPropertyByteArray },
811};
812
813int register_android_media_Drm(JNIEnv *env) {
814    return AndroidRuntime::registerNativeMethods(env,
815                "android/media/MediaDrm", gMethods, NELEM(gMethods));
816}
817
818