Loading services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ public: MOCK_METHOD3(allocateVirtualDisplay, std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*)); MOCK_METHOD2(allocatePhysicalDisplay, void(hwc2_display_t, DisplayId)); MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId)); MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*)); MOCK_METHOD3(getDeviceCompositionChanges, Loading services/surfaceflinger/DisplayHardware/HWComposer.cpp +94 −79 Original line number Diff line number Diff line Loading @@ -205,56 +205,14 @@ bool HWComposer::hasDisplayCapability(const std::optional<DisplayId>& displayId, std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, HWC2::Connection connection) { std::optional<DisplayIdentificationInfo> info; if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) { info = DisplayIdentificationInfo{.id = *displayId, .name = std::string(), .deviceProductInfo = std::nullopt}; } else { if (connection == HWC2::Connection::Disconnected) { ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId); switch (connection) { case HWC2::Connection::Connected: return onHotplugConnect(hwcDisplayId); case HWC2::Connection::Disconnected: return onHotplugDisconnect(hwcDisplayId); case HWC2::Connection::Invalid: return {}; } info = onHotplugConnect(hwcDisplayId); if (!info) return {}; } ALOGV("%s: %s %s display %s with HWC ID %" PRIu64, __FUNCTION__, to_string(connection).c_str(), hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external", to_string(info->id).c_str(), hwcDisplayId); if (connection == HWC2::Connection::Connected) { auto& displayData = mDisplayData[info->id]; // If we get a hotplug connected event for a display we already have, // destroy the display and recreate it. This will force us to requery // the display params and recreate all layers on that display. if (displayData.hwcDisplay != nullptr && displayData.hwcDisplay->isConnected()) { ALOGI("Hotplug connecting an already connected display." " Clearing old display state."); } displayData.hwcDisplay.reset(); auto newDisplay = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId, HWC2::DisplayType::Physical); newDisplay->setConnected(true); displayData.hwcDisplay = std::move(newDisplay); mPhysicalDisplayIdMap[hwcDisplayId] = info->id; } else if (connection == HWC2::Connection::Disconnected) { // The display will later be destroyed by a call to // destroyDisplay(). For now we just mark it disconnected. auto& displayData = mDisplayData[info->id]; if (displayData.hwcDisplay) { displayData.hwcDisplay->setConnected(false); } else { ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId); } // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay // via SurfaceFlinger's onHotplugReceived callback handling } return info; } bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) { Loading Loading @@ -337,6 +295,22 @@ std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint return displayId; } void HWComposer::allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) { if (!mInternalHwcDisplayId) { mInternalHwcDisplayId = hwcDisplayId; } else if (mInternalHwcDisplayId != hwcDisplayId && !mExternalHwcDisplayId) { mExternalHwcDisplayId = hwcDisplayId; } auto& displayData = mDisplayData[displayId]; auto newDisplay = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId, HWC2::DisplayType::Physical); newDisplay->setConnected(true); displayData.hwcDisplay = std::move(newDisplay); mPhysicalDisplayIdMap[hwcDisplayId] = displayId; } HWC2::Layer* HWComposer::createLayer(DisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId, nullptr); Loading Loading @@ -911,52 +885,93 @@ std::optional<hwc2_display_t> HWComposer::fromPhysicalDisplayId(DisplayId displa return {}; } std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) { bool HWComposer::shouldIgnoreHotplugConnect(hwc2_display_t hwcDisplayId, bool hasDisplayIdentificationData) const { if (isUsingVrComposer() && mInternalHwcDisplayId) { ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId); return {}; return true; } if (mHasMultiDisplaySupport && !hasDisplayIdentificationData) { ALOGE("Ignoring connection of display %" PRIu64 " without identification data", hwcDisplayId); return true; } if (!mHasMultiDisplaySupport && mInternalHwcDisplayId && mExternalHwcDisplayId) { ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId); return true; } return false; } std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) { std::optional<DisplayIdentificationInfo> info; if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) { info = DisplayIdentificationInfo{.id = *displayId, .name = std::string(), .deviceProductInfo = std::nullopt}; } else { uint8_t port; DisplayIdentificationData data; const bool hasMultiDisplaySupport = getDisplayIdentificationData(hwcDisplayId, &port, &data); const bool hasDisplayIdentificationData = getDisplayIdentificationData(hwcDisplayId, &port, &data); if (mPhysicalDisplayIdMap.empty()) { mHasMultiDisplaySupport = hasMultiDisplaySupport; mHasMultiDisplaySupport = hasDisplayIdentificationData; ALOGI("Switching to %s multi-display mode", hasMultiDisplaySupport ? "generalized" : "legacy"); } else if (mHasMultiDisplaySupport && !hasMultiDisplaySupport) { ALOGE("Ignoring connection of display %" PRIu64 " without identification data", hwcDisplayId); return {}; mHasMultiDisplaySupport ? "generalized" : "legacy"); } std::optional<DisplayIdentificationInfo> info; if (shouldIgnoreHotplugConnect(hwcDisplayId, hasDisplayIdentificationData)) { return {}; } info = [this, hwcDisplayId, &port, &data, hasDisplayIdentificationData] { const bool isPrimary = !mInternalHwcDisplayId; if (mHasMultiDisplaySupport) { info = parseDisplayIdentificationData(port, data); ALOGE_IF(!info, "Failed to parse identification data for display %" PRIu64, hwcDisplayId); } else if (mInternalHwcDisplayId && mExternalHwcDisplayId) { ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId); return {}; if (const auto info = parseDisplayIdentificationData(port, data)) { return *info; } ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId); } else { ALOGW_IF(hasMultiDisplaySupport, "Ignoring identification data for display %" PRIu64, hwcDisplayId); port = mInternalHwcDisplayId ? HWC_DISPLAY_EXTERNAL : HWC_DISPLAY_PRIMARY; ALOGW_IF(hasDisplayIdentificationData, "Ignoring identification data for display %" PRIu64, hwcDisplayId); port = isPrimary ? HWC_DISPLAY_PRIMARY : HWC_DISPLAY_EXTERNAL; } if (!mInternalHwcDisplayId) { mInternalHwcDisplayId = hwcDisplayId; } else if (!mExternalHwcDisplayId) { mExternalHwcDisplayId = hwcDisplayId; return DisplayIdentificationInfo{.id = getFallbackDisplayId(port), .name = isPrimary ? "Internal display" : "External display", .deviceProductInfo = std::nullopt}; }(); } if (info) return info; if (!isConnected(info->id)) { allocatePhysicalDisplay(hwcDisplayId, info->id); } return info; } return DisplayIdentificationInfo{.id = getFallbackDisplayId(port), .name = hwcDisplayId == mInternalHwcDisplayId ? "Internal display" : "External display", std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect( hwc2_display_t hwcDisplayId) { const auto displayId = toPhysicalDisplayId(hwcDisplayId); if (!displayId) { ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId); return {}; } // The display will later be destroyed by a call to // destroyDisplay(). For now we just mark it disconnected. if (isConnected(*displayId)) { mDisplayData[*displayId].hwcDisplay->setConnected(false); } else { ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId); } // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay // via SurfaceFlinger's onHotplugReceived callback handling return DisplayIdentificationInfo{.id = *displayId, .name = std::string(), .deviceProductInfo = std::nullopt}; } Loading services/surfaceflinger/DisplayHardware/HWComposer.h +10 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,8 @@ public: virtual std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height, ui::PixelFormat* format) = 0; virtual void allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) = 0; // Attempts to create a new layer on this display virtual HWC2::Layer* createLayer(DisplayId displayId) = 0; // Destroy a previously created layer Loading Loading @@ -164,6 +166,7 @@ public: // Returns stable display ID (and display name on connection of new or previously disconnected // display), or std::nullopt if hotplug event was ignored. // This function is called from SurfaceFlinger. virtual std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId, HWC2::Connection connection) = 0; Loading Loading @@ -238,6 +241,9 @@ public: std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height, ui::PixelFormat* format) override; // Called from SurfaceFlinger, when the state for a new physical display needs to be recreated. void allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) override; // Attempts to create a new layer on this display HWC2::Layer* createLayer(DisplayId displayId) override; // Destroy a previously created layer Loading Loading @@ -361,6 +367,10 @@ private: friend TestableSurfaceFlinger; std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId); std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hwc2_display_t hwcDisplayId); bool shouldIgnoreHotplugConnect(hwc2_display_t hwcDisplayId, bool hasDisplayIdentificationData) const; void loadCapabilities(); void loadLayerMetadataSupport(); uint32_t getMaxVirtualDisplayCount() const; Loading Loading
services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ public: MOCK_METHOD3(allocateVirtualDisplay, std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*)); MOCK_METHOD2(allocatePhysicalDisplay, void(hwc2_display_t, DisplayId)); MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId)); MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*)); MOCK_METHOD3(getDeviceCompositionChanges, Loading
services/surfaceflinger/DisplayHardware/HWComposer.cpp +94 −79 Original line number Diff line number Diff line Loading @@ -205,56 +205,14 @@ bool HWComposer::hasDisplayCapability(const std::optional<DisplayId>& displayId, std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, HWC2::Connection connection) { std::optional<DisplayIdentificationInfo> info; if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) { info = DisplayIdentificationInfo{.id = *displayId, .name = std::string(), .deviceProductInfo = std::nullopt}; } else { if (connection == HWC2::Connection::Disconnected) { ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId); switch (connection) { case HWC2::Connection::Connected: return onHotplugConnect(hwcDisplayId); case HWC2::Connection::Disconnected: return onHotplugDisconnect(hwcDisplayId); case HWC2::Connection::Invalid: return {}; } info = onHotplugConnect(hwcDisplayId); if (!info) return {}; } ALOGV("%s: %s %s display %s with HWC ID %" PRIu64, __FUNCTION__, to_string(connection).c_str(), hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external", to_string(info->id).c_str(), hwcDisplayId); if (connection == HWC2::Connection::Connected) { auto& displayData = mDisplayData[info->id]; // If we get a hotplug connected event for a display we already have, // destroy the display and recreate it. This will force us to requery // the display params and recreate all layers on that display. if (displayData.hwcDisplay != nullptr && displayData.hwcDisplay->isConnected()) { ALOGI("Hotplug connecting an already connected display." " Clearing old display state."); } displayData.hwcDisplay.reset(); auto newDisplay = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId, HWC2::DisplayType::Physical); newDisplay->setConnected(true); displayData.hwcDisplay = std::move(newDisplay); mPhysicalDisplayIdMap[hwcDisplayId] = info->id; } else if (connection == HWC2::Connection::Disconnected) { // The display will later be destroyed by a call to // destroyDisplay(). For now we just mark it disconnected. auto& displayData = mDisplayData[info->id]; if (displayData.hwcDisplay) { displayData.hwcDisplay->setConnected(false); } else { ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId); } // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay // via SurfaceFlinger's onHotplugReceived callback handling } return info; } bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) { Loading Loading @@ -337,6 +295,22 @@ std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint return displayId; } void HWComposer::allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) { if (!mInternalHwcDisplayId) { mInternalHwcDisplayId = hwcDisplayId; } else if (mInternalHwcDisplayId != hwcDisplayId && !mExternalHwcDisplayId) { mExternalHwcDisplayId = hwcDisplayId; } auto& displayData = mDisplayData[displayId]; auto newDisplay = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId, HWC2::DisplayType::Physical); newDisplay->setConnected(true); displayData.hwcDisplay = std::move(newDisplay); mPhysicalDisplayIdMap[hwcDisplayId] = displayId; } HWC2::Layer* HWComposer::createLayer(DisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId, nullptr); Loading Loading @@ -911,52 +885,93 @@ std::optional<hwc2_display_t> HWComposer::fromPhysicalDisplayId(DisplayId displa return {}; } std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) { bool HWComposer::shouldIgnoreHotplugConnect(hwc2_display_t hwcDisplayId, bool hasDisplayIdentificationData) const { if (isUsingVrComposer() && mInternalHwcDisplayId) { ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId); return {}; return true; } if (mHasMultiDisplaySupport && !hasDisplayIdentificationData) { ALOGE("Ignoring connection of display %" PRIu64 " without identification data", hwcDisplayId); return true; } if (!mHasMultiDisplaySupport && mInternalHwcDisplayId && mExternalHwcDisplayId) { ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId); return true; } return false; } std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) { std::optional<DisplayIdentificationInfo> info; if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) { info = DisplayIdentificationInfo{.id = *displayId, .name = std::string(), .deviceProductInfo = std::nullopt}; } else { uint8_t port; DisplayIdentificationData data; const bool hasMultiDisplaySupport = getDisplayIdentificationData(hwcDisplayId, &port, &data); const bool hasDisplayIdentificationData = getDisplayIdentificationData(hwcDisplayId, &port, &data); if (mPhysicalDisplayIdMap.empty()) { mHasMultiDisplaySupport = hasMultiDisplaySupport; mHasMultiDisplaySupport = hasDisplayIdentificationData; ALOGI("Switching to %s multi-display mode", hasMultiDisplaySupport ? "generalized" : "legacy"); } else if (mHasMultiDisplaySupport && !hasMultiDisplaySupport) { ALOGE("Ignoring connection of display %" PRIu64 " without identification data", hwcDisplayId); return {}; mHasMultiDisplaySupport ? "generalized" : "legacy"); } std::optional<DisplayIdentificationInfo> info; if (shouldIgnoreHotplugConnect(hwcDisplayId, hasDisplayIdentificationData)) { return {}; } info = [this, hwcDisplayId, &port, &data, hasDisplayIdentificationData] { const bool isPrimary = !mInternalHwcDisplayId; if (mHasMultiDisplaySupport) { info = parseDisplayIdentificationData(port, data); ALOGE_IF(!info, "Failed to parse identification data for display %" PRIu64, hwcDisplayId); } else if (mInternalHwcDisplayId && mExternalHwcDisplayId) { ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId); return {}; if (const auto info = parseDisplayIdentificationData(port, data)) { return *info; } ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId); } else { ALOGW_IF(hasMultiDisplaySupport, "Ignoring identification data for display %" PRIu64, hwcDisplayId); port = mInternalHwcDisplayId ? HWC_DISPLAY_EXTERNAL : HWC_DISPLAY_PRIMARY; ALOGW_IF(hasDisplayIdentificationData, "Ignoring identification data for display %" PRIu64, hwcDisplayId); port = isPrimary ? HWC_DISPLAY_PRIMARY : HWC_DISPLAY_EXTERNAL; } if (!mInternalHwcDisplayId) { mInternalHwcDisplayId = hwcDisplayId; } else if (!mExternalHwcDisplayId) { mExternalHwcDisplayId = hwcDisplayId; return DisplayIdentificationInfo{.id = getFallbackDisplayId(port), .name = isPrimary ? "Internal display" : "External display", .deviceProductInfo = std::nullopt}; }(); } if (info) return info; if (!isConnected(info->id)) { allocatePhysicalDisplay(hwcDisplayId, info->id); } return info; } return DisplayIdentificationInfo{.id = getFallbackDisplayId(port), .name = hwcDisplayId == mInternalHwcDisplayId ? "Internal display" : "External display", std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect( hwc2_display_t hwcDisplayId) { const auto displayId = toPhysicalDisplayId(hwcDisplayId); if (!displayId) { ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId); return {}; } // The display will later be destroyed by a call to // destroyDisplay(). For now we just mark it disconnected. if (isConnected(*displayId)) { mDisplayData[*displayId].hwcDisplay->setConnected(false); } else { ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId); } // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay // via SurfaceFlinger's onHotplugReceived callback handling return DisplayIdentificationInfo{.id = *displayId, .name = std::string(), .deviceProductInfo = std::nullopt}; } Loading
services/surfaceflinger/DisplayHardware/HWComposer.h +10 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,8 @@ public: virtual std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height, ui::PixelFormat* format) = 0; virtual void allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) = 0; // Attempts to create a new layer on this display virtual HWC2::Layer* createLayer(DisplayId displayId) = 0; // Destroy a previously created layer Loading Loading @@ -164,6 +166,7 @@ public: // Returns stable display ID (and display name on connection of new or previously disconnected // display), or std::nullopt if hotplug event was ignored. // This function is called from SurfaceFlinger. virtual std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId, HWC2::Connection connection) = 0; Loading Loading @@ -238,6 +241,9 @@ public: std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height, ui::PixelFormat* format) override; // Called from SurfaceFlinger, when the state for a new physical display needs to be recreated. void allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) override; // Attempts to create a new layer on this display HWC2::Layer* createLayer(DisplayId displayId) override; // Destroy a previously created layer Loading Loading @@ -361,6 +367,10 @@ private: friend TestableSurfaceFlinger; std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId); std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hwc2_display_t hwcDisplayId); bool shouldIgnoreHotplugConnect(hwc2_display_t hwcDisplayId, bool hasDisplayIdentificationData) const; void loadCapabilities(); void loadLayerMetadataSupport(); uint32_t getMaxVirtualDisplayCount() const; Loading