Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cea4787f authored by Su Hong Koo's avatar Su Hong Koo
Browse files

SF: Add sfdo command to force set pacesetter display

This CL adds a new command to sfdo to forcibly change the pacesetter
display to one specified by the ID. This is useful for testing various
connected display scenarios where refresh rates differ. The selected
display will remain the pacesetter until it is either disconnected
or another sfdo command to force-set/unset the pacesetter is invoked.

This CL also adds another sfdo command to reset the forced pacesetter.
The reset command is a no-op if no display was forced as a pacestter.
Currently, the reset sets the front internal display as the new
pacesetter if the pacesetter_selection flag is disabled.

Flag: NONE adb backdoor
Test: Invoked sfdo force-pacesetter DISP_ID && reset on a foldable
Bug: 389982668
Change-Id: I2ac891c75f4346b7e11e438b8026d5c8c5a6298f
parent 5beefff9
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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
@@ -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.");
+14 −0
Original line number Diff line number Diff line
@@ -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();
}
+4 −0
Original line number Diff line number Diff line
@@ -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; }

+42 −9
Original line number Diff line number Diff line
@@ -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)) {
@@ -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;
@@ -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!");
@@ -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);
    }
@@ -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));
@@ -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;
+24 −6
Original line number Diff line number Diff line
@@ -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>;
@@ -499,14 +511,17 @@ private:
    void resync() 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;
@@ -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