Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72882de6 authored by Edwin Wong's avatar Edwin Wong Committed by Android (Google) Code Review
Browse files

Merge "Add onExpirationUpdate and onKeyStatusChange listeners."

parents f7996c2c ad02cc6c
Loading
Loading
Loading
Loading
+21 −3
Original line number Diff line number Diff line
@@ -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);
+143 −22
Original line number Diff line number Diff line
@@ -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;
    if (sessionIdSize <= 0) {
        ALOGE("Invalid session id size");
        return;
    }

    std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]);
    sessionId.ptr = sessionIdData.get();
    sessionId.length = sessionIdSize;
        obj->read(sessionIdData, sessionId.length);
    status_t err = obj->read(sessionIdData.get(), sessionId.length);
    if (err != OK) {
        ALOGE("Failed to read session id, error=%d", err);
        return;
    }

    int32_t dataSize = obj->readInt32();
    uint8_t *data = NULL;
    if (dataSize) {
        data = new uint8_t[dataSize];
        obj->read(data, dataSize);
    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);
        }

    // translate DrmPlugin event types into their NDK equivalents
        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,18 +169,29 @@ 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;
    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" {

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

    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) {
+95 −29
Original line number Diff line number Diff line
@@ -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.