Merge changes from topic "rm_changes" into main

* changes:
  resourcemanager: protect resources from concurrent access
  resourcemanager: use std::vector for ResourceList
diff --git a/camera/Android.mk b/camera/Android.mk
deleted file mode 100644
index d9068c0..0000000
--- a/camera/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2010 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 $(call all-subdir-makefiles)
diff --git a/camera/include/camera/camera2/SessionConfiguration.h b/camera/include/camera/camera2/SessionConfiguration.h
index 29913f6..73fafb4 100644
--- a/camera/include/camera/camera2/SessionConfiguration.h
+++ b/camera/include/camera/camera2/SessionConfiguration.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HARDWARE_CAMERA2_SESSIONCONFIGURATION_H
 #define ANDROID_HARDWARE_CAMERA2_SESSIONCONFIGURATION_H
 
+#include "OutputConfiguration.h"
+
 #include <binder/Parcelable.h>
 
 namespace android {
@@ -25,8 +27,6 @@
 namespace camera2 {
 namespace params {
 
-class OutputConfiguration;
-
 class SessionConfiguration : public android::Parcelable {
 public:
 
diff --git a/camera/tests/Android.bp b/camera/tests/Android.bp
new file mode 100644
index 0000000..65b8b41
--- /dev/null
+++ b/camera/tests/Android.bp
@@ -0,0 +1,52 @@
+// Copyright 2013 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.
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "frameworks_av_camera_license",
+    ],
+}
+
+cc_test {
+    name: "camera_client_test",
+    srcs: [
+        "VendorTagDescriptorTests.cpp",
+        "CameraBinderTests.cpp",
+        "CameraZSLTests.cpp",
+        "CameraCharacteristicsPermission.cpp",
+    ],
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libcutils",
+        "libcamera_metadata",
+        "libcamera_client",
+        "libgui",
+        "libsync",
+        "libui",
+        "libdl",
+        "libbinder",
+    ],
+    include_dirs: [
+        "system/media/private/camera/include",
+        "system/media/camera/tests",
+        "frameworks/av/services/camera/libcameraservice",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+}
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
deleted file mode 100644
index 7f8078e..0000000
--- a/camera/tests/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_SRC_FILES:= \
-	VendorTagDescriptorTests.cpp \
-	CameraBinderTests.cpp \
-	CameraZSLTests.cpp \
-	CameraCharacteristicsPermission.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libutils \
-	libcutils \
-	libcamera_metadata \
-	libcamera_client \
-	libgui \
-	libsync \
-	libui \
-	libdl \
-	libbinder
-
-LOCAL_C_INCLUDES += \
-	system/media/private/camera/include \
-	system/media/camera/tests \
-	frameworks/av/services/camera/libcameraservice \
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE:= camera_client_test
-LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS:= notice
-LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../NOTICE
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/media/aconfig/Android.bp b/media/aconfig/Android.bp
index 96bf4f5..f95d723 100644
--- a/media/aconfig/Android.bp
+++ b/media/aconfig/Android.bp
@@ -14,6 +14,7 @@
     name: "aconfig_mediacodec_flags_c_lib",
     min_sdk_version: "30",
     vendor_available: true,
+    double_loadable: true,
     apex_available: [
         "//apex_available:platform",
         "com.android.media.swcodec",
diff --git a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
index 53f529e..7cba011 100644
--- a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
@@ -25,6 +25,7 @@
 #define AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_CPP
 #endif  // BACKEND_NDK_IMPL
 
+#include <functional>
 #include <limits>
 #include <type_traits>
 #include <utility>
diff --git a/media/codec2/TEST_MAPPING b/media/codec2/TEST_MAPPING
index 8a894f3..b911e11 100644
--- a/media/codec2/TEST_MAPPING
+++ b/media/codec2/TEST_MAPPING
@@ -25,5 +25,8 @@
         }
       ]
     }
+  ],
+  "postsubmit": [
+    { "name": "c2aidl_gtracker_test"}
   ]
 }
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
index 10e4b79..76680a3 100644
--- a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
+++ b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
@@ -648,6 +648,24 @@
             if (res == 0) {
                 ALOGV("dav1d found a sequenceHeader (%dx%d) for in_frameIndex=%ld.", seq.max_width,
                       seq.max_height, (long)in_frameIndex);
+                if (seq.max_width != mWidth || seq.max_height != mHeight) {
+                    drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
+                    mWidth = seq.max_width;
+                    mHeight = seq.max_height;
+
+                    C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
+                    std::vector<std::unique_ptr<C2SettingResult>> failures;
+                    c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+                    if (err == C2_OK) {
+                        work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
+                    } else {
+                        ALOGE("Config update size failed");
+                        mSignalledError = true;
+                        work->result = C2_CORRUPTED;
+                        work->workletsProcessed = 1u;
+                        return;
+                    }
+                }
             }
 
             // insert OBU TD if it is not present.
@@ -921,26 +939,6 @@
         return false;
     }
 
-    const int width = img.p.w;
-    const int height = img.p.h;
-    if (width != mWidth || height != mHeight) {
-        mWidth = width;
-        mHeight = height;
-
-        C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
-        std::vector<std::unique_ptr<C2SettingResult>> failures;
-        c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
-        if (err == C2_OK) {
-            work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
-        } else {
-            ALOGE("Config update size failed");
-            mSignalledError = true;
-            work->result = C2_CORRUPTED;
-            work->workletsProcessed = 1u;
-            return false;
-        }
-    }
-
     getVuiParams(&img);
 
     // out_frameIndex that the decoded picture returns from dav1d.
diff --git a/media/codec2/components/raw/C2SoftRawDec.cpp b/media/codec2/components/raw/C2SoftRawDec.cpp
index a03d4e2..ea13071 100644
--- a/media/codec2/components/raw/C2SoftRawDec.cpp
+++ b/media/codec2/components/raw/C2SoftRawDec.cpp
@@ -65,7 +65,7 @@
         addParameter(
                 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
                 .withDefault(new C2StreamChannelCountInfo::output(0u, 2))
-                .withFields({C2F(mChannelCount, value).inRange(1, 8)})
+                .withFields({C2F(mChannelCount, value).inRange(1, 12)})
                 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
                 .build());
 
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
index 7a9af18..48b6e21 100644
--- a/media/codec2/hal/aidl/Android.bp
+++ b/media/codec2/hal/aidl/Android.bp
@@ -24,7 +24,7 @@
     shared_libs: [
         "android.hardware.common-V2-ndk",
         "android.hardware.media.bufferpool@2.0",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
         "android.hardware.media.c2-V1-ndk",
         "libbinder_ndk",
         "libbase",
@@ -84,7 +84,7 @@
 
     shared_libs: [
         "android.hardware.common-V2-ndk",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
         "android.hardware.media.c2-V1-ndk",
         "libbase",
         "libbinder_ndk",
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
index 4605af3..4c2d5d3 100644
--- a/media/codec2/hal/aidl/Component.cpp
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -403,6 +403,22 @@
     return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
 }
 
+ScopedAStatus Component::connectToInputSurface(
+        const std::shared_ptr<IInputSurface>& inputSurface,
+        std::shared_ptr<IInputSurfaceConnection> *connection) {
+    // TODO
+    (void)inputSurface;
+    (void)connection;
+    return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
+}
+
+ScopedAStatus Component::asInputSink(
+        std::shared_ptr<IInputSink> *sink) {
+    // TODO
+    (void)sink;
+    return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
+}
+
 void Component::initListener(const std::shared_ptr<Component>& self) {
     if (__builtin_available(android __ANDROID_API_T__, *)) {
         std::shared_ptr<C2Component::Listener> c2listener =
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index 58407d1..f0a1490 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -273,6 +273,13 @@
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus ComponentStore::createInputSurface(
+        std::shared_ptr<IInputSurface> *inputSurface) {
+    // TODO
+    (void)inputSurface;
+    return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
+}
+
 void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
     // invalidate unsupported struct descriptors if a new interface is loaded as it may have
     // exposed new descriptors
diff --git a/media/codec2/hal/aidl/Configurable.cpp b/media/codec2/hal/aidl/Configurable.cpp
index 0326263..2daaac2 100644
--- a/media/codec2/hal/aidl/Configurable.cpp
+++ b/media/codec2/hal/aidl/Configurable.cpp
@@ -19,6 +19,7 @@
 #include <android-base/logging.h>
 
 #include <android/binder_auto_utils.h>
+#include <android-base/hex.h>
 #include <codec2/aidl/Configurable.h>
 #include <codec2/aidl/ParamTypes.h>
 
@@ -61,7 +62,7 @@
 ScopedAStatus CachedConfigurable::query(
         const std::vector<int32_t>& indices,
         bool mayBlock,
-        Params* params) {
+        QueryResult *queryResult) {
     typedef C2Param::Index Index;
     std::vector<Index> c2heapParamIndices(
             (Index*)indices.data(),
@@ -72,13 +73,11 @@
             mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
             &c2heapParams);
 
-    if (!CreateParamsBlob(params, c2heapParams)) {
+    if (!CreateParamsBlob(&(queryResult->params), c2heapParams)) {
         LOG(WARNING) << "query -- invalid output params.";
     }
-    if (c2res == C2_OK) {
-        return ScopedAStatus::ok();
-    }
-    return ScopedAStatus::fromServiceSpecificError(c2res);
+    queryResult->status.status = c2res;
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus CachedConfigurable::config(
@@ -115,10 +114,8 @@
     if (!CreateParamsBlob(&result->params, c2params)) {
         LOG(DEBUG) << "config -- invalid output params.";
     }
-    if (c2res == C2_OK) {
-        return ScopedAStatus::ok();
-    }
-    return ScopedAStatus::fromServiceSpecificError(c2res);
+    result->status.status = c2res;
+    return ScopedAStatus::ok();
 }
 
 ScopedAStatus CachedConfigurable::querySupportedParams(
@@ -139,8 +136,6 @@
                 LOG(WARNING) << "querySupportedParams -- invalid output params.";
                 break;
             }
-        } else {
-            res = Status::BAD_INDEX;
         }
     }
     paramDesc->resize(dstIx);
@@ -153,7 +148,7 @@
 ScopedAStatus CachedConfigurable::querySupportedValues(
         const std::vector<FieldSupportedValuesQuery>& fields,
         bool mayBlock,
-        std::vector<FieldSupportedValuesQueryResult>* result) {
+        QuerySupportedValuesResult *queryValues) {
     std::vector<C2FieldSupportedValuesQuery> c2fields;
     {
         // C2FieldSupportedValuesQuery objects are restricted in that some
@@ -173,22 +168,20 @@
     c2_status_t c2res = mIntf->querySupportedValues(
             c2fields,
             mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK);
-    result->resize(fields.size());
+    queryValues->values.resize(fields.size());
     size_t dstIx = 0;
     for (const C2FieldSupportedValuesQuery &res : c2fields) {
-        if (ToAidl(&(*result)[dstIx], res)) {
+        if (ToAidl(&(queryValues->values[dstIx]), res)) {
             ++dstIx;
         } else {
-            result->resize(dstIx);
+            queryValues->values.resize(dstIx);
             c2res = C2_CORRUPTED;
             LOG(WARNING) << "querySupportedValues -- invalid output params.";
             break;
         }
     }
-    if (c2res == C2_OK) {
-        return ScopedAStatus::ok();
-    }
-    return ScopedAStatus::fromServiceSpecificError(c2res);
+    queryValues->status.status = c2res;
+    return ScopedAStatus::ok();
 }
 
 }  // namespace utils
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/Component.h b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
index 4a090e9..94b760f 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/Component.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
@@ -27,6 +27,9 @@
 #include <aidl/android/hardware/media/c2/IComponentInterface.h>
 #include <aidl/android/hardware/media/c2/IComponentListener.h>
 #include <aidl/android/hardware/media/c2/IComponentStore.h>
+#include <aidl/android/hardware/media/c2/IInputSink.h>
+#include <aidl/android/hardware/media/c2/IInputSurface.h>
+#include <aidl/android/hardware/media/c2/IInputSurfaceConnection.h>
 
 #include <C2Component.h>
 #include <C2Buffer.h>
@@ -71,6 +74,11 @@
     ::ndk::ScopedAStatus configureVideoTunnel(
             int32_t avSyncHwId,
             common::NativeHandle* handle) override;
+    ::ndk::ScopedAStatus connectToInputSurface(
+            const std::shared_ptr<IInputSurface>& inputSurface,
+            std::shared_ptr<IInputSurfaceConnection> *connection) override;
+    ::ndk::ScopedAStatus asInputSink(
+            std::shared_ptr<IInputSink> *sink) override;
 
 protected:
     c2_status_t mInit;
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index b3c97d5..0698b0f 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -23,6 +23,7 @@
 
 #include <aidl/android/hardware/media/bufferpool2/IClientManager.h>
 #include <aidl/android/hardware/media/c2/BnComponentStore.h>
+#include <aidl/android/hardware/media/c2/IInputSurface.h>
 
 #include <C2Component.h>
 #include <C2Param.h>
@@ -85,6 +86,8 @@
             std::shared_ptr<IComponentInterface> *intf) override;
     virtual ::ndk::ScopedAStatus listComponents(
             std::vector<IComponentStore::ComponentTraits>* traits) override;
+    virtual ::ndk::ScopedAStatus createInputSurface(
+            std::shared_ptr<IInputSurface> *inputSurface) override;
     virtual ::ndk::ScopedAStatus getStructDescriptors(
             const std::vector<int32_t>& indices,
             std::vector<StructDescriptor> *descs) override;
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h b/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
index 6cc2c1b..96d3516 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
@@ -111,7 +111,7 @@
     virtual ::ndk::ScopedAStatus query(
             const std::vector<int32_t>& indices,
             bool mayBlock,
-            Params* params) override;
+            QueryResult* result) override;
 
     virtual ::ndk::ScopedAStatus config(
             const ::aidl::android::hardware::media::c2::Params& params,
@@ -126,7 +126,7 @@
     virtual ::ndk::ScopedAStatus querySupportedValues(
             const std::vector<FieldSupportedValuesQuery>& fields,
             bool mayBlock,
-            std::vector<FieldSupportedValuesQueryResult>* result) override;
+            QuerySupportedValuesResult* result) override;
 
 protected:
     // Common Codec2.0 interface wrapper
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 0b5b940..af6f4ae 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -43,7 +43,7 @@
         "android.hardware.media.c2@1.0",
         "android.hardware.media.c2@1.1",
         "android.hardware.media.c2@1.2",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
         "android.hardware.media.c2-V1-ndk",
         "libbase",
         "libbinder",
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 0848fc6..01b0678 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -174,20 +174,16 @@
 
 GraphicsTracker::GraphicsTracker(int maxDequeueCount)
     : mBufferCache(new BufferCache()), mMaxDequeue{maxDequeueCount},
-    mMaxDequeueRequested{maxDequeueCount},
     mMaxDequeueCommitted{maxDequeueCount},
-    mMaxDequeueRequestedSeqId{0UL}, mMaxDequeueCommittedSeqId{0ULL},
     mDequeueable{maxDequeueCount},
     mTotalDequeued{0}, mTotalCancelled{0}, mTotalDropped{0}, mTotalReleased{0},
     mInConfig{false}, mStopped{false} {
     if (maxDequeueCount < kMaxDequeueMin) {
         mMaxDequeue = kMaxDequeueMin;
-        mMaxDequeueRequested = kMaxDequeueMin;
         mMaxDequeueCommitted = kMaxDequeueMin;
         mDequeueable = kMaxDequeueMin;
     } else if(maxDequeueCount > kMaxDequeueMax) {
         mMaxDequeue = kMaxDequeueMax;
-        mMaxDequeueRequested = kMaxDequeueMax;
         mMaxDequeueCommitted = kMaxDequeueMax;
         mDequeueable = kMaxDequeueMax;
     }
@@ -197,34 +193,36 @@
     mReadPipeFd.reset(pipefd[0]);
     mWritePipeFd.reset(pipefd[1]);
 
-    mEventQueueThread = std::thread([this](){processEvent();});
-    writeIncDequeueable(mDequeueable);
+    // ctor does not require lock to be held.
+    writeIncDequeueableLocked(mDequeueable);
 
     CHECK(ret >= 0);
-    CHECK(mEventQueueThread.joinable());
 }
 
 GraphicsTracker::~GraphicsTracker() {
     stop();
-    if (mEventQueueThread.joinable()) {
-        mEventQueueThread.join();
-    }
 }
 
 bool GraphicsTracker::adjustDequeueConfLocked(bool *updateDequeue) {
     // TODO: can't we adjust during config? not committing it may safe?
     *updateDequeue = false;
-    if (!mInConfig && mMaxDequeueRequested < mMaxDequeue) {
-        int delta = mMaxDequeue - mMaxDequeueRequested;
+    if (!mInConfig && mMaxDequeueRequested.has_value() && mMaxDequeueRequested < mMaxDequeue) {
+        int delta = mMaxDequeue - mMaxDequeueRequested.value();
+        int drained = 0;
         // Since we are supposed to increase mDequeuable by one already
         int adjustable = mDequeueable + 1;
         if (adjustable >= delta) {
-            mMaxDequeue = mMaxDequeueRequested;
+            mMaxDequeue = mMaxDequeueRequested.value();
             mDequeueable -= (delta - 1);
+            drained = delta - 1;
         } else {
             mMaxDequeue -= adjustable;
+            drained = mDequeueable;
             mDequeueable = 0;
         }
+        if (drained > 0) {
+            drainDequeueableLocked(drained);
+        }
         if (mMaxDequeueRequested == mMaxDequeue && mMaxDequeueRequested != mMaxDequeueCommitted) {
             *updateDequeue = true;
         }
@@ -235,6 +233,7 @@
 
 c2_status_t GraphicsTracker::configureGraphics(
         const sp<IGraphicBufferProducer>& igbp, uint32_t generation) {
+    // TODO: wait until operations to previous IGBP is completed.
     std::shared_ptr<BufferCache> prevCache;
     int prevDequeueCommitted;
 
@@ -254,14 +253,28 @@
     if (igbp) {
         ret = igbp->getUniqueId(&bqId);
     }
-    if (ret != ::android::OK || prevCache->mGeneration == generation || prevCache->mBqId == bqId) {
+    if (ret != ::android::OK ||
+            prevCache->mGeneration == generation) {
+        ALOGE("new surface configure fail due to wrong or same bqId or same generation:"
+              "igbp(%d:%llu -> %llu), gen(%lu -> %lu)", (bool)igbp,
+              (unsigned long long)prevCache->mBqId, (unsigned long long)bqId,
+              (unsigned long)prevCache->mGeneration, (unsigned long)generation);
+        std::unique_lock<std::mutex> l(mLock);
+        mInConfig = false;
         return C2_BAD_VALUE;
     }
-    ret = igbp->setMaxDequeuedBufferCount(prevDequeueCommitted);
-    if (ret != ::android::OK) {
-        // TODO: sort out the error from igbp and return an error accordingly.
-        return C2_CORRUPTED;
+    if (igbp) {
+        ret = igbp->setMaxDequeuedBufferCount(prevDequeueCommitted);
+        if (ret != ::android::OK) {
+            ALOGE("new surface maxDequeueBufferCount configure fail");
+            // TODO: sort out the error from igbp and return an error accordingly.
+            std::unique_lock<std::mutex> l(mLock);
+            mInConfig = false;
+            return C2_CORRUPTED;
+        }
     }
+    ALOGD("new surface configured with id:%llu gen:%lu maxDequeue:%d",
+          (unsigned long long)bqId, (unsigned long)generation, prevDequeueCommitted);
     std::shared_ptr<BufferCache> newCache = std::make_shared<BufferCache>(bqId, generation, igbp);
     {
         std::unique_lock<std::mutex> l(mLock);
@@ -283,59 +296,74 @@
     // (Sometimes maxDequeueCount cannot be committed if the number of
     // dequeued buffer count is bigger.)
     int maxDequeueToCommit;
-    // max dequeue count which is committed to IGBP currently
-    // (actually mMaxDequeueCommitted, but needs to be read outside lock.)
-    int curMaxDequeueCommitted;
     std::unique_lock<std::mutex> cl(mConfigLock);
     {
         std::unique_lock<std::mutex> l(mLock);
-        if (mMaxDequeueRequested == maxDequeueCount) {
+        if (mMaxDequeueRequested.has_value()) {
+            if (mMaxDequeueRequested == maxDequeueCount) {
+                ALOGD("maxDequeueCount requested with %d already", maxDequeueCount);
+                return C2_OK;
+            }
+        } else if (mMaxDequeue == maxDequeueCount) {
+            ALOGD("maxDequeueCount is already %d", maxDequeueCount);
             return C2_OK;
         }
         mInConfig = true;
         mMaxDequeueRequested = maxDequeueCount;
         cache = mBufferCache;
-        curMaxDequeueCommitted = mMaxDequeueCommitted;
         if (mMaxDequeue <= maxDequeueCount) {
             maxDequeueToCommit = maxDequeueCount;
         } else {
             // Since mDequeuable is decreasing,
             // a delievered ready to allocate event may not be fulfilled.
             // Another waiting via a waitable object may be necessary in the case.
-            int delta = mMaxDequeue - maxDequeueCount;
-            if (delta <= mDequeueable) {
-                maxDequeueToCommit = maxDequeueCount;
-                mDequeueable -= delta;
-            } else {
-                maxDequeueToCommit = mMaxDequeue - mDequeueable;
-                mDequeueable = 0;
+            int delta = std::min(mMaxDequeue - maxDequeueCount, mDequeueable);
+            maxDequeueToCommit = mMaxDequeue - delta;
+            mDequeueable -= delta;
+            if (delta > 0) {
+                drainDequeueableLocked(delta);
             }
         }
     }
 
     bool committed = true;
-    if (cache->mIgbp && maxDequeueToCommit != curMaxDequeueCommitted) {
+    if (cache->mIgbp && maxDequeueToCommit != mMaxDequeueCommitted) {
         ::android::status_t ret = cache->mIgbp->setMaxDequeuedBufferCount(maxDequeueToCommit);
         committed = (ret == ::android::OK);
-        if (!committed) {
+        if (committed) {
+            ALOGD("maxDequeueCount committed to IGBP: %d", maxDequeueToCommit);
+        } else {
             // This should not happen.
-            ALOGE("dequeueCount failed with error(%d)", (int)ret);
+            ALOGE("maxdequeueCount update to IGBP failed with error(%d)", (int)ret);
         }
     }
 
+    int oldMaxDequeue = 0;
+    int requested = 0;
     {
         std::unique_lock<std::mutex> l(mLock);
         mInConfig = false;
+        oldMaxDequeue = mMaxDequeue;
+        mMaxDequeue = maxDequeueToCommit; // we already drained dequeueable
         if (committed) {
+            clearCacheIfNecessaryLocked(cache, maxDequeueToCommit);
             mMaxDequeueCommitted = maxDequeueToCommit;
-            int delta = mMaxDequeueCommitted - mMaxDequeue;
+            if (mMaxDequeueRequested == mMaxDequeueCommitted &&
+                  mMaxDequeueRequested == mMaxDequeue) {
+                mMaxDequeueRequested.reset();
+            }
+            if (mMaxDequeueRequested.has_value()) {
+                requested = mMaxDequeueRequested.value();
+            }
+            int delta = mMaxDequeueCommitted - oldMaxDequeue;
             if (delta > 0) {
                 mDequeueable += delta;
-                l.unlock();
-                writeIncDequeueable(delta);
+                writeIncDequeueableLocked(delta);
             }
         }
     }
+    ALOGD("maxDqueueCount change %d -> %d: pending: %d",
+          oldMaxDequeue, maxDequeueToCommit, requested);
 
     if (!committed) {
         return C2_CORRUPTED;
@@ -350,48 +378,60 @@
     std::unique_lock<std::mutex> cl(mConfigLock);
     {
         std::unique_lock<std::mutex> l(mLock);
-        if (mMaxDequeue == mMaxDequeueRequested && mMaxDequeueCommitted != mMaxDequeueRequested) {
-            dequeueCommit = mMaxDequeue;
-            mInConfig = true;
-            cache = mBufferCache;
-        } else {
+        if (!mMaxDequeueRequested.has_value() || mMaxDequeue != mMaxDequeueRequested) {
             return;
         }
+        if (mMaxDequeueCommitted == mMaxDequeueRequested) {
+            // already committed. may not happen.
+            mMaxDequeueRequested.reset();
+            return;
+        }
+        dequeueCommit = mMaxDequeue;
+        mInConfig = true;
+        cache = mBufferCache;
     }
     bool committed = true;
     if (cache->mIgbp) {
         ::android::status_t ret = cache->mIgbp->setMaxDequeuedBufferCount(dequeueCommit);
         committed = (ret == ::android::OK);
-        if (!committed) {
+        if (committed) {
+            ALOGD("delayed maxDequeueCount update to IGBP: %d", dequeueCommit);
+        } else {
             // This should not happen.
-            ALOGE("dequeueCount failed with error(%d)", (int)ret);
+            ALOGE("delayed maxdequeueCount update to IGBP failed with error(%d)", (int)ret);
         }
     }
-    int cleared = 0;
     {
         // cache == mCache here, since we locked config.
         std::unique_lock<std::mutex> l(mLock);
         mInConfig = false;
         if (committed) {
-            if (cache->mIgbp && dequeueCommit < mMaxDequeueCommitted) {
-                // we are shrinking # of buffers, so clearing the cache.
-                for (auto it = cache->mBuffers.begin(); it != cache->mBuffers.end();) {
-                    uint64_t bid = it->second->mId;
-                    if (mDequeued.count(bid) == 0 || mDeallocating.count(bid) > 0) {
-                        ++cleared;
-                        it = cache->mBuffers.erase(it);
-                    } else {
-                        ++it;
-                    }
-                }
-            }
+            clearCacheIfNecessaryLocked(cache, dequeueCommit);
             mMaxDequeueCommitted = dequeueCommit;
         }
+        mMaxDequeueRequested.reset();
     }
-    if (cleared > 0) {
-        ALOGD("%d buffers are cleared from cache, due to IGBP capacity change", cleared);
-    }
+}
 
+void GraphicsTracker::clearCacheIfNecessaryLocked(const std::shared_ptr<BufferCache> &cache,
+                                            int maxDequeueCommitted) {
+    int cleared = 0;
+    size_t origCacheSize = cache->mBuffers.size();
+    if (cache->mIgbp && maxDequeueCommitted < mMaxDequeueCommitted) {
+        // we are shrinking # of buffers in the case, so evict the previous
+        // cached buffers.
+        for (auto it = cache->mBuffers.begin(); it != cache->mBuffers.end();) {
+            uint64_t bid = it->second->mId;
+            if (mDequeued.count(bid) == 0 || mDeallocating.count(bid) > 0) {
+                ++cleared;
+                it = cache->mBuffers.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+    ALOGD("Cache size %zu -> %zu: maybe_cleared(%d), dequeued(%zu)",
+          origCacheSize, cache->mBuffers.size(), cleared, mDequeued.size());
 }
 
 int GraphicsTracker::getCurDequeueable() {
@@ -400,70 +440,58 @@
 }
 
 void GraphicsTracker::stop() {
-    bool expected = false;
-    std::unique_lock<std::mutex> l(mEventLock);
-    bool updated = mStopped.compare_exchange_strong(expected, true);
-    if (updated) {
-        int writeFd = mWritePipeFd.release();
+   // TODO: wait until all operation to current IGBP
+   // being completed.
+    std::unique_lock<std::mutex> l(mLock);
+    if (mStopped) {
+        return;
+    }
+    mStopped = true;
+    int writeFd = mWritePipeFd.release();
+    if (writeFd >= 0) {
         ::close(writeFd);
-        int readFd = mReadPipeFd.release();
-        ::close(readFd);
-        mEventCv.notify_one();
     }
 }
 
-void GraphicsTracker::writeIncDequeueable(int inc) {
+void GraphicsTracker::writeIncDequeueableLocked(int inc) {
     CHECK(inc > 0 && inc < kMaxDequeueMax);
     thread_local char buf[kMaxDequeueMax];
-    int diff = 0;
-    {
-        std::unique_lock<std::mutex> l(mEventLock);
-        if (mStopped) {
-            return;
-        }
-        CHECK(mWritePipeFd.get() >= 0);
-        int ret = ::write(mWritePipeFd.get(), buf, inc);
-        if (ret == inc) {
-            return;
-        }
-        diff = ret < 0 ? inc : inc - ret;
-
-        // Partial write or EINTR. This will not happen in a real scenario.
-        mIncDequeueable += diff;
-        if (mIncDequeueable > 0) {
-            l.unlock();
-            mEventCv.notify_one();
-            ALOGW("updating dequeueable to pipefd pending");
-        }
+    if (mStopped) { // reading end closed;
+        return;
     }
+    int writeFd = mWritePipeFd.get();
+    if (writeFd < 0) {
+        // initialization fail and not valid though.
+        return;
+    }
+    int ret = ::write(writeFd, buf, inc);
+    // Since this is non-blocking i/o, it never returns EINTR.
+    //
+    // ::write() to pipe guarantee to succeed atomically if it writes less than
+    // the given PIPE_BUF. And the buffer size in pipe/fifo is at least 4K and our total
+    // max pending buffer size is 64. So it never returns EAGAIN here either.
+    // See pipe(7) for further information.
+    //
+    // Other errors are serious errors and we cannot synchronize mDequeueable to
+    // length of pending buffer in pipe/fifo anymore. So better to abort here.
+    // TODO: do not abort here. (b/318717399)
+    CHECK(ret == inc);
 }
 
-void GraphicsTracker::processEvent() {
-    // This is for partial/failed writes to the writing end.
-    // This may not happen in the real scenario.
+void GraphicsTracker::drainDequeueableLocked(int dec) {
+    CHECK(dec > 0 && dec < kMaxDequeueMax);
     thread_local char buf[kMaxDequeueMax];
-    while (true) {
-        std::unique_lock<std::mutex> l(mEventLock);
-        if (mStopped) {
-            break;
-        }
-        if (mIncDequeueable > 0) {
-            int inc = mIncDequeueable > kMaxDequeueMax ? kMaxDequeueMax : mIncDequeueable;
-            int ret = ::write(mWritePipeFd.get(), buf, inc);
-            int written = ret <= 0 ? 0 : ret;
-            mIncDequeueable -= written;
-            if (mIncDequeueable > 0) {
-                l.unlock();
-                if (ret < 0) {
-                    ALOGE("write to writing end failed %d", errno);
-                } else {
-                    ALOGW("partial write %d(%d)", inc, written);
-                }
-                continue;
-            }
-        }
-        mEventCv.wait(l);
+    if (mStopped) {
+        return;
     }
+    int readFd = mReadPipeFd.get();
+    if (readFd < 0) {
+        // initializationf fail and not valid though.
+        return;
+    }
+    int ret = ::read(readFd, buf, dec);
+    // TODO: no dot abort here. (b/318717399)
+    CHECK(ret == dec);
 }
 
 c2_status_t GraphicsTracker::getWaitableFd(int *pipeFd) {
@@ -539,8 +567,7 @@
             return;
         }
         mDequeueable++;
-        l.unlock();
-        writeIncDequeueable(1);
+        writeIncDequeueableLocked(1);
     }
 }
 
@@ -715,14 +742,13 @@
             return C2_OK;
         }
         mDequeueable++;
-        l.unlock();
-        writeIncDequeueable(1);
+        writeIncDequeueableLocked(1);
     }
     return C2_OK;
 }
 
 void GraphicsTracker::commitDeallocate(
-        std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid) {
+        std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid, bool *updateDequeue) {
     std::unique_lock<std::mutex> l(mLock);
     size_t del1 = mDequeued.erase(bid);
     size_t del2 = mDeallocating.erase(bid);
@@ -730,9 +756,11 @@
     if (cache) {
         cache->unblockSlot(slotId);
     }
+    if (adjustDequeueConfLocked(updateDequeue)) {
+        return;
+    }
     mDequeueable++;
-    l.unlock();
-    writeIncDequeueable(1);
+    writeIncDequeueableLocked(1);
 }
 
 
@@ -758,7 +786,10 @@
     // cache->mIgbp is not null, if completed is false.
     (void)cache->mIgbp->cancelBuffer(slotId, rFence);
 
-    commitDeallocate(cache, slotId, bid);
+    commitDeallocate(cache, slotId, bid, &updateDequeue);
+    if (updateDequeue) {
+        updateDequeueConf();
+    }
     return C2_OK;
 }
 
@@ -785,8 +816,7 @@
             return C2_BAD_STATE;
         }
         mDequeueable++;
-        l.unlock();
-        writeIncDequeueable(1);
+        writeIncDequeueableLocked(1);
         return C2_BAD_STATE;
     }
     std::shared_ptr<BufferItem> buffer = it->second;
@@ -828,8 +858,7 @@
             return;
         }
         mDequeueable++;
-        l.unlock();
-        writeIncDequeueable(1);
+        writeIncDequeueableLocked(1);
         return;
     }
 }
@@ -843,6 +872,9 @@
         ALOGE("retrieving AHB-ID for GraphicBlock failed");
         return C2_CORRUPTED;
     }
+    std::shared_ptr<_C2BlockPoolData> poolData =
+            _C2BlockFactory::GetGraphicBlockPoolData(blk);
+    _C2BlockFactory::DisownIgbaBlock(poolData);
     std::shared_ptr<BufferCache> cache;
     std::shared_ptr<BufferItem> buffer;
     std::shared_ptr<BufferItem> oldBuffer;
@@ -870,13 +902,19 @@
         if (!gb) {
             ALOGE("render: realloc-ing a new buffer for migration failed");
             std::shared_ptr<BufferCache> nullCache;
-            commitDeallocate(nullCache, -1, bid);
+            commitDeallocate(nullCache, -1, bid, &updateDequeue);
+            if (updateDequeue) {
+                updateDequeueConf();
+            }
             return C2_REFUSED;
         }
         if (cache->mIgbp->attachBuffer(&(newBuffer->mSlot), gb) != ::android::OK) {
             ALOGE("render: attaching a new buffer to IGBP failed");
             std::shared_ptr<BufferCache> nullCache;
-            commitDeallocate(nullCache, -1, bid);
+            commitDeallocate(nullCache, -1, bid, &updateDequeue);
+            if (updateDequeue) {
+                updateDequeueConf();
+            }
             return C2_REFUSED;
         }
         cache->waitOnSlot(newBuffer->mSlot);
@@ -890,11 +928,13 @@
         CHECK(renderRes != ::android::BAD_VALUE);
         ALOGE("render: failed to queueBuffer() err = %d", renderRes);
         (void) cache->mIgbp->cancelBuffer(buffer->mSlot, input.fence);
-        commitDeallocate(cache, buffer->mSlot, bid);
+        commitDeallocate(cache, buffer->mSlot, bid, &updateDequeue);
+        if (updateDequeue) {
+            updateDequeueConf();
+        }
         return C2_REFUSED;
     }
 
-    updateDequeue = false;
     commitRender(cache, buffer, oldBuffer, output->bufferReplaced, &updateDequeue);
     if (updateDequeue) {
         updateDequeueConf();
@@ -909,8 +949,7 @@
         if (mBufferCache->mGeneration == generation) {
             if (!adjustDequeueConfLocked(&updateDequeue)) {
                 mDequeueable++;
-                l.unlock();
-                writeIncDequeueable(1);
+                writeIncDequeueableLocked(1);
             }
         }
     }
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 2d19ecc..85b5ec8 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -635,21 +635,22 @@
     if (heapParams) {
         heapParams->reserve(heapParams->size() + numIndices);
     }
-    c2_aidl::Params result;
+    c2_aidl::IConfigurable::QueryResult result;
     ndk::ScopedAStatus transStatus = mBase->query(indices, (mayBlock == C2_MAY_BLOCK), &result);
     c2_status_t status = GetC2Status(transStatus, "query");
     if (status != C2_OK) {
         return status;
     }
+    status = static_cast<c2_status_t>(result.status.status);
 
     std::vector<C2Param*> paramPointers;
-    if (!c2_aidl::utils::ParseParamsBlob(&paramPointers, result)) {
+    if (!c2_aidl::utils::ParseParamsBlob(&paramPointers, result.params)) {
         LOG(ERROR) << "query -- error while parsing params.";
         return C2_CORRUPTED;
     }
     size_t i = 0;
-    for (auto it = paramPointers.begin();
-            it != paramPointers.end(); ) {
+    size_t numUpdatedStackParams = 0;
+    for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
         C2Param* paramPointer = *it;
         if (numStackIndices > 0) {
             --numStackIndices;
@@ -676,7 +677,9 @@
                 status = C2_BAD_INDEX;
                 continue;
             }
-            if (!stackParams[i++]->updateFrom(*paramPointer)) {
+            if (stackParams[i++]->updateFrom(*paramPointer)) {
+                ++numUpdatedStackParams;
+            } else {
                 LOG(WARNING) << "query -- param update failed: "
                                 "index = "
                              << paramPointer->index() << ".";
@@ -696,6 +699,13 @@
         }
         ++it;
     }
+    size_t numQueried = numUpdatedStackParams;
+    if (heapParams) {
+        numQueried += heapParams->size();
+    }
+    if (status == C2_OK && indices.size() != numQueried) {
+        status = C2_BAD_INDEX;
+    }
     return status;
 }
 
@@ -714,6 +724,7 @@
     if (status != C2_OK) {
         return status;
     }
+    status = static_cast<c2_status_t>(result.status.status);
     size_t i = failures->size();
     failures->resize(i + result.failures.size());
     for (const c2_aidl::SettingResult& sf : result.failures) {
@@ -764,21 +775,23 @@
         }
     }
 
-    std::vector<c2_aidl::FieldSupportedValuesQueryResult> result;
+    c2_aidl::IConfigurable::QuerySupportedValuesResult result;
+
     ndk::ScopedAStatus transStatus = mBase->querySupportedValues(
             inFields, (mayBlock == C2_MAY_BLOCK), &result);
     c2_status_t status = GetC2Status(transStatus, "querySupportedValues");
     if (status != C2_OK) {
         return status;
     }
-    if (result.size() != fields.size()) {
+    status = static_cast<c2_status_t>(result.status.status);
+    if (result.values.size() != fields.size()) {
         LOG(ERROR) << "querySupportedValues -- "
                       "input and output lists "
                       "have different sizes.";
         return C2_CORRUPTED;
     }
     for (size_t i = 0; i < fields.size(); ++i) {
-        if (!c2_aidl::utils::FromAidl(&fields[i], inFields[i], result[i])) {
+        if (!c2_aidl::utils::FromAidl(&fields[i], inFields[i], result.values[i])) {
             LOG(ERROR) << "querySupportedValues -- "
                           "invalid returned value.";
             return C2_CORRUPTED;
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
index 4640243..dd6c869 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -27,6 +27,7 @@
 #include <mutex>
 #include <set>
 #include <thread>
+#include <optional>
 
 #include <C2Buffer.h>
 
@@ -234,12 +235,14 @@
     std::map<uint64_t, std::shared_ptr<BufferItem>> mDequeued;
     std::set<uint64_t> mDeallocating;
 
+    // These member variables are read and modified accessed as follows.
+    // 1. mConfigLock being held
+    //    Set mInConfig true with mLock in the beginning
+    //    Clear mInConfig with mLock in the end
+    // 2. mLock is held and mInConfig is false.
     int mMaxDequeue;
-    int mMaxDequeueRequested;
     int mMaxDequeueCommitted;
-
-    uint32_t mMaxDequeueRequestedSeqId;
-    uint32_t mMaxDequeueCommittedSeqId;
+    std::optional<int> mMaxDequeueRequested;
 
     int mDequeueable;
 
@@ -271,13 +274,6 @@
     ::android::base::unique_fd mWritePipeFd;  // The writing end file descriptor
 
     std::atomic<bool> mStopped;
-    std::thread mEventQueueThread; // Thread to handle interrupted
-                                   // writes to the writing end.
-    std::mutex mEventLock;
-    std::condition_variable mEventCv;
-
-    bool mStopEventThread;
-    int mIncDequeueable; // pending # of write to increase dequeueable eventfd
 
 private:
     explicit GraphicsTracker(int maxDequeueCount);
@@ -289,6 +285,9 @@
     bool adjustDequeueConfLocked(bool *updateDequeueConf);
 
     void updateDequeueConf();
+    void clearCacheIfNecessaryLocked(
+            const std::shared_ptr<BufferCache> &cache,
+            int maxDequeueCommitted);
 
     c2_status_t requestAllocate(std::shared_ptr<BufferCache> *cache);
     c2_status_t requestDeallocate(uint64_t bid, const sp<Fence> &fence,
@@ -305,7 +304,9 @@
                         bool cached, int slotId, const sp<Fence> &fence,
                         std::shared_ptr<BufferItem> *buffer,
                         bool *updateDequeue);
-    void commitDeallocate(std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid);
+    void commitDeallocate(std::shared_ptr<BufferCache> &cache,
+                          int slotId, uint64_t bid,
+                          bool *updateDequeue);
     void commitRender(const std::shared_ptr<BufferCache> &cache,
                       const std::shared_ptr<BufferItem> &buffer,
                       const std::shared_ptr<BufferItem> &oldBuffer,
@@ -318,8 +319,8 @@
             bool *cached, int *rSlotId, sp<Fence> *rFence,
             std::shared_ptr<BufferItem> *buffer);
 
-    void writeIncDequeueable(int inc);
-    void processEvent();
+    void writeIncDequeueableLocked(int inc);
+    void drainDequeueableLocked(int dec);
 };
 
 } // namespace aidl::android::hardware::media::c2::implementation
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index fdb28f4..df89510 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -29,6 +29,7 @@
 #include <C2BufferPriv.h>
 #include <C2Config.h>
 #include <C2Debug.h>
+#include <codec2/common/HalSelection.h>
 #include <codec2/hidl/client.h>
 #include <gui/BufferQueue.h>
 #include <gui/IConsumerListener.h>
@@ -407,30 +408,45 @@
                       surfaceMode_t surfMode) {
     using namespace android;
     sp<IGraphicBufferProducer> producer = nullptr;
+    sp<IGraphicBufferConsumer> consumer = nullptr;
+    sp<GLConsumer> texture = nullptr;
+    sp<ANativeWindow> surface = nullptr;
     static std::atomic_uint32_t surfaceGeneration{0};
     uint32_t generation =
             (getpid() << 10) |
             ((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1) & ((1 << 10) - 1));
     int32_t maxDequeueBuffers = kSmoothnessFactor + kRenderingDepth;
+    C2BlockPool::local_id_t poolId = C2BlockPool::BASIC_GRAPHIC;
+    std::shared_ptr<Codec2Client::Configurable> configurable;
+    bool aidl = ::android::IsCodec2AidlHalSelected();
+    if (aidl) {
+        // AIDL does not support blockpool-less mode.
+        c2_status_t poolRet = component->createBlockPool(
+                C2PlatformAllocatorStore::IGBA, &poolId, &configurable);
+        ASSERT_EQ(poolRet, C2_OK) << "setOutputSurface failed";
+    }
+
     if (surfMode == SURFACE) {
-        sp<IGraphicBufferConsumer> consumer = nullptr;
         BufferQueue::createBufferQueue(&producer, &consumer);
         ASSERT_NE(producer, nullptr) << "createBufferQueue returned invalid producer";
         ASSERT_NE(consumer, nullptr) << "createBufferQueue returned invalid consumer";
 
-        sp<GLConsumer> texture =
+        texture =
                 new GLConsumer(consumer, 0 /* tex */, GLConsumer::TEXTURE_EXTERNAL,
                                true /* useFenceSync */, false /* isControlledByApp */);
 
-        sp<ANativeWindow> gSurface = new Surface(producer);
-        ASSERT_NE(gSurface, nullptr) << "getSurface failed";
+        surface = new Surface(producer);
+        ASSERT_NE(surface, nullptr) << "failed to create Surface object";
 
         producer->setGenerationNumber(generation);
     }
 
-    c2_status_t err = component->setOutputSurface(C2BlockPool::BASIC_GRAPHIC, producer, generation,
+    c2_status_t err = component->setOutputSurface(poolId, producer, generation,
                                                   maxDequeueBuffers);
-    ASSERT_EQ(err, C2_OK) << "setOutputSurface failed";
+    std::string surfStr = surfMode == NO_SURFACE ? "NO_SURFACE" :
+            (surfMode == NULL_SURFACE ? "NULL_SURFACE" : "WITH_SURFACE");
+
+    ASSERT_EQ(err, C2_OK) << "setOutputSurface failed, surfMode: " << surfStr;
 }
 
 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index fbb4f18..8ecb9c0 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -19,6 +19,7 @@
 
 #include <android-base/logging.h>
 #include <android/binder_process.h>
+#include <codec2/common/HalSelection.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <stdio.h>
@@ -71,7 +72,9 @@
         std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
         CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mGraphicAllocator),
                  C2_OK);
-        mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++);
+        C2PooledBlockPool::BufferPoolVer ver = ::android::IsCodec2AidlHalSelected() ?
+                C2PooledBlockPool::VER_AIDL2 : C2PooledBlockPool::VER_HIDL;
+        mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++, ver);
         ASSERT_NE(mGraphicPool, nullptr);
 
         std::vector<std::unique_ptr<C2Param>> queried;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 3bb6593..5c1755e 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -1049,7 +1049,11 @@
         // Unwrap raw buffer handle from the C2Handle
         native_handle_t *nh = UnwrapNativeCodec2GrallocHandle(handle);
         if (!nh) {
-            return;
+            nh = UnwrapNativeCodec2AhwbHandle(handle);
+            if (!nh) {
+                ALOGE("handle is not compatible to neither C2HandleGralloc nor C2HandleAhwb");
+                return;
+            }
         }
         // Import the raw handle so IMapper can use the buffer. The imported
         // handle must be freed when the client is done with the buffer.
diff --git a/media/codec2/tests/aidl/Android.bp b/media/codec2/tests/aidl/Android.bp
new file mode 100644
index 0000000..2ad245c
--- /dev/null
+++ b/media/codec2/tests/aidl/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_av_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_test {
+    name: "c2aidl_gtracker_test",
+    test_suites: ["device-tests"],
+    defaults: [
+        "libcodec2-aidl-client-defaults",
+    ],
+
+    header_libs: [
+        "libcodec2_client_headers",
+        "libcodec2_internal",
+        "libcodec2_vndk_headers",
+    ],
+
+    srcs: [
+        "GraphicsTracker_test.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcodec2_client",
+        "libgui",
+        "libnativewindow",
+        "libui",
+    ],
+}
diff --git a/media/codec2/tests/aidl/GraphicsTracker_test.cpp b/media/codec2/tests/aidl/GraphicsTracker_test.cpp
new file mode 100644
index 0000000..9008086
--- /dev/null
+++ b/media/codec2/tests/aidl/GraphicsTracker_test.cpp
@@ -0,0 +1,820 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "GraphicsTracker_test"
+#include <unistd.h>
+
+#include <android/hardware_buffer.h>
+#include <codec2/aidl/GraphicsTracker.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
+#include <gui/IConsumerListener.h>
+#include <gui/Surface.h>
+#include <private/android/AHardwareBufferHelpers.h>
+
+#include <C2BlockInternal.h>
+#include <C2FenceFactory.h>
+
+#include <atomic>
+#include <memory>
+#include <iostream>
+#include <thread>
+
+using ::aidl::android::hardware::media::c2::implementation::GraphicsTracker;
+using ::android::BufferItem;
+using ::android::BufferQueue;
+using ::android::Fence;
+using ::android::GraphicBuffer;
+using ::android::IGraphicBufferProducer;
+using ::android::IGraphicBufferConsumer;
+using ::android::IProducerListener;
+using ::android::IConsumerListener;
+using ::android::OK;
+using ::android::sp;
+using ::android::wp;
+
+namespace {
+struct BqStatistics {
+    std::atomic<int> mDequeued;
+    std::atomic<int> mQueued;
+    std::atomic<int> mBlocked;
+    std::atomic<int> mDropped;
+    std::atomic<int> mDiscarded;
+    std::atomic<int> mReleased;
+
+    void log() {
+        ALOGD("Dequeued: %d, Queued: %d, Blocked: %d, "
+              "Dropped: %d, Discarded %d, Released %d",
+              (int)mDequeued, (int)mQueued, (int)mBlocked,
+              (int)mDropped, (int)mDiscarded, (int)mReleased);
+    }
+
+    void clear() {
+        mDequeued = 0;
+        mQueued = 0;
+        mBlocked = 0;
+        mDropped = 0;
+        mDiscarded = 0;
+        mReleased = 0;
+    }
+};
+
+struct DummyConsumerListener : public android::BnConsumerListener {
+    void onFrameAvailable(const BufferItem& /* item */) override {}
+    void onBuffersReleased() override {}
+    void onSidebandStreamChanged() override {}
+};
+
+struct TestConsumerListener : public android::BnConsumerListener {
+    TestConsumerListener(const sp<IGraphicBufferConsumer> &consumer)
+            : BnConsumerListener(), mConsumer(consumer) {}
+    void onFrameAvailable(const BufferItem&) override {
+        constexpr static int kRenderDelayUs = 1000000/30; // 30fps
+        BufferItem buffer;
+        // consume buffer
+        sp<IGraphicBufferConsumer> consumer = mConsumer.promote();
+        if (consumer != nullptr && consumer->acquireBuffer(&buffer, 0) == android::NO_ERROR) {
+            ::usleep(kRenderDelayUs);
+            consumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber,
+                                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, buffer.mFence);
+        }
+    }
+    void onBuffersReleased() override {}
+    void onSidebandStreamChanged() override {}
+
+    wp<IGraphicBufferConsumer> mConsumer;
+};
+
+struct TestProducerListener : public android::BnProducerListener {
+    TestProducerListener(std::shared_ptr<GraphicsTracker> tracker,
+                         std::shared_ptr<BqStatistics> &stat,
+                         uint32_t generation) : BnProducerListener(),
+        mTracker(tracker), mStat(stat), mGeneration(generation) {}
+    virtual void onBufferReleased() override {
+        auto tracker = mTracker.lock();
+        if (tracker) {
+            mStat->mReleased++;
+            tracker->onReleased(mGeneration);
+        }
+    }
+    virtual bool needsReleaseNotify() override { return true; }
+    virtual void onBuffersDiscarded(const std::vector<int32_t>&) override {}
+
+    std::weak_ptr<GraphicsTracker> mTracker;
+    std::shared_ptr<BqStatistics> mStat;
+    uint32_t mGeneration;
+};
+
+struct Frame {
+    AHardwareBuffer *buffer_;
+    sp<Fence> fence_;
+
+    Frame() : buffer_{nullptr}, fence_{nullptr} {}
+    Frame(AHardwareBuffer *buffer, sp<Fence> fence)
+            : buffer_(buffer), fence_(fence) {}
+    ~Frame() {
+        if (buffer_) {
+            AHardwareBuffer_release(buffer_);
+        }
+    }
+};
+
+struct FrameQueue {
+    bool mStopped;
+    bool mDrain;
+    std::queue<std::shared_ptr<Frame>> mQueue;
+    std::mutex mMutex;
+    std::condition_variable mCond;
+
+    FrameQueue() : mStopped{false}, mDrain{false} {}
+
+    bool queueItem(AHardwareBuffer *buffer, sp<Fence> fence) {
+        std::shared_ptr<Frame> frame = std::make_shared<Frame>(buffer, fence);
+        if (mStopped) {
+            return false;
+        }
+        if (!frame) {
+            return false;
+        }
+        std::unique_lock<std::mutex> l(mMutex);
+        mQueue.emplace(frame);
+        l.unlock();
+        mCond.notify_all();
+        return true;
+    }
+
+    void stop(bool drain = false) {
+        bool stopped = false;
+        {
+            std::unique_lock<std::mutex> l(mMutex);
+            if (!mStopped) {
+                mStopped = true;
+                mDrain = drain;
+                stopped = true;
+            }
+            l.unlock();
+            if (stopped) {
+                mCond.notify_all();
+            }
+        }
+    }
+
+    bool waitItem(std::shared_ptr<Frame> *frame) {
+        while(true) {
+            std::unique_lock<std::mutex> l(mMutex);
+            if (!mDrain && mStopped) {
+                // stop without consuming the queue.
+                return false;
+            }
+            if (!mQueue.empty()) {
+                *frame = mQueue.front();
+                mQueue.pop();
+                return true;
+            } else if (mStopped) {
+                // stop after consuming the queue.
+                return false;
+            }
+            mCond.wait(l);
+        }
+    }
+};
+
+} // namespace anonymous
+
+class GraphicsTrackerTest : public ::testing::Test {
+public:
+    const uint64_t kTestUsageFlag = GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+    void queueBuffer(FrameQueue *queue) {
+        while (true) {
+            std::shared_ptr<Frame> frame;
+            if (!queue->waitItem(&frame)) {
+                break;
+            }
+            uint64_t bid;
+            if (__builtin_available(android __ANDROID_API_T__, *)) {
+                if (AHardwareBuffer_getId(frame->buffer_, &bid) !=
+                        android::NO_ERROR) {
+                    break;
+                }
+            } else {
+                break;
+            }
+            android::status_t ret = frame->fence_->wait(-1);
+            if (ret != android::NO_ERROR) {
+                mTracker->deallocate(bid, frame->fence_);
+                mBqStat->mDiscarded++;
+                continue;
+            }
+
+            std::shared_ptr<C2GraphicBlock> blk =
+                    _C2BlockFactory::CreateGraphicBlock(frame->buffer_);
+            if (!blk) {
+                mTracker->deallocate(bid, Fence::NO_FENCE);
+                mBqStat->mDiscarded++;
+                continue;
+            }
+            IGraphicBufferProducer::QueueBufferInput input(
+                    0, false,
+                    HAL_DATASPACE_UNKNOWN, android::Rect(0, 0, 1, 1),
+                    NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+            IGraphicBufferProducer::QueueBufferOutput output{};
+            c2_status_t res = mTracker->render(
+                    blk->share(C2Rect(1, 1), C2Fence()),
+                    input, &output);
+            if (res != C2_OK) {
+                mTracker->deallocate(bid, Fence::NO_FENCE);
+                mBqStat->mDiscarded++;
+                continue;
+            }
+            if (output.bufferReplaced) {
+                mBqStat->mDropped++;
+            }
+            mBqStat->mQueued++;
+        }
+    }
+
+    void stopTrackerAfterUs(int us) {
+        ::usleep(us);
+        mTracker->stop();
+    }
+
+protected:
+    bool init(int maxDequeueCount) {
+        mTracker = GraphicsTracker::CreateGraphicsTracker(maxDequeueCount);
+        if (!mTracker) {
+            return false;
+        }
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        if (!mProducer || !mConsumer) {
+            return false;
+        }
+        return true;
+    }
+    bool configure(sp<IProducerListener> producerListener,
+                   sp<IConsumerListener> consumerListener,
+                   int maxAcquiredCount = 1, bool controlledByApp = true) {
+        if (mConsumer->consumerConnect(
+                consumerListener, controlledByApp) != ::android::NO_ERROR) {
+            return false;
+        }
+        if (mConsumer->setMaxAcquiredBufferCount(maxAcquiredCount) != ::android::NO_ERROR) {
+            return false;
+        }
+        IGraphicBufferProducer::QueueBufferOutput qbo{};
+        if (mProducer->connect(producerListener,
+                          NATIVE_WINDOW_API_MEDIA, true, &qbo) != ::android::NO_ERROR) {
+            return false;
+        }
+        if (mProducer->setDequeueTimeout(0) != ::android::NO_ERROR) {
+            return false;
+        }
+        return true;
+    }
+
+    virtual void TearDown() override {
+        mBqStat->log();
+        mBqStat->clear();
+
+        if (mTracker) {
+            mTracker->stop();
+            mTracker.reset();
+        }
+        if (mProducer) {
+            mProducer->disconnect(NATIVE_WINDOW_API_MEDIA);
+        }
+        mProducer.clear();
+        mConsumer.clear();
+    }
+
+protected:
+    std::shared_ptr<BqStatistics> mBqStat = std::make_shared<BqStatistics>();
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+    std::shared_ptr<GraphicsTracker> mTracker;
+};
+
+
+TEST_F(GraphicsTrackerTest, AllocateAndBlockedTest) {
+    uint32_t generation = 1;
+    const int maxDequeueCount = 10;
+
+    ASSERT_TRUE(init(maxDequeueCount));
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new DummyConsumerListener()));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+    c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+    ASSERT_EQ(C2_OK, ret);
+    ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+    AHardwareBuffer *buf;
+    sp<Fence> fence;
+    uint64_t bid;
+
+    // Allocate and check dequeueable
+    if (__builtin_available(android __ANDROID_API_T__, *)) {
+        for (int i = 0; i < maxDequeueCount; ++i) {
+            ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+            ASSERT_EQ(C2_OK, ret);
+            mBqStat->mDequeued++;
+            ASSERT_EQ(maxDequeueCount - (i + 1), mTracker->getCurDequeueable());
+            ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bid));
+            ALOGD("alloced : bufferId: %llu", (unsigned long long)bid);
+            AHardwareBuffer_release(buf);
+        }
+    } else {
+        GTEST_SKIP();
+    }
+
+    // Allocate should be blocked
+    ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+    ALOGD("alloc : err(%d, %d)", ret, C2_BLOCKING);
+    ASSERT_EQ(C2_BLOCKING, ret);
+    mBqStat->mBlocked++;
+    ASSERT_EQ(0, mTracker->getCurDequeueable());
+}
+
+TEST_F(GraphicsTrackerTest, AllocateAndDeallocateTest) {
+    uint32_t generation = 1;
+    const int maxDequeueCount = 10;
+
+    ASSERT_TRUE(init(maxDequeueCount));
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new DummyConsumerListener()));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+    c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+    ASSERT_EQ(C2_OK, ret);
+
+    ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+    AHardwareBuffer *buf;
+    sp<Fence> fence;
+    uint64_t bid;
+    std::vector<uint64_t> bids;
+
+    // Allocate and store buffer id
+    if (__builtin_available(android __ANDROID_API_T__, *)) {
+        for (int i = 0; i < maxDequeueCount; ++i) {
+            ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+            ASSERT_EQ(C2_OK, ret);
+            mBqStat->mDequeued++;
+            ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bid));
+            bids.push_back(bid);
+            ALOGD("alloced : bufferId: %llu", (unsigned long long)bid);
+            AHardwareBuffer_release(buf);
+        }
+    } else {
+        GTEST_SKIP();
+    }
+
+    // Deallocate and check dequeueable
+    for (int i = 0; i < maxDequeueCount; ++i) {
+        ALOGD("dealloc : bufferId: %llu", (unsigned long long)bids[i]);
+        ret = mTracker->deallocate(bids[i], Fence::NO_FENCE);
+        ASSERT_EQ(C2_OK, ret);
+        ASSERT_EQ(i + 1, mTracker->getCurDequeueable());
+        mBqStat->mDiscarded++;
+    }
+}
+
+TEST_F(GraphicsTrackerTest, DropAndReleaseTest) {
+    uint32_t generation = 1;
+    const int maxDequeueCount = 10;
+
+    ASSERT_TRUE(init(maxDequeueCount));
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new DummyConsumerListener()));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+    c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+    ASSERT_EQ(C2_OK, ret);
+
+    ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+    FrameQueue frameQueue;
+    std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+    AHardwareBuffer *buf1, *buf2;
+    sp<Fence> fence1, fence2;
+
+    ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf1, &fence1);
+    ASSERT_EQ(C2_OK, ret);
+    mBqStat->mDequeued++;
+    ASSERT_EQ(maxDequeueCount - 1, mTracker->getCurDequeueable());
+
+    ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf2, &fence2);
+    ASSERT_EQ(C2_OK, ret);
+    mBqStat->mDequeued++;
+    ASSERT_EQ(maxDequeueCount - 2, mTracker->getCurDequeueable());
+
+    // Queue two buffers without consuming, one should be dropped
+    ASSERT_TRUE(frameQueue.queueItem(buf1, fence1));
+    ASSERT_TRUE(frameQueue.queueItem(buf2, fence2));
+
+    frameQueue.stop(true);
+    if (queueThread.joinable()) {
+        queueThread.join();
+    }
+
+    ASSERT_EQ(maxDequeueCount - 1, mTracker->getCurDequeueable());
+
+    // Consume one buffer and release
+    BufferItem item;
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence));
+    // Nothing to consume
+    ASSERT_NE(OK, mConsumer->acquireBuffer(&item, 0));
+
+    ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+    ASSERT_EQ(1, mBqStat->mReleased);
+    ASSERT_EQ(1, mBqStat->mDropped);
+}
+
+TEST_F(GraphicsTrackerTest, RenderTest) {
+    uint32_t generation = 1;
+    const int maxDequeueCount = 10;
+    const int maxNumAlloc = 20;
+
+    ASSERT_TRUE(init(maxDequeueCount));
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new TestConsumerListener(mConsumer), 1, false));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+    ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+    ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+    int waitFd = -1;
+    ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+    C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+
+    FrameQueue frameQueue;
+    std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+
+    int numAlloc = 0;
+
+    while (numAlloc < maxNumAlloc) {
+        AHardwareBuffer *buf;
+        sp<Fence> fence;
+        c2_status_t ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+        if (ret == C2_BLOCKING) {
+            mBqStat->mBlocked++;
+            c2_status_t waitRes = waitFence.wait(3000000000);
+            if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+                continue;
+            }
+            ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+            break;
+        }
+        if (ret != C2_OK) {
+            ALOGE("alloc error: c2_err(%d)", ret);
+            break;
+        }
+        mBqStat->mDequeued++;
+        if (!frameQueue.queueItem(buf, fence)) {
+            ALOGE("queue to render failed");
+            break;
+        }
+        ++numAlloc;
+    }
+
+    frameQueue.stop(true);
+    // Wait more than enough time(1 sec) to render all queued frames for sure.
+    ::usleep(1000000);
+
+    if (queueThread.joinable()) {
+        queueThread.join();
+    }
+    ASSERT_EQ(numAlloc, maxNumAlloc);
+    ASSERT_EQ(numAlloc, mBqStat->mDequeued);
+    ASSERT_EQ(mBqStat->mDequeued, mBqStat->mQueued);
+    ASSERT_EQ(mBqStat->mDequeued, mBqStat->mReleased + mBqStat->mDropped);
+}
+
+TEST_F(GraphicsTrackerTest, StopAndWaitTest) {
+    uint32_t generation = 1;
+    const int maxDequeueCount = 2;
+
+    ASSERT_TRUE(init(maxDequeueCount));
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new TestConsumerListener(mConsumer), 1, false));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+    ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+    ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+    int waitFd = -1;
+    ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+    C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+    AHardwareBuffer *buf1, *buf2;
+    sp<Fence> fence;
+
+    ASSERT_EQ(C2_OK, mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf1, &fence));
+    mBqStat->mDequeued++;
+    AHardwareBuffer_release(buf1);
+
+    ASSERT_EQ(C2_OK, mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf2, &fence));
+    mBqStat->mDequeued++;
+    AHardwareBuffer_release(buf2);
+
+    ASSERT_EQ(0, mTracker->getCurDequeueable());
+    ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(3000000000));
+
+    std::thread stopThread(&GraphicsTrackerTest::stopTrackerAfterUs, this, 500000);
+    ASSERT_EQ(C2_BAD_STATE, waitFence.wait(3000000000));
+
+    if (stopThread.joinable()) {
+        stopThread.join();
+    }
+}
+
+TEST_F(GraphicsTrackerTest, SurfaceChangeTest) {
+    uint32_t generation = 1;
+    const int maxDequeueCount = 10;
+
+    const int maxNumAlloc = 20;
+
+    const int firstPassAlloc = 12;
+    const int firstPassRender = 8;
+
+    ASSERT_TRUE(init(maxDequeueCount));
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new TestConsumerListener(mConsumer), 1, false));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+    ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+    ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+    int waitFd = -1;
+    ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+    C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+    AHardwareBuffer *bufs[maxNumAlloc];
+    sp<Fence> fences[maxNumAlloc];
+
+    FrameQueue frameQueue;
+    std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+    int numAlloc = 0;
+
+    for (int i = 0; i < firstPassRender; ++i) {
+        ASSERT_EQ(C2_OK, mTracker->allocate(
+                0, 0, 0, kTestUsageFlag, &bufs[i], &fences[i]));
+        mBqStat->mDequeued++;
+        numAlloc++;
+        ASSERT_EQ(true, frameQueue.queueItem(bufs[i], fences[i]));
+    }
+
+    while (numAlloc < firstPassAlloc) {
+        c2_status_t ret = mTracker->allocate(
+                0, 0, 0, kTestUsageFlag, &bufs[numAlloc], &fences[numAlloc]);
+        if (ret == C2_BLOCKING) {
+            mBqStat->mBlocked++;
+            c2_status_t waitRes = waitFence.wait(3000000000);
+            if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+                continue;
+            }
+            ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+            break;
+        }
+        if (ret != C2_OK) {
+            ALOGE("alloc error: c2_err(%d)", ret);
+            break;
+        }
+        mBqStat->mDequeued++;
+        numAlloc++;
+    }
+    ASSERT_EQ(numAlloc, firstPassAlloc);
+
+    // switching surface
+    sp<IGraphicBufferProducer> oldProducer = mProducer;
+    sp<IGraphicBufferConsumer> oldConsumer = mConsumer;
+    mProducer.clear();
+    mConsumer.clear();
+    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+    ASSERT_TRUE((bool)mProducer && (bool)mConsumer);
+
+    generation += 1;
+
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new TestConsumerListener(mConsumer), 1, false));
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+    ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+    ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+    ASSERT_EQ(OK, oldProducer->disconnect(NATIVE_WINDOW_API_MEDIA));
+    oldProducer.clear();
+    oldConsumer.clear();
+
+    for (int i = firstPassRender ; i < firstPassAlloc; ++i) {
+        ASSERT_EQ(true, frameQueue.queueItem(bufs[i], fences[i]));
+    }
+
+    while (numAlloc < maxNumAlloc) {
+        AHardwareBuffer *buf;
+        sp<Fence> fence;
+        c2_status_t ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+        if (ret == C2_BLOCKING) {
+            mBqStat->mBlocked++;
+            c2_status_t waitRes = waitFence.wait(3000000000);
+            if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+                continue;
+            }
+            ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+            break;
+        }
+        if (ret != C2_OK) {
+            ALOGE("alloc error: c2_err(%d)", ret);
+            break;
+        }
+        mBqStat->mDequeued++;
+        if (!frameQueue.queueItem(buf, fence)) {
+            ALOGE("queue to render failed");
+            break;
+        }
+        ++numAlloc;
+    }
+
+    ASSERT_EQ(numAlloc, maxNumAlloc);
+
+    frameQueue.stop(true);
+    // Wait more than enough time(1 sec) to render all queued frames for sure.
+    ::usleep(1000000);
+
+    if (queueThread.joinable()) {
+        queueThread.join();
+    }
+    // mReleased should not be checked. IProducerListener::onBufferReleased()
+    // from the previous Surface could be missing after a new Surface was
+    // configured. Instead check # of dequeueable and queueBuffer() calls.
+    ASSERT_EQ(numAlloc, mBqStat->mQueued);
+    ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+    for (int i = 0; i < maxDequeueCount; ++i) {
+        AHardwareBuffer *buf;
+        sp<Fence> fence;
+
+        ASSERT_EQ(C2_OK, mTracker->allocate(
+                0, 0, 0, kTestUsageFlag, &buf, &fence));
+        AHardwareBuffer_release(buf);
+        mBqStat->mDequeued++;
+        numAlloc++;
+    }
+    ASSERT_EQ(C2_BLOCKING, mTracker->allocate(
+            0, 0, 0, kTestUsageFlag, &bufs[0], &fences[0]));
+}
+
+TEST_F(GraphicsTrackerTest, maxDequeueIncreaseTest) {
+    uint32_t generation = 1;
+    int maxDequeueCount = 10;
+    int dequeueIncrease = 4;
+
+    int numAlloc = 0;
+
+    ASSERT_TRUE(init(maxDequeueCount));
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new TestConsumerListener(mConsumer), 1, false));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+    ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+
+    int waitFd = -1;
+    ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+    C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+    AHardwareBuffer *buf;
+    sp<Fence> fence;
+    uint64_t bids[maxDequeueCount];
+    if (__builtin_available(android __ANDROID_API_T__, *)) {
+        for (int i = 0; i < maxDequeueCount; ++i) {
+            ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+            ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+            ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bids[i]));
+            AHardwareBuffer_release(buf);
+            mBqStat->mDequeued++;
+            numAlloc++;
+        }
+    } else {
+        GTEST_SKIP();
+    }
+    ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+    ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+    ASSERT_EQ(C2_OK, mTracker->deallocate(bids[0], Fence::NO_FENCE));
+    mBqStat->mDiscarded++;
+
+    maxDequeueCount += dequeueIncrease;
+    ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+    for (int i = 0; i < dequeueIncrease + 1; ++i) {
+        ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+        ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+        AHardwareBuffer_release(buf);
+        mBqStat->mDequeued++;
+        numAlloc++;
+    }
+    ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+    ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+    ASSERT_EQ(C2_OK, mTracker->deallocate(bids[1], Fence::NO_FENCE));
+    mBqStat->mDiscarded++;
+
+    maxDequeueCount += dequeueIncrease;
+    ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+    for (int i = 0; i < dequeueIncrease + 1; ++i) {
+        ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+        ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+        AHardwareBuffer_release(buf);
+        mBqStat->mDequeued++;
+        numAlloc++;
+    }
+    ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+    ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+}
+
+TEST_F(GraphicsTrackerTest, maxDequeueDecreaseTest) {
+    uint32_t generation = 1;
+    int maxDequeueCount = 12;
+    int dequeueDecrease = 4;
+
+    int numAlloc = 0;
+
+    ASSERT_TRUE(init(maxDequeueCount));
+    ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+                          new TestConsumerListener(mConsumer), 1, false));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+    ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+
+    int waitFd = -1;
+    ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+    C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+    AHardwareBuffer *buf;
+    sp<Fence> fence;
+    uint64_t bids[maxDequeueCount];
+    if (__builtin_available(android __ANDROID_API_T__, *)) {
+        for (int i = 0; i < maxDequeueCount; ++i) {
+            ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+            ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+            ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bids[i]));
+            AHardwareBuffer_release(buf);
+            mBqStat->mDequeued++;
+            numAlloc++;
+        }
+    } else {
+        GTEST_SKIP();
+    }
+    ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+    ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+    int discardIdx = 0;
+    maxDequeueCount -= dequeueDecrease;
+    ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+    for (int i = 0; i < dequeueDecrease + 1; ++i) {
+        ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+        ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+        ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+        mBqStat->mDiscarded++;
+    }
+    ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+    ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+    mBqStat->mDequeued++;
+
+    ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+    mBqStat->mDiscarded++;
+    ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+    mBqStat->mDiscarded++;
+    maxDequeueCount -= dequeueDecrease;
+
+    ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+    for (int i = 0; i < dequeueDecrease - 1; ++i) {
+        ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+        ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+        ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+        mBqStat->mDiscarded++;
+    }
+    ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+    ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+    mBqStat->mDequeued++;
+}
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index af2683b..9f57bfd 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -84,7 +84,7 @@
         "libbase",
         "libdmabufheap",
         "android.hardware.media.bufferpool@2.0",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
     ],
 
     local_include_dirs: [
@@ -102,7 +102,7 @@
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
         "android.hardware.media.bufferpool@2.0",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
         "android.hardware.media.c2-V1-ndk",
         "libbase",
         "libbinder_ndk",
@@ -162,11 +162,12 @@
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.media.bufferpool2-V1-ndk",
+        "android.hardware.media.bufferpool2-V2-ndk",
         "android.hardware.media.c2-V1-ndk",
     ],
 
     shared_libs: [
+        "libbinder",
         "libbinder_ndk",
         "libui",
         "libdl",
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 107ce89..60b5b29 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -383,7 +383,7 @@
     }
 
     uint8_t *pointer = nullptr;
-    err = mapper.lock(handle, usage, bounds, (void **)&pointer, nullptr, nullptr);
+    err = mapper.lock(handle, usage, bounds, (void **)&pointer);
     if (err != NO_ERROR || pointer == nullptr) {
         return C2_CORRUPTED;
     }
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 52ebe25..5d50fc3 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -335,7 +335,8 @@
             p.reset();
         }
     } else {
-        ALOGE("Create sync fence from invalid fd");
+        ALOGV("Create sync fence from invalid fd");
+        return C2Fence();
     }
     return C2Fence(p);
 }
@@ -531,7 +532,9 @@
             p = SyncFenceImpl::CreateFromNativeHandle(handle);
             break;
         default:
-            ALOGD("Unsupported fence type %d", type);
+            ALOGV("Unsupported fence type %d", type);
+            // If this is malformed-handle close the handle here.
+            (void) native_handle_close(handle);
             // return a null-fence in this case
             break;
     }
diff --git a/media/codec2/vndk/platform/C2IgbaBuffer.cpp b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
index 2051e8f..eafdb22 100644
--- a/media/codec2/vndk/platform/C2IgbaBuffer.cpp
+++ b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
@@ -193,7 +193,7 @@
             width, height, format, usage, kBlockingFetchTimeoutNs, &origId, block, &fence);
 
     if (res == C2_BLOCKING) {
-        return C2_TIMED_OUT;
+        return C2_BLOCKING;
     }
     if (res != C2_OK) {
         return res;
diff --git a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
index e1ff3eb..1b06ea7 100644
--- a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
+++ b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
@@ -19,6 +19,8 @@
 #include "aaudio/AAudioTesting.h"
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include <functional>
+
 constexpr int32_t kRandomStringLength = 256;
 constexpr int32_t kMaxRuns = 100;
 constexpr int64_t kNanosPerMillisecond = 1000 * 1000;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index f050a20..ae37152 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1704,10 +1704,14 @@
             __func__, mPortId, deviceId, mSelectedDeviceId, mRoutedDeviceId);
     if (mSelectedDeviceId != deviceId) {
         mSelectedDeviceId = deviceId;
-        if (mStatus == NO_ERROR && mSelectedDeviceId != mRoutedDeviceId) {
+        if (mStatus == NO_ERROR) {
+            // allow track invalidation when track is not playing to propagate
+            // the updated mSelectedDeviceId
             if (isPlaying_l()) {
-                android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
-                mProxy->interrupt();
+                if (mSelectedDeviceId != mRoutedDeviceId) {
+                    android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+                    mProxy->interrupt();
+                }
             } else {
                 // if the track is idle, try to restore now and
                 // defer to next start if not possible
diff --git a/media/libaudioclient/TEST_MAPPING b/media/libaudioclient/TEST_MAPPING
index bd508b3..234e858 100644
--- a/media/libaudioclient/TEST_MAPPING
+++ b/media/libaudioclient/TEST_MAPPING
@@ -41,11 +41,19 @@
         }
       ]
     }
-  ]
+  ],
+  "postsubmit": [
   // TODO(b/302036943): Enable once we make it pass with AIDL HAL on CF.
-  // "postsubmit": [
   //   {
   //      "name": "audioeffect_analysis"
-  //   }
-  // ]
+  //   },
+    {
+      "name": "CtsVirtualDevicesTestCases",
+      "options" : [
+        {
+          "include-filter": "android.virtualdevice.cts.VirtualAudioTest"
+        }
+      ]
+    }
+  ]
 }
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index fc3f699..2af18cc 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -974,7 +974,7 @@
     if (mModule == nullptr) return NO_INIT;
     {
         std::lock_guard l(mLock);
-        mMapper.resetUnusedPatchesAndPortConfigs();
+        mMapper.resetUnusedPatchesPortConfigsAndPorts();
     }
     ModuleDebug debug{ .simulateDeviceConnections = enabled };
     status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index 196b432..39999a5 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -180,18 +180,6 @@
 
     State state;
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getState(&state)));
-    // in case of buffer/ioHandle re-configure for an opened effect, close it and re-open
-    if (state != State::INIT && mCommon != common) {
-        ALOGI("%s at state %s, common parameter change from %s to %s, closing effect", __func__,
-              android::internal::ToString(state).c_str(), mCommon.toString().c_str(),
-              common.toString().c_str());
-        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->close()));
-        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getState(&state)));
-        mStatusQ.reset();
-        mInputQ.reset();
-        mOutputQ.reset();
-    }
-
     if (state == State::INIT) {
         ALOGI("%s at state %s, opening effect with input %s output %s", __func__,
               android::internal::ToString(state).c_str(), common.input.toString().c_str(),
@@ -199,16 +187,7 @@
         IEffect::OpenEffectReturn openReturn;
         RETURN_STATUS_IF_ERROR(
                 statusTFromBinderStatus(mEffect->open(common, std::nullopt, &openReturn)));
-
-        if (mIsProxyEffect) {
-            mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ();
-            mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ();
-            mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ();
-        } else {
-            mStatusQ = std::make_shared<StatusMQ>(openReturn.statusMQ);
-            mInputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ);
-            mOutputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ);
-        }
+        updateMqs(openReturn);
 
         if (status_t status = updateEventFlags(); status != OK) {
             ALOGV("%s closing at status %d", __func__, status);
@@ -225,6 +204,18 @@
     return *static_cast<int32_t*>(pReplyData) = OK;
 }
 
+void EffectConversionHelperAidl::updateMqs(const IEffect::OpenEffectReturn& ret) {
+    if (mIsProxyEffect) {
+        mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ();
+        mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ();
+        mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ();
+    } else {
+        mStatusQ = std::make_shared<StatusMQ>(ret.statusMQ);
+        mInputQ = std::make_shared<DataMQ>(ret.inputDataMQ);
+        mOutputQ = std::make_shared<DataMQ>(ret.outputDataMQ);
+    }
+}
+
 status_t EffectConversionHelperAidl::handleGetConfig(uint32_t cmdSize __unused,
                                                      const void* pCmdData __unused,
                                                      uint32_t* replySize, void* pReplyData) {
@@ -517,5 +508,13 @@
     return desc;
 }
 
+status_t EffectConversionHelperAidl::reopen() {
+    IEffect::OpenEffectReturn openReturn;
+    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->reopen(&openReturn)));
+
+    updateMqs(openReturn);
+    return OK;
+}
+
 }  // namespace effect
 }  // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 5db334c..8b9efb3 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -47,6 +47,7 @@
     bool isBypassingOrTunnel() const;
 
     ::aidl::android::hardware::audio::effect::Descriptor getDescriptor() const;
+    status_t reopen();
 
   protected:
     const int32_t mSessionId;
@@ -108,6 +109,8 @@
     std::shared_ptr<android::hardware::EventFlag> mEfGroup = nullptr;
     status_t updateEventFlags();
 
+    void updateMqs(const ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn& ret);
+
     status_t handleInit(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
                         void* pReplyData);
     status_t handleSetConfig(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index f26444c..2836727 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -56,6 +56,7 @@
 using ::aidl::android::hardware::audio::effect::Descriptor;
 using ::aidl::android::hardware::audio::effect::IEffect;
 using ::aidl::android::hardware::audio::effect::IFactory;
+using ::aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
 using ::aidl::android::hardware::audio::effect::State;
 
 namespace android {
@@ -165,26 +166,37 @@
 
 // write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
 status_t EffectHalAidl::process() {
+    const std::string effectName = mConversion->getDescriptor().common.name;
     State state = State::INIT;
     if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
         state != State::PROCESSING) {
-        ALOGI("%s skipping %s process because it's %s", __func__,
-              mConversion->getDescriptor().common.name.c_str(),
+        ALOGI("%s skipping %s process because it's %s", __func__, effectName.c_str(),
               mConversion->isBypassing()
                       ? "bypassing"
                       : aidl::android::hardware::audio::effect::toString(state).c_str());
         return -ENODATA;
     }
 
+    // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
+    auto efGroup = mConversion->getEventFlagGroup();
+    if (!efGroup) {
+        ALOGE("%s invalid efGroup", __func__);
+        return INVALID_OPERATION;
+    }
+
+    if (uint32_t efState = 0;
+        ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState, 1 /* ns */,
+                                       true /* retry */)) {
+        ALOGI("%s %s receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str());
+        mConversion->reopen();
+    }
     auto statusQ = mConversion->getStatusMQ();
     auto inputQ = mConversion->getInputMQ();
     auto outputQ = mConversion->getOutputMQ();
-    auto efGroup = mConversion->getEventFlagGroup();
     if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
-        !outputQ->isValid() || !efGroup) {
-        ALOGE("%s invalid FMQ [Status %d I %d O %d] efGroup %p", __func__,
-              statusQ ? statusQ->isValid() : 0, inputQ ? inputQ->isValid() : 0,
-              outputQ ? outputQ->isValid() : 0, efGroup.get());
+        !outputQ->isValid()) {
+        ALOGE("%s invalid FMQ [Status %d I %d O %d]", __func__, statusQ ? statusQ->isValid() : 0,
+              inputQ ? inputQ->isValid() : 0, outputQ ? outputQ->isValid() : 0);
         return INVALID_OPERATION;
     }
 
@@ -225,8 +237,8 @@
         return INVALID_OPERATION;
     }
 
-    ALOGD("%s %s consumed %zu produced %zu", __func__,
-          mConversion->getDescriptor().common.name.c_str(), floatsToWrite, floatsToRead);
+    ALOGD("%s %s consumed %zu produced %zu", __func__, effectName.c_str(), floatsToWrite,
+          floatsToRead);
     return OK;
 }
 
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index aee42a9..d73a36c 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -106,8 +106,8 @@
 ndk::ScopedAStatus EffectProxy::open(const Parameter::Common& common,
                                      const std::optional<Parameter::Specific>& specific,
                                      IEffect::OpenEffectReturn* ret __unused) {
-    ndk::ScopedAStatus status = ndk::ScopedAStatus::fromExceptionCodeWithMessage(
-            EX_ILLEGAL_ARGUMENT, "nullEffectHandle");
+    ndk::ScopedAStatus status =
+            ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "nullEffectHandle");
     for (auto& sub : mSubEffects) {
         IEffect::OpenEffectReturn openReturn;
         if (!sub.handle || !(status = sub.handle->open(common, specific, &openReturn)).isOk()) {
@@ -130,6 +130,31 @@
     return status;
 }
 
+ndk::ScopedAStatus EffectProxy::reopen(OpenEffectReturn* ret __unused) {
+    ndk::ScopedAStatus status =
+            ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "nullEffectHandle");
+    for (auto& sub : mSubEffects) {
+        IEffect::OpenEffectReturn openReturn;
+        if (!sub.handle || !(status = sub.handle->reopen(&openReturn)).isOk()) {
+            ALOGE("%s: failed to open %p UUID %s", __func__, sub.handle.get(),
+                  ::android::audio::utils::toString(sub.descriptor.common.id.uuid).c_str());
+            break;
+        }
+        sub.effectMq.statusQ = std::make_shared<StatusMQ>(openReturn.statusMQ);
+        sub.effectMq.inputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ);
+        sub.effectMq.outputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ);
+    }
+
+    // close all opened effects if failure
+    if (!status.isOk()) {
+        ALOGE("%s: closing all sub-effects with error %s", __func__,
+              status.getDescription().c_str());
+        close();
+    }
+
+    return status;
+}
+
 ndk::ScopedAStatus EffectProxy::close() {
     return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) {
         return effect->close();
diff --git a/media/libaudiohal/impl/EffectProxy.h b/media/libaudiohal/impl/EffectProxy.h
index 0d62642..9b9e8f1 100644
--- a/media/libaudiohal/impl/EffectProxy.h
+++ b/media/libaudiohal/impl/EffectProxy.h
@@ -62,6 +62,8 @@
                     specific,
             ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn* ret) override;
     ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus reopen(
+            ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn* ret) override;
     ndk::ScopedAStatus getDescriptor(
             ::aidl::android::hardware::audio::effect::Descriptor* desc) override;
     ndk::ScopedAStatus command(::aidl::android::hardware::audio::effect::CommandId id) override;
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index 63ace8c..2b7f298 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -238,6 +238,29 @@
     return OK;
 }
 
+status_t Hal2AidlMapper::createOrUpdatePortConfigRetry(
+        const AudioPortConfig& requestedPortConfig, AudioPortConfig* result, bool* created) {
+    AudioPortConfig suggestedOrAppliedPortConfig;
+    RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig,
+                    &suggestedOrAppliedPortConfig, created));
+    if (suggestedOrAppliedPortConfig.id == 0) {
+        // Try again with the suggested config
+        suggestedOrAppliedPortConfig.id = requestedPortConfig.id;
+        AudioPortConfig appliedPortConfig;
+        RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(suggestedOrAppliedPortConfig,
+                        &appliedPortConfig, created));
+        if (appliedPortConfig.id == 0) {
+            ALOGE("%s: module %s did not apply suggested config %s", __func__,
+                    mInstance.c_str(), suggestedOrAppliedPortConfig.toString().c_str());
+            return NO_INIT;
+        }
+        *result = appliedPortConfig;
+    } else {
+        *result = suggestedOrAppliedPortConfig;
+    }
+    return OK;
+}
+
 void Hal2AidlMapper::eraseConnectedPort(int32_t portId) {
     mPorts.erase(portId);
     mConnectedPorts.erase(portId);
@@ -247,6 +270,7 @@
         ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str());
         mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>();
     }
+    updateDynamicMixPorts();
 }
 
 status_t Hal2AidlMapper::findOrCreatePatch(
@@ -294,27 +318,19 @@
         if (config != nullptr) {
             setPortConfigFromConfig(&requestedPortConfig, *config);
         }
-        AudioPortConfig suggestedOrAppliedPortConfig;
-        RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig,
-                        &suggestedOrAppliedPortConfig, created));
-        if (suggestedOrAppliedPortConfig.id == 0) {
-            // Try again with the suggested config
-            suggestedOrAppliedPortConfig.id = requestedPortConfig.id;
-            AudioPortConfig appliedPortConfig;
-            RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(suggestedOrAppliedPortConfig,
-                            &appliedPortConfig, created));
-            if (appliedPortConfig.id == 0) {
-                ALOGE("%s: module %s did not apply suggested config %s", __func__,
-                        mInstance.c_str(), suggestedOrAppliedPortConfig.toString().c_str());
-                return NO_INIT;
-            }
-            *portConfig = appliedPortConfig;
-        } else {
-            *portConfig = suggestedOrAppliedPortConfig;
-        }
+        return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
     } else {
-        *portConfig = portConfigIt->second;
-        *created = false;
+        AudioPortConfig requestedPortConfig = portConfigIt->second;
+        if (config != nullptr) {
+            setPortConfigFromConfig(&requestedPortConfig, *config);
+        }
+
+        if (requestedPortConfig != portConfigIt->second) {
+            return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
+        } else {
+            *portConfig = portConfigIt->second;
+            *created = false;
+        }
     }
     return OK;
 }
@@ -370,12 +386,12 @@
         return BAD_VALUE;
     } else {
         AudioPortConfig requestedPortConfig = portConfigIt->second;
-        if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
-            AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
-            if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
-                    source != AudioSource::SYS_RESERVED_INVALID) {
-                mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
-            }
+        setPortConfigFromConfig(&requestedPortConfig, config);
+
+        AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
+        if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
+                source != AudioSource::SYS_RESERVED_INVALID) {
+            mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
         }
 
         if (requestedPortConfig != portConfigIt->second) {
@@ -410,9 +426,19 @@
                 requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
                 portConfig, created);
     } else if (requestedPortConfig.ext.getTag() == Tag::device) {
-        return findOrCreateDevicePortConfig(
-                requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
-                portConfig, created);
+        if (const auto& p = requestedPortConfig;
+                p.sampleRate.has_value() && p.channelMask.has_value() &&
+                p.format.has_value()) {
+            AudioConfig config;
+            setConfigFromPortConfig(&config, requestedPortConfig);
+            return findOrCreateDevicePortConfig(
+                    requestedPortConfig.ext.get<Tag::device>().device, &config,
+                    portConfig, created);
+        } else {
+            return findOrCreateDevicePortConfig(
+                    requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
+                    portConfig, created);
+        }
     }
     ALOGW("%s: unsupported audio port config: %s",
             __func__, requestedPortConfig.toString().c_str());
@@ -704,7 +730,7 @@
             this, __func__, ioHandle, device.toString().c_str(),
             flags.toString().c_str(), toString(source).c_str(),
             config->toString().c_str(), mixPortConfig->toString().c_str());
-    resetUnusedPatchesAndPortConfigs();
+    resetUnusedPatchesPortConfigsAndPorts();
     const AudioConfig initialConfig = *config;
     // Find / create AudioPortConfigs for the device port and the mix port,
     // then find / create a patch between them, and open a stream on the mix port.
@@ -832,7 +858,7 @@
             result = BAD_VALUE;
         }
     }
-    resetUnusedPortConfigs();
+    resetUnusedPortConfigsAndPorts();
     return result;
 }
 
@@ -849,7 +875,7 @@
     ALOGE("%s: port config id %d not found", __func__, portConfigId);
 }
 
-void Hal2AidlMapper::resetUnusedPatchesAndPortConfigs() {
+void Hal2AidlMapper::resetUnusedPatchesPortConfigsAndPorts() {
     // Since patches can be created independently of streams via 'createOrUpdatePatch',
     // here we only clean up patches for released streams.
     std::set<int32_t> patchesToRelease;
@@ -863,11 +889,11 @@
             it = mStreams.erase(it);
         }
     }
-    // 'releaseAudioPatches' also resets unused port configs.
+    // 'releaseAudioPatches' also resets unused port configs and ports.
     releaseAudioPatches(patchesToRelease);
 }
 
-void Hal2AidlMapper::resetUnusedPortConfigs() {
+void Hal2AidlMapper::resetUnusedPortConfigsAndPorts() {
     // The assumption is that port configs are used to create patches
     // (or to open streams, but that involves creation of patches, too). Thus,
     // orphaned port configs can and should be reset.
@@ -908,6 +934,7 @@
 }
 
 status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort, bool connected) {
+    resetUnusedPatchesPortConfigsAndPorts();
     if (connected) {
         AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device;
         std::optional<AudioPort> templatePort;
@@ -942,7 +969,6 @@
             }
             templatePort = portsIt->second;
         }
-        resetUnusedPatchesAndPortConfigs();
 
         // Use the ID of the "template" port, use all the information from the provided port.
         AudioPort connectedPort = devicePort;
@@ -969,7 +995,6 @@
             ALOGD("%s: device port for device %s found in the module %s",
                     __func__, matchDevice.toString().c_str(), mInstance.c_str());
         }
-        resetUnusedPatchesAndPortConfigs();
 
         // Disconnection of remote submix out with address "0" is a special case. We need to replace
         // the connected port entry with the "augmented template".
@@ -1002,6 +1027,9 @@
     if (status == OK) {
         auto portIt = mPorts.find(portId);
         if (portIt != mPorts.end()) {
+            if (port->ext.getTag() == AudioPortExt::Tag::mix && portIt->second != *port) {
+                mDynamicMixPortIds.insert(portId);
+            }
             portIt->second = *port;
         } else {
             ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
@@ -1050,4 +1078,15 @@
     return OK;
 }
 
+void Hal2AidlMapper::updateDynamicMixPorts() {
+    for (int32_t portId : mDynamicMixPortIds) {
+        if (auto it = mPorts.find(portId); it != mPorts.end()) {
+            updateAudioPort(portId, &it->second);
+        } else {
+            // This must not happen
+            ALOGE("%s, cannot find port for id=%d", __func__, portId);
+        }
+    }
+}
+
 } // namespace android
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
index 21cfd5a..f937173 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.h
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -91,7 +91,7 @@
         ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
         Cleanups* cleanups = nullptr);
     status_t releaseAudioPatch(int32_t patchId);
-    void resetUnusedPatchesAndPortConfigs();
+    void resetUnusedPatchesPortConfigsAndPorts();
     status_t setDevicePortConnectedState(
             const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected);
 
@@ -126,6 +126,9 @@
     status_t createOrUpdatePortConfig(
             const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
             ::aidl::android::media::audio::common::AudioPortConfig* result, bool *created);
+    status_t createOrUpdatePortConfigRetry(
+            const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+            ::aidl::android::media::audio::common::AudioPortConfig* result, bool *created);
     void eraseConnectedPort(int32_t portId);
     status_t findOrCreatePatch(
         const std::set<int32_t>& sourcePortConfigIds,
@@ -181,10 +184,11 @@
     status_t releaseAudioPatches(const std::set<int32_t>& patchIds);
     void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); }
     void resetPortConfig(int32_t portConfigId);
-    void resetUnusedPortConfigs();
+    void resetUnusedPortConfigsAndPorts();
     status_t updateAudioPort(
             int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
     status_t updateRoutes();
+    void updateDynamicMixPorts();
 
     Ports mPorts;
     // Remote submix "template" ports (no address specified, no profiles).
@@ -202,6 +206,7 @@
     ConnectedPorts mConnectedPorts;
     std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort>
             mDisconnectedPortReplacement;
+    std::set<int32_t> mDynamicMixPortIds;
 };
 
 }  // namespace android
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 378d919..5f525d7 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -234,7 +234,9 @@
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
     if (!mStream) return NO_INIT;
-    return mStream->dump(fd, Args(args).args(), args.size());
+    status_t status = mStream->dump(fd, Args(args).args(), args.size());
+    mStreamPowerLog.dump(fd);
+    return status;
 }
 
 status_t StreamHalAidl::start() {
@@ -808,6 +810,7 @@
                         mOffloadMetadata.channelMask = VALUE_OR_RETURN_STATUS(
                                 ::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
                                         channel_mask, false /*isInput*/));
+                        return OK;
                     }
                     return BAD_VALUE;
                 }))) {
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index 37633ae..b56872c 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -69,6 +69,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/media/libeffects/downmix/aidl/DownmixContext.cpp b/media/libeffects/downmix/aidl/DownmixContext.cpp
index 13e0e5a..5fb44b5 100644
--- a/media/libeffects/downmix/aidl/DownmixContext.cpp
+++ b/media/libeffects/downmix/aidl/DownmixContext.cpp
@@ -111,7 +111,6 @@
 }
 
 IEffect::Status DownmixContext::downmixProcess(float* in, float* out, int samples) {
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
     IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
 
     if (in == nullptr || out == nullptr ||
@@ -132,7 +131,6 @@
     bool accumulate = false;
     int frames = samples * sizeof(float) / getInputFrameSize();
     if (mType == Downmix::Type::STRIP) {
-        int inputChannelCount = getChannelCount(mChMask);
         while (frames) {
             if (accumulate) {
                 out[0] = std::clamp(out[0] + in[0], -1.f, 1.f);
@@ -141,7 +139,7 @@
                 out[0] = in[0];
                 out[1] = in[1];
             }
-            in += inputChannelCount;
+            in += mInputChannelCount;
             out += 2;
             frames--;
         }
@@ -153,8 +151,11 @@
             return status;
         }
     }
-    LOG(DEBUG) << __func__ << " done processing";
-    return {STATUS_OK, samples, samples};
+    int producedSamples = (samples / mInputChannelCount) << 1;
+    LOG(DEBUG) << __func__ << " done processing " << samples << " samples, generated "
+               << producedSamples << " frameSize: " << getInputFrameSize() << " - "
+               << getOutputFrameSize();
+    return {STATUS_OK, samples, producedSamples};
 }
 
 void DownmixContext::init_params(const Parameter::Common& common) {
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.cpp b/media/libeffects/downmix/aidl/EffectDownmix.cpp
index 702a6f0..c82c23b 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.cpp
+++ b/media/libeffects/downmix/aidl/EffectDownmix.cpp
@@ -71,42 +71,6 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus DownmixImpl::setParameterCommon(const Parameter& param) {
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
-
-    auto tag = param.getTag();
-    switch (tag) {
-        case Parameter::common:
-            RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
-                      EX_ILLEGAL_ARGUMENT, "setCommFailed");
-            break;
-        case Parameter::deviceDescription:
-            RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
-                              RetCode::SUCCESS,
-                      EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
-            break;
-        case Parameter::mode:
-            RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
-                      EX_ILLEGAL_ARGUMENT, "setModeFailed");
-            break;
-        case Parameter::source:
-            RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
-                      EX_ILLEGAL_ARGUMENT, "setSourceFailed");
-            break;
-        case Parameter::volumeStereo:
-            RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
-                              RetCode::SUCCESS,
-                      EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
-            break;
-        default: {
-            LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
-            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
-                                                                    "commonParamNotSupported");
-        }
-    }
-    return ndk::ScopedAStatus::ok();
-}
-
 ndk::ScopedAStatus DownmixImpl::commandImpl(CommandId command) {
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
     switch (command) {
@@ -206,6 +170,43 @@
     return RetCode::SUCCESS;
 }
 
+void DownmixImpl::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)) {
+        LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag invalid";
+    }
+
+    {
+        std::lock_guard lg(mImplMutex);
+        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;
+        }
+
+        const auto availableToRead = inputMQ->availableToRead();
+        const auto availableToWrite = outputMQ->availableToWrite() *
+                                      mImplContext->getInputFrameSize() /
+                                      mImplContext->getOutputFrameSize();
+        auto processSamples = std::min(availableToRead, availableToWrite);
+        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;
+        }
+    }
+}
+
 // Processing method running in EffectWorker thread.
 IEffect::Status DownmixImpl::effectProcessImpl(float* in, float* out, int sampleToProcess) {
     if (!mContext) {
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.h b/media/libeffects/downmix/aidl/EffectDownmix.h
index 812d26b..54557dc 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.h
+++ b/media/libeffects/downmix/aidl/EffectDownmix.h
@@ -34,21 +34,26 @@
         LOG(DEBUG) << __func__;
     }
 
-    ndk::ScopedAStatus commandImpl(CommandId command) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterCommon(const Parameter& param) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    RetCode releaseContext() override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process)
+            REQUIRES(mImplMutex) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> getContext() override { return mContext; }
     std::string getEffectName() override { return kEffectName; }
 
+    // downmix override the process because of different input/output sample size requirement
+    void process() override;
+
   private:
-    std::shared_ptr<DownmixContext> mContext;
-    ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+    std::shared_ptr<DownmixContext> mContext GUARDED_BY(mImplMutex);
+    ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
index 9e154cf..e93a4e6 100644
--- a/media/libeffects/dynamicsproc/Android.bp
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -95,6 +95,6 @@
     ],
 
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
index 85ea53a..1fedea4 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -211,11 +211,12 @@
     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(!mContext || !mImplContext, EX_NULL_POINTER, "createContextFailed");
+    mEventFlag = mImplContext->getStatusEventFlag();
 
-    RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
     if (specific.has_value()) {
         RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
     } else {
@@ -227,8 +228,8 @@
     }
 
     mState = State::IDLE;
-    context->dupeFmq(ret);
-    RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+    mContext->dupeFmq(ret);
+    RETURN_IF(createThread(getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
               "FailedToCreateWorker");
     return ndk::ScopedAStatus::ok();
 }
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
index 1e1e72e..4897888 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
@@ -39,22 +39,25 @@
     ndk::ScopedAStatus open(const Parameter::Common& common,
                             const std::optional<Parameter::Specific>& specific,
                             OpenEffectReturn* ret) override;
-    ndk::ScopedAStatus commandImpl(CommandId command) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
     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;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    RetCode releaseContext() override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process)
+            REQUIRES(mImplMutex) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> getContext() override { return mContext; }
     std::string getEffectName() override { return kEffectName; }
 
   private:
-    std::shared_ptr<DynamicsProcessingContext> mContext;
+    std::shared_ptr<DynamicsProcessingContext> mContext GUARDED_BY(mImplMutex);
     ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
-                                                      Parameter::Specific* specific);
+                                                      Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
     bool isParamInRange(const Parameter::Specific& specific);
 };
 
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
index f3a3860..042b063 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -63,6 +63,9 @@
 }
 
 RetCode DynamicsProcessingContext::setCommon(const Parameter::Common& common) {
+    if(auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+        return ret;
+    }
     mCommon = common;
     init();
     LOG(INFO) << __func__ << common.toString();
@@ -312,7 +315,9 @@
 
 void DynamicsProcessingContext::init() {
     std::lock_guard lg(mMutex);
-    mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+    if (mState == DYNAMICS_PROCESSING_STATE_UNINITIALIZED) {
+        mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+    }
     mChannelCount = static_cast<int>(::aidl::android::hardware::audio::common::getChannelCount(
             mCommon.input.base.channelMask));
 }
diff --git a/media/libeffects/hapticgenerator/Android.bp b/media/libeffects/hapticgenerator/Android.bp
index cc19a80..7d96b53 100644
--- a/media/libeffects/hapticgenerator/Android.bp
+++ b/media/libeffects/hapticgenerator/Android.bp
@@ -84,6 +84,6 @@
     ],
 
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
index fe9616a..53dcd49 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
@@ -33,16 +33,18 @@
         LOG(DEBUG) << __func__;
     }
 
-    ndk::ScopedAStatus commandImpl(CommandId command) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
     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;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    RetCode releaseContext() override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process)
+            REQUIRES(mImplMutex) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> getContext() override { return mContext; }
     std::string getEffectName() override { return kEffectName; }
 
   private:
diff --git a/media/libeffects/loudness/Android.bp b/media/libeffects/loudness/Android.bp
index 05bbec3..46e4669 100644
--- a/media/libeffects/loudness/Android.bp
+++ b/media/libeffects/loudness/Android.bp
@@ -69,6 +69,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
index 5b9e924..e2e716c 100644
--- a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
+++ b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
@@ -33,22 +33,25 @@
         LOG(DEBUG) << __func__;
     }
 
-    ndk::ScopedAStatus commandImpl(CommandId command) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
     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;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    RetCode releaseContext() override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process)
+            REQUIRES(mImplMutex) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> getContext() override { return mContext; }
     std::string getEffectName() override { return kEffectName; }
 
   private:
-    std::shared_ptr<LoudnessEnhancerContext> mContext;
+    std::shared_ptr<LoudnessEnhancerContext> 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/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index 71bb2ef..bb7e4c6 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -20,6 +20,7 @@
 #define LOG_TAG "BundleContext"
 #include <android-base/logging.h>
 #include <audio_utils/power.h>
+#include <media/AidlConversionCppNdk.h>
 #include <Utils.h>
 
 #include "BundleContext.h"
@@ -36,9 +37,10 @@
               const lvm::BundleEffectType& type)
         : EffectContext(statusDepth, common), mType(type) {
     LOG(DEBUG) << __func__ << type;
-    int channelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+
+    int inputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
             common.input.base.channelMask);
-    mSamplesPerSecond = common.input.base.sampleRate * channelCount;
+    mSamplesPerSecond = common.input.base.sampleRate * inputChannelCount;
 }
 
 BundleContext::~BundleContext() {
@@ -50,9 +52,15 @@
     std::lock_guard lg(mMutex);
     // init with pre-defined preset NORMAL
     for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-        mBandGainMdB[i] = lvm::kSoftPresets[0 /* normal */][i] * 100;
+        mBandGainmB[i] = lvm::kSoftPresets[0 /* normal */][i] * 100;
     }
 
+    // Initialise control params
+    LVM_ControlParams_t controlParams;
+    RetCode retStatus = initControlParameter(controlParams);
+    RETURN_VALUE_IF(retStatus != RetCode::SUCCESS, RetCode::ERROR_ILLEGAL_PARAMETER,
+                    " UnsupportedParams");
+
     // allocate lvm instance
     LVM_ReturnStatus_en status;
     LVM_InstParams_t params = {.BufferMode = LVM_UNMANAGED_BUFFERS,
@@ -63,8 +71,6 @@
     GOTO_IF_LVM_ERROR(status, deinit, "LVM_GetInstanceHandleFailed");
 
     // set control
-    LVM_ControlParams_t controlParams;
-    initControlParameter(controlParams);
     status = LVM_SetControlParameters(mInstance, &controlParams);
     GOTO_IF_LVM_ERROR(status, deinit, "LVM_SetControlParametersFailed");
 
@@ -227,8 +233,8 @@
         bool viEnabled = params.VirtualizerOperatingMode == LVM_MODE_ON;
 
         if (eqEnabled) {
-            for (size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-                float bandFactor = mBandGainMdB[i] / 1500.0;
+            for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+                float bandFactor = mBandGainmB[i] / 1500.0;
                 float bandCoefficient = lvm::kBandEnergyCoefficient[i];
                 float bandEnergy = bandFactor * bandCoefficient * bandCoefficient;
                 if (bandEnergy > 0) energyContribution += bandEnergy;
@@ -236,9 +242,9 @@
 
             // cross EQ coefficients
             float bandFactorSum = 0;
-            for (size_t i = 0; i < lvm::MAX_NUM_BANDS - 1; i++) {
-                float bandFactor1 = mBandGainMdB[i] / 1500.0;
-                float bandFactor2 = mBandGainMdB[i + 1] / 1500.0;
+            for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS - 1; i++) {
+                float bandFactor1 = mBandGainmB[i] / 1500.0;
+                float bandFactor2 = mBandGainmB[i + 1] / 1500.0;
 
                 if (bandFactor1 > 0 && bandFactor2 > 0) {
                     float crossEnergy =
@@ -259,8 +265,8 @@
             energyContribution += boostFactor * boostCoefficient * boostCoefficient;
 
             if (eqEnabled) {
-                for (size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-                    float bandFactor = mBandGainMdB[i] / 1500.0;
+                for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+                    float bandFactor = mBandGainmB[i] / 1500.0;
                     float bandCrossCoefficient = lvm::kBassBoostEnergyCrossCoefficient[i];
                     float bandEnergy = boostFactor * bandFactor * bandCrossCoefficient;
                     if (bandEnergy > 0) energyBassBoost += bandEnergy;
@@ -312,7 +318,9 @@
             device != AudioDeviceDescription{AudioDeviceType::OUT_CARKIT,
                                              AudioDeviceDescription::CONNECTION_BT_SCO} &&
             device != AudioDeviceDescription{AudioDeviceType::OUT_SPEAKER,
-                                             AudioDeviceDescription::CONNECTION_BT_A2DP}) {
+                                             AudioDeviceDescription::CONNECTION_BT_A2DP} &&
+            device != AudioDeviceDescription{AudioDeviceType::OUT_SUBMIX,
+                                             AudioDeviceDescription::CONNECTION_VIRTUAL}) {
             return false;
         }
     }
@@ -329,7 +337,9 @@
             device != AudioDeviceDescription{AudioDeviceType::OUT_HEADPHONE,
                                              AudioDeviceDescription::CONNECTION_BT_A2DP} &&
             device != AudioDeviceDescription{AudioDeviceType::OUT_HEADSET,
-                                             AudioDeviceDescription::CONNECTION_USB}) {
+                                             AudioDeviceDescription::CONNECTION_USB} &&
+            device != AudioDeviceDescription{AudioDeviceType::OUT_SUBMIX,
+                                             AudioDeviceDescription::CONNECTION_VIRTUAL}) {
             return false;
         }
     }
@@ -469,6 +479,7 @@
 RetCode BundleContext::setEqualizerBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels) {
     RETURN_VALUE_IF(bandLevels.size() > lvm::MAX_NUM_BANDS || bandLevels.empty(),
                     RetCode::ERROR_ILLEGAL_PARAMETER, "sizeExceedMax");
+
     RetCode ret = updateControlParameter(bandLevels);
     if (RetCode::SUCCESS == ret) {
         mCurPresetIdx = lvm::PRESET_CUSTOM;
@@ -483,15 +494,13 @@
     std::vector<Equalizer::BandLevel> bandLevels;
     bandLevels.reserve(lvm::MAX_NUM_BANDS);
     for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
-        bandLevels.emplace_back(
-                Equalizer::BandLevel{static_cast<int32_t>(i), mBandGainMdB[i]});
+        bandLevels.emplace_back(Equalizer::BandLevel{static_cast<int32_t>(i), mBandGainmB[i]});
     }
     return bandLevels;
 }
 
 std::vector<int32_t> BundleContext::getEqualizerCenterFreqs() {
     std::vector<int32_t> freqs;
-
     LVM_ControlParams_t params;
     {
         std::lock_guard lg(mMutex);
@@ -518,7 +527,7 @@
     RETURN_VALUE_IF(!isBandLevelIndexInRange(bandLevels), RetCode::ERROR_ILLEGAL_PARAMETER,
                     "indexOutOfRange");
 
-    std::array<int, lvm::MAX_NUM_BANDS> tempLevel(mBandGainMdB);
+    std::array<int, lvm::MAX_NUM_BANDS> tempLevel(mBandGainmB);
     for (const auto& it : bandLevels) {
         tempLevel[it.index] = it.levelMb;
     }
@@ -539,8 +548,8 @@
         RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, &params),
                         RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
     }
-    mBandGainMdB = tempLevel;
-    LOG(DEBUG) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGainMdB)
+    mBandGainmB = tempLevel;
+    LOG(DEBUG) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGainmB)
                << "mdB";
 
     return RetCode::SUCCESS;
@@ -618,11 +627,30 @@
     return RetCode::SUCCESS;
 }
 
-void BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+RetCode BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+    int outputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+            mCommon.output.base.channelMask);
+    auto outputChannelMaskConv = aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+            mCommon.output.base.channelMask, /*isInput*/ false);
+    RETURN_VALUE_IF(!outputChannelMaskConv.ok(), RetCode::ERROR_ILLEGAL_PARAMETER,
+                    " outputChannelMaskNotValid");
+
+    params.NrChannels = outputChannelCount;
+    params.ChMask = outputChannelMaskConv.value();
+    params.SampleRate = lvmFsForSampleRate(mCommon.input.base.sampleRate);
+
+    int inputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+            mCommon.input.base.channelMask);
+    if (inputChannelCount == 1) {
+        params.SourceFormat = LVM_MONO;
+    } else if (inputChannelCount == 2) {
+        params.SourceFormat = LVM_STEREO;
+    } else if (inputChannelCount > 2 && inputChannelCount <= LVM_MAX_CHANNELS) {
+        params.SourceFormat = LVM_MULTICHANNEL;
+    }
+
     /* General parameters */
     params.OperatingMode = LVM_MODE_ON;
-    params.SampleRate = LVM_FS_44100;
-    params.SourceFormat = LVM_STEREO;
     params.SpeakerType = LVM_HEADPHONES;
 
     /* Concert Sound parameters */
@@ -657,13 +685,7 @@
     params.PSA_Enable = LVM_PSA_OFF;
     params.PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
 
-    /* TE Control parameters */
-    params.TE_OperatingMode = LVM_TE_OFF;
-    params.TE_EffectLevel = 0;
-
-    params.NrChannels = audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
-    params.ChMask = AUDIO_CHANNEL_OUT_STEREO;
-    params.SourceFormat = LVM_STEREO;
+    return RetCode::SUCCESS;
 }
 
 void BundleContext::initHeadroomParameter(LVM_HeadroomParams_t& params) const {
@@ -832,13 +854,13 @@
             LOG(DEBUG) << "Effect_process() processing last frame";
         }
         mNumberEffectsCalled = 0;
-        LVM_UINT16 frames = samples * sizeof(float) / frameSize;
         float* outTmp = (accumulate ? getWorkBuffer() : out);
         /* Process the samples */
         LVM_ReturnStatus_en lvmStatus;
         {
             std::lock_guard lg(mMutex);
-            lvmStatus = LVM_Process(mInstance, in, outTmp, frames, 0);
+
+            lvmStatus = LVM_Process(mInstance, in, outTmp, inputFrameCount, 0);
             if (lvmStatus != LVM_SUCCESS) {
                 LOG(ERROR) << __func__ << lvmStatus;
                 return {EX_UNSUPPORTED_OPERATION, 0, 0};
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index 779d53a..809f402 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -41,15 +41,6 @@
     RetCode disable();
     RetCode disableOperatingMode();
 
-    void setSampleRate(const int sampleRate) { mSampleRate = sampleRate; }
-    int getSampleRate() const { return mSampleRate; }
-
-    void setChannelMask(const aidl::android::media::audio::common::AudioChannelLayout& chMask) {
-        mChMask = chMask;
-    }
-    aidl::android::media::audio::common::AudioChannelLayout getChannelMask() const {
-        return mChMask;
-    }
     bool isDeviceSupportedBassBoost(
             const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
                     devices);
@@ -105,9 +96,7 @@
     LVM_Handle_t mInstance GUARDED_BY(mMutex);
 
     aidl::android::media::audio::common::AudioDeviceDescription mVirtualizerForcedDevice;
-    aidl::android::media::audio::common::AudioChannelLayout mChMask;
 
-    int mSampleRate = LVM_FS_44100;
     int mSamplesPerSecond = 0;
     int mSamplesToExitCountEq = 0;
     int mSamplesToExitCountBb = 0;
@@ -129,7 +118,7 @@
     int mBassStrengthSaved = 0;
     // Equalizer
     int mCurPresetIdx = lvm::PRESET_CUSTOM; /* Current preset being used */
-    std::array<int, lvm::MAX_NUM_BANDS> mBandGainMdB; /* band gain in millibels */
+    std::array<int, lvm::MAX_NUM_BANDS> mBandGainmB; /* band gain in millibels */
     // Virtualizer
     int mVirtStrengthSaved = 0; /* Conversion between Get/Set */
     bool mVirtualizerTempDisabled = false;
@@ -139,7 +128,7 @@
     float mVolume = 0;
     bool mMuteEnabled = false; /* Must store as mute = -96dB level */
 
-    void initControlParameter(LVM_ControlParams_t& params) const;
+    RetCode initControlParameter(LVM_ControlParams_t& params) const;
     void initHeadroomParameter(LVM_HeadroomParams_t& params) const;
     RetCode limitLevel();
     static float VolToDb(float vol);
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index 3148d36..257e972 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -425,10 +425,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> EffectBundleAidl::getContext() {
-    return mContext;
-}
-
 RetCode EffectBundleAidl::releaseContext() {
     if (mContext) {
         GlobalSession::getGlobalSession().releaseSession(mType, mContext->getSessionId());
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
index ec1abe8..429e941 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
@@ -36,41 +36,47 @@
     ~EffectBundleAidl() override;
 
     ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
-    ndk::ScopedAStatus setParameterCommon(const Parameter& param) override;
-    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
-    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                            Parameter::Specific* specific) override;
+    ndk::ScopedAStatus setParameterCommon(const Parameter& param) REQUIRES(mImplMutex) 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;
 
-    ndk::ScopedAStatus commandImpl(CommandId command) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return *mEffectName; }
 
   private:
-    std::shared_ptr<BundleContext> mContext;
+    std::shared_ptr<BundleContext> mContext GUARDED_BY(mImplMutex);
     const Descriptor* mDescriptor;
     const std::string* mEffectName;
     lvm::BundleEffectType mType = lvm::BundleEffectType::EQUALIZER;
 
     IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
 
-    ndk::ScopedAStatus setParameterBassBoost(const Parameter::Specific& specific);
-    ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Id& id,
-                                             Parameter::Specific* specific);
+    ndk::ScopedAStatus setParameterBassBoost(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
+    ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 
-    ndk::ScopedAStatus setParameterEqualizer(const Parameter::Specific& specific);
-    ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Id& id,
-                                             Parameter::Specific* specific);
-    ndk::ScopedAStatus setParameterVolume(const Parameter::Specific& specific);
-    ndk::ScopedAStatus getParameterVolume(const Volume::Id& id, Parameter::Specific* specific);
-    ndk::ScopedAStatus setParameterVirtualizer(const Parameter::Specific& specific);
+    ndk::ScopedAStatus setParameterEqualizer(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
+    ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
+    ndk::ScopedAStatus setParameterVolume(const Parameter::Specific& specific) REQUIRES(mImplMutex);
+    ndk::ScopedAStatus getParameterVolume(const Volume::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
+    ndk::ScopedAStatus setParameterVirtualizer(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
     ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Id& id,
-                                               Parameter::Specific* specific);
+                                               Parameter::Specific* specific) REQUIRES(mImplMutex);
 };
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index 5fb3966..a50ba93 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -118,14 +118,19 @@
         "libhardware_headers",
     ],
     shared_libs: [
+        "libaudio_aidl_conversion_common_ndk",
+        "libaudioutils",
+        "libbinder",
         "liblog",
+        "libstagefright_foundation",
     ],
     cflags: [
         "-Wthread-safety",
+        "-DBACKEND_NDK",
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
 
@@ -156,6 +161,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
index b49d109..f9afe69 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
@@ -358,10 +358,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> EffectReverb::getContext() {
-    return mContext;
-}
-
 RetCode EffectReverb::releaseContext() {
     if (mContext) {
         mContext.reset();
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
index d7d2bbd..e0771a1 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
@@ -30,35 +30,41 @@
 
     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;
 
-    ndk::ScopedAStatus commandImpl(CommandId command) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return *mEffectName; }
 
   private:
-    std::shared_ptr<ReverbContext> mContext;
+    std::shared_ptr<ReverbContext> mContext GUARDED_BY(mImplMutex);
     const Descriptor* mDescriptor;
     const std::string* mEffectName;
     lvm::ReverbEffectType mType;
 
     IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
 
-    ndk::ScopedAStatus setParameterPresetReverb(const Parameter::Specific& specific);
+    ndk::ScopedAStatus setParameterPresetReverb(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
     ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Id& id,
-                                                Parameter::Specific* specific);
+                                                Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 
-    ndk::ScopedAStatus setParameterEnvironmentalReverb(const Parameter::Specific& specific);
+    ndk::ScopedAStatus setParameterEnvironmentalReverb(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
     ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Id& id,
-                                                       Parameter::Specific* specific);
+                                                       Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index 564eb36..994b061 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -89,6 +89,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
index e8ae8b3..7552804 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
@@ -412,10 +412,6 @@
     return mContext;
 }
 
-std::shared_ptr<EffectContext> EffectPreProcessing::getContext() {
-    return mContext;
-}
-
 RetCode EffectPreProcessing::releaseContext() {
     if (mContext) {
         PreProcessingSession::getPreProcessingSession().releaseSession(mType,
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
index fad848a..9ce5597 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
@@ -31,41 +31,51 @@
 
     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;
 
-    ndk::ScopedAStatus commandImpl(CommandId command) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
 
     std::string getEffectName() override { return *mEffectName; }
 
   private:
-    std::shared_ptr<PreProcessingContext> mContext;
+    std::shared_ptr<PreProcessingContext> mContext GUARDED_BY(mImplMutex);
     const Descriptor* mDescriptor;
     const std::string* mEffectName;
     PreProcessingEffectType mType;
 
-    ndk::ScopedAStatus setParameterAcousticEchoCanceler(const Parameter::Specific& specific);
+    ndk::ScopedAStatus setParameterAcousticEchoCanceler(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
     ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Id& id,
-                                                        Parameter::Specific* specific);
+                                                        Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 
-    ndk::ScopedAStatus setParameterAutomaticGainControlV1(const Parameter::Specific& specific);
+    ndk::ScopedAStatus setParameterAutomaticGainControlV1(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
     ndk::ScopedAStatus getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Id& id,
-                                                          Parameter::Specific* specific);
+                                                          Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 
-    ndk::ScopedAStatus setParameterAutomaticGainControlV2(const Parameter::Specific& specific);
+    ndk::ScopedAStatus setParameterAutomaticGainControlV2(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
     ndk::ScopedAStatus getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Id& id,
-                                                          Parameter::Specific* specific);
+                                                          Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 
-    ndk::ScopedAStatus setParameterNoiseSuppression(const Parameter::Specific& specific);
+    ndk::ScopedAStatus setParameterNoiseSuppression(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex);
     ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Id& id,
-                                                    Parameter::Specific* specific);
+                                                    Parameter::Specific* specific)
+            REQUIRES(mImplMutex);
 };
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
index c1e4eda..2c44e5c 100644
--- a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
@@ -141,6 +141,9 @@
 }
 
 RetCode PreProcessingContext::setCommon(const Parameter::Common& common) {
+    if(auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+        return ret;
+    }
     mCommon = common;
     updateConfigs(common);
     return RetCode::SUCCESS;
diff --git a/media/libeffects/visualizer/Android.bp b/media/libeffects/visualizer/Android.bp
index a8b665b..66ceadf 100644
--- a/media/libeffects/visualizer/Android.bp
+++ b/media/libeffects/visualizer/Android.bp
@@ -70,6 +70,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/media/libeffects/visualizer/aidl/Visualizer.h b/media/libeffects/visualizer/aidl/Visualizer.h
index ec725db..b48c85e 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.h
+++ b/media/libeffects/visualizer/aidl/Visualizer.h
@@ -35,23 +35,25 @@
         LOG(DEBUG) << __func__;
     }
 
-    ndk::ScopedAStatus commandImpl(CommandId command) override;
+    ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
     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;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
-    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
-    RetCode releaseContext() override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+            REQUIRES(mImplMutex) override;
+    IEffect::Status effectProcessImpl(float* in, float* out, int process)
+            REQUIRES(mImplMutex) override;
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex) override;
+    RetCode releaseContext() REQUIRES(mImplMutex) override;
 
-    std::shared_ptr<EffectContext> getContext() override { return mContext; }
     std::string getEffectName() override { return kEffectName; }
 
   private:
     static const std::vector<Range::VisualizerRange> kRanges;
-    std::shared_ptr<VisualizerContext> mContext;
+    std::shared_ptr<VisualizerContext> 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/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
index e33cc0f..4436fb9 100644
--- a/media/libmedia/CharacterEncodingDetector.cpp
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -198,7 +198,9 @@
             ALOGV("@@@ checking %s", name);
             const char *s = mValues.getEntry(i);
             int32_t inputLength = strlen(s);
-            const char *enc;
+            // Use encoding determined from the combination of artist/album/title etc.
+            // as default if there is no better match found.
+            const char *enc = combinedenc;
 
             if (!allprintable && (!strcmp(name, "artist") ||
                     !strcmp(name, "albumartist") ||
@@ -216,13 +218,12 @@
                     const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
                     const UCharsetMatch* bestSingleMatch = getPreferred(s, inputLength,
                             ucma, matches, &goodmatchSingle, &highestSingle);
-                    if (goodmatchSingle || highestSingle > highest)
-                        enc = ucsdet_getName(bestSingleMatch, &status);
-                    else
-                        enc = combinedenc;
-                } else {
-                    // use encoding determined from the combination of artist/album/title etc.
-                    enc = combinedenc;
+                    // getPreferred could return a null. Check for null before calling
+                    // ucsdet_getName.
+                    if (bestSingleMatch != NULL) {
+                        if (goodmatchSingle || highestSingle > highest)
+                            enc = ucsdet_getName(bestSingleMatch, &status);
+                    }
                 }
             } else {
                 if (isPrintableAscii(s, inputLength)) {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 0af9d12..712b405 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -137,7 +137,7 @@
             cflags: [
                 "-DDISABLE_AUDIO_SYSTEM_OFFLOAD",
             ],
-        }
+        },
     },
 }
 
@@ -273,7 +273,7 @@
         "VideoFrameSchedulerBase.cpp",
         "VideoFrameScheduler.cpp",
         "VideoRenderQualityTracker.cpp",
-      ],
+    ],
 
     shared_libs: [
         "libstagefright_framecapture_utils",
@@ -330,7 +330,7 @@
         "libmedia_ndkformatpriv",
     ],
 
-    header_libs:[
+    header_libs: [
         "libmediadrm_headers",
         "libnativeloader-headers",
         "libstagefright_xmlparser_headers",
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index f16e635..604dcb0 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -298,6 +298,11 @@
             ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err);
             break;
         }
+        if (img == nullptr) {
+            (void)buf->unlock(); // Since lock() was successful.
+            ALOGE("error pushing blank frames: lock succeeded: buf mapping is nullptr");
+            break;
+        }
 
         *img = 0;
 
diff --git a/media/libstagefright/colorconversion/fuzzer/Android.bp b/media/libstagefright/colorconversion/fuzzer/Android.bp
index 76b054a..237e715 100644
--- a/media/libstagefright/colorconversion/fuzzer/Android.bp
+++ b/media/libstagefright/colorconversion/fuzzer/Android.bp
@@ -47,9 +47,15 @@
     ],
     fuzz_config: {
         cc: [
-            "android-media-fuzzing-reports@google.com",
+            "android-fwk-video@google.com",
         ],
-        componentid: 155276,
+        componentid: 42195,
+        hotlists: ["4593311"],
+        description: "The fuzzer targets the APIs of libstagefright_color_conversion",
+        vector: "local_no_privileges_required",
+        service_privilege: "constrained",
+        users: "multi_user",
+        fuzzed_code_usage: "shipped",
     },
 }
 
diff --git a/media/libstagefright/data/media_codecs_google_c2_audio.xml b/media/libstagefright/data/media_codecs_google_c2_audio.xml
index 509f7a9..0d9e0ec 100644
--- a/media/libstagefright/data/media_codecs_google_c2_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_audio.xml
@@ -66,7 +66,7 @@
         </MediaCodec>
         <MediaCodec name="c2.android.raw.decoder" type="audio/raw">
             <Alias name="OMX.google.raw.decoder" />
-            <Limit name="channel-count" max="8" />
+            <Limit name="channel-count" max="12" />
             <Limit name="sample-rate" ranges="8000-192000" />
             <Limit name="bitrate" range="1-10000000" />
         </MediaCodec>
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index ee41867..24020d1 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -80,7 +80,7 @@
         </MediaCodec>
         <MediaCodec name="c2.android.raw.decoder" type="audio/raw">
             <Alias name="OMX.google.raw.decoder" />
-            <Limit name="channel-count" max="8" />
+            <Limit name="channel-count" max="12" />
             <Limit name="sample-rate" ranges="8000-192000" />
             <Limit name="bitrate" range="1-10000000" />
             <Attribute name="software-codec" />
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 3c95c6d..f4c40e1 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -810,6 +810,9 @@
 inline constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
 inline constexpr char KEY_MAX_HEIGHT[] = "max-height";
 inline constexpr char KEY_MAX_INPUT_SIZE[] = "max-input-size";
+inline constexpr char KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE[] = "buffer-batch-max-output-size";
+inline constexpr char KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE[] =
+        "buffer-batch-threshold-output-size";
 inline constexpr char KEY_MAX_OUTPUT_CHANNEL_COUNT[] = "max-output-channel-count";
 inline constexpr char KEY_MAX_PTS_GAP_TO_ENCODER[] = "max-pts-gap-to-encoder";
 inline constexpr char KEY_MAX_WIDTH[] = "max-width";
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 54c5697..79ab009 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -184,6 +184,9 @@
 
 cc_defaults {
     name: "libstagefright_softomx-defaults",
+    // TODO (b/316432618) Software OMX codecs are no longer used, disable building them till
+    // this code is removed completely.
+    enabled: false,
     vendor_available: true,
 
     cflags: [
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index 65d537b..f95fc4d 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -148,6 +148,11 @@
                 return C2_TRANSACTION_FAILED;
             }
         }
+        status = static_cast<c2_status_t>(configResult.status.status);
+        if (status != C2_BAD_INDEX) {
+            LOG(DEBUG) << "config -- call failed: "
+                       << status << ".";
+        }
         size_t i = failures->size();
         failures->resize(i + configResult.failures.size());
         for (const c2_aidl::SettingResult& sf : configResult.failures) {
@@ -320,8 +325,8 @@
             heapParams->reserve(heapParams->size() + numIndices);
         }
         c2_status_t status = C2_OK;
-        c2_aidl::Params aidlParams;
-        ScopedAStatus transResult = mAidlConfigurable->query(indices, true, &aidlParams);
+        c2_aidl::IConfigurable::QueryResult aidlResult;
+        ScopedAStatus transResult = mAidlConfigurable->query(indices, true, &aidlResult);
         if (!transResult.isOk()) {
             if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
                 status = c2_status_t(transResult.getServiceSpecificError());
@@ -332,8 +337,12 @@
                 return C2_TRANSACTION_FAILED;
             }
         }
+        status = static_cast<c2_status_t>(aidlResult.status.status);
+        if (status != C2_OK) {
+            LOG(DEBUG) << "query -- call failed: " << status << ".";
+        }
         std::vector<C2Param*> paramPointers;
-        if (!c2_aidl::utils::ParseParamsBlob(&paramPointers, aidlParams)) {
+        if (!c2_aidl::utils::ParseParamsBlob(&paramPointers, aidlResult.params)) {
             LOG(ERROR) << "query -- error while parsing params.";
             return C2_CORRUPTED;
         }
@@ -488,9 +497,9 @@
         }
 
         c2_status_t status = C2_OK;
-        std::vector<c2_aidl::FieldSupportedValuesQueryResult> queryResults;
+        c2_aidl::IConfigurable::QuerySupportedValuesResult queryResult;
         ScopedAStatus transResult = mAidlConfigurable->querySupportedValues(
-                aidlFields, true, &queryResults);
+                aidlFields, true, &queryResult);
         if (!transResult.isOk()) {
             if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
                 status = c2_status_t(transResult.getServiceSpecificError());
@@ -502,14 +511,19 @@
                 return C2_TRANSACTION_FAILED;
             }
         }
-        if (queryResults.size() != fields.size()) {
+        status = static_cast<c2_status_t>(queryResult.status.status);
+        if (status != C2_OK) {
+            LOG(DEBUG) << "querySupportedValues -- call failed: "
+                       << status << ".";
+        }
+        if (queryResult.values.size() != fields.size()) {
             LOG(ERROR) << "querySupportedValues -- "
                           "input and output lists "
                           "have different sizes.";
             return C2_CORRUPTED;
         }
         for (size_t i = 0; i < fields.size(); ++i) {
-            if (!c2_aidl::utils::FromAidl(&fields[i], aidlFields[i], queryResults[i])) {
+            if (!c2_aidl::utils::FromAidl(&fields[i], aidlFields[i], queryResult.values[i])) {
                 LOG(ERROR) << "querySupportedValues -- "
                               "invalid returned value.";
                 return C2_CORRUPTED;
@@ -803,6 +817,7 @@
         }
     }
 
+    bool registered = false;
     if (platformVersion >= __ANDROID_API_V__) {
         if (!aidlStore) {
             aidlStore = ::ndk::SharedRefBase::make<c2_aidl::utils::ComponentStore>(
@@ -812,23 +827,27 @@
             std::string(c2_aidl::IComponentStore::descriptor) + "/software";
         binder_exception_t ex = AServiceManager_addService(
                 aidlStore->asBinder().get(), serviceName.c_str());
-        if (ex != EX_NONE) {
+        if (ex == EX_NONE) {
+            registered = true;
+        } else {
             LOG(ERROR) << "Cannot register software Codec2 AIDL service.";
-            return;
         }
     }
 
     if (!hidlStore) {
-        hidlStore = ::android::sp<V1_0::utils::ComponentStore>::make(
+        hidlStore = ::android::sp<V1_2::utils::ComponentStore>::make(
                 std::make_shared<H2C2ComponentStore>(nullptr));
-        hidlVer = "1.0";
+        hidlVer = "1.2";
     }
-    if (hidlStore->registerAsService("software") != android::OK) {
+    if (hidlStore->registerAsService("software") == android::OK) {
+        registered = true;
+    } else {
         LOG(ERROR) << "Cannot register software Codec2 v" << hidlVer << " service.";
-        return;
     }
 
-    LOG(INFO) << "Software Codec2 service created and registered.";
+    if (registered) {
+        LOG(INFO) << "Software Codec2 service created and registered.";
+    }
 
     ABinderProcess_joinThreadPool();
     ::android::hardware::joinRpcThreadpool();
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index 0a8d2ab..d096d63 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -189,6 +189,8 @@
     ],
 
     dictionary: "mkv_extractor_fuzzer.dict",
+
+    corpus: ["corpus/*"],
 }
 
 cc_fuzz {
diff --git a/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c b/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c
new file mode 100755
index 0000000..8b31683
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e b/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e
new file mode 100755
index 0000000..f4d475d
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3 b/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3
new file mode 100755
index 0000000..8438e66
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69 b/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69
new file mode 100755
index 0000000..2f622cd
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600 b/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600
new file mode 100755
index 0000000..f053c01
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65 b/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65
new file mode 100755
index 0000000..872451c
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8 b/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8
new file mode 100755
index 0000000..2f7e3ea
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687 b/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687
new file mode 100755
index 0000000..10b5f9a
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620 b/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620
new file mode 100755
index 0000000..969b7a2
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498 b/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498
new file mode 100755
index 0000000..bd146b1
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da b/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da
new file mode 100755
index 0000000..7cf844e
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da
Binary files differ
diff --git a/media/module/extractors/wav/WAVExtractor.cpp b/media/module/extractors/wav/WAVExtractor.cpp
index 9c3bac6..d278103 100644
--- a/media/module/extractors/wav/WAVExtractor.cpp
+++ b/media/module/extractors/wav/WAVExtractor.cpp
@@ -219,7 +219,7 @@
 
             mNumChannels = U16_LE_AT(&formatSpec[2]);
 
-            if (mNumChannels < 1 || mNumChannels > FCC_8) {
+            if (mNumChannels < 1 || mNumChannels > FCC_12) {
                 ALOGE("Unsupported number of channels (%d)", mNumChannels);
                 return AMEDIA_ERROR_UNSUPPORTED;
             }
diff --git a/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml b/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
index c3a0ced..f8906dc 100644
--- a/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
+++ b/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
@@ -15,6 +15,7 @@
 -->
 <configuration description="Unit test configuration for {MODULE}">
     <option name="test-suite-tag" value="TranscoderTests" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="false" />
         <option name="push-file" key="TranscodingTestAssets" value="/data/local/tmp/TranscodingTestAssets" />
diff --git a/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index 88c3fd3..fed8fc9 100644
--- a/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -20,6 +20,7 @@
 #define LOG_TAG "VideoTrackTranscoderTests"
 
 #include <android-base/logging.h>
+#include <android/binder_process.h>
 #include <fcntl.h>
 #include <gtest/gtest.h>
 #include <media/MediaSampleReaderNDK.h>
@@ -221,5 +222,6 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 8b9dde3..9ec7700 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -208,19 +208,21 @@
 }
 
 cc_test {
-    name: "AImageReaderWindowHandleTest",
+    name: "AImageReaderWindowTest",
     test_suites: ["device-tests"],
-    srcs: ["tests/AImageReaderWindowHandleTest.cpp"],
+    srcs: ["tests/AImageReaderWindowTest.cpp"],
     shared_libs: [
         "libbinder",
         "libmediandk",
         "libmediautils",
         "libnativewindow",
         "libgui",
+        "libhidlbase",
         "libutils",
         "libui",
         "libcutils",
         "android.hardware.graphics.bufferqueue@1.0",
+        "android.hidl.token@1.0",
     ],
 
     header_libs: [
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 9de511e..a26681e 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -450,6 +450,10 @@
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
+EXPORT const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE =
+        "buffer-batch-max-output-size";
+EXPORT const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE =
+        "buffer-batch-threshold-output-size";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
 EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime";
diff --git a/media/ndk/TEST_MAPPING b/media/ndk/TEST_MAPPING
index e420812..1a15728 100644
--- a/media/ndk/TEST_MAPPING
+++ b/media/ndk/TEST_MAPPING
@@ -1,7 +1,7 @@
 // mappings for frameworks/av/media/ndk
 {
   "presubmit": [
-    { "name": "AImageReaderWindowHandleTest" },
+    { "name": "AImageReaderWindowTest" },
     { "name": "libmediandk_test" }
   ]
 }
diff --git a/media/ndk/fuzzer/ndk_crypto_fuzzer.cpp b/media/ndk/fuzzer/ndk_crypto_fuzzer.cpp
index 2b22f0f..fcb0520 100644
--- a/media/ndk/fuzzer/ndk_crypto_fuzzer.cpp
+++ b/media/ndk/fuzzer/ndk_crypto_fuzzer.cpp
@@ -16,6 +16,9 @@
 
 #include <fuzzer/FuzzedDataProvider.h>
 #include <media/NdkMediaCrypto.h>
+#include <functional>
+
+#include <functional>
 
 constexpr size_t kMaxString = 256;
 constexpr size_t kMinBytes = 0;
diff --git a/media/ndk/fuzzer/ndk_image_reader_fuzzer.cpp b/media/ndk/fuzzer/ndk_image_reader_fuzzer.cpp
index 6c11798..6450742 100644
--- a/media/ndk/fuzzer/ndk_image_reader_fuzzer.cpp
+++ b/media/ndk/fuzzer/ndk_image_reader_fuzzer.cpp
@@ -18,6 +18,7 @@
 #include <fuzzer/FuzzedDataProvider.h>
 #include <gui/BufferQueue.h>
 #include <media/NdkImageReader.h>
+#include <functional>
 
 constexpr int32_t kMaxSize = INT_MAX;
 constexpr int32_t kMinSize = 1;
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index b722b74..4fc9918 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -534,7 +534,8 @@
  * Get the native_handle_t corresponding to the ANativeWindow owned by the
  * AImageReader provided.
  *
- * This is deprecated in API level 35 and will return AMEDIA_ERROR_UNKNOWN.
+ * This is deprecated on devices with vendor API level greater than 34 and
+ * will return AMEDIA_ERROR_UNKNOWN on those devices.
  * The native_handle_t is no longer used with AIDL interfaces and
  * ANativeWindow is used directly instead.
  * Use AImageRead_getWindow to get the ANativeWindow and use that object.
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 24a10dc..cc1dd9f 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -187,6 +187,8 @@
 extern const char* AMEDIAFORMAT_KEY_MAX_B_FRAMES __INTRODUCED_IN(34);
 extern const char* AMEDIAFORMAT_KEY_MAX_HEIGHT __INTRODUCED_IN(21);
 extern const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE __INTRODUCED_IN(21);
+extern const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE __INTRODUCED_IN(35);
+extern const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE __INTRODUCED_IN(35);
 extern const char* AMEDIAFORMAT_KEY_MAX_WIDTH __INTRODUCED_IN(21);
 extern const char* AMEDIAFORMAT_KEY_MIME __INTRODUCED_IN(21);
 extern const char* AMEDIAFORMAT_KEY_MPEG_USER_DATA __INTRODUCED_IN(28);
diff --git a/media/ndk/tests/AImageReaderWindowHandleTest.cpp b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
deleted file mode 100644
index 27864c2..0000000
--- a/media/ndk/tests/AImageReaderWindowHandleTest.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-#include <media/NdkImageReader.h>
-#include <media/NdkImage.h>
-#include <mediautils/AImageReaderUtils.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <NdkImagePriv.h>
-#include <NdkImageReaderPriv.h>
-#include <vndk/hardware_buffer.h>
-#include <memory>
-
-namespace android {
-
-using HGraphicBufferProducer = hardware::graphics::bufferqueue::V1_0::
-        IGraphicBufferProducer;
-using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
-using aimg::AImageReader_getHGBPFromHandle;
-
-typedef IGraphicBufferProducer::QueueBufferInput QueueBufferInput;
-typedef IGraphicBufferProducer::QueueBufferOutput QueueBufferOutput;
-
-static constexpr uint64_t kImageBufferUsage =
-    AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
-static constexpr int kImageWidth = 640;
-static constexpr int kImageHeight = 480;
-static constexpr int kImageFormat = AIMAGE_FORMAT_RGBA_8888;
-static constexpr int kMaxImages = 1;
-
-static constexpr int64_t kQueueBufferInputTimeStamp = 1384888611;
-static constexpr bool kQueueBufferInputIsAutoTimeStamp = false;
-static constexpr android_dataspace kQueueBufferInputDataspace = HAL_DATASPACE_UNKNOWN;
-static const Rect kQueueBufferInputRect = Rect(kImageWidth, kImageHeight);
-static constexpr int kQueueBufferInputScalingMode = 0;
-static constexpr int kQueueBufferInputTransform = 0;
-static const sp<Fence> kQueueBufferInputFence = Fence::NO_FENCE;
-
-static constexpr int kOnImageAvailableWaitUs = 100 * 1000;
-
-class AImageReaderWindowHandleTest : public ::testing::Test {
-   public:
-    void SetUp() override {
-        AImageReader_newWithUsage(kImageWidth, kImageHeight, kImageFormat,
-                                  kImageBufferUsage , kMaxImages, &imageReader_);
-        media_status_t ret = AMEDIA_ERROR_UNKNOWN;
-        ASSERT_NE(imageReader_, nullptr);
-        ret = AImageReader_setImageListener(imageReader_,
-                                            &imageReaderAvailableCb_);
-        ASSERT_EQ(ret, AMEDIA_OK);
-        ret = AImageReader_setBufferRemovedListener(imageReader_,
-                                                    &imageReaderDetachedCb_);
-        ASSERT_EQ(ret, AMEDIA_OK);
-    }
-    void TearDown() override {
-        if (imageReader_) {
-            AImageReader_delete(imageReader_);
-        }
-    }
-
-    void HandleImageAvailable() {
-        AImage *outImage = nullptr;
-        media_status_t ret = AMEDIA_OK;
-        auto imageDeleter = [](AImage *img) { AImage_delete(img); };
-        std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
-
-        // Test that the image can be acquired.
-        ret = AImageReader_acquireNextImage(imageReader_, &outImage);
-        ASSERT_EQ(ret, AMEDIA_OK);
-        img.reset(outImage);
-        ASSERT_NE(img, nullptr);
-
-        // Test that we can get a handle to the image's hardware buffer and a
-        // native handle to it.
-        AHardwareBuffer *hardwareBuffer = nullptr;
-        ret = AImage_getHardwareBuffer(img.get(), &hardwareBuffer);
-        ASSERT_EQ(ret, AMEDIA_OK);
-        ASSERT_NE(hardwareBuffer, nullptr);
-        const native_handle_t *nh = AHardwareBuffer_getNativeHandle(hardwareBuffer);
-        ASSERT_NE(nh, nullptr);
-        std::unique_lock<std::mutex> lock(imageAvailableMutex_);
-        imageAvailable_ = true;
-        imageCondVar_.notify_one();
-    }
-
-    static void onImageAvailable(void *context, AImageReader *reader) {
-        (void)reader;
-        AImageReaderWindowHandleTest *thisContext =
-            reinterpret_cast<AImageReaderWindowHandleTest *>(context);
-        thisContext->HandleImageAvailable();
-    }
-
-    static void onBufferRemoved(void *, AImageReader *, AHardwareBuffer *) {
-    }
-
-    AImageReader *imageReader_ = nullptr;
-    AImageReader_ImageListener imageReaderAvailableCb_{this, onImageAvailable};
-    AImageReader_BufferRemovedListener imageReaderDetachedCb_{this, onBufferRemoved};
-    std::mutex imageAvailableMutex_;
-    std::condition_variable imageCondVar_;
-    bool imageAvailable_ = false;
-};
-
-static void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
-    const size_t PIXEL_SIZE = 4;
-    for (int x = 0; x < w; x++) {
-        for (int y = 0; y < h; y++) {
-            off_t offset = (y * stride + x) * PIXEL_SIZE;
-            for (int c = 0; c < 4; c++) {
-                int parityX = (x / (1 << (c+2))) & 1;
-                int parityY = (y / (1 << (c+2))) & 1;
-                buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
-            }
-        }
-    }
-}
-
-TEST_F(AImageReaderWindowHandleTest, CreateWindowNativeHandle) {
-    // Check that we can create a native_handle_t corresponding to the
-    // AImageReader.
-    native_handle_t *nh = nullptr;
-    AImageReader_getWindowNativeHandle(imageReader_, &nh);
-    ASSERT_NE(nh, nullptr);
-
-    // Check that there are only ints in the handle.
-    ASSERT_EQ(nh->numFds, 0);
-    ASSERT_NE(nh->numInts, 0);
-
-    // Check that the HGBP can be retrieved from the handle.
-    sp<HGraphicBufferProducer> hgbp =  AImageReader_getHGBPFromHandle(nh);
-    ASSERT_NE(hgbp, nullptr);
-    sp<IGraphicBufferProducer> igbp = new H2BGraphicBufferProducer(hgbp);
-    int dequeuedSlot = -1;
-    sp<Fence> dequeuedFence;
-    IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, igbp->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
-
-    // Test that we can dequeue a buffer.
-    ASSERT_EQ(OK,
-              ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-                      (igbp->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
-                                           kImageWidth, kImageHeight,
-                                           kImageFormat, kImageBufferUsage,
-                                           nullptr, nullptr)));
-    EXPECT_LE(0, dequeuedSlot);
-    EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
-
-    sp<GraphicBuffer> dequeuedBuffer;
-    igbp->requestBuffer(dequeuedSlot, &dequeuedBuffer);
-    uint8_t* img = nullptr;
-    ASSERT_EQ(NO_ERROR, dequeuedBuffer->lock(kImageBufferUsage, (void**)(&img)));
-
-    // Write in some dummy image data.
-    fillRGBA8Buffer(img, dequeuedBuffer->getWidth(), dequeuedBuffer->getHeight(),
-                    dequeuedBuffer->getStride());
-    ASSERT_EQ(NO_ERROR, dequeuedBuffer->unlock());
-    QueueBufferInput queueBufferInput(kQueueBufferInputTimeStamp,
-                                      kQueueBufferInputIsAutoTimeStamp,
-                                      kQueueBufferInputDataspace,
-                                      kQueueBufferInputRect,
-                                      kQueueBufferInputScalingMode,
-                                      kQueueBufferInputTransform,
-                                      kQueueBufferInputFence);
-    QueueBufferOutput queueBufferOutput;
-    ASSERT_EQ(OK, igbp->queueBuffer(dequeuedSlot, queueBufferInput,
-                                    &queueBufferOutput));
-    // wait until the onImageAvailable callback is called, or timeout completes.
-    std::unique_lock<std::mutex> lock(imageAvailableMutex_);
-    imageCondVar_.wait_for(lock, std::chrono::microseconds(kOnImageAvailableWaitUs),
-                           [this]{ return this->imageAvailable_;});
-    EXPECT_TRUE(imageAvailable_) <<  "Timed out waiting for image data to be handled!\n";
-}
-
-class AImageReaderPrivateFormatTest : public ::testing::Test {
-  public:
-    void SetUp() override {
-        auto status = AImageReader_new(kImageWidth, kImageHeight, AIMAGE_FORMAT_RAW_DEPTH,
-                                       kMaxImages, &imgReader);
-        EXPECT_TRUE(status == AMEDIA_OK);
-    }
-
-    void TearDown() override {
-        if (imgReader) {
-            AImageReader_delete(imgReader);
-        }
-    }
-    AImageReader *imgReader = nullptr;
-};
-
-TEST_F(AImageReaderPrivateFormatTest, CreateTest) {
-    EXPECT_TRUE(imgReader != nullptr);
-}
-
-
-}  // namespace android
diff --git a/media/ndk/tests/AImageReaderWindowTest.cpp b/media/ndk/tests/AImageReaderWindowTest.cpp
new file mode 100644
index 0000000..650b990
--- /dev/null
+++ b/media/ndk/tests/AImageReaderWindowTest.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2018 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 <android/hidl/token/1.0/ITokenManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <media/NdkImageReader.h>
+#include <media/NdkImage.h>
+#include <mediautils/AImageReaderUtils.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <NdkImagePriv.h>
+#include <NdkImageReaderPriv.h>
+#include <vndk/hardware_buffer.h>
+#include <memory>
+
+namespace android {
+
+using HGraphicBufferProducer = hardware::graphics::bufferqueue::V1_0::
+        IGraphicBufferProducer;
+using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+using hidl::manager::V1_2::IServiceManager;
+using hidl::token::V1_0::ITokenManager;
+using aimg::AImageReader_getHGBPFromHandle;
+
+typedef IGraphicBufferProducer::QueueBufferInput QueueBufferInput;
+typedef IGraphicBufferProducer::QueueBufferOutput QueueBufferOutput;
+
+static constexpr uint64_t kImageBufferUsage =
+    AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+static constexpr int kImageWidth = 640;
+static constexpr int kImageHeight = 480;
+static constexpr int kImageFormat = AIMAGE_FORMAT_RGBA_8888;
+static constexpr int kMaxImages = 1;
+
+static constexpr int64_t kQueueBufferInputTimeStamp = 1384888611;
+static constexpr bool kQueueBufferInputIsAutoTimeStamp = false;
+static constexpr android_dataspace kQueueBufferInputDataspace = HAL_DATASPACE_UNKNOWN;
+static const Rect kQueueBufferInputRect = Rect(kImageWidth, kImageHeight);
+static constexpr int kQueueBufferInputScalingMode = 0;
+static constexpr int kQueueBufferInputTransform = 0;
+static const sp<Fence> kQueueBufferInputFence = Fence::NO_FENCE;
+
+static constexpr int kOnImageAvailableWaitUs = 100 * 1000;
+
+class AImageReaderWindowTest : public ::testing::Test {
+   public:
+    void SetUp() override {
+        AImageReader_newWithUsage(kImageWidth, kImageHeight, kImageFormat,
+                                  kImageBufferUsage , kMaxImages, &imageReader_);
+        media_status_t ret = AMEDIA_ERROR_UNKNOWN;
+        ASSERT_NE(imageReader_, nullptr);
+        ret = AImageReader_setImageListener(imageReader_,
+                                            &imageReaderAvailableCb_);
+        ASSERT_EQ(ret, AMEDIA_OK);
+        ret = AImageReader_setBufferRemovedListener(imageReader_,
+                                                    &imageReaderDetachedCb_);
+        ASSERT_EQ(ret, AMEDIA_OK);
+    }
+    void TearDown() override {
+        if (imageReader_) {
+            AImageReader_delete(imageReader_);
+        }
+    }
+
+    void HandleImageAvailable() {
+        AImage *outImage = nullptr;
+        media_status_t ret = AMEDIA_OK;
+        auto imageDeleter = [](AImage *img) { AImage_delete(img); };
+        std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
+
+        // Test that the image can be acquired.
+        ret = AImageReader_acquireNextImage(imageReader_, &outImage);
+        ASSERT_EQ(ret, AMEDIA_OK);
+        img.reset(outImage);
+        ASSERT_NE(img, nullptr);
+
+        // Test that we can get a handle to the image's hardware buffer and a
+        // native handle to it.
+        AHardwareBuffer *hardwareBuffer = nullptr;
+        ret = AImage_getHardwareBuffer(img.get(), &hardwareBuffer);
+        ASSERT_EQ(ret, AMEDIA_OK);
+        ASSERT_NE(hardwareBuffer, nullptr);
+        const native_handle_t *nh = AHardwareBuffer_getNativeHandle(hardwareBuffer);
+        ASSERT_NE(nh, nullptr);
+        std::unique_lock<std::mutex> lock(imageAvailableMutex_);
+        imageAvailable_ = true;
+        imageCondVar_.notify_one();
+    }
+
+    static void onImageAvailable(void *context, AImageReader *reader) {
+        (void)reader;
+        AImageReaderWindowTest *thisContext =
+            reinterpret_cast<AImageReaderWindowTest *>(context);
+        thisContext->HandleImageAvailable();
+    }
+
+    static void onBufferRemoved(void *, AImageReader *, AHardwareBuffer *) {
+    }
+
+    static void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
+        const size_t PIXEL_SIZE = 4;
+        for (int x = 0; x < w; x++) {
+            for (int y = 0; y < h; y++) {
+                off_t offset = (y * stride + x) * PIXEL_SIZE;
+                for (int c = 0; c < 4; c++) {
+                    int parityX = (x / (1 << (c+2))) & 1;
+                    int parityY = (y / (1 << (c+2))) & 1;
+                    buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
+                }
+            }
+        }
+    }
+
+    void validateIGBP(sp<IGraphicBufferProducer>& igbp) {
+        int dequeuedSlot = -1;
+        sp<Fence> dequeuedFence;
+        IGraphicBufferProducer::QueueBufferOutput output;
+        ASSERT_EQ(OK, igbp->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
+
+        // Test that we can dequeue a buffer.
+        ASSERT_EQ(OK,
+                  ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+                          (igbp->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+                                               kImageWidth, kImageHeight,
+                                               kImageFormat, kImageBufferUsage,
+                                               nullptr, nullptr)));
+        EXPECT_LE(0, dequeuedSlot);
+        EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
+
+        sp<GraphicBuffer> dequeuedBuffer;
+        igbp->requestBuffer(dequeuedSlot, &dequeuedBuffer);
+        uint8_t* img = nullptr;
+        ASSERT_EQ(NO_ERROR, dequeuedBuffer->lock(kImageBufferUsage, (void**)(&img)));
+
+        // Write in some placeholder image data.
+        fillRGBA8Buffer(img, dequeuedBuffer->getWidth(), dequeuedBuffer->getHeight(),
+                        dequeuedBuffer->getStride());
+        ASSERT_EQ(NO_ERROR, dequeuedBuffer->unlock());
+        QueueBufferInput queueBufferInput(kQueueBufferInputTimeStamp,
+                                          kQueueBufferInputIsAutoTimeStamp,
+                                          kQueueBufferInputDataspace,
+                                          kQueueBufferInputRect,
+                                          kQueueBufferInputScalingMode,
+                                          kQueueBufferInputTransform,
+                                          kQueueBufferInputFence);
+        QueueBufferOutput queueBufferOutput;
+        ASSERT_EQ(OK, igbp->queueBuffer(dequeuedSlot, queueBufferInput,
+                                        &queueBufferOutput));
+        // wait until the onImageAvailable callback is called, or timeout completes.
+        std::unique_lock<std::mutex> lock(imageAvailableMutex_);
+        imageCondVar_.wait_for(lock, std::chrono::microseconds(kOnImageAvailableWaitUs),
+                               [this]{ return this->imageAvailable_;});
+        EXPECT_TRUE(imageAvailable_) <<  "Timed out waiting for image data to be handled!\n";
+    }
+
+    AImageReader *imageReader_ = nullptr;
+    AImageReader_ImageListener imageReaderAvailableCb_{this, onImageAvailable};
+    AImageReader_BufferRemovedListener imageReaderDetachedCb_{this, onBufferRemoved};
+    std::mutex imageAvailableMutex_;
+    std::condition_variable imageCondVar_;
+    bool imageAvailable_ = false;
+};
+
+
+TEST_F(AImageReaderWindowTest, CreateWindowNativeHandle) {
+    // Check that we can create a native_handle_t corresponding to the
+    // AImageReader.
+    native_handle_t *nh = nullptr;
+    media_status_t status = AImageReader_getWindowNativeHandle(imageReader_, &nh);
+
+    // On newer devices without the HIDL TokenManager service this API is
+    // deprecated and will return an error.
+    if (IServiceManager::Transport::EMPTY ==
+        hardware::defaultServiceManager1_2()->getTransport(ITokenManager::descriptor, "default")) {
+      EXPECT_EQ(status, AMEDIA_ERROR_UNKNOWN);
+      return;
+    }
+    ASSERT_NE(nh, nullptr);
+
+    // Check that there are only ints in the handle.
+    ASSERT_EQ(nh->numFds, 0);
+    ASSERT_NE(nh->numInts, 0);
+
+    // Check that the HGBP can be retrieved from the handle.
+    sp<HGraphicBufferProducer> hgbp =  AImageReader_getHGBPFromHandle(nh);
+    ASSERT_NE(hgbp, nullptr);
+    sp<IGraphicBufferProducer> igbp = new H2BGraphicBufferProducer(hgbp);
+
+    validateIGBP(igbp);
+}
+
+TEST_F(AImageReaderWindowTest, CreateWindow) {
+    ANativeWindow* window = nullptr;
+    media_status_t status = AImageReader_getWindow(imageReader_, &window);
+
+    ASSERT_NE(window, nullptr);
+
+    sp<IGraphicBufferProducer> igbp = Surface::getIGraphicBufferProducer(window);
+
+    validateIGBP(igbp);
+}
+
+class AImageReaderPrivateFormatTest : public ::testing::Test {
+  public:
+    void SetUp() override {
+        auto status = AImageReader_new(kImageWidth, kImageHeight, AIMAGE_FORMAT_RAW_DEPTH,
+                                       kMaxImages, &imgReader);
+        EXPECT_TRUE(status == AMEDIA_OK);
+    }
+
+    void TearDown() override {
+        if (imgReader) {
+            AImageReader_delete(imgReader);
+        }
+    }
+    AImageReader *imgReader = nullptr;
+};
+
+TEST_F(AImageReaderPrivateFormatTest, CreateTest) {
+    EXPECT_TRUE(imgReader != nullptr);
+}
+
+
+}  // namespace android
diff --git a/media/utils/include/mediautils/ExtendedAccumulator.h b/media/utils/include/mediautils/ExtendedAccumulator.h
index 7e3e170..30045f3 100644
--- a/media/utils/include/mediautils/ExtendedAccumulator.h
+++ b/media/utils/include/mediautils/ExtendedAccumulator.h
@@ -48,9 +48,9 @@
 
   public:
     enum class Wrap {
-        NORMAL = 0,
-        UNDERFLOW = 1,
-        OVERFLOW = 2,
+        Normal = 0,
+        Underflow = 1,
+        Overflow = 2,
     };
 
     using UnsignedInt = Integral;
@@ -63,11 +63,11 @@
     std::pair<SignedInt, Wrap> poll(UnsignedInt value) {
         auto acc = mAccumulated.load(std::memory_order_relaxed);
         const auto bottom_bits = static_cast<UnsignedInt>(acc);
-        std::pair<SignedInt, Wrap> res = {0, Wrap::NORMAL};
+        std::pair<SignedInt, Wrap> res = {0, Wrap::Normal};
         const bool overflow = __builtin_sub_overflow(value, bottom_bits, &res.first);
 
         if (overflow) {
-            res.second = (res.first > 0) ? Wrap::OVERFLOW : Wrap::UNDERFLOW;
+            res.second = (res.first > 0) ? Wrap::Overflow : Wrap::Underflow;
         }
 
         const bool acc_overflow = __builtin_add_overflow(acc, res.first, &acc);
diff --git a/media/utils/include/mediautils/StaticStringView.h b/media/utils/include/mediautils/StaticStringView.h
index 14be240..e9a5deb 100644
--- a/media/utils/include/mediautils/StaticStringView.h
+++ b/media/utils/include/mediautils/StaticStringView.h
@@ -21,15 +21,15 @@
 
 #pragma push_macro("EXPLICIT_CONVERSION_GENERATE_OPERATOR")
 #undef EXPLICIT_CONVERSION_GENERATE_OPERATOR
-#define EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, op)               \
-    friend constexpr bool operator op(T lhs, T rhs) {                 \
-        return operator op(static_cast<U>(lhs), static_cast<U>(rhs)); \
-    }                                                                 \
-    friend constexpr bool operator op(T lhs, U rhs) {                 \
-        return operator op(static_cast<U>(lhs), rhs);                 \
-    }                                                                 \
-    friend constexpr bool operator op(U lhs, T rhs) {                 \
-        return operator op(lhs, static_cast<U>(rhs));                 \
+#define EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, op)    \
+    friend constexpr bool operator op(T lhs, T rhs) {      \
+        return static_cast<U>(lhs) op static_cast<U>(rhs); \
+    }                                                      \
+    friend constexpr bool operator op(T lhs, U rhs) {      \
+        return static_cast<U>(lhs) op rhs;                 \
+    }                                                      \
+    friend constexpr bool operator op(U lhs, T rhs) {      \
+        return lhs op static_cast<U>(rhs);                 \
     }
 
 #pragma push_macro("EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS")
diff --git a/media/utils/tests/extended_accumulator_tests.cpp b/media/utils/tests/extended_accumulator_tests.cpp
index e243e7e..2591df0 100644
--- a/media/utils/tests/extended_accumulator_tests.cpp
+++ b/media/utils/tests/extended_accumulator_tests.cpp
@@ -68,10 +68,10 @@
     EXPECT_EQ(result, delta);
 
     // Test overflow/underflow event reporting.
-    if (next < base) EXPECT_EQ(TestDetect::Wrap::UNDERFLOW, status);
+    if (next < base) EXPECT_EQ(TestDetect::Wrap::Underflow, status);
     else if (next > base + std::numeric_limits<TestUInt>::max())
-        EXPECT_EQ(TestDetect::Wrap::OVERFLOW, status);
-    else EXPECT_EQ(TestDetect::Wrap::NORMAL, status);
+        EXPECT_EQ(TestDetect::Wrap::Overflow, status);
+    else EXPECT_EQ(TestDetect::Wrap::Normal, status);
 }
 
 // Test this utility on every combination of prior and update value for the
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index ae60ed0..2577ca8 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -23,6 +23,7 @@
 #include <audio_utils/mutex.h>
 #include <audio_utils/LinearMap.h>
 #include <binder/AppOpsManager.h>
+#include <utils/RWLock.h>
 
 namespace android {
 
@@ -352,6 +353,7 @@
     // Must hold thread lock to access tee patches
     template <class F>
     void                forEachTeePatchTrack_l(F f) {
+        RWLock::AutoRLock readLock(mTeePatchesRWLock);
         for (auto& tp : mTeePatches) { f(tp.patchTrack); }
     };
 
@@ -387,6 +389,7 @@
     audio_output_flags_t mFlags;
     TeePatches mTeePatches;
     std::optional<TeePatches> mTeePatchesToUpdate;
+    RWLock              mTeePatchesRWLock;
     const float         mSpeed;
     const bool          mIsSpatialized;
     const bool          mIsBitPerfect;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 224c65b..4fe5b84 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1081,7 +1081,13 @@
         // Additionally PatchProxyBufferProvider::obtainBuffer (called by PathTrack::getNextBuffer)
         // does not allow 0 frame size request contrary to getNextBuffer
     }
-    for (auto& teePatch : mTeePatches) {
+    TeePatches teePatches;
+    if (mTeePatchesRWLock.tryReadLock() == NO_ERROR) {
+        // Cache a copy of tee patches in case it is updated while using.
+        teePatches = mTeePatches;
+        mTeePatchesRWLock.unlock();
+    }
+    for (auto& teePatch : teePatches) {
         IAfPatchRecord* patchRecord = teePatch.patchRecord.get();
         const size_t framesWritten = patchRecord->writeFrames(
                 sourceBuffer.i8, frameCount, mFrameSize);
@@ -1094,7 +1100,7 @@
     using namespace std::chrono_literals;
     // Average is ~20us per track, this should virtually never be logged (Logging takes >200us)
     ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__,
-             spent.count(), mTeePatches.size());
+             spent.count(), teePatches.size());
 }
 
 // ExtendedAudioBufferProvider interface
@@ -1616,7 +1622,10 @@
 void Track::updateTeePatches_l() {
     if (mTeePatchesToUpdate.has_value()) {
         forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->destroy(); });
-        mTeePatches = mTeePatchesToUpdate.value();
+        {
+            RWLock::AutoWLock writeLock(mTeePatchesRWLock);
+            mTeePatches = std::move(mTeePatchesToUpdate.value());
+        }
         if (mState == TrackBase::ACTIVE || mState == TrackBase::RESUMING ||
                 mState == TrackBase::STOPPING_1) {
             forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->start(); });
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 58e5311..2fd908f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3225,7 +3225,8 @@
         ALOGD("%s: no group matching with %s", __FUNCTION__, toString(attributes).c_str());
         return BAD_VALUE;
     }
-    ALOGV("%s: group %d matching with %s", __FUNCTION__, group, toString(attributes).c_str());
+    ALOGV("%s: group %d matching with %s index %d",
+            __FUNCTION__, group, toString(attributes).c_str(), index);
     status_t status = NO_ERROR;
     IVolumeCurves &curves = getVolumeCurves(attributes);
     VolumeSource vs = toVolumeSource(group);
@@ -3342,6 +3343,21 @@
             status = volStatus;
         }
     }
+
+    // update voice volume if the an active call route exists
+    if (mCallRxSourceClient != nullptr && mCallRxSourceClient->isConnected()
+            && (curSrcDevices.find(
+                Volume::getDeviceForVolume({mCallRxSourceClient->sinkDevice()->type()}))
+                != curSrcDevices.end())) {
+        bool isVoiceVolSrc;
+        bool isBtScoVolSrc;
+        if (isVolumeConsistentForCalls(vs, {mCallRxSourceClient->sinkDevice()->type()},
+                isVoiceVolSrc, isBtScoVolSrc, __func__)
+                && (isVoiceVolSrc || isBtScoVolSrc)) {
+            setVoiceVolume(index, curves, isVoiceVolSrc, 0);
+        }
+    }
+
     mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
     return status;
 }
@@ -7815,26 +7831,16 @@
                outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
         return NO_ERROR;
     }
-    VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL, false);
-    VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO, false);
-    bool isVoiceVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (callVolSrc == volumeSource);
-    bool isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (btScoVolSrc == volumeSource);
 
-    bool isScoRequested = isScoRequestedForComm();
-    bool isHAUsed = isHearingAidUsedForComm();
-
-    // do not change in call volume if bluetooth is connected and vice versa
-    // if sco and call follow same curves, bypass forceUseForComm
-    if ((callVolSrc != btScoVolSrc) &&
-            ((isVoiceVolSrc && isScoRequested) ||
-             (isBtScoVolSrc && !(isScoRequested || isHAUsed))) &&
-            !isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
-        ALOGV("%s cannot set volume group %d volume when is%srequested for comm", __func__,
-             volumeSource, isScoRequested ? " " : " not ");
+    bool isVoiceVolSrc;
+    bool isBtScoVolSrc;
+    if (!isVolumeConsistentForCalls(
+            volumeSource, deviceTypes, isVoiceVolSrc, isBtScoVolSrc, __func__)) {
         // Do not return an error here as AudioService will always set both voice call
-        // and bluetooth SCO volumes due to stream aliasing.
+        // and Bluetooth SCO volumes due to stream aliasing.
         return NO_ERROR;
     }
+
     if (deviceTypes.empty()) {
         deviceTypes = outputDesc->devices().types();
         index = curves.getVolumeIndex(deviceTypes);
@@ -7859,21 +7865,51 @@
             deviceTypes, delayMs, force, isVoiceVolSrc);
 
     if (outputDesc == mPrimaryOutput && (isVoiceVolSrc || isBtScoVolSrc)) {
-        float voiceVolume;
-        // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed by the headset
-        if (isVoiceVolSrc) {
-            voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
-        } else {
-            voiceVolume = index == 0 ? 0.0 : 1.0;
-        }
-        if (voiceVolume != mLastVoiceVolume) {
-            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
-            mLastVoiceVolume = voiceVolume;
-        }
+        setVoiceVolume(index, curves, isVoiceVolSrc, delayMs);
     }
     return NO_ERROR;
 }
 
+void AudioPolicyManager::setVoiceVolume(
+        int index, IVolumeCurves &curves, bool isVoiceVolSrc, int delayMs) {
+    float voiceVolume;
+    // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed
+    // by the headset
+    if (isVoiceVolSrc) {
+        voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
+    } else {
+        voiceVolume = index == 0 ? 0.0 : 1.0;
+    }
+    if (voiceVolume != mLastVoiceVolume) {
+        mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+        mLastVoiceVolume = voiceVolume;
+    }
+}
+
+bool AudioPolicyManager::isVolumeConsistentForCalls(VolumeSource volumeSource,
+                                                   const DeviceTypeSet& deviceTypes,
+                                                   bool& isVoiceVolSrc,
+                                                   bool& isBtScoVolSrc,
+                                                   const char* caller) {
+    const VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL, false);
+    const VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO, false);
+    const bool isScoRequested = isScoRequestedForComm();
+    const bool isHAUsed = isHearingAidUsedForComm();
+
+    isVoiceVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (callVolSrc == volumeSource);
+    isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (btScoVolSrc == volumeSource);
+
+    if ((callVolSrc != btScoVolSrc) &&
+            ((isVoiceVolSrc && isScoRequested) ||
+             (isBtScoVolSrc && !(isScoRequested || isHAUsed))) &&
+            !isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
+        ALOGV("%s cannot set volume group %d volume when is%srequested for comm", caller,
+             volumeSource, isScoRequested ? " " : " not ");
+        return false;
+    }
+    return true;
+}
+
 void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
                                             const DeviceTypeSet& deviceTypes,
                                             int delayMs,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 5b9f6ad..8f8550c 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -575,6 +575,20 @@
                                            DeviceTypeSet deviceTypes,
                                            int delayMs = 0, bool force = false);
 
+        void setVoiceVolume(int index, IVolumeCurves &curves, bool isVoiceVolSrc, int delayMs);
+
+        // returns true if the supplied set of volume source and devices are consistent with
+        // call volume rules:
+        // if Bluetooth SCO and voice call use different volume curves:
+        // - do not apply voice call volume if Bluetooth SCO is used for call
+        // - do not apply Bluetooth SCO volume if SCO or Hearing Aid is not used for call.
+        // Also updates the booleans isVoiceVolSrc and isBtScoVolSrc according to the
+        // volume source supplied.
+        bool isVolumeConsistentForCalls(VolumeSource volumeSource,
+                                       const DeviceTypeSet& deviceTypes,
+                                       bool& isVoiceVolSrc,
+                                       bool& isBtScoVolSrc,
+                                       const char* caller);
         // apply all stream volumes to the specified output and device
         void applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
                                 const DeviceTypeSet& deviceTypes,
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index a2f17c2..506b3bc 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -95,31 +95,6 @@
         "android.hidl.memory@1.0",
     ],
 
-    runtime_libs: [
-        "libstagefright_soft_aacdec",
-        "libstagefright_soft_aacenc",
-        "libstagefright_soft_amrdec",
-        "libstagefright_soft_amrnbenc",
-        "libstagefright_soft_amrwbenc",
-        "libstagefright_soft_avcdec",
-        "libstagefright_soft_avcenc",
-        "libstagefright_soft_flacdec",
-        "libstagefright_soft_flacenc",
-        "libstagefright_soft_g711dec",
-        "libstagefright_soft_gsmdec",
-        "libstagefright_soft_hevcdec",
-        "libstagefright_soft_mp3dec",
-        "libstagefright_soft_mpeg2dec",
-        "libstagefright_soft_mpeg4dec",
-        "libstagefright_soft_mpeg4enc",
-        "libstagefright_soft_opusdec",
-        "libstagefright_soft_rawdec",
-        "libstagefright_soft_vorbisdec",
-        "libstagefright_soft_vpxdec",
-        "libstagefright_soft_vpxenc",
-        "libstagefright_softomx_plugin",
-    ],
-
     // OMX interfaces force this to stay in 32-bit mode;
     compile_multilib: "32",
 
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
index a55c3eb..0c6aafd 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
@@ -52,6 +52,9 @@
 getdents64: 1
 ppoll: 1
 
+clock_gettime: 1
+pipe2: 1
+
 # Required by AddressSanitizer
 gettid: 1
 sched_yield: 1
diff --git a/tools/mainline_hook_partial.sh b/tools/mainline_hook_partial.sh
index cd3e579..63ae4c0 100755
--- a/tools/mainline_hook_partial.sh
+++ b/tools/mainline_hook_partial.sh
Binary files differ
diff --git a/tools/mainline_hook_project.sh b/tools/mainline_hook_project.sh
index 1cc3b2b..d58143e 100755
--- a/tools/mainline_hook_project.sh
+++ b/tools/mainline_hook_project.sh
@@ -16,8 +16,8 @@
 
 
 # tunables
-DEV_BRANCH=master
-MAINLINE_BRANCH=tm-mainline-prod
+DEV_BRANCH=main
+MAINLINE_BRANCH=udc-mainline-prod
 
 ###
 RED=$(tput setaf 1)