Merge "NdkMedia: fix android.mediav2.cts.CodecEncoderSurfaceTest failed." into main
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Android.bp b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
index eaf5051..0b0d46a 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
@@ -8,21 +8,7 @@
 }
 
 cc_defaults {
-    name: "aidl_clearkey_service_defaults",
-    vendor: true,
-
-    srcs: [
-        "CreatePluginFactories.cpp",
-        "CryptoPlugin.cpp",
-        "DrmFactory.cpp",
-        "DrmPlugin.cpp",
-    ],
-
-    relative_install_path: "hw",
-
-    cflags: ["-Wall", "-Werror", "-Wthread-safety"],
-
-    include_dirs: ["frameworks/av/include"],
+    name: "aidl_clearkey_service_defaults-use-shared-deps",
 
     shared_libs: [
         "libbase",
@@ -39,6 +25,46 @@
         "libclearkeybase",
         "libjsoncpp",
     ],
+}
+
+cc_defaults {
+    name: "aidl_clearkey_service_defaults-use-static-deps",
+
+    stl: "c++_static",
+
+    shared_libs: [
+        "libbinder_ndk",
+        "libcrypto",
+        "liblog",
+    ],
+
+    static_libs: [
+        "android.hardware.common-V2-ndk",
+        "android.hardware.drm-V1-ndk",
+        "libbase",
+        "libclearkeybase",
+        "libjsoncpp",
+        "libprotobuf-cpp-lite",
+        "libutils",
+    ],
+}
+
+cc_defaults {
+    name: "aidl_clearkey_service_defaults",
+    vendor: true,
+
+    srcs: [
+        "CreatePluginFactories.cpp",
+        "CryptoPlugin.cpp",
+        "DrmFactory.cpp",
+        "DrmPlugin.cpp",
+    ],
+
+    relative_install_path: "hw",
+
+    cflags: ["-Wall", "-Werror", "-Wthread-safety"],
+
+    include_dirs: ["frameworks/av/include"],
 
     local_include_dirs: ["include"],
 
@@ -49,7 +75,10 @@
 
 cc_binary {
     name: "android.hardware.drm-service.clearkey",
-    defaults: ["aidl_clearkey_service_defaults"],
+    defaults: [
+        "aidl_clearkey_service_defaults",
+        "aidl_clearkey_service_defaults-use-shared-deps",
+    ],
     srcs: ["Service.cpp"],
     init_rc: ["android.hardware.drm-service.clearkey.rc"],
     vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
@@ -57,17 +86,31 @@
 
 cc_binary {
     name: "android.hardware.drm-service-lazy.clearkey",
-    defaults: ["aidl_clearkey_service_defaults"],
+    defaults: [
+        "aidl_clearkey_service_defaults",
+        "aidl_clearkey_service_defaults-use-shared-deps",
+    ],
     overrides: ["android.hardware.drm-service.clearkey"],
     srcs: ["ServiceLazy.cpp"],
     init_rc: ["android.hardware.drm-service-lazy.clearkey.rc"],
     vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
 }
 
+cc_binary {
+    name: "android.hardware.drm-service.clearkey.apex",
+    stem: "android.hardware.drm-service.clearkey",
+    defaults: [
+        "aidl_clearkey_service_defaults",
+        "aidl_clearkey_service_defaults-use-static-deps",
+    ],
+    srcs: ["Service.cpp"],
+    installable: false, // installed in APEX
+}
+
 phony {
     name: "android.hardware.drm@latest-service.clearkey",
     required: [
-        "android.hardware.drm-service.clearkey",
+        "com.android.hardware.drm.clearkey",
     ],
 }
 
@@ -123,3 +166,34 @@
         ],
     },
 }
+
+apex {
+    name: "com.android.hardware.drm.clearkey",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.android.hardware.key",
+    certificate: ":com.android.hardware.certificate",
+    vendor: true,
+    updatable: false,
+
+    binaries: [
+        "android.hardware.drm-service.clearkey.apex",
+    ],
+    prebuilts: [
+        "android.hardware.drm-service.clearkey.apex.rc",
+        "android.hardware.drm-service.clearkey.xml"
+    ],
+}
+
+prebuilt_etc {
+    name: "android.hardware.drm-service.clearkey.apex.rc",
+    src: "android.hardware.drm-service.clearkey.apex.rc",
+    installable: false,
+}
+
+prebuilt_etc {
+    name: "android.hardware.drm-service.clearkey.xml",
+    src: "android.hardware.drm-service.clearkey.xml",
+    sub_dir: "vintf",
+    installable: false,
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.apex.rc b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.apex.rc
new file mode 100644
index 0000000..f4645b3
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.apex.rc
@@ -0,0 +1,7 @@
+service vendor.drm-clearkey-service /apex/com.android.hardware.drm.clearkey/bin/hw/android.hardware.drm-service.clearkey
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    task_profiles ProcessCapacityHigh
+    interface aidl android.hardware.drm.IDrmFactory/clearkey
diff --git a/drm/mediadrm/plugins/clearkey/aidl/file_contexts b/drm/mediadrm/plugins/clearkey/aidl/file_contexts
new file mode 100644
index 0000000..e9e6ca2
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.drm-service(-lazy)?\.clearkey    u:object_r:hal_drm_clearkey_aidl_exec:s0
diff --git a/drm/mediadrm/plugins/clearkey/aidl/manifest.json b/drm/mediadrm/plugins/clearkey/aidl/manifest.json
new file mode 100644
index 0000000..369dc21
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.hardware.drm.clearkey",
+  "version": 1
+}
diff --git a/media/aconfig/Android.bp b/media/aconfig/Android.bp
new file mode 100644
index 0000000..4b489e2
--- /dev/null
+++ b/media/aconfig/Android.bp
@@ -0,0 +1,16 @@
+aconfig_declarations {
+    name: "aconfig_mediacodec_flags",
+    package: "com.android.media.codec.flags",
+    srcs: ["mediacodec_flags.aconfig"],
+}
+
+java_aconfig_library {
+    name: "aconfig_mediacodec_flags_java_lib",
+    aconfig_declarations: "aconfig_mediacodec_flags",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+cc_aconfig_library {
+    name: "aconfig_mediacodec_flags_c_lib",
+    aconfig_declarations: "aconfig_mediacodec_flags",
+}
diff --git a/media/aconfig/mediacodec_flags.aconfig b/media/aconfig/mediacodec_flags.aconfig
new file mode 100644
index 0000000..67ba3e5
--- /dev/null
+++ b/media/aconfig/mediacodec_flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.media.codec.flags"
+
+flag {
+  name: "large_audio_frame"
+  namespace: "codec_fwk"
+  description: "Feature flags for large audio frame support"
+  bug: "297219557"
+}
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
index b968c39..a6a6b77 100644
--- a/media/codec2/hal/aidl/Android.bp
+++ b/media/codec2/hal/aidl/Android.bp
@@ -6,6 +6,7 @@
 // use libcodec2-aidl-client-defaults instead
 cc_library {
     name: "libcodec2_aidl_client",
+    min_sdk_version: "31",
 
     srcs: [
         "BufferTypes.cpp",
@@ -53,8 +54,8 @@
 // use libcodec2-aidl-defaults instead
 cc_library {
     name: "libcodec2_aidl",
+    min_sdk_version: "31",
     vendor_available: true,
-    min_sdk_version: "34",
     apex_available: [
         "//apex_available:platform",
         "com.android.media.swcodec",
@@ -131,11 +132,12 @@
 // public dependency for Codec 2.0 HAL service implementations
 cc_defaults {
     name: "libcodec2-aidl-defaults",
-    min_sdk_version: "34",
+    min_sdk_version: "31",
     defaults: ["libcodec2-impl-defaults"],
 
     shared_libs: [
         "android.hardware.media.c2-V1-ndk",
+        "libbinder_ndk",
         "libcodec2_aidl",
     ],
 }
@@ -143,7 +145,7 @@
 // public dependency for Codec 2.0 HAL client
 cc_defaults {
     name: "libcodec2-aidl-client-defaults",
-    min_sdk_version: "34",
+    min_sdk_version: "31",
     defaults: ["libcodec2-impl-defaults"],
 
     shared_libs: [
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
index fa18c3e..9c21a5b 100644
--- a/media/codec2/hal/aidl/Component.cpp
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -301,7 +301,7 @@
     switch (allocator.getTag()) {
         case ALLOCATOR_ID:
 #ifdef __ANDROID_APEX__
-            status = CreateCodec2BlockPool(
+            status = ::android::CreateCodec2BlockPool(
                     static_cast<::android::C2PlatformAllocatorStore::id_t>(
                             allocator.get<ALLOCATOR_ID>()),
                     mComponent,
@@ -405,18 +405,22 @@
 }
 
 void Component::initListener(const std::shared_ptr<Component>& self) {
-    std::shared_ptr<C2Component::Listener> c2listener =
-            std::make_shared<Listener>(self);
-    c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
-    if (res != C2_OK) {
-        mInit = res;
-    }
+    if (__builtin_available(android __ANDROID_API_T__, *)) {
+        std::shared_ptr<C2Component::Listener> c2listener =
+                std::make_shared<Listener>(self);
+        c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
+        if (res != C2_OK) {
+            mInit = res;
+        }
 
-    mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(
-            AIBinder_DeathRecipient_new(OnBinderDied));
-    mDeathContext = new DeathContext{weak_from_this()};
-    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), OnBinderUnlinked);
-    AIBinder_linkToDeath(mListener->asBinder().get(), mDeathRecipient.get(), mDeathContext);
+        mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(
+                AIBinder_DeathRecipient_new(OnBinderDied));
+        mDeathContext = new DeathContext{weak_from_this()};
+        AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), OnBinderUnlinked);
+        AIBinder_linkToDeath(mListener->asBinder().get(), mDeathRecipient.get(), mDeathContext);
+    } else {
+        mInit = C2_NO_INIT;
+    }
 }
 
 // static
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index 19734c0..2489683 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -51,8 +51,11 @@
 namespace c2 {
 namespace utils {
 
+#ifndef __ANDROID_APEX__
 using ::android::DefaultFilterPlugin;
 using ::android::FilterWrapper;
+#endif
+
 using ::ndk::ScopedAStatus;
 
 namespace /* unnamed */ {
diff --git a/media/codec2/hal/client/GraphicBufferAllocator.cpp b/media/codec2/hal/client/GraphicBufferAllocator.cpp
index bbef1b5..7045537 100644
--- a/media/codec2/hal/client/GraphicBufferAllocator.cpp
+++ b/media/codec2/hal/client/GraphicBufferAllocator.cpp
@@ -62,14 +62,12 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus GraphicBufferAllocator::getWaitableFds(
-        IGraphicBufferAllocator::WaitableFds* _aidl_return) {
-    int allocFd;
-    int statusFd;
-    c2_status_t ret = mGraphicsTracker->getWaitableFds(&allocFd, &statusFd);
+::ndk::ScopedAStatus GraphicBufferAllocator::getWaitableFd(
+        ::ndk::ScopedFileDescriptor* _aidl_return) {
+    int pipeFd;
+    c2_status_t ret = mGraphicsTracker->getWaitableFd(&pipeFd);
     if (ret == C2_OK) {
-        _aidl_return->allocEvent.set(allocFd);
-        _aidl_return->statusEvent.set(statusFd);
+        _aidl_return->set(pipeFd);
         return ::ndk::ScopedAStatus::ok();
     }
     return ::ndk::ScopedAStatus::fromServiceSpecificError(ret);
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 5a2cb86..2424f7b 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -13,7 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <sys/eventfd.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <private/android/AHardwareBufferHelpers.h>
@@ -25,6 +26,9 @@
 
 namespace {
 
+static constexpr int kMaxDequeueMin = 1;
+static constexpr int kMaxDequeueMax = ::android::BufferQueueDefs::NUM_BUFFER_SLOTS - 2;
+
 c2_status_t retrieveAHardwareBufferId(const C2ConstGraphicBlock &blk, uint64_t *bid) {
     // TODO
     (void)blk;
@@ -139,21 +143,26 @@
     mDequeueable{maxDequeueCount},
     mTotalDequeued{0}, mTotalCancelled{0}, mTotalDropped{0}, mTotalReleased{0},
     mInConfig{false}, mStopped{false} {
-    if (maxDequeueCount <= 0) {
-        mMaxDequeue = kDefaultMaxDequeue;
-        mMaxDequeueRequested = kDefaultMaxDequeue;
-        mMaxDequeueCommitted = kDefaultMaxDequeue;
-        mDequeueable = kDefaultMaxDequeue;
+    if (maxDequeueCount < kMaxDequeueMin) {
+        mMaxDequeue = kMaxDequeueMin;
+        mMaxDequeueRequested = kMaxDequeueMin;
+        mMaxDequeueCommitted = kMaxDequeueMin;
+        mDequeueable = kMaxDequeueMin;
+    } else if(maxDequeueCount > kMaxDequeueMax) {
+        mMaxDequeue = kMaxDequeueMax;
+        mMaxDequeueRequested = kMaxDequeueMax;
+        mMaxDequeueCommitted = kMaxDequeueMax;
+        mDequeueable = kMaxDequeueMax;
     }
-    int allocEventFd = ::eventfd(mDequeueable, EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE);
-    int statusEventFd = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+    int pipefd[2] = { -1, -1};
+    int ret = ::pipe2(pipefd, O_CLOEXEC | O_NONBLOCK);
 
-    mAllocEventFd.reset(allocEventFd);
-    mStopEventFd.reset(statusEventFd);
+    mReadPipeFd.reset(pipefd[0]);
+    mWritePipeFd.reset(pipefd[1]);
 
     mEventQueueThread = std::thread([this](){processEvent();});
 
-    CHECK(allocEventFd >= 0 && statusEventFd >= 0);
+    CHECK(ret >= 0);
     CHECK(mEventQueueThread.joinable());
 }
 
@@ -161,7 +170,6 @@
     stop();
     if (mEventQueueThread.joinable()) {
         std::unique_lock<std::mutex> l(mEventLock);
-        mStopEventThread = true;
         l.unlock();
         mEventCv.notify_one();
         mEventQueueThread.join();
@@ -231,6 +239,11 @@
 c2_status_t GraphicsTracker::configureMaxDequeueCount(int maxDequeueCount) {
     std::shared_ptr<BufferCache> cache;
 
+    if (maxDequeueCount < kMaxDequeueMin || maxDequeueCount > kMaxDequeueMax) {
+        ALOGE("max dequeue count %d is not valid", maxDequeueCount);
+        return C2_BAD_VALUE;
+    }
+
     // max dequeue count which can be committed to IGBP.
     // (Sometimes maxDequeueCount cannot be committed if the number of
     // dequeued buffer count is bigger.)
@@ -347,89 +360,76 @@
 
 void GraphicsTracker::stop() {
     bool expected = false;
+    std::unique_lock<std::mutex> l(mEventLock);
     bool updated = mStopped.compare_exchange_strong(expected, true);
     if (updated) {
-        uint64_t val = 1ULL;
-        int ret = ::write(mStopEventFd.get(), &val, 8);
-        if (ret < 0) {
-            // EINTR maybe
-            std::unique_lock<std::mutex> l(mEventLock);
-            mStopRequest = true;
-            l.unlock();
-            mEventCv.notify_one();
-            ALOGW("stop() status update pending");
-        }
+        int writeFd = mWritePipeFd.release();
+        ::close(writeFd);
     }
 }
 
 void GraphicsTracker::writeIncDequeueable(int inc) {
-    uint64_t val = inc;
-    int ret = ::write(mAllocEventFd.get(), &val, 8);
-    if (ret < 0) {
-        // EINTR due to signal handling maybe, this should be rare
+    CHECK(inc > 0 && inc < kMaxDequeueMax);
+    thread_local char buf[kMaxDequeueMax];
+    int diff = 0;
+    {
         std::unique_lock<std::mutex> l(mEventLock);
-        mIncDequeueable += inc;
-        l.unlock();
-        mEventCv.notify_one();
-        ALOGW("updating dequeueable to eventfd pending");
+        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");
+        }
     }
 }
 
 void GraphicsTracker::processEvent() {
-    // This is for write() failure of eventfds.
-    // write() failure other than EINTR should not happen.
-    int64_t acc = 0;
-    bool stopRequest = false;
-    bool stopCommitted = false;
-
+    // This is for partial/failed writes to the writing end.
+    // This may not happen in the real scenario.
+    thread_local char buf[kMaxDequeueMax];
     while (true) {
-        {
-            std::unique_lock<std::mutex> l(mEventLock);
-            acc += mIncDequeueable;
-            mIncDequeueable = 0;
-            stopRequest |= mStopRequest;
-            mStopRequest = false;
-            if (acc == 0 && stopRequest == stopCommitted) {
-                if (mStopEventThread) {
-                    break;
+        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);
                 }
-                mEventCv.wait(l);
                 continue;
             }
         }
-
-        if (acc > 0) {
-            int ret = ::write(mAllocEventFd.get(), &acc, 8);
-            if (ret > 0) {
-                acc = 0;
-            }
-        }
-        if (stopRequest && !stopCommitted) {
-            uint64_t val = 1ULL;
-            int ret = ::write(mStopEventFd.get(), &val, 8);
-            if (ret > 0) {
-                stopCommitted = true;
-            }
-        }
-        if (mStopEventThread) {
-            break;
-        }
+        mEventCv.wait(l);
     }
 }
 
-c2_status_t GraphicsTracker::getWaitableFds(int *allocFd, int *statusFd) {
-    *allocFd = ::dup(mAllocEventFd.get());
-    *statusFd = ::dup(mStopEventFd.get());
-
-    if (*allocFd < 0 || *statusFd < 0) {
-        if (*allocFd >= 0) {
-            ::close(*allocFd);
-            *allocFd = -1;
+c2_status_t GraphicsTracker::getWaitableFd(int *pipeFd) {
+    *pipeFd = ::dup(mReadPipeFd.get());
+    if (*pipeFd < 0) {
+        if (mReadPipeFd.get() < 0) {
+            return C2_BAD_STATE;
         }
-        if (*statusFd >= 0) {
-            ::close(*statusFd);
-            *statusFd = -1;
-        }
+        // dup error
+        ALOGE("dup() for the reading end failed %d", errno);
         return C2_NO_MEMORY;
     }
     return C2_OK;
@@ -438,8 +438,8 @@
 c2_status_t GraphicsTracker::requestAllocate(std::shared_ptr<BufferCache> *cache) {
     std::lock_guard<std::mutex> l(mLock);
     if (mDequeueable > 0) {
-        uint64_t val;
-        int ret = ::read(mAllocEventFd.get(), &val, 8);
+        char buf[1];
+        int ret = ::read(mReadPipeFd.get(), buf, 1);
         if (ret < 0) {
             if (errno == EINTR) {
                 // Do we really need to care for cancel due to signal handling?
@@ -452,6 +452,10 @@
             }
             CHECK(errno != 0);
         }
+        if (ret == 0) {
+            // writing end is closed
+            return C2_BAD_STATE;
+        }
         mDequeueable--;
         *cache = mBufferCache;
         return C2_OK;
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index accb9fd..e3f8b1c 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -1953,7 +1953,8 @@
         std::shared_ptr<Codec2Client::Configurable>* configurable) {
     if (mAidlBase) {
         c2_aidl::IComponent::BlockPool aidlBlockPool;
-        ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(id, &aidlBlockPool);
+        ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(static_cast<int32_t>(id),
+                                                                      &aidlBlockPool);
         c2_status_t status = GetC2Status(transStatus, "createBlockPool");
         if (status != C2_OK) {
             return status;
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
index f9c8aca..902c53f 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
@@ -38,8 +38,8 @@
 
     ::ndk::ScopedAStatus deallocate(int64_t in_id, bool* _aidl_return) override;
 
-    ::ndk::ScopedAStatus getWaitableFds(
-            IGraphicBufferAllocator::WaitableFds* _aidl_return) override;
+    ::ndk::ScopedAStatus getWaitableFd(
+            ::ndk::ScopedFileDescriptor* _aidl_return) override;
 
     /**
      * Configuring Surface/BufferQueue for the interface.
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
index 681b7e8..1fd9049 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -142,15 +142,15 @@
     void onReleased(uint32_t generation);
 
     /**
-     * Get waitable fds for events.(allocate is ready, end of life cycle)
+     * Get waitable fd for events.(allocate is ready, end of life cycle)
      *
-     * @param[out]  allocFd     eventFd which signals being ready to allocate
-     * @param[out]  statusFd    eventFd which signals end of life cycle.
-     *                          When signaled no more allocate is possible.
+     * @param[out]  pipeFd      a file descriptor created from pipe2()
+     *                          in order for notifying being ready to allocate
+     *
      * @return  C2_OK
      *          C2_NO_MEMORY    Max # of fd reached.(not really a memory issue)
      */
-    c2_status_t getWaitableFds(int *allocFd, int *statusFd);
+    c2_status_t getWaitableFd(int *pipeFd);
 
     /**
      *  Ends to use the class. after the call, allocate will fail.
@@ -158,8 +158,6 @@
     void stop();
 
 private:
-    static constexpr int kDefaultMaxDequeue = 2;
-
     struct BufferCache;
 
     struct BufferItem {
@@ -246,21 +244,30 @@
     std::mutex mLock; // locks for data synchronization
     std::mutex mConfigLock; // locks for configuration change.
 
+    // NOTE: pipe2() creates two file descriptors for allocatable events
+    // and irrecoverable error events notification.
+    //
+    // A byte will be written to the writing end whenever a buffer is ready to
+    // dequeue/allocate. A byte will be read from the reading end whenever
+    // an allocate/dequeue event happens.
+    //
+    // The writing end will be closed when the end-of-lifecycle event was met.
+    //
+    // The reading end will be shared to the remote processes. Remote processes
+    // use ::poll() to check whether a buffer is ready to allocate/ready.
+    // Also ::poll() will let remote processes know the end-of-lifecycle event
+    // by returning POLLHUP event from the reading end.
+    ::android::base::unique_fd mReadPipeFd;   // The reading end file descriptor
+    ::android::base::unique_fd mWritePipeFd;  // The writing end file descriptor
+
     std::atomic<bool> mStopped;
-
-    ::android::base::unique_fd mAllocEventFd; // eventfd in semaphore mode which
-                                              // mirrors mDqueueable.
-    ::android::base::unique_fd mStopEventFd; // eventfd which indicates the life
-                                             // cycle of the class being stopped.
-
     std::thread mEventQueueThread; // Thread to handle interrupted
-                                   // writes to eventfd{s}.
+                                   // writes to the writing end.
     std::mutex mEventLock;
     std::condition_variable mEventCv;
 
     bool mStopEventThread;
     int mIncDequeueable; // pending # of write to increase dequeueable eventfd
-    bool mStopRequest; // pending write to statusfd
 
 private:
     explicit GraphicsTracker(int maxDequeueCount);
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 8305feb..db68b96 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
@@ -500,7 +500,7 @@
     description("Encodes input file");
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    bool signalEOS = std::get<3>(GetParam());
+    bool signalEOS = std::get<2>(GetParam());
     // Send an empty frame to receive CSD data from encoder.
     bool sendEmptyFirstFrame = std::get<3>(GetParam());
     mConfigBPictures = std::get<4>(GetParam());
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 385912a..22c4aee 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -2128,8 +2128,15 @@
 
     if (notifyClient && !buffer && !flags) {
         if (mTunneled && drop && outputFormat) {
-            ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
-                  mName, work->input.ordinal.frameIndex.peekull());
+            if (mOutputFormat != outputFormat) {
+                ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
+                      mName, work->input.ordinal.frameIndex.peekull());
+                mOutputFormat = outputFormat;
+            } else {
+                ALOGV("[%s] onWorkDone: Not reporting output buffer without format change (%lld)",
+                      mName, work->input.ordinal.frameIndex.peekull());
+                notifyClient = false;
+            }
         } else {
             ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
                   mName, work->input.ordinal.frameIndex.peekull());
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 763eae9..a37c383 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -301,6 +301,7 @@
     std::shared_ptr<C2BlockPool> mInputAllocator;
     QueueSync mQueueSync;
     std::vector<std::unique_ptr<C2Param>> mParamsToBeSet;
+    sp<AMessage> mOutputFormat;
 
     struct Input {
         Input();
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 0803dc3..fef465a 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -319,6 +319,450 @@
     return C2_OK;
 }
 
+static c2_status_t PopulatePlaneLayout(
+        buffer_handle_t buffer,
+        const Rect &rect,
+        uint32_t format,
+        uint64_t grallocUsage,
+        uint32_t stride,
+        C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+    // 'NATIVE' on Android means LITTLE_ENDIAN
+    constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE;
+
+    // Try to resolve IMPLEMENTATION_DEFINED format to accurate format if
+    // possible.
+    uint32_t fourCc;
+    if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
+        !GraphicBufferMapper::get().getPixelFormatFourCC(buffer, &fourCc)) {
+        switch (fourCc)  {
+            case DRM_FORMAT_XBGR8888:
+                 format = static_cast<uint32_t>(PixelFormat4::RGBX_8888);
+                 break;
+            case DRM_FORMAT_ABGR8888:
+                 format = static_cast<uint32_t>(PixelFormat4::RGBA_8888);
+                 break;
+            default:
+                 break;
+        }
+    }
+
+    switch (format) {
+        case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
+            // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
+            // Surface. In all other cases it is RGBA. We don't know which case it is here, so
+            // default to YUV for now.
+            void *pointer = nullptr;
+            // TODO: fence
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(RGBA_1010102)");
+                return C2_CORRUPTED;
+            }
+            // treat as 32-bit values
+            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_V] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_A] = (uint8_t *)pointer;
+            layout->type = C2PlanarLayout::TYPE_YUVA;
+            layout->numPlanes = 4;
+            layout->rootPlanes = 1;
+            layout->planes[C2PlanarLayout::PLANE_Y] = {
+                C2PlaneInfo::CHANNEL_Y,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                32,                             // allocatedDepth
+                10,                             // bitDepth
+                10,                             // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_U] = {
+                C2PlaneInfo::CHANNEL_CB,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                32,                             // allocatedDepth
+                10,                             // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_V] = {
+                C2PlaneInfo::CHANNEL_CR,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                32,                             // allocatedDepth
+                10,                             // bitDepth
+                20,                             // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_A] = {
+                C2PlaneInfo::CHANNEL_A,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                32,                             // allocatedDepth
+                2,                              // bitDepth
+                30,                             // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            break;
+        }
+
+        case static_cast<uint32_t>(PixelFormat4::RGBA_8888):
+            // TODO: alpha channel
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::RGBX_8888): {
+            void *pointer = nullptr;
+            // TODO: fence
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(RGBA_8888)");
+                return C2_CORRUPTED;
+            }
+            addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
+            addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
+            layout->type = C2PlanarLayout::TYPE_RGB;
+            layout->numPlanes = 3;
+            layout->rootPlanes = 1;
+            layout->planes[C2PlanarLayout::PLANE_R] = {
+                C2PlaneInfo::CHANNEL_R,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_G] = {
+                C2PlaneInfo::CHANNEL_G,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                1,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_B] = {
+                C2PlaneInfo::CHANNEL_B,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                2,                              // offset
+            };
+            break;
+        }
+
+        case static_cast<uint32_t>(PixelFormat4::BLOB): {
+            void *pointer = nullptr;
+            // TODO: fence
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(BLOB)");
+                return C2_CORRUPTED;
+            }
+            *addr = (uint8_t *)pointer;
+            break;
+        }
+
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YV12): {
+            android_ycbcr ycbcrLayout;
+
+            status_t err = GraphicBufferMapper::get().lockYCbCr(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, &ycbcrLayout);
+            if (err) {
+                ALOGE("failed transaction: lockYCbCr (err=%d)", err);
+                return C2_CORRUPTED;
+            }
+            if (!ycbcrLayout.y || !ycbcrLayout.cb || !ycbcrLayout.cr
+                    || ycbcrLayout.ystride == 0
+                    || ycbcrLayout.cstride == 0
+                    || ycbcrLayout.chroma_step == 0) {
+                ALOGE("invalid layout: lockYCbCr (y=%s cb=%s cr=%s "
+                        "ystride=%zu cstride=%zu chroma_step=%zu)",
+                        ycbcrLayout.y ? "(non-null)" : "(null)",
+                        ycbcrLayout.cb ? "(non-null)" : "(null)",
+                        ycbcrLayout.cr ? "(non-null)" : "(null)",
+                        ycbcrLayout.ystride, ycbcrLayout.cstride, ycbcrLayout.chroma_step);
+                return C2_CORRUPTED;
+            }
+
+            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+            addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+            layout->type = C2PlanarLayout::TYPE_YUV;
+            layout->numPlanes = 3;
+            layout->rootPlanes = 3;
+            layout->planes[C2PlanarLayout::PLANE_Y] = {
+                C2PlaneInfo::CHANNEL_Y,         // channel
+                1,                              // colInc
+                (int32_t)ycbcrLayout.ystride,   // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_U] = {
+                C2PlaneInfo::CHANNEL_CB,          // channel
+                (int32_t)ycbcrLayout.chroma_step, // colInc
+                (int32_t)ycbcrLayout.cstride,     // rowInc
+                2,                                // mColSampling
+                2,                                // mRowSampling
+                8,                                // allocatedDepth
+                8,                                // bitDepth
+                0,                                // rightShift
+                C2PlaneInfo::NATIVE,              // endianness
+                C2PlanarLayout::PLANE_U,          // rootIx
+                0,                                // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_V] = {
+                C2PlaneInfo::CHANNEL_CR,          // channel
+                (int32_t)ycbcrLayout.chroma_step, // colInc
+                (int32_t)ycbcrLayout.cstride,     // rowInc
+                2,                                // mColSampling
+                2,                                // mRowSampling
+                8,                                // allocatedDepth
+                8,                                // bitDepth
+                0,                                // rightShift
+                C2PlaneInfo::NATIVE,              // endianness
+                C2PlanarLayout::PLANE_V,          // rootIx
+                0,                                // offset
+            };
+            break;
+        }
+
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
+            // In Android T, P010 is relaxed to allow arbitrary stride for the Y and UV planes,
+            // try locking with the gralloc4 mapper first.
+            c2_status_t status = Gralloc4Mapper_lock(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, layout, addr);
+            if (status == C2_OK) {
+                break;
+            }
+
+            void *pointer = nullptr;
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(YCBCR_P010)");
+                return C2_CORRUPTED;
+            }
+            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + stride * 2 * rect.height();
+            addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2;
+            layout->type = C2PlanarLayout::TYPE_YUV;
+            layout->numPlanes = 3;
+            layout->rootPlanes = 2;
+            layout->planes[C2PlanarLayout::PLANE_Y] = {
+                C2PlaneInfo::CHANNEL_Y,         // channel
+                2,                              // colInc
+                static_cast<int32_t>(2 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                kEndianness,                    // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_U] = {
+                C2PlaneInfo::CHANNEL_CB,        // channel
+                4,                              // colInc
+                static_cast<int32_t>(2 * stride), // rowInc
+                2,                              // mColSampling
+                2,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                kEndianness,                    // endianness
+                C2PlanarLayout::PLANE_U,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_V] = {
+                C2PlaneInfo::CHANNEL_CR,        // channel
+                4,                              // colInc
+                static_cast<int32_t>(2 * stride), // rowInc
+                2,                              // mColSampling
+                2,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                kEndianness,                    // endianness
+                C2PlanarLayout::PLANE_U,        // rootIx
+                2,                              // offset
+            };
+            break;
+        }
+
+        default: {
+            // We don't know what it is, let's try to lock it with gralloc4
+            android_ycbcr ycbcrLayout;
+            if (isAtLeastT()) {
+                c2_status_t status = Gralloc4Mapper_lock(
+                        const_cast<native_handle_t*>(buffer), grallocUsage, rect, layout, addr);
+                if (status == C2_OK) {
+                    break;
+                }
+            }
+
+            // fallback to lockYCbCr
+            status_t err = GraphicBufferMapper::get().lockYCbCr(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, &ycbcrLayout);
+            if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
+                    && ycbcrLayout.ystride > 0
+                    && ycbcrLayout.cstride > 0
+                    && ycbcrLayout.chroma_step > 0) {
+                addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+                addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+                addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+                layout->type = C2PlanarLayout::TYPE_YUV;
+                layout->numPlanes = 3;
+                layout->rootPlanes = 3;
+                layout->planes[C2PlanarLayout::PLANE_Y] = {
+                    C2PlaneInfo::CHANNEL_Y,         // channel
+                    1,                              // colInc
+                    (int32_t)ycbcrLayout.ystride,   // rowInc
+                    1,                              // mColSampling
+                    1,                              // mRowSampling
+                    8,                              // allocatedDepth
+                    8,                              // bitDepth
+                    0,                              // rightShift
+                    C2PlaneInfo::NATIVE,            // endianness
+                    C2PlanarLayout::PLANE_Y,        // rootIx
+                    0,                              // offset
+                };
+                layout->planes[C2PlanarLayout::PLANE_U] = {
+                    C2PlaneInfo::CHANNEL_CB,          // channel
+                    (int32_t)ycbcrLayout.chroma_step, // colInc
+                    (int32_t)ycbcrLayout.cstride,     // rowInc
+                    2,                                // mColSampling
+                    2,                                // mRowSampling
+                    8,                                // allocatedDepth
+                    8,                                // bitDepth
+                    0,                                // rightShift
+                    C2PlaneInfo::NATIVE,              // endianness
+                    C2PlanarLayout::PLANE_U,          // rootIx
+                    0,                                // offset
+                };
+                layout->planes[C2PlanarLayout::PLANE_V] = {
+                    C2PlaneInfo::CHANNEL_CR,          // channel
+                    (int32_t)ycbcrLayout.chroma_step, // colInc
+                    (int32_t)ycbcrLayout.cstride,     // rowInc
+                    2,                                // mColSampling
+                    2,                                // mRowSampling
+                    8,                                // allocatedDepth
+                    8,                                // bitDepth
+                    0,                                // rightShift
+                    C2PlaneInfo::NATIVE,              // endianness
+                    C2PlanarLayout::PLANE_V,          // rootIx
+                    0,                                // offset
+                };
+                break;
+            }
+
+            // We really don't know what this is; lock the buffer and pass it through ---
+            // the client may know how to interpret it.
+
+            // unlock previous allocation if it was successful
+            if (err == OK) {
+                err = GraphicBufferMapper::get().unlock(buffer);
+                if (err) {
+                    ALOGE("failed transaction: unlock");
+                    return C2_CORRUPTED;
+                }
+            }
+
+            void *pointer = nullptr;
+            err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(??? %x)", format);
+                return C2_CORRUPTED;
+            }
+            addr[0] = (uint8_t *)pointer;
+            layout->type = C2PlanarLayout::TYPE_UNKNOWN;
+            layout->numPlanes = 1;
+            layout->rootPlanes = 1;
+            layout->planes[0] = {
+                // TODO: CHANNEL_UNKNOWN?
+                C2PlaneInfo::channel_t(0xFF),   // channel
+                1,                              // colInc
+                int32_t(stride),               // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                0,                              // rootIx
+                0,                              // offset
+            };
+            break;
+        }
+    }
+    return C2_OK;
+}
+
+static void HandleInterleavedPlanes(
+        C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+    if (layout->type == C2PlanarLayout::TYPE_YUV && layout->rootPlanes == 3) {
+        intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+        intptr_t uvColInc = layout->planes[C2PlanarLayout::PLANE_U].colInc;
+        if (uvOffset > 0 && uvOffset < uvColInc) {
+            layout->rootPlanes = 2;
+            layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+            layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+        } else if (uvOffset < 0 && uvOffset > -uvColInc) {
+            layout->rootPlanes = 2;
+            layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+            layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+        }
+    }
+}
+
 } // unnamed namespace
 
 
@@ -476,440 +920,14 @@
                 mStride, generation, igbp_id, igbp_slot);
     }
 
-    // 'NATIVE' on Android means LITTLE_ENDIAN
-    constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE;
-
-    // Try to resolve IMPLEMENTATION_DEFINED format to accurate format if
-    // possible.
-    uint32_t format = mFormat;
-    uint32_t fourCc;
-    if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
-        !GraphicBufferMapper::get().getPixelFormatFourCC(mBuffer, &fourCc)) {
-        switch (fourCc)  {
-            case DRM_FORMAT_XBGR8888:
-                 format = static_cast<uint32_t>(PixelFormat4::RGBX_8888);
-                 break;
-            case DRM_FORMAT_ABGR8888:
-                 format = static_cast<uint32_t>(PixelFormat4::RGBA_8888);
-                 break;
-            default:
-                 break;
-        }
-    }
-
-    switch (format) {
-        case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
-            // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
-            // Surface. In all other cases it is RGBA. We don't know which case it is here, so
-            // default to YUV for now.
-            void *pointer = nullptr;
-            // TODO: fence
-            status_t err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(RGBA_1010102)");
-                return C2_CORRUPTED;
-            }
-            // treat as 32-bit values
-            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_V] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_A] = (uint8_t *)pointer;
-            layout->type = C2PlanarLayout::TYPE_YUVA;
-            layout->numPlanes = 4;
-            layout->rootPlanes = 1;
-            layout->planes[C2PlanarLayout::PLANE_Y] = {
-                C2PlaneInfo::CHANNEL_Y,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                32,                             // allocatedDepth
-                10,                             // bitDepth
-                10,                             // rightShift
-                C2PlaneInfo::LITTLE_END,        // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_U] = {
-                C2PlaneInfo::CHANNEL_CB,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                32,                             // allocatedDepth
-                10,                             // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::LITTLE_END,        // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_V] = {
-                C2PlaneInfo::CHANNEL_CR,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                32,                             // allocatedDepth
-                10,                             // bitDepth
-                20,                             // rightShift
-                C2PlaneInfo::LITTLE_END,        // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_A] = {
-                C2PlaneInfo::CHANNEL_A,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                32,                             // allocatedDepth
-                2,                              // bitDepth
-                30,                             // rightShift
-                C2PlaneInfo::LITTLE_END,        // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            break;
-        }
-
-        case static_cast<uint32_t>(PixelFormat4::RGBA_8888):
-            // TODO: alpha channel
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::RGBX_8888): {
-            void *pointer = nullptr;
-            // TODO: fence
-            status_t err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(RGBA_8888)");
-                return C2_CORRUPTED;
-            }
-            addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
-            addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
-            layout->type = C2PlanarLayout::TYPE_RGB;
-            layout->numPlanes = 3;
-            layout->rootPlanes = 1;
-            layout->planes[C2PlanarLayout::PLANE_R] = {
-                C2PlaneInfo::CHANNEL_R,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                C2PlanarLayout::PLANE_R,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_G] = {
-                C2PlaneInfo::CHANNEL_G,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                C2PlanarLayout::PLANE_R,        // rootIx
-                1,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_B] = {
-                C2PlaneInfo::CHANNEL_B,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                C2PlanarLayout::PLANE_R,        // rootIx
-                2,                              // offset
-            };
-            break;
-        }
-
-        case static_cast<uint32_t>(PixelFormat4::BLOB): {
-            void *pointer = nullptr;
-            // TODO: fence
-            status_t err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(BLOB)");
-                return C2_CORRUPTED;
-            }
-            *addr = (uint8_t *)pointer;
-            break;
-        }
-
-        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP):
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP):
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I):
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YV12): {
-            android_ycbcr ycbcrLayout;
-
-            status_t err = GraphicBufferMapper::get().lockYCbCr(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
-            if (err) {
-                ALOGE("failed transaction: lockYCbCr (err=%d)", err);
-                return C2_CORRUPTED;
-            }
-            if (!ycbcrLayout.y || !ycbcrLayout.cb || !ycbcrLayout.cr
-                    || ycbcrLayout.ystride == 0
-                    || ycbcrLayout.cstride == 0
-                    || ycbcrLayout.chroma_step == 0) {
-                ALOGE("invalid layout: lockYCbCr (y=%s cb=%s cr=%s "
-                        "ystride=%zu cstride=%zu chroma_step=%zu)",
-                        ycbcrLayout.y ? "(non-null)" : "(null)",
-                        ycbcrLayout.cb ? "(non-null)" : "(null)",
-                        ycbcrLayout.cr ? "(non-null)" : "(null)",
-                        ycbcrLayout.ystride, ycbcrLayout.cstride, ycbcrLayout.chroma_step);
-                return C2_CORRUPTED;
-            }
-
-            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
-            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
-            addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
-            layout->type = C2PlanarLayout::TYPE_YUV;
-            layout->numPlanes = 3;
-            layout->rootPlanes = 3;
-            layout->planes[C2PlanarLayout::PLANE_Y] = {
-                C2PlaneInfo::CHANNEL_Y,         // channel
-                1,                              // colInc
-                (int32_t)ycbcrLayout.ystride,   // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_U] = {
-                C2PlaneInfo::CHANNEL_CB,          // channel
-                (int32_t)ycbcrLayout.chroma_step, // colInc
-                (int32_t)ycbcrLayout.cstride,     // rowInc
-                2,                                // mColSampling
-                2,                                // mRowSampling
-                8,                                // allocatedDepth
-                8,                                // bitDepth
-                0,                                // rightShift
-                C2PlaneInfo::NATIVE,              // endianness
-                C2PlanarLayout::PLANE_U,          // rootIx
-                0,                                // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_V] = {
-                C2PlaneInfo::CHANNEL_CR,          // channel
-                (int32_t)ycbcrLayout.chroma_step, // colInc
-                (int32_t)ycbcrLayout.cstride,     // rowInc
-                2,                                // mColSampling
-                2,                                // mRowSampling
-                8,                                // allocatedDepth
-                8,                                // bitDepth
-                0,                                // rightShift
-                C2PlaneInfo::NATIVE,              // endianness
-                C2PlanarLayout::PLANE_V,          // rootIx
-                0,                                // offset
-            };
-            break;
-        }
-
-        case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
-            // In Android T, P010 is relaxed to allow arbitrary stride for the Y and UV planes,
-            // try locking with the gralloc4 mapper first.
-            c2_status_t status = Gralloc4Mapper_lock(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
-            if (status == C2_OK) {
-                break;
-            }
-
-            void *pointer = nullptr;
-            status_t err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(YCBCR_P010)");
-                return C2_CORRUPTED;
-            }
-            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + mStride * 2 * rect.height();
-            addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2;
-            layout->type = C2PlanarLayout::TYPE_YUV;
-            layout->numPlanes = 3;
-            layout->rootPlanes = 2;
-            layout->planes[C2PlanarLayout::PLANE_Y] = {
-                C2PlaneInfo::CHANNEL_Y,         // channel
-                2,                              // colInc
-                static_cast<int32_t>(2 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                16,                             // allocatedDepth
-                10,                             // bitDepth
-                6,                              // rightShift
-                kEndianness,                    // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_U] = {
-                C2PlaneInfo::CHANNEL_CB,        // channel
-                4,                              // colInc
-                static_cast<int32_t>(2 * mStride), // rowInc
-                2,                              // mColSampling
-                2,                              // mRowSampling
-                16,                             // allocatedDepth
-                10,                             // bitDepth
-                6,                              // rightShift
-                kEndianness,                    // endianness
-                C2PlanarLayout::PLANE_U,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_V] = {
-                C2PlaneInfo::CHANNEL_CR,        // channel
-                4,                              // colInc
-                static_cast<int32_t>(2 * mStride), // rowInc
-                2,                              // mColSampling
-                2,                              // mRowSampling
-                16,                             // allocatedDepth
-                10,                             // bitDepth
-                6,                              // rightShift
-                kEndianness,                    // endianness
-                C2PlanarLayout::PLANE_U,        // rootIx
-                2,                              // offset
-            };
-            break;
-        }
-
-        default: {
-            // We don't know what it is, let's try to lock it with gralloc4
-            android_ycbcr ycbcrLayout;
-            if (isAtLeastT()) {
-                c2_status_t status = Gralloc4Mapper_lock(
-                        const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
-                if (status == C2_OK) {
-                    break;
-                }
-            }
-
-            // fallback to lockYCbCr
-            status_t err = GraphicBufferMapper::get().lockYCbCr(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
-            if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
-                    && ycbcrLayout.ystride > 0
-                    && ycbcrLayout.cstride > 0
-                    && ycbcrLayout.chroma_step > 0) {
-                addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
-                addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
-                addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
-                layout->type = C2PlanarLayout::TYPE_YUV;
-                layout->numPlanes = 3;
-                layout->rootPlanes = 3;
-                layout->planes[C2PlanarLayout::PLANE_Y] = {
-                    C2PlaneInfo::CHANNEL_Y,         // channel
-                    1,                              // colInc
-                    (int32_t)ycbcrLayout.ystride,   // rowInc
-                    1,                              // mColSampling
-                    1,                              // mRowSampling
-                    8,                              // allocatedDepth
-                    8,                              // bitDepth
-                    0,                              // rightShift
-                    C2PlaneInfo::NATIVE,            // endianness
-                    C2PlanarLayout::PLANE_Y,        // rootIx
-                    0,                              // offset
-                };
-                layout->planes[C2PlanarLayout::PLANE_U] = {
-                    C2PlaneInfo::CHANNEL_CB,          // channel
-                    (int32_t)ycbcrLayout.chroma_step, // colInc
-                    (int32_t)ycbcrLayout.cstride,     // rowInc
-                    2,                                // mColSampling
-                    2,                                // mRowSampling
-                    8,                                // allocatedDepth
-                    8,                                // bitDepth
-                    0,                                // rightShift
-                    C2PlaneInfo::NATIVE,              // endianness
-                    C2PlanarLayout::PLANE_U,          // rootIx
-                    0,                                // offset
-                };
-                layout->planes[C2PlanarLayout::PLANE_V] = {
-                    C2PlaneInfo::CHANNEL_CR,          // channel
-                    (int32_t)ycbcrLayout.chroma_step, // colInc
-                    (int32_t)ycbcrLayout.cstride,     // rowInc
-                    2,                                // mColSampling
-                    2,                                // mRowSampling
-                    8,                                // allocatedDepth
-                    8,                                // bitDepth
-                    0,                                // rightShift
-                    C2PlaneInfo::NATIVE,              // endianness
-                    C2PlanarLayout::PLANE_V,          // rootIx
-                    0,                                // offset
-                };
-                break;
-            }
-
-            // We really don't know what this is; lock the buffer and pass it through ---
-            // the client may know how to interpret it.
-
-            // unlock previous allocation if it was successful
-            if (err == OK) {
-                err = GraphicBufferMapper::get().unlock(mBuffer);
-                if (err) {
-                    ALOGE("failed transaction: unlock");
-                    return C2_CORRUPTED;
-                }
-            }
-
-            void *pointer = nullptr;
-            err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(??? %x)", mFormat);
-                return C2_CORRUPTED;
-            }
-            addr[0] = (uint8_t *)pointer;
-            layout->type = C2PlanarLayout::TYPE_UNKNOWN;
-            layout->numPlanes = 1;
-            layout->rootPlanes = 1;
-            layout->planes[0] = {
-                // TODO: CHANNEL_UNKNOWN?
-                C2PlaneInfo::channel_t(0xFF),   // channel
-                1,                              // colInc
-                int32_t(mStride),               // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                0,                              // rootIx
-                0,                              // offset
-            };
-            break;
-        }
+    c2_status_t ret = PopulatePlaneLayout(
+            mBuffer, rect, mFormat, grallocUsage, mStride, layout, addr);
+    if (ret != C2_OK) {
+        return ret;
     }
     mLocked = true;
 
-    // handle interleaved formats
-    if (layout->type == C2PlanarLayout::TYPE_YUV && layout->rootPlanes == 3) {
-        intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
-        intptr_t uvColInc = layout->planes[C2PlanarLayout::PLANE_U].colInc;
-        if (uvOffset > 0 && uvOffset < uvColInc) {
-            layout->rootPlanes = 2;
-            layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
-            layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
-        } else if (uvOffset < 0 && uvOffset > -uvColInc) {
-            layout->rootPlanes = 2;
-            layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
-            layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
-        }
-    }
+    HandleInterleavedPlanes(layout, addr);
 
     ALOGV("C2AllocationGralloc::map: layout: type=%d numPlanes=%d rootPlanes=%d",
           layout->type, layout->numPlanes, layout->rootPlanes);
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 0344fd3..b91ac6d 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -16,6 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "C2FenceFactory"
+#include <poll.h>
+
+#include <android-base/unique_fd.h>
 #include <cutils/native_handle.h>
 #include <utils/Log.h>
 #include <ui/Fence.h>
@@ -32,6 +35,7 @@
         NULL_FENCE,
         SURFACE_FENCE,
         SYNC_FENCE,
+        PIPE_FENCE,
     };
 
     virtual c2_status_t wait(c2_nsecs_t timeoutNs) = 0;
@@ -353,6 +357,154 @@
     return C2Fence(p);
 }
 
+/**
+ * Fence implementation for notifying # of events available based on
+ * file descriptors created by pipe()/pipe2(). The writing end of the
+ * file descriptors is used to create the implementation.
+ * The implementation supports all C2Fence interface.
+ */
+class _C2FenceFactory::PipeFenceImpl: public C2Fence::Impl {
+private:
+    bool waitEvent(c2_nsecs_t timeoutNs, bool *hangUp, bool *event) const {
+        if (!mValid) {
+            *hangUp = true;
+            return true;
+        }
+
+        struct pollfd pfd;
+        pfd.fd = mPipeFd.get();
+        pfd.events = POLLIN;
+        pfd.revents = 0;
+        struct timespec ts;
+        if (timeoutNs >= 0) {
+            ts.tv_sec = int(timeoutNs / 1000000000);
+            ts.tv_nsec = timeoutNs;
+        } else {
+            ALOGD("polling for indefinite duration requested, but changed to wait for %d sec",
+                  kPipeFenceWaitLimitSecs);
+            ts.tv_sec = kPipeFenceWaitLimitSecs;
+            ts.tv_nsec = 0;
+        }
+        int ret = ::ppoll(&pfd, 1, &ts, nullptr);
+        if (ret >= 0) {
+            if (pfd.revents) {
+                if (pfd.revents & ~POLLIN) {
+                    // Mostly this means the writing end fd was closed.
+                    *hangUp = true;
+                    mValid = false;
+                    ALOGD("PipeFenceImpl: pipe fd hangup or err event returned");
+                }
+                *event = true;
+                return true;
+            }
+            // event not ready yet.
+            return true;
+        }
+        if (errno == EINTR) {
+            // poll() was cancelled by signal or inner kernel status.
+            return false;
+        }
+        // Since poll error happened here, treat the error is irrecoverable.
+        ALOGE("PipeFenceImpl: poll() error %d", errno);
+        *hangUp = true;
+        mValid = false;
+        return true;
+    }
+
+public:
+    virtual c2_status_t wait(c2_nsecs_t timeoutNs) {
+        if (!mValid) {
+            return C2_BAD_STATE;
+        }
+        bool hangUp = false;
+        bool event = false;
+        if (waitEvent(timeoutNs, &hangUp, &event)) {
+            if (hangUp) {
+                return C2_BAD_STATE;
+            }
+            if (event) {
+                return C2_OK;
+            }
+            return C2_TIMED_OUT;
+        } else {
+            return C2_CANCELED;
+        }
+    }
+
+    virtual bool valid() const {
+        if (!mValid) {
+            return false;
+        }
+        bool hangUp = false;
+        bool event = false;
+        if (waitEvent(0, &hangUp, &event)) {
+            if (hangUp) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    virtual bool ready() const {
+        if (!mValid) {
+            return false;
+        }
+        bool hangUp = false;
+        bool event = false;
+        if (waitEvent(0, &hangUp, &event)) {
+            if (event) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    virtual int fd() const {
+        if (!mValid) {
+            return -1;
+        }
+        return ::dup(mPipeFd.get());
+    }
+
+    virtual bool isHW() const {
+        return false;
+    }
+
+    virtual type_t type() const {
+        return PIPE_FENCE;
+    }
+
+    virtual native_handle_t *createNativeHandle() const {
+        // This is not supported.
+        return nullptr;
+    }
+
+    virtual ~PipeFenceImpl() = default;
+
+    PipeFenceImpl(int fd) : mPipeFd(fd) {
+        mValid = (mPipeFd.get() >= 0);
+    }
+
+private:
+    friend struct _C2FenceFactory;
+    static constexpr int kPipeFenceWaitLimitSecs = 5;
+
+    mutable std::atomic<bool> mValid;
+    ::android::base::unique_fd mPipeFd;
+};
+
+C2Fence _C2FenceFactory::CreatePipeFence(int fd) {
+    std::shared_ptr<_C2FenceFactory::PipeFenceImpl> impl =
+        std::make_shared<_C2FenceFactory::PipeFenceImpl>(fd);
+    std::shared_ptr<C2Fence::Impl> p = std::static_pointer_cast<C2Fence::Impl>(impl);
+    if (!p) {
+        ALOGE("PipeFence creation failure");
+    } else if (!impl->mValid) {
+        p.reset();
+    }
+    return C2Fence(p);
+}
+
 native_handle_t* _C2FenceFactory::CreateNativeHandle(const C2Fence& fence) {
     return fence.mImpl? fence.mImpl->createNativeHandle() : nullptr;
 }
diff --git a/media/codec2/vndk/include/C2FenceFactory.h b/media/codec2/vndk/include/C2FenceFactory.h
index ef25c47..9b09980 100644
--- a/media/codec2/vndk/include/C2FenceFactory.h
+++ b/media/codec2/vndk/include/C2FenceFactory.h
@@ -39,6 +39,7 @@
 
     class SurfaceFenceImpl;
     class SyncFenceImpl;
+    class PipeFenceImpl;
 
     /*
      * Create C2Fence for BufferQueueBased blockpool.
@@ -66,6 +67,15 @@
      */
     static C2Fence CreateMultipleFdSyncFence(const std::vector<int>& fenceFds);
 
+    /*
+     * Create C2Fence from an fd created by pipe()/pipe2() syscall.
+     *
+     * \param fd                An fd representing the write end from a pair of
+     *                          file descriptors which are created by
+     *                          pipe()/pipe2() syscall.
+     */
+    static C2Fence CreatePipeFence(int fd);
+
     /**
      * Create a native handle from fence for marshalling
      *
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 1e8dcca..5b90158 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -114,7 +114,6 @@
         "libnblog",
         "libprocessgroup",
         "libshmemcompat",
-        "libxml2",
         "mediametricsservice-aidl-cpp",
         "packagemanager_aidl-cpp",
         "shared-file-region-aidl-cpp",
diff --git a/media/libaudioclient/tests/audio_test_utils.cpp b/media/libaudioclient/tests/audio_test_utils.cpp
index 1e26ff6..ee5489b 100644
--- a/media/libaudioclient/tests/audio_test_utils.cpp
+++ b/media/libaudioclient/tests/audio_test_utils.cpp
@@ -26,25 +26,10 @@
 #define WAIT_PERIOD_MS 10  // from AudioTrack.cpp
 #define MAX_WAIT_TIME_MS 5000
 
-template <class T>
-constexpr void (*xmlDeleter)(T* t);
-template <>
-constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
-template <>
-constexpr auto xmlDeleter<xmlChar> = [](xmlChar* s) { xmlFree(s); };
-
-/** @return a unique_ptr with the correct deleter for the libxml2 object. */
-template <class T>
-constexpr auto make_xmlUnique(T* t) {
-    // Wrap deleter in lambda to enable empty base optimization
-    auto deleter = [](T* t) { xmlDeleter<T>(t); };
-    return std::unique_ptr<T, decltype(deleter)>{t, deleter};
-}
-
 void OnAudioDeviceUpdateNotifier::onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                                       audio_port_handle_t deviceId) {
     std::unique_lock<std::mutex> lock{mMutex};
-    ALOGD("%s  audioIo=%d deviceId=%d", __func__, audioIo, deviceId);
+    ALOGI("%s: audioIo=%d deviceId=%d", __func__, audioIo, deviceId);
     mAudioIo = audioIo;
     mDeviceId = deviceId;
     mCondition.notify_all();
@@ -727,184 +712,17 @@
 }
 
 std::string dumpPortConfig(const audio_port_config& port) {
-    std::ostringstream result;
-    std::string deviceInfo;
-    if (port.type == AUDIO_PORT_TYPE_DEVICE) {
-        if (port.ext.device.type & AUDIO_DEVICE_BIT_IN) {
-            InputDeviceConverter::maskToString(port.ext.device.type, deviceInfo);
-        } else {
-            OutputDeviceConverter::maskToString(port.ext.device.type, deviceInfo);
-        }
-        deviceInfo += std::string(", address = ") + port.ext.device.address;
-    }
-    result << "audio_port_handle_t = " << port.id << ", "
-           << "Role = " << (port.role == AUDIO_PORT_ROLE_SOURCE ? "source" : "sink") << ", "
-           << "Type = " << (port.type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix") << ", "
-           << "deviceInfo = " << (port.type == AUDIO_PORT_TYPE_DEVICE ? deviceInfo : "") << ", "
-           << "config_mask = 0x" << std::hex << port.config_mask << std::dec << ", ";
-    if (port.config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-        result << "sample rate = " << port.sample_rate << ", ";
-    }
-    if (port.config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-        result << "channel mask = " << port.channel_mask << ", ";
-    }
-    if (port.config_mask & AUDIO_PORT_CONFIG_FORMAT) {
-        result << "format = " << port.format << ", ";
-    }
-    result << "input flags = " << port.flags.input << ", ";
-    result << "output flags = " << port.flags.output << ", ";
-    result << "mix io handle = " << (port.type == AUDIO_PORT_TYPE_DEVICE ? 0 : port.ext.mix.handle)
-           << "\n";
-    return result.str();
+    auto aidlPortConfig = legacy2aidl_audio_port_config_AudioPortConfigFw(port);
+    return aidlPortConfig.ok() ? aidlPortConfig.value().toString()
+                               : "Error while converting audio port config to AIDL";
 }
 
 std::string dumpPatch(const audio_patch& patch) {
-    std::ostringstream result;
-    result << "----------------- Dumping Patch ------------ \n";
-    result << "Patch Handle: " << patch.id << ", sources: " << patch.num_sources
-           << ", sink: " << patch.num_sinks << "\n";
-    audio_port_v7 port;
-    for (uint32_t i = 0; i < patch.num_sources; i++) {
-        result << "----------------- Dumping Source Port Config @ index " << i
-               << " ------------ \n";
-        result << dumpPortConfig(patch.sources[i]);
-        result << "----------------- Dumping Source Port for id " << patch.sources[i].id
-               << " ------------ \n";
-        getPortById(patch.sources[i].id, port);
-        result << dumpPort(port);
-    }
-    for (uint32_t i = 0; i < patch.num_sinks; i++) {
-        result << "----------------- Dumping Sink Port Config @ index " << i << " ------------ \n";
-        result << dumpPortConfig(patch.sinks[i]);
-        result << "----------------- Dumping Sink Port for id " << patch.sinks[i].id
-               << " ------------ \n";
-        getPortById(patch.sinks[i].id, port);
-        result << dumpPort(port);
-    }
-    return result.str();
+    auto aidlPatch = legacy2aidl_audio_patch_AudioPatchFw(patch);
+    return aidlPatch.ok() ? aidlPatch.value().toString() : "Error while converting patch to AIDL";
 }
 
 std::string dumpPort(const audio_port_v7& port) {
-    std::ostringstream result;
-    std::string deviceInfo;
-    if (port.type == AUDIO_PORT_TYPE_DEVICE) {
-        if (port.ext.device.type & AUDIO_DEVICE_BIT_IN) {
-            InputDeviceConverter::maskToString(port.ext.device.type, deviceInfo);
-        } else {
-            OutputDeviceConverter::maskToString(port.ext.device.type, deviceInfo);
-        }
-        deviceInfo += std::string(", address = ") + port.ext.device.address;
-    }
-    result << "audio_port_handle_t = " << port.id << ", "
-           << "Role = " << (port.role == AUDIO_PORT_ROLE_SOURCE ? "source" : "sink") << ", "
-           << "Type = " << (port.type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix") << ", "
-           << "deviceInfo = " << (port.type == AUDIO_PORT_TYPE_DEVICE ? deviceInfo : "") << ", "
-           << "Name = " << port.name << ", "
-           << "num profiles = " << port.num_audio_profiles << ", "
-           << "mix io handle = " << (port.type == AUDIO_PORT_TYPE_DEVICE ? 0 : port.ext.mix.handle)
-           << ", ";
-    for (int i = 0; i < port.num_audio_profiles; i++) {
-        result << "AudioProfile = " << i << " {";
-        result << "format = " << port.audio_profiles[i].format << ", ";
-        result << "samplerates = ";
-        for (int j = 0; j < port.audio_profiles[i].num_sample_rates; j++) {
-            result << port.audio_profiles[i].sample_rates[j] << ", ";
-        }
-        result << "channelmasks = ";
-        for (int j = 0; j < port.audio_profiles[i].num_channel_masks; j++) {
-            result << "0x" << std::hex << port.audio_profiles[i].channel_masks[j] << std::dec
-                   << ", ";
-        }
-        result << "} ";
-    }
-    result << dumpPortConfig(port.active_config);
-    return result.str();
-}
-
-std::string getXmlAttribute(const xmlNode* cur, const char* attribute) {
-    auto charPtr = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
-    if (charPtr == NULL) {
-        return "";
-    }
-    std::string value(reinterpret_cast<const char*>(charPtr.get()));
-    return value;
-}
-
-status_t parse_audio_policy_configuration_xml(std::vector<std::string>& attachedDevices,
-                                              std::vector<MixPort>& mixPorts,
-                                              std::vector<Route>& routes) {
-    std::string path = audio_find_readable_configuration_file("audio_policy_configuration.xml");
-    if (path.length() == 0) return UNKNOWN_ERROR;
-    auto doc = make_xmlUnique(xmlParseFile(path.c_str()));
-    if (doc == nullptr) return UNKNOWN_ERROR;
-    xmlNode* root = xmlDocGetRootElement(doc.get());
-    if (root == nullptr) return UNKNOWN_ERROR;
-    if (xmlXIncludeProcess(doc.get()) < 0) return UNKNOWN_ERROR;
-    mixPorts.clear();
-    if (!xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>("audioPolicyConfiguration"))) {
-        std::string raw{getXmlAttribute(root, "version")};
-        for (auto* child = root->xmlChildrenNode; child != nullptr; child = child->next) {
-            if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>("modules"))) {
-                xmlNode* root = child;
-                for (auto* child = root->xmlChildrenNode; child != nullptr; child = child->next) {
-                    if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>("module"))) {
-                        xmlNode* root = child;
-                        for (auto* child = root->xmlChildrenNode; child != nullptr;
-                             child = child->next) {
-                            if (!xmlStrcmp(child->name,
-                                           reinterpret_cast<const xmlChar*>("mixPorts"))) {
-                                xmlNode* root = child;
-                                for (auto* child = root->xmlChildrenNode; child != nullptr;
-                                     child = child->next) {
-                                    if (!xmlStrcmp(child->name,
-                                                   reinterpret_cast<const xmlChar*>("mixPort"))) {
-                                        MixPort mixPort;
-                                        xmlNode* root = child;
-                                        mixPort.name = getXmlAttribute(root, "name");
-                                        mixPort.role = getXmlAttribute(root, "role");
-                                        mixPort.flags = getXmlAttribute(root, "flags");
-                                        if (mixPort.role == "source") mixPorts.push_back(mixPort);
-                                    }
-                                }
-                            } else if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(
-                                                                       "attachedDevices"))) {
-                                xmlNode* root = child;
-                                for (auto* child = root->xmlChildrenNode; child != nullptr;
-                                     child = child->next) {
-                                    if (!xmlStrcmp(child->name,
-                                                   reinterpret_cast<const xmlChar*>("item"))) {
-                                        auto xmlValue = make_xmlUnique(xmlNodeListGetString(
-                                                child->doc, child->xmlChildrenNode, 1));
-                                        if (xmlValue == nullptr) {
-                                            raw = "";
-                                        } else {
-                                            raw = reinterpret_cast<const char*>(xmlValue.get());
-                                        }
-                                        std::string& value = raw;
-                                        attachedDevices.push_back(std::move(value));
-                                    }
-                                }
-                            } else if (!xmlStrcmp(child->name,
-                                                  reinterpret_cast<const xmlChar*>("routes"))) {
-                                xmlNode* root = child;
-                                for (auto* child = root->xmlChildrenNode; child != nullptr;
-                                     child = child->next) {
-                                    if (!xmlStrcmp(child->name,
-                                                   reinterpret_cast<const xmlChar*>("route"))) {
-                                        Route route;
-                                        xmlNode* root = child;
-                                        route.name = getXmlAttribute(root, "name");
-                                        route.sources = getXmlAttribute(root, "sources");
-                                        route.sink = getXmlAttribute(root, "sink");
-                                        routes.push_back(route);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-    return OK;
+    auto aidlPort = legacy2aidl_audio_port_v7_AudioPortFw(port);
+    return aidlPort.ok() ? aidlPort.value().toString() : "Error while converting port to AIDL";
 }
diff --git a/media/libaudioclient/tests/audio_test_utils.h b/media/libaudioclient/tests/audio_test_utils.h
index 90c30c2..76e4642 100644
--- a/media/libaudioclient/tests/audio_test_utils.h
+++ b/media/libaudioclient/tests/audio_test_utils.h
@@ -28,8 +28,6 @@
 #include <thread>
 
 #include <binder/MemoryDealer.h>
-#include <libxml/parser.h>
-#include <libxml/xinclude.h>
 #include <media/AidlConversion.h>
 #include <media/AudioRecord.h>
 #include <media/AudioTrack.h>
@@ -48,9 +46,6 @@
     std::string sink;
 };
 
-status_t parse_audio_policy_configuration_xml(std::vector<std::string>& attachedDevices,
-                                              std::vector<MixPort>& mixPorts,
-                                              std::vector<Route>& routes);
 status_t listAudioPorts(std::vector<audio_port_v7>& portsVec);
 status_t listAudioPatches(std::vector<struct audio_patch>& patchesVec);
 status_t getPortByAttributes(audio_port_role_t role, audio_port_type_t type,
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index 19d1abc..fa990b5 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -15,10 +15,13 @@
  */
 
 //#define LOG_NDEBUG 0
+#define LOG_TAG "AudioRoutingTest"
 
+#include <string.h>
+
+#include <binder/ProcessState.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
-#include <string.h>
 
 #include "audio_test_utils.h"
 
@@ -63,12 +66,16 @@
         EXPECT_NE(0, ap->getAudioTrackHandle()->getFlags() & output_flags[i]);
         audio_patch patch;
         EXPECT_EQ(OK, getPatchForOutputMix(cb->mAudioIo, patch));
-        for (auto j = 0; j < patch.num_sources; j++) {
-            if (patch.sources[j].type == AUDIO_PORT_TYPE_MIX &&
-                patch.sources[j].ext.mix.handle == cb->mAudioIo) {
-                if ((patch.sources[j].flags.output & output_flags[i]) == 0) {
-                    ADD_FAILURE() << "expected output flag " << output_flags[i] << " is absent";
-                    std::cerr << dumpPortConfig(patch.sources[j]);
+        if (output_flags[i] != AUDIO_OUTPUT_FLAG_FAST) {
+            // A "normal" output can still have a FastMixer, depending on the buffer size.
+            // Thus, a fast track can be created on a mix port which does not have the FAST flag.
+            for (auto j = 0; j < patch.num_sources; j++) {
+                if (patch.sources[j].type == AUDIO_PORT_TYPE_MIX &&
+                    patch.sources[j].ext.mix.handle == cb->mAudioIo) {
+                    SCOPED_TRACE(dumpPortConfig(patch.sources[j]));
+                    EXPECT_NE(0, patch.sources[j].flags.output & output_flags[i])
+                            << "expected output flag "
+                            << audio_output_flag_to_string(output_flags[i]) << " is absent";
                 }
             }
         }
@@ -259,3 +266,25 @@
     captureA->stop();
     playback->stop();
 }
+
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+  public:
+    void OnTestStart(const ::testing::TestInfo& test_info) override {
+        TraceTestState("Started", test_info);
+    }
+    void OnTestEnd(const ::testing::TestInfo& test_info) override {
+        TraceTestState("Completed", test_info);
+    }
+
+  private:
+    static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
+        ALOGI("%s %s::%s", state.c_str(), test_info.test_suite_name(), test_info.name());
+    }
+};
+
+int main(int argc, char** argv) {
+    android::ProcessState::self()->startThreadPool();
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+    return RUN_ALL_TESTS();
+}
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index b09a379..2869ca4 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -615,28 +615,37 @@
 
 android::media::audio::common::AudioPort GenerateUniqueDeviceAddress(
         const android::media::audio::common::AudioPort& port) {
+    // Point-to-point connections do not use addresses.
+    static const std::set<std::string> kPointToPointConnections = {
+            AudioDeviceDescription::CONNECTION_ANALOG(), AudioDeviceDescription::CONNECTION_HDMI(),
+            AudioDeviceDescription::CONNECTION_HDMI_ARC(),
+            AudioDeviceDescription::CONNECTION_HDMI_EARC(),
+            AudioDeviceDescription::CONNECTION_SPDIF()};
     static int nextId = 0;
     using Tag = AudioDeviceAddress::Tag;
+    const auto& deviceDescription = port.ext.get<AudioPortExt::Tag::device>().device.type;
     AudioDeviceAddress address;
-    switch (suggestDeviceAddressTag(port.ext.get<AudioPortExt::Tag::device>().device.type)) {
-        case Tag::id:
-            address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
-            break;
-        case Tag::mac:
-            address = AudioDeviceAddress::make<Tag::mac>(
-                    std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
-            break;
-        case Tag::ipv4:
-            address = AudioDeviceAddress::make<Tag::ipv4>(
-                    std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
-            break;
-        case Tag::ipv6:
-            address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
-                    0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
-            break;
-        case Tag::alsa:
-            address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
-            break;
+    if (kPointToPointConnections.count(deviceDescription.connection) == 0) {
+        switch (suggestDeviceAddressTag(deviceDescription)) {
+            case Tag::id:
+                address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
+                break;
+            case Tag::mac:
+                address = AudioDeviceAddress::make<Tag::mac>(
+                        std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
+                break;
+            case Tag::ipv4:
+                address = AudioDeviceAddress::make<Tag::ipv4>(
+                        std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
+                break;
+            case Tag::ipv6:
+                address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
+                        0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
+                break;
+            case Tag::alsa:
+                address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
+                break;
+        }
     }
     android::media::audio::common::AudioPort result = port;
     result.ext.get<AudioPortExt::Tag::device>().device.address = std::move(address);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 362f373..131684c 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -1080,6 +1080,7 @@
                 "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
                 __func__, mInstance.c_str(), connectedPort.toString().c_str(),
                 it->second.toString().c_str());
+        mConnectedPorts[connectedPort.id] = false;
     } else {  // !connected
         AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
         auto portsIt = findPort(matchDevice);
@@ -1099,10 +1100,11 @@
             RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
                             mModule->disconnectExternalDevice(portId)));
             mPorts.erase(portsIt);
+            mConnectedPorts.erase(portId);
         } else {
             ALOGD("%s: since device port ID %d is used by a stream, "
                     "external device disconnection postponed", __func__, portId);
-            mConnectedPortIdsHeldByStreams.insert(portId);
+            mConnectedPorts[portId] = true;
         }
     }
     return updateRoutes();
@@ -1601,8 +1603,25 @@
     } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
         return mPorts.find(mDefaultOutputPortId);
     }
-    return std::find_if(mPorts.begin(), mPorts.end(),
-            [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+    if (device.address.getTag() != AudioDeviceAddress::id ||
+            !device.address.get<AudioDeviceAddress::id>().empty()) {
+        return std::find_if(mPorts.begin(), mPorts.end(),
+                [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+    }
+    // For connection w/o an address, two ports can be found: the template port,
+    // and a connected port (if exists). Make sure we return the connected port.
+    DeviceHalAidl::Ports::iterator portIt = mPorts.end();
+    for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
+        if (audioDeviceMatches(device, it->second)) {
+            if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
+                return it;
+            } else {
+                // Will return 'it' if there is no connected port.
+                portIt = it;
+            }
+        }
+    }
+    return portIt;
 }
 
 DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
@@ -1765,7 +1784,8 @@
     std::set<int32_t> retryDeviceDisconnection;
     for (const auto& portConfigAndIdPair : portConfigIds) {
         resetPortConfig(portConfigAndIdPair.first);
-        if (mConnectedPortIdsHeldByStreams.count(portConfigAndIdPair.second) != 0) {
+        if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
+                it != mConnectedPorts.end() && it->second) {
             retryDeviceDisconnection.insert(portConfigAndIdPair.second);
         }
     }
@@ -1774,7 +1794,7 @@
             TIME_CHECK();
             if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
                 mPorts.erase(portId);
-                mConnectedPortIdsHeldByStreams.erase(portId);
+                mConnectedPorts.erase(portId);
                 ALOGD("%s: executed postponed external device disconnection for port ID %d",
                         __func__, portId);
             }
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 329adba..da96d80 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -187,6 +187,8 @@
         Status status = Status::UNKNOWN;
         MicrophoneInfoProvider::Info info;
     };
+    // IDs of ports for connected external devices, and whether they are held by streams.
+    using ConnectedPorts = std::map<int32_t /*port ID*/, bool>;
     using Patches = std::map<int32_t /*patch ID*/,
             ::aidl::android::hardware::audio::core::AudioPatch>;
     using PortConfigs = std::map<int32_t /*port config ID*/,
@@ -313,7 +315,7 @@
     std::mutex mLock;
     std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock);
     std::set<audio_port_handle_t> mDeviceDisconnectionNotified;
-    std::set<int32_t> mConnectedPortIdsHeldByStreams;
+    ConnectedPorts mConnectedPorts;
 };
 
 } // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index aecbba7..196b432 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -255,37 +255,37 @@
 status_t EffectConversionHelperAidl::handleReset(uint32_t cmdSize __unused,
                                                  const void* pCmdData __unused, uint32_t* replySize,
                                                  void* pReplyData) {
-    if (!replySize || !pReplyData) {
+    if (!replySize || *replySize != sizeof(int) || !pReplyData) {
         ALOGE("%s parameter invalid, replySize %s pReplyData %p", __func__,
               numericPointerToString(replySize).c_str(), pReplyData);
         return BAD_VALUE;
     }
 
-    return statusTFromBinderStatus(mEffect->command(CommandId::RESET));
+    return *(int *)pReplyData = statusTFromBinderStatus(mEffect->command(CommandId::RESET));
 }
 
 status_t EffectConversionHelperAidl::handleEnable(uint32_t cmdSize __unused,
                                                   const void* pCmdData __unused,
                                                   uint32_t* replySize, void* pReplyData) {
-    if (!replySize || !pReplyData) {
+    if (!replySize || *replySize != sizeof(int) || !pReplyData) {
         ALOGE("%s parameter invalid, replySize %s pReplyData %p", __func__,
               numericPointerToString(replySize).c_str(), pReplyData);
         return BAD_VALUE;
     }
 
-    return statusTFromBinderStatus(mEffect->command(CommandId::START));
+    return *(int *)pReplyData = statusTFromBinderStatus(mEffect->command(CommandId::START));
 }
 
 status_t EffectConversionHelperAidl::handleDisable(uint32_t cmdSize __unused,
                                                    const void* pCmdData __unused,
                                                    uint32_t* replySize, void* pReplyData) {
-    if (!replySize || !pReplyData) {
+    if (!replySize || *replySize != sizeof(int) || !pReplyData) {
         ALOGE("%s parameter invalid, replySize %s pReplyData %p", __func__,
               numericPointerToString(replySize).c_str(), pReplyData);
         return BAD_VALUE;
     }
 
-    return statusTFromBinderStatus(mEffect->command(CommandId::STOP));
+    return *(int *)pReplyData = statusTFromBinderStatus(mEffect->command(CommandId::STOP));
 }
 
 status_t EffectConversionHelperAidl::handleSetAudioSource(uint32_t cmdSize, const void* pCmdData,
@@ -477,7 +477,7 @@
                   efGroup);
             status = (status == OK) ? BAD_VALUE : status;
         }
-    } else if (isBypassingOrOffload()) {
+    } else if (isBypassingOrTunnel()) {
         // for effect with bypass (no processing) or offloadIndication flag, it's okay to not have
         // statusQ
         return OK;
@@ -487,8 +487,8 @@
     return status;
 }
 
-bool EffectConversionHelperAidl::isBypassingOrOffload() const {
-    return isBypassing() || isOffload();
+bool EffectConversionHelperAidl::isBypassingOrTunnel() const {
+    return isBypassing() || isTunnel();
 }
 
 bool EffectConversionHelperAidl::isBypassing() const {
@@ -497,10 +497,10 @@
             (mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isBypassing()));
 }
 
-bool EffectConversionHelperAidl::isOffload() const {
+bool EffectConversionHelperAidl::isTunnel() const {
     return mEffect &&
-           (mDesc.common.flags.offloadIndication ||
-            (mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isOffload()));
+           (mDesc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL ||
+            (mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isTunnel()));
 }
 
 Descriptor EffectConversionHelperAidl::getDescriptor() const {
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index b2ef155..5db334c 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -43,8 +43,8 @@
     std::shared_ptr<android::hardware::EventFlag> getEventFlagGroup() { return mEfGroup; }
 
     bool isBypassing() const;
-    bool isOffload() const;
-    bool isBypassingOrOffload() const;
+    bool isTunnel() const;
+    bool isBypassingOrTunnel() const;
 
     ::aidl::android::hardware::audio::effect::Descriptor getDescriptor() const;
 
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index 642d352..f26444c 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -173,7 +173,7 @@
               mConversion->isBypassing()
                       ? "bypassing"
                       : aidl::android::hardware::audio::effect::toString(state).c_str());
-        return OK;
+        return -ENODATA;
     }
 
     auto statusQ = mConversion->getStatusMQ();
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index 4d7db4c..1099b6d 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -278,8 +278,9 @@
     return mSubEffects[mActiveSubIdx].descriptor.common.flags.bypass;
 }
 
-bool EffectProxy::isOffload() const {
-    return mSubEffects[mActiveSubIdx].descriptor.common.flags.offloadIndication;
+bool EffectProxy::isTunnel() const {
+    return mSubEffects[mActiveSubIdx].descriptor.common.flags.hwAcceleratorMode ==
+           Flags::HardwareAccelerator::TUNNEL;
 }
 
 binder_status_t EffectProxy::dump(int fd, const char** args, uint32_t numArgs) {
diff --git a/media/libaudiohal/impl/EffectProxy.h b/media/libaudiohal/impl/EffectProxy.h
index e14eb8a..0d62642 100644
--- a/media/libaudiohal/impl/EffectProxy.h
+++ b/media/libaudiohal/impl/EffectProxy.h
@@ -98,7 +98,7 @@
     }
 
     bool isBypassing() const;
-    bool isOffload() const;
+    bool isTunnel() const;
 
     // call dump for all sub-effects
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index c058386..e74fc16 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -193,7 +193,7 @@
     StreamDescriptor::Reply reply;
     switch (state) {
         case StreamDescriptor::State::ACTIVE:
-            if (status_t status = pause(&reply); status != OK) return status;
+            RETURN_STATUS_IF_ERROR(pause(&reply));
             if (reply.state != StreamDescriptor::State::PAUSED) {
                 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
                         __func__, toString(reply.state).c_str());
@@ -203,7 +203,7 @@
         case StreamDescriptor::State::PAUSED:
         case StreamDescriptor::State::DRAIN_PAUSED:
             if (mIsInput) return flush();
-            if (status_t status = flush(&reply); status != OK) return status;
+            RETURN_STATUS_IF_ERROR(flush(&reply));
             if (reply.state != StreamDescriptor::State::IDLE) {
                 ALOGE("%s: unexpected stream state: %s (expected IDLE)",
                         __func__, toString(reply.state).c_str());
@@ -211,10 +211,8 @@
             }
             FALLTHROUGH_INTENDED;
         case StreamDescriptor::State::IDLE:
-            if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
-                            &reply, true /*safeFromNonWorkerThread*/); status != OK) {
-                return status;
-            }
+            RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
+                            &reply, true /*safeFromNonWorkerThread*/));
             if (reply.state != StreamDescriptor::State::STANDBY) {
                 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
                         __func__, toString(reply.state).c_str());
@@ -244,10 +242,7 @@
     const auto state = getState();
     StreamDescriptor::Reply reply;
     if (state == StreamDescriptor::State::STANDBY) {
-        if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true);
-                status != OK) {
-            return status;
-        }
+        RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
         return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true);
     }
 
@@ -264,10 +259,7 @@
     ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
     if (!mStream) return NO_INIT;
     StreamDescriptor::Reply reply;
-    if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
-        return status;
-    }
-
+    RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
     *latency = std::clamp(std::max<int32_t>(0, reply.latencyMs), 1, 3000);
     ALOGW_IF(reply.latencyMs != static_cast<int32_t>(*latency),
              "Suspicious latency value reported by HAL: %d, clamped to %u", reply.latencyMs,
@@ -279,11 +271,9 @@
     ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
     if (!mStream) return NO_INIT;
     StreamDescriptor::Reply reply;
-    if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
-        return status;
-    }
-    *frames = reply.observable.frames;
-    *timestamp = reply.observable.timeNs;
+    RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+    *frames = std::max<int64_t>(0, reply.observable.frames);
+    *timestamp = std::max<int64_t>(0, reply.observable.timeNs);
     return OK;
 }
 
@@ -292,12 +282,9 @@
     if (!mStream) return NO_INIT;
     StreamDescriptor::Reply reply;
     // TODO: switch to updateCountersIfNeeded once we sort out mWorkerTid initialization
-    if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true);
-            status != OK) {
-        return status;
-    }
-    *frames = reply.hardware.frames;
-    *timestamp = reply.hardware.timeNs;
+    RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true));
+    *frames = std::max<int64_t>(0, reply.hardware.frames);
+    *timestamp = std::max<int64_t>(0, reply.hardware.timeNs);
     return OK;
 }
 
@@ -305,10 +292,8 @@
     ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
     if (!mStream) return NO_INIT;
     StreamDescriptor::Reply reply;
-    if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
-        return status;
-    }
-    *frames = reply.xrunFrames;
+    RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+    *frames = std::max<int32_t>(0, reply.xrunFrames);
     return OK;
 }
 
@@ -323,10 +308,7 @@
     // stream state), however this scenario wasn't supported by the HIDL HAL.
     if (getState() == StreamDescriptor::State::STANDBY) {
         StreamDescriptor::Reply reply;
-        if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
-                status != OK) {
-            return status;
-        }
+        RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply));
         if (reply.state != StreamDescriptor::State::IDLE) {
             ALOGE("%s: failed to get the stream out of standby, actual state: %s",
                     __func__, toString(reply.state).c_str());
@@ -345,9 +327,7 @@
         }
     }
     StreamDescriptor::Reply reply;
-    if (status_t status = sendCommand(burst, &reply); status != OK) {
-        return status;
-    }
+    RETURN_STATUS_IF_ERROR(sendCommand(burst, &reply));
     *transferred = reply.fmqByteCount;
     if (mIsInput) {
         LOG_ALWAYS_FATAL_IF(*transferred > bytes,
@@ -385,11 +365,8 @@
             if (state == StreamDescriptor::State::IDLE) {
                 StreamDescriptor::Reply localReply{};
                 StreamDescriptor::Reply* innerReply = reply ?: &localReply;
-                if (status_t status =
-                        sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply);
-                        status != OK) {
-                    return status;
-                }
+                RETURN_STATUS_IF_ERROR(
+                        sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
                 if (innerReply->state != StreamDescriptor::State::ACTIVE) {
                     ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
                             __func__, toString(innerReply->state).c_str());
@@ -452,10 +429,7 @@
         return BAD_VALUE;
     }
     int64_t aidlPosition = 0, aidlTimestamp = 0;
-    if (status_t status = getHardwarePosition(&aidlPosition, &aidlTimestamp); status != OK) {
-        return status;
-    }
-
+    RETURN_STATUS_IF_ERROR(getHardwarePosition(&aidlPosition, &aidlTimestamp));
     position->time_nanoseconds = aidlTimestamp;
     position->position_frames = static_cast<int32_t>(aidlPosition);
     return OK;
@@ -503,6 +477,11 @@
     }
     {
         std::lock_guard l(mLock);
+        // Not every command replies with 'latencyMs' field filled out, substitute the last
+        // returned value in that case.
+        if (reply->latencyMs <= 0) {
+            reply->latencyMs = mLastReply.latencyMs;
+        }
         mLastReply = *reply;
     }
     switch (reply->status) {
@@ -608,10 +587,8 @@
         return BAD_VALUE;
     }
     int64_t aidlFrames = 0, aidlTimestamp = 0;
-    if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
-        return OK;
-    }
-    *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
+    RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
+    *dspFrames = static_cast<uint32_t>(aidlFrames);
     return OK;
 }
 
@@ -680,10 +657,8 @@
         return BAD_VALUE;
     }
     int64_t aidlFrames = 0, aidlTimestamp = 0;
-    if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
-        return status;
-    }
-    *frames = std::max<int64_t>(0, aidlFrames);
+    RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
+    *frames = aidlFrames;
     timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
     timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
     return OK;
@@ -901,9 +876,7 @@
         return BAD_VALUE;
     }
     int32_t aidlXruns = 0;
-    if (status_t status = getXruns(&aidlXruns); status != OK) {
-        return status;
-    }
+    RETURN_STATUS_IF_ERROR(getXruns(&aidlXruns));
     *framesLost = std::max<int32_t>(0, aidlXruns);
     return OK;
 }
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 3b369bd..4acc6ac 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -207,10 +207,13 @@
 
     status_t getLatency(uint32_t *latency);
 
+    // Always returns non-negative values.
     status_t getObservablePosition(int64_t *frames, int64_t *timestamp);
 
+    // Always returns non-negative values.
     status_t getHardwarePosition(int64_t *frames, int64_t *timestamp);
 
+    // Always returns non-negative values.
     status_t getXruns(int32_t *frames);
 
     status_t transfer(void *buffer, size_t bytes, size_t *transferred);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 8be9c48..5c9f68e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1609,23 +1609,21 @@
         mFramesInput++;
     }
 
-    const int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
-    BufferFlightTiming_t startdata = { presentationUs, nowNs };
+    // mutex access to mBuffersInFlight and other stats
+    Mutex::Autolock al(mLatencyLock);
 
-    {
-        // mutex access to mBuffersInFlight and other stats
-        Mutex::Autolock al(mLatencyLock);
-
-
-        // XXX: we *could* make sure that the time is later than the end of queue
-        // as part of a consistency check...
+    // XXX: we *could* make sure that the time is later than the end of queue
+    // as part of a consistency check...
+    if (!mTunneled) {
+        const int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
+        BufferFlightTiming_t startdata = { presentationUs, nowNs };
         mBuffersInFlight.push_back(startdata);
-
-        if (mIsLowLatencyModeOn && mIndexOfFirstFrameWhenLowLatencyOn < 0) {
-            mIndexOfFirstFrameWhenLowLatencyOn = mInputBufferCounter;
-        }
-        ++mInputBufferCounter;
     }
+
+    if (mIsLowLatencyModeOn && mIndexOfFirstFrameWhenLowLatencyOn < 0) {
+        mIndexOfFirstFrameWhenLowLatencyOn = mInputBufferCounter;
+    }
+    ++mInputBufferCounter;
 }
 
 // when we get a buffer back from the codec
diff --git a/media/libstagefright/tests/HEVC/AndroidTest.xml b/media/libstagefright/tests/HEVC/AndroidTest.xml
index 00bb3e5..8c7bb91 100644
--- a/media/libstagefright/tests/HEVC/AndroidTest.xml
+++ b/media/libstagefright/tests/HEVC/AndroidTest.xml
@@ -34,6 +34,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="HEVCUtilsUnitTest" />
-        <option name="native-test-flag" value="-P /sdcard/tests/HEVCUtilsUnitTest-1.0/" />
+        <option name="native-test-flag" value="-P /sdcard/test/HEVCUtilsUnitTest-1.0/" />
     </test>
 </configuration>
diff --git a/media/libstagefright/timedtext/test/AndroidTest.xml b/media/libstagefright/timedtext/test/AndroidTest.xml
index 0d5d79f..b536059 100644
--- a/media/libstagefright/timedtext/test/AndroidTest.xml
+++ b/media/libstagefright/timedtext/test/AndroidTest.xml
@@ -34,6 +34,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="TimedTextUnitTest" />
-        <option name="native-test-flag" value="-P /data/local/tmp/TimedTextUnitTest-1.0/" />
+        <option name="native-test-flag" value="-P /sdcard/test/TimedTextUnitTest-1.0/" />
     </test>
 </configuration>
diff --git a/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp b/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
index 2016b2a..fee5c94 100644
--- a/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
+++ b/media/libstagefright/writer_fuzzers/WriterFuzzerBase.cpp
@@ -226,7 +226,13 @@
         mediaBuffer->add_ref();
 
         // This pushBuffer will wait until the mediaBuffer is consumed.
-        if (currentTrack->pushBuffer(mediaBuffer) != OK) {
+        android::status_t pushStatus = currentTrack->pushBuffer(mediaBuffer);
+
+        if (pushStatus != OK) {
+            if (pushStatus == INVALID_OPERATION) {
+                // In Case of INVALID_OPERATION, mObserver needs to be set before calling release()
+                mediaBuffer->setObserver(currentTrack.get());
+            }
             mediaBuffer->release();
         }
     }
diff --git a/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp b/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
index e5983e4..fba4230 100644
--- a/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
+++ b/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
@@ -17,6 +17,7 @@
 #include "fuzzer/FuzzedDataProvider.h"
 #include <C2Config.h>
 #include <C2Param.h>
+#include <android/api-level.h>
 
 using namespace std;
 
@@ -59,11 +60,31 @@
   if (!store) {
     return;
   }
-  android::sp<V1_1::IComponentStore> storeV1_1 =
+
+  int32_t platformVersion = android_get_device_api_level();
+  if (platformVersion >= __ANDROID_API_S__) {
+    android::sp<V1_2::IComponentStore> storeV1_2 =
+      new V1_2::utils::ComponentStore(store);
+    if (storeV1_2->registerAsService(string(kServiceName)) != android::OK) {
+      return;
+    }
+  } else if (platformVersion == __ANDROID_API_R__) {
+    android::sp<V1_1::IComponentStore> storeV1_1 =
       new V1_1::utils::ComponentStore(store);
-  if (storeV1_1->registerAsService(string(kServiceName)) != android::OK) {
+    if (storeV1_1->registerAsService(string(kServiceName)) != android::OK) {
+      return;
+    }
+  } else if (platformVersion == __ANDROID_API_Q__) {
+    android::sp<V1_0::IComponentStore> storeV1_0 =
+      new V1_0::utils::ComponentStore(store);
+    if (storeV1_0->registerAsService(string(kServiceName)) != android::OK) {
+      return;
+    }
+  }
+  else {
     return;
   }
+
   string const preferredStoreName = string(kServiceName);
   sp<IComponentStore> preferredStore =
       IComponentStore::getService(preferredStoreName.c_str());
diff --git a/media/module/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp b/media/module/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
index 8f8ad4e..86979f4 100644
--- a/media/module/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
+++ b/media/module/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
@@ -615,7 +615,7 @@
 }
 
 void CustomCsvReporter::PrintRunData(const Run& run) {
-    if (run.error_occurred) {
+    if (run.skipped) {
         return;
     }
     std::ostream& Out = GetOutputStream();
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp
index 8aafe33..6377195 100644
--- a/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp
+++ b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
@@ -40,7 +41,7 @@
 }
 
 void MtpMockDatabase::addObject(MtpObjectInfo* info) {
-    assert(hasStorage(info->storageID));
+    assert(hasStorage(info->mStorageID));
 
     // we take ownership
     mObjects.push_back(info);
diff --git a/media/mtp/tests/MtpFuzzer/mtp_data_packet_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_data_packet_fuzzer.cpp
index 83c6076..635c7a4 100644
--- a/media/mtp/tests/MtpFuzzer/mtp_data_packet_fuzzer.cpp
+++ b/media/mtp/tests/MtpFuzzer/mtp_data_packet_fuzzer.cpp
@@ -17,6 +17,7 @@
 #include <MtpDataPacket.h>
 #include <MtpDevHandle.h>
 #include <MtpPacketFuzzerUtils.h>
+#include <functional>
 #include <fuzzer/FuzzedDataProvider.h>
 #include <utils/String16.h>
 
diff --git a/media/mtp/tests/MtpFuzzer/mtp_device_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_device_fuzzer.cpp
index c32d28a..d34eae0 100644
--- a/media/mtp/tests/MtpFuzzer/mtp_device_fuzzer.cpp
+++ b/media/mtp/tests/MtpFuzzer/mtp_device_fuzzer.cpp
@@ -23,6 +23,7 @@
 #include <MtpStringBuffer.h>
 #include <android-base/unique_fd.h>
 #include <fcntl.h>
+#include <functional>
 #include <fuzzer/FuzzedDataProvider.h>
 #include <linux/usb/ch9.h>
 #include <sys/mman.h>
diff --git a/media/mtp/tests/MtpFuzzer/mtp_event_packet_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_event_packet_fuzzer.cpp
index 3bd3be2..c00b4ca 100644
--- a/media/mtp/tests/MtpFuzzer/mtp_event_packet_fuzzer.cpp
+++ b/media/mtp/tests/MtpFuzzer/mtp_event_packet_fuzzer.cpp
@@ -17,6 +17,7 @@
 #include <MtpDevHandle.h>
 #include <MtpEventPacket.h>
 #include <MtpPacketFuzzerUtils.h>
+#include <functional>
 #include <fuzzer/FuzzedDataProvider.h>
 
 using namespace android;
diff --git a/media/mtp/tests/MtpFuzzer/mtp_packet_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_packet_fuzzer.cpp
index 6fc2a96..d1836e7 100644
--- a/media/mtp/tests/MtpFuzzer/mtp_packet_fuzzer.cpp
+++ b/media/mtp/tests/MtpFuzzer/mtp_packet_fuzzer.cpp
@@ -17,7 +17,9 @@
 #include <MtpDevHandle.h>
 #include <MtpPacket.h>
 #include <MtpPacketFuzzerUtils.h>
+#include <functional>
 #include <fuzzer/FuzzedDataProvider.h>
+#include <mtp.h>
 
 using namespace android;
 
@@ -35,7 +37,8 @@
 };
 
 void MtpPacketFuzzer::process() {
-    MtpPacket mtpPacket(mFdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize)); /*bufferSize*/
+    MtpPacket mtpPacket(mFdp.ConsumeIntegralInRange<size_t>(MTP_CONTAINER_HEADER_SIZE,
+                                                            kMaxSize)); /*bufferSize*/
     while (mFdp.remaining_bytes() > 0) {
         auto mtpPacketAPI = mFdp.PickValueInArray<const std::function<void()>>({
                 [&]() {
diff --git a/media/mtp/tests/MtpFuzzer/mtp_property_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_property_fuzzer.cpp
index 6300256..7a657c0 100644
--- a/media/mtp/tests/MtpFuzzer/mtp_property_fuzzer.cpp
+++ b/media/mtp/tests/MtpFuzzer/mtp_property_fuzzer.cpp
@@ -18,6 +18,7 @@
 #include <MtpDevHandle.h>
 #include <MtpPacketFuzzerUtils.h>
 #include <MtpProperty.h>
+#include <functional>
 #include <fuzzer/FuzzedDataProvider.h>
 #include <utils/String16.h>
 
diff --git a/media/mtp/tests/MtpFuzzer/mtp_request_packet_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_request_packet_fuzzer.cpp
index 19fbc5b..3b2fae2 100644
--- a/media/mtp/tests/MtpFuzzer/mtp_request_packet_fuzzer.cpp
+++ b/media/mtp/tests/MtpFuzzer/mtp_request_packet_fuzzer.cpp
@@ -17,8 +17,9 @@
 #include <MtpDevHandle.h>
 #include <MtpPacketFuzzerUtils.h>
 #include <MtpRequestPacket.h>
-#include <fuzzer/FuzzedDataProvider.h>
 #include <fstream>
+#include <functional>
+#include <fuzzer/FuzzedDataProvider.h>
 
 using namespace android;
 
diff --git a/media/mtp/tests/MtpFuzzer/mtp_response_packet_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_response_packet_fuzzer.cpp
index 697785f..a841d2f 100644
--- a/media/mtp/tests/MtpFuzzer/mtp_response_packet_fuzzer.cpp
+++ b/media/mtp/tests/MtpFuzzer/mtp_response_packet_fuzzer.cpp
@@ -17,6 +17,7 @@
 #include <MtpDevHandle.h>
 #include <MtpPacketFuzzerUtils.h>
 #include <MtpResponsePacket.h>
+#include <functional>
 #include <fuzzer/FuzzedDataProvider.h>
 
 using namespace android;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index bbfe763..dfe3157 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -825,7 +825,10 @@
     if (mStatus != NO_ERROR || mEffectInterface == 0) {
         return;
     }
-    mEffectInterface->command(EFFECT_CMD_RESET, 0, NULL, 0, NULL);
+
+    int reply = 0;
+    uint32_t replySize = sizeof(reply);
+    mEffectInterface->command(EFFECT_CMD_RESET, 0, NULL, &replySize, &reply);
 }
 
 status_t AudioFlinger::EffectModule::configure()
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ad8cdb9..daf3f39 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -452,9 +452,9 @@
 status_t AudioPolicyManager::deviceToAudioPort(audio_devices_t device, const char* device_address,
                                                const char* device_name,
                                                media::AudioPortFw* aidlPort) {
-    DeviceDescriptorBase devDescr(device, device_address);
-    devDescr.setName(device_name);
-    return devDescr.writeToParcelable(aidlPort);
+    const auto devDescr = sp<DeviceDescriptorBase>::make(device, device_address);
+    devDescr->setName(device_name);
+    return devDescr->writeToParcelable(aidlPort);
 }
 
 void AudioPolicyManager::setEngineDeviceConnectionState(const sp<DeviceDescriptor> device,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 98298ea..7f3130e 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -86,6 +86,7 @@
 };
 
 #define CAMERA_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0)
+#define CAMERA_DEVICE_API_VERSION_1_2 HARDWARE_DEVICE_API_VERSION(1, 2)
 #define CAMERA_DEVICE_API_VERSION_3_0 HARDWARE_DEVICE_API_VERSION(3, 0)
 #define CAMERA_DEVICE_API_VERSION_3_1 HARDWARE_DEVICE_API_VERSION(3, 1)
 #define CAMERA_DEVICE_API_VERSION_3_2 HARDWARE_DEVICE_API_VERSION(3, 2)
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4198b71..4344902 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -51,6 +51,7 @@
 #include <cutils/properties.h>
 #include <camera/StringUtils.h>
 
+#include <android-base/properties.h>
 #include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
 #include <android/hardware/camera2/ICameraDeviceUser.h>
 
@@ -749,8 +750,7 @@
         auto firstRequest = requestList->begin();
         for (auto& outputStream : (*firstRequest)->mOutputStreams) {
             if (outputStream->isVideoStream()) {
-                (*firstRequest)->mBatchSize = requestList->size();
-                outputStream->setBatchSize(requestList->size());
+                applyMaxBatchSizeLocked(requestList, outputStream);
                 break;
             }
         }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index d7cfa94..7243fc0 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -656,6 +656,15 @@
     status_t initializeCommonLocked();
 
     /**
+     * Update capture request list so that each batch size honors the batch_size_max report from
+     * the HAL. Set the batch size to output stream for buffer operations.
+     *
+     * Must be called with mLock held.
+     */
+    virtual void applyMaxBatchSizeLocked(
+            RequestList* requestList, const sp<camera3::Camera3OutputStreamInterface>& stream) = 0;
+
+    /**
      * Get the last request submitted to the hal by the request thread.
      *
      * Must be called with mLock held.
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index 1f9313e..1f2ac23 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -51,6 +51,7 @@
 
 #include <aidl/android/hardware/camera/device/ICameraInjectionSession.h>
 #include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/properties.h>
 #include <android/binder_ibinder_platform.h>
 #include <android/hardware/camera2/ICameraDeviceUser.h>
 #include <camera/StringUtils.h>
@@ -309,6 +310,20 @@
         }
     }
 
+    // batch size limit is applied to the device with camera device version larger than 3.2 which is
+    // AIDL v2
+    hardware::hidl_version maxVersion{0, 0};
+    IPCTransport transport = IPCTransport::AIDL;
+    res = manager->getHighestSupportedVersion(mId, &maxVersion, &transport);
+    if (res != OK) {
+        ALOGE("%s: Error in getting camera device version id: %s (%d)", __FUNCTION__,
+              strerror(-res), res);
+        return res;
+    }
+    int deviceVersion = HARDWARE_DEVICE_API_VERSION(maxVersion.get_major(), maxVersion.get_minor());
+
+    mBatchSizeLimitEnabled = (deviceVersion >= CAMERA_DEVICE_API_VERSION_1_2);
+
     return initializeCommonLocked();
 }
 
@@ -1572,6 +1587,66 @@
     return OK;
 }
 
+void AidlCamera3Device::applyMaxBatchSizeLocked(
+        RequestList* requestList, const sp<camera3::Camera3OutputStreamInterface>& stream) {
+    int batchSize = requestList->size();
+
+    if (!mBatchSizeLimitEnabled) {
+        (*requestList->begin())->mBatchSize = batchSize;
+        stream->setBatchSize(batchSize);
+        return;
+    }
+
+    const auto& metadata = (*requestList->begin())->mSettingsList.begin()->metadata;
+
+    uint32_t tag = ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS;
+    auto sensorPixelModeEntry = metadata.find(ANDROID_SENSOR_PIXEL_MODE);
+    if (sensorPixelModeEntry.count != 0) {
+        if (ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION == sensorPixelModeEntry.data.u8[0]) {
+            tag = ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+        }
+    }
+
+    const auto fpsRange = metadata.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
+    if (fpsRange.count > 1) {
+        auto configEntry = mDeviceInfo.find(tag);
+        for (size_t index = 4; index < configEntry.count; index += 5) {
+            if (stream->getWidth() == static_cast<uint32_t>(configEntry.data.i32[index - 4]) &&
+                stream->getHeight() == static_cast<uint32_t>(configEntry.data.i32[index - 3]) &&
+                fpsRange.data.i32[0] == configEntry.data.i32[index - 2] &&
+                fpsRange.data.i32[1] == configEntry.data.i32[index - 1]) {
+                const int maxBatchSize = configEntry.data.i32[index - 1] / 30;
+                const int reportedSize = configEntry.data.i32[index];
+
+                if (maxBatchSize % reportedSize == 0 && requestList->size() % reportedSize == 0) {
+                    batchSize = reportedSize;
+                    ALOGVV("Matching high speed configuration found. Limit batch size to %d",
+                           batchSize);
+                } else if (maxBatchSize % reportedSize == 0 &&
+                           reportedSize % requestList->size() == 0) {
+                    ALOGVV("Matching high speed configuration found, but requested batch size is "
+                           "divisor of batch_size_max. No need to limit batch size.");
+                } else {
+                    ALOGW("Matching high speed configuration found, but batch_size_max is not a "
+                          "divisor of corresponding fps_max/30 or requested batch size is not a "
+                          "divisor of batch_size_max, (fps_max %d, batch_size_max %d, requested "
+                          "batch size %zu)",
+                          configEntry.data.i32[index - 1], reportedSize, requestList->size());
+                }
+                break;
+            }
+        }
+    }
+
+    for (auto request = requestList->begin(); request != requestList->end(); request++) {
+        if (requestList->distance(requestList->begin(), request) % batchSize == 0) {
+            (*request)->mBatchSize = batchSize;
+        }
+    }
+
+    stream->setBatchSize(batchSize);
+}
+
 status_t AidlCamera3Device::injectionCameraInitialize(const std::string &injectedCamId,
             sp<CameraProviderManager> manager) {
         return (static_cast<AidlCamera3DeviceInjectionMethods *>
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
index f4554d4..4d7d139 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -252,6 +252,10 @@
     };
 
   private:
+    virtual void applyMaxBatchSizeLocked(
+            RequestList* requestList,
+            const sp<camera3::Camera3OutputStreamInterface>& stream) override;
+
     virtual status_t injectionCameraInitialize(const std::string &injectCamId,
             sp<CameraProviderManager> manager) override;
 
@@ -271,6 +275,9 @@
 
     std::shared_ptr<AidlCameraDeviceCallbacks> mCallbacks = nullptr;
 
+    // Whether the batch_size_max field in the high speed configuration actually applied to
+    // capture requests.
+    bool mBatchSizeLimitEnabled = false;
 
 }; // class AidlCamera3Device
 
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index c22aad6..d234d83 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -699,6 +699,14 @@
     // Java side to make sure the CameraCaptureSession is properly closed
 }
 
+void HidlCamera3Device::applyMaxBatchSizeLocked(
+        RequestList* requestList, const sp<camera3::Camera3OutputStreamInterface>& stream) {
+    int batchSize = requestList->size();
+
+    (*requestList->begin())->mBatchSize = batchSize;
+    stream->setBatchSize(batchSize);
+}
+
 sp<Camera3Device::RequestThread> HidlCamera3Device::createNewRequestThread(
                 wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker,
                 sp<Camera3Device::HalInterface> interface,
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
index e64bcf0..2d33277 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
@@ -213,6 +213,10 @@
     hardware::Return<void> notifyHelper(
             const hardware::hidl_vec<NotifyMsgType>& msgs);
 
+    virtual void applyMaxBatchSizeLocked(
+            RequestList* requestList,
+            const sp<camera3::Camera3OutputStreamInterface>& stream) override;
+
     virtual status_t injectionCameraInitialize(const std::string &injectCamId,
             sp<CameraProviderManager> manager) override;