SF: Populate DisplayConnectionType in DisplayInfo
Without HWC support, fall back to categorizing the primary display as
internal, and secondary displays as external.
Also, validate displays in HWComposer for other 2.4 APIs.
Bug: 134771872
Test: dumpsys SurfaceFlinger --displays
Test: dumpsys display
Test: libsurfaceflinger_unittest
Change-Id: I139eeab9cc34e21a1b8584a2fcb9c9fd5dc43ac3
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 7773319..69f86d3 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -20,8 +20,11 @@
namespace android {
+enum class DisplayConnectionType { Internal, External };
+
// Immutable information about physical display.
struct DisplayInfo {
+ DisplayConnectionType connectionType = DisplayConnectionType::Internal;
float density = 0.f;
bool secure = false;
};
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 502a33f..358177e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -88,6 +88,7 @@
MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(DisplayId));
MOCK_METHOD3(setActiveColorMode, status_t(DisplayId, ui::ColorMode, ui::RenderIntent));
MOCK_CONST_METHOD0(isUsingVrComposer, bool());
+ MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(DisplayId));
MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(DisplayId));
MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(DisplayId));
MOCK_METHOD4(setActiveConfigWithConstraints,
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6ff39b4..cd6bbd1 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -49,16 +49,16 @@
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId)
+ std::optional<DisplayId> displayId)
: flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
: mFlinger(args.flinger),
mDisplayToken(args.displayToken),
mSequenceId(args.sequenceId),
- mIsVirtual(args.isVirtual),
+ mConnectionType(args.connectionType),
mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
- compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId,
+ compositionengine::DisplayCreationArgs{args.isVirtual(), args.displayId,
args.powerAdvisor})},
mPhysicalOrientation(args.physicalOrientation),
mIsPrimary(args.isPrimary) {
@@ -248,10 +248,18 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = getId() ? to_string(*getId()) + ", " : std::string();
- return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
- isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
- mDisplayName.c_str());
+ std::string displayId;
+ if (const auto id = getId()) {
+ displayId = to_string(*id) + ", ";
+ }
+
+ const char* type = "virtual";
+ if (mConnectionType) {
+ type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external";
+ }
+
+ return base::StringPrintf("DisplayDevice{%s%s%s, \"%s\"}", displayId.c_str(), type,
+ isPrimary() ? ", primary" : "", mDisplayName.c_str());
}
void DisplayDevice::dump(std::string& result) const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index f45feae..d970b82 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,6 +28,7 @@
#include <math/mat4.h>
#include <renderengine/RenderEngine.h>
#include <system/window.h>
+#include <ui/DisplayInfo.h>
#include <ui/DisplayState.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
@@ -52,7 +53,6 @@
struct CompositionInfo;
struct DisplayDeviceCreationArgs;
-struct DisplayInfo;
namespace compositionengine {
class Display;
@@ -71,7 +71,9 @@
return mCompositionDisplay;
}
- bool isVirtual() const { return mIsVirtual; }
+ std::optional<DisplayConnectionType> getConnectionType() const { return mConnectionType; }
+
+ bool isVirtual() const { return !mConnectionType; }
bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
@@ -159,7 +161,7 @@
const sp<SurfaceFlinger> mFlinger;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
- const bool mIsVirtual;
+ const std::optional<DisplayConnectionType> mConnectionType;
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
@@ -178,10 +180,19 @@
};
struct DisplayDeviceState {
- bool isVirtual() const { return !displayId.has_value(); }
+ struct Physical {
+ DisplayId id;
+ DisplayConnectionType type;
+
+ bool operator==(const Physical& other) const {
+ return id == other.id && type == other.type;
+ }
+ };
+
+ bool isVirtual() const { return !physical; }
int32_t sequenceId = sNextSequenceId++;
- std::optional<DisplayId> displayId;
+ std::optional<Physical> physical;
sp<IGraphicBufferProducer> surface;
ui::LayerStack layerStack = ui::NO_LAYER_STACK;
Rect viewport;
@@ -199,15 +210,17 @@
struct DisplayDeviceCreationArgs {
// We use a constructor to ensure some of the values are set, without
// assuming a default value.
- DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId);
+ DisplayDeviceCreationArgs(const sp<SurfaceFlinger>&, const wp<IBinder>& displayToken,
+ std::optional<DisplayId>);
+
+ bool isVirtual() const { return !connectionType; }
const sp<SurfaceFlinger> flinger;
const wp<IBinder> displayToken;
const std::optional<DisplayId> displayId;
int32_t sequenceId{0};
- bool isVirtual{false};
+ std::optional<DisplayConnectionType> connectionType;
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<compositionengine::DisplaySurface> displaySurface;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 41e7879..dd3dba1 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -95,13 +95,13 @@
}
namespace impl {
+
Display::Display(android::Hwc2::Composer& composer,
const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
DisplayType type)
: mComposer(composer),
mCapabilities(capabilities),
mId(id),
- mIsConnected(false),
mType(type) {
ALOGV("Created display %" PRIu64, id);
}
@@ -109,20 +109,27 @@
Display::~Display() {
mLayers.clear();
- if (mType == DisplayType::Virtual) {
- ALOGV("Destroying virtual display");
- auto intError = mComposer.destroyVirtualDisplay(mId);
- auto error = static_cast<Error>(intError);
- ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64
- ") failed: %s (%d)", mId, to_string(error).c_str(), intError);
- } else if (mType == DisplayType::Physical) {
- auto error = setVsyncEnabled(HWC2::Vsync::Disable);
- if (error != Error::None) {
- ALOGE("~Display: Failed to disable vsync for display %" PRIu64
- ": %s (%d)", mId, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ Error error = Error::None;
+ const char* msg;
+ switch (mType) {
+ case DisplayType::Physical:
+ error = setVsyncEnabled(HWC2::Vsync::Disable);
+ msg = "disable VSYNC for";
+ break;
+
+ case DisplayType::Virtual:
+ error = static_cast<Error>(mComposer.destroyVirtualDisplay(mId));
+ msg = "destroy virtual";
+ break;
+
+ case DisplayType::Invalid: // Used in unit tests.
+ break;
}
+
+ ALOGE_IF(error != Error::None, "%s: Failed to %s display %" PRIu64 ": %s (%d)", __FUNCTION__,
+ msg, mId, to_string(error).c_str(), static_cast<int32_t>(error));
+
+ ALOGV("Destroyed display %" PRIu64, mId);
}
// Required by HWC2 display
@@ -372,9 +379,19 @@
return Error::None;
}
-Error Display::getType(DisplayType* outType) const
-{
- *outType = mType;
+Error Display::getConnectionType(android::DisplayConnectionType* outType) const {
+ if (mType != DisplayType::Physical) return Error::BadDisplay;
+
+ using ConnectionType = Hwc2::IComposerClient::DisplayConnectionType;
+ ConnectionType connectionType;
+ const auto error = static_cast<Error>(mComposer.getDisplayConnectionType(mId, &connectionType));
+ if (error != Error::None) {
+ return error;
+ }
+
+ *outType = connectionType == ConnectionType::INTERNAL
+ ? android::DisplayConnectionType::Internal
+ : android::DisplayConnectionType::External;
return Error::None;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e7cf5ff..5524bd7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -25,6 +25,7 @@
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
+#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -191,7 +192,8 @@
[[clang::warn_unused_result]] virtual Error getRequests(
DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, LayerRequest>* outLayerRequests) = 0;
- [[clang::warn_unused_result]] virtual Error getType(DisplayType* outType) const = 0;
+ [[clang::warn_unused_result]] virtual Error getConnectionType(
+ android::DisplayConnectionType*) const = 0;
[[clang::warn_unused_result]] virtual Error supportsDoze(bool* outSupport) const = 0;
[[clang::warn_unused_result]] virtual Error getHdrCapabilities(
android::HdrCapabilities* outCapabilities) const = 0;
@@ -268,7 +270,7 @@
Error getName(std::string* outName) const override;
Error getRequests(DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, LayerRequest>* outLayerRequests) override;
- Error getType(DisplayType* outType) const override;
+ Error getConnectionType(android::DisplayConnectionType*) const override;
Error supportsDoze(bool* outSupport) const override;
Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
Error getDisplayedContentSamplingAttributes(android::ui::PixelFormat* outFormat,
@@ -332,16 +334,17 @@
android::Hwc2::Composer& mComposer;
const std::unordered_set<Capability>& mCapabilities;
- hwc2_display_t mId;
- bool mIsConnected;
+ const hwc2_display_t mId;
DisplayType mType;
- std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
+ bool mIsConnected = false;
+ std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
std::once_flag mDisplayCapabilityQueryFlag;
std::unordered_set<DisplayCapability> mDisplayCapabilities;
};
+
} // namespace impl
class Layer {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 153cfe7..80fd7cd 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -406,18 +406,32 @@
// Composer 2.4
+DisplayConnectionType HWComposer::getDisplayConnectionType(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal);
+ const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay;
+
+ DisplayConnectionType type;
+ const auto error = hwcDisplay->getConnectionType(&type);
+
+ const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId
+ ? DisplayConnectionType::Internal
+ : DisplayConnectionType::External;
+
+ RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE);
+ return type;
+}
+
bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, false);
return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported();
}
nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, 0);
+
nsecs_t vsyncPeriodNanos;
auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos);
- if (error != HWC2::Error::None) {
- LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period");
- return 0;
- }
-
+ RETURN_IF_HWC_ERROR(error, displayId, 0);
return vsyncPeriodNanos;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index effe43b..75b52ef 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -184,6 +184,7 @@
virtual bool isUsingVrComposer() const = 0;
// Composer 2.4
+ virtual DisplayConnectionType getDisplayConnectionType(DisplayId) const = 0;
virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0;
virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0;
virtual status_t setActiveConfigWithConstraints(
@@ -319,6 +320,7 @@
bool isUsingVrComposer() const override;
// Composer 2.4
+ DisplayConnectionType getDisplayConnectionType(DisplayId) const override;
bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override;
nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override;
status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 33d85cb..1f7310a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -785,14 +785,18 @@
return NAME_NOT_FOUND;
}
- if (display->isVirtual()) {
+ if (const auto connectionType = display->getConnectionType())
+ info->connectionType = *connectionType;
+ else {
return INVALID_OPERATION;
}
if (mEmulatedDisplayDensity) {
info->density = mEmulatedDisplayDensity;
} else {
- info->density = display->isPrimary() ? mInternalDisplayDensity : FALLBACK_DENSITY;
+ info->density = info->connectionType == DisplayConnectionType::Internal
+ ? mInternalDisplayDensity
+ : FALLBACK_DENSITY;
}
info->secure = display->isSecure();
@@ -2243,30 +2247,38 @@
continue;
}
+ const DisplayId displayId = info->id;
+ const auto it = mPhysicalDisplayTokens.find(displayId);
+
if (event.connection == HWC2::Connection::Connected) {
- if (!mPhysicalDisplayTokens.count(info->id)) {
- ALOGV("Creating display %s", to_string(info->id).c_str());
+ if (it == mPhysicalDisplayTokens.end()) {
+ ALOGV("Creating display %s", to_string(displayId).c_str());
+
if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
- initScheduler(info->id);
+ initScheduler(displayId);
}
- mPhysicalDisplayTokens[info->id] = new BBinder();
+
DisplayDeviceState state;
- state.displayId = info->id;
+ state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId)};
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = info->name;
- mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+
+ sp<IBinder> token = new BBinder();
+ mCurrentState.displays.add(token, state);
+ mPhysicalDisplayTokens.emplace(displayId, std::move(token));
+
mInterceptor->saveDisplayCreation(state);
}
} else {
- ALOGV("Removing display %s", to_string(info->id).c_str());
+ ALOGV("Removing display %s", to_string(displayId).c_str());
- ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+ const ssize_t index = mCurrentState.displays.indexOfKey(it->second);
if (index >= 0) {
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
}
- mPhysicalDisplayTokens.erase(info->id);
+ mPhysicalDisplayTokens.erase(it);
}
processDisplayChangesLocked();
@@ -2286,13 +2298,16 @@
const sp<IGraphicBufferProducer>& producer) {
DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
creationArgs.sequenceId = state.sequenceId;
- creationArgs.isVirtual = state.isVirtual();
creationArgs.isSecure = state.isSecure;
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
+ if (const auto& physical = state.physical) {
+ creationArgs.connectionType = physical->type;
+ }
+
const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
@@ -2483,8 +2498,8 @@
"surface is provided (%p), ignoring it",
state.surface.get());
- displayId = state.displayId;
- LOG_ALWAYS_FATAL_IF(!displayId);
+ LOG_FATAL_IF(!state.physical);
+ displayId = state.physical->id;
dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
producer = bqProducer;
}
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 6884b4c..1f9d46c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -595,8 +595,8 @@
creation->set_id(info.sequenceId);
creation->set_name(info.displayName);
creation->set_is_secure(info.isSecure);
- if (info.displayId) {
- creation->set_display_id(info.displayId->value);
+ if (info.physical) {
+ creation->set_display_id(info.physical->id.value);
}
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 888e009..27e2e8d 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -286,13 +286,14 @@
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
- test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
- false /* isVirtual */, true /* isPrimary */)
- .setDisplaySurface(test->mDisplaySurface)
- .setNativeWindow(test->mNativeWindow)
- .setSecure(Derived::IS_SECURE)
- .setPowerMode(Derived::INIT_POWER_MODE)
- .inject();
+ test->mDisplay =
+ FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal, true /* isPrimary */)
+ .setDisplaySurface(test->mDisplaySurface)
+ .setNativeWindow(test->mNativeWindow)
+ .setSecure(Derived::IS_SECURE)
+ .setPowerMode(Derived::INIT_POWER_MODE)
+ .inject();
Mock::VerifyAndClear(test->mNativeWindow);
test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index dddad92..fd2ccc4 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -312,6 +312,16 @@
static std::optional<DisplayId> get() { return {}; }
};
+template <typename>
+struct DisplayConnectionTypeGetter {
+ static constexpr std::optional<DisplayConnectionType> value;
+};
+
+template <typename PhysicalDisplay>
+struct DisplayConnectionTypeGetter<PhysicalDisplayId<PhysicalDisplay>> {
+ static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+};
+
// DisplayIdType can be:
// 1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
// 2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
@@ -320,6 +330,7 @@
Secure secure, Primary primary, int grallocUsage>
struct DisplayVariant {
using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+ using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
// The display width and height
static constexpr int WIDTH = width;
@@ -345,8 +356,8 @@
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto injector =
- FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
- static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+ FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), CONNECTION_TYPE::value,
+ static_cast<bool>(PRIMARY));
injector.setSecure(static_cast<bool>(SECURE));
injector.setNativeWindow(test->mNativeWindow);
@@ -450,6 +461,15 @@
}
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
+ constexpr auto CONNECTION_TYPE =
+ PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+ ? IComposerClient::DisplayConnectionType::INTERNAL
+ : IComposerClient::DisplayConnectionType::EXTERNAL;
+
+ EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
+ .WillOnce(
+ DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(Hwc2::V2_4::Error::NONE)));
+
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
@@ -514,6 +534,7 @@
template <bool hasIdentificationData>
struct PrimaryDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
static constexpr Primary PRIMARY = Primary::TRUE;
static constexpr uint8_t PORT = 255;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
@@ -522,6 +543,7 @@
template <bool hasIdentificationData>
struct ExternalDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 254;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
@@ -1183,7 +1205,8 @@
GetBestColorModeTest()
: DisplayTransactionTest(),
- mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
+ mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal,
true /* isPrimary */)) {}
void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
@@ -1285,8 +1308,6 @@
class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
public:
static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
- static constexpr bool DEFAULT_DISPLAY_IS_VIRTUAL = false;
- static constexpr bool DEFAULT_DISPLAY_IS_PRIMARY = true;
static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary
static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
@@ -1316,8 +1337,8 @@
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT));
- return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, DEFAULT_DISPLAY_IS_VIRTUAL,
- DEFAULT_DISPLAY_IS_PRIMARY)
+ return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal, true /* isPrimary */)
.setNativeWindow(mNativeWindow)
.setPhysicalOrientation(mPhysicalOrientation)
.inject();
@@ -1647,8 +1668,12 @@
// Invocation
DisplayDeviceState state;
- state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get();
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ state.physical = {*displayId, *connectionType};
+ }
+
state.isSecure = static_cast<bool>(Case::Display::SECURE);
auto device =
@@ -1660,6 +1685,7 @@
ASSERT_TRUE(device != nullptr);
EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+ EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
@@ -1823,21 +1849,24 @@
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
+ std::optional<DisplayDeviceState::Physical> expectedPhysical;
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ expectedPhysical = {*displayId, *connectionType};
+ }
+
// The display should have been set up in the current display state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& current = getCurrentDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get(),
- current.displayId);
+ EXPECT_EQ(expectedPhysical, current.physical);
// The display should have been set up in the drawing display state
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get(),
- draw.displayId);
+ EXPECT_EQ(expectedPhysical, draw.physical);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 64838ca..6886d3b 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -546,10 +546,11 @@
class FakeDisplayDeviceInjector {
public:
FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
- const std::optional<DisplayId>& displayId, bool isVirtual,
+ std::optional<DisplayId> displayId,
+ std::optional<DisplayConnectionType> connectionType,
bool isPrimary)
: mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
- mCreationArgs.isVirtual = isVirtual;
+ mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
}
@@ -612,7 +613,12 @@
sp<DisplayDevice> inject() {
DisplayDeviceState state;
- state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
+ if (const auto type = mCreationArgs.connectionType) {
+ const auto id = mCreationArgs.displayId;
+ LOG_ALWAYS_FATAL_IF(!id);
+ state.physical = {*id, *type};
+ }
+
state.isSecure = mCreationArgs.isSecure;
sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
@@ -620,9 +626,8 @@
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
- if (!mCreationArgs.isVirtual) {
- LOG_ALWAYS_FATAL_IF(!state.displayId);
- mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
+ if (const auto& physical = state.physical) {
+ mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
}
return device;