Home | History | Annotate | Download | only in ndk
      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 "NdkMediaDrm.h"
     21 
     22 #include <cutils/properties.h>
     23 #include <utils/Log.h>
     24 #include <utils/StrongPointer.h>
     25 #include <gui/Surface.h>
     26 
     27 #include <media/IDrm.h>
     28 #include <media/IDrmClient.h>
     29 #include <media/stagefright/MediaErrors.h>
     30 #include <binder/IServiceManager.h>
     31 #include <media/IMediaDrmService.h>
     32 #include <ndk/NdkMediaCrypto.h>
     33 
     34 
     35 using namespace android;
     36 
     37 typedef Vector<uint8_t> idvec_t;
     38 
     39 struct DrmListener: virtual public BnDrmClient
     40 {
     41 private:
     42     AMediaDrm *mObj;
     43     AMediaDrmEventListener mListener;
     44 
     45 public:
     46     DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
     47     void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
     48 };
     49 
     50 struct AMediaDrm {
     51     sp<IDrm> mDrm;
     52     sp<IDrmClient> mDrmClient;
     53     List<idvec_t> mIds;
     54     KeyedVector<String8, String8> mQueryResults;
     55     Vector<uint8_t> mKeyRequest;
     56     Vector<uint8_t> mProvisionRequest;
     57     String8 mProvisionUrl;
     58     String8 mPropertyString;
     59     Vector<uint8_t> mPropertyByteArray;
     60     List<Vector<uint8_t> > mSecureStops;
     61     sp<DrmListener> mListener;
     62 };
     63 
     64 void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
     65     if (!mListener) {
     66         return;
     67     }
     68 
     69     AMediaDrmSessionId sessionId = {NULL, 0};
     70     int32_t sessionIdSize = obj->readInt32();
     71     if (sessionIdSize) {
     72         uint8_t *sessionIdData = new uint8_t[sessionIdSize];
     73         sessionId.ptr = sessionIdData;
     74         sessionId.length = sessionIdSize;
     75         obj->read(sessionIdData, sessionId.length);
     76     }
     77 
     78     int32_t dataSize = obj->readInt32();
     79     uint8_t *data = NULL;
     80     if (dataSize) {
     81         data = new uint8_t[dataSize];
     82         obj->read(data, dataSize);
     83     }
     84 
     85     // translate DrmPlugin event types into their NDK equivalents
     86     AMediaDrmEventType ndkEventType;
     87     switch(eventType) {
     88         case DrmPlugin::kDrmPluginEventProvisionRequired:
     89             ndkEventType = EVENT_PROVISION_REQUIRED;
     90             break;
     91         case DrmPlugin::kDrmPluginEventKeyNeeded:
     92             ndkEventType = EVENT_KEY_REQUIRED;
     93             break;
     94         case DrmPlugin::kDrmPluginEventKeyExpired:
     95             ndkEventType = EVENT_KEY_EXPIRED;
     96             break;
     97         case DrmPlugin::kDrmPluginEventVendorDefined:
     98             ndkEventType = EVENT_VENDOR_DEFINED;
     99             break;
    100         default:
    101             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
    102             return;
    103     }
    104 
    105     (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
    106 
    107     delete [] sessionId.ptr;
    108     delete [] data;
    109 }
    110 
    111 
    112 extern "C" {
    113 
    114 static media_status_t translateStatus(status_t status) {
    115     media_status_t result = AMEDIA_ERROR_UNKNOWN;
    116     switch (status) {
    117         case OK:
    118             result = AMEDIA_OK;
    119             break;
    120         case android::ERROR_DRM_NOT_PROVISIONED:
    121             result = AMEDIA_DRM_NOT_PROVISIONED;
    122             break;
    123         case android::ERROR_DRM_RESOURCE_BUSY:
    124             result = AMEDIA_DRM_RESOURCE_BUSY;
    125             break;
    126         case android::ERROR_DRM_DEVICE_REVOKED:
    127             result = AMEDIA_DRM_DEVICE_REVOKED;
    128             break;
    129         case android::ERROR_DRM_CANNOT_HANDLE:
    130             result = AMEDIA_ERROR_INVALID_PARAMETER;
    131             break;
    132         case android::ERROR_DRM_TAMPER_DETECTED:
    133             result = AMEDIA_DRM_TAMPER_DETECTED;
    134             break;
    135         case android::ERROR_DRM_SESSION_NOT_OPENED:
    136             result = AMEDIA_DRM_SESSION_NOT_OPENED;
    137             break;
    138         case android::ERROR_DRM_NO_LICENSE:
    139             result = AMEDIA_DRM_NEED_KEY;
    140             break;
    141         case android::ERROR_DRM_LICENSE_EXPIRED:
    142             result = AMEDIA_DRM_LICENSE_EXPIRED;
    143             break;
    144         default:
    145             break;
    146     }
    147     return result;
    148 }
    149 
    150 static sp<IDrm> CreateDrm() {
    151     sp<IServiceManager> sm = defaultServiceManager();
    152     sp<IBinder> binder = sm->getService(String16("media.drm"));
    153 
    154     sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
    155     if (service == NULL) {
    156         return NULL;
    157     }
    158 
    159     sp<IDrm> drm = service->makeDrm();
    160     if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
    161         return NULL;
    162     }
    163     return drm;
    164 }
    165 
    166 
    167 static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
    168     sp<IDrm> drm = CreateDrm();
    169 
    170     if (drm == NULL) {
    171         return NULL;
    172     }
    173 
    174     status_t err = drm->createPlugin(uuid);
    175 
    176     if (err != OK) {
    177         return NULL;
    178     }
    179 
    180     return drm;
    181 }
    182 
    183 EXPORT
    184 bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
    185     sp<IDrm> drm = CreateDrm();
    186 
    187     if (drm == NULL) {
    188         return false;
    189     }
    190 
    191     String8 mimeStr = mimeType ? String8(mimeType) : String8("");
    192     return drm->isCryptoSchemeSupported(uuid, mimeStr);
    193 }
    194 
    195 EXPORT
    196 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
    197     AMediaDrm *mObj = new AMediaDrm();
    198     mObj->mDrm = CreateDrmFromUUID(uuid);
    199     return mObj;
    200 }
    201 
    202 EXPORT
    203 void AMediaDrm_release(AMediaDrm *mObj) {
    204     if (mObj->mDrm != NULL) {
    205         mObj->mDrm->setListener(NULL);
    206         mObj->mDrm->destroyPlugin();
    207         mObj->mDrm.clear();
    208     }
    209     delete mObj;
    210 }
    211 
    212 EXPORT
    213 media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
    214     if (!mObj || mObj->mDrm == NULL) {
    215         return AMEDIA_ERROR_INVALID_OBJECT;
    216     }
    217     mObj->mListener = new DrmListener(mObj, listener);
    218     mObj->mDrm->setListener(mObj->mListener);
    219     return AMEDIA_OK;
    220 }
    221 
    222 
    223 static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
    224     iter = mObj->mIds.begin();
    225     while (iter != mObj->mIds.end()) {
    226         if (iter->array() == id.ptr && iter->size() == id.length) {
    227             return true;
    228         }
    229     }
    230     return false;
    231 }
    232 
    233 EXPORT
    234 media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) {
    235     if (!mObj || mObj->mDrm == NULL) {
    236         return AMEDIA_ERROR_INVALID_OBJECT;
    237     }
    238     if (!sessionId) {
    239         return AMEDIA_ERROR_INVALID_PARAMETER;
    240     }
    241     Vector<uint8_t> session;
    242     status_t status = mObj->mDrm->openSession(session);
    243     if (status == OK) {
    244         mObj->mIds.push_front(session);
    245         List<idvec_t>::iterator iter = mObj->mIds.begin();
    246         sessionId->ptr = iter->array();
    247         sessionId->length = iter->size();
    248     }
    249     return AMEDIA_OK;
    250 }
    251 
    252 EXPORT
    253 media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
    254     if (!mObj || mObj->mDrm == NULL) {
    255         return AMEDIA_ERROR_INVALID_OBJECT;
    256     }
    257     if (!sessionId) {
    258         return AMEDIA_ERROR_INVALID_PARAMETER;
    259     }
    260 
    261     List<idvec_t>::iterator iter;
    262     if (!findId(mObj, *sessionId, iter)) {
    263         return AMEDIA_DRM_SESSION_NOT_OPENED;
    264     }
    265     mObj->mDrm->closeSession(*iter);
    266     mObj->mIds.erase(iter);
    267     return AMEDIA_OK;
    268 }
    269 
    270 EXPORT
    271 media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
    272         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
    273         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
    274         const uint8_t **keyRequest, size_t *keyRequestSize) {
    275 
    276     if (!mObj || mObj->mDrm == NULL) {
    277         return AMEDIA_ERROR_INVALID_OBJECT;
    278     }
    279     if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
    280         return AMEDIA_ERROR_INVALID_PARAMETER;
    281     }
    282 
    283     List<idvec_t>::iterator iter;
    284     if (!findId(mObj, *scope, iter)) {
    285         return AMEDIA_DRM_SESSION_NOT_OPENED;
    286     }
    287 
    288     Vector<uint8_t> mdInit;
    289     mdInit.appendArray(init, initSize);
    290     DrmPlugin::KeyType mdKeyType;
    291     switch (keyType) {
    292         case KEY_TYPE_STREAMING:
    293             mdKeyType = DrmPlugin::kKeyType_Streaming;
    294             break;
    295         case KEY_TYPE_OFFLINE:
    296             mdKeyType = DrmPlugin::kKeyType_Offline;
    297             break;
    298         case KEY_TYPE_RELEASE:
    299             mdKeyType = DrmPlugin::kKeyType_Release;
    300             break;
    301         default:
    302             return AMEDIA_ERROR_INVALID_PARAMETER;
    303     }
    304     KeyedVector<String8, String8> mdOptionalParameters;
    305     for (size_t i = 0; i < numOptionalParameters; i++) {
    306         mdOptionalParameters.add(String8(optionalParameters[i].mKey),
    307                 String8(optionalParameters[i].mValue));
    308     }
    309     String8 defaultUrl;
    310     DrmPlugin::KeyRequestType keyRequestType;
    311     status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
    312             mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
    313             &keyRequestType);
    314     if (status != OK) {
    315         return translateStatus(status);
    316     } else {
    317         *keyRequest = mObj->mKeyRequest.array();
    318         *keyRequestSize = mObj->mKeyRequest.size();
    319     }
    320     return AMEDIA_OK;
    321 }
    322 
    323 EXPORT
    324 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
    325         const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
    326 
    327     if (!mObj || mObj->mDrm == NULL) {
    328         return AMEDIA_ERROR_INVALID_OBJECT;
    329     }
    330     if (!scope || !response || !responseSize || !keySetId) {
    331         return AMEDIA_ERROR_INVALID_PARAMETER;
    332     }
    333 
    334     List<idvec_t>::iterator iter;
    335     if (!findId(mObj, *scope, iter)) {
    336         return AMEDIA_DRM_SESSION_NOT_OPENED;
    337     }
    338     Vector<uint8_t> mdResponse;
    339     mdResponse.appendArray(response, responseSize);
    340 
    341     Vector<uint8_t> mdKeySetId;
    342     status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
    343     if (status == OK) {
    344         mObj->mIds.push_front(mdKeySetId);
    345         List<idvec_t>::iterator iter = mObj->mIds.begin();
    346         keySetId->ptr = iter->array();
    347         keySetId->length = iter->size();
    348     } else {
    349         keySetId->ptr = NULL;
    350         keySetId->length = 0;
    351     }
    352     return AMEDIA_OK;
    353 }
    354 
    355 EXPORT
    356 media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
    357         const AMediaDrmKeySetId *keySetId) {
    358 
    359     if (!mObj || mObj->mDrm == NULL) {
    360         return AMEDIA_ERROR_INVALID_OBJECT;
    361     }
    362     if (!sessionId || !keySetId) {
    363         return AMEDIA_ERROR_INVALID_PARAMETER;
    364     }
    365     List<idvec_t>::iterator iter;
    366     if (!findId(mObj, *sessionId, iter)) {
    367         return AMEDIA_DRM_SESSION_NOT_OPENED;
    368     }
    369     Vector<uint8_t> keySet;
    370     keySet.appendArray(keySetId->ptr, keySetId->length);
    371     return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
    372 }
    373 
    374 EXPORT
    375 media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
    376     if (!mObj || mObj->mDrm == NULL) {
    377         return AMEDIA_ERROR_INVALID_OBJECT;
    378     }
    379     if (!keySetId) {
    380         return AMEDIA_ERROR_INVALID_PARAMETER;
    381     }
    382     List<idvec_t>::iterator iter;
    383     status_t status;
    384     if (!findId(mObj, *keySetId, iter)) {
    385         Vector<uint8_t> keySet;
    386         keySet.appendArray(keySetId->ptr, keySetId->length);
    387         status = mObj->mDrm->removeKeys(keySet);
    388     } else {
    389         status = mObj->mDrm->removeKeys(*iter);
    390         mObj->mIds.erase(iter);
    391     }
    392     return translateStatus(status);
    393 }
    394 
    395 EXPORT
    396 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
    397         AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
    398 
    399     if (!mObj || mObj->mDrm == NULL) {
    400         return AMEDIA_ERROR_INVALID_OBJECT;
    401     }
    402     if (!sessionId || !numPairs) {
    403         return AMEDIA_ERROR_INVALID_PARAMETER;
    404     }
    405     List<idvec_t>::iterator iter;
    406     if (!findId(mObj, *sessionId, iter)) {
    407         return AMEDIA_DRM_SESSION_NOT_OPENED;
    408     }
    409 
    410     status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
    411     if (status != OK) {
    412         *numPairs = 0;
    413         return translateStatus(status);
    414     }
    415 
    416     if (mObj->mQueryResults.size() > *numPairs) {
    417         *numPairs = mObj->mQueryResults.size();
    418         return AMEDIA_DRM_SHORT_BUFFER;
    419     }
    420 
    421     for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
    422         keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
    423         keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
    424     }
    425     *numPairs = mObj->mQueryResults.size();
    426     return AMEDIA_OK;
    427 }
    428 
    429 EXPORT
    430 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
    431         size_t *provisionRequestSize, const char **serverUrl) {
    432     if (!mObj || mObj->mDrm == NULL) {
    433         return AMEDIA_ERROR_INVALID_OBJECT;
    434     }
    435     if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
    436         return AMEDIA_ERROR_INVALID_PARAMETER;
    437     }
    438 
    439     status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
    440             mObj->mProvisionRequest, mObj->mProvisionUrl);
    441     if (status != OK) {
    442         return translateStatus(status);
    443     } else {
    444         *provisionRequest = mObj->mProvisionRequest.array();
    445         *provisionRequestSize = mObj->mProvisionRequest.size();
    446         *serverUrl = mObj->mProvisionUrl.string();
    447     }
    448     return AMEDIA_OK;
    449 }
    450 
    451 EXPORT
    452 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
    453         const uint8_t *response, size_t responseSize) {
    454     if (!mObj || mObj->mDrm == NULL) {
    455         return AMEDIA_ERROR_INVALID_OBJECT;
    456     }
    457     if (!response || !responseSize) {
    458         return AMEDIA_ERROR_INVALID_PARAMETER;
    459     }
    460 
    461     Vector<uint8_t> mdResponse;
    462     mdResponse.appendArray(response, responseSize);
    463 
    464     Vector<uint8_t> unused;
    465     return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
    466 }
    467 
    468 EXPORT
    469 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
    470         AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
    471 
    472     if (!mObj || mObj->mDrm == NULL) {
    473         return AMEDIA_ERROR_INVALID_OBJECT;
    474     }
    475     if (!numSecureStops) {
    476         return AMEDIA_ERROR_INVALID_PARAMETER;
    477     }
    478     status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
    479     if (status != OK) {
    480         *numSecureStops = 0;
    481         return translateStatus(status);
    482     }
    483     if (*numSecureStops < mObj->mSecureStops.size()) {
    484         return AMEDIA_DRM_SHORT_BUFFER;
    485     }
    486     List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
    487     size_t i = 0;
    488     while (iter != mObj->mSecureStops.end()) {
    489         secureStops[i].ptr = iter->array();
    490         secureStops[i].length = iter->size();
    491         ++iter;
    492         ++i;
    493     }
    494     *numSecureStops = mObj->mSecureStops.size();
    495     return AMEDIA_OK;
    496 }
    497 
    498 EXPORT
    499 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
    500         const AMediaDrmSecureStop *ssRelease) {
    501 
    502     if (!mObj || mObj->mDrm == NULL) {
    503         return AMEDIA_ERROR_INVALID_OBJECT;
    504     }
    505     if (!ssRelease) {
    506         return AMEDIA_ERROR_INVALID_PARAMETER;
    507     }
    508 
    509     Vector<uint8_t> release;
    510     release.appendArray(ssRelease->ptr, ssRelease->length);
    511     return translateStatus(mObj->mDrm->releaseSecureStops(release));
    512 }
    513 
    514 
    515 EXPORT
    516 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
    517         const char **propertyValue) {
    518 
    519     if (!mObj || mObj->mDrm == NULL) {
    520         return AMEDIA_ERROR_INVALID_OBJECT;
    521     }
    522     if (!propertyName || !propertyValue) {
    523         return AMEDIA_ERROR_INVALID_PARAMETER;
    524     }
    525 
    526     status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
    527             mObj->mPropertyString);
    528 
    529     if (status == OK) {
    530         *propertyValue = mObj->mPropertyString.string();
    531     } else {
    532         *propertyValue = NULL;
    533     }
    534     return translateStatus(status);
    535 }
    536 
    537 EXPORT
    538 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
    539         const char *propertyName, AMediaDrmByteArray *propertyValue) {
    540     if (!mObj || mObj->mDrm == NULL) {
    541         return AMEDIA_ERROR_INVALID_OBJECT;
    542     }
    543     if (!propertyName || !propertyValue) {
    544         return AMEDIA_ERROR_INVALID_PARAMETER;
    545     }
    546 
    547     status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
    548             mObj->mPropertyByteArray);
    549 
    550     if (status == OK) {
    551         propertyValue->ptr = mObj->mPropertyByteArray.array();
    552         propertyValue->length = mObj->mPropertyByteArray.size();
    553     } else {
    554         propertyValue->ptr = NULL;
    555         propertyValue->length = 0;
    556     }
    557     return translateStatus(status);
    558 }
    559 
    560 EXPORT
    561 media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
    562         const char *propertyName, const char *value) {
    563     if (!mObj || mObj->mDrm == NULL) {
    564         return AMEDIA_ERROR_INVALID_OBJECT;
    565     }
    566 
    567     return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
    568                     String8(value)));
    569 }
    570 
    571 EXPORT
    572 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
    573         const char *propertyName, const uint8_t *value, size_t valueSize) {
    574 
    575     Vector<uint8_t> byteArray;
    576     byteArray.appendArray(value, valueSize);
    577 
    578     return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
    579                     byteArray));
    580 }
    581 
    582 
    583 static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
    584         const AMediaDrmSessionId &sessionId,
    585         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
    586         const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
    587 
    588     if (!mObj || mObj->mDrm == NULL) {
    589         return AMEDIA_ERROR_INVALID_OBJECT;
    590     }
    591     List<idvec_t>::iterator iter;
    592     if (!findId(mObj, sessionId, iter)) {
    593         return AMEDIA_DRM_SESSION_NOT_OPENED;
    594     }
    595 
    596     status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
    597     if (status != OK) {
    598         return translateStatus(status);
    599     }
    600 
    601     Vector<uint8_t> keyIdVec;
    602     const size_t kKeyIdSize = 16;
    603     keyIdVec.appendArray(keyId, kKeyIdSize);
    604 
    605     Vector<uint8_t> inputVec;
    606     inputVec.appendArray(input, dataSize);
    607 
    608     Vector<uint8_t> ivVec;
    609     const size_t kIvSize = 16;
    610     ivVec.appendArray(iv, kIvSize);
    611 
    612     Vector<uint8_t> outputVec;
    613     if (encrypt) {
    614         status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
    615     } else {
    616         status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
    617     }
    618     if (status == OK) {
    619         memcpy(output, outputVec.array(), outputVec.size());
    620     }
    621     return translateStatus(status);
    622 }
    623 
    624 EXPORT
    625 media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
    626         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
    627         const uint8_t *input, uint8_t *output, size_t dataSize) {
    628     if (!sessionId) {
    629         return AMEDIA_ERROR_INVALID_PARAMETER;
    630     }
    631     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
    632             input, output, dataSize, true);
    633 }
    634 
    635 EXPORT
    636 media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
    637         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
    638         const uint8_t *input, uint8_t *output, size_t dataSize) {
    639     if (!sessionId) {
    640         return AMEDIA_ERROR_INVALID_PARAMETER;
    641     }
    642     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
    643             input, output, dataSize, false);
    644 }
    645 
    646 EXPORT
    647 media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
    648         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
    649         uint8_t *signature, size_t *signatureSize) {
    650 
    651     if (!mObj || mObj->mDrm == NULL) {
    652         return AMEDIA_ERROR_INVALID_OBJECT;
    653     }
    654     if (!sessionId) {
    655         return AMEDIA_ERROR_INVALID_PARAMETER;
    656     }
    657     List<idvec_t>::iterator iter;
    658     if (!findId(mObj, *sessionId, iter)) {
    659         return AMEDIA_DRM_SESSION_NOT_OPENED;
    660     }
    661 
    662     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
    663     if (status != OK) {
    664         return translateStatus(status);
    665     }
    666 
    667     Vector<uint8_t> keyIdVec;
    668     const size_t kKeyIdSize = 16;
    669     keyIdVec.appendArray(keyId, kKeyIdSize);
    670 
    671     Vector<uint8_t> messageVec;
    672     messageVec.appendArray(message, messageSize);
    673 
    674     Vector<uint8_t> signatureVec;
    675     status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
    676     if (signatureVec.size() > *signatureSize) {
    677         return AMEDIA_DRM_SHORT_BUFFER;
    678     }
    679     if (status == OK) {
    680         memcpy(signature, signatureVec.array(), signatureVec.size());
    681     }
    682     return translateStatus(status);
    683 }
    684 
    685 EXPORT
    686 media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
    687         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
    688         const uint8_t *signature, size_t signatureSize) {
    689 
    690     if (!mObj || mObj->mDrm == NULL) {
    691         return AMEDIA_ERROR_INVALID_OBJECT;
    692     }
    693     if (!sessionId) {
    694         return AMEDIA_ERROR_INVALID_PARAMETER;
    695     }
    696     List<idvec_t>::iterator iter;
    697     if (!findId(mObj, *sessionId, iter)) {
    698         return AMEDIA_DRM_SESSION_NOT_OPENED;
    699     }
    700 
    701     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
    702     if (status != OK) {
    703         return translateStatus(status);
    704     }
    705 
    706     Vector<uint8_t> keyIdVec;
    707     const size_t kKeyIdSize = 16;
    708     keyIdVec.appendArray(keyId, kKeyIdSize);
    709 
    710     Vector<uint8_t> messageVec;
    711     messageVec.appendArray(message, messageSize);
    712 
    713     Vector<uint8_t> signatureVec;
    714     signatureVec.appendArray(signature, signatureSize);
    715 
    716     bool match;
    717     status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
    718     if (status == OK) {
    719         return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
    720     }
    721     return translateStatus(status);
    722 }
    723 
    724 } // extern "C"
    725