[sf] Pass metadata to layer during composition

Adds the simple bits of code to grab a snapshot of the front-end Layer
generic metadata, storing a copy in LayerFECompositionState, and then
sending int to the HWC2::Layer along with other "geometry update"
settings.

As the metadata stored in the layers uses integer keys, they need to be
translated to name strings. For hard-coded mapping is defined, with a
TODO left to remove the hard-coded mapping.

A test is added to ensure that the metadata is written by OutputLayer
when present, and that it is not set as part of a "per-frame" update.

Bug: 139747351
Test: atest libcompositionengine_test

Change-Id: I63f2a34e1fb70e1aefc5aa7e97ce56b7c2579a29
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 40cd3e0..d8ce629 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -40,6 +40,29 @@
 
 namespace android::compositionengine {
 
+// More complex metadata for this layer
+struct GenericLayerMetadataEntry {
+    // True if the metadata may affect the composed result.
+    // See setLayerGenericMetadata in IComposerClient.hal
+    bool mandatory;
+
+    // Byte blob or parcel
+    std::vector<uint8_t> value;
+
+    std::string dumpAsString() const;
+};
+
+inline bool operator==(const GenericLayerMetadataEntry& lhs, const GenericLayerMetadataEntry& rhs) {
+    return lhs.mandatory == rhs.mandatory && lhs.value == rhs.value;
+}
+
+// Defining PrintTo helps with Google Tests.
+inline void PrintTo(const GenericLayerMetadataEntry& v, ::std::ostream* os) {
+    *os << v.dumpAsString();
+}
+
+using GenericLayerMetadataMap = std::unordered_map<std::string, GenericLayerMetadataEntry>;
+
 /*
  * Used by LayerFE::getCompositionState
  */
@@ -115,6 +138,8 @@
     // The appId for this layer
     int appId{0};
 
+    GenericLayerMetadataMap metadata;
+
     /*
      * Per-frame content
      */
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 3e0f803..02e3a45 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -32,6 +32,20 @@
 
 } // namespace
 
+std::string GenericLayerMetadataEntry::dumpAsString() const {
+    using android::base::StringAppendF;
+    std::string out;
+
+    out.append("GenericLayerMetadataEntry{mandatory: ");
+    StringAppendF(&out, "%d", mandatory);
+    out.append(" value: ");
+    for (uint8_t byte : value) {
+        StringAppendF(&out, "0x08%" PRIx8 " ", byte);
+    }
+    out.append("]}");
+    return out;
+}
+
 LayerFECompositionState::~LayerFECompositionState() = default;
 
 void LayerFECompositionState::dump(std::string& out) const {
@@ -65,6 +79,17 @@
     dumpVal(out, "type", type);
     dumpVal(out, "appId", appId);
 
+    if (!metadata.empty()) {
+        out.append("\n      metadata {");
+        for (const auto& [key, entry] : metadata) {
+            out.append("\n           ");
+            out.append(key);
+            out.append("=");
+            out.append(entry.dumpAsString());
+        }
+        out.append("\n      }\n      ");
+    }
+
     dumpVal(out, "composition type", toString(compositionType), compositionType);
 
     out.append("\n      buffer: ");
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index b538d75..3aa7956 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -406,6 +406,14 @@
         ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(),
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
+
+    for (const auto& [name, entry] : outputIndependentState.metadata) {
+        if (auto error = hwcLayer->setLayerGenericMetadata(name, entry.mandatory, entry.value);
+            error != HWC2::Error::None) {
+            ALOGE("[%s] Failed to set generic metadata %s %s (%d)", getLayerFE().getDebugName(),
+                  name.c_str(), to_string(error).c_str(), static_cast<int32_t>(error));
+        }
+    }
 }
 
 void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
@@ -661,4 +669,3 @@
 
 } // namespace impl
 } // namespace android::compositionengine
-
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 963062f..1b5617c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -625,6 +625,8 @@
     static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
     static constexpr int kSupportedPerFrameMetadata = 101;
     static constexpr int kExpectedHwcSlot = 0;
+    static constexpr bool kLayerGenericMetadata1Mandatory = true;
+    static constexpr bool kLayerGenericMetadata2Mandatory = true;
 
     static const half4 kColor;
     static const Rect kDisplayFrame;
@@ -635,6 +637,10 @@
     static native_handle_t* kSidebandStreamHandle;
     static const sp<GraphicBuffer> kBuffer;
     static const sp<Fence> kFence;
+    static const std::string kLayerGenericMetadata1Key;
+    static const std::vector<uint8_t> kLayerGenericMetadata1Value;
+    static const std::string kLayerGenericMetadata2Key;
+    static const std::vector<uint8_t> kLayerGenericMetadata2Value;
 
     OutputLayerWriteStateToHWCTest() {
         auto& outputLayerState = mOutputLayer.editState();
@@ -669,6 +675,13 @@
     // Some tests may need to simulate unsupported HWC calls
     enum class SimulateUnsupported { None, ColorTransform };
 
+    void includeGenericLayerMetadataInState() {
+        mLayerFEState.metadata[kLayerGenericMetadata1Key] = {kLayerGenericMetadata1Mandatory,
+                                                             kLayerGenericMetadata1Value};
+        mLayerFEState.metadata[kLayerGenericMetadata2Key] = {kLayerGenericMetadata2Mandatory,
+                                                             kLayerGenericMetadata2Value};
+    }
+
     void expectGeometryCommonCalls() {
         EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
@@ -720,6 +733,18 @@
         EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence));
     }
 
+    void expectGenericLayerMetadataCalls() {
+        // Note: Can be in any order.
+        EXPECT_CALL(*mHwcLayer,
+                    setLayerGenericMetadata(kLayerGenericMetadata1Key,
+                                            kLayerGenericMetadata1Mandatory,
+                                            kLayerGenericMetadata1Value));
+        EXPECT_CALL(*mHwcLayer,
+                    setLayerGenericMetadata(kLayerGenericMetadata2Key,
+                                            kLayerGenericMetadata2Mandatory,
+                                            kLayerGenericMetadata2Value));
+    }
+
     std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
     StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
 };
@@ -739,6 +764,13 @@
         reinterpret_cast<native_handle_t*>(1031);
 const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
 const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
+const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key =
+        "com.example.metadata.1";
+const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}};
+const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Key =
+        "com.example.metadata.2";
+const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Value{
+        {4, 5, 6, 7}};
 
 TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) {
     EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr));
@@ -862,6 +894,30 @@
     mOutputLayer.writeStateToHWC(false);
 }
 
+TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+    includeGenericLayerMetadataInState();
+
+    expectGeometryCommonCalls();
+    expectPerFrameCommonCalls();
+    expectSetHdrMetadataAndBufferCalls();
+    expectGenericLayerMetadataCalls();
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+    mOutputLayer.writeStateToHWC(true);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+    includeGenericLayerMetadataInState();
+
+    expectPerFrameCommonCalls();
+    expectSetHdrMetadataAndBufferCalls();
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+    mOutputLayer.writeStateToHWC(false);
+}
+
 /*
  * OutputLayer::writeCursorPositionToHWC()
  */
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6ff23c5..e04e0ab 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -475,6 +475,26 @@
 
     compositionState->type = type;
     compositionState->appId = appId;
+
+    compositionState->metadata.clear();
+    const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
+    for (const auto& [key, mandatory] : supportedMetadata) {
+        const auto& genericLayerMetadataCompatibilityMap =
+                mFlinger->getGenericLayerMetadataKeyMap();
+        auto compatIter = genericLayerMetadataCompatibilityMap.find(key);
+        if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) {
+            continue;
+        }
+        const uint32_t id = compatIter->second;
+
+        auto it = drawingState.metadata.mMap.find(id);
+        if (it == std::end(drawingState.metadata.mMap)) {
+            continue;
+        }
+
+        compositionState->metadata
+                .emplace(key, compositionengine::GenericLayerMetadataEntry{mandatory, it->second});
+    }
 }
 
 void Layer::preparePerFrameCompositionState() {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7ed6342..084251c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5851,6 +5851,21 @@
     return NO_ERROR;
 }
 
+const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayerMetadataKeyMap()
+        const {
+    // TODO(b/149500060): Remove this fixed/static mapping. Please prefer taking
+    // on the work to remove the table in that bug rather than adding more to
+    // it.
+    static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{
+            // Note: METADATA_OWNER_UID and METADATA_WINDOW_TYPE are officially
+            // supported, and exposed via the
+            // IVrComposerClient::VrCommand::SET_LAYER_INFO command.
+            {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID},
+            {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR},
+    };
+    return genericLayerMetadataKeyMap;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8cabcf0..763df23 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1153,6 +1153,15 @@
 
     std::atomic<nsecs_t> mExpectedPresentTime = 0;
 
+    /* ------------------------------------------------------------------------
+     * Generic Layer Metadata
+     */
+    const std::unordered_map<std::string, uint32_t>& getGenericLayerMetadataKeyMap() const;
+
+    /* ------------------------------------------------------------------------
+     * Misc
+     */
+
     std::mutex mActiveConfigLock;
     // This bit is set once we start setting the config. We read from this bit during the
     // process. If at the end, this bit is different than mDesiredActiveConfig, we restart