Merge "Implement Camera Id Remapping in CameraService" into main
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 43dae1d..38c5aa5 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -23,6 +23,7 @@
     name: "libcodec2_client",
 
     srcs: [
+        "GraphicsTracker.cpp",
         "client.cpp",
         "output.cpp",
     ],
@@ -49,6 +50,7 @@
         "libgui",
         "libhidlbase",
         "liblog",
+        "libnativewindow",
         "libstagefright_bufferpool@2.0.1",
         "libui",
         "libutils",
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
new file mode 100644
index 0000000..5a2cb86
--- /dev/null
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -0,0 +1,836 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <sys/eventfd.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <private/android/AHardwareBufferHelpers.h>
+#include <vndk/hardware_buffer.h>
+
+#include <codec2/aidl/GraphicsTracker.h>
+
+namespace aidl::android::hardware::media::c2::implementation {
+
+namespace {
+
+c2_status_t retrieveAHardwareBufferId(const C2ConstGraphicBlock &blk, uint64_t *bid) {
+    // TODO
+    (void)blk;
+    (void)bid;
+    return C2_OK;
+}
+
+} // anonymous namespace
+
+GraphicsTracker::BufferItem::BufferItem(
+        uint32_t generation, int slot, const sp<GraphicBuffer>& buf, const sp<Fence>& fence) :
+        mInit{false}, mGeneration{generation}, mSlot{slot} {
+    if (!buf) {
+        return;
+    }
+    AHardwareBuffer *pBuf = AHardwareBuffer_from_GraphicBuffer(buf.get());
+    int ret = AHardwareBuffer_getId(pBuf, &mId);
+    if (ret != ::android::OK) {
+        return;
+    }
+    mUsage = buf->getUsage();
+    AHardwareBuffer_acquire(pBuf);
+    mBuf = pBuf;
+    mFence = fence;
+    mInit = true;
+}
+
+GraphicsTracker::BufferItem::BufferItem(
+        uint32_t generation,
+        AHardwareBuffer_Desc *desc, AHardwareBuffer *pBuf) :
+        mInit{true}, mGeneration{generation}, mSlot{-1},
+        mBuf{pBuf}, mUsage{::android::AHardwareBuffer_convertToGrallocUsageBits(desc->usage)},
+        mFence{Fence::NO_FENCE} {
+}
+
+GraphicsTracker::BufferItem::~BufferItem() {
+    if (mInit) {
+        AHardwareBuffer_release(mBuf);
+    }
+}
+
+sp<GraphicBuffer> GraphicsTracker::BufferItem::updateBuffer(
+        uint64_t newUsage, uint32_t newGeneration) {
+    if (!mInit) {
+        return nullptr;
+    }
+    newUsage |= mUsage;
+    uint64_t ahbUsage = ::android::AHardwareBuffer_convertFromGrallocUsageBits(newUsage);
+    AHardwareBuffer_Desc desc;
+    AHardwareBuffer_describe(mBuf, &desc);
+    // TODO: we need well-established buffer migration features from graphics.
+    // (b/273776738)
+    desc.usage = ahbUsage;
+    const native_handle_t *handle = AHardwareBuffer_getNativeHandle(mBuf);
+    if (!handle) {
+        return nullptr;
+    }
+
+    AHardwareBuffer *newBuf;
+    int err = AHardwareBuffer_createFromHandle(&desc, handle,
+                                     AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
+                                     &newBuf);
+    if (err != ::android::NO_ERROR) {
+        return nullptr;
+    }
+
+    GraphicBuffer *gb = ::android::AHardwareBuffer_to_GraphicBuffer(newBuf);
+    if (!gb) {
+        AHardwareBuffer_release(newBuf);
+        return nullptr;
+    }
+
+    gb->setGenerationNumber(newGeneration);
+    mUsage = newUsage;
+    mGeneration = newGeneration;
+    AHardwareBuffer_release(mBuf);
+    // acquire is already done when creating.
+    mBuf = newBuf;
+    return gb;
+}
+
+void GraphicsTracker::BufferCache::waitOnSlot(int slot) {
+    // TODO: log
+    CHECK(0 <= slot && slot < kNumSlots);
+    BlockedSlot *p = &mBlockedSlots[slot];
+    std::unique_lock<std::mutex> l(p->l);
+    while (p->blocked) {
+        p->cv.wait(l);
+    }
+}
+
+void GraphicsTracker::BufferCache::blockSlot(int slot) {
+    CHECK(0 <= slot && slot < kNumSlots);
+    BlockedSlot *p = &mBlockedSlots[slot];
+    std::unique_lock<std::mutex> l(p->l);
+    p->blocked = true;
+}
+
+void GraphicsTracker::BufferCache::unblockSlot(int slot) {
+    CHECK(0 <= slot && slot < kNumSlots);
+    BlockedSlot *p = &mBlockedSlots[slot];
+    std::unique_lock<std::mutex> l(p->l);
+    p->blocked = false;
+    l.unlock();
+    p->cv.notify_one();
+}
+
+GraphicsTracker::GraphicsTracker(int maxDequeueCount)
+    : mMaxDequeue{maxDequeueCount}, mMaxDequeueRequested{maxDequeueCount},
+    mMaxDequeueCommitted{maxDequeueCount},
+    mMaxDequeueRequestedSeqId{0UL}, mMaxDequeueCommittedSeqId{0ULL},
+    mDequeueable{maxDequeueCount},
+    mTotalDequeued{0}, mTotalCancelled{0}, mTotalDropped{0}, mTotalReleased{0},
+    mInConfig{false}, mStopped{false} {
+    if (maxDequeueCount <= 0) {
+        mMaxDequeue = kDefaultMaxDequeue;
+        mMaxDequeueRequested = kDefaultMaxDequeue;
+        mMaxDequeueCommitted = kDefaultMaxDequeue;
+        mDequeueable = kDefaultMaxDequeue;
+    }
+    int allocEventFd = ::eventfd(mDequeueable, EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE);
+    int statusEventFd = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+
+    mAllocEventFd.reset(allocEventFd);
+    mStopEventFd.reset(statusEventFd);
+
+    mEventQueueThread = std::thread([this](){processEvent();});
+
+    CHECK(allocEventFd >= 0 && statusEventFd >= 0);
+    CHECK(mEventQueueThread.joinable());
+}
+
+GraphicsTracker::~GraphicsTracker() {
+    stop();
+    if (mEventQueueThread.joinable()) {
+        std::unique_lock<std::mutex> l(mEventLock);
+        mStopEventThread = true;
+        l.unlock();
+        mEventCv.notify_one();
+        mEventQueueThread.join();
+    }
+}
+
+bool GraphicsTracker::adjustDequeueConfLocked(bool *updateDequeue) {
+    // TODO: can't we adjust during config? not committing it may safe?
+    *updateDequeue = false;
+    if (!mInConfig && mMaxDequeueRequested < mMaxDequeue) {
+        int delta = mMaxDequeue - mMaxDequeueRequested;
+        // Since we are supposed to increase mDequeuable by one already
+        int adjustable = mDequeueable + 1;
+        if (adjustable >= delta) {
+            mMaxDequeue = mMaxDequeueRequested;
+            mDequeueable -= (delta - 1);
+        } else {
+            mMaxDequeue -= adjustable;
+            mDequeueable = 0;
+        }
+        if (mMaxDequeueRequested == mMaxDequeue && mMaxDequeueRequested != mMaxDequeueCommitted) {
+            *updateDequeue = true;
+        }
+        return true;
+    }
+    return false;
+}
+
+c2_status_t GraphicsTracker::configureGraphics(
+        const sp<IGraphicBufferProducer>& igbp, uint32_t generation) {
+    std::shared_ptr<BufferCache> prevCache;
+    int prevDequeueCommitted;
+
+    std::unique_lock<std::mutex> cl(mConfigLock);
+    {
+        std::unique_lock<std::mutex> l(mLock);
+        mInConfig = true;
+        prevCache = mBufferCache;
+        prevDequeueCommitted = mMaxDequeueCommitted;
+    }
+    // NOTE: Switching to the same surface is blocked from MediaCodec.
+    // Switching to the same surface might not work if tried, since disconnect()
+    // to the old surface in MediaCodec and allocate from the new surface from
+    // GraphicsTracker cannot be synchronized properly.
+    uint64_t bqId{0ULL};
+    ::android::status_t ret = ::android::OK;
+    if (igbp) {
+        ret = igbp->getUniqueId(&bqId);
+    }
+    if (ret != ::android::OK || prevCache->mGeneration == generation || prevCache->mBqId == bqId) {
+        return C2_BAD_VALUE;
+    }
+    ret = igbp->setMaxDequeuedBufferCount(prevDequeueCommitted);
+    if (ret != ::android::OK) {
+        // TODO: sort out the error from igbp and return an error accordingly.
+        return C2_CORRUPTED;
+    }
+    std::shared_ptr<BufferCache> newCache = std::make_shared<BufferCache>(bqId, generation, igbp);
+    {
+        std::unique_lock<std::mutex> l(mLock);
+        mInConfig = false;
+        mBufferCache = newCache;
+    }
+    return C2_OK;
+}
+
+c2_status_t GraphicsTracker::configureMaxDequeueCount(int maxDequeueCount) {
+    std::shared_ptr<BufferCache> cache;
+
+    // max dequeue count which can be committed to IGBP.
+    // (Sometimes maxDequeueCount cannot be committed if the number of
+    // dequeued buffer count is bigger.)
+    int maxDequeueToCommit;
+    // max dequeue count which is committed to IGBP currently
+    // (actually mMaxDequeueCommitted, but needs to be read outside lock.)
+    int curMaxDequeueCommitted;
+    std::unique_lock<std::mutex> cl(mConfigLock);
+    {
+        std::unique_lock<std::mutex> l(mLock);
+        if (mMaxDequeueRequested == maxDequeueCount) {
+            return C2_OK;
+        }
+        mInConfig = true;
+        mMaxDequeueRequested = maxDequeueCount;
+        cache = mBufferCache;
+        curMaxDequeueCommitted = mMaxDequeueCommitted;
+        if (mMaxDequeue <= maxDequeueCount) {
+            maxDequeueToCommit = maxDequeueCount;
+        } else {
+            // Since mDequeuable is decreasing,
+            // a delievered ready to allocate event may not be fulfilled.
+            // Another waiting via a waitable object may be necessary in the case.
+            int delta = mMaxDequeue - maxDequeueCount;
+            if (delta <= mDequeueable) {
+                maxDequeueToCommit = maxDequeueCount;
+                mDequeueable -= delta;
+            } else {
+                maxDequeueToCommit = mMaxDequeue - mDequeueable;
+                mDequeueable = 0;
+            }
+        }
+    }
+
+    bool committed = true;
+    if (cache->mIgbp && maxDequeueToCommit != curMaxDequeueCommitted) {
+        ::android::status_t ret = cache->mIgbp->setMaxDequeuedBufferCount(maxDequeueToCommit);
+        committed = (ret == ::android::OK);
+        if (!committed) {
+            // This should not happen.
+            ALOGE("dequeueCount failed with error(%d)", (int)ret);
+        }
+    }
+
+    {
+        std::unique_lock<std::mutex> l(mLock);
+        mInConfig = false;
+        if (committed) {
+            mMaxDequeueCommitted = maxDequeueToCommit;
+            int delta = mMaxDequeueCommitted - mMaxDequeue;
+            if (delta > 0) {
+                mDequeueable += delta;
+                l.unlock();
+                writeIncDequeueable(delta);
+            }
+        }
+    }
+
+    if (!committed) {
+        return C2_CORRUPTED;
+    }
+    return C2_OK;
+}
+
+void GraphicsTracker::updateDequeueConf() {
+    std::shared_ptr<BufferCache> cache;
+    int dequeueCommit;
+    std::unique_lock<std::mutex> cl(mConfigLock);
+    {
+        std::unique_lock<std::mutex> l(mLock);
+        if (mMaxDequeue == mMaxDequeueRequested && mMaxDequeueCommitted != mMaxDequeueRequested) {
+            dequeueCommit = mMaxDequeue;
+            mInConfig = true;
+            cache = mBufferCache;
+        } else {
+            return;
+        }
+    }
+    bool committed = true;
+    if (cache->mIgbp) {
+        ::android::status_t ret = cache->mIgbp->setMaxDequeuedBufferCount(dequeueCommit);
+        committed = (ret == ::android::OK);
+        if (!committed) {
+            // This should not happen.
+            ALOGE("dequeueCount failed with error(%d)", (int)ret);
+        }
+    }
+    int cleared = 0;
+    {
+        // cache == mCache here, since we locked config.
+        std::unique_lock<std::mutex> l(mLock);
+        mInConfig = false;
+        if (committed) {
+            if (cache->mIgbp && dequeueCommit < mMaxDequeueCommitted) {
+                // we are shrinking # of buffers, so clearing the cache.
+                for (auto it = cache->mBuffers.begin(); it != cache->mBuffers.end();) {
+                    uint64_t bid = it->second->mId;
+                    if (mDequeued.count(bid) == 0 || mDeallocating.count(bid) > 0) {
+                        ++cleared;
+                        it = cache->mBuffers.erase(it);
+                    } else {
+                        ++it;
+                    }
+                }
+            }
+            mMaxDequeueCommitted = dequeueCommit;
+        }
+    }
+    if (cleared > 0) {
+        ALOGD("%d buffers are cleared from cache, due to IGBP capacity change", cleared);
+    }
+
+}
+
+void GraphicsTracker::stop() {
+    bool expected = false;
+    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");
+        }
+    }
+}
+
+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
+        std::unique_lock<std::mutex> l(mEventLock);
+        mIncDequeueable += inc;
+        l.unlock();
+        mEventCv.notify_one();
+        ALOGW("updating dequeueable to eventfd 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;
+
+    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;
+                }
+                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;
+        }
+    }
+}
+
+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;
+        }
+        if (*statusFd >= 0) {
+            ::close(*statusFd);
+            *statusFd = -1;
+        }
+        return C2_NO_MEMORY;
+    }
+    return C2_OK;
+}
+
+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);
+        if (ret < 0) {
+            if (errno == EINTR) {
+                // Do we really need to care for cancel due to signal handling?
+                return C2_CANCELED;
+            }
+            if (errno == EAGAIN) {
+                // proper usage of waitable object should not return this.
+                // but there could be alloc requests from HAL ignoring the internal status.
+                return C2_BLOCKING;
+            }
+            CHECK(errno != 0);
+        }
+        mDequeueable--;
+        *cache = mBufferCache;
+        return C2_OK;
+    }
+    return C2_BLOCKING;
+}
+
+// If {@code cached} is {@code true}, {@code pBuffer} should be read from the
+// current cached status. Otherwise, {@code pBuffer} should be written to
+// current caches status.
+void GraphicsTracker::commitAllocate(c2_status_t res, const std::shared_ptr<BufferCache> &cache,
+                    bool cached, int slot, const sp<Fence> &fence,
+                    std::shared_ptr<BufferItem> *pBuffer, bool *updateDequeue) {
+    std::unique_lock<std::mutex> l(mLock);
+    if (res == C2_OK) {
+        if (cached) {
+            auto it = cache->mBuffers.find(slot);
+            CHECK(it != cache->mBuffers.end());
+            it->second->mFence = fence;
+            *pBuffer = it->second;
+        } else if (cache.get() == mBufferCache.get() && mBufferCache->mIgbp) {
+            // Cache the buffer if it is allocated from the current IGBP
+            CHECK(slot >= 0);
+            auto ret = mBufferCache->mBuffers.emplace(slot, *pBuffer);
+            if (!ret.second) {
+                ret.first->second = *pBuffer;
+            }
+        }
+        uint64_t bid = (*pBuffer)->mId;
+        auto mapRet = mDequeued.emplace(bid, *pBuffer);
+        CHECK(mapRet.second);
+    } else {
+        if (adjustDequeueConfLocked(updateDequeue)) {
+            return;
+        }
+        mDequeueable++;
+        l.unlock();
+        writeIncDequeueable(1);
+    }
+}
+
+
+// if a buffer is newly allocated, {@code cached} is {@code false},
+// and the buffer is in the {@code buffer}
+// otherwise, {@code cached} is {@code false} and the buffer should be
+// retrieved by commitAllocate();
+c2_status_t GraphicsTracker::_allocate(const std::shared_ptr<BufferCache> &cache,
+                                      uint32_t width, uint32_t height, PixelFormat format,
+                                      int64_t usage,
+                                      bool *cached,
+                                      int *rSlotId,
+                                      sp<Fence> *rFence,
+                                      std::shared_ptr<BufferItem> *buffer) {
+    ::android::sp<IGraphicBufferProducer> igbp = cache->mIgbp;
+    uint32_t generation = cache->mGeneration;
+    if (!igbp) {
+        // allocate directly
+        AHardwareBuffer_Desc desc;
+        desc.width = width;
+        desc.height = height;
+        desc.layers = 1u;
+        desc.format = ::android::AHardwareBuffer_convertFromPixelFormat(format);
+        desc.usage = ::android::AHardwareBuffer_convertFromGrallocUsageBits(usage);
+        desc.rfu0 = 0;
+        desc.rfu1 = 0;
+
+        AHardwareBuffer *buf;
+        int ret = AHardwareBuffer_allocate(&desc, &buf);
+        if (ret != ::android::OK) {
+            ALOGE("direct allocation of AHB failed(%d)", ret);
+            return ret == ::android::NO_MEMORY ? C2_NO_MEMORY : C2_CORRUPTED;
+        }
+        *cached = false;
+        *buffer = std::make_shared<BufferItem>(generation, &desc, buf);
+        if (!*buffer) {
+            AHardwareBuffer_release(buf);
+            return C2_NO_MEMORY;
+        }
+        return C2_OK;
+    }
+
+    int slotId;
+    uint64_t outBufferAge;
+    ::android::FrameEventHistoryDelta outTimestamps;
+    sp<Fence> fence;
+
+    ::android::status_t status = igbp->dequeueBuffer(
+            &slotId, &fence, width, height, format, usage, &outBufferAge, &outTimestamps);
+    if (status < ::android::OK) {
+        ALOGE("dequeueBuffer() error %d", (int)status);
+        return C2_CORRUPTED;
+    }
+    cache->waitOnSlot(slotId);
+    bool exists = false;
+    {
+        std::unique_lock<std::mutex> l(mLock);
+        if (cache.get() == mBufferCache.get() &&
+            cache->mBuffers.find(slotId) != cache->mBuffers.end()) {
+            exists = true;
+        }
+    }
+    bool needsRealloc = status & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
+    if (needsRealloc || !exists) {
+        sp<GraphicBuffer> realloced;
+        status = igbp->requestBuffer(slotId, &realloced);
+        if (status != ::android::OK) {
+            igbp->cancelBuffer(slotId, fence);
+            return C2_CORRUPTED;
+        }
+        *buffer = std::make_shared<BufferItem>(generation, slotId, realloced, fence);
+        if (!(*buffer)->mInit) {
+            buffer->reset();
+            igbp->cancelBuffer(slotId, fence);
+            return C2_CORRUPTED;
+        }
+        *cached = false;
+        return C2_OK;
+    }
+    *cached = true;
+    *rSlotId = slotId;
+    *rFence = fence;
+    return C2_OK;
+}
+
+c2_status_t GraphicsTracker::allocate(
+        uint32_t width, uint32_t height, PixelFormat format, uint64_t usage,
+        AHardwareBuffer **buf, sp<Fence> *rFence) {
+    if (mStopped.load() == true) {
+        return C2_BAD_STATE;
+    }
+    std::shared_ptr<BufferCache> cache;
+    c2_status_t res = requestAllocate(&cache);
+    if (res != C2_OK) {
+        return res;
+    }
+
+    bool cached = false;
+    int slotId;
+    sp<Fence> fence;
+    std::shared_ptr<BufferItem> buffer;
+    bool updateDequeue;
+    res = _allocate(cache, width, height, format, usage, &cached, &slotId, &fence, &buffer);
+    commitAllocate(res, cache, cached, slotId, fence, &buffer, &updateDequeue);
+    if (res == C2_OK) {
+        *buf = buffer->mBuf;
+        *rFence = buffer->mFence;
+        // *buf should be valid even if buffer is dtor-ed.
+        AHardwareBuffer_acquire(*buf);
+    }
+    if (updateDequeue) {
+        updateDequeueConf();
+    }
+    return res;
+}
+
+c2_status_t GraphicsTracker::requestDeallocate(uint64_t bid, const sp<Fence> &fence,
+                                              bool *completed, bool *updateDequeue,
+                                              std::shared_ptr<BufferCache> *cache, int *slotId,
+                                              sp<Fence> *rFence) {
+    std::unique_lock<std::mutex> l(mLock);
+    if (mDeallocating.find(bid) != mDeallocating.end()) {
+        ALOGE("Tries to deallocate a buffer which is already deallocating or rendering");
+        return C2_DUPLICATE;
+    }
+    auto it = mDequeued.find(bid);
+    if (it == mDequeued.end()) {
+        ALOGE("Tried to deallocate non dequeued buffer");
+        return C2_NOT_FOUND;
+    }
+
+    std::shared_ptr<BufferItem> buffer = it->second;
+    if (buffer->mGeneration == mBufferCache->mGeneration && mBufferCache->mIgbp) {
+        auto it = mBufferCache->mBuffers.find(buffer->mSlot);
+        CHECK(it != mBufferCache->mBuffers.end() && it->second.get() == buffer.get());
+        *cache = mBufferCache;
+        *slotId = buffer->mSlot;
+        *rFence = ( fence == Fence::NO_FENCE) ? buffer->mFence : fence;
+        // mark this deallocating
+        mDeallocating.emplace(bid);
+        mBufferCache->blockSlot(buffer->mSlot);
+        *completed = false;
+    } else { // buffer is not from the current underlying Graphics.
+        mDequeued.erase(bid);
+        *completed = true;
+        if (adjustDequeueConfLocked(updateDequeue)) {
+            return C2_OK;
+        }
+        mDequeueable++;
+        l.unlock();
+        writeIncDequeueable(1);
+    }
+    return C2_OK;
+}
+
+void GraphicsTracker::commitDeallocate(
+        std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid) {
+    std::lock_guard<std::mutex> l(mLock);
+    size_t del1 = mDequeued.erase(bid);
+    size_t del2 = mDeallocating.erase(bid);
+    CHECK(del1 > 0 && del2 > 0);
+    mDequeueable++;
+    if (cache) {
+        cache->unblockSlot(slotId);
+    }
+}
+
+
+c2_status_t GraphicsTracker::deallocate(uint64_t bid, const sp<Fence> &fence) {
+    bool completed;
+    bool updateDequeue;
+    std::shared_ptr<BufferCache> cache;
+    int slotId;
+    sp<Fence> rFence;
+    c2_status_t res = requestDeallocate(bid, fence, &completed, &updateDequeue,
+                                        &cache, &slotId, &rFence);
+    if (res != C2_OK) {
+        return res;
+    }
+    if (completed == true) {
+        if (updateDequeue) {
+            updateDequeueConf();
+        }
+        return C2_OK;
+    }
+
+    // ignore return value since IGBP could be already stale.
+    // cache->mIgbp is not null, if completed is false.
+    (void)cache->mIgbp->cancelBuffer(slotId, rFence);
+
+    commitDeallocate(cache, slotId, bid);
+    return C2_OK;
+}
+
+c2_status_t GraphicsTracker::requestRender(uint64_t bid, std::shared_ptr<BufferCache> *cache,
+                                          std::shared_ptr<BufferItem> *pBuffer,
+                                          bool *updateDequeue) {
+    std::unique_lock<std::mutex> l(mLock);
+    if (mDeallocating.find(bid) != mDeallocating.end()) {
+        ALOGE("Tries to render a buffer which is already deallocating or rendering");
+        return C2_DUPLICATE;
+    }
+    auto it = mDequeued.find(bid);
+    if (it == mDequeued.end()) {
+        ALOGE("Tried to render non dequeued buffer");
+        return C2_NOT_FOUND;
+    }
+    if (!mBufferCache->mIgbp) {
+        // Render requested without surface.
+        // reclaim the buffer for dequeue.
+        // TODO: is this correct for API wise?
+        mDequeued.erase(it);
+        if (adjustDequeueConfLocked(updateDequeue)) {
+            return C2_BAD_STATE;
+        }
+        mDequeueable++;
+        l.unlock();
+        writeIncDequeueable(1);
+        return C2_BAD_STATE;
+    }
+    std::shared_ptr<BufferItem> buffer = it->second;
+    *cache = mBufferCache;
+    if (buffer->mGeneration == mBufferCache->mGeneration) {
+        auto it = mBufferCache->mBuffers.find(buffer->mSlot);
+        CHECK(it != mBufferCache->mBuffers.end() && it->second.get() == buffer.get());
+        mBufferCache->blockSlot(buffer->mSlot);
+    }
+    *pBuffer = buffer;
+    mDeallocating.emplace(bid);
+    return C2_OK;
+}
+
+void GraphicsTracker::commitRender(uint64_t origBid,
+                                  const std::shared_ptr<BufferCache> &cache,
+                                  const std::shared_ptr<BufferItem> &buffer,
+                                  bool *updateDequeue) {
+    std::unique_lock<std::mutex> l(mLock);
+    uint64_t bid = buffer->mId;
+
+    if (cache.get() != mBufferCache.get()) {
+        // Surface changed, no need to wait for buffer being released.
+        mDeallocating.erase(bid);
+        mDequeued.erase(bid);
+        if (adjustDequeueConfLocked(updateDequeue)) {
+            return;
+        }
+        mDequeueable++;
+        l.unlock();
+        writeIncDequeueable(1);
+        return;
+    }
+
+    if (origBid != bid) {
+        // migration happened, need to register the buffer to Cache
+        mBufferCache->mBuffers.emplace(buffer->mSlot, buffer);
+    }
+    mDeallocating.erase(bid);
+    mDequeued.erase(bid);
+}
+
+c2_status_t GraphicsTracker::render(const C2ConstGraphicBlock& blk,
+                                   const IGraphicBufferProducer::QueueBufferInput &input,
+                                   IGraphicBufferProducer::QueueBufferOutput *output) {
+    uint64_t bid;
+    c2_status_t res = retrieveAHardwareBufferId(blk, &bid);
+    if (res != C2_OK) {
+        ALOGE("retrieving AHB-ID for GraphicBlock failed");
+        return C2_CORRUPTED;
+    }
+    std::shared_ptr<BufferCache> cache;
+    std::shared_ptr<BufferItem> buffer;
+    bool updateDequeue = false;
+    res = requestRender(bid, &cache, &buffer, &updateDequeue);
+    if (res != C2_OK) {
+        if (updateDequeue) {
+            updateDequeueConf();
+        }
+        return res;
+    }
+    ::android::status_t migrateRes = ::android::OK;
+    ::android::status_t renderRes = ::android::OK;
+    if (cache->mGeneration != buffer->mGeneration) {
+        uint64_t newUsage = 0ULL;
+        int slotId = -1;;
+
+        (void) cache->mIgbp->getConsumerUsage(&newUsage);
+        sp<GraphicBuffer> gb = buffer->updateBuffer(newUsage, cache->mGeneration);
+        if (gb) {
+            migrateRes = cache->mIgbp->attachBuffer(&(buffer->mSlot), gb);
+        } else {
+            ALOGW("realloc-ing a new buffer for migration failed");
+            migrateRes = ::android::INVALID_OPERATION;
+        }
+    }
+    if (migrateRes == ::android::OK) {
+        renderRes = cache->mIgbp->queueBuffer(buffer->mSlot, input, output);
+        if (renderRes != ::android::OK) {
+            CHECK(renderRes != ::android::BAD_VALUE);
+        }
+    }
+    if (migrateRes != ::android::OK || renderRes != ::android::OK) {
+        // since it is not renderable, just de-allocate
+        if (migrateRes != ::android::OK) {
+            std::shared_ptr<BufferCache> nullCache;
+            commitDeallocate(nullCache, -1, bid);
+        } else {
+            (void) cache->mIgbp->cancelBuffer(buffer->mSlot, input.fence);
+            commitDeallocate(cache, buffer->mSlot, bid);
+        }
+        ALOGE("migration error(%d), render error(%d)", (int)migrateRes, (int)renderRes);
+        return C2_REFUSED;
+    }
+
+    updateDequeue = false;
+    commitRender(bid, cache, buffer, &updateDequeue);
+    if (updateDequeue) {
+        updateDequeueConf();
+    }
+    if (output->bufferReplaced) {
+        // in case of buffer drop during render
+        onReleased(cache->mGeneration);
+    }
+    return C2_OK;
+}
+
+void GraphicsTracker::onReleased(uint32_t generation) {
+    bool updateDequeue = false;
+    {
+        std::unique_lock<std::mutex> l(mLock);
+        if (mBufferCache->mGeneration == generation) {
+            if (!adjustDequeueConfLocked(&updateDequeue)) {
+                mDequeueable++;
+                l.unlock();
+                writeIncDequeueable(1);
+            }
+        }
+    }
+    if (updateDequeue) {
+        updateDequeueConf();
+    }
+}
+
+} // namespace aidl::android::hardware::media::c2::implementation
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
new file mode 100644
index 0000000..681b7e8
--- /dev/null
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware_buffer.h>
+#include <android-base/unique_fd.h>
+#include <gui/IGraphicBufferProducer.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <thread>
+
+#include <C2Buffer.h>
+
+namespace aidl::android::hardware::media::c2::implementation {
+
+using ::android::IGraphicBufferProducer;
+using ::android::GraphicBuffer;
+using ::android::Fence;
+using ::android::PixelFormat;
+using ::android::sp;
+/**
+ * The class allocates AHardwareBuffer(GraphicBuffer)s using BufferQueue.
+ *
+ * The class tracks and manages outstanding # of allocations for buffer
+ * recycling. So Graphics operations which affects # of outstanding allocation
+ * should be done via the class. (e.g. rendering a buffer to display)
+ *
+ * The class is supposed to be wrapped into IGraphicBufferAllocator AIDL interface,
+ * and the interface will be passed to HAL for a specific BlockPool instance.
+ *
+ * The class has one to one relation with HAL side Graphic C2BlockPool.
+ * The life cycle of the class is tied to a HAL side BlockPool object.
+ *
+ * So, reset()/stop() of HAL which related to blokcpool destruction will terminate the
+ * use of the class. And a new instance should be created in order for start()
+ * of HAL.
+ */
+class GraphicsTracker {
+public:
+    static std::shared_ptr<GraphicsTracker> CreateGraphicsTracker(int maxDequeueCount) {
+        GraphicsTracker *p = new GraphicsTracker(maxDequeueCount);
+        std::shared_ptr<GraphicsTracker> sp(p);
+        return sp;
+    }
+
+    ~GraphicsTracker();
+
+    /**
+     * Configure a new surface to render/allocate graphic blocks.
+     *
+     * Graphic  blocks from the old surface will be migrated to the new surface,
+     * if possible. Configuring to a null surface is possible in the case,
+     * an allocation request will be fulfilled by a direct allocation(not using
+     * BQ). generation should be different to the previous generations.
+     *
+     * @param[in] igbp        the new surface to configure
+     * @param[in] generation  identifier for each configured surface
+     */
+    c2_status_t configureGraphics(const sp<IGraphicBufferProducer>& igbp, uint32_t generation);
+
+    /**
+     * Configure max # of outstanding allocations at any given time.
+     *
+     * @param[in] maxDequeueCount    max # of outstanding allocation to configure
+     */
+    c2_status_t configureMaxDequeueCount(int maxDequeueCount);
+
+    /**
+     * Allocates a AHardwareBuffer.
+     *
+     * @param[in] width       width
+     * @param[in] height      height
+     * @param[in] PixelFormat pixel format which describes color format and etc
+     * @param[in] usage       gralloc usage bits
+     * @param[out] buf        the allocated buffer
+     * @param[out] fence      fence for the allocated buffer
+     * @return  C2_OK         the buffer is allocated
+     *          C2_BAD_STATE  stop() is called and in stopped state
+     *          C2_BLOCKING   should be waited to allocate
+     *          C2_NO_MEMORY  out of memory
+     *          C2_CORRUPTED
+     */
+    c2_status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage,
+                         AHardwareBuffer **buf, sp<Fence> *fence);
+
+    /**
+     * Deallocates a AHardwareBuffer
+     *
+     * @param[in] bufId         id of the buffer to deallocate
+     * @param[in] fence         i/o fence for the buffer
+     * @return  C2_OK           the buffer is successfully deallocated.
+     *          C2_DUPLICATE    deallocation/render request is pending already.
+     *          C2_NOT_FOUND    the buffer with the id is not allocated.
+     */
+    c2_status_t deallocate(uint64_t bufId, const sp<Fence> &fence);
+
+    /**
+     * Render a GraphicBlock which is associated to a pending allocated buffer
+     *
+     * @param[in] block         GraphicBlock
+     * @param[in] input         render input params to Graphics
+     * @param[out] output       render output params from Graphics
+     * @return  C2_OK           the buffer is now ready to render
+     *          C2_BAD_STATE    there is no surface to render.
+     *                          (null surface mode or life cycle ends)
+     *          C2_DUPLICATE    deallocation/render request is pending already.
+     *          C2_NOT_FOUND    the buffer with the id is not allocated.
+     *          C2_REFUSED      the buffer is refused to render from Graphics
+     *          C2_CORRUPTED
+     */
+    c2_status_t render(const C2ConstGraphicBlock& block,
+                       const IGraphicBufferProducer::QueueBufferInput& input,
+                       IGraphicBufferProducer::QueueBufferOutput *output);
+
+    /**
+     * Notifies when a Buffer is ready to allocate from Graphics.
+     * If generation does not match to the current, notifications via the interface
+     * will be ignored. (In the case, the notifications are from one of the old surfaces
+     * which is no longer used.)
+     *
+     * @param[in] generation    generation id for specifying Graphics(BQ)
+     */
+    void onReleased(uint32_t generation);
+
+    /**
+     * Get waitable fds 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.
+     * @return  C2_OK
+     *          C2_NO_MEMORY    Max # of fd reached.(not really a memory issue)
+     */
+    c2_status_t getWaitableFds(int *allocFd, int *statusFd);
+
+    /**
+     *  Ends to use the class. after the call, allocate will fail.
+     */
+    void stop();
+
+private:
+    static constexpr int kDefaultMaxDequeue = 2;
+
+    struct BufferCache;
+
+    struct BufferItem {
+        bool mInit;
+        uint64_t mId;
+        uint32_t mGeneration;
+        int mSlot;
+        AHardwareBuffer *mBuf;
+        uint64_t mUsage; // Gralloc usage format, not AHB
+        sp<Fence> mFence;
+
+        // Create from a GraphicBuffer
+        BufferItem(uint32_t generation, int slot,
+                   const sp<GraphicBuffer>& buf,
+                   const sp<Fence> &fence);
+
+        // Create from an AHB (no slot information)
+        // Should be attached to IGBP for rendering
+        BufferItem(uint32_t generation,
+                   AHardwareBuffer_Desc *desc,
+                   AHardwareBuffer *pBuf);
+
+        ~BufferItem();
+
+        sp<GraphicBuffer> updateBuffer(uint64_t newUsage, uint32_t newGeneration);
+    };
+
+    struct BufferCache {
+        static constexpr int kNumSlots = ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
+
+        uint64_t mBqId;
+        uint32_t mGeneration;
+        ::android::sp<IGraphicBufferProducer> mIgbp;
+
+        // Maps slotId to buffer
+        // IGBP::dequeueBuffer(), IGBP::queueBuffer() and IGBP::cancelBuffer()
+        // require slotId.
+        std::map<int, std::shared_ptr<BufferItem>> mBuffers;
+
+        // block slot use, while deallocating(cancel, render and etc)
+        struct BlockedSlot {
+            std::mutex l;
+            std::condition_variable cv;
+            bool blocked;
+            BlockedSlot() : blocked{false} {}
+            ~BlockedSlot() = default;
+        };
+
+        BlockedSlot mBlockedSlots[kNumSlots];
+
+        BufferCache() : mBqId{0ULL}, mGeneration{0}, mIgbp{nullptr} {}
+        BufferCache(uint64_t bqId, uint32_t generation, const sp<IGraphicBufferProducer>& igbp) :
+            mBqId{bqId}, mGeneration{generation}, mIgbp{igbp} {}
+
+        void waitOnSlot(int slot);
+
+        void blockSlot(int slot);
+
+        void unblockSlot(int slot);
+    };
+
+    std::shared_ptr<BufferCache> mBufferCache;
+    // Maps bufferId to buffer
+    std::map<uint64_t, std::shared_ptr<BufferItem>> mDequeued;
+    std::set<uint64_t> mDeallocating;
+
+    int mMaxDequeue;
+    int mMaxDequeueRequested;
+    int mMaxDequeueCommitted;
+
+    uint32_t mMaxDequeueRequestedSeqId;
+    uint32_t mMaxDequeueCommittedSeqId;
+
+    int mDequeueable;
+
+    // TODO: statistics
+    uint64_t mTotalDequeued;
+    //uint64_t mTotalQueued;
+    uint64_t mTotalCancelled;
+    uint64_t mTotalDropped;
+    uint64_t mTotalReleased;
+
+    bool mInConfig;
+    std::mutex mLock; // locks for data synchronization
+    std::mutex mConfigLock; // locks for configuration change.
+
+    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}.
+    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);
+
+    // return {@code true} only when dequeue config adjust happened.
+    // {@code updateDequeueConf} is an output parameter, and returns
+    // {@code true} only when the current dequeue conf is required to be
+    // updated to IGBP(BQ) as a result of the adjust.
+    bool adjustDequeueConfLocked(bool *updateDequeueConf);
+
+    void updateDequeueConf();
+
+    c2_status_t requestAllocate(std::shared_ptr<BufferCache> *cache);
+    c2_status_t requestDeallocate(uint64_t bid, const sp<Fence> &fence,
+                                  bool *completed, bool *updateDequeue,
+                                  std::shared_ptr<BufferCache> *cache, int *slotId,
+                                  sp<Fence> *rFence);
+    c2_status_t requestRender(uint64_t bid, std::shared_ptr<BufferCache> *cache,
+                              std::shared_ptr<BufferItem> *pBuffer,
+                              bool *updateDequeue);
+
+    void commitAllocate(c2_status_t res,
+                        const std::shared_ptr<BufferCache> &cache,
+                        bool cached, int slotId, const sp<Fence> &fence,
+                        std::shared_ptr<BufferItem> *buffer,
+                        bool *updateDequeue);
+    void commitDeallocate(std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid);
+    void commitRender(uint64_t origBid,
+                      const std::shared_ptr<BufferCache> &cache,
+                      const std::shared_ptr<BufferItem> &buffer,
+                      bool *updateDequeue);
+
+    c2_status_t _allocate(
+            const std::shared_ptr<BufferCache> &cache,
+            uint32_t width, uint32_t height, PixelFormat format, int64_t usage,
+            bool *cached, int *rSlotId, sp<Fence> *rFence,
+            std::shared_ptr<BufferItem> *buffer);
+
+    void writeIncDequeueable(int inc);
+    void processEvent();
+};
+
+} // namespace aidl::android::hardware::media::c2::implementation
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
index f00b1a0..a8f9f7e 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
+#include <algorithm>
+#include <map>
 #include <memory>
+#include <string>
 
 #define LOG_TAG "DevicesFactoryHalAidl"
 //#define LOG_NDEBUG 0
@@ -75,6 +78,21 @@
                 if (strcmp(instance, "default") == 0) instance = "primary";
                 static_cast<decltype(names)>(context)->push_back(instance);
             });
+    std::sort(names->begin(), names->end(), [](const std::string& lhs,
+                    const std::string& rhs) {
+        // This order corresponds to the canonical order of modules as specified in
+        // the reference 'audio_policy_configuration_7_0.xml' file.
+        static const std::map<std::string, int> kPriorities{
+            { "primary", 0 }, { "a2dp", 1 }, { "usb", 2 }, { "r_submix", 3 },
+            { "bluetooth", 4 }, { "hearing_aid", 5 }, { "msd", 6 }, { "stub", 7 }
+        };
+        auto lhsIt = kPriorities.find(lhs);
+        auto rhsIt = kPriorities.find(rhs);
+        if (lhsIt != kPriorities.end() && rhsIt != kPriorities.end()) {
+            return lhsIt->second < rhsIt->second;
+        }
+        return lhsIt != kPriorities.end();
+    });
     return OK;
 }
 
diff --git a/media/libstagefright/rtsp/fuzzer/Android.bp b/media/libstagefright/rtsp/fuzzer/Android.bp
index 8e10b0c..a2791ba 100644
--- a/media/libstagefright/rtsp/fuzzer/Android.bp
+++ b/media/libstagefright/rtsp/fuzzer/Android.bp
@@ -62,3 +62,28 @@
         "libcutils",
     ],
 }
+
+cc_fuzz {
+    name: "packet_source_fuzzer",
+    srcs: [
+        "packet_source_fuzzer.cpp",
+    ],
+    defaults: [
+        "libstagefright_rtsp_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "rtsp_connection_fuzzer",
+    srcs: [
+        "rtsp_connection_fuzzer.cpp",
+    ],
+    shared_libs: [
+        "libcrypto",
+        "libcutils",
+        "libnetd_client",
+    ],
+    defaults: [
+        "libstagefright_rtsp_fuzzer_defaults",
+    ],
+}
diff --git a/media/libstagefright/rtsp/fuzzer/README.md b/media/libstagefright/rtsp/fuzzer/README.md
index 657fb48..bc7be29 100644
--- a/media/libstagefright/rtsp/fuzzer/README.md
+++ b/media/libstagefright/rtsp/fuzzer/README.md
@@ -3,6 +3,8 @@
 ## Table of contents
 + [sdploader_fuzzer](#SDPLoader)
 + [rtp_writer_fuzzer](#ARTPWriter)
++ [packet_source_fuzzer](#packetSource)
++ [rtsp_connection_fuzzer](#ARTSPConnection)
 
 # <a name="SDPLoader"></a> Fuzzer for SDPLoader
 
@@ -62,3 +64,54 @@
   $ adb sync data
   $ adb shell /data/fuzz/arm64/rtp_writer_fuzzer/rtp_writer_fuzzer
 ```
+
+# <a name="packetSource"></a> Fuzzer for  PacketSource
+
+ PacketSource supports the following parameters:
+1. Codec (parameter name: "kCodecs")
+2. Format (parameter name: "kFmtp")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`kCodecs`| 0. `opus`<br/>1. `ISAC`<br/>2. `VP8`<br/>3. `google-data`<br/>4. `G722`<br/>5. `PCMU`<br/>6. `PCMA`<br/>7. `CN`<br/>8. `telephone-event`<br/>9. `VP9`<br/>10. `red`<br/>11. `ulpfec`<br/>12. `rtx`<br/>13. `H264`<br/>14. `iLBC`<br/>15. `H261`<br/>16. `MPV`<br/>17. `H263`<br/>18. `AMR`<br/>19. `AC3`<br/>20. `G723`<br/>21. `G729A`<br/>22. `MP4V-ES`<br/>23. `H265`<br/>24. `H263-2000`<br/>25. `H263-1998`<br/>26. `AMR-WB`<br/>27. `MP4A-LATM`<br/>28. `MP2T`<br/>29. `mpeg4-generic` |Value obtained from FuzzedDataProvider|
+|`kFmtp`| <br/>0. `br=`<br/>1. `bw=`<br/>2. `ch-aw-recv=`<br/>3. `mode-change-capability=`<br/>4. `max-red =`<br/>5. `octet-align=`<br/>6. `mode-change-capability=`<br/>7. `profile-level-id=`<br/>8. `packetization-mode=`<br/>9. `profile=`<br/>10. `level=` <br/>11. `apt=`<br/>12. `annexb=`<br/>13. `protocol=`<br/>14. `config=`<br/>15. `streamtype=`<br/>16. `mode=`<br/>17. `sizelength=`<br/>18. `indexlength=`<br/>19. `indexdeltalength=`<br/>20. `minptime=`<br/>21. `useinbandfec=`<br/>22. `maxplaybackrate=`<br/>23. `stereo=`<br/>24. `level-asymmetry-allowed=`<br/>25. `max-fs=`<br/>26. `max-fr=`|Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) packet_source_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/packet_source_fuzzer/packet_source_fuzzer
+```
+
+# <a name="ARTSPConnection"></a> Fuzzer for ARTSPConnection
+
+## Design Considerations
+This fuzzer aims at covering ARTSPConnection.cpp. A server is implemented in the fuzzer. After accepting a connect request, the server accepts the connections and handles them in a seperate thread. The threads are maintained in a ThreadPool which limits the maximum number of threads alive at a time. When the fuzzer process ends, all the threads in the ThreadPool are joined to the main thread.
+The inputs to the server are generated using FuzzedDataProvider and stored in a variable 'mFuzzData'. As this variable is shared among multiple threads, mutex is used to ensure synchronization.
+### Fuzzer Inputs:
+The inputs generated in the fuzzer using FuzzzedDataProvider have been randomized as much as possible. Due to the constraints in the module source code, the inputs have to be limited and arranged in some specific format.
+
+ARTSPConnection supports the following parameters:
+1. Authentication Type (parameter name: "kAuthType")
+2. FuzzData (parameter name: "mFuzzData")
+3. RequestData (parameter name: "mFuzzRequestData")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`kAuthType`| 0.`Basic`<br/>1.`Digest`|Value obtained from FuzzedDataProvider|
+|`mFuzzData`| `String` |Value obtained from FuzzedDataProvider|
+|`mFuzzRequestData`| `String` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) rtsp_connection_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/rtsp_connection_fuzzer/rtsp_connection_fuzzer
diff --git a/media/libstagefright/rtsp/fuzzer/packet_source_fuzzer.cpp b/media/libstagefright/rtsp/fuzzer/packet_source_fuzzer.cpp
new file mode 100644
index 0000000..a3d7535
--- /dev/null
+++ b/media/libstagefright/rtsp/fuzzer/packet_source_fuzzer.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/rtsp/APacketSource.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
+
+using namespace android;
+
+static constexpr int32_t kMinValue = 0;
+static constexpr int32_t kMaxIPAddress = 255;
+static constexpr int32_t kMaxFmt = 255;
+static constexpr int32_t kMinAPICase = 0;
+static constexpr int32_t kMaxPacketSourceAPI = 5;
+static constexpr size_t kMinIndex = 1;
+static constexpr size_t kMaxCodecConfigs = 4;
+
+std::string kCodecs[] = {"opus",        "ISAC",         "VP8",
+                         "google-data", "G722",         "PCMU",
+                         "PCMA",        "CN",           "telephone-event",
+                         "VP9",         "red",          "ulpfec",
+                         "rtx",         "H264",         "iLBC",
+                         "H261",        "MPV",          "H263",
+                         "AMR",         "AC3",          "G723",
+                         "G729A",       "H264",         "MP4V-ES",
+                         "H265",        "H263-2000",    "H263-1998",
+                         "AMR",         "AMR-WB",       "MP4A-LATM",
+                         "MP2T",        "mpeg4-generic"};
+
+std::string kFmtp[] = {"br=",
+                       "bw=",
+                       "ch-aw-recv=",
+                       "mode-change-capability=",
+                       "max-red =",
+                       "octet-align=",
+                       "mode-change-capability=",
+                       "max-red=",
+                       "profile-level-id=",
+                       "packetization-mode=",
+                       "profile=",
+                       "level=",
+                       "apt=",
+                       "annexb=",
+                       "protocol=",
+                       "streamtype=",
+                       "mode=",
+                       "sizelength=",
+                       "indexlength=",
+                       "indexdeltalength=",
+                       "minptime=",
+                       "useinbandfec=",
+                       "maxplaybackrate=",
+                       "stereo=",
+                       "level-asymmetry-allowed=",
+                       "max-fs=",
+                       "max-fr="};
+
+std::string kCodecConfigString[kMaxCodecConfigs][2] = {{"H264", "profile-level-id="},
+                                                       {"MP4A-LATM", "config="},
+                                                       {"MP4V-ES", "config="},
+                                                       {"mpeg4-generic", "mode="}};
+
+class ASessionPacketFuzzer {
+  public:
+    ASessionPacketFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+  private:
+    FuzzedDataProvider mFdp;
+};
+
+bool checkFormatSupport(const std::string& codec, const std::string& format) {
+    for (int i = 0; i < kMaxCodecConfigs; ++i) {
+        if (codec == kCodecConfigString[i][0]) {
+            if (format == kCodecConfigString[i][1]) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+void ASessionPacketFuzzer::process() {
+    AString inputString;
+    const sp<ASessionDescription> sessionPacket = sp<ASessionDescription>::make();
+    std::string codec = mFdp.PickValueInArray(kCodecs);
+    std::string ipAddress =
+            std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxIPAddress)) + "." +
+            std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxIPAddress)) + "." +
+            std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxIPAddress)) + "." + "0";
+    std::string format = mFdp.PickValueInArray(kFmtp);
+    std::string fmptStr = format + std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxFmt)) +
+                          ";" + mFdp.PickValueInArray(kFmtp) +
+                          std::to_string(mFdp.ConsumeIntegralInRange(kMinValue, kMaxFmt));
+    sessionPacket->SDPStringFactory(
+            inputString, ipAddress.c_str() /* ip */, mFdp.ConsumeBool() /* isAudio */,
+            mFdp.ConsumeIntegral<unsigned int>() /* port */,
+            mFdp.ConsumeIntegral<unsigned int>() /* payloadType */,
+            mFdp.ConsumeIntegral<unsigned int>() /* as */, codec.c_str(), /* codec */
+            fmptStr.c_str() /* fmtp */, mFdp.ConsumeIntegral<int32_t>() /* width */,
+            mFdp.ConsumeIntegral<int32_t>() /* height */,
+            mFdp.ConsumeIntegral<int32_t>() /* cvoExtMap */);
+    sessionPacket->setTo(inputString.c_str(), inputString.size());
+    size_t trackSize = sessionPacket->countTracks();
+    AString desc = nullptr;
+    while (mFdp.remaining_bytes()) {
+        int32_t packetSourceAPI =
+                mFdp.ConsumeIntegralInRange<size_t>(kMinAPICase, kMaxPacketSourceAPI);
+        switch (packetSourceAPI) {
+            case 0: {
+                unsigned long payload = 0;
+                AString params = nullptr;
+                sessionPacket->getFormatType(mFdp.ConsumeIntegralInRange(kMinIndex, trackSize - 1),
+                                             &payload, &desc, &params);
+                break;
+            }
+            case 1: {
+                int32_t width, height;
+                unsigned long payload = mFdp.ConsumeIntegral<unsigned long>();
+                sessionPacket->getDimensions(mFdp.ConsumeIntegralInRange(kMinIndex, trackSize - 1),
+                                             payload, &width, &height);
+                break;
+            }
+            case 2: {
+                int32_t cvoExtMap = mFdp.ConsumeIntegral<int32_t>();
+                sessionPacket->getCvoExtMap(mFdp.ConsumeIntegralInRange(kMinIndex, trackSize - 1),
+                                            &cvoExtMap);
+                break;
+            }
+            case 3: {
+                int64_t durationUs = mFdp.ConsumeIntegral<int64_t>();
+                sessionPacket->getDurationUs(&durationUs);
+                break;
+            }
+            case 4: {
+                int32_t timeScale, numChannels;
+                if (desc != nullptr) {
+                    sessionPacket->ParseFormatDesc(desc.c_str(), &timeScale, &numChannels);
+                }
+                break;
+            }
+            case 5: {
+                if (checkFormatSupport(codec, format)) {
+                    sp<APacketSource> packetSource = sp<APacketSource>::make(
+                            sessionPacket, mFdp.ConsumeIntegralInRange(kMinIndex, trackSize - 1));
+                }
+                break;
+            }
+        }
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    ASessionPacketFuzzer packetSourceFuzzer(data, size);
+    packetSourceFuzzer.process();
+    return 0;
+}
diff --git a/media/libstagefright/rtsp/fuzzer/rtsp_connection_fuzzer.cpp b/media/libstagefright/rtsp/fuzzer/rtsp_connection_fuzzer.cpp
new file mode 100644
index 0000000..51c423e
--- /dev/null
+++ b/media/libstagefright/rtsp/fuzzer/rtsp_connection_fuzzer.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arpa/inet.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/rtsp/ARTSPConnection.h>
+#include <thread>
+
+using namespace android;
+
+const std::string kAuthType[] = {"Basic", "Digest"};
+const std::string kTab = "\t";
+const std::string kCSeq = "CSeq: ";
+const std::string kSpace = " ";
+const std::string kNewLine = "\n";
+const std::string kBinaryHeader = "$";
+const std::string kNonce = " nonce=\"\"";
+const std::string kRealm = " realm=\"\"";
+const std::string kHeaderBoundary = "\r\n\r\n";
+const std::string kContentLength = "content-length: ";
+const std::string kDefaultRequestValue = "INVALID_FORMAT";
+const std::string kUrlPrefix = "rtsp://root:pass@127.0.0.1:";
+const std::string kRequestMarker = "REQUEST_SENT";
+const std::string kQuitResponse = "\n\n\n\n";
+const std::string kRTSPVersion = "RTSP/1.0";
+const std::string kValidResponse = kRTSPVersion + " 200 \n";
+const std::string kAuthString = kRTSPVersion + " 401 \nwww-authenticate: ";
+constexpr char kNullValue = '\0';
+constexpr char kDefaultValue = '0';
+constexpr int32_t kWhat = 'resp';
+constexpr int32_t kMinPort = 100;
+constexpr int32_t kMaxPort = 999;
+constexpr int32_t kMinASCIIValue = 32;
+constexpr int32_t kMaxASCIIValue = 126;
+constexpr int32_t kMinContentLength = 0;
+constexpr int32_t kMaxContentLength = 1000;
+constexpr int32_t kBinaryVectorSize = 3;
+constexpr int32_t kDefaultCseqValue = 1;
+constexpr int32_t kBufferSize = 1024;
+constexpr int32_t kMaxLoopRuns = 5;
+constexpr int32_t kPort = 554;
+constexpr int32_t kMaxBytes = 128;
+constexpr int32_t kMaxThreads = 1024;
+
+struct FuzzAHandler : public AHandler {
+  public:
+    FuzzAHandler(std::function<void()> signalEosFunction)
+        : mSignalEosFunction(std::move(signalEosFunction)) {}
+    ~FuzzAHandler() = default;
+
+  protected:
+    void onMessageReceived(const sp<AMessage>& msg) override {
+        switch (msg->what()) {
+            case kWhat: {
+                mSignalEosFunction();
+                break;
+            }
+        }
+    }
+
+  private:
+    std::function<void()> mSignalEosFunction;
+};
+
+class RTSPConnectionFuzzer {
+  public:
+    RTSPConnectionFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    ~RTSPConnectionFuzzer() {
+        // wait for all the threads to join the main thread
+        for (auto& thread : mThreadPool) {
+            if (thread.joinable()) {
+                thread.join();
+            }
+        }
+        close(mServerFd);
+    }
+    void process();
+
+  private:
+    void signalEos();
+    void startServer();
+    void createFuzzData();
+    void acceptConnection();
+    void handleConnection(int32_t);
+    void handleClientResponse(int32_t);
+    void sendValidResponse(int32_t, int32_t);
+    int32_t checkSocket(int32_t);
+    size_t generateBinaryDataSize(std::string);
+    bool checkValidRequestData(const AString&);
+    bool mEosReached = false;
+    bool mServerFailure = false;
+    bool mNotifyResponseListener = false;
+    int32_t mServerFd;
+    std::string mFuzzData = "";
+    std::string mFuzzRequestData = "";
+    std::string mRequestData = kDefaultRequestValue;
+    std::mutex mFuzzDataMutex;
+    std::mutex mMsgPostCompleteMutex;
+    std::condition_variable mConditionalVariable;
+    std::vector<std::thread> mThreadPool;
+    FuzzedDataProvider mFdp;
+};
+
+size_t RTSPConnectionFuzzer::generateBinaryDataSize(std::string values) {
+    // computed the binary data size as done in ARTSPConnection.cpp
+    uint8_t x = values[0];
+    uint8_t y = values[1];
+    return x << 8 | y;
+}
+
+bool RTSPConnectionFuzzer::checkValidRequestData(const AString& request) {
+    if (request.find(kHeaderBoundary.c_str()) <= 0) {
+        return false;
+    }
+    ssize_t space = request.find(kSpace.c_str());
+    if (space <= 0) {
+        return false;
+    }
+    if (request.find(kSpace.c_str(), space + 1) <= 0) {
+        return false;
+    }
+    return true;
+}
+
+void RTSPConnectionFuzzer::createFuzzData() {
+    std::unique_lock fuzzLock(mFuzzDataMutex);
+    mFuzzData = "";
+    mFuzzRequestData = "";
+    int32_t contentLength = 0;
+    if (mFdp.ConsumeBool()) {
+        if (mFdp.ConsumeBool()) {
+            // if we want to handle server request
+            mFuzzData.append(kSpace + kSpace + kRTSPVersion);
+        } else {
+            // if we want to notify response listener
+            mFuzzData.append(
+                    kRTSPVersion + kSpace +
+                    std::to_string(mFdp.ConsumeIntegralInRange<uint16_t>(kMinPort, kMaxPort)) +
+                    kSpace);
+        }
+        mFuzzData.append(kNewLine);
+        if (mFdp.ConsumeBool()) {
+            contentLength =
+                    mFdp.ConsumeIntegralInRange<int32_t>(kMinContentLength, kMaxContentLength);
+            mFuzzData.append(kContentLength + std::to_string(contentLength) + kNewLine);
+            if (mFdp.ConsumeBool()) {
+                mFdp.ConsumeBool() ? mFuzzData.append(kSpace + kNewLine)
+                                   : mFuzzData.append(kTab + kNewLine);
+            }
+        }
+        // new line to break out of infinite for loop
+        mFuzzData.append(kNewLine);
+        if (contentLength) {
+            std::string contentData = mFdp.ConsumeBytesAsString(contentLength);
+            contentData.resize(contentLength, kDefaultValue);
+            mFuzzData.append(contentData);
+        }
+    } else {
+        // for binary data
+        std::string randomValues(kBinaryVectorSize, kNullValue);
+        for (size_t idx = 0; idx < kBinaryVectorSize; ++idx) {
+            randomValues[idx] =
+                    (char)mFdp.ConsumeIntegralInRange<uint8_t>(kMinASCIIValue, kMaxASCIIValue);
+        }
+        size_t binaryDataSize = generateBinaryDataSize(randomValues);
+        std::string data = mFdp.ConsumeBytesAsString(binaryDataSize);
+        data.resize(binaryDataSize, kDefaultValue);
+        mFuzzData.append(kBinaryHeader + randomValues + data);
+    }
+    if (mFdp.ConsumeBool()) {
+        mRequestData = mFdp.ConsumeRandomLengthString(kMaxBytes) + kSpace + kSpace +
+                       kHeaderBoundary + mFdp.ConsumeRandomLengthString(kMaxBytes);
+        // Check if Request data is valid
+        if (checkValidRequestData(mRequestData.c_str())) {
+            if (mFdp.ConsumeBool()) {
+                if (mFdp.ConsumeBool()) {
+                    // if we want to handle server request
+                    mFuzzRequestData.append(kSpace + kSpace + kRTSPVersion + kNewLine);
+                } else {
+                    // if we want to add authentication headers
+                    mNotifyResponseListener = true;
+                    mFuzzRequestData.append(kAuthString);
+                    if (mFdp.ConsumeBool()) {
+                        // for Authentication type: Basic
+                        mFuzzRequestData.append(kAuthType[0]);
+                    } else {
+                        // for Authentication type: Digest
+                        mFuzzRequestData.append(kAuthType[1]);
+                        mFuzzRequestData.append(kNonce);
+                        mFuzzRequestData.append(kRealm);
+                    }
+                    mFuzzRequestData.append(kNewLine);
+                }
+            } else {
+                mNotifyResponseListener = false;
+                mFuzzRequestData.append(kValidResponse);
+            }
+        } else {
+            mRequestData = kDefaultRequestValue;
+        }
+    } else {
+        mRequestData = kDefaultRequestValue;
+        mFuzzData.append(kNewLine);
+    }
+}
+
+void RTSPConnectionFuzzer::signalEos() {
+    mEosReached = true;
+    mConditionalVariable.notify_all();
+    return;
+}
+
+int32_t RTSPConnectionFuzzer::checkSocket(int32_t newSocket) {
+    struct timeval tv;
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+
+    fd_set rs;
+    FD_ZERO(&rs);
+    FD_SET(newSocket, &rs);
+
+    return select(newSocket + 1, &rs, nullptr, nullptr, &tv);
+}
+
+void RTSPConnectionFuzzer::sendValidResponse(int32_t newSocket, int32_t cseq = -1) {
+    std::string validResponse = kValidResponse;
+    if (cseq != -1) {
+        validResponse.append(kCSeq + std::to_string(cseq));
+        validResponse.append(kNewLine + kNewLine);
+    } else {
+        validResponse.append(kNewLine);
+    }
+    send(newSocket, validResponse.c_str(), validResponse.size(), 0);
+}
+
+void RTSPConnectionFuzzer::handleClientResponse(int32_t newSocket) {
+    char buffer[kBufferSize] = {0};
+    if (checkSocket(newSocket) == 1) {
+        read(newSocket, buffer, kBufferSize);
+    }
+}
+
+void RTSPConnectionFuzzer::handleConnection(int32_t newSocket) {
+    std::unique_lock fuzzLock(mFuzzDataMutex);
+    send(newSocket, mFuzzData.c_str(), mFuzzData.size(), 0);
+    if (mFuzzData[0] == kSpace[0]) {
+        handleClientResponse(newSocket);
+    }
+
+    if (mFuzzRequestData != "") {
+        char buffer[kBufferSize] = {0};
+        if (checkSocket(newSocket) == 1 && recv(newSocket, buffer, kBufferSize, MSG_DONTWAIT) > 0) {
+            // Extract the 'CSeq' value present at the end of header
+            std::string clientResponse(buffer);
+            std::string header = clientResponse.substr(0, clientResponse.find(kHeaderBoundary));
+            char cseq = header[header.rfind(kCSeq) + kCSeq.length()];
+            int32_t cseqValue = cseq ? cseq - '0' : kDefaultCseqValue;
+            std::string response = mFuzzRequestData;
+            response.append(kCSeq + std::to_string(cseqValue));
+            response.append(kNewLine + kNewLine);
+            send(newSocket, response.data(), response.length(), 0);
+
+            if (!mNotifyResponseListener) {
+                char buffer[kBufferSize] = {0};
+                if (checkSocket(newSocket) == 1) {
+                    if (recv(newSocket, buffer, kBufferSize, MSG_DONTWAIT) > 0) {
+                        // Extract the 'CSeq' value present at the end of header
+                        std::string clientResponse(buffer);
+                        std::string header =
+                                clientResponse.substr(0, clientResponse.find(kHeaderBoundary));
+                        char cseq = header[header.rfind(kCSeq) + kCSeq.length()];
+                        int32_t cseqValue = cseq ? cseq - '0' : kDefaultCseqValue;
+                        sendValidResponse(newSocket, cseqValue);
+                    } else {
+                        sendValidResponse(newSocket);
+                    }
+                }
+            }
+        } else {
+            // If no data to read, then send a valid response
+            // to release the mutex lock in fuzzer
+            sendValidResponse(newSocket);
+        }
+    }
+    send(newSocket, kQuitResponse.c_str(), kQuitResponse.size(), 0);
+}
+
+void RTSPConnectionFuzzer::startServer() {
+    signal(SIGPIPE, SIG_IGN);
+    mServerFd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+    struct sockaddr_in serverAddress;
+    serverAddress.sin_family = AF_INET;
+    serverAddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    serverAddress.sin_port = htons(kPort);
+
+    // Get rid of "Address in use" error
+    int32_t opt = 1;
+    if (setsockopt(mServerFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
+        mServerFailure = true;
+    }
+
+    // Bind the socket and set for listening.
+    if (bind(mServerFd, (struct sockaddr*)(&serverAddress), sizeof(serverAddress)) < 0) {
+        mServerFailure = true;
+    }
+
+    if (listen(mServerFd, 5) < 0) {
+        mServerFailure = true;
+    }
+}
+
+void RTSPConnectionFuzzer::acceptConnection() {
+    int32_t clientFd = accept4(mServerFd, nullptr, nullptr, SOCK_CLOEXEC);
+    handleConnection(clientFd);
+    close(clientFd);
+}
+
+void RTSPConnectionFuzzer::process() {
+    startServer();
+    if (mServerFailure) {
+        return;
+    }
+    sp<ALooper> looper = sp<ALooper>::make();
+    sp<FuzzAHandler> handler =
+            sp<FuzzAHandler>::make(std::bind(&RTSPConnectionFuzzer::signalEos, this));
+    sp<ARTSPConnection> rtspConnection =
+            sp<ARTSPConnection>::make(mFdp.ConsumeBool(), mFdp.ConsumeIntegral<uint64_t>());
+    looper->start();
+    looper->registerHandler(rtspConnection);
+    looper->registerHandler(handler);
+    sp<AMessage> replymsg = sp<AMessage>::make(kWhat, handler);
+    std::string url = kUrlPrefix + std::to_string(kPort) + "/";
+
+    while (mFdp.remaining_bytes() && mThreadPool.size() < kMaxThreads) {
+        createFuzzData();
+        mThreadPool.push_back(std::thread(&RTSPConnectionFuzzer::acceptConnection, this));
+        if (mFdp.ConsumeBool()) {
+            rtspConnection->observeBinaryData(replymsg);
+        }
+
+        {
+            rtspConnection->connect(url.c_str(), replymsg);
+            std::unique_lock waitForMsgPostComplete(mMsgPostCompleteMutex);
+            mConditionalVariable.wait(waitForMsgPostComplete, [this] {
+                if (mEosReached == true) {
+                    mEosReached = false;
+                    return true;
+                }
+                return mEosReached;
+            });
+        }
+
+        if (mRequestData != kDefaultRequestValue) {
+            rtspConnection->sendRequest(mRequestData.c_str(), replymsg);
+            std::unique_lock waitForMsgPostComplete(mMsgPostCompleteMutex);
+            mConditionalVariable.wait(waitForMsgPostComplete, [this] {
+                if (mEosReached == true) {
+                    mEosReached = false;
+                    return true;
+                }
+                return mEosReached;
+            });
+        }
+
+        if (mFdp.ConsumeBool()) {
+            rtspConnection->disconnect(replymsg);
+            std::unique_lock waitForMsgPostComplete(mMsgPostCompleteMutex);
+            mConditionalVariable.wait(waitForMsgPostComplete, [this] {
+                if (mEosReached == true) {
+                    mEosReached = false;
+                    return true;
+                }
+                return mEosReached;
+            });
+        }
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    RTSPConnectionFuzzer rtspFuzz(data, size);
+    rtspFuzz.process();
+    return 0;
+}
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index febccac..a03ed06 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -315,6 +315,13 @@
     wp<AudioPolicyMix> mPolicyMix;  // non NULL when used by a dynamic policy
 
     virtual uint32_t getRecommendedMuteDurationMs() const { return 0; }
+    virtual std::string info() const {
+        std::string result;
+        result.append("[portId:" );
+        result.append(android::internal::ToString(getId()));
+        result.append("]");
+        return result;
+    }
 
 protected:
     const sp<PolicyAudioPort> mPolicyAudioPort;
@@ -457,6 +464,8 @@
 
     PortHandleVector getClientsForStream(audio_stream_type_t streamType) const;
 
+    virtual std::string info() const override;
+
     const sp<IOProfile> mProfile;          // I/O profile this output derives from
     audio_io_handle_t mIoHandle;           // output handle
     uint32_t mLatency;                  //
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 8b23311..c29ad9c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -980,6 +980,18 @@
     return clientsForStream;
 }
 
+std::string SwAudioOutputDescriptor::info() const {
+    std::string result;
+    result.append("[" );
+    result.append(AudioOutputDescriptor::info());
+    result.append("[io:" );
+    result.append(android::internal::ToString(mIoHandle));
+    result.append(", " );
+    result.append(mProfile->getTagName());
+    result.append("]]");
+    return result;
+}
+
 void SwAudioOutputCollection::dump(String8 *dst) const
 {
     dst->appendFormat("\n Outputs (%zu):\n", size());
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
index e214ae9..8c7a7de 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
@@ -89,7 +89,12 @@
         if (aidlPort.ext.getTag() == AudioPortExt::mix) {
             auto mixPort = sp<IOProfile>::make("", AUDIO_PORT_ROLE_NONE);
             RETURN_STATUS_IF_ERROR(mixPort->readFromParcelable(fwPort));
-            sortAudioProfiles(mixPort->getAudioProfiles());
+            auto& profiles = mixPort->getAudioProfiles();
+            if (profiles.empty()) {
+                profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
+            } else {
+                sortAudioProfiles(mixPort->getAudioProfiles());
+            }
             mixPorts.add(mixPort);
             ports.emplace(aidlPort.id, mixPort);
         } else if (aidlPort.ext.getTag() == AudioPortExt::device) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 216d2eb..1f6946c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -275,23 +275,29 @@
                 session, dstIo);
         effectsToMove = getOrphanEffectsForSession(session);
     } else {
-        ALOGV("%s: moving effects for session %d from io=%d to io=%d", __func__,
-                session, srcIo, dstIo);
-        sp<AudioInputDescriptor> previousInputDesc = inputs->valueFor(srcIo);
-        effectsToMove = getEffectsForIo(srcIo);
-        for (size_t i = 0; i < effectsToMove.size(); ++i) {
-            sp<EffectDescriptor> effect = effectsToMove.valueAt(i);
-            effect->mEnabledWhenMoved = effect->mEnabled;
-            previousInputDesc->trackEffectEnabled(effect, false);
+        ALOGV("%s: moving effects for session %d from io=%d to io=%d", __func__, session, srcIo,
+              dstIo);
+        if (const sp<AudioInputDescriptor>& previousInputDesc = inputs->valueFor(srcIo)) {
+            effectsToMove = getEffectsForIo(srcIo);
+            for (size_t i = 0; i < effectsToMove.size(); ++i) {
+                const sp<EffectDescriptor>& effect = effectsToMove.valueAt(i);
+                effect->mEnabledWhenMoved = effect->mEnabled;
+                previousInputDesc->trackEffectEnabled(effect, false);
+            }
+        } else {
+            ALOGW("%s: no effect descriptor for srcIo %d", __func__, srcIo);
         }
     }
     moveEffects(session, srcIo, dstIo, clientInterface);
 
     if (dstIo != AUDIO_IO_HANDLE_NONE) {
-        sp<AudioInputDescriptor> inputDesc = inputs->valueFor(dstIo);
-        for (size_t i = 0; i < effectsToMove.size(); ++i) {
-            sp<EffectDescriptor> effect = effectsToMove.valueAt(i);
-            inputDesc->trackEffectEnabled(effect, effect->mEnabledWhenMoved);
+        if (const sp<AudioInputDescriptor>& inputDesc = inputs->valueFor(dstIo)) {
+            for (size_t i = 0; i < effectsToMove.size(); ++i) {
+                const sp<EffectDescriptor>& effect = effectsToMove.valueAt(i);
+                inputDesc->trackEffectEnabled(effect, effect->mEnabledWhenMoved);
+            }
+        } else {
+            ALOGW("%s: no effect descriptor for dstIo %d", __func__, dstIo);
         }
     }
 }
diff --git a/services/audiopolicy/fuzzer/aidl/Android.bp b/services/audiopolicy/fuzzer/aidl/Android.bp
new file mode 100644
index 0000000..38a2cde
--- /dev/null
+++ b/services/audiopolicy/fuzzer/aidl/Android.bp
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+cc_defaults {
+    name: "audiopolicy_aidl_fuzzer_defaults",
+    shared_libs: [
+        "audiopolicy-aidl-cpp",
+        "audiopolicy-types-aidl-cpp",
+        "framework-permission-aidl-cpp",
+        "libaudiopolicy",
+        "libaudiopolicymanagerdefault",
+        "libactivitymanager_aidl",
+        "libaudiohal",
+        "libaudiopolicyservice",
+        "libaudioflinger",
+        "libaudioclient",
+        "libaudioprocessing",
+        "libhidlbase",
+        "liblog",
+        "libmediautils",
+        "libnblog",
+        "libnbaio",
+        "libpowermanager",
+        "libvibrator",
+        "packagemanager_aidl-cpp",
+    ],
+    static_libs: [
+        "libfakeservicemanager",
+        "libmediaplayerservice",
+    ],
+    header_libs: [
+        "libaudiohal_headers",
+        "libaudioflinger_headers",
+        "libaudiopolicymanager_interface_headers",
+        "libbinder_headers",
+        "libmedia_headers",
+    ],
+    fuzz_config: {
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 155276,
+        hotlists: ["4593311"],
+        description: "The fuzzer targets the APIs of libaudiopolicy",
+        vector: "local_no_privileges_required",
+        service_privilege: "privileged",
+        users: "multi_user",
+        fuzzed_code_usage: "shipped",
+    },
+}
+
+cc_fuzz {
+    name: "audiopolicy_aidl_fuzzer",
+    srcs: ["audiopolicy_aidl_fuzzer.cpp"],
+    defaults: [
+        "audiopolicy_aidl_fuzzer_defaults",
+        "service_fuzzer_defaults",
+    ],
+}
diff --git a/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
new file mode 100644
index 0000000..ca79c49
--- /dev/null
+++ b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <AudioFlinger.h>
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_process.h>
+#include <android/media/IAudioPolicyService.h>
+#include <fakeservicemanager/FakeServiceManager.h>
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzbinder/random_binder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/IAudioFlinger.h>
+#include <service/AudioPolicyService.h>
+
+using namespace android;
+using namespace android::binder;
+using namespace android::hardware;
+using android::fuzzService;
+
+[[clang::no_destroy]] static std::once_flag gSmOnce;
+sp<FakeServiceManager> gFakeServiceManager;
+
+bool addService(const String16& serviceName, const sp<FakeServiceManager>& fakeServiceManager,
+                FuzzedDataProvider& fdp) {
+    sp<IBinder> binder = getRandomBinder(&fdp);
+    if (binder == nullptr) {
+        return false;
+    }
+    CHECK_EQ(NO_ERROR, fakeServiceManager->addService(serviceName, binder));
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    std::call_once(gSmOnce, [&] {
+        /* Create a FakeServiceManager instance and add required services */
+        gFakeServiceManager = sp<FakeServiceManager>::make();
+        setDefaultServiceManager(gFakeServiceManager);
+    });
+    gFakeServiceManager->clear();
+
+    for (const char* service :
+         {"activity", "sensor_privacy", "permission", "scheduling_policy",
+          "android.hardware.audio.core.IConfig", "batterystats", "media.metrics"}) {
+        if (!addService(String16(service), gFakeServiceManager, fdp)) {
+            return 0;
+        }
+    }
+
+    const auto audioFlinger = sp<AudioFlinger>::make();
+    const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+
+    CHECK_EQ(NO_ERROR,
+             gFakeServiceManager->addService(
+                     String16(IAudioFlinger::DEFAULT_SERVICE_NAME), IInterface::asBinder(afAdapter),
+                     false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+
+    AudioSystem::get_audio_flinger_for_fuzzer();
+    const auto audioPolicyService = sp<AudioPolicyService>::make();
+
+    CHECK_EQ(NO_ERROR,
+             gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
+                                             false /* allowIsolated */,
+                                             IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+
+    fuzzService(media::IAudioPolicyService::asBinder(audioPolicyService),
+                FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e06e032..d5505b5 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -337,7 +337,7 @@
                     outputsToReopenWithDevices.emplace(mOutputs.keyAt(i), newDevices);
                     continue;
                 }
-                setOutputDevices(desc, newDevices, force, 0);
+                setOutputDevices(__func__, desc, newDevices, force, 0);
             }
             if (!desc->isDuplicated() && desc->mProfile->hasDynamicAudioProfile() &&
                     !activeMediaDevices.empty() && desc->devices() != activeMediaDevices &&
@@ -728,7 +728,7 @@
     // Use legacy routing method for voice calls via setOutputDevice() on primary output.
     // Otherwise, create two audio patches for TX and RX path.
     if (!createRxPatch) {
-        muteWaitMs = setOutputDevices(mPrimaryOutput, rxDevices, true, delayMs);
+        muteWaitMs = setOutputDevices(__func__, mPrimaryOutput, rxDevices, true, delayMs);
     } else { // create RX path audio patch
         connectTelephonyRxAudioSource();
         // If the TX device is on the primary HW module but RX device is
@@ -888,7 +888,7 @@
                 disconnectTelephonyAudioSource(mCallRxSourceClient);
                 disconnectTelephonyAudioSource(mCallTxSourceClient);
             }
-            setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
+            setOutputDevices(__func__, mPrimaryOutput, rxDevices, force, 0);
         }
     }
 
@@ -906,7 +906,7 @@
                 outputsToReopen.emplace(mOutputs.keyAt(i), newDevices);
                 continue;
             }
-            setOutputDevices(desc, newDevices, forceRouting, 0 /*delayMs*/, nullptr,
+            setOutputDevices(__func__, desc, newDevices, forceRouting, 0 /*delayMs*/, nullptr,
                              true /*requiresMuteCheck*/, !forceRouting /*requiresVolumeCheck*/);
         }
     }
@@ -2339,7 +2339,8 @@
             return DEAD_OBJECT;
         }
         const uint32_t muteWaitMs =
-                setOutputDevices(outputDesc, devices, force, 0, nullptr, requiresMuteCheck);
+                setOutputDevices(__func__, outputDesc, devices, force, 0, nullptr,
+                                 requiresMuteCheck);
 
         // apply volume rules for current stream and device if necessary
         auto &curves = getVolumeCurves(client->attributes());
@@ -2422,7 +2423,7 @@
                     outputsToReopen.emplace(mOutputs.keyAt(i), newDevices);
                     continue;
                 }
-                setOutputDevices(desc, newDevices, force, delayMs);
+                setOutputDevices(__func__, desc, newDevices, force, delayMs);
                 // re-apply device specific volume if not done by setOutputDevice()
                 if (!force) {
                     applyStreamVolumes(desc, newDevices.types(), delayMs);
@@ -2524,7 +2525,7 @@
             // still contain data that needs to be drained. The latency only covers the audio HAL
             // and kernel buffers. Also the latency does not always include additional delay in the
             // audio path (audio DSP, CODEC ...)
-            setOutputDevices(outputDesc, newDevices, false, outputDesc->latency()*2,
+            setOutputDevices(__func__, outputDesc, newDevices, false, outputDesc->latency()*2,
                              nullptr, true /*requiresMuteCheck*/, requiresVolumeCheck);
 
             // force restoring the device selection on other active outputs if it differs from the
@@ -2547,7 +2548,7 @@
                         outputsToReopen.emplace(mOutputs.keyAt(i), newDevices2);
                         continue;
                     }
-                    setOutputDevices(desc, newDevices2, force, delayMs);
+                    setOutputDevices(__func__, desc, newDevices2, force, delayMs);
 
                     // re-apply device specific volume if not done by setOutputDevice()
                     if (!force) {
@@ -3951,8 +3952,9 @@
                 outputsToReopen.emplace(mOutputs.keyAt(i), newDevices);
                 continue;
             }
-            waitMs = setOutputDevices(outputDesc, newDevices, forceRouting, delayMs, nullptr,
-                                      !skipDelays /*requiresMuteCheck*/,
+
+            waitMs = setOutputDevices(__func__, outputDesc, newDevices, forceRouting, delayMs,
+                                       nullptr, !skipDelays /*requiresMuteCheck*/,
                                       !forceRouting /*requiresVolumeCheck*/, skipDelays);
             // Only apply special touch sound delay once
             delayMs = 0;
@@ -4939,7 +4941,7 @@
         // TODO: reconfigure output format and channels here
         ALOGV("%s setting device %s on output %d",
               __func__, dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
-        setOutputDevices(outputDesc, devices, true, 0, handle);
+        setOutputDevices(__func__, outputDesc, devices, true, 0, handle);
         index = mAudioPatches.indexOfKey(*handle);
         if (index >= 0) {
             if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
@@ -5198,7 +5200,7 @@
             return BAD_VALUE;
         }
 
-        setOutputDevices(outputDesc,
+        setOutputDevices(__func__, outputDesc,
                          getNewOutputDevices(outputDesc, true /*fromCache*/),
                          true,
                          0,
@@ -5252,7 +5254,7 @@
             //      3 / Inactive Output previously hosting SwBridge that can be closed.
             bool updateDevice = outputDesc->isActive() || !sourceDesc->useSwBridge() ||
                     sourceDesc->canCloseOutput();
-            setOutputDevices(outputDesc,
+            setOutputDevices(__func__, outputDesc,
                              updateDevice ? getNewOutputDevices(outputDesc, true /*fromCache*/) :
                                             outputDesc->devices(),
                              force,
@@ -5389,7 +5391,7 @@
                 outputsToReopen.emplace(mOutputs.keyAt(j), newDevices);
                 continue;
             }
-            setOutputDevices(outputDesc, newDevices, false);
+            setOutputDevices(__func__, outputDesc, newDevices, false);
         }
     }
     reopenOutputsWithDevices(outputsToReopen);
@@ -6271,7 +6273,7 @@
                 outputDesc->close();
             } else {
                 addOutput(output, outputDesc);
-                setOutputDevices(outputDesc,
+                setOutputDevices(__func__, outputDesc,
                                  DeviceVector(supportedDevice),
                                  true,
                                  0,
@@ -6471,8 +6473,8 @@
                 if (device_distinguishes_on_address(deviceType)) {
                     ALOGV("checkOutputsForDevice(): setOutputDevices %s",
                             device->toString().c_str());
-                    setOutputDevices(desc, DeviceVector(device), true/*force*/, 0/*delay*/,
-                                     NULL/*patch handle*/);
+                    setOutputDevices(__func__, desc, DeviceVector(device), true/*force*/,
+                                      0/*delay*/, NULL/*patch handle*/);
                 }
                 ALOGV("checkOutputsForDevice(): adding output %d", output);
             }
@@ -7355,7 +7357,7 @@
                 if (!desc->supportedDevices().containsAtLeastOne(outputDesc->supportedDevices())) {
                     continue;
                 }
-                ALOGVV("%s() %s (curDevice %s)", __func__,
+                ALOGVV("%s() output %s %s (curDevice %s)", __func__, desc->info().c_str(),
                       mute ? "muting" : "unmuting", curDevices.toString().c_str());
                 setStrategyMute(productStrategy, mute, desc, mute ? 0 : delayMs);
                 if (desc->isStrategyActive(productStrategy)) {
@@ -7408,7 +7410,8 @@
     return 0;
 }
 
-uint32_t AudioPolicyManager::setOutputDevices(const sp<SwAudioOutputDescriptor>& outputDesc,
+uint32_t AudioPolicyManager::setOutputDevices(const char *caller,
+                                              const sp<SwAudioOutputDescriptor>& outputDesc,
                                               const DeviceVector &devices,
                                               bool force,
                                               int delayMs,
@@ -7417,13 +7420,15 @@
                                               bool skipMuteDelay)
 {
     // TODO(b/262404095): Consider if the output need to be reopened.
-    ALOGV("%s device %s delayMs %d", __func__, devices.toString().c_str(), delayMs);
+    std::string logPrefix = std::string("caller ") + caller + outputDesc->info();
+    ALOGV("%s %s device %s delayMs %d", __func__, logPrefix.c_str(),
+          devices.toString().c_str(), delayMs);
     uint32_t muteWaitMs;
 
     if (outputDesc->isDuplicated()) {
-        muteWaitMs = setOutputDevices(outputDesc->subOutput1(), devices, force, delayMs,
+        muteWaitMs = setOutputDevices(__func__, outputDesc->subOutput1(), devices, force, delayMs,
                 nullptr /* patchHandle */, requiresMuteCheck, skipMuteDelay);
-        muteWaitMs += setOutputDevices(outputDesc->subOutput2(), devices, force, delayMs,
+        muteWaitMs += setOutputDevices(__func__, outputDesc->subOutput2(), devices, force, delayMs,
                 nullptr /* patchHandle */, requiresMuteCheck, skipMuteDelay);
         return muteWaitMs;
     }
@@ -7433,7 +7438,8 @@
     DeviceVector prevDevices = outputDesc->devices();
     DeviceVector availPrevDevices = mAvailableOutputDevices.filter(prevDevices);
 
-    ALOGV("setOutputDevices() prevDevice %s", prevDevices.toString().c_str());
+    ALOGV("%s %s prevDevice %s", __func__, logPrefix.c_str(),
+          prevDevices.toString().c_str());
 
     if (!filteredDevices.isEmpty()) {
         outputDesc->setDevices(filteredDevices);
@@ -7443,7 +7449,8 @@
     if (requiresMuteCheck) {
         muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevices, delayMs);
     } else {
-        ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
+        ALOGV("%s: %s suppressing checkDeviceMuteStrategies", __func__,
+              logPrefix.c_str());
         muteWaitMs = 0;
     }
 
@@ -7453,7 +7460,8 @@
     // output profile or if new device is not supported AND previous device(s) is(are) still
     // available (otherwise reset device must be done on the output)
     if (!devices.isEmpty() && filteredDevices.isEmpty() && !availPrevDevices.empty()) {
-        ALOGV("%s: unsupported device %s for output", __func__, devices.toString().c_str());
+        ALOGV("%s: %s unsupported device %s for output", __func__, logPrefix.c_str(),
+              devices.toString().c_str());
         // restore previous device after evaluating strategy mute state
         outputDesc->setDevices(prevDevices);
         return muteWaitMs;
@@ -7466,16 +7474,19 @@
     //  AND the output is connected by a valid audio patch.
     // Doing this check here allows the caller to call setOutputDevices() without conditions
     if ((filteredDevices.isEmpty() || filteredDevices == prevDevices) && !force && outputRouted) {
-        ALOGV("%s setting same device %s or null device, force=%d, patch handle=%d", __func__,
-              filteredDevices.toString().c_str(), force, outputDesc->getPatchHandle());
+        ALOGV("%s %s setting same device %s or null device, force=%d, patch handle=%d",
+              __func__, logPrefix.c_str(), filteredDevices.toString().c_str(), force,
+              outputDesc->getPatchHandle());
         if (requiresVolumeCheck && !filteredDevices.isEmpty()) {
-            ALOGV("%s setting same device on routed output, force apply volumes", __func__);
+            ALOGV("%s %s setting same device on routed output, force apply volumes",
+                  __func__, logPrefix.c_str());
             applyStreamVolumes(outputDesc, filteredDevices.types(), delayMs, true /*force*/);
         }
         return muteWaitMs;
     }
 
-    ALOGV("%s changing device to %s", __func__, filteredDevices.toString().c_str());
+    ALOGV("%s %s changing device to %s", __func__, logPrefix.c_str(),
+          filteredDevices.toString().c_str());
 
     // do the routing
     if (filteredDevices.isEmpty() || mAvailableOutputDevices.filter(filteredDevices).empty()) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 863c785..509cc79 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -526,6 +526,7 @@
 
         /**
          * @brief setOutputDevices change the route of the specified output.
+         * @param caller of the method
          * @param outputDesc to be considered
          * @param device to be considered to route the output
          * @param force if true, force the routing even if no change.
@@ -539,7 +540,8 @@
          * @return the number of ms we have slept to allow new routing to take effect in certain
          *        cases.
          */
-        uint32_t setOutputDevices(const sp<SwAudioOutputDescriptor>& outputDesc,
+        uint32_t setOutputDevices(const char *caller,
+                                  const sp<SwAudioOutputDescriptor>& outputDesc,
                                   const DeviceVector &device,
                                   bool force = false,
                                   int delayMs = 0,
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 4876195..87a4420 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -73,7 +73,9 @@
                 cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
                 clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
                 /*legacyClient*/ true),
-        mParameters(api1CameraId, cameraFacing)
+        mParameters(api1CameraId, cameraFacing),
+        mLatestRequestIds(kMaxRequestIds),
+        mLatestFailedRequestIds(kMaxRequestIds)
 {
     ATRACE_CALL();
 
@@ -1835,7 +1837,7 @@
                     (hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT == errorCode)) {
                 Mutex::Autolock al(mLatestRequestMutex);
 
-                mLatestFailedRequestId = resultExtras.requestId;
+                mLatestFailedRequestIds.add(resultExtras.requestId);
                 mLatestRequestSignal.signal();
             }
             mCaptureSequencer->notifyError(errorCode, resultExtras);
@@ -2410,7 +2412,10 @@
 
 status_t Camera2Client::waitUntilRequestIdApplied(int32_t requestId, nsecs_t timeout) {
     Mutex::Autolock l(mLatestRequestMutex);
-    while ((mLatestRequestId != requestId) && (mLatestFailedRequestId != requestId)) {
+    while ((std::find(mLatestRequestIds.begin(), mLatestRequestIds.end(), requestId) ==
+            mLatestRequestIds.end()) &&
+           (std::find(mLatestFailedRequestIds.begin(), mLatestFailedRequestIds.end(), requestId) ==
+            mLatestFailedRequestIds.end())) {
         nsecs_t startTime = systemTime();
 
         auto res = mLatestRequestSignal.waitRelative(mLatestRequestMutex, timeout);
@@ -2419,13 +2424,14 @@
         timeout -= (systemTime() - startTime);
     }
 
-    return (mLatestRequestId == requestId) ? OK : DEAD_OBJECT;
+    return (std::find(mLatestRequestIds.begin(), mLatestRequestIds.end(), requestId) !=
+             mLatestRequestIds.end()) ? OK : DEAD_OBJECT;
 }
 
 void Camera2Client::notifyRequestId(int32_t requestId) {
     Mutex::Autolock al(mLatestRequestMutex);
 
-    mLatestRequestId = requestId;
+    mLatestRequestIds.add(requestId);
     mLatestRequestSignal.signal();
 }
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index fe12690..9ec1eb5 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -22,11 +22,7 @@
 #include "common/Camera2ClientBase.h"
 #include "api1/client2/Parameters.h"
 #include "api1/client2/FrameProcessor.h"
-//#include "api1/client2/StreamingProcessor.h"
-//#include "api1/client2/JpegProcessor.h"
-//#include "api1/client2/ZslProcessor.h"
-//#include "api1/client2/CaptureSequencer.h"
-//#include "api1/client2/CallbackProcessor.h"
+#include <media/RingBuffer.h>
 
 namespace android {
 
@@ -263,8 +259,8 @@
 
     mutable Mutex mLatestRequestMutex;
     Condition mLatestRequestSignal;
-    int32_t mLatestRequestId = -1;
-    int32_t mLatestFailedRequestId = -1;
+    static constexpr size_t kMaxRequestIds = BufferQueueDefs::NUM_BUFFER_SLOTS;
+    RingBuffer<int32_t> mLatestRequestIds, mLatestFailedRequestIds;
     status_t waitUntilRequestIdApplied(int32_t requestId, nsecs_t timeout);
     status_t waitUntilCurrentRequestIdLocked();
 };
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index 5e79d6b..9659db8 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -607,8 +607,9 @@
             aidl::android::hardware::camera::device::CameraMetadata pChars;
             status = interface->getPhysicalCameraCharacteristics(id, &pChars);
             if (!status.isOk()) {
-                ALOGE("%s: Transaction error getting physical camera %s characteristics for %s: %s",
-                        __FUNCTION__, id.c_str(), id.c_str(), status.getMessage());
+                ALOGE("%s: Transaction error getting physical camera %s characteristics for "
+                        "logical id %s: %s", __FUNCTION__, id.c_str(), mId.c_str(),
+                        status.getMessage());
                 return;
             }
             std::vector<uint8_t> &pMetadata = pChars.metadata;
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index bf7a471..aeb0abc 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -743,8 +743,9 @@
             });
 
             if (!ret.isOk()) {
-                ALOGE("%s: Transaction error getting physical camera %s characteristics for %s: %s",
-                        __FUNCTION__, id.c_str(), id.c_str(), ret.description().c_str());
+                ALOGE("%s: Transaction error getting physical camera %s characteristics for"
+                        " logical id %s: %s", __FUNCTION__, id.c_str(), mId.c_str(),
+                        ret.description().c_str());
                 return;
             }
             if (status != Status::OK) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index a275cfb..597b9aa 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -3034,6 +3034,7 @@
         mNotifyPipelineDrain(false),
         mFrameNumber(0),
         mLatestRequestId(NAME_NOT_FOUND),
+        mLatestFailedRequestId(NAME_NOT_FOUND),
         mCurrentAfTriggerId(0),
         mCurrentPreCaptureTriggerId(0),
         mRotateAndCropOverride(ANDROID_SCALER_ROTATE_AND_CROP_NONE),
@@ -3285,7 +3286,7 @@
     ATRACE_CALL();
     Mutex::Autolock l(mLatestRequestMutex);
     status_t res;
-    while (mLatestRequestId != requestId) {
+    while (mLatestRequestId != requestId && mLatestFailedRequestId != requestId) {
         nsecs_t startTime = systemTime();
 
         res = mLatestRequestSignal.waitRelative(mLatestRequestMutex, timeout);
@@ -4363,6 +4364,12 @@
                         hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
                         captureRequest->mResultExtras);
             }
+            {
+                Mutex::Autolock al(mLatestRequestMutex);
+
+                mLatestFailedRequestId = captureRequest->mResultExtras.requestId;
+                mLatestRequestSignal.signal();
+            }
         }
 
         // Remove yet-to-be submitted inflight request from inflightMap
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 0c1bbcb..a1e25fd 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1142,6 +1142,7 @@
         Condition          mLatestRequestSignal;
         // android.request.id for latest process_capture_request
         int32_t            mLatestRequestId;
+        int32_t            mLatestFailedRequestId;
         CameraMetadata     mLatestRequest;
         std::unordered_map<std::string, CameraMetadata> mLatestPhysicalRequest;