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

Commit 9c930d0c authored by Robert Shih's avatar Robert Shih
Browse files

ICrypto: remove binder inheritance

Bug: 134787536
Test: GtsMediaTestCases
Change-Id: Id67dc9e793ee886e4cc49370d800c7f3580df313
parent e6cbccae
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ cc_library_shared {
    srcs: [
        "DrmPluginPath.cpp",
        "DrmSessionManager.cpp",
        "ICrypto.cpp",
        "IDrm.cpp",
        "IDrmClient.cpp",
        "IMediaDrmService.cpp",

drm/libmediadrm/ICrypto.cpp

deleted100644 → 0
+0 −475
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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 "ICrypto"
#include <binder/Parcel.h>
#include <binder/IMemory.h>
#include <cutils/log.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
#include <mediadrm/ICrypto.h>
#include <utils/Log.h>

namespace android {

enum {
    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
    IS_CRYPTO_SUPPORTED,
    CREATE_PLUGIN,
    DESTROY_PLUGIN,
    REQUIRES_SECURE_COMPONENT,
    DECRYPT,
    NOTIFY_RESOLUTION,
    SET_MEDIADRM_SESSION,
    SET_HEAP,
    UNSET_HEAP,
};

struct BpCrypto : public BpInterface<ICrypto> {
    explicit BpCrypto(const sp<IBinder> &impl)
        : BpInterface<ICrypto>(impl) {
    }

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

        return reply.readInt32();
    }

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

        return reply.readInt32() != 0;
    }

    virtual status_t createPlugin(
            const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.write(uuid, 16);
        data.writeInt32(opaqueSize);

        if (opaqueSize > 0) {
            data.write(opaqueData, opaqueSize);
        }

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

        return reply.readInt32();
    }

    virtual status_t destroyPlugin() {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        remote()->transact(DESTROY_PLUGIN, data, &reply);

        return reply.readInt32();
    }

    virtual bool requiresSecureDecoderComponent(
            const char *mime) const {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.writeCString(mime);
        remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);

        return reply.readInt32() != 0;
    }

    virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
            const SourceBuffer &source, size_t offset,
            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
            const DestinationBuffer &destination, AString *errorDetailMsg) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.writeInt32(mode);
        data.writeInt32(pattern.mEncryptBlocks);
        data.writeInt32(pattern.mSkipBlocks);

        static const uint8_t kDummy[16] = { 0 };

        if (key == NULL) {
            key = kDummy;
        }

        if (iv == NULL) {
            iv = kDummy;
        }

        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(totalSize);
        data.writeStrongBinder(IInterface::asBinder(source.mSharedMemory));
        data.writeInt32(source.mHeapSeqNum);
        data.writeInt32(offset);

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

        data.writeInt32((int32_t)destination.mType);
        if (destination.mType == kDestinationTypeNativeHandle) {
            if (destination.mHandle == NULL) {
                return BAD_VALUE;
            }
            data.writeNativeHandle(destination.mHandle);
        } else {
            if (destination.mSharedMemory == NULL) {
                return BAD_VALUE;
            }
            data.writeStrongBinder(IInterface::asBinder(destination.mSharedMemory));
        }

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

        ssize_t result = reply.readInt32();

        if (isCryptoError(result)) {
            AString msg = reply.readCString();
            if (errorDetailMsg) {
                *errorDetailMsg = msg;
            }
        }

        return result;
    }

    virtual void notifyResolution(
        uint32_t width, uint32_t height) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.writeInt32(width);
        data.writeInt32(height);
        remote()->transact(NOTIFY_RESOLUTION, data, &reply);
    }

    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());

        writeVector(data, sessionId);
        remote()->transact(SET_MEDIADRM_SESSION, data, &reply);

        return reply.readInt32();
    }

    virtual int32_t setHeap(const sp<IMemoryHeap> &heap) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.writeStrongBinder(IInterface::asBinder(heap));
        status_t err = remote()->transact(SET_HEAP, data, &reply);
        if (err != NO_ERROR) {
            return -1;
        }
        int32_t seqNum;
        if (reply.readInt32(&seqNum) != NO_ERROR) {
            return -1;
        }
        return seqNum;
    }

    virtual void unsetHeap(int32_t seqNum) {
        Parcel data, reply;
        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
        data.writeInt32(seqNum);
        remote()->transact(UNSET_HEAP, data, &reply);
        return;
    }


private:
    void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
        uint32_t size = reply.readInt32();
        vector.insertAt((size_t)0, size);
        reply.read(vector.editArray(), size);
    }

    void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
        data.writeInt32(vector.size());
        data.write(vector.array(), vector.size());
    }

    DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
};

IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");

////////////////////////////////////////////////////////////////////////////////

void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
    uint32_t size = data.readInt32();
    if (vector.insertAt((size_t)0, size) < 0) {
        vector.clear();
    }
    if (data.read(vector.editArray(), size) != NO_ERROR) {
        vector.clear();
        android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
    }
}

void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
    reply->writeInt32(vector.size());
    reply->write(vector.array(), vector.size());
}

status_t BnCrypto::onTransact(
    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
    switch (code) {
        case INIT_CHECK:
        {
            CHECK_INTERFACE(ICrypto, data, reply);
            reply->writeInt32(initCheck());

            return OK;
        }

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

            return OK;
        }

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

            uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));

            size_t opaqueSize = data.readInt32();
            void *opaqueData = NULL;

            const size_t kMaxOpaqueSize = 100 * 1024;
            if (opaqueSize > kMaxOpaqueSize) {
                return BAD_VALUE;
            }

            opaqueData = malloc(opaqueSize);
            if (NULL == opaqueData) {
                return NO_MEMORY;
            }

            data.read(opaqueData, opaqueSize);
            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));

            free(opaqueData);
            opaqueData = NULL;

            return OK;
        }

        case DESTROY_PLUGIN:
        {
            CHECK_INTERFACE(ICrypto, data, reply);
            reply->writeInt32(destroyPlugin());

            return OK;
        }

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

            const char *mime = data.readCString();
            if (mime == NULL) {
                reply->writeInt32(BAD_VALUE);
            } else {
                reply->writeInt32(requiresSecureDecoderComponent(mime));
            }

            return OK;
        }

        case DECRYPT:
        {
            CHECK_INTERFACE(ICrypto, data, reply);

            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
            CryptoPlugin::Pattern pattern;
            pattern.mEncryptBlocks = data.readInt32();
            pattern.mSkipBlocks = data.readInt32();

            uint8_t key[16];
            data.read(key, sizeof(key));

            uint8_t iv[16];
            data.read(iv, sizeof(iv));

            size_t totalSize = data.readInt32();

            SourceBuffer source;

            source.mSharedMemory =
                interface_cast<IMemory>(data.readStrongBinder());
            if (source.mSharedMemory == NULL) {
                reply->writeInt32(BAD_VALUE);
                return OK;
            }
            source.mHeapSeqNum = data.readInt32();

            int32_t offset = data.readInt32();

            int32_t numSubSamples = data.readInt32();
            if (numSubSamples < 0 || numSubSamples > 0xffff) {
                reply->writeInt32(BAD_VALUE);
                return OK;
            }

            std::unique_ptr<CryptoPlugin::SubSample[]> subSamples =
                    std::make_unique<CryptoPlugin::SubSample[]>(numSubSamples);

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

            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;
                }
                sp<IMemory> dest = destination.mSharedMemory;
                if (totalSize > dest->size() ||
                        (size_t)dest->offset() > dest->size() - totalSize) {
                    reply->writeInt32(BAD_VALUE);
                    android_errorWriteLog(0x534e4554, "71389378");
                    return OK;
                }
            } else {
                reply->writeInt32(BAD_VALUE);
                android_errorWriteLog(0x534e4554, "70526702");
                return OK;
            }

            AString errorDetailMsg;
            ssize_t result;

            size_t sumSubsampleSizes = 0;
            bool overflow = false;
            for (int32_t i = 0; i < numSubSamples; ++i) {
                CryptoPlugin::SubSample &ss = subSamples[i];
                if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
                    sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
                } else {
                    overflow = true;
                }
                if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
                    sumSubsampleSizes += ss.mNumBytesOfClearData;
                } else {
                    overflow = true;
                }
            }

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

            reply->writeInt32(result);

            if (isCryptoError(result)) {
                reply->writeCString(errorDetailMsg.c_str());
            }

            if (destination.mType == kDestinationTypeNativeHandle) {
                int err;
                if ((err = native_handle_close(destination.mHandle)) < 0) {
                    ALOGW("secure buffer native_handle_close failed: %d", err);
                }
                if ((err = native_handle_delete(destination.mHandle)) < 0) {
                    ALOGW("secure buffer native_handle_delete failed: %d", err);
                }
            }

            subSamples.reset();
            return OK;
        }

        case NOTIFY_RESOLUTION:
        {
            CHECK_INTERFACE(ICrypto, data, reply);

            int32_t width = data.readInt32();
            int32_t height = data.readInt32();
            notifyResolution(width, height);

            return OK;
        }

        case SET_MEDIADRM_SESSION:
        {
            CHECK_INTERFACE(IDrm, data, reply);
            Vector<uint8_t> sessionId;
            readVector(data, sessionId);
            reply->writeInt32(setMediaDrmSession(sessionId));
            return OK;
        }

        case SET_HEAP:
        {
            CHECK_INTERFACE(ICrypto, data, reply);
            sp<IMemoryHeap> heap =
                interface_cast<IMemoryHeap>(data.readStrongBinder());
            reply->writeInt32(setHeap(heap));
            return OK;
        }

        case UNSET_HEAP:
        {
            CHECK_INTERFACE(ICrypto, data, reply);
            int32_t seqNum = data.readInt32();
            unsetHeap(seqNum);
            return OK;
        }

        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

}  // namespace android
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ class IMemoryHeap;

namespace android {

struct CryptoHal : public BnCrypto {
struct CryptoHal : public ICrypto {
    CryptoHal();
    virtual ~CryptoHal();

+8 −12
Original line number Diff line number Diff line
@@ -14,10 +14,11 @@
 * limitations under the License.
 */

#include <binder/IInterface.h>
#include <cutils/native_handle.h>
#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>

#ifndef ANDROID_ICRYPTO_H_

@@ -29,8 +30,9 @@ struct AString;
class IMemory;
class IMemoryHeap;

struct ICrypto : public IInterface {
    DECLARE_META_INTERFACE(Crypto);
struct ICrypto : public RefBase {

    virtual ~ICrypto() {}

    virtual status_t initCheck() const = 0;

@@ -79,17 +81,11 @@ struct ICrypto : public IInterface {
    virtual int32_t setHeap(const sp<IMemoryHeap>& heap) = 0;
    virtual void unsetHeap(int32_t seqNum) = 0;

private:
    DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
};
protected:
    ICrypto() {}

struct BnCrypto : public BnInterface<ICrypto> {
    virtual status_t onTransact(
            uint32_t code, const Parcel &data, Parcel *reply,
            uint32_t flags = 0);
private:
    void readVector(const Parcel &data, Vector<uint8_t> &vector) const;
    void writeVector(Parcel *reply, Vector<uint8_t> const &vector) const;
    DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
};

}  // namespace android