Merge "CCodec: fix update pixelFormatInfo for pre-S"
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 32d7723..e04dd7e 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -619,6 +619,7 @@
         return Void();
     }
 
+    Mutex::Autolock lock(mSecurityLevelLock);
     std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr =
             mSecurityLevel.find(sid);
     if (itr == mSecurityLevel.end()) {
@@ -691,6 +692,7 @@
         return Status::ERROR_DRM_SESSION_NOT_OPENED;
     }
 
+    Mutex::Autolock lock(mSecurityLevelLock);
     std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr =
             mSecurityLevel.find(sid);
     if (itr != mSecurityLevel.end()) {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index cb5c9fe..1019520 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -414,7 +414,8 @@
     std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
     std::map<std::string, std::vector<uint8_t> > mReleaseKeysMap;
     std::map<std::vector<uint8_t>, std::string> mPlaybackId;
-    std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel;
+    std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel
+        GUARDED_BY(mSecurityLevelLock);
     sp<IDrmPluginListener> mListener;
     sp<IDrmPluginListener_V1_2> mListenerV1_2;
     SessionLibrary *mSessionLibrary;
@@ -434,6 +435,7 @@
 
     DeviceFiles mFileHandle;
     Mutex mSecureStopLock;
+    Mutex mSecurityLevelLock;
 
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
 };
diff --git a/media/codec2/hidl/services/Android.bp b/media/codec2/hidl/services/Android.bp
index b36e80a..524519c 100644
--- a/media/codec2/hidl/services/Android.bp
+++ b/media/codec2/hidl/services/Android.bp
@@ -85,6 +85,9 @@
         arm64: {
             src: "seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy",
         },
+        riscv64: {
+            src: "seccomp_policy/android.hardware.media.c2@1.2-default-riscv64.policy",
+        },
         x86: {
             src: "seccomp_policy/android.hardware.media.c2@1.2-default-x86.policy",
         },
@@ -96,3 +99,4 @@
     // This may be removed.
     required: ["crash_dump.policy"],
 }
+
diff --git a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-riscv64.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-riscv64.policy
new file mode 100644
index 0000000..27f0b95
--- /dev/null
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-riscv64.policy
@@ -0,0 +1,75 @@
+# Copyright (C) 2019 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.
+
+futex: 1
+# ioctl calls are filtered via the selinux policy.
+ioctl: 1
+sched_yield: 1
+close: 1
+dup: 1
+ppoll: 1
+mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+mmap: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+getuid: 1
+getrlimit: 1
+fstat: 1
+newfstatat: 1
+fstatfs: 1
+memfd_create: 1
+ftruncate: 1
+
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
+munmap: 1
+prctl: 1
+writev: 1
+sigaltstack: 1
+clone: 1
+exit: 1
+lseek: 1
+rt_sigprocmask: 1
+openat: 1
+write: 1
+nanosleep: 1
+setpriority: 1
+set_tid_address: 1
+getdents64: 1
+readlinkat: 1
+read: 1
+pread64: 1
+gettimeofday: 1
+faccessat: 1
+exit_group: 1
+restart_syscall: 1
+rt_sigreturn: 1
+getrandom: 1
+madvise: 1
+
+# crash dump policy additions
+clock_gettime: 1
+getpid: 1
+gettid: 1
+pipe2: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigaction: 1
+rt_tgsigqueueinfo: 1
+#mprotect: arg2 in 0x1|0x2
+munmap: 1
+#mmap: arg2 in 0x1|0x2
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
+
diff --git a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
index ef5800d..332d3ac 100644
--- a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp
@@ -38,7 +38,7 @@
            !strcmp(deviceCodeName, "Tiramisu");
 }
 
-bool isVendorApiOrFirstApiAtLeastT() {
+static bool isP010Allowed() {
     // The first SDK the device shipped with.
     static const int32_t kProductFirstApiLevel =
         base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
@@ -47,6 +47,17 @@
     // to signal which VSR requirements they conform to even if the first device SDK was higher.
     static const int32_t kBoardFirstApiLevel =
         base::GetIntProperty<int32_t>("ro.board.first_api_level", 0);
+
+    // Some devices that launched prior to Android S may not support P010 correctly, even
+    // though they may advertise it as supported.
+    if (kProductFirstApiLevel != 0 && kProductFirstApiLevel < __ANDROID_API_S__) {
+        return false;
+    }
+
+    if (kBoardFirstApiLevel != 0 && kBoardFirstApiLevel < __ANDROID_API_S__) {
+        return false;
+    }
+
     static const int32_t kBoardApiLevel =
         base::GetIntProperty<int32_t>("ro.board.api_level", 0);
 
@@ -67,7 +78,7 @@
     // API alone. For now limit P010 to devices that launched with Android T or known to conform
     // to Android T VSR (as opposed to simply limiting to a T vendor image).
     if (format == (AHardwareBuffer_Format)HAL_PIXEL_FORMAT_YCBCR_P010 &&
-            !isVendorApiOrFirstApiAtLeastT()) {
+            !isP010Allowed()) {
         return false;
     }
 
diff --git a/media/codec2/vndk/include/C2SurfaceSyncObj.h b/media/codec2/vndk/include/C2SurfaceSyncObj.h
index ac87fe4..d858f27 100644
--- a/media/codec2/vndk/include/C2SurfaceSyncObj.h
+++ b/media/codec2/vndk/include/C2SurfaceSyncObj.h
@@ -72,12 +72,13 @@
     /**
      * Notify a buffer is queued. Return whether the upcoming dequeue operation
      * is not blocked. if it's blocked and waitId is non-null, waitId is returned
-     * to be used for waiting.
+     * to be used for waiting. Notify(wake-up) waitors only when 'notify' is
+     * true.
      *
      * \retval false    dequeue operation is blocked now.
      * \retval true     dequeue operation is possible.
      */
-    bool notifyQueuedLocked(uint32_t *waitId = nullptr);
+    bool notifyQueuedLocked(uint32_t *waitId = nullptr, bool notify = true);
 
     /**
      * Notify a buffer is dequeued.
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index e67e42f..270bbf4 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -436,8 +436,8 @@
             if (status == -ETIME) {
                 // fence is not signalled yet.
                 if (syncVar) {
-                    syncVar->lock();
                     (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+                    syncVar->lock();
                     dequeueable = syncVar->notifyQueuedLocked(&waitId);
                     syncVar->unlock();
                     if (c2Fence) {
@@ -452,8 +452,8 @@
             if (status != android::NO_ERROR) {
                 ALOGD("buffer fence wait error %d", status);
                 if (syncVar) {
-                    syncVar->lock();
                     (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+                    syncVar->lock();
                     syncVar->notifyQueuedLocked();
                     syncVar->unlock();
                     if (c2Fence) {
@@ -502,8 +502,8 @@
             } else if (status != android::NO_ERROR) {
                 slotBuffer.clear();
                 if (syncVar) {
-                    syncVar->lock();
                     (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+                    syncVar->lock();
                     syncVar->notifyQueuedLocked();
                     syncVar->unlock();
                     if (c2Fence) {
@@ -550,8 +550,8 @@
             // Block was not created. call requestBuffer# again next time.
             slotBuffer.clear();
             if (syncVar) {
-                syncVar->lock();
                 (void)mProducer->cancelBuffer(slot, hFenceWrapper.getHandle()).isOk();
+                syncVar->lock();
                 syncVar->notifyQueuedLocked();
                 syncVar->unlock();
                 if (c2Fence) {
@@ -813,11 +813,10 @@
         if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId && !mOwner.expired()) {
             C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
             if (syncVar) {
+                mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
                 syncVar->lock();
-                if (syncVar->getSyncStatusLocked() == C2SyncVariables::STATUS_ACTIVE) {
-                    mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
-                    syncVar->notifyQueuedLocked();
-                }
+                syncVar->notifyQueuedLocked(nullptr,
+                        syncVar->getSyncStatusLocked() == C2SyncVariables::STATUS_ACTIVE);
                 syncVar->unlock();
             } else {
                 mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
@@ -826,11 +825,10 @@
     } else if (!mOwner.expired()) {
         C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
         if (syncVar) {
+            mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
             syncVar->lock();
-            if (syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_SWITCHING) {
-                mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
-                syncVar->notifyQueuedLocked();
-            }
+            syncVar->notifyQueuedLocked(nullptr,
+                    syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_SWITCHING);
             syncVar->unlock();
         } else {
             mIgbp->cancelBuffer(mBqSlot, hidl_handle{}).isOk();
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index 2115cc3..99bccac 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -177,12 +177,14 @@
     return true;
 }
 
-bool C2SyncVariables::notifyQueuedLocked(uint32_t *waitId) {
+bool C2SyncVariables::notifyQueuedLocked(uint32_t *waitId, bool notify) {
     // Note. thundering herds may occur. Edge trigged signalling.
     // But one waiter will guarantee to dequeue. others may wait again.
     // Minimize futex syscall(trap) for the main use case(one waiter case).
     if (mMaxDequeueCount == mCurDequeueCount--) {
-        broadcast();
+        if (notify) {
+            broadcast();
+        }
         return true;
     }
 
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index 1521882..6586e01 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -1039,6 +1039,16 @@
         {
             AUDIO_FORMAT_DRA, make_AudioFormatDescription(MEDIA_MIMETYPE_AUDIO_DRA)
         },
+        {
+            // Note: not in the IANA registry.
+            AUDIO_FORMAT_APTX_ADAPTIVE_QLEA,
+            make_AudioFormatDescription("audio/vnd.qcom.aptx.adaptive.r3")
+        },
+        {
+            // Note: not in the IANA registry.
+            AUDIO_FORMAT_APTX_ADAPTIVE_R4,
+            make_AudioFormatDescription("audio/vnd.qcom.aptx.adaptive.r4")
+        },
     }};
     return pairs;
 }
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
new file mode 100644
index 0000000..2defa4e
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BundleContext"
+#include <Utils.h>
+
+#include "BundleContext.h"
+#include "BundleTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+RetCode BundleContext::init() {
+    // init with pre-defined preset NORMAL
+    for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+        mBandGaindB[i] = lvm::kSoftPresets[0 /* normal */][i];
+    }
+
+    // allocate lvm instance
+    LVM_ReturnStatus_en status;
+    LVM_InstParams_t params = {.BufferMode = LVM_UNMANAGED_BUFFERS,
+                               .MaxBlockSize = lvm::MAX_CALL_SIZE,
+                               .EQNB_NumBands = lvm::MAX_NUM_BANDS,
+                               .PSA_Included = LVM_PSA_ON};
+    status = LVM_GetInstanceHandle(&mInstance, &params);
+    GOTO_IF_LVM_ERROR(status, deinit, "LVM_GetInstanceHandleFailed");
+
+    // set control
+    LVM_ControlParams_t controlParams;
+    initControlParameter(controlParams);
+    status = LVM_SetControlParameters(mInstance, &controlParams);
+    GOTO_IF_LVM_ERROR(status, deinit, "LVM_SetControlParametersFailed");
+
+    /* Set the headroom parameters */
+    LVM_HeadroomParams_t headroomParams;
+    initHeadroomParameter(headroomParams);
+    status = LVM_SetHeadroomParams(mInstance, &headroomParams);
+    GOTO_IF_LVM_ERROR(status, deinit, "LVM_SetHeadroomParamsFailed");
+
+    return RetCode::SUCCESS;
+
+deinit:
+    deInit();
+    return RetCode::ERROR_EFFECT_LIB_ERROR;
+}
+
+void BundleContext::deInit() {
+    if (mInstance) {
+        LVM_DelInstanceHandle(&mInstance);
+        mInstance = nullptr;
+    }
+}
+
+RetCode BundleContext::enable() {
+    LVM_ControlParams_t params;
+    RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, &params),
+                    RetCode::ERROR_EFFECT_LIB_ERROR, "failGetControlParams");
+    if (mType == lvm::BundleEffectType::EQUALIZER) {
+        LOG(DEBUG) << __func__ << " enable bundle EQ";
+        params.EQNB_OperatingMode = LVM_EQNB_ON;
+    }
+    RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
+                    RetCode::ERROR_EFFECT_LIB_ERROR, "failSetControlParams");
+    mEnabled = true;
+    // LvmEffect_limitLevel(pContext);
+    return RetCode::SUCCESS;
+}
+
+RetCode BundleContext::disable() {
+    LVM_ControlParams_t params;
+    RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, &params),
+                    RetCode::ERROR_EFFECT_LIB_ERROR, "failGetControlParams");
+    if (mType == lvm::BundleEffectType::EQUALIZER) {
+        LOG(DEBUG) << __func__ << " disable bundle EQ";
+        params.EQNB_OperatingMode = LVM_EQNB_OFF;
+    }
+    RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
+                    RetCode::ERROR_EFFECT_LIB_ERROR, "failSetControlParams");
+    mEnabled = false;
+    // LvmEffect_limitLevel(pContext);
+    return RetCode::SUCCESS;
+}
+
+LVM_INT16 BundleContext::LVC_ToDB_s32Tos16(LVM_INT32 Lin_fix) const {
+    LVM_INT16 db_fix;
+    LVM_INT16 Shift;
+    LVM_INT16 SmallRemainder;
+    LVM_UINT32 Remainder = (LVM_UINT32)Lin_fix;
+
+    /* Count leading bits, 1 cycle in assembly*/
+    for (Shift = 0; Shift < 32; Shift++) {
+        if ((Remainder & 0x80000000U) != 0) {
+            break;
+        }
+        Remainder = Remainder << 1;
+    }
+
+    /*
+     * Based on the approximation equation (for Q11.4 format):
+     *
+     * dB = -96 * Shift + 16 * (8 * Remainder - 2 * Remainder^2)
+     */
+    db_fix = (LVM_INT16)(-96 * Shift); /* Six dB steps in Q11.4 format*/
+    SmallRemainder = (LVM_INT16)((Remainder & 0x7fffffff) >> 24);
+    db_fix = (LVM_INT16)(db_fix + SmallRemainder);
+    SmallRemainder = (LVM_INT16)(SmallRemainder * SmallRemainder);
+    db_fix = (LVM_INT16)(db_fix - (LVM_INT16)((LVM_UINT16)SmallRemainder >> 9));
+
+    /* Correct for small offset */
+    db_fix = (LVM_INT16)(db_fix - 5);
+
+    return db_fix;
+}
+
+// TODO: replace with more generic approach, like: audio_utils_power_from_amplitude
+int16_t BundleContext::VolToDb(uint32_t vol) const {
+    int16_t dB;
+
+    dB = LVC_ToDB_s32Tos16(vol << 7);
+    dB = (dB + 8) >> 4;
+    dB = (dB < -96) ? -96 : dB;
+
+    return dB;
+}
+
+RetCode BundleContext::setVolumeStereo(const Parameter::VolumeStereo& volume) {
+    LVM_ControlParams_t params;
+    LVM_ReturnStatus_en status = LVM_SUCCESS;
+
+    // Convert volume to dB
+    int leftdB = VolToDb(volume.left);
+    int rightdB = VolToDb(volume.right);
+    int maxdB = std::max(leftdB, rightdB);
+    int pandB = rightdB - leftdB;
+    // TODO: add volume effect implementation here:
+    // android::VolumeSetVolumeLevel(pContext, (int16_t)(maxdB * 100));
+    LOG(DEBUG) << __func__ << " pandB: " << pandB << " maxdB " << maxdB;
+
+    RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, &params),
+                    RetCode::ERROR_EFFECT_LIB_ERROR, "");
+
+    params.VC_Balance = pandB;
+
+    RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
+                    RetCode::ERROR_EFFECT_LIB_ERROR, "");
+
+    mVolumeStereo = volume;
+    return RetCode::SUCCESS;
+}
+
+RetCode BundleContext::setEqualizerPreset(const int presetIdx) {
+    if (presetIdx < 0 || presetIdx >= lvm::MAX_NUM_PRESETS) {
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+
+    std::vector<Equalizer::BandLevel> bandLevels;
+    bandLevels.reserve(lvm::MAX_NUM_BANDS);
+    for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+        bandLevels.emplace_back(Equalizer::BandLevel{i, lvm::kSoftPresets[presetIdx][i]});
+    }
+
+    RetCode ret = updateControlParameter(bandLevels);
+    if (RetCode::SUCCESS == ret) {
+        mCurPresetIdx = presetIdx;
+        LOG(INFO) << __func__ << " success with " << presetIdx;
+    } else {
+        LOG(ERROR) << __func__ << " failed to setPreset " << presetIdx;
+    }
+    return ret;
+}
+
+RetCode BundleContext::setEqualizerBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels) {
+    RETURN_VALUE_IF(bandLevels.size() > lvm::MAX_NUM_BANDS || bandLevels.empty(),
+                    RetCode::ERROR_ILLEGAL_PARAMETER, "sizeExceedMax");
+    RetCode ret = updateControlParameter(bandLevels);
+    if (RetCode::SUCCESS == ret) {
+        mCurPresetIdx = lvm::PRESET_CUSTOM;
+        LOG(INFO) << __func__ << " succeed with " << ::android::internal::ToString(bandLevels);
+    } else {
+        LOG(ERROR) << __func__ << " failed with " << ::android::internal::ToString(bandLevels);
+    }
+    return ret;
+}
+
+std::vector<Equalizer::BandLevel> BundleContext::getEqualizerBandLevels() const {
+    std::vector<Equalizer::BandLevel> bandLevels;
+    bandLevels.reserve(lvm::MAX_NUM_BANDS);
+    for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+        bandLevels.emplace_back(Equalizer::BandLevel{i, mBandGaindB[i]});
+    }
+    return bandLevels;
+}
+
+bool BundleContext::isBandLevelIndexInRange(
+        const std::vector<Equalizer::BandLevel>& bandLevels) const {
+    const auto [min, max] =
+            std::minmax_element(bandLevels.begin(), bandLevels.end(),
+                                [](const auto& a, const auto& b) { return a.index < b.index; });
+    return min->index >= 0 && max->index < lvm::MAX_NUM_BANDS;
+}
+
+RetCode BundleContext::updateControlParameter(const std::vector<Equalizer::BandLevel>& bandLevels) {
+    RETURN_VALUE_IF(!isBandLevelIndexInRange(bandLevels), RetCode::ERROR_ILLEGAL_PARAMETER,
+                    "indexOutOfRange");
+
+    std::array<int, lvm::MAX_NUM_BANDS> tempLevel;
+    for (const auto& it : bandLevels) {
+        tempLevel[it.index] = it.levelMb;
+    }
+
+    LVM_ControlParams_t params;
+    RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, &params),
+                    RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+    for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+        params.pEQNB_BandDefinition[i].Frequency = lvm::kPresetsFrequencies[i];
+        params.pEQNB_BandDefinition[i].QFactor = lvm::kPresetsQFactors[i];
+        params.pEQNB_BandDefinition[i].Gain = tempLevel[i];
+    }
+
+    RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
+                    RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+    mBandGaindB = tempLevel;
+    LOG(INFO) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGaindB);
+
+    return RetCode::SUCCESS;
+}
+
+void BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+    /* General parameters */
+    params.OperatingMode = LVM_MODE_ON;
+    params.SampleRate = LVM_FS_44100;
+    params.SourceFormat = LVM_STEREO;
+    params.SpeakerType = LVM_HEADPHONES;
+
+    /* Concert Sound parameters */
+    params.VirtualizerOperatingMode = LVM_MODE_OFF;
+    params.VirtualizerType = LVM_CONCERTSOUND;
+    params.VirtualizerReverbLevel = 100;
+    params.CS_EffectLevel = LVM_CS_EFFECT_NONE;
+
+    params.EQNB_OperatingMode = LVM_EQNB_OFF;
+    params.EQNB_NBands = lvm::MAX_NUM_BANDS;
+    params.pEQNB_BandDefinition = getDefaultEqualizerBandDefs();
+
+    /* Volume Control parameters */
+    params.VC_EffectLevel = 0;
+    params.VC_Balance = 0;
+
+    /* Treble Enhancement parameters */
+    params.TE_OperatingMode = LVM_TE_OFF;
+    params.TE_EffectLevel = 0;
+
+    /* PSA Control parameters */
+    params.PSA_Enable = LVM_PSA_OFF;
+    params.PSA_PeakDecayRate = (LVM_PSA_DecaySpeed_en)0;
+
+    /* Bass Enhancement parameters */
+    params.BE_OperatingMode = LVM_BE_OFF;
+    params.BE_EffectLevel = 0;
+    params.BE_CentreFreq = LVM_BE_CENTRE_90Hz;
+    params.BE_HPF = LVM_BE_HPF_ON;
+
+    /* PSA Control parameters */
+    params.PSA_Enable = LVM_PSA_OFF;
+    params.PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
+
+    /* TE Control parameters */
+    params.TE_OperatingMode = LVM_TE_OFF;
+    params.TE_EffectLevel = 0;
+
+    params.NrChannels = audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
+    params.ChMask = AUDIO_CHANNEL_OUT_STEREO;
+    params.SourceFormat = LVM_STEREO;
+}
+
+void BundleContext::initHeadroomParameter(LVM_HeadroomParams_t& params) const {
+    params.pHeadroomDefinition = getDefaultEqualizerHeadroomBanDefs();
+    params.NHeadroomBands = 2;
+    params.Headroom_OperatingMode = LVM_HEADROOM_OFF;
+}
+
+LVM_EQNB_BandDef_t *BundleContext::getDefaultEqualizerBandDefs() {
+    static LVM_EQNB_BandDef_t* BandDefs = []() {
+        static LVM_EQNB_BandDef_t tempDefs[lvm::MAX_NUM_BANDS];
+        /* N-Band Equaliser parameters */
+        for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+            tempDefs[i].Frequency = lvm::kPresetsFrequencies[i];
+            tempDefs[i].QFactor = lvm::kPresetsQFactors[i];
+            tempDefs[i].Gain = lvm::kSoftPresets[0/* normal */][i];
+        }
+        return tempDefs;
+    }();
+
+    return BandDefs;
+}
+
+LVM_HeadroomBandDef_t *BundleContext::getDefaultEqualizerHeadroomBanDefs() {
+    static LVM_HeadroomBandDef_t HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS] = {
+            {
+                    .Limit_Low = 20,
+                    .Limit_High = 4999,
+                    .Headroom_Offset = 0,
+            },
+            {
+                    .Limit_Low = 5000,
+                    .Limit_High = 24000,
+                    .Headroom_Offset = 0,
+            },
+    };
+    return HeadroomBandDef;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
new file mode 100644
index 0000000..616ab78
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -0,0 +1,115 @@
+/*
+ * 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 <android-base/logging.h>
+#include <array>
+
+#include "BundleTypes.h"
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class BundleContext final : public EffectContext {
+  public:
+    BundleContext(int statusDepth, const Parameter::Common& common,
+                  const lvm::BundleEffectType& type)
+        : EffectContext(statusDepth, common), mType(type) {
+        LOG(DEBUG) << __func__ << type;
+    }
+    ~BundleContext() override {
+        LOG(DEBUG) << __func__;
+        deInit();
+    }
+
+    RetCode init();
+    void deInit();
+    lvm::BundleEffectType getBundleType() const { return mType; }
+
+    RetCode enable();
+    RetCode disable();
+
+    LVM_Handle_t getLvmInstance() const { return mInstance; }
+
+    void setSampleRate (const int sampleRate) { mSampleRate = sampleRate; }
+    int getSampleRate() const { return mSampleRate; }
+
+    void setChannelMask(const aidl::android::media::audio::common::AudioChannelLayout& chMask) {
+        mChMask = chMask;
+    }
+    aidl::android::media::audio::common::AudioChannelLayout getChannelMask() const {
+        return mChMask;
+    }
+
+    RetCode setEqualizerPreset(const int presetIdx);
+    int getEqualizerPreset() const { return mCurPresetIdx; }
+    RetCode setEqualizerBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels);
+    std::vector<Equalizer::BandLevel> getEqualizerBandLevels() const;
+
+    RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) override;
+    Parameter::VolumeStereo getVolumeStereo() override { return mVolumeStereo; };
+
+  private:
+    const lvm::BundleEffectType mType;
+    bool mEnabled = false;
+    LVM_Handle_t mInstance = nullptr;
+
+    aidl::android::media::audio::common::AudioDeviceDescription mVirtualizerForcedDevice;
+    aidl::android::media::audio::common::AudioChannelLayout mChMask;
+
+    int mSampleRate = LVM_FS_44100;
+    int mSamplesPerSecond = 0;
+    int mSamplesToExitCountEq = 0;
+    int mSamplesToExitCountBb = 0;
+    int mSamplesToExitCountVirt = 0;
+    int mFrameCount = 0;
+
+    /* Bitmask whether drain is in progress due to disabling the effect.
+       The corresponding bit to an effect is set by 1 << lvm_effect_en. */
+    int mEffectInDrain = 0;
+
+    /* Bitmask whether process() was called for a particular effect.
+       The corresponding bit to an effect is set by 1 << lvm_effect_en. */
+    int mEffectProcessCalled = 0;
+    int mNumberEffectsEnabled = 0;
+    int mNumberEffectsCalled = 0;
+    bool mFirstVolume = false;
+    // Bass
+    bool mBassTempDisabled = false;
+    int mBassStrengthSaved = 0;
+    // Equalizer
+    int mCurPresetIdx = lvm::PRESET_CUSTOM; /* Current preset being used */
+    std::array<int, lvm::MAX_NUM_BANDS> mBandGaindB;
+    // Virtualizer
+    int mVirtStrengthSaved = 0; /* Conversion between Get/Set */
+    bool mVirtualizerTempDisabled = false;
+    // Volume
+    int mLevelSaved = 0; /* for when mute is set, level must be saved */
+    bool mMuteEnabled = false; /* Must store as mute = -96dB level */
+
+    void initControlParameter(LVM_ControlParams_t& params) const;
+    void initHeadroomParameter(LVM_HeadroomParams_t& params) const;
+    int16_t VolToDb(uint32_t vol) const;
+    LVM_INT16 LVC_ToDB_s32Tos16(LVM_INT32 Lin_fix) const;
+    RetCode updateControlParameter(const std::vector<Equalizer::BandLevel>& bandLevels);
+    bool isBandLevelIndexInRange(const std::vector<Equalizer::BandLevel>& bandLevels) const;
+    static LVM_EQNB_BandDef_t* getDefaultEqualizerBandDefs();
+    static LVM_HeadroomBandDef_t* getDefaultEqualizerHeadroomBanDefs();
+};
+
+}  // namespace aidl::android::hardware::audio::effect
+
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
new file mode 100644
index 0000000..1772bd1
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -0,0 +1,163 @@
+/*
+ * 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 <array>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include "effect-impl/EffectUUID.h"
+#include "effect-impl/EffectTypes.h"
+#include "LVM.h"
+
+namespace aidl::android::hardware::audio::effect {
+namespace lvm {
+
+constexpr inline size_t MAX_NUM_PRESETS = 10;
+constexpr inline size_t MAX_NUM_BANDS = 5;
+constexpr inline size_t MAX_CALL_SIZE = 256;
+constexpr inline int BASS_BOOST_CUP_LOAD_ARM9E = 150;   // Expressed in 0.1 MIPS
+constexpr inline int VIRTUALIZER_CUP_LOAD_ARM9E = 120;  // Expressed in 0.1 MIPS
+constexpr inline int EQUALIZER_CUP_LOAD_ARM9E = 220;    // Expressed in 0.1 MIPS
+constexpr inline int VOLUME_CUP_LOAD_ARM9E = 0;         // Expressed in 0.1 MIPS
+constexpr inline int BUNDLE_MEM_USAGE = 25;             // Expressed in kB
+constexpr inline int PRESET_CUSTOM = -1;
+
+static const std::vector<Equalizer::BandFrequency> kEqBandFrequency = {{0, 30000, 120000},
+                                                                       {1, 120001, 460000},
+                                                                       {2, 460001, 1800000},
+                                                                       {3, 1800001, 7000000},
+                                                                       {4, 7000001, 20000000}};
+
+/*
+Frequencies in Hz
+Note: If these frequencies change, please update LimitLevel values accordingly.
+*/
+constexpr inline std::array<uint16_t, MAX_NUM_BANDS> kPresetsFrequencies = {60, 230, 910, 3600,
+                                                                            14000};
+
+/* Q factor multiplied by 100 */
+constexpr inline std::array<uint16_t, MAX_NUM_BANDS> kPresetsQFactors = {96, 96, 96, 96, 96};
+
+constexpr inline std::array<std::array<int16_t, MAX_NUM_BANDS>, MAX_NUM_PRESETS> kSoftPresets = {
+        {{3, 0, 0, 0, 3},    /* Normal Preset */
+         {5, 3, -2, 4, 4},   /* Classical Preset */
+         {6, 0, 2, 4, 1},    /* Dance Preset */
+         {0, 0, 0, 0, 0},    /* Flat Preset */
+         {3, 0, 0, 2, -1},   /* Folk Preset */
+         {4, 1, 9, 3, 0},    /* Heavy Metal Preset */
+         {5, 3, 0, 1, 3},    /* Hip Hop Preset */
+         {4, 2, -2, 2, 5},   /* Jazz Preset */
+         {-1, 2, 5, 1, -2},  /* Pop Preset */
+         {5, 3, -1, 3, 5}}}; /* Rock Preset */
+
+static const std::vector<Equalizer::Preset> kEqPresets = {
+        {0, "Normal"},      {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
+        {5, "Heavy Metal"}, {6, "Hip Hop"},   {7, "Jazz"},  {8, "Pop"},  {9, "Rock"}};
+
+static const Equalizer::Capability kEqCap = {.bandFrequencies = kEqBandFrequency,
+                                             .presets = kEqPresets};
+
+static const Descriptor kEqualizerDesc = {
+        .common = {.id = {.type = EqualizerTypeUUID,
+                          .uuid = EqualizerBundleImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = "EqualizerBundle",
+                   .implementor = "NXP Software Ltd."},
+        .capability = Capability::make<Capability::equalizer>(kEqCap)};
+
+// TODO: add descriptors for other bundle effect types here.
+static const Descriptor kVirtualizerDesc;
+static const Descriptor kBassBoostDesc;
+static const Descriptor kVolumeDesc;
+
+/* The following tables have been computed using the actual levels measured by the output of
+ * white noise or pink noise (IEC268-1) for the EQ and BassBoost Effects. These are estimates of
+ * the actual energy that 'could' be present in the given band.
+ * If the frequency values in EQNB_5BandPresetsFrequencies change, these values might need to be
+ * updated.
+ */
+constexpr inline std::array<float, MAX_NUM_BANDS> kBandEnergyCoefficient = {7.56, 9.69, 9.59, 7.37,
+                                                                            2.88};
+
+constexpr inline std::array<float, MAX_NUM_BANDS - 1> kBandEnergyCrossCoefficient = {126.0, 115.0,
+                                                                                     125.0, 104.0};
+
+constexpr inline std::array<float, MAX_NUM_BANDS> kBassBoostEnergyCrossCoefficient = {
+        221.21, 208.10, 28.16, 0.0, 0.0};
+
+constexpr inline float kBassBoostEnergyCoefficient = 9.00;
+
+constexpr inline float kVirtualizerContribution = 1.9;
+
+enum class BundleEffectType {
+    BASS_BOOST,
+    VIRTUALIZER,
+    EQUALIZER,
+    VOLUME,
+};
+
+inline std::ostream& operator<<(std::ostream& out, const BundleEffectType& type) {
+    switch (type) {
+        case BundleEffectType::BASS_BOOST:
+            return out << "BASS_BOOST";
+        case BundleEffectType::VIRTUALIZER:
+            return out << "VIRTUALIZER";
+        case BundleEffectType::EQUALIZER:
+            return out << "EQUALIZER";
+        case BundleEffectType::VOLUME:
+            return out << "VOLUME";
+    }
+    return out << "EnumBundleEffectTypeError";
+}
+
+inline std::ostream& operator<<(std::ostream& out, const LVM_ReturnStatus_en& status) {
+    switch (status) {
+        case LVM_SUCCESS:
+            return out << "LVM_SUCCESS";
+        case LVM_ALIGNMENTERROR:
+            return out << "LVM_ALIGNMENTERROR";
+        case LVM_NULLADDRESS:
+            return out << "LVM_NULLADDRESS";
+        case LVM_OUTOFRANGE:
+            return out << "LVM_OUTOFRANGE";
+        case LVM_INVALIDNUMSAMPLES:
+            return out << "LVM_INVALIDNUMSAMPLES";
+        case LVM_WRONGAUDIOTIME:
+            return out << "LVM_WRONGAUDIOTIME";
+        case LVM_ALGORITHMDISABLED:
+            return out << "LVM_ALGORITHMDISABLED";
+        case LVM_ALGORITHMPSA:
+            return out << "LVM_ALGORITHMPSA";
+        case LVM_RETURNSTATUS_DUMMY:
+            return out << "LVM_RETURNSTATUS_DUMMY";
+    }
+    return out << "EnumLvmRetStatusError";
+}
+
+#define GOTO_IF_LVM_ERROR(status, tag, log)                                       \
+    do {                                                                          \
+        LVM_ReturnStatus_en temp = (status);                                      \
+        if (temp != LVM_SUCCESS) {                                                \
+            LOG(ERROR) << __func__ << " return status: " << temp << " " << (log); \
+            goto tag;                                                             \
+        }                                                                         \
+    } while (0)
+
+}  // namespace lvm
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
new file mode 100644
index 0000000..569356f
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "EffectBundleAidl"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+#include <audio_effects/effect_bassboost.h>
+#include <audio_effects/effect_equalizer.h>
+#include <audio_effects/effect_virtualizer.h>
+
+#include "EffectBundleAidl.h"
+#include <LVM.h>
+#include <limits.h>
+
+using aidl::android::hardware::audio::effect::EffectBundleAidl;
+using aidl::android::hardware::audio::effect::EqualizerBundleImplUUID;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (uuid == nullptr || *uuid != EqualizerBundleImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<EffectBundleAidl>(*uuid);
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    if (!instanceSp) {
+        LOG(ERROR) << __func__ << "nullInstance";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    State state;
+    ndk::ScopedAStatus status = instanceSp->getState(&state);
+    if (!status.isOk() || State::INIT != state) {
+        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+                   << " in state: " << toString(state) << ", status: " << status.getDescription();
+        return EX_ILLEGAL_STATE;
+    }
+    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectBundleAidl::EffectBundleAidl(const AudioUuid& uuid) {
+    LOG(DEBUG) << __func__ << uuid.toString();
+    if (uuid == EqualizerBundleImplUUID) {
+        mType = lvm::BundleEffectType::EQUALIZER;
+        mDescriptor = &lvm::kEqualizerDesc;
+    } else {
+        // TODO: add other bundle effect types here.
+        LOG(ERROR) << __func__ << uuid.toString() << " not supported yet!";
+    }
+}
+
+EffectBundleAidl::~EffectBundleAidl() {
+    releaseContext();
+    LOG(DEBUG) << __func__;
+}
+
+ndk::ScopedAStatus EffectBundleAidl::getDescriptor(Descriptor* _aidl_return) {
+    RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+    LOG(DEBUG) << _aidl_return->toString();
+    *_aidl_return = *mDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectBundleAidl::setParameterCommon(const Parameter& param) {
+    std::lock_guard lg(mMutex);
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    auto tag = param.getTag();
+    switch (tag) {
+        case Parameter::common:
+            RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setCommFailed");
+            break;
+        case Parameter::deviceDescription:
+            RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
+            break;
+        case Parameter::mode:
+            RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setModeFailed");
+            break;
+        case Parameter::source:
+            RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setSourceFailed");
+            break;
+        case Parameter::volumeStereo:
+            RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
+            break;
+        default: {
+            LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "commonParamNotSupported");
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectBundleAidl::setParameterSpecific(const Parameter::Specific& specific) {
+    LOG(DEBUG) << __func__ << " specific " << specific.toString();
+    auto tag = specific.getTag();
+    RETURN_IF(tag != Parameter::Specific::equalizer, EX_ILLEGAL_ARGUMENT,
+              "specificParamNotSupported");
+    RETURN_IF(mContext == nullptr, EX_NULL_POINTER , "nullContext");
+
+    auto& eq = specific.get<Parameter::Specific::equalizer>();
+    auto eqTag = eq.getTag();
+    switch (eqTag) {
+        case Equalizer::preset:
+            RETURN_IF(mContext->setEqualizerPreset(eq.get<Equalizer::preset>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
+            break;
+        case Equalizer::bandLevels:
+            RETURN_IF(mContext->setEqualizerBandLevels(eq.get<Equalizer::bandLevels>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
+            break;
+        default:
+            LOG(ERROR) << __func__ << " unsupported parameter " << specific.toString();
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "eqTagNotSupported");
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectBundleAidl::getParameterSpecific(const Parameter::Id& id,
+                                                          Parameter::Specific* specific) {
+    RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::equalizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto eqId = id.get<Parameter::Id::equalizerTag>();
+    auto eqIdTag = eqId.getTag();
+    switch (eqIdTag) {
+        case Equalizer::Id::commonTag:
+            return getParameterEqualizer(eqId.get<Equalizer::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " tag " << toString(eqIdTag) << " not supported";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "EqualizerTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus EffectBundleAidl::getParameterEqualizer(const Equalizer::Tag& tag,
+                                                           Parameter::Specific* specific) {
+    std::lock_guard lg(mMutex);
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    Equalizer eqParam;
+    switch (tag) {
+        case Equalizer::bandLevels: {
+            eqParam.set<Equalizer::bandLevels>(mContext->getEqualizerBandLevels());
+            break;
+        }
+        case Equalizer::preset: {
+            eqParam.set<Equalizer::preset>(mContext->getEqualizerPreset());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "unsupportedTag");
+        }
+    }
+
+    specific->set<Parameter::Specific::equalizer>(eqParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> EffectBundleAidl::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+        return mContext;
+    }
+
+    // GlobalSession is a singleton
+    mContext =
+            GlobalSession::getGlobalSession().createSession(mType, 1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+RetCode EffectBundleAidl::releaseContext() {
+    if (mContext) {
+        GlobalSession::getGlobalSession().releaseSession(mType, mContext->getSessionId());
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EffectBundleAidl::effectProcessImpl(float* in, float* out, int sampleToProcess) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << sampleToProcess;
+    if (!mContext) {
+        LOG(ERROR) << __func__ << " nullContext";
+        return {EX_NULL_POINTER, 0, 0};
+    }
+
+    auto frameSize = mContext->getInputFrameSize();
+    if (0 == frameSize) {
+        LOG(ERROR) << __func__ << " frameSizeIs0";
+        return {EX_ILLEGAL_ARGUMENT, 0, 0};
+    }
+
+    LOG(DEBUG) << __func__ << " start processing";
+    LVM_UINT16 frames = sampleToProcess * sizeof(float) / frameSize;
+    LVM_ReturnStatus_en lvmStatus = LVM_Process(mContext->getLvmInstance(), in, out, frames, 0);
+    if (lvmStatus != LVM_SUCCESS) {
+        LOG(ERROR) << __func__ << lvmStatus;
+        return {EX_UNSUPPORTED_OPERATION, 0, 0};
+    }
+    LOG(DEBUG) << __func__ << " done processing";
+    return {STATUS_OK, sampleToProcess, sampleToProcess};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
new file mode 100644
index 0000000..5fdf301
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
@@ -0,0 +1,73 @@
+/*
+ * 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 <functional>
+#include <map>
+#include <memory>
+#include <mutex>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <android-base/logging.h>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+#include "BundleContext.h"
+#include "BundleTypes.h"
+#include "GlobalSession.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectBundleAidl final : public EffectImpl {
+  public:
+    explicit EffectBundleAidl(const AudioUuid& uuid);
+    ~EffectBundleAidl() override;
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+    ndk::ScopedAStatus setParameterCommon(const Parameter& param) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                            Parameter::Specific* specific) override;
+    IEffect::Status effectProcessImpl(float *in, float *out, int process) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    RetCode releaseContext() override;
+
+    ndk::ScopedAStatus commandStart() override {
+        mContext->enable();
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus commandStop() override {
+        mContext->disable();
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus commandReset() override {
+            mContext->disable();
+            return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    const Descriptor* mDescriptor;
+    lvm::BundleEffectType mType = lvm::BundleEffectType::EQUALIZER;
+    std::shared_ptr<BundleContext> mContext;
+
+    IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
+    ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
+                                             Parameter::Specific* specific);
+};
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Aidl/GlobalSession.h b/media/libeffects/lvm/wrapper/Aidl/GlobalSession.h
new file mode 100644
index 0000000..9226274
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Aidl/GlobalSession.h
@@ -0,0 +1,118 @@
+/*
+ * 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 <algorithm>
+#include <memory>
+#include <unordered_map>
+
+#include <android-base/logging.h>
+
+#include "BundleContext.h"
+#include "BundleTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+/**
+ * @brief Maintain all effect bundle sessions.
+ *
+ * Sessions are identified with the session ID, maximum of MAX_BUNDLE_SESSIONS is supported by the
+ * bundle implementation.
+ */
+class GlobalSession {
+  public:
+    static GlobalSession& getGlobalSession() {
+        static GlobalSession instance;
+        return instance;
+    }
+
+    bool isSessionIdExist(int sessionId) const { return mSessionMap.count(sessionId); }
+
+    static bool findBundleTypeInList(std::vector<std::shared_ptr<BundleContext>>& list,
+                                     const lvm::BundleEffectType& type, bool remove = false) {
+        auto itor = std::find_if(list.begin(), list.end(),
+                                  [type](const std::shared_ptr<BundleContext>& bundle) {
+                                      return bundle ? bundle->getBundleType() == type : false;
+                                  });
+        if (itor == list.end()) {
+            return false;
+        }
+        if (remove && *itor) {
+            (*itor)->deInit();
+            list.erase(itor);
+        }
+        return true;
+    }
+
+    /**
+     * Create a certain type of BundleContext in shared_ptr container, each session must not have
+     * more than one session for each type.
+     */
+    std::shared_ptr<BundleContext> createSession(const lvm::BundleEffectType& type, int statusDepth,
+                                                 const Parameter::Common& common) {
+        int sessionId = common.session;
+        LOG(DEBUG) << __func__ << type << " with sessionId " << sessionId;
+        std::lock_guard lg(mMutex);
+        if (mSessionMap.count(sessionId) == 0 && mSessionMap.size() >= MAX_BUNDLE_SESSIONS) {
+            LOG(ERROR) << __func__ << " exceed max bundle session";
+            return nullptr;
+        }
+
+        if (mSessionMap.count(sessionId)) {
+            if (findBundleTypeInList(mSessionMap[sessionId], type)) {
+                LOG(ERROR) << __func__ << type << " already exist in session " << sessionId;
+                return nullptr;
+            }
+        }
+
+        auto& list = mSessionMap[sessionId];
+        auto context = std::make_shared<BundleContext>(statusDepth, common, type);
+        RETURN_VALUE_IF(!context, nullptr, "failedToCreateContext");
+
+        RetCode ret = context->init();
+        if (RetCode::SUCCESS != ret) {
+            LOG(ERROR) << __func__ << " context init ret " << ret;
+            return nullptr;
+        }
+        list.push_back(context);
+        return context;
+    }
+
+    void releaseSession(const lvm::BundleEffectType& type, int sessionId) {
+        LOG(DEBUG) << __func__ << type << " sessionId " << sessionId;
+        std::lock_guard lg(mMutex);
+        if (mSessionMap.count(sessionId)) {
+            auto& list = mSessionMap[sessionId];
+            if (!findBundleTypeInList(list, type, true /* remove */)) {
+                LOG(ERROR) << __func__ << " can't find " << type << "in session " << sessionId;
+                return;
+            }
+            if (list.size() == 0) {
+                mSessionMap.erase(sessionId);
+            }
+        }
+    }
+
+  private:
+    // Lock for mSessionMap access.
+    std::mutex mMutex;
+    // Max session number supported.
+    static constexpr int MAX_BUNDLE_SESSIONS = 32;
+    std::unordered_map<int /* session ID */, std::vector<std::shared_ptr<BundleContext>>>
+            mSessionMap GUARDED_BY(mMutex);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index 1287514..a32188a 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -100,3 +100,29 @@
         integer_overflow: true,
     },
 }
+
+cc_library_shared {
+    name: "libbundleaidl",
+    srcs: [
+        "Aidl/BundleContext.cpp",
+        "Aidl/EffectBundleAidl.cpp",
+        ":effectCommonFile",
+    ],
+    static_libs: ["libmusicbundle"],
+    defaults: [
+        "aidlaudioservice_defaults",
+        "latest_android_hardware_audio_effect_ndk_shared",
+        "latest_android_media_audio_common_types_ndk_shared",
+    ],
+    local_include_dirs: ["Aidl"],
+    header_libs: [
+        "libaudioeffects",
+        "libhardware_headers",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
\ No newline at end of file
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 9c989ce..38ad494 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -741,6 +741,17 @@
     msg->post();
 }
 
+void Spatializer::resetEngineHeadPose_l() {
+    ALOGV("%s mEngine %p", __func__, mEngine.get());
+    if (mEngine == nullptr) {
+        return;
+    }
+    const std::vector<float> headToStage(6, 0.0);
+    setEffectParameter_l(SPATIALIZER_PARAM_HEAD_TO_STAGE, headToStage);
+    setEffectParameter_l(SPATIALIZER_PARAM_HEADTRACKING_MODE,
+            std::vector<SpatializerHeadTrackingMode>{SpatializerHeadTrackingMode::DISABLED});
+}
+
 void Spatializer::onHeadToStagePoseMsg(const std::vector<float>& headToStage) {
     ALOGV("%s", __func__);
     sp<media::ISpatializerHeadTrackingCallback> callback;
@@ -792,8 +803,12 @@
         }
         mActualHeadTrackingMode = spatializerMode;
         if (mEngine != nullptr) {
-            setEffectParameter_l(SPATIALIZER_PARAM_HEADTRACKING_MODE,
-                                 std::vector<SpatializerHeadTrackingMode>{spatializerMode});
+            if (spatializerMode == SpatializerHeadTrackingMode::DISABLED) {
+                resetEngineHeadPose_l();
+            } else {
+                setEffectParameter_l(SPATIALIZER_PARAM_HEADTRACKING_MODE,
+                                     std::vector<SpatializerHeadTrackingMode>{spatializerMode});
+            }
         }
         callback = mHeadTrackingCallback;
         mLocalLog.log("%s: %s, spatializerMode %s", __func__, media::toString(mode).c_str(),
@@ -920,22 +935,34 @@
 
 void Spatializer::checkSensorsState_l() {
     audio_latency_mode_t requestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
-    bool lowLatencySupported = mSupportedLatencyModes.empty()
-            || (std::find(mSupportedLatencyModes.begin(), mSupportedLatencyModes.end(),
-                    AUDIO_LATENCY_MODE_LOW) != mSupportedLatencyModes.end());
-    if (mSupportsHeadTracking && mPoseController != nullptr) {
-        if (lowLatencySupported && mNumActiveTracks > 0 && mLevel != SpatializationLevel::NONE
-            && mDesiredHeadTrackingMode != HeadTrackingMode::STATIC
-            && mHeadSensor != SpatializerPoseController::INVALID_SENSOR) {
-            mPoseController->setHeadSensor(mHeadSensor);
-            mPoseController->setScreenSensor(mScreenSensor);
-            requestedLatencyMode = AUDIO_LATENCY_MODE_LOW;
+    const bool supportsSetLatencyMode = !mSupportedLatencyModes.empty();
+    const bool supportsLowLatencyMode = supportsSetLatencyMode && std::find(
+            mSupportedLatencyModes.begin(), mSupportedLatencyModes.end(),
+            AUDIO_LATENCY_MODE_LOW) != mSupportedLatencyModes.end();
+    if (mSupportsHeadTracking) {
+        if (mPoseController != nullptr) {
+            // TODO(b/253297301, b/255433067) reenable low latency condition check
+            // for Head Tracking after Bluetooth HAL supports it correctly.
+            if (mNumActiveTracks > 0 && mLevel != SpatializationLevel::NONE
+                && mDesiredHeadTrackingMode != HeadTrackingMode::STATIC
+                && mHeadSensor != SpatializerPoseController::INVALID_SENSOR) {
+                if (mEngine != nullptr) {
+                    setEffectParameter_l(SPATIALIZER_PARAM_HEADTRACKING_MODE,
+                            std::vector<SpatializerHeadTrackingMode>{mActualHeadTrackingMode});
+                }
+                mPoseController->setHeadSensor(mHeadSensor);
+                mPoseController->setScreenSensor(mScreenSensor);
+                if (supportsLowLatencyMode) requestedLatencyMode = AUDIO_LATENCY_MODE_LOW;
+            } else {
+                mPoseController->setHeadSensor(SpatializerPoseController::INVALID_SENSOR);
+                mPoseController->setScreenSensor(SpatializerPoseController::INVALID_SENSOR);
+                resetEngineHeadPose_l();
+            }
         } else {
-            mPoseController->setHeadSensor(SpatializerPoseController::INVALID_SENSOR);
-            mPoseController->setScreenSensor(SpatializerPoseController::INVALID_SENSOR);
+            resetEngineHeadPose_l();
         }
     }
-    if (mOutput != AUDIO_IO_HANDLE_NONE) {
+    if (mOutput != AUDIO_IO_HANDLE_NONE && supportsSetLatencyMode) {
         AudioSystem::setRequestedLatencyMode(mOutput, requestedLatencyMode);
     }
 }
@@ -946,8 +973,6 @@
             mEngine->setEnabled(true);
             setEffectParameter_l(SPATIALIZER_PARAM_LEVEL,
                     std::vector<SpatializationLevel>{mLevel});
-            setEffectParameter_l(SPATIALIZER_PARAM_HEADTRACKING_MODE,
-                    std::vector<SpatializerHeadTrackingMode>{mActualHeadTrackingMode});
         } else {
             setEffectParameter_l(SPATIALIZER_PARAM_LEVEL,
                     std::vector<SpatializationLevel>{SpatializationLevel::NONE});
@@ -969,6 +994,7 @@
         mPoseController->setDisplayOrientation(mDisplayOrientation);
     } else if (!isControllerNeeded && mPoseController != nullptr) {
         mPoseController.reset();
+        resetEngineHeadPose_l();
     }
     if (mPoseController != nullptr) {
         mPoseController->setDesiredMode(mDesiredHeadTrackingMode);
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 2687b5c..bcbd92b 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -350,6 +350,12 @@
      */
     void checkEngineState_l() REQUIRES(mLock);
 
+    /**
+     * Reset head tracking mode and recenter pose in engine: Called when the head tracking
+     * is disabled.
+     */
+    void resetEngineHeadPose_l() REQUIRES(mLock);
+
     /** Effect engine descriptor */
     const effect_descriptor_t mEngineDescriptor;
     /** Callback interface to parent audio policy service */
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 123cd75..8b2af90 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -953,6 +953,12 @@
                 false);
 
     if (availableVideoStabilizationModes.count > 1) {
+        for (size_t i = 0; i < availableVideoStabilizationModes.count; i++) {
+            if (availableVideoStabilizationModes.data.u8[i] ==
+                ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON) {
+                videoStabilizationOnSupported = true;
+            }
+        }
         params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
                 CameraParameters::TRUE);
     } else {
@@ -2373,9 +2379,11 @@
             reqCropRegion, 4);
     if (res != OK) return res;
 
-    uint8_t reqVstabMode = videoStabilization ?
+    uint8_t reqVstabMode = videoStabilization ? videoStabilizationOnSupported ?
             ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON :
+                    ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION :
             ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+
     res = request->update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
             &reqVstabMode, 1);
     if (res != OK) return res;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index cbe62a7..fd18a5d 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -147,6 +147,7 @@
 
     bool recordingHint;
     bool videoStabilization;
+    bool videoStabilizationOnSupported = false;
 
     CameraParameters2 params;
     String8 paramsFlattened;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 7c2f34f..fa83ee9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -250,20 +250,28 @@
             Mutex::Autolock l(mLock);
             if (mStatus == STATUS_UNINITIALIZED) return res;
 
-            if (mStatus == STATUS_ACTIVE ||
-                    (mStatus == STATUS_ERROR && mRequestThread != NULL)) {
-                res = mRequestThread->clearRepeatingRequests();
-                if (res != OK) {
-                    SET_ERR_L("Can't stop streaming");
-                    // Continue to close device even in case of error
-                } else {
-                    res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration);
+            if (mRequestThread != NULL) {
+                if (mStatus == STATUS_ACTIVE || mStatus == STATUS_ERROR) {
+                    res = mRequestThread->clear();
                     if (res != OK) {
-                        SET_ERR_L("Timeout waiting for HAL to drain (% " PRIi64 " ns)",
-                                maxExpectedDuration);
+                        SET_ERR_L("Can't stop streaming");
                         // Continue to close device even in case of error
+                    } else {
+                        res = waitUntilStateThenRelock(/*active*/ false, maxExpectedDuration);
+                        if (res != OK) {
+                            SET_ERR_L("Timeout waiting for HAL to drain (% " PRIi64 " ns)",
+                                    maxExpectedDuration);
+                            // Continue to close device even in case of error
+                        }
                     }
                 }
+                // Signal to request thread that we're not expecting any
+                // more requests. This will be true since once we're in
+                // disconnect and we've cleared off the request queue, the
+                // request thread can't receive any new requests through
+                // binder calls - since disconnect holds
+                // mBinderSerialization lock.
+                mRequestThread->setRequestClearing();
             }
 
             if (mStatus == STATUS_ERROR) {
@@ -3047,7 +3055,8 @@
 
 }
 
-status_t Camera3Device::RequestThread::clearRepeatingRequestsLocked(/*out*/int64_t *lastFrameNumber) {
+status_t Camera3Device::RequestThread::clearRepeatingRequestsLocked(
+        /*out*/int64_t *lastFrameNumber) {
     std::vector<int32_t> streamIds;
     for (const auto& request : mRepeatingRequests) {
         for (const auto& stream : request->mOutputStreams) {
@@ -3072,8 +3081,6 @@
     Mutex::Autolock l(mRequestLock);
     ALOGV("RequestThread::%s:", __FUNCTION__);
 
-    mRepeatingRequests.clear();
-
     // Send errors for all requests pending in the request queue, including
     // pending repeating requests
     sp<NotificationListener> listener = mListener.promote();
@@ -3111,10 +3118,7 @@
 
     Mutex::Autolock al(mTriggerMutex);
     mTriggerMap.clear();
-    if (lastFrameNumber != NULL) {
-        *lastFrameNumber = mRepeatingLastFrameNumber;
-    }
-    mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;
+    clearRepeatingRequestsLocked(lastFrameNumber);
     mRequestClearing = true;
     mRequestSignal.signal();
     return OK;
@@ -4209,6 +4213,11 @@
     return;
 }
 
+void Camera3Device::RequestThread::setRequestClearing() {
+    Mutex::Autolock l(mRequestLock);
+    mRequestClearing = true;
+}
+
 sp<Camera3Device::CaptureRequest>
         Camera3Device::RequestThread::waitForNextRequestLocked() {
     status_t res;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 3c60ba2..ac070a6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -856,6 +856,9 @@
          */
         void     setPaused(bool paused);
 
+        // set mRequestClearing - no new requests are expected to be queued to RequestThread
+        void setRequestClearing();
+
         /**
          * Wait until thread processes the capture request with settings'
          * android.request.id == requestId.
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index 4488efb..3222950 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -54,6 +54,9 @@
         arm64: {
             src: "seccomp_policy/mediaswcodec-arm64.policy",
         },
+        riscv64: {
+            src: "seccomp_policy/mediaswcodec-riscv64.policy",
+        },
         x86: {
             src: "seccomp_policy/mediaswcodec-x86.policy",
         },
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
new file mode 100644
index 0000000..a55c3eb
--- /dev/null
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
@@ -0,0 +1,60 @@
+# 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.
+
+read: 1
+mprotect: 1
+prctl: 1
+openat: 1
+getuid: 1
+getrlimit: 1
+writev: 1
+ioctl: 1
+close: 1
+mmap: 1
+munmap: 1
+fstat: 1
+madvise: 1
+newfstatat: 1
+futex: 1
+faccessat: 1
+lseek: 1
+clone: 1
+sigaltstack: 1
+rt_sigprocmask: 1
+setpriority: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+readlinkat: 1
+fstatfs: 1
+pread64: 1
+mremap: 1
+dup: 1
+set_tid_address: 1
+write: 1
+nanosleep: 1
+sched_setscheduler: 1
+uname: 1
+memfd_create: 1
+ftruncate: 1
+getdents64: 1
+ppoll: 1
+
+# Required by AddressSanitizer
+gettid: 1
+sched_yield: 1
+getpid: 1
+
+@include /apex/com.android.media.swcodec/etc/seccomp_policy/code_coverage.riscv64.policy
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index 85ce110..acafe56 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -74,6 +74,9 @@
         arm64: {
             src: "seccomp_policy/mediaextractor-arm64.policy",
         },
+        riscv64: {
+            src: "seccomp_policy/mediaextractor-riscv64.policy",
+        },
         x86: {
             src: "seccomp_policy/mediaextractor-x86.policy",
         },
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-riscv64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-riscv64.policy
new file mode 100644
index 0000000..df143dd
--- /dev/null
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-riscv64.policy
@@ -0,0 +1,48 @@
+# Organized by frequency of systemcall - in descending order for
+# best performance.
+ioctl: 1
+futex: 1
+prctl: 1
+write: 1
+getpriority: 1
+close: 1
+dup: 1
+mmap: 1
+munmap: 1
+openat: 1
+mprotect: 1
+madvise: 1
+getuid: 1
+fstat: 1
+fstatfs: 1
+read: 1
+setpriority: 1
+sigaltstack: 1
+clone: 1
+sched_setscheduler: 1
+lseek: 1
+newfstatat: 1
+faccessat: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+rt_sigprocmask: 1
+getrlimit: 1
+nanosleep: 1
+getrandom: 1
+timer_create: 1
+timer_settime: 1
+timer_delete: 1
+
+# for dynamically loading extractors
+getdents64: 1
+readlinkat: 1
+pread64: 1
+mremap: 1
+
+# Required by Sanitizers
+sched_yield: 1
+
+@include /apex/com.android.media/etc/seccomp_policy/crash_dump.riscv64.policy
+@include /apex/com.android.media/etc/seccomp_policy/code_coverage.riscv64.policy