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

Commit a4b27bb0 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Implementing CryptoAsync"

parents a0d32ed3 8024460e
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -238,6 +238,7 @@ cc_library {
        "CallbackMediaSource.cpp",
        "CallbackMediaSource.cpp",
        "CameraSource.cpp",
        "CameraSource.cpp",
        "CameraSourceTimeLapse.cpp",
        "CameraSourceTimeLapse.cpp",
        "CryptoAsync.cpp",
        "FrameDecoder.cpp",
        "FrameDecoder.cpp",
        "HevcUtils.cpp",
        "HevcUtils.cpp",
        "InterfaceUtils.cpp",
        "InterfaceUtils.cpp",
+289 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "CryptoAsync"

#include <log/log.h>

#include "hidl/HidlSupport.h"
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>

#include <media/MediaCodecBuffer.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/CryptoAsync.h>

namespace android {

CryptoAsync::~CryptoAsync() {
}

status_t CryptoAsync::decrypt(sp<AMessage> &msg) {
    int32_t decryptAction;
    CHECK(msg->findInt32("action", &decryptAction));
    if (mCallback == nullptr) {
       ALOGE("Crypto callback channel is not set");
       return -ENOSYS;
    }
    bool shouldPost = false;
    Mutexed<std::list<sp<AMessage>>>::Locked pendingBuffers(mPendingBuffers);
    if (mState != kCryptoAsyncActive) {
       ALOGE("Cannot decrypt in errored state");
       return -ENOSYS;
    }
    shouldPost = pendingBuffers->size() == 0 ? true : false;
    pendingBuffers->push_back(std::move(msg));
    if (shouldPost) {
       sp<AMessage> decryptMsg = new AMessage(kWhatDecrypt, this);
       decryptMsg->post();
    }
    return OK;
}

void CryptoAsync::stop(std::list<sp<AMessage>> * const buffers) {
    sp<AMessage>  stopMsg = new AMessage(kWhatStop, this);
    stopMsg->setPointer("remaining", static_cast<void*>(buffers));
    sp<AMessage> response;
    status_t err = stopMsg->postAndAwaitResponse(&response);
    if (err == OK && response != NULL) {
        CHECK(response->findInt32("err", &err));
    } else {
        ALOGE("Error handling stop in CryptoAsync");
        //TODO: handle the error here.
    }
}

status_t CryptoAsync::decryptAndQueue(sp<AMessage> & msg) {
    std::shared_ptr<BufferChannelBase> channel = mBufferChannel.lock();
    status_t err = OK;
    sp<RefBase> obj;
    size_t numSubSamples = 0;
    int32_t secure = 0;
    CryptoPlugin::Mode mode;
    CryptoPlugin::Pattern pattern;
    sp<ABuffer> keyBuffer;
    sp<ABuffer> ivBuffer;
    sp<ABuffer> subSamplesBuffer;
    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");
        msg->setInt32("err", err);
        msg->setInt32("actionCode", ACTION_CODE_FATAL);
        msg->setString("errorDetail", errorDetailMsg);
        errorList.push_back(std::move(msg));
        mCallback->onDecryptError(errorList);
   }
   return err;
}

status_t CryptoAsync::attachEncryptedBufferAndQueue(sp<AMessage> & msg) {
    std::shared_ptr<BufferChannelBase> channel = mBufferChannel.lock();
    status_t err = OK;
    sp<RefBase> obj;
    sp<RefBase> mem_obj;
    sp<hardware::HidlMemory> memory;
    size_t numSubSamples = 0;
    int32_t secure = 0;
    size_t offset;
    size_t size;
    CryptoPlugin::Mode mode;
    CryptoPlugin::Pattern pattern;
    sp<ABuffer> keyBuffer;
    sp<ABuffer> ivBuffer;
    sp<ABuffer> subSamplesBuffer;
    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);
    CHECK(msg->findObject("memory", &mem_obj));
    CHECK(msg->findSize("offset", (size_t*)&offset));
    AString errorDetailMsg;
    // get key info
    const uint8_t * key = keyBuffer.get() != nullptr ? keyBuffer.get()->data() : nullptr;
    // get iv info
    const uint8_t * iv = ivBuffer.get() != nullptr ? ivBuffer.get()->data() : nullptr;

    const CryptoPlugin::SubSample * subSamples =
     (CryptoPlugin::SubSample *)(subSamplesBuffer.get()->data());

    // get MediaCodecBuffer
    sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());

    // get HidlMemory
    memory = static_cast<MediaCodec::WrapperObject<sp<hardware::HidlMemory>> *>
        (mem_obj.get())->value;

    // attach buffer
    err = channel->attachEncryptedBuffer(
        memory, secure, key, iv, mode, pattern,
        offset, subSamples, numSubSamples, buffer);

    // a generic error
    auto handleError = [this, &err, &msg]() {
        std::list<sp<AMessage>> errorList;
        msg->removeEntryByName("buffer");
        msg->setInt32("err", err);
        msg->setInt32("actionCode", ACTION_CODE_FATAL);
        errorList.push_back(std::move(msg));
        mCallback->onDecryptError(errorList);
    };
    if (err != OK) {
        handleError();
        return err;
     }
     offset = buffer->offset();
     size = buffer->size();

    if (offset + size > buffer->capacity()) {
        err = -ENOSYS;
        handleError();
        return err;
    }
    buffer->setRange(offset, size);
    err = channel->queueInputBuffer(buffer);
    if (err != OK) {
        handleError();
        return err;
    }
   return err;
}

void CryptoAsync::onMessageReceived(const sp<AMessage> & msg) {
    status_t err = OK;
    auto getCurrentAndNextTask =
        [this](sp<AMessage> * const  current, uint32_t & nextTask) -> status_t {
        sp<AMessage> obj;
        Mutexed<std::list<sp<AMessage>>>::Locked pendingBuffers(mPendingBuffers);
        if ((pendingBuffers->size() == 0) || (mState != kCryptoAsyncActive)) {
           return -ENOMSG;
        }
        *current = std::move(*(pendingBuffers->begin()));
        pendingBuffers->pop_front();
        //Try to see if we will be able to process next buffer
        while((nextTask == kWhatDoNothing) && pendingBuffers->size() > 0)
        {
            sp<AMessage> & nextBuffer = pendingBuffers->front();
            if (nextBuffer == nullptr) {
                pendingBuffers->pop_front();
                continue;
            }
            nextTask = kWhatDecrypt;
        }
        return OK;
    };
    switch(msg->what()) {
        case kWhatDecrypt:
        {
            sp<AMessage> thisMsg;
            uint32_t nextTask = kWhatDoNothing;
            if(OK != getCurrentAndNextTask(&thisMsg, nextTask)) {
                return;
            }
            if (thisMsg != nullptr) {
                int32_t action;
                err = OK;
                CHECK(thisMsg->findInt32("action", &action));
                switch(action) {
                    case kActionDecrypt:
                    {
                        err = decryptAndQueue(thisMsg);
                        break;
                    }

                    case kActionAttachEncryptedBuffer:
                    {
                        err = attachEncryptedBufferAndQueue(thisMsg);
                        break;
                    }

                    default:
                    {
                        ALOGE("Unrecognized action in decrypt");
                    }
                }
                if (err != OK) {
                    Mutexed<std::list<sp<AMessage>>>::Locked pendingBuffers(mPendingBuffers);
                    mState = kCryptoAsyncError;
                }
            }
            // we won't take  next buffers if buffer caused
            // an error. We want the caller to deal with the error first
            // Expected behahiour is that the caller acknowledge the error
            // with a call to stop() which clear the queues.
            // Then move forward with processing of next set of buffers.
            if (mState == kCryptoAsyncActive && nextTask != kWhatDoNothing) {
                sp<AMessage> nextMsg = new AMessage(nextTask,this);
                nextMsg->post();
            }
            break;
        }

        case kWhatStop:
        {
            typedef std::list<sp<AMessage>> ReturnListType;
            ReturnListType * returnList = nullptr;
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));
            sp<AMessage> response = new AMessage;
            msg->findPointer("remaining", (void**)(&returnList));
            Mutexed<std::list<sp<AMessage>>>::Locked pendingBuffers(mPendingBuffers);
            if (returnList) {
                returnList->clear();
                returnList->splice(returnList->end(), std::move(*pendingBuffers));
            }
            pendingBuffers->clear();
            mState = kCryptoAsyncActive;
            response->setInt32("err", OK);
            response->postReply(replyID);

            break;
        }

        default:
        {
            status_t err = OK;
            //TODO: do something with error here.
            (void)err;
            break;
        }
    }
}

}  // namespace android
+190 −63

File changed.

Preview size limit exceeded, changes collapsed.

+139 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef CRYPTO_ASYNC_H_
#define CRYPTO_ASYNC_H_

#include <media/stagefright/CodecBase.h>
#include <media/stagefright/foundation/Mutexed.h>
namespace android {

class CryptoAsync: public AHandler {
public:

    class CryptoAsyncCallback {
    public:

        virtual ~CryptoAsyncCallback() = default;

        /*
         * Callback with result for queuing the decrypted buffer to the
         * underlying codec. Cannot block this function
         */
        virtual void onDecryptComplete(const sp<AMessage>& result) = 0;

        /*
         * Callback with error information while decryption. Cannot block
         * this call. The return should contain the error information
         * and the buffer the caused the error.
         */
        virtual void onDecryptError(const std::list<sp<AMessage>>& errorMsg) = 0;
    };

    // Ideally we should be returning the output of the decryption in
    // onDecryptComple() calback and let the next module take over the
    // rest of the processing. In the current state, the next step will
    // be to queue the output the codec which is done using BufferChannel

    // In order to prevent thread hop to just do that, we have created
    // a dependency on BufferChannel here to queue the buffer to the codec
    // immediately after decryption.
    CryptoAsync(std::weak_ptr<BufferChannelBase> bufferChannel)
        :mState(kCryptoAsyncActive) {
        mBufferChannel = std::move(bufferChannel);
    }

    // Destructor
    virtual ~CryptoAsync();

    inline void setCallback(std::unique_ptr<CryptoAsyncCallback>&& callback) {
        mCallback = std::move(callback);
    }

    // Call this function to decrypt the buffer in the message.
    status_t decrypt(sp<AMessage>& msg);

    // This function stops further processing in the thread and returns
    // with any unprocessed buffers from the queue.
    // We can use this method in case of flush or clearing the queue
    // upon error. When the processing hits an error, the self processing
    // in this looper stops and in-fact., there is a need to clear (call stop())
    // for the queue to become operational again. Also acts like a rest.
    void stop(std::list<sp<AMessage>> * const buffers = nullptr);

    // Describes two actions for decrypt();
    // kActionDecrypt - decrypts the buffer and queues to codec
    // kActionAttachEncryptedBuffer - decrypts and attaches the buffer
    //                               and queues to the codec.
    // TODO: kActionAttachEncryptedBuffer is meant to work with
    // BLOCK_MODEL which is not yet implemented.
    enum : uint32_t {
        // decryption types
        kActionDecrypt                 = (1 <<  0),
        kActionAttachEncryptedBuffer   = (1 <<  1)
    };
protected:

    // Message types for the looper
    enum : uint32_t {
        // used with decrypt()
        // Exact decryption type as described by the above enum
        // decides what "action" to take. The "action" should be
        // part of this message
        kWhatDecrypt         = 1,
        // used with stop()
        kWhatStop            = 2,
        // place holder
        kWhatDoNothing       = 10
    };

    // Defines the staste of this thread.
    typedef enum : uint32_t {
        // kCryptoAsyncActive as long as we have not encountered
        // any errors during processing. Any errors will
        // put the state to error and the thread now refuses to
        // do further processing until the error state is cleared
        // with a call to stop()

        kCryptoAsyncActive  = (0 <<  0),
        // state of the looper when encountered with error during
        // processing
        kCryptoAsyncError   = (1 <<  8)
    } CryptoAsyncState;

    // Implements kActionDecrypt
    status_t decryptAndQueue(sp<AMessage>& msg);

    // Implements kActionAttachEncryptedBuffer
    status_t attachEncryptedBufferAndQueue(sp<AMessage>& msg);

    // Implements the Looper
    void onMessageReceived(const sp<AMessage>& msg) override;

    std::unique_ptr<CryptoAsyncCallback> mCallback;
private:

    CryptoAsyncState mState;

    // Queue holding any pending buffers
    Mutexed<std::list<sp<AMessage>>> mPendingBuffers;

    std::weak_ptr<BufferChannelBase> mBufferChannel;
};

}  // namespace android

#endif  // CRYPTO_ASYNC_H_
+7 −0
Original line number Original line Diff line number Diff line
@@ -55,6 +55,7 @@ struct CodecBase;
struct CodecParameterDescriptor;
struct CodecParameterDescriptor;
class IBatteryStats;
class IBatteryStats;
struct ICrypto;
struct ICrypto;
class CryptoAsync;
class MediaCodecBuffer;
class MediaCodecBuffer;
class IMemory;
class IMemory;
struct PersistentSurface;
struct PersistentSurface;
@@ -82,6 +83,7 @@ struct MediaCodec : public AHandler {
    enum ConfigureFlags {
    enum ConfigureFlags {
        CONFIGURE_FLAG_ENCODE           = 1,
        CONFIGURE_FLAG_ENCODE           = 1,
        CONFIGURE_FLAG_USE_BLOCK_MODEL  = 2,
        CONFIGURE_FLAG_USE_BLOCK_MODEL  = 2,
        CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4,
    };
    };


    enum BufferFlags {
    enum BufferFlags {
@@ -106,6 +108,7 @@ struct MediaCodec : public AHandler {
        CB_ERROR = 3,
        CB_ERROR = 3,
        CB_OUTPUT_FORMAT_CHANGED = 4,
        CB_OUTPUT_FORMAT_CHANGED = 4,
        CB_RESOURCE_RECLAIMED = 5,
        CB_RESOURCE_RECLAIMED = 5,
        CB_CRYPTO_ERROR = 6,
    };
    };


    static const pid_t kNoPid = -1;
    static const pid_t kNoPid = -1;
@@ -376,6 +379,7 @@ private:
        kFlagIsComponentAllocated       = 2048,
        kFlagIsComponentAllocated       = 2048,
        kFlagPushBlankBuffersOnShutdown = 4096,
        kFlagPushBlankBuffersOnShutdown = 4096,
        kFlagUseBlockModel              = 8192,
        kFlagUseBlockModel              = 8192,
        kFlagUseCryptoAsync             = 16384,
    };
    };


    struct BufferInfo {
    struct BufferInfo {
@@ -530,6 +534,8 @@ private:
    bool mCpuBoostRequested;
    bool mCpuBoostRequested;


    std::shared_ptr<BufferChannelBase> mBufferChannel;
    std::shared_ptr<BufferChannelBase> mBufferChannel;
    sp<CryptoAsync> mCryptoAsync;
    sp<ALooper> mCryptoLooper;


    std::unique_ptr<PlaybackDurationAccumulator> mPlaybackDurationAccumulator;
    std::unique_ptr<PlaybackDurationAccumulator> mPlaybackDurationAccumulator;
    bool mIsSurfaceToScreen;
    bool mIsSurfaceToScreen;
@@ -583,6 +589,7 @@ private:


    void onInputBufferAvailable();
    void onInputBufferAvailable();
    void onOutputBufferAvailable();
    void onOutputBufferAvailable();
    void onCryptoError(const sp<AMessage> &msg);
    void onError(status_t err, int32_t actionCode, const char *detail = NULL);
    void onError(status_t err, int32_t actionCode, const char *detail = NULL);
    void onOutputFormatChanged();
    void onOutputFormatChanged();