Adding HDR10+ Dynamic Metadata Support

Bug: 118343714
Test: build, flash, boot
Test: VtsGraphicsComposerV2_3TargetTest should pass
Change-Id: Iee78818bc2704f4045b62251ea2cc75af72a0609
diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal
index e5ee3c5..cf78dea 100644
--- a/graphics/composer/2.3/IComposerClient.hal
+++ b/graphics/composer/2.3/IComposerClient.hal
@@ -20,6 +20,7 @@
 import android.hardware.graphics.common@1.1::PixelFormat;
 import android.hardware.graphics.common@1.2::ColorMode;
 import android.hardware.graphics.common@1.2::Dataspace;
+import android.hardware.graphics.common@1.2::Hdr;
 import android.hardware.graphics.composer@2.1::IComposerClient.Command;
 import @2.2::IComposerClient;
 import @2.1::Display;
@@ -27,7 +28,7 @@
 
 interface IComposerClient extends @2.2::IComposerClient {
 
-    // TODO: Move this enum to LLNDK after we decide where to put graphic types.
+    // Bug: Move this enum to LLNDK after we decide where to put graphic types.
     /**
      * Required capabilities which are supported by the display. The
      * particular set of supported capabilities for a given display may be
@@ -63,6 +64,48 @@
         DOZE = 2,
     };
 
+    //Bug: Move this enum to LLNDK after we decide where to put graphic types.
+    /**
+     * PerFrameMetadataKey
+     *
+     * A set of PerFrameMetadataKey pertains specifically to blob-formatted
+     * metadata (as opposed to float-valued metadata).
+     * The list of keys that represent blobs are:
+     * 1. HDR10_PLUS_SEI
+     */
+    enum PerFrameMetadataKey : @2.2::IComposerClient.PerFrameMetadataKey {
+        /**HDR10+ metadata
+         * Specifies a metadata blob adhering to
+         * the ST2094-40 SEI message spec, Version 1.0
+         */
+        HDR10_PLUS_SEI,
+    };
+
+    /**
+     * PerFrameMetadata
+     * This struct encapsulates float-valued
+     * metadata - key must not be in the list
+     * of keys representing blob-formatted metadata
+     * (see PerFrameMetadataKey)
+     */
+    struct PerFrameMetadata {
+        PerFrameMetadataKey key;
+        float value;
+    };
+
+    /**
+     * PerFrameMetadataBlob
+     * This struct encapsulates blob
+     * metadata - key must be one of the list of keys
+     * associated with blob-type metadata key
+     * and the blob must adhere to the format specified by
+     * that key (See PerFrameMetadataKey).
+     */
+    struct PerFrameMetadataBlob {
+        PerFrameMetadataKey key;
+        vec<uint8_t> blob;
+    };
+
     enum Command : @2.2::IComposerClient.Command {
         /**
          * SET_LAYER_COLOR_TRANSFORM has this pseudo prototype
@@ -106,6 +149,22 @@
          * @param matrix is a 4x4 transform matrix (16 floats) as described above.
          */
         SET_LAYER_COLOR_TRANSFORM = 0x40d << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+
+        /* SET_LAYER_PER_FRAME_METADATA_BLOBS has this pseudo prototype
+         *
+         *   setLayerPerFrameMetadataBlobs(Display display, Layer layer,
+         *                                   vec<PerFrameMetadataBlob> metadata);
+         *
+         *   This command sends metadata that may be used for tone-mapping the
+         *   associated layer.  The metadata structure follows a {key, blob}
+         *   format (see the PerFrameMetadataBlob struct).  All keys must be
+         *   returned by a prior call to getPerFrameMetadataKeys and must
+         *   be part of the list of keys associated with blob-type metadata
+         *   (see PerFrameMetadataKey).
+         *
+         *   This method may be called every frame.
+         */
+        SET_LAYER_PER_FRAME_METADATA_BLOBS = 0x304 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
     };
 
     /**
@@ -399,4 +458,43 @@
     getDisplayCapabilities(Display display)
               generates (Error error,
                          vec<DisplayCapability> capabilities);
+
+    /**
+     * Returns the PerFrameMetadataKeys that are supported by this device.
+     *
+     * @param display is the display on which to create the layer.
+     * @return keys is the vector of PerFrameMetadataKey keys that are
+     *        supported by this device.
+     * @return error is NONE upon success. Otherwise,
+     *         UNSUPPORTED if not supported on underlying HAL
+     */
+    getPerFrameMetadataKeys_2_3(Display display)
+          generates (Error error,
+                     vec<PerFrameMetadataKey> keys);
+
+    /**
+     * Returns the high dynamic range (HDR) capabilities of the given display,
+     * which are invariant with regard to the active configuration.
+     *
+     * Displays which are not HDR-capable must return no types.
+     *
+     * @param display is the display to query.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     * @return types is an array of HDR types, may have 0 elements if the
+     *         display is not HDR-capable.
+     * @return maxLuminance is the desired content maximum luminance for this
+     *         display in cd/m^2.
+     * @return maxAverageLuminance - the desired content maximum frame-average
+     *         luminance for this display in cd/m^2.
+     * @return minLuminance is the desired content minimum luminance for this
+     *         display in cd/m^2.
+     */
+    @callflow(next="*")
+    getHdrCapabilities_2_3(Display display)
+            generates (Error error,
+                       vec<Hdr> types,
+                       float maxLuminance,
+                       float maxAverageLuminance,
+                       float minLuminance);
 };
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index 6c95a1f..11863fa 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -26,6 +26,7 @@
 #include <android/hardware/graphics/composer/2.3/IComposer.h>
 #include <android/hardware/graphics/composer/2.3/IComposerClient.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <limits>
 
 namespace android {
 namespace hardware {
@@ -44,6 +45,16 @@
 // units of uint32_t's.
 class CommandWriterBase : public V2_2::CommandWriterBase {
    public:
+    void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
+        beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
+                         metadataVec.size() * 2);
+        for (const auto& metadata : metadataVec) {
+            writeSigned(static_cast<int32_t>(metadata.key));
+            writeFloat(metadata.value);
+        }
+        endCommand();
+    }
+
     void setLayerDataspace(Dataspace dataspace) {
         setLayerDataspaceInternal(static_cast<int32_t>(dataspace));
     }
@@ -66,11 +77,59 @@
         endCommand();
     }
 
+    void setLayerPerFrameMetadataBlobs(
+        const hidl_vec<IComposerClient::PerFrameMetadataBlob>& metadata) {
+        size_t commandLength = 0;
+
+        if (metadata.size() > std::numeric_limits<uint32_t>::max()) {
+            LOG_FATAL("too many metadata blobs - dynamic metadata size is too large");
+            return;
+        }
+
+        // number of blobs
+        commandLength += metadata.size();
+
+        for (auto metadataBlob : metadata) {
+            commandLength += sizeof(int32_t);  // key of metadata blob
+            commandLength += 1;                // size information of metadata blob
+
+            // metadata content size
+            size_t metadataSize = metadataBlob.blob.size() / sizeof(uint32_t);
+            commandLength += metadataSize;
+            commandLength +=
+                (metadataBlob.blob.size() - (metadataSize * sizeof(uint32_t)) > 0) ? 1 : 0;
+        }
+
+        if (commandLength > std::numeric_limits<uint16_t>::max()) {
+            LOG_FATAL("dynamic metadata size is too large");
+            return;
+        }
+
+        // Blobs are written as:
+        // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...}
+        uint16_t length = static_cast<uint16_t>(commandLength);
+        beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
+        write(static_cast<uint32_t>(metadata.size()));
+        for (auto metadataBlob : metadata) {
+            writeSigned(static_cast<int32_t>(metadataBlob.key));
+            write(static_cast<uint32_t>(metadataBlob.blob.size()));
+            writeBlob(static_cast<uint32_t>(metadataBlob.blob.size()), metadataBlob.blob.data());
+        }
+        endCommand();
+    }
+
    protected:
     void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
         V2_2::CommandWriterBase::beginCommand_2_2(
             static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length);
     }
+
+    void writeBlob(uint32_t length, const unsigned char* blob) {
+        memcpy(&mData[mDataWritten], blob, length);
+        uint32_t numElements = length / 4;
+        mDataWritten += numElements;
+        mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0;
+    }
 };
 
 // This class helps parse a command queue.  Note that all sizes/lengths are in
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
index 69872d2..edc203e 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -21,6 +21,7 @@
 #endif
 
 #include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-hal/2.2/ComposerResources.h>
 #include <composer-hal/2.3/ComposerClient.h>
 #include <composer-hal/2.3/ComposerCommandEngine.h>
 #include <composer-hal/2.3/ComposerHal.h>
@@ -38,6 +39,14 @@
 template <typename Interface, typename Hal>
 class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl<Interface, Hal> {
    public:
+    Return<void> getPerFrameMetadataKeys_2_3(
+        Display display, IComposerClient::getPerFrameMetadataKeys_2_3_cb hidl_cb) override {
+        std::vector<IComposerClient::PerFrameMetadataKey> keys;
+        Error error = mHal->getPerFrameMetadataKeys_2_3(display, &keys);
+        hidl_cb(error, keys);
+        return Void();
+    }
+
     Return<Error> setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) override {
         return mHal->setColorMode_2_3(display, mode, intent);
     }
@@ -67,6 +76,18 @@
         return Void();
     }
 
+    Return<void> getHdrCapabilities_2_3(
+        Display display, IComposerClient::getHdrCapabilities_2_3_cb hidl_cb) override {
+        hidl_vec<Hdr> types;
+        float max_lumi = 0.0f;
+        float max_avg_lumi = 0.0f;
+        float min_lumi = 0.0f;
+        Error err =
+            mHal->getHdrCapabilities_2_3(display, &types, &max_lumi, &max_avg_lumi, &min_lumi);
+        hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi);
+        return Void();
+    }
+
     Return<Error> getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
                                              PixelFormat format, Dataspace dataspace) override {
         Error err = mHal->getClientTargetSupport_2_3(display, width, height, format, dataspace);
@@ -151,12 +172,19 @@
         return Void();
     }
 
+   protected:
+    std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override {
+        return std::make_unique<ComposerCommandEngine>(
+            mHal, static_cast<V2_2::hal::ComposerResources*>(mResources.get()));
+    }
+
    private:
     using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>;
     using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
     using BaseType2_1::mCommandEngine;
     using BaseType2_1::mCommandEngineMutex;
     using BaseType2_1::mHal;
+    using BaseType2_1::mResources;
 };
 
 }  // namespace detail
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
index c3dcbcd..1a40d96 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
@@ -43,6 +43,8 @@
         switch (static_cast<IComposerClient::Command>(command)) {
             case IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM:
                 return executeSetLayerColorTransform(length);
+            case IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS:
+                return executeSetLayerPerFrameMetadataBlobs(length);
             default:
                 return BaseType2_2::executeCommand(command, length);
         }
@@ -65,6 +67,48 @@
         return true;
     }
 
+    bool executeSetLayerPerFrameMetadataBlobs(uint16_t length) {
+        // must have at least one metadata blob
+        // of at least size 1 in queue (i.e {/*numBlobs=*/1, key, size, blob})
+        if (length < 4) {
+            return false;
+        }
+
+        uint32_t numBlobs = read();
+        length--;
+
+        std::vector<IComposerClient::PerFrameMetadataBlob> metadata;
+
+        for (size_t i = 0; i < numBlobs; i++) {
+            IComposerClient::PerFrameMetadataKey key =
+                static_cast<IComposerClient::PerFrameMetadataKey>(readSigned());
+            uint32_t blobSize = read();
+
+            length -= 2;
+
+            if (length * sizeof(uint32_t) < blobSize) {
+                return false;
+            }
+
+            metadata.push_back({key, std::vector<uint8_t>()});
+            IComposerClient::PerFrameMetadataBlob& metadataBlob = metadata.back();
+            metadataBlob.blob.resize(blobSize);
+            readBlob(blobSize, metadataBlob.blob.data());
+        }
+        auto err = mHal->setLayerPerFrameMetadataBlobs(mCurrentDisplay, mCurrentLayer, metadata);
+        if (err != Error::NONE) {
+            mWriter.setError(getCommandLoc(), err);
+        }
+        return true;
+    }
+
+    void readBlob(uint32_t size, void* blob) {
+        memcpy(blob, &mData[mDataRead], size);
+        uint32_t numElements = size / sizeof(uint32_t);
+        mDataRead += numElements;
+        mDataRead += (size - numElements * sizeof(uint32_t) != 0) ? 1 : 0;
+    }
+
    private:
     using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
     using BaseType2_1::mWriter;
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
index c7de848..882621f 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
@@ -29,12 +29,19 @@
 using common::V1_1::RenderIntent;
 using common::V1_2::ColorMode;
 using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
 using V2_1::Display;
 using V2_1::Error;
 using V2_1::Layer;
 
 class ComposerHal : public V2_2::hal::ComposerHal {
    public:
+    Error getPerFrameMetadataKeys(
+        Display display, std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* outKeys) {
+        return getPerFrameMetadataKeys_2_3(
+            display, reinterpret_cast<std::vector<IComposerClient::PerFrameMetadataKey>*>(outKeys));
+    }
+
     Error setColorMode_2_2(Display display, common::V1_1::ColorMode mode,
                            RenderIntent intent) override {
         return setColorMode_2_3(display, static_cast<ColorMode>(mode), intent);
@@ -57,6 +64,24 @@
                                                reinterpret_cast<Dataspace*>(outDataspace));
     }
 
+    Error getHdrCapabilities(Display display, hidl_vec<common::V1_0::Hdr>* outTypes,
+                             float* outMaxLuminance, float* outMaxAverageLuminance,
+                             float* outMinLuminance) override {
+        return getHdrCapabilities_2_3(display, reinterpret_cast<hidl_vec<Hdr>*>(outTypes),
+                                      outMaxLuminance, outMaxAverageLuminance, outMinLuminance);
+    }
+
+    Error setLayerPerFrameMetadata(
+        Display display, Layer layer,
+        const std::vector<V2_2::IComposerClient::PerFrameMetadata>& metadata) override {
+        return setLayerPerFrameMetadata_2_3(
+            display, layer,
+            reinterpret_cast<const std::vector<IComposerClient::PerFrameMetadata>&>(metadata));
+    }
+
+    virtual Error getPerFrameMetadataKeys_2_3(
+        Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0;
+
     virtual Error setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) = 0;
 
     virtual Error getRenderIntents_2_3(Display display, ColorMode mode,
@@ -68,7 +93,12 @@
                                              PixelFormat format, Dataspace dataspace) = 0;
     virtual Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat,
                                                   Dataspace* outDataspace) = 0;
-
+    virtual Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes,
+                                         float* outMaxLuminance, float* outMaxAverageLuminance,
+                                         float* outMinLuminance) = 0;
+    virtual Error setLayerPerFrameMetadata_2_3(
+        Display display, Layer layer,
+        const std::vector<IComposerClient::PerFrameMetadata>& metadata) = 0;
     virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
                                                std::vector<uint8_t>* outData) = 0;
     virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0;
@@ -86,6 +116,9 @@
                                             hidl_vec<uint64_t>& sampleComponent3) = 0;
     virtual Error getDisplayCapabilities(
         Display display, hidl_vec<IComposerClient::DisplayCapability>* outCapabilities) = 0;
+    virtual Error setLayerPerFrameMetadataBlobs(
+        Display display, Layer layer,
+        std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) = 0;
 };
 
 }  // namespace hal
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
index f7ce7e8..9fb6d4b 100644
--- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -38,6 +38,7 @@
 using common::V1_1::RenderIntent;
 using common::V1_2::ColorMode;
 using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
 using V2_1::Display;
 using V2_1::Error;
 
@@ -45,6 +46,29 @@
 template <typename Hal>
 class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
    public:
+    Error getPerFrameMetadataKeys_2_3(
+        Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override {
+        std::vector<V2_2::IComposerClient::PerFrameMetadataKey> castKeys;
+        Error error = getPerFrameMetadataKeys(display, &castKeys);
+        if (error != Error::NONE) {
+            return error;
+        }
+        outKeys->clear();
+        for (auto key : castKeys) {
+            outKeys->push_back(static_cast<IComposerClient::PerFrameMetadataKey>(key));
+        }
+        return Error::NONE;
+    }
+
+    Error setLayerPerFrameMetadata_2_3(
+        Display display, Layer layer,
+        const std::vector<IComposerClient::PerFrameMetadata>& metadata) override {
+        return setLayerPerFrameMetadata(
+            display, layer,
+            reinterpret_cast<const std::vector<V2_2::IComposerClient::PerFrameMetadata>&>(
+                metadata));
+    }
+
     Error setColorMode_2_3(Display display, ColorMode mode, RenderIntent intent) override {
         return setColorMode_2_2(display, static_cast<common::V1_1::ColorMode>(mode), intent);
     }
@@ -59,6 +83,12 @@
                                  reinterpret_cast<hidl_vec<common::V1_1::ColorMode>*>(outModes));
     }
 
+    Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance,
+                                 float* outMaxAverageLuminance, float* outMinLuminance) override {
+        return getHdrCapabilities(display, reinterpret_cast<hidl_vec<common::V1_0::Hdr>*>(outTypes),
+                                  outMaxLuminance, outMaxAverageLuminance, outMinLuminance);
+    }
+
     Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
                                      PixelFormat format, Dataspace dataspace) override {
         return getClientTargetSupport_2_2(display, width, height, format,
@@ -186,6 +216,33 @@
         return Error::NONE;
     }
 
+    Error setLayerPerFrameMetadataBlobs(
+        Display display, Layer layer,
+        std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override {
+        if (!mDispatch.setLayerPerFrameMetadataBlobs) {
+            return Error::UNSUPPORTED;
+        }
+
+        std::vector<IComposerClient::PerFrameMetadataKey> keys;
+        std::vector<uint32_t> sizes;
+        std::vector<uint8_t> blobs;
+
+        for (auto metadataBlob : metadata) {
+            keys.push_back(metadataBlob.key);
+            sizes.push_back(metadataBlob.blob.size());
+
+            int writeIndex = blobs.size();
+            blobs.resize(blobs.size() + metadataBlob.blob.size());
+            memcpy(blobs.data() + writeIndex, metadataBlob.blob.data(), metadataBlob.blob.size());
+        }
+
+        int32_t err = mDispatch.setLayerPerFrameMetadataBlobs(
+            mDevice, display, layer, static_cast<uint32_t>(metadata.size()),
+            reinterpret_cast<int32_t*>(keys.data()), reinterpret_cast<uint32_t*>(sizes.data()),
+            blobs.data());
+        return static_cast<Error>(err);
+    }
+
    protected:
     bool initDispatch() override {
         if (!BaseType2_2::initDispatch()) {
@@ -204,6 +261,8 @@
                                    &mDispatch.getDisplayedContentSample);
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES,
                                    &mDispatch.getDisplayCapabilities);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_PER_FRAME_METADATA_BLOBS,
+                                   &mDispatch.setLayerPerFrameMetadataBlobs);
         return true;
     }
 
@@ -215,16 +274,20 @@
         HWC2_PFN_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED setDisplayedContentSamplingEnabled;
         HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLE getDisplayedContentSample;
         HWC2_PFN_GET_DISPLAY_CAPABILITIES getDisplayCapabilities;
+        HWC2_PFN_SET_LAYER_PER_FRAME_METADATA_BLOBS setLayerPerFrameMetadataBlobs;
     } mDispatch = {};
 
     using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;
     using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_1::getHdrCapabilities;
     using BaseType2_1::mDevice;
     using BaseType2_2::getClientTargetSupport_2_2;
     using BaseType2_2::getColorModes_2_2;
+    using BaseType2_2::getPerFrameMetadataKeys;
     using BaseType2_2::getReadbackBufferAttributes;
     using BaseType2_2::getRenderIntents;
     using BaseType2_2::setColorMode_2_2;
+    using BaseType2_2::setLayerPerFrameMetadata;
 };
 
 }  // namespace detail
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
index c631c50..0e541ed 100644
--- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -108,6 +108,33 @@
     return error == Error::NONE;
 }
 
+std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient::getPerFrameMetadataKeys_2_3(
+    Display display) {
+    std::vector<IComposerClient::PerFrameMetadataKey> keys;
+    mClient->getPerFrameMetadataKeys_2_3(display, [&](const auto& tmpError, const auto& tmpKeys) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get perFrameMetadataKeys";
+        keys = tmpKeys;
+    });
+    return keys;
+}
+
+std::vector<Hdr> ComposerClient::getHdrCapabilities_2_3(Display display, float* outMaxLuminance,
+                                                        float* outMaxAverageLuminance,
+                                                        float* outMinLuminance) {
+    std::vector<Hdr> types;
+    mClient->getHdrCapabilities_2_3(
+        display, [&](const auto& tmpError, const auto& tmpTypes, const auto& tmpMaxLuminance,
+                     const auto& tmpMaxAverageLuminance, const auto& tmpMinLuminance) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR capabilities";
+            types = tmpTypes;
+            *outMaxLuminance = tmpMaxLuminance;
+            *outMaxAverageLuminance = tmpMaxAverageLuminance;
+            *outMinLuminance = tmpMinLuminance;
+        });
+
+    return types;
+}
+
 Error ComposerClient::getDisplayedContentSamplingAttributes(
     uint64_t display, PixelFormat& format, Dataspace& dataspace,
     hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index d3aa779..7add322 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -36,6 +36,7 @@
 using common::V1_1::RenderIntent;
 using common::V1_2::ColorMode;
 using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
 using V2_1::Display;
 using V2_1::Error;
 using V2_3::IComposer;
@@ -89,10 +90,15 @@
     void getReadbackBufferAttributes_2_3(Display display, PixelFormat* outPixelFormat,
                                          Dataspace* outDataspace);
 
+    std::vector<Hdr> getHdrCapabilities_2_3(Display display, float* outMaxLuminance,
+                                            float* outMaxAverageLuminance, float* outMinLuminance);
+
     bool getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
                                     PixelFormat format, Dataspace dataspace);
     std::vector<IComposerClient::DisplayCapability> getDisplayCapabilities(Display display);
 
+    std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys_2_3(Display display);
+
    private:
     const sp<IComposerClient> mClient;
 };
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index 6c5cb5d..535f847 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -20,10 +20,12 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.3/ComposerVts.h>
+#include <mapper-vts/2.0/MapperVts.h>
 
 namespace android {
 namespace hardware {
@@ -33,10 +35,13 @@
 namespace vts {
 namespace {
 
+using common::V1_0::BufferUsage;
 using common::V1_1::PixelFormat;
 using common::V1_1::RenderIntent;
 using common::V1_2::ColorMode;
 using common::V1_2::Dataspace;
+using mapper::V2_0::IMapper;
+using mapper::V2_0::vts::Gralloc;
 
 // Test environment for graphics.composer
 class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -80,6 +85,8 @@
     }
 
     void TearDown() override {
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_EQ(0, mReader->mCompositionChanges.size());
         if (mComposerCallback != nullptr) {
             EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
             EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
@@ -131,6 +138,44 @@
     }
 };
 
+// Tests for IComposerClient::Command.
+class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
+   protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+
+        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+
+        mWriter = std::make_unique<CommandWriterBase>(1024);
+        mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+    }
+
+    void TearDown() override {
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+    }
+
+    const native_handle_t* allocate() {
+        IMapper::BufferDescriptorInfo info{};
+        info.width = 64;
+        info.height = 64;
+        info.layerCount = 1;
+        info.format = static_cast<common::V1_0::PixelFormat>(PixelFormat::RGBA_8888);
+        info.usage =
+            static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+        return mGralloc->allocate(info);
+    }
+
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+    std::unique_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+
+   private:
+    std::unique_ptr<Gralloc> mGralloc;
+};
+
 /**
  * Test IComposerClient::getDisplayIdentificationData.
  *
@@ -152,6 +197,57 @@
 }
 
 /**
+ * Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+
+    /**
+     * 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
+     */
+
+    std::vector<IComposerClient::PerFrameMetadata> hidlMetadata;
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_X, 0.3127});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_Y, 0.3290});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_LUMINANCE, 100.0});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MIN_LUMINANCE, 0.1});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
+    hidlMetadata.push_back(
+        {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
+    mWriter->setLayerPerFrameMetadata(hidlMetadata);
+    execute();
+
+    if (mReader->mErrors.size() == 1 &&
+        static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) {
+        mReader->mErrors.clear();
+        GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported";
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer));
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer));
+}
+
+/**
  * TestIComposerClient::getReadbackBufferAttributes_2_3
  */
 TEST_F(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) {
@@ -353,6 +449,13 @@
 
     mWriter->setLayerColorTransform(matrix.data());
     execute();
+
+    if (mReader->mErrors.size() == 1 &&
+        static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) {
+        mReader->mErrors.clear();
+        GTEST_SUCCEED() << "setLayerColorTransform is not supported";
+        return;
+    }
 }
 
 TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
@@ -444,6 +547,29 @@
         [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_DISPLAY, tmpError); });
 }
 
+TEST_F(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) {
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+
+    std::vector<IComposerClient::PerFrameMetadataBlob> metadata;
+    metadata.push_back(
+        {IComposerClient::PerFrameMetadataKey::HDR10_PLUS_SEI, std::vector<uint8_t>(1, 0xff)});
+
+    mWriter->setLayerPerFrameMetadataBlobs(metadata);
+    execute();
+
+    if (mReader->mErrors.size() == 1 &&
+        static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) {
+        mReader->mErrors.clear();
+        GTEST_SUCCEED() << "setLayerDynamicPerFrameMetadata is not supported";
+        return;
+    }
+}
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_3