ui: Refactor stable ID generation for GPU virtual displays

This is a partial port of  http://ag/17832464 for main.

Use ftl::stable_hash to generate stable ID from uniqueId for GPU virtual
displays. This allows FLAG_STABLE consistent with PhysicalDisplayId that
uses a unique EDID, as well as being stable across reboots when using
hardcoded or static unique ID.

Add DisplayId.isStable()/isVirtual() interfaces and refactor previous
legacy usages.

Bug: 339525838
Bug: 137375833
Bug: 194863377
Test: atest libsurfaceflinger_unittest
Test: atest DisplayId_test
Flag: EXEMPT refactor
Change-Id: I54f4d3803c8c23266a3461660146af7ae017e4be
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h
index 3a31fa0..8a14db8 100644
--- a/libs/ui/include/ui/DisplayId.h
+++ b/libs/ui/include/ui/DisplayId.h
@@ -20,6 +20,7 @@
 #include <ostream>
 #include <string>
 
+#include <ftl/hash.h>
 #include <ftl/optional.h>
 
 namespace android {
@@ -38,6 +39,9 @@
     constexpr DisplayId(const DisplayId&) = default;
     DisplayId& operator=(const DisplayId&) = default;
 
+    constexpr bool isVirtual() const { return value & FLAG_VIRTUAL; }
+    constexpr bool isStable() const { return value & FLAG_STABLE; }
+
     uint64_t value;
 
     // For deserialization.
@@ -76,10 +80,10 @@
 // DisplayId of a physical display, such as the internal display or externally connected display.
 struct PhysicalDisplayId : DisplayId {
     static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) {
-        if (id.value & FLAG_VIRTUAL) {
+        if (id.isVirtual()) {
             return std::nullopt;
         }
-        return {PhysicalDisplayId(id)};
+        return PhysicalDisplayId(id);
     }
 
     // Returns a stable ID based on EDID information.
@@ -117,25 +121,23 @@
     static constexpr uint64_t FLAG_GPU = 1ULL << 61;
 
     static constexpr std::optional<VirtualDisplayId> tryCast(DisplayId id) {
-        if (id.value & FLAG_VIRTUAL) {
-            return {VirtualDisplayId(id)};
+        if (id.isVirtual()) {
+            return VirtualDisplayId(id);
         }
         return std::nullopt;
     }
 
 protected:
-    constexpr VirtualDisplayId(uint64_t flags, BaseId baseId)
-          : DisplayId(DisplayId::FLAG_VIRTUAL | flags | baseId) {}
-
+    explicit constexpr VirtualDisplayId(uint64_t value) : DisplayId(FLAG_VIRTUAL | value) {}
     explicit constexpr VirtualDisplayId(DisplayId other) : DisplayId(other) {}
 };
 
 struct HalVirtualDisplayId : VirtualDisplayId {
-    explicit constexpr HalVirtualDisplayId(BaseId baseId) : VirtualDisplayId(0, baseId) {}
+    explicit constexpr HalVirtualDisplayId(BaseId baseId) : VirtualDisplayId(baseId) {}
 
     static constexpr std::optional<HalVirtualDisplayId> tryCast(DisplayId id) {
-        if ((id.value & FLAG_VIRTUAL) && !(id.value & VirtualDisplayId::FLAG_GPU)) {
-            return {HalVirtualDisplayId(id)};
+        if (id.isVirtual() && !(id.value & FLAG_GPU)) {
+            return HalVirtualDisplayId(id);
         }
         return std::nullopt;
     }
@@ -145,17 +147,27 @@
 };
 
 struct GpuVirtualDisplayId : VirtualDisplayId {
-    explicit constexpr GpuVirtualDisplayId(BaseId baseId)
-          : VirtualDisplayId(VirtualDisplayId::FLAG_GPU, baseId) {}
+    explicit constexpr GpuVirtualDisplayId(BaseId baseId) : VirtualDisplayId(FLAG_GPU | baseId) {}
+
+    static constexpr std::optional<GpuVirtualDisplayId> fromUniqueId(const std::string& uniqueId) {
+        if (const auto hashOpt = ftl::stable_hash(uniqueId)) {
+            return GpuVirtualDisplayId(HashTag{}, *hashOpt);
+        }
+        return {};
+    }
 
     static constexpr std::optional<GpuVirtualDisplayId> tryCast(DisplayId id) {
-        if ((id.value & FLAG_VIRTUAL) && (id.value & VirtualDisplayId::FLAG_GPU)) {
-            return {GpuVirtualDisplayId(id)};
+        if (id.isVirtual() && (id.value & FLAG_GPU)) {
+            return GpuVirtualDisplayId(id);
         }
         return std::nullopt;
     }
 
 private:
+    struct HashTag {}; // Disambiguate with BaseId constructor.
+    constexpr GpuVirtualDisplayId(HashTag, uint64_t hash)
+          : VirtualDisplayId(FLAG_STABLE | FLAG_GPU | hash) {}
+
     explicit constexpr GpuVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {}
 };
 
@@ -169,7 +181,7 @@
         if (GpuVirtualDisplayId::tryCast(id)) {
             return std::nullopt;
         }
-        return {HalDisplayId(id)};
+        return HalDisplayId(id);
     }
 
 private:
diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp
index 8ddee7e..1115804 100644
--- a/libs/ui/tests/DisplayId_test.cpp
+++ b/libs/ui/tests/DisplayId_test.cpp
@@ -24,7 +24,7 @@
     constexpr uint8_t port = 1;
     constexpr uint16_t manufacturerId = 13;
     constexpr uint32_t modelHash = 42;
-    PhysicalDisplayId id = PhysicalDisplayId::fromEdid(port, manufacturerId, modelHash);
+    const PhysicalDisplayId id = PhysicalDisplayId::fromEdid(port, manufacturerId, modelHash);
     EXPECT_EQ(port, id.getPort());
     EXPECT_EQ(manufacturerId, id.getManufacturerId());
     EXPECT_FALSE(VirtualDisplayId::tryCast(id));
@@ -39,7 +39,7 @@
 
 TEST(DisplayIdTest, createPhysicalIdFromPort) {
     constexpr uint8_t port = 3;
-    PhysicalDisplayId id = PhysicalDisplayId::fromPort(port);
+    const PhysicalDisplayId id = PhysicalDisplayId::fromPort(port);
     EXPECT_EQ(port, id.getPort());
     EXPECT_FALSE(VirtualDisplayId::tryCast(id));
     EXPECT_FALSE(HalVirtualDisplayId::tryCast(id));
@@ -52,7 +52,22 @@
 }
 
 TEST(DisplayIdTest, createGpuVirtualId) {
-    GpuVirtualDisplayId id(42);
+    const GpuVirtualDisplayId id(42);
+    EXPECT_TRUE(VirtualDisplayId::tryCast(id));
+    EXPECT_TRUE(GpuVirtualDisplayId::tryCast(id));
+    EXPECT_FALSE(HalVirtualDisplayId::tryCast(id));
+    EXPECT_FALSE(PhysicalDisplayId::tryCast(id));
+    EXPECT_FALSE(HalDisplayId::tryCast(id));
+
+    EXPECT_EQ(id, DisplayId::fromValue(id.value));
+    EXPECT_EQ(id, DisplayId::fromValue<GpuVirtualDisplayId>(id.value));
+}
+
+TEST(DisplayIdTest, createGpuVirtualIdFromUniqueId) {
+    static const std::string kUniqueId("virtual:ui:DisplayId_test");
+    const auto idOpt = GpuVirtualDisplayId::fromUniqueId(kUniqueId);
+    ASSERT_TRUE(idOpt.has_value());
+    const GpuVirtualDisplayId id = idOpt.value();
     EXPECT_TRUE(VirtualDisplayId::tryCast(id));
     EXPECT_TRUE(GpuVirtualDisplayId::tryCast(id));
     EXPECT_FALSE(HalVirtualDisplayId::tryCast(id));
@@ -64,7 +79,7 @@
 }
 
 TEST(DisplayIdTest, createHalVirtualId) {
-    HalVirtualDisplayId id(42);
+    const HalVirtualDisplayId id(42);
     EXPECT_TRUE(VirtualDisplayId::tryCast(id));
     EXPECT_TRUE(HalVirtualDisplayId::tryCast(id));
     EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id));