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