diff options
| -rw-r--r-- | drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp | 24 | ||||
| -rw-r--r-- | media/ndk/NdkMediaDrm.cpp | 165 | ||||
| -rw-r--r-- | media/ndk/include/media/NdkMediaDrm.h | 124 |
3 files changed, 259 insertions, 54 deletions
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp index d51e29dc57..3b6108526b 100644 --- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp +++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp @@ -245,11 +245,29 @@ Return<void> DrmPlugin::provideKeyResponse( setPlayPolicy(); std::vector<uint8_t> keySetId; + keySetId.clear(); + Status status = session->provideKeyResponse(response); if (status == Status::OK) { - // This is for testing AMediaDrm_setOnEventListener only. - sendEvent(EventType::VENDOR_DEFINED, 0, scope); - keySetId.clear(); + // Test calling AMediaDrm listeners. + sendEvent(EventType::VENDOR_DEFINED, toVector(scope), toVector(scope)); + + sendExpirationUpdate(toVector(scope), 100); + + std::vector<KeyStatus> keysStatus; + KeyStatus keyStatus; + + std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC }; + keyStatus.keyId = keyId1; + keyStatus.type = V1_0::KeyStatusType::USABLE; + keysStatus.push_back(keyStatus); + + std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF }; + keyStatus.keyId = keyId2; + keyStatus.type = V1_0::KeyStatusType::EXPIRED; + keysStatus.push_back(keyStatus); + + sendKeysChange(toVector(scope), keysStatus, true); } installSecureStop(scope); diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp index 5597488637..2552073324 100644 --- a/media/ndk/NdkMediaDrm.cpp +++ b/media/ndk/NdkMediaDrm.cpp @@ -17,6 +17,8 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NdkMediaDrm" +#include <inttypes.h> + #include <media/NdkMediaDrm.h> #include <cutils/properties.h> @@ -40,10 +42,32 @@ struct DrmListener: virtual public BnDrmClient { private: AMediaDrm *mObj; - AMediaDrmEventListener mListener; + AMediaDrmEventListener mEventListener; + AMediaDrmExpirationUpdateListener mExpirationUpdateListener; + AMediaDrmKeysChangeListener mKeysChangeListener; public: - DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {} + DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), + mEventListener(listener), mExpirationUpdateListener(NULL), mKeysChangeListener(NULL) {} + + DrmListener(AMediaDrm *obj, AMediaDrmExpirationUpdateListener listener) : mObj(obj), + mEventListener(NULL), mExpirationUpdateListener(listener), mKeysChangeListener(NULL) {} + + DrmListener(AMediaDrm *obj, AMediaDrmKeysChangeListener listener) : mObj(obj), + mEventListener(NULL), mExpirationUpdateListener(NULL), mKeysChangeListener(listener) {} + + void setEventListener(AMediaDrmEventListener listener) { + mEventListener = listener; + } + + void setExpirationUpdateListener(AMediaDrmExpirationUpdateListener listener) { + mExpirationUpdateListener = listener; + } + + void setKeysChangeListener(AMediaDrmKeysChangeListener listener) { + mKeysChangeListener = listener; + } + void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj); }; @@ -62,27 +86,75 @@ struct AMediaDrm { }; void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) { - if (!mListener) { + if (!mEventListener && !mExpirationUpdateListener && !mKeysChangeListener) { + ALOGE("No listeners are specified"); return; } + obj->setDataPosition(0); + AMediaDrmSessionId sessionId = {NULL, 0}; int32_t sessionIdSize = obj->readInt32(); - if (sessionIdSize) { - uint8_t *sessionIdData = new uint8_t[sessionIdSize]; - sessionId.ptr = sessionIdData; - sessionId.length = sessionIdSize; - obj->read(sessionIdData, sessionId.length); + if (sessionIdSize <= 0) { + ALOGE("Invalid session id size"); + return; } - int32_t dataSize = obj->readInt32(); - uint8_t *data = NULL; - if (dataSize) { - data = new uint8_t[dataSize]; - obj->read(data, dataSize); + std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]); + sessionId.ptr = sessionIdData.get(); + sessionId.length = sessionIdSize; + status_t err = obj->read(sessionIdData.get(), sessionId.length); + if (err != OK) { + ALOGE("Failed to read session id, error=%d", err); + return; } - // translate DrmPlugin event types into their NDK equivalents + if (DrmPlugin::kDrmPluginEventExpirationUpdate == eventType) { + int64_t expiryTimeInMS = obj->readInt64(); + if (expiryTimeInMS >= 0) { + (*mExpirationUpdateListener)(mObj, &sessionId, expiryTimeInMS); + } else { + ALOGE("Failed to read expiry time, status=%" PRId64 "", expiryTimeInMS); + } + return; + } else if (DrmPlugin::kDrmPluginEventKeysChange == eventType) { + int32_t numKeys = 0; + err = obj->readInt32(&numKeys); + if (err != OK) { + ALOGE("Failed to read number of keys status, error=%d", err); + return; + } + + Vector<AMediaDrmKeyStatus> keysStatus; + std::vector<std::unique_ptr<uint8_t[]> > dataPointers; + AMediaDrmKeyStatus keyStatus; + + for (size_t i = 0; i < numKeys; ++i) { + keyStatus.keyId.ptr = nullptr; + keyStatus.keyId.length = 0; + int32_t idSize = obj->readInt32(); + if (idSize > 0) { + std::unique_ptr<uint8_t[]> data(new uint8_t[idSize]); + err = obj->read(data.get(), idSize); + if (err != OK) { + ALOGE("Failed to read key data, error=%d", err); + return; + } + keyStatus.keyId.ptr = data.get(); + keyStatus.keyId.length = idSize; + dataPointers.push_back(std::move(data)); + } + keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(obj->readInt32()); + keysStatus.push(keyStatus); + } + + bool hasNewUsableKey = obj->readInt32(); + (*mKeysChangeListener)(mObj, &sessionId, keysStatus.array(), numKeys, hasNewUsableKey); + return; + } + + // Handles AMediaDrmEventListener below: + // translates DrmPlugin event types into their NDK equivalents AMediaDrmEventType ndkEventType; switch(eventType) { case DrmPlugin::kDrmPluginEventProvisionRequired: @@ -97,19 +169,30 @@ void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel case DrmPlugin::kDrmPluginEventVendorDefined: ndkEventType = EVENT_VENDOR_DEFINED; break; + case DrmPlugin::kDrmPluginEventSessionReclaimed: + ndkEventType = EVENT_SESSION_RECLAIMED; + break; default: ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType); - goto cleanup; + return; } - (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize); - - cleanup: - delete [] sessionId.ptr; - delete [] data; + int32_t dataSize = obj->readInt32(); + uint8_t *data = NULL; + if (dataSize > 0) { + data = new uint8_t[dataSize]; + err = obj->read(data, dataSize); + if (err == OK) { + (*mEventListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize); + } else { + ALOGE("Failed to read event data, error=%d", err); + } + delete [] data; + } else { + ALOGE("Error reading parcel: invalid event data size=%d", dataSize); + } } - extern "C" { static media_status_t translateStatus(status_t status) { @@ -198,6 +281,8 @@ EXPORT AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { AMediaDrm *mObj = new AMediaDrm(); mObj->mDrm = CreateDrmFromUUID(uuid); + + mObj->mListener.clear(); return mObj; } @@ -216,11 +301,47 @@ media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListe if (!mObj || mObj->mDrm == NULL) { return AMEDIA_ERROR_INVALID_OBJECT; } - mObj->mListener = new DrmListener(mObj, listener); + + if (mObj->mListener.get()) { + mObj->mListener->setEventListener(listener); + } else { + mObj->mListener = new DrmListener(mObj, listener); + } + mObj->mDrm->setListener(mObj->mListener); + return AMEDIA_OK; +} + +EXPORT +media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *mObj, + AMediaDrmExpirationUpdateListener listener) { + if (!mObj || mObj->mDrm == NULL) { + return AMEDIA_ERROR_INVALID_OBJECT; + } + + if (mObj->mListener.get()) { + mObj->mListener->setExpirationUpdateListener(listener); + } else { + mObj->mListener = new DrmListener(mObj, listener); + } mObj->mDrm->setListener(mObj->mListener); return AMEDIA_OK; } +EXPORT +media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *mObj, + AMediaDrmKeysChangeListener listener) { + if (!mObj || mObj->mDrm == NULL) { + return AMEDIA_ERROR_INVALID_OBJECT; + } + + if (mObj->mListener.get()) { + mObj->mListener->setKeysChangeListener(listener); + } else { + mObj->mListener = new DrmListener(mObj, listener); + } + mObj->mDrm->setListener(mObj->mListener); + return AMEDIA_OK; +} static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) { for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) { diff --git a/media/ndk/include/media/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h index 020968173b..2e438d9cbf 100644 --- a/media/ndk/include/media/NdkMediaDrm.h +++ b/media/ndk/include/media/NdkMediaDrm.h @@ -56,6 +56,7 @@ typedef AMediaDrmByteArray AMediaDrmSessionId; typedef AMediaDrmByteArray AMediaDrmScope; typedef AMediaDrmByteArray AMediaDrmKeySetId; typedef AMediaDrmByteArray AMediaDrmSecureStop; +typedef AMediaDrmByteArray AMediaDrmKeyId; typedef enum AMediaDrmEventType { /** @@ -81,12 +82,89 @@ typedef enum AMediaDrmEventType { * This event may indicate some specific vendor-defined condition, see your * DRM provider documentation for details */ - EVENT_VENDOR_DEFINED = 4 + EVENT_VENDOR_DEFINED = 4, + + /** + * This event indicates that a session opened by the app has been reclaimed + * by the resource manager. + */ + EVENT_SESSION_RECLAIMED = 5, } AMediaDrmEventType; +typedef enum AMediaDrmKeyType { + /** + * This key request type specifies that the keys will be for online use, they will + * not be saved to the device for subsequent use when the device is not connected + * to a network. + */ + KEY_TYPE_STREAMING = 1, + + /** + * This key request type specifies that the keys will be for offline use, they + * will be saved to the device for use when the device is not connected to a network. + */ + KEY_TYPE_OFFLINE = 2, + + /** + * This key request type specifies that previously saved offline keys should be released. + */ + KEY_TYPE_RELEASE = 3 +} AMediaDrmKeyType; + +/** + * Data type containing {key, value} pair + */ +typedef struct AMediaDrmKeyValuePair { + const char *mKey; + const char *mValue; +} AMediaDrmKeyValue; + +typedef enum AMediaKeyStatusType { + /** + * The key is currently usable to decrypt media data. + */ + KEY_STATUS_TYPE_USABLE, + + /** + * The key is no longer usable to decrypt media data because its expiration + * time has passed. + */ + KEY_STATUS_TYPE_EXPIRED, + + /** + * The key is not currently usable to decrypt media data because its output + * requirements cannot currently be met. + */ + KEY_STATUS_TYPE_OUTPUTNOTALLOWED, + + /** + * The status of the key is not yet known and is being determined. + */ + KEY_STATUS_TYPE_STATUSPENDING, + + /** + * The key is not currently usable to decrypt media data because of an + * internal error in processing unrelated to input parameters. + */ + KEY_STATUS_TYPE_INTERNALERROR, + +} AMediaDrmKeyStatusType; + +typedef struct AMediaDrmKeyStatus { + AMediaDrmKeyId keyId; + AMediaDrmKeyStatusType keyType; +} AMediaDrmKeyStatus; + typedef void (*AMediaDrmEventListener)(AMediaDrm *, const AMediaDrmSessionId *sessionId, AMediaDrmEventType eventType, int extra, const uint8_t *data, size_t dataSize); +typedef void (*AMediaDrmExpirationUpdateListener)(AMediaDrm *, + const AMediaDrmSessionId *sessionId, int64_t expiryTimeInMS); + +typedef void (*AMediaDrmKeysChangeListener)(AMediaDrm *, + const AMediaDrmSessionId *sessionId, const AMediaDrmKeyStatus *keyStatus, + size_t numKeys, bool hasNewUsableKey); + #if __ANDROID_API__ >= 21 /** @@ -120,6 +198,22 @@ media_status_t AMediaDrm_setOnEventListener(AMediaDrm *, AMediaDrmEventListener listener) __INTRODUCED_IN(21); /** + * Register a callback to be invoked when an expiration update event occurs + * + * listener is the callback that will be invoked on event + */ +media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *, + AMediaDrmExpirationUpdateListener listener) __INTRODUCED_IN(29); + +/** + * Register a callback to be invoked when a key status change event occurs + * + * listener is the callback that will be invoked on event + */ +media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *, + AMediaDrmKeysChangeListener listener) __INTRODUCED_IN(29); + +/** * Open a new session with the MediaDrm object. A session ID is returned. * * returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed @@ -135,34 +229,6 @@ media_status_t AMediaDrm_openSession(AMediaDrm *, media_status_t AMediaDrm_closeSession(AMediaDrm *, const AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21); -typedef enum AMediaDrmKeyType { - /** - * This key request type species that the keys will be for online use, they will - * not be saved to the device for subsequent use when the device is not connected - * to a network. - */ - KEY_TYPE_STREAMING = 1, - - /** - * This key request type specifies that the keys will be for offline use, they - * will be saved to the device for use when the device is not connected to a network. - */ - KEY_TYPE_OFFLINE = 2, - - /** - * This key request type specifies that previously saved offline keys should be released. - */ - KEY_TYPE_RELEASE = 3 -} AMediaDrmKeyType; - -/** - * Data type containing {key, value} pair - */ -typedef struct AMediaDrmKeyValuePair { - const char *mKey; - const char *mValue; -} AMediaDrmKeyValue; - /** * A key request/response exchange occurs between the app and a license server * to obtain or release keys used to decrypt encrypted content. |
