Add onExpirationUpdate and onKeyStatusChange listeners.

We must only create one DrmListener instance.
We then process different listeners in DrmListener::notify.

To facilitate testing, we call the listeners from clearkey plugin's
provideKeyResponse function. We have previously tested
EventType::VENDOR_DEFINED in the same manner.

bug: 77712870

Test: native CTS test testClearKeyPlaybackCenc
Test: CTS MediaDrmMockTest
Change-Id: Ie15e3012a4068824f72371a66e9fca2ee27180f8
Merged-In: Ie15e3012a4068824f72371a66e9fca2ee27180f8
gugelfrei
Edwin Wong 6 years ago committed by Ilya Matyukhin
parent 1b7026ed1e
commit 439774e7ca

@ -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);

@ -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) {

@ -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
/**
@ -119,6 +197,22 @@ void AMediaDrm_release(AMediaDrm *) __INTRODUCED_IN(21);
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.
*
@ -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.

Loading…
Cancel
Save