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> &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> 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> &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;
+    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 &paramSets);
 
+    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: ["."],
 }