Loading services/surfaceflinger/Display/DisplayIdentification.cpp +12 −7 Original line number Diff line number Diff line Loading @@ -318,24 +318,29 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { view = view.subspan(kDescriptorLength); } // Prefer display name instead of using product code or (integer) serial number, since the // latter have been observed to change on some displays with multiple inputs. As fields are // discovered to be empty, fall back to less reliable fields. std::string_view modelString = displayName; if (modelString.empty()) { ALOGW("Invalid EDID: falling back to serial number due to missing display name."); ALOGW("EDID: falling back to serial number due to missing display name."); modelString = descriptorBlockSerialNumber; } if (modelString.empty()) { ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number."); ALOGW("EDID: falling back to ASCII text due to missing serial number."); modelString = asciiText; } std::string productString; if (modelString.empty()) { ALOGE("Invalid EDID: display name and fallback descriptors are missing."); return {}; ALOGW("EDID: falling back to PNP + ProductID due to missing unspecified text."); productString = std::string(pnpId->data()) + std::to_string(productId); modelString = productString; } // Hash model string instead of using product code or (integer) serial number, since the latter // have been observed to change on some displays with multiple inputs. Use a stable hash instead // of std::hash which is only required to be same within a single execution of a program. // Use a stable hash instead of std::hash which is only required to be same within a single // execution of a program. const uint32_t modelHash = static_cast<uint32_t>(*ftl::stable_hash(modelString)); // Parse extension blocks. Loading services/surfaceflinger/tests/unittests/DisplayIdentification_test.cpp +37 −0 Original line number Diff line number Diff line Loading @@ -130,6 +130,16 @@ const unsigned char kCtlDisplayEdid[] = "\x10\x3e\x96\x00\x09\x25\x21\x00\x00\x18\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4"; const unsigned char kEdidWithMissingDescriptors[] = "\x00\xff\xff\xff\xff\xff\xff\x00\x09\xe5\x76\x0a\x00\x00\x00\x00" "\x19\x1f\x01\x04\xa5\x1c\x13\x78\x03\xee\x95\xa3\x54\x4c\x99\x26" "\x0f\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" "\x01\x01\x01\x01\x01\x01\x12\x5c\xd0\x18\x81\xe0\x2d\x50\x30\x20" "\x36\x00\x1d\xbe\x10\x00\x00\x1a\x62\x3d\xd0\x18\x81\xe0\x2d\x50" "\x30\x20\x36\x00\x1d\xbe\x10\x00\x00\x1a\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" "\x00\x0d\x28\xff\x0a\x3c\xc8\x0f\x0b\x23\xc8\x00\x00\x00\x00\xcc"; template <size_t N> DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) { return DisplayIdentificationData(bytes, bytes + N - 1); Loading Loading @@ -171,6 +181,12 @@ const DisplayIdentificationData& getCtlDisplayEdid() { return data; } const DisplayIdentificationData& getEdidWithMissingDescriptors() { static const DisplayIdentificationData data = asDisplayIdentificationData(kEdidWithMissingDescriptors); return data; } TEST(DisplayIdentificationTest, isEdid) { EXPECT_FALSE(isEdid({})); Loading Loading @@ -328,6 +344,27 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(768, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); EXPECT_EQ(521, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); EXPECT_EQ(293, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); edid = parseEdid(getEdidWithMissingDescriptors()); ASSERT_TRUE(edid); EXPECT_EQ("", edid->displayName); EXPECT_TRUE(!edid->hashedBlockZeroSerialNumberOpt.has_value()); EXPECT_FALSE(edid->hashedDescriptorBlockSerialNumberOpt.has_value()); EXPECT_EQ(2533, edid->manufacturerId); EXPECT_STREQ("BOE", edid->pnpId.data()); EXPECT_EQ(2678, edid->productId); // modelHash derived from PNP ID and Product ID since descriptors are missing. EXPECT_EQ(hash("BOE2678"), edid->modelHash); EXPECT_EQ(hash("BOE2678"), 565221063); EXPECT_EQ(31, edid->manufactureOrModelYear); EXPECT_EQ(25, edid->manufactureWeek); EXPECT_EQ(28, edid->physicalSizeInCm.width); EXPECT_EQ(19, edid->physicalSizeInCm.height); ASSERT_TRUE(!edid->cea861Block); EXPECT_EQ(2256, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width); EXPECT_EQ(1504, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); EXPECT_EQ(285, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); EXPECT_EQ(190, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); } TEST(DisplayIdentificationTest, parseInvalidEdid) { Loading Loading
services/surfaceflinger/Display/DisplayIdentification.cpp +12 −7 Original line number Diff line number Diff line Loading @@ -318,24 +318,29 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { view = view.subspan(kDescriptorLength); } // Prefer display name instead of using product code or (integer) serial number, since the // latter have been observed to change on some displays with multiple inputs. As fields are // discovered to be empty, fall back to less reliable fields. std::string_view modelString = displayName; if (modelString.empty()) { ALOGW("Invalid EDID: falling back to serial number due to missing display name."); ALOGW("EDID: falling back to serial number due to missing display name."); modelString = descriptorBlockSerialNumber; } if (modelString.empty()) { ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number."); ALOGW("EDID: falling back to ASCII text due to missing serial number."); modelString = asciiText; } std::string productString; if (modelString.empty()) { ALOGE("Invalid EDID: display name and fallback descriptors are missing."); return {}; ALOGW("EDID: falling back to PNP + ProductID due to missing unspecified text."); productString = std::string(pnpId->data()) + std::to_string(productId); modelString = productString; } // Hash model string instead of using product code or (integer) serial number, since the latter // have been observed to change on some displays with multiple inputs. Use a stable hash instead // of std::hash which is only required to be same within a single execution of a program. // Use a stable hash instead of std::hash which is only required to be same within a single // execution of a program. const uint32_t modelHash = static_cast<uint32_t>(*ftl::stable_hash(modelString)); // Parse extension blocks. Loading
services/surfaceflinger/tests/unittests/DisplayIdentification_test.cpp +37 −0 Original line number Diff line number Diff line Loading @@ -130,6 +130,16 @@ const unsigned char kCtlDisplayEdid[] = "\x10\x3e\x96\x00\x09\x25\x21\x00\x00\x18\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4"; const unsigned char kEdidWithMissingDescriptors[] = "\x00\xff\xff\xff\xff\xff\xff\x00\x09\xe5\x76\x0a\x00\x00\x00\x00" "\x19\x1f\x01\x04\xa5\x1c\x13\x78\x03\xee\x95\xa3\x54\x4c\x99\x26" "\x0f\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" "\x01\x01\x01\x01\x01\x01\x12\x5c\xd0\x18\x81\xe0\x2d\x50\x30\x20" "\x36\x00\x1d\xbe\x10\x00\x00\x1a\x62\x3d\xd0\x18\x81\xe0\x2d\x50" "\x30\x20\x36\x00\x1d\xbe\x10\x00\x00\x1a\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" "\x00\x0d\x28\xff\x0a\x3c\xc8\x0f\x0b\x23\xc8\x00\x00\x00\x00\xcc"; template <size_t N> DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) { return DisplayIdentificationData(bytes, bytes + N - 1); Loading Loading @@ -171,6 +181,12 @@ const DisplayIdentificationData& getCtlDisplayEdid() { return data; } const DisplayIdentificationData& getEdidWithMissingDescriptors() { static const DisplayIdentificationData data = asDisplayIdentificationData(kEdidWithMissingDescriptors); return data; } TEST(DisplayIdentificationTest, isEdid) { EXPECT_FALSE(isEdid({})); Loading Loading @@ -328,6 +344,27 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(768, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); EXPECT_EQ(521, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); EXPECT_EQ(293, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); edid = parseEdid(getEdidWithMissingDescriptors()); ASSERT_TRUE(edid); EXPECT_EQ("", edid->displayName); EXPECT_TRUE(!edid->hashedBlockZeroSerialNumberOpt.has_value()); EXPECT_FALSE(edid->hashedDescriptorBlockSerialNumberOpt.has_value()); EXPECT_EQ(2533, edid->manufacturerId); EXPECT_STREQ("BOE", edid->pnpId.data()); EXPECT_EQ(2678, edid->productId); // modelHash derived from PNP ID and Product ID since descriptors are missing. EXPECT_EQ(hash("BOE2678"), edid->modelHash); EXPECT_EQ(hash("BOE2678"), 565221063); EXPECT_EQ(31, edid->manufactureOrModelYear); EXPECT_EQ(25, edid->manufactureWeek); EXPECT_EQ(28, edid->physicalSizeInCm.width); EXPECT_EQ(19, edid->physicalSizeInCm.height); ASSERT_TRUE(!edid->cea861Block); EXPECT_EQ(2256, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width); EXPECT_EQ(1504, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); EXPECT_EQ(285, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); EXPECT_EQ(190, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); } TEST(DisplayIdentificationTest, parseInvalidEdid) { Loading