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