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 "android_runtime/Log.h"
25 #include "android_os_Parcel.h"
26 #include "jni.h"
27 #include "JNIHelp.h"
28
29 #include <binder/IServiceManager.h>
30 #include <binder/Parcel.h>
31 #include <cutils/properties.h>
32 #include <media/IDrm.h>
33 #include <media/IMediaDrmService.h>
34 #include <media/stagefright/foundation/ADebug.h>
35 #include <media/stagefright/MediaErrors.h>
36
37 namespace android {
38
39 #define FIND_CLASS(var, className) \
40 var = env->FindClass(className); \
41 LOG_FATAL_IF(! var, "Unable to find class " className);
42
43 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
44 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
45 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
46
47 #define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
48 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
49 LOG_FATAL_IF(! var, "Unable to find method " fieldName);
50
51 #define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
52 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
53 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
54
55 #define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
56 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
57 LOG_FATAL_IF(! var, "Unable to find static method " fieldName);
58
59
60 struct RequestFields {
61 jfieldID data;
62 jfieldID defaultUrl;
63 jfieldID requestType;
64 };
65
66 struct ArrayListFields {
67 jmethodID init;
68 jmethodID add;
69 };
70
71 struct HashmapFields {
72 jmethodID init;
73 jmethodID get;
74 jmethodID put;
75 jmethodID entrySet;
76 };
77
78 struct SetFields {
79 jmethodID iterator;
80 };
81
82 struct IteratorFields {
83 jmethodID next;
84 jmethodID hasNext;
85 };
86
87 struct EntryFields {
88 jmethodID getKey;
89 jmethodID getValue;
90 };
91
92 struct EventTypes {
93 jint kEventProvisionRequired;
94 jint kEventKeyRequired;
95 jint kEventKeyExpired;
96 jint kEventVendorDefined;
97 jint kEventSessionReclaimed;
98 } gEventTypes;
99
100 struct EventWhat {
101 jint kWhatDrmEvent;
102 jint kWhatExpirationUpdate;
103 jint kWhatKeyStatusChange;
104 } gEventWhat;
105
106 struct KeyTypes {
107 jint kKeyTypeStreaming;
108 jint kKeyTypeOffline;
109 jint kKeyTypeRelease;
110 } gKeyTypes;
111
112 struct KeyRequestTypes {
113 jint kKeyRequestTypeInitial;
114 jint kKeyRequestTypeRenewal;
115 jint kKeyRequestTypeRelease;
116 } gKeyRequestTypes;
117
118 struct CertificateTypes {
119 jint kCertificateTypeNone;
120 jint kCertificateTypeX509;
121 } gCertificateTypes;
122
123 struct CertificateFields {
124 jfieldID wrappedPrivateKey;
125 jfieldID certificateData;
126 };
127
128 struct StateExceptionFields {
129 jmethodID init;
130 jclass classId;
131 };
132
133 struct fields_t {
134 jfieldID context;
135 jmethodID post_event;
136 RequestFields keyRequest;
137 RequestFields provisionRequest;
138 ArrayListFields arraylist;
139 HashmapFields hashmap;
140 SetFields set;
141 IteratorFields iterator;
142 EntryFields entry;
143 CertificateFields certificate;
144 StateExceptionFields stateException;
145 jclass certificateClassId;
146 jclass hashmapClassId;
147 jclass arraylistClassId;
148 jclass stringClassId;
149 };
150
151 static fields_t gFields;
152
153 // ----------------------------------------------------------------------------
154 // ref-counted object for callbacks
155 class JNIDrmListener: public DrmListener
156 {
157 public:
158 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
159 ~JNIDrmListener();
160 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
161 private:
162 JNIDrmListener();
163 jclass mClass; // Reference to MediaDrm class
164 jobject mObject; // Weak ref to MediaDrm Java object to call on
165 };
166
JNIDrmListener(JNIEnv * env,jobject thiz,jobject weak_thiz)167 JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
168 {
169 // Hold onto the MediaDrm class for use in calling the static method
170 // that posts events to the application thread.
171 jclass clazz = env->GetObjectClass(thiz);
172 if (clazz == NULL) {
173 ALOGE("Can't find android/media/MediaDrm");
174 jniThrowException(env, "java/lang/Exception",
175 "Can't find android/media/MediaDrm");
176 return;
177 }
178 mClass = (jclass)env->NewGlobalRef(clazz);
179
180 // We use a weak reference so the MediaDrm object can be garbage collected.
181 // The reference is only used as a proxy for callbacks.
182 mObject = env->NewGlobalRef(weak_thiz);
183 }
184
~JNIDrmListener()185 JNIDrmListener::~JNIDrmListener()
186 {
187 // remove global references
188 JNIEnv *env = AndroidRuntime::getJNIEnv();
189 env->DeleteGlobalRef(mObject);
190 env->DeleteGlobalRef(mClass);
191 }
192
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)193 void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
194 const Parcel *obj)
195 {
196 jint jwhat;
197 jint jeventType = 0;
198
199 // translate DrmPlugin event types into their java equivalents
200 switch (eventType) {
201 case DrmPlugin::kDrmPluginEventProvisionRequired:
202 jwhat = gEventWhat.kWhatDrmEvent;
203 jeventType = gEventTypes.kEventProvisionRequired;
204 break;
205 case DrmPlugin::kDrmPluginEventKeyNeeded:
206 jwhat = gEventWhat.kWhatDrmEvent;
207 jeventType = gEventTypes.kEventKeyRequired;
208 break;
209 case DrmPlugin::kDrmPluginEventKeyExpired:
210 jwhat = gEventWhat.kWhatDrmEvent;
211 jeventType = gEventTypes.kEventKeyExpired;
212 break;
213 case DrmPlugin::kDrmPluginEventVendorDefined:
214 jwhat = gEventWhat.kWhatDrmEvent;
215 jeventType = gEventTypes.kEventVendorDefined;
216 break;
217 case DrmPlugin::kDrmPluginEventSessionReclaimed:
218 jwhat = gEventWhat.kWhatDrmEvent;
219 jeventType = gEventTypes.kEventSessionReclaimed;
220 break;
221 case DrmPlugin::kDrmPluginEventExpirationUpdate:
222 jwhat = gEventWhat.kWhatExpirationUpdate;
223 break;
224 case DrmPlugin::kDrmPluginEventKeysChange:
225 jwhat = gEventWhat.kWhatKeyStatusChange;
226 break;
227 default:
228 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
229 return;
230 }
231
232 JNIEnv *env = AndroidRuntime::getJNIEnv();
233 if (obj && obj->dataSize() > 0) {
234 jobject jParcel = createJavaParcelObject(env);
235 if (jParcel != NULL) {
236 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
237 nativeParcel->setData(obj->data(), obj->dataSize());
238 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
239 jwhat, jeventType, extra, jParcel);
240 env->DeleteLocalRef(jParcel);
241 }
242 }
243
244 if (env->ExceptionCheck()) {
245 ALOGW("An exception occurred while notifying an event.");
246 LOGW_EX(env);
247 env->ExceptionClear();
248 }
249 }
250
throwStateException(JNIEnv * env,const char * msg,status_t err)251 static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
252 ALOGE("Illegal state exception: %s (%d)", msg, err);
253
254 jobject exception = env->NewObject(gFields.stateException.classId,
255 gFields.stateException.init, static_cast<int>(err),
256 env->NewStringUTF(msg));
257 env->Throw(static_cast<jthrowable>(exception));
258 }
259
throwExceptionAsNecessary(JNIEnv * env,status_t err,const char * msg=NULL)260 static bool throwExceptionAsNecessary(
261 JNIEnv *env, status_t err, const char *msg = NULL) {
262
263 const char *drmMessage = NULL;
264
265 switch (err) {
266 case ERROR_DRM_UNKNOWN:
267 drmMessage = "General DRM error";
268 break;
269 case ERROR_DRM_NO_LICENSE:
270 drmMessage = "No license";
271 break;
272 case ERROR_DRM_LICENSE_EXPIRED:
273 drmMessage = "License expired";
274 break;
275 case ERROR_DRM_SESSION_NOT_OPENED:
276 drmMessage = "Session not opened";
277 break;
278 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
279 drmMessage = "Not initialized";
280 break;
281 case ERROR_DRM_DECRYPT:
282 drmMessage = "Decrypt error";
283 break;
284 case ERROR_DRM_CANNOT_HANDLE:
285 drmMessage = "Unsupported scheme or data format";
286 break;
287 case ERROR_DRM_TAMPER_DETECTED:
288 drmMessage = "Invalid state";
289 break;
290 default:
291 break;
292 }
293
294 String8 vendorMessage;
295 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
296 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
297 drmMessage = vendorMessage.string();
298 }
299
300 if (err == BAD_VALUE) {
301 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
302 return true;
303 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
304 jniThrowException(env, "android/media/NotProvisionedException", msg);
305 return true;
306 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
307 jniThrowException(env, "android/media/ResourceBusyException", msg);
308 return true;
309 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
310 jniThrowException(env, "android/media/DeniedByServerException", msg);
311 return true;
312 } else if (err == DEAD_OBJECT) {
313 jniThrowException(env, "android/media/MediaDrmResetException",
314 "mediaserver died");
315 return true;
316 } else if (err != OK) {
317 String8 errbuf;
318 if (drmMessage != NULL) {
319 if (msg == NULL) {
320 msg = drmMessage;
321 } else {
322 errbuf = String8::format("%s: %s", msg, drmMessage);
323 msg = errbuf.string();
324 }
325 }
326 throwStateException(env, msg, err);
327 return true;
328 }
329 return false;
330 }
331
GetDrm(JNIEnv * env,jobject thiz)332 static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
333 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
334 return jdrm ? jdrm->getDrm() : NULL;
335 }
336
JDrm(JNIEnv * env,jobject thiz,const uint8_t uuid[16])337 JDrm::JDrm(
338 JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
339 mObject = env->NewWeakGlobalRef(thiz);
340 mDrm = MakeDrm(uuid);
341 if (mDrm != NULL) {
342 mDrm->setListener(this);
343 }
344 }
345
~JDrm()346 JDrm::~JDrm() {
347 JNIEnv *env = AndroidRuntime::getJNIEnv();
348
349 env->DeleteWeakGlobalRef(mObject);
350 mObject = NULL;
351 }
352
353 // static
MakeDrm()354 sp<IDrm> JDrm::MakeDrm() {
355 sp<IServiceManager> sm = defaultServiceManager();
356
357 sp<IBinder> binder = sm->getService(String16("media.drm"));
358 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
359 if (service == NULL) {
360 return NULL;
361 }
362
363 sp<IDrm> drm = service->makeDrm();
364 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
365 return NULL;
366 }
367
368 return drm;
369 }
370
371 // static
MakeDrm(const uint8_t uuid[16])372 sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
373 sp<IDrm> drm = MakeDrm();
374
375 if (drm == NULL) {
376 return NULL;
377 }
378
379 status_t err = drm->createPlugin(uuid);
380
381 if (err != OK) {
382 return NULL;
383 }
384
385 return drm;
386 }
387
setListener(const sp<DrmListener> & listener)388 status_t JDrm::setListener(const sp<DrmListener>& listener) {
389 Mutex::Autolock lock(mLock);
390 mListener = listener;
391 return OK;
392 }
393
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)394 void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
395 sp<DrmListener> listener;
396 mLock.lock();
397 listener = mListener;
398 mLock.unlock();
399
400 if (listener != NULL) {
401 Mutex::Autolock lock(mNotifyLock);
402 listener->notify(eventType, extra, obj);
403 }
404 }
405
disconnect()406 void JDrm::disconnect() {
407 if (mDrm != NULL) {
408 mDrm->destroyPlugin();
409 mDrm.clear();
410 }
411 }
412
413
414 // static
IsCryptoSchemeSupported(const uint8_t uuid[16],const String8 & mimeType)415 bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
416 sp<IDrm> drm = MakeDrm();
417
418 if (drm == NULL) {
419 return false;
420 }
421
422 return drm->isCryptoSchemeSupported(uuid, mimeType);
423 }
424
initCheck() const425 status_t JDrm::initCheck() const {
426 return mDrm == NULL ? NO_INIT : OK;
427 }
428
429 // JNI conversion utilities
JByteArrayToVector(JNIEnv * env,jbyteArray const & byteArray)430 static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
431 Vector<uint8_t> vector;
432 size_t length = env->GetArrayLength(byteArray);
433 vector.insertAt((size_t)0, length);
434 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
435 return vector;
436 }
437
VectorToJByteArray(JNIEnv * env,Vector<uint8_t> const & vector)438 static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
439 size_t length = vector.size();
440 jbyteArray result = env->NewByteArray(length);
441 if (result != NULL) {
442 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
443 }
444 return result;
445 }
446
JStringToString8(JNIEnv * env,jstring const & jstr)447 static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
448 String8 result;
449
450 const char *s = env->GetStringUTFChars(jstr, NULL);
451 if (s) {
452 result = s;
453 env->ReleaseStringUTFChars(jstr, s);
454 }
455 return result;
456 }
457
458 /*
459 import java.util.HashMap;
460 import java.util.Set;
461 import java.Map.Entry;
462 import jav.util.Iterator;
463
464 HashMap<k, v> hm;
465 Set<Entry<k, v> > s = hm.entrySet();
466 Iterator i = s.iterator();
467 Entry e = s.next();
468 */
469
HashMapToKeyedVector(JNIEnv * env,jobject & hashMap,bool * pIsOK)470 static KeyedVector<String8, String8> HashMapToKeyedVector(
471 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
472 jclass clazz = gFields.stringClassId;
473 KeyedVector<String8, String8> keyedVector;
474 *pIsOK = true;
475
476 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
477 if (entrySet) {
478 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
479 if (iterator) {
480 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
481 while (hasNext) {
482 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
483 if (entry) {
484 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
485 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
486 jniThrowException(env, "java/lang/IllegalArgumentException",
487 "HashMap key is not a String");
488 env->DeleteLocalRef(entry);
489 *pIsOK = false;
490 break;
491 }
492 jstring jkey = static_cast<jstring>(obj);
493
494 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
495 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
496 jniThrowException(env, "java/lang/IllegalArgumentException",
497 "HashMap value is not a String");
498 env->DeleteLocalRef(entry);
499 *pIsOK = false;
500 break;
501 }
502 jstring jvalue = static_cast<jstring>(obj);
503
504 String8 key = JStringToString8(env, jkey);
505 String8 value = JStringToString8(env, jvalue);
506 keyedVector.add(key, value);
507
508 env->DeleteLocalRef(jkey);
509 env->DeleteLocalRef(jvalue);
510 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
511 }
512 env->DeleteLocalRef(entry);
513 }
514 env->DeleteLocalRef(iterator);
515 }
516 env->DeleteLocalRef(entrySet);
517 }
518 return keyedVector;
519 }
520
KeyedVectorToHashMap(JNIEnv * env,KeyedVector<String8,String8> const & map)521 static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
522 jclass clazz = gFields.hashmapClassId;
523 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
524 for (size_t i = 0; i < map.size(); ++i) {
525 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
526 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
527 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
528 env->DeleteLocalRef(jkey);
529 env->DeleteLocalRef(jvalue);
530 }
531 return hashMap;
532 }
533
ListOfVectorsToArrayListOfByteArray(JNIEnv * env,List<Vector<uint8_t>> list)534 static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
535 List<Vector<uint8_t> > list) {
536 jclass clazz = gFields.arraylistClassId;
537 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
538 List<Vector<uint8_t> >::iterator iter = list.begin();
539 while (iter != list.end()) {
540 jbyteArray byteArray = VectorToJByteArray(env, *iter);
541 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
542 env->DeleteLocalRef(byteArray);
543 iter++;
544 }
545
546 return arrayList;
547 }
548
549 } // namespace android
550
551 using namespace android;
552
setDrm(JNIEnv * env,jobject thiz,const sp<JDrm> & drm)553 static sp<JDrm> setDrm(
554 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
555 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
556 if (drm != NULL) {
557 drm->incStrong(thiz);
558 }
559 if (old != NULL) {
560 old->decStrong(thiz);
561 }
562 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
563
564 return old;
565 }
566
CheckSession(JNIEnv * env,const sp<IDrm> & drm,jbyteArray const & jsessionId)567 static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
568 {
569 if (drm == NULL) {
570 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
571 return false;
572 }
573
574 if (jsessionId == NULL) {
575 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
576 return false;
577 }
578 return true;
579 }
580
android_media_MediaDrm_release(JNIEnv * env,jobject thiz)581 static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
582 sp<JDrm> drm = setDrm(env, thiz, NULL);
583 if (drm != NULL) {
584 drm->setListener(NULL);
585 drm->disconnect();
586 }
587 }
588
android_media_MediaDrm_native_init(JNIEnv * env)589 static void android_media_MediaDrm_native_init(JNIEnv *env) {
590 jclass clazz;
591 FIND_CLASS(clazz, "android/media/MediaDrm");
592 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
593 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
594 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
595
596 jfieldID field;
597 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
598 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
599 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
600 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
601 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
602 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
603 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
604 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
605 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
606 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
607
608 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
609 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
610 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
611 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
612 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
613 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
614
615 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
616 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
617 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
618 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
619 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
620 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
621
622 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
623 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
624 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
625 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
626
627 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
628 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
629 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
630 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
631
632 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
633 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
634 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
635 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
636 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
637 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
638
639 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
640 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
641 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
642
643 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
644 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
645 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
646 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
647
648 FIND_CLASS(clazz, "java/util/ArrayList");
649 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
650 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
651
652 FIND_CLASS(clazz, "java/util/HashMap");
653 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
654 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
655 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
656 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
657 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
658
659 FIND_CLASS(clazz, "java/util/Set");
660 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
661
662 FIND_CLASS(clazz, "java/util/Iterator");
663 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
664 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
665
666 FIND_CLASS(clazz, "java/util/Map$Entry");
667 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
668 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
669
670 FIND_CLASS(clazz, "java/util/HashMap");
671 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
672
673 FIND_CLASS(clazz, "java/lang/String");
674 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
675
676 FIND_CLASS(clazz, "java/util/ArrayList");
677 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
678
679 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
680 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
681 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
682 }
683
android_media_MediaDrm_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jbyteArray uuidObj)684 static void android_media_MediaDrm_native_setup(
685 JNIEnv *env, jobject thiz,
686 jobject weak_this, jbyteArray uuidObj) {
687
688 if (uuidObj == NULL) {
689 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
690 return;
691 }
692
693 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
694
695 if (uuid.size() != 16) {
696 jniThrowException(env, "java/lang/IllegalArgumentException",
697 "invalid UUID size, expected 16 bytes");
698 return;
699 }
700
701 sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
702
703 status_t err = drm->initCheck();
704
705 if (err != OK) {
706 jniThrowException(
707 env,
708 "android/media/UnsupportedSchemeException",
709 "Failed to instantiate drm object.");
710 return;
711 }
712
713 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
714 drm->setListener(listener);
715 setDrm(env, thiz, drm);
716 }
717
android_media_MediaDrm_native_finalize(JNIEnv * env,jobject thiz)718 static void android_media_MediaDrm_native_finalize(
719 JNIEnv *env, jobject thiz) {
720 android_media_MediaDrm_release(env, thiz);
721 }
722
android_media_MediaDrm_isCryptoSchemeSupportedNative(JNIEnv * env,jobject,jbyteArray uuidObj,jstring jmimeType)723 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
724 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
725
726 if (uuidObj == NULL) {
727 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
728 return false;
729 }
730
731 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
732
733 if (uuid.size() != 16) {
734 jniThrowException(
735 env,
736 "java/lang/IllegalArgumentException",
737 "invalid UUID size, expected 16 bytes");
738 return false;
739 }
740
741 String8 mimeType;
742 if (jmimeType != NULL) {
743 mimeType = JStringToString8(env, jmimeType);
744 }
745
746 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
747 }
748
android_media_MediaDrm_openSession(JNIEnv * env,jobject thiz)749 static jbyteArray android_media_MediaDrm_openSession(
750 JNIEnv *env, jobject thiz) {
751 sp<IDrm> drm = GetDrm(env, thiz);
752
753 if (drm == NULL) {
754 jniThrowException(env, "java/lang/IllegalStateException",
755 "MediaDrm obj is null");
756 return NULL;
757 }
758
759 Vector<uint8_t> sessionId;
760 status_t err = drm->openSession(sessionId);
761
762 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
763 return NULL;
764 }
765
766 return VectorToJByteArray(env, sessionId);
767 }
768
android_media_MediaDrm_closeSession(JNIEnv * env,jobject thiz,jbyteArray jsessionId)769 static void android_media_MediaDrm_closeSession(
770 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
771 sp<IDrm> drm = GetDrm(env, thiz);
772
773 if (!CheckSession(env, drm, jsessionId)) {
774 return;
775 }
776
777 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
778
779 status_t err = drm->closeSession(sessionId);
780
781 throwExceptionAsNecessary(env, err, "Failed to close session");
782 }
783
android_media_MediaDrm_getKeyRequest(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jinitData,jstring jmimeType,jint jkeyType,jobject joptParams)784 static jobject android_media_MediaDrm_getKeyRequest(
785 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
786 jstring jmimeType, jint jkeyType, jobject joptParams) {
787 sp<IDrm> drm = GetDrm(env, thiz);
788
789 if (!CheckSession(env, drm, jsessionId)) {
790 return NULL;
791 }
792
793 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
794
795 Vector<uint8_t> initData;
796 if (jinitData != NULL) {
797 initData = JByteArrayToVector(env, jinitData);
798 }
799
800 String8 mimeType;
801 if (jmimeType != NULL) {
802 mimeType = JStringToString8(env, jmimeType);
803 }
804
805 DrmPlugin::KeyType keyType;
806 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
807 keyType = DrmPlugin::kKeyType_Streaming;
808 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
809 keyType = DrmPlugin::kKeyType_Offline;
810 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
811 keyType = DrmPlugin::kKeyType_Release;
812 } else {
813 jniThrowException(env, "java/lang/IllegalArgumentException",
814 "invalid keyType");
815 return NULL;
816 }
817
818 KeyedVector<String8, String8> optParams;
819 if (joptParams != NULL) {
820 bool isOK;
821 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
822 if (!isOK) {
823 return NULL;
824 }
825 }
826
827 Vector<uint8_t> request;
828 String8 defaultUrl;
829 DrmPlugin::KeyRequestType keyRequestType;
830
831 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
832 keyType, optParams, request, defaultUrl, &keyRequestType);
833
834 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
835 return NULL;
836 }
837
838 // Fill out return obj
839 jclass clazz;
840 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
841
842 jobject keyObj = NULL;
843
844 if (clazz) {
845 keyObj = env->AllocObject(clazz);
846 jbyteArray jrequest = VectorToJByteArray(env, request);
847 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
848
849 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
850 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
851
852 switch (keyRequestType) {
853 case DrmPlugin::kKeyRequestType_Initial:
854 env->SetIntField(keyObj, gFields.keyRequest.requestType,
855 gKeyRequestTypes.kKeyRequestTypeInitial);
856 break;
857 case DrmPlugin::kKeyRequestType_Renewal:
858 env->SetIntField(keyObj, gFields.keyRequest.requestType,
859 gKeyRequestTypes.kKeyRequestTypeRenewal);
860 break;
861 case DrmPlugin::kKeyRequestType_Release:
862 env->SetIntField(keyObj, gFields.keyRequest.requestType,
863 gKeyRequestTypes.kKeyRequestTypeRelease);
864 break;
865 default:
866 throwStateException(env, "DRM plugin failure: unknown key request type",
867 ERROR_DRM_UNKNOWN);
868 break;
869 }
870 }
871
872 return keyObj;
873 }
874
android_media_MediaDrm_provideKeyResponse(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jresponse)875 static jbyteArray android_media_MediaDrm_provideKeyResponse(
876 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
877 sp<IDrm> drm = GetDrm(env, thiz);
878
879 if (!CheckSession(env, drm, jsessionId)) {
880 return NULL;
881 }
882
883 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
884
885 if (jresponse == NULL) {
886 jniThrowException(env, "java/lang/IllegalArgumentException",
887 "key response is null");
888 return NULL;
889 }
890 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
891 Vector<uint8_t> keySetId;
892
893 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
894
895 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
896 return NULL;
897 }
898 return VectorToJByteArray(env, keySetId);
899 }
900
android_media_MediaDrm_removeKeys(JNIEnv * env,jobject thiz,jbyteArray jkeysetId)901 static void android_media_MediaDrm_removeKeys(
902 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
903 sp<IDrm> drm = GetDrm(env, thiz);
904
905 if (jkeysetId == NULL) {
906 jniThrowException(env, "java/lang/IllegalArgumentException",
907 "keySetId is null");
908 return;
909 }
910
911 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
912
913 status_t err = drm->removeKeys(keySetId);
914
915 throwExceptionAsNecessary(env, err, "Failed to remove keys");
916 }
917
android_media_MediaDrm_restoreKeys(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jkeysetId)918 static void android_media_MediaDrm_restoreKeys(
919 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
920 jbyteArray jkeysetId) {
921
922 sp<IDrm> drm = GetDrm(env, thiz);
923
924 if (!CheckSession(env, drm, jsessionId)) {
925 return;
926 }
927
928 if (jkeysetId == NULL) {
929 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
930 return;
931 }
932
933 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
934 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
935
936 status_t err = drm->restoreKeys(sessionId, keySetId);
937
938 throwExceptionAsNecessary(env, err, "Failed to restore keys");
939 }
940
android_media_MediaDrm_queryKeyStatus(JNIEnv * env,jobject thiz,jbyteArray jsessionId)941 static jobject android_media_MediaDrm_queryKeyStatus(
942 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
943 sp<IDrm> drm = GetDrm(env, thiz);
944
945 if (!CheckSession(env, drm, jsessionId)) {
946 return NULL;
947 }
948 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
949
950 KeyedVector<String8, String8> infoMap;
951
952 status_t err = drm->queryKeyStatus(sessionId, infoMap);
953
954 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
955 return NULL;
956 }
957
958 return KeyedVectorToHashMap(env, infoMap);
959 }
960
android_media_MediaDrm_getProvisionRequestNative(JNIEnv * env,jobject thiz,jint jcertType,jstring jcertAuthority)961 static jobject android_media_MediaDrm_getProvisionRequestNative(
962 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
963 sp<IDrm> drm = GetDrm(env, thiz);
964
965 if (drm == NULL) {
966 jniThrowException(env, "java/lang/IllegalStateException",
967 "MediaDrm obj is null");
968 return NULL;
969 }
970
971 Vector<uint8_t> request;
972 String8 defaultUrl;
973
974 String8 certType;
975 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
976 certType = "X.509";
977 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
978 certType = "none";
979 } else {
980 certType = "invalid";
981 }
982
983 String8 certAuthority = JStringToString8(env, jcertAuthority);
984 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
985
986 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
987 return NULL;
988 }
989
990 // Fill out return obj
991 jclass clazz;
992 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
993
994 jobject provisionObj = NULL;
995
996 if (clazz) {
997 provisionObj = env->AllocObject(clazz);
998 jbyteArray jrequest = VectorToJByteArray(env, request);
999 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1000
1001 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1002 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1003 }
1004
1005 return provisionObj;
1006 }
1007
android_media_MediaDrm_provideProvisionResponseNative(JNIEnv * env,jobject thiz,jbyteArray jresponse)1008 static jobject android_media_MediaDrm_provideProvisionResponseNative(
1009 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1010 sp<IDrm> drm = GetDrm(env, thiz);
1011
1012 if (drm == NULL) {
1013 jniThrowException(env, "java/lang/IllegalStateException",
1014 "MediaDrm obj is null");
1015 return NULL;
1016 }
1017
1018 if (jresponse == NULL) {
1019 jniThrowException(env, "java/lang/IllegalArgumentException",
1020 "provision response is null");
1021 return NULL;
1022 }
1023
1024 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
1025 Vector<uint8_t> certificate, wrappedKey;
1026
1027 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1028
1029 // Fill out return obj
1030 jclass clazz = gFields.certificateClassId;
1031
1032 jobject certificateObj = NULL;
1033
1034 if (clazz && certificate.size() && wrappedKey.size()) {
1035 certificateObj = env->AllocObject(clazz);
1036 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1037 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1038
1039 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1040 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1041 }
1042
1043 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
1044 return certificateObj;
1045 }
1046
android_media_MediaDrm_getSecureStops(JNIEnv * env,jobject thiz)1047 static jobject android_media_MediaDrm_getSecureStops(
1048 JNIEnv *env, jobject thiz) {
1049 sp<IDrm> drm = GetDrm(env, thiz);
1050
1051 if (drm == NULL) {
1052 jniThrowException(env, "java/lang/IllegalStateException",
1053 "MediaDrm obj is null");
1054 return NULL;
1055 }
1056
1057 List<Vector<uint8_t> > secureStops;
1058
1059 status_t err = drm->getSecureStops(secureStops);
1060
1061 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1062 return NULL;
1063 }
1064
1065 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1066 }
1067
android_media_MediaDrm_getSecureStop(JNIEnv * env,jobject thiz,jbyteArray ssid)1068 static jbyteArray android_media_MediaDrm_getSecureStop(
1069 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1070 sp<IDrm> drm = GetDrm(env, thiz);
1071
1072 if (drm == NULL) {
1073 jniThrowException(env, "java/lang/IllegalStateException",
1074 "MediaDrm obj is null");
1075 return NULL;
1076 }
1077
1078 Vector<uint8_t> secureStop;
1079
1080 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1081
1082 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1083 return NULL;
1084 }
1085
1086 return VectorToJByteArray(env, secureStop);
1087 }
1088
android_media_MediaDrm_releaseSecureStops(JNIEnv * env,jobject thiz,jbyteArray jssRelease)1089 static void android_media_MediaDrm_releaseSecureStops(
1090 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1091 sp<IDrm> drm = GetDrm(env, thiz);
1092
1093 if (drm == NULL) {
1094 jniThrowException(env, "java/lang/IllegalStateException",
1095 "MediaDrm obj is null");
1096 return;
1097 }
1098
1099 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1100
1101 status_t err = drm->releaseSecureStops(ssRelease);
1102
1103 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1104 }
1105
android_media_MediaDrm_releaseAllSecureStops(JNIEnv * env,jobject thiz)1106 static void android_media_MediaDrm_releaseAllSecureStops(
1107 JNIEnv *env, jobject thiz) {
1108 sp<IDrm> drm = GetDrm(env, thiz);
1109
1110 if (drm == NULL) {
1111 jniThrowException(env, "java/lang/IllegalStateException",
1112 "MediaDrm obj is null");
1113 return;
1114 }
1115
1116 status_t err = drm->releaseAllSecureStops();
1117
1118 throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
1119 }
1120
android_media_MediaDrm_getPropertyString(JNIEnv * env,jobject thiz,jstring jname)1121 static jstring android_media_MediaDrm_getPropertyString(
1122 JNIEnv *env, jobject thiz, jstring jname) {
1123 sp<IDrm> drm = GetDrm(env, thiz);
1124
1125 if (drm == NULL) {
1126 jniThrowException(env, "java/lang/IllegalStateException",
1127 "MediaDrm obj is null");
1128 return NULL;
1129 }
1130
1131 if (jname == NULL) {
1132 jniThrowException(env, "java/lang/IllegalArgumentException",
1133 "property name String is null");
1134 return NULL;
1135 }
1136
1137 String8 name = JStringToString8(env, jname);
1138 String8 value;
1139
1140 status_t err = drm->getPropertyString(name, value);
1141
1142 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1143 return NULL;
1144 }
1145
1146 return env->NewStringUTF(value.string());
1147 }
1148
android_media_MediaDrm_getPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname)1149 static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1150 JNIEnv *env, jobject thiz, jstring jname) {
1151 sp<IDrm> drm = GetDrm(env, thiz);
1152
1153 if (drm == NULL) {
1154 jniThrowException(env, "java/lang/IllegalStateException",
1155 "MediaDrm obj is null");
1156 return NULL;
1157 }
1158
1159 if (jname == NULL) {
1160 jniThrowException(env, "java/lang/IllegalArgumentException",
1161 "property name String is null");
1162 return NULL;
1163 }
1164
1165 String8 name = JStringToString8(env, jname);
1166 Vector<uint8_t> value;
1167
1168 status_t err = drm->getPropertyByteArray(name, value);
1169
1170 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1171 return NULL;
1172 }
1173
1174 return VectorToJByteArray(env, value);
1175 }
1176
android_media_MediaDrm_setPropertyString(JNIEnv * env,jobject thiz,jstring jname,jstring jvalue)1177 static void android_media_MediaDrm_setPropertyString(
1178 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1179 sp<IDrm> drm = GetDrm(env, thiz);
1180
1181 if (drm == NULL) {
1182 jniThrowException(env, "java/lang/IllegalStateException",
1183 "MediaDrm obj is null");
1184 return;
1185 }
1186
1187 if (jname == NULL) {
1188 jniThrowException(env, "java/lang/IllegalArgumentException",
1189 "property name String is null");
1190 return;
1191 }
1192
1193 if (jvalue == NULL) {
1194 jniThrowException(env, "java/lang/IllegalArgumentException",
1195 "property value String is null");
1196 return;
1197 }
1198
1199 String8 name = JStringToString8(env, jname);
1200 String8 value = JStringToString8(env, jvalue);
1201
1202 status_t err = drm->setPropertyString(name, value);
1203
1204 throwExceptionAsNecessary(env, err, "Failed to set property");
1205 }
1206
android_media_MediaDrm_setPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname,jbyteArray jvalue)1207 static void android_media_MediaDrm_setPropertyByteArray(
1208 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1209 sp<IDrm> drm = GetDrm(env, thiz);
1210
1211 if (drm == NULL) {
1212 jniThrowException(env, "java/lang/IllegalStateException",
1213 "MediaDrm obj is null");
1214 return;
1215 }
1216
1217 if (jname == NULL) {
1218 jniThrowException(env, "java/lang/IllegalArgumentException",
1219 "property name String is null");
1220 return;
1221 }
1222
1223 if (jvalue == NULL) {
1224 jniThrowException(env, "java/lang/IllegalArgumentException",
1225 "property value byte array is null");
1226 return;
1227 }
1228
1229 String8 name = JStringToString8(env, jname);
1230 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1231
1232 status_t err = drm->setPropertyByteArray(name, value);
1233
1234 throwExceptionAsNecessary(env, err, "Failed to set property");
1235 }
1236
android_media_MediaDrm_setCipherAlgorithmNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1237 static void android_media_MediaDrm_setCipherAlgorithmNative(
1238 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1239 jstring jalgorithm) {
1240
1241 sp<IDrm> drm = GetDrm(env, jdrm);
1242
1243 if (!CheckSession(env, drm, jsessionId)) {
1244 return;
1245 }
1246
1247 if (jalgorithm == NULL) {
1248 jniThrowException(env, "java/lang/IllegalArgumentException",
1249 "algorithm String is null");
1250 return;
1251 }
1252
1253 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1254 String8 algorithm = JStringToString8(env, jalgorithm);
1255
1256 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1257
1258 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1259 }
1260
android_media_MediaDrm_setMacAlgorithmNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1261 static void android_media_MediaDrm_setMacAlgorithmNative(
1262 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1263 jstring jalgorithm) {
1264
1265 sp<IDrm> drm = GetDrm(env, jdrm);
1266
1267 if (!CheckSession(env, drm, jsessionId)) {
1268 return;
1269 }
1270
1271 if (jalgorithm == NULL) {
1272 jniThrowException(env, "java/lang/IllegalArgumentException",
1273 "algorithm String is null");
1274 return;
1275 }
1276
1277 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1278 String8 algorithm = JStringToString8(env, jalgorithm);
1279
1280 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1281
1282 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1283 }
1284
1285
android_media_MediaDrm_encryptNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1286 static jbyteArray android_media_MediaDrm_encryptNative(
1287 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1288 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1289
1290 sp<IDrm> drm = GetDrm(env, jdrm);
1291
1292 if (!CheckSession(env, drm, jsessionId)) {
1293 return NULL;
1294 }
1295
1296 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1297 jniThrowException(env, "java/lang/IllegalArgumentException",
1298 "required argument is null");
1299 return NULL;
1300 }
1301
1302 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1303 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1304 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1305 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1306 Vector<uint8_t> output;
1307
1308 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1309
1310 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1311 return NULL;
1312 }
1313
1314 return VectorToJByteArray(env, output);
1315 }
1316
android_media_MediaDrm_decryptNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1317 static jbyteArray android_media_MediaDrm_decryptNative(
1318 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1319 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1320
1321 sp<IDrm> drm = GetDrm(env, jdrm);
1322
1323 if (!CheckSession(env, drm, jsessionId)) {
1324 return NULL;
1325 }
1326
1327 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1328 jniThrowException(env, "java/lang/IllegalArgumentException",
1329 "required argument is null");
1330 return NULL;
1331 }
1332
1333 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1334 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1335 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1336 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1337 Vector<uint8_t> output;
1338
1339 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1340 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1341 return NULL;
1342 }
1343
1344 return VectorToJByteArray(env, output);
1345 }
1346
android_media_MediaDrm_signNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage)1347 static jbyteArray android_media_MediaDrm_signNative(
1348 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1349 jbyteArray jkeyId, jbyteArray jmessage) {
1350
1351 sp<IDrm> drm = GetDrm(env, jdrm);
1352
1353 if (!CheckSession(env, drm, jsessionId)) {
1354 return NULL;
1355 }
1356
1357 if (jkeyId == NULL || jmessage == NULL) {
1358 jniThrowException(env, "java/lang/IllegalArgumentException",
1359 "required argument is null");
1360 return NULL;
1361 }
1362
1363 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1364 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1365 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1366 Vector<uint8_t> signature;
1367
1368 status_t err = drm->sign(sessionId, keyId, message, signature);
1369
1370 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1371 return NULL;
1372 }
1373
1374 return VectorToJByteArray(env, signature);
1375 }
1376
android_media_MediaDrm_verifyNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage,jbyteArray jsignature)1377 static jboolean android_media_MediaDrm_verifyNative(
1378 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1379 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1380
1381 sp<IDrm> drm = GetDrm(env, jdrm);
1382
1383 if (!CheckSession(env, drm, jsessionId)) {
1384 return false;
1385 }
1386
1387 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
1388 jniThrowException(env, "java/lang/IllegalArgumentException",
1389 "required argument is null");
1390 return false;
1391 }
1392
1393 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1394 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1395 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1396 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1397 bool match;
1398
1399 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1400
1401 throwExceptionAsNecessary(env, err, "Failed to verify");
1402 return match;
1403 }
1404
1405
android_media_MediaDrm_signRSANative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm,jbyteArray jwrappedKey,jbyteArray jmessage)1406 static jbyteArray android_media_MediaDrm_signRSANative(
1407 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1408 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1409
1410 sp<IDrm> drm = GetDrm(env, jdrm);
1411
1412 if (!CheckSession(env, drm, jsessionId)) {
1413 return NULL;
1414 }
1415
1416 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1417 jniThrowException(env, "java/lang/IllegalArgumentException",
1418 "required argument is null");
1419 return NULL;
1420 }
1421
1422 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1423 String8 algorithm = JStringToString8(env, jalgorithm);
1424 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1425 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1426 Vector<uint8_t> signature;
1427
1428 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1429
1430 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1431 return NULL;
1432 }
1433
1434 return VectorToJByteArray(env, signature);
1435 }
1436
1437
1438 static const JNINativeMethod gMethods[] = {
1439 { "release", "()V", (void *)android_media_MediaDrm_release },
1440 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1441
1442 { "native_setup", "(Ljava/lang/Object;[B)V",
1443 (void *)android_media_MediaDrm_native_setup },
1444
1445 { "native_finalize", "()V",
1446 (void *)android_media_MediaDrm_native_finalize },
1447
1448 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
1449 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1450
1451 { "openSession", "()[B",
1452 (void *)android_media_MediaDrm_openSession },
1453
1454 { "closeSession", "([B)V",
1455 (void *)android_media_MediaDrm_closeSession },
1456
1457 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1458 "Landroid/media/MediaDrm$KeyRequest;",
1459 (void *)android_media_MediaDrm_getKeyRequest },
1460
1461 { "provideKeyResponse", "([B[B)[B",
1462 (void *)android_media_MediaDrm_provideKeyResponse },
1463
1464 { "removeKeys", "([B)V",
1465 (void *)android_media_MediaDrm_removeKeys },
1466
1467 { "restoreKeys", "([B[B)V",
1468 (void *)android_media_MediaDrm_restoreKeys },
1469
1470 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1471 (void *)android_media_MediaDrm_queryKeyStatus },
1472
1473 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1474 (void *)android_media_MediaDrm_getProvisionRequestNative },
1475
1476 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1477 (void *)android_media_MediaDrm_provideProvisionResponseNative },
1478
1479 { "getSecureStops", "()Ljava/util/List;",
1480 (void *)android_media_MediaDrm_getSecureStops },
1481
1482 { "getSecureStop", "([B)[B",
1483 (void *)android_media_MediaDrm_getSecureStop },
1484
1485 { "releaseSecureStops", "([B)V",
1486 (void *)android_media_MediaDrm_releaseSecureStops },
1487
1488 { "releaseAllSecureStops", "()V",
1489 (void *)android_media_MediaDrm_releaseAllSecureStops },
1490
1491 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1492 (void *)android_media_MediaDrm_getPropertyString },
1493
1494 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1495 (void *)android_media_MediaDrm_getPropertyByteArray },
1496
1497 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1498 (void *)android_media_MediaDrm_setPropertyString },
1499
1500 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1501 (void *)android_media_MediaDrm_setPropertyByteArray },
1502
1503 { "setCipherAlgorithmNative",
1504 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1505 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1506
1507 { "setMacAlgorithmNative",
1508 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1509 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1510
1511 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1512 (void *)android_media_MediaDrm_encryptNative },
1513
1514 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1515 (void *)android_media_MediaDrm_decryptNative },
1516
1517 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1518 (void *)android_media_MediaDrm_signNative },
1519
1520 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1521 (void *)android_media_MediaDrm_verifyNative },
1522
1523 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1524 (void *)android_media_MediaDrm_signRSANative },
1525 };
1526
register_android_media_Drm(JNIEnv * env)1527 int register_android_media_Drm(JNIEnv *env) {
1528 return AndroidRuntime::registerNativeMethods(env,
1529 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1530 }
1531