Widevine drm aidl: address API review
Interface update in change 16810770 Bug: 214410088 Test: atest VtsAidlHalDrmTargetTest Change-Id: I19da51ef75952f5ff6c7c02e0393f574e69ee30b
This commit is contained in:
@@ -28,7 +28,7 @@ namespace hardware {
|
||||
namespace drm {
|
||||
namespace widevine {
|
||||
|
||||
using ::aidl::android::hardware::drm::BufferType;
|
||||
using ::aidl::android::hardware::drm::DestinationBuffer;
|
||||
using ::aidl::android::hardware::drm::Mode;
|
||||
using ::aidl::android::hardware::drm::SharedBuffer;
|
||||
using ::aidl::android::hardware::drm::Status;
|
||||
@@ -64,15 +64,16 @@ WVCryptoPlugin::~WVCryptoPlugin() {
|
||||
}
|
||||
|
||||
SharedBufferBase::SharedBufferBase(
|
||||
const ::aidl::android::hardware::common::Ashmem& mem)
|
||||
const ::aidl::android::hardware::drm::SharedBuffer& mem)
|
||||
: mBase(nullptr), mSize(mem.size) {
|
||||
if (mem.fd.get() < 0) {
|
||||
if (mem.handle.fds.empty()) {
|
||||
return;
|
||||
}
|
||||
auto addr = mmap(nullptr, mem.size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
mem.fd.get(), 0);
|
||||
auto fd = mem.handle.fds[0].get();
|
||||
auto addr =
|
||||
mmap(nullptr, mem.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
ALOGE("mmap err: fd %d; errno %s", mem.fd.get(), strerror(errno));
|
||||
ALOGE("mmap err: fd %d; errno %s", fd, strerror(errno));
|
||||
} else {
|
||||
mBase = static_cast<uint8_t*>(addr);
|
||||
}
|
||||
@@ -129,97 +130,99 @@ SharedBufferBase::~SharedBufferBase() {
|
||||
}
|
||||
|
||||
::ndk::ScopedAStatus WVCryptoPlugin::setSharedBufferBase(
|
||||
const ::aidl::android::hardware::common::Ashmem& in_base,
|
||||
int32_t in_bufferId) {
|
||||
const ::aidl::android::hardware::drm::SharedBuffer& in_base) {
|
||||
std::lock_guard<std::mutex> shared_buffer_lock(mSharedBufferLock);
|
||||
|
||||
mSharedBufferMap[in_bufferId] = std::make_shared<SharedBufferBase>(in_base);
|
||||
mSharedBufferMap[in_base.bufferId] =
|
||||
std::make_shared<SharedBufferBase>(in_base);
|
||||
return ::ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
::ndk::ScopedAStatus WVCryptoPlugin::decrypt(
|
||||
bool in_secure, const std::vector<uint8_t>& in_keyId,
|
||||
const std::vector<uint8_t>& in_iv,
|
||||
::aidl::android::hardware::drm::Mode in_mode,
|
||||
const ::aidl::android::hardware::drm::Pattern& in_pattern,
|
||||
const std::vector<SubSample>& in_subSamples,
|
||||
const ::aidl::android::hardware::drm::SharedBuffer& in_source,
|
||||
int64_t in_offset,
|
||||
const ::aidl::android::hardware::drm::DestinationBuffer& in_destination,
|
||||
::aidl::android::hardware::drm::DecryptResult* _aidl_return) {
|
||||
_aidl_return->bytesWritten = 0;
|
||||
const ::aidl::android::hardware::drm::DecryptArgs& in_args,
|
||||
int32_t* _aidl_return) {
|
||||
const char* detailedError = "";
|
||||
*_aidl_return = 0; // bytes decrypted
|
||||
|
||||
uint8_t* srcPtr = nullptr;
|
||||
void* destPtr = nullptr;
|
||||
// Convert parameters to the form the CDM wishes to consume them in.
|
||||
const KeyId cryptoKey(reinterpret_cast<const char*>(in_keyId.data()),
|
||||
const KeyId cryptoKey(reinterpret_cast<const char*>(in_args.keyId.data()),
|
||||
wvcdm::KEY_ID_SIZE);
|
||||
|
||||
// start scope for lock_guard
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mSharedBufferLock);
|
||||
if (mSharedBufferMap.find(in_source.bufferId) == mSharedBufferMap.end()) {
|
||||
_aidl_return->detailedError = "source decrypt buffer base not set";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
||||
if (mSharedBufferMap.find(in_args.source.bufferId) ==
|
||||
mSharedBufferMap.end()) {
|
||||
detailedError = "source decrypt buffer base not set";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
|
||||
}
|
||||
|
||||
if (in_destination.type == BufferType::SHARED_MEMORY) {
|
||||
const SharedBuffer& dest = in_destination.nonsecureMemory;
|
||||
const auto NON_SECURE = DestinationBuffer::Tag::nonsecureMemory;
|
||||
if (in_args.destination.getTag() == NON_SECURE) {
|
||||
const SharedBuffer& dest = in_args.destination.get<NON_SECURE>();
|
||||
if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) {
|
||||
_aidl_return->detailedError = "destination decrypt buffer base not set";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
||||
detailedError = "destination decrypt buffer base not set";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE,
|
||||
detailedError);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_mode != Mode::UNENCRYPTED && in_mode != Mode::AES_CTR &&
|
||||
in_mode != Mode::AES_CBC) {
|
||||
_aidl_return->detailedError =
|
||||
if (in_args.mode != Mode::UNENCRYPTED && in_args.mode != Mode::AES_CTR &&
|
||||
in_args.mode != Mode::AES_CBC) {
|
||||
detailedError =
|
||||
"The requested encryption mode is not supported by Widevine CDM.";
|
||||
return toNdkScopedAStatus(Status::BAD_VALUE);
|
||||
} else if (in_mode == Mode::AES_CTR &&
|
||||
(in_pattern.encryptBlocks != 0 || in_pattern.skipBlocks != 0)) {
|
||||
_aidl_return->detailedError =
|
||||
"The 'cens' schema is not supported by Widevine CDM.";
|
||||
return toNdkScopedAStatus(Status::BAD_VALUE);
|
||||
return toNdkScopedAStatus(Status::BAD_VALUE, detailedError);
|
||||
} else if (in_args.mode == Mode::AES_CTR &&
|
||||
(in_args.pattern.encryptBlocks != 0 ||
|
||||
in_args.pattern.skipBlocks != 0)) {
|
||||
detailedError = "The 'cens' schema is not supported by Widevine CDM.";
|
||||
return toNdkScopedAStatus(Status::BAD_VALUE, detailedError);
|
||||
}
|
||||
|
||||
auto src = mSharedBufferMap[in_source.bufferId];
|
||||
auto src = mSharedBufferMap[in_args.source.bufferId];
|
||||
if (src->mBase == nullptr) {
|
||||
_aidl_return->detailedError = "source is a nullptr";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
||||
detailedError = "source is a nullptr";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
|
||||
}
|
||||
|
||||
size_t totalSrcSize = 0;
|
||||
if (__builtin_add_overflow(in_source.offset, in_offset, &totalSrcSize) ||
|
||||
__builtin_add_overflow(totalSrcSize, in_source.size, &totalSrcSize) ||
|
||||
if (__builtin_add_overflow(in_args.source.offset, in_args.offset,
|
||||
&totalSrcSize) ||
|
||||
__builtin_add_overflow(totalSrcSize, in_args.source.size,
|
||||
&totalSrcSize) ||
|
||||
totalSrcSize > src->mSize) {
|
||||
android_errorWriteLog(0x534e4554, "176496160");
|
||||
_aidl_return->detailedError = "invalid source buffer size";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
||||
detailedError = "invalid source buffer size";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
|
||||
}
|
||||
|
||||
srcPtr = src->mBase + in_source.offset + in_offset;
|
||||
srcPtr = src->mBase + in_args.source.offset + in_args.offset;
|
||||
|
||||
if (in_destination.type == BufferType::SHARED_MEMORY) {
|
||||
const SharedBuffer& destBuffer = in_destination.nonsecureMemory;
|
||||
if (in_args.destination.getTag() == NON_SECURE) {
|
||||
const SharedBuffer& destBuffer = in_args.destination.get<NON_SECURE>();
|
||||
auto dest = mSharedBufferMap[destBuffer.bufferId];
|
||||
if (dest->mBase == nullptr) {
|
||||
_aidl_return->detailedError = "destination is a nullptr";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
||||
detailedError = "destination is a nullptr";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE,
|
||||
detailedError);
|
||||
}
|
||||
size_t totalDstSize = 0;
|
||||
if (__builtin_add_overflow(destBuffer.offset, destBuffer.size,
|
||||
&totalDstSize) ||
|
||||
totalDstSize > dest->mSize) {
|
||||
android_errorWriteLog(0x534e4554, "176444622");
|
||||
_aidl_return->detailedError = "invalid buffer size";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE);
|
||||
detailedError = "invalid buffer size";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE,
|
||||
detailedError);
|
||||
}
|
||||
destPtr = static_cast<void*>(dest->mBase +
|
||||
in_destination.nonsecureMemory.offset);
|
||||
} else if (in_destination.type == BufferType::NATIVE_HANDLE) {
|
||||
native_handle_t* handle =
|
||||
android::makeFromAidl(in_destination.secureMemory);
|
||||
destPtr = static_cast<void*>(
|
||||
dest->mBase + in_args.destination.get<NON_SECURE>().offset);
|
||||
} else if (in_args.destination.getTag() ==
|
||||
DestinationBuffer::Tag::secureMemory) {
|
||||
native_handle_t* handle = android::makeFromAidl(
|
||||
in_args.destination.get<DestinationBuffer::Tag::secureMemory>());
|
||||
destPtr = static_cast<void*>(handle);
|
||||
}
|
||||
} // lock_guard scope
|
||||
@@ -227,14 +230,14 @@ SharedBufferBase::~SharedBufferBase() {
|
||||
// Set up the decrypt params
|
||||
CdmDecryptionParametersV16 params;
|
||||
params.key_id = cryptoKey;
|
||||
params.is_secure = in_secure;
|
||||
if (in_mode == Mode::AES_CTR) {
|
||||
params.is_secure = in_args.secure;
|
||||
if (in_args.mode == Mode::AES_CTR) {
|
||||
params.cipher_mode = wvcdm::kCipherModeCtr;
|
||||
} else if (in_mode == Mode::AES_CBC) {
|
||||
} else if (in_args.mode == Mode::AES_CBC) {
|
||||
params.cipher_mode = wvcdm::kCipherModeCbc;
|
||||
}
|
||||
params.pattern.encrypt_blocks = in_pattern.encryptBlocks;
|
||||
params.pattern.skip_blocks = in_pattern.skipBlocks;
|
||||
params.pattern.encrypt_blocks = in_args.pattern.encryptBlocks;
|
||||
params.pattern.skip_blocks = in_args.pattern.skipBlocks;
|
||||
|
||||
// Set up the sample
|
||||
// Android's API only supports one at a time
|
||||
@@ -243,16 +246,17 @@ SharedBufferBase::~SharedBufferBase() {
|
||||
sample.encrypt_buffer = srcPtr;
|
||||
sample.decrypt_buffer = destPtr;
|
||||
sample.decrypt_buffer_offset = 0;
|
||||
sample.iv = in_iv;
|
||||
sample.iv = in_args.iv;
|
||||
|
||||
// Set up the subsamples
|
||||
// We abuse std::transform() here to also do some side-effects: Tallying the
|
||||
// total size of the sample and checking if any of the data is protected.
|
||||
size_t totalSize = 0;
|
||||
bool hasProtectedData = false;
|
||||
sample.subsamples.reserve(in_subSamples.size());
|
||||
sample.subsamples.reserve(in_args.subSamples.size());
|
||||
std::transform(
|
||||
in_subSamples.data(), in_subSamples.data() + in_subSamples.size(),
|
||||
in_args.subSamples.data(),
|
||||
in_args.subSamples.data() + in_args.subSamples.size(),
|
||||
std::back_inserter(sample.subsamples),
|
||||
[&](const SubSample& subSample) -> CdmDecryptionSubsample {
|
||||
totalSize +=
|
||||
@@ -265,23 +269,22 @@ SharedBufferBase::~SharedBufferBase() {
|
||||
sample.encrypt_buffer_length = totalSize;
|
||||
sample.decrypt_buffer_size = totalSize;
|
||||
|
||||
if (in_mode == Mode::UNENCRYPTED && hasProtectedData) {
|
||||
_aidl_return->detailedError =
|
||||
"Protected ranges found in allegedly clear data.";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
|
||||
if (in_args.mode == Mode::UNENCRYPTED && hasProtectedData) {
|
||||
detailedError = "Protected ranges found in allegedly clear data.";
|
||||
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE, detailedError);
|
||||
}
|
||||
|
||||
// Decrypt
|
||||
std::string errorDetailMsg;
|
||||
Status res = attemptDecrypt(params, hasProtectedData, &errorDetailMsg);
|
||||
if (res != Status::OK) {
|
||||
_aidl_return->detailedError = errorDetailMsg;
|
||||
return toNdkScopedAStatus(res);
|
||||
detailedError = errorDetailMsg.data();
|
||||
return toNdkScopedAStatus(res, detailedError);
|
||||
}
|
||||
|
||||
_aidl_return->bytesWritten = totalSize;
|
||||
_aidl_return->detailedError = errorDetailMsg;
|
||||
return toNdkScopedAStatus(Status::OK);
|
||||
*_aidl_return = totalSize; // return bytes decrypted
|
||||
detailedError = errorDetailMsg.data();
|
||||
return toNdkScopedAStatus(Status::OK, detailedError);
|
||||
}
|
||||
|
||||
Status WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParametersV16& params,
|
||||
|
||||
Reference in New Issue
Block a user