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

Commit dfb4f40d authored by Arun Johnson's avatar Arun Johnson Committed by Automerger Merge Worker
Browse files

Merge "Implement secure API functions for large audio frames" into main am: bfe7b66f

parents e1d89f80 bfe7b66f
Loading
Loading
Loading
Loading
+256 −0
Original line number Diff line number Diff line
@@ -483,6 +483,130 @@ int32_t CCodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) {
    return heapSeqNum;
}

typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
typedef WrapperObject<std::vector<std::unique_ptr<CodecCryptoInfo>>> CryptoInfosWrapper;
status_t CCodecBufferChannel::attachEncryptedBuffers(
        const sp<hardware::HidlMemory> &memory,
        size_t offset,
        const sp<MediaCodecBuffer> &buffer,
        bool secure,
        AString* errorDetailMsg) {
    static const C2MemoryUsage kDefaultReadWriteUsage{
        C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
    if (!hasCryptoOrDescrambler()) {
        ALOGE("attachEncryptedBuffers requires Crypto/descrambler object");
        return -ENOSYS;
    }
    size_t size = 0;
    CHECK(buffer->meta()->findSize("ssize", &size));
    if (size == 0) {
        buffer->setRange(0, 0);
        return OK;
    }
    sp<RefBase> obj;
    CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
    sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
    CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
    sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
    if (secure || (mCrypto == nullptr)) {
        if (cryptoInfos->value.size() != 1) {
            ALOGE("Cannot decrypt multiple access units");
            return -ENOSYS;
        }
        // we are dealing with just one cryptoInfo or descrambler.
        std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
        if (info == nullptr) {
            ALOGE("Cannot decrypt, CryptoInfos are null.");
            return -ENOSYS;
        }
        return attachEncryptedBuffer(
                memory,
                secure,
                info->mKey,
                info->mIv,
                info->mMode,
                info->mPattern,
                offset,
                info->mSubSamples,
                info->mNumSubSamples,
                buffer,
                errorDetailMsg);
    }
    std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
    std::shared_ptr<C2LinearBlock> block;
    c2_status_t err = pool->fetchLinearBlock(
            size,
            kDefaultReadWriteUsage,
            &block);
    if (err != C2_OK) {
        ALOGI("[%s] attachEncryptedBuffers: fetchLinearBlock failed: size = %zu (%s) err = %d",
              mName, size, secure ? "secure" : "non-secure", err);
        return NO_MEMORY;
    }
    ensureDecryptDestination(size);
    C2WriteView wView = block->map().get();
    if (wView.error() != C2_OK) {
        ALOGI("[%s] attachEncryptedBuffers: block map error: %d (non-secure)",
              mName, wView.error());
        return UNKNOWN_ERROR;
    }

    ssize_t result = -1;
    ssize_t codecDataOffset = 0;
    size_t inBufferOffset = 0;
    size_t outBufferSize = 0;
    uint32_t cryptoInfoIdx = 0;
    int32_t heapSeqNum = getHeapSeqNum(memory);
    hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
    hardware::drm::V1_0::DestinationBuffer dst;
    dst.type = DrmBufferType::SHARED_MEMORY;
    IMemoryToSharedBuffer(
            mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
    for (int i = 0; i < bufferInfos->value.size(); i++) {
        if (bufferInfos->value[i].mSize > 0) {
            std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[cryptoInfoIdx++]);
            result = mCrypto->decrypt(
                    (uint8_t*)info->mKey,
                    (uint8_t*)info->mIv,
                    info->mMode,
                    info->mPattern,
                    src,
                    inBufferOffset,
                    info->mSubSamples,
                    info->mNumSubSamples,
                    dst,
                    errorDetailMsg);
            inBufferOffset += bufferInfos->value[i].mSize;
            if (result < 0) {
                ALOGI("[%s] attachEncryptedBuffers: decrypt failed: result = %zd",
                        mName, result);
                return result;
            }
            if (wView.error() == C2_OK) {
                if (wView.size() < result) {
                    ALOGI("[%s] attachEncryptedBuffers: block size too small:"
                            "size=%u result=%zd (non-secure)", mName, wView.size(), result);
                    return UNKNOWN_ERROR;
                }
                memcpy(wView.data(), mDecryptDestination->unsecurePointer(), result);
                bufferInfos->value[i].mSize = result;
                wView.setOffset(wView.offset() + result);
            }
            outBufferSize += result;
        }
    }
    if (wView.error() == C2_OK) {
        wView.setOffset(0);
    }
    std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
            block->share(codecDataOffset, outBufferSize - codecDataOffset, C2Fence{}))};
    if (!buffer->copy(c2Buffer)) {
        ALOGI("[%s] attachEncryptedBuffers: buffer copy failed", mName);
        return -ENOSYS;
    }
    return OK;
}

status_t CCodecBufferChannel::attachEncryptedBuffer(
        const sp<hardware::HidlMemory> &memory,
        bool secure,
@@ -777,6 +901,138 @@ status_t CCodecBufferChannel::queueSecureInputBuffer(
    return queueInputBufferInternal(buffer, block, bufferSize);
}

status_t CCodecBufferChannel::queueSecureInputBuffers(
        const sp<MediaCodecBuffer> &buffer,
        bool secure,
        AString *errorDetailMsg) {
    QueueGuard guard(mSync);
    if (!guard.isRunning()) {
        ALOGD("[%s] No more buffers should be queued at current state.", mName);
        return -ENOSYS;
    }

    if (!hasCryptoOrDescrambler()) {
        ALOGE("queueSecureInputBuffers requires a Crypto/descrambler Object");
        return -ENOSYS;
    }
    sp<RefBase> obj;
    CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
    sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
    CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
    sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
    if (secure || mCrypto == nullptr) {
        if (cryptoInfos->value.size() != 1) {
            ALOGE("Cannot decrypt multiple access units on native handles");
            return -ENOSYS;
        }
        std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
        if (info == nullptr) {
            ALOGE("Cannot decrypt, CryptoInfos are null");
            return -ENOSYS;
        }
        return queueSecureInputBuffer(
                buffer,
                secure,
                info->mKey,
                info->mIv,
                info->mMode,
                info->mPattern,
                info->mSubSamples,
                info->mNumSubSamples,
                errorDetailMsg);
    }
    sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());

    std::shared_ptr<C2LinearBlock> block;
    size_t allocSize = buffer->size();
    size_t bufferSize = 0;
    c2_status_t blockRes = C2_OK;
    bool copied = false;
    ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
            "CCodecBufferChannel::decrypt(%s)", mName).c_str());
    if (mSendEncryptedInfoBuffer) {
        static const C2MemoryUsage kDefaultReadWriteUsage{
            C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
        constexpr int kAllocGranule0 = 1024 * 64;
        constexpr int kAllocGranule1 = 1024 * 1024;
        std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
        // round up encrypted sizes to limit fragmentation and encourage buffer reuse
        if (allocSize <= kAllocGranule1) {
            bufferSize = align(allocSize, kAllocGranule0);
        } else {
            bufferSize = align(allocSize, kAllocGranule1);
        }
        blockRes = pool->fetchLinearBlock(
                bufferSize, kDefaultReadWriteUsage, &block);

        if (blockRes == C2_OK) {
            C2WriteView view = block->map().get();
            if (view.error() == C2_OK && view.size() == bufferSize) {
                copied = true;
                // TODO: only copy clear sections
                memcpy(view.data(), buffer->data(), allocSize);
            }
        }
    }

    if (!copied) {
        block.reset();
    }
    // size of cryptoInfo and accessUnitInfo should be the same?
    ssize_t result = -1;
    ssize_t codecDataOffset = 0;
    size_t inBufferOffset = 0;
    size_t outBufferSize = 0;
    uint32_t cryptoInfoIdx = 0;
    {
        // scoped this block to enable destruction of mappedBlock
        std::unique_ptr<EncryptedLinearBlockBuffer::MappedBlock> mappedBlock = nullptr;
        hardware::drm::V1_0::DestinationBuffer destination;
        destination.type = DrmBufferType::SHARED_MEMORY;
        IMemoryToSharedBuffer(
                mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
        encryptedBuffer->getMappedBlock(&mappedBlock);
        hardware::drm::V1_0::SharedBuffer source;
        encryptedBuffer->fillSourceBuffer(&source);
        for (int i = 0 ; i < bufferInfos->value.size(); i++) {
            if (bufferInfos->value[i].mSize > 0) {
                std::unique_ptr<CodecCryptoInfo> info =
                        std::move(cryptoInfos->value[cryptoInfoIdx++]);
                if (info->mNumSubSamples == 1
                        && info->mSubSamples[0].mNumBytesOfClearData == 0
                        && info->mSubSamples[0].mNumBytesOfEncryptedData == 0) {
                    // no data so we only populate the bufferInfo
                    result = 0;
                } else {
                    result = mCrypto->decrypt(
                            (uint8_t*)info->mKey,
                            (uint8_t*)info->mIv,
                            info->mMode,
                            info->mPattern,
                            source,
                            inBufferOffset,
                            info->mSubSamples,
                            info->mNumSubSamples,
                            destination,
                            errorDetailMsg);
                    inBufferOffset += bufferInfos->value[i].mSize;
                    if (result < 0) {
                        ALOGI("[%s] decrypt failed: result=%zd", mName, result);
                        return result;
                    }
                    if (destination.type == DrmBufferType::SHARED_MEMORY && mappedBlock) {
                        mappedBlock->copyDecryptedContent(mDecryptDestination, result);
                    }
                    bufferInfos->value[i].mSize = result;
                    outBufferSize += result;
                }
            }
        }
        buffer->setRange(codecDataOffset, outBufferSize - codecDataOffset);
    }
    return queueInputBufferInternal(buffer, block, bufferSize);
}

void CCodecBufferChannel::feedInputBufferIfAvailable() {
    QueueGuard guard(mSync);
    if (!guard.isRunning()) {
+10 −0
Original line number Diff line number Diff line
@@ -73,6 +73,10 @@ public:
            const CryptoPlugin::SubSample *subSamples,
            size_t numSubSamples,
            AString *errorDetailMsg) override;
    status_t queueSecureInputBuffers(
            const sp<MediaCodecBuffer> &buffer,
            bool secure,
            AString *errorDetailMsg) override;
    status_t attachBuffer(
            const std::shared_ptr<C2Buffer> &c2Buffer,
            const sp<MediaCodecBuffer> &buffer) override;
@@ -88,6 +92,12 @@ public:
            size_t numSubSamples,
            const sp<MediaCodecBuffer> &buffer,
            AString* errorDetailMsg) override;
    status_t attachEncryptedBuffers(
            const sp<hardware::HidlMemory> &memory,
            size_t offset,
            const sp<MediaCodecBuffer> &buffer,
            bool secure,
            AString* errorDetailMsg) override;
    status_t renderOutputBuffer(
            const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
    void pollForRenderedBuffers() override;
+31 −0
Original line number Diff line number Diff line
@@ -1036,6 +1036,37 @@ native_handle_t *EncryptedLinearBlockBuffer::handle() const {
    return const_cast<native_handle_t *>(mBlock->handle());
}

void EncryptedLinearBlockBuffer::getMappedBlock(
        std::unique_ptr<MappedBlock> * const mappedBlock) const {
    if (mappedBlock) {
        mappedBlock->reset(new EncryptedLinearBlockBuffer::MappedBlock(mBlock));
    }
    return;
}

EncryptedLinearBlockBuffer::MappedBlock::MappedBlock(
        const std::shared_ptr<C2LinearBlock> &block) : mView(block->map().get()) {
}

bool EncryptedLinearBlockBuffer::MappedBlock::copyDecryptedContent(
        const sp<IMemory> &decrypted, size_t length) {
    if (mView.error() != C2_OK) {
        return false;
    }
    if (mView.size() < length) {
        ALOGE("View size(%d) less than decrypted length(%zu)",
                mView.size(), length);
        return false;
    }
    memcpy(mView.data(), decrypted->unsecurePointer(), length);
    mView.setOffset(mView.offset() + length);
    return true;
}

EncryptedLinearBlockBuffer::MappedBlock::~MappedBlock() {
    mView.setOffset(0);
}

using ::aidl::android::hardware::graphics::common::Cta861_3;
using ::aidl::android::hardware::graphics::common::Smpte2086;

+11 −0
Original line number Diff line number Diff line
@@ -384,6 +384,17 @@ public:
     */
    native_handle_t *handle() const;

    class MappedBlock {
    public:
        explicit MappedBlock(const std::shared_ptr<C2LinearBlock> &block);
        virtual ~MappedBlock();
        bool copyDecryptedContent(const sp<IMemory> &decrypted, size_t length);
    private:
        C2WriteView mView;
    };

    void getMappedBlock(std::unique_ptr<MappedBlock> * const mappedBlock) const;

private:

    std::shared_ptr<C2LinearBlock> mBlock;
+49 −15
Original line number Diff line number Diff line
@@ -30,6 +30,36 @@

namespace android {

CryptoAsync::CryptoAsyncInfo::CryptoAsyncInfo(const std::unique_ptr<CodecCryptoInfo> &info) {
    if (info == nullptr) {
        return;
    }
    size_t key_len = (info->mKey != nullptr)? 16 : 0;
    size_t iv_len = (info->mIv != nullptr)? 16 : 0;
    mNumSubSamples = info->mNumSubSamples;
    mMode = info->mMode;
    mPattern = info->mPattern;
    if (key_len > 0) {
        mKeyBuffer = ABuffer::CreateAsCopy((void*)info->mKey, key_len);
        mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
    }
    if (iv_len > 0) {
        mIvBuffer = ABuffer::CreateAsCopy((void*)info->mIv, iv_len);
        mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
    }
    mSubSamplesBuffer =
        new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
    if (mSubSamplesBuffer.get()) {
        CryptoPlugin::SubSample * samples =
           (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
        for (int s = 0 ; s < mNumSubSamples ; s++) {
            samples[s].mNumBytesOfClearData = info->mSubSamples[s].mNumBytesOfClearData;
            samples[s].mNumBytesOfEncryptedData = info->mSubSamples[s].mNumBytesOfEncryptedData;
        }
        mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
    }
}

CryptoAsync::~CryptoAsync() {
}

@@ -79,23 +109,27 @@ status_t CryptoAsync::decryptAndQueue(sp<AMessage> & msg) {
    sp<ABuffer> keyBuffer;
    sp<ABuffer> ivBuffer;
    sp<ABuffer> subSamplesBuffer;
    AString errorDetailMsg;
    msg->findObject("buffer", &obj);
    msg->findInt32("secure", &secure);
    sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
    if (buffer->meta()->findObject("cryptoInfos", &obj)) {
        err = channel->queueSecureInputBuffers(buffer, secure, &errorDetailMsg);
    } else {
        msg->findInt32("encryptBlocks", (int32_t*)&pattern.mEncryptBlocks);
        msg->findInt32("skipBlocks", (int32_t*)&pattern.mSkipBlocks);
        msg->findBuffer("key", &keyBuffer);
        msg->findBuffer("iv", &ivBuffer);
        msg->findBuffer("subSamples", &subSamplesBuffer);
    msg->findInt32("secure", &secure);
        msg->findSize("numSubSamples", &numSubSamples);
    msg->findObject("buffer", &obj);
        msg->findInt32("mode", (int32_t*)&mode);
    AString errorDetailMsg;
        const uint8_t * key = keyBuffer.get() != nullptr ? keyBuffer.get()->data() : nullptr;
        const uint8_t * iv = ivBuffer.get() != nullptr ? ivBuffer.get()->data() : nullptr;
        const CryptoPlugin::SubSample * subSamples =
           (CryptoPlugin::SubSample *)(subSamplesBuffer.get()->data());
    sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
        err = channel->queueSecureInputBuffer(buffer, secure, key, iv, mode,
            pattern, subSamples, numSubSamples, &errorDetailMsg);
    }
    if (err != OK) {
        std::list<sp<AMessage>> errorList;
        msg->removeEntryByName("buffer");
Loading