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 mObj->mIds.push_front(session);
385 List<idvec_t>::iterator iter = mObj->mIds.begin();
386 sessionId->ptr = iter->array();
387 sessionId->length = iter->size();
388 }
389 return AMEDIA_OK;
390 }
391
392 EXPORT
AMediaDrm_closeSession(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId)393 media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
394 if (!mObj || mObj->mDrm == NULL) {
395 return AMEDIA_ERROR_INVALID_OBJECT;
396 }
397 if (!sessionId) {
398 return AMEDIA_ERROR_INVALID_PARAMETER;
399 }
400
401 List<idvec_t>::iterator iter;
402 if (!findId(mObj, *sessionId, iter)) {
403 return AMEDIA_DRM_SESSION_NOT_OPENED;
404 }
405 mObj->mDrm->closeSession(*iter);
406 mObj->mIds.erase(iter);
407 return AMEDIA_OK;
408 }
409
410 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)411 media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
412 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
413 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
414 const uint8_t **keyRequest, size_t *keyRequestSize) {
415
416 if (!mObj || mObj->mDrm == NULL) {
417 return AMEDIA_ERROR_INVALID_OBJECT;
418 }
419 if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
420 return AMEDIA_ERROR_INVALID_PARAMETER;
421 }
422
423 List<idvec_t>::iterator iter;
424 if (!findId(mObj, *scope, iter)) {
425 return AMEDIA_DRM_SESSION_NOT_OPENED;
426 }
427
428 Vector<uint8_t> mdInit;
429 mdInit.appendArray(init, initSize);
430 DrmPlugin::KeyType mdKeyType;
431 switch (keyType) {
432 case KEY_TYPE_STREAMING:
433 mdKeyType = DrmPlugin::kKeyType_Streaming;
434 break;
435 case KEY_TYPE_OFFLINE:
436 mdKeyType = DrmPlugin::kKeyType_Offline;
437 break;
438 case KEY_TYPE_RELEASE:
439 mdKeyType = DrmPlugin::kKeyType_Release;
440 break;
441 default:
442 return AMEDIA_ERROR_INVALID_PARAMETER;
443 }
444 KeyedVector<String8, String8> mdOptionalParameters;
445 for (size_t i = 0; i < numOptionalParameters; i++) {
446 mdOptionalParameters.add(String8(optionalParameters[i].mKey),
447 String8(optionalParameters[i].mValue));
448 }
449 String8 defaultUrl;
450 DrmPlugin::KeyRequestType keyRequestType;
451 mObj->mKeyRequest.clear();
452 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
453 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
454 &keyRequestType);
455 if (status != OK) {
456 return translateStatus(status);
457 } else {
458 *keyRequest = mObj->mKeyRequest.array();
459 *keyRequestSize = mObj->mKeyRequest.size();
460 }
461 return AMEDIA_OK;
462 }
463
464 EXPORT
AMediaDrm_provideKeyResponse(AMediaDrm * mObj,const AMediaDrmScope * scope,const uint8_t * response,size_t responseSize,AMediaDrmKeySetId * keySetId)465 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
466 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
467
468 if (!mObj || mObj->mDrm == NULL) {
469 return AMEDIA_ERROR_INVALID_OBJECT;
470 }
471 if (!scope || !response || !responseSize || !keySetId) {
472 return AMEDIA_ERROR_INVALID_PARAMETER;
473 }
474
475 List<idvec_t>::iterator iter;
476 if (!findId(mObj, *scope, iter)) {
477 return AMEDIA_DRM_SESSION_NOT_OPENED;
478 }
479 Vector<uint8_t> mdResponse;
480 mdResponse.appendArray(response, responseSize);
481
482 Vector<uint8_t> mdKeySetId;
483 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
484 if (status == OK) {
485 mObj->mIds.push_front(mdKeySetId);
486 List<idvec_t>::iterator iter = mObj->mIds.begin();
487 keySetId->ptr = iter->array();
488 keySetId->length = iter->size();
489 } else {
490 keySetId->ptr = NULL;
491 keySetId->length = 0;
492 }
493 return AMEDIA_OK;
494 }
495
496 EXPORT
AMediaDrm_restoreKeys(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const AMediaDrmKeySetId * keySetId)497 media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
498 const AMediaDrmKeySetId *keySetId) {
499
500 if (!mObj || mObj->mDrm == NULL) {
501 return AMEDIA_ERROR_INVALID_OBJECT;
502 }
503 if (!sessionId || !keySetId) {
504 return AMEDIA_ERROR_INVALID_PARAMETER;
505 }
506 List<idvec_t>::iterator iter;
507 if (!findId(mObj, *sessionId, iter)) {
508 return AMEDIA_DRM_SESSION_NOT_OPENED;
509 }
510 Vector<uint8_t> keySet;
511 keySet.appendArray(keySetId->ptr, keySetId->length);
512 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
513 }
514
515 EXPORT
AMediaDrm_removeKeys(AMediaDrm * mObj,const AMediaDrmSessionId * keySetId)516 media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
517 if (!mObj || mObj->mDrm == NULL) {
518 return AMEDIA_ERROR_INVALID_OBJECT;
519 }
520 if (!keySetId) {
521 return AMEDIA_ERROR_INVALID_PARAMETER;
522 }
523 List<idvec_t>::iterator iter;
524 status_t status;
525 if (!findId(mObj, *keySetId, iter)) {
526 Vector<uint8_t> keySet;
527 keySet.appendArray(keySetId->ptr, keySetId->length);
528 status = mObj->mDrm->removeKeys(keySet);
529 } else {
530 status = mObj->mDrm->removeKeys(*iter);
531 mObj->mIds.erase(iter);
532 }
533 return translateStatus(status);
534 }
535
536 EXPORT
AMediaDrm_queryKeyStatus(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,AMediaDrmKeyValue * keyValuePairs,size_t * numPairs)537 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
538 AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
539
540 if (!mObj || mObj->mDrm == NULL) {
541 return AMEDIA_ERROR_INVALID_OBJECT;
542 }
543 if (!sessionId || !numPairs) {
544 return AMEDIA_ERROR_INVALID_PARAMETER;
545 }
546 List<idvec_t>::iterator iter;
547 if (!findId(mObj, *sessionId, iter)) {
548 return AMEDIA_DRM_SESSION_NOT_OPENED;
549 }
550
551 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
552 if (status != OK) {
553 *numPairs = 0;
554 return translateStatus(status);
555 }
556
557 if (mObj->mQueryResults.size() > *numPairs) {
558 *numPairs = mObj->mQueryResults.size();
559 return AMEDIA_DRM_SHORT_BUFFER;
560 }
561
562 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
563 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
564 keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string();
565 }
566 *numPairs = mObj->mQueryResults.size();
567 return AMEDIA_OK;
568 }
569
570 EXPORT
AMediaDrm_getProvisionRequest(AMediaDrm * mObj,const uint8_t ** provisionRequest,size_t * provisionRequestSize,const char ** serverUrl)571 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
572 size_t *provisionRequestSize, const char **serverUrl) {
573 if (!mObj || mObj->mDrm == NULL) {
574 return AMEDIA_ERROR_INVALID_OBJECT;
575 }
576 if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
577 return AMEDIA_ERROR_INVALID_PARAMETER;
578 }
579
580 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
581 mObj->mProvisionRequest, mObj->mProvisionUrl);
582 if (status != OK) {
583 return translateStatus(status);
584 } else {
585 *provisionRequest = mObj->mProvisionRequest.array();
586 *provisionRequestSize = mObj->mProvisionRequest.size();
587 *serverUrl = mObj->mProvisionUrl.string();
588 }
589 return AMEDIA_OK;
590 }
591
592 EXPORT
AMediaDrm_provideProvisionResponse(AMediaDrm * mObj,const uint8_t * response,size_t responseSize)593 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
594 const uint8_t *response, size_t responseSize) {
595 if (!mObj || mObj->mDrm == NULL) {
596 return AMEDIA_ERROR_INVALID_OBJECT;
597 }
598 if (!response || !responseSize) {
599 return AMEDIA_ERROR_INVALID_PARAMETER;
600 }
601
602 Vector<uint8_t> mdResponse;
603 mdResponse.appendArray(response, responseSize);
604
605 Vector<uint8_t> unused;
606 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
607 }
608
609 EXPORT
AMediaDrm_getSecureStops(AMediaDrm * mObj,AMediaDrmSecureStop * secureStops,size_t * numSecureStops)610 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
611 AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
612
613 if (!mObj || mObj->mDrm == NULL) {
614 return AMEDIA_ERROR_INVALID_OBJECT;
615 }
616 if (!numSecureStops) {
617 return AMEDIA_ERROR_INVALID_PARAMETER;
618 }
619 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
620 if (status != OK) {
621 *numSecureStops = 0;
622 return translateStatus(status);
623 }
624 if (*numSecureStops < mObj->mSecureStops.size()) {
625 return AMEDIA_DRM_SHORT_BUFFER;
626 }
627 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
628 size_t i = 0;
629 while (iter != mObj->mSecureStops.end()) {
630 secureStops[i].ptr = iter->array();
631 secureStops[i].length = iter->size();
632 ++iter;
633 ++i;
634 }
635 *numSecureStops = mObj->mSecureStops.size();
636 return AMEDIA_OK;
637 }
638
639 EXPORT
AMediaDrm_releaseSecureStops(AMediaDrm * mObj,const AMediaDrmSecureStop * ssRelease)640 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
641 const AMediaDrmSecureStop *ssRelease) {
642
643 if (!mObj || mObj->mDrm == NULL) {
644 return AMEDIA_ERROR_INVALID_OBJECT;
645 }
646 if (!ssRelease) {
647 return AMEDIA_ERROR_INVALID_PARAMETER;
648 }
649
650 Vector<uint8_t> release;
651 release.appendArray(ssRelease->ptr, ssRelease->length);
652 return translateStatus(mObj->mDrm->releaseSecureStops(release));
653 }
654
655
656 EXPORT
AMediaDrm_getPropertyString(AMediaDrm * mObj,const char * propertyName,const char ** propertyValue)657 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
658 const char **propertyValue) {
659
660 if (!mObj || mObj->mDrm == NULL) {
661 return AMEDIA_ERROR_INVALID_OBJECT;
662 }
663 if (!propertyName || !propertyValue) {
664 return AMEDIA_ERROR_INVALID_PARAMETER;
665 }
666
667 status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
668 mObj->mPropertyString);
669
670 if (status == OK) {
671 *propertyValue = mObj->mPropertyString.string();
672 } else {
673 *propertyValue = NULL;
674 }
675 return translateStatus(status);
676 }
677
678 EXPORT
AMediaDrm_getPropertyByteArray(AMediaDrm * mObj,const char * propertyName,AMediaDrmByteArray * propertyValue)679 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
680 const char *propertyName, AMediaDrmByteArray *propertyValue) {
681 if (!mObj || mObj->mDrm == NULL) {
682 return AMEDIA_ERROR_INVALID_OBJECT;
683 }
684 if (!propertyName || !propertyValue) {
685 return AMEDIA_ERROR_INVALID_PARAMETER;
686 }
687
688 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
689 mObj->mPropertyByteArray);
690
691 if (status == OK) {
692 propertyValue->ptr = mObj->mPropertyByteArray.array();
693 propertyValue->length = mObj->mPropertyByteArray.size();
694 } else {
695 propertyValue->ptr = NULL;
696 propertyValue->length = 0;
697 }
698 return translateStatus(status);
699 }
700
701 EXPORT
AMediaDrm_setPropertyString(AMediaDrm * mObj,const char * propertyName,const char * value)702 media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
703 const char *propertyName, const char *value) {
704 if (!mObj || mObj->mDrm == NULL) {
705 return AMEDIA_ERROR_INVALID_OBJECT;
706 }
707
708 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
709 String8(value)));
710 }
711
712 EXPORT
AMediaDrm_setPropertyByteArray(AMediaDrm * mObj,const char * propertyName,const uint8_t * value,size_t valueSize)713 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
714 const char *propertyName, const uint8_t *value, size_t valueSize) {
715
716 Vector<uint8_t> byteArray;
717 byteArray.appendArray(value, valueSize);
718
719 return translateStatus(mObj->mDrm->setPropertyByteArray(String8(propertyName),
720 byteArray));
721 }
722
723
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)724 static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
725 const AMediaDrmSessionId &sessionId,
726 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
727 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
728
729 if (!mObj || mObj->mDrm == NULL) {
730 return AMEDIA_ERROR_INVALID_OBJECT;
731 }
732 List<idvec_t>::iterator iter;
733 if (!findId(mObj, sessionId, iter)) {
734 return AMEDIA_DRM_SESSION_NOT_OPENED;
735 }
736
737 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
738 if (status != OK) {
739 return translateStatus(status);
740 }
741
742 Vector<uint8_t> keyIdVec;
743 const size_t kKeyIdSize = 16;
744 keyIdVec.appendArray(keyId, kKeyIdSize);
745
746 Vector<uint8_t> inputVec;
747 inputVec.appendArray(input, dataSize);
748
749 Vector<uint8_t> ivVec;
750 const size_t kIvSize = 16;
751 ivVec.appendArray(iv, kIvSize);
752
753 Vector<uint8_t> outputVec;
754 if (encrypt) {
755 status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
756 } else {
757 status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
758 }
759 if (status == OK) {
760 memcpy(output, outputVec.array(), outputVec.size());
761 }
762 return translateStatus(status);
763 }
764
765 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)766 media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
767 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
768 const uint8_t *input, uint8_t *output, size_t dataSize) {
769 if (!sessionId) {
770 return AMEDIA_ERROR_INVALID_PARAMETER;
771 }
772 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
773 input, output, dataSize, true);
774 }
775
776 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)777 media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
778 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
779 const uint8_t *input, uint8_t *output, size_t dataSize) {
780 if (!sessionId) {
781 return AMEDIA_ERROR_INVALID_PARAMETER;
782 }
783 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
784 input, output, dataSize, false);
785 }
786
787 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)788 media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
789 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
790 uint8_t *signature, size_t *signatureSize) {
791
792 if (!mObj || mObj->mDrm == NULL) {
793 return AMEDIA_ERROR_INVALID_OBJECT;
794 }
795 if (!sessionId) {
796 return AMEDIA_ERROR_INVALID_PARAMETER;
797 }
798 List<idvec_t>::iterator iter;
799 if (!findId(mObj, *sessionId, iter)) {
800 return AMEDIA_DRM_SESSION_NOT_OPENED;
801 }
802
803 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
804 if (status != OK) {
805 return translateStatus(status);
806 }
807
808 Vector<uint8_t> keyIdVec;
809 const size_t kKeyIdSize = 16;
810 keyIdVec.appendArray(keyId, kKeyIdSize);
811
812 Vector<uint8_t> messageVec;
813 messageVec.appendArray(message, messageSize);
814
815 Vector<uint8_t> signatureVec;
816 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
817 if (signatureVec.size() > *signatureSize) {
818 return AMEDIA_DRM_SHORT_BUFFER;
819 }
820 if (status == OK) {
821 memcpy(signature, signatureVec.array(), signatureVec.size());
822 }
823 return translateStatus(status);
824 }
825
826 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)827 media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
828 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
829 const uint8_t *signature, size_t signatureSize) {
830
831 if (!mObj || mObj->mDrm == NULL) {
832 return AMEDIA_ERROR_INVALID_OBJECT;
833 }
834 if (!sessionId) {
835 return AMEDIA_ERROR_INVALID_PARAMETER;
836 }
837 List<idvec_t>::iterator iter;
838 if (!findId(mObj, *sessionId, iter)) {
839 return AMEDIA_DRM_SESSION_NOT_OPENED;
840 }
841
842 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
843 if (status != OK) {
844 return translateStatus(status);
845 }
846
847 Vector<uint8_t> keyIdVec;
848 const size_t kKeyIdSize = 16;
849 keyIdVec.appendArray(keyId, kKeyIdSize);
850
851 Vector<uint8_t> messageVec;
852 messageVec.appendArray(message, messageSize);
853
854 Vector<uint8_t> signatureVec;
855 signatureVec.appendArray(signature, signatureSize);
856
857 bool match;
858 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
859 if (status == OK) {
860 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
861 }
862 return translateStatus(status);
863 }
864
865 } // extern "C"
866