Effect AIDL: implement IEffect.reopen

- add IEffect.reopen implementation
- now data MQs can update at runtime, sync
  EffectContext access
- add clang thread annotation

Bug: 302036943
Test: atest VtsHalAudioEffectTargetTest
Test: build and test audio effect on Pixel
Change-Id: I3e9fdc2d5eb50b8c1377e0da75573f0eba7ea3f1
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 7e06c2c..bfa2783 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -230,6 +230,7 @@
 filegroup {
     name: "effectCommonFile",
     srcs: [
+        "EffectContext.cpp",
         "EffectThread.cpp",
         "EffectImpl.cpp",
     ],
diff --git a/audio/aidl/default/EffectContext.cpp b/audio/aidl/default/EffectContext.cpp
new file mode 100644
index 0000000..2e12918
--- /dev/null
+++ b/audio/aidl/default/EffectContext.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2024 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 <memory>
+#define LOG_TAG "AHAL_EffectContext"
+#include "effect-impl/EffectContext.h"
+#include "include/effect-impl/EffectTypes.h"
+
+using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::media::audio::common::PcmType;
+using ::android::hardware::EventFlag;
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectContext::EffectContext(size_t statusDepth, const Parameter::Common& common) {
+    LOG_ALWAYS_FATAL_IF(RetCode::SUCCESS != setCommon(common), "illegalCommonParameter");
+
+    // in/outBuffer size in float (FMQ data format defined for DataMQ)
+    size_t inBufferSizeInFloat = common.input.frameCount * mInputFrameSize / sizeof(float);
+    size_t outBufferSizeInFloat = common.output.frameCount * mOutputFrameSize / sizeof(float);
+
+    // only status FMQ use the EventFlag
+    mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
+    mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
+    mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
+
+    if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
+        LOG(ERROR) << __func__ << " created invalid FMQ";
+    }
+
+    ::android::status_t status =
+            EventFlag::createEventFlag(mStatusMQ->getEventFlagWord(), &mEfGroup);
+    LOG_ALWAYS_FATAL_IF(status != ::android::OK || !mEfGroup, " create EventFlagGroup failed ");
+    mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
+}
+
+// reset buffer status by abandon input data in FMQ
+void EffectContext::resetBuffer() {
+    auto buffer = static_cast<float*>(mWorkBuffer.data());
+    std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
+    if (mInputMQ) {
+        mInputMQ->read(buffer, mInputMQ->availableToRead());
+    }
+}
+
+void EffectContext::dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet) {
+    if (!mInputMQ) {
+        mInputMQ = std::make_shared<DataMQ>(mCommon.input.frameCount * mInputFrameSize /
+                                            sizeof(float));
+    }
+    if (!mOutputMQ) {
+        mOutputMQ = std::make_shared<DataMQ>(mCommon.output.frameCount * mOutputFrameSize /
+                                             sizeof(float));
+    }
+    dupeFmq(effectRet);
+}
+
+void EffectContext::dupeFmq(IEffect::OpenEffectReturn* effectRet) {
+    if (effectRet) {
+        effectRet->statusMQ = mStatusMQ->dupeDesc();
+        effectRet->inputDataMQ = mInputMQ->dupeDesc();
+        effectRet->outputDataMQ = mOutputMQ->dupeDesc();
+    }
+}
+
+float* EffectContext::getWorkBuffer() {
+    return static_cast<float*>(mWorkBuffer.data());
+}
+
+std::shared_ptr<EffectContext::StatusMQ> EffectContext::getStatusFmq() const {
+    return mStatusMQ;
+}
+
+std::shared_ptr<EffectContext::DataMQ> EffectContext::getInputDataFmq() const {
+    return mInputMQ;
+}
+
+std::shared_ptr<EffectContext::DataMQ> EffectContext::getOutputDataFmq() const {
+    return mOutputMQ;
+}
+
+size_t EffectContext::getInputFrameSize() const {
+    return mInputFrameSize;
+}
+
+size_t EffectContext::getOutputFrameSize() const {
+    return mOutputFrameSize;
+}
+
+int EffectContext::getSessionId() const {
+    return mCommon.session;
+}
+
+int EffectContext::getIoHandle() const {
+    return mCommon.ioHandle;
+}
+
+RetCode EffectContext::setOutputDevice(
+        const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device) {
+    mOutputDevice = device;
+    return RetCode::SUCCESS;
+}
+
+std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
+EffectContext::getOutputDevice() {
+    return mOutputDevice;
+}
+
+RetCode EffectContext::setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
+    mMode = mode;
+    return RetCode::SUCCESS;
+}
+aidl::android::media::audio::common::AudioMode EffectContext::getAudioMode() {
+    return mMode;
+}
+
+RetCode EffectContext::setAudioSource(
+        const aidl::android::media::audio::common::AudioSource& source) {
+    mSource = source;
+    return RetCode::SUCCESS;
+}
+
+aidl::android::media::audio::common::AudioSource EffectContext::getAudioSource() {
+    return mSource;
+}
+
+RetCode EffectContext::setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
+    mVolumeStereo = volumeStereo;
+    return RetCode::SUCCESS;
+}
+
+Parameter::VolumeStereo EffectContext::getVolumeStereo() {
+    return mVolumeStereo;
+}
+
+RetCode EffectContext::setCommon(const Parameter::Common& common) {
+    LOG(VERBOSE) << __func__ << common.toString();
+    auto& input = common.input;
+    auto& output = common.output;
+
+    if (input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT ||
+        output.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT) {
+        LOG(ERROR) << __func__ << " illegal IO, input "
+                   << ::android::internal::ToString(input.base.format) << ", output "
+                   << ::android::internal::ToString(output.base.format);
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+
+    if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+        return ret;
+    }
+
+    mInputChannelCount = getChannelCount(input.base.channelMask);
+    mOutputChannelCount = getChannelCount(output.base.channelMask);
+    if (mInputChannelCount == 0 || mOutputChannelCount == 0) {
+        LOG(ERROR) << __func__ << " illegal channel count input " << mInputChannelCount
+                   << ", output " << mOutputChannelCount;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+
+    mCommon = common;
+    return RetCode::SUCCESS;
+}
+
+Parameter::Common EffectContext::getCommon() {
+    LOG(VERBOSE) << __func__ << mCommon.toString();
+    return mCommon;
+}
+
+EventFlag* EffectContext::getStatusEventFlag() {
+    return mEfGroup;
+}
+
+RetCode EffectContext::updateIOFrameSize(const Parameter::Common& common) {
+    const auto iFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
+            common.input.base.format, common.input.base.channelMask);
+    const auto oFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
+            common.output.base.format, common.output.base.channelMask);
+
+    bool needUpdateMq = false;
+    if (mInputMQ &&
+        (mInputFrameSize != iFrameSize || mCommon.input.frameCount != common.input.frameCount)) {
+        mInputMQ.reset();
+        needUpdateMq = true;
+    }
+    if (mOutputMQ &&
+        (mOutputFrameSize != oFrameSize || mCommon.output.frameCount != common.output.frameCount)) {
+        mOutputMQ.reset();
+        needUpdateMq = true;
+    }
+    mInputFrameSize = iFrameSize;
+    mOutputFrameSize = oFrameSize;
+    if (needUpdateMq) {
+        return notifyDataMqUpdate();
+    }
+    return RetCode::SUCCESS;
+}
+
+RetCode EffectContext::notifyDataMqUpdate() {
+    if (!mEfGroup) {
+        LOG(ERROR) << __func__ << ": invalid EventFlag group";
+        return RetCode::ERROR_EVENT_FLAG_ERROR;
+    }
+
+    if (const auto ret = mEfGroup->wake(kEventFlagDataMqUpdate); ret != ::android::OK) {
+        LOG(ERROR) << __func__ << ": wake failure with ret " << ret;
+        return RetCode::ERROR_EVENT_FLAG_ERROR;
+    }
+    LOG(DEBUG) << __func__ << " : signal client for reopen";
+    return RetCode::SUCCESS;
+}
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 3c12f83..b76269a 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <memory>
 #define LOG_TAG "AHAL_EffectImpl"
 #include "effect-impl/EffectImpl.h"
 #include "effect-impl/EffectTypes.h"
@@ -22,6 +23,7 @@
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::State;
 using aidl::android::media::audio::common::PcmType;
+using ::android::hardware::EventFlag;
 
 extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
     State state;
@@ -45,50 +47,62 @@
     RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
                       common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
               EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
+    std::lock_guard lg(mImplMutex);
     RETURN_OK_IF(mState != State::INIT);
-    auto context = createContext(common);
-    RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
+    mImplContext = createContext(common);
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
+    mEventFlag = mImplContext->getStatusEventFlag();
 
     if (specific.has_value()) {
         RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
     }
 
     mState = State::IDLE;
-    context->dupeFmq(ret);
-    RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+    mImplContext->dupeFmq(ret);
+    RETURN_IF(createThread(getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
               "FailedToCreateWorker");
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::reopen(OpenEffectReturn* ret) {
+    std::lock_guard lg(mImplMutex);
     RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "alreadyClosed");
 
     // TODO: b/302036943 add reopen implementation
-    auto context = getContext();
-    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
-    context->dupeFmq(ret);
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
+    mImplContext->dupeFmqWithReopen(ret);
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::close() {
-    RETURN_OK_IF(mState == State::INIT);
-    RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
+    {
+        std::lock_guard lg(mImplMutex);
+        RETURN_OK_IF(mState == State::INIT);
+        RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
+        mState = State::INIT;
+    }
 
+    RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+              "notifyEventFlagFailed");
     // stop the worker thread, ignore the return code
     RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
               "FailedToDestroyWorker");
-    mState = State::INIT;
-    RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
-              "FailedToCreateWorker");
+
+    {
+        std::lock_guard lg(mImplMutex);
+        releaseContext();
+        mImplContext.reset();
+    }
 
     LOG(DEBUG) << getEffectName() << __func__;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
+    std::lock_guard lg(mImplMutex);
     LOG(VERBOSE) << getEffectName() << __func__ << " with: " << param.toString();
 
-    const auto tag = param.getTag();
+    const auto& tag = param.getTag();
     switch (tag) {
         case Parameter::common:
         case Parameter::deviceDescription:
@@ -110,8 +124,8 @@
 }
 
 ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
-    auto tag = id.getTag();
-    switch (tag) {
+    std::lock_guard lg(mImplMutex);
+    switch (id.getTag()) {
         case Parameter::Id::commonTag: {
             RETURN_IF_ASTATUS_NOT_OK(getParameterCommon(id.get<Parameter::Id::commonTag>(), param),
                                      "CommonParamNotSupported");
@@ -131,30 +145,30 @@
 }
 
 ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
-    auto context = getContext();
-    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
 
-    auto tag = param.getTag();
+    const auto& tag = param.getTag();
     switch (tag) {
         case Parameter::common:
-            RETURN_IF(context->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+            RETURN_IF(mImplContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setCommFailed");
             break;
         case Parameter::deviceDescription:
-            RETURN_IF(context->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
+            RETURN_IF(mImplContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
                               RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
             break;
         case Parameter::mode:
-            RETURN_IF(context->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
+            RETURN_IF(mImplContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setModeFailed");
             break;
         case Parameter::source:
-            RETURN_IF(context->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+            RETURN_IF(mImplContext->setAudioSource(param.get<Parameter::source>()) !=
+                              RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setSourceFailed");
             break;
         case Parameter::volumeStereo:
-            RETURN_IF(context->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+            RETURN_IF(mImplContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
                               RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
             break;
@@ -169,28 +183,27 @@
 }
 
 ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
-    auto context = getContext();
-    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
 
     switch (tag) {
         case Parameter::common: {
-            param->set<Parameter::common>(context->getCommon());
+            param->set<Parameter::common>(mImplContext->getCommon());
             break;
         }
         case Parameter::deviceDescription: {
-            param->set<Parameter::deviceDescription>(context->getOutputDevice());
+            param->set<Parameter::deviceDescription>(mImplContext->getOutputDevice());
             break;
         }
         case Parameter::mode: {
-            param->set<Parameter::mode>(context->getAudioMode());
+            param->set<Parameter::mode>(mImplContext->getAudioMode());
             break;
         }
         case Parameter::source: {
-            param->set<Parameter::source>(context->getAudioSource());
+            param->set<Parameter::source>(mImplContext->getAudioSource());
             break;
         }
         case Parameter::volumeStereo: {
-            param->set<Parameter::volumeStereo>(context->getVolumeStereo());
+            param->set<Parameter::volumeStereo>(mImplContext->getVolumeStereo());
             break;
         }
         default: {
@@ -202,30 +215,34 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus EffectImpl::getState(State* state) {
+ndk::ScopedAStatus EffectImpl::getState(State* state) NO_THREAD_SAFETY_ANALYSIS {
     *state = mState;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::command(CommandId command) {
-    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
+    std::lock_guard lg(mImplMutex);
+    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
     LOG(DEBUG) << getEffectName() << __func__ << ": receive command: " << toString(command)
                << " at state " << toString(mState);
 
     switch (command) {
         case CommandId::START:
-            RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
             RETURN_OK_IF(mState == State::PROCESSING);
             RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
-            startThread();
             mState = State::PROCESSING;
+            RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagFailed");
+            startThread();
             break;
         case CommandId::STOP:
         case CommandId::RESET:
             RETURN_OK_IF(mState == State::IDLE);
+            mState = State::IDLE;
+            RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
+                      "notifyEventFlagFailed");
             stopThread();
             RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
-            mState = State::IDLE;
             break;
         default:
             LOG(ERROR) << getEffectName() << __func__ << " instance still processing";
@@ -237,19 +254,41 @@
 }
 
 ndk::ScopedAStatus EffectImpl::commandImpl(CommandId command) {
-    auto context = getContext();
-    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+    RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
     if (command == CommandId::RESET) {
-        context->resetBuffer();
+        mImplContext->resetBuffer();
     }
     return ndk::ScopedAStatus::ok();
 }
 
+std::shared_ptr<EffectContext> EffectImpl::createContext(const Parameter::Common& common) {
+    return std::make_shared<EffectContext>(1 /* statusMqDepth */, common);
+}
+
+RetCode EffectImpl::releaseContext() {
+    if (mImplContext) {
+        mImplContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
 void EffectImpl::cleanUp() {
     command(CommandId::STOP);
     close();
 }
 
+RetCode EffectImpl::notifyEventFlag(uint32_t flag) {
+    if (!mEventFlag) {
+        LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag invalid";
+        return RetCode::ERROR_EVENT_FLAG_ERROR;
+    }
+    if (const auto ret = mEventFlag->wake(flag); ret != ::android::OK) {
+        LOG(ERROR) << getEffectName() << __func__ << ": wake failure with ret " << ret;
+        return RetCode::ERROR_EVENT_FLAG_ERROR;
+    }
+    return RetCode::SUCCESS;
+}
+
 IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size_t produced) {
     IEffect::Status ret;
     ret.status = status;
@@ -258,6 +297,48 @@
     return ret;
 }
 
+void EffectImpl::process() {
+    /**
+     * wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
+     * in the life cycle of workerThread (threadLoop).
+     */
+    uint32_t efState = 0;
+    if (!mEventFlag ||
+        ::android::OK != mEventFlag->wait(kEventFlagNotEmpty, &efState, 0 /* no timeout */,
+                                          true /* retry */) ||
+        !(efState & kEventFlagNotEmpty)) {
+        LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag - " << mEventFlag
+                   << " efState - " << std::hex << efState;
+        return;
+    }
+
+    {
+        std::lock_guard lg(mImplMutex);
+        if (mState != State::PROCESSING) {
+            LOG(DEBUG) << getEffectName() << " skip process in state: " << toString(mState);
+            return;
+        }
+        RETURN_VALUE_IF(!mImplContext, void(), "nullContext");
+        auto statusMQ = mImplContext->getStatusFmq();
+        auto inputMQ = mImplContext->getInputDataFmq();
+        auto outputMQ = mImplContext->getOutputDataFmq();
+        auto buffer = mImplContext->getWorkBuffer();
+        if (!inputMQ || !outputMQ) {
+            return;
+        }
+
+        auto processSamples = inputMQ->availableToRead();
+        if (processSamples) {
+            inputMQ->read(buffer, processSamples);
+            IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
+            outputMQ->write(buffer, status.fmqProduced);
+            statusMQ->writeBlocking(&status, 1);
+            LOG(VERBOSE) << getEffectName() << __func__ << ": done processing, effect consumed "
+                         << status.fmqConsumed << " produced " << status.fmqProduced;
+        }
+    }
+}
+
 // A placeholder processing implementation to copy samples from input to output
 IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int samples) {
     for (int i = 0; i < samples; i++) {
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 47ba9f4..fdd4803 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -25,8 +25,6 @@
 #include "effect-impl/EffectThread.h"
 #include "effect-impl/EffectTypes.h"
 
-using ::android::hardware::EventFlag;
-
 namespace aidl::android::hardware::audio::effect {
 
 EffectThread::EffectThread() {
@@ -38,31 +36,18 @@
     LOG(DEBUG) << __func__ << " done";
 }
 
-RetCode EffectThread::createThread(std::shared_ptr<EffectContext> context, const std::string& name,
-                                   int priority) {
+RetCode EffectThread::createThread(const std::string& name, int priority) {
     if (mThread.joinable()) {
         LOG(WARNING) << mName << __func__ << " thread already created, no-op";
         return RetCode::SUCCESS;
     }
+
     mName = name;
     mPriority = priority;
     {
         std::lock_guard lg(mThreadMutex);
         mStop = true;
         mExit = false;
-        mThreadContext = std::move(context);
-        auto statusMQ = mThreadContext->getStatusFmq();
-        EventFlag* efGroup = nullptr;
-        ::android::status_t status =
-                EventFlag::createEventFlag(statusMQ->getEventFlagWord(), &efGroup);
-        if (status != ::android::OK || !efGroup) {
-            LOG(ERROR) << mName << __func__ << " create EventFlagGroup failed " << status
-                       << " efGroup " << efGroup;
-            return RetCode::ERROR_THREAD;
-        }
-        mEfGroup.reset(efGroup);
-        // kickoff and wait for commands (CommandId::START/STOP) or IEffect.close from client
-        mEfGroup->wake(kEventFlagNotEmpty);
     }
 
     mThread = std::thread(&EffectThread::threadLoop, this);
@@ -75,16 +60,12 @@
         std::lock_guard lg(mThreadMutex);
         mStop = mExit = true;
     }
-    mCv.notify_one();
 
+    mCv.notify_one();
     if (mThread.joinable()) {
         mThread.join();
     }
 
-    {
-        std::lock_guard lg(mThreadMutex);
-        mThreadContext.reset();
-    }
     LOG(DEBUG) << mName << __func__;
     return RetCode::SUCCESS;
 }
@@ -96,7 +77,6 @@
         mCv.notify_one();
     }
 
-    mEfGroup->wake(kEventFlagNotEmpty);
     LOG(DEBUG) << mName << __func__;
     return RetCode::SUCCESS;
 }
@@ -108,7 +88,6 @@
         mCv.notify_one();
     }
 
-    mEfGroup->wake(kEventFlagNotEmpty);
     LOG(DEBUG) << mName << __func__;
     return RetCode::SUCCESS;
 }
@@ -117,13 +96,6 @@
     pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
     setpriority(PRIO_PROCESS, 0, mPriority);
     while (true) {
-        /**
-         * wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
-         * in the life cycle of workerThread (threadLoop).
-         */
-        uint32_t efState = 0;
-        mEfGroup->wait(kEventFlagNotEmpty, &efState);
-
         {
             std::unique_lock l(mThreadMutex);
             ::android::base::ScopedLockAssertion lock_assertion(mThreadMutex);
@@ -132,27 +104,8 @@
                 LOG(INFO) << __func__ << " EXIT!";
                 return;
             }
-            process_l();
         }
-    }
-}
-
-void EffectThread::process_l() {
-    RETURN_VALUE_IF(!mThreadContext, void(), "nullContext");
-
-    auto statusMQ = mThreadContext->getStatusFmq();
-    auto inputMQ = mThreadContext->getInputDataFmq();
-    auto outputMQ = mThreadContext->getOutputDataFmq();
-    auto buffer = mThreadContext->getWorkBuffer();
-
-    auto processSamples = inputMQ->availableToRead();
-    if (processSamples) {
-        inputMQ->read(buffer, processSamples);
-        IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
-        outputMQ->write(buffer, status.fmqProduced);
-        statusMQ->writeBlocking(&status, 1);
-        LOG(VERBOSE) << mName << __func__ << ": done processing, effect consumed "
-                     << status.fmqConsumed << " produced " << status.fmqProduced;
+        process();
     }
 }
 
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
index 5e18f1b..be0927c 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -168,10 +168,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> AcousticEchoCancelerSw::getContext() {
-    return mContext;
-}
-
 RetCode AcousticEchoCancelerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
index 73cf42b..95738f8 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
@@ -52,21 +52,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
     IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
 
   private:
     static const std::vector<Range::AcousticEchoCancelerRange> kRanges;
-    std::shared_ptr<AcousticEchoCancelerSwContext> mContext;
+    std::shared_ptr<AcousticEchoCancelerSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Tag& tag,
-                                                        Parameter::Specific* specific);
+                                                        Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.cpp b/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.cpp
index ce10ae1..d865b7e 100644
--- a/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.cpp
+++ b/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.cpp
@@ -177,10 +177,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> AutomaticGainControlV1Sw::getContext() {
-    return mContext;
-}
-
 RetCode AutomaticGainControlV1Sw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.h b/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.h
index 7d2a69f..76b91ae 100644
--- a/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.h
+++ b/audio/aidl/default/automaticGainControlV1/AutomaticGainControlV1Sw.h
@@ -53,21 +53,24 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
     static const std::vector<Range::AutomaticGainControlV1Range> kRanges;
-    std::shared_ptr<AutomaticGainControlV1SwContext> mContext;
+    std::shared_ptr<AutomaticGainControlV1SwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Tag& tag,
-                                                          Parameter::Specific* specific);
+                                                          Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.cpp b/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.cpp
index 1e336ac..3ff6e38 100644
--- a/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.cpp
+++ b/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.cpp
@@ -180,10 +180,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> AutomaticGainControlV2Sw::getContext() {
-    return mContext;
-}
-
 RetCode AutomaticGainControlV2Sw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.h b/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.h
index 9aa60ea..863d470 100644
--- a/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.h
+++ b/audio/aidl/default/automaticGainControlV2/AutomaticGainControlV2Sw.h
@@ -59,21 +59,24 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
     static const std::vector<Range::AutomaticGainControlV2Range> kRanges;
-    std::shared_ptr<AutomaticGainControlV2SwContext> mContext;
+    std::shared_ptr<AutomaticGainControlV2SwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Tag& tag,
-                                                          Parameter::Specific* specific);
+                                                          Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index 6072d89..60adc30 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.cpp
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -151,10 +151,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> BassBoostSw::getContext() {
-    return mContext;
-}
-
 RetCode BassBoostSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
index 1132472..901e455 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.h
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -51,21 +51,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
     static const std::vector<Range::BassBoostRange> kRanges;
-    std::shared_ptr<BassBoostSwContext> mContext;
+    std::shared_ptr<BassBoostSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Tag& tag,
-                                             Parameter::Specific* specific);
+                                             Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/downmix/DownmixSw.cpp b/audio/aidl/default/downmix/DownmixSw.cpp
index ce5fe20..19ab2e8 100644
--- a/audio/aidl/default/downmix/DownmixSw.cpp
+++ b/audio/aidl/default/downmix/DownmixSw.cpp
@@ -144,10 +144,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> DownmixSw::getContext() {
-    return mContext;
-}
-
 RetCode DownmixSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/downmix/DownmixSw.h b/audio/aidl/default/downmix/DownmixSw.h
index 3f8a09b..1a9f0f0 100644
--- a/audio/aidl/default/downmix/DownmixSw.h
+++ b/audio/aidl/default/downmix/DownmixSw.h
@@ -55,20 +55,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int sample) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int sample)
+            REQUIRES(mImplMutex) override;
 
   private:
-    std::shared_ptr<DownmixSwContext> mContext;
+    std::shared_ptr<DownmixSwContext> mContext GUARDED_BY(mImplMutex);
 
-    ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+    ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index e8f90b2..36face1 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -260,10 +260,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> DynamicsProcessingSw::getContext() {
-    return mContext;
-}
-
 RetCode DynamicsProcessingSw::releaseContext() {
     if (mContext) {
         mContext.reset();
@@ -282,6 +278,9 @@
 }
 
 RetCode DynamicsProcessingSwContext::setCommon(const Parameter::Common& common) {
+    if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+        return ret;
+    }
     mCommon = common;
     mChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
             common.input.base.channelMask);
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 641cf71..98edca0 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -113,15 +113,17 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; };
 
   private:
@@ -130,9 +132,10 @@
     static const Range::DynamicsProcessingRange kPreEqBandRange;
     static const Range::DynamicsProcessingRange kPostEqBandRange;
     static const std::vector<Range::DynamicsProcessingRange> kRanges;
-    std::shared_ptr<DynamicsProcessingSwContext> mContext;
+    std::shared_ptr<DynamicsProcessingSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
-                                                      Parameter::Specific* specific);
+                                                      Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 
 };  // DynamicsProcessingSw
 
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
index 73975c6..7937a6a 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -267,10 +267,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> EnvReverbSw::getContext() {
-    return mContext;
-}
-
 RetCode EnvReverbSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
index 5e31e2f..367462b 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -100,21 +100,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::EnvironmentalReverbRange> kRanges;
-    std::shared_ptr<EnvReverbSwContext> mContext;
+    std::shared_ptr<EnvReverbSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
-                                                       Parameter::Specific* specific);
+                                                       Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
index b2add31..640b3ba 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.cpp
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -198,10 +198,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> EqualizerSw::getContext() {
-    return mContext;
-}
-
 RetCode EqualizerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
index 56af3b5..caaa129 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -97,15 +97,17 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
@@ -113,7 +115,7 @@
     static const std::vector<Equalizer::Preset> kPresets;
     static const std::vector<Range::EqualizerRange> kRanges;
     ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
-                                             Parameter::Specific* specific);
+                                             Parameter::Specific* specific) REQUIRES(mImplMutex);
     std::shared_ptr<EqualizerSwContext> mContext;
 };
 
diff --git a/audio/aidl/default/extension/ExtensionEffect.cpp b/audio/aidl/default/extension/ExtensionEffect.cpp
index 4a4d71b6..11916c8 100644
--- a/audio/aidl/default/extension/ExtensionEffect.cpp
+++ b/audio/aidl/default/extension/ExtensionEffect.cpp
@@ -123,10 +123,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> ExtensionEffect::getContext() {
-    return mContext;
-}
-
 RetCode ExtensionEffect::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/extension/ExtensionEffect.h b/audio/aidl/default/extension/ExtensionEffect.h
index e7a068b..b560860 100644
--- a/audio/aidl/default/extension/ExtensionEffect.h
+++ b/audio/aidl/default/extension/ExtensionEffect.h
@@ -54,18 +54,20 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
-    std::shared_ptr<ExtensionEffectContext> mContext;
+    std::shared_ptr<ExtensionEffectContext> mContext GUARDED_BY(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index 27cdac8..7469ab9 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -158,10 +158,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> HapticGeneratorSw::getContext() {
-    return mContext;
-}
-
 RetCode HapticGeneratorSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
index 3bbe41a..47f3848 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -67,21 +67,24 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
-    std::shared_ptr<HapticGeneratorSwContext> mContext;
+    std::shared_ptr<HapticGeneratorSwContext> mContext GUARDED_BY(mImplMutex);
 
     ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::Tag& tag,
-                                                   Parameter::Specific* specific);
+                                                   Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 89d0c7c..24f3b5d 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -21,6 +21,7 @@
 #include <Utils.h>
 #include <android-base/logging.h>
 #include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
 
 #include <aidl/android/hardware/audio/effect/BnEffect.h>
 #include "EffectTypes.h"
@@ -36,127 +37,73 @@
             float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
             DataMQ;
 
-    EffectContext(size_t statusDepth, const Parameter::Common& common) {
-        auto& input = common.input;
-        auto& output = common.output;
-
-        LOG_ALWAYS_FATAL_IF(
-                input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
-                "inputFormatNotFloat");
-        LOG_ALWAYS_FATAL_IF(output.base.format.pcm !=
-                                    aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
-                            "outputFormatNotFloat");
-
-        size_t inputChannelCount =
-                ::aidl::android::hardware::audio::common::getChannelCount(input.base.channelMask);
-        LOG_ALWAYS_FATAL_IF(inputChannelCount == 0, "inputChannelCountNotValid");
-        size_t outputChannelCount =
-                ::aidl::android::hardware::audio::common::getChannelCount(output.base.channelMask);
-        LOG_ALWAYS_FATAL_IF(outputChannelCount == 0, "outputChannelCountNotValid");
-
-        mInputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
-                input.base.format, input.base.channelMask);
-        mOutputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
-                output.base.format, output.base.channelMask);
-        // in/outBuffer size in float (FMQ data format defined for DataMQ)
-        size_t inBufferSizeInFloat = input.frameCount * mInputFrameSize / sizeof(float);
-        size_t outBufferSizeInFloat = output.frameCount * mOutputFrameSize / sizeof(float);
-
-        // only status FMQ use the EventFlag
-        mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
-        mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
-        mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
-
-        if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
-            LOG(ERROR) << __func__ << " created invalid FMQ";
+    EffectContext(size_t statusDepth, const Parameter::Common& common);
+    virtual ~EffectContext() {
+        if (mEfGroup) {
+            ::android::hardware::EventFlag::deleteEventFlag(&mEfGroup);
         }
-        mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
-        mCommon = common;
     }
-    virtual ~EffectContext() {}
 
-    std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; }
-    std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; }
-    std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
+    std::shared_ptr<StatusMQ> getStatusFmq() const;
+    std::shared_ptr<DataMQ> getInputDataFmq() const;
+    std::shared_ptr<DataMQ> getOutputDataFmq() const;
 
-    float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
+    float* getWorkBuffer();
 
     // reset buffer status by abandon input data in FMQ
-    void resetBuffer() {
-        auto buffer = static_cast<float*>(mWorkBuffer.data());
-        std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
-        mInputMQ->read(buffer, mInputMQ->availableToRead());
-    }
+    void resetBuffer();
+    void dupeFmq(IEffect::OpenEffectReturn* effectRet);
+    size_t getInputFrameSize() const;
+    size_t getOutputFrameSize() const;
+    int getSessionId() const;
+    int getIoHandle() const;
 
-    void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
-        if (effectRet) {
-            effectRet->statusMQ = mStatusMQ->dupeDesc();
-            effectRet->inputDataMQ = mInputMQ->dupeDesc();
-            effectRet->outputDataMQ = mOutputMQ->dupeDesc();
-        }
-    }
-    size_t getInputFrameSize() { return mInputFrameSize; }
-    size_t getOutputFrameSize() { return mOutputFrameSize; }
-    int getSessionId() { return mCommon.session; }
-    int getIoHandle() { return mCommon.ioHandle; }
+    virtual void dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet);
 
     virtual RetCode setOutputDevice(
-            const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
-                    device) {
-        mOutputDevice = device;
-        return RetCode::SUCCESS;
-    }
+            const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device);
 
     virtual std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
-    getOutputDevice() {
-        return mOutputDevice;
-    }
+    getOutputDevice();
 
-    virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
-        mMode = mode;
-        return RetCode::SUCCESS;
-    }
-    virtual aidl::android::media::audio::common::AudioMode getAudioMode() { return mMode; }
+    virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode);
+    virtual aidl::android::media::audio::common::AudioMode getAudioMode();
 
-    virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source) {
-        mSource = source;
-        return RetCode::SUCCESS;
-    }
-    virtual aidl::android::media::audio::common::AudioSource getAudioSource() { return mSource; }
+    virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source);
+    virtual aidl::android::media::audio::common::AudioSource getAudioSource();
 
-    virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
-        mVolumeStereo = volumeStereo;
-        return RetCode::SUCCESS;
-    }
-    virtual Parameter::VolumeStereo getVolumeStereo() { return mVolumeStereo; }
+    virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo);
+    virtual Parameter::VolumeStereo getVolumeStereo();
 
-    virtual RetCode setCommon(const Parameter::Common& common) {
-        mCommon = common;
-        LOG(VERBOSE) << __func__ << mCommon.toString();
-        return RetCode::SUCCESS;
-    }
-    virtual Parameter::Common getCommon() {
-        LOG(VERBOSE) << __func__ << mCommon.toString();
-        return mCommon;
-    }
+    virtual RetCode setCommon(const Parameter::Common& common);
+    virtual Parameter::Common getCommon();
+
+    virtual ::android::hardware::EventFlag* getStatusEventFlag();
 
   protected:
-    // common parameters
     size_t mInputFrameSize;
     size_t mOutputFrameSize;
-    Parameter::Common mCommon;
-    std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice;
-    aidl::android::media::audio::common::AudioMode mMode;
-    aidl::android::media::audio::common::AudioSource mSource;
-    Parameter::VolumeStereo mVolumeStereo;
+    size_t mInputChannelCount;
+    size_t mOutputChannelCount;
+    Parameter::Common mCommon = {};
+    std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice = {};
+    aidl::android::media::audio::common::AudioMode mMode =
+            aidl::android::media::audio::common::AudioMode::SYS_RESERVED_INVALID;
+    aidl::android::media::audio::common::AudioSource mSource =
+            aidl::android::media::audio::common::AudioSource::SYS_RESERVED_INVALID;
+    Parameter::VolumeStereo mVolumeStereo = {};
+    RetCode updateIOFrameSize(const Parameter::Common& common);
+    RetCode notifyDataMqUpdate();
 
   private:
     // fmq and buffers
     std::shared_ptr<StatusMQ> mStatusMQ;
     std::shared_ptr<DataMQ> mInputMQ;
     std::shared_ptr<DataMQ> mOutputMQ;
-    // TODO handle effect process input and output
+    // std::shared_ptr<IEffect::OpenEffectReturn> mRet;
     // work buffer set by effect instances, the access and update are in same thread
     std::vector<float> mWorkBuffer;
+
+    ::android::hardware::EventFlag* mEfGroup;
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
index 242a268..21f6502 100644
--- a/audio/aidl/default/include/effect-impl/EffectImpl.h
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -49,33 +49,54 @@
     virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
     virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
 
-    virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
-    virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
+    virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param) REQUIRES(mImplMutex);
+    virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param)
+            REQUIRES(mImplMutex);
 
     /* Methods MUST be implemented by each effect instances */
     virtual ndk::ScopedAStatus getDescriptor(Descriptor* desc) = 0;
-    virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
+    virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) = 0;
     virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                                    Parameter::Specific* specific) = 0;
+                                                    Parameter::Specific* specific)
+            REQUIRES(mImplMutex) = 0;
 
     virtual std::string getEffectName() = 0;
-    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex);
+    virtual RetCode releaseContext() REQUIRES(mImplMutex) = 0;
 
     /**
-     * Effect context methods must be implemented by each effect.
-     * Each effect can derive from EffectContext and define its own context, but must upcast to
-     * EffectContext for EffectImpl to use.
+     * @brief effectProcessImpl is running in worker thread which created in EffectThread.
+     *
+     * EffectThread will make sure effectProcessImpl only be called after startThread() successful
+     * and before stopThread() successful.
+     *
+     * effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
+     * cause deadlock.
+     *
+     * @param in address of input float buffer.
+     * @param out address of output float buffer.
+     * @param samples number of samples to process.
+     * @return IEffect::Status
      */
-    virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
-    virtual std::shared_ptr<EffectContext> getContext() = 0;
-    virtual RetCode releaseContext() = 0;
+    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
+
+    /**
+     * process() get data from data MQs, and call effectProcessImpl() for effect data processing.
+     * Its important for the implementation to use mImplMutex for context synchronization.
+     */
+    void process() override;
 
   protected:
-    State mState = State::INIT;
+    State mState GUARDED_BY(mImplMutex) = State::INIT;
 
     IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
     void cleanUp();
 
+    std::mutex mImplMutex;
+    std::shared_ptr<EffectContext> mImplContext GUARDED_BY(mImplMutex);
+
     /**
      * Optional CommandId handling methods for effects to override.
      * For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
@@ -83,6 +104,9 @@
      * For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
      * EffectThread processing.
      */
-    virtual ndk::ScopedAStatus commandImpl(CommandId id);
+    virtual ndk::ScopedAStatus commandImpl(CommandId id) REQUIRES(mImplMutex);
+
+    RetCode notifyEventFlag(uint32_t flag);
+    ::android::hardware::EventFlag* mEventFlag;
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index ae51ef7..3dbb0e6 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -36,8 +36,7 @@
     virtual ~EffectThread();
 
     // called by effect implementation.
-    RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name,
-                         int priority = ANDROID_PRIORITY_URGENT_AUDIO);
+    RetCode createThread(const std::string& name, int priority = ANDROID_PRIORITY_URGENT_AUDIO);
     RetCode destroyThread();
     RetCode startThread();
     RetCode stopThread();
@@ -46,32 +45,11 @@
     void threadLoop();
 
     /**
-     * @brief effectProcessImpl is running in worker thread which created in EffectThread.
-     *
-     * Effect implementation should think about concurrency in the implementation if necessary.
-     * Parameter setting usually implemented in context (derived from EffectContext), and some
-     * parameter maybe used in the processing, then effect implementation should consider using a
-     * mutex to protect these parameter.
-     *
-     * EffectThread will make sure effectProcessImpl only be called after startThread() successful
-     * and before stopThread() successful.
-     *
-     * effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
-     * cause deadlock.
-     *
-     * @param in address of input float buffer.
-     * @param out address of output float buffer.
-     * @param samples number of samples to process.
-     * @return IEffect::Status
-     */
-    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
-
-    /**
      * process() call effectProcessImpl() for effect data processing, it is necessary for the
      * processing to be called under Effect thread mutex mThreadMutex, to avoid the effect state
      * change before/during data processing, and keep the thread and effect state consistent.
      */
-    virtual void process_l() REQUIRES(mThreadMutex);
+    virtual void process() = 0;
 
   private:
     static constexpr int kMaxTaskNameLen = 15;
@@ -80,16 +58,7 @@
     std::condition_variable mCv;
     bool mStop GUARDED_BY(mThreadMutex) = true;
     bool mExit GUARDED_BY(mThreadMutex) = false;
-    std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex);
 
-    struct EventFlagDeleter {
-        void operator()(::android::hardware::EventFlag* flag) const {
-            if (flag) {
-                ::android::hardware::EventFlag::deleteEventFlag(&flag);
-            }
-        }
-    };
-    std::unique_ptr<::android::hardware::EventFlag, EventFlagDeleter> mEfGroup;
     std::thread mThread;
     int mPriority;
     std::string mName;
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index 4bda7be..9740d6e 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -46,7 +46,8 @@
     ERROR_NULL_POINTER,      /* NULL pointer */
     ERROR_ALIGNMENT_ERROR,   /* Memory alignment error */
     ERROR_BLOCK_SIZE_EXCEED, /* Maximum block size exceeded */
-    ERROR_EFFECT_LIB_ERROR
+    ERROR_EFFECT_LIB_ERROR,  /* Effect implementation library error */
+    ERROR_EVENT_FLAG_ERROR   /* Error with effect event flags */
 };
 
 static const int INVALID_AUDIO_SESSION_ID = -1;
@@ -67,6 +68,8 @@
             return out << "ERROR_BLOCK_SIZE_EXCEED";
         case RetCode::ERROR_EFFECT_LIB_ERROR:
             return out << "ERROR_EFFECT_LIB_ERROR";
+        case RetCode::ERROR_EVENT_FLAG_ERROR:
+            return out << "ERROR_EVENT_FLAG_ERROR";
     }
 
     return out << "EnumError: " << code;
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
index 7954316..1e70716 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -147,10 +147,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> LoudnessEnhancerSw::getContext() {
-    return mContext;
-}
-
 RetCode LoudnessEnhancerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
index 25824f2..cf71a5f 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -54,20 +54,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
-    std::shared_ptr<LoudnessEnhancerSwContext> mContext;
+    std::shared_ptr<LoudnessEnhancerSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
-                                                    Parameter::Specific* specific);
+                                                    Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
index a3208df..d304416 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
@@ -155,10 +155,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> NoiseSuppressionSw::getContext() {
-    return mContext;
-}
-
 RetCode NoiseSuppressionSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
index fc1e028..acef8ee 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
@@ -55,20 +55,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
-    std::shared_ptr<NoiseSuppressionSwContext> mContext;
+    std::shared_ptr<NoiseSuppressionSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Tag& tag,
-                                                    Parameter::Specific* specific);
+                                                    Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
index 3f02eb7..2ac2010 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.cpp
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -161,10 +161,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> PresetReverbSw::getContext() {
-    return mContext;
-}
-
 RetCode PresetReverbSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
index 9ceee7c..61fc88c 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.h
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -56,21 +56,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
-    std::shared_ptr<PresetReverbSwContext> mContext;
+    std::shared_ptr<PresetReverbSwContext> mContext GUARDED_BY(mImplMutex);
 
     ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Tag& tag,
-                                                Parameter::Specific* specific);
+                                                Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/spatializer/SpatializerSw.cpp b/audio/aidl/default/spatializer/SpatializerSw.cpp
index 434ed5a..6d3c4bd 100644
--- a/audio/aidl/default/spatializer/SpatializerSw.cpp
+++ b/audio/aidl/default/spatializer/SpatializerSw.cpp
@@ -141,10 +141,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> SpatializerSw::getContext() {
-    return mContext;
-}
-
 RetCode SpatializerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/spatializer/SpatializerSw.h b/audio/aidl/default/spatializer/SpatializerSw.h
index b205704..b321e83 100644
--- a/audio/aidl/default/spatializer/SpatializerSw.h
+++ b/audio/aidl/default/spatializer/SpatializerSw.h
@@ -50,19 +50,21 @@
     ~SpatializerSw();
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return kEffectName; };
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
 
   private:
     static const std::vector<Range::SpatializerRange> kRanges;
-    std::shared_ptr<SpatializerSwContext> mContext = nullptr;
+    std::shared_ptr<SpatializerSwContext> mContext GUARDED_BY(mImplMutex) = nullptr;
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index 0e8435e..091b0b7 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -203,10 +203,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> VirtualizerSw::getContext() {
-    return mContext;
-}
-
 RetCode VirtualizerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index 5e114d9..9287838 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -59,24 +59,25 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
     IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::VirtualizerRange> kRanges;
-    std::shared_ptr<VirtualizerSwContext> mContext;
+    std::shared_ptr<VirtualizerSwContext> mContext GUARDED_BY(mImplMutex);
 
     ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Tag& tag,
-                                               Parameter::Specific* specific);
+                                               Parameter::Specific* specific) REQUIRES(mImplMutex);
     ndk::ScopedAStatus getSpeakerAngles(const Virtualizer::SpeakerAnglesPayload payload,
-                                        Parameter::Specific* specific);
+                                        Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 285c102..54f7f1c 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -190,10 +190,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> VisualizerSw::getContext() {
-    return mContext;
-}
-
 RetCode VisualizerSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index 995774e..4b87b04 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -72,21 +72,23 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::VisualizerRange> kRanges;
-    std::shared_ptr<VisualizerSwContext> mContext;
+    std::shared_ptr<VisualizerSwContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
-                                              Parameter::Specific* specific);
+                                              Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
index 8902584..dd019f6 100644
--- a/audio/aidl/default/volume/VolumeSw.cpp
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -160,10 +160,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> VolumeSw::getContext() {
-    return mContext;
-}
-
 RetCode VolumeSw::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
index 1432b2b..3fc0d97 100644
--- a/audio/aidl/default/volume/VolumeSw.h
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -57,21 +57,24 @@
     }
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    std::shared_ptr<EffectContext> getContext() override;
-    RetCode releaseContext() override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+            REQUIRES(mImplMutex) override;
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::VolumeRange> kRanges;
-    std::shared_ptr<VolumeSwContext> mContext;
+    std::shared_ptr<VolumeSwContext> mContext GUARDED_BY(mImplMutex);
 
-    ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific);
+    ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 4a5c537..9fa7f9f 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -43,6 +43,7 @@
 using aidl::android::hardware::audio::effect::CommandId;
 using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
 using aidl::android::hardware::audio::effect::kEventFlagNotEmpty;
 using aidl::android::hardware::audio::effect::Parameter;
 using aidl::android::hardware::audio::effect::Range;
@@ -191,6 +192,16 @@
             ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
         }
     }
+    static void expectDataMqUpdateEventFlag(std::unique_ptr<StatusMQ>& statusMq) {
+        EventFlag* efGroup;
+        ASSERT_EQ(::android::OK,
+                  EventFlag::createEventFlag(statusMq->getEventFlagWord(), &efGroup));
+        ASSERT_NE(nullptr, efGroup);
+        uint32_t efState = 0;
+        EXPECT_EQ(::android::OK, efGroup->wait(kEventFlagDataMqUpdate, &efState, 1'000'000 /*1ms*/,
+                                               true /* retry */));
+        EXPECT_TRUE(efState & kEventFlagDataMqUpdate);
+    }
     static Parameter::Common createParamCommon(
             int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
             long iFrameCount = 0x100, long oFrameCount = 0x100,
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 418fedb..01cdd81 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -609,6 +609,49 @@
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
+// Verify Parameters kept after reset.
+TEST_P(AudioEffectTest, SetCommonParameterAndReopen) {
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
+
+    Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
+    common.input.frameCount++;
+    ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
+    ASSERT_TRUE(statusMQ->isValid());
+    expectDataMqUpdateEventFlag(statusMQ);
+    EXPECT_IS_OK(mEffect->reopen(&ret));
+    inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    ASSERT_TRUE(inputMQ->isValid());
+    ASSERT_TRUE(outputMQ->isValid());
+
+    common.output.frameCount++;
+    ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
+    ASSERT_TRUE(statusMQ->isValid());
+    expectDataMqUpdateEventFlag(statusMQ);
+    EXPECT_IS_OK(mEffect->reopen(&ret));
+    inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    ASSERT_TRUE(inputMQ->isValid());
+    ASSERT_TRUE(outputMQ->isValid());
+
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+}
+
 /// Data processing test
 // Send data to effects and expect it to be consumed by checking statusMQ.
 // Effects exposing bypass flags or operating in offload mode will be skipped.
@@ -684,6 +727,59 @@
     ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
+// Send data to effects and expect it to be consumed after effect reopen (IO AudioConfig change).
+// Effects exposing bypass flags or operating in offload mode will be skipped.
+TEST_P(AudioEffectDataPathTest, ConsumeDataAfterReopen) {
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+    Parameter::Common common = EffectHelper::createParamCommon(
+            0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+            kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+    IEffect::OpenEffectReturn ret;
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
+    auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
+
+    std::vector<float> buffer;
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(
+            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
+
+    // set a new common parameter with different IO frameCount, reopen
+    Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
+    common.input.frameCount += 4;
+    common.output.frameCount += 4;
+    ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
+    ASSERT_TRUE(statusMQ->isValid());
+    expectDataMqUpdateEventFlag(statusMQ);
+    EXPECT_IS_OK(mEffect->reopen(&ret));
+    inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(statusMQ->isValid());
+    ASSERT_TRUE(inputMQ->isValid());
+    ASSERT_TRUE(outputMQ->isValid());
+
+    // verify data consume again
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
+    EXPECT_NO_FATAL_FAILURE(
+            EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
+
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
+
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+}
+
 // Send data to IDLE effects and expect it to be consumed after effect start.
 // Effects exposing bypass flags or operating in offload mode will be skipped.
 TEST_P(AudioEffectDataPathTest, SendDataAtIdleAndConsumeDataInProcessing) {