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