Merge "libaudiohal: Add support for audio@7.1"
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 71df58c..6e1e10b 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -28,7 +28,11 @@
"DrmSessionManager.cpp",
"SharedLibrary.cpp",
"DrmHal.cpp",
+ "DrmHalHidl.cpp",
+ "DrmHalAidl.cpp",
"CryptoHal.cpp",
+ "CryptoHalHidl.cpp",
+ "CryptoHalAidl.cpp",
"DrmUtils.cpp",
],
@@ -63,10 +67,12 @@
"android.hardware.drm@1.4",
"libhidlallocatorutils",
"libhidlbase",
+ "android.hardware.drm-V1-ndk",
],
static_libs: [
"resourcemanager_aidl_interface-ndk",
+ "libaidlcommonsupport",
],
export_shared_lib_headers: [
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index e0db1c4..f95d527 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -16,389 +16,100 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "CryptoHal"
-#include <utils/Log.h>
-
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <hidl/ServiceManagement.h>
-#include <hidlmemory/FrameworkUtils.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>
#include <mediadrm/CryptoHal.h>
+#include <mediadrm/CryptoHalHidl.h>
+#include <mediadrm/CryptoHalAidl.h>
#include <mediadrm/DrmUtils.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::DrmUtils::toStatusT;
-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::HidlMemory;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-typedef drm::V1_2::Status Status_V1_2;
-
namespace android {
-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;
+CryptoHal::CryptoHal() {
+ mCryptoHalAidl = sp<CryptoHalAidl>::make();
+ mCryptoHalHidl = sp<CryptoHalHidl>::make();
}
-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 String8 toString8(hidl_string hString) {
- return String8(hString.c_str());
-}
-
-
-CryptoHal::CryptoHal()
- : mFactories(makeCryptoFactories()),
- mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
- mHeapSeqNum(0) {
-}
-
-CryptoHal::~CryptoHal() {
-}
-
-Vector<sp<ICryptoFactory>> CryptoHal::makeCryptoFactories() {
- Vector<sp<ICryptoFactory>> factories;
-
- auto manager = hardware::defaultServiceManager1_2();
- if (manager != NULL) {
- manager->listManifestByInterface(drm::V1_0::ICryptoFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_0::ICryptoFactory::getService(instance);
- if (factory != NULL) {
- ALOGD("found drm@1.0 ICryptoFactory %s", instance.c_str());
- factories.push_back(factory);
- }
- }
- }
- );
- manager->listManifestByInterface(drm::V1_1::ICryptoFactory::descriptor,
- [&factories](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = drm::V1_1::ICryptoFactory::getService(instance);
- if (factory != NULL) {
- ALOGD("found drm@1.1 ICryptoFactory %s", instance.c_str());
- factories.push_back(factory);
- }
- }
- }
- );
- }
-
- if (factories.size() == 0) {
- // must be in passthrough mode, load the default passthrough service
- auto passthrough = ICryptoFactory::getService();
- if (passthrough != NULL) {
- ALOGI("makeCryptoFactories: using default passthrough crypto instance");
- factories.push_back(passthrough);
- } else {
- ALOGE("Failed to find any crypto factories");
- }
- }
- return factories;
-}
-
-sp<ICryptoPlugin> CryptoHal::makeCryptoPlugin(const sp<ICryptoFactory>& factory,
- const uint8_t uuid[16], const void *initData, size_t initDataSize) {
-
- sp<ICryptoPlugin> plugin;
- Return<void> hResult = factory->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;
- }
- );
- if (!hResult.isOk()) {
- mInitCheck = DEAD_OBJECT;
- }
- return plugin;
-}
-
+CryptoHal::~CryptoHal() {}
status_t CryptoHal::initCheck() const {
- return mInitCheck;
+ if (mCryptoHalAidl->initCheck() == OK || mCryptoHalHidl->initCheck() == OK) return OK;
+ if (mCryptoHalAidl->initCheck() == NO_INIT || mCryptoHalHidl->initCheck() == NO_INIT)
+ return NO_INIT;
+ return mCryptoHalHidl->initCheck();
}
-
bool CryptoHal::isCryptoSchemeSupported(const uint8_t uuid[16]) {
- Mutex::Autolock autoLock(mLock);
-
- for (size_t i = 0; i < mFactories.size(); i++) {
- if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
- return true;
- }
- }
- return false;
+ return mCryptoHalAidl->isCryptoSchemeSupported(uuid) ||
+ mCryptoHalHidl->isCryptoSchemeSupported(uuid);
}
-status_t CryptoHal::createPlugin(const uint8_t uuid[16], const void *data,
- size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- 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);
- }
- }
- }
-
- if (mInitCheck == NO_INIT) {
- mInitCheck = mPlugin == NULL ? ERROR_UNSUPPORTED : OK;
- }
-
- return mInitCheck;
+status_t CryptoHal::createPlugin(const uint8_t uuid[16], const void* data, size_t size) {
+ if (mCryptoHalAidl->createPlugin(uuid, data, size) != OK)
+ return mCryptoHalHidl->createPlugin(uuid, data, size);
+ return OK;
}
status_t CryptoHal::destroyPlugin() {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- mPlugin.clear();
- mPluginV1_2.clear();
- return OK;
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->destroyPlugin();
+ return mCryptoHalHidl->destroyPlugin();
}
-bool CryptoHal::requiresSecureDecoderComponent(const char *mime) const {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return false;
- }
-
- Return<bool> hResult = mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
- if (!hResult.isOk()) {
- return false;
- }
- return hResult;
-}
-
-
-/**
- * If the heap base isn't set, get the heap base from the HidlMemory
- * 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.
- */
-int32_t CryptoHal::setHeapBase(const sp<HidlMemory>& heap) {
- if (heap == NULL || mHeapSeqNum < 0) {
- ALOGE("setHeapBase(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
- return -1;
- }
-
- Mutex::Autolock autoLock(mLock);
-
- int32_t seqNum = mHeapSeqNum++;
- uint32_t bufferId = static_cast<uint32_t>(seqNum);
- mHeapSizes.add(seqNum, heap->size());
- Return<void> hResult = mPlugin->setSharedBufferBase(*heap, bufferId);
- ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
- return seqNum;
-}
-
-void CryptoHal::clearHeapBase(int32_t seqNum) {
- Mutex::Autolock autoLock(mLock);
-
- /*
- * Clear the remote shared memory mapping by setting the shared
- * buffer base to a null hidl_memory.
- *
- * TODO: Add a releaseSharedBuffer method in a future DRM HAL
- * API version to make this explicit.
- */
- ssize_t index = mHeapSizes.indexOfKey(seqNum);
- if (index >= 0) {
- if (mPlugin != NULL) {
- uint32_t bufferId = static_cast<uint32_t>(seqNum);
- Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
- ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
- }
- mHeapSizes.removeItem(seqNum);
- }
-}
-
-status_t CryptoHal::checkSharedBuffer(const ::SharedBuffer &buffer) {
- int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
- // memory must be in one of the heaps that have been set
- if (mHeapSizes.indexOfKey(seqNum) < 0) {
- return UNKNOWN_ERROR;
- }
-
- // memory must be within the address space of the heap
- size_t heapSize = mHeapSizes.valueFor(seqNum);
- if (heapSize < buffer.offset + buffer.size ||
- SIZE_MAX - buffer.offset < buffer.size) {
- android_errorWriteLog(0x534e4554, "76221123");
- return UNKNOWN_ERROR;
- }
-
- return OK;
-}
-
-ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
- CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const ::SharedBuffer &hSource, size_t offset,
- const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const ::DestinationBuffer &hDestination, AString *errorDetailMsg) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- 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;
- if (hDestination.type == BufferType::SHARED_MEMORY) {
- status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
- if (status != OK) {
- return status;
- }
- secure = false;
- } else if (hDestination.type == BufferType::NATIVE_HANDLE) {
- secure = true;
- } else {
- android_errorWriteLog(0x534e4554, "70526702");
- return UNKNOWN_ERROR;
- }
-
- status_t status = checkSharedBuffer(hSource);
- if (status != OK) {
- return status;
- }
-
- status_t err = UNKNOWN_ERROR;
- uint32_t bytesWritten = 0;
-
- Return<void> hResult;
-
- mLock.unlock();
- 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(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;
- *errorDetailMsg = toString8(hDetailedError);
- }
- err = toStatusT(status);
- }
- );
- }
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- if (err == OK) {
- return bytesWritten;
- }
- return err;
+bool CryptoHal::requiresSecureDecoderComponent(const char* mime) const {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK)
+ return mCryptoHalAidl->requiresSecureDecoderComponent(mime);
+ return mCryptoHalHidl->requiresSecureDecoderComponent(mime);
}
void CryptoHal::notifyResolution(uint32_t width, uint32_t height) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) {
+ mCryptoHalAidl->notifyResolution(width, height);
return;
}
- auto hResult = mPlugin->notifyResolution(width, height);
- ALOGE_IF(!hResult.isOk(), "notifyResolution txn failed %s", hResult.description().c_str());
+ mCryptoHalHidl->notifyResolution(width, height);
}
-status_t CryptoHal::setMediaDrmSession(const Vector<uint8_t> &sessionId) {
- Mutex::Autolock autoLock(mLock);
+status_t CryptoHal::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->setMediaDrmSession(sessionId);
+ return mCryptoHalHidl->setMediaDrmSession(sessionId);
+}
- if (mInitCheck != OK) {
- return mInitCheck;
+ssize_t CryptoHal::decrypt(const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern& pattern, const ::SharedBuffer& source,
+ size_t offset, const CryptoPlugin::SubSample* subSamples,
+ size_t numSubSamples, const ::DestinationBuffer& destination,
+ AString* errorDetailMsg) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK)
+ return mCryptoHalAidl->decrypt(key, iv, mode, pattern, source, offset, subSamples,
+ numSubSamples, destination, errorDetailMsg);
+ return mCryptoHalHidl->decrypt(key, iv, mode, pattern, source, offset, subSamples,
+ numSubSamples, destination, errorDetailMsg);
+}
+
+int32_t CryptoHal::setHeap(const sp<HidlMemory>& heap) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->setHeap(heap);
+ return mCryptoHalHidl->setHeap(heap);
+}
+
+void CryptoHal::unsetHeap(int32_t seqNum) {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) {
+ mCryptoHalAidl->unsetHeap(seqNum);
+ return;
}
- auto err = mPlugin->setMediaDrmSession(toHidlVec(sessionId));
- return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
+ mCryptoHalHidl->unsetHeap(seqNum);
}
-status_t CryptoHal::getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const {
- Mutex::Autolock autoLock(mLock);
- return DrmUtils::GetLogMessages<drm::V1_4::ICryptoPlugin>(mPlugin, logs);
+status_t CryptoHal::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ // This requires plugin to be created.
+ if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->getLogMessages(logs);
+ return mCryptoHalHidl->getLogMessages(logs);
}
-} // namespace android
+
+} // namespace android
\ No newline at end of file
diff --git a/drm/libmediadrm/CryptoHalAidl.cpp b/drm/libmediadrm/CryptoHalAidl.cpp
new file mode 100644
index 0000000..a688728
--- /dev/null
+++ b/drm/libmediadrm/CryptoHalAidl.cpp
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2021 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 "CryptoHalAidl"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <mediadrm/CryptoHalAidl.h>
+#include <mediadrm/DrmUtils.h>
+
+using ::aidl::android::hardware::drm::BufferType;
+using ::aidl::android::hardware::drm::DecryptResult;
+using DestinationBufferAidl = ::aidl::android::hardware::drm::DestinationBuffer;
+using ::aidl::android::hardware::drm::Mode;
+using ::aidl::android::hardware::drm::Pattern;
+using SharedBufferAidl = ::aidl::android::hardware::drm::SharedBuffer;
+using ::aidl::android::hardware::drm::Status;
+using ::aidl::android::hardware::drm::SubSample;
+using ::aidl::android::hardware::drm::Uuid;
+
+using ::aidl::android::hardware::common::Ashmem;
+
+using ::android::sp;
+using ::android::DrmUtils::toStatusTAidl;
+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::HidlMemory;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::aidl::android::hardware::drm::Uuid;
+// -------Hidl interface related-----------------
+// TODO: replace before removing hidl interface
+
+using BufferTypeHidl = ::android::hardware::drm::V1_0::BufferType;
+using SharedBufferHidl = ::android::hardware::drm::V1_0::SharedBuffer;
+using DestinationBufferHidl = ::android::hardware::drm::V1_0::DestinationBuffer;
+
+// -------Hidl interface related end-------------
+
+namespace android {
+
+static Uuid toAidlUuid(const uint8_t* uuid) {
+ Uuid uuidAidl;
+ uuidAidl.uuid = std::vector<uint8_t>(uuid, uuid + 16);
+ return uuidAidl;
+}
+
+template <typename Byte = uint8_t>
+static std::vector<Byte> toStdVec(const Vector<uint8_t>& vector) {
+ auto v = reinterpret_cast<const Byte*>(vector.array());
+ std::vector<Byte> vec(v, v + vector.size());
+ return vec;
+}
+
+// -------Hidl interface related-----------------
+// TODO: replace before removing hidl interface
+status_t CryptoHalAidl::checkSharedBuffer(const SharedBufferHidl& buffer) {
+ int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
+ // memory must be in one of the heaps that have been set
+ if (mHeapSizes.indexOfKey(seqNum) < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ // memory must be within the address space of the heap
+ size_t heapSize = mHeapSizes.valueFor(seqNum);
+ if (heapSize < buffer.offset + buffer.size || SIZE_MAX - buffer.offset < buffer.size) {
+ android_errorWriteLog(0x534e4554, "76221123");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+static SharedBufferAidl hidlSharedBufferToAidlSharedBuffer(const SharedBufferHidl& buffer) {
+ SharedBufferAidl aidlsb;
+ aidlsb.bufferId = buffer.bufferId;
+ aidlsb.offset = buffer.offset;
+ aidlsb.size = buffer.size;
+ return aidlsb;
+}
+
+static DestinationBufferAidl hidlDestinationBufferToAidlDestinationBuffer(
+ const DestinationBufferHidl& buffer) {
+ DestinationBufferAidl aidldb;
+ // skip negative convert check as count of enum elements are 2
+ aidldb.type = static_cast<BufferType>((int32_t)buffer.type);
+ aidldb.nonsecureMemory = hidlSharedBufferToAidlSharedBuffer(buffer.nonsecureMemory);
+ aidldb.secureMemory = ::android::makeToAidl(buffer.secureMemory.getNativeHandle());
+ return aidldb;
+}
+
+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 const Vector<uint8_t> toVector(const std::vector<uint8_t>& vec) {
+ Vector<uint8_t> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return *const_cast<const Vector<uint8_t>*>(&vector);
+}
+
+static String8 toString8(const std::string& string) {
+ return String8(string.c_str());
+}
+
+// -------Hidl interface related end--------------
+
+CryptoHalAidl::CryptoHalAidl()
+ : mFactories(makeCryptoFactories()),
+ mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
+ mHeapSeqNum(0) {}
+
+CryptoHalAidl::~CryptoHalAidl() {}
+
+std::vector<std::shared_ptr<ICryptoFactoryAidl>> CryptoHalAidl::makeCryptoFactories() {
+ std::vector<std::shared_ptr<ICryptoFactoryAidl>> factories;
+ AServiceManager_forEachDeclaredInstance(
+ ICryptoFactoryAidl::descriptor, static_cast<void*>(&factories),
+ [](const char* instance, void* context) {
+ auto fullName = std::string(ICryptoFactoryAidl::descriptor) + "/" + std::string(instance);
+ auto factory = ICryptoFactoryAidl::fromBinder(
+ ::ndk::SpAIBinder(AServiceManager_getService(fullName.c_str())));
+ if (factory == nullptr) {
+ ALOGE("not found ICryptoFactoryAidl. Instance name:[%s]", fullName.c_str());
+ return;
+ }
+
+ ALOGI("found ICryptoFactoryAidl. Instance name:[%s]", fullName.c_str());
+ static_cast<std::vector<std::shared_ptr<ICryptoFactoryAidl>>*>(context)
+ ->emplace_back(factory);
+ });
+
+ return factories;
+}
+
+status_t CryptoHalAidl::initCheck() const {
+ return mInitCheck;
+}
+
+bool CryptoHalAidl::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+ Mutex::Autolock autoLock(mLock);
+
+ bool isSupported = false;
+ Uuid uuidAidl = toAidlUuid(uuid);
+ for (size_t i = 0; i < mFactories.size(); i++) {
+ if (mFactories[i]->isCryptoSchemeSupported(uuidAidl, &isSupported).isOk()) {
+ if (isSupported) break;
+ }
+ }
+ return isSupported;
+}
+
+status_t CryptoHalAidl::createPlugin(const uint8_t uuid[16], const void* data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ bool isSupported = false;
+ Uuid uuidAidl = toAidlUuid(uuid);
+ std::vector<uint8_t> dataAidl = toStdVec(toVector(toHidlVec(data, size)));
+ for (size_t i = 0; i < mFactories.size(); i++) {
+ if (mFactories[i]->isCryptoSchemeSupported(uuidAidl, &isSupported).isOk() && isSupported) {
+ mPlugin = makeCryptoPlugin(mFactories[i], uuidAidl, dataAidl);
+ // Reserve place for future plugins with new versions
+
+ break;
+ }
+ }
+
+ if (mInitCheck == NO_INIT) {
+ mInitCheck = mPlugin == NULL ? ERROR_UNSUPPORTED : OK;
+ }
+
+ return mInitCheck;
+}
+
+std::shared_ptr<ICryptoPluginAidl> CryptoHalAidl::makeCryptoPlugin(
+ const std::shared_ptr<ICryptoFactoryAidl>& factory, const Uuid& uuidAidl,
+ const std::vector<uint8_t> initData) {
+ std::shared_ptr<ICryptoPluginAidl> pluginAidl;
+ if (factory->createPlugin(uuidAidl, initData, &pluginAidl).isOk()) {
+ ALOGI("Create ICryptoPluginAidl. UUID:[%s]", uuidAidl.toString().c_str());
+ } else {
+ mInitCheck = DEAD_OBJECT;
+ ALOGE("Failed to create ICryptoPluginAidl. UUID:[%s]", uuidAidl.toString().c_str());
+ }
+
+ return pluginAidl;
+}
+
+status_t CryptoHalAidl::destroyPlugin() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ mPlugin.reset();
+ return OK;
+}
+
+bool CryptoHalAidl::requiresSecureDecoderComponent(const char* mime) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return false;
+ }
+
+ std::string mimeStr = std::string(mime);
+ bool result;
+ if (!mPlugin->requiresSecureDecoderComponent(mimeStr, &result).isOk()) {
+ ALOGE("Failed to requiresSecureDecoderComponent. mime:[%s]", mime);
+ return false;
+ }
+
+ return result;
+}
+
+void CryptoHalAidl::notifyResolution(uint32_t width, uint32_t height) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return;
+ }
+
+ // Check negative width and height after type conversion
+ // Log error and return if any is negative
+ if ((int32_t)width < 0 || (int32_t)height < 0) {
+ ALOGE("Negative width: %d or height %d in notifyResolution", width, height);
+ return;
+ }
+
+ ::ndk::ScopedAStatus status = mPlugin->notifyResolution(width, height);
+ if (!status.isOk()) {
+ ALOGE("notifyResolution txn failed status code: %d", status.getServiceSpecificError());
+ }
+}
+
+status_t CryptoHalAidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ auto err = mPlugin->setMediaDrmSession(toStdVec(sessionId));
+ return err.isOk() ? toStatusTAidl(err.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+ssize_t CryptoHalAidl::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern& pattern,
+ const SharedBufferHidl& hSource, size_t offset,
+ const CryptoPlugin::SubSample* subSamples, size_t numSubSamples,
+ const DestinationBufferHidl& hDestination, AString* errorDetailMsg) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ Mode aMode;
+ switch (mode) {
+ case CryptoPlugin::kMode_Unencrypted:
+ aMode = Mode::UNENCRYPTED;
+ break;
+ case CryptoPlugin::kMode_AES_CTR:
+ aMode = Mode::AES_CTR;
+ break;
+ case CryptoPlugin::kMode_AES_WV:
+ aMode = Mode::AES_CBC_CTS;
+ break;
+ case CryptoPlugin::kMode_AES_CBC:
+ aMode = Mode::AES_CBC;
+ break;
+ default:
+ return UNKNOWN_ERROR;
+ }
+
+ Pattern aPattern;
+ aPattern.encryptBlocks = pattern.mEncryptBlocks;
+ aPattern.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);
+ }
+
+ bool secure;
+ if (hDestination.type == BufferTypeHidl::SHARED_MEMORY) {
+ status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
+ if (status != OK) {
+ return status;
+ }
+ secure = false;
+ } else if (hDestination.type == BufferTypeHidl::NATIVE_HANDLE) {
+ secure = true;
+ } else {
+ android_errorWriteLog(0x534e4554, "70526702");
+ return UNKNOWN_ERROR;
+ }
+
+ status_t status = checkSharedBuffer(hSource);
+ if (status != OK) {
+ return status;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+ mLock.unlock();
+
+ std::vector<uint8_t> keyIdAidl = std::vector<uint8_t>(keyId, keyId + 16);
+ std::vector<uint8_t> ivAidl = std::vector<uint8_t>(iv, iv + 16);
+ DecryptResult result;
+ err = mPlugin->decrypt(secure, keyIdAidl, ivAidl, aMode, aPattern, stdSubSamples,
+ hidlSharedBufferToAidlSharedBuffer(hSource), offset,
+ hidlDestinationBufferToAidlDestinationBuffer(hDestination), &result)
+ .isOk()
+ ? OK
+ : DEAD_OBJECT;
+
+ *errorDetailMsg = toString8(result.detailedError);
+ if (err != OK) {
+ ALOGE("Failed on decrypt, error message:%s, bytes written:%d", result.detailedError.c_str(),
+ result.bytesWritten);
+ return err;
+ }
+
+ return result.bytesWritten;
+}
+
+int32_t CryptoHalAidl::setHeap(const sp<HidlMemory>& heap) {
+ if (heap == NULL || mHeapSeqNum < 0) {
+ ALOGE("setHeap(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
+ return -1;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+
+ int32_t seqNum = mHeapSeqNum++;
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ mHeapSizes.add(seqNum, heap->size());
+
+ Ashmem memAidl;
+ memAidl.fd.set(heap->handle()->data[0]);
+ memAidl.size = heap->size();
+
+ ALOGE_IF(!mPlugin->setSharedBufferBase(memAidl, bufferId).isOk(),
+ "setSharedBufferBase(): remote call failed");
+ return seqNum;
+}
+
+void CryptoHalAidl::unsetHeap(int32_t seqNum) {
+ Mutex::Autolock autoLock(mLock);
+
+ /*
+ * Clear the remote shared memory mapping by setting the shared
+ * buffer base to a null hidl_memory.
+ *
+ * TODO: Add a releaseSharedBuffer method in a future DRM HAL
+ * API version to make this explicit.
+ */
+ ssize_t index = mHeapSizes.indexOfKey(seqNum);
+ if (index >= 0) {
+ if (mPlugin != NULL) {
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ Ashmem memAidl;
+ memAidl.fd.set(-1);
+ memAidl.size = 0;
+ ALOGE_IF(!mPlugin->setSharedBufferBase(memAidl, bufferId).isOk(),
+ "setSharedBufferBase(): remote call failed");
+ }
+ mHeapSizes.removeItem(seqNum);
+ }
+}
+
+status_t CryptoHalAidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ Mutex::Autolock autoLock(mLock);
+ // Need to convert logmessage
+
+ return DrmUtils::GetLogMessagesAidl<ICryptoPluginAidl>(mPlugin, logs);
+}
+} // namespace android
\ No newline at end of file
diff --git a/drm/libmediadrm/CryptoHalHidl.cpp b/drm/libmediadrm/CryptoHalHidl.cpp
new file mode 100644
index 0000000..cbb6ddf
--- /dev/null
+++ b/drm/libmediadrm/CryptoHalHidl.cpp
@@ -0,0 +1,395 @@
+/*
+ * 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 "CryptoHalHidl"
+#include <utils/Log.h>
+
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <mediadrm/CryptoHalHidl.h>
+#include <mediadrm/DrmUtils.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::sp;
+using ::android::DrmUtils::toStatusT;
+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::HidlMemory;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+typedef drm::V1_2::Status Status_V1_2;
+
+namespace android {
+
+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 String8 toString8(hidl_string hString) {
+ return String8(hString.c_str());
+}
+
+CryptoHalHidl::CryptoHalHidl()
+ : mFactories(makeCryptoFactories()),
+ mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
+ mHeapSeqNum(0) {}
+
+CryptoHalHidl::~CryptoHalHidl() {}
+
+Vector<sp<ICryptoFactory>> CryptoHalHidl::makeCryptoFactories() {
+ Vector<sp<ICryptoFactory>> factories;
+
+ auto manager = hardware::defaultServiceManager1_2();
+ if (manager != NULL) {
+ manager->listManifestByInterface(
+ drm::V1_0::ICryptoFactory::descriptor,
+ [&factories](const hidl_vec<hidl_string>& registered) {
+ for (const auto& instance : registered) {
+ auto factory = drm::V1_0::ICryptoFactory::getService(instance);
+ if (factory != NULL) {
+ ALOGD("found drm@1.0 ICryptoFactory %s", instance.c_str());
+ factories.push_back(factory);
+ }
+ }
+ });
+ manager->listManifestByInterface(
+ drm::V1_1::ICryptoFactory::descriptor,
+ [&factories](const hidl_vec<hidl_string>& registered) {
+ for (const auto& instance : registered) {
+ auto factory = drm::V1_1::ICryptoFactory::getService(instance);
+ if (factory != NULL) {
+ ALOGD("found drm@1.1 ICryptoFactory %s", instance.c_str());
+ factories.push_back(factory);
+ }
+ }
+ });
+ }
+
+ if (factories.size() == 0) {
+ // must be in passthrough mode, load the default passthrough service
+ auto passthrough = ICryptoFactory::getService();
+ if (passthrough != NULL) {
+ ALOGI("makeCryptoFactories: using default passthrough crypto instance");
+ factories.push_back(passthrough);
+ } else {
+ ALOGE("Failed to find any crypto factories");
+ }
+ }
+ return factories;
+}
+
+sp<ICryptoPlugin> CryptoHalHidl::makeCryptoPlugin(const sp<ICryptoFactory>& factory,
+ const uint8_t uuid[16], const void* initData,
+ size_t initDataSize) {
+ sp<ICryptoPlugin> plugin;
+ Return<void> hResult =
+ factory->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;
+ });
+ if (!hResult.isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ return plugin;
+}
+
+status_t CryptoHalHidl::initCheck() const {
+ return mInitCheck;
+}
+
+bool CryptoHalHidl::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (size_t i = 0; i < mFactories.size(); i++) {
+ if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t CryptoHalHidl::createPlugin(const uint8_t uuid[16], const void* data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ 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);
+ }
+ }
+ }
+
+ if (mInitCheck == NO_INIT) {
+ mInitCheck = mPlugin == NULL ? ERROR_UNSUPPORTED : OK;
+ }
+
+ return mInitCheck;
+}
+
+status_t CryptoHalHidl::destroyPlugin() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ mPlugin.clear();
+ mPluginV1_2.clear();
+ return OK;
+}
+
+bool CryptoHalHidl::requiresSecureDecoderComponent(const char* mime) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return false;
+ }
+
+ Return<bool> hResult = mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
+ if (!hResult.isOk()) {
+ return false;
+ }
+ return hResult;
+}
+
+/**
+ * If the heap base isn't set, get the heap base from the HidlMemory
+ * 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.
+ */
+int32_t CryptoHalHidl::setHeapBase(const sp<HidlMemory>& heap) {
+ if (heap == NULL || mHeapSeqNum < 0) {
+ ALOGE("setHeapBase(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
+ return -1;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+
+ int32_t seqNum = mHeapSeqNum++;
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ mHeapSizes.add(seqNum, heap->size());
+ Return<void> hResult = mPlugin->setSharedBufferBase(*heap, bufferId);
+ ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+ return seqNum;
+}
+
+void CryptoHalHidl::clearHeapBase(int32_t seqNum) {
+ Mutex::Autolock autoLock(mLock);
+
+ /*
+ * Clear the remote shared memory mapping by setting the shared
+ * buffer base to a null hidl_memory.
+ *
+ * TODO: Add a releaseSharedBuffer method in a future DRM HAL
+ * API version to make this explicit.
+ */
+ ssize_t index = mHeapSizes.indexOfKey(seqNum);
+ if (index >= 0) {
+ if (mPlugin != NULL) {
+ uint32_t bufferId = static_cast<uint32_t>(seqNum);
+ Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
+ ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+ }
+ mHeapSizes.removeItem(seqNum);
+ }
+}
+
+status_t CryptoHalHidl::checkSharedBuffer(const ::SharedBuffer& buffer) {
+ int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
+ // memory must be in one of the heaps that have been set
+ if (mHeapSizes.indexOfKey(seqNum) < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ // memory must be within the address space of the heap
+ size_t heapSize = mHeapSizes.valueFor(seqNum);
+ if (heapSize < buffer.offset + buffer.size || SIZE_MAX - buffer.offset < buffer.size) {
+ android_errorWriteLog(0x534e4554, "76221123");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+ssize_t CryptoHalHidl::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern& pattern,
+ const drm::V1_0::SharedBuffer& hSource, size_t offset,
+ const CryptoPlugin::SubSample* subSamples, size_t numSubSamples,
+ const drm::V1_0::DestinationBuffer& hDestination,
+ AString* errorDetailMsg) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ 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;
+ if (hDestination.type == BufferType::SHARED_MEMORY) {
+ status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
+ if (status != OK) {
+ return status;
+ }
+ secure = false;
+ } else if (hDestination.type == BufferType::NATIVE_HANDLE) {
+ secure = true;
+ } else {
+ android_errorWriteLog(0x534e4554, "70526702");
+ return UNKNOWN_ERROR;
+ }
+
+ status_t status = checkSharedBuffer(hSource);
+ if (status != OK) {
+ return status;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+ uint32_t bytesWritten = 0;
+
+ Return<void> hResult;
+
+ mLock.unlock();
+ 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(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;
+ *errorDetailMsg = toString8(hDetailedError);
+ }
+ err = toStatusT(status);
+ });
+ }
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ if (err == OK) {
+ return bytesWritten;
+ }
+ return err;
+}
+
+void CryptoHalHidl::notifyResolution(uint32_t width, uint32_t height) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return;
+ }
+
+ auto hResult = mPlugin->notifyResolution(width, height);
+ ALOGE_IF(!hResult.isOk(), "notifyResolution txn failed %s", hResult.description().c_str());
+}
+
+status_t CryptoHalHidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ auto err = mPlugin->setMediaDrmSession(toHidlVec(sessionId));
+ return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
+}
+
+status_t CryptoHalHidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ Mutex::Autolock autoLock(mLock);
+ return DrmUtils::GetLogMessages<drm::V1_4::ICryptoPlugin>(mPlugin, logs);
+}
+} // namespace android
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 40d1e0c..fe8b9f6 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -17,1557 +17,273 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmHal"
-#include <aidl/android/media/BnResourceManagerClient.h>
-#include <android/binder_manager.h>
-#include <android/hardware/drm/1.2/types.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <hidl/ServiceManagement.h>
-#include <media/EventMetric.h>
-#include <media/MediaMetrics.h>
-#include <media/PluginMetricsReporting.h>
-#include <media/drm/DrmAPI.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/base64.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaErrors.h>
#include <mediadrm/DrmHal.h>
-#include <mediadrm/DrmSessionClientInterface.h>
-#include <mediadrm/DrmSessionManager.h>
-#include <mediadrm/IDrmMetricsConsumer.h>
+#include <mediadrm/DrmHalAidl.h>
+#include <mediadrm/DrmHalHidl.h>
#include <mediadrm/DrmUtils.h>
-#include <utils/Log.h>
-
-#include <iomanip>
-#include <vector>
-
-using drm::V1_0::KeyedVector;
-using drm::V1_0::KeyRequestType;
-using drm::V1_0::KeyType;
-using drm::V1_0::KeyValue;
-using drm::V1_0::SecureStop;
-using drm::V1_0::SecureStopId;
-using drm::V1_0::Status;
-using drm::V1_1::HdcpLevel;
-using drm::V1_1::SecureStopRelease;
-using drm::V1_1::SecurityLevel;
-using drm::V1_2::KeySetId;
-using drm::V1_2::KeyStatusType;
-using ::android::DrmUtils::toStatusT;
-using ::android::hardware::drm::V1_1::DrmMetricGroup;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::os::PersistableBundle;
-using ::android::sp;
-
-typedef drm::V1_1::KeyRequestType KeyRequestType_V1_1;
-typedef drm::V1_2::Status Status_V1_2;
-typedef drm::V1_2::HdcpLevel HdcpLevel_V1_2;
-
-namespace {
-
-// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
-// in the MediaDrm API.
-constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
-constexpr char kEqualsSign[] = "=";
-
-template<typename T>
-std::string toBase64StringNoPad(const T* data, size_t size) {
- // Note that the base 64 conversion only works with arrays of single-byte
- // values. If the source is empty or is not an array of single-byte values,
- // return empty string.
- if (size == 0 || sizeof(data[0]) != 1) {
- return "";
- }
-
- android::AString outputString;
- encodeBase64(data, size, &outputString);
- // Remove trailing equals padding if it exists.
- while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
- outputString.erase(outputString.size() - 1, 1);
- }
-
- return std::string(outputString.c_str(), outputString.size());
-}
-
-} // anonymous namespace
namespace android {
-#define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
-
-static const Vector<uint8_t> toVector(const hidl_vec<uint8_t> &vec) {
- Vector<uint8_t> vector;
- vector.appendArray(vec.data(), vec.size());
- return *const_cast<const Vector<uint8_t> *>(&vector);
+DrmHal::DrmHal() {
+ mDrmHalHidl = sp<DrmHalHidl>::make();
+ mDrmHalAidl = ndk::SharedRefBase::make<DrmHalAidl>();
}
-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 String8 toString8(const hidl_string &string) {
- return String8(string.c_str());
-}
-
-static hidl_string toHidlString(const String8& string) {
- return hidl_string(string.string());
-}
-
-static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
- switch(level) {
- case SecurityLevel::SW_SECURE_CRYPTO:
- return DrmPlugin::kSecurityLevelSwSecureCrypto;
- case SecurityLevel::SW_SECURE_DECODE:
- return DrmPlugin::kSecurityLevelSwSecureDecode;
- case SecurityLevel::HW_SECURE_CRYPTO:
- return DrmPlugin::kSecurityLevelHwSecureCrypto;
- case SecurityLevel::HW_SECURE_DECODE:
- return DrmPlugin::kSecurityLevelHwSecureDecode;
- case SecurityLevel::HW_SECURE_ALL:
- return DrmPlugin::kSecurityLevelHwSecureAll;
- default:
- return DrmPlugin::kSecurityLevelUnknown;
- }
-}
-
-static SecurityLevel toHidlSecurityLevel(DrmPlugin::SecurityLevel level) {
- switch(level) {
- case DrmPlugin::kSecurityLevelSwSecureCrypto:
- return SecurityLevel::SW_SECURE_CRYPTO;
- case DrmPlugin::kSecurityLevelSwSecureDecode:
- return SecurityLevel::SW_SECURE_DECODE;
- case DrmPlugin::kSecurityLevelHwSecureCrypto:
- return SecurityLevel::HW_SECURE_CRYPTO;
- case DrmPlugin::kSecurityLevelHwSecureDecode:
- return SecurityLevel::HW_SECURE_DECODE;
- case DrmPlugin::kSecurityLevelHwSecureAll:
- return SecurityLevel::HW_SECURE_ALL;
- default:
- return SecurityLevel::UNKNOWN;
- }
-}
-
-static DrmPlugin::OfflineLicenseState toOfflineLicenseState(
- OfflineLicenseState licenseState) {
- switch(licenseState) {
- case OfflineLicenseState::USABLE:
- return DrmPlugin::kOfflineLicenseStateUsable;
- case OfflineLicenseState::INACTIVE:
- return DrmPlugin::kOfflineLicenseStateReleased;
- default:
- return DrmPlugin::kOfflineLicenseStateUnknown;
- }
-}
-
-static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel_V1_2 level) {
- switch(level) {
- case HdcpLevel_V1_2::HDCP_NONE:
- return DrmPlugin::kHdcpNone;
- case HdcpLevel_V1_2::HDCP_V1:
- return DrmPlugin::kHdcpV1;
- case HdcpLevel_V1_2::HDCP_V2:
- return DrmPlugin::kHdcpV2;
- case HdcpLevel_V1_2::HDCP_V2_1:
- return DrmPlugin::kHdcpV2_1;
- case HdcpLevel_V1_2::HDCP_V2_2:
- return DrmPlugin::kHdcpV2_2;
- case HdcpLevel_V1_2::HDCP_V2_3:
- return DrmPlugin::kHdcpV2_3;
- case HdcpLevel_V1_2::HDCP_NO_OUTPUT:
- return DrmPlugin::kHdcpNoOutput;
- default:
- return DrmPlugin::kHdcpLevelUnknown;
- }
-}
-static ::KeyedVector toHidlKeyedVector(const KeyedVector<String8, String8>&
- keyedVector) {
- std::vector<KeyValue> stdKeyedVector;
- for (size_t i = 0; i < keyedVector.size(); i++) {
- KeyValue keyValue;
- keyValue.key = toHidlString(keyedVector.keyAt(i));
- keyValue.value = toHidlString(keyedVector.valueAt(i));
- stdKeyedVector.push_back(keyValue);
- }
- return ::KeyedVector(stdKeyedVector);
-}
-
-static KeyedVector<String8, String8> toKeyedVector(const ::KeyedVector&
- hKeyedVector) {
- KeyedVector<String8, String8> keyedVector;
- for (size_t i = 0; i < hKeyedVector.size(); i++) {
- keyedVector.add(toString8(hKeyedVector[i].key),
- toString8(hKeyedVector[i].value));
- }
- return keyedVector;
-}
-
-static List<Vector<uint8_t>> toSecureStops(const hidl_vec<SecureStop>&
- hSecureStops) {
- List<Vector<uint8_t>> secureStops;
- for (size_t i = 0; i < hSecureStops.size(); i++) {
- secureStops.push_back(toVector(hSecureStops[i].opaqueData));
- }
- return secureStops;
-}
-
-static List<Vector<uint8_t>> toSecureStopIds(const hidl_vec<SecureStopId>&
- hSecureStopIds) {
- List<Vector<uint8_t>> secureStopIds;
- for (size_t i = 0; i < hSecureStopIds.size(); i++) {
- secureStopIds.push_back(toVector(hSecureStopIds[i]));
- }
- return secureStopIds;
-}
-
-static List<Vector<uint8_t>> toKeySetIds(const hidl_vec<KeySetId>&
- hKeySetIds) {
- List<Vector<uint8_t>> keySetIds;
- for (size_t i = 0; i < hKeySetIds.size(); i++) {
- keySetIds.push_back(toVector(hKeySetIds[i]));
- }
- return keySetIds;
-}
-
-Mutex DrmHal::mLock;
-
-struct DrmHal::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
- explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
- : mSessionId(sessionId),
- mDrm(drm) {}
-
- ::ndk::ScopedAStatus reclaimResource(bool* _aidl_return) override;
- ::ndk::ScopedAStatus getName(::std::string* _aidl_return) override;
-
- const Vector<uint8_t> mSessionId;
-
- virtual ~DrmSessionClient();
-
-private:
- wp<DrmHal> mDrm;
-
- DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
-};
-
-::ndk::ScopedAStatus DrmHal::DrmSessionClient::reclaimResource(bool* _aidl_return) {
- auto sessionId = mSessionId;
- sp<DrmHal> drm = mDrm.promote();
- if (drm == NULL) {
- *_aidl_return = true;
- return ::ndk::ScopedAStatus::ok();
- }
- status_t err = drm->closeSession(sessionId);
- if (err != OK) {
- *_aidl_return = false;
- return ::ndk::ScopedAStatus::ok();
- }
- drm->sendEvent(EventType::SESSION_RECLAIMED,
- toHidlVec(sessionId), hidl_vec<uint8_t>());
- *_aidl_return = true;
- return ::ndk::ScopedAStatus::ok();
-}
-
-::ndk::ScopedAStatus DrmHal::DrmSessionClient::getName(::std::string* _aidl_return) {
- String8 name;
- sp<DrmHal> drm = mDrm.promote();
- if (drm == NULL) {
- name.append("<deleted>");
- } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK
- || name.isEmpty()) {
- name.append("<Get vendor failed or is empty>");
- }
- name.append("[");
- for (size_t i = 0; i < mSessionId.size(); ++i) {
- name.appendFormat("%02x", mSessionId[i]);
- }
- name.append("]");
- *_aidl_return = name;
- return ::ndk::ScopedAStatus::ok();
-}
-
-DrmHal::DrmSessionClient::~DrmSessionClient() {
- DrmSessionManager::Instance()->removeSession(mSessionId);
-}
-
-DrmHal::DrmHal()
- : mFactories(makeDrmFactories()),
- mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
-}
-
-void DrmHal::closeOpenSessions() {
- Mutex::Autolock autoLock(mLock);
- auto openSessions = mOpenSessions;
- for (size_t i = 0; i < openSessions.size(); i++) {
- mLock.unlock();
- closeSession(openSessions[i]->mSessionId);
- mLock.lock();
- }
- mOpenSessions.clear();
-}
-
-DrmHal::~DrmHal() {
-}
-
-void DrmHal::cleanup() {
- closeOpenSessions();
-
- Mutex::Autolock autoLock(mLock);
- reportFrameworkMetrics(reportPluginMetrics());
-
- setListener(NULL);
- mInitCheck = NO_INIT;
- 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;
- }
- }
- mPlugin.clear();
- mPluginV1_1.clear();
- mPluginV1_2.clear();
- mPluginV1_4.clear();
-}
-
-std::vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
- static std::vector<sp<IDrmFactory>> factories(DrmUtils::MakeDrmFactories());
- if (factories.size() == 0) {
- // must be in passthrough mode, load the default passthrough service
- auto passthrough = IDrmFactory::getService();
- if (passthrough != NULL) {
- DrmUtils::LOG2BI("makeDrmFactories: using default passthrough drm instance");
- factories.push_back(passthrough);
- } else {
- DrmUtils::LOG2BE("Failed to find any drm factories");
- }
- }
- return factories;
-}
-
-sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
- const uint8_t uuid[16], const String8& appPackageName) {
- mAppPackageName = appPackageName;
- mMetrics.SetAppPackageName(appPackageName);
- mMetrics.SetAppUid(AIBinder_getCallingUid());
-
- sp<IDrmPlugin> plugin;
- Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
- [&](Status status, const sp<IDrmPlugin>& hPlugin) {
- if (status != Status::OK) {
- DrmUtils::LOG2BE(uuid, "Failed to make drm plugin: %d", status);
- return;
- }
- plugin = hPlugin;
- }
- );
-
- if (!hResult.isOk()) {
- DrmUtils::LOG2BE(uuid, "createPlugin remote call failed: %s",
- hResult.description().c_str());
- }
-
- return plugin;
-}
+DrmHal::~DrmHal() {}
status_t DrmHal::initCheck() const {
- return mInitCheck;
+ if (mDrmHalAidl->initCheck() == OK || mDrmHalHidl->initCheck() == OK) return OK;
+ if (mDrmHalAidl->initCheck() == NO_INIT || mDrmHalHidl->initCheck() == NO_INIT) return NO_INIT;
+ return mDrmHalHidl->initCheck();
}
-status_t DrmHal::setListener(const sp<IDrmClient>& listener)
-{
- Mutex::Autolock lock(mEventLock);
- mListener = listener;
- return NO_ERROR;
+status_t DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel securityLevel, bool* result) {
+ status_t statusResult;
+ statusResult = mDrmHalAidl->isCryptoSchemeSupported(uuid, mimeType, securityLevel, result);
+ if (*result) return statusResult;
+ return mDrmHalHidl->isCryptoSchemeSupported(uuid, mimeType, securityLevel, result);
}
-Return<void> DrmHal::sendEvent(EventType hEventType,
- const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) {
- mMetrics.mEventCounter.Increment(hEventType);
-
- mEventLock.lock();
- sp<IDrmClient> listener = mListener;
- mEventLock.unlock();
-
- if (listener != NULL) {
- Mutex::Autolock lock(mNotifyLock);
- DrmPlugin::EventType eventType;
- switch(hEventType) {
- case EventType::PROVISION_REQUIRED:
- eventType = DrmPlugin::kDrmPluginEventProvisionRequired;
- break;
- case EventType::KEY_NEEDED:
- eventType = DrmPlugin::kDrmPluginEventKeyNeeded;
- break;
- case EventType::KEY_EXPIRED:
- eventType = DrmPlugin::kDrmPluginEventKeyExpired;
- break;
- case EventType::VENDOR_DEFINED:
- eventType = DrmPlugin::kDrmPluginEventVendorDefined;
- break;
- case EventType::SESSION_RECLAIMED:
- eventType = DrmPlugin::kDrmPluginEventSessionReclaimed;
- break;
- default:
- return Void();
- }
- listener->sendEvent(eventType, sessionId, data);
- }
- return Void();
-}
-
-Return<void> DrmHal::sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
- int64_t expiryTimeInMS) {
-
- mEventLock.lock();
- sp<IDrmClient> listener = mListener;
- mEventLock.unlock();
-
- if (listener != NULL) {
- Mutex::Autolock lock(mNotifyLock);
- listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
- }
- return Void();
-}
-
-Return<void> DrmHal::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus_V1_0>& keyStatusList_V1_0, bool hasNewUsableKey) {
- std::vector<KeyStatus> keyStatusVec;
- for (const auto &keyStatus_V1_0 : keyStatusList_V1_0) {
- keyStatusVec.push_back({keyStatus_V1_0.keyId,
- static_cast<KeyStatusType>(keyStatus_V1_0.type)});
- }
- hidl_vec<KeyStatus> keyStatusList_V1_2(keyStatusVec);
- return sendKeysChange_1_2(sessionId, keyStatusList_V1_2, hasNewUsableKey);
-}
-
-Return<void> DrmHal::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus>& hKeyStatusList, bool hasNewUsableKey) {
-
- mEventLock.lock();
- sp<IDrmClient> listener = mListener;
- mEventLock.unlock();
-
- if (listener != NULL) {
- std::vector<DrmKeyStatus> keyStatusList;
- size_t nKeys = hKeyStatusList.size();
- for (size_t i = 0; i < nKeys; ++i) {
- const KeyStatus &keyStatus = hKeyStatusList[i];
- uint32_t type;
- switch(keyStatus.type) {
- case KeyStatusType::USABLE:
- type = DrmPlugin::kKeyStatusType_Usable;
- break;
- case KeyStatusType::EXPIRED:
- type = DrmPlugin::kKeyStatusType_Expired;
- break;
- case KeyStatusType::OUTPUTNOTALLOWED:
- type = DrmPlugin::kKeyStatusType_OutputNotAllowed;
- break;
- case KeyStatusType::STATUSPENDING:
- type = DrmPlugin::kKeyStatusType_StatusPending;
- break;
- case KeyStatusType::USABLEINFUTURE:
- type = DrmPlugin::kKeyStatusType_UsableInFuture;
- break;
- case KeyStatusType::INTERNALERROR:
- default:
- type = DrmPlugin::kKeyStatusType_InternalError;
- break;
- }
- keyStatusList.push_back({type, keyStatus.keyId});
- mMetrics.mKeyStatusChangeCounter.Increment(keyStatus.type);
- }
-
- Mutex::Autolock lock(mNotifyLock);
- listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
- } else {
- // There's no listener. But we still want to count the key change
- // events.
- size_t nKeys = hKeyStatusList.size();
- for (size_t i = 0; i < nKeys; i++) {
- mMetrics.mKeyStatusChangeCounter.Increment(hKeyStatusList[i].type);
- }
- }
-
- return Void();
-}
-
-Return<void> DrmHal::sendSessionLostState(
- const hidl_vec<uint8_t>& sessionId) {
-
- mEventLock.lock();
- sp<IDrmClient> listener = mListener;
- mEventLock.unlock();
-
- if (listener != NULL) {
- Mutex::Autolock lock(mNotifyLock);
- listener->sendSessionLostState(sessionId);
- }
- return Void();
-}
-
-status_t DrmHal::matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
- const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported) {
- *isSupported = false;
-
- // handle default value cases
- if (level == DrmPlugin::kSecurityLevelUnknown) {
- if (mimeType == "") {
- // isCryptoSchemeSupported(uuid)
- *isSupported = true;
- } else {
- // isCryptoSchemeSupported(uuid, mimeType)
- *isSupported = factory->isContentTypeSupported(mimeType.string());
- }
- return OK;
- } else if (mimeType == "") {
- return BAD_VALUE;
- }
-
- sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
- if (factoryV1_2 == NULL) {
- return ERROR_UNSUPPORTED;
- } else {
- *isSupported = factoryV1_2->isCryptoSchemeSupported_1_2(uuid,
- mimeType.string(), toHidlSecurityLevel(level));
- return OK;
- }
-}
-
-status_t DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported) {
- Mutex::Autolock autoLock(mLock);
- *isSupported = false;
- for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
- if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
- return matchMimeTypeAndSecurityLevel(mFactories[i],
- uuid, mimeType, level, isSupported);
- }
- }
- return OK;
-}
-
-status_t DrmHal::createPlugin(const uint8_t uuid[16],
- const String8& appPackageName) {
- Mutex::Autolock autoLock(mLock);
-
- for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
- auto hResult = mFactories[i]->isCryptoSchemeSupported(uuid);
- if (hResult.isOk() && hResult) {
- auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
- if (plugin != NULL) {
- mPlugin = plugin;
- mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
- mPluginV1_2 = drm::V1_2::IDrmPlugin::castFrom(mPlugin);
- mPluginV1_4 = drm::V1_4::IDrmPlugin::castFrom(mPlugin);
- break;
- }
- }
- }
-
- if (mPlugin == NULL) {
- DrmUtils::LOG2BE(uuid, "No supported hal instance found");
- mInitCheck = ERROR_UNSUPPORTED;
- } 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();
- mPluginV1_4.clear();
- }
- }
-
-
- return mInitCheck;
+status_t DrmHal::createPlugin(const uint8_t uuid[16], const String8& appPackageName) {
+ status_t statusResult;
+ statusResult = mDrmHalAidl->createPlugin(uuid, appPackageName);
+ if (statusResult != OK) return mDrmHalHidl->createPlugin(uuid, appPackageName);
+ return statusResult;
}
status_t DrmHal::destroyPlugin() {
- cleanup();
- return OK;
+ status_t statusResult = mDrmHalAidl->destroyPlugin();
+ status_t statusResultHidl = mDrmHalHidl->destroyPlugin();
+ if (statusResult != OK) return statusResult;
+ return statusResultHidl;
}
-status_t DrmHal::openSession(DrmPlugin::SecurityLevel level,
- Vector<uint8_t> &sessionId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- SecurityLevel hSecurityLevel = toHidlSecurityLevel(level);
- bool setSecurityLevel = true;
-
- if (level == DrmPlugin::kSecurityLevelMax) {
- setSecurityLevel = false;
- } else {
- if (hSecurityLevel == SecurityLevel::UNKNOWN) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
- }
-
- status_t err = UNKNOWN_ERROR;
- bool retry = true;
- do {
- hidl_vec<uint8_t> hSessionId;
-
- Return<void> hResult;
- if (mPluginV1_1 == NULL || !setSecurityLevel) {
- hResult = mPlugin->openSession(
- [&](Status status,const hidl_vec<uint8_t>& id) {
- if (status == Status::OK) {
- sessionId = toVector(id);
- }
- err = toStatusT(status);
- }
- );
- } else {
- hResult = mPluginV1_1->openSession_1_1(hSecurityLevel,
- [&](Status status, const hidl_vec<uint8_t>& id) {
- if (status == Status::OK) {
- sessionId = toVector(id);
- }
- err = toStatusT(status);
- }
- );
- }
-
- if (!hResult.isOk()) {
- err = DEAD_OBJECT;
- }
-
- if (err == ERROR_DRM_RESOURCE_BUSY && retry) {
- mLock.unlock();
- // reclaimSession may call back to closeSession, since mLock is
- // shared between Drm instances, we should unlock here to avoid
- // deadlock.
- retry = DrmSessionManager::Instance()->reclaimSession(AIBinder_getCallingPid());
- mLock.lock();
- } else {
- retry = false;
- }
- } while (retry);
-
- if (err == OK) {
- std::shared_ptr<DrmSessionClient> client =
- ndk::SharedRefBase::make<DrmSessionClient>(this, sessionId);
- DrmSessionManager::Instance()->addSession(AIBinder_getCallingPid(),
- std::static_pointer_cast<IResourceManagerClient>(client), sessionId);
- mOpenSessions.push_back(client);
- mMetrics.SetSessionStart(sessionId);
- }
-
- mMetrics.mOpenSessionCounter.Increment(err);
- return err;
+status_t DrmHal::openSession(DrmPlugin::SecurityLevel securityLevel, Vector<uint8_t>& sessionId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->openSession(securityLevel, sessionId);
+ return mDrmHalHidl->openSession(securityLevel, sessionId);
}
-status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status = mPlugin->closeSession(toHidlVec(sessionId));
- if (status.isOk()) {
- if (status == Status::OK) {
- DrmSessionManager::Instance()->removeSession(sessionId);
- for (auto i = mOpenSessions.begin(); i != mOpenSessions.end(); i++) {
- if (isEqualSessionId((*i)->mSessionId, sessionId)) {
- mOpenSessions.erase(i);
- break;
- }
- }
- }
- status_t response = toStatusT(status);
- mMetrics.SetSessionEnd(sessionId);
- mMetrics.mCloseSessionCounter.Increment(response);
- return response;
- }
- mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT);
- return DEAD_OBJECT;
+status_t DrmHal::closeSession(Vector<uint8_t> const& sessionId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->closeSession(sessionId);
+ return mDrmHalHidl->closeSession(sessionId);
}
-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;
- }
+status_t DrmHal::getKeyRequest(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& initData,
+ String8 const& mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->getKeyRequest(sessionId, initData, mimeType, keyType,
+ optionalParameters, request, defaultUrl, keyRequestType);
+ return mDrmHalHidl->getKeyRequest(sessionId, initData, mimeType, keyType, optionalParameters,
+ request, defaultUrl, keyRequestType);
}
-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::provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response, Vector<uint8_t>& keySetId) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->provideKeyResponse(sessionId, response, keySetId);
+ return mDrmHalHidl->provideKeyResponse(sessionId, response, keySetId);
}
-status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData, String8 const &mimeType,
- DrmPlugin::KeyType keyType, KeyedVector<String8,
- String8> const &optionalParameters, Vector<uint8_t> &request,
- String8 &defaultUrl, DrmPlugin::KeyRequestType *keyRequestType) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
- EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- KeyType hKeyType;
- if (keyType == DrmPlugin::kKeyType_Streaming) {
- hKeyType = KeyType::STREAMING;
- } else if (keyType == DrmPlugin::kKeyType_Offline) {
- hKeyType = KeyType::OFFLINE;
- } else if (keyType == DrmPlugin::kKeyType_Release) {
- hKeyType = KeyType::RELEASE;
- } else {
- keyRequestTimer.SetAttribute(BAD_VALUE);
- return BAD_VALUE;
- }
-
- ::KeyedVector hOptionalParameters = toHidlKeyedVector(optionalParameters);
-
- status_t err = UNKNOWN_ERROR;
- Return<void> hResult;
-
- 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(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,
- KeyRequestType_V1_1 hKeyRequestType,
- const hidl_string& hDefaultUrl) {
- if (status == Status::OK) {
- request = toVector(hRequest);
- defaultUrl = toString8(hDefaultUrl);
- *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
- }
- err = toStatusT(status);
- });
- } else {
- hResult = mPlugin->getKeyRequest(
- toHidlVec(sessionId), toHidlVec(initData),
- toHidlString(mimeType), hKeyType, hOptionalParameters,
- [&](Status status, const hidl_vec<uint8_t>& hRequest,
- KeyRequestType hKeyRequestType,
- const hidl_string& hDefaultUrl) {
- if (status == Status::OK) {
- request = toVector(hRequest);
- defaultUrl = toString8(hDefaultUrl);
- *keyRequestType = toKeyRequestType(hKeyRequestType);
- }
- err = toStatusT(status);
- });
- }
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- keyRequestTimer.SetAttribute(err);
- return err;
+status_t DrmHal::removeKeys(Vector<uint8_t> const& keySetId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->removeKeys(keySetId);
+ return mDrmHalHidl->removeKeys(keySetId);
}
-status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
- EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->provideKeyResponse(toHidlVec(sessionId),
- toHidlVec(response),
- [&](Status status, const hidl_vec<uint8_t>& hKeySetId) {
- if (status == Status::OK) {
- keySetId = toVector(hKeySetId);
- }
- err = toStatusT(status);
- }
- );
- err = hResult.isOk() ? err : DEAD_OBJECT;
- keyResponseTimer.SetAttribute(err);
- return err;
+status_t DrmHal::restoreKeys(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keySetId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->restoreKeys(sessionId, keySetId);
+ return mDrmHalHidl->restoreKeys(sessionId, keySetId);
}
-status_t DrmHal::removeKeys(Vector<uint8_t> const &keySetId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status = mPlugin->removeKeys(toHidlVec(keySetId));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->queryKeyStatus(sessionId, infoMap);
+ return mDrmHalHidl->queryKeyStatus(sessionId, infoMap);
}
-status_t DrmHal::restoreKeys(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keySetId) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- Return<Status> status = mPlugin->restoreKeys(toHidlVec(sessionId),
- toHidlVec(keySetId));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->getProvisionRequest(certType, certAuthority, request, defaultUrl);
+ return mDrmHalHidl->getProvisionRequest(certType, certAuthority, request, defaultUrl);
}
-status_t DrmHal::queryKeyStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- ::KeyedVector hInfoMap;
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->queryKeyStatus(toHidlVec(sessionId),
- [&](Status status, const hidl_vec<KeyValue>& map) {
- if (status == Status::OK) {
- infoMap = toKeyedVector(map);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->provideProvisionResponse(response, certificate, wrappedKey);
+ return mDrmHalHidl->provideProvisionResponse(response, certificate, wrappedKey);
}
-status_t DrmHal::getProvisionRequest(String8 const &certType,
- String8 const &certAuthority, Vector<uint8_t> &request,
- String8 &defaultUrl) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
- Return<void> hResult;
-
- if (mPluginV1_2 != NULL) {
- 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(status);
- }
- );
- } else {
- hResult = mPlugin->getProvisionRequest(
- toHidlString(certType), toHidlString(certAuthority),
- [&](Status status, const hidl_vec<uint8_t>& hRequest,
- const hidl_string& hDefaultUrl) {
- if (status == Status::OK) {
- request = toVector(hRequest);
- defaultUrl = toString8(hDefaultUrl);
- }
- err = toStatusT(status);
- }
- );
- }
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- mMetrics.mGetProvisionRequestCounter.Increment(err);
- return err;
+status_t DrmHal::getSecureStops(List<Vector<uint8_t>>& secureStops) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getSecureStops(secureStops);
+ return mDrmHalHidl->getSecureStops(secureStops);
}
-status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const &response,
- Vector<uint8_t> &certificate, Vector<uint8_t> &wrappedKey) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->provideProvisionResponse(toHidlVec(response),
- [&](Status status, const hidl_vec<uint8_t>& hCertificate,
- const hidl_vec<uint8_t>& hWrappedKey) {
- if (status == Status::OK) {
- certificate = toVector(hCertificate);
- wrappedKey = toVector(hWrappedKey);
- }
- err = toStatusT(status);
- }
- );
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- mMetrics.mProvideProvisionResponseCounter.Increment(err);
- return err;
+status_t DrmHal::getSecureStopIds(List<Vector<uint8_t>>& secureStopIds) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getSecureStopIds(secureStopIds);
+ return mDrmHalHidl->getSecureStopIds(secureStopIds);
}
-status_t DrmHal::getSecureStops(List<Vector<uint8_t>> &secureStops) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->getSecureStops(
- [&](Status status, const hidl_vec<SecureStop>& hSecureStops) {
- if (status == Status::OK) {
- secureStops = toSecureStops(hSecureStops);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getSecureStop(ssid, secureStop);
+ return mDrmHalHidl->getSecureStop(ssid, secureStop);
}
-
-status_t DrmHal::getSecureStopIds(List<Vector<uint8_t>> &secureStopIds) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_1 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPluginV1_1->getSecureStopIds(
- [&](Status status, const hidl_vec<SecureStopId>& hSecureStopIds) {
- if (status == Status::OK) {
- secureStopIds = toSecureStopIds(hSecureStopIds);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::releaseSecureStops(Vector<uint8_t> const& ssRelease) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->releaseSecureStops(ssRelease);
+ return mDrmHalHidl->releaseSecureStops(ssRelease);
}
-
-status_t DrmHal::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->getSecureStop(toHidlVec(ssid),
- [&](Status status, const SecureStop& hSecureStop) {
- if (status == Status::OK) {
- secureStop = toVector(hSecureStop.opaqueData);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
-}
-
-status_t DrmHal::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status(Status::ERROR_DRM_UNKNOWN);
- if (mPluginV1_1 != NULL) {
- SecureStopRelease secureStopRelease;
- secureStopRelease.opaqueData = toHidlVec(ssRelease);
- status = mPluginV1_1->releaseSecureStops(secureStopRelease);
- } else {
- status = mPlugin->releaseSecureStop(toHidlVec(ssRelease));
- }
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
-}
-
-status_t DrmHal::removeSecureStop(Vector<uint8_t> const &ssid) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_1 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- Return<Status> status = mPluginV1_1->removeSecureStop(toHidlVec(ssid));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::removeSecureStop(Vector<uint8_t> const& ssid) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->removeSecureStop(ssid);
+ return mDrmHalHidl->removeSecureStop(ssid);
}
status_t DrmHal::removeAllSecureStops() {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status(Status::ERROR_DRM_UNKNOWN);
- if (mPluginV1_1 != NULL) {
- status = mPluginV1_1->removeAllSecureStops();
- } else {
- status = mPlugin->releaseAllSecureStops();
- }
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->removeAllSecureStops();
+ return mDrmHalHidl->removeAllSecureStops();
}
-status_t DrmHal::getHdcpLevels(DrmPlugin::HdcpLevel *connected,
- DrmPlugin::HdcpLevel *max) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- if (connected == NULL || max == NULL) {
- return BAD_VALUE;
- }
- status_t err = UNKNOWN_ERROR;
-
- *connected = DrmPlugin::kHdcpLevelUnknown;
- *max = DrmPlugin::kHdcpLevelUnknown;
-
- Return<void> hResult;
- if (mPluginV1_2 != NULL) {
- hResult = mPluginV1_2->getHdcpLevels_1_2(
- [&](Status_V1_2 status, const HdcpLevel_V1_2& hConnected, const HdcpLevel_V1_2& hMax) {
- if (status == Status_V1_2::OK) {
- *connected = toHdcpLevel(hConnected);
- *max = toHdcpLevel(hMax);
- }
- err = toStatusT(status);
- });
- } else if (mPluginV1_1 != NULL) {
- hResult = mPluginV1_1->getHdcpLevels(
- [&](Status status, const HdcpLevel& hConnected, const HdcpLevel& hMax) {
- if (status == Status::OK) {
- *connected = toHdcpLevel(static_cast<HdcpLevel_V1_2>(hConnected));
- *max = toHdcpLevel(static_cast<HdcpLevel_V1_2>(hMax));
- }
- err = toStatusT(status);
- });
- } else {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getHdcpLevels(DrmPlugin::HdcpLevel* connectedLevel,
+ DrmPlugin::HdcpLevel* maxLevel) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getHdcpLevels(connectedLevel, maxLevel);
+ return mDrmHalHidl->getHdcpLevels(connectedLevel, maxLevel);
}
-status_t DrmHal::getNumberOfSessions(uint32_t *open, uint32_t *max) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- if (open == NULL || max == NULL) {
- return BAD_VALUE;
- }
- status_t err = UNKNOWN_ERROR;
-
- *open = 0;
- *max = 0;
-
- if (mPluginV1_1 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- Return<void> hResult = mPluginV1_1->getNumberOfSessions(
- [&](Status status, uint32_t hOpen, uint32_t hMax) {
- if (status == Status::OK) {
- *open = hOpen;
- *max = hMax;
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getNumberOfSessions(uint32_t* currentSessions, uint32_t* maxSessions) const {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->getNumberOfSessions(currentSessions, maxSessions);
+ return mDrmHalHidl->getNumberOfSessions(currentSessions, maxSessions);
}
-status_t DrmHal::getSecurityLevel(Vector<uint8_t> const &sessionId,
- DrmPlugin::SecurityLevel *level) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- if (level == NULL) {
- return BAD_VALUE;
- }
- status_t err = UNKNOWN_ERROR;
-
- if (mPluginV1_1 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
- }
-
- *level = DrmPlugin::kSecurityLevelUnknown;
-
- Return<void> hResult = mPluginV1_1->getSecurityLevel(toHidlVec(sessionId),
- [&](Status status, SecurityLevel hLevel) {
- if (status == Status::OK) {
- *level = toSecurityLevel(hLevel);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getSecurityLevel(sessionId, level);
+ return mDrmHalHidl->getSecurityLevel(sessionId, level);
}
-status_t DrmHal::getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_2 == NULL) {
- return ERROR_UNSUPPORTED;
- }
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPluginV1_2->getOfflineLicenseKeySetIds(
- [&](Status status, const hidl_vec<KeySetId>& hKeySetIds) {
- if (status == Status::OK) {
- keySetIds = toKeySetIds(hKeySetIds);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getOfflineLicenseKeySetIds(keySetIds);
+ return mDrmHalHidl->getOfflineLicenseKeySetIds(keySetIds);
}
-status_t DrmHal::removeOfflineLicense(Vector<uint8_t> const &keySetId) {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_2 == NULL) {
- return ERROR_UNSUPPORTED;
- }
-
- Return<Status> status = mPluginV1_2->removeOfflineLicense(toHidlVec(keySetId));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::removeOfflineLicense(Vector<uint8_t> const& keySetId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->removeOfflineLicense(keySetId);
+ return mDrmHalHidl->removeOfflineLicense(keySetId);
}
-status_t DrmHal::getOfflineLicenseState(Vector<uint8_t> const &keySetId,
- DrmPlugin::OfflineLicenseState *licenseState) const {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPluginV1_2 == NULL) {
- return ERROR_UNSUPPORTED;
- }
- *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPluginV1_2->getOfflineLicenseState(toHidlVec(keySetId),
- [&](Status status, OfflineLicenseState hLicenseState) {
- if (status == Status::OK) {
- *licenseState = toOfflineLicenseState(hLicenseState);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->getOfflineLicenseState(keySetId, licenseState);
+ return mDrmHalHidl->getOfflineLicenseState(keySetId, licenseState);
}
-status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
- Mutex::Autolock autoLock(mLock);
- return getPropertyStringInternal(name, value);
+status_t DrmHal::getPropertyString(String8 const& name, String8& value) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getPropertyString(name, value);
+ return mDrmHalHidl->getPropertyString(name, value);
}
-status_t DrmHal::getPropertyStringInternal(String8 const &name, String8 &value) const {
- // This function is internal to the class and should only be called while
- // mLock is already held.
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->getPropertyString(toHidlString(name),
- [&](Status status, const hidl_string& hValue) {
- if (status == Status::OK) {
- value = toString8(hValue);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getPropertyByteArray(name, value);
+ return mDrmHalHidl->getPropertyByteArray(name, value);
}
-status_t DrmHal::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
- Mutex::Autolock autoLock(mLock);
- return getPropertyByteArrayInternal(name, value);
+status_t DrmHal::setPropertyString(String8 const& name, String8 const& value) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setPropertyString(name, value);
+ return mDrmHalHidl->setPropertyString(name, value);
}
-status_t DrmHal::getPropertyByteArrayInternal(String8 const &name, Vector<uint8_t> &value ) const {
- // This function is internal to the class and should only be called while
- // mLock is already held.
- INIT_CHECK();
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->getPropertyByteArray(toHidlString(name),
- [&](Status status, const hidl_vec<uint8_t>& hValue) {
- if (status == Status::OK) {
- value = toVector(hValue);
- }
- err = toStatusT(status);
- }
- );
-
- err = hResult.isOk() ? err : DEAD_OBJECT;
- if (name == kPropertyDeviceUniqueId) {
- mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
- }
- return err;
+status_t DrmHal::setPropertyByteArray(String8 const& name, Vector<uint8_t> const& value) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setPropertyByteArray(name, value);
+ return mDrmHalHidl->setPropertyByteArray(name, value);
}
-status_t DrmHal::setPropertyString(String8 const &name, String8 const &value ) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status = mPlugin->setPropertyString(toHidlString(name),
- toHidlString(value));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::getMetrics(const sp<IDrmMetricsConsumer>& consumer) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getMetrics(consumer);
+ return mDrmHalHidl->getMetrics(consumer);
}
-status_t DrmHal::setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value ) const {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- Return<Status> status = mPlugin->setPropertyByteArray(toHidlString(name),
- toHidlVec(value));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::setCipherAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->setCipherAlgorithm(sessionId, algorithm);
+ return mDrmHalHidl->setCipherAlgorithm(sessionId, algorithm);
}
-status_t DrmHal::getMetrics(const sp<IDrmMetricsConsumer> &consumer) {
- if (consumer == nullptr) {
- return UNEXPECTED_NULL;
- }
- consumer->consumeFrameworkMetrics(mMetrics);
-
- // Append vendor metrics if they are supported.
- if (mPluginV1_1 != NULL) {
- String8 vendor;
- String8 description;
- if (getPropertyStringInternal(String8("vendor"), vendor) != OK
- || vendor.isEmpty()) {
- ALOGE("Get vendor failed or is empty");
- vendor = "NONE";
- }
- if (getPropertyStringInternal(String8("description"), description) != OK
- || description.isEmpty()) {
- ALOGE("Get description failed or is empty.");
- description = "NONE";
- }
- vendor += ".";
- vendor += description;
-
- hidl_vec<DrmMetricGroup> pluginMetrics;
- status_t err = UNKNOWN_ERROR;
-
- Return<void> status = mPluginV1_1->getMetrics(
- [&](Status status, hidl_vec<DrmMetricGroup> pluginMetrics) {
- if (status != Status::OK) {
- ALOGV("Error getting plugin metrics: %d", status);
- } else {
- consumer->consumeHidlMetrics(vendor, pluginMetrics);
- }
- err = toStatusT(status);
- });
- return status.isOk() ? err : DEAD_OBJECT;
- }
-
- return OK;
+status_t DrmHal::setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setMacAlgorithm(sessionId, algorithm);
+ return mDrmHalHidl->setMacAlgorithm(sessionId, algorithm);
}
-status_t DrmHal::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- Return<Status> status = mPlugin->setCipherAlgorithm(toHidlVec(sessionId),
- toHidlString(algorithm));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->encrypt(sessionId, keyId, input, iv, output);
+ return mDrmHalHidl->encrypt(sessionId, keyId, input, iv, output);
}
-status_t DrmHal::setMacAlgorithm(Vector<uint8_t> const &sessionId,
- String8 const &algorithm) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- Return<Status> status = mPlugin->setMacAlgorithm(toHidlVec(sessionId),
- toHidlString(algorithm));
- return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+status_t DrmHal::decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->decrypt(sessionId, keyId, input, iv, output);
+ return mDrmHalHidl->decrypt(sessionId, keyId, input, iv, output);
}
-status_t DrmHal::encrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->encrypt(toHidlVec(sessionId),
- toHidlVec(keyId), toHidlVec(input), toHidlVec(iv),
- [&](Status status, const hidl_vec<uint8_t>& hOutput) {
- if (status == Status::OK) {
- output = toVector(hOutput);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->sign(sessionId, keyId, message, signature);
+ return mDrmHalHidl->sign(sessionId, keyId, message, signature);
}
-status_t DrmHal::decrypt(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
- Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->decrypt(toHidlVec(sessionId),
- toHidlVec(keyId), toHidlVec(input), toHidlVec(iv),
- [&](Status status, const hidl_vec<uint8_t>& hOutput) {
- if (status == Status::OK) {
- output = toVector(hOutput);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->verify(sessionId, keyId, message, signature, match);
+ return mDrmHalHidl->verify(sessionId, keyId, message, signature, match);
}
-status_t DrmHal::sign(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
- Vector<uint8_t> &signature) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->sign(toHidlVec(sessionId),
- toHidlVec(keyId), toHidlVec(message),
- [&](Status status, const hidl_vec<uint8_t>& hSignature) {
- if (status == Status::OK) {
- signature = toVector(hSignature);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature) {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->signRSA(sessionId, algorithm, message, wrappedKey, signature);
+ return mDrmHalHidl->signRSA(sessionId, algorithm, message, wrappedKey, signature);
}
-status_t DrmHal::verify(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
- Vector<uint8_t> const &signature, bool &match) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->verify(toHidlVec(sessionId),toHidlVec(keyId),
- toHidlVec(message), toHidlVec(signature),
- [&](Status status, bool hMatch) {
- if (status == Status::OK) {
- match = hMatch;
- } else {
- match = false;
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::setListener(const sp<IDrmClient>& listener) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setListener(listener);
+ return mDrmHalHidl->setListener(listener);
}
-status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId,
- String8 const &algorithm, Vector<uint8_t> const &message,
- Vector<uint8_t> const &wrappedKey, Vector<uint8_t> &signature) {
- Mutex::Autolock autoLock(mLock);
- INIT_CHECK();
-
- DrmSessionManager::Instance()->useSession(sessionId);
-
- status_t err = UNKNOWN_ERROR;
-
- Return<void> hResult = mPlugin->signRSA(toHidlVec(sessionId),
- toHidlString(algorithm), toHidlVec(message), toHidlVec(wrappedKey),
- [&](Status status, const hidl_vec<uint8_t>& hSignature) {
- if (status == Status::OK) {
- signature = toVector(hSignature);
- }
- err = toStatusT(status);
- }
- );
-
- return hResult.isOk() ? err : DEAD_OBJECT;
+status_t DrmHal::requiresSecureDecoder(const char* mime, bool* required) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->requiresSecureDecoder(mime, required);
+ return mDrmHalHidl->requiresSecureDecoder(mime, required);
}
-std::string DrmHal::reportFrameworkMetrics(const std::string& pluginMetrics) const
-{
- mediametrics_handle_t item(mediametrics_create("mediadrm"));
- mediametrics_setUid(item, mMetrics.GetAppUid());
- String8 vendor;
- String8 description;
- status_t result = getPropertyStringInternal(String8("vendor"), vendor);
- if (result != OK) {
- ALOGE("Failed to get vendor from drm plugin: %d", result);
- } else {
- mediametrics_setCString(item, "vendor", vendor.c_str());
- }
- result = getPropertyStringInternal(String8("description"), description);
- if (result != OK) {
- ALOGE("Failed to get description from drm plugin: %d", result);
- } else {
- mediametrics_setCString(item, "description", description.c_str());
- }
-
- std::string serializedMetrics;
- result = mMetrics.GetSerializedMetrics(&serializedMetrics);
- if (result != OK) {
- ALOGE("Failed to serialize framework metrics: %d", result);
- }
- std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
- serializedMetrics.size());
- if (!b64EncodedMetrics.empty()) {
- mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
- }
- if (!pluginMetrics.empty()) {
- mediametrics_setCString(item, "plugin_metrics", pluginMetrics.c_str());
- }
- if (!mediametrics_selfRecord(item)) {
- ALOGE("Failed to self record framework metrics");
- }
- mediametrics_delete(item);
- return serializedMetrics;
+status_t DrmHal::requiresSecureDecoder(const char* mime, DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const {
+ if (mDrmHalAidl->initCheck() == OK)
+ return mDrmHalAidl->requiresSecureDecoder(mime, securityLevel, required);
+ return mDrmHalHidl->requiresSecureDecoder(mime, securityLevel, required);
}
-std::string DrmHal::reportPluginMetrics() const
-{
- Vector<uint8_t> metricsVector;
- String8 vendor;
- String8 description;
- std::string metricsString;
- if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
- getPropertyStringInternal(String8("description"), description) == OK &&
- getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
- metricsString = toBase64StringNoPad(metricsVector.array(),
- metricsVector.size());
- status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
- description, mMetrics.GetAppUid());
- if (res != OK) {
- ALOGE("Metrics were retrieved but could not be reported: %d", res);
- }
- }
- return metricsString;
+status_t DrmHal::setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId) {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->setPlaybackId(sessionId, playbackId);
+ return mDrmHalHidl->setPlaybackId(sessionId, playbackId);
}
-status_t DrmHal::requiresSecureDecoder(const char *mime, bool *required) const {
- Mutex::Autolock autoLock(mLock);
- if (mPluginV1_4 == NULL) {
- return false;
- }
- auto hResult = mPluginV1_4->requiresSecureDecoderDefault(hidl_string(mime));
- if (!hResult.isOk()) {
- DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %s", hResult.description().c_str());
- return DEAD_OBJECT;
- }
- if (required) {
- *required = hResult;
- }
- return OK;
-}
-
-status_t DrmHal::requiresSecureDecoder(const char *mime, DrmPlugin::SecurityLevel securityLevel,
- bool *required) const {
- Mutex::Autolock autoLock(mLock);
- if (mPluginV1_4 == NULL) {
- return false;
- }
- auto hLevel = toHidlSecurityLevel(securityLevel);
- auto hResult = mPluginV1_4->requiresSecureDecoder(hidl_string(mime), hLevel);
- if (!hResult.isOk()) {
- DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %s", hResult.description().c_str());
- return DEAD_OBJECT;
- }
- if (required) {
- *required = hResult;
- }
- return OK;
-}
-
-status_t DrmHal::setPlaybackId(Vector<uint8_t> const &sessionId, const char *playbackId) {
- Mutex::Autolock autoLock(mLock);
- if (mPluginV1_4 == NULL) {
- return ERROR_UNSUPPORTED;
- }
- auto err = mPluginV1_4->setPlaybackId(toHidlVec(sessionId), hidl_string(playbackId));
- return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
-}
-
-status_t DrmHal::getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const {
- Mutex::Autolock autoLock(mLock);
- return DrmUtils::GetLogMessages<drm::V1_4::IDrmPlugin>(mPlugin, logs);
+status_t DrmHal::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ if (mDrmHalAidl->initCheck() == OK) return mDrmHalAidl->getLogMessages(logs);
+ return mDrmHalHidl->getLogMessages(logs);
}
} // namespace android
diff --git a/drm/libmediadrm/DrmHalAidl.cpp b/drm/libmediadrm/DrmHalAidl.cpp
new file mode 100644
index 0000000..7df57a3
--- /dev/null
+++ b/drm/libmediadrm/DrmHalAidl.cpp
@@ -0,0 +1,1326 @@
+/*
+ * Copyright (C) 2021 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 "DrmHalAidl"
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <media/PluginMetricsReporting.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <mediadrm/DrmHalAidl.h>
+#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/DrmUtils.h>
+
+using ::android::DrmUtils::toStatusTAidl;
+
+using ::aidl::android::hardware::drm::DrmMetricNamedValue;
+using ::aidl::android::hardware::drm::DrmMetricValue;
+using ::aidl::android::hardware::drm::HdcpLevel;
+using ::aidl::android::hardware::drm::HdcpLevels;
+using ::aidl::android::hardware::drm::KeyRequest;
+using ::aidl::android::hardware::drm::KeyRequestType;
+using ::aidl::android::hardware::drm::KeySetId;
+using ::aidl::android::hardware::drm::KeyStatus;
+using ::aidl::android::hardware::drm::KeyStatusType;
+using ::aidl::android::hardware::drm::KeyType;
+using ::aidl::android::hardware::drm::KeyValue;
+using ::aidl::android::hardware::drm::NumberOfSessions;
+using ::aidl::android::hardware::drm::OfflineLicenseState;
+using ::aidl::android::hardware::drm::OpaqueData;
+using ::aidl::android::hardware::drm::ProvideProvisionResponseResult;
+using ::aidl::android::hardware::drm::ProvisionRequest;
+using ::aidl::android::hardware::drm::SecureStop;
+using ::aidl::android::hardware::drm::SecureStopId;
+using ::aidl::android::hardware::drm::SecurityLevel;
+using ::aidl::android::hardware::drm::Status;
+using ::aidl::android::hardware::drm::Uuid;
+using DrmMetricGroupAidl = ::aidl::android::hardware::drm::DrmMetricGroup;
+using DrmMetricGroupHidl = ::android::hardware::drm::V1_1::DrmMetricGroup;
+using DrmMetricAidl = ::aidl::android::hardware::drm::DrmMetric;
+using DrmMetricHidl = ::android::hardware::drm::V1_1::DrmMetricGroup::Metric;
+using ValueHidl = ::android::hardware::drm::V1_1::DrmMetricGroup::Value;
+using AttributeHidl = ::android::hardware::drm::V1_1::DrmMetricGroup::Attribute;
+using IDrmPluginAidl = ::aidl::android::hardware::drm::IDrmPlugin;
+using EventTypeAidl = ::aidl::android::hardware::drm::EventType;
+using KeyStatusAidl = ::aidl::android::hardware::drm::KeyStatus;
+using ::android::hardware::hidl_vec;
+
+namespace {
+
+constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
+constexpr char kEqualsSign[] = "=";
+
+template <typename T>
+std::string toBase64StringNoPad(const T* data, size_t size) {
+ // Note that the base 64 conversion only works with arrays of single-byte
+ // values. If the source is empty or is not an array of single-byte values,
+ // return empty string.
+ if (size == 0 || sizeof(data[0]) != 1) {
+ return "";
+ }
+
+ android::AString outputString;
+ encodeBase64(data, size, &outputString);
+ // Remove trailing equals padding if it exists.
+ while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
+ outputString.erase(outputString.size() - 1, 1);
+ }
+
+ return std::string(outputString.c_str(), outputString.size());
+}
+
+} // anonymous namespace
+
+namespace android {
+
+#define INIT_CHECK() \
+ { \
+ if (mInitCheck != OK) return mInitCheck; \
+ }
+
+static Uuid toAidlUuid(const uint8_t* uuid) {
+ Uuid uuidAidl;
+ uuidAidl.uuid = std::vector<uint8_t>(uuid, uuid + 16);
+ return uuidAidl;
+}
+
+template <typename Byte = uint8_t>
+static std::vector<Byte> toStdVec(const Vector<uint8_t>& vector) {
+ auto v = reinterpret_cast<const Byte*>(vector.array());
+ std::vector<Byte> vec(v, v + vector.size());
+ return vec;
+}
+
+static const Vector<uint8_t> toVector(const std::vector<uint8_t>& vec) {
+ Vector<uint8_t> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return *const_cast<const Vector<uint8_t>*>(&vector);
+}
+
+static String8 toString8(const std::string& string) {
+ return String8(string.c_str());
+}
+
+static std::string toStdString(const String8& string8) {
+ return std::string(string8.string());
+}
+
+static std::vector<KeyValue> toKeyValueVector(const KeyedVector<String8, String8>& keyedVector) {
+ std::vector<KeyValue> stdKeyedVector;
+ for (size_t i = 0; i < keyedVector.size(); i++) {
+ KeyValue keyValue;
+ keyValue.key = toStdString(keyedVector.keyAt(i));
+ keyValue.value = toStdString(keyedVector.valueAt(i));
+ stdKeyedVector.push_back(keyValue);
+ }
+ return stdKeyedVector;
+}
+
+static KeyedVector<String8, String8> toKeyedVector(const std::vector<KeyValue>& keyValueVec) {
+ KeyedVector<String8, String8> keyedVector;
+ for (size_t i = 0; i < keyValueVec.size(); i++) {
+ keyedVector.add(toString8(keyValueVec[i].key), toString8(keyValueVec[i].value));
+ }
+ return keyedVector;
+}
+
+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;
+ case KeyRequestType::NONE:
+ return DrmPlugin::kKeyRequestType_None;
+ break;
+ case KeyRequestType::UPDATE:
+ return DrmPlugin::kKeyRequestType_Update;
+ break;
+ default:
+ return DrmPlugin::kKeyRequestType_Unknown;
+ break;
+ }
+}
+
+static List<Vector<uint8_t>> toSecureStops(const std::vector<SecureStop>& aSecureStops) {
+ List<Vector<uint8_t>> secureStops;
+ for (size_t i = 0; i < aSecureStops.size(); i++) {
+ secureStops.push_back(toVector(aSecureStops[i].opaqueData));
+ }
+ return secureStops;
+}
+
+static List<Vector<uint8_t>> toSecureStopIds(const std::vector<SecureStopId>& aSecureStopIds) {
+ List<Vector<uint8_t>> secureStopIds;
+ for (size_t i = 0; i < aSecureStopIds.size(); i++) {
+ secureStopIds.push_back(toVector(aSecureStopIds[i].secureStopId));
+ }
+ return secureStopIds;
+}
+
+static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel level) {
+ switch (level) {
+ case HdcpLevel::HDCP_NONE:
+ return DrmPlugin::kHdcpNone;
+ case HdcpLevel::HDCP_V1:
+ return DrmPlugin::kHdcpV1;
+ case HdcpLevel::HDCP_V2:
+ return DrmPlugin::kHdcpV2;
+ case HdcpLevel::HDCP_V2_1:
+ return DrmPlugin::kHdcpV2_1;
+ case HdcpLevel::HDCP_V2_2:
+ return DrmPlugin::kHdcpV2_2;
+ case HdcpLevel::HDCP_V2_3:
+ return DrmPlugin::kHdcpV2_3;
+ case HdcpLevel::HDCP_NO_OUTPUT:
+ return DrmPlugin::kHdcpNoOutput;
+ default:
+ return DrmPlugin::kHdcpLevelUnknown;
+ }
+}
+
+static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
+ switch (level) {
+ case SecurityLevel::SW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelSwSecureCrypto;
+ case SecurityLevel::SW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelSwSecureDecode;
+ case SecurityLevel::HW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelHwSecureCrypto;
+ case SecurityLevel::HW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelHwSecureDecode;
+ case SecurityLevel::HW_SECURE_ALL:
+ return DrmPlugin::kSecurityLevelHwSecureAll;
+ case SecurityLevel::DEFAULT:
+ return DrmPlugin::kSecurityLevelMax;
+ default:
+ return DrmPlugin::kSecurityLevelUnknown;
+ }
+}
+
+static SecurityLevel toAidlSecurityLevel(DrmPlugin::SecurityLevel level) {
+ switch (level) {
+ case DrmPlugin::kSecurityLevelSwSecureCrypto:
+ return SecurityLevel::SW_SECURE_CRYPTO;
+ case DrmPlugin::kSecurityLevelSwSecureDecode:
+ return SecurityLevel::SW_SECURE_DECODE;
+ case DrmPlugin::kSecurityLevelHwSecureCrypto:
+ return SecurityLevel::HW_SECURE_CRYPTO;
+ case DrmPlugin::kSecurityLevelHwSecureDecode:
+ return SecurityLevel::HW_SECURE_DECODE;
+ case DrmPlugin::kSecurityLevelHwSecureAll:
+ return SecurityLevel::HW_SECURE_ALL;
+ case DrmPlugin::kSecurityLevelMax:
+ return SecurityLevel::DEFAULT;
+ default:
+ return SecurityLevel::UNKNOWN;
+ }
+}
+
+static List<Vector<uint8_t>> toKeySetIds(const std::vector<KeySetId>& hKeySetIds) {
+ List<Vector<uint8_t>> keySetIds;
+ for (size_t i = 0; i < hKeySetIds.size(); i++) {
+ keySetIds.push_back(toVector(hKeySetIds[i].keySetId));
+ }
+ return keySetIds;
+}
+
+static DrmPlugin::OfflineLicenseState toOfflineLicenseState(OfflineLicenseState licenseState) {
+ switch (licenseState) {
+ case OfflineLicenseState::USABLE:
+ return DrmPlugin::kOfflineLicenseStateUsable;
+ case OfflineLicenseState::INACTIVE:
+ return DrmPlugin::kOfflineLicenseStateReleased;
+ default:
+ return DrmPlugin::kOfflineLicenseStateUnknown;
+ }
+}
+
+template <typename T = uint8_t>
+static hidl_vec<T> toHidlVec(const Vector<T>& vector) {
+ hidl_vec<T> vec;
+ vec.setToExternal(const_cast<T*>(vector.array()), vector.size());
+ return vec;
+}
+
+Mutex DrmHalAidl::mLock;
+
+static hidl_vec<DrmMetricGroupHidl> toDrmMetricGroupHidl(std::vector<DrmMetricGroupAidl> result) {
+ Vector<DrmMetricGroupHidl> resultHidl;
+ for (auto r : result) {
+ DrmMetricGroupHidl re;
+ Vector<DrmMetricHidl> tmpMetric;
+ for (auto m : r.metrics) {
+ DrmMetricHidl me;
+ me.name = m.name;
+ Vector<AttributeHidl> aTmp;
+ for (auto attr : m.attributes) {
+ AttributeHidl attrHidl;
+ attrHidl.name = attr.name;
+
+ switch (attr.value.getTag()) {
+ case DrmMetricValue::Tag::int64Value:
+ attrHidl.type = DrmMetricGroupHidl::ValueType::INT64_TYPE;
+ attrHidl.int64Value = attr.value.get<DrmMetricValue::Tag::int64Value>();
+ break;
+ case DrmMetricValue::Tag::doubleValue:
+ attrHidl.type = DrmMetricGroupHidl::ValueType::DOUBLE_TYPE;
+ attrHidl.doubleValue = attr.value.get<DrmMetricValue::Tag::doubleValue>();
+ break;
+ case DrmMetricValue::Tag::stringValue:
+ attrHidl.type = DrmMetricGroupHidl::ValueType::STRING_TYPE;
+ attrHidl.stringValue = attr.value.get<DrmMetricValue::Tag::stringValue>();
+ break;
+ default:
+ break;
+ }
+
+ aTmp.push_back(attrHidl);
+ }
+
+ me.attributes = toHidlVec<AttributeHidl>(aTmp);
+
+ Vector<ValueHidl> vTmp;
+ for (auto value : m.values) {
+ ValueHidl valueHidl;
+ valueHidl.componentName = value.name;
+ switch (value.value.getTag()) {
+ case DrmMetricValue::Tag::int64Value:
+ valueHidl.type = DrmMetricGroupHidl::ValueType::INT64_TYPE;
+ valueHidl.int64Value = value.value.get<DrmMetricValue::Tag::int64Value>();
+ break;
+ case DrmMetricValue::Tag::doubleValue:
+ valueHidl.type = DrmMetricGroupHidl::ValueType::DOUBLE_TYPE;
+ valueHidl.doubleValue = value.value.get<DrmMetricValue::Tag::doubleValue>();
+ break;
+ case DrmMetricValue::Tag::stringValue:
+ valueHidl.type = DrmMetricGroupHidl::ValueType::STRING_TYPE;
+ valueHidl.stringValue = value.value.get<DrmMetricValue::Tag::stringValue>();
+ break;
+ default:
+ break;
+ }
+
+ vTmp.push_back(valueHidl);
+ }
+
+ me.values = toHidlVec<ValueHidl>(vTmp);
+ tmpMetric.push_back(me);
+ }
+
+ re.metrics = toHidlVec<DrmMetricHidl>(tmpMetric);
+ resultHidl.push_back(re);
+ }
+
+ return toHidlVec<DrmMetricGroupHidl>(resultHidl);
+}
+
+// DrmSessionClient Definition
+
+struct DrmHalAidl::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
+ explicit DrmSessionClient(DrmHalAidl* drm, const Vector<uint8_t>& sessionId)
+ : mSessionId(sessionId), mDrm(drm) {}
+
+ ::ndk::ScopedAStatus reclaimResource(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus getName(::std::string* _aidl_return) override;
+
+ const Vector<uint8_t> mSessionId;
+
+ virtual ~DrmSessionClient();
+
+ private:
+ wp<DrmHalAidl> mDrm;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+};
+
+::ndk::ScopedAStatus DrmHalAidl::DrmSessionClient::reclaimResource(bool* _aidl_return) {
+ auto sessionId = mSessionId;
+ sp<DrmHalAidl> drm = mDrm.promote();
+ if (drm == NULL) {
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ status_t err = drm->closeSession(sessionId);
+ if (err != OK) {
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ drm->onEvent(EventTypeAidl::SESSION_RECLAIMED, toHidlVec(sessionId), hidl_vec<uint8_t>());
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHalAidl::DrmSessionClient::getName(::std::string* _aidl_return) {
+ String8 name;
+ sp<DrmHalAidl> drm = mDrm.promote();
+ if (drm == NULL) {
+ name.append("<deleted>");
+ } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK || name.isEmpty()) {
+ name.append("<Get vendor failed or is empty>");
+ }
+ name.append("[");
+ for (size_t i = 0; i < mSessionId.size(); ++i) {
+ name.appendFormat("%02x", mSessionId[i]);
+ }
+ name.append("]");
+ *_aidl_return = name;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+DrmHalAidl::DrmSessionClient::~DrmSessionClient() {
+ DrmSessionManager::Instance()->removeSession(mSessionId);
+}
+
+// DrmHalAidl methods
+DrmHalAidl::DrmHalAidl()
+ : mFactories(makeDrmFactories()),
+ mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {}
+
+status_t DrmHalAidl::initCheck() const {
+ return mInitCheck;
+}
+
+DrmHalAidl::~DrmHalAidl() {}
+
+std::vector<std::shared_ptr<IDrmFactoryAidl>> DrmHalAidl::makeDrmFactories() {
+ std::vector<std::shared_ptr<IDrmFactoryAidl>> factories;
+ AServiceManager_forEachDeclaredInstance(
+ IDrmFactoryAidl::descriptor, static_cast<void*>(&factories),
+ [](const char* instance, void* context) {
+ auto fullName = std::string(IDrmFactoryAidl::descriptor) + "/" + std::string(instance);
+ auto factory = IDrmFactoryAidl::fromBinder(
+ ::ndk::SpAIBinder(AServiceManager_getService(fullName.c_str())));
+ if (factory == nullptr) {
+ ALOGE("not found IDrmFactory. Instance name:[%s]", fullName.c_str());
+ return;
+ }
+
+ ALOGI("found IDrmFactory. Instance name:[%s]", fullName.c_str());
+ static_cast<std::vector<std::shared_ptr<IDrmFactoryAidl>>*>(context)->emplace_back(
+ factory);
+ });
+
+ return factories;
+}
+
+status_t DrmHalAidl::setListener(const sp<IDrmClient>& listener) {
+ Mutex::Autolock lock(mEventLock);
+ mListener = listener;
+ return NO_ERROR;
+}
+
+status_t DrmHalAidl::isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel level, bool* isSupported) {
+ Mutex::Autolock autoLock(mLock);
+ *isSupported = false;
+ Uuid uuidAidl = toAidlUuid(uuid);
+ SecurityLevel levelAidl = static_cast<SecurityLevel>((int32_t)level);
+ std::string mimeTypeStr = mimeType.string();
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ if (mFactories[i]
+ ->isCryptoSchemeSupported(uuidAidl, mimeTypeStr, levelAidl, isSupported)
+ .isOk()) {
+ if (*isSupported) break;
+ }
+ }
+
+ return OK;
+}
+
+status_t DrmHalAidl::createPlugin(const uint8_t uuid[16], const String8& appPackageName) {
+ Mutex::Autolock autoLock(mLock);
+
+ Uuid uuidAidl = toAidlUuid(uuid);
+ std::string appPackageNameAidl = toStdString(appPackageName);
+ std::shared_ptr<IDrmPluginAidl> pluginAidl;
+ mMetrics.SetAppPackageName(appPackageName);
+ mMetrics.SetAppUid(AIBinder_getCallingUid());
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ ::ndk::ScopedAStatus status =
+ mFactories[i]->createPlugin(uuidAidl, appPackageNameAidl, &pluginAidl);
+ if (status.isOk()) {
+ if (pluginAidl != NULL) {
+ mPlugin = pluginAidl;
+ break;
+ }
+ } else {
+ DrmUtils::LOG2BE(uuid, "Failed to make drm plugin: %d",
+ status.getServiceSpecificError());
+ }
+ }
+
+ if (mPlugin == NULL) {
+ DrmUtils::LOG2BE(uuid, "No supported hal instance found");
+ mInitCheck = ERROR_UNSUPPORTED;
+ } else {
+ mInitCheck = OK;
+
+ if (!mPlugin->setListener(shared_from_this()).isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+
+ if (mInitCheck != OK) {
+ mPlugin.reset();
+ }
+ }
+
+ return mInitCheck;
+}
+
+status_t DrmHalAidl::openSession(DrmPlugin::SecurityLevel level, Vector<uint8_t>& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ SecurityLevel aSecurityLevel = toAidlSecurityLevel(level);
+
+ if (aSecurityLevel == SecurityLevel::UNKNOWN) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+ bool retry = true;
+ do {
+ std::vector<uint8_t> aSessionId;
+
+ ::ndk::ScopedAStatus status = mPlugin->openSession(aSecurityLevel, &aSessionId);
+ if (status.isOk()) sessionId = toVector(aSessionId);
+ err = status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+
+ if (err == ERROR_DRM_RESOURCE_BUSY && retry) {
+ mLock.unlock();
+ // reclaimSession may call back to closeSession, since mLock is
+ // shared between Drm instances, we should unlock here to avoid
+ // deadlock.
+ retry = DrmSessionManager::Instance()->reclaimSession(AIBinder_getCallingPid());
+ mLock.lock();
+ } else {
+ retry = false;
+ }
+ } while (retry);
+
+ if (err == OK) {
+ std::shared_ptr<DrmSessionClient> client =
+ ndk::SharedRefBase::make<DrmSessionClient>(this, sessionId);
+ DrmSessionManager::Instance()->addSession(
+ AIBinder_getCallingPid(), std::static_pointer_cast<IResourceManagerClient>(client),
+ sessionId);
+ mOpenSessions.push_back(client);
+ mMetrics.SetSessionStart(sessionId);
+ }
+
+ mMetrics.mOpenSessionCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalAidl::closeSession(Vector<uint8_t> const& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::vector<uint8_t> sessionIdAidl = toStdVec(sessionId);
+ ::ndk::ScopedAStatus status = mPlugin->closeSession(sessionIdAidl);
+ if (status.isOk()) {
+ DrmSessionManager::Instance()->removeSession(sessionId);
+ for (auto i = mOpenSessions.begin(); i != mOpenSessions.end(); i++) {
+ if (isEqualSessionId((*i)->mSessionId, sessionId)) {
+ mOpenSessions.erase(i);
+ break;
+ }
+ }
+
+ status_t response = toStatusTAidl(status.getServiceSpecificError());
+ mMetrics.SetSessionEnd(sessionId);
+ mMetrics.mCloseSessionCounter.Increment(response);
+ return response;
+ }
+ mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT);
+ return DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getKeyRequest(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& initData, String8 const& mimeType,
+ DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ KeyType aKeyType;
+ if (keyType == DrmPlugin::kKeyType_Streaming) {
+ aKeyType = KeyType::STREAMING;
+ } else if (keyType == DrmPlugin::kKeyType_Offline) {
+ aKeyType = KeyType::OFFLINE;
+ } else if (keyType == DrmPlugin::kKeyType_Release) {
+ aKeyType = KeyType::RELEASE;
+ } else {
+ keyRequestTimer.SetAttribute(BAD_VALUE);
+ return BAD_VALUE;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+
+ std::vector<uint8_t> sessionIdAidl = toStdVec(sessionId);
+ std::vector<uint8_t> initDataAidl = toStdVec(initData);
+ KeyRequest keyRequest;
+
+ ::ndk::ScopedAStatus status =
+ mPlugin->getKeyRequest(sessionIdAidl, initDataAidl, toStdString(mimeType), aKeyType,
+ toKeyValueVector(optionalParameters), &keyRequest);
+ if (status.isOk()) {
+ request = toVector(keyRequest.request);
+ defaultUrl = toString8(keyRequest.defaultUrl);
+ *keyRequestType = toKeyRequestType(keyRequest.requestType);
+ }
+
+ err = status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+ keyRequestTimer.SetAttribute(err);
+ return err;
+}
+
+status_t DrmHalAidl::provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response,
+ Vector<uint8_t>& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ std::vector<uint8_t> sessionIdAidl = toStdVec(sessionId);
+ std::vector<uint8_t> responseAidl = toStdVec(response);
+ KeySetId keySetIdsAidl;
+ ::ndk::ScopedAStatus status =
+ mPlugin->provideKeyResponse(sessionIdAidl, responseAidl, &keySetIdsAidl);
+
+ if (status.isOk()) keySetId = toVector(keySetIdsAidl.keySetId);
+ err = status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+ keyResponseTimer.SetAttribute(err);
+ return err;
+}
+
+status_t DrmHalAidl::removeKeys(Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ ::ndk::ScopedAStatus status = mPlugin->removeKeys(toStdVec(keySetId));
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::restoreKeys(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ KeySetId keySetIdsAidl;
+ keySetIdsAidl.keySetId = toStdVec(keySetId);
+ ::ndk::ScopedAStatus status = mPlugin->restoreKeys(toStdVec(sessionId), keySetIdsAidl);
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<KeyValue> infoMapAidl;
+ ::ndk::ScopedAStatus status = mPlugin->queryKeyStatus(toStdVec(sessionId), &infoMapAidl);
+
+ infoMap = toKeyedVector(infoMapAidl);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ ProvisionRequest requestAidl;
+ ::ndk::ScopedAStatus status = mPlugin->getProvisionRequest(
+ toStdString(certType), toStdString(certAuthority), &requestAidl);
+
+ request = toVector(requestAidl.request);
+ defaultUrl = toString8(requestAidl.defaultUrl);
+
+ err = status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+ mMetrics.mGetProvisionRequestCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalAidl::provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+ ProvideProvisionResponseResult result;
+ ::ndk::ScopedAStatus status = mPlugin->provideProvisionResponse(toStdVec(response), &result);
+
+ certificate = toVector(result.certificate);
+ wrappedKey = toVector(result.wrappedKey);
+ err = status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+ mMetrics.mProvideProvisionResponseCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalAidl::getSecureStops(List<Vector<uint8_t>>& secureStops) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::vector<SecureStop> result;
+ ::ndk::ScopedAStatus status = mPlugin->getSecureStops(&result);
+
+ secureStops = toSecureStops(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getSecureStopIds(List<Vector<uint8_t>>& secureStopIds) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::vector<SecureStopId> result;
+ ::ndk::ScopedAStatus status = mPlugin->getSecureStopIds(&result);
+
+ secureStopIds = toSecureStopIds(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ SecureStopId ssidAidl;
+ ssidAidl.secureStopId = toStdVec(ssid);
+
+ SecureStop result;
+ ::ndk::ScopedAStatus status = mPlugin->getSecureStop(ssidAidl, &result);
+
+ secureStop = toVector(result.opaqueData);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::releaseSecureStops(Vector<uint8_t> const& ssRelease) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ OpaqueData ssId;
+ ssId.opaqueData = toStdVec(ssRelease);
+ ::ndk::ScopedAStatus status = mPlugin->releaseSecureStops(ssId);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::removeSecureStop(Vector<uint8_t> const& ssid) {
+ Mutex::Autolock autoLock(mLock);
+
+ INIT_CHECK();
+
+ SecureStopId ssidAidl;
+ ssidAidl.secureStopId = toStdVec(ssid);
+ ::ndk::ScopedAStatus status = mPlugin->removeSecureStop(ssidAidl);
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::removeAllSecureStops() {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ ::ndk::ScopedAStatus status = mPlugin->releaseAllSecureStops();
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getHdcpLevels(DrmPlugin::HdcpLevel* connected,
+ DrmPlugin::HdcpLevel* max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (connected == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+
+ *connected = DrmPlugin::kHdcpLevelUnknown;
+ *max = DrmPlugin::kHdcpLevelUnknown;
+
+ HdcpLevels lvlsAidl;
+ ::ndk::ScopedAStatus status = mPlugin->getHdcpLevels(&lvlsAidl);
+
+ *connected = toHdcpLevel(lvlsAidl.connectedLevel);
+ *max = toHdcpLevel(lvlsAidl.maxLevel);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getNumberOfSessions(uint32_t* open, uint32_t* max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (open == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+
+ *open = 0;
+ *max = 0;
+
+ NumberOfSessions result;
+ ::ndk::ScopedAStatus status = mPlugin->getNumberOfSessions(&result);
+
+ *open = result.currentSessions;
+ *max = result.maxSessions;
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (level == NULL) {
+ return BAD_VALUE;
+ }
+
+ *level = DrmPlugin::kSecurityLevelUnknown;
+
+ SecurityLevel result;
+ ::ndk::ScopedAStatus status = mPlugin->getSecurityLevel(toStdVec(sessionId), &result);
+
+ *level = toSecurityLevel(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::vector<KeySetId> result;
+ ::ndk::ScopedAStatus status = mPlugin->getOfflineLicenseKeySetIds(&result);
+
+ keySetIds = toKeySetIds(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::removeOfflineLicense(Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ KeySetId keySetIdAidl;
+ keySetIdAidl.keySetId = toStdVec(keySetId);
+ ::ndk::ScopedAStatus status = mPlugin->removeOfflineLicense(keySetIdAidl);
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const {
+ Mutex::Autolock autoLock(mLock);
+
+ INIT_CHECK();
+ *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
+
+ KeySetId keySetIdAidl;
+ keySetIdAidl.keySetId = toStdVec(keySetId);
+
+ OfflineLicenseState result;
+ ::ndk::ScopedAStatus status = mPlugin->getOfflineLicenseState(keySetIdAidl, &result);
+
+ *licenseState = toOfflineLicenseState(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getPropertyString(String8 const& name, String8& value) const {
+ Mutex::Autolock autoLock(mLock);
+ return getPropertyStringInternal(name, value);
+}
+
+status_t DrmHalAidl::getPropertyStringInternal(String8 const& name, String8& value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
+ INIT_CHECK();
+
+ std::string result;
+ ::ndk::ScopedAStatus status = mPlugin->getPropertyString(toStdString(name), &result);
+
+ value = toString8(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const {
+ Mutex::Autolock autoLock(mLock);
+ return getPropertyByteArrayInternal(name, value);
+}
+
+status_t DrmHalAidl::getPropertyByteArrayInternal(String8 const& name,
+ Vector<uint8_t>& value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status = mPlugin->getPropertyByteArray(toStdString(name), &result);
+
+ value = toVector(result);
+ err = status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+ if (name == kPropertyDeviceUniqueId) {
+ mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
+ }
+ return err;
+}
+
+status_t DrmHalAidl::setPropertyString(String8 const& name, String8 const& value) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ ::ndk::ScopedAStatus status = mPlugin->setPropertyString(toStdString(name), toStdString(value));
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::setPropertyByteArray(String8 const& name, Vector<uint8_t> const& value) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ ::ndk::ScopedAStatus status = mPlugin->setPropertyByteArray(toStdString(name), toStdVec(value));
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getMetrics(const sp<IDrmMetricsConsumer>& consumer) {
+ if (consumer == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ consumer->consumeFrameworkMetrics(mMetrics);
+
+ // Append vendor metrics if they are supported.
+
+ String8 vendor;
+ String8 description;
+ if (getPropertyStringInternal(String8("vendor"), vendor) != OK || vendor.isEmpty()) {
+ ALOGE("Get vendor failed or is empty");
+ vendor = "NONE";
+ }
+ if (getPropertyStringInternal(String8("description"), description) != OK ||
+ description.isEmpty()) {
+ ALOGE("Get description failed or is empty.");
+ description = "NONE";
+ }
+ vendor += ".";
+ vendor += description;
+
+ hidl_vec<DrmMetricGroupHidl> pluginMetrics;
+ status_t err = UNKNOWN_ERROR;
+
+ std::vector<DrmMetricGroupAidl> result;
+ ::ndk::ScopedAStatus status = mPlugin->getMetrics(&result);
+
+ if (status.isOk()) {
+ pluginMetrics = toDrmMetricGroupHidl(result);
+ consumer->consumeHidlMetrics(vendor, pluginMetrics);
+ }
+
+ err = status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+
+ return err;
+}
+
+status_t DrmHalAidl::setCipherAlgorithm(Vector<uint8_t> const& sessionId,
+ String8 const& algorithm) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ ::ndk::ScopedAStatus status =
+ mPlugin->setCipherAlgorithm(toStdVec(sessionId), toStdString(algorithm));
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ ::ndk::ScopedAStatus status =
+ mPlugin->setMacAlgorithm(toStdVec(sessionId), toStdString(algorithm));
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status = mPlugin->encrypt(toStdVec(sessionId), toStdVec(keyId),
+ toStdVec(input), toStdVec(iv), &result);
+
+ output = toVector(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status = mPlugin->decrypt(toStdVec(sessionId), toStdVec(keyId),
+ toStdVec(input), toStdVec(iv), &result);
+
+ output = toVector(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status =
+ mPlugin->sign(toStdVec(sessionId), toStdVec(keyId), toStdVec(message), &result);
+
+ signature = toVector(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ ::ndk::ScopedAStatus status = mPlugin->verify(toStdVec(sessionId), toStdVec(keyId),
+ toStdVec(message), toStdVec(signature), &match);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ std::vector<uint8_t> result;
+ ::ndk::ScopedAStatus status =
+ mPlugin->signRSA(toStdVec(sessionId), toStdString(algorithm), toStdVec(message),
+ toStdVec(wrappedKey), &result);
+
+ signature = toVector(result);
+
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::requiresSecureDecoder(const char* mime, bool* required) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ std::string mimeAidl(mime);
+ ::ndk::ScopedAStatus status = mPlugin->requiresSecureDecoderDefault(mimeAidl, required);
+ if (!status.isOk()) {
+ DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %d", status.getServiceSpecificError());
+ return DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+status_t DrmHalAidl::requiresSecureDecoder(const char* mime, DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ auto aLevel = toAidlSecurityLevel(securityLevel);
+ std::string mimeAidl(mime);
+ ::ndk::ScopedAStatus status = mPlugin->requiresSecureDecoder(mimeAidl, aLevel, required);
+ if (!status.isOk()) {
+ DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %d", status.getServiceSpecificError());
+ return DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+status_t DrmHalAidl::setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ std::string playbackIdAidl(playbackId);
+ ::ndk::ScopedAStatus status = mPlugin->setPlaybackId(toStdVec(sessionId), playbackIdAidl);
+ return status.isOk() ? toStatusTAidl(status.getServiceSpecificError()) : DEAD_OBJECT;
+}
+
+status_t DrmHalAidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ Mutex::Autolock autoLock(mLock);
+ return DrmUtils::GetLogMessagesAidl<IDrmPluginAidl>(mPlugin, logs);
+}
+
+void DrmHalAidl::closeOpenSessions() {
+ Mutex::Autolock autoLock(mLock);
+ auto openSessions = mOpenSessions;
+ for (size_t i = 0; i < openSessions.size(); i++) {
+ mLock.unlock();
+ closeSession(openSessions[i]->mSessionId);
+ mLock.lock();
+ }
+ mOpenSessions.clear();
+}
+
+std::string DrmHalAidl::reportPluginMetrics() const {
+ Vector<uint8_t> metricsVector;
+ String8 vendor;
+ String8 description;
+ std::string metricsString;
+ if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
+ getPropertyStringInternal(String8("description"), description) == OK &&
+ getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
+ metricsString = toBase64StringNoPad(metricsVector.array(), metricsVector.size());
+ status_t res = android::reportDrmPluginMetrics(metricsString, vendor, description,
+ mMetrics.GetAppUid());
+ if (res != OK) {
+ ALOGE("Metrics were retrieved but could not be reported: %d", res);
+ }
+ }
+ return metricsString;
+}
+
+std::string DrmHalAidl::reportFrameworkMetrics(const std::string& pluginMetrics) const {
+ mediametrics_handle_t item(mediametrics_create("mediadrm"));
+ mediametrics_setUid(item, mMetrics.GetAppUid());
+ String8 vendor;
+ String8 description;
+ status_t result = getPropertyStringInternal(String8("vendor"), vendor);
+ if (result != OK) {
+ ALOGE("Failed to get vendor from drm plugin: %d", result);
+ } else {
+ mediametrics_setCString(item, "vendor", vendor.c_str());
+ }
+ result = getPropertyStringInternal(String8("description"), description);
+ if (result != OK) {
+ ALOGE("Failed to get description from drm plugin: %d", result);
+ } else {
+ mediametrics_setCString(item, "description", description.c_str());
+ }
+
+ std::string serializedMetrics;
+ result = mMetrics.GetSerializedMetrics(&serializedMetrics);
+ if (result != OK) {
+ ALOGE("Failed to serialize framework metrics: %d", result);
+ }
+ std::string b64EncodedMetrics =
+ toBase64StringNoPad(serializedMetrics.data(), serializedMetrics.size());
+ if (!b64EncodedMetrics.empty()) {
+ mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
+ }
+ if (!pluginMetrics.empty()) {
+ mediametrics_setCString(item, "plugin_metrics", pluginMetrics.c_str());
+ }
+ if (!mediametrics_selfRecord(item)) {
+ ALOGE("Failed to self record framework metrics");
+ }
+ mediametrics_delete(item);
+ return serializedMetrics;
+}
+
+void DrmHalAidl::cleanup() {
+ closeOpenSessions();
+
+ Mutex::Autolock autoLock(mLock);
+ reportFrameworkMetrics(reportPluginMetrics());
+
+ setListener(NULL);
+ mInitCheck = NO_INIT;
+ if (mPlugin != NULL) {
+ if (!mPlugin->setListener(NULL).isOk()) {
+ mInitCheck = DEAD_OBJECT;
+ }
+ }
+
+ mPlugin.reset();
+}
+
+status_t DrmHalAidl::destroyPlugin() {
+ cleanup();
+ return OK;
+}
+
+::ndk::ScopedAStatus DrmHalAidl::onEvent(EventTypeAidl eventTypeAidl,
+ const std::vector<uint8_t>& sessionId,
+ const std::vector<uint8_t>& data) {
+ ::ndk::ScopedAStatus _aidl_status;
+ mMetrics.mEventCounter.Increment((uint32_t)eventTypeAidl);
+
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ DrmPlugin::EventType eventType;
+ switch (eventTypeAidl) {
+ case EventTypeAidl::PROVISION_REQUIRED:
+ eventType = DrmPlugin::kDrmPluginEventProvisionRequired;
+ break;
+ case EventTypeAidl::KEY_NEEDED:
+ eventType = DrmPlugin::kDrmPluginEventKeyNeeded;
+ break;
+ case EventTypeAidl::KEY_EXPIRED:
+ eventType = DrmPlugin::kDrmPluginEventKeyExpired;
+ break;
+ case EventTypeAidl::VENDOR_DEFINED:
+ eventType = DrmPlugin::kDrmPluginEventVendorDefined;
+ break;
+ case EventTypeAidl::SESSION_RECLAIMED:
+ eventType = DrmPlugin::kDrmPluginEventSessionReclaimed;
+ break;
+ default:
+ return _aidl_status;
+ }
+
+ listener->sendEvent(eventType, toHidlVec(toVector(sessionId)), toHidlVec(toVector(data)));
+ }
+
+ return _aidl_status;
+}
+
+::ndk::ScopedAStatus DrmHalAidl::onExpirationUpdate(const std::vector<uint8_t>& sessionId,
+ int64_t expiryTimeInMS) {
+ ::ndk::ScopedAStatus _aidl_status;
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendExpirationUpdate(toHidlVec(toVector(sessionId)), expiryTimeInMS);
+ }
+
+ return _aidl_status;
+}
+
+::ndk::ScopedAStatus DrmHalAidl::onKeysChange(const std::vector<uint8_t>& sessionId,
+ const std::vector<KeyStatus>& keyStatusListAidl,
+ bool hasNewUsableKey) {
+ ::ndk::ScopedAStatus _aidl_status;
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ std::vector<DrmKeyStatus> keyStatusList;
+ size_t nKeys = keyStatusListAidl.size();
+ for (size_t i = 0; i < nKeys; ++i) {
+ const KeyStatus& keyStatus = keyStatusListAidl[i];
+ uint32_t type;
+ switch (keyStatus.type) {
+ case KeyStatusType::USABLE:
+ type = DrmPlugin::kKeyStatusType_Usable;
+ break;
+ case KeyStatusType::EXPIRED:
+ type = DrmPlugin::kKeyStatusType_Expired;
+ break;
+ case KeyStatusType::OUTPUTNOTALLOWED:
+ type = DrmPlugin::kKeyStatusType_OutputNotAllowed;
+ break;
+ case KeyStatusType::STATUSPENDING:
+ type = DrmPlugin::kKeyStatusType_StatusPending;
+ break;
+ case KeyStatusType::USABLEINFUTURE:
+ type = DrmPlugin::kKeyStatusType_UsableInFuture;
+ break;
+ case KeyStatusType::INTERNALERROR:
+ default:
+ type = DrmPlugin::kKeyStatusType_InternalError;
+ break;
+ }
+ keyStatusList.push_back({type, toHidlVec(toVector(keyStatus.keyId))});
+ mMetrics.mKeyStatusChangeCounter.Increment((uint32_t)keyStatus.type);
+ }
+
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendKeysChange(toHidlVec(toVector(sessionId)), keyStatusList, hasNewUsableKey);
+ }
+ else {
+ // There's no listener. But we still want to count the key change
+ // events.
+ size_t nKeys = keyStatusListAidl.size();
+
+ for (size_t i = 0; i < nKeys; i++) {
+ mMetrics.mKeyStatusChangeCounter.Increment((uint32_t)keyStatusListAidl[i].type);
+ }
+ }
+
+ return _aidl_status;
+}
+
+::ndk::ScopedAStatus DrmHalAidl::onSessionLostState(const std::vector<uint8_t>& sessionId) {
+ ::ndk::ScopedAStatus _aidl_status;
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendSessionLostState(toHidlVec(toVector(sessionId)));
+ }
+
+ return _aidl_status;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/drm/libmediadrm/DrmHalHidl.cpp b/drm/libmediadrm/DrmHalHidl.cpp
new file mode 100644
index 0000000..a5dd4d7
--- /dev/null
+++ b/drm/libmediadrm/DrmHalHidl.cpp
@@ -0,0 +1,1516 @@
+/*
+ * Copyright (C) 2021 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 "DrmHalHidl"
+
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <android/binder_manager.h>
+#include <android/hardware/drm/1.2/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+#include <media/EventMetric.h>
+#include <media/MediaMetrics.h>
+#include <media/PluginMetricsReporting.h>
+#include <media/drm/DrmAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <mediadrm/DrmHalHidl.h>
+#include <mediadrm/DrmSessionClientInterface.h>
+#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/DrmUtils.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <utils/Log.h>
+
+#include <iomanip>
+#include <vector>
+
+using ::android::sp;
+using ::android::DrmUtils::toStatusT;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::os::PersistableBundle;
+using drm::V1_0::KeyedVector;
+using drm::V1_0::KeyRequestType;
+using drm::V1_0::KeyType;
+using drm::V1_0::KeyValue;
+using drm::V1_0::SecureStop;
+using drm::V1_0::SecureStopId;
+using drm::V1_0::Status;
+using drm::V1_1::HdcpLevel;
+using drm::V1_1::SecureStopRelease;
+using drm::V1_1::SecurityLevel;
+using drm::V1_2::KeySetId;
+using drm::V1_2::KeyStatusType;
+
+typedef drm::V1_1::KeyRequestType KeyRequestType_V1_1;
+typedef drm::V1_2::Status Status_V1_2;
+typedef drm::V1_2::HdcpLevel HdcpLevel_V1_2;
+
+namespace {
+
+// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
+// in the MediaDrm API.
+constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
+constexpr char kEqualsSign[] = "=";
+
+template <typename T>
+std::string toBase64StringNoPad(const T* data, size_t size) {
+ // Note that the base 64 conversion only works with arrays of single-byte
+ // values. If the source is empty or is not an array of single-byte values,
+ // return empty string.
+ if (size == 0 || sizeof(data[0]) != 1) {
+ return "";
+ }
+
+ android::AString outputString;
+ encodeBase64(data, size, &outputString);
+ // Remove trailing equals padding if it exists.
+ while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
+ outputString.erase(outputString.size() - 1, 1);
+ }
+
+ return std::string(outputString.c_str(), outputString.size());
+}
+
+} // anonymous namespace
+
+namespace android {
+
+#define INIT_CHECK() \
+ { \
+ if (mInitCheck != OK) return mInitCheck; \
+ }
+
+static const Vector<uint8_t> toVector(const hidl_vec<uint8_t>& vec) {
+ Vector<uint8_t> vector;
+ vector.appendArray(vec.data(), vec.size());
+ return *const_cast<const Vector<uint8_t>*>(&vector);
+}
+
+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 String8 toString8(const hidl_string& string) {
+ return String8(string.c_str());
+}
+
+static hidl_string toHidlString(const String8& string) {
+ return hidl_string(string.string());
+}
+
+static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
+ switch (level) {
+ case SecurityLevel::SW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelSwSecureCrypto;
+ case SecurityLevel::SW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelSwSecureDecode;
+ case SecurityLevel::HW_SECURE_CRYPTO:
+ return DrmPlugin::kSecurityLevelHwSecureCrypto;
+ case SecurityLevel::HW_SECURE_DECODE:
+ return DrmPlugin::kSecurityLevelHwSecureDecode;
+ case SecurityLevel::HW_SECURE_ALL:
+ return DrmPlugin::kSecurityLevelHwSecureAll;
+ default:
+ return DrmPlugin::kSecurityLevelUnknown;
+ }
+}
+
+static SecurityLevel toHidlSecurityLevel(DrmPlugin::SecurityLevel level) {
+ switch (level) {
+ case DrmPlugin::kSecurityLevelSwSecureCrypto:
+ return SecurityLevel::SW_SECURE_CRYPTO;
+ case DrmPlugin::kSecurityLevelSwSecureDecode:
+ return SecurityLevel::SW_SECURE_DECODE;
+ case DrmPlugin::kSecurityLevelHwSecureCrypto:
+ return SecurityLevel::HW_SECURE_CRYPTO;
+ case DrmPlugin::kSecurityLevelHwSecureDecode:
+ return SecurityLevel::HW_SECURE_DECODE;
+ case DrmPlugin::kSecurityLevelHwSecureAll:
+ return SecurityLevel::HW_SECURE_ALL;
+ default:
+ return SecurityLevel::UNKNOWN;
+ }
+}
+
+static DrmPlugin::OfflineLicenseState toOfflineLicenseState(OfflineLicenseState licenseState) {
+ switch (licenseState) {
+ case OfflineLicenseState::USABLE:
+ return DrmPlugin::kOfflineLicenseStateUsable;
+ case OfflineLicenseState::INACTIVE:
+ return DrmPlugin::kOfflineLicenseStateReleased;
+ default:
+ return DrmPlugin::kOfflineLicenseStateUnknown;
+ }
+}
+
+static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel_V1_2 level) {
+ switch (level) {
+ case HdcpLevel_V1_2::HDCP_NONE:
+ return DrmPlugin::kHdcpNone;
+ case HdcpLevel_V1_2::HDCP_V1:
+ return DrmPlugin::kHdcpV1;
+ case HdcpLevel_V1_2::HDCP_V2:
+ return DrmPlugin::kHdcpV2;
+ case HdcpLevel_V1_2::HDCP_V2_1:
+ return DrmPlugin::kHdcpV2_1;
+ case HdcpLevel_V1_2::HDCP_V2_2:
+ return DrmPlugin::kHdcpV2_2;
+ case HdcpLevel_V1_2::HDCP_V2_3:
+ return DrmPlugin::kHdcpV2_3;
+ case HdcpLevel_V1_2::HDCP_NO_OUTPUT:
+ return DrmPlugin::kHdcpNoOutput;
+ default:
+ return DrmPlugin::kHdcpLevelUnknown;
+ }
+}
+static ::KeyedVector toHidlKeyedVector(const KeyedVector<String8, String8>& keyedVector) {
+ std::vector<KeyValue> stdKeyedVector;
+ for (size_t i = 0; i < keyedVector.size(); i++) {
+ KeyValue keyValue;
+ keyValue.key = toHidlString(keyedVector.keyAt(i));
+ keyValue.value = toHidlString(keyedVector.valueAt(i));
+ stdKeyedVector.push_back(keyValue);
+ }
+ return ::KeyedVector(stdKeyedVector);
+}
+
+static KeyedVector<String8, String8> toKeyedVector(const ::KeyedVector& hKeyedVector) {
+ KeyedVector<String8, String8> keyedVector;
+ for (size_t i = 0; i < hKeyedVector.size(); i++) {
+ keyedVector.add(toString8(hKeyedVector[i].key), toString8(hKeyedVector[i].value));
+ }
+ return keyedVector;
+}
+
+static List<Vector<uint8_t>> toSecureStops(const hidl_vec<SecureStop>& hSecureStops) {
+ List<Vector<uint8_t>> secureStops;
+ for (size_t i = 0; i < hSecureStops.size(); i++) {
+ secureStops.push_back(toVector(hSecureStops[i].opaqueData));
+ }
+ return secureStops;
+}
+
+static List<Vector<uint8_t>> toSecureStopIds(const hidl_vec<SecureStopId>& hSecureStopIds) {
+ List<Vector<uint8_t>> secureStopIds;
+ for (size_t i = 0; i < hSecureStopIds.size(); i++) {
+ secureStopIds.push_back(toVector(hSecureStopIds[i]));
+ }
+ return secureStopIds;
+}
+
+static List<Vector<uint8_t>> toKeySetIds(const hidl_vec<KeySetId>& hKeySetIds) {
+ List<Vector<uint8_t>> keySetIds;
+ for (size_t i = 0; i < hKeySetIds.size(); i++) {
+ keySetIds.push_back(toVector(hKeySetIds[i]));
+ }
+ return keySetIds;
+}
+
+Mutex DrmHalHidl::mLock;
+
+struct DrmHalHidl::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
+ explicit DrmSessionClient(DrmHalHidl* drm, const Vector<uint8_t>& sessionId)
+ : mSessionId(sessionId), mDrm(drm) {}
+
+ ::ndk::ScopedAStatus reclaimResource(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus getName(::std::string* _aidl_return) override;
+
+ const Vector<uint8_t> mSessionId;
+
+ virtual ~DrmSessionClient();
+
+ private:
+ wp<DrmHalHidl> mDrm;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+};
+
+::ndk::ScopedAStatus DrmHalHidl::DrmSessionClient::reclaimResource(bool* _aidl_return) {
+ auto sessionId = mSessionId;
+ sp<DrmHalHidl> drm = mDrm.promote();
+ if (drm == NULL) {
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ status_t err = drm->closeSession(sessionId);
+ if (err != OK) {
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+ }
+ drm->sendEvent(EventType::SESSION_RECLAIMED, toHidlVec(sessionId), hidl_vec<uint8_t>());
+ *_aidl_return = true;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHalHidl::DrmSessionClient::getName(::std::string* _aidl_return) {
+ String8 name;
+ sp<DrmHalHidl> drm = mDrm.promote();
+ if (drm == NULL) {
+ name.append("<deleted>");
+ } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK || name.isEmpty()) {
+ name.append("<Get vendor failed or is empty>");
+ }
+ name.append("[");
+ for (size_t i = 0; i < mSessionId.size(); ++i) {
+ name.appendFormat("%02x", mSessionId[i]);
+ }
+ name.append("]");
+ *_aidl_return = name;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+DrmHalHidl::DrmSessionClient::~DrmSessionClient() {
+ DrmSessionManager::Instance()->removeSession(mSessionId);
+}
+
+DrmHalHidl::DrmHalHidl()
+ : mFactories(makeDrmFactories()),
+ mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {}
+
+void DrmHalHidl::closeOpenSessions() {
+ Mutex::Autolock autoLock(mLock);
+ auto openSessions = mOpenSessions;
+ for (size_t i = 0; i < openSessions.size(); i++) {
+ mLock.unlock();
+ closeSession(openSessions[i]->mSessionId);
+ mLock.lock();
+ }
+ mOpenSessions.clear();
+}
+
+DrmHalHidl::~DrmHalHidl() {}
+
+void DrmHalHidl::cleanup() {
+ closeOpenSessions();
+
+ Mutex::Autolock autoLock(mLock);
+ reportFrameworkMetrics(reportPluginMetrics());
+
+ setListener(NULL);
+ mInitCheck = NO_INIT;
+ 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;
+ }
+ }
+ mPlugin.clear();
+ mPluginV1_1.clear();
+ mPluginV1_2.clear();
+ mPluginV1_4.clear();
+}
+
+std::vector<sp<IDrmFactory>> DrmHalHidl::makeDrmFactories() {
+ static std::vector<sp<IDrmFactory>> factories(DrmUtils::MakeDrmFactories());
+ if (factories.size() == 0) {
+ // must be in passthrough mode, load the default passthrough service
+ auto passthrough = IDrmFactory::getService();
+ if (passthrough != NULL) {
+ DrmUtils::LOG2BI("makeDrmFactories: using default passthrough drm instance");
+ factories.push_back(passthrough);
+ } else {
+ DrmUtils::LOG2BE("Failed to find any drm factories");
+ }
+ }
+ return factories;
+}
+
+sp<IDrmPlugin> DrmHalHidl::makeDrmPlugin(const sp<IDrmFactory>& factory, const uint8_t uuid[16],
+ const String8& appPackageName) {
+ mAppPackageName = appPackageName;
+ mMetrics.SetAppPackageName(appPackageName);
+ mMetrics.SetAppUid(AIBinder_getCallingUid());
+
+ sp<IDrmPlugin> plugin;
+ Return<void> hResult = factory->createPlugin(
+ uuid, appPackageName.string(), [&](Status status, const sp<IDrmPlugin>& hPlugin) {
+ if (status != Status::OK) {
+ DrmUtils::LOG2BE(uuid, "Failed to make drm plugin: %d", status);
+ return;
+ }
+ plugin = hPlugin;
+ });
+
+ if (!hResult.isOk()) {
+ DrmUtils::LOG2BE(uuid, "createPlugin remote call failed: %s",
+ hResult.description().c_str());
+ }
+
+ return plugin;
+}
+
+status_t DrmHalHidl::initCheck() const {
+ return mInitCheck;
+}
+
+status_t DrmHalHidl::setListener(const sp<IDrmClient>& listener) {
+ Mutex::Autolock lock(mEventLock);
+ mListener = listener;
+ return NO_ERROR;
+}
+
+Return<void> DrmHalHidl::sendEvent(EventType hEventType, const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<uint8_t>& data) {
+ mMetrics.mEventCounter.Increment((uint32_t)hEventType);
+
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ DrmPlugin::EventType eventType;
+ switch (hEventType) {
+ case EventType::PROVISION_REQUIRED:
+ eventType = DrmPlugin::kDrmPluginEventProvisionRequired;
+ break;
+ case EventType::KEY_NEEDED:
+ eventType = DrmPlugin::kDrmPluginEventKeyNeeded;
+ break;
+ case EventType::KEY_EXPIRED:
+ eventType = DrmPlugin::kDrmPluginEventKeyExpired;
+ break;
+ case EventType::VENDOR_DEFINED:
+ eventType = DrmPlugin::kDrmPluginEventVendorDefined;
+ break;
+ case EventType::SESSION_RECLAIMED:
+ eventType = DrmPlugin::kDrmPluginEventSessionReclaimed;
+ break;
+ default:
+ return Void();
+ }
+ listener->sendEvent(eventType, sessionId, data);
+ }
+ return Void();
+}
+
+Return<void> DrmHalHidl::sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
+ int64_t expiryTimeInMS) {
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
+ }
+ return Void();
+}
+
+Return<void> DrmHalHidl::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus_V1_0>& keyStatusList_V1_0,
+ bool hasNewUsableKey) {
+ std::vector<KeyStatus> keyStatusVec;
+ for (const auto& keyStatus_V1_0 : keyStatusList_V1_0) {
+ keyStatusVec.push_back(
+ {keyStatus_V1_0.keyId, static_cast<KeyStatusType>(keyStatus_V1_0.type)});
+ }
+ hidl_vec<KeyStatus> keyStatusList_V1_2(keyStatusVec);
+ return sendKeysChange_1_2(sessionId, keyStatusList_V1_2, hasNewUsableKey);
+}
+
+Return<void> DrmHalHidl::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& hKeyStatusList,
+ bool hasNewUsableKey) {
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ std::vector<DrmKeyStatus> keyStatusList;
+ size_t nKeys = hKeyStatusList.size();
+ for (size_t i = 0; i < nKeys; ++i) {
+ const KeyStatus& keyStatus = hKeyStatusList[i];
+ uint32_t type;
+ switch (keyStatus.type) {
+ case KeyStatusType::USABLE:
+ type = DrmPlugin::kKeyStatusType_Usable;
+ break;
+ case KeyStatusType::EXPIRED:
+ type = DrmPlugin::kKeyStatusType_Expired;
+ break;
+ case KeyStatusType::OUTPUTNOTALLOWED:
+ type = DrmPlugin::kKeyStatusType_OutputNotAllowed;
+ break;
+ case KeyStatusType::STATUSPENDING:
+ type = DrmPlugin::kKeyStatusType_StatusPending;
+ break;
+ case KeyStatusType::USABLEINFUTURE:
+ type = DrmPlugin::kKeyStatusType_UsableInFuture;
+ break;
+ case KeyStatusType::INTERNALERROR:
+ default:
+ type = DrmPlugin::kKeyStatusType_InternalError;
+ break;
+ }
+ keyStatusList.push_back({type, keyStatus.keyId});
+ mMetrics.mKeyStatusChangeCounter.Increment((uint32_t)keyStatus.type);
+ }
+
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+ } else {
+ // There's no listener. But we still want to count the key change
+ // events.
+ size_t nKeys = hKeyStatusList.size();
+ for (size_t i = 0; i < nKeys; i++) {
+ mMetrics.mKeyStatusChangeCounter.Increment((uint32_t)hKeyStatusList[i].type);
+ }
+ }
+
+ return Void();
+}
+
+Return<void> DrmHalHidl::sendSessionLostState(const hidl_vec<uint8_t>& sessionId) {
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->sendSessionLostState(sessionId);
+ }
+ return Void();
+}
+
+status_t DrmHalHidl::matchMimeTypeAndSecurityLevel(const sp<IDrmFactory>& factory,
+ const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool* isSupported) {
+ *isSupported = false;
+
+ // handle default value cases
+ if (level == DrmPlugin::kSecurityLevelUnknown) {
+ if (mimeType == "") {
+ // isCryptoSchemeSupported(uuid)
+ *isSupported = true;
+ } else {
+ // isCryptoSchemeSupported(uuid, mimeType)
+ *isSupported = factory->isContentTypeSupported(mimeType.string());
+ }
+ return OK;
+ } else if (mimeType == "") {
+ return BAD_VALUE;
+ }
+
+ sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
+ if (factoryV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
+ } else {
+ *isSupported = factoryV1_2->isCryptoSchemeSupported_1_2(uuid, mimeType.string(),
+ toHidlSecurityLevel(level));
+ return OK;
+ }
+}
+
+status_t DrmHalHidl::isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel level, bool* isSupported) {
+ Mutex::Autolock autoLock(mLock);
+ *isSupported = false;
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+ return matchMimeTypeAndSecurityLevel(mFactories[i], uuid, mimeType, level, isSupported);
+ }
+ }
+ return OK;
+}
+
+status_t DrmHalHidl::createPlugin(const uint8_t uuid[16], const String8& appPackageName) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ auto hResult = mFactories[i]->isCryptoSchemeSupported(uuid);
+ if (hResult.isOk() && hResult) {
+ auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
+ if (plugin != NULL) {
+ mPlugin = plugin;
+ mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
+ mPluginV1_2 = drm::V1_2::IDrmPlugin::castFrom(mPlugin);
+ mPluginV1_4 = drm::V1_4::IDrmPlugin::castFrom(mPlugin);
+ break;
+ }
+ }
+ }
+
+ if (mPlugin == NULL) {
+ DrmUtils::LOG2BE(uuid, "No supported hal instance found");
+ mInitCheck = ERROR_UNSUPPORTED;
+ } 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();
+ mPluginV1_4.clear();
+ }
+ }
+
+ return mInitCheck;
+}
+
+status_t DrmHalHidl::destroyPlugin() {
+ cleanup();
+ return OK;
+}
+
+status_t DrmHalHidl::openSession(DrmPlugin::SecurityLevel level, Vector<uint8_t>& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ SecurityLevel hSecurityLevel = toHidlSecurityLevel(level);
+ bool setSecurityLevel = true;
+
+ if (level == DrmPlugin::kSecurityLevelMax) {
+ setSecurityLevel = false;
+ } else {
+ if (hSecurityLevel == SecurityLevel::UNKNOWN) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+ }
+
+ status_t err = UNKNOWN_ERROR;
+ bool retry = true;
+ do {
+ hidl_vec<uint8_t> hSessionId;
+
+ Return<void> hResult;
+ if (mPluginV1_1 == NULL || !setSecurityLevel) {
+ hResult = mPlugin->openSession([&](Status status, const hidl_vec<uint8_t>& id) {
+ if (status == Status::OK) {
+ sessionId = toVector(id);
+ }
+ err = toStatusT(status);
+ });
+ } else {
+ hResult = mPluginV1_1->openSession_1_1(hSecurityLevel,
+ [&](Status status, const hidl_vec<uint8_t>& id) {
+ if (status == Status::OK) {
+ sessionId = toVector(id);
+ }
+ err = toStatusT(status);
+ });
+ }
+
+ if (!hResult.isOk()) {
+ err = DEAD_OBJECT;
+ }
+
+ if (err == ERROR_DRM_RESOURCE_BUSY && retry) {
+ mLock.unlock();
+ // reclaimSession may call back to closeSession, since mLock is
+ // shared between Drm instances, we should unlock here to avoid
+ // deadlock.
+ retry = DrmSessionManager::Instance()->reclaimSession(AIBinder_getCallingPid());
+ mLock.lock();
+ } else {
+ retry = false;
+ }
+ } while (retry);
+
+ if (err == OK) {
+ std::shared_ptr<DrmSessionClient> client =
+ ndk::SharedRefBase::make<DrmSessionClient>(this, sessionId);
+ DrmSessionManager::Instance()->addSession(
+ AIBinder_getCallingPid(), std::static_pointer_cast<IResourceManagerClient>(client),
+ sessionId);
+ mOpenSessions.push_back(client);
+ mMetrics.SetSessionStart(sessionId);
+ }
+
+ mMetrics.mOpenSessionCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalHidl::closeSession(Vector<uint8_t> const& sessionId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status = mPlugin->closeSession(toHidlVec(sessionId));
+ if (status.isOk()) {
+ if (status == Status::OK) {
+ DrmSessionManager::Instance()->removeSession(sessionId);
+ for (auto i = mOpenSessions.begin(); i != mOpenSessions.end(); i++) {
+ if (isEqualSessionId((*i)->mSessionId, sessionId)) {
+ mOpenSessions.erase(i);
+ break;
+ }
+ }
+ }
+ status_t response = toStatusT(status);
+ mMetrics.SetSessionEnd(sessionId);
+ mMetrics.mCloseSessionCounter.Increment(response);
+ return response;
+ }
+ mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT);
+ 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 DrmHalHidl::getKeyRequest(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& initData, String8 const& mimeType,
+ DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ KeyType hKeyType;
+ if (keyType == DrmPlugin::kKeyType_Streaming) {
+ hKeyType = KeyType::STREAMING;
+ } else if (keyType == DrmPlugin::kKeyType_Offline) {
+ hKeyType = KeyType::OFFLINE;
+ } else if (keyType == DrmPlugin::kKeyType_Release) {
+ hKeyType = KeyType::RELEASE;
+ } else {
+ keyRequestTimer.SetAttribute(BAD_VALUE);
+ return BAD_VALUE;
+ }
+
+ ::KeyedVector hOptionalParameters = toHidlKeyedVector(optionalParameters);
+
+ status_t err = UNKNOWN_ERROR;
+ Return<void> hResult;
+
+ 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(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,
+ KeyRequestType_V1_1 hKeyRequestType, const hidl_string& hDefaultUrl) {
+ if (status == Status::OK) {
+ request = toVector(hRequest);
+ defaultUrl = toString8(hDefaultUrl);
+ *keyRequestType = toKeyRequestType_1_1(hKeyRequestType);
+ }
+ err = toStatusT(status);
+ });
+ } else {
+ hResult = mPlugin->getKeyRequest(
+ toHidlVec(sessionId), toHidlVec(initData), toHidlString(mimeType), hKeyType,
+ hOptionalParameters,
+ [&](Status status, const hidl_vec<uint8_t>& hRequest,
+ KeyRequestType hKeyRequestType, const hidl_string& hDefaultUrl) {
+ if (status == Status::OK) {
+ request = toVector(hRequest);
+ defaultUrl = toString8(hDefaultUrl);
+ *keyRequestType = toKeyRequestType(hKeyRequestType);
+ }
+ err = toStatusT(status);
+ });
+ }
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ keyRequestTimer.SetAttribute(err);
+ return err;
+}
+
+status_t DrmHalHidl::provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response,
+ Vector<uint8_t>& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->provideKeyResponse(toHidlVec(sessionId), toHidlVec(response),
+ [&](Status status, const hidl_vec<uint8_t>& hKeySetId) {
+ if (status == Status::OK) {
+ keySetId = toVector(hKeySetId);
+ }
+ err = toStatusT(status);
+ });
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ keyResponseTimer.SetAttribute(err);
+ return err;
+}
+
+status_t DrmHalHidl::removeKeys(Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status = mPlugin->removeKeys(toHidlVec(keySetId));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::restoreKeys(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ Return<Status> status = mPlugin->restoreKeys(toHidlVec(sessionId), toHidlVec(keySetId));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ ::KeyedVector hInfoMap;
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->queryKeyStatus(
+ toHidlVec(sessionId), [&](Status status, const hidl_vec<KeyValue>& map) {
+ if (status == Status::OK) {
+ infoMap = toKeyedVector(map);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+ Return<void> hResult;
+
+ if (mPluginV1_2 != NULL) {
+ 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(status);
+ });
+ } else {
+ hResult = mPlugin->getProvisionRequest(toHidlString(certType), toHidlString(certAuthority),
+ [&](Status status, const hidl_vec<uint8_t>& hRequest,
+ const hidl_string& hDefaultUrl) {
+ if (status == Status::OK) {
+ request = toVector(hRequest);
+ defaultUrl = toString8(hDefaultUrl);
+ }
+ err = toStatusT(status);
+ });
+ }
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ mMetrics.mGetProvisionRequestCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalHidl::provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->provideProvisionResponse(
+ toHidlVec(response), [&](Status status, const hidl_vec<uint8_t>& hCertificate,
+ const hidl_vec<uint8_t>& hWrappedKey) {
+ if (status == Status::OK) {
+ certificate = toVector(hCertificate);
+ wrappedKey = toVector(hWrappedKey);
+ }
+ err = toStatusT(status);
+ });
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ mMetrics.mProvideProvisionResponseCounter.Increment(err);
+ return err;
+}
+
+status_t DrmHalHidl::getSecureStops(List<Vector<uint8_t>>& secureStops) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->getSecureStops([&](Status status, const hidl_vec<SecureStop>& hSecureStops) {
+ if (status == Status::OK) {
+ secureStops = toSecureStops(hSecureStops);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getSecureStopIds(List<Vector<uint8_t>>& secureStopIds) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPluginV1_1->getSecureStopIds(
+ [&](Status status, const hidl_vec<SecureStopId>& hSecureStopIds) {
+ if (status == Status::OK) {
+ secureStopIds = toSecureStopIds(hSecureStopIds);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->getSecureStop(
+ toHidlVec(ssid), [&](Status status, const SecureStop& hSecureStop) {
+ if (status == Status::OK) {
+ secureStop = toVector(hSecureStop.opaqueData);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::releaseSecureStops(Vector<uint8_t> const& ssRelease) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status(Status::ERROR_DRM_UNKNOWN);
+ if (mPluginV1_1 != NULL) {
+ SecureStopRelease secureStopRelease;
+ secureStopRelease.opaqueData = toHidlVec(ssRelease);
+ status = mPluginV1_1->releaseSecureStops(secureStopRelease);
+ } else {
+ status = mPlugin->releaseSecureStop(toHidlVec(ssRelease));
+ }
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::removeSecureStop(Vector<uint8_t> const& ssid) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<Status> status = mPluginV1_1->removeSecureStop(toHidlVec(ssid));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::removeAllSecureStops() {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status(Status::ERROR_DRM_UNKNOWN);
+ if (mPluginV1_1 != NULL) {
+ status = mPluginV1_1->removeAllSecureStops();
+ } else {
+ status = mPlugin->releaseAllSecureStops();
+ }
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getHdcpLevels(DrmPlugin::HdcpLevel* connected,
+ DrmPlugin::HdcpLevel* max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (connected == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ *connected = DrmPlugin::kHdcpLevelUnknown;
+ *max = DrmPlugin::kHdcpLevelUnknown;
+
+ Return<void> hResult;
+ if (mPluginV1_2 != NULL) {
+ hResult = mPluginV1_2->getHdcpLevels_1_2([&](Status_V1_2 status,
+ const HdcpLevel_V1_2& hConnected,
+ const HdcpLevel_V1_2& hMax) {
+ if (status == Status_V1_2::OK) {
+ *connected = toHdcpLevel(hConnected);
+ *max = toHdcpLevel(hMax);
+ }
+ err = toStatusT(status);
+ });
+ } else if (mPluginV1_1 != NULL) {
+ hResult = mPluginV1_1->getHdcpLevels(
+ [&](Status status, const HdcpLevel& hConnected, const HdcpLevel& hMax) {
+ if (status == Status::OK) {
+ *connected = toHdcpLevel(static_cast<HdcpLevel_V1_2>(hConnected));
+ *max = toHdcpLevel(static_cast<HdcpLevel_V1_2>(hMax));
+ }
+ err = toStatusT(status);
+ });
+ } else {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getNumberOfSessions(uint32_t* open, uint32_t* max) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (open == NULL || max == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ *open = 0;
+ *max = 0;
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ Return<void> hResult =
+ mPluginV1_1->getNumberOfSessions([&](Status status, uint32_t hOpen, uint32_t hMax) {
+ if (status == Status::OK) {
+ *open = hOpen;
+ *max = hMax;
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ if (level == NULL) {
+ return BAD_VALUE;
+ }
+ status_t err = UNKNOWN_ERROR;
+
+ if (mPluginV1_1 == NULL) {
+ return ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ *level = DrmPlugin::kSecurityLevelUnknown;
+
+ Return<void> hResult = mPluginV1_1->getSecurityLevel(toHidlVec(sessionId),
+ [&](Status status, SecurityLevel hLevel) {
+ if (status == Status::OK) {
+ *level = toSecurityLevel(hLevel);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPluginV1_2->getOfflineLicenseKeySetIds(
+ [&](Status status, const hidl_vec<KeySetId>& hKeySetIds) {
+ if (status == Status::OK) {
+ keySetIds = toKeySetIds(hKeySetIds);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::removeOfflineLicense(Vector<uint8_t> const& keySetId) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ Return<Status> status = mPluginV1_2->removeOfflineLicense(toHidlVec(keySetId));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPluginV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+ *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPluginV1_2->getOfflineLicenseState(
+ toHidlVec(keySetId), [&](Status status, OfflineLicenseState hLicenseState) {
+ if (status == Status::OK) {
+ *licenseState = toOfflineLicenseState(hLicenseState);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getPropertyString(String8 const& name, String8& value) const {
+ Mutex::Autolock autoLock(mLock);
+ return getPropertyStringInternal(name, value);
+}
+
+status_t DrmHalHidl::getPropertyStringInternal(String8 const& name, String8& value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->getPropertyString(
+ toHidlString(name), [&](Status status, const hidl_string& hValue) {
+ if (status == Status::OK) {
+ value = toString8(hValue);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const {
+ Mutex::Autolock autoLock(mLock);
+ return getPropertyByteArrayInternal(name, value);
+}
+
+status_t DrmHalHidl::getPropertyByteArrayInternal(String8 const& name,
+ Vector<uint8_t>& value) const {
+ // This function is internal to the class and should only be called while
+ // mLock is already held.
+ INIT_CHECK();
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->getPropertyByteArray(
+ toHidlString(name), [&](Status status, const hidl_vec<uint8_t>& hValue) {
+ if (status == Status::OK) {
+ value = toVector(hValue);
+ }
+ err = toStatusT(status);
+ });
+
+ err = hResult.isOk() ? err : DEAD_OBJECT;
+ if (name == kPropertyDeviceUniqueId) {
+ mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
+ }
+ return err;
+}
+
+status_t DrmHalHidl::setPropertyString(String8 const& name, String8 const& value) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status = mPlugin->setPropertyString(toHidlString(name), toHidlString(value));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::setPropertyByteArray(String8 const& name, Vector<uint8_t> const& value) const {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ Return<Status> status = mPlugin->setPropertyByteArray(toHidlString(name), toHidlVec(value));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getMetrics(const sp<IDrmMetricsConsumer>& consumer) {
+ if (consumer == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+ consumer->consumeFrameworkMetrics(mMetrics);
+
+ // Append vendor metrics if they are supported.
+ if (mPluginV1_1 != NULL) {
+ String8 vendor;
+ String8 description;
+ if (getPropertyStringInternal(String8("vendor"), vendor) != OK || vendor.isEmpty()) {
+ ALOGE("Get vendor failed or is empty");
+ vendor = "NONE";
+ }
+ if (getPropertyStringInternal(String8("description"), description) != OK ||
+ description.isEmpty()) {
+ ALOGE("Get description failed or is empty.");
+ description = "NONE";
+ }
+ vendor += ".";
+ vendor += description;
+
+ hidl_vec<DrmMetricGroup> pluginMetrics;
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> status =
+ mPluginV1_1->getMetrics([&](Status status, hidl_vec<DrmMetricGroup> pluginMetrics) {
+ if (status != Status::OK) {
+ ALOGV("Error getting plugin metrics: %d", status);
+ } else {
+ consumer->consumeHidlMetrics(vendor, pluginMetrics);
+ }
+ err = toStatusT(status);
+ });
+ return status.isOk() ? err : DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+status_t DrmHalHidl::setCipherAlgorithm(Vector<uint8_t> const& sessionId,
+ String8 const& algorithm) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ Return<Status> status =
+ mPlugin->setCipherAlgorithm(toHidlVec(sessionId), toHidlString(algorithm));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ Return<Status> status = mPlugin->setMacAlgorithm(toHidlVec(sessionId), toHidlString(algorithm));
+ return status.isOk() ? toStatusT(status) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->encrypt(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input),
+ toHidlVec(iv), [&](Status status, const hidl_vec<uint8_t>& hOutput) {
+ if (status == Status::OK) {
+ output = toVector(hOutput);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->decrypt(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input),
+ toHidlVec(iv), [&](Status status, const hidl_vec<uint8_t>& hOutput) {
+ if (status == Status::OK) {
+ output = toVector(hOutput);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->sign(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(message),
+ [&](Status status, const hidl_vec<uint8_t>& hSignature) {
+ if (status == Status::OK) {
+ signature = toVector(hSignature);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult =
+ mPlugin->verify(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(message),
+ toHidlVec(signature), [&](Status status, bool hMatch) {
+ if (status == Status::OK) {
+ match = hMatch;
+ } else {
+ match = false;
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature) {
+ Mutex::Autolock autoLock(mLock);
+ INIT_CHECK();
+
+ DrmSessionManager::Instance()->useSession(sessionId);
+
+ status_t err = UNKNOWN_ERROR;
+
+ Return<void> hResult = mPlugin->signRSA(
+ toHidlVec(sessionId), toHidlString(algorithm), toHidlVec(message),
+ toHidlVec(wrappedKey), [&](Status status, const hidl_vec<uint8_t>& hSignature) {
+ if (status == Status::OK) {
+ signature = toVector(hSignature);
+ }
+ err = toStatusT(status);
+ });
+
+ return hResult.isOk() ? err : DEAD_OBJECT;
+}
+
+std::string DrmHalHidl::reportFrameworkMetrics(const std::string& pluginMetrics) const {
+ mediametrics_handle_t item(mediametrics_create("mediadrm"));
+ mediametrics_setUid(item, mMetrics.GetAppUid());
+ String8 vendor;
+ String8 description;
+ status_t result = getPropertyStringInternal(String8("vendor"), vendor);
+ if (result != OK) {
+ ALOGE("Failed to get vendor from drm plugin: %d", result);
+ } else {
+ mediametrics_setCString(item, "vendor", vendor.c_str());
+ }
+ result = getPropertyStringInternal(String8("description"), description);
+ if (result != OK) {
+ ALOGE("Failed to get description from drm plugin: %d", result);
+ } else {
+ mediametrics_setCString(item, "description", description.c_str());
+ }
+
+ std::string serializedMetrics;
+ result = mMetrics.GetSerializedMetrics(&serializedMetrics);
+ if (result != OK) {
+ ALOGE("Failed to serialize framework metrics: %d", result);
+ }
+ std::string b64EncodedMetrics =
+ toBase64StringNoPad(serializedMetrics.data(), serializedMetrics.size());
+ if (!b64EncodedMetrics.empty()) {
+ mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
+ }
+ if (!pluginMetrics.empty()) {
+ mediametrics_setCString(item, "plugin_metrics", pluginMetrics.c_str());
+ }
+ if (!mediametrics_selfRecord(item)) {
+ ALOGE("Failed to self record framework metrics");
+ }
+ mediametrics_delete(item);
+ return serializedMetrics;
+}
+
+std::string DrmHalHidl::reportPluginMetrics() const {
+ Vector<uint8_t> metricsVector;
+ String8 vendor;
+ String8 description;
+ std::string metricsString;
+ if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
+ getPropertyStringInternal(String8("description"), description) == OK &&
+ getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
+ metricsString = toBase64StringNoPad(metricsVector.array(), metricsVector.size());
+ status_t res = android::reportDrmPluginMetrics(metricsString, vendor, description,
+ mMetrics.GetAppUid());
+ if (res != OK) {
+ ALOGE("Metrics were retrieved but could not be reported: %d", res);
+ }
+ }
+ return metricsString;
+}
+
+status_t DrmHalHidl::requiresSecureDecoder(const char* mime, bool* required) const {
+ Mutex::Autolock autoLock(mLock);
+ if (mPluginV1_4 == NULL) {
+ return false;
+ }
+ auto hResult = mPluginV1_4->requiresSecureDecoderDefault(hidl_string(mime));
+ if (!hResult.isOk()) {
+ DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %s", hResult.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (required) {
+ *required = hResult;
+ }
+ return OK;
+}
+
+status_t DrmHalHidl::requiresSecureDecoder(const char* mime, DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const {
+ Mutex::Autolock autoLock(mLock);
+ if (mPluginV1_4 == NULL) {
+ return false;
+ }
+ auto hLevel = toHidlSecurityLevel(securityLevel);
+ auto hResult = mPluginV1_4->requiresSecureDecoder(hidl_string(mime), hLevel);
+ if (!hResult.isOk()) {
+ DrmUtils::LOG2BE("requiresSecureDecoder txn failed: %s", hResult.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (required) {
+ *required = hResult;
+ }
+ return OK;
+}
+
+status_t DrmHalHidl::setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId) {
+ Mutex::Autolock autoLock(mLock);
+ if (mPluginV1_4 == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+ auto err = mPluginV1_4->setPlaybackId(toHidlVec(sessionId), hidl_string(playbackId));
+ return err.isOk() ? toStatusT(err) : DEAD_OBJECT;
+}
+
+status_t DrmHalHidl::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ Mutex::Autolock autoLock(mLock);
+ return DrmUtils::GetLogMessages<drm::V1_4::IDrmPlugin>(mPlugin, logs);
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp
index 996fd19..77b5343 100644
--- a/drm/libmediadrm/DrmMetrics.cpp
+++ b/drm/libmediadrm/DrmMetrics.cpp
@@ -123,20 +123,19 @@
});
mKeyStatusChangeCounter.ExportValues(
- [&](const KeyStatusType key_status_type, const int64_t value) {
+ [&](const uint32_t key_status_type, const int64_t value) {
DrmFrameworkMetrics::Counter *counter =
metrics.add_key_status_change_counter();
counter->set_count(value);
- counter->mutable_attributes()->set_key_status_type(
- (uint32_t)key_status_type);
+ counter->mutable_attributes()->set_key_status_type(key_status_type);
});
mEventCounter.ExportValues(
- [&](const EventType event_type, const int64_t value) {
+ [&](const uint32_t event_type, const int64_t value) {
DrmFrameworkMetrics::Counter *counter =
metrics.add_event_callback_counter();
counter->set_count(value);
- counter->mutable_attributes()->set_event_type((uint32_t)event_type);
+ counter->mutable_attributes()->set_event_type(event_type);
});
mGetDeviceUniqueIdCounter.ExportValues(
diff --git a/drm/libmediadrm/DrmMetricsConsumer.cpp b/drm/libmediadrm/DrmMetricsConsumer.cpp
index 5f0b26e..dca3050 100644
--- a/drm/libmediadrm/DrmMetricsConsumer.cpp
+++ b/drm/libmediadrm/DrmMetricsConsumer.cpp
@@ -32,26 +32,24 @@
namespace {
-template <typename T> std::string GetAttributeName(T type);
-
-template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
- static const char *type_names[] = {"USABLE", "EXPIRED",
+std::string GetAttributeName(std::string typeName, uint32_t attribute) {
+ if (typeName == "KeyStatusChange") {
+ static const char *type_names[] = {"USABLE", "EXPIRED",
"OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
"INTERNAL_ERROR", "USABLE_IN_FUTURE"};
- if (((size_t)type) >= arraysize(type_names)) {
- return "UNKNOWN_TYPE";
+ if (attribute >= arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[attribute];
}
- return type_names[(size_t)type];
-}
-
-template <> std::string GetAttributeName<EventType>(EventType type) {
+
static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
"KEY_EXPIRED", "VENDOR_DEFINED",
"SESSION_RECLAIMED"};
- if (((size_t)type) >= arraysize(type_names)) {
+ if (attribute >= arraysize(type_names)) {
return "UNKNOWN_TYPE";
}
- return type_names[(size_t)type];
+ return type_names[attribute];
}
template <typename T>
@@ -87,14 +85,14 @@
template <typename T>
void ExportCounterMetricWithAttributeNames(
- const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
+ const android::CounterMetric<T> &counter, std::string typeName, PersistableBundle *metrics) {
if (!metrics) {
ALOGE("metrics was unexpectedly null.");
return;
}
- counter.ExportValues([&](const T &attribute, const int64_t value) {
+ counter.ExportValues([&](const uint32_t attribute, const int64_t value) {
std::string name = counter.metric_name() + "." +
- GetAttributeName(attribute) + ".count";
+ GetAttributeName(typeName, attribute) + ".count";
metrics->putLong(android::String16(name.c_str()), value);
});
}
@@ -196,8 +194,8 @@
ExportEventMetric(metrics.mProvideKeyResponseTimeUs, mBundle);
ExportCounterMetric(metrics.mGetProvisionRequestCounter, mBundle);
ExportCounterMetric(metrics.mProvideProvisionResponseCounter, mBundle);
- ExportCounterMetricWithAttributeNames(metrics.mKeyStatusChangeCounter, mBundle);
- ExportCounterMetricWithAttributeNames(metrics.mEventCounter, mBundle);
+ ExportCounterMetricWithAttributeNames(metrics.mKeyStatusChangeCounter, "KeyStatusChange", mBundle);
+ ExportCounterMetricWithAttributeNames(metrics.mEventCounter, "Event", mBundle);
ExportCounterMetric(metrics.mGetDeviceUniqueIdCounter, mBundle);
ExportSessionLifespans(metrics.GetSessionLifespans(), mBundle);
return android::OK;
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
index 0b117a3..bca292d 100644
--- a/drm/libmediadrm/DrmUtils.cpp
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -32,10 +32,10 @@
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/HidlSupport.h>
+#include <cutils/properties.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/String16.h>
-#include <cutils/properties.h>
#include <mediadrm/CryptoHal.h>
#include <mediadrm/DrmHal.h>
@@ -57,10 +57,10 @@
namespace {
-template<typename Hal>
-Hal *MakeObject(status_t *pstatus) {
+template <typename Hal>
+Hal* MakeObject(status_t* pstatus) {
status_t err = OK;
- status_t &status = pstatus ? *pstatus : err;
+ status_t& status = pstatus ? *pstatus : err;
auto obj = new Hal();
status = obj->initCheck();
if (status != OK && status != NO_INIT) {
@@ -70,43 +70,44 @@
}
template <typename Hal, typename V, typename M>
-void MakeHidlFactories(const uint8_t uuid[16], V &factories, M& instances) {
+void MakeHidlFactories(const uint8_t uuid[16], V& factories, M& instances) {
sp<HServiceManager> serviceManager = HServiceManager::getService();
if (serviceManager == nullptr) {
LOG2BE("Failed to get service manager");
return;
}
- serviceManager->listManifestByInterface(Hal::descriptor, [&](const hidl_vec<hidl_string> ®istered) {
- for (const auto &instance : registered) {
- auto factory = Hal::getService(instance);
- if (factory != nullptr) {
- instances[instance.c_str()] = Hal::descriptor;
- if (!uuid) {
- factories.push_back(factory);
- continue;
+ serviceManager->listManifestByInterface(
+ Hal::descriptor, [&](const hidl_vec<hidl_string>& registered) {
+ for (const auto& instance : registered) {
+ auto factory = Hal::getService(instance);
+ if (factory != nullptr) {
+ instances[instance.c_str()] = Hal::descriptor;
+ if (!uuid) {
+ factories.push_back(factory);
+ continue;
+ }
+ auto supported = factory->isCryptoSchemeSupported(uuid);
+ if (!supported.isOk()) {
+ LOG2BE(uuid, "isCryptoSchemeSupported txn failed: %s",
+ supported.description().c_str());
+ continue;
+ }
+ if (supported) {
+ factories.push_back(factory);
+ }
+ }
}
- auto supported = factory->isCryptoSchemeSupported(uuid);
- if (!supported.isOk()) {
- LOG2BE(uuid, "isCryptoSchemeSupported txn failed: %s",
- supported.description().c_str());
- continue;
- }
- if (supported) {
- factories.push_back(factory);
- }
- }
- }
- });
+ });
}
template <typename Hal, typename V>
-void MakeHidlFactories(const uint8_t uuid[16], V &factories) {
+void MakeHidlFactories(const uint8_t uuid[16], V& factories) {
std::map<std::string, std::string> instances;
MakeHidlFactories<Hal>(uuid, factories, instances);
}
-hidl_vec<uint8_t> toHidlVec(const void *ptr, size_t size) {
+hidl_vec<uint8_t> toHidlVec(const void* ptr, size_t size) {
hidl_vec<uint8_t> vec(size);
if (ptr != nullptr) {
memcpy(vec.data(), ptr, size);
@@ -114,19 +115,19 @@
return vec;
}
-hidl_array<uint8_t, 16> toHidlArray16(const uint8_t *ptr) {
+hidl_array<uint8_t, 16> toHidlArray16(const uint8_t* ptr) {
if (ptr == nullptr) {
return hidl_array<uint8_t, 16>();
}
return hidl_array<uint8_t, 16>(ptr);
}
-sp<::V1_0::IDrmPlugin> MakeDrmPlugin(const sp<::V1_0::IDrmFactory> &factory,
- const uint8_t uuid[16], const char *appPackageName) {
+sp<::V1_0::IDrmPlugin> MakeDrmPlugin(const sp<::V1_0::IDrmFactory>& factory, const uint8_t uuid[16],
+ const char* appPackageName) {
sp<::V1_0::IDrmPlugin> plugin;
auto err = factory->createPlugin(
toHidlArray16(uuid), hidl_string(appPackageName),
- [&](::V1_0::Status status, const sp<::V1_0::IDrmPlugin> &hPlugin) {
+ [&](::V1_0::Status status, const sp<::V1_0::IDrmPlugin>& hPlugin) {
if (status != ::V1_0::Status::OK) {
LOG2BE(uuid, "MakeDrmPlugin failed: %d", status);
return;
@@ -141,13 +142,13 @@
}
}
-sp<::V1_0::ICryptoPlugin> MakeCryptoPlugin(const sp<::V1_0::ICryptoFactory> &factory,
- const uint8_t uuid[16], const void *initData,
+sp<::V1_0::ICryptoPlugin> MakeCryptoPlugin(const sp<::V1_0::ICryptoFactory>& factory,
+ const uint8_t uuid[16], const void* initData,
size_t initDataSize) {
sp<::V1_0::ICryptoPlugin> plugin;
auto err = factory->createPlugin(
toHidlArray16(uuid), toHidlVec(initData, initDataSize),
- [&](::V1_0::Status status, const sp<::V1_0::ICryptoPlugin> &hPlugin) {
+ [&](::V1_0::Status status, const sp<::V1_0::ICryptoPlugin>& hPlugin) {
if (status != ::V1_0::Status::OK) {
LOG2BE(uuid, "MakeCryptoPlugin failed: %d", status);
return;
@@ -162,17 +163,17 @@
}
}
-} // namespace
+} // namespace
bool UseDrmService() {
return property_get_bool("mediadrm.use_mediadrmserver", true);
}
-sp<IDrm> MakeDrm(status_t *pstatus) {
+sp<IDrm> MakeDrm(status_t* pstatus) {
return MakeObject<DrmHal>(pstatus);
}
-sp<ICrypto> MakeCrypto(status_t *pstatus) {
+sp<ICrypto> MakeCrypto(status_t* pstatus) {
return MakeObject<CryptoHal>(pstatus);
}
@@ -191,9 +192,9 @@
}
std::vector<sp<::V1_0::IDrmPlugin>> MakeDrmPlugins(const uint8_t uuid[16],
- const char *appPackageName) {
+ const char* appPackageName) {
std::vector<sp<::V1_0::IDrmPlugin>> plugins;
- for (const auto &factory : MakeDrmFactories(uuid)) {
+ for (const auto& factory : MakeDrmFactories(uuid)) {
plugins.push_back(MakeDrmPlugin(factory, uuid, appPackageName));
}
return plugins;
@@ -209,10 +210,11 @@
return cryptoFactories;
}
-std::vector<sp<ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16], const void *initData,
- size_t initDataSize) {
- std::vector<sp<ICryptoPlugin>> plugins;
- for (const auto &factory : MakeCryptoFactories(uuid)) {
+std::vector<sp<::V1_0::ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16],
+ const void* initData,
+ size_t initDataSize) {
+ std::vector<sp<::V1_0::ICryptoPlugin>> plugins;
+ for (const auto& factory : MakeCryptoFactories(uuid)) {
plugins.push_back(MakeCryptoPlugin(factory, uuid, initData, initDataSize));
}
return plugins;
@@ -220,90 +222,90 @@
status_t toStatusT_1_4(::V1_4::Status status) {
switch (status) {
- case ::V1_4::Status::OK:
- return OK;
- case ::V1_4::Status::BAD_VALUE:
- return BAD_VALUE;
- case ::V1_4::Status::ERROR_DRM_CANNOT_HANDLE:
- return ERROR_DRM_CANNOT_HANDLE;
- case ::V1_4::Status::ERROR_DRM_DECRYPT:
- return ERROR_DRM_DECRYPT;
- case ::V1_4::Status::ERROR_DRM_DEVICE_REVOKED:
- return ERROR_DRM_DEVICE_REVOKED;
- case ::V1_4::Status::ERROR_DRM_FRAME_TOO_LARGE:
- return ERROR_DRM_FRAME_TOO_LARGE;
- case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
- return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
- case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_SECURITY:
- return ERROR_DRM_INSUFFICIENT_SECURITY;
- case ::V1_4::Status::ERROR_DRM_INVALID_STATE:
- return ERROR_DRM_INVALID_STATE;
- case ::V1_4::Status::ERROR_DRM_LICENSE_EXPIRED:
- return ERROR_DRM_LICENSE_EXPIRED;
- case ::V1_4::Status::ERROR_DRM_NO_LICENSE:
- return ERROR_DRM_NO_LICENSE;
- case ::V1_4::Status::ERROR_DRM_NOT_PROVISIONED:
- return ERROR_DRM_NOT_PROVISIONED;
- case ::V1_4::Status::ERROR_DRM_RESOURCE_BUSY:
- return ERROR_DRM_RESOURCE_BUSY;
- case ::V1_4::Status::ERROR_DRM_RESOURCE_CONTENTION:
- return ERROR_DRM_RESOURCE_CONTENTION;
- case ::V1_4::Status::ERROR_DRM_SESSION_LOST_STATE:
- return ERROR_DRM_SESSION_LOST_STATE;
- case ::V1_4::Status::ERROR_DRM_SESSION_NOT_OPENED:
- return ERROR_DRM_SESSION_NOT_OPENED;
+ case ::V1_4::Status::OK:
+ return OK;
+ case ::V1_4::Status::BAD_VALUE:
+ return BAD_VALUE;
+ case ::V1_4::Status::ERROR_DRM_CANNOT_HANDLE:
+ return ERROR_DRM_CANNOT_HANDLE;
+ case ::V1_4::Status::ERROR_DRM_DECRYPT:
+ return ERROR_DRM_DECRYPT;
+ case ::V1_4::Status::ERROR_DRM_DEVICE_REVOKED:
+ return ERROR_DRM_DEVICE_REVOKED;
+ case ::V1_4::Status::ERROR_DRM_FRAME_TOO_LARGE:
+ return ERROR_DRM_FRAME_TOO_LARGE;
+ case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
+ return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
+ case ::V1_4::Status::ERROR_DRM_INSUFFICIENT_SECURITY:
+ return ERROR_DRM_INSUFFICIENT_SECURITY;
+ case ::V1_4::Status::ERROR_DRM_INVALID_STATE:
+ return ERROR_DRM_INVALID_STATE;
+ case ::V1_4::Status::ERROR_DRM_LICENSE_EXPIRED:
+ return ERROR_DRM_LICENSE_EXPIRED;
+ case ::V1_4::Status::ERROR_DRM_NO_LICENSE:
+ return ERROR_DRM_NO_LICENSE;
+ case ::V1_4::Status::ERROR_DRM_NOT_PROVISIONED:
+ return ERROR_DRM_NOT_PROVISIONED;
+ case ::V1_4::Status::ERROR_DRM_RESOURCE_BUSY:
+ return ERROR_DRM_RESOURCE_BUSY;
+ case ::V1_4::Status::ERROR_DRM_RESOURCE_CONTENTION:
+ return ERROR_DRM_RESOURCE_CONTENTION;
+ case ::V1_4::Status::ERROR_DRM_SESSION_LOST_STATE:
+ return ERROR_DRM_SESSION_LOST_STATE;
+ case ::V1_4::Status::ERROR_DRM_SESSION_NOT_OPENED:
+ return ERROR_DRM_SESSION_NOT_OPENED;
- // New in S / drm@1.4:
- case ::V1_4::Status::CANNOT_DECRYPT_ZERO_SUBSAMPLES:
- return ERROR_DRM_ZERO_SUBSAMPLES;
- case ::V1_4::Status::CRYPTO_LIBRARY_ERROR:
- return ERROR_DRM_CRYPTO_LIBRARY;
- case ::V1_4::Status::GENERAL_OEM_ERROR:
- return ERROR_DRM_GENERIC_OEM;
- case ::V1_4::Status::GENERAL_PLUGIN_ERROR:
- return ERROR_DRM_GENERIC_PLUGIN;
- case ::V1_4::Status::INIT_DATA_INVALID:
- return ERROR_DRM_INIT_DATA;
- case ::V1_4::Status::KEY_NOT_LOADED:
- return ERROR_DRM_KEY_NOT_LOADED;
- case ::V1_4::Status::LICENSE_PARSE_ERROR:
- return ERROR_DRM_LICENSE_PARSE;
- case ::V1_4::Status::LICENSE_POLICY_ERROR:
- return ERROR_DRM_LICENSE_POLICY;
- case ::V1_4::Status::LICENSE_RELEASE_ERROR:
- return ERROR_DRM_LICENSE_RELEASE;
- case ::V1_4::Status::LICENSE_REQUEST_REJECTED:
- return ERROR_DRM_LICENSE_REQUEST_REJECTED;
- case ::V1_4::Status::LICENSE_RESTORE_ERROR:
- return ERROR_DRM_LICENSE_RESTORE;
- case ::V1_4::Status::LICENSE_STATE_ERROR:
- return ERROR_DRM_LICENSE_STATE;
- case ::V1_4::Status::MALFORMED_CERTIFICATE:
- return ERROR_DRM_CERTIFICATE_MALFORMED;
- case ::V1_4::Status::MEDIA_FRAMEWORK_ERROR:
- return ERROR_DRM_MEDIA_FRAMEWORK;
- case ::V1_4::Status::MISSING_CERTIFICATE:
- return ERROR_DRM_CERTIFICATE_MISSING;
- case ::V1_4::Status::PROVISIONING_CERTIFICATE_ERROR:
- return ERROR_DRM_PROVISIONING_CERTIFICATE;
- case ::V1_4::Status::PROVISIONING_CONFIGURATION_ERROR:
- return ERROR_DRM_PROVISIONING_CONFIG;
- case ::V1_4::Status::PROVISIONING_PARSE_ERROR:
- return ERROR_DRM_PROVISIONING_PARSE;
- case ::V1_4::Status::PROVISIONING_REQUEST_REJECTED:
- return ERROR_DRM_PROVISIONING_REQUEST_REJECTED;
- case ::V1_4::Status::RETRYABLE_PROVISIONING_ERROR:
- return ERROR_DRM_PROVISIONING_RETRY;
- case ::V1_4::Status::SECURE_STOP_RELEASE_ERROR:
- return ERROR_DRM_SECURE_STOP_RELEASE;
- case ::V1_4::Status::STORAGE_READ_FAILURE:
- return ERROR_DRM_STORAGE_READ;
- case ::V1_4::Status::STORAGE_WRITE_FAILURE:
- return ERROR_DRM_STORAGE_WRITE;
+ // New in S / drm@1.4:
+ case ::V1_4::Status::CANNOT_DECRYPT_ZERO_SUBSAMPLES:
+ return ERROR_DRM_ZERO_SUBSAMPLES;
+ case ::V1_4::Status::CRYPTO_LIBRARY_ERROR:
+ return ERROR_DRM_CRYPTO_LIBRARY;
+ case ::V1_4::Status::GENERAL_OEM_ERROR:
+ return ERROR_DRM_GENERIC_OEM;
+ case ::V1_4::Status::GENERAL_PLUGIN_ERROR:
+ return ERROR_DRM_GENERIC_PLUGIN;
+ case ::V1_4::Status::INIT_DATA_INVALID:
+ return ERROR_DRM_INIT_DATA;
+ case ::V1_4::Status::KEY_NOT_LOADED:
+ return ERROR_DRM_KEY_NOT_LOADED;
+ case ::V1_4::Status::LICENSE_PARSE_ERROR:
+ return ERROR_DRM_LICENSE_PARSE;
+ case ::V1_4::Status::LICENSE_POLICY_ERROR:
+ return ERROR_DRM_LICENSE_POLICY;
+ case ::V1_4::Status::LICENSE_RELEASE_ERROR:
+ return ERROR_DRM_LICENSE_RELEASE;
+ case ::V1_4::Status::LICENSE_REQUEST_REJECTED:
+ return ERROR_DRM_LICENSE_REQUEST_REJECTED;
+ case ::V1_4::Status::LICENSE_RESTORE_ERROR:
+ return ERROR_DRM_LICENSE_RESTORE;
+ case ::V1_4::Status::LICENSE_STATE_ERROR:
+ return ERROR_DRM_LICENSE_STATE;
+ case ::V1_4::Status::MALFORMED_CERTIFICATE:
+ return ERROR_DRM_CERTIFICATE_MALFORMED;
+ case ::V1_4::Status::MEDIA_FRAMEWORK_ERROR:
+ return ERROR_DRM_MEDIA_FRAMEWORK;
+ case ::V1_4::Status::MISSING_CERTIFICATE:
+ return ERROR_DRM_CERTIFICATE_MISSING;
+ case ::V1_4::Status::PROVISIONING_CERTIFICATE_ERROR:
+ return ERROR_DRM_PROVISIONING_CERTIFICATE;
+ case ::V1_4::Status::PROVISIONING_CONFIGURATION_ERROR:
+ return ERROR_DRM_PROVISIONING_CONFIG;
+ case ::V1_4::Status::PROVISIONING_PARSE_ERROR:
+ return ERROR_DRM_PROVISIONING_PARSE;
+ case ::V1_4::Status::PROVISIONING_REQUEST_REJECTED:
+ return ERROR_DRM_PROVISIONING_REQUEST_REJECTED;
+ case ::V1_4::Status::RETRYABLE_PROVISIONING_ERROR:
+ return ERROR_DRM_PROVISIONING_RETRY;
+ case ::V1_4::Status::SECURE_STOP_RELEASE_ERROR:
+ return ERROR_DRM_SECURE_STOP_RELEASE;
+ case ::V1_4::Status::STORAGE_READ_FAILURE:
+ return ERROR_DRM_STORAGE_READ;
+ case ::V1_4::Status::STORAGE_WRITE_FAILURE:
+ return ERROR_DRM_STORAGE_WRITE;
- case ::V1_4::Status::ERROR_DRM_UNKNOWN:
- default:
- return ERROR_DRM_UNKNOWN;
+ case ::V1_4::Status::ERROR_DRM_UNKNOWN:
+ default:
+ return ERROR_DRM_UNKNOWN;
}
return ERROR_DRM_UNKNOWN;
}
@@ -312,20 +314,34 @@
char logPriorityToChar(::V1_4::LogPriority priority) {
char p = 'U';
switch (priority) {
- case ::V1_4::LogPriority::VERBOSE: p = 'V'; break;
- case ::V1_4::LogPriority::DEBUG: p = 'D'; break;
- case ::V1_4::LogPriority::INFO: p = 'I'; break;
- case ::V1_4::LogPriority::WARN: p = 'W'; break;
- case ::V1_4::LogPriority::ERROR: p = 'E'; break;
- case ::V1_4::LogPriority::FATAL: p = 'F'; break;
- default: p = 'U'; break;
+ case ::V1_4::LogPriority::VERBOSE:
+ p = 'V';
+ break;
+ case ::V1_4::LogPriority::DEBUG:
+ p = 'D';
+ break;
+ case ::V1_4::LogPriority::INFO:
+ p = 'I';
+ break;
+ case ::V1_4::LogPriority::WARN:
+ p = 'W';
+ break;
+ case ::V1_4::LogPriority::ERROR:
+ p = 'E';
+ break;
+ case ::V1_4::LogPriority::FATAL:
+ p = 'F';
+ break;
+ default:
+ p = 'U';
+ break;
}
return p;
}
} // namespace
-std::string GetExceptionMessage(status_t err, const char *msg,
- const Vector<::V1_4::LogMessage> &logs) {
+std::string GetExceptionMessage(status_t err, const char* msg,
+ const Vector<::V1_4::LogMessage>& logs) {
std::string ruler("==============================");
std::string header("Beginning of DRM Plugin Log");
std::string footer("End of DRM Plugin Log");
@@ -355,7 +371,7 @@
return msg8.c_str();
}
-void LogBuffer::addLog(const ::V1_4::LogMessage &log) {
+void LogBuffer::addLog(const ::V1_4::LogMessage& log) {
std::unique_lock<std::mutex> lock(mMutex);
mBuffer.push_back(log);
while (mBuffer.size() > MAX_CAPACITY) {
diff --git a/drm/libmediadrm/fuzzer/Android.bp b/drm/libmediadrm/fuzzer/Android.bp
index 49bbad4..a85e3cf 100644
--- a/drm/libmediadrm/fuzzer/Android.bp
+++ b/drm/libmediadrm/fuzzer/Android.bp
@@ -36,6 +36,7 @@
"libmediadrm",
"liblog",
"resourcemanager_aidl_interface-ndk",
+ "libaidlcommonsupport",
],
header_libs: [
"libmedia_headers",
@@ -59,6 +60,7 @@
"android.hardware.drm@1.4",
"libhidlallocatorutils",
"libhidlbase",
+ "android.hardware.drm-V1-ndk",
],
fuzz_config: {
cc: [
diff --git a/drm/libmediadrm/fuzzer/mediadrm_fuzzer.cpp b/drm/libmediadrm/fuzzer/mediadrm_fuzzer.cpp
index 8df0477..eabd41f 100644
--- a/drm/libmediadrm/fuzzer/mediadrm_fuzzer.cpp
+++ b/drm/libmediadrm/fuzzer/mediadrm_fuzzer.cpp
@@ -24,6 +24,8 @@
#include <mediadrm/DrmHal.h>
#include <utils/String8.h>
#include "fuzzer/FuzzedDataProvider.h"
+#include <binder/PersistableBundle.h>
+#include <android/hardware/drm/1.0/types.h>
#define AES_BLOCK_SIZE 16
#define UNUSED_PARAM __attribute__((unused))
@@ -33,6 +35,7 @@
using android::hardware::fromHeap;
using ::android::os::PersistableBundle;
using drm::V1_0::BufferType;
+using ::android::hardware::drm::V1_0::DestinationBuffer;
enum {
INVALID_UUID = 0,
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
index 5fd39e6..5be59f0 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHal.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHal.h
@@ -15,25 +15,12 @@
*/
#ifndef CRYPTO_HAL_H_
-
#define CRYPTO_HAL_H_
-#include <android/hardware/drm/1.0/ICryptoFactory.h>
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.1/ICryptoFactory.h>
-#include <android/hardware/drm/1.2/ICryptoPlugin.h>
-#include <android/hardware/drm/1.4/ICryptoPlugin.h>
-
#include <mediadrm/ICrypto.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
-namespace drm = ::android::hardware::drm;
-using drm::V1_0::ICryptoFactory;
-using drm::V1_0::ICryptoPlugin;
-using drm::V1_0::SharedBuffer;
-using drm::V1_0::DestinationBuffer;
-
using ::android::hardware::HidlMemory;
class IMemoryHeap;
@@ -43,67 +30,30 @@
struct CryptoHal : public ICrypto {
CryptoHal();
virtual ~CryptoHal();
-
virtual status_t initCheck() const;
-
virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
-
virtual status_t createPlugin(
const uint8_t uuid[16], const void *data, size_t size);
-
virtual status_t destroyPlugin();
-
virtual bool requiresSecureDecoderComponent(
const char *mime) const;
-
virtual void notifyResolution(uint32_t width, uint32_t height);
-
virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
-
virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
- const ::SharedBuffer &source, size_t offset,
+ const drm::V1_0::SharedBuffer &source, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
- const ::DestinationBuffer &destination,
+ const drm::V1_0::DestinationBuffer &destination,
AString *errorDetailMsg);
-
- virtual int32_t setHeap(const sp<HidlMemory>& heap) {
- return setHeapBase(heap);
- }
- virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
-
+ virtual int32_t setHeap(const sp<HidlMemory>& heap);
+ virtual void unsetHeap(int32_t seqNum);
virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
-
private:
- mutable Mutex mLock;
-
- const Vector<sp<ICryptoFactory>> mFactories;
- sp<ICryptoPlugin> mPlugin;
- sp<drm::V1_2::ICryptoPlugin> mPluginV1_2;
-
- /**
- * mInitCheck is:
- * NO_INIT if a plugin hasn't been created yet
- * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
- * OK after a plugin has been created and mPlugin is valid
- */
- status_t mInitCheck;
-
- KeyedVector<int32_t, size_t> mHeapSizes;
- int32_t mHeapSeqNum;
-
- Vector<sp<ICryptoFactory>> makeCryptoFactories();
- sp<ICryptoPlugin> makeCryptoPlugin(const sp<ICryptoFactory>& factory,
- const uint8_t uuid[16], const void *initData, size_t size);
-
- int32_t setHeapBase(const sp<HidlMemory>& heap);
- void clearHeapBase(int32_t seqNum);
-
- status_t checkSharedBuffer(const ::SharedBuffer& buffer);
-
+ sp<ICrypto> mCryptoHalHidl;
+ sp<ICrypto> mCryptoHalAidl;
DISALLOW_EVIL_CONSTRUCTORS(CryptoHal);
};
-} // namespace android
+}
-#endif // CRYPTO_HAL_H_
+#endif
\ No newline at end of file
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h b/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
new file mode 100644
index 0000000..a25b091
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 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_HAL_AIDL_H_
+#define CRYPTO_HAL_AIDL_H_
+
+#include <aidl/android/hardware/drm/ICryptoFactory.h>
+#include <aidl/android/hardware/drm/ICryptoPlugin.h>
+
+#include <mediadrm/ICrypto.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+using ICryptoFactoryAidl = ::aidl::android::hardware::drm::ICryptoFactory;
+using ICryptoPluginAidl = ::aidl::android::hardware::drm::ICryptoPlugin;
+using ::aidl::android::hardware::drm::Uuid;
+
+// -------Hidl interface related-----------------
+// TODO: replace before removing hidl interface
+using ::android::hardware::drm::V1_0::DestinationBuffer;
+using ::android::hardware::drm::V1_0::SharedBuffer;
+
+using ::android::hardware::HidlMemory;
+
+// -------Hidl interface related end-------------
+
+class IMemoryHeap;
+
+namespace android {
+
+struct CryptoHalAidl : public ICrypto {
+ CryptoHalAidl();
+ virtual ~CryptoHalAidl();
+ virtual status_t initCheck() const;
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+ virtual status_t createPlugin(const uint8_t uuid[16], const void* data, size_t size);
+ virtual status_t destroyPlugin();
+ virtual bool requiresSecureDecoderComponent(const char* mime) const;
+ virtual void notifyResolution(uint32_t width, uint32_t height);
+ virtual status_t setMediaDrmSession(const Vector<uint8_t>& sessionId);
+ virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern& pattern, const ::SharedBuffer& source,
+ size_t offset, const CryptoPlugin::SubSample* subSamples,
+ size_t numSubSamples, const ::DestinationBuffer& destination,
+ AString* errorDetailMsg);
+ virtual int32_t setHeap(const sp<HidlMemory>& heap);
+ virtual void unsetHeap(int32_t seqNum);
+ virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const;
+
+ private:
+ mutable Mutex mLock;
+
+ const std::vector<std::shared_ptr<ICryptoFactoryAidl>> mFactories;
+ std::shared_ptr<ICryptoPluginAidl> mPlugin;
+
+ /**
+ * mInitCheck is:
+ * NO_INIT if a plugin hasn't been created yet
+ * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
+ * OK after a plugin has been created and mPlugin is valid
+ */
+ status_t mInitCheck;
+
+ KeyedVector<int32_t, size_t> mHeapSizes;
+ int32_t mHeapSeqNum;
+
+ std::vector<std::shared_ptr<ICryptoFactoryAidl>> makeCryptoFactories();
+ std::shared_ptr<ICryptoPluginAidl> makeCryptoPlugin(
+ const std::shared_ptr<ICryptoFactoryAidl>& factory, const Uuid& uuidAidl,
+ const std::vector<uint8_t> initData);
+
+ status_t checkSharedBuffer(const ::SharedBuffer& buffer);
+
+ DISALLOW_EVIL_CONSTRUCTORS(CryptoHalAidl);
+};
+
+} // namespace android
+
+#endif // CRYPTO_HAL_H_
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h b/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
new file mode 100644
index 0000000..6db1e89
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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_HAL_HIDL_H_
+#define CRYPTO_HAL_HIDL_H_
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.2/ICryptoPlugin.h>
+#include <android/hardware/drm/1.4/ICryptoPlugin.h>
+
+#include <mediadrm/ICrypto.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::ICryptoFactory;
+using drm::V1_0::ICryptoPlugin;
+using drm::V1_0::SharedBuffer;
+using drm::V1_0::DestinationBuffer;
+
+using ::android::hardware::HidlMemory;
+
+class IMemoryHeap;
+
+namespace android {
+
+struct CryptoHalHidl : public ICrypto {
+ CryptoHalHidl();
+ virtual ~CryptoHalHidl();
+
+ virtual status_t initCheck() const;
+
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+
+ virtual status_t createPlugin(
+ const uint8_t uuid[16], const void *data, size_t size);
+
+ virtual status_t destroyPlugin();
+
+ virtual bool requiresSecureDecoderComponent(
+ const char *mime) const;
+
+ virtual void notifyResolution(uint32_t width, uint32_t height);
+
+ virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
+
+ virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
+ const ::SharedBuffer &source, size_t offset,
+ const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+ const ::DestinationBuffer &destination,
+ AString *errorDetailMsg);
+
+ virtual int32_t setHeap(const sp<HidlMemory>& heap) {
+ return setHeapBase(heap);
+ }
+ virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
+
+ virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
+
+private:
+ mutable Mutex mLock;
+
+ const Vector<sp<ICryptoFactory>> mFactories;
+ sp<ICryptoPlugin> mPlugin;
+ sp<drm::V1_2::ICryptoPlugin> mPluginV1_2;
+
+ /**
+ * mInitCheck is:
+ * NO_INIT if a plugin hasn't been created yet
+ * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
+ * OK after a plugin has been created and mPlugin is valid
+ */
+ status_t mInitCheck;
+
+ KeyedVector<int32_t, size_t> mHeapSizes;
+ int32_t mHeapSeqNum;
+
+ Vector<sp<ICryptoFactory>> makeCryptoFactories();
+ sp<ICryptoPlugin> makeCryptoPlugin(const sp<ICryptoFactory>& factory,
+ const uint8_t uuid[16], const void *initData, size_t size);
+
+ int32_t setHeapBase(const sp<HidlMemory>& heap);
+ void clearHeapBase(int32_t seqNum);
+
+ status_t checkSharedBuffer(const ::SharedBuffer& buffer);
+
+ DISALLOW_EVIL_CONSTRUCTORS(CryptoHalHidl);
+};
+
+} // namespace android
+
+#endif // CRYPTO_HAL_H_
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index 7eb1dec..bb58585 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -14,77 +14,27 @@
* limitations under the License.
*/
-#ifndef DRM_HAL_H_
-
-#define DRM_HAL_H_
-
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.1/IDrmFactory.h>
-#include <android/hardware/drm/1.1/IDrmPlugin.h>
-#include <android/hardware/drm/1.2/IDrmFactory.h>
-#include <android/hardware/drm/1.2/IDrmPlugin.h>
-#include <android/hardware/drm/1.2/IDrmPluginListener.h>
-#include <android/hardware/drm/1.4/IDrmPlugin.h>
-#include <android/hardware/drm/1.4/types.h>
-
-#include <media/drm/DrmAPI.h>
-#include <mediadrm/DrmMetrics.h>
-#include <mediadrm/DrmSessionManager.h>
#include <mediadrm/IDrm.h>
-#include <mediadrm/IDrmClient.h>
-#include <mediadrm/IDrmMetricsConsumer.h>
-#include <utils/threads.h>
-namespace drm = ::android::hardware::drm;
-using drm::V1_0::EventType;
-using drm::V1_0::IDrmFactory;
-using drm::V1_0::IDrmPlugin;
-using drm::V1_0::IDrmPluginListener;
-using drm::V1_1::SecurityLevel;
-using drm::V1_2::KeyStatus;
-using drm::V1_2::OfflineLicenseState;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2;
-typedef drm::V1_0::KeyStatus KeyStatus_V1_0;
+#ifndef DRM_HAL_H_
+#define DRM_HAL_H_
namespace android {
-struct DrmSessionClientInterface;
-
-inline bool operator==(const Vector<uint8_t> &l, const Vector<uint8_t> &r) {
- if (l.size() != r.size()) return false;
- return memcmp(l.array(), r.array(), l.size()) == 0;
-}
-
-struct DrmHal : public IDrm,
- public IDrmPluginListener_V1_2 {
-
- struct DrmSessionClient;
-
+struct DrmHal : public IDrm {
DrmHal();
virtual ~DrmHal();
-
virtual status_t initCheck() const;
-
virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8& mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported);
-
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel securityLevel,
+ bool *result);
virtual status_t createPlugin(const uint8_t uuid[16],
const String8 &appPackageName);
-
virtual status_t destroyPlugin();
-
- virtual status_t openSession(DrmPlugin::SecurityLevel level,
+ virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
Vector<uint8_t> &sessionId);
-
virtual status_t closeSession(Vector<uint8_t> const &sessionId);
-
virtual status_t
getKeyRequest(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &initData,
@@ -92,168 +42,88 @@
KeyedVector<String8, String8> const &optionalParameters,
Vector<uint8_t> &request, String8 &defaultUrl,
DrmPlugin::KeyRequestType *keyRequestType);
-
virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &response,
Vector<uint8_t> &keySetId);
-
virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
-
virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keySetId);
-
virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
KeyedVector<String8, String8> &infoMap) const;
-
virtual status_t getProvisionRequest(String8 const &certType,
String8 const &certAuthority,
Vector<uint8_t> &request,
- String8 &defaulUrl);
-
+ String8 &defaultUrl);
virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey);
-
virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops);
virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds);
virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
-
virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
virtual status_t removeSecureStop(Vector<uint8_t> const &ssid);
virtual status_t removeAllSecureStops();
-
virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connectedLevel,
DrmPlugin::HdcpLevel *maxLevel) const;
virtual status_t getNumberOfSessions(uint32_t *currentSessions,
uint32_t *maxSessions) const;
virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
DrmPlugin::SecurityLevel *level) const;
-
virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const;
virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId);
virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
DrmPlugin::OfflineLicenseState *licenseState) const;
-
- virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
+ virtual status_t getPropertyString(String8 const &name, String8 &value) const;
virtual status_t getPropertyByteArray(String8 const &name,
- Vector<uint8_t> &value ) const;
- virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
+ Vector<uint8_t> &value) const;
+ virtual status_t setPropertyString(String8 const &name,
+ String8 const &value ) const;
virtual status_t setPropertyByteArray(String8 const &name,
- Vector<uint8_t> const &value ) const;
+ Vector<uint8_t> const &value) const;
virtual status_t getMetrics(const sp<IDrmMetricsConsumer> &consumer);
-
virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm);
-
virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm);
-
virtual status_t encrypt(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId,
Vector<uint8_t> const &input,
Vector<uint8_t> const &iv,
Vector<uint8_t> &output);
-
virtual status_t decrypt(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId,
Vector<uint8_t> const &input,
Vector<uint8_t> const &iv,
Vector<uint8_t> &output);
-
virtual status_t sign(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId,
Vector<uint8_t> const &message,
Vector<uint8_t> &signature);
-
virtual status_t verify(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &keyId,
Vector<uint8_t> const &message,
Vector<uint8_t> const &signature,
bool &match);
-
virtual status_t signRSA(Vector<uint8_t> const &sessionId,
String8 const &algorithm,
Vector<uint8_t> const &message,
Vector<uint8_t> const &wrappedKey,
Vector<uint8_t> &signature);
-
virtual status_t setListener(const sp<IDrmClient>& listener);
-
virtual status_t requiresSecureDecoder(const char *mime, bool *required) const;
-
virtual status_t requiresSecureDecoder(const char *mime, DrmPlugin::SecurityLevel securityLevel,
bool *required) const;
-
virtual status_t setPlaybackId(
Vector<uint8_t> const &sessionId,
const char *playbackId);
-
virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
- // Methods of IDrmPluginListener
- Return<void> sendEvent(EventType eventType,
- const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data);
-
- Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
- int64_t expiryTimeInMS);
-
- Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus_V1_0>& keyStatusList, bool hasNewUsableKey);
-
- Return<void> sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey);
-
- Return<void> sendSessionLostState(const hidl_vec<uint8_t>& sessionId);
-
private:
- static Mutex mLock;
-
- sp<IDrmClient> mListener;
- mutable Mutex mEventLock;
- mutable Mutex mNotifyLock;
-
- const std::vector<sp<IDrmFactory>> mFactories;
- sp<IDrmPlugin> mPlugin;
- sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
- sp<drm::V1_2::IDrmPlugin> mPluginV1_2;
- sp<drm::V1_4::IDrmPlugin> mPluginV1_4;
- String8 mAppPackageName;
-
- // Mutable to allow modification within GetPropertyByteArray.
- mutable MediaDrmMetrics mMetrics;
-
- std::vector<std::shared_ptr<DrmSessionClient>> mOpenSessions;
- void closeOpenSessions();
- void cleanup();
-
- /**
- * mInitCheck is:
- * NO_INIT if a plugin hasn't been created yet
- * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
- * OK after a plugin has been created and mPlugin is valid
- */
- status_t mInitCheck;
-
- std::vector<sp<IDrmFactory>> makeDrmFactories();
- sp<IDrmPlugin> makeDrmPlugin(const sp<IDrmFactory>& factory,
- const uint8_t uuid[16], const String8& appPackageName);
-
- void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
-
- std::string reportPluginMetrics() const;
- std::string reportFrameworkMetrics(const std::string& pluginMetrics) const;
- status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
- status_t getPropertyByteArrayInternal(String8 const &name,
- Vector<uint8_t> &value) const;
- status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
- const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level,
- bool *isSupported);
-
+ sp<IDrm> mDrmHalHidl;
+ std::shared_ptr<IDrm> mDrmHalAidl;
DISALLOW_EVIL_CONSTRUCTORS(DrmHal);
};
-} // namespace android
+} // namespace android
-#endif // DRM_HAL_H_
+#endif
\ No newline at end of file
diff --git a/drm/libmediadrm/include/mediadrm/DrmHalAidl.h b/drm/libmediadrm/include/mediadrm/DrmHalAidl.h
new file mode 100644
index 0000000..6720734
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmHalAidl.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 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 DRM_HAL_AIDL_H_
+#define DRM_HAL_AIDL_H_
+
+#include <aidl/android/hardware/drm/BnDrmPluginListener.h>
+#include <aidl/android/hardware/drm/IDrmFactory.h>
+#include <aidl/android/hardware/drm/IDrmPlugin.h>
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <mediadrm/DrmMetrics.h>
+#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/IDrm.h>
+#include <memory>
+
+using ::aidl::android::hardware::drm::BnDrmPluginListener;
+using IDrmPluginAidl = ::aidl::android::hardware::drm::IDrmPlugin;
+using IDrmFactoryAidl = ::aidl::android::hardware::drm::IDrmFactory;
+using EventTypeAidl = ::aidl::android::hardware::drm::EventType;
+using KeyStatusAidl = ::aidl::android::hardware::drm::KeyStatus;
+using ::aidl::android::hardware::drm::Uuid;
+
+namespace android {
+struct DrmHalAidl : public IDrm,
+ public BnDrmPluginListener,
+ std::enable_shared_from_this<BnDrmPluginListener> {
+ struct DrmSessionClient;
+ DrmHalAidl();
+ virtual ~DrmHalAidl();
+ virtual status_t initCheck() const;
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType,
+ DrmPlugin::SecurityLevel securityLevel, bool* result);
+ virtual status_t createPlugin(const uint8_t uuid[16], const String8& appPackageName);
+ virtual status_t destroyPlugin();
+ virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
+ Vector<uint8_t>& sessionId);
+ virtual status_t closeSession(Vector<uint8_t> const& sessionId);
+ virtual status_t getKeyRequest(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& initData, String8 const& mimeType,
+ DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType);
+ virtual status_t provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response, Vector<uint8_t>& keySetId);
+ virtual status_t removeKeys(Vector<uint8_t> const& keySetId);
+ virtual status_t restoreKeys(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keySetId);
+ virtual status_t queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const;
+ virtual status_t getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl);
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey);
+ virtual status_t getSecureStops(List<Vector<uint8_t>>& secureStops);
+ virtual status_t getSecureStopIds(List<Vector<uint8_t>>& secureStopIds);
+ virtual status_t getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop);
+ virtual status_t releaseSecureStops(Vector<uint8_t> const& ssRelease);
+ virtual status_t removeSecureStop(Vector<uint8_t> const& ssid);
+ virtual status_t removeAllSecureStops();
+ virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel* connectedLevel,
+ DrmPlugin::HdcpLevel* maxLevel) const;
+ virtual status_t getNumberOfSessions(uint32_t* currentSessions, uint32_t* maxSessions) const;
+ virtual status_t getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const;
+ virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const;
+ virtual status_t removeOfflineLicense(Vector<uint8_t> const& keySetId);
+ virtual status_t getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const;
+ virtual status_t getPropertyString(String8 const& name, String8& value) const;
+ virtual status_t getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const;
+ virtual status_t setPropertyString(String8 const& name, String8 const& value) const;
+ virtual status_t setPropertyByteArray(String8 const& name, Vector<uint8_t> const& value) const;
+ virtual status_t getMetrics(const sp<IDrmMetricsConsumer>& consumer);
+ virtual status_t setCipherAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm);
+ virtual status_t setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm);
+ virtual status_t encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output);
+ virtual status_t decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output);
+ virtual status_t sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature);
+ virtual status_t verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match);
+ virtual status_t signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature);
+ virtual status_t setListener(const sp<IDrmClient>& listener);
+ virtual status_t requiresSecureDecoder(const char* mime, bool* required) const;
+ virtual status_t requiresSecureDecoder(const char* mime, DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const;
+ virtual status_t setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId);
+ virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const;
+ // Methods of IDrmPluginListenerAidl
+ ::ndk::ScopedAStatus onEvent(EventTypeAidl in_eventType,
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_data);
+ ::ndk::ScopedAStatus onExpirationUpdate(const std::vector<uint8_t>& in_sessionId,
+ int64_t in_expiryTimeInMS);
+ ::ndk::ScopedAStatus onKeysChange(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<KeyStatusAidl>& in_keyStatusList,
+ bool in_hasNewUsableKey);
+ ::ndk::ScopedAStatus onSessionLostState(const std::vector<uint8_t>& in_sessionId);
+
+ private:
+ static Mutex mLock;
+ sp<IDrmClient> mListener;
+ mutable Mutex mEventLock;
+ mutable Mutex mNotifyLock;
+ const std::vector<std::shared_ptr<IDrmFactoryAidl>> mFactories;
+ std::shared_ptr<IDrmPluginAidl> mPlugin;
+ std::vector<std::shared_ptr<IDrmFactoryAidl>> makeDrmFactories();
+ status_t mInitCheck;
+ mutable MediaDrmMetrics mMetrics;
+ std::vector<std::shared_ptr<DrmSessionClient>> mOpenSessions;
+ void cleanup();
+ void closeOpenSessions();
+ std::string reportPluginMetrics() const;
+ std::string reportFrameworkMetrics(const std::string& pluginMetrics) const;
+ status_t getPropertyStringInternal(String8 const& name, String8& value) const;
+ status_t getPropertyByteArrayInternal(String8 const& name, Vector<uint8_t>& value) const;
+ DISALLOW_EVIL_CONSTRUCTORS(DrmHalAidl);
+};
+
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/drm/libmediadrm/include/mediadrm/DrmHalHidl.h b/drm/libmediadrm/include/mediadrm/DrmHalHidl.h
new file mode 100644
index 0000000..91dc700
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmHalHidl.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2021 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 DRM_HAL_HIDL_H_
+#define DRM_HAL_HIDL_H_
+
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hardware/drm/1.2/IDrmPlugin.h>
+#include <android/hardware/drm/1.2/IDrmPluginListener.h>
+#include <android/hardware/drm/1.4/IDrmPlugin.h>
+#include <android/hardware/drm/1.4/types.h>
+
+#include <media/drm/DrmAPI.h>
+#include <mediadrm/DrmMetrics.h>
+#include <mediadrm/DrmSessionManager.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IDrmClient.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <utils/threads.h>
+
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::EventType;
+using drm::V1_0::IDrmFactory;
+using drm::V1_0::IDrmPlugin;
+using drm::V1_0::IDrmPluginListener;
+using drm::V1_1::SecurityLevel;
+using drm::V1_2::KeyStatus;
+using drm::V1_2::OfflineLicenseState;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2;
+typedef drm::V1_0::KeyStatus KeyStatus_V1_0;
+
+namespace android {
+
+struct DrmSessionClientInterface;
+
+inline bool operator==(const Vector<uint8_t> &l, const Vector<uint8_t> &r) {
+ if (l.size() != r.size()) return false;
+ return memcmp(l.array(), r.array(), l.size()) == 0;
+}
+
+struct DrmHalHidl : public IDrm,
+ public IDrmPluginListener_V1_2 {
+
+ struct DrmSessionClient;
+
+ DrmHalHidl();
+ virtual ~DrmHalHidl();
+
+ virtual status_t initCheck() const;
+
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+ const String8& mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported);
+
+ virtual status_t createPlugin(const uint8_t uuid[16],
+ const String8 &appPackageName);
+
+ virtual status_t destroyPlugin();
+
+ virtual status_t openSession(DrmPlugin::SecurityLevel level,
+ Vector<uint8_t> &sessionId);
+
+ virtual status_t closeSession(Vector<uint8_t> const &sessionId);
+
+ virtual status_t
+ getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl,
+ DrmPlugin::KeyRequestType *keyRequestType);
+
+ virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId);
+
+ virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
+
+ virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId);
+
+ virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const;
+
+ virtual status_t getProvisionRequest(String8 const &certType,
+ String8 const &certAuthority,
+ Vector<uint8_t> &request,
+ String8 &defaultUrl);
+
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
+ Vector<uint8_t> &certificate,
+ Vector<uint8_t> &wrappedKey);
+
+ virtual status_t getSecureStops(List<Vector<uint8_t>> &secureStops);
+ virtual status_t getSecureStopIds(List<Vector<uint8_t>> &secureStopIds);
+ virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
+
+ virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
+ virtual status_t removeSecureStop(Vector<uint8_t> const &ssid);
+ virtual status_t removeAllSecureStops();
+
+ virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connectedLevel,
+ DrmPlugin::HdcpLevel *maxLevel) const;
+ virtual status_t getNumberOfSessions(uint32_t *currentSessions,
+ uint32_t *maxSessions) const;
+ virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
+ DrmPlugin::SecurityLevel *level) const;
+
+ virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t>> &keySetIds) const;
+ virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId);
+ virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
+ DrmPlugin::OfflineLicenseState *licenseState) const;
+
+ virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
+ virtual status_t getPropertyByteArray(String8 const &name,
+ Vector<uint8_t> &value ) const;
+ virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
+ virtual status_t setPropertyByteArray(String8 const &name,
+ Vector<uint8_t> const &value ) const;
+ virtual status_t getMetrics(const sp<IDrmMetricsConsumer> &consumer);
+
+ virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ virtual status_t encrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output);
+
+ virtual status_t decrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output);
+
+ virtual status_t sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature);
+
+ virtual status_t verify(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &signature,
+ bool &match);
+
+ virtual status_t signRSA(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &wrappedKey,
+ Vector<uint8_t> &signature);
+
+ virtual status_t setListener(const sp<IDrmClient>& listener);
+
+ virtual status_t requiresSecureDecoder(const char *mime, bool *required) const;
+
+ virtual status_t requiresSecureDecoder(const char *mime, DrmPlugin::SecurityLevel securityLevel,
+ bool *required) const;
+
+ virtual status_t setPlaybackId(
+ Vector<uint8_t> const &sessionId,
+ const char *playbackId);
+
+ virtual status_t getLogMessages(Vector<drm::V1_4::LogMessage> &logs) const;
+
+ // Methods of IDrmPluginListener
+ Return<void> sendEvent(EventType eventType,
+ const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data);
+
+ Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
+ int64_t expiryTimeInMS);
+
+ Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus_V1_0>& keyStatusList, bool hasNewUsableKey);
+
+ Return<void> sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
+ const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey);
+
+ Return<void> sendSessionLostState(const hidl_vec<uint8_t>& sessionId);
+
+private:
+ static Mutex mLock;
+
+ sp<IDrmClient> mListener;
+ mutable Mutex mEventLock;
+ mutable Mutex mNotifyLock;
+
+ const std::vector<sp<IDrmFactory>> mFactories;
+ sp<IDrmPlugin> mPlugin;
+ sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
+ sp<drm::V1_2::IDrmPlugin> mPluginV1_2;
+ sp<drm::V1_4::IDrmPlugin> mPluginV1_4;
+ String8 mAppPackageName;
+
+ // Mutable to allow modification within GetPropertyByteArray.
+ mutable MediaDrmMetrics mMetrics;
+
+ std::vector<std::shared_ptr<DrmSessionClient>> mOpenSessions;
+ void closeOpenSessions();
+ void cleanup();
+
+ /**
+ * mInitCheck is:
+ * NO_INIT if a plugin hasn't been created yet
+ * ERROR_UNSUPPORTED if a plugin can't be created for the uuid
+ * OK after a plugin has been created and mPlugin is valid
+ */
+ status_t mInitCheck;
+
+ std::vector<sp<IDrmFactory>> makeDrmFactories();
+ sp<IDrmPlugin> makeDrmPlugin(const sp<IDrmFactory>& factory,
+ const uint8_t uuid[16], const String8& appPackageName);
+
+ void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
+
+ std::string reportPluginMetrics() const;
+ std::string reportFrameworkMetrics(const std::string& pluginMetrics) const;
+ status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
+ status_t getPropertyByteArrayInternal(String8 const &name,
+ Vector<uint8_t> &value) const;
+ status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+ const uint8_t uuid[16],
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported);
+
+ DISALLOW_EVIL_CONSTRUCTORS(DrmHalHidl);
+};
+
+} // namespace android
+
+#endif // DRM_HAL_H_
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetrics.h b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
index 100b8f7..e1775c7 100644
--- a/drm/libmediadrm/include/mediadrm/DrmMetrics.h
+++ b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
@@ -50,12 +50,10 @@
CounterMetric<status_t> mGetProvisionRequestCounter;
// Count of provideProvisionResponse calls.
CounterMetric<status_t> mProvideProvisionResponseCounter;
-
// Count of key status events broken out by status type.
- CounterMetric<::android::hardware::drm::V1_2::KeyStatusType>
- mKeyStatusChangeCounter;
+ CounterMetric<uint32_t> mKeyStatusChangeCounter;
// Count of events broken out by event type
- CounterMetric<::android::hardware::drm::V1_0::EventType> mEventCounter;
+ CounterMetric<uint32_t> mEventCounter;
// Count getPropertyByteArray calls to retrieve the device unique id.
CounterMetric<status_t> mGetDeviceUniqueIdCounter;
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
index ec0b878..5679cfd 100644
--- a/drm/libmediadrm/interface/mediadrm/DrmUtils.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -38,12 +38,18 @@
#include <mutex>
#include <string>
#include <vector>
+#include <aidl/android/hardware/drm/LogMessage.h>
+#include <aidl/android/hardware/drm/Status.h>
using namespace ::android::hardware::drm;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
+using ::aidl::android::hardware::drm::LogPriority;
+using ::aidl::android::hardware::drm::LogMessage;
+using StatusAidl = ::aidl::android::hardware::drm::Status;
+
namespace android {
struct ICrypto;
@@ -180,6 +186,136 @@
return toStatusT_1_4(err);
}
+inline status_t toStatusTAidl(int32_t serviceError) {
+ auto status = static_cast<StatusAidl>(serviceError);
+ switch (status) {
+ case StatusAidl::OK:
+ return OK;
+ case StatusAidl::BAD_VALUE:
+ return BAD_VALUE;
+ case StatusAidl::ERROR_DRM_CANNOT_HANDLE:
+ return ERROR_DRM_CANNOT_HANDLE;
+ case StatusAidl::ERROR_DRM_DECRYPT:
+ return ERROR_DRM_DECRYPT;
+ case StatusAidl::ERROR_DRM_DEVICE_REVOKED:
+ return ERROR_DRM_DEVICE_REVOKED;
+ case StatusAidl::ERROR_DRM_FRAME_TOO_LARGE:
+ return ERROR_DRM_FRAME_TOO_LARGE;
+ case StatusAidl::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
+ return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
+ case StatusAidl::ERROR_DRM_INSUFFICIENT_SECURITY:
+ return ERROR_DRM_INSUFFICIENT_SECURITY;
+ case StatusAidl::ERROR_DRM_INVALID_STATE:
+ return ERROR_DRM_INVALID_STATE;
+ case StatusAidl::ERROR_DRM_LICENSE_EXPIRED:
+ return ERROR_DRM_LICENSE_EXPIRED;
+ case StatusAidl::ERROR_DRM_NO_LICENSE:
+ return ERROR_DRM_NO_LICENSE;
+ case StatusAidl::ERROR_DRM_NOT_PROVISIONED:
+ return ERROR_DRM_NOT_PROVISIONED;
+ case StatusAidl::ERROR_DRM_RESOURCE_BUSY:
+ return ERROR_DRM_RESOURCE_BUSY;
+ case StatusAidl::ERROR_DRM_RESOURCE_CONTENTION:
+ return ERROR_DRM_RESOURCE_CONTENTION;
+ case StatusAidl::ERROR_DRM_SESSION_LOST_STATE:
+ return ERROR_DRM_SESSION_LOST_STATE;
+ case StatusAidl::ERROR_DRM_SESSION_NOT_OPENED:
+ return ERROR_DRM_SESSION_NOT_OPENED;
+
+ // New in S / drm@1.4:
+ case StatusAidl::CANNOT_DECRYPT_ZERO_SUBSAMPLES:
+ return ERROR_DRM_ZERO_SUBSAMPLES;
+ case StatusAidl::CRYPTO_LIBRARY_ERROR:
+ return ERROR_DRM_CRYPTO_LIBRARY;
+ case StatusAidl::GENERAL_OEM_ERROR:
+ return ERROR_DRM_GENERIC_OEM;
+ case StatusAidl::GENERAL_PLUGIN_ERROR:
+ return ERROR_DRM_GENERIC_PLUGIN;
+ case StatusAidl::INIT_DATA_INVALID:
+ return ERROR_DRM_INIT_DATA;
+ case StatusAidl::KEY_NOT_LOADED:
+ return ERROR_DRM_KEY_NOT_LOADED;
+ case StatusAidl::LICENSE_PARSE_ERROR:
+ return ERROR_DRM_LICENSE_PARSE;
+ case StatusAidl::LICENSE_POLICY_ERROR:
+ return ERROR_DRM_LICENSE_POLICY;
+ case StatusAidl::LICENSE_RELEASE_ERROR:
+ return ERROR_DRM_LICENSE_RELEASE;
+ case StatusAidl::LICENSE_REQUEST_REJECTED:
+ return ERROR_DRM_LICENSE_REQUEST_REJECTED;
+ case StatusAidl::LICENSE_RESTORE_ERROR:
+ return ERROR_DRM_LICENSE_RESTORE;
+ case StatusAidl::LICENSE_STATE_ERROR:
+ return ERROR_DRM_LICENSE_STATE;
+ case StatusAidl::MALFORMED_CERTIFICATE:
+ return ERROR_DRM_CERTIFICATE_MALFORMED;
+ case StatusAidl::MEDIA_FRAMEWORK_ERROR:
+ return ERROR_DRM_MEDIA_FRAMEWORK;
+ case StatusAidl::MISSING_CERTIFICATE:
+ return ERROR_DRM_CERTIFICATE_MISSING;
+ case StatusAidl::PROVISIONING_CERTIFICATE_ERROR:
+ return ERROR_DRM_PROVISIONING_CERTIFICATE;
+ case StatusAidl::PROVISIONING_CONFIGURATION_ERROR:
+ return ERROR_DRM_PROVISIONING_CONFIG;
+ case StatusAidl::PROVISIONING_PARSE_ERROR:
+ return ERROR_DRM_PROVISIONING_PARSE;
+ case StatusAidl::PROVISIONING_REQUEST_REJECTED:
+ return ERROR_DRM_PROVISIONING_REQUEST_REJECTED;
+ case StatusAidl::RETRYABLE_PROVISIONING_ERROR:
+ return ERROR_DRM_PROVISIONING_RETRY;
+ case StatusAidl::SECURE_STOP_RELEASE_ERROR:
+ return ERROR_DRM_SECURE_STOP_RELEASE;
+ case StatusAidl::STORAGE_READ_FAILURE:
+ return ERROR_DRM_STORAGE_READ;
+ case StatusAidl::STORAGE_WRITE_FAILURE:
+ return ERROR_DRM_STORAGE_WRITE;
+
+ case StatusAidl::ERROR_DRM_UNKNOWN:
+ default:
+ return ERROR_DRM_UNKNOWN;
+ }
+ return ERROR_DRM_UNKNOWN;
+}
+
+template<typename T, typename U>
+status_t GetLogMessagesAidl(const std::shared_ptr<U> &obj, Vector<::V1_4::LogMessage> &logs) {
+ std::shared_ptr<T> plugin = obj;
+ if (obj == NULL) {
+ LOG2BW("%s obj is null", U::descriptor);
+ } else if (plugin == NULL) {
+ LOG2BW("Cannot cast %s obj to %s plugin", U::descriptor, T::descriptor);
+ }
+
+ std::vector<LogMessage> pluginLogsAidl;
+ if (plugin != NULL) {
+ if(!plugin->getLogMessages(&pluginLogsAidl).isOk()) {
+ LOG2BW("%s::getLogMessages remote call failed", T::descriptor);
+ }
+ }
+
+ std::vector<::V1_4::LogMessage> pluginLogs;
+ for (LogMessage log : pluginLogsAidl) {
+ ::V1_4::LogMessage logHidl;
+ logHidl.timeMs = log.timeMs;
+ // skip negative convert check as count of enum elements is 7
+ logHidl.priority = static_cast<::V1_4::LogPriority>((int32_t)log.priority);
+ logHidl.message = log.message;
+ pluginLogs.push_back(logHidl);
+ }
+
+ auto allLogs(gLogBuf.getLogs());
+ LOG2BD("framework logs size %zu; plugin logs size %zu",
+ allLogs.size(), pluginLogs.size());
+ std::copy(pluginLogs.begin(), pluginLogs.end(), std::back_inserter(allLogs));
+ std::sort(allLogs.begin(), allLogs.end(),
+ [](const ::V1_4::LogMessage &a, const ::V1_4::LogMessage &b) {
+ return a.timeMs < b.timeMs;
+ });
+
+ logs.appendVector(allLogs);
+ return OK;
+}
+
template<typename T, typename U>
status_t GetLogMessages(const sp<U> &obj, Vector<::V1_4::LogMessage> &logs) {
sp<T> plugin = T::castFrom(obj);
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp
index f362d60..237a88b 100644
--- a/drm/libmediadrm/tests/DrmMetrics_test.cpp
+++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp
@@ -83,8 +83,8 @@
metrics.mProvideProvisionResponseCounter.Increment(OK);
metrics.mGetDeviceUniqueIdCounter.Increment(OK);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
- metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::USABLE);
+ metrics.mEventCounter.Increment((uint32_t)EventType::PROVISION_REQUIRED);
PersistableBundle bundle;
DrmMetricsConsumer consumer(&bundle);
@@ -151,16 +151,16 @@
metrics.mGetDeviceUniqueIdCounter.Increment(OK);
metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR);
- metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
- metrics.mEventCounter.Increment(EventType::KEY_NEEDED);
- metrics.mEventCounter.Increment(EventType::KEY_EXPIRED);
- metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
- metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::USABLE);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::EXPIRED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::OUTPUTNOTALLOWED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::STATUSPENDING);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::INTERNALERROR);
+ metrics.mEventCounter.Increment((uint32_t)EventType::PROVISION_REQUIRED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::KEY_NEEDED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::KEY_EXPIRED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::VENDOR_DEFINED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::SESSION_RECLAIMED);
android::Vector<uint8_t> sessionId1;
sessionId1.push_back(1);
@@ -284,16 +284,16 @@
metrics.mGetDeviceUniqueIdCounter.Increment(OK);
metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING);
- metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR);
- metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
- metrics.mEventCounter.Increment(EventType::KEY_NEEDED);
- metrics.mEventCounter.Increment(EventType::KEY_EXPIRED);
- metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
- metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::USABLE);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::EXPIRED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::OUTPUTNOTALLOWED);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::STATUSPENDING);
+ metrics.mKeyStatusChangeCounter.Increment((uint32_t)KeyStatusType::INTERNALERROR);
+ metrics.mEventCounter.Increment((uint32_t)EventType::PROVISION_REQUIRED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::KEY_NEEDED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::KEY_EXPIRED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::VENDOR_DEFINED);
+ metrics.mEventCounter.Increment((uint32_t)EventType::SESSION_RECLAIMED);
std::string serializedMetrics;
ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index 0d1fe27..930b026 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -40,6 +40,12 @@
defaults: ["libstagefright_bufferpool@2.0-default"],
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
+
// TODO: b/147147992
double_loadable: true,
cflags: [
diff --git a/media/codec2/components/tests/Android.bp b/media/codec2/components/tests/Android.bp
index 3c68eee..be2abf2 100644
--- a/media/codec2/components/tests/Android.bp
+++ b/media/codec2/components/tests/Android.bp
@@ -9,44 +9,13 @@
cc_defaults {
name: "C2SoftCodecTest-defaults",
+ defaults: [ "libcodec2-static-defaults" ],
gtest: true,
host_supported: false,
srcs: [
"C2SoftCodecTest.cpp",
],
- static_libs: [
- "liblog",
- "libion",
- "libfmq",
- "libbase",
- "libutils",
- "libcutils",
- "libcodec2",
- "libhidlbase",
- "libdmabufheap",
- "libcodec2_vndk",
- "libnativewindow",
- "libcodec2_soft_common",
- "libsfplugin_ccodec_utils",
- "libstagefright_foundation",
- "libstagefright_bufferpool@2.0.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.media.bufferpool@2.0",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
- "android.hardware.graphics.bufferqueue@2.0",
- ],
-
- shared_libs: [
- "libui",
- "libdl",
- "libhardware",
- "libvndksupport",
- "libprocessgroup",
- ],
-
cflags: [
"-Wall",
"-Werror",
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 16e507c..70e742c 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -687,6 +687,9 @@
LEVEL_DV_MAIN_UHD_30, ///< Dolby Vision main tier uhd30
LEVEL_DV_MAIN_UHD_48, ///< Dolby Vision main tier uhd48
LEVEL_DV_MAIN_UHD_60, ///< Dolby Vision main tier uhd60
+ LEVEL_DV_MAIN_UHD_120, ///< Dolby Vision main tier uhd120
+ LEVEL_DV_MAIN_8K_30, ///< Dolby Vision main tier 8k30
+ LEVEL_DV_MAIN_8K_60, ///< Dolby Vision main tier 8k60
LEVEL_DV_HIGH_HD_24 = _C2_PL_DV_BASE + 0x100, ///< Dolby Vision high tier hd24
LEVEL_DV_HIGH_HD_30, ///< Dolby Vision high tier hd30
@@ -697,6 +700,9 @@
LEVEL_DV_HIGH_UHD_30, ///< Dolby Vision high tier uhd30
LEVEL_DV_HIGH_UHD_48, ///< Dolby Vision high tier uhd48
LEVEL_DV_HIGH_UHD_60, ///< Dolby Vision high tier uhd60
+ LEVEL_DV_HIGH_UHD_120, ///< Dolby Vision high tier uhd120
+ LEVEL_DV_HIGH_8K_30, ///< Dolby Vision high tier 8k30
+ LEVEL_DV_HIGH_8K_60, ///< Dolby Vision high tier 8k60
// AV1 levels
LEVEL_AV1_2 = _C2_PL_AV1_BASE , ///< AV1 Level 2
diff --git a/media/codec2/fuzzer/Android.bp b/media/codec2/fuzzer/Android.bp
index bd1fac6..3adc212 100644
--- a/media/codec2/fuzzer/Android.bp
+++ b/media/codec2/fuzzer/Android.bp
@@ -28,43 +28,12 @@
cc_defaults {
name: "C2Fuzzer-defaults",
+ defaults: [ "libcodec2-static-defaults" ],
+
srcs: [
"C2Fuzzer.cpp",
],
- static_libs: [
- "liblog",
- "libion",
- "libfmq",
- "libbase",
- "libutils",
- "libcutils",
- "libcodec2",
- "libhidlbase",
- "libdmabufheap",
- "libcodec2_vndk",
- "libnativewindow",
- "libcodec2_soft_common",
- "libsfplugin_ccodec_utils",
- "libstagefright_foundation",
- "libstagefright_bufferpool@2.0.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.media.bufferpool@2.0",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
- "android.hardware.graphics.bufferqueue@2.0",
- ],
-
- shared_libs: [
- "libui",
- "libdl",
- "libbinder",
- "libhardware",
- "libvndksupport",
- "libprocessgroup",
- ],
-
cflags: [
"-Wall",
"-Werror",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 1f8b33d..5df28f0 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1018,29 +1018,31 @@
} else {
pixelFormatInfo = nullptr;
}
- std::optional<uint32_t> flexPixelFormat{};
- std::optional<uint32_t> flexPlanarPixelFormat{};
- std::optional<uint32_t> flexSemiPlanarPixelFormat{};
+ // bit depth -> format
+ std::map<uint32_t, uint32_t> flexPixelFormat;
+ std::map<uint32_t, uint32_t> flexPlanarPixelFormat;
+ std::map<uint32_t, uint32_t> flexSemiPlanarPixelFormat;
if (pixelFormatInfo && *pixelFormatInfo) {
for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
const C2FlexiblePixelFormatDescriptorStruct &desc =
pixelFormatInfo->m.values[i];
- if (desc.bitDepth != 8
- || desc.subsampling != C2Color::YUV_420
+ if (desc.subsampling != C2Color::YUV_420
// TODO(b/180076105): some device report wrong layout
// || desc.layout == C2Color::INTERLEAVED_PACKED
// || desc.layout == C2Color::INTERLEAVED_ALIGNED
|| desc.layout == C2Color::UNKNOWN_LAYOUT) {
continue;
}
- if (!flexPixelFormat) {
- flexPixelFormat = desc.pixelFormat;
+ if (flexPixelFormat.count(desc.bitDepth) == 0) {
+ flexPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
}
- if (desc.layout == C2Color::PLANAR_PACKED && !flexPlanarPixelFormat) {
- flexPlanarPixelFormat = desc.pixelFormat;
+ if (desc.layout == C2Color::PLANAR_PACKED
+ && flexPlanarPixelFormat.count(desc.bitDepth) == 0) {
+ flexPlanarPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
}
- if (desc.layout == C2Color::SEMIPLANAR_PACKED && !flexSemiPlanarPixelFormat) {
- flexSemiPlanarPixelFormat = desc.pixelFormat;
+ if (desc.layout == C2Color::SEMIPLANAR_PACKED
+ && flexSemiPlanarPixelFormat.count(desc.bitDepth) == 0) {
+ flexSemiPlanarPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
}
}
}
@@ -1050,7 +1052,7 @@
if (!(config->mDomain & Config::IS_ENCODER)) {
if (surface == nullptr) {
const char *prefix = "";
- if (flexSemiPlanarPixelFormat) {
+ if (flexSemiPlanarPixelFormat.count(8) != 0) {
format = COLOR_FormatYUV420SemiPlanar;
prefix = "semi-";
} else {
@@ -1067,17 +1069,34 @@
if ((config->mDomain & Config::IS_ENCODER) || !surface) {
switch (format) {
case COLOR_FormatYUV420Flexible:
- format = flexPixelFormat.value_or(COLOR_FormatYUV420Planar);
+ format = COLOR_FormatYUV420Planar;
+ if (flexPixelFormat.count(8) != 0) {
+ format = flexPixelFormat[8];
+ }
break;
case COLOR_FormatYUV420Planar:
case COLOR_FormatYUV420PackedPlanar:
- format = flexPlanarPixelFormat.value_or(
- flexPixelFormat.value_or(format));
+ if (flexPlanarPixelFormat.count(8) != 0) {
+ format = flexPlanarPixelFormat[8];
+ } else if (flexPixelFormat.count(8) != 0) {
+ format = flexPixelFormat[8];
+ }
break;
case COLOR_FormatYUV420SemiPlanar:
case COLOR_FormatYUV420PackedSemiPlanar:
- format = flexSemiPlanarPixelFormat.value_or(
- flexPixelFormat.value_or(format));
+ if (flexSemiPlanarPixelFormat.count(8) != 0) {
+ format = flexSemiPlanarPixelFormat[8];
+ } else if (flexPixelFormat.count(8) != 0) {
+ format = flexPixelFormat[8];
+ }
+ break;
+ case COLOR_FormatYUVP010:
+ format = COLOR_FormatYUVP010;
+ if (flexSemiPlanarPixelFormat.count(10) != 0) {
+ format = flexSemiPlanarPixelFormat[10];
+ } else if (flexPixelFormat.count(10) != 0) {
+ format = flexPixelFormat[10];
+ }
break;
default:
// No-op
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 7f9de21..2d3c70a 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -363,21 +363,22 @@
break;
case COLOR_FormatYUVP010:
+ // stride is in bytes
mediaImage->mPlane[mediaImage->Y].mOffset = 0;
mediaImage->mPlane[mediaImage->Y].mColInc = 2;
- mediaImage->mPlane[mediaImage->Y].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
- mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride * 2;
+ mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
mediaImage->mPlane[mediaImage->U].mColInc = 4;
- mediaImage->mPlane[mediaImage->U].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->U].mRowInc = stride;
mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
- mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 2 + 2;
+ mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 2;
mediaImage->mPlane[mediaImage->V].mColInc = 4;
- mediaImage->mPlane[mediaImage->V].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->V].mRowInc = stride;
mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
if (tryWrapping) {
@@ -538,8 +539,8 @@
mInitCheck = BAD_VALUE;
return;
}
- bufferSize += stride * vStride
- / plane.rowSampling / plane.colSampling * divUp(mAllocatedDepth, 8u);
+ // stride is in bytes
+ bufferSize += stride * vStride / plane.rowSampling / plane.colSampling;
}
mBackBufferSize = bufferSize;
@@ -792,8 +793,14 @@
ALOGD("format had no width / height");
return nullptr;
}
- // NOTE: we currently only support YUV420 formats for byte-buffer mode.
- sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
+ int32_t colorFormat = COLOR_FormatYUV420Flexible;
+ int32_t bpp = 12; // 8(Y) + 2(U) + 2(V)
+ if (format->findInt32(KEY_COLOR_FORMAT, &colorFormat)) {
+ if (colorFormat == COLOR_FormatYUVP010) {
+ bpp = 24; // 16(Y) + 4(U) + 4(V)
+ }
+ }
+ sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * bpp / 8));
return new ConstGraphicBlockBuffer(
format,
aBuffer,
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index 67d7ed2..63bd64b 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -54,6 +54,9 @@
using Traits = C2Component::Traits;
+// HAL pixel format -> framework color format
+typedef std::map<uint32_t, int32_t> PixelFormatMap;
+
namespace /* unnamed */ {
bool hasPrefix(const std::string& s, const char* prefix) {
@@ -67,6 +70,26 @@
s.compare(s.size() - suffixLen, suffixLen, suffix) == 0;
}
+std::optional<int32_t> findFrameworkColorFormat(
+ const C2FlexiblePixelFormatDescriptorStruct &desc) {
+ switch (desc.bitDepth) {
+ case 8u:
+ if (desc.layout == C2Color::PLANAR_PACKED
+ || desc.layout == C2Color::SEMIPLANAR_PACKED) {
+ return COLOR_FormatYUV420Flexible;
+ }
+ break;
+ case 10u:
+ if (desc.layout == C2Color::SEMIPLANAR_PACKED) {
+ return COLOR_FormatYUVP010;
+ }
+ break;
+ default:
+ break;
+ }
+ return std::nullopt;
+}
+
// returns true if component advertised supported profile level(s)
bool addSupportedProfileLevels(
std::shared_ptr<Codec2Client::Interface> intf,
@@ -211,27 +234,69 @@
void addSupportedColorFormats(
std::shared_ptr<Codec2Client::Interface> intf,
MediaCodecInfo::CapabilitiesWriter *caps,
- const Traits& trait, const std::string &mediaType) {
- (void)intf;
-
+ const Traits& trait, const std::string &mediaType,
+ const PixelFormatMap &pixelFormatMap) {
// TODO: get this from intf() as well, but how do we map them to
// MediaCodec color formats?
bool encoder = trait.kind == C2Component::KIND_ENCODER;
if (mediaType.find("video") != std::string::npos
|| mediaType.find("image") != std::string::npos) {
+
+ std::vector<C2FieldSupportedValuesQuery> query;
+ if (encoder) {
+ C2StreamPixelFormatInfo::input pixelFormat;
+ query.push_back(C2FieldSupportedValuesQuery::Possible(
+ C2ParamField::Make(pixelFormat, pixelFormat.value)));
+ } else {
+ C2StreamPixelFormatInfo::output pixelFormat;
+ query.push_back(C2FieldSupportedValuesQuery::Possible(
+ C2ParamField::Make(pixelFormat, pixelFormat.value)));
+ }
+ std::list<int32_t> supportedColorFormats;
+ if (intf->querySupportedValues(query, C2_DONT_BLOCK) == C2_OK) {
+ if (query[0].status == C2_OK) {
+ const C2FieldSupportedValues &fsv = query[0].values;
+ if (fsv.type == C2FieldSupportedValues::VALUES) {
+ for (C2Value::Primitive value : fsv.values) {
+ auto it = pixelFormatMap.find(value.u32);
+ if (it != pixelFormatMap.end()) {
+ auto it2 = std::find(
+ supportedColorFormats.begin(),
+ supportedColorFormats.end(),
+ it->second);
+ if (it2 == supportedColorFormats.end()) {
+ supportedColorFormats.push_back(it->second);
+ }
+ }
+ }
+ }
+ }
+ }
+ auto addDefaultColorFormat = [caps, &supportedColorFormats](int32_t colorFormat) {
+ caps->addColorFormat(colorFormat);
+ auto it = std::find(
+ supportedColorFormats.begin(), supportedColorFormats.end(), colorFormat);
+ if (it != supportedColorFormats.end()) {
+ supportedColorFormats.erase(it);
+ }
+ };
+
// vendor video codecs prefer opaque format
if (trait.name.find("android") == std::string::npos) {
- caps->addColorFormat(COLOR_FormatSurface);
+ addDefaultColorFormat(COLOR_FormatSurface);
}
- caps->addColorFormat(COLOR_FormatYUV420Flexible);
- caps->addColorFormat(COLOR_FormatYUV420Planar);
- caps->addColorFormat(COLOR_FormatYUV420SemiPlanar);
- caps->addColorFormat(COLOR_FormatYUV420PackedPlanar);
- caps->addColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
+ addDefaultColorFormat(COLOR_FormatYUV420Flexible);
+ addDefaultColorFormat(COLOR_FormatYUV420Planar);
+ addDefaultColorFormat(COLOR_FormatYUV420SemiPlanar);
+ addDefaultColorFormat(COLOR_FormatYUV420PackedPlanar);
+ addDefaultColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
// framework video encoders must support surface format, though it is unclear
// that they will be able to map it if it is opaque
if (encoder && trait.name.find("android") != std::string::npos) {
- caps->addColorFormat(COLOR_FormatSurface);
+ addDefaultColorFormat(COLOR_FormatSurface);
+ }
+ for (int32_t colorFormat : supportedColorFormats) {
+ caps->addColorFormat(colorFormat);
}
}
}
@@ -423,6 +488,7 @@
}
}
+ std::map<std::string, PixelFormatMap> nameToPixelFormatMap;
for (const Traits& trait : traits) {
C2Component::rank_t rank = trait.rank;
@@ -436,8 +502,9 @@
nameAndAliases.insert(nameAndAliases.begin(), trait.name);
for (const std::string &nameOrAlias : nameAndAliases) {
bool isAlias = trait.name != nameOrAlias;
+ std::shared_ptr<Codec2Client> client;
std::shared_ptr<Codec2Client::Interface> intf =
- Codec2Client::CreateInterfaceByName(nameOrAlias.c_str());
+ Codec2Client::CreateInterfaceByName(nameOrAlias.c_str(), &client);
if (!intf) {
ALOGD("could not create interface for %s'%s'",
isAlias ? "alias " : "",
@@ -631,7 +698,40 @@
caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
}
}
- addSupportedColorFormats(intf, caps.get(), trait, mediaType);
+
+ auto it = nameToPixelFormatMap.find(client->getServiceName());
+ if (it == nameToPixelFormatMap.end()) {
+ it = nameToPixelFormatMap.try_emplace(client->getServiceName()).first;
+ PixelFormatMap &pixelFormatMap = it->second;
+ pixelFormatMap[HAL_PIXEL_FORMAT_YCBCR_420_888] = COLOR_FormatYUV420Flexible;
+ pixelFormatMap[HAL_PIXEL_FORMAT_YCBCR_P010] = COLOR_FormatYUVP010;
+ pixelFormatMap[HAL_PIXEL_FORMAT_RGBA_1010102] = COLOR_Format32bitABGR2101010;
+ pixelFormatMap[HAL_PIXEL_FORMAT_RGBA_FP16] = COLOR_Format64bitABGRFloat;
+
+ std::shared_ptr<C2StoreFlexiblePixelFormatDescriptorsInfo> pixelFormatInfo;
+ std::vector<std::unique_ptr<C2Param>> heapParams;
+ if (client->query(
+ {},
+ {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
+ C2_MAY_BLOCK,
+ &heapParams) == C2_OK
+ && heapParams.size() == 1u) {
+ pixelFormatInfo.reset(C2StoreFlexiblePixelFormatDescriptorsInfo::From(
+ heapParams[0].release()));
+ }
+ if (pixelFormatInfo && *pixelFormatInfo) {
+ for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
+ C2FlexiblePixelFormatDescriptorStruct &desc =
+ pixelFormatInfo->m.values[i];
+ std::optional<int32_t> colorFormat = findFrameworkColorFormat(desc);
+ if (colorFormat) {
+ pixelFormatMap[desc.pixelFormat] = *colorFormat;
+ }
+ }
+ }
+ }
+ addSupportedColorFormats(
+ intf, caps.get(), trait, mediaType, it->second);
}
}
}
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 2213001..b761c35 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -88,7 +88,7 @@
uint32_t planeW = img->mWidth / plane.colSampling;
uint32_t planeH = img->mHeight / plane.rowSampling;
- bool canCopyByRow = (plane.colInc == 1) && (img->mPlane[i].mColInc == 1);
+ bool canCopyByRow = (plane.colInc == bpp) && (img->mPlane[i].mColInc == bpp);
bool canCopyByPlane = canCopyByRow && (plane.rowInc == img->mPlane[i].mRowInc);
if (canCopyByPlane) {
MemCopier<ToMediaImage, 0>::copy(imgRow, viewRow, plane.rowInc * planeH);
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index f557830..93f29ca 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -18,6 +18,9 @@
#define LOG_TAG "Codec2Mapper"
#include <utils/Log.h>
+#include <map>
+#include <optional>
+
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/SurfaceUtils.h>
#include <media/stagefright/foundation/ALookup.h>
@@ -167,6 +170,9 @@
{ C2Config::LEVEL_DV_MAIN_UHD_30, DolbyVisionLevelUhd30 },
{ C2Config::LEVEL_DV_MAIN_UHD_48, DolbyVisionLevelUhd48 },
{ C2Config::LEVEL_DV_MAIN_UHD_60, DolbyVisionLevelUhd60 },
+ { C2Config::LEVEL_DV_MAIN_UHD_120, DolbyVisionLevelUhd120 },
+ { C2Config::LEVEL_DV_MAIN_8K_30, DolbyVisionLevel8k30 },
+ { C2Config::LEVEL_DV_MAIN_8K_60, DolbyVisionLevel8k60 },
// high tiers are not yet supported on android, for now map them to main tier
{ C2Config::LEVEL_DV_HIGH_HD_24, DolbyVisionLevelHd24 },
@@ -178,6 +184,9 @@
{ C2Config::LEVEL_DV_HIGH_UHD_30, DolbyVisionLevelUhd30 },
{ C2Config::LEVEL_DV_HIGH_UHD_48, DolbyVisionLevelUhd48 },
{ C2Config::LEVEL_DV_HIGH_UHD_60, DolbyVisionLevelUhd60 },
+ { C2Config::LEVEL_DV_HIGH_UHD_120, DolbyVisionLevelUhd120 },
+ { C2Config::LEVEL_DV_HIGH_8K_30, DolbyVisionLevel8k30 },
+ { C2Config::LEVEL_DV_HIGH_8K_60, DolbyVisionLevel8k60 },
};
ALookup<C2Config::profile_t, int32_t> sDolbyVisionProfiles = {
@@ -402,6 +411,30 @@
{ C2Config::PROFILE_AV1_0, AV1ProfileMain10HDR10Plus },
};
+// HAL_PIXEL_FORMAT_* -> COLOR_Format*
+ALookup<uint32_t, int32_t> sPixelFormats = {
+ { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, COLOR_FormatSurface },
+
+ // YCBCR_420_888 maps to YUV420Flexible and vice versa
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420Flexible },
+
+ // Fallback matches for YCBCR_420_888
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420Planar },
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420SemiPlanar },
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420PackedPlanar },
+ { HAL_PIXEL_FORMAT_YCBCR_420_888, COLOR_FormatYUV420PackedSemiPlanar },
+
+ // Fallback matches for YUV420Flexible
+ { HAL_PIXEL_FORMAT_YCRCB_420_SP, COLOR_FormatYUV420Flexible },
+ { HAL_PIXEL_FORMAT_YV12, COLOR_FormatYUV420Flexible },
+
+ { HAL_PIXEL_FORMAT_YCBCR_422_SP, COLOR_FormatYUV422PackedSemiPlanar },
+ { HAL_PIXEL_FORMAT_YCBCR_422_I, COLOR_FormatYUV422PackedPlanar },
+ { HAL_PIXEL_FORMAT_YCBCR_P010, COLOR_FormatYUVP010 },
+ { HAL_PIXEL_FORMAT_RGBA_1010102, COLOR_Format32bitABGR2101010 },
+ { HAL_PIXEL_FORMAT_RGBA_FP16, COLOR_Format64bitABGRFloat },
+};
+
/**
* A helper that passes through vendor extension profile and level values.
*/
@@ -975,41 +1008,19 @@
// static
bool C2Mapper::mapPixelFormatFrameworkToCodec(
int32_t frameworkValue, uint32_t *c2Value) {
- switch (frameworkValue) {
- case COLOR_FormatSurface:
- *c2Value = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- return true;
- case COLOR_FormatYUV420Flexible:
- case COLOR_FormatYUV420Planar:
- case COLOR_FormatYUV420SemiPlanar:
- case COLOR_FormatYUV420PackedPlanar:
- case COLOR_FormatYUV420PackedSemiPlanar:
- *c2Value = HAL_PIXEL_FORMAT_YCBCR_420_888;
- return true;
- default:
- // Passthrough
- *c2Value = uint32_t(frameworkValue);
- return true;
+ if (!sPixelFormats.map(frameworkValue, c2Value)) {
+ // passthrough if not mapped
+ *c2Value = uint32_t(frameworkValue);
}
+ return true;
}
// static
bool C2Mapper::mapPixelFormatCodecToFramework(
uint32_t c2Value, int32_t *frameworkValue) {
- switch (c2Value) {
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
- *frameworkValue = COLOR_FormatSurface;
- return true;
- case HAL_PIXEL_FORMAT_YCBCR_422_SP:
- case HAL_PIXEL_FORMAT_YCRCB_420_SP:
- case HAL_PIXEL_FORMAT_YCBCR_422_I:
- case HAL_PIXEL_FORMAT_YCBCR_420_888:
- case HAL_PIXEL_FORMAT_YV12:
- *frameworkValue = COLOR_FormatYUV420Flexible;
- return true;
- default:
- // Passthrough
- *frameworkValue = int32_t(c2Value);
- return true;
+ if (!sPixelFormats.map(c2Value, frameworkValue)) {
+ // passthrough if not mapped
+ *frameworkValue = int32_t(c2Value);
}
+ return true;
}
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index be81c84..27cd1f8 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -73,11 +73,12 @@
"libbase",
"libcutils",
"libdl",
+ "libdmabufheap",
+ "libfmq",
+ "libgralloctypes",
"libhardware",
"libhidlbase",
"libion",
- "libdmabufheap",
- "libfmq",
"liblog",
"libnativewindow",
"libstagefright_foundation",
@@ -92,6 +93,44 @@
],
}
+// public dependency for statically linking to libcodec2_vndk for unit tests
+cc_defaults {
+ name: "libcodec2-static-defaults",
+
+ static_libs: [
+ "liblog",
+ "libion",
+ "libfmq",
+ "libbase",
+ "libutils",
+ "libcutils",
+ "libcodec2",
+ "libhidlbase",
+ "libdmabufheap",
+ "libcodec2_vndk",
+ "libnativewindow",
+ "libcodec2_soft_common",
+ "libsfplugin_ccodec_utils",
+ "libstagefright_foundation",
+ "libstagefright_bufferpool@2.0.1",
+ "libgralloctypes",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.media.bufferpool@2.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ ],
+
+ shared_libs: [
+ "libui",
+ "libdl",
+ "libhardware",
+ "libvndksupport",
+ "libprocessgroup",
+ ],
+}
+
// public dependency for implementing Codec 2 components
cc_defaults {
name: "libcodec2-impl-defaults",
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 6a7f19c..b5200a5 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -20,8 +20,10 @@
#include <mutex>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
#include <android/hardware/graphics/common/1.2/types.h>
#include <cutils/native_handle.h>
+#include <gralloctypes/Gralloc4.h>
#include <hardware/gralloc.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
@@ -29,6 +31,7 @@
#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>
+#include <C2Debug.h>
#include <C2PlatformSupport.h>
using ::android::hardware::hidl_handle;
@@ -230,8 +233,89 @@
}
};
+static
+c2_status_t Gralloc4Mapper_lock(native_handle_t *handle, uint64_t usage, const Rect& bounds,
+ C2PlanarLayout *layout, uint8_t **addr) {
+ GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+
+ std::vector<ui::PlaneLayout> planes;
+ // this method is only supported on Gralloc 4 or later
+ status_t err = mapper.getPlaneLayouts(handle, &planes);
+ if (err != NO_ERROR || planes.empty()) {
+ return C2_CANNOT_DO;
+ }
+
+ uint8_t *pointer = nullptr;
+ err = mapper.lock(handle, usage, bounds, (void **)&pointer, nullptr, nullptr);
+ if (err != NO_ERROR || pointer == nullptr) {
+ return C2_CORRUPTED;
+ }
+
+ using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+ using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+
+ layout->type = C2PlanarLayout::TYPE_YUV;
+ layout->numPlanes = 0;
+ layout->rootPlanes = 0;
+
+ for (const ui::PlaneLayout &plane : planes) {
+ layout->rootPlanes++;
+ uint32_t lastOffsetInBits = 0;
+ uint32_t rootIx = 0;
+
+ for (const PlaneLayoutComponent &component : plane.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
+ return C2_CANNOT_DO;
+ }
+
+ uint32_t rightShiftBits = component.offsetInBits - lastOffsetInBits;
+ uint32_t allocatedDepthInBits = component.sizeInBits + rightShiftBits;
+ C2PlanarLayout::plane_index_t planeId;
+ C2PlaneInfo::channel_t channel;
+
+ switch (static_cast<PlaneLayoutComponentType>(component.type.value)) {
+ case PlaneLayoutComponentType::Y:
+ planeId = C2PlanarLayout::PLANE_Y;
+ channel = C2PlaneInfo::CHANNEL_Y;
+ break;
+ case PlaneLayoutComponentType::CB:
+ planeId = C2PlanarLayout::PLANE_U;
+ channel = C2PlaneInfo::CHANNEL_CB;
+ break;
+ case PlaneLayoutComponentType::CR:
+ planeId = C2PlanarLayout::PLANE_V;
+ channel = C2PlaneInfo::CHANNEL_CR;
+ break;
+ default:
+ return C2_CORRUPTED;
+ }
+
+ addr[planeId] = pointer + plane.offsetInBytes + (component.offsetInBits / 8);
+ layout->planes[planeId] = {
+ channel, // channel
+ static_cast<int32_t>(plane.sampleIncrementInBits / 8), // colInc
+ static_cast<int32_t>(plane.strideInBytes), // rowInc
+ static_cast<uint32_t>(plane.horizontalSubsampling), // mColSampling
+ static_cast<uint32_t>(plane.verticalSubsampling), // mRowSampling
+ allocatedDepthInBits, // allocatedDepth (bits)
+ static_cast<uint32_t>(component.sizeInBits), // bitDepth (bits)
+ rightShiftBits, // rightShift (bits)
+ C2PlaneInfo::NATIVE, // endianness
+ rootIx, // rootIx
+ static_cast<uint32_t>(component.offsetInBits / 8), // offset (bytes)
+ };
+
+ layout->numPlanes++;
+ lastOffsetInBits = component.offsetInBits + component.sizeInBits;
+ rootIx++;
+ }
+ }
+ return C2_OK;
+}
+
} // unnamed namespace
+
native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) {
return C2HandleGralloc::UnwrapNativeHandle(handle);
}
@@ -385,6 +469,10 @@
mBuffer, mWidth, mHeight, mFormat, mGrallocUsage,
mStride, generation, igbp_id, igbp_slot);
}
+
+ // 'NATIVE' on Android means LITTLE_ENDIAN
+ constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE;
+
switch (mFormat) {
case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
// TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
@@ -646,7 +734,7 @@
16, // allocatedDepth
10, // bitDepth
6, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
+ kEndianness, // endianness
C2PlanarLayout::PLANE_Y, // rootIx
0, // offset
};
@@ -659,7 +747,7 @@
16, // allocatedDepth
10, // bitDepth
6, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
+ kEndianness, // endianness
C2PlanarLayout::PLANE_U, // rootIx
0, // offset
};
@@ -672,7 +760,7 @@
16, // allocatedDepth
10, // bitDepth
6, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
+ kEndianness, // endianness
C2PlanarLayout::PLANE_U, // rootIx
2, // offset
};
@@ -680,9 +768,15 @@
}
default: {
- // We don't know what it is, but let's try to lock it.
+ // We don't know what it is, let's try to lock it with gralloc4
android_ycbcr ycbcrLayout;
+ c2_status_t status = Gralloc4Mapper_lock(
+ const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
+ if (status == C2_OK) {
+ break;
+ }
+ // fallback to lockYCbCr
status_t err = GraphicBufferMapper::get().lockYCbCr(
const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
diff --git a/media/codecs/mp3dec/Android.bp b/media/codecs/mp3dec/Android.bp
index 1ab0511..6659ea5 100644
--- a/media/codecs/mp3dec/Android.bp
+++ b/media/codecs/mp3dec/Android.bp
@@ -47,6 +47,10 @@
name: "libstagefright_mp3dec",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
host_supported:true,
srcs: [
diff --git a/media/extractors/Android.bp b/media/extractors/Android.bp
index 66585da..51d41fb 100644
--- a/media/extractors/Android.bp
+++ b/media/extractors/Android.bp
@@ -28,8 +28,12 @@
"liblog",
],
- // extractors are supposed to work on Q(29)
+ // extractors are expected to run on Q(29)
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
relative_install_path: "extractors",
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 8836c47..fb935b6 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1127,10 +1127,10 @@
void *data;
size_t size;
- if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2,
+ if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0,
&data, &size)
- && size >= 5) {
- const uint8_t *ptr = (const uint8_t *)data;
+ && size >= 24) {
+ const uint8_t *ptr = (const uint8_t *)data + (size - 24);
const uint8_t profile = ptr[2] >> 1;
const uint8_t bl_compatibility_id = (ptr[4]) >> 4;
bool create_two_tracks = false;
@@ -1147,13 +1147,15 @@
track_b->timescale = mLastTrack->timescale;
track_b->sampleTable = mLastTrack->sampleTable;
- track_b->includes_expensive_metadata = mLastTrack->includes_expensive_metadata;
+ track_b->includes_expensive_metadata =
+ mLastTrack->includes_expensive_metadata;
track_b->skipTrack = mLastTrack->skipTrack;
track_b->elst_needs_processing = mLastTrack->elst_needs_processing;
track_b->elst_media_time = mLastTrack->elst_media_time;
track_b->elst_segment_duration = mLastTrack->elst_segment_duration;
track_b->elst_shift_start_ticks = mLastTrack->elst_shift_start_ticks;
- track_b->elst_initial_empty_edit_ticks = mLastTrack->elst_initial_empty_edit_ticks;
+ track_b->elst_initial_empty_edit_ticks =
+ mLastTrack->elst_initial_empty_edit_ticks;
track_b->subsample_encryption = mLastTrack->subsample_encryption;
track_b->mTx3gBuffer = mLastTrack->mTx3gBuffer;
@@ -1166,11 +1168,11 @@
mLastTrack->next = track_b;
track_b->next = NULL;
- // we want to remove the csd-2 key from the metadata, but
+ // we want to remove the csd-0 key from the metadata, but
// don't have an AMediaFormat_* function to do so. Settle
- // for replacing this csd-2 with an empty csd-2.
+ // for replacing this csd-0 with an empty csd-0.
uint8_t emptybuffer[8] = {};
- AMediaFormat_setBuffer(track_b->meta, AMEDIAFORMAT_KEY_CSD_2,
+ AMediaFormat_setBuffer(track_b->meta, AMEDIAFORMAT_KEY_CSD_0,
emptybuffer, 0);
if (4 == profile || 7 == profile || 8 == profile ) {
@@ -1182,6 +1184,8 @@
} else if (10 == profile) {
AMediaFormat_setString(track_b->meta,
AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+ AMediaFormat_setBuffer(track_b->meta, AMEDIAFORMAT_KEY_CSD_0,
+ data, size - 24);
} // Should never get to else part
mLastTrack = track_b;
@@ -2591,9 +2595,11 @@
*offset += chunk_size;
break;
}
- case FOURCC("dvcC"):
- case FOURCC("dvvC"): {
+ case FOURCC("dvcC"):
+ case FOURCC("dvvC"):
+ case FOURCC("dvwC"):
+ {
if (chunk_data_size != 24) {
return ERROR_MALFORMED;
}
@@ -2612,14 +2618,29 @@
if (mLastTrack == NULL)
return ERROR_MALFORMED;
- AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2,
- buffer.get(), chunk_data_size);
+ void *data = nullptr;
+ size_t size = 0;
+ if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
+ //if csd-0 is already present, then append dvcc
+ auto csd0_dvcc = heapbuffer<uint8_t>(size + chunk_data_size);
+
+ memcpy(csd0_dvcc.get(), data, size);
+ memcpy(csd0_dvcc.get() + size, buffer.get(), chunk_data_size);
+
+ AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0,
+ csd0_dvcc.get(), size + chunk_data_size);
+ } else {
+ //if not set csd-0 directly
+ AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_0,
+ buffer.get(), chunk_data_size);
+ }
AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME,
MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
*offset += chunk_size;
break;
}
+
case FOURCC("d263"):
{
*offset += chunk_size;
@@ -4458,7 +4479,6 @@
if (!AMediaFormat_getString(track->meta, AMEDIAFORMAT_KEY_MIME, &mime)) {
return NULL;
}
-
sp<ItemTable> itemTable;
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
void *data;
@@ -4491,14 +4511,14 @@
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
void *data;
size_t size;
- if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)
+ || size < 24) {
return NULL;
}
- const uint8_t *ptr = (const uint8_t *)data;
-
+ const uint8_t *ptr = (const uint8_t *)data + (size - 24);
// dv_major.dv_minor Should be 1.0 or 2.1
- if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
+ if ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)) {
return NULL;
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)
@@ -4576,7 +4596,7 @@
return ERROR_MALFORMED;
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
- if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
return ERROR_MALFORMED;
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
@@ -5152,11 +5172,11 @@
ALOGV("%s DolbyVision stream detected", __FUNCTION__);
void *data;
size_t size;
- CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_2, &data, &size));
+ CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_0, &data, &size));
- const uint8_t *ptr = (const uint8_t *)data;
+ const uint8_t *ptr = (const uint8_t *)data + (size - 24);
- CHECK(size == 24);
+ CHECK(size >= 24);
// dv_major.dv_minor Should be 1.0 or 2.1
CHECK(!((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)));
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index be39527..33e2848 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -11,6 +11,10 @@
name: "libaudioclient_headers",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
host_supported: true,
header_libs: [
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 86139c7..be81481 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1972,6 +1972,19 @@
return result.value_or(false);
}
+bool AudioSystem::isUltrasoundSupported() {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return false;
+
+ auto result = [&]() -> ConversionResult<bool> {
+ bool retVal;
+ RETURN_IF_ERROR(
+ statusTFromBinderStatus(aps->isUltrasoundSupported(&retVal)));
+ return retVal;
+ }();
+ return result.value_or(false);
+}
+
status_t AudioSystem::getHwOffloadFormatsSupportedForBluetoothMedia(
audio_devices_t device, std::vector<audio_format_t>* formats) {
if (formats == nullptr) {
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index b1a9d94..c3e8dfb 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -312,6 +312,8 @@
boolean isHapticPlaybackSupported();
+ boolean isUltrasoundSupported();
+
AudioProductStrategy[] listAudioProductStrategies();
int /* product_strategy_t */ getProductStrategyFromAudioAttributes(in AudioAttributesEx aa,
boolean fallbackOnDefault);
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 09127fb..4280a6a 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -444,6 +444,8 @@
static bool isHapticPlaybackSupported();
+ static bool isUltrasoundSupported();
+
static status_t listAudioProductStrategies(AudioProductStrategyVector &strategies);
static status_t getProductStrategyFromAudioAttributes(
const AudioAttributes &aa, product_strategy_t &productStrategy,
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index 727b86f..159f898 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -11,6 +11,10 @@
name: "libaudiofoundation_headers",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
export_include_dirs: ["include"],
header_libs: [
diff --git a/media/libheadtracking/Android.bp b/media/libheadtracking/Android.bp
index b0563e2..1d41889 100644
--- a/media/libheadtracking/Android.bp
+++ b/media/libheadtracking/Android.bp
@@ -14,6 +14,7 @@
"HeadTrackingProcessor.cpp",
"ModeSelector.cpp",
"Pose.cpp",
+ "PoseBias.cpp",
"PoseDriftCompensator.cpp",
"PoseRateLimiter.cpp",
"QuaternionUtil.cpp",
@@ -67,6 +68,7 @@
"HeadTrackingProcessor-test.cpp",
"ModeSelector-test.cpp",
"Pose-test.cpp",
+ "PoseBias-test.cpp",
"PoseDriftCompensator-test.cpp",
"PoseRateLimiter-test.cpp",
"QuaternionUtil-test.cpp",
diff --git a/media/libheadtracking/HeadTrackingProcessor.cpp b/media/libheadtracking/HeadTrackingProcessor.cpp
index f2f15df..71fae8a 100644
--- a/media/libheadtracking/HeadTrackingProcessor.cpp
+++ b/media/libheadtracking/HeadTrackingProcessor.cpp
@@ -17,7 +17,7 @@
#include "media/HeadTrackingProcessor.h"
#include "ModeSelector.h"
-#include "PoseDriftCompensator.h"
+#include "PoseBias.h"
#include "QuaternionUtil.h"
#include "ScreenHeadFusion.h"
#include "StillnessDetector.h"
@@ -33,14 +33,6 @@
public:
HeadTrackingProcessorImpl(const Options& options, HeadTrackingMode initialMode)
: mOptions(options),
- mHeadPoseDriftCompensator(PoseDriftCompensator::Options{
- .translationalDriftTimeConstant = options.translationalDriftTimeConstant,
- .rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
- }),
- mScreenPoseDriftCompensator(PoseDriftCompensator::Options{
- .translationalDriftTimeConstant = options.translationalDriftTimeConstant,
- .rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
- }),
mHeadStillnessDetector(StillnessDetector::Options{
.defaultValue = false,
.windowDuration = options.autoRecenterWindowDuration,
@@ -65,7 +57,7 @@
const Twist3f& headTwist) override {
Pose3f predictedWorldToHead =
worldToHead * integrate(headTwist, mOptions.predictionDuration);
- mHeadPoseDriftCompensator.setInput(timestamp, predictedWorldToHead);
+ mHeadPoseBias.setInput(predictedWorldToHead);
mHeadStillnessDetector.setInput(timestamp, predictedWorldToHead);
mWorldToHeadTimestamp = timestamp;
}
@@ -78,7 +70,7 @@
}
Pose3f worldToLogicalScreen = worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle));
- mScreenPoseDriftCompensator.setInput(timestamp, worldToLogicalScreen);
+ mScreenPoseBias.setInput(worldToLogicalScreen);
mScreenStillnessDetector.setInput(timestamp, worldToLogicalScreen);
mWorldToScreenTimestamp = timestamp;
}
@@ -94,7 +86,7 @@
void calculate(int64_t timestamp) override {
// Handle the screen first, since it might trigger a recentering of the head.
if (mWorldToScreenTimestamp.has_value()) {
- const Pose3f worldToLogicalScreen = mScreenPoseDriftCompensator.getOutput();
+ const Pose3f worldToLogicalScreen = mScreenPoseBias.getOutput();
bool screenStable = mScreenStillnessDetector.calculate(timestamp);
mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
// Whenever the screen is unstable, recenter the head pose.
@@ -107,11 +99,11 @@
// Handle head.
if (mWorldToHeadTimestamp.has_value()) {
- Pose3f worldToHead = mHeadPoseDriftCompensator.getOutput();
+ Pose3f worldToHead = mHeadPoseBias.getOutput();
// Auto-recenter.
if (mHeadStillnessDetector.calculate(timestamp)) {
recenter(true, false);
- worldToHead = mHeadPoseDriftCompensator.getOutput();
+ worldToHead = mHeadPoseBias.getOutput();
}
mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
@@ -142,11 +134,11 @@
void recenter(bool recenterHead, bool recenterScreen) override {
if (recenterHead) {
- mHeadPoseDriftCompensator.recenter();
+ mHeadPoseBias.recenter();
mHeadStillnessDetector.reset();
}
if (recenterScreen) {
- mScreenPoseDriftCompensator.recenter();
+ mScreenPoseBias.recenter();
mScreenStillnessDetector.reset();
}
@@ -169,8 +161,8 @@
std::optional<int64_t> mWorldToHeadTimestamp;
std::optional<int64_t> mWorldToScreenTimestamp;
Pose3f mHeadToStagePose;
- PoseDriftCompensator mHeadPoseDriftCompensator;
- PoseDriftCompensator mScreenPoseDriftCompensator;
+ PoseBias mHeadPoseBias;
+ PoseBias mScreenPoseBias;
StillnessDetector mHeadStillnessDetector;
StillnessDetector mScreenStillnessDetector;
ScreenHeadFusion mScreenHeadFusion;
diff --git a/media/libheadtracking/PoseBias-test.cpp b/media/libheadtracking/PoseBias-test.cpp
new file mode 100644
index 0000000..9f42a2c
--- /dev/null
+++ b/media/libheadtracking/PoseBias-test.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "PoseBias.h"
+#include "QuaternionUtil.h"
+#include "TestUtil.h"
+
+namespace android {
+namespace media {
+namespace {
+
+using Eigen::Quaternionf;
+using Eigen::Vector3f;
+
+TEST(PoseBias, Initial) {
+ PoseBias bias;
+ EXPECT_EQ(bias.getOutput(), Pose3f());
+}
+
+TEST(PoseBias, Basic) {
+ Pose3f pose1({1, 2, 3}, Quaternionf::UnitRandom());
+ Pose3f pose2({4, 5, 6}, Quaternionf::UnitRandom());
+
+ PoseBias bias;
+ bias.setInput(pose1);
+ EXPECT_EQ(pose1, bias.getOutput());
+ bias.recenter();
+ EXPECT_EQ(bias.getOutput(), Pose3f());
+ bias.setInput(pose2);
+ EXPECT_EQ(bias.getOutput(), pose1.inverse() * pose2);
+ bias.recenter();
+ EXPECT_EQ(bias.getOutput(), Pose3f());
+}
+
+} // namespace
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/PoseBias.cpp b/media/libheadtracking/PoseBias.cpp
new file mode 100644
index 0000000..33afca6
--- /dev/null
+++ b/media/libheadtracking/PoseBias.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "PoseBias.h"
+
+namespace android {
+namespace media {
+
+void PoseBias::setInput(const Pose3f& input) {
+ mLastWorldToInput = input;
+}
+
+void PoseBias::recenter() {
+ mBiasToWorld = mLastWorldToInput.inverse();
+}
+
+Pose3f PoseBias::getOutput() const {
+ return mBiasToWorld * mLastWorldToInput;
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/PoseBias.h b/media/libheadtracking/PoseBias.h
new file mode 100644
index 0000000..9acb49d
--- /dev/null
+++ b/media/libheadtracking/PoseBias.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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.
+ */
+#pragma once
+
+#include "media/Pose.h"
+
+namespace android {
+namespace media {
+
+/**
+ * Biasing for a stream of poses.
+ *
+ * This filter takes a stream of poses and at any time during the stream, can change the frame of
+ * reference for the stream to be that of the last pose received, via the recenter() operation.
+ *
+ * Typical usage:
+ * PoseBias bias;
+ *
+ * bias.setInput(...);
+ * output = bias.getOutput();
+ * bias.setInput(...);
+ * output = bias.getOutput();
+ * bias.setInput(...);
+ * output = bias.getOutput();
+ * bias.recenter(); // Reference frame is now equal to the last input.
+ * output = bias.getOutput(); // This is now the identity pose.
+ *
+ * There doesn't need to be a 1:1 correspondence between setInput() and getOutput() calls.
+ * The initial bias point is identity.
+ *
+ * This implementation is thread-compatible, but not thread-safe.
+ */
+class PoseBias {
+ public:
+ void setInput(const Pose3f& input);
+
+ void recenter();
+
+ Pose3f getOutput() const;
+
+ private:
+ Pose3f mLastWorldToInput;
+ Pose3f mBiasToWorld;
+};
+
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/PoseProcessingGraph.png b/media/libheadtracking/PoseProcessingGraph.png
index 2b4ea68..325b667 100644
--- a/media/libheadtracking/PoseProcessingGraph.png
+++ b/media/libheadtracking/PoseProcessingGraph.png
Binary files differ
diff --git a/media/libheadtracking/README.md b/media/libheadtracking/README.md
index 5ec157b..44f7bb2 100644
--- a/media/libheadtracking/README.md
+++ b/media/libheadtracking/README.md
@@ -115,11 +115,9 @@
#### World
It is sometimes convenient to use an intermediate frame when dealing with
-head-to-screen transforms. The “world” frame is an arbitrary frame of reference
-in the physical world, relative to which we can measure the head pose and screen
-pose. In (very common) cases when we can’t establish such an absolute frame, we
-can take each measurement relative to a separate, arbitrary frame and high-pass
-the result.
+head-to-screen transforms. The “world” frame is a frame of reference in the
+physical world, relative to which we can measure the head pose and screen pose.
+It is arbitrary, but expected to be stable (fixed).
## Processing Description
@@ -133,15 +131,10 @@
The Predictor block gets pose + twist (pose derivative) and extrapolates to
obtain a predicted head pose (w/ given latency).
-### Drift / Bias Compensator
+### Bias
-The Drift / Bias Compensator blocks serve two purposes:
-
-- Compensate for floating reference axes by applying a high-pass filter, which
- slowly pulls the pose toward identity.
-- Establish the reference frame for the poses by having the ability to set the
- current pose as the reference for future poses (recentering). Effectively,
- this is resetting the filter state to identity.
+The Bias blocks establish the reference frame for the poses by having the
+ability to set the current pose as the reference for future poses (recentering).
### Orientation Compensation
@@ -157,7 +150,7 @@
module may indicate that the user is likely not in front of the screen via the
“valid” output.
-## Stillness Detector
+### Stillness Detector
The stillness detector blocks detect when their incoming pose stream has been
stable for a given amount of time (allowing for a configurable amount of error).
diff --git a/media/libheadtracking/SensorPoseProvider.cpp b/media/libheadtracking/SensorPoseProvider.cpp
index 0e96b03..f3f9b77 100644
--- a/media/libheadtracking/SensorPoseProvider.cpp
+++ b/media/libheadtracking/SensorPoseProvider.cpp
@@ -351,7 +351,7 @@
Eigen::Vector3f rotation = {event.head_tracker.rx, event.head_tracker.ry,
event.head_tracker.rz};
Eigen::Vector3f twist = {event.head_tracker.vx, event.head_tracker.vy,
- event.head_tracker.rz};
+ event.head_tracker.vz};
Eigen::Quaternionf quat = rotationVectorToQuaternion(rotation);
bool isNewReference =
!discontinutyCount->has_value() ||
diff --git a/media/libheadtracking/include/media/HeadTrackingProcessor.h b/media/libheadtracking/include/media/HeadTrackingProcessor.h
index 2af560e..1744be3 100644
--- a/media/libheadtracking/include/media/HeadTrackingProcessor.h
+++ b/media/libheadtracking/include/media/HeadTrackingProcessor.h
@@ -38,8 +38,6 @@
struct Options {
float maxTranslationalVelocity = std::numeric_limits<float>::infinity();
float maxRotationalVelocity = std::numeric_limits<float>::infinity();
- float translationalDriftTimeConstant = std::numeric_limits<float>::infinity();
- float rotationalDriftTimeConstant = std::numeric_limits<float>::infinity();
int64_t freshnessTimeout = std::numeric_limits<int64_t>::max();
float predictionDuration = 0;
int64_t autoRecenterWindowDuration = std::numeric_limits<int64_t>::max();
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 4a2523f..2dd5784 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -19,6 +19,10 @@
name: "libmedia_headers",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
export_include_dirs: ["include"],
header_libs: [
@@ -214,6 +218,11 @@
name: "libmedia_midiiowrapper",
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+
srcs: ["MidiIoWrapper.cpp"],
@@ -441,6 +450,6 @@
apex_available: [
"//apex_available:platform",
- "com.android.media"
+ "com.android.media",
],
}
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 67d33fa..85768bd 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -20,12 +20,14 @@
#define LOG_TAG "MediaProfiles"
#include <stdlib.h>
+#include <utils/misc.h>
#include <utils/Log.h>
#include <utils/Vector.h>
#include <cutils/properties.h>
#include <expat.h>
#include <media/MediaProfiles.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <OMX_Video.h>
#include <sys/stat.h>
@@ -86,7 +88,24 @@
{"h263", VIDEO_ENCODER_H263},
{"h264", VIDEO_ENCODER_H264},
{"m4v", VIDEO_ENCODER_MPEG_4_SP},
- {"hevc", VIDEO_ENCODER_HEVC}
+ {"vp8", VIDEO_ENCODER_VP8},
+ {"hevc", VIDEO_ENCODER_HEVC},
+ {"vp9", VIDEO_ENCODER_VP9},
+ {"dolbyvision", VIDEO_ENCODER_DOLBY_VISION},
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sChromaSubsamplingNameMap[] = {
+ {"yuv 4:2:0", CHROMA_SUBSAMPLING_YUV_420},
+ {"yuv 4:2:2", CHROMA_SUBSAMPLING_YUV_422},
+ {"yuv 4:4:4", CHROMA_SUBSAMPLING_YUV_444},
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sHdrFormatNameMap[] = {
+ {"sdr", HDR_FORMAT_NONE},
+ {"hlg", HDR_FORMAT_HLG},
+ {"hdr10", HDR_FORMAT_HDR10},
+ {"hdr10+", HDR_FORMAT_HDR10PLUS},
+ {"dolbyvision", HDR_FORMAT_DOLBY_VISION},
};
const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
@@ -164,12 +183,18 @@
MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
{
ALOGV("video codec:");
- ALOGV("codec = %d", codec.mCodec);
+ ALOGV("codec = %d (%s)", codec.mCodec,
+ findNameForTag(sVideoEncoderNameMap, NELEM(sVideoEncoderNameMap), codec.mCodec));
ALOGV("bit rate: %d", codec.mBitRate);
ALOGV("frame width: %d", codec.mFrameWidth);
ALOGV("frame height: %d", codec.mFrameHeight);
ALOGV("frame rate: %d", codec.mFrameRate);
ALOGV("profile: %d", codec.mProfile);
+ ALOGV("chroma: %s", findNameForTag(sChromaSubsamplingNameMap, NELEM(sChromaSubsamplingNameMap),
+ codec.mChromaSubsampling));
+ ALOGV("bit depth: %d", codec.mBitDepth);
+ ALOGV("hdr format: %s", findNameForTag(sHdrFormatNameMap, NELEM(sHdrFormatNameMap),
+ codec.mHdrFormat));
}
/*static*/ void
@@ -232,6 +257,155 @@
return tag;
}
+/*static*/ const char *
+MediaProfiles::findNameForTag(
+ const MediaProfiles::NameToTagMap *map, size_t nMappings, int tag, const char *def_)
+{
+ for (size_t i = 0; i < nMappings; ++i) {
+ if (map[i].tag == tag) {
+ return map[i].name;
+ }
+ }
+ return def_;
+}
+
+/*static*/ bool
+MediaProfiles::detectAdvancedVideoProfile(
+ video_encoder codec, int profile,
+ chroma_subsampling *chroma, int *bitDepth, hdr_format *hdr)
+{
+ // default values
+ *chroma = CHROMA_SUBSAMPLING_YUV_420;
+ *bitDepth = 8;
+ *hdr = HDR_FORMAT_NONE;
+
+ switch (codec) {
+ case VIDEO_ENCODER_H263:
+ case VIDEO_ENCODER_MPEG_4_SP:
+ case VIDEO_ENCODER_VP8:
+ // these are always 4:2:0 SDR 8-bit
+ return true;
+
+ case VIDEO_ENCODER_H264:
+ switch (profile) {
+ case AVCProfileBaseline:
+ case AVCProfileConstrainedBaseline:
+ case AVCProfileMain:
+ case AVCProfileExtended:
+ case AVCProfileHigh:
+ case AVCProfileConstrainedHigh:
+ return true;
+ case AVCProfileHigh10:
+ // returning false here as this could be an HLG stream
+ *bitDepth = 10;
+ return false;
+ case AVCProfileHigh422:
+ *chroma = CHROMA_SUBSAMPLING_YUV_422;
+ // returning false here as bit-depth could be 8 or 10
+ return false;
+ case AVCProfileHigh444:
+ *chroma = CHROMA_SUBSAMPLING_YUV_444;
+ // returning false here as bit-depth could be 8 or 10
+ return false;
+ default:
+ return false;
+ }
+ // flow does not get here
+
+ case VIDEO_ENCODER_HEVC:
+ switch (profile) {
+ case HEVCProfileMain:
+ return true;
+ case HEVCProfileMain10:
+ *bitDepth = 10;
+ // returning false here as this could be an HLG stream
+ return false;
+ case HEVCProfileMain10HDR10:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10;
+ return true;
+ case HEVCProfileMain10HDR10Plus:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10PLUS;
+ return true;
+ default:
+ return false;
+ }
+ // flow does not get here
+
+ case VIDEO_ENCODER_VP9:
+ switch (profile) {
+ case VP9Profile0:
+ return true;
+ case VP9Profile2:
+ // this is always 10-bit on Android */
+ *bitDepth = 10;
+ // returning false here as this could be an HLG stream
+ return false;
+ case VP9Profile2HDR:
+ // this is always 10-bit on Android */
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10;
+ return true;
+ case VP9Profile2HDR10Plus:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10PLUS;
+ return true;
+ default:
+ return false;
+ }
+ // flow does not get here
+
+ case VIDEO_ENCODER_DOLBY_VISION:
+ {
+ // for Dolby Vision codec we always assume 10-bit DV
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_DOLBY_VISION;
+
+ switch (profile) {
+ case DolbyVisionProfileDvheDer /* profile 2 deprecated */:
+ case DolbyVisionProfileDvheDen /* profile 3 deprecated */:
+ case DolbyVisionProfileDvavPer /* profile 0 deprecated */:
+ case DolbyVisionProfileDvavPen /* profile 1 deprecated */:
+ case DolbyVisionProfileDvheDtr /* dvhe.04 */:
+ case DolbyVisionProfileDvheStn /* dvhe.05 */:
+ case DolbyVisionProfileDvheDth /* profile 6 deprecated */:
+ case DolbyVisionProfileDvheDtb /* dvhe.07 */:
+ case DolbyVisionProfileDvheSt /* dvhe.08 */:
+ case DolbyVisionProfileDvavSe /* dvav.09 */:
+ case DolbyVisionProfileDvav110 /* dvav1.10 */:
+ return true;
+ default:
+ return false;
+ }
+ // flow does not get here
+ }
+
+ case VIDEO_ENCODER_AV1:
+ switch (profile) {
+ case AV1ProfileMain10:
+ *bitDepth = 10;
+ // returning false here as this could be an HLG stream
+ return false;
+ case AV1ProfileMain10HDR10:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10;
+ return true;
+ case AV1ProfileMain10HDR10Plus:
+ *bitDepth = 10;
+ *hdr = HDR_FORMAT_HDR10PLUS;
+ return true;
+ default:
+ return false;
+ }
+ // flow does not get here
+
+ default:
+ return false;
+ }
+ // flow does not get here
+}
+
/*static*/ void
MediaProfiles::createVideoCodec(const char **atts, size_t natts, MediaProfiles *profiles)
{
@@ -250,13 +424,56 @@
}
int profile = -1;
- if (natts >= 12 && !strcmp("profile", atts[10])) {
- profile = atoi(atts[11]);
+ chroma_subsampling chroma = CHROMA_SUBSAMPLING_YUV_420;
+ int bitDepth = 8;
+ hdr_format hdr = HDR_FORMAT_NONE;
+ if (codec == VIDEO_ENCODER_DOLBY_VISION) {
+ bitDepth = 10;
+ hdr = HDR_FORMAT_DOLBY_VISION;
}
- VideoCodec videoCodec {
+ if (natts >= 12 && !strcmp("profile", atts[10])) {
+ profile = atoi(atts[11]);
+ if (!detectAdvancedVideoProfile(
+ (video_encoder)codec, profile, &chroma, &bitDepth, &hdr)) {
+ // if not detected read values from the attributes
+ for (size_t ix = 12; natts >= ix + 2; ix += 2) {
+ if (!strcmp("chroma", atts[ix])) {
+ int chromaTag = findTagForName(sChromaSubsamplingNameMap,
+ NELEM(sChromaSubsamplingNameMap), atts[ix + 1]);
+ if (chromaTag == -1) {
+ ALOGE("MediaProfiles::createVideoCodec invalid chroma %s", atts[ix + 1]);
+ return;
+ } else {
+ chroma = (chroma_subsampling)chromaTag;
+ }
+ } else if (!strcmp("bitDepth", atts[ix])) {
+ bitDepth = atoi(atts[ix + 1]);
+ if (bitDepth < 8 || bitDepth > 16) {
+ ALOGE("MediaProfiles::createVideoCodec invalid bidDepth %s", atts[ix + 1]);
+ return;
+ }
+ } else if (!strcmp("hdr", atts[ix])) {
+ int hdrTag = findTagForName(sHdrFormatNameMap,
+ NELEM(sHdrFormatNameMap), atts[ix + 1]);
+ if (hdrTag == -1) {
+ ALOGE("MediaProfiles::createVideoCodec invalid hdr %s", atts[ix + 1]);
+ return;
+ } else {
+ hdr = (hdr_format)hdrTag;
+ }
+ } else {
+ // ignoring here. TODO: rewrite this whole file to ignore invalid attrs
+ ALOGD("MediaProfiles::createVideoCodec ignoring invalid attr %s", atts[ix]);
+ }
+ }
+ }
+ }
+
+ VideoCodec videoCodec{
static_cast<video_encoder>(codec),
- atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), profile };
+ atoi(atts[3]) /* bitRate */, atoi(atts[5]) /* width */, atoi(atts[7]) /* height */,
+ atoi(atts[9]) /* frameRate */, profile, chroma, bitDepth, hdr };
logVideoCodec(videoCodec);
size_t nCamcorderProfiles;
diff --git a/media/libmedia/include/media/MediaProfiles.h b/media/libmedia/include/media/MediaProfiles.h
index 4a898e2..e75b694 100644
--- a/media/libmedia/include/media/MediaProfiles.h
+++ b/media/libmedia/include/media/MediaProfiles.h
@@ -81,6 +81,19 @@
AUDIO_DECODER_WMA,
};
+enum chroma_subsampling {
+ CHROMA_SUBSAMPLING_YUV_420,
+ CHROMA_SUBSAMPLING_YUV_422,
+ CHROMA_SUBSAMPLING_YUV_444,
+};
+
+enum hdr_format {
+ HDR_FORMAT_NONE,
+ HDR_FORMAT_HLG,
+ HDR_FORMAT_HDR10,
+ HDR_FORMAT_HDR10PLUS,
+ HDR_FORMAT_DOLBY_VISION,
+};
class MediaProfiles
{
@@ -117,13 +130,19 @@
* @param profile codec profile (for MediaCodec) or -1 for none
*/
VideoCodec(video_encoder codec, int bitrate, int frameWidth, int frameHeight, int frameRate,
- int profile = -1)
+ int profile = -1,
+ chroma_subsampling chroma = CHROMA_SUBSAMPLING_YUV_420,
+ int bitDepth = 8,
+ hdr_format hdr = HDR_FORMAT_NONE)
: mCodec(codec),
mBitRate(bitrate),
mFrameWidth(frameWidth),
mFrameHeight(frameHeight),
mFrameRate(frameRate),
- mProfile(profile) {
+ mProfile(profile),
+ mChromaSubsampling(chroma),
+ mBitDepth(bitDepth),
+ mHdrFormat(hdr) {
}
VideoCodec(const VideoCodec&) = default;
@@ -160,6 +179,21 @@
return mProfile;
}
+ /** Returns the chroma subsampling. */
+ chroma_subsampling getChromaSubsampling() const {
+ return mChromaSubsampling;
+ }
+
+ /** Returns the bit depth. */
+ int getBitDepth() const {
+ return mBitDepth;
+ }
+
+ /** Returns the chroma subsampling. */
+ hdr_format getHdrFormat() const {
+ return mHdrFormat;
+ }
+
private:
video_encoder mCodec;
int mBitRate;
@@ -167,6 +201,9 @@
int mFrameHeight;
int mFrameRate;
int mProfile;
+ chroma_subsampling mChromaSubsampling;
+ int mBitDepth;
+ hdr_format mHdrFormat;
friend class MediaProfiles;
};
@@ -533,6 +570,39 @@
static int findTagForName(const NameToTagMap *map, size_t nMappings, const char *name);
/**
+ * Finds the string representation for an integer enum tag.
+ *
+ * This is the reverse for findTagForName
+ *
+ * @param map the name-to-tag map to search
+ * @param nMappings the number of mappings in |map|
+ * @param tag the enum value to find
+ * @param def_ the return value if the enum is not found
+ *
+ * @return the string name corresponding to |tag| or |def_| if not found.
+ */
+ static const char *findNameForTag(
+ const NameToTagMap *map, size_t nMappings,
+ int tag, const char *def_ = "(unknown)");
+
+ /**
+ * Updates the chroma subsampling, bit-depth and hdr-format for
+ * advanced codec profiles.
+ *
+ * @param codec the video codec type
+ * @param profile the MediaCodec profile
+ * @param chroma pointer to the chroma subsampling output
+ * @param bitDepth pointer to the bit depth output
+ * @param hdr pointer to the hdr format output
+ *
+ * @return true, if the profile fully determined chroma, bit-depth and hdr-format, false
+ * otherwise.
+ */
+ static bool detectAdvancedVideoProfile(
+ video_encoder codec, int profile,
+ chroma_subsampling *chroma, int *bitDepth, hdr_format *hdr);
+
+ /**
* Check on existing profiles with the following criteria:
* 1. Low quality profile must have the lowest video
* resolution product (width x height)
@@ -549,6 +619,8 @@
// Mappings from name (for instance, codec name) to enum value
static const NameToTagMap sVideoEncoderNameMap[];
+ static const NameToTagMap sChromaSubsamplingNameMap[];
+ static const NameToTagMap sHdrFormatNameMap[];
static const NameToTagMap sAudioEncoderNameMap[];
static const NameToTagMap sFileFormatMap[];
static const NameToTagMap sVideoDecoderNameMap[];
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index d54ff32..dd18144 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -108,7 +108,9 @@
VIDEO_ENCODER_MPEG_4_SP = 3,
VIDEO_ENCODER_VP8 = 4,
VIDEO_ENCODER_HEVC = 5,
-
+ VIDEO_ENCODER_VP9 = 6,
+ VIDEO_ENCODER_DOLBY_VISION = 7,
+ VIDEO_ENCODER_AV1 = 8,
VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
};
diff --git a/media/libmediaformatshaper/Android.bp b/media/libmediaformatshaper/Android.bp
index bdd1465..7e8f351 100644
--- a/media/libmediaformatshaper/Android.bp
+++ b/media/libmediaformatshaper/Android.bp
@@ -95,10 +95,10 @@
min_sdk_version: "29",
- apex_available: [
- "//apex_available:platform",
- "com.android.media",
- ],
+ // the library lives only in the module
+ // framework accesses with dlopen() and uses "libmediaformatshaper_headers" so both
+ // sides track to the interface.
+ apex_available: ["com.android.media"],
version_script: "exports.lds",
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
index 71b8c2b..71a3168 100644
--- a/media/libmediaplayerservice/nuplayer/Android.bp
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -76,6 +76,7 @@
"libmedia",
"libmediadrm",
"libpowermanager",
+ "android.hardware.drm-V1-ndk",
],
static_libs: [
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 01cb9b3..5da32c9 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -35,6 +35,7 @@
#include <media/stagefright/FrameCaptureProcessor.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
@@ -192,6 +193,13 @@
*dstBpp = 4;
return true;
}
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ {
+ *dstFormat = (OMX_COLOR_FORMATTYPE)COLOR_Format32bitABGR2101010;
+ *captureFormat = ui::PixelFormat::RGBA_1010102;
+ *dstBpp = 4;
+ return true;
+ }
default:
{
ALOGE("Unsupported color format: %d", colorFormat);
@@ -523,8 +531,12 @@
return NULL;
}
- // TODO: Use Flexible color instead
- videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ if (dstFormat() == COLOR_Format32bitABGR2101010) {
+ videoFormat->setInt32("color-format", COLOR_FormatYUVP010);
+ } else {
+ // TODO: Use Flexible color instead
+ videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ }
// For the thumbnail extraction case, try to allocate single buffer in both
// input and output ports, if seeking to a sync frame. NOTE: This request may
@@ -632,6 +644,11 @@
crop_bottom = height - 1;
}
+ int32_t slice_height;
+ if (outputFormat->findInt32("slice-height", &slice_height) && slice_height > 0) {
+ height = slice_height;
+ }
+
if (mFrame == NULL) {
sp<IMemory> frameMem = allocVideoFrame(
trackMeta(),
@@ -831,8 +848,12 @@
return NULL;
}
- // TODO: Use Flexible color instead
- videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ if (dstFormat() == COLOR_Format32bitABGR2101010) {
+ videoFormat->setInt32("color-format", COLOR_FormatYUVP010);
+ } else {
+ // TODO: Use Flexible color instead
+ videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ }
if ((mGridRows == 1) && (mGridCols == 1)) {
videoFormat->setInt32("android._num-input-buffers", 1);
@@ -938,6 +959,11 @@
crop_bottom = height - 1;
}
+ int32_t slice_height;
+ if (outputFormat->findInt32("slice-height", &slice_height) && slice_height > 0) {
+ height = slice_height;
+ }
+
int32_t crop_width, crop_height;
crop_width = crop_right - crop_left + 1;
crop_height = crop_bottom - crop_top + 1;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 3784dde..a0c8f8a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -156,7 +156,7 @@
bool isHeic() const { return mIsHeic; }
bool isAudio() const { return mIsAudio; }
bool isMPEG4() const { return mIsMPEG4; }
- bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic; }
+ bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic || mIsDovi; }
bool isExifData(MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const;
void addChunkOffset(off64_t offset);
void addItemOffsetAndSize(off64_t offset, size_t size, bool isExif);
@@ -164,6 +164,7 @@
TrackId& getTrackId() { return mTrackId; }
status_t dump(int fd, const Vector<String16>& args) const;
static const char *getFourCCForMime(const char *mime);
+ const char *getDoviFourCC() const;
const char *getTrackType() const;
void resetInternal();
int64_t trackMetaDataSize();
@@ -316,6 +317,7 @@
volatile bool mStarted;
bool mIsAvc;
bool mIsHevc;
+ bool mIsDovi;
bool mIsAudio;
bool mIsVideo;
bool mIsHeic;
@@ -370,6 +372,10 @@
uint8_t mProfileCompatible;
uint8_t mLevelIdc;
+ uint8_t mDoviProfile;
+ void *mDoviConfigData;
+ size_t mDoviConfigDataSize;
+
void *mCodecSpecificData;
size_t mCodecSpecificDataSize;
bool mGotAllCodecSpecificData;
@@ -422,6 +428,8 @@
status_t parseHEVCCodecSpecificData(
const uint8_t *data, size_t size, HevcParameterSets ¶mSets);
+ status_t makeDoviCodecSpecificData();
+
// Track authoring progress status
void trackProgressStatus(int64_t timeUs, status_t err = OK);
void initTrackingProgressStatus(MetaData *params);
@@ -459,6 +467,7 @@
void writePaspBox();
void writeAvccBox();
void writeHvccBox();
+ void writeDoviConfigBox();
void writeUrlBox();
void writeDrefBox();
void writeDinfBox();
@@ -618,6 +627,17 @@
return OK;
}
+const char *MPEG4Writer::Track::getDoviFourCC() const {
+ if (mDoviProfile == 5) {
+ return "dvh1";
+ } else if (mDoviProfile == 8) {
+ return "hvc1";
+ } else if (mDoviProfile == 9 || mDoviProfile == 32) {
+ return "avc1";
+ }
+ return (const char*)NULL;
+}
+
// static
const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) {
if (mime == NULL) {
@@ -672,7 +692,9 @@
mIsBackgroundMode |= isBackgroundMode;
}
- if (Track::getFourCCForMime(mime) == NULL) {
+ if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ ALOGV("Add source mime '%s'", mime);
+ } else if (Track::getFourCCForMime(mime) == NULL) {
ALOGE("Unsupported mime '%s'", mime);
return ERROR_UNSUPPORTED;
}
@@ -2151,6 +2173,8 @@
mMinCttsOffsetTimeUs(0),
mMinCttsOffsetTicks(0),
mMaxCttsOffsetTicks(0),
+ mDoviConfigData(NULL),
+ mDoviConfigDataSize(0),
mCodecSpecificData(NULL),
mCodecSpecificDataSize(0),
mGotAllCodecSpecificData(false),
@@ -2177,6 +2201,7 @@
mMeta->findCString(kKeyMIMEType, &mime);
mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+ mIsDovi = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
mIsAudio = !strncasecmp(mime, "audio/", 6);
mIsVideo = !strncasecmp(mime, "video/", 6);
mIsHeic = !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
@@ -2611,7 +2636,12 @@
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
mMeta->findData(kKeyHVCC, &type, &data, &size);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
- mMeta->findData(kKeyDVCC, &type, &data, &size);
+ makeDoviCodecSpecificData();
+ if (!mMeta->findData(kKeyAVCC, &type, &data, &size) &&
+ !mMeta->findData(kKeyHVCC, &type, &data, &size)) {
+ ALOGE("Failed: No HVCC/AVCC for Dolby Vision ..\n");
+ return;
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
@@ -2652,6 +2682,11 @@
free(mCodecSpecificData);
mCodecSpecificData = NULL;
}
+
+ if (mDoviConfigData != NULL) {
+ free(mDoviConfigData);
+ mDoviConfigData = NULL;
+ }
}
void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
@@ -3330,6 +3365,37 @@
return OK;
}
+status_t MPEG4Writer::Track::makeDoviCodecSpecificData() {
+ uint32_t type;
+ const void *data = NULL;
+ size_t size = 0;
+
+ if (mDoviConfigData != NULL) {
+ ALOGE("Already have Dolby Vision codec specific data");
+ return OK;
+ }
+
+ if (!mMeta->findData(kKeyDVCC, &type, &data, &size)
+ && !mMeta->findData(kKeyDVVC, &type, &data, &size)
+ && !mMeta->findData(kKeyDVWC, &type, &data, &size)) {
+ ALOGE("Failed getting Dovi config for Dolby Vision %d", (int)size);
+ return ERROR_MALFORMED;
+ }
+
+ mDoviConfigData = malloc(size);
+ if (mDoviConfigData == NULL) {
+ ALOGE("Failed allocating Dolby Vision config data");
+ return ERROR_MALFORMED;
+ }
+
+ mDoviConfigDataSize = size;
+ memcpy(mDoviConfigData, data, size);
+
+ mDoviProfile = (((char *)data)[2] >> 1) & 0x7f; //getting profile info
+
+ return OK;
+}
+
/*
* Updates the drift time from the audio track so that
* the video track can get the updated drift time information
@@ -3475,6 +3541,23 @@
err = copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(),
buffer->range_length());
}
+ if (mIsDovi) {
+ err = makeDoviCodecSpecificData();
+
+ const void *data = NULL;
+ size_t size = 0;
+
+ uint32_t type = 0;
+ if (mDoviProfile == 9){
+ mMeta->findData(kKeyAVCC, &type, &data, &size);
+ } else if (mDoviProfile < 9) {
+ mMeta->findData(kKeyHVCC, &type, &data, &size);
+ }
+
+ if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
+ mGotAllCodecSpecificData = true;
+ }
+ }
}
buffer->release();
@@ -4174,6 +4257,7 @@
!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime) ||
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, mime) ||
!strcasecmp(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, mime)) {
if (!mCodecSpecificData ||
mCodecSpecificDataSize <= 0) {
@@ -4298,7 +4382,13 @@
const char *mime;
bool success = mMeta->findCString(kKeyMIMEType, &mime);
CHECK(success);
- const char *fourcc = getFourCCForMime(mime);
+ const char *fourcc;
+ if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ fourcc = getDoviFourCC();
+ } else {
+ fourcc = getFourCCForMime(mime);
+ }
+
if (fourcc == NULL) {
ALOGE("Unknown mime type '%s'.", mime);
TRESPASS();
@@ -4338,6 +4428,13 @@
writeAvccBox();
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
writeHvccBox();
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, mime)) {
+ if (mDoviProfile <= 8) {
+ writeHvccBox();
+ } else if (mDoviProfile == 9 || mDoviProfile == 32) {
+ writeAvccBox();
+ }
+ writeDoviConfigBox();
}
writePaspBox();
@@ -4879,12 +4976,11 @@
mOwner->endBox(); // avcC
}
-
void MPEG4Writer::Track::writeHvccBox() {
CHECK(mCodecSpecificData);
CHECK_GE(mCodecSpecificDataSize, 5u);
- // Patch avcc's lengthSize field to match the number
+ // Patch hvcc's lengthSize field to match the number
// of bytes we use to indicate the size of a nal unit.
uint8_t *ptr = (uint8_t *)mCodecSpecificData;
ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
@@ -4893,6 +4989,24 @@
mOwner->endBox(); // hvcC
}
+void MPEG4Writer::Track::writeDoviConfigBox() {
+ CHECK(mDoviConfigData);
+ CHECK_EQ(mDoviConfigDataSize, 24u);
+
+ uint8_t *ptr = (uint8_t *)mDoviConfigData;
+ uint8_t profile = (ptr[2] >> 1) & 0x7f;
+
+ if (profile > 10) {
+ mOwner->beginBox("dvwC");
+ } else if (profile > 7) {
+ mOwner->beginBox("dvvC");
+ } else {
+ mOwner->beginBox("dvcC");
+ }
+ mOwner->write(mDoviConfigData, mDoviConfigDataSize);
+ mOwner->endBox(); // dvwC/dvvC/dvcC
+}
+
void MPEG4Writer::Track::writeD263Box() {
mOwner->beginBox("d263");
mOwner->writeInt32(0); // vendor
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index a6df5bb..1854588 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -28,9 +28,6 @@
#include "include/HevcUtils.h"
#include <cutils/properties.h>
-#include <media/openmax/OMX_Audio.h>
-#include <media/openmax/OMX_Video.h>
-#include <media/openmax/OMX_VideoExt.h>
#include <media/stagefright/CodecBase.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -57,6 +54,14 @@
#define AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS \
"mpegh-compatible-sets"
+namespace {
+ // TODO: this should possibly be handled in an else
+ constexpr static int32_t AACObjectNull = 0;
+
+ // TODO: decide if we should just not transmit the level in this case
+ constexpr static int32_t DolbyVisionLevelUnknown = 0;
+}
+
namespace android {
static status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
@@ -156,21 +161,22 @@
audioObjectType >>= 11;
}
- const static ALookup<uint16_t, OMX_AUDIO_AACPROFILETYPE> profiles {
- { 1, OMX_AUDIO_AACObjectMain },
- { 2, OMX_AUDIO_AACObjectLC },
- { 3, OMX_AUDIO_AACObjectSSR },
- { 4, OMX_AUDIO_AACObjectLTP },
- { 5, OMX_AUDIO_AACObjectHE },
- { 6, OMX_AUDIO_AACObjectScalable },
- { 17, OMX_AUDIO_AACObjectERLC },
- { 23, OMX_AUDIO_AACObjectLD },
- { 29, OMX_AUDIO_AACObjectHE_PS },
- { 39, OMX_AUDIO_AACObjectELD },
- { 42, OMX_AUDIO_AACObjectXHE },
+
+ const static ALookup<uint16_t, int32_t> profiles {
+ { 1, AACObjectMain },
+ { 2, AACObjectLC },
+ { 3, AACObjectSSR },
+ { 4, AACObjectLTP },
+ { 5, AACObjectHE },
+ { 6, AACObjectScalable },
+ { 17, AACObjectERLC },
+ { 23, AACObjectLD },
+ { 29, AACObjectHE_PS },
+ { 39, AACObjectELD },
+ { 42, AACObjectXHE },
};
- OMX_AUDIO_AACPROFILETYPE profile;
+ int32_t profile;
if (profiles.map(audioObjectType, &profile)) {
format->setInt32("profile", profile);
}
@@ -184,53 +190,53 @@
const uint8_t constraints = ptr[2];
const uint8_t level = ptr[3];
- const static ALookup<uint8_t, OMX_VIDEO_AVCLEVELTYPE> levels {
- { 9, OMX_VIDEO_AVCLevel1b }, // technically, 9 is only used for High+ profiles
- { 10, OMX_VIDEO_AVCLevel1 },
- { 11, OMX_VIDEO_AVCLevel11 }, // prefer level 1.1 for the value 11
- { 11, OMX_VIDEO_AVCLevel1b },
- { 12, OMX_VIDEO_AVCLevel12 },
- { 13, OMX_VIDEO_AVCLevel13 },
- { 20, OMX_VIDEO_AVCLevel2 },
- { 21, OMX_VIDEO_AVCLevel21 },
- { 22, OMX_VIDEO_AVCLevel22 },
- { 30, OMX_VIDEO_AVCLevel3 },
- { 31, OMX_VIDEO_AVCLevel31 },
- { 32, OMX_VIDEO_AVCLevel32 },
- { 40, OMX_VIDEO_AVCLevel4 },
- { 41, OMX_VIDEO_AVCLevel41 },
- { 42, OMX_VIDEO_AVCLevel42 },
- { 50, OMX_VIDEO_AVCLevel5 },
- { 51, OMX_VIDEO_AVCLevel51 },
- { 52, OMX_VIDEO_AVCLevel52 },
- { 60, OMX_VIDEO_AVCLevel6 },
- { 61, OMX_VIDEO_AVCLevel61 },
- { 62, OMX_VIDEO_AVCLevel62 },
+ const static ALookup<uint8_t, int32_t> levels {
+ { 9, AVCLevel1b }, // technically, 9 is only used for High+ profiles
+ { 10, AVCLevel1 },
+ { 11, AVCLevel11 }, // prefer level 1.1 for the value 11
+ { 11, AVCLevel1b },
+ { 12, AVCLevel12 },
+ { 13, AVCLevel13 },
+ { 20, AVCLevel2 },
+ { 21, AVCLevel21 },
+ { 22, AVCLevel22 },
+ { 30, AVCLevel3 },
+ { 31, AVCLevel31 },
+ { 32, AVCLevel32 },
+ { 40, AVCLevel4 },
+ { 41, AVCLevel41 },
+ { 42, AVCLevel42 },
+ { 50, AVCLevel5 },
+ { 51, AVCLevel51 },
+ { 52, AVCLevel52 },
+ { 60, AVCLevel6 },
+ { 61, AVCLevel61 },
+ { 62, AVCLevel62 },
};
- const static ALookup<uint8_t, OMX_VIDEO_AVCPROFILETYPE> profiles {
- { 66, OMX_VIDEO_AVCProfileBaseline },
- { 77, OMX_VIDEO_AVCProfileMain },
- { 88, OMX_VIDEO_AVCProfileExtended },
- { 100, OMX_VIDEO_AVCProfileHigh },
- { 110, OMX_VIDEO_AVCProfileHigh10 },
- { 122, OMX_VIDEO_AVCProfileHigh422 },
- { 244, OMX_VIDEO_AVCProfileHigh444 },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 66, AVCProfileBaseline },
+ { 77, AVCProfileMain },
+ { 88, AVCProfileExtended },
+ { 100, AVCProfileHigh },
+ { 110, AVCProfileHigh10 },
+ { 122, AVCProfileHigh422 },
+ { 244, AVCProfileHigh444 },
};
// set profile & level if they are recognized
- OMX_VIDEO_AVCPROFILETYPE codecProfile;
- OMX_VIDEO_AVCLEVELTYPE codecLevel;
+ int32_t codecProfile;
+ int32_t codecLevel;
if (profiles.map(profile, &codecProfile)) {
if (profile == 66 && (constraints & 0x40)) {
- codecProfile = (OMX_VIDEO_AVCPROFILETYPE)OMX_VIDEO_AVCProfileConstrainedBaseline;
+ codecProfile = AVCProfileConstrainedBaseline;
} else if (profile == 100 && (constraints & 0x0C) == 0x0C) {
- codecProfile = (OMX_VIDEO_AVCPROFILETYPE)OMX_VIDEO_AVCProfileConstrainedHigh;
+ codecProfile = AVCProfileConstrainedHigh;
}
format->setInt32("profile", codecProfile);
if (levels.map(level, &codecLevel)) {
// for 9 && 11 decide level based on profile and constraint_set3 flag
if (level == 11 && (profile == 66 || profile == 77 || profile == 88)) {
- codecLevel = (constraints & 0x10) ? OMX_VIDEO_AVCLevel1b : OMX_VIDEO_AVCLevel11;
+ codecLevel = (constraints & 0x10) ? AVCLevel1b : AVCLevel11;
}
format->setInt32("level", codecLevel);
}
@@ -256,41 +262,44 @@
// All Dolby Profiles will have profile and level info in MediaFormat
// Profile 8 and 9 will have bl_compatibility_id too.
- const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONPROFILETYPE> profiles{
- {1, OMX_VIDEO_DolbyVisionProfileDvavPen},
- {3, OMX_VIDEO_DolbyVisionProfileDvheDen},
- {4, OMX_VIDEO_DolbyVisionProfileDvheDtr},
- {5, OMX_VIDEO_DolbyVisionProfileDvheStn},
- {6, OMX_VIDEO_DolbyVisionProfileDvheDth},
- {7, OMX_VIDEO_DolbyVisionProfileDvheDtb},
- {8, OMX_VIDEO_DolbyVisionProfileDvheSt},
- {9, OMX_VIDEO_DolbyVisionProfileDvavSe},
- {10, OMX_VIDEO_DolbyVisionProfileDvav110},
+ const static ALookup<uint8_t, int32_t> profiles{
+ {1, DolbyVisionProfileDvavPen},
+ {3, DolbyVisionProfileDvheDen},
+ {4, DolbyVisionProfileDvheDtr},
+ {5, DolbyVisionProfileDvheStn},
+ {6, DolbyVisionProfileDvheDth},
+ {7, DolbyVisionProfileDvheDtb},
+ {8, DolbyVisionProfileDvheSt},
+ {9, DolbyVisionProfileDvavSe},
+ {10, DolbyVisionProfileDvav110},
};
- const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONLEVELTYPE> levels{
- {0, OMX_VIDEO_DolbyVisionLevelUnknown},
- {1, OMX_VIDEO_DolbyVisionLevelHd24},
- {2, OMX_VIDEO_DolbyVisionLevelHd30},
- {3, OMX_VIDEO_DolbyVisionLevelFhd24},
- {4, OMX_VIDEO_DolbyVisionLevelFhd30},
- {5, OMX_VIDEO_DolbyVisionLevelFhd60},
- {6, OMX_VIDEO_DolbyVisionLevelUhd24},
- {7, OMX_VIDEO_DolbyVisionLevelUhd30},
- {8, OMX_VIDEO_DolbyVisionLevelUhd48},
- {9, OMX_VIDEO_DolbyVisionLevelUhd60},
+ const static ALookup<uint8_t, int32_t> levels{
+ {0, DolbyVisionLevelUnknown},
+ {1, DolbyVisionLevelHd24},
+ {2, DolbyVisionLevelHd30},
+ {3, DolbyVisionLevelFhd24},
+ {4, DolbyVisionLevelFhd30},
+ {5, DolbyVisionLevelFhd60},
+ {6, DolbyVisionLevelUhd24},
+ {7, DolbyVisionLevelUhd30},
+ {8, DolbyVisionLevelUhd48},
+ {9, DolbyVisionLevelUhd60},
+ {10, DolbyVisionLevelUhd120},
+ {11, DolbyVisionLevel8k30},
+ {12, DolbyVisionLevel8k60},
};
// set rpuAssoc
if (rpu_present_flag && el_present_flag && !bl_present_flag) {
format->setInt32("rpuAssoc", 1);
}
// set profile & level if they are recognized
- OMX_VIDEO_DOLBYVISIONPROFILETYPE codecProfile;
- OMX_VIDEO_DOLBYVISIONLEVELTYPE codecLevel;
+ int32_t codecProfile;
+ int32_t codecLevel;
if (profiles.map(profile, &codecProfile)) {
format->setInt32("profile", codecProfile);
- if (codecProfile == OMX_VIDEO_DolbyVisionProfileDvheSt ||
- codecProfile == OMX_VIDEO_DolbyVisionProfileDvavSe) {
+ if (codecProfile == DolbyVisionProfileDvheSt ||
+ codecProfile == DolbyVisionProfileDvavSe) {
format->setInt32("bl_compatibility_id", bl_compatibility_id);
}
if (levels.map(level, &codecLevel)) {
@@ -307,32 +316,32 @@
const uint8_t profile = ptr[6];
const uint8_t level = ptr[5];
- const static ALookup<uint8_t, OMX_VIDEO_H263PROFILETYPE> profiles {
- { 0, OMX_VIDEO_H263ProfileBaseline },
- { 1, OMX_VIDEO_H263ProfileH320Coding },
- { 2, OMX_VIDEO_H263ProfileBackwardCompatible },
- { 3, OMX_VIDEO_H263ProfileISWV2 },
- { 4, OMX_VIDEO_H263ProfileISWV3 },
- { 5, OMX_VIDEO_H263ProfileHighCompression },
- { 6, OMX_VIDEO_H263ProfileInternet },
- { 7, OMX_VIDEO_H263ProfileInterlace },
- { 8, OMX_VIDEO_H263ProfileHighLatency },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 0, H263ProfileBaseline },
+ { 1, H263ProfileH320Coding },
+ { 2, H263ProfileBackwardCompatible },
+ { 3, H263ProfileISWV2 },
+ { 4, H263ProfileISWV3 },
+ { 5, H263ProfileHighCompression },
+ { 6, H263ProfileInternet },
+ { 7, H263ProfileInterlace },
+ { 8, H263ProfileHighLatency },
};
- const static ALookup<uint8_t, OMX_VIDEO_H263LEVELTYPE> levels {
- { 10, OMX_VIDEO_H263Level10 },
- { 20, OMX_VIDEO_H263Level20 },
- { 30, OMX_VIDEO_H263Level30 },
- { 40, OMX_VIDEO_H263Level40 },
- { 45, OMX_VIDEO_H263Level45 },
- { 50, OMX_VIDEO_H263Level50 },
- { 60, OMX_VIDEO_H263Level60 },
- { 70, OMX_VIDEO_H263Level70 },
+ const static ALookup<uint8_t, int32_t> levels {
+ { 10, H263Level10 },
+ { 20, H263Level20 },
+ { 30, H263Level30 },
+ { 40, H263Level40 },
+ { 45, H263Level45 },
+ { 50, H263Level50 },
+ { 60, H263Level60 },
+ { 70, H263Level70 },
};
// set profile & level if they are recognized
- OMX_VIDEO_H263PROFILETYPE codecProfile;
- OMX_VIDEO_H263LEVELTYPE codecLevel;
+ int32_t codecProfile;
+ int32_t codecLevel;
if (profiles.map(profile, &codecProfile)) {
format->setInt32("profile", codecProfile);
if (levels.map(level, &codecLevel)) {
@@ -350,59 +359,59 @@
const uint8_t tier = (ptr[1] & 0x20) >> 5;
const uint8_t level = ptr[12];
- const static ALookup<std::pair<uint8_t, uint8_t>, OMX_VIDEO_HEVCLEVELTYPE> levels {
- { { 0, 30 }, OMX_VIDEO_HEVCMainTierLevel1 },
- { { 0, 60 }, OMX_VIDEO_HEVCMainTierLevel2 },
- { { 0, 63 }, OMX_VIDEO_HEVCMainTierLevel21 },
- { { 0, 90 }, OMX_VIDEO_HEVCMainTierLevel3 },
- { { 0, 93 }, OMX_VIDEO_HEVCMainTierLevel31 },
- { { 0, 120 }, OMX_VIDEO_HEVCMainTierLevel4 },
- { { 0, 123 }, OMX_VIDEO_HEVCMainTierLevel41 },
- { { 0, 150 }, OMX_VIDEO_HEVCMainTierLevel5 },
- { { 0, 153 }, OMX_VIDEO_HEVCMainTierLevel51 },
- { { 0, 156 }, OMX_VIDEO_HEVCMainTierLevel52 },
- { { 0, 180 }, OMX_VIDEO_HEVCMainTierLevel6 },
- { { 0, 183 }, OMX_VIDEO_HEVCMainTierLevel61 },
- { { 0, 186 }, OMX_VIDEO_HEVCMainTierLevel62 },
- { { 1, 30 }, OMX_VIDEO_HEVCHighTierLevel1 },
- { { 1, 60 }, OMX_VIDEO_HEVCHighTierLevel2 },
- { { 1, 63 }, OMX_VIDEO_HEVCHighTierLevel21 },
- { { 1, 90 }, OMX_VIDEO_HEVCHighTierLevel3 },
- { { 1, 93 }, OMX_VIDEO_HEVCHighTierLevel31 },
- { { 1, 120 }, OMX_VIDEO_HEVCHighTierLevel4 },
- { { 1, 123 }, OMX_VIDEO_HEVCHighTierLevel41 },
- { { 1, 150 }, OMX_VIDEO_HEVCHighTierLevel5 },
- { { 1, 153 }, OMX_VIDEO_HEVCHighTierLevel51 },
- { { 1, 156 }, OMX_VIDEO_HEVCHighTierLevel52 },
- { { 1, 180 }, OMX_VIDEO_HEVCHighTierLevel6 },
- { { 1, 183 }, OMX_VIDEO_HEVCHighTierLevel61 },
- { { 1, 186 }, OMX_VIDEO_HEVCHighTierLevel62 },
+ const static ALookup<std::pair<uint8_t, uint8_t>, int32_t> levels {
+ { { 0, 30 }, HEVCMainTierLevel1 },
+ { { 0, 60 }, HEVCMainTierLevel2 },
+ { { 0, 63 }, HEVCMainTierLevel21 },
+ { { 0, 90 }, HEVCMainTierLevel3 },
+ { { 0, 93 }, HEVCMainTierLevel31 },
+ { { 0, 120 }, HEVCMainTierLevel4 },
+ { { 0, 123 }, HEVCMainTierLevel41 },
+ { { 0, 150 }, HEVCMainTierLevel5 },
+ { { 0, 153 }, HEVCMainTierLevel51 },
+ { { 0, 156 }, HEVCMainTierLevel52 },
+ { { 0, 180 }, HEVCMainTierLevel6 },
+ { { 0, 183 }, HEVCMainTierLevel61 },
+ { { 0, 186 }, HEVCMainTierLevel62 },
+ { { 1, 30 }, HEVCHighTierLevel1 },
+ { { 1, 60 }, HEVCHighTierLevel2 },
+ { { 1, 63 }, HEVCHighTierLevel21 },
+ { { 1, 90 }, HEVCHighTierLevel3 },
+ { { 1, 93 }, HEVCHighTierLevel31 },
+ { { 1, 120 }, HEVCHighTierLevel4 },
+ { { 1, 123 }, HEVCHighTierLevel41 },
+ { { 1, 150 }, HEVCHighTierLevel5 },
+ { { 1, 153 }, HEVCHighTierLevel51 },
+ { { 1, 156 }, HEVCHighTierLevel52 },
+ { { 1, 180 }, HEVCHighTierLevel6 },
+ { { 1, 183 }, HEVCHighTierLevel61 },
+ { { 1, 186 }, HEVCHighTierLevel62 },
};
- const static ALookup<uint8_t, OMX_VIDEO_HEVCPROFILETYPE> profiles {
- { 1, OMX_VIDEO_HEVCProfileMain },
- { 2, OMX_VIDEO_HEVCProfileMain10 },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 1, HEVCProfileMain },
+ { 2, HEVCProfileMain10 },
// use Main for Main Still Picture decoding
- { 3, OMX_VIDEO_HEVCProfileMain },
+ { 3, HEVCProfileMain },
};
// set profile & level if they are recognized
- OMX_VIDEO_HEVCPROFILETYPE codecProfile;
- OMX_VIDEO_HEVCLEVELTYPE codecLevel;
+ int32_t codecProfile;
+ int32_t codecLevel;
if (!profiles.map(profile, &codecProfile)) {
if (ptr[2] & 0x40 /* general compatibility flag 1 */) {
// Note that this case covers Main Still Picture too
- codecProfile = OMX_VIDEO_HEVCProfileMain;
+ codecProfile = HEVCProfileMain;
} else if (ptr[2] & 0x20 /* general compatibility flag 2 */) {
- codecProfile = OMX_VIDEO_HEVCProfileMain10;
+ codecProfile = HEVCProfileMain10;
} else {
return;
}
}
// bump to HDR profile
- if (isHdr(format) && codecProfile == OMX_VIDEO_HEVCProfileMain10) {
- codecProfile = OMX_VIDEO_HEVCProfileMain10HDR10;
+ if (isHdr(format) && codecProfile == HEVCProfileMain10) {
+ codecProfile = HEVCProfileMain10HDR10;
}
format->setInt32("profile", codecProfile);
@@ -422,36 +431,36 @@
}
const uint8_t indication = ((seq[4] & 0xF) << 4) | ((seq[5] & 0xF0) >> 4);
- const static ALookup<uint8_t, OMX_VIDEO_MPEG2PROFILETYPE> profiles {
- { 0x50, OMX_VIDEO_MPEG2ProfileSimple },
- { 0x40, OMX_VIDEO_MPEG2ProfileMain },
- { 0x30, OMX_VIDEO_MPEG2ProfileSNR },
- { 0x20, OMX_VIDEO_MPEG2ProfileSpatial },
- { 0x10, OMX_VIDEO_MPEG2ProfileHigh },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 0x50, MPEG2ProfileSimple },
+ { 0x40, MPEG2ProfileMain },
+ { 0x30, MPEG2ProfileSNR },
+ { 0x20, MPEG2ProfileSpatial },
+ { 0x10, MPEG2ProfileHigh },
};
- const static ALookup<uint8_t, OMX_VIDEO_MPEG2LEVELTYPE> levels {
- { 0x0A, OMX_VIDEO_MPEG2LevelLL },
- { 0x08, OMX_VIDEO_MPEG2LevelML },
- { 0x06, OMX_VIDEO_MPEG2LevelH14 },
- { 0x04, OMX_VIDEO_MPEG2LevelHL },
- { 0x02, OMX_VIDEO_MPEG2LevelHP },
+ const static ALookup<uint8_t, int32_t> levels {
+ { 0x0A, MPEG2LevelLL },
+ { 0x08, MPEG2LevelML },
+ { 0x06, MPEG2LevelH14 },
+ { 0x04, MPEG2LevelHL },
+ { 0x02, MPEG2LevelHP },
};
const static ALookup<uint8_t,
- std::pair<OMX_VIDEO_MPEG2PROFILETYPE, OMX_VIDEO_MPEG2LEVELTYPE>> escapes {
+ std::pair<int32_t, int32_t>> escapes {
/* unsupported
- { 0x8E, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelLL } },
- { 0x8D, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelML } },
- { 0x8B, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelH14 } },
- { 0x8A, { XXX_MPEG2ProfileMultiView, OMX_VIDEO_MPEG2LevelHL } }, */
- { 0x85, { OMX_VIDEO_MPEG2Profile422, OMX_VIDEO_MPEG2LevelML } },
- { 0x82, { OMX_VIDEO_MPEG2Profile422, OMX_VIDEO_MPEG2LevelHL } },
+ { 0x8E, { XXX_MPEG2ProfileMultiView, MPEG2LevelLL } },
+ { 0x8D, { XXX_MPEG2ProfileMultiView, MPEG2LevelML } },
+ { 0x8B, { XXX_MPEG2ProfileMultiView, MPEG2LevelH14 } },
+ { 0x8A, { XXX_MPEG2ProfileMultiView, MPEG2LevelHL } }, */
+ { 0x85, { MPEG2Profile422, MPEG2LevelML } },
+ { 0x82, { MPEG2Profile422, MPEG2LevelHL } },
};
- OMX_VIDEO_MPEG2PROFILETYPE profile;
- OMX_VIDEO_MPEG2LEVELTYPE level;
- std::pair<OMX_VIDEO_MPEG2PROFILETYPE, OMX_VIDEO_MPEG2LEVELTYPE> profileLevel;
+ int32_t profile;
+ int32_t level;
+ std::pair<int32_t, int32_t> profileLevel;
if (escapes.map(indication, &profileLevel)) {
format->setInt32("profile", profileLevel.first);
format->setInt32("level", profileLevel.second);
@@ -468,16 +477,16 @@
// esds seems to only contain the profile for MPEG-2
uint8_t objType;
if (esds.getObjectTypeIndication(&objType) == OK) {
- const static ALookup<uint8_t, OMX_VIDEO_MPEG2PROFILETYPE> profiles{
- { 0x60, OMX_VIDEO_MPEG2ProfileSimple },
- { 0x61, OMX_VIDEO_MPEG2ProfileMain },
- { 0x62, OMX_VIDEO_MPEG2ProfileSNR },
- { 0x63, OMX_VIDEO_MPEG2ProfileSpatial },
- { 0x64, OMX_VIDEO_MPEG2ProfileHigh },
- { 0x65, OMX_VIDEO_MPEG2Profile422 },
+ const static ALookup<uint8_t, int32_t> profiles{
+ { 0x60, MPEG2ProfileSimple },
+ { 0x61, MPEG2ProfileMain },
+ { 0x62, MPEG2ProfileSNR },
+ { 0x63, MPEG2ProfileSpatial },
+ { 0x64, MPEG2ProfileHigh },
+ { 0x65, MPEG2Profile422 },
};
- OMX_VIDEO_MPEG2PROFILETYPE profile;
+ int32_t profile;
if (profiles.map(objType, &profile)) {
format->setInt32("profile", profile);
}
@@ -492,82 +501,82 @@
const uint8_t indication = seq[4];
const static ALookup<uint8_t,
- std::pair<OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_MPEG4LEVELTYPE>> table {
- { 0b00000001, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 } },
- { 0b00000010, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 } },
- { 0b00000011, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 } },
- { 0b00000100, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level4a } },
- { 0b00000101, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level5 } },
- { 0b00000110, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level6 } },
- { 0b00001000, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 } },
- { 0b00001001, { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b } },
- { 0b00010000, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level0 } },
- { 0b00010001, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level1 } },
- { 0b00010010, { OMX_VIDEO_MPEG4ProfileSimpleScalable, OMX_VIDEO_MPEG4Level2 } },
+ std::pair<int32_t, int32_t>> table {
+ { 0b00000001, { MPEG4ProfileSimple, MPEG4Level1 } },
+ { 0b00000010, { MPEG4ProfileSimple, MPEG4Level2 } },
+ { 0b00000011, { MPEG4ProfileSimple, MPEG4Level3 } },
+ { 0b00000100, { MPEG4ProfileSimple, MPEG4Level4a } },
+ { 0b00000101, { MPEG4ProfileSimple, MPEG4Level5 } },
+ { 0b00000110, { MPEG4ProfileSimple, MPEG4Level6 } },
+ { 0b00001000, { MPEG4ProfileSimple, MPEG4Level0 } },
+ { 0b00001001, { MPEG4ProfileSimple, MPEG4Level0b } },
+ { 0b00010000, { MPEG4ProfileSimpleScalable, MPEG4Level0 } },
+ { 0b00010001, { MPEG4ProfileSimpleScalable, MPEG4Level1 } },
+ { 0b00010010, { MPEG4ProfileSimpleScalable, MPEG4Level2 } },
/* unsupported
- { 0b00011101, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level0 } },
- { 0b00011110, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level1 } },
- { 0b00011111, { XXX_MPEG4ProfileSimpleScalableER, OMX_VIDEO_MPEG4Level2 } }, */
- { 0b00100001, { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level1 } },
- { 0b00100010, { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level2 } },
- { 0b00110010, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level2 } },
- { 0b00110011, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level3 } },
- { 0b00110100, { OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level4 } },
+ { 0b00011101, { XXX_MPEG4ProfileSimpleScalableER, MPEG4Level0 } },
+ { 0b00011110, { XXX_MPEG4ProfileSimpleScalableER, MPEG4Level1 } },
+ { 0b00011111, { XXX_MPEG4ProfileSimpleScalableER, MPEG4Level2 } }, */
+ { 0b00100001, { MPEG4ProfileCore, MPEG4Level1 } },
+ { 0b00100010, { MPEG4ProfileCore, MPEG4Level2 } },
+ { 0b00110010, { MPEG4ProfileMain, MPEG4Level2 } },
+ { 0b00110011, { MPEG4ProfileMain, MPEG4Level3 } },
+ { 0b00110100, { MPEG4ProfileMain, MPEG4Level4 } },
/* deprecated
- { 0b01000010, { OMX_VIDEO_MPEG4ProfileNbit, OMX_VIDEO_MPEG4Level2 } }, */
- { 0b01010001, { OMX_VIDEO_MPEG4ProfileScalableTexture, OMX_VIDEO_MPEG4Level1 } },
- { 0b01100001, { OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level1 } },
- { 0b01100010, { OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level2 } },
- { 0b01100011, { OMX_VIDEO_MPEG4ProfileSimpleFBA, OMX_VIDEO_MPEG4Level1 } },
- { 0b01100100, { OMX_VIDEO_MPEG4ProfileSimpleFBA, OMX_VIDEO_MPEG4Level2 } },
- { 0b01110001, { OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level1 } },
- { 0b01110010, { OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level2 } },
- { 0b10000001, { OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level1 } },
- { 0b10000010, { OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level2 } },
- { 0b10010001, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level1 } },
- { 0b10010010, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level2 } },
- { 0b10010011, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level3 } },
- { 0b10010100, { OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level4 } },
- { 0b10100001, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level1 } },
- { 0b10100010, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level2 } },
- { 0b10100011, { OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level3 } },
- { 0b10110001, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level1 } },
- { 0b10110010, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level2 } },
- { 0b10110011, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level3 } },
- { 0b10110100, { OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level4 } },
- { 0b11000001, { OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level1 } },
- { 0b11000010, { OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level2 } },
- { 0b11010001, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level1 } },
- { 0b11010010, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level2 } },
- { 0b11010011, { OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level3 } },
+ { 0b01000010, { MPEG4ProfileNbit, MPEG4Level2 } }, */
+ { 0b01010001, { MPEG4ProfileScalableTexture, MPEG4Level1 } },
+ { 0b01100001, { MPEG4ProfileSimpleFace, MPEG4Level1 } },
+ { 0b01100010, { MPEG4ProfileSimpleFace, MPEG4Level2 } },
+ { 0b01100011, { MPEG4ProfileSimpleFBA, MPEG4Level1 } },
+ { 0b01100100, { MPEG4ProfileSimpleFBA, MPEG4Level2 } },
+ { 0b01110001, { MPEG4ProfileBasicAnimated, MPEG4Level1 } },
+ { 0b01110010, { MPEG4ProfileBasicAnimated, MPEG4Level2 } },
+ { 0b10000001, { MPEG4ProfileHybrid, MPEG4Level1 } },
+ { 0b10000010, { MPEG4ProfileHybrid, MPEG4Level2 } },
+ { 0b10010001, { MPEG4ProfileAdvancedRealTime, MPEG4Level1 } },
+ { 0b10010010, { MPEG4ProfileAdvancedRealTime, MPEG4Level2 } },
+ { 0b10010011, { MPEG4ProfileAdvancedRealTime, MPEG4Level3 } },
+ { 0b10010100, { MPEG4ProfileAdvancedRealTime, MPEG4Level4 } },
+ { 0b10100001, { MPEG4ProfileCoreScalable, MPEG4Level1 } },
+ { 0b10100010, { MPEG4ProfileCoreScalable, MPEG4Level2 } },
+ { 0b10100011, { MPEG4ProfileCoreScalable, MPEG4Level3 } },
+ { 0b10110001, { MPEG4ProfileAdvancedCoding, MPEG4Level1 } },
+ { 0b10110010, { MPEG4ProfileAdvancedCoding, MPEG4Level2 } },
+ { 0b10110011, { MPEG4ProfileAdvancedCoding, MPEG4Level3 } },
+ { 0b10110100, { MPEG4ProfileAdvancedCoding, MPEG4Level4 } },
+ { 0b11000001, { MPEG4ProfileAdvancedCore, MPEG4Level1 } },
+ { 0b11000010, { MPEG4ProfileAdvancedCore, MPEG4Level2 } },
+ { 0b11010001, { MPEG4ProfileAdvancedScalable, MPEG4Level1 } },
+ { 0b11010010, { MPEG4ProfileAdvancedScalable, MPEG4Level2 } },
+ { 0b11010011, { MPEG4ProfileAdvancedScalable, MPEG4Level3 } },
/* unsupported
- { 0b11100001, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level1 } },
- { 0b11100010, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level2 } },
- { 0b11100011, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level3 } },
- { 0b11100100, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level4 } },
- { 0b11100101, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level1 } },
- { 0b11100110, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level2 } },
- { 0b11100111, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level3 } },
- { 0b11101000, { XXX_MPEG4ProfileCoreStudio, OMX_VIDEO_MPEG4Level4 } },
- { 0b11101011, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level5 } },
- { 0b11101100, { XXX_MPEG4ProfileSimpleStudio, OMX_VIDEO_MPEG4Level6 } }, */
- { 0b11110000, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level0 } },
- { 0b11110001, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level1 } },
- { 0b11110010, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level2 } },
- { 0b11110011, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3 } },
- { 0b11110100, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level4 } },
- { 0b11110101, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level5 } },
- { 0b11110111, { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3b } },
+ { 0b11100001, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level1 } },
+ { 0b11100010, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level2 } },
+ { 0b11100011, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level3 } },
+ { 0b11100100, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level4 } },
+ { 0b11100101, { XXX_MPEG4ProfileCoreStudio, MPEG4Level1 } },
+ { 0b11100110, { XXX_MPEG4ProfileCoreStudio, MPEG4Level2 } },
+ { 0b11100111, { XXX_MPEG4ProfileCoreStudio, MPEG4Level3 } },
+ { 0b11101000, { XXX_MPEG4ProfileCoreStudio, MPEG4Level4 } },
+ { 0b11101011, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level5 } },
+ { 0b11101100, { XXX_MPEG4ProfileSimpleStudio, MPEG4Level6 } }, */
+ { 0b11110000, { MPEG4ProfileAdvancedSimple, MPEG4Level0 } },
+ { 0b11110001, { MPEG4ProfileAdvancedSimple, MPEG4Level1 } },
+ { 0b11110010, { MPEG4ProfileAdvancedSimple, MPEG4Level2 } },
+ { 0b11110011, { MPEG4ProfileAdvancedSimple, MPEG4Level3 } },
+ { 0b11110100, { MPEG4ProfileAdvancedSimple, MPEG4Level4 } },
+ { 0b11110101, { MPEG4ProfileAdvancedSimple, MPEG4Level5 } },
+ { 0b11110111, { MPEG4ProfileAdvancedSimple, MPEG4Level3b } },
/* deprecated
- { 0b11111000, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level0 } },
- { 0b11111001, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level1 } },
- { 0b11111010, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level2 } },
- { 0b11111011, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level3 } },
- { 0b11111100, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level4 } },
- { 0b11111101, { XXX_MPEG4ProfileFineGranularityScalable, OMX_VIDEO_MPEG4Level5 } }, */
+ { 0b11111000, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level0 } },
+ { 0b11111001, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level1 } },
+ { 0b11111010, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level2 } },
+ { 0b11111011, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level3 } },
+ { 0b11111100, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level4 } },
+ { 0b11111101, { XXX_MPEG4ProfileFineGranularityScalable, MPEG4Level5 } }, */
};
- std::pair<OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_MPEG4LEVELTYPE> profileLevel;
+ std::pair<int32_t, int32_t> profileLevel;
if (table.map(indication, &profileLevel)) {
format->setInt32("profile", profileLevel.first);
format->setInt32("level", profileLevel.second);
@@ -590,19 +599,19 @@
switch (id) {
case 1 /* profileId */:
if (length >= 1) {
- const static ALookup<uint8_t, OMX_VIDEO_VP9PROFILETYPE> profiles {
- { 0, OMX_VIDEO_VP9Profile0 },
- { 1, OMX_VIDEO_VP9Profile1 },
- { 2, OMX_VIDEO_VP9Profile2 },
- { 3, OMX_VIDEO_VP9Profile3 },
+ const static ALookup<uint8_t, int32_t> profiles {
+ { 0, VP9Profile0 },
+ { 1, VP9Profile1 },
+ { 2, VP9Profile2 },
+ { 3, VP9Profile3 },
};
- const static ALookup<OMX_VIDEO_VP9PROFILETYPE, OMX_VIDEO_VP9PROFILETYPE> toHdr {
- { OMX_VIDEO_VP9Profile2, OMX_VIDEO_VP9Profile2HDR },
- { OMX_VIDEO_VP9Profile3, OMX_VIDEO_VP9Profile3HDR },
+ const static ALookup<int32_t, int32_t> toHdr {
+ { VP9Profile2, VP9Profile2HDR },
+ { VP9Profile3, VP9Profile3HDR },
};
- OMX_VIDEO_VP9PROFILETYPE profile;
+ int32_t profile;
if (profiles.map(data[0], &profile)) {
// convert to HDR profile
if (isHdr(format)) {
@@ -615,24 +624,24 @@
break;
case 2 /* levelId */:
if (length >= 1) {
- const static ALookup<uint8_t, OMX_VIDEO_VP9LEVELTYPE> levels {
- { 10, OMX_VIDEO_VP9Level1 },
- { 11, OMX_VIDEO_VP9Level11 },
- { 20, OMX_VIDEO_VP9Level2 },
- { 21, OMX_VIDEO_VP9Level21 },
- { 30, OMX_VIDEO_VP9Level3 },
- { 31, OMX_VIDEO_VP9Level31 },
- { 40, OMX_VIDEO_VP9Level4 },
- { 41, OMX_VIDEO_VP9Level41 },
- { 50, OMX_VIDEO_VP9Level5 },
- { 51, OMX_VIDEO_VP9Level51 },
- { 52, OMX_VIDEO_VP9Level52 },
- { 60, OMX_VIDEO_VP9Level6 },
- { 61, OMX_VIDEO_VP9Level61 },
- { 62, OMX_VIDEO_VP9Level62 },
+ const static ALookup<uint8_t, int32_t> levels {
+ { 10, VP9Level1 },
+ { 11, VP9Level11 },
+ { 20, VP9Level2 },
+ { 21, VP9Level21 },
+ { 30, VP9Level3 },
+ { 31, VP9Level31 },
+ { 40, VP9Level4 },
+ { 41, VP9Level41 },
+ { 50, VP9Level5 },
+ { 51, VP9Level51 },
+ { 52, VP9Level52 },
+ { 60, VP9Level6 },
+ { 61, VP9Level61 },
+ { 62, VP9Level62 },
};
- OMX_VIDEO_VP9LEVELTYPE level;
+ int32_t level;
if (levels.map(data[0], &level)) {
format->setInt32("level", level);
}
@@ -1504,7 +1513,30 @@
msg->setBuffer("csd-0", buffer);
}
- if (meta->findData(kKeyDVCC, &type, &data, &size)) {
+ if (meta->findData(kKeyDVCC, &type, &data, &size)
+ || meta->findData(kKeyDVVC, &type, &data, &size)
+ || meta->findData(kKeyDVWC, &type, &data, &size)) {
+ sp<ABuffer> buffer, csdOrg;
+ if (msg->findBuffer("csd-0", &csdOrg)) {
+ buffer = new (std::nothrow) ABuffer(size + csdOrg->size());
+ if (buffer.get() == NULL || buffer->base() == NULL) {
+ return NO_MEMORY;
+ }
+
+ memcpy(buffer->data(), csdOrg->data(), csdOrg->size());
+ memcpy(buffer->data() + csdOrg->size(), data, size);
+ } else {
+ buffer = new (std::nothrow) ABuffer(size);
+ if (buffer.get() == NULL || buffer->base() == NULL) {
+ return NO_MEMORY;
+ }
+ memcpy(buffer->data(), data, size);
+ }
+
+ buffer->meta()->setInt32("csd", true);
+ buffer->meta()->setInt64("timeUs", 0);
+ msg->setBuffer("csd-0", buffer);
+
const uint8_t *ptr = (const uint8_t *)data;
ALOGV("DV: calling parseDolbyVisionProfileLevelFromDvcc with data size %zu", size);
parseDolbyVisionProfileLevelFromDvcc(ptr, size, msg);
@@ -2009,30 +2041,134 @@
mime == MEDIA_MIMETYPE_IMAGE_AVIF) {
meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
- if (msg->findBuffer("csd-2", &csd2)) {
- //dvcc should be 24
- if (csd2->size() == 24) {
- meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
- uint8_t *dvcc = csd2->data();
- const uint8_t profile = dvcc[2] >> 1;
- if (profile > 1 && profile < 9) {
+ int32_t needCreateDoviCSD = 0;
+ int32_t profile = 0;
+ uint8_t bl_compatibility = 0;
+ if (msg->findInt32("profile", &profile)) {
+ if (profile == DolbyVisionProfileDvheSt) {
+ profile = 8;
+ bl_compatibility = 4;
+ } else if (profile == DolbyVisionProfileDvavSe) {
+ profile = 9;
+ bl_compatibility = 2;
+ }
+ if (profile == 8 || profile == 9) {
+ needCreateDoviCSD = 1;
+ }
+ } else {
+ ALOGW("did not find dolby vision profile");
+ }
+ // No dovi csd data, need to create it
+ if (needCreateDoviCSD) {
+ uint8_t dvcc[24];
+ int32_t level = 0;
+ uint8_t level_val = 0;
+
+ if (msg->findInt32("level", &level)) {
+ const static ALookup<int32_t, uint8_t> levels {
+ {DolbyVisionLevelUnknown, 0},
+ {DolbyVisionLevelHd24, 1},
+ {DolbyVisionLevelHd30, 2},
+ {DolbyVisionLevelFhd24, 3},
+ {DolbyVisionLevelFhd30, 4},
+ {DolbyVisionLevelFhd60, 5},
+ {DolbyVisionLevelUhd24, 6},
+ {DolbyVisionLevelUhd30, 7},
+ {DolbyVisionLevelUhd48, 8},
+ {DolbyVisionLevelUhd60, 9},
+ {DolbyVisionLevelUhd120, 10},
+ {DolbyVisionLevel8k30, 11},
+ {DolbyVisionLevel8k60, 12},
+ };
+ levels.map(level, &level_val);
+ ALOGV("found dolby vision level: %d, value: %d", level, level_val);
+ }
+
+ dvcc[0] = 1; // major version
+ dvcc[1] = 0; // minor version
+ dvcc[2] = (uint8_t)((profile & 0x7f) << 1);// dolby vision profile
+ dvcc[2] = (uint8_t)((dvcc[2] | (uint8_t)((level_val >> 5) & 0x1)) & 0xff);
+ dvcc[3] = (uint8_t)((level_val & 0x1f) << 3); // dolby vision level
+ dvcc[3] = (uint8_t)(dvcc[3] | (1 << 2)); // rpu_present_flag
+ dvcc[3] = (uint8_t)(dvcc[3] | (1)); // bl_present_flag
+ dvcc[4] = (uint8_t)(bl_compatibility << 4);// bl_compatibility id
+
+ std::vector<uint8_t> dvcc_data(24);
+ memcpy(dvcc_data.data(), dvcc, 24);
+ if (profile > 10) {
+ meta->setData(kKeyDVWC, kTypeDVWC, dvcc_data.data(), 24);
+ } else if (profile > 7) {
+ meta->setData(kKeyDVVC, kTypeDVVC, dvcc_data.data(), 24);
+ } else {
+ meta->setData(kKeyDVCC, kTypeDVCC, dvcc_data.data(), 24);
+ }
+ } else if (csd0size >= 24) { // have dovi csd, just send it out...
+ uint8_t *dvconfig = csd0->data() + (csd0size -24);
+ profile = dvconfig[2] >> 1;
+ if (profile > 10) {
+ meta->setData(kKeyDVWC, kTypeDVWC, dvconfig, 24);
+ } else if (profile > 7) {
+ meta->setData(kKeyDVVC, kTypeDVVC, dvconfig, 24);
+ } else {
+ meta->setData(kKeyDVCC, kTypeDVCC, dvconfig, 24);
+ }
+ } else {
+ return BAD_VALUE;
+ }
+
+ // Send the avc/hevc/av1 csd data...
+ if (csd0size >= 24) {
+ sp<ABuffer> csd;
+ if ( profile > 1 && profile < 9) {
+ if (msg->findBuffer("csd-hevc", &csd)) {
+ meta->setData(kKeyHVCC, kTypeHVCC, csd->data(), csd->size());
+ } else if (csd0size > 24) {
std::vector<uint8_t> hvcc(csd0size + 1024);
size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
- } else if (DolbyVisionProfileDvav110 == profile) {
- meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
- } else {
- sp<ABuffer> csd1;
- if (msg->findBuffer("csd-1", &csd1)) {
- std::vector<char> avcc(csd0size + csd1->size() + 1024);
- size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
- meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
- }
}
+ } else if (profile == 9) {
+ sp<ABuffer> csd1;
+ if (msg->findBuffer("csd-avc", &csd)) {
+ meta->setData(kKeyAVCC, kTypeAVCC, csd->data(), csd->size());
+ } else if (msg->findBuffer("csd-1", &csd1)) {
+ std::vector<char> avcc(csd0size + csd1->size() + 1024);
+ size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
+ meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+ } else { // for dolby vision avc, csd0 also holds csd1
+ size_t i = 0;
+ int csd0realsize = 0;
+ do {
+ i = findNextNalStartCode(csd0->data() + i,
+ csd0->size() - i) - csd0->data();
+ if (i > 0) {
+ csd0realsize = i;
+ break;
+ }
+ i += 4;
+ } while(i < csd0->size());
+ // buffer0 -> csd0
+ sp<ABuffer> buffer0 = new (std::nothrow) ABuffer(csd0realsize);
+ if (buffer0.get() == NULL || buffer0->base() == NULL) {
+ return NO_MEMORY;
+ }
+ memcpy(buffer0->data(), csd0->data(), csd0realsize);
+ // buffer1 -> csd1
+ sp<ABuffer> buffer1 = new (std::nothrow)
+ ABuffer(csd0->size() - csd0realsize);
+ if (buffer1.get() == NULL || buffer1->base() == NULL) {
+ return NO_MEMORY;
+ }
+ memcpy(buffer1->data(), csd0->data()+csd0realsize,
+ csd0->size() - csd0realsize);
+
+ std::vector<char> avcc(csd0->size() + 1024);
+ size_t outsize = reassembleAVCC(buffer0, buffer1, avcc.data());
+ meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+ }
+ } else if (profile == 10) {
+ meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size() - 24);
}
- } else {
- ALOGE("We need csd-2!!. %s", msg->debugString().c_str());
- return BAD_VALUE;
}
} else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
@@ -2080,17 +2216,6 @@
meta->setData(kKeyStreamHeader, 'mdat', csd0->data(), csd0->size());
} else if (msg->findBuffer("d263", &csd0)) {
meta->setData(kKeyD263, kTypeD263, csd0->data(), csd0->size());
- } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION && msg->findBuffer("csd-2", &csd2)) {
- meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
-
- // Remove CSD-2 from the data here to avoid duplicate data in meta
- meta->remove(kKeyOpaqueCSD2);
-
- if (msg->findBuffer("csd-avc", &csd0)) {
- meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
- } else if (msg->findBuffer("csd-hevc", &csd0)) {
- meta->setData(kKeyHVCC, kTypeHVCC, csd0->data(), csd0->size());
- }
}
// XXX TODO add whatever other keys there are
@@ -2173,29 +2298,29 @@
}
struct aac_format_conv_t {
- OMX_AUDIO_AACPROFILETYPE eAacProfileType;
+ int32_t eAacProfileType;
audio_format_t format;
};
static const struct aac_format_conv_t profileLookup[] = {
- { OMX_AUDIO_AACObjectMain, AUDIO_FORMAT_AAC_MAIN},
- { OMX_AUDIO_AACObjectLC, AUDIO_FORMAT_AAC_LC},
- { OMX_AUDIO_AACObjectSSR, AUDIO_FORMAT_AAC_SSR},
- { OMX_AUDIO_AACObjectLTP, AUDIO_FORMAT_AAC_LTP},
- { OMX_AUDIO_AACObjectHE, AUDIO_FORMAT_AAC_HE_V1},
- { OMX_AUDIO_AACObjectScalable, AUDIO_FORMAT_AAC_SCALABLE},
- { OMX_AUDIO_AACObjectERLC, AUDIO_FORMAT_AAC_ERLC},
- { OMX_AUDIO_AACObjectLD, AUDIO_FORMAT_AAC_LD},
- { OMX_AUDIO_AACObjectHE_PS, AUDIO_FORMAT_AAC_HE_V2},
- { OMX_AUDIO_AACObjectELD, AUDIO_FORMAT_AAC_ELD},
- { OMX_AUDIO_AACObjectXHE, AUDIO_FORMAT_AAC_XHE},
- { OMX_AUDIO_AACObjectNull, AUDIO_FORMAT_AAC},
+ { AACObjectMain, AUDIO_FORMAT_AAC_MAIN},
+ { AACObjectLC, AUDIO_FORMAT_AAC_LC},
+ { AACObjectSSR, AUDIO_FORMAT_AAC_SSR},
+ { AACObjectLTP, AUDIO_FORMAT_AAC_LTP},
+ { AACObjectHE, AUDIO_FORMAT_AAC_HE_V1},
+ { AACObjectScalable, AUDIO_FORMAT_AAC_SCALABLE},
+ { AACObjectERLC, AUDIO_FORMAT_AAC_ERLC},
+ { AACObjectLD, AUDIO_FORMAT_AAC_LD},
+ { AACObjectHE_PS, AUDIO_FORMAT_AAC_HE_V2},
+ { AACObjectELD, AUDIO_FORMAT_AAC_ELD},
+ { AACObjectXHE, AUDIO_FORMAT_AAC_XHE},
+ { AACObjectNull, AUDIO_FORMAT_AAC},
};
void mapAACProfileToAudioFormat( audio_format_t& format, uint64_t eAacProfile)
{
-const struct aac_format_conv_t* p = &profileLookup[0];
- while (p->eAacProfileType != OMX_AUDIO_AACObjectNull) {
+ const struct aac_format_conv_t* p = &profileLookup[0];
+ while (p->eAacProfileType != AACObjectNull) {
if (eAacProfile == p->eAacProfileType) {
format = p->format;
return;
@@ -2235,7 +2360,7 @@
// Offloading depends on audio DSP capabilities.
int32_t aacaot = -1;
if (meta->findInt32(kKeyAACAOT, &aacaot)) {
- mapAACProfileToAudioFormat(info->format,(OMX_AUDIO_AACPROFILETYPE) aacaot);
+ mapAACProfileToAudioFormat(info->format, aacaot);
}
int32_t srate = -1;
diff --git a/media/libstagefright/codecs/common/Android.bp b/media/libstagefright/codecs/common/Android.bp
index 08691e7..affc837 100644
--- a/media/libstagefright/codecs/common/Android.bp
+++ b/media/libstagefright/codecs/common/Android.bp
@@ -21,6 +21,10 @@
name: "libstagefright_enc_common",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
srcs: ["cmnMemory.c"],
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index c7dc415..6004cf8 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaErrors.h>
#include "libyuv/convert_from.h"
@@ -51,13 +52,17 @@
static bool isRGB(OMX_COLOR_FORMATTYPE colorFormat) {
return colorFormat == OMX_COLOR_Format16bitRGB565
|| colorFormat == OMX_COLOR_Format32BitRGBA8888
- || colorFormat == OMX_COLOR_Format32bitBGRA8888;
+ || colorFormat == OMX_COLOR_Format32bitBGRA8888
+ || colorFormat == COLOR_Format32bitABGR2101010;
}
bool ColorConverter::ColorSpace::isBt709() {
return (mStandard == ColorUtils::kColorStandardBT709);
}
+bool ColorConverter::ColorSpace::isBt2020() {
+ return (mStandard == ColorUtils::kColorStandardBT2020);
+}
bool ColorConverter::ColorSpace::isJpeg() {
return ((mStandard == ColorUtils::kColorStandardBT601_625)
@@ -70,16 +75,19 @@
: mSrcFormat(from),
mDstFormat(to),
mSrcColorSpace({0, 0, 0}),
- mClip(NULL) {
+ mClip(NULL),
+ mClip10Bit(NULL) {
}
ColorConverter::~ColorConverter() {
delete[] mClip;
mClip = NULL;
+ delete[] mClip10Bit;
+ mClip10Bit = NULL;
}
bool ColorConverter::isValid() const {
- switch (mSrcFormat) {
+ switch ((int32_t)mSrcFormat) {
case OMX_COLOR_FormatYUV420Planar16:
if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
return true;
@@ -102,6 +110,8 @@
#else
return mDstFormat == OMX_COLOR_Format16bitRGB565;
#endif
+ case COLOR_FormatYUVP010:
+ return mDstFormat == COLOR_Format32bitABGR2101010;
default:
return false;
@@ -143,9 +153,10 @@
mCropTop(cropTop),
mCropRight(cropRight),
mCropBottom(cropBottom) {
- switch(mColorFormat) {
+ switch((int32_t)mColorFormat) {
case OMX_COLOR_Format16bitRGB565:
case OMX_COLOR_FormatYUV420Planar16:
+ case COLOR_FormatYUVP010:
case OMX_COLOR_FormatCbYCrY:
mBpp = 2;
mStride = 2 * mWidth;
@@ -153,6 +164,7 @@
case OMX_COLOR_Format32bitBGRA8888:
case OMX_COLOR_Format32BitRGBA8888:
+ case COLOR_Format32bitABGR2101010:
case OMX_COLOR_FormatYUV444Y410:
mBpp = 4;
mStride = 4 * mWidth;
@@ -213,7 +225,7 @@
status_t err;
- switch (mSrcFormat) {
+ switch ((int32_t)mSrcFormat) {
case OMX_COLOR_FormatYUV420Planar:
#ifdef USE_LIBYUV
err = convertYUV420PlanarUseLibYUV(src, dst);
@@ -235,6 +247,19 @@
break;
}
+ case COLOR_FormatYUVP010:
+ {
+#if PERF_PROFILING
+ int64_t startTimeUs = ALooper::GetNowUs();
+#endif
+ err = convertYUVP010(src, dst);
+#if PERF_PROFILING
+ int64_t endTimeUs = ALooper::GetNowUs();
+ ALOGD("convertYUVP010 took %lld us", (long long) (endTimeUs - startTimeUs));
+#endif
+ break;
+ }
+
case OMX_COLOR_FormatCbYCrY:
err = convertCbYCrY(src, dst);
break;
@@ -439,23 +464,23 @@
}
std::function<void (void *, bool, signed, signed, signed, signed, signed, signed)>
-getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, uint8_t *kAdjustedClip) {
- switch (dstFormat) {
+getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, void *kAdjustedClip) {
+ switch ((int)dstFormat) {
case OMX_COLOR_Format16bitRGB565:
{
return [kAdjustedClip](void *dst_ptr, bool uncropped,
signed r1, signed g1, signed b1,
signed r2, signed g2, signed b2) {
uint32_t rgb1 =
- ((kAdjustedClip[r1] >> 3) << 11)
- | ((kAdjustedClip[g1] >> 2) << 5)
- | (kAdjustedClip[b1] >> 3);
+ ((((uint8_t *)kAdjustedClip)[r1] >> 3) << 11)
+ | ((((uint8_t *)kAdjustedClip)[g1] >> 2) << 5)
+ | (((uint8_t *)kAdjustedClip)[b1] >> 3);
if (uncropped) {
uint32_t rgb2 =
- ((kAdjustedClip[r2] >> 3) << 11)
- | ((kAdjustedClip[g2] >> 2) << 5)
- | (kAdjustedClip[b2] >> 3);
+ ((((uint8_t *)kAdjustedClip)[r2] >> 3) << 11)
+ | ((((uint8_t *)kAdjustedClip)[g2] >> 2) << 5)
+ | (((uint8_t *)kAdjustedClip)[b2] >> 3);
*(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1;
} else {
@@ -469,16 +494,16 @@
signed r1, signed g1, signed b1,
signed r2, signed g2, signed b2) {
((uint32_t *)dst_ptr)[0] =
- (kAdjustedClip[r1])
- | (kAdjustedClip[g1] << 8)
- | (kAdjustedClip[b1] << 16)
+ (((uint8_t *)kAdjustedClip)[r1])
+ | (((uint8_t *)kAdjustedClip)[g1] << 8)
+ | (((uint8_t *)kAdjustedClip)[b1] << 16)
| (0xFF << 24);
if (uncropped) {
((uint32_t *)dst_ptr)[1] =
- (kAdjustedClip[r2])
- | (kAdjustedClip[g2] << 8)
- | (kAdjustedClip[b2] << 16)
+ (((uint8_t *)kAdjustedClip)[r2])
+ | (((uint8_t *)kAdjustedClip)[g2] << 8)
+ | (((uint8_t *)kAdjustedClip)[b2] << 16)
| (0xFF << 24);
}
};
@@ -489,20 +514,41 @@
signed r1, signed g1, signed b1,
signed r2, signed g2, signed b2) {
((uint32_t *)dst_ptr)[0] =
- (kAdjustedClip[b1])
- | (kAdjustedClip[g1] << 8)
- | (kAdjustedClip[r1] << 16)
+ (((uint8_t *)kAdjustedClip)[b1])
+ | (((uint8_t *)kAdjustedClip)[g1] << 8)
+ | (((uint8_t *)kAdjustedClip)[r1] << 16)
| (0xFF << 24);
if (uncropped) {
((uint32_t *)dst_ptr)[1] =
- (kAdjustedClip[b2])
- | (kAdjustedClip[g2] << 8)
- | (kAdjustedClip[r2] << 16)
+ (((uint8_t *)kAdjustedClip)[b2])
+ | (((uint8_t *)kAdjustedClip)[g2] << 8)
+ | (((uint8_t *)kAdjustedClip)[r2] << 16)
| (0xFF << 24);
}
};
}
+ case COLOR_Format32bitABGR2101010:
+ {
+ return [kAdjustedClip](void *dst_ptr, bool uncropped,
+ signed r1, signed g1, signed b1,
+ signed r2, signed g2, signed b2) {
+ ((uint32_t *)dst_ptr)[0] =
+ (((uint16_t *)kAdjustedClip)[r1])
+ | (((uint16_t *)kAdjustedClip)[g1] << 10)
+ | (((uint16_t *)kAdjustedClip)[b1] << 20)
+ | (3 << 30);
+
+ if (uncropped) {
+ ((uint32_t *)dst_ptr)[1] =
+ (((uint16_t *)kAdjustedClip)[r2])
+ | (((uint16_t *)kAdjustedClip)[g2] << 10)
+ | (((uint16_t *)kAdjustedClip)[b2] << 20)
+ | (3 << 30);
+ }
+ };
+ }
+
default:
TRESPASS();
}
@@ -514,7 +560,7 @@
uint8_t *kAdjustedClip = initClip();
auto readFromSrc = getReadFromSrc(mSrcFormat);
- auto writeToDst = getWriteToDst(mDstFormat, kAdjustedClip);
+ auto writeToDst = getWriteToDst(mDstFormat, (void *)kAdjustedClip);
uint8_t *dst_ptr = (uint8_t *)dst.mBits
+ dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
@@ -591,34 +637,116 @@
return convertYUV420Planar(src, dst);
}
-/*
- * Pack 10-bit YUV into RGBA_1010102.
- *
- * Media sends 10-bit YUV in a RGBA_1010102 format buffer. SF will handle
- * the conversion to RGB using RenderEngine fallback.
- *
- * We do not perform a YUV->RGB conversion here, however the conversion with
- * BT2020 to Full range is below for reference:
- *
- * B = 1.168 *(Y - 64) + 2.148 *(U - 512)
- * G = 1.168 *(Y - 64) - 0.652 *(V - 512) - 0.188 *(U - 512)
- * R = 1.168 *(Y - 64) + 1.683 *(V - 512)
- *
- * B = 1196/1024 *(Y - 64) + 2200/1024 *(U - 512)
- * G = .................... - 668/1024 *(V - 512) - 192/1024 *(U - 512)
- * R = .................... + 1723/1024 *(V - 512)
- *
- * min_B = (1196 *(- 64) + 2200 *(- 512)) / 1024 = -1175
- * min_G = (1196 *(- 64) - 668 *(1023 - 512) - 192 *(1023 - 512)) / 1024 = -504
- * min_R = (1196 *(- 64) + 1723 *(- 512)) / 1024 = -937
- *
- * max_B = (1196 *(1023 - 64) + 2200 *(1023 - 512)) / 1024 = 2218
- * max_G = (1196 *(1023 - 64) - 668 *(- 512) - 192 *(- 512)) / 1024 = 1551
- * max_R = (1196 *(1023 - 64) + 1723 *(1023 - 512)) / 1024 = 1980
- *
- * clip range -1175 .. 2218
- *
- */
+status_t ColorConverter::convertYUVP010(
+ const BitmapParams &src, const BitmapParams &dst) {
+ if (mDstFormat == COLOR_Format32bitABGR2101010) {
+ return convertYUVP010ToRGBA1010102(src, dst);
+ }
+
+ return ERROR_UNSUPPORTED;
+}
+
+status_t ColorConverter::convertYUVP010ToRGBA1010102(
+ const BitmapParams &src, const BitmapParams &dst) {
+ uint16_t *kAdjustedClip10bit = initClip10Bit();
+
+// auto readFromSrc = getReadFromSrc(mSrcFormat);
+ auto writeToDst = getWriteToDst(mDstFormat, (void *)kAdjustedClip10bit);
+
+ uint8_t *dst_ptr = (uint8_t *)dst.mBits
+ + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
+
+ uint16_t *src_y = (uint16_t *)((uint8_t *)src.mBits
+ + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp);
+
+ uint16_t *src_uv = (uint16_t *)((uint8_t *)src.mBits
+ + src.mStride * src.mHeight
+ + (src.mCropTop / 2) * src.mStride + src.mCropLeft * src.mBpp);
+
+ // BT.2020 Limited Range conversion
+
+ // B = 1.168 *(Y - 64) + 2.148 *(U - 512)
+ // G = 1.168 *(Y - 64) - 0.652 *(V - 512) - 0.188 *(U - 512)
+ // R = 1.168 *(Y - 64) + 1.683 *(V - 512)
+
+ // B = 1196/1024 *(Y - 64) + 2200/1024 *(U - 512)
+ // G = .................... - 668/1024 *(V - 512) - 192/1024 *(U - 512)
+ // R = .................... + 1723/1024 *(V - 512)
+
+ // min_B = (1196 *(- 64) + 2200 *(- 512)) / 1024 = -1175
+ // min_G = (1196 *(- 64) - 668 *(1023 - 512) - 192 *(1023 - 512)) / 1024 = -504
+ // min_R = (1196 *(- 64) + 1723 *(- 512)) / 1024 = -937
+
+ // max_B = (1196 *(1023 - 64) + 2200 *(1023 - 512)) / 1024 = 2218
+ // max_G = (1196 *(1023 - 64) - 668 *(- 512) - 192 *(- 512)) / 1024 = 1551
+ // max_R = (1196 *(1023 - 64) + 1723 *(1023 - 512)) / 1024 = 1980
+
+ // clip range -1175 .. 2218
+
+ // BT.709 Limited Range conversion
+
+ // B = 1.164 * (Y - 64) + 2.018 * (U - 512)
+ // G = 1.164 * (Y - 64) - 0.813 * (V - 512) - 0.391 * (U - 512)
+ // R = 1.164 * (Y - 64) + 1.596 * (V - 512)
+
+ // B = 1192/1024 * (Y - 64) + 2068/1024 * (U - 512)
+ // G = .................... - 832/1024 * (V - 512) - 400/1024 * (U - 512)
+ // R = .................... + 1636/1024 * (V - 512)
+
+ // min_B = (1192 * (- 64) + 2068 * (- 512)) / 1024 = -1108
+
+ // max_B = (1192 * (1023 - 64) + 517 * (1023 - 512)) / 1024 = 2148
+
+ // clip range -1108 .. 2148
+
+ signed mY = 1196, mU_B = 2200, mV_G = -668, mV_R = 1723, mU_G = -192;
+ if (!mSrcColorSpace.isBt2020()) {
+ mY = 1192;
+ mU_B = 2068;
+ mV_G = -832;
+ mV_R = 1636;
+ mU_G = -400;
+ }
+ for (size_t y = 0; y < src.cropHeight(); ++y) {
+ for (size_t x = 0; x < src.cropWidth(); x += 2) {
+ signed y1, y2, u, v;
+ y1 = (src_y[x] >> 6) - 64;
+ y2 = (src_y[x + 1] >> 6) - 64;
+ u = int(src_uv[x] >> 6) - 512;
+ v = int(src_uv[x + 1] >> 6) - 512;
+
+ signed u_b = u * mU_B;
+ signed u_g = u * mU_G;
+ signed v_g = v * mV_G;
+ signed v_r = v * mV_R;
+
+ signed tmp1 = y1 * mY;
+ signed b1 = (tmp1 + u_b) / 1024;
+ signed g1 = (tmp1 + v_g + u_g) / 1024;
+ signed r1 = (tmp1 + v_r) / 1024;
+
+ signed tmp2 = y2 * mY;
+ signed b2 = (tmp2 + u_b) / 1024;
+ signed g2 = (tmp2 + v_g + u_g) / 1024;
+ signed r2 = (tmp2 + v_r) / 1024;
+
+ bool uncropped = x + 1 < src.cropWidth();
+
+ writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2);
+ }
+
+ src_y += src.mStride / 2;
+
+ if (y & 1) {
+ src_uv += src.mStride / 2;
+ }
+
+ dst_ptr += dst.mStride;
+ }
+
+ return OK;
+}
+
#if !USE_NEON_Y410
@@ -1033,4 +1161,19 @@
return &mClip[-kClipMin];
}
+uint16_t *ColorConverter::initClip10Bit() {
+ static const signed kClipMin = -1176;
+ static const signed kClipMax = 2219;
+
+ if (mClip10Bit == NULL) {
+ mClip10Bit = new uint16_t[kClipMax - kClipMin + 1];
+
+ for (signed i = kClipMin; i <= kClipMax; ++i) {
+ mClip10Bit[i - kClipMin] = (i < 0) ? 0 : (i > 1023) ? 1023 : (uint16_t)i;
+ }
+ }
+
+ return &mClip10Bit[-kClipMin];
+}
+
} // namespace android
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 665aae1..83fcc01 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -21,6 +21,12 @@
name: "libstagefright_flacdec",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+
host_supported: true,
srcs: [
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 5f86c22..1b31392 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -23,6 +23,11 @@
vendor_available: true,
host_supported: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
}
cc_defaults {
@@ -130,12 +135,19 @@
name: "libstagefright_foundation",
defaults: ["libstagefright_foundation_defaults"],
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
}
cc_library_static {
name: "libstagefright_foundation_without_imemory",
defaults: ["libstagefright_foundation_defaults"],
min_sdk_version: "29",
+ apex_available: ["com.android.media"],
+
cflags: [
"-Wno-multichar",
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index 3f5ba47..bea3e34 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -20,6 +20,11 @@
cc_library_static {
name: "libstagefright_id3",
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+
srcs: ["ID3.cpp"],
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index 75b0d8e..1d86a22 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -54,6 +54,7 @@
uint32_t mTransfer;
bool isBt709();
+ bool isBt2020();
bool isJpeg();
};
@@ -78,8 +79,10 @@
OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
ColorSpace mSrcColorSpace;
uint8_t *mClip;
+ uint16_t *mClip10Bit;
uint8_t *initClip();
+ uint16_t *initClip10Bit();
status_t convertCbYCrY(
const BitmapParams &src, const BitmapParams &dst);
@@ -111,6 +114,12 @@
status_t convertTIYUV420PackedSemiPlanar(
const BitmapParams &src, const BitmapParams &dst);
+ status_t convertYUVP010(
+ const BitmapParams &src, const BitmapParams &dst);
+
+ status_t convertYUVP010ToRGBA1010102(
+ const BitmapParams &src, const BitmapParams &dst);
+
ColorConverter(const ColorConverter &);
ColorConverter &operator=(const ColorConverter &);
};
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 656267c..fa9dc8b 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -540,6 +540,9 @@
constexpr int32_t DolbyVisionLevelUhd30 = 0x40;
constexpr int32_t DolbyVisionLevelUhd48 = 0x80;
constexpr int32_t DolbyVisionLevelUhd60 = 0x100;
+constexpr int32_t DolbyVisionLevelUhd120 = 0x200;
+constexpr int32_t DolbyVisionLevel8k30 = 0x400;
+constexpr int32_t DolbyVisionLevel8k60 = 0x800;
inline static const char *asString_DolbyVisionLevel(int32_t i, const char *def = "??") {
switch (i) {
@@ -552,6 +555,9 @@
case DolbyVisionLevelUhd30: return "Uhd30";
case DolbyVisionLevelUhd48: return "Uhd48";
case DolbyVisionLevelUhd60: return "Uhd60";
+ case DolbyVisionLevelUhd120: return "Uhd120";
+ case DolbyVisionLevel8k30: return "8k30";
+ case DolbyVisionLevel8k60: return "8k60";
default: return def;
}
}
@@ -586,9 +592,11 @@
constexpr int32_t COLOR_Format24bitBGR888 = 12;
constexpr int32_t COLOR_Format24bitRGB888 = 11;
constexpr int32_t COLOR_Format25bitARGB1888 = 14;
+constexpr int32_t COLOR_Format32bitABGR2101010 = 0x7F00AAA2;
constexpr int32_t COLOR_Format32bitABGR8888 = 0x7F00A000;
constexpr int32_t COLOR_Format32bitARGB8888 = 16;
constexpr int32_t COLOR_Format32bitBGRA8888 = 15;
+constexpr int32_t COLOR_Format64bitABGRFloat = 0x7F000F16;
constexpr int32_t COLOR_Format8bitRGB332 = 2;
constexpr int32_t COLOR_FormatCbYCrY = 27;
constexpr int32_t COLOR_FormatCrYCbY = 28;
@@ -642,9 +650,11 @@
case COLOR_Format24bitBGR888: return "24bitBGR888";
case COLOR_Format24bitRGB888: return "24bitRGB888";
case COLOR_Format25bitARGB1888: return "25bitARGB1888";
+ case COLOR_Format32bitABGR2101010: return "32bitABGR2101010";
case COLOR_Format32bitABGR8888: return "32bitABGR8888";
case COLOR_Format32bitARGB8888: return "32bitARGB8888";
case COLOR_Format32bitBGRA8888: return "32bitBGRA8888";
+ case COLOR_Format64bitABGRFloat: return "64bitABGRFloat";
case COLOR_Format8bitRGB332: return "8bitRGB332";
case COLOR_FormatCbYCrY: return "CbYCrY";
case COLOR_FormatCrYCbY: return "CrYCbY";
@@ -677,6 +687,7 @@
case COLOR_FormatYUV422SemiPlanar: return "YUV422SemiPlanar";
case COLOR_FormatYUV444Flexible: return "YUV444Flexible";
case COLOR_FormatYUV444Interleaved: return "YUV444Interleaved";
+ case COLOR_FormatYUVP010: return "YUVP010";
case COLOR_QCOM_FormatYUV420SemiPlanar: return "QCOM_YUV420SemiPlanar";
case COLOR_TI_FormatYUV420PackedSemiPlanar: return "TI_YUV420PackedSemiPlanar";
default: return def;
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index c80012e..88c1f3f 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -60,6 +60,8 @@
kKeyAVCC = 'avcc', // raw data
kKeyHVCC = 'hvcc', // raw data
kKeyDVCC = 'dvcc', // raw data
+ kKeyDVVC = 'dvvc', // raw data
+ kKeyDVWC = 'dvwc', // raw data
kKeyAV1C = 'av1c', // raw data
kKeyThumbnailHVCC = 'thvc', // raw data
kKeyThumbnailAV1C = 'tav1', // raw data
@@ -283,6 +285,8 @@
kTypeHVCC = 'hvcc',
kTypeAV1C = 'av1c',
kTypeDVCC = 'dvcc',
+ kTypeDVVC = 'dvvc',
+ kTypeDVWC = 'dvwc',
kTypeD263 = 'd263',
kTypeHCOS = 'hcos',
};
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 6c5e6cb..f50acae 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -145,6 +145,7 @@
"libgui",
"libui",
"libmediandk_utils",
+ "android.hardware.drm-V1-ndk",
],
export_header_lib_headers: ["jni_headers"],
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 99f81c7..733fea4 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -31,6 +31,7 @@
#include <sys/resource.h>
#include <thread>
+#include <android-base/stringprintf.h>
#include <android/media/IAudioPolicyService.h>
#include <android/os/IExternalVibratorService.h>
#include <binder/IPCThreadState.h>
@@ -106,6 +107,7 @@
#define MAX_AAUDIO_PROPERTY_DEVICE_HAL_VERSION 7.0
+using ::android::base::StringPrintf;
using media::IEffectClient;
using media::audio::common::AudioMMapPolicyInfo;
using media::audio::common::AudioMMapPolicyType;
@@ -4088,11 +4090,14 @@
sp<EffectModule> effect = chain->getEffectFromId_l(0);
Vector< sp<EffectModule> > removed;
status_t status = NO_ERROR;
+ std::string errorString;
while (effect != 0) {
srcThread->removeEffect_l(effect);
removed.add(effect);
status = dstThread->addEffect_l(effect);
if (status != NO_ERROR) {
+ errorString = StringPrintf(
+ "cannot add effect %p to destination thread", effect.get());
break;
}
// removeEffect_l() has stopped the effect if it was active so it must be restarted
@@ -4105,7 +4110,7 @@
if (dstChain == 0) {
dstChain = effect->getCallback()->chain().promote();
if (dstChain == 0) {
- ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
+ errorString = StringPrintf("cannot get chain from effect %p", effect.get());
status = NO_INIT;
break;
}
@@ -4113,12 +4118,28 @@
effect = chain->getEffectFromId_l(0);
}
+ size_t restored = 0;
if (status != NO_ERROR) {
- for (size_t i = 0; i < removed.size(); i++) {
- srcThread->addEffect_l(removed[i]);
+ for (const auto& effect : removed) {
+ if (srcThread->addEffect_l(effect) == NO_ERROR) {
+ ++restored;
+ }
}
}
+ if (status != NO_ERROR) {
+ if (errorString.empty()) {
+ errorString = StringPrintf("%s: failed status %d", __func__, status);
+ }
+ ALOGW("%s: %s unsuccessful move of session %d from srcThread %p to dstThread %p "
+ "(%zu effects removed from srcThread, %zu effects restored to srcThread)",
+ __func__, errorString.c_str(), sessionId, srcThread, dstThread,
+ removed.size(), restored);
+ } else {
+ ALOGD("%s: successful move of session %d from srcThread %p to dstThread %p "
+ "(%zu effects moved)",
+ __func__, sessionId, srcThread, dstThread, removed.size());
+ }
return status;
}
diff --git a/services/audioflinger/OWNERS b/services/audioflinger/OWNERS
index 034d161..17d4c37 100644
--- a/services/audioflinger/OWNERS
+++ b/services/audioflinger/OWNERS
@@ -1,4 +1,4 @@
-gkasten@google.com
hunga@google.com
jmtrivi@google.com
mnaganov@google.com
+philburk@google.com
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index ea958f5..e8e478b 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -300,6 +300,8 @@
virtual bool isHapticPlaybackSupported() = 0;
+ virtual bool isUltrasoundSupported() = 0;
+
virtual status_t getHwOffloadFormatsSupportedForBluetoothMedia(
audio_devices_t device, std::vector<audio_format_t> *formats) = 0;
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 150a9a8..7a06206 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -71,7 +71,10 @@
audio_policy_dev_state_t state)
{
audio_devices_t deviceType = devDesc->type();
- if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)) {
+ if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)
+ && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ // USB dock does not follow the rule of last removable device connected wins.
+ // It is only used if no removable device is connected or if set as preferred device
mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
}
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 4c3d92c..dc34a38 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -272,7 +272,8 @@
devices = availableOutputDevices.getFirstDevicesFromTypes(
getLastRemovableMediaDevices());
if (!devices.isEmpty()) break;
- devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_EARPIECE);
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_EARPIECE});
} break;
case STRATEGY_SONIFICATION:
@@ -364,7 +365,8 @@
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
}
if (devices2.isEmpty()) {
- devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_SPEAKER});
}
DeviceVector devices3;
if (strategy == STRATEGY_MEDIA) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 48176da..bd295ce 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4933,6 +4933,37 @@
return false;
}
+bool AudioPolicyManager::isUltrasoundSupported()
+{
+ bool hasUltrasoundOutput = false;
+ bool hasUltrasoundInput = false;
+ for (const auto& hwModule : mHwModules) {
+ const OutputProfileCollection &outputProfiles = hwModule->getOutputProfiles();
+ if (!hasUltrasoundOutput) {
+ for (const auto &outProfile : outputProfiles) {
+ if (outProfile->getFlags() & AUDIO_OUTPUT_FLAG_ULTRASOUND) {
+ hasUltrasoundOutput = true;
+ break;
+ }
+ }
+ }
+
+ const InputProfileCollection &inputProfiles = hwModule->getInputProfiles();
+ if (!hasUltrasoundInput) {
+ for (const auto &inputProfile : inputProfiles) {
+ if (inputProfile->getFlags() & AUDIO_INPUT_FLAG_ULTRASOUND) {
+ hasUltrasoundInput = true;
+ break;
+ }
+ }
+ }
+
+ if (hasUltrasoundOutput && hasUltrasoundInput)
+ return true;
+ }
+ return false;
+}
+
bool AudioPolicyManager::isCallScreenModeSupported()
{
return getConfig().isCallScreenModeSupported();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index b4fc4d4..165ac13 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -327,6 +327,8 @@
virtual bool isHapticPlaybackSupported();
+ virtual bool isUltrasoundSupported();
+
virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies)
{
return mEngine->listAudioProductStrategies(strategies);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 3929e55..87a350f 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -166,6 +166,7 @@
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
return Status::ok();
}
+ Mutex::Autolock _l(mLock);
AutoCallerClear acc;
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(
@@ -2058,6 +2059,17 @@
return Status::ok();
}
+Status AudioPolicyService::isUltrasoundSupported(bool* _aidl_return)
+{
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ *_aidl_return = mAudioPolicyManager->isUltrasoundSupported();
+ return Status::ok();
+}
+
Status AudioPolicyService::listAudioProductStrategies(
std::vector<media::AudioProductStrategy>* _aidl_return) {
AudioProductStrategyVector strategies;
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index ba28857..ac5af6b 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -224,6 +224,7 @@
binder::Status setA11yServicesUids(const std::vector<int32_t>& uids) override;
binder::Status setCurrentImeUid(int32_t uid) override;
binder::Status isHapticPlaybackSupported(bool* _aidl_return) override;
+ binder::Status isUltrasoundSupported(bool* _aidl_return) override;
binder::Status listAudioProductStrategies(
std::vector<media::AudioProductStrategy>* _aidl_return) override;
binder::Status getProductStrategyFromAudioAttributes(const media::AudioAttributesEx& aa,
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index 440a7ff..ef0eb2a 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -40,20 +40,6 @@
// This is how fast, in rad/s, we allow rotation angle to shift during rate-limiting.
constexpr float kMaxRotationalVelocity = 8;
-// This should be set to the typical time scale that the translation sensors used drift in. This
-// means, loosely, for how long we can trust the reading to be "accurate enough". This would
-// determine the time constants used for high-pass filtering those readings. If the value is set
-// too high, we may experience drift. If it is set too low, we may experience poses tending toward
-// identity too fast.
-constexpr auto kTranslationalDriftTimeConstant = 40s;
-
-// This should be set to the typical time scale that the rotation sensors used drift in. This
-// means, loosely, for how long we can trust the reading to be "accurate enough". This would
-// determine the time constants used for high-pass filtering those readings. If the value is set
-// too high, we may experience drift. If it is set too low, we may experience poses tending toward
-// identity too fast.
-constexpr auto kRotationalDriftTimeConstant = 60s;
-
// This is how far into the future we predict the head pose, using linear extrapolation based on
// twist (velocity). It should be set to a value that matches the characteristic durations of moving
// one's head. The higher we set this, the more latency we are able to reduce, but setting this too
@@ -100,9 +86,6 @@
mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
.maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
.maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
- .translationalDriftTimeConstant =
- double(Ticks(kTranslationalDriftTimeConstant).count()),
- .rotationalDriftTimeConstant = double(Ticks(kRotationalDriftTimeConstant).count()),
.freshnessTimeout = Ticks(sensorPeriod * kMaxLostSamples).count(),
.predictionDuration = Ticks(kPredictionDuration).count(),
.autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index bf4d524..4488efb 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -19,6 +19,7 @@
name: "mediaswcodec",
vendor_available: true,
min_sdk_version: "29",
+ apex_available: ["com.android.media.swcodec"],
srcs: [
"main_swcodecservice.cpp",
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index d10e339..12cc32a 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -10,6 +10,12 @@
cc_library {
name: "libmedia_codecserviceregistrant",
vendor_available: true,
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
srcs: [
"CodecServiceRegistrant.cpp",
],
diff --git a/services/minijail/Android.bp b/services/minijail/Android.bp
index 038197f..decc5fe 100644
--- a/services/minijail/Android.bp
+++ b/services/minijail/Android.bp
@@ -28,6 +28,11 @@
defaults: ["libavservices_minijail_defaults"],
vendor_available: true,
min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+
export_include_dirs: ["."],
}