SF: Update the cached display modes in HWComposer on hotplug
Currently configs in HWComposer are cached only once
per display and never updated on subseqent onHotplug
events. This may cause setActiveConfigsWithConstraints
to fail for a valid config.
This CL also removes the test HandleTransactionLockedTest::
processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected,
since it's testing an unsupported use case and its
incompatible with the tests we've added.
Bug: 159590486
Test: atest HWComposerConfigsTest
Change-Id: Ifb22c33ba5078bde35ae20a2f94a8630316da024
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 5fa72b8..6f3987f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -74,6 +74,7 @@
namespace hal = android::hardware::graphics::composer::hal;
+namespace android {
namespace {
using android::hardware::Return;
@@ -88,47 +89,46 @@
mSequenceId(sequenceId),
mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
- android::hardware::Return<void> onHotplug(hal::HWDisplayId display,
- hal::Connection conn) override {
+ Return<void> onHotplug(hal::HWDisplayId display, hal::Connection conn) override {
mCallback->onHotplugReceived(mSequenceId, display, conn);
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onRefresh(hal::HWDisplayId display) override {
+ Return<void> onRefresh(hal::HWDisplayId display) override {
mCallback->onRefreshReceived(mSequenceId, display);
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onVsync(hal::HWDisplayId display, int64_t timestamp) override {
+ Return<void> onVsync(hal::HWDisplayId display, int64_t timestamp) override {
if (!mVsyncSwitchingSupported) {
mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
} else {
ALOGW("Unexpected onVsync callback on composer >= 2.4, ignoring.");
}
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onVsync_2_4(hal::HWDisplayId display, int64_t timestamp,
- hal::VsyncPeriodNanos vsyncPeriodNanos) override {
+ Return<void> onVsync_2_4(hal::HWDisplayId display, int64_t timestamp,
+ hal::VsyncPeriodNanos vsyncPeriodNanos) override {
if (mVsyncSwitchingSupported) {
mCallback->onVsyncReceived(mSequenceId, display, timestamp,
std::make_optional(vsyncPeriodNanos));
} else {
ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring.");
}
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onVsyncPeriodTimingChanged(
+ Return<void> onVsyncPeriodTimingChanged(
hal::HWDisplayId display,
const hal::VsyncPeriodChangeTimeline& updatedTimeline) override {
mCallback->onVsyncPeriodTimingChangedReceived(mSequenceId, display, updatedTimeline);
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onSeamlessPossible(hal::HWDisplayId display) override {
+ Return<void> onSeamlessPossible(hal::HWDisplayId display) override {
mCallback->onSeamlessPossible(mSequenceId, display);
- return android::hardware::Void();
+ return Void();
}
private:
@@ -139,8 +139,6 @@
} // namespace
-namespace android {
-
HWComposer::~HWComposer() = default;
namespace impl {
@@ -295,6 +293,7 @@
hal::DisplayType::PHYSICAL);
newDisplay->setConnected(true);
displayData.hwcDisplay = std::move(newDisplay);
+ displayData.configs = displayData.hwcDisplay->getConfigs();
mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
}
@@ -335,14 +334,9 @@
PhysicalDisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
- const auto& displayData = mDisplayData.at(displayId);
- auto configs = displayData.hwcDisplay->getConfigs();
- if (displayData.configMap.empty()) {
- for (size_t i = 0; i < configs.size(); ++i) {
- displayData.configMap[i] = configs[i];
- }
- }
- return configs;
+ // We cache the configs when the DisplayData is created on hotplug. If the configs need to
+ // change HWC will send a hotplug event which will recreate displayData.
+ return mDisplayData.at(displayId).configs;
}
std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
@@ -653,13 +647,13 @@
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
- if (displayData.configMap.count(configId) == 0) {
+ if (configId >= displayData.configs.size()) {
LOG_DISPLAY_ERROR(displayId, ("Invalid config " + std::to_string(configId)).c_str());
return BAD_INDEX;
}
auto error =
- displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configMap[configId],
+ displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configs[configId],
constraints, outTimeline);
RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
return NO_ERROR;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index d8af5bf..81750de 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -183,7 +183,6 @@
virtual nsecs_t getRefreshTimestamp(PhysicalDisplayId) const = 0;
virtual bool isConnected(PhysicalDisplayId) const = 0;
- // Non-const because it can update configMap inside of mDisplayData
virtual std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
PhysicalDisplayId) const = 0;
@@ -319,7 +318,6 @@
nsecs_t getRefreshTimestamp(PhysicalDisplayId) const override;
bool isConnected(PhysicalDisplayId) const override;
- // Non-const because it can update configMap inside of mDisplayData
std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
PhysicalDisplayId) const override;
@@ -378,8 +376,7 @@
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
buffer_handle_t outbufHandle = nullptr;
sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
- mutable std::unordered_map<int32_t,
- std::shared_ptr<const HWC2::Display::Config>> configMap;
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
bool validateWasSkipped;
hal::Error presentError;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 5b78483..f19177b 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -528,6 +528,7 @@
HwcConfigIndexType currentConfigId)
: mKnownFrameRates(constructKnownFrameRates(configs)) {
LOG_ALWAYS_FATAL_IF(configs.empty());
+ LOG_ALWAYS_FATAL_IF(currentConfigId.value() < 0);
LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());
for (auto configId = HwcConfigIndexType(0); configId.value() < configs.size(); configId++) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index db75312..cadea69 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -865,26 +865,12 @@
/*
* H/W composer
*/
-
- // The current hardware composer interface.
- //
- // The following thread safety rules apply when accessing mHwc, either
- // directly or via getHwComposer():
- //
- // 1. When recreating mHwc, acquire mStateLock. Recreating mHwc must only be
- // done on the main thread.
- //
- // 2. When accessing mHwc on the main thread, it's not necessary to acquire
- // mStateLock.
- //
- // 3. When accessing mHwc on a thread other than the main thread, we always
+ // The following thread safety rules apply when accessing HWComposer:
+ // 1. When reading display state from HWComposer on the main thread, it's not necessary to
+ // acquire mStateLock.
+ // 2. When accessing HWComposer on a thread other than the main thread, we always
// need to acquire mStateLock. This is because the main thread could be
- // in the process of destroying the current mHwc instance.
- //
- // The above thread safety rules only apply to SurfaceFlinger.cpp. In
- // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
- // destroy it, so it's always safe to access mHwc from any thread without
- // acquiring mStateLock.
+ // in the process of writing display state, e.g. creating or destroying a display.
HWComposer& getHwComposer() const;
/*
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 01cdb28..012b55b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -364,7 +364,7 @@
static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
// The HWC active configuration id
- static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
+ static constexpr hal::HWConfigId HWC_ACTIVE_CONFIG_ID = 2001;
static constexpr PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
@@ -415,6 +415,45 @@
ceDisplayArgs);
}
+ static void setupHwcGetConfigsCallExpectations(DisplayTransactionTest* test) {
+ if (HWC_DISPLAY_TYPE == DisplayType::PHYSICAL) {
+ EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(std::vector<hal::HWConfigId>{
+ HWC_ACTIVE_CONFIG_ID}),
+ Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::WIDTH, _))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::HEIGHT, _))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::VSYNC_PERIOD, _))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::DPI_X, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::DPI_Y, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::CONFIG_GROUP, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
+ } else {
+ EXPECT_CALL(*test->mComposer, getDisplayConfigs(_, _)).Times(0);
+ EXPECT_CALL(*test->mComposer, getDisplayAttribute(_, _, _, _)).Times(0);
+ }
+ }
+
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
constexpr auto CONNECTION_TYPE =
PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
@@ -426,33 +465,8 @@
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
.WillOnce(Return(hal::Error::NONE));
- EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
- Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::WIDTH, _))
- .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::HEIGHT, _))
- .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::VSYNC_PERIOD, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::DPI_X, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::DPI_Y, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::CONFIG_GROUP, _))
- .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
+
+ setupHwcGetConfigsCallExpectations(test);
if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
@@ -559,6 +573,11 @@
ceDisplayArgs);
}
+ static void setupHwcGetConfigsCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayConfigs(_, _)).Times(0);
+ EXPECT_CALL(*test->mComposer, getDisplayAttribute(_, _, _, _)).Times(0);
+ }
+
static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
}
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index fa12315..bc1e88a 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -42,7 +42,10 @@
namespace android {
namespace {
-namespace hal = android::hardware::graphics::composer::hal;
+namespace V2_1 = hardware::graphics::composer::V2_1;
+namespace V2_4 = hardware::graphics::composer::V2_4;
+
+using Hwc2::Config;
using ::testing::_;
using ::testing::DoAll;
@@ -170,5 +173,88 @@
EXPECT_EQ(hal::Error::UNSUPPORTED, result);
}
+class HWComposerConfigsTest : public testing::Test {
+public:
+ Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
+ MockHWC2ComposerCallback mCallback;
+
+ void setActiveConfig(Config config) {
+ EXPECT_CALL(*mHal, getActiveConfig(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(config), Return(V2_1::Error::NONE)));
+ }
+
+ void setDisplayConfigs(std::vector<Config> configs) {
+ EXPECT_CALL(*mHal, getDisplayConfigs(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(configs), Return(V2_1::Error::NONE)));
+ EXPECT_CALL(*mHal, getDisplayAttribute(_, _, _, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(1), Return(V2_1::Error::NONE)));
+ }
+
+ void testSetActiveConfigWithConstraintsCommon(bool isVsyncPeriodSwitchSupported);
+};
+
+void HWComposerConfigsTest::testSetActiveConfigWithConstraintsCommon(
+ bool isVsyncPeriodSwitchSupported) {
+ EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+ EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+ EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)).WillOnce(Return(V2_4::Error::UNSUPPORTED));
+ EXPECT_CALL(*mHal, registerCallback(_));
+ EXPECT_CALL(*mHal, setVsyncEnabled(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
+ EXPECT_CALL(*mHal, getDisplayIdentificationData(_, _, _))
+ .WillRepeatedly(Return(V2_1::Error::UNSUPPORTED));
+ EXPECT_CALL(*mHal, setClientTargetSlotCount(_)).WillRepeatedly(Return(V2_1::Error::NONE));
+
+ EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported())
+ .WillRepeatedly(Return(isVsyncPeriodSwitchSupported));
+
+ if (isVsyncPeriodSwitchSupported) {
+ EXPECT_CALL(*mHal, setActiveConfigWithConstraints(_, _, _, _))
+ .WillRepeatedly(Return(V2_4::Error::NONE));
+ } else {
+ EXPECT_CALL(*mHal, setActiveConfig(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
+ }
+
+ impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+ hwc.setConfiguration(&mCallback, 123);
+
+ setDisplayConfigs({15});
+ setActiveConfig(15);
+
+ const auto physicalId = PhysicalDisplayId::fromPort(0);
+ const hal::HWDisplayId hwcId = 0;
+ hwc.allocatePhysicalDisplay(hwcId, physicalId);
+
+ hal::VsyncPeriodChangeConstraints constraints;
+ constraints.desiredTimeNanos = systemTime();
+ constraints.seamlessRequired = false;
+
+ hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
+ constexpr size_t kConfigIndex = 0;
+ const auto status =
+ hwc.setActiveConfigWithConstraints(physicalId, kConfigIndex, constraints, &timeline);
+ EXPECT_EQ(NO_ERROR, status);
+
+ const std::vector<Config> kConfigs{7, 8, 9, 10, 11};
+ // Change the set of supported modes.
+ setDisplayConfigs(kConfigs);
+ setActiveConfig(11);
+ hwc.onHotplug(hwcId, hal::Connection::CONNECTED);
+ hwc.allocatePhysicalDisplay(hwcId, physicalId);
+
+ for (size_t configIndex = 0; configIndex < kConfigs.size(); configIndex++) {
+ const auto status =
+ hwc.setActiveConfigWithConstraints(physicalId, configIndex, constraints, &timeline);
+ EXPECT_EQ(NO_ERROR, status) << "Error when switching to config " << configIndex;
+ }
+}
+
+TEST_F(HWComposerConfigsTest, setActiveConfigWithConstraintsWithVsyncSwitchingSupported) {
+ testSetActiveConfigWithConstraintsCommon(/*supported=*/true);
+}
+
+TEST_F(HWComposerConfigsTest, setActiveConfigWithConstraintsWithVsyncSwitchingNotSupported) {
+ testSetActiveConfigWithConstraintsCommon(/*supported=*/false);
+}
+
} // namespace
-} // namespace android
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
index cd3f6ab..65efc85 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
@@ -144,7 +144,7 @@
// SF should have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+ ASSERT_EQ(mFlinger.mutablePhysicalDisplayTokens().count(displayId), 1);
auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
verifyDisplayIsConnected<Case>(displayToken);
@@ -259,14 +259,6 @@
processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest,
- processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected) {
- // Inject an external display.
- ExternalDisplayVariant::injectHwcDisplay(this);
-
- processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
-}
-
TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 61f0788..cedb404 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -223,6 +223,7 @@
// Various native window calls will be made.
Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+ Case::Display::setupHwcGetConfigsCallExpectations(this);
Case::WideColorSupport::setupComposerCallExpectations(this);
Case::HdrSupport::setupComposerCallExpectations(this);
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
@@ -236,6 +237,7 @@
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
ASSERT_TRUE(hwcDisplayId);
+ mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId);
state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId};
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 25aaa14..b57d473 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -561,8 +561,15 @@
const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId);
LOG_ALWAYS_FATAL_IF(!physicalId);
flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, *physicalId);
- (mIsPrimary ? flinger->mutableInternalHwcDisplayId()
- : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
+ if (mIsPrimary) {
+ flinger->mutableInternalHwcDisplayId() = mHwcDisplayId;
+ } else {
+ // If there is an external HWC display there should always be an internal ID
+ // as well. Set it to some arbitrary value.
+ auto& internalId = flinger->mutableInternalHwcDisplayId();
+ if (!internalId) internalId = mHwcDisplayId - 1;
+ flinger->mutableExternalHwcDisplayId() = mHwcDisplayId;
+ }
}
}