Merge "C2BqPool: Handle generation # retrieval failure" into qt-dev
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 7cd832a..8dd6e00 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -7689,14 +7689,14 @@
      * case, when the application configures a RAW stream, the camera device will make sure
      * the active physical camera will remain active to ensure consistent RAW output
      * behavior, and not switch to other physical cameras.</p>
-     * <p>To maintain backward compatibility, the capture request and result metadata tags
-     * required for basic camera functionalities will be solely based on the
-     * logical camera capabiltity. Other request and result metadata tags, on the other
-     * hand, will be based on current active physical camera. For example, the physical
-     * cameras' sensor sensitivity and lens capability could be different from each other.
-     * So when the application manually controls sensor exposure time/gain, or does manual
-     * focus control, it must checks the current active physical camera's exposure, gain,
-     * and focus distance range.</p>
+     * <p>The capture request and result metadata tags required for backward compatible camera
+     * functionalities will be solely based on the logical camera capabiltity. On the other
+     * hand, the use of manual capture controls (sensor or post-processing) with a
+     * logical camera may result in unexpected behavior when the HAL decides to switch
+     * between physical cameras with different characteristics under the hood. For example,
+     * when the application manually sets exposure time and sensitivity while zooming in,
+     * the brightness of the camera images may suddenly change because HAL switches from one
+     * physical camera to the other.</p>
      *
      * @see ACAMERA_LENS_DISTORTION
      * @see ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION
@@ -8330,7 +8330,7 @@
      * fire the flash for flash power metering during precapture, and then fire the flash
      * for the final capture, if a flash is available on the device and the AE mode is set to
      * enable the flash.</p>
-     * <p>Devices that initially shipped with Android version <a href="https://developer.android.com/reference/android/os/Build.VERSION_CODES.html#Q">Q</a> or newer will not include any LEGACY-level devices.</p>
+     * <p>Devices that initially shipped with Android version <a href="https://developer.android.com/reference/android/os/Build/VERSION_CODES.html#Q">Q</a> or newer will not include any LEGACY-level devices.</p>
      *
      * @see ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
      * @see ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index d27fe32..78d221e 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -76,10 +76,11 @@
             Mutexed<Jobs>::Locked jobs(mJobs);
             nsecs_t nowNs = systemTime();
             bool queued = false;
-            for (auto it = jobs->queues.begin(); it != jobs->queues.end(); ++it) {
+            for (auto it = jobs->queues.begin(); it != jobs->queues.end(); ) {
                 Queue &queue = it->second;
                 if (queue.workList.empty()
                         || nowNs - queue.lastQueuedTimestampNs < kIntervalNs) {
+                    ++it;
                     continue;
                 }
                 std::shared_ptr<Codec2Client::Component> comp = queue.component.lock();
@@ -109,6 +110,7 @@
                 }
                 jobs.lock();
 
+                it = jobs->queues.upper_bound(comp);
                 queued = true;
             }
             if (queued) {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 8be9a1d..9778498 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -220,7 +220,6 @@
         const std::shared_ptr<CCodecCallback> &callback)
     : mHeapSeqNum(-1),
       mCCodecCallback(callback),
-      mDelay(0),
       mFrameIndex(0u),
       mFirstValidFrameIndex(0u),
       mMetaMode(MODE_NONE),
@@ -814,7 +813,6 @@
 
     size_t numInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
     size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
-    mDelay = inputDelayValue + pipelineDelayValue + outputDelayValue;
 
     // TODO: get this from input format
     bool secure = mComponent->getName().find(".secure") != std::string::npos;
@@ -1377,25 +1375,35 @@
                         (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
 
                         bool outputBuffersChanged = false;
-                        Mutexed<Output>::Locked output(mOutput);
-                        output->outputDelay = outputDelay.value;
-                        size_t numOutputSlots = outputDelay.value + kSmoothnessFactor;
-                        if (output->numSlots < numOutputSlots) {
-                            output->numSlots = numOutputSlots;
-                            if (output->buffers->isArrayMode()) {
-                                OutputBuffersArray *array =
-                                    (OutputBuffersArray *)output->buffers.get();
-                                ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
-                                      mName, numOutputSlots);
-                                array->grow(numOutputSlots);
-                                outputBuffersChanged = true;
+                        size_t numOutputSlots = 0;
+                        {
+                            Mutexed<Output>::Locked output(mOutput);
+                            output->outputDelay = outputDelay.value;
+                            numOutputSlots = outputDelay.value + kSmoothnessFactor;
+                            if (output->numSlots < numOutputSlots) {
+                                output->numSlots = numOutputSlots;
+                                if (output->buffers->isArrayMode()) {
+                                    OutputBuffersArray *array =
+                                        (OutputBuffersArray *)output->buffers.get();
+                                    ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
+                                          mName, numOutputSlots);
+                                    array->grow(numOutputSlots);
+                                    outputBuffersChanged = true;
+                                }
                             }
+                            numOutputSlots = output->numSlots;
                         }
-                        output.unlock();
 
                         if (outputBuffersChanged) {
                             mCCodecCallback->onOutputBuffersChanged();
                         }
+
+                        uint32_t depth = mReorderStash.lock()->depth();
+                        Mutexed<OutputSurface>::Locked output(mOutputSurface);
+                        output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
+                        if (output->surface) {
+                            output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
+                        }
                     }
                 }
                 break;
@@ -1620,7 +1628,12 @@
     // When client pushed EOS, we want all the work to be done quickly.
     // Otherwise, component may have stalled work due to input starvation up to
     // the sum of the delay in the pipeline.
-    size_t n = mInputMetEos ? 0 : mDelay;
+    size_t n = 0;
+    if (!mInputMetEos) {
+        size_t outputDelay = mOutput.lock()->outputDelay;
+        Mutexed<Input>::Locked input(mInput);
+        n = input->inputDelay + input->pipelineDelay + outputDelay;
+    }
     return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
 }
 
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index ae57678..ee3455d 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -228,8 +228,6 @@
     QueueSync mQueueSync;
     std::vector<std::unique_ptr<C2Param>> mParamsToBeSet;
 
-    size_t mDelay;
-
     struct Input {
         Input();
 
@@ -306,6 +304,7 @@
                 const C2WorkOrdinalStruct &ordinal);
         void defer(const Entry &entry);
         bool hasPending() const;
+        uint32_t depth() const { return mDepth; }
 
     private:
         std::list<Entry> mPending;
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index ca69810..b6ddfab 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -50,8 +50,10 @@
 
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.media.bufferpool@2.0",
         "libbase",
         "libbinder",
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 286c48a..af97e61 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -20,6 +20,8 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
 #include <cutils/native_handle.h>
 #include <hardware/gralloc.h>
 
@@ -29,7 +31,7 @@
 
 namespace android {
 
-namespace {
+namespace /* unnamed */ {
     enum : uint64_t {
         /**
          * Usage mask that is passed through from gralloc to Codec 2.0 usage.
@@ -40,7 +42,7 @@
 
     // verify that passthrough mask is within the platform mask
     static_assert((~C2MemoryUsage::PLATFORM_MASK & PASSTHROUGH_USAGE_MASK) == 0, "");
-}
+} // unnamed
 
 C2MemoryUsage C2AndroidMemoryUsage::FromGrallocUsage(uint64_t usage) {
     // gralloc does not support WRITE_PROTECTED
@@ -59,39 +61,59 @@
             (expected & PASSTHROUGH_USAGE_MASK));
 }
 
-using ::android::hardware::graphics::allocator::V2_0::IAllocator;
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using ::android::hardware::graphics::mapper::V2_0::Error;
-using ::android::hardware::graphics::mapper::V2_0::IMapper;
-using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using PixelFormat2 = ::android::hardware::graphics::common::V1_0::PixelFormat;
+using PixelFormat3 = ::android::hardware::graphics::common::V1_2::PixelFormat;
 
-namespace {
+using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using BufferDescriptor2 = ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
+using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
 
-struct BufferDescriptorInfo {
-    IMapper::BufferDescriptorInfo mapperInfo;
+using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
+using BufferDescriptor3 = ::android::hardware::graphics::mapper::V3_0::BufferDescriptor;
+using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
+using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
+
+namespace /* unnamed */ {
+
+struct BufferDescriptorInfo2 {
+    IMapper2::BufferDescriptorInfo mapperInfo;
     uint32_t stride;
 };
 
-}
+struct BufferDescriptorInfo3 {
+    IMapper3::BufferDescriptorInfo mapperInfo;
+    uint32_t stride;
+};
 
 /* ===================================== GRALLOC ALLOCATION ==================================== */
-static c2_status_t maperr2error(Error maperr) {
+c2_status_t maperr2error(Error2 maperr) {
     switch (maperr) {
-        case Error::NONE:           return C2_OK;
-        case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
-        case Error::BAD_BUFFER:     return C2_BAD_VALUE;
-        case Error::BAD_VALUE:      return C2_BAD_VALUE;
-        case Error::NO_RESOURCES:   return C2_NO_MEMORY;
-        case Error::UNSUPPORTED:    return C2_CANNOT_DO;
+        case Error2::NONE:           return C2_OK;
+        case Error2::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+        case Error2::BAD_BUFFER:     return C2_BAD_VALUE;
+        case Error2::BAD_VALUE:      return C2_BAD_VALUE;
+        case Error2::NO_RESOURCES:   return C2_NO_MEMORY;
+        case Error2::UNSUPPORTED:    return C2_CANNOT_DO;
     }
     return C2_CORRUPTED;
 }
 
-static
+c2_status_t maperr2error(Error3 maperr) {
+    switch (maperr) {
+        case Error3::NONE:           return C2_OK;
+        case Error3::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+        case Error3::BAD_BUFFER:     return C2_BAD_VALUE;
+        case Error3::BAD_VALUE:      return C2_BAD_VALUE;
+        case Error3::NO_RESOURCES:   return C2_NO_MEMORY;
+        case Error3::UNSUPPORTED:    return C2_CANNOT_DO;
+    }
+    return C2_CORRUPTED;
+}
+
 bool native_handle_is_invalid(const native_handle_t *const handle) {
     // perform basic validation of a native handle
     if (handle == nullptr) {
@@ -230,23 +252,6 @@
         return res;
     }
 
-    static native_handle_t* UnwrapNativeHandle(
-            const C2Handle *const handle,
-            uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) {
-        const ExtraData *xd = getExtraData(handle);
-        if (xd == nullptr || xd->magic != MAGIC) {
-            return nullptr;
-        }
-        *generation = xd->generation;
-        *igbp_id = unsigned(xd->igbp_id_lo) | uint64_t(unsigned(xd->igbp_id_hi)) << 32;
-        *igbp_slot = xd->igbp_slot;
-        native_handle_t *res = native_handle_create(handle->numFds, handle->numInts - NUM_INTS);
-        if (res != nullptr) {
-            memcpy(&res->data, &handle->data, sizeof(int) * (res->numFds + res->numInts));
-        }
-        return res;
-    }
-
     static const C2HandleGralloc* Import(
             const C2Handle *const handle,
             uint32_t *width, uint32_t *height, uint32_t *format,
@@ -268,16 +273,12 @@
     }
 };
 
+} // unnamed namespace
+
 native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) {
     return C2HandleGralloc::UnwrapNativeHandle(handle);
 }
 
-native_handle_t *UnwrapNativeCodec2GrallocHandle(
-        const C2Handle *const handle,
-        uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) {
-    return C2HandleGralloc::UnwrapNativeHandle(handle, generation, igbp_id, igbp_slot);
-}
-
 C2Handle *WrapNativeCodec2GrallocHandle(
         const native_handle_t *const handle,
         uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
@@ -309,8 +310,14 @@
     // internal methods
     // |handle| will be moved.
     C2AllocationGralloc(
-              const BufferDescriptorInfo &info,
-              const sp<IMapper> &mapper,
+              const BufferDescriptorInfo2 &info,
+              const sp<IMapper2> &mapper,
+              hidl_handle &hidlHandle,
+              const C2HandleGralloc *const handle,
+              C2Allocator::id_t allocatorId);
+    C2AllocationGralloc(
+              const BufferDescriptorInfo3 &info,
+              const sp<IMapper3> &mapper,
               hidl_handle &hidlHandle,
               const C2HandleGralloc *const handle,
               C2Allocator::id_t allocatorId);
@@ -318,8 +325,10 @@
     c2_status_t status() const;
 
 private:
-    const BufferDescriptorInfo mInfo;
-    const sp<IMapper> mMapper;
+    const BufferDescriptorInfo2 mInfo2{};
+    const sp<IMapper2> mMapper2{nullptr};
+    const BufferDescriptorInfo3 mInfo3{};
+    const sp<IMapper3> mMapper3{nullptr};
     const hidl_handle mHidlHandle;
     const C2HandleGralloc *mHandle;
     buffer_handle_t mBuffer;
@@ -330,14 +339,31 @@
 };
 
 C2AllocationGralloc::C2AllocationGralloc(
-          const BufferDescriptorInfo &info,
-          const sp<IMapper> &mapper,
+          const BufferDescriptorInfo2 &info,
+          const sp<IMapper2> &mapper,
           hidl_handle &hidlHandle,
           const C2HandleGralloc *const handle,
           C2Allocator::id_t allocatorId)
     : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
-      mInfo(info),
-      mMapper(mapper),
+      mInfo2(info),
+      mMapper2(mapper),
+      mHidlHandle(std::move(hidlHandle)),
+      mHandle(handle),
+      mBuffer(nullptr),
+      mLockedHandle(nullptr),
+      mLocked(false),
+      mAllocatorId(allocatorId) {
+}
+
+C2AllocationGralloc::C2AllocationGralloc(
+          const BufferDescriptorInfo3 &info,
+          const sp<IMapper3> &mapper,
+          hidl_handle &hidlHandle,
+          const C2HandleGralloc *const handle,
+          C2Allocator::id_t allocatorId)
+    : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
+      mInfo3(info),
+      mMapper3(mapper),
       mHidlHandle(std::move(hidlHandle)),
       mHandle(handle),
       mBuffer(nullptr),
@@ -353,7 +379,17 @@
         unmap(addr, C2Rect(), nullptr);
     }
     if (mBuffer) {
-        mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
+        if (mMapper2) {
+            if (!mMapper2->freeBuffer(const_cast<native_handle_t *>(
+                    mBuffer)).isOk()) {
+                ALOGE("failed transaction: freeBuffer");
+            }
+        } else {
+            if (!mMapper3->freeBuffer(const_cast<native_handle_t *>(
+                    mBuffer)).isOk()) {
+                ALOGE("failed transaction: freeBuffer");
+            }
+        }
     }
     if (mHandle) {
         native_handle_delete(
@@ -388,13 +424,29 @@
 
     c2_status_t err = C2_OK;
     if (!mBuffer) {
-        mMapper->importBuffer(
-                mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
-                    err = maperr2error(maperr);
-                    if (err == C2_OK) {
-                        mBuffer = static_cast<buffer_handle_t>(buffer);
-                    }
-                });
+        if (mMapper2) {
+            if (!mMapper2->importBuffer(
+                    mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
+                        err = maperr2error(maperr);
+                        if (err == C2_OK) {
+                            mBuffer = static_cast<buffer_handle_t>(buffer);
+                        }
+                    }).isOk()) {
+                ALOGE("failed transaction: importBuffer");
+                return C2_CORRUPTED;
+            }
+        } else {
+            if (!mMapper3->importBuffer(
+                    mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
+                        err = maperr2error(maperr);
+                        if (err == C2_OK) {
+                            mBuffer = static_cast<buffer_handle_t>(buffer);
+                        }
+                    }).isOk()) {
+                ALOGE("failed transaction: importBuffer (@3.0)");
+                return C2_CORRUPTED;
+            }
+        }
         if (err != C2_OK) {
             ALOGD("importBuffer failed: %d", err);
             return err;
@@ -409,30 +461,66 @@
         if (mHandle) {
             mHandle->getIgbpData(&generation, &igbp_id, &igbp_slot);
         }
-        mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
-                mBuffer, mInfo.mapperInfo.width, mInfo.mapperInfo.height,
-                (uint32_t)mInfo.mapperInfo.format, mInfo.mapperInfo.usage, mInfo.stride,
-                generation, igbp_id, igbp_slot);
+        if (mMapper2) {
+            mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
+                    mBuffer, mInfo2.mapperInfo.width, mInfo2.mapperInfo.height,
+                    (uint32_t)mInfo2.mapperInfo.format, mInfo2.mapperInfo.usage,
+                    mInfo2.stride, generation, igbp_id, igbp_slot);
+        } else {
+            mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
+                    mBuffer, mInfo3.mapperInfo.width, mInfo3.mapperInfo.height,
+                    (uint32_t)mInfo3.mapperInfo.format, mInfo3.mapperInfo.usage,
+                    mInfo3.stride, generation, igbp_id, igbp_slot);
+        }
     }
 
-    switch (mInfo.mapperInfo.format) {
-        case PixelFormat::RGBA_1010102: {
+    PixelFormat3 format = mMapper2 ?
+            PixelFormat3(mInfo2.mapperInfo.format) :
+            PixelFormat3(mInfo3.mapperInfo.format);
+    switch (format) {
+        case PixelFormat3::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;
-            mMapper->lock(
-                    const_cast<native_handle_t *>(mBuffer),
-                    grallocUsage,
-                    { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
-                    // TODO: fence
-                    hidl_handle(),
-                    [&err, &pointer](const auto &maperr, const auto &mapPointer) {
-                        err = maperr2error(maperr);
-                        if (err == C2_OK) {
-                            pointer = mapPointer;
-                        }
-                    });
+            if (mMapper2) {
+                if (!mMapper2->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_1010102)");
+                    return C2_CORRUPTED;
+                }
+            } else {
+                if (!mMapper3->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer,
+                                         int32_t bytesPerPixel, int32_t bytesPerStride) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                            (void)bytesPerPixel;
+                            (void)bytesPerStride;
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_1010102) (@3.0)");
+                    return C2_CORRUPTED;
+                }
+            }
             if (err != C2_OK) {
                 ALOGD("lock failed: %d", err);
                 return err;
@@ -445,10 +533,13 @@
             layout->type = C2PlanarLayout::TYPE_YUVA;
             layout->numPlanes = 4;
             layout->rootPlanes = 1;
+            int32_t stride = mMapper2 ?
+                    int32_t(mInfo2.stride) :
+                    int32_t(mInfo3.stride);
             layout->planes[C2PlanarLayout::PLANE_Y] = {
                 C2PlaneInfo::CHANNEL_Y,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 32,                             // allocatedDepth
@@ -461,7 +552,7 @@
             layout->planes[C2PlanarLayout::PLANE_U] = {
                 C2PlaneInfo::CHANNEL_CB,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 32,                             // allocatedDepth
@@ -474,7 +565,7 @@
             layout->planes[C2PlanarLayout::PLANE_V] = {
                 C2PlaneInfo::CHANNEL_CR,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 32,                             // allocatedDepth
@@ -487,7 +578,7 @@
             layout->planes[C2PlanarLayout::PLANE_A] = {
                 C2PlaneInfo::CHANNEL_A,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 32,                             // allocatedDepth
@@ -500,23 +591,49 @@
             break;
         }
 
-        case PixelFormat::RGBA_8888:
+        case PixelFormat3::RGBA_8888:
             // TODO: alpha channel
             // fall-through
-        case PixelFormat::RGBX_8888: {
+        case PixelFormat3::RGBX_8888: {
             void *pointer = nullptr;
-            mMapper->lock(
-                    const_cast<native_handle_t *>(mBuffer),
-                    grallocUsage,
-                    { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
-                    // TODO: fence
-                    hidl_handle(),
-                    [&err, &pointer](const auto &maperr, const auto &mapPointer) {
-                        err = maperr2error(maperr);
-                        if (err == C2_OK) {
-                            pointer = mapPointer;
-                        }
-                    });
+            if (mMapper2) {
+                if (!mMapper2->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_8888)");
+                    return C2_CORRUPTED;
+                }
+            } else {
+                if (!mMapper3->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer,
+                                         int32_t bytesPerPixel, int32_t bytesPerStride) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                            (void)bytesPerPixel;
+                            (void)bytesPerStride;
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_8888) (@3.0)");
+                    return C2_CORRUPTED;
+                }
+            }
             if (err != C2_OK) {
                 ALOGD("lock failed: %d", err);
                 return err;
@@ -527,10 +644,13 @@
             layout->type = C2PlanarLayout::TYPE_RGB;
             layout->numPlanes = 3;
             layout->rootPlanes = 1;
+            int32_t stride = mMapper2 ?
+                    int32_t(mInfo2.stride) :
+                    int32_t(mInfo3.stride);
             layout->planes[C2PlanarLayout::PLANE_R] = {
                 C2PlaneInfo::CHANNEL_R,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 8,                              // allocatedDepth
@@ -543,7 +663,7 @@
             layout->planes[C2PlanarLayout::PLANE_G] = {
                 C2PlaneInfo::CHANNEL_G,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 8,                              // allocatedDepth
@@ -556,7 +676,7 @@
             layout->planes[C2PlanarLayout::PLANE_B] = {
                 C2PlaneInfo::CHANNEL_B,         // channel
                 4,                              // colInc
-                4 * (int32_t)mInfo.stride,      // rowInc
+                4 * stride,                     // rowInc
                 1,                              // mColSampling
                 1,                              // mRowSampling
                 8,                              // allocatedDepth
@@ -569,23 +689,65 @@
             break;
         }
 
-        case PixelFormat::YCBCR_420_888:
+        case PixelFormat3::YCBCR_420_888:
             // fall-through
-        case PixelFormat::YV12:
+        case PixelFormat3::YV12:
             // fall-through
         default: {
+            struct YCbCrLayout {
+                void* y;
+                void* cb;
+                void* cr;
+                uint32_t yStride;
+                uint32_t cStride;
+                uint32_t chromaStep;
+            };
             YCbCrLayout ycbcrLayout;
-            mMapper->lockYCbCr(
-                    const_cast<native_handle_t *>(mBuffer), grallocUsage,
-                    { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
-                    // TODO: fence
-                    hidl_handle(),
-                    [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
-                        err = maperr2error(maperr);
-                        if (err == C2_OK) {
-                            ycbcrLayout = mapLayout;
-                        }
-                    });
+            if (mMapper2) {
+                if (!mMapper2->lockYCbCr(
+                        const_cast<native_handle_t *>(mBuffer), grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                ycbcrLayout = YCbCrLayout{
+                                        mapLayout.y,
+                                        mapLayout.cb,
+                                        mapLayout.cr,
+                                        mapLayout.yStride,
+                                        mapLayout.cStride,
+                                        mapLayout.chromaStep};
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lockYCbCr");
+                    return C2_CORRUPTED;
+                }
+            } else {
+                if (!mMapper3->lockYCbCr(
+                        const_cast<native_handle_t *>(mBuffer), grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                ycbcrLayout = YCbCrLayout{
+                                        mapLayout.y,
+                                        mapLayout.cb,
+                                        mapLayout.cr,
+                                        mapLayout.yStride,
+                                        mapLayout.cStride,
+                                        mapLayout.chromaStep};
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lockYCbCr (@3.0)");
+                    return C2_CORRUPTED;
+                }
+            }
             if (err != C2_OK) {
                 ALOGD("lockYCbCr failed: %d", err);
                 return err;
@@ -662,17 +824,37 @@
 
     std::lock_guard<std::mutex> lock(mMappedLock);
     c2_status_t err = C2_OK;
-    mMapper->unlock(
-            const_cast<native_handle_t *>(mBuffer),
-            [&err, &fence](const auto &maperr, const auto &releaseFence) {
-                // TODO
-                (void) fence;
-                (void) releaseFence;
-                err = maperr2error(maperr);
-                if (err == C2_OK) {
-                    // TODO: fence
-                }
-            });
+    if (mMapper2) {
+        if (!mMapper2->unlock(
+                const_cast<native_handle_t *>(mBuffer),
+                [&err, &fence](const auto &maperr, const auto &releaseFence) {
+                    // TODO
+                    (void) fence;
+                    (void) releaseFence;
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        // TODO: fence
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: unlock");
+            return C2_CORRUPTED;
+        }
+    } else {
+        if (!mMapper3->unlock(
+                const_cast<native_handle_t *>(mBuffer),
+                [&err, &fence](const auto &maperr, const auto &releaseFence) {
+                    // TODO
+                    (void) fence;
+                    (void) releaseFence;
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        // TODO: fence
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: unlock (@3.0)");
+            return C2_CORRUPTED;
+        }
+    }
     if (err == C2_OK) {
         mLocked = false;
     }
@@ -713,8 +895,10 @@
 private:
     std::shared_ptr<C2Allocator::Traits> mTraits;
     c2_status_t mInit;
-    sp<IAllocator> mAllocator;
-    sp<IMapper> mMapper;
+    sp<IAllocator2> mAllocator2;
+    sp<IMapper2> mMapper2;
+    sp<IAllocator3> mAllocator3;
+    sp<IMapper3> mMapper3;
     const bool mBufferQueue;
 };
 
@@ -734,10 +918,18 @@
     mTraits = std::make_shared<C2Allocator::Traits>(traits);
 
     // gralloc allocator is a singleton, so all objects share a global service
-    mAllocator = IAllocator::getService();
-    mMapper = IMapper::getService();
-    if (mAllocator == nullptr || mMapper == nullptr) {
-        mInit = C2_CORRUPTED;
+    mAllocator3 = IAllocator3::getService();
+    mMapper3 = IMapper3::getService();
+    if (!mAllocator3 || !mMapper3) {
+        mAllocator3 = nullptr;
+        mMapper3 = nullptr;
+        mAllocator2 = IAllocator2::getService();
+        mMapper2 = IMapper2::getService();
+        if (!mAllocator2 || !mMapper2) {
+            mAllocator2 = nullptr;
+            mMapper2 = nullptr;
+            mInit = C2_CORRUPTED;
+        }
     }
 }
 
@@ -748,84 +940,176 @@
     ALOGV("allocating buffer with usage %#llx => %#llx",
           (long long)usage.expected, (long long)grallocUsage);
 
-    BufferDescriptorInfo info = {
-        {
-            width,
-            height,
-            1u,  // layerCount
-            (PixelFormat)format,
-            grallocUsage,
-        },
-        0u,  // stride placeholder
-    };
     c2_status_t err = C2_OK;
-    BufferDescriptor desc;
-    mMapper->createDescriptor(
-            info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
-                err = maperr2error(maperr);
-                if (err == C2_OK) {
-                    desc = descriptor;
-                }
-            });
-    if (err != C2_OK) {
-        return err;
+    hidl_handle buffer{};
+
+    if (mMapper2) {
+        BufferDescriptorInfo2 info = {
+            {
+                width,
+                height,
+                1u,  // layerCount
+                PixelFormat2(format),
+                grallocUsage,
+            },
+            0u,  // stride placeholder
+        };
+        BufferDescriptor2 desc;
+        if (!mMapper2->createDescriptor(
+                info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        desc = descriptor;
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: createDescriptor");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+
+        // IAllocator shares IMapper error codes.
+        if (!mAllocator2->allocate(
+                desc,
+                1u,
+                [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
+                    err = maperr2error(maperr);
+                    if (err != C2_OK) {
+                        return;
+                    }
+                    if (buffers.size() != 1u) {
+                        err = C2_CORRUPTED;
+                        return;
+                    }
+                    info.stride = stride;
+                    buffer = buffers[0];
+                }).isOk()) {
+            ALOGE("failed transaction: allocate");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper2, buffer,
+                C2HandleGralloc::WrapAndMoveNativeHandle(
+                        buffer.getNativeHandle(),
+                        width, height,
+                        format, grallocUsage, info.stride,
+                        0, 0, mBufferQueue ? ~0 : 0),
+                mTraits->id));
+        return C2_OK;
+    } else {
+        BufferDescriptorInfo3 info = {
+            {
+                width,
+                height,
+                1u,  // layerCount
+                PixelFormat3(format),
+                grallocUsage,
+            },
+            0u,  // stride placeholder
+        };
+        BufferDescriptor3 desc;
+        if (!mMapper3->createDescriptor(
+                info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        desc = descriptor;
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: createDescriptor");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+
+        // IAllocator shares IMapper error codes.
+        if (!mAllocator3->allocate(
+                desc,
+                1u,
+                [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
+                    err = maperr2error(maperr);
+                    if (err != C2_OK) {
+                        return;
+                    }
+                    if (buffers.size() != 1u) {
+                        err = C2_CORRUPTED;
+                        return;
+                    }
+                    info.stride = stride;
+                    buffer = buffers[0];
+                }).isOk()) {
+            ALOGE("failed transaction: allocate");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper3, buffer,
+                C2HandleGralloc::WrapAndMoveNativeHandle(
+                        buffer.getNativeHandle(),
+                        width, height,
+                        format, grallocUsage, info.stride,
+                        0, 0, mBufferQueue ? ~0 : 0),
+                mTraits->id));
+        return C2_OK;
     }
-
-    // IAllocator shares IMapper error codes.
-    hidl_handle buffer;
-    mAllocator->allocate(
-            desc,
-            1u,
-            [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
-                err = maperr2error(maperr);
-                if (err != C2_OK) {
-                    return;
-                }
-                if (buffers.size() != 1u) {
-                    err = C2_CORRUPTED;
-                    return;
-                }
-                info.stride = stride;
-                buffer = buffers[0];
-            });
-    if (err != C2_OK) {
-        return err;
-    }
-
-
-    allocation->reset(new C2AllocationGralloc(
-            info, mMapper, buffer,
-            C2HandleGralloc::WrapAndMoveNativeHandle(
-                    buffer.getNativeHandle(),
-                    info.mapperInfo.width, info.mapperInfo.height,
-                    (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride,
-                    0, 0, mBufferQueue ? ~0 : 0),
-            mTraits->id));
-    return C2_OK;
 }
 
 c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation(
         const C2Handle *handle,
         std::shared_ptr<C2GraphicAllocation> *allocation) {
-    BufferDescriptorInfo info;
-    info.mapperInfo.layerCount = 1u;
-    uint32_t generation;
-    uint64_t igbp_id;
-    uint32_t igbp_slot;
-    const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
-            handle,
-            &info.mapperInfo.width, &info.mapperInfo.height,
-            (uint32_t *)&info.mapperInfo.format, (uint64_t *)&info.mapperInfo.usage, &info.stride,
-            &generation, &igbp_id, &igbp_slot);
-    if (grallocHandle == nullptr) {
-        return C2_BAD_VALUE;
+    if (mMapper2) {
+        BufferDescriptorInfo2 info;
+        info.mapperInfo.layerCount = 1u;
+        uint32_t generation;
+        uint64_t igbp_id;
+        uint32_t igbp_slot;
+        const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
+                handle,
+                &info.mapperInfo.width, &info.mapperInfo.height,
+                (uint32_t *)&info.mapperInfo.format,
+                (uint64_t *)&info.mapperInfo.usage,
+                &info.stride,
+                &generation, &igbp_id, &igbp_slot);
+        if (grallocHandle == nullptr) {
+            return C2_BAD_VALUE;
+        }
+
+        hidl_handle hidlHandle;
+        hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
+
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper2, hidlHandle, grallocHandle, mTraits->id));
+        return C2_OK;
+    } else {
+        BufferDescriptorInfo3 info;
+        info.mapperInfo.layerCount = 1u;
+        uint32_t generation;
+        uint64_t igbp_id;
+        uint32_t igbp_slot;
+        const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
+                handle,
+                &info.mapperInfo.width, &info.mapperInfo.height,
+                (uint32_t *)&info.mapperInfo.format,
+                (uint64_t *)&info.mapperInfo.usage,
+                &info.stride,
+                &generation, &igbp_id, &igbp_slot);
+        if (grallocHandle == nullptr) {
+            return C2_BAD_VALUE;
+        }
+
+        hidl_handle hidlHandle;
+        hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
+
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper3, hidlHandle, grallocHandle, mTraits->id));
+        return C2_OK;
     }
-
-    hidl_handle hidlHandle;
-    hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
-
-    allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle, mTraits->id));
-    return C2_OK;
 }
 
 C2AllocatorGralloc::C2AllocatorGralloc(id_t id, bool bufferQueue)