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

Commit 1bd139a2 authored by Andreas Huber's avatar Andreas Huber
Browse files

New Crypto services talking to the new crypto "HAL".

Change-Id: I69ed31e7a8b4d69d1209d2d516f94d258f072566
related-to-bug: 6275919
parent d22da88f
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include <gui/SurfaceTextureClient.h>
#include <media/AudioTrack.h>
#include <media/ICrypto.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -318,7 +319,9 @@ status_t SimplePlayer::onPrepare() {
        CHECK(state->mCodec != NULL);

        err = state->mCodec->configure(
                format, mNativeWindow->getSurfaceTextureClient(),
                format,
                mNativeWindow->getSurfaceTextureClient(),
                NULL /* crypto */,
                0 /* flags */);

        CHECK_EQ(err, (status_t)OK);
+66 −3
Original line number Diff line number Diff line
@@ -20,8 +20,10 @@

#include "SimplePlayer.h"

#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>

#include <media/ICrypto.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -59,6 +61,33 @@ struct CodecState {
    bool mIsAudio;
};

static sp<ICrypto> makeCrypto(
        const uint8_t uuid[16], const void *data, size_t size) {
    sp<IServiceManager> sm = defaultServiceManager();

    sp<IBinder> binder =
        sm->getService(String16("media.player"));

    sp<IMediaPlayerService> service =
        interface_cast<IMediaPlayerService>(binder);

    CHECK(service != NULL);

    sp<ICrypto> crypto = service->makeCrypto();

    if (crypto == NULL || crypto->initCheck() != OK) {
        return NULL;
    }

    status_t err = crypto->createPlugin(uuid, data, size);

    if (err != OK) {
        return NULL;
    }

    return crypto;
}

}  // namespace android

static int decode(
@@ -78,6 +107,8 @@ static int decode(
        return 1;
    }

    sp<ICrypto> crypto;

    KeyedVector<size_t, CodecState> stateByTrack;

    bool haveAudio = false;
@@ -113,7 +144,38 @@ static int decode(
        state->mNumBuffersDecoded = 0;
        state->mIsAudio = isAudio;

        if (decryptInputBuffers && !isAudio) {
        if (decryptInputBuffers && crypto == NULL) {
            sp<ABuffer> emm;
            CHECK(format->findBuffer("emm", &emm));

            sp<ABuffer> ecm;
            CHECK(format->findBuffer("ecm", &ecm));

            struct WVOpaqueInitData {
                uint8_t mEMM[16];
                uint8_t mECM[32];

            } opaque;

            CHECK_EQ(emm->size(), sizeof(opaque.mEMM));
            memcpy(opaque.mEMM, emm->data(), emm->size());

            CHECK_EQ(ecm->size(), 80u);
            // bytes 16..47 of the original ecm stream data.
            memcpy(opaque.mECM, ecm->data() + 16, 32);

            static const uint8_t kUUIDWidevine[16] = {
                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
            };

            crypto = makeCrypto(kUUIDWidevine, &opaque, sizeof(opaque));
            CHECK(crypto != NULL);
            CHECK_EQ(crypto->initCheck(), (status_t)OK);
        }

        if (decryptInputBuffers
                && crypto->requiresSecureDecoderComponent(mime.c_str())) {
            static const MediaCodecList *list = MediaCodecList::getInstance();

            ssize_t index =
@@ -137,7 +199,8 @@ static int decode(

        err = state->mCodec->configure(
                format, isVideo ? surface : NULL,
                decryptInputBuffers ? MediaCodec::CONFIGURE_FLAG_SECURE : 0);
                crypto,
                0 /* flags */);

        CHECK_EQ(err, (status_t)OK);

+17 −16
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include <binder/IInterface.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/hardware/CryptoAPI.h>

#ifndef ANDROID_ICRYPTO_H_

@@ -26,26 +27,26 @@ namespace android {
struct ICrypto : public IInterface {
    DECLARE_META_INTERFACE(Crypto);

    virtual status_t initialize() = 0;
    virtual status_t terminate() = 0;
    virtual status_t initCheck() const = 0;

    virtual status_t setEntitlementKey(
            const void *key, size_t keyLength) = 0;
    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;

    virtual status_t setEntitlementControlMessage(
            const void *msg, size_t msgLength) = 0;
    virtual status_t createPlugin(
            const uint8_t uuid[16], const void *data, size_t size) = 0;

    // "dstData" is in media_server's address space (but inaccessible).
    virtual ssize_t decryptVideo(
            const void *iv, size_t ivLength,
            const void *srcData, size_t srcDataSize,
            void *dstData, size_t dstDataOffset) = 0;
    virtual status_t destroyPlugin() = 0;

    // "dstData" is in the calling process' address space.
    virtual ssize_t decryptAudio(
            const void *iv, size_t ivLength,
            const void *srcData, size_t srcDataSize,
            void *dstData, size_t dstDataSize) = 0;
    virtual bool requiresSecureDecoderComponent(
            const char *mime) const = 0;

    virtual status_t decrypt(
            bool secure,
            const uint8_t key[16],
            const uint8_t iv[16],
            CryptoPlugin::Mode mode,
            const void *srcPtr,
            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
            void *dstPtr) = 0;

private:
    DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ struct SurfaceTextureClient;
struct MediaCodec : public AHandler {
    enum ConfigureFlags {
        CONFIGURE_FLAG_ENCODE   = 1,
        CONFIGURE_FLAG_SECURE   = 2,
    };

    enum BufferFlags {
@@ -53,6 +52,7 @@ struct MediaCodec : public AHandler {
    status_t configure(
            const sp<AMessage> &format,
            const sp<SurfaceTextureClient> &nativeWindow,
            const sp<ICrypto> &crypto,
            uint32_t flags);

    status_t start();
+122 −147
Original line number Diff line number Diff line
@@ -25,12 +25,12 @@
namespace android {

enum {
    INITIALIZE = IBinder::FIRST_CALL_TRANSACTION,
    TERMINATE,
    SET_ENTITLEMENT_KEY,
    SET_ECM,
    DECRYPT_VIDEO,
    DECRYPT_AUDIO,
    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
    IS_CRYPTO_SUPPORTED,
    CREATE_PLUGIN,
    DESTROY_PLUGIN,
    REQUIRES_SECURE_COMPONENT,
    DECRYPT,
};

struct BpCrypto : public BpInterface<ICrypto> {
@@ -38,104 +38,97 @@ struct BpCrypto : public BpInterface<ICrypto> {
        : BpInterface<ICrypto>(impl) {
    }

    virtual status_t initialize() {
    virtual status_t initCheck() const {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        remote()->transact(INITIALIZE, data, &reply);
        remote()->transact(INIT_CHECK, data, &reply);

        return reply.readInt32();
    }

    virtual status_t terminate() {
    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        remote()->transact(TERMINATE, data, &reply);
        data.write(uuid, 16);
        remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);

        return reply.readInt32();
        return reply.readInt32() != 0;
    }

    virtual status_t setEntitlementKey(
            const void *key, size_t keyLength) {
    virtual status_t createPlugin(
            const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.writeInt32(keyLength);
        data.write(key, keyLength);
        remote()->transact(SET_ENTITLEMENT_KEY, data, &reply);
        data.write(uuid, 16);
        data.writeInt32(opaqueSize);
        data.write(opaqueData, opaqueSize);
        remote()->transact(CREATE_PLUGIN, data, &reply);

        return reply.readInt32();
    }

    virtual status_t setEntitlementControlMessage(
            const void *msg, size_t msgLength) {
    virtual status_t destroyPlugin() {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.writeInt32(msgLength);
        data.write(msg, msgLength);
        remote()->transact(SET_ECM, data, &reply);
        remote()->transact(DESTROY_PLUGIN, data, &reply);

        return reply.readInt32();
    }

    virtual ssize_t decryptVideo(
            const void *iv, size_t ivLength,
            const void *srcData, size_t srcDataSize,
            void *dstData, size_t dstDataOffset) {
    virtual bool requiresSecureDecoderComponent(
            const char *mime) const {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        if (iv == NULL) {
            if (ivLength > 0) {
                return -EINVAL;
            }

            data.writeInt32(-1);
        } else {
            data.writeInt32(ivLength);
            data.write(iv, ivLength);
        }
        data.writeCString(mime);
        remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);

        data.writeInt32(srcDataSize);
        data.write(srcData, srcDataSize);

        data.writeIntPtr((intptr_t)dstData);
        data.writeInt32(dstDataOffset);

        remote()->transact(DECRYPT_VIDEO, data, &reply);

        return reply.readInt32();
        return reply.readInt32() != 0;
    }

    virtual ssize_t decryptAudio(
            const void *iv, size_t ivLength,
            const void *srcData, size_t srcDataSize,
            void *dstData, size_t dstDataSize) {
    virtual status_t decrypt(
            bool secure,
            const uint8_t key[16],
            const uint8_t iv[16],
            CryptoPlugin::Mode mode,
            const void *srcPtr,
            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
            void *dstPtr) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        if (iv == NULL) {
            if (ivLength > 0) {
                return -EINVAL;
        data.writeInt32(secure);
        data.writeInt32(mode);
        data.write(key, 16);
        data.write(iv, 16);

        size_t totalSize = 0;
        for (size_t i = 0; i < numSubSamples; ++i) {
            totalSize += subSamples[i].mNumBytesOfEncryptedData;
            totalSize += subSamples[i].mNumBytesOfClearData;
        }

            data.writeInt32(-1);
        } else {
            data.writeInt32(ivLength);
            data.write(iv, ivLength);
        }
        data.writeInt32(totalSize);
        data.write(srcPtr, totalSize);

        data.writeInt32(numSubSamples);
        data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);

        data.writeInt32(srcDataSize);
        data.write(srcData, srcDataSize);
        data.writeInt32(dstDataSize);
        if (secure) {
            data.writeIntPtr((intptr_t)dstPtr);
        }

        remote()->transact(DECRYPT_AUDIO, data, &reply);
        remote()->transact(DECRYPT, data, &reply);

        ssize_t res = reply.readInt32();
        status_t result = reply.readInt32();

        if (res <= 0) {
            return res;
        if (result != OK) {
            return result;
        }

        reply.read(dstData, res);
        if (!secure) {
            reply.read(dstPtr, totalSize);
        }

        return res;
        return OK;
    }

private:
@@ -149,138 +142,120 @@ IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
status_t BnCrypto::onTransact(
    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
    switch (code) {
        case INITIALIZE:
        case INIT_CHECK:
        {
            CHECK_INTERFACE(ICrypto, data, reply);
            reply->writeInt32(initialize());
            reply->writeInt32(initCheck());

            return OK;
        }

        case TERMINATE:
        case IS_CRYPTO_SUPPORTED:
        {
            CHECK_INTERFACE(ICrypto, data, reply);
            reply->writeInt32(terminate());
            uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));
            reply->writeInt32(isCryptoSchemeSupported(uuid));

            return OK;
        }

        case SET_ENTITLEMENT_KEY:
        case CREATE_PLUGIN:
        {
            CHECK_INTERFACE(ICrypto, data, reply);

            size_t keyLength = data.readInt32();
            void *key = malloc(keyLength);
            data.read(key, keyLength);
            uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));

            reply->writeInt32(setEntitlementKey(key, keyLength));
            size_t opaqueSize = data.readInt32();
            void *opaqueData = malloc(opaqueSize);
            data.read(opaqueData, opaqueSize);

            free(key);
            key = NULL;
            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));

            free(opaqueData);
            opaqueData = NULL;

            return OK;
        }

        case SET_ECM:
        case DESTROY_PLUGIN:
        {
            CHECK_INTERFACE(ICrypto, data, reply);

            size_t msgLength = data.readInt32();
            void *msg = malloc(msgLength);
            data.read(msg, msgLength);

            reply->writeInt32(setEntitlementControlMessage(msg, msgLength));

            free(msg);
            msg = NULL;
            reply->writeInt32(destroyPlugin());

            return OK;
        }

        case DECRYPT_VIDEO:
        case REQUIRES_SECURE_COMPONENT:
        {
            CHECK_INTERFACE(ICrypto, data, reply);

            void *iv = NULL;
            const char *mime = data.readCString();
            reply->writeInt32(requiresSecureDecoderComponent(mime));

            int32_t ivLength = data.readInt32();
            if (ivLength >= 0) {
                iv = malloc(ivLength);
                data.read(iv, ivLength);
            return OK;
        }

            size_t srcDataSize = data.readInt32();
            void *srcData = malloc(srcDataSize);
            data.read(srcData, srcDataSize);
        case DECRYPT:
        {
            CHECK_INTERFACE(ICrypto, data, reply);

            void *dstData = (void *)data.readIntPtr();
            size_t dstDataOffset = data.readInt32();
            bool secure = data.readInt32() != 0;
            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();

            reply->writeInt32(
                    decryptVideo(
                        iv,
                        ivLength < 0 ? 0 : ivLength,
                        srcData,
                        srcDataSize,
                        dstData,
                        dstDataOffset));
            uint8_t key[16];
            data.read(key, sizeof(key));

            free(srcData);
            srcData = NULL;
            uint8_t iv[16];
            data.read(iv, sizeof(iv));

            if (iv != NULL) {
                free(iv);
                iv = NULL;
            }
            size_t totalSize = data.readInt32();
            void *srcData = malloc(totalSize);
            data.read(srcData, totalSize);

            return OK;
        }
            int32_t numSubSamples = data.readInt32();

        case DECRYPT_AUDIO:
        {
            CHECK_INTERFACE(ICrypto, data, reply);
            CryptoPlugin::SubSample *subSamples =
                new CryptoPlugin::SubSample[numSubSamples];

            void *iv = NULL;
            data.read(
                    subSamples,
                    sizeof(CryptoPlugin::SubSample) * numSubSamples);

            int32_t ivLength = data.readInt32();
            if (ivLength >= 0) {
                iv = malloc(ivLength);
                data.read(iv, ivLength);
            void *dstPtr;
            if (secure) {
                dstPtr = (void *)data.readIntPtr();
            } else {
                dstPtr = malloc(totalSize);
            }

            size_t srcDataSize = data.readInt32();
            void *srcData = malloc(srcDataSize);
            data.read(srcData, srcDataSize);

            size_t dstDataSize = data.readInt32();
            void *dstData = malloc(dstDataSize);

            ssize_t res =
                decryptAudio(
            status_t err = decrypt(
                    secure,
                    key,
                    iv,
                        ivLength < 0 ? 0 : ivLength,
                    mode,
                    srcData,
                        srcDataSize,
                        dstData,
                        dstDataSize);
                    subSamples, numSubSamples,
                    dstPtr);

            reply->writeInt32(res);
            reply->writeInt32(err);

            if (res > 0) {
                reply->write(dstData, res);
            if (!secure) {
                if (err == OK) {
                    reply->write(dstPtr, totalSize);
                }

            free(dstData);
            dstData = NULL;
                free(dstPtr);
                dstPtr = NULL;
            }

            delete[] subSamples;
            subSamples = NULL;

            free(srcData);
            srcData = NULL;

            if (iv != NULL) {
                free(iv);
                iv = NULL;
            }

            return OK;
        }

Loading