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

Commit 29bcb384 authored by Jeff Tinker's avatar Jeff Tinker Committed by Android (Google) Code Review
Browse files

Merge "Implement client code to use Drm and Crypto HALs"

parents 6b2704c8 a53d6553
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -7,14 +7,21 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    Crypto.cpp \
    Drm.cpp \
    DrmSessionManager.cpp \
    ICrypto.cpp \
    IDrm.cpp \
    IDrmClient.cpp \
    IMediaDrmService.cpp \
    SharedLibrary.cpp
ifeq ($(ENABLE_TREBLE_DRM), true)
LOCAL_SRC_FILES += \
    DrmHal.cpp \
    CryptoHal.cpp
else
LOCAL_SRC_FILES += \
    Drm.cpp \
    Crypto.cpp
endif

LOCAL_SHARED_LIBRARIES := \
    libbinder \
@@ -24,6 +31,13 @@ LOCAL_SHARED_LIBRARIES := \
    libmediautils \
    libstagefright_foundation \
    libutils
ifeq ($(ENABLE_TREBLE_DRM), true)
LOCAL_SHARED_LIBRARIES += \
    android.hidl.base@1.0 \
    android.hardware.drm@1.0 \
    libhidlbase \
    libhidlmemory
endif

LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall

+19 −14
Original line number Diff line number Diff line
@@ -233,16 +233,12 @@ bool Crypto::requiresSecureDecoderComponent(const char *mime) const {
    return mPlugin->requiresSecureDecoderComponent(mime);
}

ssize_t Crypto::decrypt(
        DestinationType dstType,
        const uint8_t key[16],
        const uint8_t iv[16],
        CryptoPlugin::Mode mode,
        const CryptoPlugin::Pattern &pattern,
        const sp<IMemory> &sharedBuffer, size_t offset,
ssize_t Crypto::decrypt(const uint8_t key[16], const uint8_t iv[16],
        CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
        const sp<IMemory> &source, size_t offset,
        const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
        void *dstPtr,
        AString *errorDetailMsg) {
        const ICrypto::DestinationBuffer &destination, AString *errorDetailMsg) {

    Mutex::Autolock autoLock(mLock);

    if (mInitCheck != OK) {
@@ -253,12 +249,21 @@ ssize_t Crypto::decrypt(
        return -EINVAL;
    }

    const void *srcPtr = static_cast<uint8_t *>(sharedBuffer->pointer()) + offset;
    const void *srcPtr = static_cast<uint8_t *>(source->pointer()) + offset;

    void *destPtr;
    bool secure = false;
    if (destination.mType == kDestinationTypeNativeHandle) {
        destPtr = static_cast<void *>(destination.mHandle);
        secure = true;
    } else {
        destPtr = destination.mSharedMemory->pointer();
    }

    ssize_t result = mPlugin->decrypt(secure, key, iv, mode, pattern, srcPtr, subSamples,
            numSubSamples, destPtr, errorDetailMsg);

    return mPlugin->decrypt(
            dstType != kDestinationTypeVmPointer,
            key, iv, mode, pattern, srcPtr, subSamples, numSubSamples, dstPtr,
            errorDetailMsg);
    return result;
}

void Crypto::notifyResolution(uint32_t width, uint32_t height) {
+328 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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 "CryptoHal"
#include <utils/Log.h>
#include <dirent.h>
#include <dlfcn.h>

#include <android/hardware/drm/1.0/types.h>

#include <binder/IMemory.h>
#include <cutils/native_handle.h>
#include <media/CryptoHal.h>
#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>

using ::android::hardware::drm::V1_0::BufferType;
using ::android::hardware::drm::V1_0::DestinationBuffer;
using ::android::hardware::drm::V1_0::ICryptoFactory;
using ::android::hardware::drm::V1_0::ICryptoPlugin;
using ::android::hardware::drm::V1_0::Mode;
using ::android::hardware::drm::V1_0::Pattern;
using ::android::hardware::drm::V1_0::SharedBuffer;
using ::android::hardware::drm::V1_0::Status;
using ::android::hardware::drm::V1_0::SubSample;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;


namespace android {

static status_t toStatusT(Status status) {
    switch (status) {
    case Status::OK:
        return OK;
    case Status::ERROR_DRM_NO_LICENSE:
        return ERROR_DRM_NO_LICENSE;
    case Status::ERROR_DRM_LICENSE_EXPIRED:
        return ERROR_DRM_LICENSE_EXPIRED;
    case Status::ERROR_DRM_RESOURCE_BUSY:
        return ERROR_DRM_RESOURCE_BUSY;
    case Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
        return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
    case Status::ERROR_DRM_SESSION_NOT_OPENED:
        return ERROR_DRM_SESSION_NOT_OPENED;
    case Status::ERROR_DRM_CANNOT_HANDLE:
        return ERROR_DRM_CANNOT_HANDLE;
    default:
        return UNKNOWN_ERROR;
    }
}


static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
    hidl_vec<uint8_t> vec;
    vec.setToExternal(const_cast<uint8_t *>(vector.array()), vector.size());
    return vec;
}

static hidl_vec<uint8_t> toHidlVec(const void *ptr, size_t size) {
    hidl_vec<uint8_t> vec;
    vec.resize(size);
    memcpy(vec.data(), ptr, size);
    return vec;
}

static hidl_array<uint8_t, 16> toHidlArray16(const uint8_t *ptr) {
    if (!ptr) {
        return hidl_array<uint8_t, 16>();
    }
    return hidl_array<uint8_t, 16>(ptr);
}


static ::SharedBuffer toSharedBuffer(const sp<IMemory>& sharedBuffer) {
    ssize_t offset;
    size_t size;
    sharedBuffer->getMemory(&offset, &size);

    ::SharedBuffer buffer;
    buffer.offset = offset >= 0 ? offset : 0;
    buffer.size = size;
    return buffer;
}

static String8 toString8(hidl_string hString) {
    return String8(hString.c_str());
}


CryptoHal::CryptoHal()
    : mFactory(makeCryptoFactory()),
      mInitCheck((mFactory == NULL) ? ERROR_UNSUPPORTED : NO_INIT),
      mHeapBase(NULL) {
}

CryptoHal::~CryptoHal() {
}


sp<ICryptoFactory> CryptoHal::makeCryptoFactory() {
    sp<ICryptoFactory> factory = ICryptoFactory::getService("crypto");
    if (factory == NULL) {
        ALOGE("Failed to make crypto factory");
    }
    return factory;
}

sp<ICryptoPlugin> CryptoHal::makeCryptoPlugin(const uint8_t uuid[16],
        const void *initData, size_t initDataSize) {
    if (mFactory == NULL){
        return NULL;
    }

    sp<ICryptoPlugin> plugin;
    Return<void> hResult = mFactory->createPlugin(toHidlArray16(uuid),
            toHidlVec(initData, initDataSize),
            [&](Status status, const sp<ICryptoPlugin>& hPlugin) {
                if (status != Status::OK) {
                    ALOGE("Failed to make crypto plugin");
                    return;
                }
                plugin = hPlugin;
            }
        );
    return plugin;
}


status_t CryptoHal::initCheck() const {
    return mInitCheck;
}


bool CryptoHal::isCryptoSchemeSupported(const uint8_t uuid[16]) {
    Mutex::Autolock autoLock(mLock);
    if (mFactory != NULL) {
        return mFactory->isCryptoSchemeSupported(uuid);
    }
    return false;
}

status_t CryptoHal::createPlugin(
        const uint8_t uuid[16], const void *data, size_t size) {
    Mutex::Autolock autoLock(mLock);

    mPlugin = makeCryptoPlugin(uuid, data, size);

    if (mPlugin == NULL) {
        mInitCheck = ERROR_UNSUPPORTED;
    } else {
        mInitCheck = OK;
    }

    return mInitCheck;
}

status_t CryptoHal::destroyPlugin() {
    Mutex::Autolock autoLock(mLock);

    if (mInitCheck != OK) {
        return mInitCheck;
    }

    mPlugin.clear();
    return OK;
}

bool CryptoHal::requiresSecureDecoderComponent(const char *mime) const {
    Mutex::Autolock autoLock(mLock);

    if (mInitCheck != OK) {
        return mInitCheck;
    }

    return mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
}


/**
 * If the heap base isn't set, get the heap base from the IMemory
 * and send it to the HAL so it can map a remote heap of the same
 * size.  Once the heap base is established, shared memory buffers
 * are sent by providing an offset into the heap and a buffer size.
 */
status_t CryptoHal::setHeapBase(const sp<IMemory>& sharedBuffer) {
    sp<IMemoryHeap> heap = sharedBuffer->getMemory(NULL, NULL);
    if (mHeapBase != heap->getBase()) {
        int fd = heap->getHeapID();
        native_handle_t* nativeHandle = native_handle_create(1, 0);
        nativeHandle->data[0] = fd;
        auto hidlHandle = hidl_handle(nativeHandle);
        auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
        mHeapBase = heap->getBase();
        Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory);
        if (!hResult.isOk()) {
            return DEAD_OBJECT;
        }
    }
    return OK;
}

ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
        CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
        const sp<IMemory> &source, size_t offset,
        const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
        const ICrypto::DestinationBuffer &destination, AString *errorDetailMsg) {
    Mutex::Autolock autoLock(mLock);

    if (mInitCheck != OK) {
        return mInitCheck;
    }

    // Establish the base of the shared memory heap
    setHeapBase(source);

    Mode hMode;
    switch(mode) {
    case CryptoPlugin::kMode_Unencrypted:
        hMode = Mode::UNENCRYPTED ;
        break;
    case CryptoPlugin::kMode_AES_CTR:
        hMode = Mode::AES_CTR;
        break;
    case CryptoPlugin::kMode_AES_WV:
        hMode = Mode::AES_CBC_CTS;
        break;
    case CryptoPlugin::kMode_AES_CBC:
        hMode = Mode::AES_CBC;
        break;
    default:
        return UNKNOWN_ERROR;
    }

    Pattern hPattern;
    hPattern.encryptBlocks = pattern.mEncryptBlocks;
    hPattern.skipBlocks = pattern.mSkipBlocks;

    std::vector<SubSample> stdSubSamples;
    for (size_t i = 0; i < numSubSamples; i++) {
        SubSample subSample;
        subSample.numBytesOfClearData = subSamples[i].mNumBytesOfClearData;
        subSample.numBytesOfEncryptedData = subSamples[i].mNumBytesOfEncryptedData;
        stdSubSamples.push_back(subSample);
    }
    auto hSubSamples = hidl_vec<SubSample>(stdSubSamples);

    bool secure;
    ::DestinationBuffer hDestination;
    if (destination.mType == kDestinationTypeSharedMemory) {
        hDestination.type = BufferType::SHARED_MEMORY;
        hDestination.nonsecureMemory = toSharedBuffer(destination.mSharedMemory);
        secure = false;
    } else {
        hDestination.type = BufferType::NATIVE_HANDLE;
        hDestination.secureMemory = hidl_handle(destination.mHandle);
        secure = true;
    }


    status_t err = UNKNOWN_ERROR;
    uint32_t bytesWritten = 0;

    Return<void> hResult = mPlugin->decrypt(secure, toHidlArray16(keyId), toHidlArray16(iv), hMode,
            hPattern, hSubSamples, toSharedBuffer(source), offset, hDestination,
            [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
                if (status == Status::OK) {
                    bytesWritten = hBytesWritten;
                    *errorDetailMsg = toString8(hDetailedError);
                }
                err = toStatusT(status);
            }
        );

    if (!hResult.isOk()) {
        err = DEAD_OBJECT;
    }

    if (err == OK) {
        return bytesWritten;
    }
    return err;
}

void CryptoHal::notifyResolution(uint32_t width, uint32_t height) {
    Mutex::Autolock autoLock(mLock);

    if (mInitCheck != OK) {
        return;
    }

    mPlugin->notifyResolution(width, height);
}

status_t CryptoHal::setMediaDrmSession(const Vector<uint8_t> &sessionId) {
    Mutex::Autolock autoLock(mLock);

    if (mInitCheck != OK) {
        return mInitCheck;
    }

    return toStatusT(mPlugin->setMediaDrmSession(toHidlVec(sessionId)));
}

}  // namespace android
+950 −0

File added.

Preview size limit exceeded, changes collapsed.

+40 −60
Original line number Diff line number Diff line
@@ -94,18 +94,13 @@ struct BpCrypto : public BpInterface<ICrypto> {
        return reply.readInt32() != 0;
    }

    virtual ssize_t decrypt(
            DestinationType dstType,
            const uint8_t key[16],
            const uint8_t iv[16],
    virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
            const sp<IMemory> &sharedBuffer, size_t offset,
            const sp<IMemory> &source, size_t offset,
            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
            void *dstPtr,
            AString *errorDetailMsg) {
            const DestinationBuffer &destination, AString *errorDetailMsg) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.writeInt32((int32_t)dstType);
        data.writeInt32(mode);
        data.writeInt32(pattern.mEncryptBlocks);
        data.writeInt32(pattern.mSkipBlocks);
@@ -130,18 +125,23 @@ struct BpCrypto : public BpInterface<ICrypto> {
        }

        data.writeInt32(totalSize);
        data.writeStrongBinder(IInterface::asBinder(sharedBuffer));
        data.writeStrongBinder(IInterface::asBinder(source));
        data.writeInt32(offset);

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

        if (dstType == kDestinationTypeNativeHandle) {
            data.writeNativeHandle(static_cast<native_handle_t *>(dstPtr));
        } else if (dstType == kDestinationTypeOpaqueHandle) {
            data.writeInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(dstPtr)));
        data.writeInt32((int32_t)destination.mType);
        if (destination.mType == kDestinationTypeNativeHandle) {
            if (destination.mHandle == NULL) {
                return BAD_VALUE;
            }
            data.writeNativeHandle(destination.mHandle);
        } else {
            dstType = kDestinationTypeVmPointer;
            if (destination.mSharedMemory == NULL) {
                return BAD_VALUE;
            }
            data.writeStrongBinder(IInterface::asBinder(destination.mSharedMemory));
        }

        remote()->transact(DECRYPT, data, &reply);
@@ -150,10 +150,6 @@ struct BpCrypto : public BpInterface<ICrypto> {

        if (isCryptoError(result)) {
            errorDetailMsg->setTo(reply.readCString());
        } else if (dstType == kDestinationTypeVmPointer) {
            // For the non-secure case, copy the decrypted
            // data from shared memory to its final destination
            memcpy(dstPtr, sharedBuffer->pointer(), result);
        }

        return result;
@@ -280,7 +276,6 @@ status_t BnCrypto::onTransact(
        {
            CHECK_INTERFACE(ICrypto, data, reply);

            DestinationType dstType = (DestinationType)data.readInt32();
            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
            CryptoPlugin::Pattern pattern;
            pattern.mEncryptBlocks = data.readInt32();
@@ -293,9 +288,9 @@ status_t BnCrypto::onTransact(
            data.read(iv, sizeof(iv));

            size_t totalSize = data.readInt32();
            sp<IMemory> sharedBuffer =
            sp<IMemory> source =
                interface_cast<IMemory>(data.readStrongBinder());
            if (sharedBuffer == NULL) {
            if (source == NULL) {
                reply->writeInt32(BAD_VALUE);
                return OK;
            }
@@ -310,21 +305,24 @@ status_t BnCrypto::onTransact(
            CryptoPlugin::SubSample *subSamples =
                    new CryptoPlugin::SubSample[numSubSamples];

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

            native_handle_t *nativeHandle = NULL;
            void *secureBufferId = NULL, *dstPtr;
            if (dstType == kDestinationTypeNativeHandle) {
                nativeHandle = data.readNativeHandle();
                dstPtr = static_cast<void *>(nativeHandle);
            } else if (dstType == kDestinationTypeOpaqueHandle) {
                secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
                dstPtr = secureBufferId;
            } else {
                dstType = kDestinationTypeVmPointer;
                dstPtr = malloc(totalSize);
            DestinationBuffer destination;
            destination.mType = (DestinationType)data.readInt32();
            if (destination.mType == kDestinationTypeNativeHandle) {
                destination.mHandle = data.readNativeHandle();
                if (destination.mHandle == NULL) {
                    reply->writeInt32(BAD_VALUE);
                    return OK;
                }
            } else if (destination.mType == kDestinationTypeSharedMemory) {
                destination.mSharedMemory =
                        interface_cast<IMemory>(data.readStrongBinder());
                if (destination.mSharedMemory == NULL) {
                    reply->writeInt32(BAD_VALUE);
                    return OK;
                }
            }

            AString errorDetailMsg;
@@ -348,20 +346,13 @@ status_t BnCrypto::onTransact(

            if (overflow || sumSubsampleSizes != totalSize) {
                result = -EINVAL;
            } else if (totalSize > sharedBuffer->size()) {
            } else if (totalSize > source->size()) {
                result = -EINVAL;
            } else if ((size_t)offset > sharedBuffer->size() - totalSize) {
            } else if ((size_t)offset > source->size() - totalSize) {
                result = -EINVAL;
            } else {
                result = decrypt(
                    dstType,
                    key,
                    iv,
                    mode, pattern,
                    sharedBuffer, offset,
                    subSamples, numSubSamples,
                    dstPtr,
                    &errorDetailMsg);
                result = decrypt(key, iv, mode, pattern, source, offset,
                        subSamples, numSubSamples, destination, &errorDetailMsg);
            }

            reply->writeInt32(result);
@@ -370,23 +361,12 @@ status_t BnCrypto::onTransact(
                reply->writeCString(errorDetailMsg.c_str());
            }

            if (dstType == kDestinationTypeVmPointer) {
                if (result >= 0) {
                    CHECK_LE(result, static_cast<ssize_t>(totalSize));
                    // For the non-secure case, pass the decrypted
                    // data back via the shared buffer rather than
                    // copying it separately over binder to avoid
                    // binder's 1MB limit.
                    memcpy(sharedBuffer->pointer(), dstPtr, result);
                }
                free(dstPtr);
                dstPtr = NULL;
            } else if (dstType == kDestinationTypeNativeHandle) {
            if (destination.mType == kDestinationTypeNativeHandle) {
                int err;
                if ((err = native_handle_close(nativeHandle)) < 0) {
                if ((err = native_handle_close(destination.mHandle)) < 0) {
                    ALOGW("secure buffer native_handle_close failed: %d", err);
                }
                if ((err = native_handle_delete(nativeHandle)) < 0) {
                if ((err = native_handle_delete(destination.mHandle)) < 0) {
                    ALOGW("secure buffer native_handle_delete failed: %d", err);
                }
            }
Loading