1 /*
2  * Copyright (C) 2014 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 "NdkMediaDrm"
19 
20 #include <inttypes.h>
21 #include <unistd.h>
22 
23 #include <media/NdkMediaDrm.h>
24 
25 #include <cutils/properties.h>
26 #include <utils/Log.h>
27 #include <utils/StrongPointer.h>
28 #include <gui/Surface.h>
29 
30 #include <android-base/properties.h>
31 #include <binder/PermissionController.h>
32 #include <mediadrm/IDrm.h>
33 #include <mediadrm/IDrmClient.h>
34 #include <media/stagefright/MediaErrors.h>
35 #include <binder/IServiceManager.h>
36 #include <media/NdkMediaCrypto.h>
37 #include <mediadrm/IMediaDrmService.h>
38 
39 
40 using namespace android;
41 
42 typedef Vector<uint8_t> idvec_t;
43 
44 struct DrmListener: virtual public BnDrmClient
45 {
46 private:
47     AMediaDrm *mObj;
48     AMediaDrmEventListener mEventListener;
49     AMediaDrmExpirationUpdateListener mExpirationUpdateListener;
50     AMediaDrmKeysChangeListener mKeysChangeListener;
51 
52 public:
DrmListenerDrmListener53     DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj),
54             mEventListener(listener), mExpirationUpdateListener(NULL), mKeysChangeListener(NULL) {}
55 
DrmListenerDrmListener56     DrmListener(AMediaDrm *obj, AMediaDrmExpirationUpdateListener listener) : mObj(obj),
57             mEventListener(NULL), mExpirationUpdateListener(listener), mKeysChangeListener(NULL) {}
58 
DrmListenerDrmListener59     DrmListener(AMediaDrm *obj, AMediaDrmKeysChangeListener listener) : mObj(obj),
60             mEventListener(NULL), mExpirationUpdateListener(NULL), mKeysChangeListener(listener) {}
61 
setEventListenerDrmListener62     void setEventListener(AMediaDrmEventListener listener) {
63         mEventListener = listener;
64     }
65 
setExpirationUpdateListenerDrmListener66     void setExpirationUpdateListener(AMediaDrmExpirationUpdateListener listener) {
67         mExpirationUpdateListener = listener;
68     }
69 
setKeysChangeListenerDrmListener70     void setKeysChangeListener(AMediaDrmKeysChangeListener listener) {
71         mKeysChangeListener = listener;
72     }
73 
74     void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
75 };
76 
77 struct AMediaDrm {
78     sp<IDrm> mDrm;
79     sp<IDrmClient> mDrmClient;
80     List<idvec_t> mIds;
81     KeyedVector<String8, String8> mQueryResults;
82     Vector<uint8_t> mKeyRequest;
83     Vector<uint8_t> mProvisionRequest;
84     String8 mProvisionUrl;
85     String8 mPropertyString;
86     Vector<uint8_t> mPropertyByteArray;
87     List<Vector<uint8_t> > mSecureStops;
88     sp<DrmListener> mListener;
89 };
90 
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)91 void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
92     if (!mEventListener || !mExpirationUpdateListener || !mKeysChangeListener) {
93         ALOGE("No listeners are specified");
94         return;
95     }
96 
97     obj->setDataPosition(0);
98 
99     AMediaDrmSessionId sessionId = {NULL, 0};
100     int32_t sessionIdSize = obj->readInt32();
101     if (sessionIdSize <= 0) {
102         ALOGE("Invalid session id size");
103         return;
104     }
105 
106     std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]);
107     sessionId.ptr = sessionIdData.get();
108     sessionId.length = sessionIdSize;
109     status_t err = obj->read(sessionIdData.get(), sessionId.length);
110     if (err != OK) {
111         ALOGE("Failed to read session id, error=%d", err);
112         return;
113     }
114 
115     if (DrmPlugin::kDrmPluginEventExpirationUpdate == eventType) {
116         int64_t expiryTimeInMS = obj->readInt64();
117         if (expiryTimeInMS >= 0) {
118             (*mExpirationUpdateListener)(mObj, &sessionId, expiryTimeInMS);
119         } else {
120             ALOGE("Failed to read expiry time, status=%" PRId64 "", expiryTimeInMS);
121         }
122         return;
123     } else if (DrmPlugin::kDrmPluginEventKeysChange == eventType) {
124         int32_t numKeys = 0;
125         err = obj->readInt32(&numKeys);
126         if (err != OK) {
127             ALOGE("Failed to read number of keys status, error=%d", err);
128             return;
129         }
130 
131         Vector<AMediaDrmKeyStatus> keysStatus;
132         std::vector<std::unique_ptr<uint8_t[]> > dataPointers;
133         AMediaDrmKeyStatus keyStatus;
134 
135         for (size_t i = 0; i < numKeys; ++i) {
136             keyStatus.keyId.ptr = nullptr;
137             keyStatus.keyId.length = 0;
138             int32_t idSize = obj->readInt32();
139             if (idSize > 0) {
140                 std::unique_ptr<uint8_t[]> data(new uint8_t[idSize]);
141                 err = obj->read(data.get(), idSize);
142                 if (err != OK) {
143                     ALOGE("Failed to read key data, error=%d", err);
144                     return;
145                 }
146                 keyStatus.keyId.ptr = data.get();
147                 keyStatus.keyId.length = idSize;
148                 dataPointers.push_back(std::move(data));
149             }
150             keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(obj->readInt32());
151             keysStatus.push(keyStatus);
152         }
153 
154         bool hasNewUsableKey = obj->readInt32();
155         (*mKeysChangeListener)(mObj, &sessionId, keysStatus.array(), numKeys, hasNewUsableKey);
156         return;
157     }
158 
159     // Handles AMediaDrmEventListener below:
160     //  translates DrmPlugin event types into their NDK equivalents
161     AMediaDrmEventType ndkEventType;
162     switch(eventType) {
163         case DrmPlugin::kDrmPluginEventProvisionRequired:
164             ndkEventType = EVENT_PROVISION_REQUIRED;
165             break;
166         case DrmPlugin::kDrmPluginEventKeyNeeded:
167             ndkEventType = EVENT_KEY_REQUIRED;
168             break;
169         case DrmPlugin::kDrmPluginEventKeyExpired:
170             ndkEventType = EVENT_KEY_EXPIRED;
171             break;
172         case DrmPlugin::kDrmPluginEventVendorDefined:
173             ndkEventType = EVENT_VENDOR_DEFINED;
174             break;
175         case DrmPlugin::kDrmPluginEventSessionReclaimed:
176             ndkEventType = EVENT_SESSION_RECLAIMED;
177             break;
178         default:
179             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
180             return;
181     }
182 
183     int32_t dataSize = obj->readInt32();
184     uint8_t *data = NULL;
185     if (dataSize > 0) {
186         data = new uint8_t[dataSize];
187         err = obj->read(data, dataSize);
188         if (err == OK) {
189             (*mEventListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
190         } else {
191             ALOGE("Failed to read event data, error=%d", err);
192         }
193         delete [] data;
194     } else {
195         ALOGE("Error reading parcel: invalid event data size=%d", dataSize);
196     }
197 }
198 
199 extern "C" {
200 
translateStatus(status_t status)201 static media_status_t translateStatus(status_t status) {
202     media_status_t result = AMEDIA_ERROR_UNKNOWN;
203     switch (status) {
204         case OK:
205             result = AMEDIA_OK;
206             break;
207         case android::ERROR_DRM_NOT_PROVISIONED:
208             result = AMEDIA_DRM_NOT_PROVISIONED;
209             break;
210         case android::ERROR_DRM_RESOURCE_BUSY:
211             result = AMEDIA_DRM_RESOURCE_BUSY;
212             break;
213         case android::ERROR_DRM_DEVICE_REVOKED:
214             result = AMEDIA_DRM_DEVICE_REVOKED;
215             break;
216         case android::ERROR_DRM_CANNOT_HANDLE:
217             result = AMEDIA_ERROR_INVALID_PARAMETER;
218             break;
219         case android::ERROR_DRM_TAMPER_DETECTED:
220             result = AMEDIA_DRM_TAMPER_DETECTED;
221             break;
222         case android::ERROR_DRM_SESSION_NOT_OPENED:
223             result = AMEDIA_DRM_SESSION_NOT_OPENED;
224             break;
225         case android::ERROR_DRM_NO_LICENSE:
226             result = AMEDIA_DRM_NEED_KEY;
227             break;
228         case android::ERROR_DRM_LICENSE_EXPIRED:
229             result = AMEDIA_DRM_LICENSE_EXPIRED;
230             break;
231         default:
232             break;
233     }
234     return result;
235 }
236 
ShouldGetAppPackageName(void)237 static bool ShouldGetAppPackageName(void) {
238     // Check what this device's first API level was.
239     int32_t firstApiLevel = android::base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
240     if (firstApiLevel == 0) {
241         // First API Level is 0 on factory ROMs, but we can assume the current SDK
242         // version is the first if it's a factory ROM.
243         firstApiLevel = android::base::GetIntProperty<int32_t>("ro.build.version.sdk", 0);
244     }
245     return firstApiLevel >= 29;  // Android Q
246 }
247 
GetAppPackageName(String8 * packageName)248 static status_t GetAppPackageName(String8 *packageName) {
249     sp<IServiceManager> serviceManager = defaultServiceManager();
250     sp<IBinder> binder = serviceManager->getService(String16("permission"));
251 
252     sp<IPermissionController> permissionContol = interface_cast<IPermissionController>(binder);
253     if (permissionContol == NULL) {
254         ALOGE("Failed to get permission service");
255         return UNKNOWN_ERROR;
256     }
257 
258     Vector<String16> packages;
259     permissionContol->getPackagesForUid(getuid(), packages);
260 
261     if (packages.isEmpty()) {
262         ALOGE("Unable to get package name for current UID");
263         return UNKNOWN_ERROR;
264     }
265 
266     *packageName = String8(packages[0]);
267     return OK;
268 }
269 
CreateDrm()270 static sp<IDrm> CreateDrm() {
271     sp<IServiceManager> sm = defaultServiceManager();
272     sp<IBinder> binder = sm->getService(String16("media.drm"));
273 
274     sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
275     if (service == NULL) {
276         return NULL;
277     }
278 
279     sp<IDrm> drm = service->makeDrm();
280     if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
281         return NULL;
282     }
283     return drm;
284 }
285 
286 
CreateDrmFromUUID(const AMediaUUID uuid)287 static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
288     sp<IDrm> drm = CreateDrm();
289 
290     if (drm == NULL) {
291         return NULL;
292     }
293 
294     String8 packageName;
295     if (ShouldGetAppPackageName()) {
296         status_t err = GetAppPackageName(&packageName);
297 
298         if (err != OK) {
299             return NULL;
300         }
301     }
302 
303     status_t err = drm->createPlugin(uuid, packageName);
304 
305     if (err != OK) {
306         return NULL;
307     }
308 
309     return drm;
310 }
311 
312 EXPORT
AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid,const char * mimeType)313 bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
314     sp<IDrm> drm = CreateDrm();
315 
316     if (drm == NULL) {
317         return false;
318     }
319 
320     String8 mimeStr = mimeType ? String8(mimeType) : String8("");
321     bool isSupported = false;
322     status_t status = drm->isCryptoSchemeSupported(uuid, mimeStr,
323             DrmPlugin::kSecurityLevelUnknown, &isSupported);
324     return (status == OK) && isSupported;
325 }
326 
327 EXPORT
AMediaDrm_createByUUID(const AMediaUUID uuid)328 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
329     AMediaDrm *mObj = new AMediaDrm();
330     mObj->mDrm = CreateDrmFromUUID(uuid);
331 
332     mObj->mListener.clear();
333     return mObj;
334 }
335 
336 EXPORT
AMediaDrm_release(AMediaDrm * mObj)337 void AMediaDrm_release(AMediaDrm *mObj) {
338     if (mObj->mDrm != NULL) {
339         mObj->mDrm->setListener(NULL);
340         mObj->mDrm->destroyPlugin();
341         mObj->mDrm.clear();
342     }
343     delete mObj;
344 }
345 
346 EXPORT
AMediaDrm_setOnEventListener(AMediaDrm * mObj,AMediaDrmEventListener listener)347 media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
348     if (!mObj || mObj->mDrm == NULL) {
349         return AMEDIA_ERROR_INVALID_OBJECT;
350     }
351 
352     if (mObj->mListener.get()) {
353         mObj->mListener->setEventListener(listener);
354     } else {
355         mObj->mListener = new DrmListener(mObj, listener);
356     }
357     mObj->mDrm->setListener(mObj->mListener);
358     return AMEDIA_OK;
359 }
360 
361 EXPORT
AMediaDrm_setOnExpirationUpdateListener(AMediaDrm * mObj,AMediaDrmExpirationUpdateListener listener)362 media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *mObj,
363         AMediaDrmExpirationUpdateListener listener) {
364     if (!mObj || mObj->mDrm == NULL) {
365         return AMEDIA_ERROR_INVALID_OBJECT;
366     }
367 
368     if (mObj->mListener.get()) {
369         mObj->mListener->setExpirationUpdateListener(listener);
370     } else {
371         mObj->mListener = new DrmListener(mObj, listener);
372     }
373     mObj->mDrm->setListener(mObj->mListener);
374     return AMEDIA_OK;
375 }
376 
377 EXPORT
AMediaDrm_setOnKeysChangeListener(AMediaDrm * mObj,AMediaDrmKeysChangeListener listener)378 media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *mObj,
379         AMediaDrmKeysChangeListener listener) {
380     if (!mObj || mObj->mDrm == NULL) {
381         return AMEDIA_ERROR_INVALID_OBJECT;
382     }
383 
384     if (mObj->mListener.get()) {
385         mObj->mListener->setKeysChangeListener(listener);
386     } else {
387         mObj->mListener = new DrmListener(mObj, listener);
388     }
389     mObj->mDrm->setListener(mObj->mListener);
390     return AMEDIA_OK;
391 }
392 
findId(AMediaDrm * mObj,const AMediaDrmByteArray & id,List<idvec_t>::iterator & iter)393 static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
394     for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
395         if (id.length == iter->size() && memcmp(iter->array(), id.ptr, iter->size()) == 0) {
396             return true;
397         }
398     }
399     return false;
400 }
401 
402 EXPORT
AMediaDrm_openSession(AMediaDrm * mObj,AMediaDrmSessionId * sessionId)403 media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) {
404     if (!mObj || mObj->mDrm == NULL) {
405         return AMEDIA_ERROR_INVALID_OBJECT;
406     }
407     if (!sessionId) {
408         return AMEDIA_ERROR_INVALID_PARAMETER;
409     }
410     Vector<uint8_t> session;
411     status_t status = mObj->mDrm->openSession(DrmPlugin::kSecurityLevelMax, session);
412     if (status == OK) {
413         mObj->mIds.push_front(session);
414         List<idvec_t>::iterator iter = mObj->mIds.begin();
415         sessionId->ptr = iter->array();
416         sessionId->length = iter->size();
417     }
418     return AMEDIA_OK;
419 }
420 
421 EXPORT
AMediaDrm_closeSession(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId)422 media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
423     if (!mObj || mObj->mDrm == NULL) {
424         return AMEDIA_ERROR_INVALID_OBJECT;
425     }
426     if (!sessionId) {
427         return AMEDIA_ERROR_INVALID_PARAMETER;
428     }
429 
430     List<idvec_t>::iterator iter;
431     if (!findId(mObj, *sessionId, iter)) {
432         return AMEDIA_DRM_SESSION_NOT_OPENED;
433     }
434     mObj->mDrm->closeSession(*iter);
435     mObj->mIds.erase(iter);
436     return AMEDIA_OK;
437 }
438 
439 EXPORT
AMediaDrm_getKeyRequest(AMediaDrm * mObj,const AMediaDrmScope * scope,const uint8_t * init,size_t initSize,const char * mimeType,AMediaDrmKeyType keyType,const AMediaDrmKeyValue * optionalParameters,size_t numOptionalParameters,const uint8_t ** keyRequest,size_t * keyRequestSize)440 media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
441         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
442         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
443         const uint8_t **keyRequest, size_t *keyRequestSize) {
444 
445     if (!mObj || mObj->mDrm == NULL) {
446         return AMEDIA_ERROR_INVALID_OBJECT;
447     }
448     if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
449         return AMEDIA_ERROR_INVALID_PARAMETER;
450     }
451 
452     List<idvec_t>::iterator iter;
453     if (!findId(mObj, *scope, iter)) {
454         return AMEDIA_DRM_SESSION_NOT_OPENED;
455     }
456 
457     Vector<uint8_t> mdInit;
458     mdInit.appendArray(init, initSize);
459     DrmPlugin::KeyType mdKeyType;
460     switch (keyType) {
461         case KEY_TYPE_STREAMING:
462             mdKeyType = DrmPlugin::kKeyType_Streaming;
463             break;
464         case KEY_TYPE_OFFLINE:
465             mdKeyType = DrmPlugin::kKeyType_Offline;
466             break;
467         case KEY_TYPE_RELEASE:
468             mdKeyType = DrmPlugin::kKeyType_Release;
469             break;
470         default:
471             return AMEDIA_ERROR_INVALID_PARAMETER;
472     }
473     KeyedVector<String8, String8> mdOptionalParameters;
474     for (size_t i = 0; i < numOptionalParameters; i++) {
475         mdOptionalParameters.add(String8(optionalParameters[i].mKey),
476                 String8(optionalParameters[i].mValue));
477     }
478     String8 defaultUrl;
479     DrmPlugin::KeyRequestType keyRequestType;
480     mObj->mKeyRequest.clear();
481     status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
482             mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
483             &keyRequestType);
484     if (status != OK) {
485         return translateStatus(status);
486     } else {
487         *keyRequest = mObj->mKeyRequest.array();
488         *keyRequestSize = mObj->mKeyRequest.size();
489     }
490     return AMEDIA_OK;
491 }
492 
493 EXPORT
AMediaDrm_provideKeyResponse(AMediaDrm * mObj,const AMediaDrmScope * scope,const uint8_t * response,size_t responseSize,AMediaDrmKeySetId * keySetId)494 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
495         const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
496 
497     if (!mObj || mObj->mDrm == NULL) {
498         return AMEDIA_ERROR_INVALID_OBJECT;
499     }
500     if (!scope || !response || !responseSize || !keySetId) {
501         return AMEDIA_ERROR_INVALID_PARAMETER;
502     }
503 
504     List<idvec_t>::iterator iter;
505     if (!findId(mObj, *scope, iter)) {
506         return AMEDIA_DRM_SESSION_NOT_OPENED;
507     }
508     Vector<uint8_t> mdResponse;
509     mdResponse.appendArray(response, responseSize);
510 
511     Vector<uint8_t> mdKeySetId;
512     status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
513     if (status == OK) {
514         mObj->mIds.push_front(mdKeySetId);
515         List<idvec_t>::iterator iter = mObj->mIds.begin();
516         keySetId->ptr = iter->array();
517         keySetId->length = iter->size();
518     } else {
519         keySetId->ptr = NULL;
520         keySetId->length = 0;
521     }
522     return AMEDIA_OK;
523 }
524 
525 EXPORT
AMediaDrm_restoreKeys(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const AMediaDrmKeySetId * keySetId)526 media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
527         const AMediaDrmKeySetId *keySetId) {
528 
529     if (!mObj || mObj->mDrm == NULL) {
530         return AMEDIA_ERROR_INVALID_OBJECT;
531     }
532     if (!sessionId || !keySetId) {
533         return AMEDIA_ERROR_INVALID_PARAMETER;
534     }
535     List<idvec_t>::iterator iter;
536     if (!findId(mObj, *sessionId, iter)) {
537         return AMEDIA_DRM_SESSION_NOT_OPENED;
538     }
539     Vector<uint8_t> keySet;
540     keySet.appendArray(keySetId->ptr, keySetId->length);
541     return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
542 }
543 
544 EXPORT
AMediaDrm_removeKeys(AMediaDrm * mObj,const AMediaDrmSessionId * keySetId)545 media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
546     if (!mObj || mObj->mDrm == NULL) {
547         return AMEDIA_ERROR_INVALID_OBJECT;
548     }
549     if (!keySetId) {
550         return AMEDIA_ERROR_INVALID_PARAMETER;
551     }
552     List<idvec_t>::iterator iter;
553     status_t status;
554     if (!findId(mObj, *keySetId, iter)) {
555         Vector<uint8_t> keySet;
556         keySet.appendArray(keySetId->ptr, keySetId->length);
557         status = mObj->mDrm->removeKeys(keySet);
558     } else {
559         status = mObj->mDrm->removeKeys(*iter);
560         mObj->mIds.erase(iter);
561     }
562     return translateStatus(status);
563 }
564 
565 EXPORT
AMediaDrm_queryKeyStatus(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,AMediaDrmKeyValue * keyValuePairs,size_t * numPairs)566 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
567         AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
568 
569     if (!mObj || mObj->mDrm == NULL) {
570         return AMEDIA_ERROR_INVALID_OBJECT;
571     }
572     if (!sessionId || !numPairs) {
573         return AMEDIA_ERROR_INVALID_PARAMETER;
574     }
575     List<idvec_t>::iterator iter;
576     if (!findId(mObj, *sessionId, iter)) {
577         return AMEDIA_DRM_SESSION_NOT_OPENED;
578     }
579 
580     status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
581     if (status != OK) {
582         *numPairs = 0;
583         return translateStatus(status);
584     }
585 
586     if (mObj->mQueryResults.size() > *numPairs) {
587         *numPairs = mObj->mQueryResults.size();
588         return AMEDIA_DRM_SHORT_BUFFER;
589     }
590 
591     for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
592         keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
593         keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string();
594     }
595     *numPairs = mObj->mQueryResults.size();
596     return AMEDIA_OK;
597 }
598 
599 EXPORT
AMediaDrm_getProvisionRequest(AMediaDrm * mObj,const uint8_t ** provisionRequest,size_t * provisionRequestSize,const char ** serverUrl)600 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
601         size_t *provisionRequestSize, const char **serverUrl) {
602     if (!mObj || mObj->mDrm == NULL) {
603         return AMEDIA_ERROR_INVALID_OBJECT;
604     }
605     if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
606         return AMEDIA_ERROR_INVALID_PARAMETER;
607     }
608 
609     status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
610             mObj->mProvisionRequest, mObj->mProvisionUrl);
611     if (status != OK) {
612         return translateStatus(status);
613     } else {
614         *provisionRequest = mObj->mProvisionRequest.array();
615         *provisionRequestSize = mObj->mProvisionRequest.size();
616         *serverUrl = mObj->mProvisionUrl.string();
617     }
618     return AMEDIA_OK;
619 }
620 
621 EXPORT
AMediaDrm_provideProvisionResponse(AMediaDrm * mObj,const uint8_t * response,size_t responseSize)622 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
623         const uint8_t *response, size_t responseSize) {
624     if (!mObj || mObj->mDrm == NULL) {
625         return AMEDIA_ERROR_INVALID_OBJECT;
626     }
627     if (!response || !responseSize) {
628         return AMEDIA_ERROR_INVALID_PARAMETER;
629     }
630 
631     Vector<uint8_t> mdResponse;
632     mdResponse.appendArray(response, responseSize);
633 
634     Vector<uint8_t> unused;
635     return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
636 }
637 
638 EXPORT
AMediaDrm_getSecureStops(AMediaDrm * mObj,AMediaDrmSecureStop * secureStops,size_t * numSecureStops)639 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
640         AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
641 
642     if (!mObj || mObj->mDrm == NULL) {
643         return AMEDIA_ERROR_INVALID_OBJECT;
644     }
645     if (!numSecureStops) {
646         return AMEDIA_ERROR_INVALID_PARAMETER;
647     }
648     status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
649     if (status != OK) {
650         *numSecureStops = 0;
651         return translateStatus(status);
652     }
653     if (*numSecureStops < mObj->mSecureStops.size()) {
654         return AMEDIA_DRM_SHORT_BUFFER;
655     }
656     List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
657     size_t i = 0;
658     while (iter != mObj->mSecureStops.end()) {
659         secureStops[i].ptr = iter->array();
660         secureStops[i].length = iter->size();
661         ++iter;
662         ++i;
663     }
664     *numSecureStops = mObj->mSecureStops.size();
665     return AMEDIA_OK;
666 }
667 
668 EXPORT
AMediaDrm_releaseSecureStops(AMediaDrm * mObj,const AMediaDrmSecureStop * ssRelease)669 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
670         const AMediaDrmSecureStop *ssRelease) {
671 
672     if (!mObj || mObj->mDrm == NULL) {
673         return AMEDIA_ERROR_INVALID_OBJECT;
674     }
675     if (!ssRelease) {
676         return AMEDIA_ERROR_INVALID_PARAMETER;
677     }
678 
679     Vector<uint8_t> release;
680     release.appendArray(ssRelease->ptr, ssRelease->length);
681     return translateStatus(mObj->mDrm->releaseSecureStops(release));
682 }
683 
684 
685 EXPORT
AMediaDrm_getPropertyString(AMediaDrm * mObj,const char * propertyName,const char ** propertyValue)686 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
687         const char **propertyValue) {
688 
689     if (!mObj || mObj->mDrm == NULL) {
690         return AMEDIA_ERROR_INVALID_OBJECT;
691     }
692     if (!propertyName || !propertyValue) {
693         return AMEDIA_ERROR_INVALID_PARAMETER;
694     }
695 
696     status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
697             mObj->mPropertyString);
698 
699     if (status == OK) {
700         *propertyValue = mObj->mPropertyString.string();
701     } else {
702         *propertyValue = NULL;
703     }
704     return translateStatus(status);
705 }
706 
707 EXPORT
AMediaDrm_getPropertyByteArray(AMediaDrm * mObj,const char * propertyName,AMediaDrmByteArray * propertyValue)708 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
709         const char *propertyName, AMediaDrmByteArray *propertyValue) {
710     if (!mObj || mObj->mDrm == NULL) {
711         return AMEDIA_ERROR_INVALID_OBJECT;
712     }
713     if (!propertyName || !propertyValue) {
714         return AMEDIA_ERROR_INVALID_PARAMETER;
715     }
716 
717     status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
718             mObj->mPropertyByteArray);
719 
720     if (status == OK) {
721         propertyValue->ptr = mObj->mPropertyByteArray.array();
722         propertyValue->length = mObj->mPropertyByteArray.size();
723     } else {
724         propertyValue->ptr = NULL;
725         propertyValue->length = 0;
726     }
727     return translateStatus(status);
728 }
729 
730 EXPORT
AMediaDrm_setPropertyString(AMediaDrm * mObj,const char * propertyName,const char * value)731 media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
732         const char *propertyName, const char *value) {
733     if (!mObj || mObj->mDrm == NULL) {
734         return AMEDIA_ERROR_INVALID_OBJECT;
735     }
736 
737     return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
738                     String8(value)));
739 }
740 
741 EXPORT
AMediaDrm_setPropertyByteArray(AMediaDrm * mObj,const char * propertyName,const uint8_t * value,size_t valueSize)742 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
743         const char *propertyName, const uint8_t *value, size_t valueSize) {
744 
745     Vector<uint8_t> byteArray;
746     byteArray.appendArray(value, valueSize);
747 
748     return translateStatus(mObj->mDrm->setPropertyByteArray(String8(propertyName),
749                     byteArray));
750 }
751 
752 
encrypt_decrypt_common(AMediaDrm * mObj,const AMediaDrmSessionId & sessionId,const char * cipherAlgorithm,uint8_t * keyId,uint8_t * iv,const uint8_t * input,uint8_t * output,size_t dataSize,bool encrypt)753 static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
754         const AMediaDrmSessionId &sessionId,
755         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
756         const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
757 
758     if (!mObj || mObj->mDrm == NULL) {
759         return AMEDIA_ERROR_INVALID_OBJECT;
760     }
761     List<idvec_t>::iterator iter;
762     if (!findId(mObj, sessionId, iter)) {
763         return AMEDIA_DRM_SESSION_NOT_OPENED;
764     }
765 
766     status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
767     if (status != OK) {
768         return translateStatus(status);
769     }
770 
771     Vector<uint8_t> keyIdVec;
772     const size_t kKeyIdSize = 16;
773     keyIdVec.appendArray(keyId, kKeyIdSize);
774 
775     Vector<uint8_t> inputVec;
776     inputVec.appendArray(input, dataSize);
777 
778     Vector<uint8_t> ivVec;
779     const size_t kIvSize = 16;
780     ivVec.appendArray(iv, kIvSize);
781 
782     Vector<uint8_t> outputVec;
783     if (encrypt) {
784         status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
785     } else {
786         status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
787     }
788     if (status == OK) {
789         memcpy(output, outputVec.array(), outputVec.size());
790     }
791     return translateStatus(status);
792 }
793 
794 EXPORT
AMediaDrm_encrypt(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const char * cipherAlgorithm,uint8_t * keyId,uint8_t * iv,const uint8_t * input,uint8_t * output,size_t dataSize)795 media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
796         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
797         const uint8_t *input, uint8_t *output, size_t dataSize) {
798     if (!sessionId) {
799         return AMEDIA_ERROR_INVALID_PARAMETER;
800     }
801     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
802             input, output, dataSize, true);
803 }
804 
805 EXPORT
AMediaDrm_decrypt(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const char * cipherAlgorithm,uint8_t * keyId,uint8_t * iv,const uint8_t * input,uint8_t * output,size_t dataSize)806 media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
807         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
808         const uint8_t *input, uint8_t *output, size_t dataSize) {
809     if (!sessionId) {
810         return AMEDIA_ERROR_INVALID_PARAMETER;
811     }
812     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
813             input, output, dataSize, false);
814 }
815 
816 EXPORT
AMediaDrm_sign(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const char * macAlgorithm,uint8_t * keyId,uint8_t * message,size_t messageSize,uint8_t * signature,size_t * signatureSize)817 media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
818         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
819         uint8_t *signature, size_t *signatureSize) {
820 
821     if (!mObj || mObj->mDrm == NULL) {
822         return AMEDIA_ERROR_INVALID_OBJECT;
823     }
824     if (!sessionId) {
825         return AMEDIA_ERROR_INVALID_PARAMETER;
826     }
827     List<idvec_t>::iterator iter;
828     if (!findId(mObj, *sessionId, iter)) {
829         return AMEDIA_DRM_SESSION_NOT_OPENED;
830     }
831 
832     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
833     if (status != OK) {
834         return translateStatus(status);
835     }
836 
837     Vector<uint8_t> keyIdVec;
838     const size_t kKeyIdSize = 16;
839     keyIdVec.appendArray(keyId, kKeyIdSize);
840 
841     Vector<uint8_t> messageVec;
842     messageVec.appendArray(message, messageSize);
843 
844     Vector<uint8_t> signatureVec;
845     status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
846     if (signatureVec.size() > *signatureSize) {
847         return AMEDIA_DRM_SHORT_BUFFER;
848     }
849     if (status == OK) {
850         memcpy(signature, signatureVec.array(), signatureVec.size());
851     }
852     return translateStatus(status);
853 }
854 
855 EXPORT
AMediaDrm_verify(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const char * macAlgorithm,uint8_t * keyId,const uint8_t * message,size_t messageSize,const uint8_t * signature,size_t signatureSize)856 media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
857         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
858         const uint8_t *signature, size_t signatureSize) {
859 
860     if (!mObj || mObj->mDrm == NULL) {
861         return AMEDIA_ERROR_INVALID_OBJECT;
862     }
863     if (!sessionId) {
864         return AMEDIA_ERROR_INVALID_PARAMETER;
865     }
866     List<idvec_t>::iterator iter;
867     if (!findId(mObj, *sessionId, iter)) {
868         return AMEDIA_DRM_SESSION_NOT_OPENED;
869     }
870 
871     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
872     if (status != OK) {
873         return translateStatus(status);
874     }
875 
876     Vector<uint8_t> keyIdVec;
877     const size_t kKeyIdSize = 16;
878     keyIdVec.appendArray(keyId, kKeyIdSize);
879 
880     Vector<uint8_t> messageVec;
881     messageVec.appendArray(message, messageSize);
882 
883     Vector<uint8_t> signatureVec;
884     signatureVec.appendArray(signature, signatureSize);
885 
886     bool match;
887     status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
888     if (status == OK) {
889         return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
890     }
891     return translateStatus(status);
892 }
893 
894 } // extern "C"
895