/*
 * Copyright 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "VtsHalGraphicsMapperV4_0TargetTest"

#include <unistd.h>
#include <chrono>
#include <thread>
#include <vector>

#include <aidl/Vintf.h>
#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
#include <aidl/android/hardware/graphics/allocator/AllocationResult.h>
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
#include <aidlcommonsupport/NativeHandle.h>

#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <android/sync.h>
#include <gralloctypes/Gralloc4.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>

#include <mapper-vts/4.0/MapperVts.h>
#include <system/graphics.h>

namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V4_0 {
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;
using aidl::android::hardware::graphics::common::Dataspace;
using aidl::android::hardware::graphics::common::ExtendableType;
using aidl::android::hardware::graphics::common::PlaneLayout;
using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
using aidl::android::hardware::graphics::common::Smpte2086;
using aidl::android::hardware::graphics::common::StandardMetadataType;

using DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
                                          const hidl_vec<uint8_t>& vec)>;

struct YCbCr {
    android_ycbcr yCbCr;
    int64_t horizontalSubSampling;
    int64_t verticalSubSampling;
};

class GraphicsMapperHidlTest
    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
  protected:
    void SetUp() override {
        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
                                                                     std::get<1>(GetParam())));
        ASSERT_TRUE(mGralloc->hasAllocator());
        ASSERT_NE(nullptr, mGralloc->getMapper().get());

        mDummyDescriptorInfo.name = "dummy";
        mDummyDescriptorInfo.width = 64;
        mDummyDescriptorInfo.height = 64;
        mDummyDescriptorInfo.layerCount = 1;
        mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
        mDummyDescriptorInfo.usage =
                static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
        mDummyDescriptorInfo.reservedSize = 0;
    }

    void TearDown() override {}

    void testGet(const IMapper::BufferDescriptorInfo& descriptorInfo,
                 const MetadataType& metadataType, DecodeFunction decode) {
        const native_handle_t* bufferHandle = nullptr;
        ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true));

        hidl_vec<uint8_t> vec;
        const auto result = mGralloc->get(bufferHandle, metadataType, &vec);

        if (metadataType == gralloc4::MetadataType_Smpte2094_10 && result == Error::UNSUPPORTED) {
            GTEST_SKIP() << "getting metadata for Smpte2094-10 is unsupported";
        }

        ASSERT_EQ(Error::NONE, result);

        ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec));
    }

    void testSet(const IMapper::BufferDescriptorInfo& descriptorInfo,
                 const MetadataType& metadataType, const hidl_vec<uint8_t>& metadata,
                 DecodeFunction decode) {
        const native_handle_t* bufferHandle = nullptr;
        ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true));

        Error err = mGralloc->set(bufferHandle, metadataType, metadata);
        if (err == Error::UNSUPPORTED) {
            GTEST_SUCCEED() << "setting this metadata is unsupported";
            return;
        }
        ASSERT_EQ(err, Error::NONE);

        hidl_vec<uint8_t> vec;
        ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec));

        ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec));
    }

    void verifyRGBA8888PlaneLayouts(const std::vector<PlaneLayout>& planeLayouts) {
        ASSERT_EQ(1, planeLayouts.size());

        const auto& planeLayout = planeLayouts.front();

        ASSERT_EQ(4, planeLayout.components.size());

        int64_t offsetInBitsR = -1;
        int64_t offsetInBitsG = -1;
        int64_t offsetInBitsB = -1;
        int64_t offsetInBitsA = -1;

        for (const auto& component : planeLayout.components) {
            if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
                continue;
            }
            EXPECT_EQ(8, component.sizeInBits);
            if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) {
                offsetInBitsR = component.offsetInBits;
            }
            if (component.type.value == gralloc4::PlaneLayoutComponentType_G.value) {
                offsetInBitsG = component.offsetInBits;
            }
            if (component.type.value == gralloc4::PlaneLayoutComponentType_B.value) {
                offsetInBitsB = component.offsetInBits;
            }
            if (component.type.value == gralloc4::PlaneLayoutComponentType_A.value) {
                offsetInBitsA = component.offsetInBits;
            }
        }

        EXPECT_EQ(0, offsetInBitsR);
        EXPECT_EQ(8, offsetInBitsG);
        EXPECT_EQ(16, offsetInBitsB);
        EXPECT_EQ(24, offsetInBitsA);

        EXPECT_EQ(0, planeLayout.offsetInBytes);
        EXPECT_EQ(32, planeLayout.sampleIncrementInBits);
        // Skip testing stride because any stride is valid
        EXPECT_EQ(mDummyDescriptorInfo.width, planeLayout.widthInSamples);
        EXPECT_EQ(mDummyDescriptorInfo.height, planeLayout.heightInSamples);
        EXPECT_LE(planeLayout.widthInSamples * planeLayout.heightInSamples * 4,
                  planeLayout.totalSizeInBytes);
        EXPECT_EQ(1, planeLayout.horizontalSubsampling);
        EXPECT_EQ(1, planeLayout.verticalSubsampling);
    }

    void verifyBufferDump(const IMapper::BufferDump& bufferDump,
                          const native_handle_t* bufferHandle = nullptr) {
        std::set<StandardMetadataType> foundMetadataTypes;

        const std::vector<IMapper::MetadataDump> metadataDump = bufferDump.metadataDump;

        for (const auto& dump : metadataDump) {
            const auto& metadataType = dump.metadataType;
            const auto& metadata = dump.metadata;

            if (!gralloc4::isStandardMetadataType(metadataType)) {
                continue;
            }

            StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType);

            if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) {
                continue;
            }

            ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end());
            foundMetadataTypes.insert(type);

            if (!bufferHandle) {
                continue;
            }

            hidl_vec<uint8_t> metadataFromGet;
            ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &metadataFromGet));

            ASSERT_EQ(metadataFromGet, metadata);
        }

        EXPECT_EQ(sRequiredMetadataTypes, foundMetadataTypes);
    }

    void getAndroidYCbCr(const native_handle_t* bufferHandle, uint8_t* data,
                         android_ycbcr* outYCbCr, int64_t* hSubsampling, int64_t* vSubsampling) {
        hidl_vec<uint8_t> vec;
        ASSERT_EQ(Error::NONE,
                  mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
        std::vector<PlaneLayout> planeLayouts;
        ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));

        outYCbCr->y = nullptr;
        outYCbCr->cb = nullptr;
        outYCbCr->cr = nullptr;
        outYCbCr->ystride = 0;
        outYCbCr->cstride = 0;
        outYCbCr->chroma_step = 0;

        for (const auto& planeLayout : planeLayouts) {
            for (const auto& planeLayoutComponent : planeLayout.components) {
                if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
                    continue;
                }
                ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);

                uint8_t* tmpData = data + planeLayout.offsetInBytes +
                                   bitsToBytes(planeLayoutComponent.offsetInBits);
                uint64_t sampleIncrementInBytes;

                auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
                switch (type) {
                    case PlaneLayoutComponentType::Y:
                        ASSERT_EQ(nullptr, outYCbCr->y);
                        ASSERT_EQ(8, planeLayoutComponent.sizeInBits);
                        ASSERT_EQ(8, planeLayout.sampleIncrementInBits);
                        outYCbCr->y = tmpData;
                        outYCbCr->ystride = planeLayout.strideInBytes;
                        break;

                    case PlaneLayoutComponentType::CB:
                    case PlaneLayoutComponentType::CR:
                        ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8);

                        sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
                        ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2);

                        if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) {
                            outYCbCr->cstride = planeLayout.strideInBytes;
                            outYCbCr->chroma_step = sampleIncrementInBytes;
                        } else {
                            ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes);
                            ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes);
                        }

                        if (*hSubsampling == 0 && *vSubsampling == 0) {
                            *hSubsampling = planeLayout.horizontalSubsampling;
                            *vSubsampling = planeLayout.verticalSubsampling;
                        } else {
                            ASSERT_EQ(*hSubsampling, planeLayout.horizontalSubsampling);
                            ASSERT_EQ(*vSubsampling, planeLayout.verticalSubsampling);
                        }

                        if (type == PlaneLayoutComponentType::CB) {
                            ASSERT_EQ(nullptr, outYCbCr->cb);
                            outYCbCr->cb = tmpData;
                        } else {
                            ASSERT_EQ(nullptr, outYCbCr->cr);
                            outYCbCr->cr = tmpData;
                        }
                        break;
                    default:
                        break;
                };
            }
        }

        ASSERT_NE(nullptr, outYCbCr->y);
        ASSERT_NE(nullptr, outYCbCr->cb);
        ASSERT_NE(nullptr, outYCbCr->cr);
    }

    YCbCr getAndroidYCbCr_P010(const native_handle_t* bufferHandle, uint8_t* data) {
        YCbCr yCbCr_P010;
        hidl_vec<uint8_t> vec;
        EXPECT_EQ(Error::NONE,
                  mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
        std::vector<PlaneLayout> planeLayouts;
        EXPECT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
        EXPECT_EQ(2, planeLayouts.size());
        EXPECT_EQ(1, planeLayouts[0].components.size());
        EXPECT_EQ(2, planeLayouts[1].components.size());

        yCbCr_P010.yCbCr.y = nullptr;
        yCbCr_P010.yCbCr.cb = nullptr;
        yCbCr_P010.yCbCr.cr = nullptr;
        yCbCr_P010.yCbCr.ystride = 0;
        yCbCr_P010.yCbCr.cstride = 0;
        yCbCr_P010.yCbCr.chroma_step = 0;
        int64_t cb_offset = 0;
        int64_t cr_offset = 0;

        for (const auto& planeLayout : planeLayouts) {
            for (const auto& planeLayoutComponent : planeLayout.components) {
                if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
                    continue;
                }

                uint8_t* tmpData = data + planeLayout.offsetInBytes +
                                   bitsToBytes(planeLayoutComponent.offsetInBits);
                uint64_t sampleIncrementInBytes = 0;
                auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
                switch (type) {
                    case PlaneLayoutComponentType::Y:
                        // For specs refer:
                        // https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats
                        EXPECT_EQ(6, planeLayoutComponent.offsetInBits);
                        EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.y);
                        EXPECT_EQ(10, planeLayoutComponent.sizeInBits);
                        EXPECT_EQ(16, planeLayout.sampleIncrementInBits);

                        yCbCr_P010.yCbCr.y = tmpData;
                        yCbCr_P010.yCbCr.ystride = planeLayout.strideInBytes;
                        break;

                    case PlaneLayoutComponentType::CB:
                    case PlaneLayoutComponentType::CR:
                        sampleIncrementInBytes = bitsToBytes(planeLayout.sampleIncrementInBits);
                        EXPECT_EQ(4, sampleIncrementInBytes);

                        if (yCbCr_P010.yCbCr.cstride == 0 && yCbCr_P010.yCbCr.chroma_step == 0) {
                            yCbCr_P010.yCbCr.cstride = planeLayout.strideInBytes;
                            yCbCr_P010.yCbCr.chroma_step = sampleIncrementInBytes;
                        } else {
                            EXPECT_EQ(yCbCr_P010.yCbCr.cstride, planeLayout.strideInBytes);
                            EXPECT_EQ(yCbCr_P010.yCbCr.chroma_step, sampleIncrementInBytes);
                        }

                        if (yCbCr_P010.horizontalSubSampling == 0 &&
                            yCbCr_P010.verticalSubSampling == 0) {
                            yCbCr_P010.horizontalSubSampling = planeLayout.horizontalSubsampling;
                            yCbCr_P010.verticalSubSampling = planeLayout.verticalSubsampling;
                        } else {
                            EXPECT_EQ(yCbCr_P010.horizontalSubSampling,
                                      planeLayout.horizontalSubsampling);
                            EXPECT_EQ(yCbCr_P010.verticalSubSampling,
                                      planeLayout.verticalSubsampling);
                        }

                        if (type == PlaneLayoutComponentType::CB) {
                            EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cb);
                            yCbCr_P010.yCbCr.cb = tmpData;
                            cb_offset = planeLayoutComponent.offsetInBits;
                        } else {
                            EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cr);
                            yCbCr_P010.yCbCr.cr = tmpData;
                            cr_offset = planeLayoutComponent.offsetInBits;
                        }
                        break;
                    default:
                        break;
                };
            }
        }

        EXPECT_EQ(cb_offset + bytesToBits(2), cr_offset);
        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.y);
        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cb);
        EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cr);
        return yCbCr_P010;
    }

    void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes,
                      uint32_t seed = 0) {
        for (uint32_t y = 0; y < height; y++) {
            memset(data, y + seed, widthInBytes);
            data += strideInBytes;
        }
    }

    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,
                  mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
        std::vector<PlaneLayout> planeLayouts;
        ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));

        verifyRGBA8888PlaneLayouts(planeLayouts);

        for (uint32_t y = 0; y < height; y++) {
            for (size_t i = 0; i < widthInBytes; i++) {
                EXPECT_EQ(static_cast<uint8_t>(y + seed), data[i]);
            }
            data += strideInBytes;
        }
    }

    void traverseYCbCrData(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 fillYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
                       int64_t hSubsampling, int64_t vSubsampling) {
        traverseYCbCrData(yCbCr, width, height, hSubsampling, vSubsampling,
                          [](auto address, auto fillingData) { *address = fillingData; });
    }

    void verifyYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
                         int64_t hSubsampling, int64_t vSubsampling) {
        traverseYCbCrData(
                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; }

    uint64_t bitsToBytes(int64_t bits) { return bits / 8; }

    uint64_t bytesToBits(int64_t bytes) { return bytes * 8; }

    std::unique_ptr<Gralloc> mGralloc;
    IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
    static const std::set<StandardMetadataType> sRequiredMetadataTypes;
};

const std::set<StandardMetadataType> GraphicsMapperHidlTest::sRequiredMetadataTypes{
        StandardMetadataType::BUFFER_ID,
        StandardMetadataType::NAME,
        StandardMetadataType::WIDTH,
        StandardMetadataType::HEIGHT,
        StandardMetadataType::LAYER_COUNT,
        StandardMetadataType::PIXEL_FORMAT_REQUESTED,
        StandardMetadataType::PIXEL_FORMAT_FOURCC,
        StandardMetadataType::PIXEL_FORMAT_MODIFIER,
        StandardMetadataType::USAGE,
        StandardMetadataType::ALLOCATION_SIZE,
        StandardMetadataType::PROTECTED_CONTENT,
        StandardMetadataType::COMPRESSION,
        StandardMetadataType::INTERLACED,
        StandardMetadataType::CHROMA_SITING,
        StandardMetadataType::PLANE_LAYOUTS,
        StandardMetadataType::DATASPACE,
        StandardMetadataType::BLEND_MODE,
};

/**
 * Test IAllocator::allocate with valid buffer descriptors.
 */
TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
    BufferDescriptor descriptor;
    ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));

    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,
                                                           Tolerance::kToleranceStrict, &stride));

        if (count >= 1) {
            EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride";
        }

        for (auto bufferHandle : bufferHandles) {
            mGralloc->freeBuffer(bufferHandle);
        }
    }
}

/**
 * Test IAllocator::allocate with invalid buffer descriptors.
 */
TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
    // this assumes any valid descriptor is non-empty
    BufferDescriptor descriptor;

    mGralloc->rawAllocate(descriptor, 1, [&](const auto& tmpError, const auto&, const auto&) {
        EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
    });
}

/**
 * Test IAllocator::allocate does not leak.
 */
TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
    auto info = mDummyDescriptorInfo;
    info.width = 1024;
    info.height = 1024;

    for (int i = 0; i < 2048; i++) {
        auto bufferHandle = mGralloc->allocate(info, false);
        mGralloc->freeBuffer(bufferHandle);
    }
}

/**
 * Test that IAllocator::allocate is thread-safe.
 */
TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
    BufferDescriptor descriptor;
    ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));

    std::atomic<bool> timeUp(false);
    std::atomic<uint64_t> allocationCount(0);
    auto threadLoop = [&]() {
        while (!timeUp) {
            mGralloc->rawAllocate(descriptor, 1, [&](const auto&, const auto&, const auto&) {
                allocationCount++;
            });
        }
    };

    std::vector<std::thread> threads;
    for (int i = 0; i < 8; i++) {
        threads.push_back(std::thread(threadLoop));
    }

    std::this_thread::sleep_for(std::chrono::seconds(3));
    timeUp = true;
    LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations";

    for (auto& thread : threads) {
        thread.join();
    }
}

/**
 * Test IMapper::createDescriptor with valid descriptor info.
 */
TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
    ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
}

/**
 * Test IMapper::createDescriptor with invalid descriptor info.
 */
TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
    auto info = mDummyDescriptorInfo;
    info.width = 0;
    mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
        EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE";
    });
}

/**
 * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
 */
TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
    const native_handle_t* bufferHandle;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
}

/**
 * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
 */
TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
    const native_handle_t* clonedBufferHandle;
    ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));

    // A cloned handle is a raw handle. Check that we can import it multiple
    // times.
    const native_handle_t* importedBufferHandles[2];
    ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] = mGralloc->importBuffer(clonedBufferHandle));
    ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] = mGralloc->importBuffer(clonedBufferHandle));
    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0]));
    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1]));

    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle));
}

/**
 * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
 */
TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
    const native_handle_t* rawHandle;
    ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));

    native_handle_t* importedHandle = nullptr;
    mGralloc->getMapper()->importBuffer(rawHandle, [&](const auto& tmpError, const auto& buffer) {
        ASSERT_EQ(Error::NONE, tmpError);
        importedHandle = static_cast<native_handle_t*>(buffer);
    });

    // free the imported handle with another mapper
    std::unique_ptr<Gralloc> anotherGralloc;
    ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
                                                                       std::get<1>(GetParam())));
    Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
    ASSERT_EQ(Error::NONE, error);

    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle));
}

/**
 * Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
 */
TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
    auto info = mDummyDescriptorInfo;
    info.width = 1024;
    info.height = 1024;

    for (int i = 0; i < 2048; i++) {
        auto bufferHandle = mGralloc->allocate(info, true);
        mGralloc->freeBuffer(bufferHandle);
    }
}

/**
 * Test IMapper::importBuffer with invalid buffers.
 */
TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
    native_handle_t* invalidHandle = nullptr;
    mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
                << "importBuffer with nullptr did not fail with BAD_BUFFER";
    });

    invalidHandle = native_handle_create(0, 0);
    mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
                << "importBuffer with invalid handle did not fail with BAD_BUFFER";
    });
    native_handle_delete(invalidHandle);
}

/**
 * Test IMapper::freeBuffer with invalid buffers.
 */
TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) {
    native_handle_t* invalidHandle = nullptr;
    Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
    EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";

    invalidHandle = native_handle_create(0, 0);
    error = mGralloc->getMapper()->freeBuffer(invalidHandle);
    EXPECT_EQ(Error::BAD_BUFFER, error)
            << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
    native_handle_delete(invalidHandle);

    const native_handle_t* clonedBufferHandle;
    ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
    error = mGralloc->getMapper()->freeBuffer(const_cast<native_handle_t*>(clonedBufferHandle));
    EXPECT_EQ(Error::BAD_BUFFER, error)
            << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";

    mGralloc->freeBuffer(clonedBufferHandle);
}

/**
 * Test IMapper::lock and IMapper::unlock.
 */
TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
    const auto& info = mDummyDescriptorInfo;

    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.release())));

    // RGBA_8888
    fillRGBA8888(data, info.height, stride * 4, info.width * 4);

    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.release())));

    ASSERT_NO_FATAL_FAILURE(
            verifyRGBA8888(bufferHandle, data, info.height, stride * 4, info.width * 4));

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}

/**
 *  Test multiple operations associated with different color formats
 */
TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::YCRCB_420_SP;

    const native_handle_t* bufferHandle;
    uint32_t 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)};
    unique_fd fence;
    uint8_t* data;

    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
                                                                        region, fence.release())));

    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 + 1, cbData);
    ASSERT_EQ(2, yCbCr.chroma_step);

    fillYCbCrData(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.release())));

    ASSERT_NO_FATAL_FAILURE(
            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));

    verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}

TEST_P(GraphicsMapperHidlTest, YV12SubsampleMetadata) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::YV12;

    const native_handle_t* bufferHandle;
    uint32_t stride;
    ASSERT_NO_FATAL_FAILURE(
            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));

    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
                               static_cast<int32_t>(info.height)};
    unique_fd fence;
    ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release()));

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
    std::vector<PlaneLayout> planeLayouts;
    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));

    ASSERT_EQ(3, planeLayouts.size());

    auto yPlane = planeLayouts[0];
    auto crPlane = planeLayouts[1];
    auto cbPlane = planeLayouts[2];

    constexpr uint32_t kCbCrSubSampleFactor = 2;
    EXPECT_EQ(kCbCrSubSampleFactor, crPlane.horizontalSubsampling);
    EXPECT_EQ(kCbCrSubSampleFactor, crPlane.verticalSubsampling);

    EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.horizontalSubsampling);
    EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.verticalSubsampling);

    const long chromaSampleWidth = info.width / kCbCrSubSampleFactor;
    const long chromaSampleHeight = info.height / kCbCrSubSampleFactor;

    EXPECT_EQ(info.width, yPlane.widthInSamples);
    EXPECT_EQ(info.height, yPlane.heightInSamples);

    EXPECT_EQ(chromaSampleWidth, crPlane.widthInSamples);
    EXPECT_EQ(chromaSampleHeight, crPlane.heightInSamples);

    EXPECT_EQ(chromaSampleWidth, cbPlane.widthInSamples);
    EXPECT_EQ(chromaSampleHeight, cbPlane.heightInSamples);

    EXPECT_LE(crPlane.widthInSamples, crPlane.strideInBytes);
    EXPECT_LE(cbPlane.widthInSamples, cbPlane.strideInBytes);

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}

TEST_P(GraphicsMapperHidlTest, Lock_YV12) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::YV12;

    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.release())));

    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);

    fillYCbCrData(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.release())));

    ASSERT_NO_FATAL_FAILURE(
            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));

    verifyYCbCrData(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.release())));

    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);

    fillYCbCrData(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.release())));

    ASSERT_NO_FATAL_FAILURE(
            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));

    verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}

TEST_P(GraphicsMapperHidlTest, Lock_RAW10) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::RAW10;

    const native_handle_t* bufferHandle;
    uint32_t stride;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(
                                    info, true, Tolerance::kToleranceUnSupported, &stride));
    if (bufferHandle == nullptr) {
        GTEST_SUCCEED() << "RAW10 format is unsupported";
        return;
    }

    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
                               static_cast<int32_t>(info.height)};
    unique_fd fence;

    ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release()));

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
    std::vector<PlaneLayout> planeLayouts;
    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));

    ASSERT_EQ(1, planeLayouts.size());
    auto planeLayout = planeLayouts[0];

    EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
    EXPECT_EQ(1, planeLayout.horizontalSubsampling);
    EXPECT_EQ(1, planeLayout.verticalSubsampling);

    ASSERT_EQ(1, planeLayout.components.size());
    auto planeLayoutComponent = planeLayout.components[0];

    EXPECT_EQ(PlaneLayoutComponentType::RAW,
              static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
    EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}

TEST_P(GraphicsMapperHidlTest, Lock_RAW12) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::RAW12;

    const native_handle_t* bufferHandle;
    uint32_t stride;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(
                                    info, true, Tolerance::kToleranceUnSupported, &stride));
    if (bufferHandle == nullptr) {
        GTEST_SUCCEED() << "RAW12 format is unsupported";
        return;
    }

    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
                               static_cast<int32_t>(info.height)};
    unique_fd fence;

    ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release()));

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
    std::vector<PlaneLayout> planeLayouts;
    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));

    ASSERT_EQ(1, planeLayouts.size());
    auto planeLayout = planeLayouts[0];

    EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
    EXPECT_EQ(1, planeLayout.horizontalSubsampling);
    EXPECT_EQ(1, planeLayout.verticalSubsampling);

    ASSERT_EQ(1, planeLayout.components.size());
    auto planeLayoutComponent = planeLayout.components[0];

    EXPECT_EQ(PlaneLayoutComponentType::RAW,
              static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
    EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}

TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_P010) {
    if (base::GetIntProperty("ro.vendor.api_level", __ANDROID_API_FUTURE__) < __ANDROID_API_T__) {
        GTEST_SKIP() << "Old vendor grallocs may not support P010";
    }
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::YCBCR_P010;

    uint32_t stride;
    const native_handle_t* bufferHandle =
            mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride);

    if (::testing::Test::IsSkipped()) {
        GTEST_SKIP();
    }

    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.release())));

    YCbCr yCbCr;
    ASSERT_NO_FATAL_FAILURE(yCbCr = getAndroidYCbCr_P010(bufferHandle, data));

    constexpr uint32_t kCbCrSubSampleFactor = 2;
    ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.horizontalSubSampling);
    ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.verticalSubSampling);

    ASSERT_EQ(0, info.height % 2);

    // fill the data
    fillYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
                  yCbCr.verticalSubSampling);
    // verify the YCbCr data
    verifyYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
                    yCbCr.verticalSubSampling);

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}

/**
 * Test IMapper::unlock with bad access region
 */
TEST_P(GraphicsMapperHidlTest, LockBadAccessRegion) {
    const auto& info = mDummyDescriptorInfo;

    const native_handle_t* bufferHandle;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));

    const IMapper::Rect accessRegion{0, 0, static_cast<int32_t>(info.width * 2),
                                     static_cast<int32_t>(info.height * 2)};
    int acquireFence = -1;

    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
    hidl_handle acquireFenceHandle;
    if (acquireFence >= 0) {
        auto h = native_handle_init(acquireFenceStorage, 1, 0);
        h->data[0] = acquireFence;
        acquireFenceHandle = h;
    }

    auto buffer = const_cast<native_handle_t*>(bufferHandle);
    mGralloc->getMapper()->lock(buffer, info.usage, accessRegion, acquireFenceHandle,
                                [&](const auto& tmpError, const auto& /*tmpData*/) {
                                    EXPECT_EQ(Error::BAD_VALUE, tmpError)
                                            << "locking with a bad access region should fail";
                                });

    if (::testing::Test::HasFailure()) {
        if (acquireFence >= 0) {
            close(acquireFence);
        }

        int releaseFence = -1;
        ASSERT_NO_FATAL_FAILURE(releaseFence = mGralloc->unlock(bufferHandle));

        if (releaseFence >= 0) {
            close(releaseFence);
        }
    }
}

/**
 * Test IMapper::unlock with invalid buffers.
 */
TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
    native_handle_t* invalidHandle = nullptr;
    mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
                << "unlock with nullptr did not fail with BAD_BUFFER";
    });

    invalidHandle = native_handle_create(0, 0);
    mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
                << "unlock with invalid handle did not fail with BAD_BUFFER";
    });
    native_handle_delete(invalidHandle);

    ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
                                    mGralloc->allocate(mDummyDescriptorInfo, false)));
    mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
                << "unlock with un-imported handle did not fail with BAD_BUFFER";
    });
    mGralloc->freeBuffer(invalidHandle);

// disabled as it fails on many existing drivers
#if 0
  ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
                              mGralloc->allocate(mDummyDescriptorInfo, true)));
  mGralloc->getMapper()->unlock(
      invalidHandle, [&](const auto& tmpError, const auto&) {
        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
            << "unlock with unlocked handle did not fail with BAD_BUFFER";
      });
  mGralloc->freeBuffer(invalidHandle);
#endif
}

/**
 * Test IMapper::flush and IMapper::reread.
 */
TEST_P(GraphicsMapperHidlTest, FlushRereadBasic) {
    const auto& info = mDummyDescriptorInfo;

    const native_handle_t* rawHandle;
    uint32_t stride;
    ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false,
                                                           Tolerance::kToleranceStrict, &stride));

    const native_handle_t* writeBufferHandle;
    const native_handle_t* readBufferHandle;
    ASSERT_NO_FATAL_FAILURE(writeBufferHandle = mGralloc->importBuffer(rawHandle));
    ASSERT_NO_FATAL_FAILURE(readBufferHandle = mGralloc->importBuffer(rawHandle));

    // lock buffer for writing
    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
                               static_cast<int32_t>(info.height)};
    uint8_t* writeData;
    ASSERT_NO_FATAL_FAILURE(
            writeData = static_cast<uint8_t*>(mGralloc->lock(
                    writeBufferHandle, static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN), region,
                    -1)));

    uint8_t* readData;
    ASSERT_NO_FATAL_FAILURE(
            readData = static_cast<uint8_t*>(mGralloc->lock(
                    readBufferHandle, static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN), region,
                    -1)));

    fillRGBA8888(writeData, info.height, stride * 4, info.width * 4);

    unique_fd fence;
    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->flushLockedBuffer(writeBufferHandle)));
    if (fence >= 0) {
        ASSERT_EQ(0, sync_wait(fence, 3500));
    }

    ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle));

    ASSERT_NO_FATAL_FAILURE(
            verifyRGBA8888(readBufferHandle, readData, info.height, stride * 4, info.width * 4));

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(readBufferHandle)));

    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(writeBufferHandle)));
}

/**
 * Test IMapper::flushLockedBuffer with bad buffer
 */
TEST_P(GraphicsMapperHidlTest, FlushLockedBufferBadBuffer) {
    ASSERT_NO_FATAL_FAILURE(mGralloc->getMapper()->flushLockedBuffer(
            nullptr, [&](const auto& tmpError, const auto& /*tmpReleaseFence*/) {
                ASSERT_EQ(Error::BAD_BUFFER, tmpError);
            }));
}

/**
 * Test IMapper::rereadLockedBuffer with bad buffer
 */
TEST_P(GraphicsMapperHidlTest, RereadLockedBufferBadBuffer) {
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->getMapper()->rereadLockedBuffer(nullptr));
}

/**
 * Test IMapper::isSupported with required format RGBA_8888
 */
TEST_P(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
    const auto& info = mDummyDescriptorInfo;
    bool supported = false;

    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
    ASSERT_TRUE(supported);
}

/**
 * Test IMapper::isSupported with required format YV12
 */
TEST_P(GraphicsMapperHidlTest, IsSupportedYV12) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::YV12;
    bool supported = false;

    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
    ASSERT_TRUE(supported);
}

/**
 * Test IMapper::isSupported with optional format Y16
 */
TEST_P(GraphicsMapperHidlTest, IsSupportedY16) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::Y16;
    bool supported = false;

    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
}

/**
 * Test IMapper::isSupported with optional format R_8
 */
TEST_P(GraphicsMapperHidlTest, IsSupportedR8) {
    auto info = mDummyDescriptorInfo;
    info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(
            aidl::android::hardware::graphics::common::PixelFormat::R_8);
    bool supported = false;

    supported = mGralloc->isSupportedNoFailure(info);

    if (!supported) {
        GTEST_SUCCEED() << "R_8 is optional; unsupported so skipping allocation test";
        return;
    }

    BufferDescriptor descriptor;
    ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));

    constexpr uint32_t count = 1;
    std::vector<const native_handle_t*> bufferHandles;
    uint32_t stride;
    ASSERT_NO_FATAL_FAILURE(bufferHandles =
                                    mGralloc->allocate(descriptor, count, false,
                                                       Tolerance::kToleranceStrict, &stride));

    EXPECT_LE(info.width, stride) << "invalid buffer stride";
    EXPECT_EQ(1u, bufferHandles.size());

    for (auto bufferHandle : bufferHandles) {
        mGralloc->freeBuffer(bufferHandle);
    }
}

/**
 * Test IMapper::get(BufferId)
 */
TEST_P(GraphicsMapperHidlTest, GetBufferId) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BufferId,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                uint64_t bufferId = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeBufferId(vec, &bufferId));
            });
}

/**
 * Test IMapper::get(Name)
 */
TEST_P(GraphicsMapperHidlTest, GetName) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Name,
            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
                std::string name;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeName(vec, &name));
                EXPECT_EQ(info.name, name);
            });
}

/**
 * Test IMapper::get(Width)
 */
TEST_P(GraphicsMapperHidlTest, GetWidth) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Width,
            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
                uint64_t width = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeWidth(vec, &width));
                EXPECT_EQ(info.width, width);
            });
}

/**
 * Test IMapper::get(Height)
 */
TEST_P(GraphicsMapperHidlTest, GetHeight) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Height,
            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
                uint64_t height = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeHeight(vec, &height));
                EXPECT_EQ(info.height, height);
            });
}

/**
 * Test IMapper::get(LayerCount)
 */
TEST_P(GraphicsMapperHidlTest, GetLayerCount) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_LayerCount,
            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
                uint64_t layerCount = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeLayerCount(vec, &layerCount));
                EXPECT_EQ(info.layerCount, layerCount);
            });
}

/**
 * Test IMapper::get(PixelFormatRequested)
 */
TEST_P(GraphicsMapperHidlTest, GetPixelFormatRequested) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested,
            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
                PixelFormat pixelFormatRequested = PixelFormat::BLOB;
                ASSERT_EQ(NO_ERROR,
                          gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested));
                EXPECT_EQ(info.format, pixelFormatRequested);
            });
}

/**
 * Test IMapper::get(PixelFormatFourCC)
 */
TEST_P(GraphicsMapperHidlTest, GetPixelFormatFourCC) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                uint32_t pixelFormatFourCC = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC));
            });
}

/**
 * Test IMapper::get(PixelFormatModifier)
 */
TEST_P(GraphicsMapperHidlTest, GetPixelFormatModifier) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                uint64_t pixelFormatModifier = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier));
            });
}

/**
 * Test IMapper::get(Usage)
 */
TEST_P(GraphicsMapperHidlTest, GetUsage) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage,
            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
                uint64_t usage = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &usage));
                EXPECT_EQ(info.usage, usage);
            });
}

/**
 * Test IMapper::get(AllocationSize)
 */
TEST_P(GraphicsMapperHidlTest, GetAllocationSize) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                uint64_t allocationSize = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize));
            });
}

/**
 * Test IMapper::get(ProtectedContent)
 */
TEST_P(GraphicsMapperHidlTest, GetProtectedContent) {
    auto info = mDummyDescriptorInfo;
    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;

    const native_handle_t* bufferHandle = nullptr;
    bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceAllErrors);
    if (!bufferHandle) {
        GTEST_SUCCEED() << "unable to allocate protected content";
        return;
    }

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));

    uint64_t protectedContent = 0;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent));
    EXPECT_EQ(1, protectedContent);
}

/**
 * Test IMapper::get(Compression)
 */
TEST_P(GraphicsMapperHidlTest, GetCompression) {
    auto info = mDummyDescriptorInfo;
    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);

    testGet(info, gralloc4::MetadataType_Compression,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &compression));

                EXPECT_EQ(gralloc4::Compression_None.name, compression.name);
                EXPECT_EQ(gralloc4::Compression_None.value, compression.value);
            });
}

/**
 * Test IMapper::get(Interlaced)
 */
TEST_P(GraphicsMapperHidlTest, GetInterlaced) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                ExtendableType interlaced = gralloc4::Interlaced_TopBottom;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced));

                EXPECT_EQ(gralloc4::Interlaced_None.name, interlaced.name);
                EXPECT_EQ(gralloc4::Interlaced_None.value, interlaced.value);
            });
}

/**
 * Test IMapper::get(ChromaSiting)
 */
TEST_P(GraphicsMapperHidlTest, GetChromaSiting) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                ExtendableType chromaSiting = gralloc4::ChromaSiting_Unknown;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting));

                EXPECT_EQ(gralloc4::ChromaSiting_None.name, chromaSiting.name);
                EXPECT_EQ(gralloc4::ChromaSiting_None.value, chromaSiting.value);
            });
}

/**
 * Test IMapper::get(PlaneLayouts)
 */
TEST_P(GraphicsMapperHidlTest, GetPlaneLayouts) {
    const native_handle_t* bufferHandle = nullptr;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));

    std::vector<PlaneLayout> planeLayouts;
    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));

    ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(planeLayouts));
}

/**
 * Test IMapper::get(Crop)
 */
TEST_P(GraphicsMapperHidlTest, GetCrop) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::RGBA_8888;
    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);

    testGet(info, gralloc4::MetadataType_Crop,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::vector<aidl::android::hardware::graphics::common::Rect> crops;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &crops));
                EXPECT_EQ(1, crops.size());
            });
}

/**
 * Test IMapper::get(Dataspace)
 */
TEST_P(GraphicsMapperHidlTest, GetDataspace) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                Dataspace dataspace = Dataspace::DISPLAY_P3;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace));
                EXPECT_EQ(Dataspace::UNKNOWN, dataspace);
            });
}

/**
 * Test IMapper::get(BlendMode)
 */
TEST_P(GraphicsMapperHidlTest, GetBlendMode) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                BlendMode blendMode = BlendMode::NONE;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode));
                EXPECT_EQ(BlendMode::INVALID, blendMode);
            });
}

/**
 * Test IMapper::get(Smpte2086)
 */
TEST_P(GraphicsMapperHidlTest, GetSmpte2086) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::optional<Smpte2086> smpte2086;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
                EXPECT_FALSE(smpte2086.has_value());
            });
}

/**
 * Test IMapper::get(Cta861_3)
 */
TEST_P(GraphicsMapperHidlTest, GetCta861_3) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::optional<Cta861_3> cta861_3;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
                EXPECT_FALSE(cta861_3.has_value());
            });
}

/**
 * Test IMapper::get(Smpte2094_40)
 */
TEST_P(GraphicsMapperHidlTest, GetSmpte2094_40) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::optional<std::vector<uint8_t>> smpte2094_40;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
                EXPECT_FALSE(smpte2094_40.has_value());
            });
}

/**
 * Test IMapper::get(Smpte2094_10)
 */
TEST_P(GraphicsMapperHidlTest, GetSmpte2094_10) {
    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_10,
            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::optional<std::vector<uint8_t>> smpte2094_10;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_10(vec, &smpte2094_10));
                EXPECT_FALSE(smpte2094_10.has_value());
            });
}

/**
 * Test IMapper::get(metadata) with a bad buffer
 */
TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) {
    const native_handle_t* bufferHandle = nullptr;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_BufferId, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Name, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Width, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Height, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_LayerCount, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_AllocationSize, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_Compression, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_Interlaced, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_ChromaSiting, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Crop, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2086, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_Cta861_3, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, &vec));
    ASSERT_EQ(0, vec.size());
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_10, &vec));
    ASSERT_EQ(0, vec.size());
}

/**
 * Test IMapper::get(metadata) for unsupported metadata
 */
TEST_P(GraphicsMapperHidlTest, GetUnsupportedMetadata) {
    const native_handle_t* bufferHandle = nullptr;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));

    MetadataType metadataTypeFake = {"FAKE", 1};

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->get(bufferHandle, metadataTypeFake, &vec));
    ASSERT_EQ(0, vec.size());
}

/**
 * Test IMapper::get(metadata) for unsupported standard metadata
 */
TEST_P(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) {
    const native_handle_t* bufferHandle = nullptr;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));

    MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999};

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->get(bufferHandle, metadataTypeFake, &vec));
    ASSERT_EQ(0, vec.size());
}

/**
 * Test IMapper::set(PixelFormatFourCC)
 */
TEST_P(GraphicsMapperHidlTest, SetPixelFormatFourCC) {
    uint32_t pixelFormatFourCC = 0x34324142;  // DRM_FORMAT_BGRA8888
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatFourCC(pixelFormatFourCC, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                uint32_t realPixelFormatFourCC = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &realPixelFormatFourCC));
                EXPECT_EQ(pixelFormatFourCC, realPixelFormatFourCC);
            });
}

/**
 * Test IMapper::set(PixelFormatModifier)
 */
TEST_P(GraphicsMapperHidlTest, SetPixelFormatModifier) {
    uint64_t pixelFormatModifier = 10;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatModifier(pixelFormatModifier, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                uint64_t realPixelFormatModifier = 0;
                ASSERT_EQ(NO_ERROR,
                          gralloc4::decodePixelFormatModifier(vec, &realPixelFormatModifier));
                EXPECT_EQ(pixelFormatModifier, realPixelFormatModifier);
            });
}

/**
 * Test IMapper::set(AllocationSize)
 */
TEST_P(GraphicsMapperHidlTest, SetAllocationSize) {
    uint64_t allocationSize = 1000000;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeAllocationSize(allocationSize, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                uint64_t realAllocationSize = 0;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &realAllocationSize));
                EXPECT_EQ(allocationSize, realAllocationSize);
            });
}

/**
 * Test IMapper::set(ProtectedContent)
 */
TEST_P(GraphicsMapperHidlTest, SetProtectedContent) {
    const native_handle_t* bufferHandle = nullptr;
    auto info = mDummyDescriptorInfo;
    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;

    bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceAllErrors);
    if (!bufferHandle) {
        GTEST_SUCCEED() << "unable to allocate protected content";
        return;
    }

    uint64_t protectedContent = 0;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeProtectedContent(protectedContent, &vec));

    Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec);
    ASSERT_EQ(err, Error::UNSUPPORTED);
    vec.resize(0);

    uint64_t realProtectedContent = 0;
    ASSERT_EQ(Error::NONE,
              mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));
    ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &realProtectedContent));
    EXPECT_EQ(1, realProtectedContent);
}

/**
 * Test IMapper::set(Compression)
 */
TEST_P(GraphicsMapperHidlTest, SetCompression) {
    auto info = mDummyDescriptorInfo;
    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);

    ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeCompression(compression, &vec));

    testSet(info, gralloc4::MetadataType_Compression, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                ExtendableType realCompression = gralloc4::Compression_None;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &realCompression));

                EXPECT_EQ(compression.name, realCompression.name);
                EXPECT_EQ(compression.value, realCompression.value);
            });
}

/**
 * Test IMapper::set(Interlaced)
 */
TEST_P(GraphicsMapperHidlTest, SetInterlaced) {
    ExtendableType interlaced = gralloc4::Interlaced_RightLeft;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeInterlaced(interlaced, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                ExtendableType realInterlaced = gralloc4::Interlaced_None;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &realInterlaced));

                EXPECT_EQ(interlaced.name, realInterlaced.name);
                EXPECT_EQ(interlaced.value, realInterlaced.value);
            });
}

/**
 * Test IMapper::set(ChromaSiting)
 */
TEST_P(GraphicsMapperHidlTest, SetChromaSiting) {
    ExtendableType chromaSiting = gralloc4::ChromaSiting_SitedInterstitial;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeChromaSiting(chromaSiting, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                ExtendableType realChromaSiting = gralloc4::ChromaSiting_None;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &realChromaSiting));

                EXPECT_EQ(chromaSiting.name, realChromaSiting.name);
                EXPECT_EQ(chromaSiting.value, realChromaSiting.value);
            });
}

/**
 * Test IMapper::set(PlaneLayouts)
 */
TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) {
    const native_handle_t* bufferHandle = nullptr;
    auto info = mDummyDescriptorInfo;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));

    std::vector<PlaneLayout> planeLayouts;
    PlaneLayout planeLayoutA;
    PlaneLayout planeLayoutRGB;
    PlaneLayoutComponent component;

    planeLayoutA.offsetInBytes = 0;
    planeLayoutA.sampleIncrementInBits = 8;
    planeLayoutA.strideInBytes = info.width + 20;
    planeLayoutA.widthInSamples = info.width;
    planeLayoutA.heightInSamples = info.height;
    planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * info.height;
    planeLayoutA.horizontalSubsampling = 1;
    planeLayoutA.verticalSubsampling = 1;

    component.type = gralloc4::PlaneLayoutComponentType_A;
    component.offsetInBits = 0;
    component.sizeInBits = 8;
    planeLayoutA.components.push_back(component);

    planeLayouts.push_back(planeLayoutA);

    planeLayoutRGB.offsetInBytes = 0;
    planeLayoutRGB.sampleIncrementInBits = 24;
    planeLayoutRGB.strideInBytes = info.width + 20;
    planeLayoutRGB.widthInSamples = info.width;
    planeLayoutRGB.heightInSamples = info.height;
    planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * info.height;
    planeLayoutRGB.horizontalSubsampling = 1;
    planeLayoutRGB.verticalSubsampling = 1;

    component.type = gralloc4::PlaneLayoutComponentType_R;
    planeLayoutRGB.components.push_back(component);
    component.type = gralloc4::PlaneLayoutComponentType_G;
    planeLayoutRGB.components.push_back(component);
    component.type = gralloc4::PlaneLayoutComponentType_B;
    planeLayoutRGB.components.push_back(component);

    planeLayouts.push_back(planeLayoutRGB);

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodePlaneLayouts(planeLayouts, &vec));

    Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    std::vector<PlaneLayout> realPlaneLayouts;
    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &realPlaneLayouts));

    ASSERT_EQ(planeLayouts.size(), realPlaneLayouts.size());

    for (int i = 0; i < realPlaneLayouts.size(); i++) {
        const auto& planeLayout = planeLayouts[i];
        const auto& realPlaneLayout = realPlaneLayouts[i];

        EXPECT_EQ(planeLayout.offsetInBytes, realPlaneLayout.offsetInBytes);
        EXPECT_EQ(planeLayout.sampleIncrementInBits, realPlaneLayout.sampleIncrementInBits);
        EXPECT_EQ(planeLayout.strideInBytes, realPlaneLayout.strideInBytes);
        EXPECT_EQ(planeLayout.widthInSamples, realPlaneLayout.widthInSamples);
        EXPECT_EQ(planeLayout.heightInSamples, realPlaneLayout.heightInSamples);
        EXPECT_LE(planeLayout.totalSizeInBytes, realPlaneLayout.totalSizeInBytes);
        EXPECT_EQ(planeLayout.horizontalSubsampling, realPlaneLayout.horizontalSubsampling);
        EXPECT_EQ(planeLayout.verticalSubsampling, realPlaneLayout.verticalSubsampling);

        ASSERT_EQ(planeLayout.components.size(), realPlaneLayout.components.size());

        for (int j = 0; j < realPlaneLayout.components.size(); j++) {
            const auto& component = planeLayout.components[j];
            const auto& realComponent = realPlaneLayout.components[j];

            EXPECT_EQ(component.type.name, realComponent.type.name);
            EXPECT_EQ(component.type.value, realComponent.type.value);
            EXPECT_EQ(component.sizeInBits, realComponent.sizeInBits);
            EXPECT_EQ(component.offsetInBits, realComponent.offsetInBits);
        }
    }
}

/**
 * Test IMapper::set(Crop)
 */
TEST_P(GraphicsMapperHidlTest, SetCrop) {
    std::vector<aidl::android::hardware::graphics::common::Rect> crops{{0, 0, 32, 32}};
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeCrop(crops, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Crop, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::vector<aidl::android::hardware::graphics::common::Rect> realCrops;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &realCrops));
                ASSERT_EQ(1, realCrops.size());
                ASSERT_EQ(crops.front().left, realCrops.front().left);
                ASSERT_EQ(crops.front().top, realCrops.front().top);
                ASSERT_EQ(crops.front().right, realCrops.front().right);
                ASSERT_EQ(crops.front().bottom, realCrops.front().bottom);
            });
}

/**
 * Test IMapper::set(Dataspace)
 */
TEST_P(GraphicsMapperHidlTest, SetDataspace) {
    Dataspace dataspace = Dataspace::SRGB_LINEAR;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                Dataspace realDataspace = Dataspace::UNKNOWN;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &realDataspace));
                EXPECT_EQ(dataspace, realDataspace);
            });
}

/**
 * Test IMapper::set(BlendMode)
 */
TEST_P(GraphicsMapperHidlTest, SetBlendMode) {
    BlendMode blendMode = BlendMode::PREMULTIPLIED;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeBlendMode(blendMode, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                BlendMode realBlendMode = BlendMode::INVALID;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &realBlendMode));
                EXPECT_EQ(blendMode, realBlendMode);
            });
}

/**
 * Test IMapper::set(Smpte2086)
 */
TEST_P(GraphicsMapperHidlTest, SetSmpte2086) {
    /**
     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
     * the D65 white point and the SRGB transfer functions.
     * Rendering Intent: Colorimetric
     * Primaries:
     *                  x       y
     *  green           0.265   0.690
     *  blue            0.150   0.060
     *  red             0.680   0.320
     *  white (D65)     0.3127  0.3290
     */
    Smpte2086 smpte2086;
    smpte2086.primaryRed.x = 0.680;
    smpte2086.primaryRed.y = 0.320;
    smpte2086.primaryGreen.x = 0.265;
    smpte2086.primaryGreen.y = 0.690;
    smpte2086.primaryBlue.x = 0.150;
    smpte2086.primaryBlue.y = 0.060;
    smpte2086.whitePoint.x = 0.3127;
    smpte2086.whitePoint.y = 0.3290;
    smpte2086.maxLuminance = 100.0;
    smpte2086.minLuminance = 0.1;

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::optional<Smpte2086> realSmpte2086;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086));
                ASSERT_TRUE(realSmpte2086.has_value());
                EXPECT_TRUE(isEqual(smpte2086.primaryRed.x, realSmpte2086->primaryRed.x));
                EXPECT_TRUE(isEqual(smpte2086.primaryRed.y, realSmpte2086->primaryRed.y));
                EXPECT_TRUE(isEqual(smpte2086.primaryGreen.x, realSmpte2086->primaryGreen.x));
                EXPECT_TRUE(isEqual(smpte2086.primaryGreen.y, realSmpte2086->primaryGreen.y));
                EXPECT_TRUE(isEqual(smpte2086.primaryBlue.x, realSmpte2086->primaryBlue.x));
                EXPECT_TRUE(isEqual(smpte2086.primaryBlue.y, realSmpte2086->primaryBlue.y));
                EXPECT_TRUE(isEqual(smpte2086.whitePoint.x, realSmpte2086->whitePoint.x));
                EXPECT_TRUE(isEqual(smpte2086.whitePoint.y, realSmpte2086->whitePoint.y));
                EXPECT_TRUE(isEqual(smpte2086.maxLuminance, realSmpte2086->maxLuminance));
                EXPECT_TRUE(isEqual(smpte2086.minLuminance, realSmpte2086->minLuminance));
            });
}

/**
 * Test IMapper::set(Cta8613)
 */
TEST_P(GraphicsMapperHidlTest, SetCta861_3) {
    Cta861_3 cta861_3;
    cta861_3.maxContentLightLevel = 78.0;
    cta861_3.maxFrameAverageLightLevel = 62.0;

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec));

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::optional<Cta861_3> realCta861_3;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3));
                ASSERT_TRUE(realCta861_3.has_value());
                EXPECT_TRUE(
                        isEqual(cta861_3.maxContentLightLevel, realCta861_3->maxContentLightLevel));
                EXPECT_TRUE(isEqual(cta861_3.maxFrameAverageLightLevel,
                                    realCta861_3->maxFrameAverageLightLevel));
            });
}

/**
 * Test IMapper::set(Smpte2094_40)
 */
TEST_P(GraphicsMapperHidlTest, SetSmpte2094_40) {
    hidl_vec<uint8_t> vec;

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::optional<std::vector<uint8_t>> realSmpte2094_40;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40));
                EXPECT_FALSE(realSmpte2094_40.has_value());
            });
}

/**
 * Test IMapper::set(Smpte2094_10)
 */
TEST_P(GraphicsMapperHidlTest, SetSmpte2094_10) {
    hidl_vec<uint8_t> vec;

    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_10, vec,
            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
                std::optional<std::vector<uint8_t>> realSmpte2094_10;
                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10));
                EXPECT_FALSE(realSmpte2094_10.has_value());
            });
}

/**
 * Test IMapper::set(metadata) with a bad buffer
 */
TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) {
    const native_handle_t* bufferHandle = nullptr;
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec));
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Compression, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Interlaced, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec));
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Crop, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec));
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_10, vec));
}

/**
 * Test get::metadata with cloned native_handle
 */
TEST_P(GraphicsMapperHidlTest, GetMetadataClonedHandle) {
    const native_handle_t* bufferHandle = nullptr;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));

    const auto dataspace = Dataspace::SRGB_LINEAR;
    {
        hidl_vec<uint8_t> metadata;
        ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &metadata));

        Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, metadata);
        if (err == Error::UNSUPPORTED) {
            GTEST_SUCCEED() << "setting this metadata is unsupported";
            return;
        }
        ASSERT_EQ(Error::NONE, err);
    }

    const native_handle_t* importedHandle;
    {
        auto clonedHandle = native_handle_clone(bufferHandle);
        ASSERT_NO_FATAL_FAILURE(importedHandle = mGralloc->importBuffer(clonedHandle));
        native_handle_close(clonedHandle);
        native_handle_delete(clonedHandle);
    }

    Dataspace realSpace = Dataspace::UNKNOWN;
    {
        hidl_vec<uint8_t> metadata;
        ASSERT_EQ(Error::NONE,
                  mGralloc->get(importedHandle, gralloc4::MetadataType_Dataspace, &metadata));
        ASSERT_NO_FATAL_FAILURE(gralloc4::decodeDataspace(metadata, &realSpace));
    }

    EXPECT_EQ(dataspace, realSpace);
}

/**
 * Test set::metadata with cloned native_handle
 */
TEST_P(GraphicsMapperHidlTest, SetMetadataClonedHandle) {
    const native_handle_t* bufferHandle = nullptr;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));

    const native_handle_t* importedHandle;
    {
        auto clonedHandle = native_handle_clone(bufferHandle);
        ASSERT_NO_FATAL_FAILURE(importedHandle = mGralloc->importBuffer(clonedHandle));
        native_handle_close(clonedHandle);
        native_handle_delete(clonedHandle);
    }

    const auto dataspace = Dataspace::SRGB_LINEAR;
    {
        hidl_vec<uint8_t> metadata;
        ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &metadata));

        Error err = mGralloc->set(importedHandle, gralloc4::MetadataType_Dataspace, metadata);
        if (err == Error::UNSUPPORTED) {
            GTEST_SUCCEED() << "setting this metadata is unsupported";
            return;
        }
        ASSERT_EQ(Error::NONE, err);
    }

    Dataspace realSpace = Dataspace::UNKNOWN;
    {
        hidl_vec<uint8_t> metadata;
        ASSERT_EQ(Error::NONE,
                  mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &metadata));
        ASSERT_NO_FATAL_FAILURE(gralloc4::decodeDataspace(metadata, &realSpace));
    }

    EXPECT_EQ(dataspace, realSpace);
}

/**
 * Test IMapper::set(metadata) for constant metadata
 */
TEST_P(GraphicsMapperHidlTest, SetConstantMetadata) {
    const native_handle_t* bufferHandle = nullptr;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));

    uint64_t bufferId = 2;
    hidl_vec<uint8_t> bufferIdVec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeBufferId(bufferId, &bufferIdVec));
    ASSERT_EQ(Error::BAD_VALUE,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, bufferIdVec));

    std::string name{"new name"};
    hidl_vec<uint8_t> nameVec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeName(name, &nameVec));
    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, nameVec));

    uint64_t width = 32;
    hidl_vec<uint8_t> widthVec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeWidth(width, &widthVec));
    ASSERT_EQ(Error::BAD_VALUE,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, widthVec));

    uint64_t height = 32;
    hidl_vec<uint8_t> heightVec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeHeight(height, &heightVec));
    ASSERT_EQ(Error::BAD_VALUE,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, heightVec));

    uint64_t layerCount = 2;
    hidl_vec<uint8_t> layerCountVec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeLayerCount(layerCount, &layerCountVec));
    ASSERT_EQ(Error::BAD_VALUE,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, layerCountVec));

    hardware::graphics::common::V1_2::PixelFormat pixelFormatRequested = PixelFormat::BLOB;
    hidl_vec<uint8_t> pixelFormatRequestedVec;
    ASSERT_EQ(NO_ERROR,
              gralloc4::encodePixelFormatRequested(pixelFormatRequested, &pixelFormatRequestedVec));
    ASSERT_EQ(Error::BAD_VALUE,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested,
                            pixelFormatRequestedVec));

    uint64_t usage = 0;
    hidl_vec<uint8_t> usageVec;
    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &usageVec));
    ASSERT_EQ(Error::BAD_VALUE,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, usageVec));
}

/**
 * Test IMapper::set(metadata) for bad metadata
 */
TEST_P(GraphicsMapperHidlTest, SetBadMetadata) {
    const native_handle_t* bufferHandle = nullptr;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Compression, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Interlaced, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec));
    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Crop, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));

    // Keep optional metadata types below and populate the encoded metadata vec
    // with some arbitrary different metadata because the common gralloc4::decode*()
    // functions do not distinguish between an empty vec and bad value.
    if (base::GetIntProperty("ro.vendor.api_level", __ANDROID_API_FUTURE__) >= __ANDROID_API_T__) {
        // Some old grallocs shipped with broken validation.
        ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(Dataspace::SRGB_LINEAR, &vec));
        ASSERT_EQ(Error::UNSUPPORTED,
                  mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
        ASSERT_EQ(Error::UNSUPPORTED,
                  mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
    }
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(BufferId)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) {
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                    gralloc4::MetadataType_BufferId, &vec));
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Name)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) {
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
                                   mDummyDescriptorInfo, gralloc4::MetadataType_Name, &vec));

    std::string name;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeName(vec, &name));
    EXPECT_EQ(mDummyDescriptorInfo.name, name);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Width)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) {
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
                                   mDummyDescriptorInfo, gralloc4::MetadataType_Width, &vec));

    uint64_t width = 0;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeWidth(vec, &width));
    EXPECT_EQ(mDummyDescriptorInfo.width, width);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Height)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) {
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
                                   mDummyDescriptorInfo, gralloc4::MetadataType_Height, &vec));

    uint64_t height = 0;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeHeight(vec, &height));
    EXPECT_EQ(mDummyDescriptorInfo.height, height);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(PixelFormatRequested)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) {
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE,
              mGralloc->getFromBufferDescriptorInfo(
                      mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested, &vec));

    PixelFormat pixelFormatRequested = PixelFormat::BLOB;
    ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested));
    EXPECT_EQ(mDummyDescriptorInfo.format, pixelFormatRequested);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(PixelFormatFourCC)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) {
    hidl_vec<uint8_t> vec;
    Error err = mGralloc->getFromBufferDescriptorInfo(
            mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    uint32_t pixelFormatFourCC = 0;
    ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC));
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(PixelFormatModifier)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) {
    hidl_vec<uint8_t> vec;
    Error err = mGralloc->getFromBufferDescriptorInfo(
            mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    uint64_t pixelFormatModifier = 0;
    ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier));
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Usage)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) {
    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
                                   mDummyDescriptorInfo, gralloc4::MetadataType_Usage, &vec));

    uint64_t usage = 0;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &usage));
    EXPECT_EQ(mDummyDescriptorInfo.usage, usage);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(AllocationSize)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) {
    hidl_vec<uint8_t> vec;
    Error err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                      gralloc4::MetadataType_AllocationSize, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    uint64_t allocationSize = 0;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize));
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(ProtectedContent)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) {
    auto info = mDummyDescriptorInfo;
    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;

    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_ProtectedContent,
                                                     &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    uint64_t protectedContent = 0;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent));
    EXPECT_EQ(1, protectedContent);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Compression)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) {
    auto info = mDummyDescriptorInfo;
    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);

    hidl_vec<uint8_t> vec;
    auto err =
            mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_Compression, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &compression));

    EXPECT_EQ(gralloc4::Compression_None.name, compression.name);
    EXPECT_EQ(gralloc4::Compression_None.value, compression.value);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Interlaced)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) {
    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                     gralloc4::MetadataType_Interlaced, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    ExtendableType interlaced = gralloc4::Interlaced_TopBottom;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced));

    EXPECT_EQ(gralloc4::Interlaced_None.name, interlaced.name);
    EXPECT_EQ(gralloc4::Interlaced_None.value, interlaced.value);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(ChromaSiting)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) {
    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                     gralloc4::MetadataType_ChromaSiting, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    ExtendableType chromaSiting = gralloc4::ChromaSiting_CositedHorizontal;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting));

    EXPECT_EQ(gralloc4::ChromaSiting_None.name, chromaSiting.name);
    EXPECT_EQ(gralloc4::ChromaSiting_None.value, chromaSiting.value);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(PlaneLayouts)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) {
    hidl_vec<uint8_t> vec;
    const auto ret = mGralloc->getFromBufferDescriptorInfo(
            mDummyDescriptorInfo, gralloc4::MetadataType_PlaneLayouts, &vec);
    if (ret == Error::NONE) {
        std::vector<PlaneLayout> planeLayouts;
        ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
        ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(planeLayouts));
    } else {
        ASSERT_EQ(Error::UNSUPPORTED, ret);
    }
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Crop)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCrop) {
    auto info = mDummyDescriptorInfo;
    info.format = PixelFormat::RGBA_8888;
    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);

    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_Crop, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    std::vector<aidl::android::hardware::graphics::common::Rect> crops;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &crops));
    EXPECT_EQ(1, crops.size());
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Dataspace)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) {
    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                     gralloc4::MetadataType_Dataspace, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    Dataspace dataspace = Dataspace::DISPLAY_P3;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace));
    EXPECT_EQ(Dataspace::UNKNOWN, dataspace);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(BlendMode)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) {
    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                     gralloc4::MetadataType_BlendMode, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    BlendMode blendMode = BlendMode::COVERAGE;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode));
    EXPECT_EQ(BlendMode::INVALID, blendMode);
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Smpte2086)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2086) {
    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                     gralloc4::MetadataType_Smpte2086, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    std::optional<Smpte2086> smpte2086;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
    EXPECT_FALSE(smpte2086.has_value());
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Cta861_3)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCta861_3) {
    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                     gralloc4::MetadataType_Cta861_3, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    std::optional<Cta861_3> cta861_3;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
    EXPECT_FALSE(cta861_3.has_value());
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_40)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) {
    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                     gralloc4::MetadataType_Smpte2094_40, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    std::optional<std::vector<uint8_t>> smpte2094_40;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
    EXPECT_FALSE(smpte2094_40.has_value());
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_10)
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_10) {
    hidl_vec<uint8_t> vec;
    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
                                                     gralloc4::MetadataType_Smpte2094_10, &vec);
    if (err == Error::UNSUPPORTED) {
        GTEST_SUCCEED() << "setting this metadata is unsupported";
        return;
    }
    ASSERT_EQ(err, Error::NONE);

    std::optional<std::vector<uint8_t>> smpte2094_10;
    ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_10(vec, &smpte2094_10));
    EXPECT_FALSE(smpte2094_10.has_value());
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) {
    MetadataType metadataTypeFake = {"FAKE", 1};

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, metadataTypeFake, &vec));
    ASSERT_EQ(0, vec.size());
}

/**
 * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported standard metadata
 */
TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMetadata) {
    MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999};

    hidl_vec<uint8_t> vec;
    ASSERT_EQ(Error::UNSUPPORTED,
              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, metadataTypeFake, &vec));
    ASSERT_EQ(0, vec.size());
}

/**
 * Test IMapper::listSupportedMetadataTypes()
 */
TEST_P(GraphicsMapperHidlTest, ListSupportedMetadataTypes) {
    hidl_vec<IMapper::MetadataTypeDescription> descriptions;
    mGralloc->getMapper()->listSupportedMetadataTypes(
            [&](const auto& tmpError, const auto& tmpDescriptions) {
                ASSERT_EQ(Error::NONE, tmpError);
                descriptions = tmpDescriptions;
            });

    std::set<StandardMetadataType> foundMetadataTypes;

    std::set<StandardMetadataType> notSettableMetadataTypes{
            StandardMetadataType::BUFFER_ID,   StandardMetadataType::NAME,
            StandardMetadataType::WIDTH,       StandardMetadataType::HEIGHT,
            StandardMetadataType::LAYER_COUNT, StandardMetadataType::PIXEL_FORMAT_REQUESTED,
            StandardMetadataType::USAGE};

    ASSERT_LE(sRequiredMetadataTypes.size(), descriptions.size());

    for (const auto& description : descriptions) {
        const auto& metadataType = description.metadataType;

        if (!gralloc4::isStandardMetadataType(metadataType)) {
            EXPECT_GT(description.description.size(), 0);
            continue;
        }

        StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType);

        if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) {
            continue;
        }

        ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end());
        foundMetadataTypes.insert(type);

        ASSERT_TRUE(description.isGettable);

        if (notSettableMetadataTypes.find(type) != notSettableMetadataTypes.end()) {
            ASSERT_FALSE(description.isSettable);
        }
    }

    ASSERT_EQ(sRequiredMetadataTypes, foundMetadataTypes);
}

/**
 * Test IMapper::dumpBuffer()
 */
TEST_P(GraphicsMapperHidlTest, DumpBuffer) {
    const native_handle_t* bufferHandle = nullptr;
    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
    auto buffer = const_cast<native_handle_t*>(bufferHandle);

    IMapper::BufferDump bufferDump;
    mGralloc->getMapper()->dumpBuffer(buffer, [&](const auto& tmpError, const auto& tmpBufferDump) {
        ASSERT_EQ(Error::NONE, tmpError);
        bufferDump = tmpBufferDump;
    });

    ASSERT_NO_FATAL_FAILURE(verifyBufferDump(bufferDump, buffer));
}

/**
 * Test IMapper::dumpBuffer() with an invalid buffer
 */
TEST_P(GraphicsMapperHidlTest, DumpBufferNullBuffer) {
    native_handle_t* bufferHandle = nullptr;
    auto buffer = const_cast<native_handle_t*>(bufferHandle);

    mGralloc->getMapper()->dumpBuffer(buffer,
                                      [&](const auto& tmpError, const auto& /*tmpBufferDump*/) {
                                          ASSERT_EQ(Error::BAD_BUFFER, tmpError);
                                      });
}

/**
 * Test IMapper::dumpBuffer() multiple
 */
TEST_P(GraphicsMapperHidlTest, DumpBuffers) {
    size_t bufferCount = 10;

    for (int i = 0; i < bufferCount; i++) {
        ASSERT_NO_FATAL_FAILURE(mGralloc->allocate(mDummyDescriptorInfo, true));
    }

    hidl_vec<IMapper::BufferDump> bufferDump;
    mGralloc->getMapper()->dumpBuffers([&](const auto& tmpError, const auto& tmpBufferDump) {
        ASSERT_EQ(Error::NONE, tmpError);
        bufferDump = tmpBufferDump;
    });

    ASSERT_EQ(bufferCount, bufferDump.size());

    for (const auto& dump : bufferDump) {
        ASSERT_NO_FATAL_FAILURE(verifyBufferDump(dump));
    }
}

/**
 * Test IMapper::getReservedRegion()
 */
TEST_P(GraphicsMapperHidlTest, GetReservedRegion) {
    const native_handle_t* bufferHandle = nullptr;
    auto info = mDummyDescriptorInfo;

    const int pageSize = getpagesize();
    ASSERT_GE(pageSize, 0);
    std::vector<uint64_t> requestedReservedSizes{1, 10, 333, static_cast<uint64_t>(pageSize) / 2,
                                                 static_cast<uint64_t>(pageSize)};

    for (auto requestedReservedSize : requestedReservedSizes) {
        info.reservedSize = requestedReservedSize;

        ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));

        void* reservedRegion = nullptr;
        uint64_t reservedSize = 0;
        ASSERT_EQ(Error::NONE,
                  mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize));
        ASSERT_NE(nullptr, reservedRegion);
        ASSERT_EQ(requestedReservedSize, reservedSize);

        uint8_t testValue = 1;
        memset(reservedRegion, testValue, reservedSize);
        for (uint64_t i = 0; i < reservedSize; i++) {
            ASSERT_EQ(testValue, static_cast<uint8_t*>(reservedRegion)[i]);
        }
    }
}

/**
 * Test IMapper::getReservedRegion() request over a page
 */
TEST_P(GraphicsMapperHidlTest, GetLargeReservedRegion) {
    const native_handle_t* bufferHandle = nullptr;
    auto info = mDummyDescriptorInfo;

    const int pageSize = getpagesize();
    ASSERT_GE(pageSize, 0);
    std::vector<uint64_t> requestedReservedSizes{static_cast<uint64_t>(pageSize) * 2,
                                                 static_cast<uint64_t>(pageSize) * 10,
                                                 static_cast<uint64_t>(pageSize) * 1000};

    for (auto requestedReservedSize : requestedReservedSizes) {
        info.reservedSize = requestedReservedSize;

        BufferDescriptor descriptor;
        ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));

        Error err = Error::NONE;

        mGralloc->rawAllocate(
                descriptor, 1, [&](const auto& tmpError, const auto&, const auto& tmpBuffers) {
                    err = tmpError;
                    if (err == Error::NONE) {
                        ASSERT_EQ(1, tmpBuffers.size());
                        ASSERT_NO_FATAL_FAILURE(bufferHandle =
                                                        mGralloc->importBuffer(tmpBuffers[0]));
                    }
                });
        if (err == Error::UNSUPPORTED) {
            continue;
        }
        ASSERT_EQ(Error::NONE, err);

        void* reservedRegion = nullptr;
        uint64_t reservedSize = 0;
        err = mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize);

        ASSERT_EQ(Error::NONE, err);
        ASSERT_NE(nullptr, reservedRegion);
        ASSERT_EQ(requestedReservedSize, reservedSize);
    }
}

/**
 * Test IMapper::getReservedRegion() across multiple mappers
 */
TEST_P(GraphicsMapperHidlTest, GetReservedRegionMultiple) {
    const native_handle_t* bufferHandle = nullptr;
    auto info = mDummyDescriptorInfo;

    const int pageSize = getpagesize();
    ASSERT_GE(pageSize, 0);
    info.reservedSize = pageSize;

    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));

    void* reservedRegion1 = nullptr;
    uint64_t reservedSize1 = 0;
    ASSERT_EQ(Error::NONE,
              mGralloc->getReservedRegion(bufferHandle, &reservedRegion1, &reservedSize1));
    ASSERT_NE(nullptr, reservedRegion1);
    ASSERT_EQ(info.reservedSize, reservedSize1);

    std::unique_ptr<Gralloc> anotherGralloc;
    ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
                                                                       std::get<1>(GetParam())));

    void* reservedRegion2 = nullptr;
    uint64_t reservedSize2 = 0;
    ASSERT_EQ(Error::NONE,
              mGralloc->getReservedRegion(bufferHandle, &reservedRegion2, &reservedSize2));
    ASSERT_EQ(reservedRegion1, reservedRegion2);
    ASSERT_EQ(reservedSize1, reservedSize2);
}

/**
 * Test IMapper::getReservedRegion() with a bad buffer
 */
TEST_P(GraphicsMapperHidlTest, GetReservedRegionBadBuffer) {
    const native_handle_t* bufferHandle = nullptr;

    void* reservedRegion = nullptr;
    uint64_t reservedSize = 0;
    ASSERT_EQ(Error::BAD_BUFFER,
              mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize));
    ASSERT_EQ(nullptr, reservedRegion);
    ASSERT_EQ(0, reservedSize);
}

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperHidlTest);

namespace {
std::vector<std::string> getAllocatorInstances() {
    std::vector<std::string> instances;
    for (auto halInstance : android::hardware::getAllHalInstanceNames(IAllocator::descriptor)) {
        instances.emplace_back(std::move(halInstance));
    }

    for (auto aidlInstance : getAidlHalInstanceNames(
                 aidl::android::hardware::graphics::allocator::IAllocator::descriptor)) {
        instances.emplace_back(std::move(aidlInstance));
    }

    return instances;
}
}  // namespace

INSTANTIATE_TEST_CASE_P(
        PerInstance, GraphicsMapperHidlTest,
        testing::Combine(
                testing::ValuesIn(getAllocatorInstances()),
                testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
        android::hardware::PrintInstanceTupleNameToString<>);

}  // namespace
}  // namespace vts
}  // namespace V4_0
}  // namespace mapper
}  // namespace graphics
}  // namespace hardware
}  // namespace android
