From 9ebb7a721aecc1da1ee3f45846010fd3945e8e22 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Tue, 27 Jun 2023 17:01:50 -0700 Subject: Update HDCP for external displays So the secure flag of Display object in Display Manager (DM) can be set correctly. HWC calls the onSync method as a workaround, to notify SurfaceFlinger (SF) about hdcp changes, SF in turn sends an event to DM, DM will then fetch and update display info. Bug: 280818362 Test: manual Change-Id: I29ce0337865b51c0fc7bf7c2d7fdd4cd6d66ef46 --- .../include/compositionengine/Display.h | 3 + .../include/compositionengine/impl/Display.h | 1 + .../include/compositionengine/mock/Display.h | 1 + .../CompositionEngine/src/Display.cpp | 4 ++ services/surfaceflinger/DisplayDevice.cpp | 4 ++ services/surfaceflinger/DisplayDevice.h | 1 + services/surfaceflinger/Scheduler/EventThread.cpp | 27 ++++++++ services/surfaceflinger/Scheduler/EventThread.h | 6 ++ services/surfaceflinger/Scheduler/Scheduler.cpp | 11 ++++ services/surfaceflinger/Scheduler/Scheduler.h | 2 + services/surfaceflinger/SurfaceFlinger.cpp | 73 ++++++++++++++++++---- services/surfaceflinger/SurfaceFlinger.h | 3 + .../unittests/DisplayTransactionTestHelpers.h | 12 ++-- .../tests/unittests/mock/MockEventThread.h | 3 + 14 files changed, 136 insertions(+), 15 deletions(-) (limited to 'services') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h index 5e84be1841..c71c517d94 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h @@ -40,6 +40,9 @@ public: // True if the display is secure virtual bool isSecure() const = 0; + // Sets the secure flag for the display + virtual void setSecure(bool secure) = 0; + // True if the display is virtual virtual bool isVirtual() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index eac5d97df3..c53b46140b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -74,6 +74,7 @@ public: void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override; void createClientCompositionCache(uint32_t cacheSize) override; void applyDisplayBrightness(const bool applyImmediately) override; + void setSecure(bool secure) override; // Internal helpers used by chooseCompositionStrategy() using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index 7e99ec2f5a..46cb95ef25 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -33,6 +33,7 @@ public: MOCK_CONST_METHOD0(getId, DisplayId()); MOCK_CONST_METHOD0(isSecure, bool()); + MOCK_METHOD1(setSecure, void(bool)); MOCK_CONST_METHOD0(isVirtual, bool()); MOCK_CONST_METHOD0(getPreferredBootHwcConfigId, int32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 690d35f068..b8b2d9a10a 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -74,6 +74,10 @@ bool Display::isSecure() const { return getState().isSecure; } +void Display::setSecure(bool secure) { + editState().isSecure = secure; +} + bool Display::isVirtual() const { return VirtualDisplayId::tryCast(mId).has_value(); } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 950b05e1da..799d62c19d 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -353,6 +353,10 @@ bool DisplayDevice::isSecure() const { return mCompositionDisplay->isSecure(); } +void DisplayDevice::setSecure(bool secure) { + mCompositionDisplay->setSecure(secure); +} + const Rect DisplayDevice::getBounds() const { return mCompositionDisplay->getState().displaySpace.getBoundsAsRect(); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index ac390cb8ff..97b56a2f19 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -95,6 +95,7 @@ public: // isSecure indicates whether this display can be trusted to display // secure surfaces. bool isSecure() const; + void setSecure(bool secure); int getWidth() const; int getHeight() const; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 693a357de5..56be1b1ff7 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -100,6 +100,11 @@ std::string toString(const DisplayEventReceiver::Event& event) { case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: return StringPrintf("ModeChanged{displayId=%s, modeId=%u}", to_string(event.header.displayId).c_str(), event.modeChange.modeId); + case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE: + return StringPrintf("HdcpLevelsChange{displayId=%s, connectedLevel=%d, maxLevel=%d}", + to_string(event.header.displayId).c_str(), + event.hdcpLevelsChange.connectedLevel, + event.hdcpLevelsChange.maxLevel); default: return "Event{}"; } @@ -170,6 +175,20 @@ DisplayEventReceiver::Event makeFrameRateOverrideFlushEvent(PhysicalDisplayId di }}; } +DisplayEventReceiver::Event makeHdcpLevelsChange(PhysicalDisplayId displayId, + int32_t connectedLevel, int32_t maxLevel) { + return DisplayEventReceiver::Event{ + .header = + DisplayEventReceiver::Event::Header{ + .type = DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE, + .displayId = displayId, + .timestamp = systemTime(), + }, + .hdcpLevelsChange.connectedLevel = connectedLevel, + .hdcpLevelsChange.maxLevel = maxLevel, + }; +} + } // namespace EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid, @@ -442,6 +461,14 @@ void EventThread::onFrameRateOverridesChanged(PhysicalDisplayId displayId, mCondition.notify_all(); } +void EventThread::onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, + int32_t maxLevel) { + std::lock_guard lock(mMutex); + + mPendingEvents.push_back(makeHdcpLevelsChange(displayId, connectedLevel, maxLevel)); + mCondition.notify_all(); +} + void EventThread::threadMain(std::unique_lock& lock) { DisplayEventConsumers consumers; diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 7842318e2e..8970103a7c 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -131,6 +131,9 @@ public: const sp& connection) const = 0; virtual void onNewVsyncSchedule(std::shared_ptr) = 0; + + virtual void onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, + int32_t maxLevel) = 0; }; struct IEventThreadCallback { @@ -177,6 +180,9 @@ public: void onNewVsyncSchedule(std::shared_ptr) override EXCLUDES(mMutex); + void onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, + int32_t maxLevel) override; + private: friend EventThreadTest; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index ce59a04808..1b72071707 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -412,6 +412,17 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis thread->onFrameRateOverridesChanged(displayId, std::move(overrides)); } +void Scheduler::onHdcpLevelsChanged(ConnectionHandle handle, PhysicalDisplayId displayId, + int32_t connectedLevel, int32_t maxLevel) { + android::EventThread* thread; + { + std::lock_guard lock(mConnectionsLock); + RETURN_IF_INVALID_HANDLE(handle); + thread = mConnections[handle].thread.get(); + } + thread->onHdcpLevelsChanged(displayId, connectedLevel, maxLevel); +} + void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) { { std::lock_guard lock(mPolicyLock); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index ce585c624a..a29d153516 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -173,6 +173,8 @@ public: void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId) EXCLUDES(mConnectionsLock); + void onHdcpLevelsChanged(ConnectionHandle, PhysicalDisplayId, int32_t, int32_t); + // Modifies work duration in the event thread. void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2769e5dfc2..bad2108ae8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -551,6 +551,12 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); + + // These are set by the HWC implementation to indicate that they will use the workarounds. + mIsHotplugErrViaNegVsync = + base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false); + + mIsHdcpViaNegVsync = base::GetBoolProperty("debug.sf.hwc_hdcp_via_neg_vsync"s, false); } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { @@ -2130,15 +2136,28 @@ nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp, std::optional vsyncPeriod) { - if (FlagManager::getInstance().connected_display()) { + if (FlagManager::getInstance().connected_display() && timestamp < 0 && + vsyncPeriod.has_value()) { // use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32 - if (mIsHotplugErrViaNegVsync && timestamp < 0 && vsyncPeriod.has_value() && - vsyncPeriod.value() == ~0) { - int hotplugErrorCode = static_cast(-timestamp); - ALOGD("SurfaceFlinger got hotplugErrorCode=%d", hotplugErrorCode); + if (mIsHotplugErrViaNegVsync && vsyncPeriod.value() == ~0) { + const int32_t hotplugErrorCode = static_cast(-timestamp); + ALOGD("SurfaceFlinger got hotplugErrorCode=%d for display %" PRIu64, hotplugErrorCode, + hwcDisplayId); mScheduler->onHotplugConnectionError(mAppConnectionHandle, hotplugErrorCode); return; } + + if (mIsHdcpViaNegVsync && vsyncPeriod.value() == ~1) { + const int32_t value = static_cast(-timestamp); + // one byte is good enough to encode android.hardware.drm.HdcpLevel + const int32_t maxLevel = (value >> 8) & 0xFF; + const int32_t connectedLevel = value & 0xFF; + ALOGD("SurfaceFlinger got HDCP level changed: connected=%d, max=%d for " + "display=%" PRIu64, + connectedLevel, maxLevel, hwcDisplayId); + updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel); + return; + } } ATRACE_NAME(vsyncPeriod @@ -3432,9 +3451,10 @@ const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId, } const sp token = sp::make(); + const ui::DisplayConnectionType connectionType = + getHwComposer().getDisplayConnectionType(displayId); - mPhysicalDisplays.try_emplace(displayId, token, displayId, - getHwComposer().getDisplayConnectionType(displayId), + mPhysicalDisplays.try_emplace(displayId, token, displayId, connectionType, std::move(displayModes), std::move(colorModes), std::move(info.deviceProductInfo)); @@ -3442,7 +3462,7 @@ const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId, state.physical = {.id = displayId, .hwcDisplayId = hwcDisplayId, .activeMode = std::move(activeMode)}; - state.isSecure = true; // All physical displays are currently considered secure. + state.isSecure = connectionType == ui::DisplayConnectionType::Internal; state.isProtected = true; state.displayName = std::move(info.name); @@ -4248,9 +4268,6 @@ void SurfaceFlinger::initScheduler(const sp& display) { sp::make(*this, RegionSamplingThread::EnvironmentTimingTunables()); mFpsReporter = sp::make(*mFrameTimeline, *this); - - mIsHotplugErrViaNegVsync = - base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false); } void SurfaceFlinger::updatePhaseConfiguration(Fps refreshRate) { @@ -8752,6 +8769,40 @@ status_t SurfaceFlinger::getStalledTransactionInfo( return NO_ERROR; } +void SurfaceFlinger::updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel, + int32_t maxLevel) { + if (!FlagManager::getInstance().connected_display()) { + return; + } + + Mutex::Autolock lock(mStateLock); + + const auto idOpt = getHwComposer().toPhysicalDisplayId(hwcDisplayId); + if (!idOpt) { + ALOGE("No display found for HDCP level changed event: connected=%d, max=%d for " + "display=%" PRIu64, + connectedLevel, maxLevel, hwcDisplayId); + return; + } + + const bool isInternalDisplay = + mPhysicalDisplays.get(*idOpt).transform(&PhysicalDisplay::isInternal).value_or(false); + if (isInternalDisplay) { + ALOGW("Unexpected HDCP level changed for internal display: connected=%d, max=%d for " + "display=%" PRIu64, + connectedLevel, maxLevel, hwcDisplayId); + return; + } + + static_cast(mScheduler->schedule([this, displayId = *idOpt, connectedLevel, maxLevel]() { + if (const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayId))) { + Mutex::Autolock lock(mStateLock); + display->setSecure(connectedLevel >= 2 /* HDCP_V1 */); + } + mScheduler->onHdcpLevelsChanged(mAppConnectionHandle, displayId, connectedLevel, maxLevel); + })); +} + std::shared_ptr SurfaceFlinger::getExternalTextureFromBufferData( BufferData& bufferData, const char* layerName, uint64_t transactionId) { if (bufferData.buffer && diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6b4440193b..c2a27230fa 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -654,6 +654,8 @@ private: status_t getStalledTransactionInfo( int pid, std::optional& result); + void updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel, int32_t maxLevel); + // Implements IBinder::DeathRecipient. void binderDied(const wp& who) override; @@ -1276,6 +1278,7 @@ private: hal::Connection connection = hal::Connection::INVALID; }; + bool mIsHdcpViaNegVsync = false; bool mIsHotplugErrViaNegVsync = false; std::mutex mHotplugMutex; diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index ee12276994..6671414ba6 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -481,14 +481,17 @@ constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY = constexpr int PHYSICAL_DISPLAY_FLAGS = 0x1; -template +template struct PhysicalDisplayVariant - : DisplayVariant, width, height, Async::FALSE, - Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY, + : DisplayVariant, width, height, Async::FALSE, secure, + PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>, HwcDisplayVariant, width, height, - Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY, + Async::FALSE, secure, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>, PhysicalDisplay> {}; @@ -515,6 +518,7 @@ struct SecondaryDisplay { }; struct TertiaryDisplay { + static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::External; static constexpr Primary PRIMARY = Primary::FALSE; static constexpr uint8_t PORT = 253; static constexpr HWDisplayId HWC_DISPLAY_ID = 1003; diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 866af3bbd0..e2b0ed1df9 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -59,6 +59,9 @@ public: MOCK_METHOD(void, requestLatestConfig, (const sp&)); MOCK_METHOD(void, pauseVsyncCallback, (bool)); MOCK_METHOD(void, onNewVsyncSchedule, (std::shared_ptr), (override)); + MOCK_METHOD(void, onHdcpLevelsChanged, + (PhysicalDisplayId displayId, int32_t connectedLevel, int32_t maxLevel), + (override)); }; } // namespace android::mock -- cgit v1.2.3-59-g8ed1b