Loading services/surfaceflinger/Scheduler/MessageQueue.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,19 @@ void MessageQueue::postMessage(sp<MessageHandler>&& handler) { mLooper->sendMessage(handler, Message()); } void MessageQueue::scheduleConfigure() { struct ConfigureHandler : MessageHandler { explicit ConfigureHandler(ICompositor& compositor) : compositor(compositor) {} void handleMessage(const Message&) override { compositor.configure(); } ICompositor& compositor; }; // TODO(b/241285876): Batch configure tasks that happen within some duration. postMessage(sp<ConfigureHandler>::make(mCompositor)); } void MessageQueue::scheduleFrame() { ATRACE_CALL(); Loading services/surfaceflinger/Scheduler/MessageQueue.h +3 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ namespace android { struct ICompositor { virtual void configure() = 0; virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0; virtual void composite(TimePoint frameTime, VsyncId) = 0; virtual void sample() = 0; Loading Loading @@ -78,6 +79,7 @@ public: virtual void setInjector(sp<EventThreadConnection>) = 0; virtual void waitMessage() = 0; virtual void postMessage(sp<MessageHandler>&&) = 0; virtual void scheduleConfigure() = 0; virtual void scheduleFrame() = 0; using Clock = std::chrono::steady_clock; Loading Loading @@ -152,6 +154,7 @@ public: void waitMessage() override; void postMessage(sp<MessageHandler>&&) override; void scheduleConfigure() override; void scheduleFrame() override; std::optional<Clock::time_point> getScheduledFrameTime() const override; Loading services/surfaceflinger/Scheduler/Scheduler.h +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ public: using Impl::getScheduledFrameTime; using Impl::setDuration; using Impl::scheduleConfigure; using Impl::scheduleFrame; // Schedule an asynchronous or synchronous task on the main thread. Loading services/surfaceflinger/SurfaceFlinger.cpp +37 −32 Original line number Diff line number Diff line Loading @@ -763,10 +763,10 @@ chooseRenderEngineTypeViaSysProp() { // Do not call property_set on main thread which will be blocked by init // Use StartPropertySetThread instead. void SurfaceFlinger::init() { void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); Mutex::Autolock _l(mStateLock); Mutex::Autolock lock(mStateLock); // Get a RenderEngine for the given display / config (can't fail) // TODO(b/77156734): We need to stop casting and use HAL types when possible. Loading Loading @@ -806,12 +806,14 @@ void SurfaceFlinger::init() { } // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); LOG_ALWAYS_FATAL_IF(!configureLocked(), "Initial display configuration failed: HWC did not hotplug"); processDisplayChangesLocked(); const auto display = getDefaultDisplayDeviceLocked(); LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback."); const auto displayId = display->getPhysicalId(); LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId), "Primary display is disconnected."); LOG_ALWAYS_FATAL_IF(!display, "Failed to configure the primary display"); LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getPhysicalId()), "Primary display is disconnected"); // initialize our drawing state mDrawingState = mCurrentState; Loading Loading @@ -1869,23 +1871,14 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { const bool connected = connection == hal::Connection::CONNECTED; ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId); // Only lock if we're not on the main thread. This function is normally // called on a hwbinder thread, but for the primary display it's called on // the main thread with the state lock already held, so don't attempt to // acquire it here. ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection}); if (std::this_thread::get_id() == mMainThreadId) { // Process all pending hot plug events immediately if we are on the main thread. processDisplayHotplugEventsLocked(); { std::lock_guard<std::mutex> lock(mHotplugMutex); mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection}); } setTransactionFlags(eDisplayTransactionNeeded); if (mScheduler) { mScheduler->scheduleConfigure(); } } void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged( Loading Loading @@ -1958,6 +1951,13 @@ TimePoint SurfaceFlinger::calculateExpectedPresentTime(TimePoint frameTime) cons return vsyncDeadline + schedule.period(); } void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) { Mutex::Autolock lock(mStateLock); if (configureLocked()) { setTransactionFlags(eDisplayTransactionNeeded); } } bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) FTL_FAKE_GUARD(kMainThreadContext) { // The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the Loading Loading @@ -2642,8 +2642,14 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( return {modes, activeMode}; } void SurfaceFlinger::processDisplayHotplugEventsLocked() { for (const auto& event : mPendingHotplugEvents) { bool SurfaceFlinger::configureLocked() { std::vector<HotplugEvent> events; { std::lock_guard<std::mutex> lock(mHotplugMutex); events = std::move(mPendingHotplugEvents); } for (const auto& event : events) { std::optional<DisplayIdentificationInfo> info = getHwComposer().onHotplug(event.hwcDisplayId, event.connection); Loading @@ -2653,6 +2659,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { const auto displayId = info->id; const auto token = mPhysicalDisplayTokens.get(displayId); const char* log; if (event.connection == hal::Connection::CONNECTED) { auto [supportedModes, activeMode] = loadDisplayModes(displayId); Loading @@ -2664,7 +2671,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { } if (!token) { ALOGV("Creating display %s", to_string(displayId).c_str()); log = "Connecting"; DisplayDeviceState state; state.physical = {.id = displayId, Loading @@ -2681,7 +2688,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { mPhysicalDisplayTokens.try_emplace(displayId, std::move(token)); mInterceptor->saveDisplayCreation(state); } else { ALOGV("Recreating display %s", to_string(displayId).c_str()); log = "Reconnecting"; auto& state = mCurrentState.displays.editValueFor(token->get()); state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. Loading @@ -2692,7 +2699,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { } } } else { ALOGV("Removing display %s", to_string(displayId).c_str()); log = "Disconnecting"; if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) { const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); Loading @@ -2703,15 +2710,14 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { mPhysicalDisplayTokens.erase(displayId); } processDisplayChangesLocked(); ALOGI("%s display %s (HAL ID %" PRIu64 ")", log, to_string(displayId).c_str(), event.hwcDisplayId); } mPendingHotplugEvents.clear(); return !events.empty(); } void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) { ALOGI("Dispatching display hotplug event displayId=%s, connected=%d", to_string(displayId).c_str(), connected); mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected); mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected); } Loading Loading @@ -3041,7 +3047,6 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; if (displayTransactionNeeded) { processDisplayChangesLocked(); processDisplayHotplugEventsLocked(); } mForceTransactionDisplayChange = displayTransactionNeeded; Loading services/surfaceflinger/SurfaceFlinger.h +19 −10 Original line number Diff line number Diff line Loading @@ -432,11 +432,6 @@ private: FINISHED, }; struct HotplugEvent { hal::HWDisplayId hwcDisplayId; hal::Connection connection = hal::Connection::INVALID; }; template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr> static Dumper dumper(F&& dump) { using namespace std::placeholders; Loading Loading @@ -611,6 +606,9 @@ private: // ICompositor overrides: // Configures physical displays, processing hotplug and/or mode setting via the Composer HAL. void configure() override; // Commits transactions for layers and displays. Returns whether any state has been invalidated, // i.e. whether a frame should be composited for each display. bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) override; Loading @@ -622,9 +620,7 @@ private: // Samples the composited frame via RegionSamplingThread. void sample() override; /* * ISchedulerCallback */ // ISchedulerCallback overrides: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; Loading @@ -634,6 +630,7 @@ private: void kernelTimerChanged(bool expired) override; // Called when the frame rate override list changed to trigger an event. void triggerOnFrameRateOverridesChanged() override; // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. void toggleKernelIdleTimer() REQUIRES(mStateLock); // Get the controller and timeout that will help decide how the kernel idle timer will be Loading Loading @@ -911,6 +908,13 @@ private: std::pair<DisplayModes, DisplayModePtr> loadDisplayModes(PhysicalDisplayId) const REQUIRES(mStateLock); // TODO(b/241285876): Move to DisplayConfigurator. // // Returns whether displays have been added/changed/removed, i.e. whether ICompositor should // commit display transactions. bool configureLocked() REQUIRES(mStateLock) REQUIRES(kMainThreadContext) EXCLUDES(mHotplugMutex); sp<DisplayDevice> setupNewDisplayDeviceInternal( const wp<IBinder>& displayToken, std::shared_ptr<compositionengine::Display> compositionDisplay, Loading @@ -922,7 +926,6 @@ private: void processDisplayChanged(const wp<IBinder>& displayToken, const DisplayDeviceState& currentState, const DisplayDeviceState& drawingState) REQUIRES(mStateLock); void processDisplayHotplugEventsLocked() REQUIRES(mStateLock); void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected); Loading Loading @@ -1145,7 +1148,13 @@ private: BootStage mBootStage = BootStage::BOOTLOADER; std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mStateLock); struct HotplugEvent { hal::HWDisplayId hwcDisplayId; hal::Connection connection = hal::Connection::INVALID; }; std::mutex mHotplugMutex; std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex); // Displays are composited in `mDisplays` order. Internal displays are inserted at boot and // never removed, so take precedence over external and virtual displays. Loading Loading
services/surfaceflinger/Scheduler/MessageQueue.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,19 @@ void MessageQueue::postMessage(sp<MessageHandler>&& handler) { mLooper->sendMessage(handler, Message()); } void MessageQueue::scheduleConfigure() { struct ConfigureHandler : MessageHandler { explicit ConfigureHandler(ICompositor& compositor) : compositor(compositor) {} void handleMessage(const Message&) override { compositor.configure(); } ICompositor& compositor; }; // TODO(b/241285876): Batch configure tasks that happen within some duration. postMessage(sp<ConfigureHandler>::make(mCompositor)); } void MessageQueue::scheduleFrame() { ATRACE_CALL(); Loading
services/surfaceflinger/Scheduler/MessageQueue.h +3 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ namespace android { struct ICompositor { virtual void configure() = 0; virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0; virtual void composite(TimePoint frameTime, VsyncId) = 0; virtual void sample() = 0; Loading Loading @@ -78,6 +79,7 @@ public: virtual void setInjector(sp<EventThreadConnection>) = 0; virtual void waitMessage() = 0; virtual void postMessage(sp<MessageHandler>&&) = 0; virtual void scheduleConfigure() = 0; virtual void scheduleFrame() = 0; using Clock = std::chrono::steady_clock; Loading Loading @@ -152,6 +154,7 @@ public: void waitMessage() override; void postMessage(sp<MessageHandler>&&) override; void scheduleConfigure() override; void scheduleFrame() override; std::optional<Clock::time_point> getScheduledFrameTime() const override; Loading
services/surfaceflinger/Scheduler/Scheduler.h +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ public: using Impl::getScheduledFrameTime; using Impl::setDuration; using Impl::scheduleConfigure; using Impl::scheduleFrame; // Schedule an asynchronous or synchronous task on the main thread. Loading
services/surfaceflinger/SurfaceFlinger.cpp +37 −32 Original line number Diff line number Diff line Loading @@ -763,10 +763,10 @@ chooseRenderEngineTypeViaSysProp() { // Do not call property_set on main thread which will be blocked by init // Use StartPropertySetThread instead. void SurfaceFlinger::init() { void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); Mutex::Autolock _l(mStateLock); Mutex::Autolock lock(mStateLock); // Get a RenderEngine for the given display / config (can't fail) // TODO(b/77156734): We need to stop casting and use HAL types when possible. Loading Loading @@ -806,12 +806,14 @@ void SurfaceFlinger::init() { } // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); LOG_ALWAYS_FATAL_IF(!configureLocked(), "Initial display configuration failed: HWC did not hotplug"); processDisplayChangesLocked(); const auto display = getDefaultDisplayDeviceLocked(); LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback."); const auto displayId = display->getPhysicalId(); LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId), "Primary display is disconnected."); LOG_ALWAYS_FATAL_IF(!display, "Failed to configure the primary display"); LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getPhysicalId()), "Primary display is disconnected"); // initialize our drawing state mDrawingState = mCurrentState; Loading Loading @@ -1869,23 +1871,14 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { const bool connected = connection == hal::Connection::CONNECTED; ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId); // Only lock if we're not on the main thread. This function is normally // called on a hwbinder thread, but for the primary display it's called on // the main thread with the state lock already held, so don't attempt to // acquire it here. ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection}); if (std::this_thread::get_id() == mMainThreadId) { // Process all pending hot plug events immediately if we are on the main thread. processDisplayHotplugEventsLocked(); { std::lock_guard<std::mutex> lock(mHotplugMutex); mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection}); } setTransactionFlags(eDisplayTransactionNeeded); if (mScheduler) { mScheduler->scheduleConfigure(); } } void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged( Loading Loading @@ -1958,6 +1951,13 @@ TimePoint SurfaceFlinger::calculateExpectedPresentTime(TimePoint frameTime) cons return vsyncDeadline + schedule.period(); } void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) { Mutex::Autolock lock(mStateLock); if (configureLocked()) { setTransactionFlags(eDisplayTransactionNeeded); } } bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) FTL_FAKE_GUARD(kMainThreadContext) { // The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the Loading Loading @@ -2642,8 +2642,14 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( return {modes, activeMode}; } void SurfaceFlinger::processDisplayHotplugEventsLocked() { for (const auto& event : mPendingHotplugEvents) { bool SurfaceFlinger::configureLocked() { std::vector<HotplugEvent> events; { std::lock_guard<std::mutex> lock(mHotplugMutex); events = std::move(mPendingHotplugEvents); } for (const auto& event : events) { std::optional<DisplayIdentificationInfo> info = getHwComposer().onHotplug(event.hwcDisplayId, event.connection); Loading @@ -2653,6 +2659,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { const auto displayId = info->id; const auto token = mPhysicalDisplayTokens.get(displayId); const char* log; if (event.connection == hal::Connection::CONNECTED) { auto [supportedModes, activeMode] = loadDisplayModes(displayId); Loading @@ -2664,7 +2671,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { } if (!token) { ALOGV("Creating display %s", to_string(displayId).c_str()); log = "Connecting"; DisplayDeviceState state; state.physical = {.id = displayId, Loading @@ -2681,7 +2688,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { mPhysicalDisplayTokens.try_emplace(displayId, std::move(token)); mInterceptor->saveDisplayCreation(state); } else { ALOGV("Recreating display %s", to_string(displayId).c_str()); log = "Reconnecting"; auto& state = mCurrentState.displays.editValueFor(token->get()); state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. Loading @@ -2692,7 +2699,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { } } } else { ALOGV("Removing display %s", to_string(displayId).c_str()); log = "Disconnecting"; if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) { const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); Loading @@ -2703,15 +2710,14 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { mPhysicalDisplayTokens.erase(displayId); } processDisplayChangesLocked(); ALOGI("%s display %s (HAL ID %" PRIu64 ")", log, to_string(displayId).c_str(), event.hwcDisplayId); } mPendingHotplugEvents.clear(); return !events.empty(); } void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) { ALOGI("Dispatching display hotplug event displayId=%s, connected=%d", to_string(displayId).c_str(), connected); mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected); mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected); } Loading Loading @@ -3041,7 +3047,6 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; if (displayTransactionNeeded) { processDisplayChangesLocked(); processDisplayHotplugEventsLocked(); } mForceTransactionDisplayChange = displayTransactionNeeded; Loading
services/surfaceflinger/SurfaceFlinger.h +19 −10 Original line number Diff line number Diff line Loading @@ -432,11 +432,6 @@ private: FINISHED, }; struct HotplugEvent { hal::HWDisplayId hwcDisplayId; hal::Connection connection = hal::Connection::INVALID; }; template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr> static Dumper dumper(F&& dump) { using namespace std::placeholders; Loading Loading @@ -611,6 +606,9 @@ private: // ICompositor overrides: // Configures physical displays, processing hotplug and/or mode setting via the Composer HAL. void configure() override; // Commits transactions for layers and displays. Returns whether any state has been invalidated, // i.e. whether a frame should be composited for each display. bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) override; Loading @@ -622,9 +620,7 @@ private: // Samples the composited frame via RegionSamplingThread. void sample() override; /* * ISchedulerCallback */ // ISchedulerCallback overrides: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; Loading @@ -634,6 +630,7 @@ private: void kernelTimerChanged(bool expired) override; // Called when the frame rate override list changed to trigger an event. void triggerOnFrameRateOverridesChanged() override; // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. void toggleKernelIdleTimer() REQUIRES(mStateLock); // Get the controller and timeout that will help decide how the kernel idle timer will be Loading Loading @@ -911,6 +908,13 @@ private: std::pair<DisplayModes, DisplayModePtr> loadDisplayModes(PhysicalDisplayId) const REQUIRES(mStateLock); // TODO(b/241285876): Move to DisplayConfigurator. // // Returns whether displays have been added/changed/removed, i.e. whether ICompositor should // commit display transactions. bool configureLocked() REQUIRES(mStateLock) REQUIRES(kMainThreadContext) EXCLUDES(mHotplugMutex); sp<DisplayDevice> setupNewDisplayDeviceInternal( const wp<IBinder>& displayToken, std::shared_ptr<compositionengine::Display> compositionDisplay, Loading @@ -922,7 +926,6 @@ private: void processDisplayChanged(const wp<IBinder>& displayToken, const DisplayDeviceState& currentState, const DisplayDeviceState& drawingState) REQUIRES(mStateLock); void processDisplayHotplugEventsLocked() REQUIRES(mStateLock); void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected); Loading Loading @@ -1145,7 +1148,13 @@ private: BootStage mBootStage = BootStage::BOOTLOADER; std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mStateLock); struct HotplugEvent { hal::HWDisplayId hwcDisplayId; hal::Connection connection = hal::Connection::INVALID; }; std::mutex mHotplugMutex; std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex); // Displays are composited in `mDisplays` order. Internal displays are inserted at boot and // never removed, so take precedence over external and virtual displays. Loading