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 <nativehelper/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],const String8 & appPackageName)337 JDrm::JDrm(
338 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
339 const String8 &appPackageName) {
340 mObject = env->NewWeakGlobalRef(thiz);
341 mDrm = MakeDrm(uuid, appPackageName);
342 if (mDrm != NULL) {
343 mDrm->setListener(this);
344 }
345 }
346
~JDrm()347 JDrm::~JDrm() {
348 JNIEnv *env = AndroidRuntime::getJNIEnv();
349
350 env->DeleteWeakGlobalRef(mObject);
351 mObject = NULL;
352 }
353
354 // static
MakeDrm()355 sp<IDrm> JDrm::MakeDrm() {
356 sp<IServiceManager> sm = defaultServiceManager();
357
358 sp<IBinder> binder = sm->getService(String16("media.drm"));
359 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
360 if (service == NULL) {
361 return NULL;
362 }
363
364 sp<IDrm> drm = service->makeDrm();
365 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
366 return NULL;
367 }
368
369 return drm;
370 }
371
372 // static
MakeDrm(const uint8_t uuid[16],const String8 & appPackageName)373 sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
374 sp<IDrm> drm = MakeDrm();
375
376 if (drm == NULL) {
377 return NULL;
378 }
379
380 status_t err = drm->createPlugin(uuid, appPackageName);
381
382 if (err != OK) {
383 return NULL;
384 }
385
386 return drm;
387 }
388
setListener(const sp<DrmListener> & listener)389 status_t JDrm::setListener(const sp<DrmListener>& listener) {
390 Mutex::Autolock lock(mLock);
391 mListener = listener;
392 return OK;
393 }
394
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)395 void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
396 sp<DrmListener> listener;
397 mLock.lock();
398 listener = mListener;
399 mLock.unlock();
400
401 if (listener != NULL) {
402 Mutex::Autolock lock(mNotifyLock);
403 listener->notify(eventType, extra, obj);
404 }
405 }
406
disconnect()407 void JDrm::disconnect() {
408 if (mDrm != NULL) {
409 mDrm->destroyPlugin();
410 mDrm.clear();
411 }
412 }
413
414
415 // static
IsCryptoSchemeSupported(const uint8_t uuid[16],const String8 & mimeType)416 bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
417 sp<IDrm> drm = MakeDrm();
418
419 if (drm == NULL) {
420 return false;
421 }
422
423 return drm->isCryptoSchemeSupported(uuid, mimeType);
424 }
425
initCheck() const426 status_t JDrm::initCheck() const {
427 return mDrm == NULL ? NO_INIT : OK;
428 }
429
430 // JNI conversion utilities
JByteArrayToVector(JNIEnv * env,jbyteArray const & byteArray)431 static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
432 Vector<uint8_t> vector;
433 size_t length = env->GetArrayLength(byteArray);
434 vector.insertAt((size_t)0, length);
435 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
436 return vector;
437 }
438
VectorToJByteArray(JNIEnv * env,Vector<uint8_t> const & vector)439 static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
440 size_t length = vector.size();
441 jbyteArray result = env->NewByteArray(length);
442 if (result != NULL) {
443 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
444 }
445 return result;
446 }
447
JStringToString8(JNIEnv * env,jstring const & jstr)448 static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
449 String8 result;
450
451 const char *s = env->GetStringUTFChars(jstr, NULL);
452 if (s) {
453 result = s;
454 env->ReleaseStringUTFChars(jstr, s);
455 }
456 return result;
457 }
458
459 /*
460 import java.util.HashMap;
461 import java.util.Set;
462 import java.Map.Entry;
463 import jav.util.Iterator;
464
465 HashMap<k, v> hm;
466 Set<Entry<k, v> > s = hm.entrySet();
467 Iterator i = s.iterator();
468 Entry e = s.next();
469 */
470
HashMapToKeyedVector(JNIEnv * env,jobject & hashMap,bool * pIsOK)471 static KeyedVector<String8, String8> HashMapToKeyedVector(
472 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
473 jclass clazz = gFields.stringClassId;
474 KeyedVector<String8, String8> keyedVector;
475 *pIsOK = true;
476
477 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
478 if (entrySet) {
479 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
480 if (iterator) {
481 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
482 while (hasNext) {
483 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
484 if (entry) {
485 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
486 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
487 jniThrowException(env, "java/lang/IllegalArgumentException",
488 "HashMap key is not a String");
489 env->DeleteLocalRef(entry);
490 *pIsOK = false;
491 break;
492 }
493 jstring jkey = static_cast<jstring>(obj);
494
495 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
496 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
497 jniThrowException(env, "java/lang/IllegalArgumentException",
498 "HashMap value is not a String");
499 env->DeleteLocalRef(entry);
500 *pIsOK = false;
501 break;
502 }
503 jstring jvalue = static_cast<jstring>(obj);
504
505 String8 key = JStringToString8(env, jkey);
506 String8 value = JStringToString8(env, jvalue);
507 keyedVector.add(key, value);
508
509 env->DeleteLocalRef(jkey);
510 env->DeleteLocalRef(jvalue);
511 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
512 }
513 env->DeleteLocalRef(entry);
514 }
515 env->DeleteLocalRef(iterator);
516 }
517 env->DeleteLocalRef(entrySet);
518 }
519 return keyedVector;
520 }
521
KeyedVectorToHashMap(JNIEnv * env,KeyedVector<String8,String8> const & map)522 static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
523 jclass clazz = gFields.hashmapClassId;
524 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
525 for (size_t i = 0; i < map.size(); ++i) {
526 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
527 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
528 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
529 env->DeleteLocalRef(jkey);
530 env->DeleteLocalRef(jvalue);
531 }
532 return hashMap;
533 }
534
ListOfVectorsToArrayListOfByteArray(JNIEnv * env,List<Vector<uint8_t>> list)535 static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
536 List<Vector<uint8_t> > list) {
537 jclass clazz = gFields.arraylistClassId;
538 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
539 List<Vector<uint8_t> >::iterator iter = list.begin();
540 while (iter != list.end()) {
541 jbyteArray byteArray = VectorToJByteArray(env, *iter);
542 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
543 env->DeleteLocalRef(byteArray);
544 iter++;
545 }
546
547 return arrayList;
548 }
549
550 } // namespace android
551
552 using namespace android;
553
setDrm(JNIEnv * env,jobject thiz,const sp<JDrm> & drm)554 static sp<JDrm> setDrm(
555 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
556 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
557 if (drm != NULL) {
558 drm->incStrong(thiz);
559 }
560 if (old != NULL) {
561 old->decStrong(thiz);
562 }
563 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
564
565 return old;
566 }
567
CheckSession(JNIEnv * env,const sp<IDrm> & drm,jbyteArray const & jsessionId)568 static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
569 {
570 if (drm == NULL) {
571 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
572 return false;
573 }
574
575 if (jsessionId == NULL) {
576 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
577 return false;
578 }
579 return true;
580 }
581
android_media_MediaDrm_release(JNIEnv * env,jobject thiz)582 static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
583 sp<JDrm> drm = setDrm(env, thiz, NULL);
584 if (drm != NULL) {
585 drm->setListener(NULL);
586 drm->disconnect();
587 }
588 }
589
android_media_MediaDrm_native_init(JNIEnv * env)590 static void android_media_MediaDrm_native_init(JNIEnv *env) {
591 jclass clazz;
592 FIND_CLASS(clazz, "android/media/MediaDrm");
593 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
594 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
595 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
596
597 jfieldID field;
598 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
599 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
600 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
601 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
602 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
603 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
604 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
605 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
606 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
607 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
608
609 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
610 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
611 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
612 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
613 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
614 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
615
616 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
617 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
618 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
619 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
620 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
621 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
622
623 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
624 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
625 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
626 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
627
628 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
629 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
630 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
631 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
632
633 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
634 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
635 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
636 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
637 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
638 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
639
640 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
641 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
642 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
643
644 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
645 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
646 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
647 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
648
649 FIND_CLASS(clazz, "java/util/ArrayList");
650 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
651 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
652
653 FIND_CLASS(clazz, "java/util/HashMap");
654 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
655 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
656 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
657 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
658 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
659
660 FIND_CLASS(clazz, "java/util/Set");
661 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
662
663 FIND_CLASS(clazz, "java/util/Iterator");
664 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
665 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
666
667 FIND_CLASS(clazz, "java/util/Map$Entry");
668 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
669 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
670
671 FIND_CLASS(clazz, "java/util/HashMap");
672 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
673
674 FIND_CLASS(clazz, "java/lang/String");
675 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
676
677 FIND_CLASS(clazz, "java/util/ArrayList");
678 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
679
680 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
681 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
682 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
683 }
684
android_media_MediaDrm_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jbyteArray uuidObj,jstring jappPackageName)685 static void android_media_MediaDrm_native_setup(
686 JNIEnv *env, jobject thiz,
687 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
688
689 if (uuidObj == NULL) {
690 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
691 return;
692 }
693
694 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
695
696 if (uuid.size() != 16) {
697 jniThrowException(env, "java/lang/IllegalArgumentException",
698 "invalid UUID size, expected 16 bytes");
699 return;
700 }
701
702 String8 packageName;
703 if (jappPackageName == NULL) {
704 jniThrowException(env, "java/lang/IllegalArgumentException",
705 "application package name cannot be null");
706 return;
707 }
708
709 packageName = JStringToString8(env, jappPackageName);
710 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
711
712 status_t err = drm->initCheck();
713
714 if (err != OK) {
715 jniThrowException(
716 env,
717 "android/media/UnsupportedSchemeException",
718 "Failed to instantiate drm object.");
719 return;
720 }
721
722 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
723 drm->setListener(listener);
724 setDrm(env, thiz, drm);
725 }
726
android_media_MediaDrm_native_finalize(JNIEnv * env,jobject thiz)727 static void android_media_MediaDrm_native_finalize(
728 JNIEnv *env, jobject thiz) {
729 android_media_MediaDrm_release(env, thiz);
730 }
731
android_media_MediaDrm_isCryptoSchemeSupportedNative(JNIEnv * env,jobject,jbyteArray uuidObj,jstring jmimeType)732 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
733 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
734
735 if (uuidObj == NULL) {
736 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
737 return false;
738 }
739
740 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
741
742 if (uuid.size() != 16) {
743 jniThrowException(
744 env,
745 "java/lang/IllegalArgumentException",
746 "invalid UUID size, expected 16 bytes");
747 return false;
748 }
749
750 String8 mimeType;
751 if (jmimeType != NULL) {
752 mimeType = JStringToString8(env, jmimeType);
753 }
754
755 return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
756 }
757
android_media_MediaDrm_openSession(JNIEnv * env,jobject thiz)758 static jbyteArray android_media_MediaDrm_openSession(
759 JNIEnv *env, jobject thiz) {
760 sp<IDrm> drm = GetDrm(env, thiz);
761
762 if (drm == NULL) {
763 jniThrowException(env, "java/lang/IllegalStateException",
764 "MediaDrm obj is null");
765 return NULL;
766 }
767
768 Vector<uint8_t> sessionId;
769 status_t err = drm->openSession(sessionId);
770
771 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
772 return NULL;
773 }
774
775 return VectorToJByteArray(env, sessionId);
776 }
777
android_media_MediaDrm_closeSession(JNIEnv * env,jobject thiz,jbyteArray jsessionId)778 static void android_media_MediaDrm_closeSession(
779 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
780 sp<IDrm> drm = GetDrm(env, thiz);
781
782 if (!CheckSession(env, drm, jsessionId)) {
783 return;
784 }
785
786 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
787
788 status_t err = drm->closeSession(sessionId);
789
790 throwExceptionAsNecessary(env, err, "Failed to close session");
791 }
792
android_media_MediaDrm_getKeyRequest(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jinitData,jstring jmimeType,jint jkeyType,jobject joptParams)793 static jobject android_media_MediaDrm_getKeyRequest(
794 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
795 jstring jmimeType, jint jkeyType, jobject joptParams) {
796 sp<IDrm> drm = GetDrm(env, thiz);
797
798 if (!CheckSession(env, drm, jsessionId)) {
799 return NULL;
800 }
801
802 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
803
804 Vector<uint8_t> initData;
805 if (jinitData != NULL) {
806 initData = JByteArrayToVector(env, jinitData);
807 }
808
809 String8 mimeType;
810 if (jmimeType != NULL) {
811 mimeType = JStringToString8(env, jmimeType);
812 }
813
814 DrmPlugin::KeyType keyType;
815 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
816 keyType = DrmPlugin::kKeyType_Streaming;
817 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
818 keyType = DrmPlugin::kKeyType_Offline;
819 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
820 keyType = DrmPlugin::kKeyType_Release;
821 } else {
822 jniThrowException(env, "java/lang/IllegalArgumentException",
823 "invalid keyType");
824 return NULL;
825 }
826
827 KeyedVector<String8, String8> optParams;
828 if (joptParams != NULL) {
829 bool isOK;
830 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
831 if (!isOK) {
832 return NULL;
833 }
834 }
835
836 Vector<uint8_t> request;
837 String8 defaultUrl;
838 DrmPlugin::KeyRequestType keyRequestType;
839
840 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
841 keyType, optParams, request, defaultUrl, &keyRequestType);
842
843 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
844 return NULL;
845 }
846
847 // Fill out return obj
848 jclass clazz;
849 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
850
851 jobject keyObj = NULL;
852
853 if (clazz) {
854 keyObj = env->AllocObject(clazz);
855 jbyteArray jrequest = VectorToJByteArray(env, request);
856 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
857
858 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
859 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
860
861 switch (keyRequestType) {
862 case DrmPlugin::kKeyRequestType_Initial:
863 env->SetIntField(keyObj, gFields.keyRequest.requestType,
864 gKeyRequestTypes.kKeyRequestTypeInitial);
865 break;
866 case DrmPlugin::kKeyRequestType_Renewal:
867 env->SetIntField(keyObj, gFields.keyRequest.requestType,
868 gKeyRequestTypes.kKeyRequestTypeRenewal);
869 break;
870 case DrmPlugin::kKeyRequestType_Release:
871 env->SetIntField(keyObj, gFields.keyRequest.requestType,
872 gKeyRequestTypes.kKeyRequestTypeRelease);
873 break;
874 default:
875 throwStateException(env, "DRM plugin failure: unknown key request type",
876 ERROR_DRM_UNKNOWN);
877 break;
878 }
879 }
880
881 return keyObj;
882 }
883
android_media_MediaDrm_provideKeyResponse(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jresponse)884 static jbyteArray android_media_MediaDrm_provideKeyResponse(
885 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
886 sp<IDrm> drm = GetDrm(env, thiz);
887
888 if (!CheckSession(env, drm, jsessionId)) {
889 return NULL;
890 }
891
892 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
893
894 if (jresponse == NULL) {
895 jniThrowException(env, "java/lang/IllegalArgumentException",
896 "key response is null");
897 return NULL;
898 }
899 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
900 Vector<uint8_t> keySetId;
901
902 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
903
904 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
905 return NULL;
906 }
907 return VectorToJByteArray(env, keySetId);
908 }
909
android_media_MediaDrm_removeKeys(JNIEnv * env,jobject thiz,jbyteArray jkeysetId)910 static void android_media_MediaDrm_removeKeys(
911 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
912 sp<IDrm> drm = GetDrm(env, thiz);
913
914 if (jkeysetId == NULL) {
915 jniThrowException(env, "java/lang/IllegalArgumentException",
916 "keySetId is null");
917 return;
918 }
919
920 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
921
922 status_t err = drm->removeKeys(keySetId);
923
924 throwExceptionAsNecessary(env, err, "Failed to remove keys");
925 }
926
android_media_MediaDrm_restoreKeys(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jkeysetId)927 static void android_media_MediaDrm_restoreKeys(
928 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
929 jbyteArray jkeysetId) {
930
931 sp<IDrm> drm = GetDrm(env, thiz);
932
933 if (!CheckSession(env, drm, jsessionId)) {
934 return;
935 }
936
937 if (jkeysetId == NULL) {
938 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
939 return;
940 }
941
942 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
943 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
944
945 status_t err = drm->restoreKeys(sessionId, keySetId);
946
947 throwExceptionAsNecessary(env, err, "Failed to restore keys");
948 }
949
android_media_MediaDrm_queryKeyStatus(JNIEnv * env,jobject thiz,jbyteArray jsessionId)950 static jobject android_media_MediaDrm_queryKeyStatus(
951 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
952 sp<IDrm> drm = GetDrm(env, thiz);
953
954 if (!CheckSession(env, drm, jsessionId)) {
955 return NULL;
956 }
957 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
958
959 KeyedVector<String8, String8> infoMap;
960
961 status_t err = drm->queryKeyStatus(sessionId, infoMap);
962
963 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
964 return NULL;
965 }
966
967 return KeyedVectorToHashMap(env, infoMap);
968 }
969
android_media_MediaDrm_getProvisionRequestNative(JNIEnv * env,jobject thiz,jint jcertType,jstring jcertAuthority)970 static jobject android_media_MediaDrm_getProvisionRequestNative(
971 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
972 sp<IDrm> drm = GetDrm(env, thiz);
973
974 if (drm == NULL) {
975 jniThrowException(env, "java/lang/IllegalStateException",
976 "MediaDrm obj is null");
977 return NULL;
978 }
979
980 Vector<uint8_t> request;
981 String8 defaultUrl;
982
983 String8 certType;
984 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
985 certType = "X.509";
986 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
987 certType = "none";
988 } else {
989 certType = "invalid";
990 }
991
992 String8 certAuthority = JStringToString8(env, jcertAuthority);
993 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
994
995 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
996 return NULL;
997 }
998
999 // Fill out return obj
1000 jclass clazz;
1001 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1002
1003 jobject provisionObj = NULL;
1004
1005 if (clazz) {
1006 provisionObj = env->AllocObject(clazz);
1007 jbyteArray jrequest = VectorToJByteArray(env, request);
1008 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1009
1010 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1011 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1012 }
1013
1014 return provisionObj;
1015 }
1016
android_media_MediaDrm_provideProvisionResponseNative(JNIEnv * env,jobject thiz,jbyteArray jresponse)1017 static jobject android_media_MediaDrm_provideProvisionResponseNative(
1018 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1019 sp<IDrm> drm = GetDrm(env, thiz);
1020
1021 if (drm == NULL) {
1022 jniThrowException(env, "java/lang/IllegalStateException",
1023 "MediaDrm obj is null");
1024 return NULL;
1025 }
1026
1027 if (jresponse == NULL) {
1028 jniThrowException(env, "java/lang/IllegalArgumentException",
1029 "provision response is null");
1030 return NULL;
1031 }
1032
1033 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
1034 Vector<uint8_t> certificate, wrappedKey;
1035
1036 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1037
1038 // Fill out return obj
1039 jclass clazz = gFields.certificateClassId;
1040
1041 jobject certificateObj = NULL;
1042
1043 if (clazz && certificate.size() && wrappedKey.size()) {
1044 certificateObj = env->AllocObject(clazz);
1045 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1046 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1047
1048 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1049 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1050 }
1051
1052 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
1053 return certificateObj;
1054 }
1055
android_media_MediaDrm_getSecureStops(JNIEnv * env,jobject thiz)1056 static jobject android_media_MediaDrm_getSecureStops(
1057 JNIEnv *env, jobject thiz) {
1058 sp<IDrm> drm = GetDrm(env, thiz);
1059
1060 if (drm == NULL) {
1061 jniThrowException(env, "java/lang/IllegalStateException",
1062 "MediaDrm obj is null");
1063 return NULL;
1064 }
1065
1066 List<Vector<uint8_t> > secureStops;
1067
1068 status_t err = drm->getSecureStops(secureStops);
1069
1070 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1071 return NULL;
1072 }
1073
1074 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1075 }
1076
android_media_MediaDrm_getSecureStop(JNIEnv * env,jobject thiz,jbyteArray ssid)1077 static jbyteArray android_media_MediaDrm_getSecureStop(
1078 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1079 sp<IDrm> drm = GetDrm(env, thiz);
1080
1081 if (drm == NULL) {
1082 jniThrowException(env, "java/lang/IllegalStateException",
1083 "MediaDrm obj is null");
1084 return NULL;
1085 }
1086
1087 Vector<uint8_t> secureStop;
1088
1089 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1090
1091 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1092 return NULL;
1093 }
1094
1095 return VectorToJByteArray(env, secureStop);
1096 }
1097
android_media_MediaDrm_releaseSecureStops(JNIEnv * env,jobject thiz,jbyteArray jssRelease)1098 static void android_media_MediaDrm_releaseSecureStops(
1099 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1100 sp<IDrm> drm = GetDrm(env, thiz);
1101
1102 if (drm == NULL) {
1103 jniThrowException(env, "java/lang/IllegalStateException",
1104 "MediaDrm obj is null");
1105 return;
1106 }
1107
1108 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1109
1110 status_t err = drm->releaseSecureStops(ssRelease);
1111
1112 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1113 }
1114
android_media_MediaDrm_releaseAllSecureStops(JNIEnv * env,jobject thiz)1115 static void android_media_MediaDrm_releaseAllSecureStops(
1116 JNIEnv *env, jobject thiz) {
1117 sp<IDrm> drm = GetDrm(env, thiz);
1118
1119 if (drm == NULL) {
1120 jniThrowException(env, "java/lang/IllegalStateException",
1121 "MediaDrm obj is null");
1122 return;
1123 }
1124
1125 status_t err = drm->releaseAllSecureStops();
1126
1127 throwExceptionAsNecessary(env, err, "Failed to release all secure stops");
1128 }
1129
android_media_MediaDrm_getPropertyString(JNIEnv * env,jobject thiz,jstring jname)1130 static jstring android_media_MediaDrm_getPropertyString(
1131 JNIEnv *env, jobject thiz, jstring jname) {
1132 sp<IDrm> drm = GetDrm(env, thiz);
1133
1134 if (drm == NULL) {
1135 jniThrowException(env, "java/lang/IllegalStateException",
1136 "MediaDrm obj is null");
1137 return NULL;
1138 }
1139
1140 if (jname == NULL) {
1141 jniThrowException(env, "java/lang/IllegalArgumentException",
1142 "property name String is null");
1143 return NULL;
1144 }
1145
1146 String8 name = JStringToString8(env, jname);
1147 String8 value;
1148
1149 status_t err = drm->getPropertyString(name, value);
1150
1151 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1152 return NULL;
1153 }
1154
1155 return env->NewStringUTF(value.string());
1156 }
1157
android_media_MediaDrm_getPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname)1158 static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1159 JNIEnv *env, jobject thiz, jstring jname) {
1160 sp<IDrm> drm = GetDrm(env, thiz);
1161
1162 if (drm == NULL) {
1163 jniThrowException(env, "java/lang/IllegalStateException",
1164 "MediaDrm obj is null");
1165 return NULL;
1166 }
1167
1168 if (jname == NULL) {
1169 jniThrowException(env, "java/lang/IllegalArgumentException",
1170 "property name String is null");
1171 return NULL;
1172 }
1173
1174 String8 name = JStringToString8(env, jname);
1175 Vector<uint8_t> value;
1176
1177 status_t err = drm->getPropertyByteArray(name, value);
1178
1179 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1180 return NULL;
1181 }
1182
1183 return VectorToJByteArray(env, value);
1184 }
1185
android_media_MediaDrm_setPropertyString(JNIEnv * env,jobject thiz,jstring jname,jstring jvalue)1186 static void android_media_MediaDrm_setPropertyString(
1187 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1188 sp<IDrm> drm = GetDrm(env, thiz);
1189
1190 if (drm == NULL) {
1191 jniThrowException(env, "java/lang/IllegalStateException",
1192 "MediaDrm obj is null");
1193 return;
1194 }
1195
1196 if (jname == NULL) {
1197 jniThrowException(env, "java/lang/IllegalArgumentException",
1198 "property name String is null");
1199 return;
1200 }
1201
1202 if (jvalue == NULL) {
1203 jniThrowException(env, "java/lang/IllegalArgumentException",
1204 "property value String is null");
1205 return;
1206 }
1207
1208 String8 name = JStringToString8(env, jname);
1209 String8 value = JStringToString8(env, jvalue);
1210
1211 status_t err = drm->setPropertyString(name, value);
1212
1213 throwExceptionAsNecessary(env, err, "Failed to set property");
1214 }
1215
android_media_MediaDrm_setPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname,jbyteArray jvalue)1216 static void android_media_MediaDrm_setPropertyByteArray(
1217 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1218 sp<IDrm> drm = GetDrm(env, thiz);
1219
1220 if (drm == NULL) {
1221 jniThrowException(env, "java/lang/IllegalStateException",
1222 "MediaDrm obj is null");
1223 return;
1224 }
1225
1226 if (jname == NULL) {
1227 jniThrowException(env, "java/lang/IllegalArgumentException",
1228 "property name String is null");
1229 return;
1230 }
1231
1232 if (jvalue == NULL) {
1233 jniThrowException(env, "java/lang/IllegalArgumentException",
1234 "property value byte array is null");
1235 return;
1236 }
1237
1238 String8 name = JStringToString8(env, jname);
1239 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1240
1241 status_t err = drm->setPropertyByteArray(name, value);
1242
1243 throwExceptionAsNecessary(env, err, "Failed to set property");
1244 }
1245
android_media_MediaDrm_setCipherAlgorithmNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1246 static void android_media_MediaDrm_setCipherAlgorithmNative(
1247 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1248 jstring jalgorithm) {
1249
1250 sp<IDrm> drm = GetDrm(env, jdrm);
1251
1252 if (!CheckSession(env, drm, jsessionId)) {
1253 return;
1254 }
1255
1256 if (jalgorithm == NULL) {
1257 jniThrowException(env, "java/lang/IllegalArgumentException",
1258 "algorithm String is null");
1259 return;
1260 }
1261
1262 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1263 String8 algorithm = JStringToString8(env, jalgorithm);
1264
1265 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1266
1267 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1268 }
1269
android_media_MediaDrm_setMacAlgorithmNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1270 static void android_media_MediaDrm_setMacAlgorithmNative(
1271 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1272 jstring jalgorithm) {
1273
1274 sp<IDrm> drm = GetDrm(env, jdrm);
1275
1276 if (!CheckSession(env, drm, jsessionId)) {
1277 return;
1278 }
1279
1280 if (jalgorithm == NULL) {
1281 jniThrowException(env, "java/lang/IllegalArgumentException",
1282 "algorithm String is null");
1283 return;
1284 }
1285
1286 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1287 String8 algorithm = JStringToString8(env, jalgorithm);
1288
1289 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1290
1291 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1292 }
1293
1294
android_media_MediaDrm_encryptNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1295 static jbyteArray android_media_MediaDrm_encryptNative(
1296 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1297 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1298
1299 sp<IDrm> drm = GetDrm(env, jdrm);
1300
1301 if (!CheckSession(env, drm, jsessionId)) {
1302 return NULL;
1303 }
1304
1305 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1306 jniThrowException(env, "java/lang/IllegalArgumentException",
1307 "required argument is null");
1308 return NULL;
1309 }
1310
1311 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1312 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1313 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1314 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1315 Vector<uint8_t> output;
1316
1317 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1318
1319 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1320 return NULL;
1321 }
1322
1323 return VectorToJByteArray(env, output);
1324 }
1325
android_media_MediaDrm_decryptNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1326 static jbyteArray android_media_MediaDrm_decryptNative(
1327 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1328 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1329
1330 sp<IDrm> drm = GetDrm(env, jdrm);
1331
1332 if (!CheckSession(env, drm, jsessionId)) {
1333 return NULL;
1334 }
1335
1336 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1337 jniThrowException(env, "java/lang/IllegalArgumentException",
1338 "required argument is null");
1339 return NULL;
1340 }
1341
1342 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1343 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1344 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1345 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1346 Vector<uint8_t> output;
1347
1348 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1349 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1350 return NULL;
1351 }
1352
1353 return VectorToJByteArray(env, output);
1354 }
1355
android_media_MediaDrm_signNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage)1356 static jbyteArray android_media_MediaDrm_signNative(
1357 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1358 jbyteArray jkeyId, jbyteArray jmessage) {
1359
1360 sp<IDrm> drm = GetDrm(env, jdrm);
1361
1362 if (!CheckSession(env, drm, jsessionId)) {
1363 return NULL;
1364 }
1365
1366 if (jkeyId == NULL || jmessage == NULL) {
1367 jniThrowException(env, "java/lang/IllegalArgumentException",
1368 "required argument is null");
1369 return NULL;
1370 }
1371
1372 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1373 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1374 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1375 Vector<uint8_t> signature;
1376
1377 status_t err = drm->sign(sessionId, keyId, message, signature);
1378
1379 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1380 return NULL;
1381 }
1382
1383 return VectorToJByteArray(env, signature);
1384 }
1385
android_media_MediaDrm_verifyNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage,jbyteArray jsignature)1386 static jboolean android_media_MediaDrm_verifyNative(
1387 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1388 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1389
1390 sp<IDrm> drm = GetDrm(env, jdrm);
1391
1392 if (!CheckSession(env, drm, jsessionId)) {
1393 return false;
1394 }
1395
1396 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
1397 jniThrowException(env, "java/lang/IllegalArgumentException",
1398 "required argument is null");
1399 return false;
1400 }
1401
1402 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1403 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1404 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1405 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1406 bool match;
1407
1408 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1409
1410 throwExceptionAsNecessary(env, err, "Failed to verify");
1411 return match;
1412 }
1413
1414
android_media_MediaDrm_signRSANative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm,jbyteArray jwrappedKey,jbyteArray jmessage)1415 static jbyteArray android_media_MediaDrm_signRSANative(
1416 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1417 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1418
1419 sp<IDrm> drm = GetDrm(env, jdrm);
1420
1421 if (!CheckSession(env, drm, jsessionId)) {
1422 return NULL;
1423 }
1424
1425 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1426 jniThrowException(env, "java/lang/IllegalArgumentException",
1427 "required argument is null");
1428 return NULL;
1429 }
1430
1431 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1432 String8 algorithm = JStringToString8(env, jalgorithm);
1433 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1434 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1435 Vector<uint8_t> signature;
1436
1437 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1438
1439 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1440 return NULL;
1441 }
1442
1443 return VectorToJByteArray(env, signature);
1444 }
1445
1446
1447 static const JNINativeMethod gMethods[] = {
1448 { "release", "()V", (void *)android_media_MediaDrm_release },
1449 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1450
1451 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
1452 (void *)android_media_MediaDrm_native_setup },
1453
1454 { "native_finalize", "()V",
1455 (void *)android_media_MediaDrm_native_finalize },
1456
1457 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
1458 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1459
1460 { "openSession", "()[B",
1461 (void *)android_media_MediaDrm_openSession },
1462
1463 { "closeSession", "([B)V",
1464 (void *)android_media_MediaDrm_closeSession },
1465
1466 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1467 "Landroid/media/MediaDrm$KeyRequest;",
1468 (void *)android_media_MediaDrm_getKeyRequest },
1469
1470 { "provideKeyResponse", "([B[B)[B",
1471 (void *)android_media_MediaDrm_provideKeyResponse },
1472
1473 { "removeKeys", "([B)V",
1474 (void *)android_media_MediaDrm_removeKeys },
1475
1476 { "restoreKeys", "([B[B)V",
1477 (void *)android_media_MediaDrm_restoreKeys },
1478
1479 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1480 (void *)android_media_MediaDrm_queryKeyStatus },
1481
1482 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1483 (void *)android_media_MediaDrm_getProvisionRequestNative },
1484
1485 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1486 (void *)android_media_MediaDrm_provideProvisionResponseNative },
1487
1488 { "getSecureStops", "()Ljava/util/List;",
1489 (void *)android_media_MediaDrm_getSecureStops },
1490
1491 { "getSecureStop", "([B)[B",
1492 (void *)android_media_MediaDrm_getSecureStop },
1493
1494 { "releaseSecureStops", "([B)V",
1495 (void *)android_media_MediaDrm_releaseSecureStops },
1496
1497 { "releaseAllSecureStops", "()V",
1498 (void *)android_media_MediaDrm_releaseAllSecureStops },
1499
1500 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
1501 (void *)android_media_MediaDrm_getPropertyString },
1502
1503 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
1504 (void *)android_media_MediaDrm_getPropertyByteArray },
1505
1506 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
1507 (void *)android_media_MediaDrm_setPropertyString },
1508
1509 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
1510 (void *)android_media_MediaDrm_setPropertyByteArray },
1511
1512 { "setCipherAlgorithmNative",
1513 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1514 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
1515
1516 { "setMacAlgorithmNative",
1517 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
1518 (void *)android_media_MediaDrm_setMacAlgorithmNative },
1519
1520 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1521 (void *)android_media_MediaDrm_encryptNative },
1522
1523 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
1524 (void *)android_media_MediaDrm_decryptNative },
1525
1526 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
1527 (void *)android_media_MediaDrm_signNative },
1528
1529 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
1530 (void *)android_media_MediaDrm_verifyNative },
1531
1532 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
1533 (void *)android_media_MediaDrm_signRSANative },
1534 };
1535
register_android_media_Drm(JNIEnv * env)1536 int register_android_media_Drm(JNIEnv *env) {
1537 return AndroidRuntime::registerNativeMethods(env,
1538 "android/media/MediaDrm", gMethods, NELEM(gMethods));
1539 }
1540