Merge "More memory test interfaces"
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 7d4f7a3..4bd8332 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -256,7 +256,7 @@
     <hal format="hidl" optional="false">
         <name>android.hardware.keymaster</name>
         <version>3.0</version>
-        <version>4.0</version>
+        <version>4.0-1</version>
         <interface>
             <name>IKeymasterDevice</name>
             <instance>default</instance>
@@ -264,7 +264,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.keymaster</name>
-        <version>4.0</version>
+        <version>4.0-1</version>
         <interface>
             <name>IKeymasterDevice</name>
             <instance>strongbox</instance>
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 497c0f8..e0c7674 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -1,5 +1,6 @@
 aidl_interface {
     name: "vintf-graphics-common",
+    host_supported: true,
     vendor_available: true,
     vndk: {
         enabled: true,
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
index 640539f..a541382 100644
--- a/graphics/mapper/4.0/IMapper.hal
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -35,18 +35,20 @@
          */
         uint32_t width;
 
-       /**
-        * The height specifies how many rows of pixels must be in the
-        * allocated buffer.
-        */
+        /**
+         * The height specifies how many rows of pixels must be in the
+         * allocated buffer.
+         */
         uint32_t height;
 
-       /**
-        * The number of image layers that must be in the allocated buffer.
-        */
+        /**
+         * The number of image layers that must be in the allocated buffer.
+         */
         uint32_t layerCount;
 
-        /** Buffer pixel format. */
+        /**
+         * Buffer pixel format.
+         */
         PixelFormat format;
 
         /**
@@ -309,5 +311,209 @@
             generates (Error error,
                        bool supported);
 
+
+    /**
+     * Description for get(...), set(...) and getFromBufferDescriptorInfo(...)
+     *
+     * ------------ Overview -----------------------------------
+     * Gralloc 4 adds support for getting and setting buffer metadata on a buffer.
+     *
+     * To get buffer metadata, the client passes in a buffer handle and a token that
+     * represents the type of buffer metadata they would like to get. IMapper returns
+     * a byte stream that contains the buffer metadata. To set the buffer metadata, the
+     * client passes in a buffer handle and a token that represents the type of buffer
+     * metadata they would like to set and a byte stream that contains the buffer metadata
+     * they are setting.
+     *
+     * Buffer metadata is global for a buffer. When the metadata is set on the buffer
+     * in a process, the updated metadata should be available to all other processes.
+     * Please see "Storing and Propagating Metadata" below for more details.
+     *
+     * The getter and setter functions have been optimized for easy vendor extension.
+     * They do not require a formal HIDL extension to add support for getting and setting
+     * vendor defined buffer metadata. In order to allow easy extension, the types used
+     * here are not typical HIDL types. See "Buffer Metadata Token" and
+     * "Buffer Metadata Stream" below for more details.
+     *
+     * ------------ Storing and Propagating Metadata -----------
+     * Buffer metadata must be global. Any changes to the metadata must be propagated
+     * to all other processes immediately. Vendors may chose how they would like support
+     * this functionality.
+     *
+     * We recommend supporting this functionality by allocating an extra page of shared
+     * memory and storing it in the buffer's native_handle_t. The buffer metadata can
+     * be stored in the extra page of shared memory. Set operations are automatically
+     * propagated to all other processes.
+     *
+     * ------------ Buffer Metadata Synchronization ------------
+     * There are no explicit buffer metadata synchronization primitives. Many devices
+     * before gralloc 4 already support getting and setting of global buffer metadata
+     * with no explicit synchronization primitives. Adding synchronization primitives
+     * would just add unnecessary complexity.
+     *
+     * The general rule is if a process has permission to write to a buffer, they
+     * have permission to write to the buffer's metadata. If a process has permission
+     * to read from a buffer, they have permission to read the buffer's metadata.
+     *
+     * There is one exception to this rule. Fences CANNOT be used to protect a buffer's
+     * metadata. A process should finish writing to a buffer's metadata before sending
+     * sending the buffer to another process that will read or write to the buffer.
+     * This exception is needed because sometimes userspace needs to read the
+     * buffer's metadata before the buffer's contents are ready.
+     *
+     * As a simple example: an app renders to a buffer and then displays the buffer.
+     * In this example when the app renders to the buffer, both the buffer and its
+     * metadata need to be updated. The app's process queues up its work on the GPU
+     * and gets back an acquire fence. The app's process must update the buffer's
+     * metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT
+     * update the buffer's metadata after enqueuing the buffer. When HardwareComposer
+     * receives the buffer, it is immediately safe to read the buffer's metadata
+     * and use it to program the display driver. To read the buffer's contents,
+     * display driver must still wait on the acquire fence.
+     *
+     * ------------ Buffer Metadata Token ----------------------
+     * In order to allow arbitrary vendor defined metadata, we could not use a
+     * HIDL enum as the buffer metadata token. Extending a HIDL enum requires a full
+     * HIDL extension. We also could not use a simple non-HIDL enum because vendor
+     * defined enums from different vendors could collide. Instead we have defined
+     * a struct that has a string representing the enum type and an int that
+     * represents the enum value. The string protects different enum values from
+     * colliding.
+     *
+     * The token struct (MetadataType) is defined as a HIDL struct since it
+     * is passed into a HIDL function. The standard buffer metadata types are NOT
+     * defined as a HIDL enum because it would have required a new IMapper version
+     * just to add future standard buffer metadata types. By putting the enum in the
+     * stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/
+     * graphics/common/StandardMetadataType.aidl), vendors will be able to optionally
+     * choose to support future standard buffer metadata types without upgrading
+     * HIDL versions. For more information see the description of "struct MetadataType".
+     *
+     * ------------ Buffer Metadata Stream ---------------------
+     * The buffer metadata is get and set as a byte stream (vec<uint8_t>). By getting
+     * and setting buffer metadata as a byte stream, vendors can use the standard
+     * getters and setter functions defined here. Vendors do NOT need to add their own
+     * getters and setter functions for each new type of buffer metadata.
+     *
+     * Converting buffer metadata into a byte stream can be non-trivial. For the standard
+     * buffer metadata types defined in StandardMetadataType.aidl, there are also
+     * support functions that will encode the buffer metadata into a byte stream
+     * and decode the buffer metadata from a byte stream. We STRONGLY recommend using
+     * these support functions. The framework will use them when getting and setting
+     * metadata. The support functions are defined in
+     * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
+     */
+
+    /**
+     * MetadataType represents the different types of buffer metadata that could be
+     * associated with a buffer. It is used by IMapper to help get and set buffer metadata
+     * on the buffer's native handle.
+     *
+     * Standard buffer metadata will have the name field set to
+     * "android.hardware.graphics.common.StandardMetadataType" and will contain values
+     * from StandardMetadataType.aidl.
+     *
+     * This struct should be "extended" by devices that use a proprietary or non-standard
+     * buffer metadata. To extend the struct, first create a custom @VendorStability vendor
+     * AIDL interface that defines the new type(s) you would like to support. Set the
+     * struct's name field to the custom aidl interface's name
+     * (eg. "vendor.mycompanyname.graphics.common.MetadataType"). Set the struct's value
+     * field to the custom @VendorStabilty vendor AIDL interface.
+     *
+     * Each company should create their own StandardMetadataType.aidl extension. The name
+     * field prevents values from different companies from colliding.
+     */
+    struct MetadataType {
+        string name;
+        int64_t value;
+    };
+
+    /**
+     * Gets the buffer metadata for a given MetadataType.
+     *
+     * Buffer metadata can be changed after allocation so clients should avoid "caching"
+     * the buffer metadata. For example, if the video resolution changes and the buffers
+     * are not reallocated, several buffer metadata values may change without warning.
+     * Clients should not expect the values to be constant. They should requery them every
+     * frame. The only exception is buffer metadata that is determined at allocation
+     * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+     * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+     * they are determined at allocation time.
+     *
+     * @param buffer Buffer containing desired metadata
+     * @param metadataType MetadataType for the metadata value being queried
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+     *        resources.
+     *     - `UNSUPPORTED` when metadataType is unknown/unsupported.
+     *        IMapper must support getting all StandardMetadataType.aidl values defined
+     *        at the time the device first launches.
+     * @return metadata Vector of bytes representing the buffer metadata associated with
+     *  the MetadataType.
+     */
+    get(pointer buffer, MetadataType metadataType)
+            generates (Error error,
+                       vec<uint8_t> metadata);
+
+    /**
+     * Sets the global value for a given MetadataType.
+     *
+     * Metadata fields are not required to be settable. This function can
+     * return Error::UNSUPPORTED whenever it doesn't support setting a
+     * particular Metadata field.
+     *
+     * The framework may attempt to set the following StandardMetadataType
+     * values: DATASPACE, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB and BLEND_MODE.
+     * We strongly encourage everyone to support setting as many of those fields as
+     * possible. If a device's Composer implementation supports a field, it should be
+     * supported here. Over time these metadata fields will be moved out of
+     * Composer/BufferQueue/etc. and into the buffer's Metadata fields.
+     * If a device's IMapper doesn't support setting those Metadata fields,
+     * eventually the device may not longer be able to support these fields.
+     *
+     * @param buffer Buffer receiving desired metadata
+     * @param metadataType MetadataType for the metadata value being set
+     * @param metadata Vector of bytes representing the value associated with
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `BAD_VALUE` when the field is constant and can never be set (such as
+     *       BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+     *       USAGE)
+     *     - `NO_RESOURCES` if the set cannot be fullfilled due to unavailability of
+     *        resources.
+     *     - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+     *       it is unsupported. Unsupported should also be returned if the metadata
+     *       is malformed.
+     */
+    set(pointer buffer, MetadataType metadataType, vec<uint8_t> metadata)
+            generates (Error error);
+
+    /**
+     * Given a BufferDescriptorInfo, gets the starting value of a given
+     * MetadataType. This can be used to query basic information about a buffer
+     * before the buffer is allocated.
+     *
+     * @param description Attributes of the descriptor.
+     * @param metadataType MetadataType for the metadata value being queried
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_VALUE` if any of the specified BufferDescriptorInfo attributes
+     *       are invalid.
+     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+     *       resources.
+     *     - `UNSUPPORTED` when any of the description attributes are unsupported or
+     *       if the metadataType is unknown/unsupported. This should also be
+     *       returned if the requested metadata is not defined until a buffer has been
+     *       allocated.
+     * @return metadata Vector of bytes representing the value associated with
+     *  the MetadataType value.
+     */
+    getFromBufferDescriptorInfo(BufferDescriptorInfo description,
+                                MetadataType metadataType)
+            generates (Error error,
+                       vec<uint8_t> metadata);
 };
 
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
index e451584..56ff116 100644
--- a/graphics/mapper/4.0/utils/vts/Android.bp
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -26,6 +26,9 @@
         "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.mapper@4.0",
     ],
+    shared_libs: [
+        "libgralloctypes",
+    ],
     export_static_lib_headers: [
         "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.mapper@4.0",
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 056b7c9..531f311 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <gralloctypes/Gralloc4.h>
 #include <mapper-vts/4.0/MapperVts.h>
 
 #include <VtsHalHidlTargetTestBase.h>
@@ -92,28 +93,39 @@
 
 std::vector<const native_handle_t*> Gralloc::allocate(const BufferDescriptor& descriptor,
                                                       uint32_t count, bool import,
-                                                      uint32_t* outStride) {
+                                                      bool allowFailure, uint32_t* outStride) {
     std::vector<const native_handle_t*> bufferHandles;
     bufferHandles.reserve(count);
-    mAllocator->allocate(descriptor, count,
-                         [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
-                             ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
-                             ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+    mAllocator->allocate(
+            descriptor, count,
+            [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
+                ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
+                ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
 
-                             for (uint32_t i = 0; i < count; i++) {
-                                 if (import) {
-                                     ASSERT_NO_FATAL_FAILURE(
-                                             bufferHandles.push_back(importBuffer(tmpBuffers[i])));
-                                 } else {
-                                     ASSERT_NO_FATAL_FAILURE(
-                                             bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
-                                 }
-                             }
+                for (uint32_t i = 0; i < count; i++) {
+                    const native_handle_t* bufferHandle = nullptr;
+                    if (import) {
+                        if (allowFailure) {
+                            bufferHandle = importBuffer(tmpBuffers[i]);
+                        } else {
+                            ASSERT_NO_FATAL_FAILURE(bufferHandle = importBuffer(tmpBuffers[i]));
+                        }
+                    } else {
+                        if (allowFailure) {
+                            bufferHandle = cloneBuffer(tmpBuffers[i]);
+                        } else {
+                            ASSERT_NO_FATAL_FAILURE(bufferHandle = cloneBuffer(tmpBuffers[i]));
+                        }
+                    }
+                    if (bufferHandle) {
+                        bufferHandles.push_back(bufferHandle);
+                    }
+                }
 
-                             if (outStride) {
-                                 *outStride = tmpStride;
-                             }
-                         });
+                if (outStride) {
+                    *outStride = tmpStride;
+                }
+            });
 
     if (::testing::Test::HasFatalFailure()) {
         bufferHandles.clear();
@@ -123,17 +135,20 @@
 }
 
 const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
-                                         bool import, uint32_t* outStride) {
+                                         bool import, bool allowFailure, uint32_t* outStride) {
     BufferDescriptor descriptor = createDescriptor(descriptorInfo);
     if (::testing::Test::HasFatalFailure()) {
         return nullptr;
     }
 
-    auto buffers = allocate(descriptor, 1, import, outStride);
+    auto buffers = allocate(descriptor, 1, import, allowFailure, outStride);
     if (::testing::Test::HasFatalFailure()) {
         return nullptr;
     }
 
+    if (buffers.size() != 1) {
+        return nullptr;
+    }
     return buffers[0];
 }
 
@@ -167,6 +182,10 @@
 }
 
 void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
+    if (bufferHandle == nullptr) {
+        return;
+    }
+
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
 
     if (mImportedBuffers.erase(bufferHandle)) {
@@ -296,6 +315,35 @@
     return supported;
 }
 
+Error Gralloc::get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+                   hidl_vec<uint8_t>* outVec) {
+    Error err;
+    mMapper->get(const_cast<native_handle_t*>(bufferHandle), metadataType,
+                 [&](const auto& tmpError, const hidl_vec<uint8_t>& tmpVec) {
+                     err = tmpError;
+                     *outVec = tmpVec;
+                 });
+    return err;
+}
+
+Error Gralloc::set(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+                   const hidl_vec<uint8_t>& vec) {
+    return mMapper->set(const_cast<native_handle_t*>(bufferHandle), metadataType, vec);
+}
+
+Error Gralloc::getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                           const IMapper::MetadataType& metadataType,
+                                           hidl_vec<uint8_t>* outVec) {
+    Error err;
+    mMapper->getFromBufferDescriptorInfo(
+            descriptorInfo, metadataType,
+            [&](const auto& tmpError, const hidl_vec<uint8_t>& tmpVec) {
+                err = tmpError;
+                *outVec = tmpVec;
+            });
+    return err;
+}
+
 }  // namespace vts
 }  // namespace V4_0
 }  // namespace mapper
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index 03ce764..28555fa 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -51,9 +51,11 @@
     //
     // Either case, the returned buffers must be freed with freeBuffer.
     std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor, uint32_t count,
-                                                 bool import = true, uint32_t* outStride = nullptr);
+                                                 bool import = true, bool allowFailure = false,
+                                                 uint32_t* outStride = nullptr);
     const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
-                                    bool import = true, uint32_t* outStride = nullptr);
+                                    bool import = true, bool allowFailure = false,
+                                    uint32_t* outStride = nullptr);
 
     // IMapper methods
 
@@ -81,6 +83,16 @@
 
     bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo);
 
+    Error get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+              hidl_vec<uint8_t>* outVec);
+
+    Error set(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+              const hidl_vec<uint8_t>& vec);
+
+    Error getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                      const IMapper::MetadataType& metadataType,
+                                      hidl_vec<uint8_t>* outVec);
+
   private:
     void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
 
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index a90ee0c..5a7548a 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -19,12 +19,16 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
     static_libs: [
+        "android.hardware.graphics.mapper@4.0-vts",
+    ],
+    shared_libs: [
         "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@4.0",
-        "android.hardware.graphics.mapper@4.0-vts",
+        "libgralloctypes",
+        "vintf-graphics-common-ndk_platform",
     ],
     test_suites: ["general-tests"],
 }
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 62ff613..1e8ec01 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -22,6 +22,7 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
+#include <gralloctypes/Gralloc4.h>
 #include <mapper-vts/4.0/MapperVts.h>
 
 namespace android {
@@ -34,6 +35,15 @@
 
 using android::hardware::graphics::common::V1_2::BufferUsage;
 using android::hardware::graphics::common::V1_2::PixelFormat;
+using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+using aidl::android::hardware::graphics::common::BlendMode;
+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 DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                          const hidl_vec<uint8_t>& vec)>;
 
 // Test environment for graphics.mapper.
 class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -57,6 +67,8 @@
                 mGralloc = std::make_unique<Gralloc>(
                         GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
                         GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+        ASSERT_NE(nullptr, mGralloc->getAllocator().get());
+        ASSERT_NE(nullptr, mGralloc->getMapper().get());
 
         mDummyDescriptorInfo.name = "dummy";
         mDummyDescriptorInfo.width = 64;
@@ -69,6 +81,85 @@
 
     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;
+        ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec));
+
+        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";
+        }
+        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 verifyDummyDescriptorInfoPlaneLayouts(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) {
+            EXPECT_EQ(GRALLOC4_PLANE_LAYOUT_COMPONENT_TYPE, component.type.name);
+            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(8, 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);
+
+        EXPECT_EQ(0, planeLayout.crop.left);
+        EXPECT_EQ(0, planeLayout.crop.top);
+        EXPECT_EQ(planeLayout.widthInSamples, planeLayout.crop.right);
+        EXPECT_EQ(planeLayout.heightInSamples, planeLayout.crop.bottom);
+    }
+
     std::unique_ptr<Gralloc> mGralloc;
     IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
 };
@@ -90,8 +181,8 @@
     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, &stride));
+        ASSERT_NO_FATAL_FAILURE(
+                bufferHandles = mGralloc->allocate(descriptor, count, false, false, &stride));
 
         if (count >= 1) {
             EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride";
@@ -293,7 +384,7 @@
 
     const native_handle_t* bufferHandle;
     uint32_t stride;
-    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride));
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride));
 
     // lock buffer for writing
     const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
@@ -354,7 +445,7 @@
 
     const native_handle_t* bufferHandle;
     uint32_t stride;
-    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride));
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, false, &stride));
 
     // lock buffer for writing
     const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
@@ -519,6 +610,987 @@
     ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
 }
 
+/**
+ * Test IMapper::get(BufferId)
+ */
+TEST_F(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_F(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_F(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_F(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_F(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_F(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_F(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_F(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_F(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_F(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_F(GraphicsMapperHidlTest, GetProtectedContent) {
+    auto info = mDummyDescriptorInfo;
+    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+    const native_handle_t* bufferHandle = nullptr;
+    bufferHandle = mGralloc->allocate(info, true, true);
+    if (bufferHandle) {
+        GTEST_SUCCEED() << "unable to allocate protected content";
+    }
+
+    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_F(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_F(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_F(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_F(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(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts));
+}
+
+/**
+ * Test IMapper::get(Dataspace)
+ */
+TEST_F(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_F(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(metadata) with a bad buffer
+ */
+TEST_F(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_Dataspace, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec));
+    ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::get(metadata) for unsupported metadata
+ */
+TEST_F(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_F(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_F(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_F(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(Usage) remove flag
+ */
+TEST_F(GraphicsMapperHidlTest, SetUsageRemoveBit) {
+    uint64_t usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN);
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t realUsage = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+                EXPECT_EQ(usage, realUsage);
+            });
+}
+/**
+ * Test IMapper::set(Usage) add flag
+ */
+TEST_F(GraphicsMapperHidlTest, SetUsageAddBit) {
+    uint64_t usage = mDummyDescriptorInfo.usage | static_cast<uint64_t>(BufferUsage::GPU_TEXTURE);
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t realUsage = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+                EXPECT_EQ(usage, realUsage);
+            });
+}
+
+/**
+ * Test IMapper::set(Usage) to test protected content
+ */
+TEST_F(GraphicsMapperHidlTest, SetUsageProtected) {
+    const native_handle_t* bufferHandle = nullptr;
+    auto info = mDummyDescriptorInfo;
+    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+    bufferHandle = mGralloc->allocate(info, true, true);
+    if (bufferHandle) {
+        GTEST_SUCCEED() << "unable to allocate protected content";
+    }
+
+    uint64_t usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY);
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
+
+    Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec);
+    ASSERT_EQ(err, Error::UNSUPPORTED);
+    vec.resize(0);
+
+    uint64_t realUsage = 0;
+    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec));
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+    EXPECT_EQ(info.usage, realUsage);
+}
+
+/**
+ * Test IMapper::set(AllocationSize)
+ */
+TEST_F(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_F(GraphicsMapperHidlTest, SetProtectedContent) {
+    const native_handle_t* bufferHandle = nullptr;
+    auto info = mDummyDescriptorInfo;
+    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+    bufferHandle = mGralloc->allocate(info, true, true);
+    if (bufferHandle) {
+        GTEST_SUCCEED() << "unable to allocate protected content";
+    }
+
+    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_F(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_F(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_F(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_F(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;
+    planeLayoutA.crop.left = 0;
+    planeLayoutA.crop.top = 0;
+    planeLayoutA.crop.right = info.width;
+    planeLayoutA.crop.bottom = info.height;
+
+    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 = 32;
+    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;
+    planeLayoutRGB.crop.left = 0;
+    planeLayoutRGB.crop.top = 0;
+    planeLayoutRGB.crop.right = info.width;
+    planeLayoutRGB.crop.bottom = info.height;
+
+    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";
+    }
+    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);
+
+        EXPECT_EQ(planeLayout.crop.left, realPlaneLayout.crop.left);
+        EXPECT_EQ(planeLayout.crop.top, realPlaneLayout.crop.top);
+        EXPECT_EQ(planeLayout.crop.right, realPlaneLayout.crop.right);
+        EXPECT_EQ(planeLayout.crop.bottom, realPlaneLayout.crop.bottom);
+
+        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(Dataspace)
+ */
+TEST_F(GraphicsMapperHidlTest, SetDataspace) {
+    Dataspace dataspace = Dataspace::V0_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_F(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(metadata) with a bad buffer
+ */
+TEST_F(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_Dataspace, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+}
+
+/**
+ * Test IMapper::set(metadata) for constant metadata
+ */
+TEST_F(GraphicsMapperHidlTest, SetConstantMetadata) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+    ASSERT_EQ(Error::BAD_VALUE,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+    ASSERT_EQ(Error::BAD_VALUE,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
+}
+
+/**
+ * Test IMapper::set(metadata) for bad metadata
+ */
+TEST_F(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_BufferId, vec));
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, 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_Usage, 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_Dataspace, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(BufferId)
+ */
+TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                    gralloc4::MetadataType_BufferId, &vec));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Name)
+ */
+TEST_F(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_F(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_F(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_F(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_F(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";
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    uint32_t pixelFormatFourCC = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PixelFormatModifier)
+ */
+TEST_F(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";
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    uint64_t pixelFormatModifier = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Usage)
+ */
+TEST_F(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_F(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";
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    uint64_t allocationSize = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(ProtectedContent)
+ */
+TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) {
+    auto info = mDummyDescriptorInfo;
+    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   info, gralloc4::MetadataType_ProtectedContent, &vec));
+
+    uint64_t protectedContent = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent));
+    EXPECT_EQ(1, protectedContent);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Compression)
+ */
+TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) {
+    auto info = mDummyDescriptorInfo;
+    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   info, gralloc4::MetadataType_Compression, &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::getFromBufferDescriptorInfo(Interlaced)
+ */
+TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, &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::getFromBufferDescriptorInfo(ChromaSiting)
+ */
+TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                    gralloc4::MetadataType_ChromaSiting, &vec));
+
+    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_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                    gralloc4::MetadataType_PlaneLayouts, &vec));
+
+    std::vector<PlaneLayout> planeLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+    ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Dataspace)
+ */
+TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, &vec));
+
+    Dataspace dataspace = Dataspace::DISPLAY_P3;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace));
+    EXPECT_EQ(Dataspace::UNKNOWN, dataspace);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(BlendMode)
+ */
+TEST_F(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, &vec));
+
+    BlendMode blendMode = BlendMode::COVERAGE;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode));
+    EXPECT_EQ(BlendMode::INVALID, blendMode);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata
+ */
+TEST_F(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_F(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());
+}
+
 }  // namespace
 }  // namespace vts
 }  // namespace V4_0
diff --git a/keymaster/4.1/Android.bp b/keymaster/4.1/Android.bp
new file mode 100644
index 0000000..eaa7e41
--- /dev/null
+++ b/keymaster/4.1/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.keymaster@4.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IKeymasterDevice.hal",
+        "IOperation.hal",
+    ],
+    interfaces: [
+        "android.hardware.keymaster@4.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/keymaster/4.1/IKeymasterDevice.hal b/keymaster/4.1/IKeymasterDevice.hal
new file mode 100644
index 0000000..64d2c9f
--- /dev/null
+++ b/keymaster/4.1/IKeymasterDevice.hal
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.keymaster@4.1;
+
+import @4.0::ErrorCode;
+import @4.0::HardwareAuthToken;
+import @4.0::IKeymasterDevice;
+import @4.0::KeyParameter;
+import @4.0::KeyPurpose;
+import @4.0::OperationHandle;
+import IOperation;
+
+/**
+ * @4.1::IKeymasterDevice is a minor extension to @4.0::IKeymasterDevice.  It adds support for
+ *
+ * - Partial hardware enforcment of UNLOCKED_DEVICE_REQUIRED keys;
+ * - Device-unique attestaion;
+ * - Early boot only keys;
+ * - Better cleanup of operations when clients die without completing or aborting them.
+ */
+interface IKeymasterDevice extends @4.0::IKeymasterDevice {
+    /**
+     * Called by client to notify the IKeymasterDevice that the device is now locked, and keys with
+     * the UNLOCKED_DEVICE_REQUIRED tag should no longer be usable.  When this function is called,
+     * the IKeymasterDevice should note the current timestamp, and attempts to use
+     * UNLOCKED_DEVICE_REQUIRED keys must be rejected with Error::DEVICE_LOCKED until an
+     * authentication token with a later timestamp is presented.  If the `passwordOnly' argument is
+     * set to true the sufficiently-recent authentication token must indicate that the user
+     * authenticated with a password, not a biometric.
+     *
+     * @param passwordOnly specifies whether the device must be unlocked with a password, rather
+     * than a biometric, before UNLOCKED_DEVICE_REQUIRED keys can be used.
+     */
+    deviceLocked(bool passwordOnly) generates (ErrorCode error);
+
+    /**
+     * Called by client to notify the IKeymasterDevice that the device has left the early boot
+     * state, and that keys with the EARLY_BOOT_ONLY tag may no longer be used.  All attempts to use
+     * an EARLY_BOOT_ONLY key after this method is called must fail with Error::INVALID_KEY_BLOB.
+     */
+    earlyBootEnded() generates (ErrorCode error);
+
+    /**
+     * Begins a cryptographic operation.  beginOp() is a variation on begin().  beginOp() has
+     * identical functionality to begin, but instead of an OperationHandle it returns an IOperation
+     * object.  An IKeymasterDevice HAL service must call linkToDeath() on the Operation before
+     * returning it, and the provided hidl_death_recipient, if called, must abort() the operation.
+     * This is to ensure that in the event a client crashes while an operation is in progress, the
+     * operation slot is freed and available for use by other clients.
+     *
+     * @4.1::IKeymasterDevices must implement both beginOp() and begin().
+     */
+    beginOp(KeyPurpose purpose, vec<uint8_t> keyBlob, vec<KeyParameter> inParams,
+        HardwareAuthToken authToken)
+        generates (ErrorCode error, vec<KeyParameter> outParam, IOperation operation);
+};
diff --git a/keymaster/4.1/IOperation.hal b/keymaster/4.1/IOperation.hal
new file mode 100644
index 0000000..7103e9e
--- /dev/null
+++ b/keymaster/4.1/IOperation.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.keymaster@4.1;
+
+import @4.0::ErrorCode;
+import @4.0::OperationHandle;
+
+/**
+ * IOperation represents an in-progress IKeymasterDevice operation.  It is returned by
+ * IKeymasterDevice.beginOp().
+ */
+interface IOperation {
+    /**
+     * Returns the operation handle to be used as an authentication challenge.
+     */
+    getOperationChallenge() generates (ErrorCode error, OperationHandle operation);
+};
diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp
new file mode 100644
index 0000000..b06878b
--- /dev/null
+++ b/keymaster/4.1/default/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 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.
+//
+
+cc_binary {
+    name: "android.hardware.keymaster@4.1-service",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.keymaster@4.1-service.rc"],
+    srcs: ["service.cpp"],
+
+    shared_libs: [
+        "android.hardware.keymaster@4.0",
+        "android.hardware.keymaster@4.1",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libkeymaster4",
+        "libkeymaster41",
+        "liblog",
+        "libutils",
+    ],
+
+}
diff --git a/keymaster/4.1/default/OWNERS b/keymaster/4.1/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/keymaster/4.1/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/keymaster/4.1/default/android.hardware.keymaster@4.1-service.rc b/keymaster/4.1/default/android.hardware.keymaster@4.1-service.rc
new file mode 100644
index 0000000..740b3c2
--- /dev/null
+++ b/keymaster/4.1/default/android.hardware.keymaster@4.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.keymaster-4-1 /vendor/bin/hw/android.hardware.keymaster@4.1-service
+    interface android.hardware.keymaster@4.0::IKeymasterDevice default
+    interface android.hardware.keymaster@4.1::IKeymasterDevice default
+    class early_hal
+    user system
+    group system drmrpc
diff --git a/keymaster/4.1/default/service.cpp b/keymaster/4.1/default/service.cpp
new file mode 100644
index 0000000..d79a291
--- /dev/null
+++ b/keymaster/4.1/default/service.cpp
@@ -0,0 +1,35 @@
+/*
+** 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.
+*/
+
+#include <android-base/logging.h>
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <AndroidKeymaster41Device.h>
+
+using android::hardware::keymaster::V4_0::SecurityLevel;
+
+int main() {
+    ::android::hardware::configureRpcThreadpool(1, true /* willJoinThreadpool */);
+    auto keymaster = ::keymaster::V4_1::CreateKeymasterDevice(SecurityLevel::SOFTWARE);
+    auto status = keymaster->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for Keymaster 4.1 (" << status << ")";
+    }
+
+    android::hardware::joinRpcThreadpool();
+    return -1;  // Should never get here.
+}
diff --git a/keymaster/4.1/support/Android.bp b/keymaster/4.1/support/Android.bp
new file mode 100644
index 0000000..34b6108
--- /dev/null
+++ b/keymaster/4.1/support/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 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.
+//
+
+cc_library {
+    name: "libkeymaster4_1support",
+    vendor_available: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "android.hardware.keymaster@3.0",
+        "android.hardware.keymaster@4.0",
+        "android.hardware.keymaster@4.1",
+        "libkeymaster4support",
+    ]
+}
diff --git a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
new file mode 100644
index 0000000..afc0eaf
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
+#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
+
+#include <keymasterV4_0/authorization_set.h>
+
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1 {
+
+using V4_0::AuthorizationSet;
+using V4_0::AuthorizationSetBuilder;
+using V4_0::KeyParameter;
+
+}  // namespace android::hardware::keymaster::V4_1
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
new file mode 100644
index 0000000..6ffe8e1
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_KEYMASTER_TAGS_H_
+#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_KEYMASTER_TAGS_H_
+
+#include <android/hardware/keymaster/4.1/types.h>
+
+#include <keymasterV4_0/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1 {
+
+using V4_0::BlockMode;
+using V4_0::Digest;
+using V4_0::EcCurve;
+using V4_0::ErrorCode;
+using V4_0::HardwareAuthToken;
+using V4_0::KeyParameter;
+using V4_0::PaddingMode;
+using V4_0::TagType;
+using V4_0::VerificationToken;
+
+using V4_0::TypedTag;
+
+using V4_0::TAG_ACTIVE_DATETIME;
+using V4_0::TAG_ALGORITHM;
+using V4_0::TAG_ALLOW_WHILE_ON_BODY;
+using V4_0::TAG_APPLICATION_DATA;
+using V4_0::TAG_APPLICATION_ID;
+using V4_0::TAG_ASSOCIATED_DATA;
+using V4_0::TAG_ATTESTATION_APPLICATION_ID;
+using V4_0::TAG_ATTESTATION_CHALLENGE;
+using V4_0::TAG_AUTH_TIMEOUT;
+using V4_0::TAG_BLOB_USAGE_REQUIREMENTS;
+using V4_0::TAG_BLOCK_MODE;
+using V4_0::TAG_BOOT_PATCHLEVEL;
+using V4_0::TAG_BOOTLOADER_ONLY;
+using V4_0::TAG_CALLER_NONCE;
+using V4_0::TAG_CONFIRMATION_TOKEN;
+using V4_0::TAG_CREATION_DATETIME;
+using V4_0::TAG_DIGEST;
+using V4_0::TAG_EC_CURVE;
+using V4_0::TAG_HARDWARE_TYPE;
+using V4_0::TAG_INCLUDE_UNIQUE_ID;
+using V4_0::TAG_INVALID;
+using V4_0::TAG_KEY_SIZE;
+using V4_0::TAG_MAC_LENGTH;
+using V4_0::TAG_MAX_USES_PER_BOOT;
+using V4_0::TAG_MIN_MAC_LENGTH;
+using V4_0::TAG_MIN_SECONDS_BETWEEN_OPS;
+using V4_0::TAG_NO_AUTH_REQUIRED;
+using V4_0::TAG_NONCE;
+using V4_0::TAG_ORIGIN;
+using V4_0::TAG_ORIGINATION_EXPIRE_DATETIME;
+using V4_0::TAG_OS_PATCHLEVEL;
+using V4_0::TAG_OS_VERSION;
+using V4_0::TAG_PADDING;
+using V4_0::TAG_PURPOSE;
+using V4_0::TAG_RESET_SINCE_ID_ROTATION;
+using V4_0::TAG_ROLLBACK_RESISTANCE;
+using V4_0::TAG_ROOT_OF_TRUST;
+using V4_0::TAG_RSA_PUBLIC_EXPONENT;
+using V4_0::TAG_TRUSTED_CONFIRMATION_REQUIRED;
+using V4_0::TAG_TRUSTED_USER_PRESENCE_REQUIRED;
+using V4_0::TAG_UNIQUE_ID;
+using V4_0::TAG_UNLOCKED_DEVICE_REQUIRED;
+using V4_0::TAG_USAGE_EXPIRE_DATETIME;
+using V4_0::TAG_USER_AUTH_TYPE;
+using V4_0::TAG_USER_ID;
+using V4_0::TAG_USER_SECURE_ID;
+using V4_0::TAG_VENDOR_PATCHLEVEL;
+
+#define DECLARE_KM_4_1_TYPED_TAG(name)                                                   \
+    typedef typename V4_0::Tag2TypedTag<(static_cast<V4_0::Tag>(V4_1::Tag::name))>::type \
+            TAG_##name##_t;                                                              \
+    static TAG_##name##_t TAG_##name;
+
+DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY);
+DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
+
+}  // namespace android::hardware::keymaster::V4_1
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_KEYMASTER_TAGS_H_
diff --git a/keymaster/4.1/types.hal b/keymaster/4.1/types.hal
new file mode 100644
index 0000000..bdf1731
--- /dev/null
+++ b/keymaster/4.1/types.hal
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.keymaster@4.1;
+
+import @4.0::ErrorCode;
+import @4.0::Tag;
+import @4.0::TagType;
+
+enum Tag : @4.0::Tag {
+    /**
+     * Keys tagged with EARLY_BOOT_ONLY may only be used, or created, during early boot, until
+     * IKeymasterDevice::earlyBootEnded() is called.
+     */
+    EARLY_BOOT_ONLY = TagType:BOOL | 305,
+    /**
+     * DEVICE_UNIQUE_ATTESTATION is an argument to IKeymasterDevice::attestKey().  It indicates that
+     * attestation using a device-unique key is requested, rather than a batch key.  Only
+     * SecurityLevel::STRONGBOX IKeymasterDevices may support device-unique attestations.
+     * SecurityLevel::TRUSTED_ENVIRONMENT IKeymasterDevices must return ErrorCode::INVALID_ARGUMENT
+     * if they receive DEVICE_UNIQUE_ATTESTATION.  SecurityLevel::STRONGBOX IKeymasterDevices need
+     * not support DEVICE_UNIQUE_ATTESTATION, and return ErrorCode::CANNOT_ATTEST_IDS if they do not
+     * support it.
+     *
+     * IKeymasterDevice implementations that support device-unique attestation MUST add the
+     * DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations.
+     */
+    DEVICE_UNIQUE_ATTESTATION = TagType:BOOL | 720,
+};
diff --git a/keymaster/4.1/vts/OWNERS b/keymaster/4.1/vts/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/keymaster/4.1/vts/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp
new file mode 100644
index 0000000..f5a0c9c
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 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.
+//
+
+cc_test {
+    name: "VtsHalKeymasterV4_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "EarlyBootKeyTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.keymaster@4.0",
+        "android.hardware.keymaster@4.1",
+        "libkeymaster4support",
+        "libkeymaster4_1support",
+    ],
+    test_suites: ["vts-core"],
+}
diff --git a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
new file mode 100644
index 0000000..4a19010
--- /dev/null
+++ b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 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.
+ */
+
+namespace android::hardware::keymaster::V4_1::test {
+
+// TODO(swillden): Put tests here.
+
+}  // namespace android::hardware::keymaster::V4_1::test