Merge "audio_mutex: Add mutex priority inheritance flag" into main
diff --git a/media/codec2/hal/client/GraphicBufferAllocator.cpp b/media/codec2/hal/client/GraphicBufferAllocator.cpp
index bbef1b5..7045537 100644
--- a/media/codec2/hal/client/GraphicBufferAllocator.cpp
+++ b/media/codec2/hal/client/GraphicBufferAllocator.cpp
@@ -62,14 +62,12 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus GraphicBufferAllocator::getWaitableFds(
-        IGraphicBufferAllocator::WaitableFds* _aidl_return) {
-    int allocFd;
-    int statusFd;
-    c2_status_t ret = mGraphicsTracker->getWaitableFds(&allocFd, &statusFd);
+::ndk::ScopedAStatus GraphicBufferAllocator::getWaitableFd(
+        ::ndk::ScopedFileDescriptor* _aidl_return) {
+    int pipeFd;
+    c2_status_t ret = mGraphicsTracker->getWaitableFd(&pipeFd);
     if (ret == C2_OK) {
-        _aidl_return->allocEvent.set(allocFd);
-        _aidl_return->statusEvent.set(statusFd);
+        _aidl_return->set(pipeFd);
         return ::ndk::ScopedAStatus::ok();
     }
     return ::ndk::ScopedAStatus::fromServiceSpecificError(ret);
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 5a2cb86..2424f7b 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -13,7 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <sys/eventfd.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <private/android/AHardwareBufferHelpers.h>
@@ -25,6 +26,9 @@
 
 namespace {
 
+static constexpr int kMaxDequeueMin = 1;
+static constexpr int kMaxDequeueMax = ::android::BufferQueueDefs::NUM_BUFFER_SLOTS - 2;
+
 c2_status_t retrieveAHardwareBufferId(const C2ConstGraphicBlock &blk, uint64_t *bid) {
     // TODO
     (void)blk;
@@ -139,21 +143,26 @@
     mDequeueable{maxDequeueCount},
     mTotalDequeued{0}, mTotalCancelled{0}, mTotalDropped{0}, mTotalReleased{0},
     mInConfig{false}, mStopped{false} {
-    if (maxDequeueCount <= 0) {
-        mMaxDequeue = kDefaultMaxDequeue;
-        mMaxDequeueRequested = kDefaultMaxDequeue;
-        mMaxDequeueCommitted = kDefaultMaxDequeue;
-        mDequeueable = kDefaultMaxDequeue;
+    if (maxDequeueCount < kMaxDequeueMin) {
+        mMaxDequeue = kMaxDequeueMin;
+        mMaxDequeueRequested = kMaxDequeueMin;
+        mMaxDequeueCommitted = kMaxDequeueMin;
+        mDequeueable = kMaxDequeueMin;
+    } else if(maxDequeueCount > kMaxDequeueMax) {
+        mMaxDequeue = kMaxDequeueMax;
+        mMaxDequeueRequested = kMaxDequeueMax;
+        mMaxDequeueCommitted = kMaxDequeueMax;
+        mDequeueable = kMaxDequeueMax;
     }
-    int allocEventFd = ::eventfd(mDequeueable, EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE);
-    int statusEventFd = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+    int pipefd[2] = { -1, -1};
+    int ret = ::pipe2(pipefd, O_CLOEXEC | O_NONBLOCK);
 
-    mAllocEventFd.reset(allocEventFd);
-    mStopEventFd.reset(statusEventFd);
+    mReadPipeFd.reset(pipefd[0]);
+    mWritePipeFd.reset(pipefd[1]);
 
     mEventQueueThread = std::thread([this](){processEvent();});
 
-    CHECK(allocEventFd >= 0 && statusEventFd >= 0);
+    CHECK(ret >= 0);
     CHECK(mEventQueueThread.joinable());
 }
 
@@ -161,7 +170,6 @@
     stop();
     if (mEventQueueThread.joinable()) {
         std::unique_lock<std::mutex> l(mEventLock);
-        mStopEventThread = true;
         l.unlock();
         mEventCv.notify_one();
         mEventQueueThread.join();
@@ -231,6 +239,11 @@
 c2_status_t GraphicsTracker::configureMaxDequeueCount(int maxDequeueCount) {
     std::shared_ptr<BufferCache> cache;
 
+    if (maxDequeueCount < kMaxDequeueMin || maxDequeueCount > kMaxDequeueMax) {
+        ALOGE("max dequeue count %d is not valid", maxDequeueCount);
+        return C2_BAD_VALUE;
+    }
+
     // max dequeue count which can be committed to IGBP.
     // (Sometimes maxDequeueCount cannot be committed if the number of
     // dequeued buffer count is bigger.)
@@ -347,89 +360,76 @@
 
 void GraphicsTracker::stop() {
     bool expected = false;
+    std::unique_lock<std::mutex> l(mEventLock);
     bool updated = mStopped.compare_exchange_strong(expected, true);
     if (updated) {
-        uint64_t val = 1ULL;
-        int ret = ::write(mStopEventFd.get(), &val, 8);
-        if (ret < 0) {
-            // EINTR maybe
-            std::unique_lock<std::mutex> l(mEventLock);
-            mStopRequest = true;
-            l.unlock();
-            mEventCv.notify_one();
-            ALOGW("stop() status update pending");
-        }
+        int writeFd = mWritePipeFd.release();
+        ::close(writeFd);
     }
 }
 
 void GraphicsTracker::writeIncDequeueable(int inc) {
-    uint64_t val = inc;
-    int ret = ::write(mAllocEventFd.get(), &val, 8);
-    if (ret < 0) {
-        // EINTR due to signal handling maybe, this should be rare
+    CHECK(inc > 0 && inc < kMaxDequeueMax);
+    thread_local char buf[kMaxDequeueMax];
+    int diff = 0;
+    {
         std::unique_lock<std::mutex> l(mEventLock);
-        mIncDequeueable += inc;
-        l.unlock();
-        mEventCv.notify_one();
-        ALOGW("updating dequeueable to eventfd pending");
+        if (mStopped) {
+            return;
+        }
+        CHECK(mWritePipeFd.get() >= 0);
+        int ret = ::write(mWritePipeFd.get(), buf, inc);
+        if (ret == inc) {
+            return;
+        }
+        diff = ret < 0 ? inc : inc - ret;
+
+        // Partial write or EINTR. This will not happen in a real scenario.
+        mIncDequeueable += diff;
+        if (mIncDequeueable > 0) {
+            l.unlock();
+            mEventCv.notify_one();
+            ALOGW("updating dequeueable to pipefd pending");
+        }
     }
 }
 
 void GraphicsTracker::processEvent() {
-    // This is for write() failure of eventfds.
-    // write() failure other than EINTR should not happen.
-    int64_t acc = 0;
-    bool stopRequest = false;
-    bool stopCommitted = false;
-
+    // This is for partial/failed writes to the writing end.
+    // This may not happen in the real scenario.
+    thread_local char buf[kMaxDequeueMax];
     while (true) {
-        {
-            std::unique_lock<std::mutex> l(mEventLock);
-            acc += mIncDequeueable;
-            mIncDequeueable = 0;
-            stopRequest |= mStopRequest;
-            mStopRequest = false;
-            if (acc == 0 && stopRequest == stopCommitted) {
-                if (mStopEventThread) {
-                    break;
+        std::unique_lock<std::mutex> l(mEventLock);
+        if (mStopped) {
+            break;
+        }
+        if (mIncDequeueable > 0) {
+            int inc = mIncDequeueable > kMaxDequeueMax ? kMaxDequeueMax : mIncDequeueable;
+            int ret = ::write(mWritePipeFd.get(), buf, inc);
+            int written = ret <= 0 ? 0 : ret;
+            mIncDequeueable -= written;
+            if (mIncDequeueable > 0) {
+                l.unlock();
+                if (ret < 0) {
+                    ALOGE("write to writing end failed %d", errno);
+                } else {
+                    ALOGW("partial write %d(%d)", inc, written);
                 }
-                mEventCv.wait(l);
                 continue;
             }
         }
-
-        if (acc > 0) {
-            int ret = ::write(mAllocEventFd.get(), &acc, 8);
-            if (ret > 0) {
-                acc = 0;
-            }
-        }
-        if (stopRequest && !stopCommitted) {
-            uint64_t val = 1ULL;
-            int ret = ::write(mStopEventFd.get(), &val, 8);
-            if (ret > 0) {
-                stopCommitted = true;
-            }
-        }
-        if (mStopEventThread) {
-            break;
-        }
+        mEventCv.wait(l);
     }
 }
 
-c2_status_t GraphicsTracker::getWaitableFds(int *allocFd, int *statusFd) {
-    *allocFd = ::dup(mAllocEventFd.get());
-    *statusFd = ::dup(mStopEventFd.get());
-
-    if (*allocFd < 0 || *statusFd < 0) {
-        if (*allocFd >= 0) {
-            ::close(*allocFd);
-            *allocFd = -1;
+c2_status_t GraphicsTracker::getWaitableFd(int *pipeFd) {
+    *pipeFd = ::dup(mReadPipeFd.get());
+    if (*pipeFd < 0) {
+        if (mReadPipeFd.get() < 0) {
+            return C2_BAD_STATE;
         }
-        if (*statusFd >= 0) {
-            ::close(*statusFd);
-            *statusFd = -1;
-        }
+        // dup error
+        ALOGE("dup() for the reading end failed %d", errno);
         return C2_NO_MEMORY;
     }
     return C2_OK;
@@ -438,8 +438,8 @@
 c2_status_t GraphicsTracker::requestAllocate(std::shared_ptr<BufferCache> *cache) {
     std::lock_guard<std::mutex> l(mLock);
     if (mDequeueable > 0) {
-        uint64_t val;
-        int ret = ::read(mAllocEventFd.get(), &val, 8);
+        char buf[1];
+        int ret = ::read(mReadPipeFd.get(), buf, 1);
         if (ret < 0) {
             if (errno == EINTR) {
                 // Do we really need to care for cancel due to signal handling?
@@ -452,6 +452,10 @@
             }
             CHECK(errno != 0);
         }
+        if (ret == 0) {
+            // writing end is closed
+            return C2_BAD_STATE;
+        }
         mDequeueable--;
         *cache = mBufferCache;
         return C2_OK;
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
index f9c8aca..902c53f 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
@@ -38,8 +38,8 @@
 
     ::ndk::ScopedAStatus deallocate(int64_t in_id, bool* _aidl_return) override;
 
-    ::ndk::ScopedAStatus getWaitableFds(
-            IGraphicBufferAllocator::WaitableFds* _aidl_return) override;
+    ::ndk::ScopedAStatus getWaitableFd(
+            ::ndk::ScopedFileDescriptor* _aidl_return) override;
 
     /**
      * Configuring Surface/BufferQueue for the interface.
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
index 681b7e8..1fd9049 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -142,15 +142,15 @@
     void onReleased(uint32_t generation);
 
     /**
-     * Get waitable fds for events.(allocate is ready, end of life cycle)
+     * Get waitable fd for events.(allocate is ready, end of life cycle)
      *
-     * @param[out]  allocFd     eventFd which signals being ready to allocate
-     * @param[out]  statusFd    eventFd which signals end of life cycle.
-     *                          When signaled no more allocate is possible.
+     * @param[out]  pipeFd      a file descriptor created from pipe2()
+     *                          in order for notifying being ready to allocate
+     *
      * @return  C2_OK
      *          C2_NO_MEMORY    Max # of fd reached.(not really a memory issue)
      */
-    c2_status_t getWaitableFds(int *allocFd, int *statusFd);
+    c2_status_t getWaitableFd(int *pipeFd);
 
     /**
      *  Ends to use the class. after the call, allocate will fail.
@@ -158,8 +158,6 @@
     void stop();
 
 private:
-    static constexpr int kDefaultMaxDequeue = 2;
-
     struct BufferCache;
 
     struct BufferItem {
@@ -246,21 +244,30 @@
     std::mutex mLock; // locks for data synchronization
     std::mutex mConfigLock; // locks for configuration change.
 
+    // NOTE: pipe2() creates two file descriptors for allocatable events
+    // and irrecoverable error events notification.
+    //
+    // A byte will be written to the writing end whenever a buffer is ready to
+    // dequeue/allocate. A byte will be read from the reading end whenever
+    // an allocate/dequeue event happens.
+    //
+    // The writing end will be closed when the end-of-lifecycle event was met.
+    //
+    // The reading end will be shared to the remote processes. Remote processes
+    // use ::poll() to check whether a buffer is ready to allocate/ready.
+    // Also ::poll() will let remote processes know the end-of-lifecycle event
+    // by returning POLLHUP event from the reading end.
+    ::android::base::unique_fd mReadPipeFd;   // The reading end file descriptor
+    ::android::base::unique_fd mWritePipeFd;  // The writing end file descriptor
+
     std::atomic<bool> mStopped;
-
-    ::android::base::unique_fd mAllocEventFd; // eventfd in semaphore mode which
-                                              // mirrors mDqueueable.
-    ::android::base::unique_fd mStopEventFd; // eventfd which indicates the life
-                                             // cycle of the class being stopped.
-
     std::thread mEventQueueThread; // Thread to handle interrupted
-                                   // writes to eventfd{s}.
+                                   // writes to the writing end.
     std::mutex mEventLock;
     std::condition_variable mEventCv;
 
     bool mStopEventThread;
     int mIncDequeueable; // pending # of write to increase dequeueable eventfd
-    bool mStopRequest; // pending write to statusfd
 
 private:
     explicit GraphicsTracker(int maxDequeueCount);
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 1ffa78f..9064eb9 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -327,6 +327,450 @@
     return C2_OK;
 }
 
+static c2_status_t PopulatePlaneLayout(
+        buffer_handle_t buffer,
+        const Rect &rect,
+        uint32_t format,
+        uint64_t grallocUsage,
+        uint32_t stride,
+        C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+    // 'NATIVE' on Android means LITTLE_ENDIAN
+    constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE;
+
+    // Try to resolve IMPLEMENTATION_DEFINED format to accurate format if
+    // possible.
+    uint32_t fourCc;
+    if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
+        !GraphicBufferMapper::get().getPixelFormatFourCC(buffer, &fourCc)) {
+        switch (fourCc)  {
+            case DRM_FORMAT_XBGR8888:
+                 format = static_cast<uint32_t>(PixelFormat4::RGBX_8888);
+                 break;
+            case DRM_FORMAT_ABGR8888:
+                 format = static_cast<uint32_t>(PixelFormat4::RGBA_8888);
+                 break;
+            default:
+                 break;
+        }
+    }
+
+    switch (format) {
+        case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
+            // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
+            // Surface. In all other cases it is RGBA. We don't know which case it is here, so
+            // default to YUV for now.
+            void *pointer = nullptr;
+            // TODO: fence
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(RGBA_1010102)");
+                return C2_CORRUPTED;
+            }
+            // treat as 32-bit values
+            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_V] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_A] = (uint8_t *)pointer;
+            layout->type = C2PlanarLayout::TYPE_YUVA;
+            layout->numPlanes = 4;
+            layout->rootPlanes = 1;
+            layout->planes[C2PlanarLayout::PLANE_Y] = {
+                C2PlaneInfo::CHANNEL_Y,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                32,                             // allocatedDepth
+                10,                             // bitDepth
+                10,                             // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_U] = {
+                C2PlaneInfo::CHANNEL_CB,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                32,                             // allocatedDepth
+                10,                             // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_V] = {
+                C2PlaneInfo::CHANNEL_CR,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                32,                             // allocatedDepth
+                10,                             // bitDepth
+                20,                             // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_A] = {
+                C2PlaneInfo::CHANNEL_A,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                32,                             // allocatedDepth
+                2,                              // bitDepth
+                30,                             // rightShift
+                C2PlaneInfo::LITTLE_END,        // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            break;
+        }
+
+        case static_cast<uint32_t>(PixelFormat4::RGBA_8888):
+            // TODO: alpha channel
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::RGBX_8888): {
+            void *pointer = nullptr;
+            // TODO: fence
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(RGBA_8888)");
+                return C2_CORRUPTED;
+            }
+            addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
+            addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
+            layout->type = C2PlanarLayout::TYPE_RGB;
+            layout->numPlanes = 3;
+            layout->rootPlanes = 1;
+            layout->planes[C2PlanarLayout::PLANE_R] = {
+                C2PlaneInfo::CHANNEL_R,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_G] = {
+                C2PlaneInfo::CHANNEL_G,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                1,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_B] = {
+                C2PlaneInfo::CHANNEL_B,         // channel
+                4,                              // colInc
+                static_cast<int32_t>(4 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                2,                              // offset
+            };
+            break;
+        }
+
+        case static_cast<uint32_t>(PixelFormat4::BLOB): {
+            void *pointer = nullptr;
+            // TODO: fence
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(BLOB)");
+                return C2_CORRUPTED;
+            }
+            *addr = (uint8_t *)pointer;
+            break;
+        }
+
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
+            // fall-through
+        case static_cast<uint32_t>(PixelFormat4::YV12): {
+            android_ycbcr ycbcrLayout;
+
+            status_t err = GraphicBufferMapper::get().lockYCbCr(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, &ycbcrLayout);
+            if (err) {
+                ALOGE("failed transaction: lockYCbCr (err=%d)", err);
+                return C2_CORRUPTED;
+            }
+            if (!ycbcrLayout.y || !ycbcrLayout.cb || !ycbcrLayout.cr
+                    || ycbcrLayout.ystride == 0
+                    || ycbcrLayout.cstride == 0
+                    || ycbcrLayout.chroma_step == 0) {
+                ALOGE("invalid layout: lockYCbCr (y=%s cb=%s cr=%s "
+                        "ystride=%zu cstride=%zu chroma_step=%zu)",
+                        ycbcrLayout.y ? "(non-null)" : "(null)",
+                        ycbcrLayout.cb ? "(non-null)" : "(null)",
+                        ycbcrLayout.cr ? "(non-null)" : "(null)",
+                        ycbcrLayout.ystride, ycbcrLayout.cstride, ycbcrLayout.chroma_step);
+                return C2_CORRUPTED;
+            }
+
+            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+            addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+            layout->type = C2PlanarLayout::TYPE_YUV;
+            layout->numPlanes = 3;
+            layout->rootPlanes = 3;
+            layout->planes[C2PlanarLayout::PLANE_Y] = {
+                C2PlaneInfo::CHANNEL_Y,         // channel
+                1,                              // colInc
+                (int32_t)ycbcrLayout.ystride,   // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_U] = {
+                C2PlaneInfo::CHANNEL_CB,          // channel
+                (int32_t)ycbcrLayout.chroma_step, // colInc
+                (int32_t)ycbcrLayout.cstride,     // rowInc
+                2,                                // mColSampling
+                2,                                // mRowSampling
+                8,                                // allocatedDepth
+                8,                                // bitDepth
+                0,                                // rightShift
+                C2PlaneInfo::NATIVE,              // endianness
+                C2PlanarLayout::PLANE_U,          // rootIx
+                0,                                // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_V] = {
+                C2PlaneInfo::CHANNEL_CR,          // channel
+                (int32_t)ycbcrLayout.chroma_step, // colInc
+                (int32_t)ycbcrLayout.cstride,     // rowInc
+                2,                                // mColSampling
+                2,                                // mRowSampling
+                8,                                // allocatedDepth
+                8,                                // bitDepth
+                0,                                // rightShift
+                C2PlaneInfo::NATIVE,              // endianness
+                C2PlanarLayout::PLANE_V,          // rootIx
+                0,                                // offset
+            };
+            break;
+        }
+
+        case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
+            // In Android T, P010 is relaxed to allow arbitrary stride for the Y and UV planes,
+            // try locking with the gralloc4 mapper first.
+            c2_status_t status = Gralloc4Mapper_lock(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, layout, addr);
+            if (status == C2_OK) {
+                break;
+            }
+
+            void *pointer = nullptr;
+            status_t err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(YCBCR_P010)");
+                return C2_CORRUPTED;
+            }
+            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
+            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + stride * 2 * rect.height();
+            addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2;
+            layout->type = C2PlanarLayout::TYPE_YUV;
+            layout->numPlanes = 3;
+            layout->rootPlanes = 2;
+            layout->planes[C2PlanarLayout::PLANE_Y] = {
+                C2PlaneInfo::CHANNEL_Y,         // channel
+                2,                              // colInc
+                static_cast<int32_t>(2 * stride), // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                kEndianness,                    // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_U] = {
+                C2PlaneInfo::CHANNEL_CB,        // channel
+                4,                              // colInc
+                static_cast<int32_t>(2 * stride), // rowInc
+                2,                              // mColSampling
+                2,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                kEndianness,                    // endianness
+                C2PlanarLayout::PLANE_U,        // rootIx
+                0,                              // offset
+            };
+            layout->planes[C2PlanarLayout::PLANE_V] = {
+                C2PlaneInfo::CHANNEL_CR,        // channel
+                4,                              // colInc
+                static_cast<int32_t>(2 * stride), // rowInc
+                2,                              // mColSampling
+                2,                              // mRowSampling
+                16,                             // allocatedDepth
+                10,                             // bitDepth
+                6,                              // rightShift
+                kEndianness,                    // endianness
+                C2PlanarLayout::PLANE_U,        // rootIx
+                2,                              // offset
+            };
+            break;
+        }
+
+        default: {
+            // We don't know what it is, let's try to lock it with gralloc4
+            android_ycbcr ycbcrLayout;
+            if (isAtLeastT()) {
+                c2_status_t status = Gralloc4Mapper_lock(
+                        const_cast<native_handle_t*>(buffer), grallocUsage, rect, layout, addr);
+                if (status == C2_OK) {
+                    break;
+                }
+            }
+
+            // fallback to lockYCbCr
+            status_t err = GraphicBufferMapper::get().lockYCbCr(
+                    const_cast<native_handle_t*>(buffer), grallocUsage, rect, &ycbcrLayout);
+            if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
+                    && ycbcrLayout.ystride > 0
+                    && ycbcrLayout.cstride > 0
+                    && ycbcrLayout.chroma_step > 0) {
+                addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+                addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+                addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+                layout->type = C2PlanarLayout::TYPE_YUV;
+                layout->numPlanes = 3;
+                layout->rootPlanes = 3;
+                layout->planes[C2PlanarLayout::PLANE_Y] = {
+                    C2PlaneInfo::CHANNEL_Y,         // channel
+                    1,                              // colInc
+                    (int32_t)ycbcrLayout.ystride,   // rowInc
+                    1,                              // mColSampling
+                    1,                              // mRowSampling
+                    8,                              // allocatedDepth
+                    8,                              // bitDepth
+                    0,                              // rightShift
+                    C2PlaneInfo::NATIVE,            // endianness
+                    C2PlanarLayout::PLANE_Y,        // rootIx
+                    0,                              // offset
+                };
+                layout->planes[C2PlanarLayout::PLANE_U] = {
+                    C2PlaneInfo::CHANNEL_CB,          // channel
+                    (int32_t)ycbcrLayout.chroma_step, // colInc
+                    (int32_t)ycbcrLayout.cstride,     // rowInc
+                    2,                                // mColSampling
+                    2,                                // mRowSampling
+                    8,                                // allocatedDepth
+                    8,                                // bitDepth
+                    0,                                // rightShift
+                    C2PlaneInfo::NATIVE,              // endianness
+                    C2PlanarLayout::PLANE_U,          // rootIx
+                    0,                                // offset
+                };
+                layout->planes[C2PlanarLayout::PLANE_V] = {
+                    C2PlaneInfo::CHANNEL_CR,          // channel
+                    (int32_t)ycbcrLayout.chroma_step, // colInc
+                    (int32_t)ycbcrLayout.cstride,     // rowInc
+                    2,                                // mColSampling
+                    2,                                // mRowSampling
+                    8,                                // allocatedDepth
+                    8,                                // bitDepth
+                    0,                                // rightShift
+                    C2PlaneInfo::NATIVE,              // endianness
+                    C2PlanarLayout::PLANE_V,          // rootIx
+                    0,                                // offset
+                };
+                break;
+            }
+
+            // We really don't know what this is; lock the buffer and pass it through ---
+            // the client may know how to interpret it.
+
+            // unlock previous allocation if it was successful
+            if (err == OK) {
+                err = GraphicBufferMapper::get().unlock(buffer);
+                if (err) {
+                    ALOGE("failed transaction: unlock");
+                    return C2_CORRUPTED;
+                }
+            }
+
+            void *pointer = nullptr;
+            err = GraphicBufferMapper::get().lock(
+                    const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(??? %x)", format);
+                return C2_CORRUPTED;
+            }
+            addr[0] = (uint8_t *)pointer;
+            layout->type = C2PlanarLayout::TYPE_UNKNOWN;
+            layout->numPlanes = 1;
+            layout->rootPlanes = 1;
+            layout->planes[0] = {
+                // TODO: CHANNEL_UNKNOWN?
+                C2PlaneInfo::channel_t(0xFF),   // channel
+                1,                              // colInc
+                int32_t(stride),               // rowInc
+                1,                              // mColSampling
+                1,                              // mRowSampling
+                8,                              // allocatedDepth
+                8,                              // bitDepth
+                0,                              // rightShift
+                C2PlaneInfo::NATIVE,            // endianness
+                0,                              // rootIx
+                0,                              // offset
+            };
+            break;
+        }
+    }
+    return C2_OK;
+}
+
+static void HandleInterleavedPlanes(
+        C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+    if (layout->type == C2PlanarLayout::TYPE_YUV && layout->rootPlanes == 3) {
+        intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+        intptr_t uvColInc = layout->planes[C2PlanarLayout::PLANE_U].colInc;
+        if (uvOffset > 0 && uvOffset < uvColInc) {
+            layout->rootPlanes = 2;
+            layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+            layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+        } else if (uvOffset < 0 && uvOffset > -uvColInc) {
+            layout->rootPlanes = 2;
+            layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+            layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+        }
+    }
+}
+
 } // unnamed namespace
 
 
@@ -488,440 +932,14 @@
                 mStride, generation, igbp_id, igbp_slot);
     }
 
-    // 'NATIVE' on Android means LITTLE_ENDIAN
-    constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE;
-
-    // Try to resolve IMPLEMENTATION_DEFINED format to accurate format if
-    // possible.
-    uint32_t format = mFormat;
-    uint32_t fourCc;
-    if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
-        !GraphicBufferMapper::get().getPixelFormatFourCC(mBuffer, &fourCc)) {
-        switch (fourCc)  {
-            case DRM_FORMAT_XBGR8888:
-                 format = static_cast<uint32_t>(PixelFormat4::RGBX_8888);
-                 break;
-            case DRM_FORMAT_ABGR8888:
-                 format = static_cast<uint32_t>(PixelFormat4::RGBA_8888);
-                 break;
-            default:
-                 break;
-        }
-    }
-
-    switch (format) {
-        case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
-            // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
-            // Surface. In all other cases it is RGBA. We don't know which case it is here, so
-            // default to YUV for now.
-            void *pointer = nullptr;
-            // TODO: fence
-            status_t err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(RGBA_1010102)");
-                return C2_CORRUPTED;
-            }
-            // treat as 32-bit values
-            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_V] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_A] = (uint8_t *)pointer;
-            layout->type = C2PlanarLayout::TYPE_YUVA;
-            layout->numPlanes = 4;
-            layout->rootPlanes = 1;
-            layout->planes[C2PlanarLayout::PLANE_Y] = {
-                C2PlaneInfo::CHANNEL_Y,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                32,                             // allocatedDepth
-                10,                             // bitDepth
-                10,                             // rightShift
-                C2PlaneInfo::LITTLE_END,        // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_U] = {
-                C2PlaneInfo::CHANNEL_CB,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                32,                             // allocatedDepth
-                10,                             // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::LITTLE_END,        // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_V] = {
-                C2PlaneInfo::CHANNEL_CR,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                32,                             // allocatedDepth
-                10,                             // bitDepth
-                20,                             // rightShift
-                C2PlaneInfo::LITTLE_END,        // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_A] = {
-                C2PlaneInfo::CHANNEL_A,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                32,                             // allocatedDepth
-                2,                              // bitDepth
-                30,                             // rightShift
-                C2PlaneInfo::LITTLE_END,        // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            break;
-        }
-
-        case static_cast<uint32_t>(PixelFormat4::RGBA_8888):
-            // TODO: alpha channel
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::RGBX_8888): {
-            void *pointer = nullptr;
-            // TODO: fence
-            status_t err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(RGBA_8888)");
-                return C2_CORRUPTED;
-            }
-            addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
-            addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
-            layout->type = C2PlanarLayout::TYPE_RGB;
-            layout->numPlanes = 3;
-            layout->rootPlanes = 1;
-            layout->planes[C2PlanarLayout::PLANE_R] = {
-                C2PlaneInfo::CHANNEL_R,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                C2PlanarLayout::PLANE_R,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_G] = {
-                C2PlaneInfo::CHANNEL_G,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                C2PlanarLayout::PLANE_R,        // rootIx
-                1,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_B] = {
-                C2PlaneInfo::CHANNEL_B,         // channel
-                4,                              // colInc
-                static_cast<int32_t>(4 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                C2PlanarLayout::PLANE_R,        // rootIx
-                2,                              // offset
-            };
-            break;
-        }
-
-        case static_cast<uint32_t>(PixelFormat4::BLOB): {
-            void *pointer = nullptr;
-            // TODO: fence
-            status_t err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(BLOB)");
-                return C2_CORRUPTED;
-            }
-            *addr = (uint8_t *)pointer;
-            break;
-        }
-
-        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP):
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP):
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I):
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
-            // fall-through
-        case static_cast<uint32_t>(PixelFormat4::YV12): {
-            android_ycbcr ycbcrLayout;
-
-            status_t err = GraphicBufferMapper::get().lockYCbCr(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
-            if (err) {
-                ALOGE("failed transaction: lockYCbCr (err=%d)", err);
-                return C2_CORRUPTED;
-            }
-            if (!ycbcrLayout.y || !ycbcrLayout.cb || !ycbcrLayout.cr
-                    || ycbcrLayout.ystride == 0
-                    || ycbcrLayout.cstride == 0
-                    || ycbcrLayout.chroma_step == 0) {
-                ALOGE("invalid layout: lockYCbCr (y=%s cb=%s cr=%s "
-                        "ystride=%zu cstride=%zu chroma_step=%zu)",
-                        ycbcrLayout.y ? "(non-null)" : "(null)",
-                        ycbcrLayout.cb ? "(non-null)" : "(null)",
-                        ycbcrLayout.cr ? "(non-null)" : "(null)",
-                        ycbcrLayout.ystride, ycbcrLayout.cstride, ycbcrLayout.chroma_step);
-                return C2_CORRUPTED;
-            }
-
-            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
-            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
-            addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
-            layout->type = C2PlanarLayout::TYPE_YUV;
-            layout->numPlanes = 3;
-            layout->rootPlanes = 3;
-            layout->planes[C2PlanarLayout::PLANE_Y] = {
-                C2PlaneInfo::CHANNEL_Y,         // channel
-                1,                              // colInc
-                (int32_t)ycbcrLayout.ystride,   // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_U] = {
-                C2PlaneInfo::CHANNEL_CB,          // channel
-                (int32_t)ycbcrLayout.chroma_step, // colInc
-                (int32_t)ycbcrLayout.cstride,     // rowInc
-                2,                                // mColSampling
-                2,                                // mRowSampling
-                8,                                // allocatedDepth
-                8,                                // bitDepth
-                0,                                // rightShift
-                C2PlaneInfo::NATIVE,              // endianness
-                C2PlanarLayout::PLANE_U,          // rootIx
-                0,                                // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_V] = {
-                C2PlaneInfo::CHANNEL_CR,          // channel
-                (int32_t)ycbcrLayout.chroma_step, // colInc
-                (int32_t)ycbcrLayout.cstride,     // rowInc
-                2,                                // mColSampling
-                2,                                // mRowSampling
-                8,                                // allocatedDepth
-                8,                                // bitDepth
-                0,                                // rightShift
-                C2PlaneInfo::NATIVE,              // endianness
-                C2PlanarLayout::PLANE_V,          // rootIx
-                0,                                // offset
-            };
-            break;
-        }
-
-        case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
-            // In Android T, P010 is relaxed to allow arbitrary stride for the Y and UV planes,
-            // try locking with the gralloc4 mapper first.
-            c2_status_t status = Gralloc4Mapper_lock(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
-            if (status == C2_OK) {
-                break;
-            }
-
-            void *pointer = nullptr;
-            status_t err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(YCBCR_P010)");
-                return C2_CORRUPTED;
-            }
-            addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
-            addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + mStride * 2 * rect.height();
-            addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2;
-            layout->type = C2PlanarLayout::TYPE_YUV;
-            layout->numPlanes = 3;
-            layout->rootPlanes = 2;
-            layout->planes[C2PlanarLayout::PLANE_Y] = {
-                C2PlaneInfo::CHANNEL_Y,         // channel
-                2,                              // colInc
-                static_cast<int32_t>(2 * mStride), // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                16,                             // allocatedDepth
-                10,                             // bitDepth
-                6,                              // rightShift
-                kEndianness,                    // endianness
-                C2PlanarLayout::PLANE_Y,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_U] = {
-                C2PlaneInfo::CHANNEL_CB,        // channel
-                4,                              // colInc
-                static_cast<int32_t>(2 * mStride), // rowInc
-                2,                              // mColSampling
-                2,                              // mRowSampling
-                16,                             // allocatedDepth
-                10,                             // bitDepth
-                6,                              // rightShift
-                kEndianness,                    // endianness
-                C2PlanarLayout::PLANE_U,        // rootIx
-                0,                              // offset
-            };
-            layout->planes[C2PlanarLayout::PLANE_V] = {
-                C2PlaneInfo::CHANNEL_CR,        // channel
-                4,                              // colInc
-                static_cast<int32_t>(2 * mStride), // rowInc
-                2,                              // mColSampling
-                2,                              // mRowSampling
-                16,                             // allocatedDepth
-                10,                             // bitDepth
-                6,                              // rightShift
-                kEndianness,                    // endianness
-                C2PlanarLayout::PLANE_U,        // rootIx
-                2,                              // offset
-            };
-            break;
-        }
-
-        default: {
-            // We don't know what it is, let's try to lock it with gralloc4
-            android_ycbcr ycbcrLayout;
-            if (isAtLeastT()) {
-                c2_status_t status = Gralloc4Mapper_lock(
-                        const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
-                if (status == C2_OK) {
-                    break;
-                }
-            }
-
-            // fallback to lockYCbCr
-            status_t err = GraphicBufferMapper::get().lockYCbCr(
-                    const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
-            if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
-                    && ycbcrLayout.ystride > 0
-                    && ycbcrLayout.cstride > 0
-                    && ycbcrLayout.chroma_step > 0) {
-                addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
-                addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
-                addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
-                layout->type = C2PlanarLayout::TYPE_YUV;
-                layout->numPlanes = 3;
-                layout->rootPlanes = 3;
-                layout->planes[C2PlanarLayout::PLANE_Y] = {
-                    C2PlaneInfo::CHANNEL_Y,         // channel
-                    1,                              // colInc
-                    (int32_t)ycbcrLayout.ystride,   // rowInc
-                    1,                              // mColSampling
-                    1,                              // mRowSampling
-                    8,                              // allocatedDepth
-                    8,                              // bitDepth
-                    0,                              // rightShift
-                    C2PlaneInfo::NATIVE,            // endianness
-                    C2PlanarLayout::PLANE_Y,        // rootIx
-                    0,                              // offset
-                };
-                layout->planes[C2PlanarLayout::PLANE_U] = {
-                    C2PlaneInfo::CHANNEL_CB,          // channel
-                    (int32_t)ycbcrLayout.chroma_step, // colInc
-                    (int32_t)ycbcrLayout.cstride,     // rowInc
-                    2,                                // mColSampling
-                    2,                                // mRowSampling
-                    8,                                // allocatedDepth
-                    8,                                // bitDepth
-                    0,                                // rightShift
-                    C2PlaneInfo::NATIVE,              // endianness
-                    C2PlanarLayout::PLANE_U,          // rootIx
-                    0,                                // offset
-                };
-                layout->planes[C2PlanarLayout::PLANE_V] = {
-                    C2PlaneInfo::CHANNEL_CR,          // channel
-                    (int32_t)ycbcrLayout.chroma_step, // colInc
-                    (int32_t)ycbcrLayout.cstride,     // rowInc
-                    2,                                // mColSampling
-                    2,                                // mRowSampling
-                    8,                                // allocatedDepth
-                    8,                                // bitDepth
-                    0,                                // rightShift
-                    C2PlaneInfo::NATIVE,              // endianness
-                    C2PlanarLayout::PLANE_V,          // rootIx
-                    0,                                // offset
-                };
-                break;
-            }
-
-            // We really don't know what this is; lock the buffer and pass it through ---
-            // the client may know how to interpret it.
-
-            // unlock previous allocation if it was successful
-            if (err == OK) {
-                err = GraphicBufferMapper::get().unlock(mBuffer);
-                if (err) {
-                    ALOGE("failed transaction: unlock");
-                    return C2_CORRUPTED;
-                }
-            }
-
-            void *pointer = nullptr;
-            err = GraphicBufferMapper::get().lock(
-                    const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
-            if (err) {
-                ALOGE("failed transaction: lock(??? %x)", mFormat);
-                return C2_CORRUPTED;
-            }
-            addr[0] = (uint8_t *)pointer;
-            layout->type = C2PlanarLayout::TYPE_UNKNOWN;
-            layout->numPlanes = 1;
-            layout->rootPlanes = 1;
-            layout->planes[0] = {
-                // TODO: CHANNEL_UNKNOWN?
-                C2PlaneInfo::channel_t(0xFF),   // channel
-                1,                              // colInc
-                int32_t(mStride),               // rowInc
-                1,                              // mColSampling
-                1,                              // mRowSampling
-                8,                              // allocatedDepth
-                8,                              // bitDepth
-                0,                              // rightShift
-                C2PlaneInfo::NATIVE,            // endianness
-                0,                              // rootIx
-                0,                              // offset
-            };
-            break;
-        }
+    c2_status_t ret = PopulatePlaneLayout(
+            mBuffer, rect, mFormat, grallocUsage, mStride, layout, addr);
+    if (ret != C2_OK) {
+        return ret;
     }
     mLocked = true;
 
-    // handle interleaved formats
-    if (layout->type == C2PlanarLayout::TYPE_YUV && layout->rootPlanes == 3) {
-        intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
-        intptr_t uvColInc = layout->planes[C2PlanarLayout::PLANE_U].colInc;
-        if (uvOffset > 0 && uvOffset < uvColInc) {
-            layout->rootPlanes = 2;
-            layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
-            layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
-        } else if (uvOffset < 0 && uvOffset > -uvColInc) {
-            layout->rootPlanes = 2;
-            layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
-            layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
-        }
-    }
+    HandleInterleavedPlanes(layout, addr);
 
     ALOGV("C2AllocationGralloc::map: layout: type=%d numPlanes=%d rootPlanes=%d",
           layout->type, layout->numPlanes, layout->rootPlanes);
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 0344fd3..b91ac6d 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -16,6 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "C2FenceFactory"
+#include <poll.h>
+
+#include <android-base/unique_fd.h>
 #include <cutils/native_handle.h>
 #include <utils/Log.h>
 #include <ui/Fence.h>
@@ -32,6 +35,7 @@
         NULL_FENCE,
         SURFACE_FENCE,
         SYNC_FENCE,
+        PIPE_FENCE,
     };
 
     virtual c2_status_t wait(c2_nsecs_t timeoutNs) = 0;
@@ -353,6 +357,154 @@
     return C2Fence(p);
 }
 
+/**
+ * Fence implementation for notifying # of events available based on
+ * file descriptors created by pipe()/pipe2(). The writing end of the
+ * file descriptors is used to create the implementation.
+ * The implementation supports all C2Fence interface.
+ */
+class _C2FenceFactory::PipeFenceImpl: public C2Fence::Impl {
+private:
+    bool waitEvent(c2_nsecs_t timeoutNs, bool *hangUp, bool *event) const {
+        if (!mValid) {
+            *hangUp = true;
+            return true;
+        }
+
+        struct pollfd pfd;
+        pfd.fd = mPipeFd.get();
+        pfd.events = POLLIN;
+        pfd.revents = 0;
+        struct timespec ts;
+        if (timeoutNs >= 0) {
+            ts.tv_sec = int(timeoutNs / 1000000000);
+            ts.tv_nsec = timeoutNs;
+        } else {
+            ALOGD("polling for indefinite duration requested, but changed to wait for %d sec",
+                  kPipeFenceWaitLimitSecs);
+            ts.tv_sec = kPipeFenceWaitLimitSecs;
+            ts.tv_nsec = 0;
+        }
+        int ret = ::ppoll(&pfd, 1, &ts, nullptr);
+        if (ret >= 0) {
+            if (pfd.revents) {
+                if (pfd.revents & ~POLLIN) {
+                    // Mostly this means the writing end fd was closed.
+                    *hangUp = true;
+                    mValid = false;
+                    ALOGD("PipeFenceImpl: pipe fd hangup or err event returned");
+                }
+                *event = true;
+                return true;
+            }
+            // event not ready yet.
+            return true;
+        }
+        if (errno == EINTR) {
+            // poll() was cancelled by signal or inner kernel status.
+            return false;
+        }
+        // Since poll error happened here, treat the error is irrecoverable.
+        ALOGE("PipeFenceImpl: poll() error %d", errno);
+        *hangUp = true;
+        mValid = false;
+        return true;
+    }
+
+public:
+    virtual c2_status_t wait(c2_nsecs_t timeoutNs) {
+        if (!mValid) {
+            return C2_BAD_STATE;
+        }
+        bool hangUp = false;
+        bool event = false;
+        if (waitEvent(timeoutNs, &hangUp, &event)) {
+            if (hangUp) {
+                return C2_BAD_STATE;
+            }
+            if (event) {
+                return C2_OK;
+            }
+            return C2_TIMED_OUT;
+        } else {
+            return C2_CANCELED;
+        }
+    }
+
+    virtual bool valid() const {
+        if (!mValid) {
+            return false;
+        }
+        bool hangUp = false;
+        bool event = false;
+        if (waitEvent(0, &hangUp, &event)) {
+            if (hangUp) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    virtual bool ready() const {
+        if (!mValid) {
+            return false;
+        }
+        bool hangUp = false;
+        bool event = false;
+        if (waitEvent(0, &hangUp, &event)) {
+            if (event) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    virtual int fd() const {
+        if (!mValid) {
+            return -1;
+        }
+        return ::dup(mPipeFd.get());
+    }
+
+    virtual bool isHW() const {
+        return false;
+    }
+
+    virtual type_t type() const {
+        return PIPE_FENCE;
+    }
+
+    virtual native_handle_t *createNativeHandle() const {
+        // This is not supported.
+        return nullptr;
+    }
+
+    virtual ~PipeFenceImpl() = default;
+
+    PipeFenceImpl(int fd) : mPipeFd(fd) {
+        mValid = (mPipeFd.get() >= 0);
+    }
+
+private:
+    friend struct _C2FenceFactory;
+    static constexpr int kPipeFenceWaitLimitSecs = 5;
+
+    mutable std::atomic<bool> mValid;
+    ::android::base::unique_fd mPipeFd;
+};
+
+C2Fence _C2FenceFactory::CreatePipeFence(int fd) {
+    std::shared_ptr<_C2FenceFactory::PipeFenceImpl> impl =
+        std::make_shared<_C2FenceFactory::PipeFenceImpl>(fd);
+    std::shared_ptr<C2Fence::Impl> p = std::static_pointer_cast<C2Fence::Impl>(impl);
+    if (!p) {
+        ALOGE("PipeFence creation failure");
+    } else if (!impl->mValid) {
+        p.reset();
+    }
+    return C2Fence(p);
+}
+
 native_handle_t* _C2FenceFactory::CreateNativeHandle(const C2Fence& fence) {
     return fence.mImpl? fence.mImpl->createNativeHandle() : nullptr;
 }
diff --git a/media/codec2/vndk/include/C2FenceFactory.h b/media/codec2/vndk/include/C2FenceFactory.h
index ef25c47..9b09980 100644
--- a/media/codec2/vndk/include/C2FenceFactory.h
+++ b/media/codec2/vndk/include/C2FenceFactory.h
@@ -39,6 +39,7 @@
 
     class SurfaceFenceImpl;
     class SyncFenceImpl;
+    class PipeFenceImpl;
 
     /*
      * Create C2Fence for BufferQueueBased blockpool.
@@ -66,6 +67,15 @@
      */
     static C2Fence CreateMultipleFdSyncFence(const std::vector<int>& fenceFds);
 
+    /*
+     * Create C2Fence from an fd created by pipe()/pipe2() syscall.
+     *
+     * \param fd                An fd representing the write end from a pair of
+     *                          file descriptors which are created by
+     *                          pipe()/pipe2() syscall.
+     */
+    static C2Fence CreatePipeFence(int fd);
+
     /**
      * Create a native handle from fence for marshalling
      *
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index c058386..e74fc16 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -193,7 +193,7 @@
     StreamDescriptor::Reply reply;
     switch (state) {
         case StreamDescriptor::State::ACTIVE:
-            if (status_t status = pause(&reply); status != OK) return status;
+            RETURN_STATUS_IF_ERROR(pause(&reply));
             if (reply.state != StreamDescriptor::State::PAUSED) {
                 ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
                         __func__, toString(reply.state).c_str());
@@ -203,7 +203,7 @@
         case StreamDescriptor::State::PAUSED:
         case StreamDescriptor::State::DRAIN_PAUSED:
             if (mIsInput) return flush();
-            if (status_t status = flush(&reply); status != OK) return status;
+            RETURN_STATUS_IF_ERROR(flush(&reply));
             if (reply.state != StreamDescriptor::State::IDLE) {
                 ALOGE("%s: unexpected stream state: %s (expected IDLE)",
                         __func__, toString(reply.state).c_str());
@@ -211,10 +211,8 @@
             }
             FALLTHROUGH_INTENDED;
         case StreamDescriptor::State::IDLE:
-            if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
-                            &reply, true /*safeFromNonWorkerThread*/); status != OK) {
-                return status;
-            }
+            RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
+                            &reply, true /*safeFromNonWorkerThread*/));
             if (reply.state != StreamDescriptor::State::STANDBY) {
                 ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
                         __func__, toString(reply.state).c_str());
@@ -244,10 +242,7 @@
     const auto state = getState();
     StreamDescriptor::Reply reply;
     if (state == StreamDescriptor::State::STANDBY) {
-        if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true);
-                status != OK) {
-            return status;
-        }
+        RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
         return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true);
     }
 
@@ -264,10 +259,7 @@
     ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
     if (!mStream) return NO_INIT;
     StreamDescriptor::Reply reply;
-    if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
-        return status;
-    }
-
+    RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
     *latency = std::clamp(std::max<int32_t>(0, reply.latencyMs), 1, 3000);
     ALOGW_IF(reply.latencyMs != static_cast<int32_t>(*latency),
              "Suspicious latency value reported by HAL: %d, clamped to %u", reply.latencyMs,
@@ -279,11 +271,9 @@
     ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
     if (!mStream) return NO_INIT;
     StreamDescriptor::Reply reply;
-    if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
-        return status;
-    }
-    *frames = reply.observable.frames;
-    *timestamp = reply.observable.timeNs;
+    RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+    *frames = std::max<int64_t>(0, reply.observable.frames);
+    *timestamp = std::max<int64_t>(0, reply.observable.timeNs);
     return OK;
 }
 
@@ -292,12 +282,9 @@
     if (!mStream) return NO_INIT;
     StreamDescriptor::Reply reply;
     // TODO: switch to updateCountersIfNeeded once we sort out mWorkerTid initialization
-    if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true);
-            status != OK) {
-        return status;
-    }
-    *frames = reply.hardware.frames;
-    *timestamp = reply.hardware.timeNs;
+    RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true));
+    *frames = std::max<int64_t>(0, reply.hardware.frames);
+    *timestamp = std::max<int64_t>(0, reply.hardware.timeNs);
     return OK;
 }
 
@@ -305,10 +292,8 @@
     ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
     if (!mStream) return NO_INIT;
     StreamDescriptor::Reply reply;
-    if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
-        return status;
-    }
-    *frames = reply.xrunFrames;
+    RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+    *frames = std::max<int32_t>(0, reply.xrunFrames);
     return OK;
 }
 
@@ -323,10 +308,7 @@
     // stream state), however this scenario wasn't supported by the HIDL HAL.
     if (getState() == StreamDescriptor::State::STANDBY) {
         StreamDescriptor::Reply reply;
-        if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
-                status != OK) {
-            return status;
-        }
+        RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply));
         if (reply.state != StreamDescriptor::State::IDLE) {
             ALOGE("%s: failed to get the stream out of standby, actual state: %s",
                     __func__, toString(reply.state).c_str());
@@ -345,9 +327,7 @@
         }
     }
     StreamDescriptor::Reply reply;
-    if (status_t status = sendCommand(burst, &reply); status != OK) {
-        return status;
-    }
+    RETURN_STATUS_IF_ERROR(sendCommand(burst, &reply));
     *transferred = reply.fmqByteCount;
     if (mIsInput) {
         LOG_ALWAYS_FATAL_IF(*transferred > bytes,
@@ -385,11 +365,8 @@
             if (state == StreamDescriptor::State::IDLE) {
                 StreamDescriptor::Reply localReply{};
                 StreamDescriptor::Reply* innerReply = reply ?: &localReply;
-                if (status_t status =
-                        sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply);
-                        status != OK) {
-                    return status;
-                }
+                RETURN_STATUS_IF_ERROR(
+                        sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
                 if (innerReply->state != StreamDescriptor::State::ACTIVE) {
                     ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
                             __func__, toString(innerReply->state).c_str());
@@ -452,10 +429,7 @@
         return BAD_VALUE;
     }
     int64_t aidlPosition = 0, aidlTimestamp = 0;
-    if (status_t status = getHardwarePosition(&aidlPosition, &aidlTimestamp); status != OK) {
-        return status;
-    }
-
+    RETURN_STATUS_IF_ERROR(getHardwarePosition(&aidlPosition, &aidlTimestamp));
     position->time_nanoseconds = aidlTimestamp;
     position->position_frames = static_cast<int32_t>(aidlPosition);
     return OK;
@@ -503,6 +477,11 @@
     }
     {
         std::lock_guard l(mLock);
+        // Not every command replies with 'latencyMs' field filled out, substitute the last
+        // returned value in that case.
+        if (reply->latencyMs <= 0) {
+            reply->latencyMs = mLastReply.latencyMs;
+        }
         mLastReply = *reply;
     }
     switch (reply->status) {
@@ -608,10 +587,8 @@
         return BAD_VALUE;
     }
     int64_t aidlFrames = 0, aidlTimestamp = 0;
-    if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
-        return OK;
-    }
-    *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
+    RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
+    *dspFrames = static_cast<uint32_t>(aidlFrames);
     return OK;
 }
 
@@ -680,10 +657,8 @@
         return BAD_VALUE;
     }
     int64_t aidlFrames = 0, aidlTimestamp = 0;
-    if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
-        return status;
-    }
-    *frames = std::max<int64_t>(0, aidlFrames);
+    RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
+    *frames = aidlFrames;
     timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
     timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
     return OK;
@@ -901,9 +876,7 @@
         return BAD_VALUE;
     }
     int32_t aidlXruns = 0;
-    if (status_t status = getXruns(&aidlXruns); status != OK) {
-        return status;
-    }
+    RETURN_STATUS_IF_ERROR(getXruns(&aidlXruns));
     *framesLost = std::max<int32_t>(0, aidlXruns);
     return OK;
 }
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 3b369bd..4acc6ac 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -207,10 +207,13 @@
 
     status_t getLatency(uint32_t *latency);
 
+    // Always returns non-negative values.
     status_t getObservablePosition(int64_t *frames, int64_t *timestamp);
 
+    // Always returns non-negative values.
     status_t getHardwarePosition(int64_t *frames, int64_t *timestamp);
 
+    // Always returns non-negative values.
     status_t getXruns(int32_t *frames);
 
     status_t transfer(void *buffer, size_t bytes, size_t *transferred);
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index b230df5..2fb5728 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -672,7 +672,7 @@
         if (out_size != NULL) {
             *out_size = abuf->capacity();
         }
-        return abuf->data();
+        return abuf->base();
     }
 
     android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
@@ -689,7 +689,7 @@
         if (out_size != NULL) {
             *out_size = abufs[idx]->capacity();
         }
-        return abufs[idx]->data();
+        return abufs[idx]->base();
     }
     ALOGE("couldn't get input buffers");
     return NULL;
@@ -707,7 +707,7 @@
         if (out_size != NULL) {
             *out_size = abuf->capacity();
         }
-        return abuf->data();
+        return abuf->base();
     }
 
     android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
@@ -720,7 +720,7 @@
         if (out_size != NULL) {
             *out_size = abufs[idx]->capacity();
         }
-        return abufs[idx]->data();
+        return abufs[idx]->base();
     }
     ALOGE("couldn't get output buffers");
     return NULL;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 61b667b..8add05e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -47,6 +47,7 @@
 #include <binder/PermissionController.h>
 #include <binder/IResultReceiver.h>
 #include <binderthreadstate/CallerUtils.h>
+#include <com_android_internal_camera_flags.h>
 #include <cutils/atomic.h>
 #include <cutils/properties.h>
 #include <cutils/misc.h>
@@ -105,6 +106,7 @@
 using hardware::camera2::ICameraInjectionSession;
 using hardware::camera2::utils::CameraIdAndSessionConfiguration;
 using hardware::camera2::utils::ConcurrentCameraIdCombination;
+namespace flags = com::android::internal::camera::flags;
 
 // ----------------------------------------------------------------------------
 // Logging support -- this is for debugging only
@@ -1648,7 +1650,6 @@
                 callingUid, procState);
     }
 
-
     // Automotive privileged client AID_AUTOMOTIVE_EVS using exterior system camera for use cases
     // such as rear view and surround view cannot be disabled and are exempt from sensor privacy
     // policy. In all other cases,if sensor privacy is enabled then prevent access to the camera.
@@ -1680,16 +1681,18 @@
                 clientUserId, cameraId.c_str());
     }
 
-    // If the System User tries to access the camera when the device is running in
-    // headless system user mode, ensure that client has the required permission
-    // CAMERA_HEADLESS_SYSTEM_USER.
-    if (isHeadlessSystemUserMode() && (clientUserId == USER_SYSTEM) &&
-            !hasPermissionsForCameraHeadlessSystemUser(cameraId, callingPid, callingUid)) {
-        ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
-        return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
-                "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" as Headless System User\
-                without camera headless system user permission",
-                clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+    if (flags::camera_hsum_permission()) {
+        // If the System User tries to access the camera when the device is running in
+        // headless system user mode, ensure that client has the required permission
+        // CAMERA_HEADLESS_SYSTEM_USER.
+        if (isHeadlessSystemUserMode() && (clientUserId == USER_SYSTEM) &&
+                !hasPermissionsForCameraHeadlessSystemUser(cameraId, callingPid, callingUid)) {
+            ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
+            return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+                    "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" as Headless System \
+                    User without camera headless system user permission",
+                    clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+        }
     }
 
     return Status::ok();
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 23051ef..6ce4d3a 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1487,6 +1487,56 @@
     return res;
 }
 
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupManualFlashStrengthControlTags() {
+    status_t res = OK;
+    auto& c = mCameraCharacteristics;
+    auto flashSingleStrengthMaxLevelEntry = c.find(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL);
+    if (flashSingleStrengthMaxLevelEntry.count == 0) {
+        int32_t flashSingleStrengthMaxLevel = 1;
+        res = c.update(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
+                &flashSingleStrengthMaxLevel, 1);
+        if (res != OK) {
+            ALOGE("%s: Failed to update ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL: %s (%d)",
+                    __FUNCTION__,strerror(-res), res);
+            return res;
+        }
+    }
+    auto flashSingleStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL);
+    if (flashSingleStrengthDefaultLevelEntry.count == 0) {
+        int32_t flashSingleStrengthDefaultLevel = 1;
+        res = c.update(ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
+                &flashSingleStrengthDefaultLevel, 1);
+        if (res != OK) {
+            ALOGE("%s: Failed to update ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL: %s (%d)",
+                    __FUNCTION__,strerror(-res), res);
+            return res;
+        }
+    }
+    auto flashTorchStrengthMaxLevelEntry = c.find(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL);
+    if (flashTorchStrengthMaxLevelEntry.count == 0) {
+        int32_t flashTorchStrengthMaxLevel = 1;
+        res = c.update(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
+                &flashTorchStrengthMaxLevel, 1);
+        if (res != OK) {
+            ALOGE("%s: Failed to update ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL: %s (%d)",
+                    __FUNCTION__,strerror(-res), res);
+            return res;
+        }
+    }
+    auto flashTorchStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL);
+    if (flashTorchStrengthDefaultLevelEntry.count == 0) {
+        int32_t flashTorchStrengthDefaultLevel = 1;
+        res = c.update(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
+                &flashTorchStrengthDefaultLevel, 1);
+        if (res != OK) {
+            ALOGE("%s: Failed to update ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL: %s (%d)",
+                    __FUNCTION__,strerror(-res), res);
+            return res;
+        }
+    }
+    return res;
+}
+
 status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags() {
     status_t res = OK;
     auto& c = mCameraCharacteristics;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 28be652..48c1134 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -683,6 +683,7 @@
             SystemCameraKind getSystemCameraKind();
             status_t fixupMonochromeTags();
             status_t fixupTorchStrengthTags();
+            status_t fixupManualFlashStrengthControlTags();
             status_t addDynamicDepthTags(bool maxResolution = false);
             status_t deriveHeicTags(bool maxResolution = false);
             status_t deriveJpegRTags(bool maxResolution = false);
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index 9659db8..085b012 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -494,6 +494,12 @@
                 __FUNCTION__, strerror(-res), res);
         return;
     }
+    res = fixupManualFlashStrengthControlTags();
+    if (OK != res) {
+        ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return;
+    }
     auto stat = addDynamicDepthTags();
     if (OK != stat) {
         ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index aeb0abc..56c0c90 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -613,6 +613,14 @@
                 __FUNCTION__, strerror(-res), res);
         return;
     }
+
+    res = fixupManualFlashStrengthControlTags();
+    if (OK != res) {
+        ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return;
+    }
+
     auto stat = addDynamicDepthTags();
     if (OK != stat) {
         ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),