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 <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 <media/IDrm.h>
     33 #include <media/IDrmClient.h>
     34 #include <media/stagefright/MediaErrors.h>
     35 #include <binder/IServiceManager.h>
     36 #include <media/IMediaDrmService.h>
     37 #include <media/NdkMediaCrypto.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:
     53     DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj),
     54             mEventListener(listener), mExpirationUpdateListener(NULL), mKeysChangeListener(NULL) {}
     55 
     56     DrmListener(AMediaDrm *obj, AMediaDrmExpirationUpdateListener listener) : mObj(obj),
     57             mEventListener(NULL), mExpirationUpdateListener(listener), mKeysChangeListener(NULL) {}
     58 
     59     DrmListener(AMediaDrm *obj, AMediaDrmKeysChangeListener listener) : mObj(obj),
     60             mEventListener(NULL), mExpirationUpdateListener(NULL), mKeysChangeListener(listener) {}
     61 
     62     void setEventListener(AMediaDrmEventListener listener) {
     63         mEventListener = listener;
     64     }
     65 
     66     void setExpirationUpdateListener(AMediaDrmExpirationUpdateListener listener) {
     67         mExpirationUpdateListener = listener;
     68     }
     69 
     70     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 
     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 
    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 
    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 
    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 
    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 
    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
    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
    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
    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
    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
    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
    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 
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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
    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
    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
    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
    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