Loading cmds/sfdo/sfdo.rs +22 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,20 @@ enum Commands { #[command(about = "Force commit ahead of next VSYNC.")] ScheduleCommit, #[command( about = "display_id = i64, Forcibly changes the pacesetter display to specified display, \ which will persist until the display is removed or another ForcePacesetter \ or ResetForcedPacesetter call is made. Valid display IDs can be obtained \ through: adb shell dumpsys SurfaceFlinger --display-ids" )] ForcePacesetter { display_id: i64 }, #[command( about = "Resets the forced pacesetter display selection made by the ForcePacesetter \ call. No-op if there was no forced pacesetter display set." )] ResetForcedPacesetter, } /// sfdo command line tool Loading Loading @@ -146,6 +160,14 @@ fn main() { eprintln!("No state, choices are [enabled | disabled]"); } } Some(Commands::ForcePacesetter { display_id }) => { let res = composer_service.forcePacesetter(*display_id); print_result("forcePacesetter", res); } Some(Commands::ResetForcedPacesetter) => { let res = composer_service.resetForcedPacesetter(); print_result("resetForcedPacesetter", res); } None => { println!("Execute SurfaceFlinger internal commands."); println!("run `adb shell sfdo help` for more to view the commands."); Loading libs/gui/aidl/android/gui/ISurfaceComposer.aidl +14 −0 Original line number Diff line number Diff line Loading @@ -650,4 +650,18 @@ interface ISurfaceComposer { * profiles. */ oneway void removeActivePictureListener(IActivePictureListener listener); /** * Force the display specified by the argument to become the pacesetter display until the * display is removed or another forcePacesetter/resetForcedPacesetter call is invoked. * Requires root */ void forcePacesetter(long displayId); /** * Resets the forced pacesetter display selection made by the forcePacesetter call. No-op * if there was no forced pacesetter display set. * Requires root */ void resetForcedPacesetter(); } libs/gui/tests/Surface_test.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -1061,6 +1061,10 @@ public: return binder::Status::ok(); } binder::Status forcePacesetter(int64_t) { return binder::Status::ok(); } binder::Status resetForcedPacesetter() { return binder::Status::ok(); } protected: IBinder* onAsBinder() override { return nullptr; } Loading services/surfaceflinger/Scheduler/Scheduler.cpp +42 −9 Original line number Diff line number Diff line Loading @@ -111,9 +111,7 @@ void Scheduler::startTimers() { } bool Scheduler::designatePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterId) { if (FlagManager::getInstance().pacesetter_selection() && !pacesetterId.has_value()) { pacesetterId = selectPacesetterDisplay(); } pacesetterId = selectPacesetterDisplay(pacesetterId); // Skip an unnecessary demotion/promotion cycle if there's no work to do. if ((ftl::FakeGuard(mDisplayLock), mPacesetterDisplayId == *pacesetterId)) { Loading @@ -138,12 +136,30 @@ bool Scheduler::designatePacesetterDisplay(std::optional<PhysicalDisplayId> pace return true; } PhysicalDisplayId Scheduler::selectPacesetterDisplay() const { bool Scheduler::forcePacesetterDisplay(PhysicalDisplayId pacesetterId) { { std::scoped_lock lock(mDisplayLock); mForcedPacesetterDisplayId = pacesetterId; } return designatePacesetterDisplay(); } PhysicalDisplayId Scheduler::selectPacesetterDisplay( std::optional<PhysicalDisplayId> desiredPacesetterId) const { std::scoped_lock lock(mDisplayLock); return selectPacesetterDisplayLocked(); return selectPacesetterDisplayLocked(desiredPacesetterId); } PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked( std::optional<PhysicalDisplayId> desiredPacesetterId) const { if (mForcedPacesetterDisplayId.has_value()) { return *mForcedPacesetterDisplayId; } if (desiredPacesetterId.has_value()) { return *desiredPacesetterId; } PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked() const { // The first display should be the new pacesetter if none of the displays are powered on. const auto& [firstDisplayId, firstDisplay] = *mDisplays.begin(); PhysicalDisplayId newPacesetterId = firstDisplayId; Loading Loading @@ -189,6 +205,19 @@ PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked() const { return newPacesetterId; } bool Scheduler::resetForcedPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterId) { { std::scoped_lock lock(mDisplayLock); if (!mForcedPacesetterDisplayId.has_value()) { return false; } mForcedPacesetterDisplayId.reset(); } return designatePacesetterDisplay(pacesetterId); } PhysicalDisplayId Scheduler::getPacesetterDisplayId() const { std::scoped_lock lock(mDisplayLock); LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId, "Missing a pacesetter!"); Loading Loading @@ -259,6 +288,10 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId, // headless virtual display.) LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!"); if (mForcedPacesetterDisplayId == displayId) { mForcedPacesetterDisplayId.reset(); } pacesetterVsyncSchedule = promotePacesetterDisplayLocked(defaultPacesetterId, kPromotionParams); } Loading Loading @@ -1069,6 +1102,7 @@ void Scheduler::dump(utils::Dumper& dumper) const { std::scoped_lock lock(mDisplayLock); ftl::FakeGuard guard(kMainThreadContext); dumper.dump("pacesetterDisplayId"sv, mPacesetterDisplayId); dumper.dump("forcedPacesetterDisplayId"sv, mForcedPacesetterDisplayId); } dumper.dump("layerHistory"sv, mLayerHistory.dump()); dumper.dump("touchTimer"sv, mTouchTimer.transform(&OneShotTimer::interval)); Loading Loading @@ -1163,11 +1197,10 @@ void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacese std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked( std::optional<PhysicalDisplayId> pacesetterId, PromotionParams params) { if (FlagManager::getInstance().pacesetter_selection() && !pacesetterId.has_value()) { pacesetterId = selectPacesetterDisplayLocked(); } pacesetterId = selectPacesetterDisplayLocked(pacesetterId); mPacesetterDisplayId = *pacesetterId; ALOGI("Display %s is the pacesetter", to_string(*pacesetterId).c_str()); std::shared_ptr<VsyncSchedule> newVsyncSchedulePtr; Loading services/surfaceflinger/Scheduler/Scheduler.h +24 −6 Original line number Diff line number Diff line Loading @@ -91,12 +91,24 @@ public: void startTimers(); // Automatically selects a pacesetter display and designates if |pacesetterId| is not present, // Automatically selects a pacesetter display and designates if `pacesetterId` is not present, // otherwise promotes `pacesetterId` to pacesetter. Returns true if a new display was chosen as // the pacesetter. bool designatePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterId = std::nullopt) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); // Force `pacesetterId` as the pacesetter display, which will remain as the pacesetter display // until it is unregistered or the forced pacesetter is reset. Returns true if the forced // pacesetter is different from the previous pacesetter. bool forcePacesetterDisplay(PhysicalDisplayId pacesetterId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); // Clears forced pacesetter display if present and sets the pacesetter to // `pacesetterId` if present, otherwise automatically selects one. No-op if // `mForcedPacesetterDisplayId` is not set. bool resetForcedPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); PhysicalDisplayId getPacesetterDisplayId() const EXCLUDES(mDisplayLock); using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>; Loading Loading @@ -499,14 +511,17 @@ private: Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock); void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock); // Returns the powered-on display with the highest refresh rate in |mDisplays| as the new // pacesetter, but does not set the display as pacesetter. // Returns the display that should be promoted to pacesetter using the following priority: // 1. `mForcedPacesetterDisplayId`, if present // 2. `desiredPacesetterId`, if specified // 3. powered-on display with the highest refresh rate in `mDisplays` // NOTE: If displays with highest refresh rates have roughly equal refresh rates, // and the current pacesetter is among them, then the current pacesetter will remain the // pacesetter. PhysicalDisplayId selectPacesetterDisplay() const REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); PhysicalDisplayId selectPacesetterDisplayLocked() const PhysicalDisplayId selectPacesetterDisplay(std::optional<PhysicalDisplayId> desiredPacesetterId) const REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); PhysicalDisplayId selectPacesetterDisplayLocked( std::optional<PhysicalDisplayId> desiredPacesetterId) const REQUIRES(kMainThreadContext, mDisplayLock); std::unique_ptr<EventThread> mRenderEventThread; Loading Loading @@ -575,6 +590,9 @@ private: // May be read from any thread, but must only be written from the main thread. ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock); ftl::Optional<PhysicalDisplayId> mForcedPacesetterDisplayId GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext); ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) { return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform( [](const Display& display) { return std::ref(const_cast<Display&>(display)); }); Loading Loading
cmds/sfdo/sfdo.rs +22 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,20 @@ enum Commands { #[command(about = "Force commit ahead of next VSYNC.")] ScheduleCommit, #[command( about = "display_id = i64, Forcibly changes the pacesetter display to specified display, \ which will persist until the display is removed or another ForcePacesetter \ or ResetForcedPacesetter call is made. Valid display IDs can be obtained \ through: adb shell dumpsys SurfaceFlinger --display-ids" )] ForcePacesetter { display_id: i64 }, #[command( about = "Resets the forced pacesetter display selection made by the ForcePacesetter \ call. No-op if there was no forced pacesetter display set." )] ResetForcedPacesetter, } /// sfdo command line tool Loading Loading @@ -146,6 +160,14 @@ fn main() { eprintln!("No state, choices are [enabled | disabled]"); } } Some(Commands::ForcePacesetter { display_id }) => { let res = composer_service.forcePacesetter(*display_id); print_result("forcePacesetter", res); } Some(Commands::ResetForcedPacesetter) => { let res = composer_service.resetForcedPacesetter(); print_result("resetForcedPacesetter", res); } None => { println!("Execute SurfaceFlinger internal commands."); println!("run `adb shell sfdo help` for more to view the commands."); Loading
libs/gui/aidl/android/gui/ISurfaceComposer.aidl +14 −0 Original line number Diff line number Diff line Loading @@ -650,4 +650,18 @@ interface ISurfaceComposer { * profiles. */ oneway void removeActivePictureListener(IActivePictureListener listener); /** * Force the display specified by the argument to become the pacesetter display until the * display is removed or another forcePacesetter/resetForcedPacesetter call is invoked. * Requires root */ void forcePacesetter(long displayId); /** * Resets the forced pacesetter display selection made by the forcePacesetter call. No-op * if there was no forced pacesetter display set. * Requires root */ void resetForcedPacesetter(); }
libs/gui/tests/Surface_test.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -1061,6 +1061,10 @@ public: return binder::Status::ok(); } binder::Status forcePacesetter(int64_t) { return binder::Status::ok(); } binder::Status resetForcedPacesetter() { return binder::Status::ok(); } protected: IBinder* onAsBinder() override { return nullptr; } Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +42 −9 Original line number Diff line number Diff line Loading @@ -111,9 +111,7 @@ void Scheduler::startTimers() { } bool Scheduler::designatePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterId) { if (FlagManager::getInstance().pacesetter_selection() && !pacesetterId.has_value()) { pacesetterId = selectPacesetterDisplay(); } pacesetterId = selectPacesetterDisplay(pacesetterId); // Skip an unnecessary demotion/promotion cycle if there's no work to do. if ((ftl::FakeGuard(mDisplayLock), mPacesetterDisplayId == *pacesetterId)) { Loading @@ -138,12 +136,30 @@ bool Scheduler::designatePacesetterDisplay(std::optional<PhysicalDisplayId> pace return true; } PhysicalDisplayId Scheduler::selectPacesetterDisplay() const { bool Scheduler::forcePacesetterDisplay(PhysicalDisplayId pacesetterId) { { std::scoped_lock lock(mDisplayLock); mForcedPacesetterDisplayId = pacesetterId; } return designatePacesetterDisplay(); } PhysicalDisplayId Scheduler::selectPacesetterDisplay( std::optional<PhysicalDisplayId> desiredPacesetterId) const { std::scoped_lock lock(mDisplayLock); return selectPacesetterDisplayLocked(); return selectPacesetterDisplayLocked(desiredPacesetterId); } PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked( std::optional<PhysicalDisplayId> desiredPacesetterId) const { if (mForcedPacesetterDisplayId.has_value()) { return *mForcedPacesetterDisplayId; } if (desiredPacesetterId.has_value()) { return *desiredPacesetterId; } PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked() const { // The first display should be the new pacesetter if none of the displays are powered on. const auto& [firstDisplayId, firstDisplay] = *mDisplays.begin(); PhysicalDisplayId newPacesetterId = firstDisplayId; Loading Loading @@ -189,6 +205,19 @@ PhysicalDisplayId Scheduler::selectPacesetterDisplayLocked() const { return newPacesetterId; } bool Scheduler::resetForcedPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterId) { { std::scoped_lock lock(mDisplayLock); if (!mForcedPacesetterDisplayId.has_value()) { return false; } mForcedPacesetterDisplayId.reset(); } return designatePacesetterDisplay(pacesetterId); } PhysicalDisplayId Scheduler::getPacesetterDisplayId() const { std::scoped_lock lock(mDisplayLock); LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId, "Missing a pacesetter!"); Loading Loading @@ -259,6 +288,10 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId, // headless virtual display.) LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!"); if (mForcedPacesetterDisplayId == displayId) { mForcedPacesetterDisplayId.reset(); } pacesetterVsyncSchedule = promotePacesetterDisplayLocked(defaultPacesetterId, kPromotionParams); } Loading Loading @@ -1069,6 +1102,7 @@ void Scheduler::dump(utils::Dumper& dumper) const { std::scoped_lock lock(mDisplayLock); ftl::FakeGuard guard(kMainThreadContext); dumper.dump("pacesetterDisplayId"sv, mPacesetterDisplayId); dumper.dump("forcedPacesetterDisplayId"sv, mForcedPacesetterDisplayId); } dumper.dump("layerHistory"sv, mLayerHistory.dump()); dumper.dump("touchTimer"sv, mTouchTimer.transform(&OneShotTimer::interval)); Loading Loading @@ -1163,11 +1197,10 @@ void Scheduler::promotePacesetterDisplay(std::optional<PhysicalDisplayId> pacese std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked( std::optional<PhysicalDisplayId> pacesetterId, PromotionParams params) { if (FlagManager::getInstance().pacesetter_selection() && !pacesetterId.has_value()) { pacesetterId = selectPacesetterDisplayLocked(); } pacesetterId = selectPacesetterDisplayLocked(pacesetterId); mPacesetterDisplayId = *pacesetterId; ALOGI("Display %s is the pacesetter", to_string(*pacesetterId).c_str()); std::shared_ptr<VsyncSchedule> newVsyncSchedulePtr; Loading
services/surfaceflinger/Scheduler/Scheduler.h +24 −6 Original line number Diff line number Diff line Loading @@ -91,12 +91,24 @@ public: void startTimers(); // Automatically selects a pacesetter display and designates if |pacesetterId| is not present, // Automatically selects a pacesetter display and designates if `pacesetterId` is not present, // otherwise promotes `pacesetterId` to pacesetter. Returns true if a new display was chosen as // the pacesetter. bool designatePacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterId = std::nullopt) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); // Force `pacesetterId` as the pacesetter display, which will remain as the pacesetter display // until it is unregistered or the forced pacesetter is reset. Returns true if the forced // pacesetter is different from the previous pacesetter. bool forcePacesetterDisplay(PhysicalDisplayId pacesetterId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); // Clears forced pacesetter display if present and sets the pacesetter to // `pacesetterId` if present, otherwise automatically selects one. No-op if // `mForcedPacesetterDisplayId` is not set. bool resetForcedPacesetterDisplay(std::optional<PhysicalDisplayId> pacesetterId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); PhysicalDisplayId getPacesetterDisplayId() const EXCLUDES(mDisplayLock); using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>; Loading Loading @@ -499,14 +511,17 @@ private: Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock); void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock); // Returns the powered-on display with the highest refresh rate in |mDisplays| as the new // pacesetter, but does not set the display as pacesetter. // Returns the display that should be promoted to pacesetter using the following priority: // 1. `mForcedPacesetterDisplayId`, if present // 2. `desiredPacesetterId`, if specified // 3. powered-on display with the highest refresh rate in `mDisplays` // NOTE: If displays with highest refresh rates have roughly equal refresh rates, // and the current pacesetter is among them, then the current pacesetter will remain the // pacesetter. PhysicalDisplayId selectPacesetterDisplay() const REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); PhysicalDisplayId selectPacesetterDisplayLocked() const PhysicalDisplayId selectPacesetterDisplay(std::optional<PhysicalDisplayId> desiredPacesetterId) const REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); PhysicalDisplayId selectPacesetterDisplayLocked( std::optional<PhysicalDisplayId> desiredPacesetterId) const REQUIRES(kMainThreadContext, mDisplayLock); std::unique_ptr<EventThread> mRenderEventThread; Loading Loading @@ -575,6 +590,9 @@ private: // May be read from any thread, but must only be written from the main thread. ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock); ftl::Optional<PhysicalDisplayId> mForcedPacesetterDisplayId GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext); ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) { return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform( [](const Display& display) { return std::ref(const_cast<Display&>(display)); }); Loading