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 #include "android_media_MediaMetricsJNI.h"
23 #include "android_os_Parcel.h"
24 #include "android_runtime/AndroidRuntime.h"
25 #include "android_runtime/Log.h"
26 #include "android_os_Parcel.h"
27 #include "jni.h"
28 #include <nativehelper/JNIHelp.h>
29
30 #include <binder/IServiceManager.h>
31 #include <binder/Parcel.h>
32 #include <binder/PersistableBundle.h>
33 #include <cutils/properties.h>
34 #include <media/stagefright/foundation/ADebug.h>
35 #include <media/stagefright/MediaErrors.h>
36 #include <mediadrm/IDrm.h>
37 #include <mediadrm/IMediaDrmService.h>
38
39 using ::android::os::PersistableBundle;
40
41
42 namespace android {
43
44 #define FIND_CLASS(var, className) \
45 var = env->FindClass(className); \
46 LOG_FATAL_IF(! (var), "Unable to find class %s", className);
47
48 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
49 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
50 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
51
52 #define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
53 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
54 LOG_FATAL_IF(! (var), "Unable to find method %s", fieldName);
55
56 #define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
57 var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
58 LOG_FATAL_IF(! (var), "Unable to find field %s", fieldName);
59
60 #define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
61 var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
62 LOG_FATAL_IF(! (var), "Unable to find static method %s", fieldName);
63
64 #define GET_STATIC_OBJECT_FIELD(var, clazz, fieldId) \
65 var = env->GetStaticObjectField(clazz, fieldId); \
66 LOG_FATAL_IF(! (var), "Unable to find static object field %p", fieldId);
67
68
69 struct RequestFields {
70 jfieldID data;
71 jfieldID defaultUrl;
72 jfieldID requestType;
73 };
74
75 struct ArrayListFields {
76 jmethodID init;
77 jmethodID add;
78 };
79
80 struct HashmapFields {
81 jmethodID init;
82 jmethodID get;
83 jmethodID put;
84 jmethodID entrySet;
85 };
86
87 struct SetFields {
88 jmethodID iterator;
89 };
90
91 struct IteratorFields {
92 jmethodID next;
93 jmethodID hasNext;
94 };
95
96 struct EntryFields {
97 jmethodID getKey;
98 jmethodID getValue;
99 };
100
101 struct EventTypes {
102 jint kEventProvisionRequired;
103 jint kEventKeyRequired;
104 jint kEventKeyExpired;
105 jint kEventVendorDefined;
106 jint kEventSessionReclaimed;
107 } gEventTypes;
108
109 struct EventWhat {
110 jint kWhatDrmEvent;
111 jint kWhatExpirationUpdate;
112 jint kWhatKeyStatusChange;
113 jint kWhatSessionLostState;
114 } gEventWhat;
115
116 struct KeyTypes {
117 jint kKeyTypeStreaming;
118 jint kKeyTypeOffline;
119 jint kKeyTypeRelease;
120 } gKeyTypes;
121
122 struct KeyRequestTypes {
123 jint kKeyRequestTypeInitial;
124 jint kKeyRequestTypeRenewal;
125 jint kKeyRequestTypeRelease;
126 jint kKeyRequestTypeNone;
127 jint kKeyRequestTypeUpdate;
128 } gKeyRequestTypes;
129
130 struct CertificateTypes {
131 jint kCertificateTypeNone;
132 jint kCertificateTypeX509;
133 } gCertificateTypes;
134
135 struct CertificateFields {
136 jfieldID wrappedPrivateKey;
137 jfieldID certificateData;
138 };
139
140 struct StateExceptionFields {
141 jmethodID init;
142 jclass classId;
143 };
144
145 struct SessionExceptionFields {
146 jmethodID init;
147 jclass classId;
148 jfieldID errorCode;
149 };
150
151 struct SessionExceptionErrorCodes {
152 jint kErrorUnknown;
153 jint kResourceContention;
154 } gSessionExceptionErrorCodes;
155
156 struct HDCPLevels {
157 jint kHdcpLevelUnknown;
158 jint kHdcpNone;
159 jint kHdcpV1;
160 jint kHdcpV2;
161 jint kHdcpV2_1;
162 jint kHdcpV2_2;
163 jint kHdcpV2_3;
164 jint kHdcpNoOutput;
165 } gHdcpLevels;
166
167 struct SecurityLevels {
168 jint kSecurityLevelUnknown;
169 jint kSecurityLevelMax;
170 jint kSecurityLevelSwSecureCrypto;
171 jint kSecurityLevelSwSecureDecode;
172 jint kSecurityLevelHwSecureCrypto;
173 jint kSecurityLevelHwSecureDecode;
174 jint kSecurityLevelHwSecureAll;
175 } gSecurityLevels;
176
177 struct OfflineLicenseState {
178 jint kOfflineLicenseStateUsable;
179 jint kOfflineLicenseStateReleased;
180 jint kOfflineLicenseStateUnknown;
181 } gOfflineLicenseStates;
182
183
184 struct fields_t {
185 jfieldID context;
186 jmethodID post_event;
187 RequestFields keyRequest;
188 RequestFields provisionRequest;
189 ArrayListFields arraylist;
190 HashmapFields hashmap;
191 SetFields set;
192 IteratorFields iterator;
193 EntryFields entry;
194 CertificateFields certificate;
195 StateExceptionFields stateException;
196 SessionExceptionFields sessionException;
197 jclass certificateClassId;
198 jclass hashmapClassId;
199 jclass arraylistClassId;
200 jclass stringClassId;
201 jobject bundleCreator;
202 jmethodID createFromParcelId;
203 jclass parcelCreatorClassId;
204 };
205
206 static fields_t gFields;
207
208 namespace {
209
210 // Helper function to convert a native PersistableBundle to a Java
211 // PersistableBundle.
nativeToJavaPersistableBundle(JNIEnv * env,jobject thiz,PersistableBundle * nativeBundle)212 jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
213 PersistableBundle* nativeBundle) {
214 if (env == NULL || thiz == NULL || nativeBundle == NULL) {
215 ALOGE("Unexpected NULL parmeter");
216 return NULL;
217 }
218
219 // Create a Java parcel with the native parcel data.
220 // Then create a new PersistableBundle with that parcel as a parameter.
221 jobject jParcel = android::createJavaParcelObject(env);
222 if (jParcel == NULL) {
223 ALOGE("Failed to create a Java Parcel.");
224 return NULL;
225 }
226
227 android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
228 if (nativeParcel == NULL) {
229 ALOGE("Failed to get the native Parcel.");
230 return NULL;
231 }
232
233 android::status_t result = nativeBundle->writeToParcel(nativeParcel);
234 nativeParcel->setDataPosition(0);
235 if (result != android::OK) {
236 ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
237 return NULL;
238 }
239
240 jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
241 gFields.createFromParcelId,
242 jParcel);
243 if (newBundle == NULL) {
244 ALOGE("Failed to create a new PersistableBundle "
245 "from the createFromParcel call.");
246 }
247
248 return newBundle;
249 }
250
251 } // namespace anonymous
252
253 // ----------------------------------------------------------------------------
254 // ref-counted object for callbacks
255 class JNIDrmListener: public DrmListener
256 {
257 public:
258 JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
259 ~JNIDrmListener();
260 virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
261 private:
262 JNIDrmListener();
263 jclass mClass; // Reference to MediaDrm class
264 jobject mObject; // Weak ref to MediaDrm Java object to call on
265 };
266
JNIDrmListener(JNIEnv * env,jobject thiz,jobject weak_thiz)267 JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
268 {
269 // Hold onto the MediaDrm class for use in calling the static method
270 // that posts events to the application thread.
271 jclass clazz = env->GetObjectClass(thiz);
272 if (clazz == NULL) {
273 ALOGE("Can't find android/media/MediaDrm");
274 jniThrowException(env, "java/lang/Exception",
275 "Can't find android/media/MediaDrm");
276 return;
277 }
278 mClass = (jclass)env->NewGlobalRef(clazz);
279
280 // We use a weak reference so the MediaDrm object can be garbage collected.
281 // The reference is only used as a proxy for callbacks.
282 mObject = env->NewGlobalRef(weak_thiz);
283 }
284
~JNIDrmListener()285 JNIDrmListener::~JNIDrmListener()
286 {
287 // remove global references
288 JNIEnv *env = AndroidRuntime::getJNIEnv();
289 env->DeleteGlobalRef(mObject);
290 env->DeleteGlobalRef(mClass);
291 }
292
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)293 void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
294 const Parcel *obj)
295 {
296 jint jwhat;
297 jint jeventType = 0;
298
299 // translate DrmPlugin event types into their java equivalents
300 switch (eventType) {
301 case DrmPlugin::kDrmPluginEventProvisionRequired:
302 jwhat = gEventWhat.kWhatDrmEvent;
303 jeventType = gEventTypes.kEventProvisionRequired;
304 break;
305 case DrmPlugin::kDrmPluginEventKeyNeeded:
306 jwhat = gEventWhat.kWhatDrmEvent;
307 jeventType = gEventTypes.kEventKeyRequired;
308 break;
309 case DrmPlugin::kDrmPluginEventKeyExpired:
310 jwhat = gEventWhat.kWhatDrmEvent;
311 jeventType = gEventTypes.kEventKeyExpired;
312 break;
313 case DrmPlugin::kDrmPluginEventVendorDefined:
314 jwhat = gEventWhat.kWhatDrmEvent;
315 jeventType = gEventTypes.kEventVendorDefined;
316 break;
317 case DrmPlugin::kDrmPluginEventSessionReclaimed:
318 jwhat = gEventWhat.kWhatDrmEvent;
319 jeventType = gEventTypes.kEventSessionReclaimed;
320 break;
321 case DrmPlugin::kDrmPluginEventExpirationUpdate:
322 jwhat = gEventWhat.kWhatExpirationUpdate;
323 break;
324 case DrmPlugin::kDrmPluginEventKeysChange:
325 jwhat = gEventWhat.kWhatKeyStatusChange;
326 break;
327 case DrmPlugin::kDrmPluginEventSessionLostState:
328 jwhat = gEventWhat.kWhatSessionLostState;
329 break;
330 default:
331 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
332 return;
333 }
334
335 JNIEnv *env = AndroidRuntime::getJNIEnv();
336 if (obj && obj->dataSize() > 0) {
337 jobject jParcel = createJavaParcelObject(env);
338 if (jParcel != NULL) {
339 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
340 nativeParcel->setData(obj->data(), obj->dataSize());
341 env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
342 jwhat, jeventType, extra, jParcel);
343 env->DeleteLocalRef(jParcel);
344 }
345 }
346
347 if (env->ExceptionCheck()) {
348 ALOGW("An exception occurred while notifying an event.");
349 LOGW_EX(env);
350 env->ExceptionClear();
351 }
352 }
353
throwStateException(JNIEnv * env,const char * msg,status_t err)354 static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
355 ALOGE("Illegal state exception: %s (%d)", msg, err);
356
357 jobject exception = env->NewObject(gFields.stateException.classId,
358 gFields.stateException.init, static_cast<int>(err),
359 env->NewStringUTF(msg));
360 env->Throw(static_cast<jthrowable>(exception));
361 }
362
throwSessionException(JNIEnv * env,const char * msg,status_t err)363 static void throwSessionException(JNIEnv *env, const char *msg, status_t err) {
364 ALOGE("Session exception: %s (%d)", msg, err);
365
366 jint jErrorCode = 0;
367 switch(err) {
368 case ERROR_DRM_RESOURCE_CONTENTION:
369 jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
370 break;
371 default:
372 break;
373 }
374
375 jobject exception = env->NewObject(gFields.sessionException.classId,
376 gFields.sessionException.init, static_cast<int>(err),
377 env->NewStringUTF(msg));
378
379 env->SetIntField(exception, gFields.sessionException.errorCode, jErrorCode);
380 env->Throw(static_cast<jthrowable>(exception));
381 }
382
isSessionException(status_t err)383 static bool isSessionException(status_t err) {
384 return err == ERROR_DRM_RESOURCE_CONTENTION;
385 }
386
throwExceptionAsNecessary(JNIEnv * env,status_t err,const char * msg=NULL)387 static bool throwExceptionAsNecessary(
388 JNIEnv *env, status_t err, const char *msg = NULL) {
389
390 const char *drmMessage = NULL;
391
392 switch (err) {
393 case ERROR_DRM_UNKNOWN:
394 drmMessage = "General DRM error";
395 break;
396 case ERROR_DRM_NO_LICENSE:
397 drmMessage = "No license";
398 break;
399 case ERROR_DRM_LICENSE_EXPIRED:
400 drmMessage = "License expired";
401 break;
402 case ERROR_DRM_SESSION_NOT_OPENED:
403 drmMessage = "Session not opened";
404 break;
405 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
406 drmMessage = "Not initialized";
407 break;
408 case ERROR_DRM_DECRYPT:
409 drmMessage = "Decrypt error";
410 break;
411 case ERROR_DRM_CANNOT_HANDLE:
412 drmMessage = "Invalid parameter or data format";
413 break;
414 case ERROR_DRM_INVALID_STATE:
415 drmMessage = "Invalid state";
416 break;
417 default:
418 break;
419 }
420
421 String8 vendorMessage;
422 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
423 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
424 drmMessage = vendorMessage.string();
425 }
426
427 if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
428 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
429 return true;
430 } else if (err == ERROR_UNSUPPORTED) {
431 jniThrowException(env, "java/lang/UnsupportedOperationException", msg);
432 return true;
433 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
434 jniThrowException(env, "android/media/NotProvisionedException", msg);
435 return true;
436 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
437 jniThrowException(env, "android/media/ResourceBusyException", msg);
438 return true;
439 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
440 jniThrowException(env, "android/media/DeniedByServerException", msg);
441 return true;
442 } else if (err == DEAD_OBJECT) {
443 jniThrowException(env, "android/media/MediaDrmResetException",
444 "mediaserver died");
445 return true;
446 } else if (isSessionException(err)) {
447 throwSessionException(env, msg, err);
448 return true;
449 } else if (err != OK) {
450 String8 errbuf;
451 if (drmMessage != NULL) {
452 if (msg == NULL) {
453 msg = drmMessage;
454 } else {
455 errbuf = String8::format("%s: %s", msg, drmMessage);
456 msg = errbuf.string();
457 }
458 }
459 throwStateException(env, msg, err);
460 return true;
461 }
462 return false;
463 }
464
GetDrm(JNIEnv * env,jobject thiz)465 static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
466 JDrm *jdrm = (JDrm *)env->GetLongField(thiz, gFields.context);
467 return jdrm ? jdrm->getDrm() : NULL;
468 }
469
JDrm(JNIEnv * env,jobject thiz,const uint8_t uuid[16],const String8 & appPackageName)470 JDrm::JDrm(
471 JNIEnv *env, jobject thiz, const uint8_t uuid[16],
472 const String8 &appPackageName) {
473 mObject = env->NewWeakGlobalRef(thiz);
474 mDrm = MakeDrm(uuid, appPackageName);
475 if (mDrm != NULL) {
476 mDrm->setListener(this);
477 }
478 }
479
~JDrm()480 JDrm::~JDrm() {
481 JNIEnv *env = AndroidRuntime::getJNIEnv();
482
483 env->DeleteWeakGlobalRef(mObject);
484 mObject = NULL;
485 }
486
487 // static
MakeDrm()488 sp<IDrm> JDrm::MakeDrm() {
489 sp<IServiceManager> sm = defaultServiceManager();
490
491 sp<IBinder> binder = sm->getService(String16("media.drm"));
492 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
493 if (service == NULL) {
494 return NULL;
495 }
496
497 sp<IDrm> drm = service->makeDrm();
498 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
499 return NULL;
500 }
501
502 return drm;
503 }
504
505 // static
MakeDrm(const uint8_t uuid[16],const String8 & appPackageName)506 sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16], const String8 &appPackageName) {
507 sp<IDrm> drm = MakeDrm();
508
509 if (drm == NULL) {
510 return NULL;
511 }
512
513 status_t err = drm->createPlugin(uuid, appPackageName);
514
515 if (err != OK) {
516 return NULL;
517 }
518
519 return drm;
520 }
521
setListener(const sp<DrmListener> & listener)522 status_t JDrm::setListener(const sp<DrmListener>& listener) {
523 Mutex::Autolock lock(mLock);
524 mListener = listener;
525 return OK;
526 }
527
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)528 void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
529 sp<DrmListener> listener;
530 mLock.lock();
531 listener = mListener;
532 mLock.unlock();
533
534 if (listener != NULL) {
535 Mutex::Autolock lock(mNotifyLock);
536 listener->notify(eventType, extra, obj);
537 }
538 }
539
disconnect()540 void JDrm::disconnect() {
541 if (mDrm != NULL) {
542 mDrm->destroyPlugin();
543 mDrm.clear();
544 }
545 }
546
547
548 // static
IsCryptoSchemeSupported(const uint8_t uuid[16],const String8 & mimeType,DrmPlugin::SecurityLevel securityLevel,bool * isSupported)549 status_t JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
550 DrmPlugin::SecurityLevel securityLevel, bool *isSupported) {
551 sp<IDrm> drm = MakeDrm();
552
553 if (drm == NULL) {
554 return BAD_VALUE;
555 }
556
557 return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel, isSupported);
558 }
559
initCheck() const560 status_t JDrm::initCheck() const {
561 return mDrm == NULL ? NO_INIT : OK;
562 }
563
564 // JNI conversion utilities
JByteArrayToVector(JNIEnv * env,jbyteArray const & byteArray)565 static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
566 Vector<uint8_t> vector;
567 size_t length = env->GetArrayLength(byteArray);
568 vector.insertAt((size_t)0, length);
569 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
570 return vector;
571 }
572
VectorToJByteArray(JNIEnv * env,Vector<uint8_t> const & vector)573 static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
574 size_t length = vector.size();
575 jbyteArray result = env->NewByteArray(length);
576 if (result != NULL) {
577 env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
578 }
579 return result;
580 }
581
JStringToString8(JNIEnv * env,jstring const & jstr)582 static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
583 String8 result;
584
585 const char *s = env->GetStringUTFChars(jstr, NULL);
586 if (s) {
587 result = s;
588 env->ReleaseStringUTFChars(jstr, s);
589 }
590 return result;
591 }
592
593 /*
594 import java.util.HashMap;
595 import java.util.Set;
596 import java.Map.Entry;
597 import jav.util.Iterator;
598
599 HashMap<k, v> hm;
600 Set<Entry<k, v>> s = hm.entrySet();
601 Iterator i = s.iterator();
602 Entry e = s.next();
603 */
604
HashMapToKeyedVector(JNIEnv * env,jobject & hashMap,bool * pIsOK)605 static KeyedVector<String8, String8> HashMapToKeyedVector(
606 JNIEnv *env, jobject &hashMap, bool* pIsOK) {
607 jclass clazz = gFields.stringClassId;
608 KeyedVector<String8, String8> keyedVector;
609 *pIsOK = true;
610
611 jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
612 if (entrySet) {
613 jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
614 if (iterator) {
615 jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
616 while (hasNext) {
617 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
618 if (entry) {
619 jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
620 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
621 jniThrowException(env, "java/lang/IllegalArgumentException",
622 "HashMap key is not a String");
623 env->DeleteLocalRef(entry);
624 *pIsOK = false;
625 break;
626 }
627 jstring jkey = static_cast<jstring>(obj);
628
629 obj = env->CallObjectMethod(entry, gFields.entry.getValue);
630 if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
631 jniThrowException(env, "java/lang/IllegalArgumentException",
632 "HashMap value is not a String");
633 env->DeleteLocalRef(entry);
634 *pIsOK = false;
635 break;
636 }
637 jstring jvalue = static_cast<jstring>(obj);
638
639 String8 key = JStringToString8(env, jkey);
640 String8 value = JStringToString8(env, jvalue);
641 keyedVector.add(key, value);
642
643 env->DeleteLocalRef(jkey);
644 env->DeleteLocalRef(jvalue);
645 hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
646 }
647 env->DeleteLocalRef(entry);
648 }
649 env->DeleteLocalRef(iterator);
650 }
651 env->DeleteLocalRef(entrySet);
652 }
653 return keyedVector;
654 }
655
KeyedVectorToHashMap(JNIEnv * env,KeyedVector<String8,String8> const & map)656 static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
657 jclass clazz = gFields.hashmapClassId;
658 jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
659 for (size_t i = 0; i < map.size(); ++i) {
660 jstring jkey = env->NewStringUTF(map.keyAt(i).string());
661 jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
662 env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
663 env->DeleteLocalRef(jkey);
664 env->DeleteLocalRef(jvalue);
665 }
666 return hashMap;
667 }
668
ListOfVectorsToArrayListOfByteArray(JNIEnv * env,List<Vector<uint8_t>> list)669 static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
670 List<Vector<uint8_t>> list) {
671 jclass clazz = gFields.arraylistClassId;
672 jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
673 List<Vector<uint8_t>>::iterator iter = list.begin();
674 while (iter != list.end()) {
675 jbyteArray byteArray = VectorToJByteArray(env, *iter);
676 env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
677 env->DeleteLocalRef(byteArray);
678 iter++;
679 }
680
681 return arrayList;
682 }
683
684 } // namespace android
685
686 using namespace android;
687
setDrm(JNIEnv * env,jobject thiz,const sp<JDrm> & drm)688 static sp<JDrm> setDrm(
689 JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
690 sp<JDrm> old = (JDrm *)env->GetLongField(thiz, gFields.context);
691 if (drm != NULL) {
692 drm->incStrong(thiz);
693 }
694 if (old != NULL) {
695 old->decStrong(thiz);
696 }
697 env->SetLongField(thiz, gFields.context, reinterpret_cast<jlong>(drm.get()));
698
699 return old;
700 }
701
CheckDrm(JNIEnv * env,const sp<IDrm> & drm)702 static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) {
703 if (drm == NULL) {
704 jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null");
705 return false;
706 }
707 return true;
708 }
709
CheckSession(JNIEnv * env,const sp<IDrm> & drm,jbyteArray const & jsessionId)710 static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
711 {
712 if (!CheckDrm(env, drm)) {
713 return false;
714 }
715
716 if (jsessionId == NULL) {
717 jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null");
718 return false;
719 }
720 return true;
721 }
722
android_media_MediaDrm_native_release(JNIEnv * env,jobject thiz)723 static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) {
724 sp<JDrm> drm = setDrm(env, thiz, NULL);
725 if (drm != NULL) {
726 drm->setListener(NULL);
727 drm->disconnect();
728 }
729 }
730
android_media_MediaDrm_native_init(JNIEnv * env)731 static void android_media_MediaDrm_native_init(JNIEnv *env) {
732 jclass clazz;
733 FIND_CLASS(clazz, "android/media/MediaDrm");
734 GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
735 GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
736 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
737
738 jfieldID field;
739 GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
740 gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
741 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
742 gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
743 GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
744 gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
745 GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
746 gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
747 GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
748 gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
749
750 GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
751 gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
752 GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
753 gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
754 GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
755 gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
756 GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
757 gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
758
759 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
760 gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
761 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
762 gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field);
763 GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
764 gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
765
766 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
767 gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
768 GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
769 gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
770
771 GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I");
772 gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field);
773 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I");
774 gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field);
775 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I");
776 gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field);
777 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I");
778 gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field);
779 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I");
780 gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
781 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
782 gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
783 GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
784 gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
785 GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
786 gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
787
788 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
789 gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
790 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
791 gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
792 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
793 gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
794 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
795 gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
796 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
797 gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
798 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
799 gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
800
801 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_USABLE", "I");
802 gOfflineLicenseStates.kOfflineLicenseStateUsable = env->GetStaticIntField(clazz, field);
803 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_RELEASED", "I");
804 gOfflineLicenseStates.kOfflineLicenseStateReleased = env->GetStaticIntField(clazz, field);
805 GET_STATIC_FIELD_ID(field, clazz, "OFFLINE_LICENSE_STATE_UNKNOWN", "I");
806 gOfflineLicenseStates.kOfflineLicenseStateUnknown = env->GetStaticIntField(clazz, field);
807
808 GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
809
810 jmethodID getMaxSecurityLevel;
811 GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
812 gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
813
814 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
815 GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
816 GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
817 GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
818
819 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
820 gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
821 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
822 gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
823 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
824 gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
825 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
826 gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
827 GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
828 gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
829
830 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
831 GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
832 GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
833
834 FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
835 GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
836 GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
837 gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
838
839 // Metrics-related fields and classes.
840 FIND_CLASS(clazz, "android/os/PersistableBundle");
841 jfieldID bundleCreatorId;
842 GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
843 "Landroid/os/Parcelable$Creator;");
844 jobject bundleCreator;
845 GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
846 gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
847 FIND_CLASS(clazz, "android/os/Parcelable$Creator");
848 GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
849 "(Landroid/os/Parcel;)Ljava/lang/Object;");
850 gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
851
852 FIND_CLASS(clazz, "java/util/ArrayList");
853 GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
854 GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
855
856 FIND_CLASS(clazz, "java/util/HashMap");
857 GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
858 GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
859 GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
860 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
861 GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
862
863 FIND_CLASS(clazz, "java/util/Set");
864 GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
865
866 FIND_CLASS(clazz, "java/util/Iterator");
867 GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
868 GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
869
870 FIND_CLASS(clazz, "java/util/Map$Entry");
871 GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
872 GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
873
874 FIND_CLASS(clazz, "java/util/HashMap");
875 gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
876
877 FIND_CLASS(clazz, "java/lang/String");
878 gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
879
880 FIND_CLASS(clazz, "java/util/ArrayList");
881 gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
882
883 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
884 GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
885 gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
886
887 FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
888 GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
889 gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
890 GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
891
892 GET_STATIC_FIELD_ID(field, clazz, "ERROR_UNKNOWN", "I");
893 gSessionExceptionErrorCodes.kErrorUnknown = env->GetStaticIntField(clazz, field);
894 GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
895 gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
896 }
897
android_media_MediaDrm_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jbyteArray uuidObj,jstring jappPackageName)898 static void android_media_MediaDrm_native_setup(
899 JNIEnv *env, jobject thiz,
900 jobject weak_this, jbyteArray uuidObj, jstring jappPackageName) {
901
902 if (uuidObj == NULL) {
903 jniThrowException(env, "java/lang/IllegalArgumentException", "uuid is null");
904 return;
905 }
906
907 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
908
909 if (uuid.size() != 16) {
910 jniThrowException(env, "java/lang/IllegalArgumentException",
911 "invalid UUID size, expected 16 bytes");
912 return;
913 }
914
915 String8 packageName;
916 if (jappPackageName == NULL) {
917 jniThrowException(env, "java/lang/IllegalArgumentException",
918 "application package name cannot be null");
919 return;
920 }
921
922 packageName = JStringToString8(env, jappPackageName);
923 sp<JDrm> drm = new JDrm(env, thiz, uuid.array(), packageName);
924
925 status_t err = drm->initCheck();
926
927 if (err != OK) {
928 jniThrowException(
929 env,
930 "android/media/UnsupportedSchemeException",
931 "Failed to instantiate drm object.");
932 return;
933 }
934
935 sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
936 drm->setListener(listener);
937 setDrm(env, thiz, drm);
938 }
939
jintToSecurityLevel(jint jlevel)940 DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
941 DrmPlugin::SecurityLevel level;
942
943 if (jlevel == gSecurityLevels.kSecurityLevelMax) {
944 level = DrmPlugin::kSecurityLevelMax;
945 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
946 level = DrmPlugin::kSecurityLevelSwSecureCrypto;
947 } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
948 level = DrmPlugin::kSecurityLevelSwSecureDecode;
949 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
950 level = DrmPlugin::kSecurityLevelHwSecureCrypto;
951 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
952 level = DrmPlugin::kSecurityLevelHwSecureDecode;
953 } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
954 level = DrmPlugin::kSecurityLevelHwSecureAll;
955 } else {
956 level = DrmPlugin::kSecurityLevelUnknown;
957 }
958 return level;
959 }
960
android_media_MediaDrm_isCryptoSchemeSupportedNative(JNIEnv * env,jobject,jbyteArray uuidObj,jstring jmimeType,jint jSecurityLevel)961 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
962 JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
963 jint jSecurityLevel) {
964
965 if (uuidObj == NULL) {
966 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
967 return false;
968 }
969
970 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
971
972 if (uuid.size() != 16) {
973 jniThrowException(
974 env,
975 "java/lang/IllegalArgumentException",
976 "invalid UUID size, expected 16 bytes");
977 return false;
978 }
979
980 String8 mimeType;
981 if (jmimeType != NULL) {
982 mimeType = JStringToString8(env, jmimeType);
983 }
984 DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
985
986 bool isSupported;
987 status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
988 securityLevel, &isSupported);
989
990 if (throwExceptionAsNecessary(env, err, "Failed to query crypto scheme support")) {
991 return false;
992 }
993 return isSupported;
994 }
995
android_media_MediaDrm_openSession(JNIEnv * env,jobject thiz,jint jlevel)996 static jbyteArray android_media_MediaDrm_openSession(
997 JNIEnv *env, jobject thiz, jint jlevel) {
998 sp<IDrm> drm = GetDrm(env, thiz);
999
1000 if (!CheckDrm(env, drm)) {
1001 return NULL;
1002 }
1003
1004 Vector<uint8_t> sessionId;
1005 DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
1006 if (level == DrmPlugin::kSecurityLevelUnknown) {
1007 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
1008 return NULL;
1009 }
1010
1011 status_t err = drm->openSession(level, sessionId);
1012
1013 if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
1014 return NULL;
1015 }
1016
1017 return VectorToJByteArray(env, sessionId);
1018 }
1019
android_media_MediaDrm_closeSession(JNIEnv * env,jobject thiz,jbyteArray jsessionId)1020 static void android_media_MediaDrm_closeSession(
1021 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1022 sp<IDrm> drm = GetDrm(env, thiz);
1023
1024 if (!CheckSession(env, drm, jsessionId)) {
1025 return;
1026 }
1027
1028 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1029
1030 status_t err = drm->closeSession(sessionId);
1031
1032 throwExceptionAsNecessary(env, err, "Failed to close session");
1033 }
1034
android_media_MediaDrm_getKeyRequest(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jinitData,jstring jmimeType,jint jkeyType,jobject joptParams)1035 static jobject android_media_MediaDrm_getKeyRequest(
1036 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
1037 jstring jmimeType, jint jkeyType, jobject joptParams) {
1038 sp<IDrm> drm = GetDrm(env, thiz);
1039
1040 if (!CheckSession(env, drm, jsessionId)) {
1041 return NULL;
1042 }
1043
1044 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1045
1046 Vector<uint8_t> initData;
1047 if (jinitData != NULL) {
1048 initData = JByteArrayToVector(env, jinitData);
1049 }
1050
1051 String8 mimeType;
1052 if (jmimeType != NULL) {
1053 mimeType = JStringToString8(env, jmimeType);
1054 }
1055
1056 DrmPlugin::KeyType keyType;
1057 if (jkeyType == gKeyTypes.kKeyTypeStreaming) {
1058 keyType = DrmPlugin::kKeyType_Streaming;
1059 } else if (jkeyType == gKeyTypes.kKeyTypeOffline) {
1060 keyType = DrmPlugin::kKeyType_Offline;
1061 } else if (jkeyType == gKeyTypes.kKeyTypeRelease) {
1062 keyType = DrmPlugin::kKeyType_Release;
1063 } else {
1064 jniThrowException(env, "java/lang/IllegalArgumentException",
1065 "invalid keyType");
1066 return NULL;
1067 }
1068
1069 KeyedVector<String8, String8> optParams;
1070 if (joptParams != NULL) {
1071 bool isOK;
1072 optParams = HashMapToKeyedVector(env, joptParams, &isOK);
1073 if (!isOK) {
1074 return NULL;
1075 }
1076 }
1077
1078 Vector<uint8_t> request;
1079 String8 defaultUrl;
1080 DrmPlugin::KeyRequestType keyRequestType;
1081
1082 status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
1083 keyType, optParams, request, defaultUrl, &keyRequestType);
1084
1085 if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
1086 return NULL;
1087 }
1088
1089 // Fill out return obj
1090 jclass clazz;
1091 FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
1092
1093 jobject keyObj = NULL;
1094
1095 if (clazz) {
1096 keyObj = env->AllocObject(clazz);
1097 jbyteArray jrequest = VectorToJByteArray(env, request);
1098 env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
1099
1100 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1101 env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
1102
1103 switch (keyRequestType) {
1104 case DrmPlugin::kKeyRequestType_Initial:
1105 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1106 gKeyRequestTypes.kKeyRequestTypeInitial);
1107 break;
1108 case DrmPlugin::kKeyRequestType_Renewal:
1109 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1110 gKeyRequestTypes.kKeyRequestTypeRenewal);
1111 break;
1112 case DrmPlugin::kKeyRequestType_Release:
1113 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1114 gKeyRequestTypes.kKeyRequestTypeRelease);
1115 break;
1116 case DrmPlugin::kKeyRequestType_None:
1117 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1118 gKeyRequestTypes.kKeyRequestTypeNone);
1119 break;
1120 case DrmPlugin::kKeyRequestType_Update:
1121 env->SetIntField(keyObj, gFields.keyRequest.requestType,
1122 gKeyRequestTypes.kKeyRequestTypeUpdate);
1123 break;
1124
1125 default:
1126 throwStateException(env, "DRM plugin failure: unknown key request type",
1127 ERROR_DRM_UNKNOWN);
1128 break;
1129 }
1130 }
1131
1132 return keyObj;
1133 }
1134
android_media_MediaDrm_provideKeyResponse(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jresponse)1135 static jbyteArray android_media_MediaDrm_provideKeyResponse(
1136 JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
1137 sp<IDrm> drm = GetDrm(env, thiz);
1138
1139 if (!CheckSession(env, drm, jsessionId)) {
1140 return NULL;
1141 }
1142
1143 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1144
1145 if (jresponse == NULL) {
1146 jniThrowException(env, "java/lang/IllegalArgumentException",
1147 "key response is null");
1148 return NULL;
1149 }
1150 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
1151 Vector<uint8_t> keySetId;
1152
1153 status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
1154
1155 if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) {
1156 return NULL;
1157 }
1158 return VectorToJByteArray(env, keySetId);
1159 }
1160
android_media_MediaDrm_removeKeys(JNIEnv * env,jobject thiz,jbyteArray jkeysetId)1161 static void android_media_MediaDrm_removeKeys(
1162 JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
1163 sp<IDrm> drm = GetDrm(env, thiz);
1164
1165 if (!CheckDrm(env, drm)) {
1166 return;
1167 }
1168
1169 if (jkeysetId == NULL) {
1170 jniThrowException(env, "java/lang/IllegalArgumentException",
1171 "keySetId is null");
1172 return;
1173 }
1174
1175 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1176
1177 status_t err = drm->removeKeys(keySetId);
1178
1179 throwExceptionAsNecessary(env, err, "Failed to remove keys");
1180 }
1181
android_media_MediaDrm_restoreKeys(JNIEnv * env,jobject thiz,jbyteArray jsessionId,jbyteArray jkeysetId)1182 static void android_media_MediaDrm_restoreKeys(
1183 JNIEnv *env, jobject thiz, jbyteArray jsessionId,
1184 jbyteArray jkeysetId) {
1185
1186 sp<IDrm> drm = GetDrm(env, thiz);
1187
1188 if (!CheckSession(env, drm, jsessionId)) {
1189 return;
1190 }
1191
1192 if (jkeysetId == NULL) {
1193 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1194 return;
1195 }
1196
1197 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1198 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
1199
1200 status_t err = drm->restoreKeys(sessionId, keySetId);
1201
1202 throwExceptionAsNecessary(env, err, "Failed to restore keys");
1203 }
1204
android_media_MediaDrm_queryKeyStatus(JNIEnv * env,jobject thiz,jbyteArray jsessionId)1205 static jobject android_media_MediaDrm_queryKeyStatus(
1206 JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
1207 sp<IDrm> drm = GetDrm(env, thiz);
1208
1209 if (!CheckSession(env, drm, jsessionId)) {
1210 return NULL;
1211 }
1212 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1213
1214 KeyedVector<String8, String8> infoMap;
1215
1216 status_t err = drm->queryKeyStatus(sessionId, infoMap);
1217
1218 if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
1219 return NULL;
1220 }
1221
1222 return KeyedVectorToHashMap(env, infoMap);
1223 }
1224
android_media_MediaDrm_getProvisionRequestNative(JNIEnv * env,jobject thiz,jint jcertType,jstring jcertAuthority)1225 static jobject android_media_MediaDrm_getProvisionRequestNative(
1226 JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
1227 sp<IDrm> drm = GetDrm(env, thiz);
1228
1229 if (!CheckDrm(env, drm)) {
1230 return NULL;
1231 }
1232
1233 Vector<uint8_t> request;
1234 String8 defaultUrl;
1235
1236 String8 certType;
1237 if (jcertType == gCertificateTypes.kCertificateTypeX509) {
1238 certType = "X.509";
1239 } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
1240 certType = "none";
1241 } else {
1242 certType = "invalid";
1243 }
1244
1245 String8 certAuthority = JStringToString8(env, jcertAuthority);
1246 status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
1247
1248 if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
1249 return NULL;
1250 }
1251
1252 // Fill out return obj
1253 jclass clazz;
1254 FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
1255
1256 jobject provisionObj = NULL;
1257
1258 if (clazz) {
1259 provisionObj = env->AllocObject(clazz);
1260 jbyteArray jrequest = VectorToJByteArray(env, request);
1261 env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
1262
1263 jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
1264 env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
1265 }
1266
1267 return provisionObj;
1268 }
1269
android_media_MediaDrm_provideProvisionResponseNative(JNIEnv * env,jobject thiz,jbyteArray jresponse)1270 static jobject android_media_MediaDrm_provideProvisionResponseNative(
1271 JNIEnv *env, jobject thiz, jbyteArray jresponse) {
1272 sp<IDrm> drm = GetDrm(env, thiz);
1273
1274 if (!CheckDrm(env, drm)) {
1275 return NULL;
1276 }
1277
1278 if (jresponse == NULL) {
1279 jniThrowException(env, "java/lang/IllegalArgumentException",
1280 "provision response is null");
1281 return NULL;
1282 }
1283
1284 Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
1285 Vector<uint8_t> certificate, wrappedKey;
1286
1287 status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
1288
1289 // Fill out return obj
1290 jclass clazz = gFields.certificateClassId;
1291
1292 jobject certificateObj = NULL;
1293
1294 if (clazz && certificate.size() && wrappedKey.size()) {
1295 certificateObj = env->AllocObject(clazz);
1296 jbyteArray jcertificate = VectorToJByteArray(env, certificate);
1297 env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
1298
1299 jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
1300 env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
1301 }
1302
1303 throwExceptionAsNecessary(env, err, "Failed to handle provision response");
1304 return certificateObj;
1305 }
1306
android_media_MediaDrm_getSecureStops(JNIEnv * env,jobject thiz)1307 static jobject android_media_MediaDrm_getSecureStops(
1308 JNIEnv *env, jobject thiz) {
1309 sp<IDrm> drm = GetDrm(env, thiz);
1310
1311 if (!CheckDrm(env, drm)) {
1312 return NULL;
1313 }
1314
1315 List<Vector<uint8_t>> secureStops;
1316
1317 status_t err = drm->getSecureStops(secureStops);
1318
1319 if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
1320 return NULL;
1321 }
1322
1323 return ListOfVectorsToArrayListOfByteArray(env, secureStops);
1324 }
1325
android_media_MediaDrm_getSecureStopIds(JNIEnv * env,jobject thiz)1326 static jobject android_media_MediaDrm_getSecureStopIds(
1327 JNIEnv *env, jobject thiz) {
1328 sp<IDrm> drm = GetDrm(env, thiz);
1329
1330 if (!CheckDrm(env, drm)) {
1331 return NULL;
1332 }
1333
1334 List<Vector<uint8_t>> secureStopIds;
1335
1336 status_t err = drm->getSecureStopIds(secureStopIds);
1337
1338 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop Ids")) {
1339 return NULL;
1340 }
1341
1342 return ListOfVectorsToArrayListOfByteArray(env, secureStopIds);
1343 }
1344
android_media_MediaDrm_getSecureStop(JNIEnv * env,jobject thiz,jbyteArray ssid)1345 static jbyteArray android_media_MediaDrm_getSecureStop(
1346 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1347 sp<IDrm> drm = GetDrm(env, thiz);
1348
1349 if (!CheckDrm(env, drm)) {
1350 return NULL;
1351 }
1352
1353 Vector<uint8_t> secureStop;
1354
1355 status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop);
1356
1357 if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) {
1358 return NULL;
1359 }
1360
1361 return VectorToJByteArray(env, secureStop);
1362 }
1363
android_media_MediaDrm_releaseSecureStops(JNIEnv * env,jobject thiz,jbyteArray jssRelease)1364 static void android_media_MediaDrm_releaseSecureStops(
1365 JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
1366 sp<IDrm> drm = GetDrm(env, thiz);
1367
1368 if (!CheckDrm(env, drm)) {
1369 return;
1370 }
1371
1372 Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
1373
1374 status_t err = drm->releaseSecureStops(ssRelease);
1375
1376 throwExceptionAsNecessary(env, err, "Failed to release secure stops");
1377 }
1378
android_media_MediaDrm_removeSecureStop(JNIEnv * env,jobject thiz,jbyteArray ssid)1379 static void android_media_MediaDrm_removeSecureStop(
1380 JNIEnv *env, jobject thiz, jbyteArray ssid) {
1381 sp<IDrm> drm = GetDrm(env, thiz);
1382
1383 if (!CheckDrm(env, drm)) {
1384 return;
1385 }
1386
1387 status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid));
1388
1389 throwExceptionAsNecessary(env, err, "Failed to remove secure stop");
1390 }
1391
android_media_MediaDrm_removeAllSecureStops(JNIEnv * env,jobject thiz)1392 static void android_media_MediaDrm_removeAllSecureStops(
1393 JNIEnv *env, jobject thiz) {
1394 sp<IDrm> drm = GetDrm(env, thiz);
1395
1396 if (!CheckDrm(env, drm)) {
1397 return;
1398 }
1399
1400 status_t err = drm->removeAllSecureStops();
1401
1402 throwExceptionAsNecessary(env, err, "Failed to remove all secure stops");
1403 }
1404
1405
HdcpLevelTojint(DrmPlugin::HdcpLevel level)1406 static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) {
1407 switch(level) {
1408 case DrmPlugin::kHdcpLevelUnknown:
1409 return gHdcpLevels.kHdcpLevelUnknown;
1410 case DrmPlugin::kHdcpNone:
1411 return gHdcpLevels.kHdcpNone;
1412 case DrmPlugin::kHdcpV1:
1413 return gHdcpLevels.kHdcpV1;
1414 case DrmPlugin::kHdcpV2:
1415 return gHdcpLevels.kHdcpV2;
1416 case DrmPlugin::kHdcpV2_1:
1417 return gHdcpLevels.kHdcpV2_1;
1418 case DrmPlugin::kHdcpV2_2:
1419 return gHdcpLevels.kHdcpV2_2;
1420 case DrmPlugin::kHdcpV2_3:
1421 return gHdcpLevels.kHdcpV2_3;
1422 case DrmPlugin::kHdcpNoOutput:
1423 return gHdcpLevels.kHdcpNoOutput;
1424 }
1425 return gHdcpLevels.kHdcpNone;
1426 }
1427
android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv * env,jobject thiz)1428 static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env,
1429 jobject thiz) {
1430 sp<IDrm> drm = GetDrm(env, thiz);
1431
1432 if (!CheckDrm(env, drm)) {
1433 return gHdcpLevels.kHdcpNone;
1434 }
1435
1436 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone;
1437 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone;
1438
1439 status_t err = drm->getHdcpLevels(&connected, &max);
1440
1441 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1442 return gHdcpLevels.kHdcpLevelUnknown;
1443 }
1444 return HdcpLevelTojint(connected);
1445 }
1446
android_media_MediaDrm_getMaxHdcpLevel(JNIEnv * env,jobject thiz)1447 static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env,
1448 jobject thiz) {
1449 sp<IDrm> drm = GetDrm(env, thiz);
1450
1451 if (!CheckDrm(env, drm)) {
1452 return gHdcpLevels.kHdcpLevelUnknown;
1453 }
1454
1455 DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
1456 DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
1457
1458 status_t err = drm->getHdcpLevels(&connected, &max);
1459
1460 if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) {
1461 return gHdcpLevels.kHdcpLevelUnknown;
1462 }
1463 return HdcpLevelTojint(max);
1464 }
1465
android_media_MediaDrm_getOpenSessionCount(JNIEnv * env,jobject thiz)1466 static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env,
1467 jobject thiz) {
1468 sp<IDrm> drm = GetDrm(env, thiz);
1469
1470 if (!CheckDrm(env, drm)) {
1471 return 0;
1472 }
1473
1474 uint32_t open = 0, max = 0;
1475 status_t err = drm->getNumberOfSessions(&open, &max);
1476
1477 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1478 return 0;
1479 }
1480 return open;
1481 }
1482
android_media_MediaDrm_getMaxSessionCount(JNIEnv * env,jobject thiz)1483 static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env,
1484 jobject thiz) {
1485 sp<IDrm> drm = GetDrm(env, thiz);
1486
1487 if (!CheckDrm(env, drm)) {
1488 return 0;
1489 }
1490
1491 uint32_t open = 0, max = 0;
1492 status_t err = drm->getNumberOfSessions(&open, &max);
1493
1494 if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) {
1495 return 0;
1496 }
1497 return max;
1498 }
1499
android_media_MediaDrm_getSecurityLevel(JNIEnv * env,jobject thiz,jbyteArray jsessionId)1500 static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env,
1501 jobject thiz, jbyteArray jsessionId) {
1502 sp<IDrm> drm = GetDrm(env, thiz);
1503
1504 if (!CheckSession(env, drm, jsessionId)) {
1505 return gSecurityLevels.kSecurityLevelUnknown;
1506 }
1507
1508 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1509
1510 DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
1511
1512 status_t err = drm->getSecurityLevel(sessionId, &level);
1513
1514 if (throwExceptionAsNecessary(env, err, "Failed to get security level")) {
1515 return gSecurityLevels.kSecurityLevelUnknown;
1516 }
1517
1518 switch(level) {
1519 case DrmPlugin::kSecurityLevelSwSecureCrypto:
1520 return gSecurityLevels.kSecurityLevelSwSecureCrypto;
1521 case DrmPlugin::kSecurityLevelSwSecureDecode:
1522 return gSecurityLevels.kSecurityLevelSwSecureDecode;
1523 case DrmPlugin::kSecurityLevelHwSecureCrypto:
1524 return gSecurityLevels.kSecurityLevelHwSecureCrypto;
1525 case DrmPlugin::kSecurityLevelHwSecureDecode:
1526 return gSecurityLevels.kSecurityLevelHwSecureDecode;
1527 case DrmPlugin::kSecurityLevelHwSecureAll:
1528 return gSecurityLevels.kSecurityLevelHwSecureAll;
1529 default:
1530 return gSecurityLevels.kSecurityLevelUnknown;
1531 }
1532 }
1533
android_media_MediaDrm_getOfflineLicenseKeySetIds(JNIEnv * env,jobject thiz)1534 static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds(
1535 JNIEnv *env, jobject thiz) {
1536 sp<IDrm> drm = GetDrm(env, thiz);
1537
1538 if (!CheckDrm(env, drm)) {
1539 return NULL;
1540 }
1541
1542 List<Vector<uint8_t> > keySetIds;
1543
1544 status_t err = drm->getOfflineLicenseKeySetIds(keySetIds);
1545
1546 if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) {
1547 return NULL;
1548 }
1549
1550 return ListOfVectorsToArrayListOfByteArray(env, keySetIds);
1551 }
1552
android_media_MediaDrm_removeOfflineLicense(JNIEnv * env,jobject thiz,jbyteArray keySetId)1553 static void android_media_MediaDrm_removeOfflineLicense(
1554 JNIEnv *env, jobject thiz, jbyteArray keySetId) {
1555 sp<IDrm> drm = GetDrm(env, thiz);
1556
1557 if (!CheckDrm(env, drm)) {
1558 return;
1559 }
1560
1561 status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId));
1562
1563 throwExceptionAsNecessary(env, err, "Failed to remove offline license");
1564 }
1565
android_media_MediaDrm_getOfflineLicenseState(JNIEnv * env,jobject thiz,jbyteArray jkeySetId)1566 static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env,
1567 jobject thiz, jbyteArray jkeySetId) {
1568 sp<IDrm> drm = GetDrm(env, thiz);
1569
1570 if (!CheckDrm(env, drm)) {
1571 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1572 }
1573
1574 Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeySetId));
1575
1576 DrmPlugin::OfflineLicenseState state = DrmPlugin::kOfflineLicenseStateUnknown;
1577
1578 status_t err = drm->getOfflineLicenseState(keySetId, &state);
1579
1580 if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) {
1581 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1582 }
1583
1584 switch(state) {
1585 case DrmPlugin::kOfflineLicenseStateUsable:
1586 return gOfflineLicenseStates.kOfflineLicenseStateUsable;
1587 case DrmPlugin::kOfflineLicenseStateReleased:
1588 return gOfflineLicenseStates.kOfflineLicenseStateReleased;
1589 default:
1590 return gOfflineLicenseStates.kOfflineLicenseStateUnknown;
1591 }
1592 }
1593
android_media_MediaDrm_getPropertyString(JNIEnv * env,jobject thiz,jstring jname)1594 static jstring android_media_MediaDrm_getPropertyString(
1595 JNIEnv *env, jobject thiz, jstring jname) {
1596 sp<IDrm> drm = GetDrm(env, thiz);
1597
1598 if (!CheckDrm(env, drm)) {
1599 return NULL;
1600 }
1601
1602 if (jname == NULL) {
1603 jniThrowException(env, "java/lang/IllegalArgumentException",
1604 "property name String is null");
1605 return NULL;
1606 }
1607
1608 String8 name = JStringToString8(env, jname);
1609 String8 value;
1610
1611 status_t err = drm->getPropertyString(name, value);
1612
1613 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1614 return NULL;
1615 }
1616
1617 return env->NewStringUTF(value.string());
1618 }
1619
android_media_MediaDrm_getPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname)1620 static jbyteArray android_media_MediaDrm_getPropertyByteArray(
1621 JNIEnv *env, jobject thiz, jstring jname) {
1622 sp<IDrm> drm = GetDrm(env, thiz);
1623
1624 if (!CheckDrm(env, drm)) {
1625 return NULL;
1626 }
1627
1628 if (jname == NULL) {
1629 jniThrowException(env, "java/lang/IllegalArgumentException",
1630 "property name String is null");
1631 return NULL;
1632 }
1633
1634 String8 name = JStringToString8(env, jname);
1635 Vector<uint8_t> value;
1636
1637 status_t err = drm->getPropertyByteArray(name, value);
1638
1639 if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
1640 return NULL;
1641 }
1642
1643 return VectorToJByteArray(env, value);
1644 }
1645
android_media_MediaDrm_setPropertyString(JNIEnv * env,jobject thiz,jstring jname,jstring jvalue)1646 static void android_media_MediaDrm_setPropertyString(
1647 JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
1648 sp<IDrm> drm = GetDrm(env, thiz);
1649
1650 if (!CheckDrm(env, drm)) {
1651 return;
1652 }
1653
1654 if (jname == NULL) {
1655 jniThrowException(env, "java/lang/IllegalArgumentException",
1656 "property name String is null");
1657 return;
1658 }
1659
1660 if (jvalue == NULL) {
1661 jniThrowException(env, "java/lang/IllegalArgumentException",
1662 "property value String is null");
1663 return;
1664 }
1665
1666 String8 name = JStringToString8(env, jname);
1667 String8 value = JStringToString8(env, jvalue);
1668
1669 status_t err = drm->setPropertyString(name, value);
1670
1671 throwExceptionAsNecessary(env, err, "Failed to set property");
1672 }
1673
android_media_MediaDrm_setPropertyByteArray(JNIEnv * env,jobject thiz,jstring jname,jbyteArray jvalue)1674 static void android_media_MediaDrm_setPropertyByteArray(
1675 JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
1676 sp<IDrm> drm = GetDrm(env, thiz);
1677
1678 if (!CheckDrm(env, drm)) {
1679 return;
1680 }
1681
1682 if (jname == NULL) {
1683 jniThrowException(env, "java/lang/IllegalArgumentException",
1684 "property name String is null");
1685 return;
1686 }
1687
1688 if (jvalue == NULL) {
1689 jniThrowException(env, "java/lang/IllegalArgumentException",
1690 "property value byte array is null");
1691 return;
1692 }
1693
1694 String8 name = JStringToString8(env, jname);
1695 Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
1696
1697 status_t err = drm->setPropertyByteArray(name, value);
1698
1699 throwExceptionAsNecessary(env, err, "Failed to set property");
1700 }
1701
android_media_MediaDrm_setCipherAlgorithmNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1702 static void android_media_MediaDrm_setCipherAlgorithmNative(
1703 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1704 jstring jalgorithm) {
1705
1706 sp<IDrm> drm = GetDrm(env, jdrm);
1707
1708 if (!CheckSession(env, drm, jsessionId)) {
1709 return;
1710 }
1711
1712 if (jalgorithm == NULL) {
1713 jniThrowException(env, "java/lang/IllegalArgumentException",
1714 "algorithm String is null");
1715 return;
1716 }
1717
1718 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1719 String8 algorithm = JStringToString8(env, jalgorithm);
1720
1721 status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
1722
1723 throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
1724 }
1725
android_media_MediaDrm_setMacAlgorithmNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm)1726 static void android_media_MediaDrm_setMacAlgorithmNative(
1727 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1728 jstring jalgorithm) {
1729
1730 sp<IDrm> drm = GetDrm(env, jdrm);
1731
1732 if (!CheckSession(env, drm, jsessionId)) {
1733 return;
1734 }
1735
1736 if (jalgorithm == NULL) {
1737 jniThrowException(env, "java/lang/IllegalArgumentException",
1738 "algorithm String is null");
1739 return;
1740 }
1741
1742 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1743 String8 algorithm = JStringToString8(env, jalgorithm);
1744
1745 status_t err = drm->setMacAlgorithm(sessionId, algorithm);
1746
1747 throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
1748 }
1749
1750
android_media_MediaDrm_encryptNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1751 static jbyteArray android_media_MediaDrm_encryptNative(
1752 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1753 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1754
1755 sp<IDrm> drm = GetDrm(env, jdrm);
1756
1757 if (!CheckSession(env, drm, jsessionId)) {
1758 return NULL;
1759 }
1760
1761 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1762 jniThrowException(env, "java/lang/IllegalArgumentException",
1763 "required argument is null");
1764 return NULL;
1765 }
1766
1767 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1768 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1769 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1770 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1771 Vector<uint8_t> output;
1772
1773 status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
1774
1775 if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) {
1776 return NULL;
1777 }
1778
1779 return VectorToJByteArray(env, output);
1780 }
1781
android_media_MediaDrm_decryptNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jinput,jbyteArray jiv)1782 static jbyteArray android_media_MediaDrm_decryptNative(
1783 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1784 jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
1785
1786 sp<IDrm> drm = GetDrm(env, jdrm);
1787
1788 if (!CheckSession(env, drm, jsessionId)) {
1789 return NULL;
1790 }
1791
1792 if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
1793 jniThrowException(env, "java/lang/IllegalArgumentException",
1794 "required argument is null");
1795 return NULL;
1796 }
1797
1798 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1799 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1800 Vector<uint8_t> input(JByteArrayToVector(env, jinput));
1801 Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
1802 Vector<uint8_t> output;
1803
1804 status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
1805 if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) {
1806 return NULL;
1807 }
1808
1809 return VectorToJByteArray(env, output);
1810 }
1811
android_media_MediaDrm_signNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage)1812 static jbyteArray android_media_MediaDrm_signNative(
1813 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1814 jbyteArray jkeyId, jbyteArray jmessage) {
1815
1816 sp<IDrm> drm = GetDrm(env, jdrm);
1817
1818 if (!CheckSession(env, drm, jsessionId)) {
1819 return NULL;
1820 }
1821
1822 if (jkeyId == NULL || jmessage == NULL) {
1823 jniThrowException(env, "java/lang/IllegalArgumentException",
1824 "required argument is null");
1825 return NULL;
1826 }
1827
1828 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1829 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1830 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1831 Vector<uint8_t> signature;
1832
1833 status_t err = drm->sign(sessionId, keyId, message, signature);
1834
1835 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1836 return NULL;
1837 }
1838
1839 return VectorToJByteArray(env, signature);
1840 }
1841
android_media_MediaDrm_verifyNative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jbyteArray jkeyId,jbyteArray jmessage,jbyteArray jsignature)1842 static jboolean android_media_MediaDrm_verifyNative(
1843 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1844 jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
1845
1846 sp<IDrm> drm = GetDrm(env, jdrm);
1847
1848 if (!CheckSession(env, drm, jsessionId)) {
1849 return false;
1850 }
1851
1852 if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
1853 jniThrowException(env, "java/lang/IllegalArgumentException",
1854 "required argument is null");
1855 return false;
1856 }
1857
1858 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1859 Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
1860 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1861 Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
1862 bool match;
1863
1864 status_t err = drm->verify(sessionId, keyId, message, signature, match);
1865
1866 throwExceptionAsNecessary(env, err, "Failed to verify");
1867 return match;
1868 }
1869
1870 static jobject
android_media_MediaDrm_native_getMetrics(JNIEnv * env,jobject thiz)1871 android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
1872 {
1873 sp<IDrm> drm = GetDrm(env, thiz);
1874
1875 if (!CheckDrm(env, drm)) {
1876 return NULL;
1877 }
1878
1879 // Retrieve current metrics snapshot from drm.
1880 PersistableBundle metrics;
1881 status_t err = drm->getMetrics(&metrics);
1882 if (err != OK) {
1883 ALOGE("getMetrics failed: %d", (int)err);
1884 return (jobject) NULL;
1885 }
1886
1887 return nativeToJavaPersistableBundle(env, thiz, &metrics);
1888 }
1889
android_media_MediaDrm_signRSANative(JNIEnv * env,jobject,jobject jdrm,jbyteArray jsessionId,jstring jalgorithm,jbyteArray jwrappedKey,jbyteArray jmessage)1890 static jbyteArray android_media_MediaDrm_signRSANative(
1891 JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
1892 jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
1893
1894 sp<IDrm> drm = GetDrm(env, jdrm);
1895
1896 if (!CheckSession(env, drm, jsessionId)) {
1897 return NULL;
1898 }
1899
1900 if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
1901 jniThrowException(env, "java/lang/IllegalArgumentException",
1902 "required argument is null");
1903 return NULL;
1904 }
1905
1906 Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
1907 String8 algorithm = JStringToString8(env, jalgorithm);
1908 Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
1909 Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
1910 Vector<uint8_t> signature;
1911
1912 status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
1913
1914 if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
1915 return NULL;
1916 }
1917
1918 return VectorToJByteArray(env, signature);
1919 }
1920
1921
1922 static const JNINativeMethod gMethods[] = {
1923 { "native_release", "()V", (void *)android_media_MediaDrm_native_release },
1924
1925 { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
1926
1927 { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
1928 (void *)android_media_MediaDrm_native_setup },
1929
1930 { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
1931 (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
1932
1933 { "openSession", "(I)[B",
1934 (void *)android_media_MediaDrm_openSession },
1935
1936 { "closeSession", "([B)V",
1937 (void *)android_media_MediaDrm_closeSession },
1938
1939 { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
1940 "Landroid/media/MediaDrm$KeyRequest;",
1941 (void *)android_media_MediaDrm_getKeyRequest },
1942
1943 { "provideKeyResponse", "([B[B)[B",
1944 (void *)android_media_MediaDrm_provideKeyResponse },
1945
1946 { "removeKeys", "([B)V",
1947 (void *)android_media_MediaDrm_removeKeys },
1948
1949 { "restoreKeys", "([B[B)V",
1950 (void *)android_media_MediaDrm_restoreKeys },
1951
1952 { "queryKeyStatus", "([B)Ljava/util/HashMap;",
1953 (void *)android_media_MediaDrm_queryKeyStatus },
1954
1955 { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
1956 (void *)android_media_MediaDrm_getProvisionRequestNative },
1957
1958 { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
1959 (void *)android_media_MediaDrm_provideProvisionResponseNative },
1960
1961 { "getSecureStops", "()Ljava/util/List;",
1962 (void *)android_media_MediaDrm_getSecureStops },
1963
1964 { "getSecureStopIds", "()Ljava/util/List;",
1965 (void *)android_media_MediaDrm_getSecureStopIds },
1966
1967 { "getSecureStop", "([B)[B",
1968 (void *)android_media_MediaDrm_getSecureStop },
1969
1970 { "releaseSecureStops", "([B)V",
1971 (void *)android_media_MediaDrm_releaseSecureStops },
1972
1973 { "removeSecureStop", "([B)V",
1974 (void *)android_media_MediaDrm_removeSecureStop },
1975
1976 { "removeAllSecureStops", "()V",
1977 (void *)android_media_MediaDrm_removeAllSecureStops },
1978
1979 { "getConnectedHdcpLevel", "()I",
1980 (void *)android_media_MediaDrm_getConnectedHdcpLevel },
1981
1982 { "getMaxHdcpLevel", "()I",
1983 (void *)android_media_MediaDrm_getMaxHdcpLevel },
1984
1985 { "getOpenSessionCount", "()I",
1986 (void *)android_media_MediaDrm_getOpenSessionCount },
1987
1988 { "getMaxSessionCount", "()I",
1989 (void *)android_media_MediaDrm_getMaxSessionCount },
1990
1991 { "getSecurityLevel", "([B)I",
1992 (void *)android_media_MediaDrm_getSecurityLevel },
1993
1994 { "removeOfflineLicense", "([B)V",
1995 (void *)android_media_MediaDrm_removeOfflineLicense },
1996
1997 { "getOfflineLicenseKeySetIds", "()Ljava/util/List;",
1998 (void *)android_media_MediaDrm_getOfflineLicenseKeySetIds },
1999
2000 { "getOfflineLicenseState", "([B)I",
2001 (void *)android_media_MediaDrm_getOfflineLicenseState },
2002
2003 { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
2004 (void *)android_media_MediaDrm_getPropertyString },
2005
2006 { "getPropertyByteArray", "(Ljava/lang/String;)[B",
2007 (void *)android_media_MediaDrm_getPropertyByteArray },
2008
2009 { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
2010 (void *)android_media_MediaDrm_setPropertyString },
2011
2012 { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
2013 (void *)android_media_MediaDrm_setPropertyByteArray },
2014
2015 { "setCipherAlgorithmNative",
2016 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2017 (void *)android_media_MediaDrm_setCipherAlgorithmNative },
2018
2019 { "setMacAlgorithmNative",
2020 "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
2021 (void *)android_media_MediaDrm_setMacAlgorithmNative },
2022
2023 { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2024 (void *)android_media_MediaDrm_encryptNative },
2025
2026 { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
2027 (void *)android_media_MediaDrm_decryptNative },
2028
2029 { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
2030 (void *)android_media_MediaDrm_signNative },
2031
2032 { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
2033 (void *)android_media_MediaDrm_verifyNative },
2034
2035 { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
2036 (void *)android_media_MediaDrm_signRSANative },
2037
2038 { "getMetricsNative", "()Landroid/os/PersistableBundle;",
2039 (void *)android_media_MediaDrm_native_getMetrics },
2040 };
2041
register_android_media_Drm(JNIEnv * env)2042 int register_android_media_Drm(JNIEnv *env) {
2043 return AndroidRuntime::registerNativeMethods(env,
2044 "android/media/MediaDrm", gMethods, NELEM(gMethods));
2045 }
2046