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

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

Merge "Add additional error conditions to MediaDrm"

parents beab72f7 b8684f3a
Loading
Loading
Loading
Loading
+50 −21
Original line number Diff line number Diff line
@@ -30,16 +30,16 @@
#include <media/stagefright/MediaErrors.h>
#include <mediadrm/CryptoHal.h>

using drm::V1_0::BufferType;
using drm::V1_0::DestinationBuffer;
using drm::V1_0::ICryptoFactory;
using drm::V1_0::ICryptoPlugin;
using drm::V1_0::Mode;
using drm::V1_0::Pattern;
using drm::V1_0::SharedBuffer;
using drm::V1_0::Status;
using drm::V1_0::SubSample;

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;
@@ -50,6 +50,7 @@ using ::android::hardware::Void;
using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::sp;

typedef drm::V1_2::Status Status_V1_2;

namespace android {

@@ -76,6 +77,18 @@ static status_t toStatusT(Status status) {
    }
}

static status_t toStatusT_1_2(Status_V1_2 status) {
    switch (status) {
    case Status_V1_2::ERROR_DRM_SESSION_LOST_STATE:
        return ERROR_DRM_SESSION_LOST_STATE;;
    case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE:
        return ERROR_DRM_FRAME_TOO_LARGE;
    case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY:
        return ERROR_DRM_INSUFFICIENT_SECURITY;
    default:
        return toStatusT(static_cast<Status>(status));
    }
}

static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
    hidl_vec<uint8_t> vec;
@@ -196,6 +209,9 @@ status_t CryptoHal::createPlugin(const uint8_t uuid[16], const void *data,
    for (size_t i = 0; i < mFactories.size(); i++) {
        if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
            mPlugin = makeCryptoPlugin(mFactories[i], uuid, data, size);
            if (mPlugin != NULL) {
                mPluginV1_2 = drm::V1_2::ICryptoPlugin::castFrom(mPlugin);
            }
        }
    }

@@ -216,6 +232,7 @@ status_t CryptoHal::destroyPlugin() {
    }

    mPlugin.clear();
    mPluginV1_2.clear();
    return OK;
}

@@ -389,8 +406,22 @@ ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
    status_t err = UNKNOWN_ERROR;
    uint32_t bytesWritten = 0;

    Return<void> hResult = mPlugin->decrypt(secure, toHidlArray16(keyId), toHidlArray16(iv), hMode,
            hPattern, hSubSamples, hSource, offset, hDestination,
    Return<void> hResult;

    if (mPluginV1_2 != NULL) {
        hResult = mPluginV1_2->decrypt_1_2(secure, toHidlArray16(keyId), toHidlArray16(iv),
                hMode, hPattern, hSubSamples, hSource, offset, hDestination,
                [&](Status_V1_2 status, uint32_t hBytesWritten, hidl_string hDetailedError) {
                    if (status == Status_V1_2::OK) {
                        bytesWritten = hBytesWritten;
                        *errorDetailMsg = toString8(hDetailedError);
                    }
                    err = toStatusT_1_2(status);
                }
            );
    } else {
        hResult = mPlugin->decrypt(secure, toHidlArray16(keyId), toHidlArray16(iv),
                hMode, hPattern, hSubSamples, hSource, offset, hDestination,
                [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
                    if (status == Status::OK) {
                        bytesWritten = hBytesWritten;
@@ -399,11 +430,9 @@ ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
                    err = toStatusT(status);
                }
            );

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

    err = hResult.isOk() ? err : DEAD_OBJECT;
    if (err == OK) {
        return bytesWritten;
    }
+149 −81
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@

using drm::V1_0::KeyedVector;
using drm::V1_0::KeyStatusType;
using drm::V1_0::KeyRequestType;
using drm::V1_0::KeyType;
using drm::V1_0::KeyValue;
using drm::V1_0::SecureStop;
@@ -60,6 +61,9 @@ using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::os::PersistableBundle;
using ::android::sp;

typedef drm::V1_1::KeyRequestType KeyRequestType_V1_1;
typedef drm::V1_2::Status Status_V1_2;

namespace {

// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
@@ -239,7 +243,7 @@ static status_t toStatusT(Status status) {
        return ERROR_DRM_CANNOT_HANDLE;
        break;
    case Status::ERROR_DRM_INVALID_STATE:
        return ERROR_DRM_TAMPER_DETECTED;
        return ERROR_DRM_INVALID_STATE;
        break;
    case Status::BAD_VALUE:
        return BAD_VALUE;
@@ -260,6 +264,19 @@ static status_t toStatusT(Status status) {
    }
}

static status_t toStatusT_1_2(Status_V1_2 status) {
    switch (status) {
    case Status_V1_2::ERROR_DRM_RESOURCE_CONTENTION:
        return ERROR_DRM_RESOURCE_CONTENTION;
    case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE:
        return ERROR_DRM_FRAME_TOO_LARGE;
    case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY:
        return ERROR_DRM_INSUFFICIENT_SECURITY;
    default:
        return toStatusT(static_cast<Status>(status));
    }
}


Mutex DrmHal::mLock;

@@ -319,8 +336,11 @@ void DrmHal::cleanup() {

    setListener(NULL);
    mInitCheck = NO_INIT;

    if (mPlugin != NULL) {
    if (mPluginV1_2 != NULL) {
        if (!mPluginV1_2->setListener(NULL).isOk()) {
            mInitCheck = DEAD_OBJECT;
        }
    } else if (mPlugin != NULL) {
        if (!mPlugin->setListener(NULL).isOk()) {
            mInitCheck = DEAD_OBJECT;
        }
@@ -532,6 +552,22 @@ Return<void> DrmHal::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
    return Void();
}

Return<void> DrmHal::sendSessionLostState(
        const hidl_vec<uint8_t>& sessionId) {

    mEventLock.lock();
    sp<IDrmClient> listener = mListener;
    mEventLock.unlock();

    if (listener != NULL) {
        Parcel obj;
        writeByteArray(obj, sessionId);
        Mutex::Autolock lock(mNotifyLock);
        listener->notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &obj);
    }
    return Void();
}

bool DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
    Mutex::Autolock autoLock(mLock);

@@ -567,17 +603,23 @@ status_t DrmHal::createPlugin(const uint8_t uuid[16],

    if (mPlugin == NULL) {
        mInitCheck = ERROR_UNSUPPORTED;
    } else {
        if (!mPlugin->setListener(this).isOk()) {
            mPlugin = NULL;
            mPluginV1_1 = NULL;
            mPluginV1_2 = NULL;
            mInitCheck = DEAD_OBJECT;
    } else {
        mInitCheck = OK;
        if (mPluginV1_2 != NULL) {
            if (!mPluginV1_2->setListener(this).isOk()) {
                mInitCheck = DEAD_OBJECT;
            }
        } else if (!mPlugin->setListener(this).isOk()) {
            mInitCheck = DEAD_OBJECT;
        }
        if (mInitCheck != OK) {
            mPlugin.clear();
            mPluginV1_1.clear();
            mPluginV1_2.clear();
        }
    }


    return mInitCheck;
}

@@ -694,6 +736,39 @@ status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) {
    return DEAD_OBJECT;
}

static DrmPlugin::KeyRequestType toKeyRequestType(
        KeyRequestType keyRequestType) {
    switch (keyRequestType) {
        case KeyRequestType::INITIAL:
            return DrmPlugin::kKeyRequestType_Initial;
            break;
        case KeyRequestType::RENEWAL:
            return DrmPlugin::kKeyRequestType_Renewal;
            break;
        case KeyRequestType::RELEASE:
            return DrmPlugin::kKeyRequestType_Release;
            break;
        default:
            return DrmPlugin::kKeyRequestType_Unknown;
            break;
    }
}

static DrmPlugin::KeyRequestType toKeyRequestType_1_1(
        KeyRequestType_V1_1 keyRequestType) {
    switch (keyRequestType) {
        case KeyRequestType_V1_1::NONE:
            return DrmPlugin::kKeyRequestType_None;
            break;
        case KeyRequestType_V1_1::UPDATE:
            return DrmPlugin::kKeyRequestType_Update;
            break;
        default:
            return toKeyRequestType(static_cast<KeyRequestType>(keyRequestType));
            break;
    }
}

status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
        Vector<uint8_t> const &initData, String8 const &mimeType,
        DrmPlugin::KeyType keyType, KeyedVector<String8,
@@ -720,73 +795,51 @@ status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
    ::KeyedVector hOptionalParameters = toHidlKeyedVector(optionalParameters);

    status_t err = UNKNOWN_ERROR;
    Return<void> hResult;

    if (mPluginV1_1 != NULL) {
        Return<void> hResult =
            mPluginV1_1->getKeyRequest_1_1(
    if (mPluginV1_2 != NULL) {
        hResult = mPluginV1_2->getKeyRequest_1_2(
                toHidlVec(sessionId), toHidlVec(initData),
                toHidlString(mimeType), hKeyType, hOptionalParameters,
                [&](Status_V1_2 status, const hidl_vec<uint8_t>& hRequest,
                        KeyRequestType_V1_1 hKeyRequestType,
                        const hidl_string& hDefaultUrl) {
                    if (status == Status_V1_2::OK) {
                        request = toVector(hRequest);
                        defaultUrl = toString8(hDefaultUrl);
                        *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
                    }
                    err = toStatusT_1_2(status);
                });
    } else if (mPluginV1_1 != NULL) {
        hResult = mPluginV1_1->getKeyRequest_1_1(
                toHidlVec(sessionId), toHidlVec(initData),
                toHidlString(mimeType), hKeyType, hOptionalParameters,
                [&](Status status, const hidl_vec<uint8_t>& hRequest,
                    drm::V1_1::KeyRequestType hKeyRequestType,
                        KeyRequestType_V1_1 hKeyRequestType,
                        const hidl_string& hDefaultUrl) {

                    if (status == Status::OK) {
                        request = toVector(hRequest);
                        defaultUrl = toString8(hDefaultUrl);

                switch (hKeyRequestType) {
                    case drm::V1_1::KeyRequestType::INITIAL:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
                        break;
                    case drm::V1_1::KeyRequestType::RENEWAL:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Renewal;
                        break;
                    case drm::V1_1::KeyRequestType::RELEASE:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Release;
                        break;
                    case drm::V1_1::KeyRequestType::NONE:
                        *keyRequestType = DrmPlugin::kKeyRequestType_None;
                        break;
                    case drm::V1_1::KeyRequestType::UPDATE:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Update;
                        break;
                    default:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
                        break;
                        *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
                    }
                    err = toStatusT(status);
            }
                });
        return hResult.isOk() ? err : DEAD_OBJECT;
    }

    Return<void> hResult = mPlugin->getKeyRequest(toHidlVec(sessionId),
            toHidlVec(initData), toHidlString(mimeType), hKeyType, hOptionalParameters,
    } else {
        hResult = mPlugin->getKeyRequest(
                toHidlVec(sessionId), toHidlVec(initData),
                toHidlString(mimeType), hKeyType, hOptionalParameters,
                [&](Status status, const hidl_vec<uint8_t>& hRequest,
                    drm::V1_0::KeyRequestType hKeyRequestType,
                        KeyRequestType hKeyRequestType,
                        const hidl_string& hDefaultUrl) {

                    if (status == Status::OK) {
                        request = toVector(hRequest);
                        defaultUrl = toString8(hDefaultUrl);

                    switch (hKeyRequestType) {
                    case drm::V1_0::KeyRequestType::INITIAL:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
                        break;
                    case drm::V1_0::KeyRequestType::RENEWAL:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Renewal;
                        break;
                    case drm::V1_0::KeyRequestType::RELEASE:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Release;
                        break;
                    default:
                        *keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
                        break;
                        *keyRequestType = toKeyRequestType(hKeyRequestType);
                    }
                    err = toStatusT(status);
                }
                });
    }

    err = hResult.isOk() ? err : DEAD_OBJECT;
    keyRequestTimer.SetAttribute(err);
@@ -868,7 +921,21 @@ status_t DrmHal::getProvisionRequest(String8 const &certType,
    INIT_CHECK();

    status_t err = UNKNOWN_ERROR;
    Return<void> hResult;

    if (mPluginV1_2 != NULL) {
        Return<void> hResult = mPluginV1_2->getProvisionRequest_1_2(
                toHidlString(certType), toHidlString(certAuthority),
                [&](Status_V1_2 status, const hidl_vec<uint8_t>& hRequest,
                        const hidl_string& hDefaultUrl) {
                    if (status == Status_V1_2::OK) {
                        request = toVector(hRequest);
                        defaultUrl = toString8(hDefaultUrl);
                    }
                    err = toStatusT_1_2(status);
                }
            );
    } else {
        Return<void> hResult = mPlugin->getProvisionRequest(
                toHidlString(certType), toHidlString(certAuthority),
                [&](Status status, const hidl_vec<uint8_t>& hRequest,
@@ -880,6 +947,7 @@ status_t DrmHal::getProvisionRequest(String8 const &certType,
                    err = toStatusT(status);
                }
            );
    }

    err = hResult.isOk() ? err : DEAD_OBJECT;
    mMetrics.mGetProvisionRequestCounter.Increment(err);
+48 −17
Original line number Diff line number Diff line
@@ -42,10 +42,42 @@ Return<void> CryptoPlugin::setSharedBufferBase(
    return Void();
}

Return<void> CryptoPlugin::decrypt(
    bool secure,
    const hidl_array<uint8_t, 16>& keyId,
    const hidl_array<uint8_t, 16>& iv,
    Mode mode,
    const Pattern& pattern,
    const hidl_vec<SubSample>& subSamples,
    const SharedBuffer& source,
    uint64_t offset,
    const DestinationBuffer& destination,
    decrypt_cb _hidl_cb) {

  Status status = Status::ERROR_DRM_UNKNOWN;
  hidl_string detailedError;
  uint32_t bytesWritten = 0;

  Return<void> hResult = decrypt_1_2(
      secure, keyId, iv, mode, pattern, subSamples, source, offset, destination,
      [&](Status_V1_2 hStatus, uint32_t hBytesWritten, hidl_string hDetailedError) {
        status = toStatus_1_0(hStatus);
        if (status == Status::OK) {
          bytesWritten = hBytesWritten;
          detailedError = hDetailedError;
        }
      }
    );

  status = hResult.isOk() ? status : Status::ERROR_DRM_CANNOT_HANDLE;
  _hidl_cb(status, bytesWritten, detailedError);
  return Void();
}

// Returns negative values for error code and positive values for the size of
// decrypted data.  In theory, the output size can be larger than the input
// size, but in practice this will never happen for AES-CTR.
Return<void> CryptoPlugin::decrypt(
Return<void> CryptoPlugin::decrypt_1_2(
        bool secure,
        const hidl_array<uint8_t, KEY_ID_SIZE>& keyId,
        const hidl_array<uint8_t, KEY_IV_SIZE>& iv,
@@ -55,17 +87,17 @@ Return<void> CryptoPlugin::decrypt(
        const SharedBuffer& source,
        uint64_t offset,
        const DestinationBuffer& destination,
        decrypt_cb _hidl_cb) {
        decrypt_1_2_cb _hidl_cb) {
    UNUSED(pattern);

    if (secure) {
        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
            "Secure decryption is not supported with ClearKey.");
        return Void();
    }

    if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
      _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
      _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
               "source decrypt buffer base not set");
      return Void();
    }
@@ -73,7 +105,7 @@ Return<void> CryptoPlugin::decrypt(
    if (destination.type == BufferType::SHARED_MEMORY) {
      const SharedBuffer& dest = destination.nonsecureMemory;
      if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) {
        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
                 "destination decrypt buffer base not set");
        return Void();
      }
@@ -81,12 +113,12 @@ Return<void> CryptoPlugin::decrypt(

    sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
    if (sourceBase == nullptr) {
        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source is a nullptr");
        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "source is a nullptr");
        return Void();
    }

    if (source.offset + offset + source.size > sourceBase->getSize()) {
        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
        return Void();
    }

@@ -98,12 +130,12 @@ Return<void> CryptoPlugin::decrypt(
        const SharedBuffer& destBuffer = destination.nonsecureMemory;
        sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
        if (destBase == nullptr) {
            _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
            return Void();
        }

        if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
            _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
            return Void();
        }
        destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
@@ -128,7 +160,7 @@ Return<void> CryptoPlugin::decrypt(

    if (mode == Mode::UNENCRYPTED) {
        if (haveEncryptedSubsamples) {
            _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
                    "Encrypted subsamples found in allegedly unencrypted data.");
            return Void();
        }
@@ -144,22 +176,21 @@ Return<void> CryptoPlugin::decrypt(
            }
        }

        _hidl_cb(Status::OK, static_cast<ssize_t>(offset), "");
        _hidl_cb(Status_V1_2::OK, static_cast<ssize_t>(offset), "");
        return Void();
    } else if (mode == Mode::AES_CTR) {
        size_t bytesDecrypted;
        Status res = mSession->decrypt(keyId.data(), iv.data(), srcPtr,
        Status_V1_2 res = mSession->decrypt(keyId.data(), iv.data(), srcPtr,
                static_cast<uint8_t*>(destPtr), toVector(subSamples), &bytesDecrypted);
        if (res == Status::OK) {
            _hidl_cb(Status::OK, static_cast<ssize_t>(bytesDecrypted), "");
        if (res == Status_V1_2::OK) {
            _hidl_cb(Status_V1_2::OK, static_cast<ssize_t>(bytesDecrypted), "");
            return Void();
        } else {
            _hidl_cb(Status::ERROR_DRM_DECRYPT, static_cast<ssize_t>(res),
                    "Decryption Error");
            _hidl_cb(res, 0, "Decryption Error");
            return Void();
        }
    } else {
        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
                "Selected encryption mode is not supported by the ClearKey DRM Plugin.");
        return Void();
    }
+71 −19

File changed.

Preview size limit exceeded, changes collapsed.

+8 −3
Original line number Diff line number Diff line
@@ -68,25 +68,30 @@ Status Session::provideKeyResponse(const std::vector<uint8_t>& response) {
    }
}

Status Session::decrypt(
Status_V1_2 Session::decrypt(
        const KeyId keyId, const Iv iv, const uint8_t* srcPtr,
        uint8_t* destPtr, const std::vector<SubSample> subSamples,
        size_t* bytesDecryptedOut) {
    Mutex::Autolock lock(mMapLock);

    if (getMockError() != Status_V1_2::OK) {
        return getMockError();
    }

    std::vector<uint8_t> keyIdVector;
    keyIdVector.clear();
    keyIdVector.insert(keyIdVector.end(), keyId, keyId + kBlockSize);
    std::map<std::vector<uint8_t>, std::vector<uint8_t> >::iterator itr;
    itr = mKeyMap.find(keyIdVector);
    if (itr == mKeyMap.end()) {
        return Status::ERROR_DRM_NO_LICENSE;
        return Status_V1_2::ERROR_DRM_NO_LICENSE;
    }

    AesCtrDecryptor decryptor;
    return decryptor.decrypt(
    Status status = decryptor.decrypt(
            itr->second /*key*/, iv, srcPtr, destPtr, subSamples,
            subSamples.size(), bytesDecryptedOut);
    return static_cast<Status_V1_2>(status);
}

} // namespace clearkey
Loading