Merge changes I926887cc,I7def937e,I530f6d89,I393fc3c4 into rvc-dev

* changes:
  gralloc4-vts: Hold fence by unique_fd to avoid leakage
  gralloc4-vts: Restore Lock_YCBCR_420_888 and create Lock_YV12
  gralloc4-vts: Extract YCbCr888 data operation from Lock_YCRCB_420_SP
  gralloc4-vts: Allow YCRCB_420_SP to be unsupported in Lock_YCRCB_420_SP
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 9f907e6..5b2a94e 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -71,7 +71,8 @@
     return mAllocator;
 }
 
-const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
+const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle,
+                                            enum Tolerance /*tolerance*/) {
     const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
     EXPECT_NE(nullptr, bufferHandle);
 
@@ -84,42 +85,37 @@
 
 std::vector<const native_handle_t*> Gralloc::allocate(const BufferDescriptor& descriptor,
                                                       uint32_t count, bool import,
-                                                      bool allowFailure, uint32_t* outStride) {
+                                                      enum Tolerance tolerance,
+                                                      uint32_t* outStride) {
     std::vector<const native_handle_t*> bufferHandles;
     bufferHandles.reserve(count);
-    mAllocator->allocate(
-            descriptor, count,
-            [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
-                if (allowFailure && tmpError == Error::UNSUPPORTED) {
-                    return;
-                }
-                ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
-                ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+    mAllocator->allocate(descriptor, count,
+                         [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
+                             if (canTolerate(tolerance, tmpError)) {
+                                 return;
+                             }
 
-                for (uint32_t i = 0; i < count; i++) {
-                    const native_handle_t* bufferHandle = nullptr;
-                    if (import) {
-                        if (allowFailure) {
-                            bufferHandle = importBuffer(tmpBuffers[i]);
-                        } else {
-                            ASSERT_NO_FATAL_FAILURE(bufferHandle = importBuffer(tmpBuffers[i]));
-                        }
-                    } else {
-                        if (allowFailure) {
-                            bufferHandle = cloneBuffer(tmpBuffers[i]);
-                        } else {
-                            ASSERT_NO_FATAL_FAILURE(bufferHandle = cloneBuffer(tmpBuffers[i]));
-                        }
-                    }
-                    if (bufferHandle) {
-                        bufferHandles.push_back(bufferHandle);
-                    }
-                }
+                             ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
+                             ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
 
-                if (outStride) {
-                    *outStride = tmpStride;
-                }
-            });
+                             for (uint32_t i = 0; i < count; i++) {
+                                 const native_handle_t* bufferHandle = nullptr;
+                                 if (import) {
+                                     ASSERT_NO_FATAL_FAILURE(
+                                             bufferHandle = importBuffer(tmpBuffers[i], tolerance));
+                                 } else {
+                                     ASSERT_NO_FATAL_FAILURE(
+                                             bufferHandle = cloneBuffer(tmpBuffers[i], tolerance));
+                                 }
+                                 if (bufferHandle) {
+                                     bufferHandles.push_back(bufferHandle);
+                                 }
+                             }
+
+                             if (outStride) {
+                                 *outStride = tmpStride;
+                             }
+                         });
 
     if (::testing::Test::HasFatalFailure()) {
         bufferHandles.clear();
@@ -129,13 +125,14 @@
 }
 
 const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
-                                         bool import, bool allowFailure, uint32_t* outStride) {
+                                         bool import, enum Tolerance tolerance,
+                                         uint32_t* outStride) {
     BufferDescriptor descriptor = createDescriptor(descriptorInfo);
     if (::testing::Test::HasFatalFailure()) {
         return nullptr;
     }
 
-    auto buffers = allocate(descriptor, 1, import, allowFailure, outStride);
+    auto buffers = allocate(descriptor, 1, import, tolerance, outStride);
     if (::testing::Test::HasFatalFailure()) {
         return nullptr;
     }
@@ -160,11 +157,14 @@
     return descriptor;
 }
 
-const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) {
+const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle,
+                                             enum Tolerance tolerance) {
     const native_handle_t* bufferHandle = nullptr;
     mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
-        ASSERT_EQ(Error::NONE, tmpError)
-                << "failed to import buffer %p" << rawHandle.getNativeHandle();
+        if (!canTolerate(tolerance, tmpError)) {
+            ASSERT_EQ(Error::NONE, tmpError)
+                    << "failed to import buffer %p" << rawHandle.getNativeHandle();
+        }
         bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
     });
 
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index cd40aa4..22a935f 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -37,6 +37,16 @@
 // A wrapper to IAllocator and IMapper.
 class Gralloc {
   public:
+    enum class Tolerance : uint32_t {
+        kToleranceStrict = 0x0U,
+        kToleranceBadDescriptor = 0x1U << std::underlying_type_t<Error>(Error::BAD_DESCRIPTOR),
+        kToleranceBadBuffer = 0x1U << std::underlying_type_t<Error>(Error::BAD_BUFFER),
+        kToleranceBadValue = 0x1U << std::underlying_type_t<Error>(Error::BAD_VALUE),
+        kToleranceNoResource = 0x1U << std::underlying_type_t<Error>(Error::NO_RESOURCES),
+        kToleranceUnSupported = 0x1U << std::underlying_type_t<Error>(Error::UNSUPPORTED),
+        kToleranceAllErrors = ~0x0U,
+    };
+
     Gralloc(const std::string& allocatorServiceName = "default",
             const std::string& mapperServiceName = "default", bool errOnFailure = true);
     ~Gralloc();
@@ -49,12 +59,27 @@
     // is true, the returned buffers are also imported into the mapper.
     //
     // Either case, the returned buffers must be freed with freeBuffer.
-    std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor, uint32_t count,
-                                                 bool import = true, bool allowFailure = false,
-                                                 uint32_t* outStride = nullptr);
+    std::vector<const native_handle_t*> allocate(
+            const BufferDescriptor& descriptor, uint32_t count, bool import = true,
+            enum Tolerance tolerance = Tolerance::kToleranceStrict, uint32_t* outStride = nullptr);
+
     const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
-                                    bool import = true, bool allowFailure = false,
-                                    uint32_t* outStride = nullptr);
+                                    bool import, enum Tolerance tolerance, uint32_t* outStride);
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import) {
+        return allocate(descriptorInfo, import, Tolerance::kToleranceStrict);
+    }
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import, enum Tolerance tolerance) {
+        return allocate(descriptorInfo, import, tolerance, nullptr);
+    }
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import, uint32_t* outStride) {
+        return allocate(descriptorInfo, import, Tolerance::kToleranceStrict, outStride);
+    }
 
     // IMapper methods
 
@@ -62,7 +87,11 @@
 
     BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
 
-    const native_handle_t* importBuffer(const hidl_handle& rawHandle);
+    const native_handle_t* importBuffer(const hidl_handle& rawHandle, enum Tolerance tolerance);
+    const native_handle_t* importBuffer(const hidl_handle& rawHandle) {
+        return importBuffer(rawHandle, Tolerance::kToleranceStrict);
+    }
+
     void freeBuffer(const native_handle_t* bufferHandle);
 
     // We use fd instead of hidl_handle in these functions to pass fences
@@ -96,11 +125,19 @@
                             uint64_t* outReservedSize);
 
   private:
+    bool canTolerate(Tolerance tolerance, Error error) {
+        return (std::underlying_type_t<Tolerance>(tolerance) &
+                0x1U << std::underlying_type_t<Error>(error)) != 0;
+    }
+
     void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
 
     // initialize without checking for failure to get service
     void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName);
-    const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
+    const native_handle_t* cloneBuffer(const hidl_handle& rawHandle, enum Tolerance tolerance);
+    const native_handle_t* cloneBuffer(const hidl_handle& rawHandle) {
+        return cloneBuffer(rawHandle, Tolerance::kToleranceStrict);
+    }
 
     sp<IAllocator> mAllocator;
     sp<IMapper> mMapper;
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 5ab647f..9e56534 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -24,6 +24,7 @@
 #include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <android/sync.h>
 #include <gralloctypes/Gralloc4.h>
 #include <gtest/gtest.h>
@@ -40,8 +41,10 @@
 namespace vts {
 namespace {
 
+using ::android::base::unique_fd;
 using android::hardware::graphics::common::V1_2::BufferUsage;
 using android::hardware::graphics::common::V1_2::PixelFormat;
+using Tolerance = ::android::hardware::graphics::mapper::V4_0::vts::Gralloc::Tolerance;
 using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
 using aidl::android::hardware::graphics::common::BlendMode;
 using aidl::android::hardware::graphics::common::Cta861_3;
@@ -276,7 +279,7 @@
         }
     }
 
-    void verifyRGBA8888(const native_handle_t* bufferHandle, uint8_t* data, uint32_t height,
+    void verifyRGBA8888(const native_handle_t* bufferHandle, const uint8_t* data, uint32_t height,
                         size_t strideInBytes, size_t widthInBytes, uint32_t seed = 0) {
         hidl_vec<uint8_t> vec;
         ASSERT_EQ(Error::NONE,
@@ -294,6 +297,49 @@
         }
     }
 
+    void traverseYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                              int64_t hSubsampling, int64_t vSubsampling,
+                              std::function<void(uint8_t*, uint8_t)> traverseFuncion) {
+        auto yData = static_cast<uint8_t*>(yCbCr.y);
+        auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+        auto crData = static_cast<uint8_t*>(yCbCr.cr);
+        auto yStride = yCbCr.ystride;
+        auto cStride = yCbCr.cstride;
+        auto chromaStep = yCbCr.chroma_step;
+
+        for (uint32_t y = 0; y < height; y++) {
+            for (uint32_t x = 0; x < width; x++) {
+                auto val = static_cast<uint8_t>(height * y + x);
+
+                traverseFuncion(yData + yStride * y + x, val);
+
+                if (y % vSubsampling == 0 && x % hSubsampling == 0) {
+                    uint32_t subSampleX = x / hSubsampling;
+                    uint32_t subSampleY = y / vSubsampling;
+                    const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX;
+                    const auto subSampleVal =
+                            static_cast<uint8_t>(height * subSampleY + subSampleX);
+
+                    traverseFuncion(cbData + subSampleOffset, subSampleVal);
+                    traverseFuncion(crData + subSampleOffset, subSampleVal + 1);
+                }
+            }
+        }
+    }
+
+    void fillYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                          int64_t hSubsampling, int64_t vSubsampling) {
+        traverseYCbCr888Data(yCbCr, width, height, hSubsampling, vSubsampling,
+                             [](auto address, auto fillingData) { *address = fillingData; });
+    }
+
+    void verifyYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                            int64_t hSubsampling, int64_t vSubsampling) {
+        traverseYCbCr888Data(
+                yCbCr, width, height, hSubsampling, vSubsampling,
+                [](auto address, auto expectedData) { EXPECT_EQ(*address, expectedData); });
+    }
+
     bool isEqual(float a, float b) { return abs(a - b) < 0.0001; }
 
     std::unique_ptr<Gralloc> mGralloc;
@@ -331,8 +377,9 @@
     for (uint32_t count = 0; count < 5; count++) {
         std::vector<const native_handle_t*> bufferHandles;
         uint32_t stride;
-        ASSERT_NO_FATAL_FAILURE(
-                bufferHandles = mGralloc->allocate(descriptor, count, false, false, &stride));
+        ASSERT_NO_FATAL_FAILURE(bufferHandles =
+                                        mGralloc->allocate(descriptor, count, false,
+                                                           Tolerance::kToleranceStrict, &stride));
 
         if (count >= 1) {
             EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride";
@@ -532,32 +579,30 @@
 
     const native_handle_t* bufferHandle;
     uint32_t stride;
-    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride));
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
 
     // lock buffer for writing
     const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
                                static_cast<int32_t>(info.height)};
-    int fence = -1;
+    unique_fd fence;
     uint8_t* data;
-    ASSERT_NO_FATAL_FAILURE(
-            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
+                                    mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
 
     // RGBA_8888
     fillRGBA8888(data, info.height, stride * 4, info.width * 4);
 
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
 
     // lock again for reading
-    ASSERT_NO_FATAL_FAILURE(
-            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
+                                    mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
 
     ASSERT_NO_FATAL_FAILURE(
             verifyRGBA8888(bufferHandle, data, info.height, stride * 4, info.width * 4));
 
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
-    if (fence >= 0) {
-        close(fence);
-    }
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
 }
 
 TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) {
@@ -566,16 +611,21 @@
 
     const native_handle_t* bufferHandle;
     uint32_t stride;
-    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride));
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(
+                                    info, true, Tolerance::kToleranceUnSupported, &stride));
+    if (bufferHandle == nullptr) {
+        GTEST_SUCCEED() << "YCRCB_420_SP format is unsupported";
+        return;
+    }
 
     // lock buffer for writing
     const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
                                static_cast<int32_t>(info.height)};
-    int fence = -1;
+    unique_fd fence;
     uint8_t* data;
 
-    ASSERT_NO_FATAL_FAILURE(
-            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
+                                    mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
 
     android_ycbcr yCbCr;
     int64_t hSubsampling = 0;
@@ -583,74 +633,122 @@
     ASSERT_NO_FATAL_FAILURE(
             getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
 
-    auto yData = static_cast<uint8_t*>(yCbCr.y);
-    auto cbData = static_cast<uint8_t*>(yCbCr.cb);
-    auto crData = static_cast<uint8_t*>(yCbCr.cr);
-    auto yStride = yCbCr.ystride;
-    auto cStride = yCbCr.cstride;
-    auto chromaStep = yCbCr.chroma_step;
-
     constexpr uint32_t kCbCrSubSampleFactor = 2;
-    ASSERT_EQ(crData + 1, cbData);
-    ASSERT_EQ(2, chromaStep);
     ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
     ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
 
-    for (uint32_t y = 0; y < info.height; y++) {
-        for (uint32_t x = 0; x < info.width; x++) {
-            auto val = static_cast<uint8_t>(info.height * y + x);
+    auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+    auto crData = static_cast<uint8_t*>(yCbCr.cr);
+    ASSERT_EQ(crData + 1, cbData);
+    ASSERT_EQ(2, yCbCr.chroma_step);
 
-            yData[yStride * y + x] = val;
+    fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
 
-            if (y % vSubsampling == 0 && x % hSubsampling == 0) {
-                uint32_t subSampleX = x / hSubsampling;
-                uint32_t subSampleY = y / vSubsampling;
-                const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX;
-                const auto subSampleVal =
-                        static_cast<uint8_t>(info.height * subSampleY + subSampleX);
-
-                cbData[subSampleOffset] = subSampleVal;
-                crData[subSampleOffset] = subSampleVal + 1;
-            }
-        }
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
 
     // lock again for reading
-    ASSERT_NO_FATAL_FAILURE(
-            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
+                                    mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
 
     ASSERT_NO_FATAL_FAILURE(
             getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
 
-    yData = static_cast<uint8_t*>(yCbCr.y);
-    cbData = static_cast<uint8_t*>(yCbCr.cb);
-    crData = static_cast<uint8_t*>(yCbCr.cr);
+    verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
 
-    for (uint32_t y = 0; y < info.height; y++) {
-        for (uint32_t x = 0; x < info.width; x++) {
-            auto val = static_cast<uint8_t>(info.height * y + x);
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
 
-            EXPECT_EQ(val, yData[yStride * y + x]);
+TEST_P(GraphicsMapperHidlTest, Lock_YV12) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YV12;
 
-            if (y % vSubsampling == 0 && x % hSubsampling == 0) {
-                uint32_t subSampleX = x / hSubsampling;
-                uint32_t subSampleY = y / vSubsampling;
-                const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX;
-                const auto subSampleVal =
-                        static_cast<uint8_t>(info.height * subSampleY + subSampleX);
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
 
-                EXPECT_EQ(subSampleVal, cbData[subSampleOffset]);
-                EXPECT_EQ(subSampleVal + 1, crData[subSampleOffset]);
-            }
-        }
-    }
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+    uint8_t* data;
 
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
-    if (fence >= 0) {
-        close(fence);
-    }
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
+                                    mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+
+    android_ycbcr yCbCr;
+    int64_t hSubsampling = 0;
+    int64_t vSubsampling = 0;
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+    auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+    auto crData = static_cast<uint8_t*>(yCbCr.cr);
+    ASSERT_EQ(crData + yCbCr.cstride * info.height / vSubsampling, cbData);
+    ASSERT_EQ(1, yCbCr.chroma_step);
+
+    fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
+                                    mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YCBCR_420_888;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+    uint8_t* data;
+
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
+                                    mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+
+    android_ycbcr yCbCr;
+    int64_t hSubsampling = 0;
+    int64_t vSubsampling = 0;
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+    fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(
+                                    mGralloc->lock(bufferHandle, info.usage, region, fence.get())));
+
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
 }
 
 /**
@@ -741,8 +839,8 @@
 
     const native_handle_t* rawHandle;
     uint32_t stride;
-    ASSERT_NO_FATAL_FAILURE(
-            rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false, false, &stride));
+    ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false,
+                                                           Tolerance::kToleranceStrict, &stride));
 
     const native_handle_t* writeBufferHandle;
     const native_handle_t* readBufferHandle;
@@ -766,11 +864,10 @@
 
     fillRGBA8888(writeData, info.height, stride * 4, info.width * 4);
 
-    int fence;
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->flushLockedBuffer(writeBufferHandle));
+    unique_fd fence;
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->flushLockedBuffer(writeBufferHandle)));
     if (fence >= 0) {
         ASSERT_EQ(0, sync_wait(fence, 3500));
-        close(fence);
     }
 
     ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle));
@@ -778,14 +875,9 @@
     ASSERT_NO_FATAL_FAILURE(
             verifyRGBA8888(readBufferHandle, readData, info.height, stride * 4, info.width * 4));
 
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(readBufferHandle));
-    if (fence >= 0) {
-        close(fence);
-    }
-    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(writeBufferHandle));
-    if (fence >= 0) {
-        close(fence);
-    }
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(readBufferHandle)));
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(writeBufferHandle)));
 }
 
 /**
@@ -964,7 +1056,7 @@
     info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
 
     const native_handle_t* bufferHandle = nullptr;
-    bufferHandle = mGralloc->allocate(info, true, true);
+    bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceAllErrors);
     if (!bufferHandle) {
         GTEST_SUCCEED() << "unable to allocate protected content";
         return;
@@ -1267,7 +1359,7 @@
     auto info = mDummyDescriptorInfo;
     info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
 
-    bufferHandle = mGralloc->allocate(info, true, true);
+    bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceAllErrors);
     if (!bufferHandle) {
         GTEST_SUCCEED() << "unable to allocate protected content";
         return;