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