blob: 55974886379537fed4d1536ad207ee6fe05d8016 [file] [log] [blame]
Jeff Tinker497ca092014-05-13 09:31:15 -07001/*
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
Marco Nelissenc7a11b22014-05-30 10:13:25 -070017//#define LOG_NDEBUG 0
Jeff Tinker497ca092014-05-13 09:31:15 -070018#define LOG_TAG "NdkMediaDrm"
19
Colin Cross7e8d4ba2017-05-04 16:17:42 -070020#include <media/NdkMediaDrm.h>
Jeff Tinker497ca092014-05-13 09:31:15 -070021
Jeff Tinkera69729d2016-02-12 08:47:00 -080022#include <cutils/properties.h>
Jeff Tinker497ca092014-05-13 09:31:15 -070023#include <utils/Log.h>
24#include <utils/StrongPointer.h>
25#include <gui/Surface.h>
26
27#include <media/IDrm.h>
28#include <media/IDrmClient.h>
29#include <media/stagefright/MediaErrors.h>
30#include <binder/IServiceManager.h>
Jeff Tinkera69729d2016-02-12 08:47:00 -080031#include <media/IMediaDrmService.h>
Colin Cross7e8d4ba2017-05-04 16:17:42 -070032#include <media/NdkMediaCrypto.h>
Jeff Tinker497ca092014-05-13 09:31:15 -070033
34
35using namespace android;
36
37typedef Vector<uint8_t> idvec_t;
38
Jeff Tinker3305b992014-05-14 18:39:25 -070039struct DrmListener: virtual public BnDrmClient
40{
41private:
42 AMediaDrm *mObj;
43 AMediaDrmEventListener mListener;
44
45public:
46 DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
47 void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
48};
49
Jeff Tinker497ca092014-05-13 09:31:15 -070050struct AMediaDrm {
51 sp<IDrm> mDrm;
52 sp<IDrmClient> mDrmClient;
Jeff Tinker497ca092014-05-13 09:31:15 -070053 List<idvec_t> mIds;
54 KeyedVector<String8, String8> mQueryResults;
55 Vector<uint8_t> mKeyRequest;
56 Vector<uint8_t> mProvisionRequest;
57 String8 mProvisionUrl;
58 String8 mPropertyString;
59 Vector<uint8_t> mPropertyByteArray;
60 List<Vector<uint8_t> > mSecureStops;
Jeff Tinker3305b992014-05-14 18:39:25 -070061 sp<DrmListener> mListener;
Jeff Tinker497ca092014-05-13 09:31:15 -070062};
63
Jeff Tinker3305b992014-05-14 18:39:25 -070064void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
65 if (!mListener) {
66 return;
67 }
68
69 AMediaDrmSessionId sessionId = {NULL, 0};
70 int32_t sessionIdSize = obj->readInt32();
71 if (sessionIdSize) {
72 uint8_t *sessionIdData = new uint8_t[sessionIdSize];
73 sessionId.ptr = sessionIdData;
74 sessionId.length = sessionIdSize;
75 obj->read(sessionIdData, sessionId.length);
76 }
77
78 int32_t dataSize = obj->readInt32();
79 uint8_t *data = NULL;
80 if (dataSize) {
81 data = new uint8_t[dataSize];
82 obj->read(data, dataSize);
83 }
84
85 // translate DrmPlugin event types into their NDK equivalents
86 AMediaDrmEventType ndkEventType;
87 switch(eventType) {
88 case DrmPlugin::kDrmPluginEventProvisionRequired:
89 ndkEventType = EVENT_PROVISION_REQUIRED;
90 break;
91 case DrmPlugin::kDrmPluginEventKeyNeeded:
92 ndkEventType = EVENT_KEY_REQUIRED;
93 break;
94 case DrmPlugin::kDrmPluginEventKeyExpired:
95 ndkEventType = EVENT_KEY_EXPIRED;
96 break;
97 case DrmPlugin::kDrmPluginEventVendorDefined:
98 ndkEventType = EVENT_VENDOR_DEFINED;
99 break;
100 default:
101 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
Greg Kaiserb6365242016-08-11 11:01:37 -0700102 goto cleanup;
Jeff Tinker3305b992014-05-14 18:39:25 -0700103 }
104
Marco Nelissen18a1b592014-05-20 08:45:18 -0700105 (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
Jeff Tinker3305b992014-05-14 18:39:25 -0700106
Greg Kaiserb6365242016-08-11 11:01:37 -0700107 cleanup:
Jeff Tinker3305b992014-05-14 18:39:25 -0700108 delete [] sessionId.ptr;
109 delete [] data;
110}
111
112
Jeff Tinker497ca092014-05-13 09:31:15 -0700113extern "C" {
114
Marco Nelissene419d7c2014-05-15 14:17:25 -0700115static media_status_t translateStatus(status_t status) {
116 media_status_t result = AMEDIA_ERROR_UNKNOWN;
Jeff Tinker497ca092014-05-13 09:31:15 -0700117 switch (status) {
118 case OK:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700119 result = AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700120 break;
121 case android::ERROR_DRM_NOT_PROVISIONED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700122 result = AMEDIA_DRM_NOT_PROVISIONED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700123 break;
124 case android::ERROR_DRM_RESOURCE_BUSY:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700125 result = AMEDIA_DRM_RESOURCE_BUSY;
Jeff Tinker497ca092014-05-13 09:31:15 -0700126 break;
127 case android::ERROR_DRM_DEVICE_REVOKED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700128 result = AMEDIA_DRM_DEVICE_REVOKED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700129 break;
130 case android::ERROR_DRM_CANNOT_HANDLE:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700131 result = AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700132 break;
133 case android::ERROR_DRM_TAMPER_DETECTED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700134 result = AMEDIA_DRM_TAMPER_DETECTED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700135 break;
136 case android::ERROR_DRM_SESSION_NOT_OPENED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700137 result = AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700138 break;
139 case android::ERROR_DRM_NO_LICENSE:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700140 result = AMEDIA_DRM_NEED_KEY;
Jeff Tinker497ca092014-05-13 09:31:15 -0700141 break;
142 case android::ERROR_DRM_LICENSE_EXPIRED:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700143 result = AMEDIA_DRM_LICENSE_EXPIRED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700144 break;
145 default:
Jeff Tinker497ca092014-05-13 09:31:15 -0700146 break;
147 }
148 return result;
149}
150
151static sp<IDrm> CreateDrm() {
152 sp<IServiceManager> sm = defaultServiceManager();
Jeff Tinker30038072016-04-25 13:41:35 -0700153 sp<IBinder> binder = sm->getService(String16("media.drm"));
Jeff Tinker497ca092014-05-13 09:31:15 -0700154
Jeff Tinker30038072016-04-25 13:41:35 -0700155 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
156 if (service == NULL) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700157 return NULL;
158 }
159
Jeff Tinker30038072016-04-25 13:41:35 -0700160 sp<IDrm> drm = service->makeDrm();
161 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
162 return NULL;
163 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700164 return drm;
165}
166
167
168static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
169 sp<IDrm> drm = CreateDrm();
170
171 if (drm == NULL) {
172 return NULL;
173 }
174
Edwin Wong68b3d9f2017-01-06 19:07:54 -0800175 String8 nullPackageName;
176 status_t err = drm->createPlugin(uuid, nullPackageName);
Jeff Tinker497ca092014-05-13 09:31:15 -0700177
178 if (err != OK) {
179 return NULL;
180 }
181
182 return drm;
183}
184
Marco Nelissen3425fd52014-05-14 11:12:46 -0700185EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700186bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
187 sp<IDrm> drm = CreateDrm();
188
189 if (drm == NULL) {
190 return false;
191 }
192
193 String8 mimeStr = mimeType ? String8(mimeType) : String8("");
194 return drm->isCryptoSchemeSupported(uuid, mimeStr);
195}
196
Marco Nelissen3425fd52014-05-14 11:12:46 -0700197EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700198AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
199 AMediaDrm *mObj = new AMediaDrm();
200 mObj->mDrm = CreateDrmFromUUID(uuid);
201 return mObj;
202}
203
Marco Nelissen3425fd52014-05-14 11:12:46 -0700204EXPORT
Jeff Tinker497ca092014-05-13 09:31:15 -0700205void AMediaDrm_release(AMediaDrm *mObj) {
206 if (mObj->mDrm != NULL) {
207 mObj->mDrm->setListener(NULL);
208 mObj->mDrm->destroyPlugin();
209 mObj->mDrm.clear();
210 }
211 delete mObj;
212}
213
Jeff Tinker3305b992014-05-14 18:39:25 -0700214EXPORT
Marco Nelissen7c96d532014-05-15 15:26:14 -0700215media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
Jeff Tinker3305b992014-05-14 18:39:25 -0700216 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissen7c96d532014-05-15 15:26:14 -0700217 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker3305b992014-05-14 18:39:25 -0700218 }
219 mObj->mListener = new DrmListener(mObj, listener);
220 mObj->mDrm->setListener(mObj->mListener);
Marco Nelissen7c96d532014-05-15 15:26:14 -0700221 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700222}
Jeff Tinker497ca092014-05-13 09:31:15 -0700223
224
225static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
Edwin Wong21030442016-10-18 12:34:05 -0700226 for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
Jeff Tinkerc5f013f2017-04-05 10:28:27 -0700227 if (id.length == iter->size() && memcmp(iter->array(), id.ptr, iter->size()) == 0) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700228 return true;
229 }
230 }
231 return false;
232}
233
Marco Nelissen3425fd52014-05-14 11:12:46 -0700234EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700235media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700236 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700237 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700238 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700239 if (!sessionId) {
240 return AMEDIA_ERROR_INVALID_PARAMETER;
241 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700242 Vector<uint8_t> session;
Jeff Tinker41d279a2018-02-11 19:52:08 +0000243 status_t status = mObj->mDrm->openSession(DrmPlugin::kSecurityLevelMax, session);
Jeff Tinker497ca092014-05-13 09:31:15 -0700244 if (status == OK) {
245 mObj->mIds.push_front(session);
246 List<idvec_t>::iterator iter = mObj->mIds.begin();
Marco Nelissen18a1b592014-05-20 08:45:18 -0700247 sessionId->ptr = iter->array();
248 sessionId->length = iter->size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700249 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700250 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700251}
252
Marco Nelissen3425fd52014-05-14 11:12:46 -0700253EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700254media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700255 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700256 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700257 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700258 if (!sessionId) {
259 return AMEDIA_ERROR_INVALID_PARAMETER;
260 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700261
262 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700263 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700264 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700265 }
266 mObj->mDrm->closeSession(*iter);
267 mObj->mIds.erase(iter);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700268 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700269}
270
Marco Nelissen3425fd52014-05-14 11:12:46 -0700271EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700272media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
Jeff Tinker497ca092014-05-13 09:31:15 -0700273 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
274 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700275 const uint8_t **keyRequest, size_t *keyRequestSize) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700276
277 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700278 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700279 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700280 if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700281 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700282 }
283
284 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700285 if (!findId(mObj, *scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700286 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700287 }
288
289 Vector<uint8_t> mdInit;
290 mdInit.appendArray(init, initSize);
291 DrmPlugin::KeyType mdKeyType;
292 switch (keyType) {
293 case KEY_TYPE_STREAMING:
294 mdKeyType = DrmPlugin::kKeyType_Streaming;
295 break;
296 case KEY_TYPE_OFFLINE:
297 mdKeyType = DrmPlugin::kKeyType_Offline;
298 break;
299 case KEY_TYPE_RELEASE:
300 mdKeyType = DrmPlugin::kKeyType_Release;
301 break;
302 default:
Marco Nelissene419d7c2014-05-15 14:17:25 -0700303 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700304 }
305 KeyedVector<String8, String8> mdOptionalParameters;
306 for (size_t i = 0; i < numOptionalParameters; i++) {
307 mdOptionalParameters.add(String8(optionalParameters[i].mKey),
308 String8(optionalParameters[i].mValue));
309 }
310 String8 defaultUrl;
Jeff Tinkerd072c902015-03-16 13:39:29 -0700311 DrmPlugin::KeyRequestType keyRequestType;
Edwin Wongb5c8f212018-07-06 17:29:24 -0700312 mObj->mKeyRequest.clear();
Jeff Tinker497ca092014-05-13 09:31:15 -0700313 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
Jeff Tinkerd072c902015-03-16 13:39:29 -0700314 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
315 &keyRequestType);
Jeff Tinker497ca092014-05-13 09:31:15 -0700316 if (status != OK) {
317 return translateStatus(status);
318 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700319 *keyRequest = mObj->mKeyRequest.array();
320 *keyRequestSize = mObj->mKeyRequest.size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700321 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700322 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700323}
324
Marco Nelissen3425fd52014-05-14 11:12:46 -0700325EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700326media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
327 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700328
329 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700330 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700331 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700332 if (!scope || !response || !responseSize || !keySetId) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700333 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700334 }
335
336 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700337 if (!findId(mObj, *scope, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700338 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700339 }
340 Vector<uint8_t> mdResponse;
341 mdResponse.appendArray(response, responseSize);
342
343 Vector<uint8_t> mdKeySetId;
344 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
345 if (status == OK) {
346 mObj->mIds.push_front(mdKeySetId);
347 List<idvec_t>::iterator iter = mObj->mIds.begin();
Marco Nelissen18a1b592014-05-20 08:45:18 -0700348 keySetId->ptr = iter->array();
349 keySetId->length = iter->size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700350 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700351 keySetId->ptr = NULL;
352 keySetId->length = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700353 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700354 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700355}
356
Marco Nelissen3425fd52014-05-14 11:12:46 -0700357EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700358media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
359 const AMediaDrmKeySetId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700360
361 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700362 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700363 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700364 if (!sessionId || !keySetId) {
365 return AMEDIA_ERROR_INVALID_PARAMETER;
366 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700367 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700368 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700369 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700370 }
371 Vector<uint8_t> keySet;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700372 keySet.appendArray(keySetId->ptr, keySetId->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700373 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
374}
375
Marco Nelissen3425fd52014-05-14 11:12:46 -0700376EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700377media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700378 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700379 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700380 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700381 if (!keySetId) {
382 return AMEDIA_ERROR_INVALID_PARAMETER;
383 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700384 List<idvec_t>::iterator iter;
385 status_t status;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700386 if (!findId(mObj, *keySetId, iter)) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700387 Vector<uint8_t> keySet;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700388 keySet.appendArray(keySetId->ptr, keySetId->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700389 status = mObj->mDrm->removeKeys(keySet);
390 } else {
391 status = mObj->mDrm->removeKeys(*iter);
392 mObj->mIds.erase(iter);
393 }
394 return translateStatus(status);
395}
396
Marco Nelissen3425fd52014-05-14 11:12:46 -0700397EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700398media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
399 AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700400
401 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700402 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700403 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700404 if (!sessionId || !numPairs) {
405 return AMEDIA_ERROR_INVALID_PARAMETER;
406 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700407 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700408 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700409 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700410 }
411
412 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
413 if (status != OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700414 *numPairs = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700415 return translateStatus(status);
416 }
417
Marco Nelissen18a1b592014-05-20 08:45:18 -0700418 if (mObj->mQueryResults.size() > *numPairs) {
419 *numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700420 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700421 }
422
423 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
424 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
Edwin Wong815c9252017-08-30 17:47:20 -0700425 keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700426 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700427 *numPairs = mObj->mQueryResults.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700428 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700429}
430
Marco Nelissen3425fd52014-05-14 11:12:46 -0700431EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700432media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
433 size_t *provisionRequestSize, const char **serverUrl) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700434 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700435 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700436 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700437 if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700438 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700439 }
440
441 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
442 mObj->mProvisionRequest, mObj->mProvisionUrl);
443 if (status != OK) {
444 return translateStatus(status);
445 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700446 *provisionRequest = mObj->mProvisionRequest.array();
447 *provisionRequestSize = mObj->mProvisionRequest.size();
448 *serverUrl = mObj->mProvisionUrl.string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700449 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700450 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700451}
452
Marco Nelissen3425fd52014-05-14 11:12:46 -0700453EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700454media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700455 const uint8_t *response, size_t responseSize) {
456 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700457 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700458 }
459 if (!response || !responseSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700460 return AMEDIA_ERROR_INVALID_PARAMETER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700461 }
462
463 Vector<uint8_t> mdResponse;
464 mdResponse.appendArray(response, responseSize);
465
466 Vector<uint8_t> unused;
467 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
468}
469
Marco Nelissen3425fd52014-05-14 11:12:46 -0700470EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700471media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700472 AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700473
474 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700475 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700476 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700477 if (!numSecureStops) {
478 return AMEDIA_ERROR_INVALID_PARAMETER;
479 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700480 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
481 if (status != OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700482 *numSecureStops = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700483 return translateStatus(status);
484 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700485 if (*numSecureStops < mObj->mSecureStops.size()) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700486 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700487 }
488 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
489 size_t i = 0;
490 while (iter != mObj->mSecureStops.end()) {
491 secureStops[i].ptr = iter->array();
492 secureStops[i].length = iter->size();
493 ++iter;
494 ++i;
495 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700496 *numSecureStops = mObj->mSecureStops.size();
Marco Nelissene419d7c2014-05-15 14:17:25 -0700497 return AMEDIA_OK;
Jeff Tinker497ca092014-05-13 09:31:15 -0700498}
499
Marco Nelissen3425fd52014-05-14 11:12:46 -0700500EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700501media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700502 const AMediaDrmSecureStop *ssRelease) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700503
504 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700505 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700506 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700507 if (!ssRelease) {
508 return AMEDIA_ERROR_INVALID_PARAMETER;
509 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700510
511 Vector<uint8_t> release;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700512 release.appendArray(ssRelease->ptr, ssRelease->length);
Jeff Tinker497ca092014-05-13 09:31:15 -0700513 return translateStatus(mObj->mDrm->releaseSecureStops(release));
514}
515
516
Marco Nelissen3425fd52014-05-14 11:12:46 -0700517EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700518media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700519 const char **propertyValue) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700520
521 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700522 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700523 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700524 if (!propertyName || !propertyValue) {
525 return AMEDIA_ERROR_INVALID_PARAMETER;
526 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700527
528 status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
529 mObj->mPropertyString);
530
531 if (status == OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700532 *propertyValue = mObj->mPropertyString.string();
Jeff Tinker497ca092014-05-13 09:31:15 -0700533 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700534 *propertyValue = NULL;
Jeff Tinker497ca092014-05-13 09:31:15 -0700535 }
536 return translateStatus(status);
537}
538
Marco Nelissen3425fd52014-05-14 11:12:46 -0700539EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700540media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
Marco Nelissen18a1b592014-05-20 08:45:18 -0700541 const char *propertyName, AMediaDrmByteArray *propertyValue) {
Jeff Tinker497ca092014-05-13 09:31:15 -0700542 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700543 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700544 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700545 if (!propertyName || !propertyValue) {
546 return AMEDIA_ERROR_INVALID_PARAMETER;
547 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700548
549 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
550 mObj->mPropertyByteArray);
551
552 if (status == OK) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700553 propertyValue->ptr = mObj->mPropertyByteArray.array();
554 propertyValue->length = mObj->mPropertyByteArray.size();
Jeff Tinker497ca092014-05-13 09:31:15 -0700555 } else {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700556 propertyValue->ptr = NULL;
557 propertyValue->length = 0;
Jeff Tinker497ca092014-05-13 09:31:15 -0700558 }
559 return translateStatus(status);
560}
561
Marco Nelissen3425fd52014-05-14 11:12:46 -0700562EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700563media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700564 const char *propertyName, const char *value) {
565 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700566 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700567 }
568
569 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
570 String8(value)));
571}
572
Marco Nelissen3425fd52014-05-14 11:12:46 -0700573EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700574media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700575 const char *propertyName, const uint8_t *value, size_t valueSize) {
576
577 Vector<uint8_t> byteArray;
578 byteArray.appendArray(value, valueSize);
579
580 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
581 byteArray));
582}
583
584
Marco Nelissene419d7c2014-05-15 14:17:25 -0700585static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
Jeff Tinker497ca092014-05-13 09:31:15 -0700586 const AMediaDrmSessionId &sessionId,
587 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
588 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
589
590 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700591 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700592 }
593 List<idvec_t>::iterator iter;
594 if (!findId(mObj, sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700595 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700596 }
597
598 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
599 if (status != OK) {
600 return translateStatus(status);
601 }
602
603 Vector<uint8_t> keyIdVec;
604 const size_t kKeyIdSize = 16;
605 keyIdVec.appendArray(keyId, kKeyIdSize);
606
607 Vector<uint8_t> inputVec;
608 inputVec.appendArray(input, dataSize);
609
610 Vector<uint8_t> ivVec;
611 const size_t kIvSize = 16;
612 ivVec.appendArray(iv, kIvSize);
613
614 Vector<uint8_t> outputVec;
615 if (encrypt) {
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800616 status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
Jeff Tinker497ca092014-05-13 09:31:15 -0700617 } else {
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800618 status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
Jeff Tinker497ca092014-05-13 09:31:15 -0700619 }
620 if (status == OK) {
621 memcpy(output, outputVec.array(), outputVec.size());
622 }
623 return translateStatus(status);
624}
625
Marco Nelissen3425fd52014-05-14 11:12:46 -0700626EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700627media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700628 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
629 const uint8_t *input, uint8_t *output, size_t dataSize) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700630 if (!sessionId) {
631 return AMEDIA_ERROR_INVALID_PARAMETER;
632 }
633 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
Jeff Tinker497ca092014-05-13 09:31:15 -0700634 input, output, dataSize, true);
635}
636
Marco Nelissen3425fd52014-05-14 11:12:46 -0700637EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700638media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700639 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
640 const uint8_t *input, uint8_t *output, size_t dataSize) {
Marco Nelissen18a1b592014-05-20 08:45:18 -0700641 if (!sessionId) {
642 return AMEDIA_ERROR_INVALID_PARAMETER;
643 }
644 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
Jeff Tinker497ca092014-05-13 09:31:15 -0700645 input, output, dataSize, false);
646}
647
Marco Nelissen3425fd52014-05-14 11:12:46 -0700648EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700649media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700650 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
651 uint8_t *signature, size_t *signatureSize) {
652
653 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700654 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700655 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700656 if (!sessionId) {
657 return AMEDIA_ERROR_INVALID_PARAMETER;
658 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700659 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700660 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700661 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700662 }
663
664 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
665 if (status != OK) {
666 return translateStatus(status);
667 }
668
669 Vector<uint8_t> keyIdVec;
670 const size_t kKeyIdSize = 16;
671 keyIdVec.appendArray(keyId, kKeyIdSize);
672
673 Vector<uint8_t> messageVec;
674 messageVec.appendArray(message, messageSize);
675
676 Vector<uint8_t> signatureVec;
677 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
678 if (signatureVec.size() > *signatureSize) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700679 return AMEDIA_DRM_SHORT_BUFFER;
Jeff Tinker497ca092014-05-13 09:31:15 -0700680 }
681 if (status == OK) {
682 memcpy(signature, signatureVec.array(), signatureVec.size());
683 }
684 return translateStatus(status);
685}
686
Marco Nelissen3425fd52014-05-14 11:12:46 -0700687EXPORT
Marco Nelissen18a1b592014-05-20 08:45:18 -0700688media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
Jeff Tinker497ca092014-05-13 09:31:15 -0700689 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
690 const uint8_t *signature, size_t signatureSize) {
691
692 if (!mObj || mObj->mDrm == NULL) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700693 return AMEDIA_ERROR_INVALID_OBJECT;
Jeff Tinker497ca092014-05-13 09:31:15 -0700694 }
Marco Nelissen18a1b592014-05-20 08:45:18 -0700695 if (!sessionId) {
696 return AMEDIA_ERROR_INVALID_PARAMETER;
697 }
Jeff Tinker497ca092014-05-13 09:31:15 -0700698 List<idvec_t>::iterator iter;
Marco Nelissen18a1b592014-05-20 08:45:18 -0700699 if (!findId(mObj, *sessionId, iter)) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700700 return AMEDIA_DRM_SESSION_NOT_OPENED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700701 }
702
703 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
704 if (status != OK) {
705 return translateStatus(status);
706 }
707
708 Vector<uint8_t> keyIdVec;
709 const size_t kKeyIdSize = 16;
710 keyIdVec.appendArray(keyId, kKeyIdSize);
711
712 Vector<uint8_t> messageVec;
713 messageVec.appendArray(message, messageSize);
714
715 Vector<uint8_t> signatureVec;
716 signatureVec.appendArray(signature, signatureSize);
717
718 bool match;
719 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
720 if (status == OK) {
Marco Nelissene419d7c2014-05-15 14:17:25 -0700721 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
Jeff Tinker497ca092014-05-13 09:31:15 -0700722 }
723 return translateStatus(status);
724}
725
726} // extern "C"