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