NdkMediaDrm.cpp revision 3425fd5a55dd31e261d2f2a9590c762d6d0a6b79
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 "NdkMediaDrm.h"
21
22#include <utils/Log.h>
23#include <utils/StrongPointer.h>
24#include <gui/Surface.h>
25
26#include <media/IDrm.h>
27#include <media/IDrmClient.h>
28#include <media/stagefright/MediaErrors.h>
29#include <binder/IServiceManager.h>
30#include <media/IMediaPlayerService.h>
31#include <ndk/NdkMediaCrypto.h>
32
33
34using namespace android;
35
36typedef Vector<uint8_t> idvec_t;
37
38struct AMediaDrm {
39    sp<IDrm> mDrm;
40    sp<IDrmClient> mDrmClient;
41    AMediaDrmEventListener mListener;
42    List<idvec_t> mIds;
43    KeyedVector<String8, String8> mQueryResults;
44    Vector<uint8_t> mKeyRequest;
45    Vector<uint8_t> mProvisionRequest;
46    String8 mProvisionUrl;
47    String8 mPropertyString;
48    Vector<uint8_t> mPropertyByteArray;
49    List<Vector<uint8_t> > mSecureStops;
50};
51
52extern "C" {
53
54static mediadrm_status_t translateStatus(status_t status) {
55    mediadrm_status_t result = MEDIADRM_UNKNOWN_ERROR;
56    switch (status) {
57        case OK:
58            result = MEDIADRM_OK;
59            break;
60        case android::ERROR_DRM_NOT_PROVISIONED:
61            result = MEDIADRM_NOT_PROVISIONED_ERROR;
62            break;
63        case android::ERROR_DRM_RESOURCE_BUSY:
64            result = MEDIADRM_RESOURCE_BUSY_ERROR;
65            break;
66        case android::ERROR_DRM_DEVICE_REVOKED:
67            result = MEDIADRM_DEVICE_REVOKED_ERROR;
68            break;
69        case android::ERROR_DRM_CANNOT_HANDLE:
70            result = MEDIADRM_INVALID_PARAMETER_ERROR;
71            break;
72        case android::ERROR_DRM_TAMPER_DETECTED:
73            result = MEDIADRM_TAMPER_DETECTED_ERROR;
74            break;
75        case android::ERROR_DRM_SESSION_NOT_OPENED:
76            result = MEDIADRM_SESSION_NOT_OPENED_ERROR;
77            break;
78        case android::ERROR_DRM_NO_LICENSE:
79            result = MEDIADRM_NEED_KEY_ERROR;
80            break;
81        case android::ERROR_DRM_LICENSE_EXPIRED:
82            result = MEDIADRM_LICENSE_EXPIRED_ERROR;
83            break;
84        default:
85            result = MEDIADRM_UNKNOWN_ERROR;
86            break;
87    }
88    return result;
89}
90
91static sp<IDrm> CreateDrm() {
92    sp<IServiceManager> sm = defaultServiceManager();
93
94    sp<IBinder> binder =
95        sm->getService(String16("media.player"));
96
97    sp<IMediaPlayerService> service =
98        interface_cast<IMediaPlayerService>(binder);
99
100    if (service == NULL) {
101        return NULL;
102    }
103
104    sp<IDrm> drm = service->makeDrm();
105
106    if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
107        return NULL;
108    }
109
110    return drm;
111}
112
113
114static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
115    sp<IDrm> drm = CreateDrm();
116
117    if (drm == NULL) {
118        return NULL;
119    }
120
121    status_t err = drm->createPlugin(uuid);
122
123    if (err != OK) {
124        return NULL;
125    }
126
127    return drm;
128}
129
130EXPORT
131bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
132    sp<IDrm> drm = CreateDrm();
133
134    if (drm == NULL) {
135        return false;
136    }
137
138    String8 mimeStr = mimeType ? String8(mimeType) : String8("");
139    return drm->isCryptoSchemeSupported(uuid, mimeStr);
140}
141
142EXPORT
143AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
144    AMediaDrm *mObj = new AMediaDrm();
145    mObj->mDrm = CreateDrmFromUUID(uuid);
146    return mObj;
147}
148
149EXPORT
150void AMediaDrm_release(AMediaDrm *mObj) {
151    if (mObj->mDrm != NULL) {
152        mObj->mDrm->setListener(NULL);
153        mObj->mDrm->destroyPlugin();
154        mObj->mDrm.clear();
155    }
156    delete mObj;
157}
158
159#if 0
160void AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
161    mObj->mListener = listener;
162}
163#endif
164
165
166static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
167    iter = mObj->mIds.begin();
168    while (iter != mObj->mIds.end()) {
169        if (iter->array() == id.ptr && iter->size() == id.length) {
170            return true;
171        }
172    }
173    return false;
174}
175
176EXPORT
177mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) {
178    if (!mObj || mObj->mDrm == NULL) {
179        return MEDIADRM_INVALID_OBJECT_ERROR;
180    }
181    Vector<uint8_t> session;
182    status_t status = mObj->mDrm->openSession(session);
183    if (status == OK) {
184        mObj->mIds.push_front(session);
185        List<idvec_t>::iterator iter = mObj->mIds.begin();
186        sessionId.ptr = iter->array();
187        sessionId.length = iter->size();
188    }
189    return MEDIADRM_OK;
190}
191
192EXPORT
193mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) {
194    if (!mObj || mObj->mDrm == NULL) {
195        return MEDIADRM_INVALID_OBJECT_ERROR;
196    }
197
198    List<idvec_t>::iterator iter;
199    if (!findId(mObj, sessionId, iter)) {
200        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
201    }
202    mObj->mDrm->closeSession(*iter);
203    mObj->mIds.erase(iter);
204    return MEDIADRM_OK;
205}
206
207EXPORT
208mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope,
209        const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
210        const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
211        const uint8_t *&keyRequest, size_t &keyRequestSize) {
212
213    if (!mObj || mObj->mDrm == NULL) {
214        return MEDIADRM_INVALID_OBJECT_ERROR;
215    }
216    if (!mimeType) {
217        return MEDIADRM_INVALID_PARAMETER_ERROR;
218    }
219
220    List<idvec_t>::iterator iter;
221    if (!findId(mObj, scope, iter)) {
222        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
223    }
224
225    Vector<uint8_t> mdInit;
226    mdInit.appendArray(init, initSize);
227    DrmPlugin::KeyType mdKeyType;
228    switch (keyType) {
229        case KEY_TYPE_STREAMING:
230            mdKeyType = DrmPlugin::kKeyType_Streaming;
231            break;
232        case KEY_TYPE_OFFLINE:
233            mdKeyType = DrmPlugin::kKeyType_Offline;
234            break;
235        case KEY_TYPE_RELEASE:
236            mdKeyType = DrmPlugin::kKeyType_Release;
237            break;
238        default:
239            return MEDIADRM_INVALID_PARAMETER_ERROR;
240    }
241    KeyedVector<String8, String8> mdOptionalParameters;
242    for (size_t i = 0; i < numOptionalParameters; i++) {
243        mdOptionalParameters.add(String8(optionalParameters[i].mKey),
244                String8(optionalParameters[i].mValue));
245    }
246    String8 defaultUrl;
247    status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
248            mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl);
249    if (status != OK) {
250        return translateStatus(status);
251    } else {
252        keyRequest = mObj->mKeyRequest.array();
253        keyRequestSize = mObj->mKeyRequest.size();
254    }
255    return MEDIADRM_OK;
256}
257
258EXPORT
259mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope,
260        const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) {
261
262    if (!mObj || mObj->mDrm == NULL) {
263        return MEDIADRM_INVALID_OBJECT_ERROR;
264    }
265    if (!response || !responseSize) {
266        return MEDIADRM_INVALID_PARAMETER_ERROR;
267    }
268
269    List<idvec_t>::iterator iter;
270    if (!findId(mObj, scope, iter)) {
271        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
272    }
273    Vector<uint8_t> mdResponse;
274    mdResponse.appendArray(response, responseSize);
275
276    Vector<uint8_t> mdKeySetId;
277    status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
278    if (status == OK) {
279        mObj->mIds.push_front(mdKeySetId);
280        List<idvec_t>::iterator iter = mObj->mIds.begin();
281        keySetId.ptr = iter->array();
282        keySetId.length = iter->size();
283    } else {
284        keySetId.ptr = NULL;
285        keySetId.length = 0;
286    }
287    return MEDIADRM_OK;
288}
289
290EXPORT
291mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
292        const AMediaDrmKeySetId &keySetId) {
293
294    if (!mObj || mObj->mDrm == NULL) {
295        return MEDIADRM_INVALID_OBJECT_ERROR;
296    }
297    List<idvec_t>::iterator iter;
298    if (!findId(mObj, sessionId, iter)) {
299        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
300    }
301    Vector<uint8_t> keySet;
302    keySet.appendArray(keySetId.ptr, keySetId.length);
303    return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
304}
305
306EXPORT
307mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) {
308    if (!mObj || mObj->mDrm == NULL) {
309        return MEDIADRM_INVALID_OBJECT_ERROR;
310    }
311    List<idvec_t>::iterator iter;
312    status_t status;
313    if (!findId(mObj, keySetId, iter)) {
314        Vector<uint8_t> keySet;
315        keySet.appendArray(keySetId.ptr, keySetId.length);
316        status = mObj->mDrm->removeKeys(keySet);
317    } else {
318        status = mObj->mDrm->removeKeys(*iter);
319        mObj->mIds.erase(iter);
320    }
321    return translateStatus(status);
322}
323
324EXPORT
325mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
326        AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) {
327
328    if (!mObj || mObj->mDrm == NULL) {
329        return MEDIADRM_INVALID_OBJECT_ERROR;
330    }
331    List<idvec_t>::iterator iter;
332    if (!findId(mObj, sessionId, iter)) {
333        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
334    }
335
336    status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
337    if (status != OK) {
338        numPairs = 0;
339        return translateStatus(status);
340    }
341
342    if (mObj->mQueryResults.size() > numPairs) {
343        numPairs = mObj->mQueryResults.size();
344        return MEDIADRM_SHORT_BUFFER;
345    }
346
347    for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
348        keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
349        keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
350    }
351    numPairs = mObj->mQueryResults.size();
352    return MEDIADRM_OK;
353}
354
355EXPORT
356mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest,
357        size_t &provisionRequestSize, const char *&serverUrl) {
358    if (!mObj || mObj->mDrm == NULL) {
359        return MEDIADRM_INVALID_OBJECT_ERROR;
360    }
361    if (!provisionRequestSize || !serverUrl) {
362        return MEDIADRM_INVALID_PARAMETER_ERROR;
363    }
364
365    status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
366            mObj->mProvisionRequest, mObj->mProvisionUrl);
367    if (status != OK) {
368        return translateStatus(status);
369    } else {
370        provisionRequest = mObj->mProvisionRequest.array();
371        provisionRequestSize = mObj->mProvisionRequest.size();
372        serverUrl = mObj->mProvisionUrl.string();
373    }
374    return MEDIADRM_OK;
375}
376
377EXPORT
378mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
379        const uint8_t *response, size_t responseSize) {
380    if (!mObj || mObj->mDrm == NULL) {
381        return MEDIADRM_INVALID_OBJECT_ERROR;
382    }
383    if (!response || !responseSize) {
384        return MEDIADRM_INVALID_PARAMETER_ERROR;
385    }
386
387    Vector<uint8_t> mdResponse;
388    mdResponse.appendArray(response, responseSize);
389
390    Vector<uint8_t> unused;
391    return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
392}
393
394EXPORT
395mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
396        AMediaDrmSecureStop *secureStops, size_t &numSecureStops) {
397
398    if (!mObj || mObj->mDrm == NULL) {
399        return MEDIADRM_INVALID_OBJECT_ERROR;
400    }
401    status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
402    if (status != OK) {
403        numSecureStops = 0;
404        return translateStatus(status);
405    }
406    if (numSecureStops < mObj->mSecureStops.size()) {
407        return MEDIADRM_SHORT_BUFFER;
408    }
409    List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
410    size_t i = 0;
411    while (iter != mObj->mSecureStops.end()) {
412        secureStops[i].ptr = iter->array();
413        secureStops[i].length = iter->size();
414        ++iter;
415        ++i;
416    }
417    numSecureStops = mObj->mSecureStops.size();
418    return MEDIADRM_OK;
419}
420
421EXPORT
422mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
423        const AMediaDrmSecureStop &ssRelease) {
424
425    if (!mObj || mObj->mDrm == NULL) {
426        return MEDIADRM_INVALID_OBJECT_ERROR;
427    }
428
429    Vector<uint8_t> release;
430    release.appendArray(ssRelease.ptr, ssRelease.length);
431    return translateStatus(mObj->mDrm->releaseSecureStops(release));
432}
433
434
435EXPORT
436mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
437        const char *&propertyValue) {
438
439    if (!mObj || mObj->mDrm == NULL) {
440        return MEDIADRM_INVALID_OBJECT_ERROR;
441    }
442
443    status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
444            mObj->mPropertyString);
445
446    if (status == OK) {
447        propertyValue = mObj->mPropertyString.string();
448    } else {
449        propertyValue = NULL;
450    }
451    return translateStatus(status);
452}
453
454EXPORT
455mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
456        const char *propertyName, AMediaDrmByteArray &propertyValue) {
457    if (!mObj || mObj->mDrm == NULL) {
458        return MEDIADRM_INVALID_OBJECT_ERROR;
459    }
460
461    status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
462            mObj->mPropertyByteArray);
463
464    if (status == OK) {
465        propertyValue.ptr = mObj->mPropertyByteArray.array();
466        propertyValue.length = mObj->mPropertyByteArray.size();
467    } else {
468        propertyValue.ptr = NULL;
469        propertyValue.length = 0;
470    }
471    return translateStatus(status);
472}
473
474EXPORT
475mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
476        const char *propertyName, const char *value) {
477    if (!mObj || mObj->mDrm == NULL) {
478        return MEDIADRM_INVALID_OBJECT_ERROR;
479    }
480
481    return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
482                    String8(value)));
483}
484
485EXPORT
486mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
487        const char *propertyName, const uint8_t *value, size_t valueSize) {
488
489    Vector<uint8_t> byteArray;
490    byteArray.appendArray(value, valueSize);
491
492    return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
493                    byteArray));
494}
495
496
497static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj,
498        const AMediaDrmSessionId &sessionId,
499        const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
500        const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
501
502    if (!mObj || mObj->mDrm == NULL) {
503        return MEDIADRM_INVALID_OBJECT_ERROR;
504    }
505    List<idvec_t>::iterator iter;
506    if (!findId(mObj, sessionId, iter)) {
507        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
508    }
509
510    status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
511    if (status != OK) {
512        return translateStatus(status);
513    }
514
515    Vector<uint8_t> keyIdVec;
516    const size_t kKeyIdSize = 16;
517    keyIdVec.appendArray(keyId, kKeyIdSize);
518
519    Vector<uint8_t> inputVec;
520    inputVec.appendArray(input, dataSize);
521
522    Vector<uint8_t> ivVec;
523    const size_t kIvSize = 16;
524    ivVec.appendArray(iv, kIvSize);
525
526    Vector<uint8_t> outputVec;
527    if (encrypt) {
528        status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
529    } else {
530        status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
531    }
532    if (status == OK) {
533        memcpy(output, outputVec.array(), outputVec.size());
534    }
535    return translateStatus(status);
536}
537
538EXPORT
539mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
540        const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
541        const uint8_t *input, uint8_t *output, size_t dataSize) {
542    return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
543            input, output, dataSize, true);
544}
545
546EXPORT
547mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
548        const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
549        const uint8_t *input, uint8_t *output, size_t dataSize) {
550    return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
551            input, output, dataSize, false);
552}
553
554EXPORT
555mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
556        const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
557        uint8_t *signature, size_t *signatureSize) {
558
559    if (!mObj || mObj->mDrm == NULL) {
560        return MEDIADRM_INVALID_OBJECT_ERROR;
561    }
562    List<idvec_t>::iterator iter;
563    if (!findId(mObj, sessionId, iter)) {
564        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
565    }
566
567    status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
568    if (status != OK) {
569        return translateStatus(status);
570    }
571
572    Vector<uint8_t> keyIdVec;
573    const size_t kKeyIdSize = 16;
574    keyIdVec.appendArray(keyId, kKeyIdSize);
575
576    Vector<uint8_t> messageVec;
577    messageVec.appendArray(message, messageSize);
578
579    Vector<uint8_t> signatureVec;
580    status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
581    if (signatureVec.size() > *signatureSize) {
582        return MEDIADRM_SHORT_BUFFER;
583    }
584    if (status == OK) {
585        memcpy(signature, signatureVec.array(), signatureVec.size());
586    }
587    return translateStatus(status);
588}
589
590EXPORT
591mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
592        const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
593        const uint8_t *signature, size_t signatureSize) {
594
595    if (!mObj || mObj->mDrm == NULL) {
596        return MEDIADRM_INVALID_OBJECT_ERROR;
597    }
598    List<idvec_t>::iterator iter;
599    if (!findId(mObj, sessionId, iter)) {
600        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
601    }
602
603    status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
604    if (status != OK) {
605        return translateStatus(status);
606    }
607
608    Vector<uint8_t> keyIdVec;
609    const size_t kKeyIdSize = 16;
610    keyIdVec.appendArray(keyId, kKeyIdSize);
611
612    Vector<uint8_t> messageVec;
613    messageVec.appendArray(message, messageSize);
614
615    Vector<uint8_t> signatureVec;
616    signatureVec.appendArray(signature, signatureSize);
617
618    bool match;
619    status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
620    if (status == OK) {
621        return match ? MEDIADRM_OK : MEDIADRM_VERIFY_FAILED;
622    }
623    return translateStatus(status);
624}
625
626} // extern "C"
627
628