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

Commit 2d736327 authored by Adithya Srinivasan's avatar Adithya Srinivasan
Browse files

Add a backdoor to change FrameTimeline's maxDisplayFrames

This change adds a backdoor entry through SurfaceFlinger to allow
modifying the max number of display frames stored in FrameTimeline. This
is particularly useful for debugging, enabling to take a trace as well
see the dump on the side.

Bug: 169894383
Test: libsurfaceflinger_unittest
Change-Id: I872e240597193d597dac4a9f096b6360edf5cce1
parent 8fc601d6
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -285,7 +285,9 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t
    dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}

FrameTimeline::FrameTimeline() : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()) {}
FrameTimeline::FrameTimeline()
      : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()),
        mMaxDisplayFrames(kDefaultMaxDisplayFrames) {}

FrameTimeline::DisplayFrame::DisplayFrame()
      : surfaceFlingerPredictions(TimelineItem()),
@@ -438,7 +440,7 @@ void FrameTimeline::flushPendingPresentFences() {
}

void FrameTimeline::finalizeCurrentDisplayFrame() {
    while (mDisplayFrames.size() >= kMaxDisplayFrames) {
    while (mDisplayFrames.size() >= mMaxDisplayFrames) {
        // We maintain only a fixed number of frames' data. Pop older frames
        mDisplayFrames.pop_front();
    }
@@ -530,4 +532,17 @@ void FrameTimeline::parseArgs(const Vector<String16>& args, std::string& result)
    }
}

void FrameTimeline::setMaxDisplayFrames(uint32_t size) {
    std::lock_guard<std::mutex> lock(mMutex);

    // The size can either increase or decrease, clear everything, to be consistent
    mDisplayFrames.clear();
    mPendingPresentFences.clear();
    mMaxDisplayFrames = size;
}

void FrameTimeline::reset() {
    setMaxDisplayFrames(kDefaultMaxDisplayFrames);
}

} // namespace android::frametimeline::impl
+10 −1
Original line number Diff line number Diff line
@@ -163,6 +163,12 @@ public:
    //         or contain janky Surface Frames.
    // -all : Dumps the entire list of DisplayFrames and the SurfaceFrames contained within
    virtual void parseArgs(const Vector<String16>& args, std::string& result) = 0;

    // Sets the max number of display frames that can be stored. Called by SF backdoor.
    virtual void setMaxDisplayFrames(uint32_t size);

    // Restores the max number of display frames to default. Called by SF backdoor.
    virtual void reset() = 0;
};

namespace impl {
@@ -240,6 +246,8 @@ public:
    void setSfPresent(nsecs_t sfPresentTime,
                      const std::shared_ptr<FenceTime>& presentFence) override;
    void parseArgs(const Vector<String16>& args, std::string& result) override;
    void setMaxDisplayFrames(uint32_t size) override;
    void reset() override;

private:
    // Friend class for testing
@@ -284,7 +292,8 @@ private:
    std::shared_ptr<DisplayFrame> mCurrentDisplayFrame GUARDED_BY(mMutex);
    TokenManager mTokenManager;
    std::mutex mMutex;
    static constexpr uint32_t kMaxDisplayFrames = 64;
    uint32_t mMaxDisplayFrames;
    static constexpr uint32_t kDefaultMaxDisplayFrames = 64;
    // The initial container size for the vector<SurfaceFrames> inside display frame. Although this
    // number doesn't represent any bounds on the number of surface frames that can go in a display
    // frame, this is a good starting size for the vector so that we can avoid the internal vector
+17 −2
Original line number Diff line number Diff line
@@ -4901,9 +4901,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
        code == IBinder::SYSPROPS_TRANSACTION) {
        return OK;
    }
    // Numbers from 1000 to 1037 are currently used for backdoors. The code
    // Numbers from 1000 to 1038 are currently used for backdoors. The code
    // in onTransact verifies that the user is root, and has access to use SF.
    if (code >= 1000 && code <= 1037) {
    if (code >= 1000 && code <= 1038) {
        ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
        return OK;
    }
@@ -5259,6 +5259,21 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r

                return NO_ERROR;
            }
            // Modify the max number of display frames stored within FrameTimeline
            case 1038: {
                n = data.readInt32();
                if (n < 0 || n > MAX_ALLOWED_DISPLAY_FRAMES) {
                    ALOGW("Invalid max size. Maximum allowed is %d", MAX_ALLOWED_DISPLAY_FRAMES);
                    return BAD_VALUE;
                }
                if (n == 0) {
                    // restore to default
                    mFrameTimeline->reset();
                    return NO_ERROR;
                }
                mFrameTimeline->setMaxDisplayFrames(n);
                return NO_ERROR;
            }
        }
    }
    return err;
+2 −0
Original line number Diff line number Diff line
@@ -499,6 +499,8 @@ private:
    }

    static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB
    // Maximum allowed number of display frames that can be set through backdoor
    static const int MAX_ALLOWED_DISPLAY_FRAMES = 2048;

    // Implements IBinder.
    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
+51 −3
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ public:
    void SetUp() override {
        mFrameTimeline = std::make_unique<impl::FrameTimeline>();
        mTokenManager = &mFrameTimeline->mTokenManager;
        maxDisplayFrames = mFrameTimeline->kMaxDisplayFrames;
        maxDisplayFrames = &mFrameTimeline->mMaxDisplayFrames;
        maxTokenRetentionTime = mTokenManager->kMaxRetentionTime;
    }

@@ -71,10 +71,15 @@ public:
        return mTokenManager->mPredictions;
    }

    uint32_t getNumberOfDisplayFrames() {
        std::lock_guard<std::mutex> lock(mFrameTimeline->mMutex);
        return static_cast<uint32_t>(mFrameTimeline->mDisplayFrames.size());
    }

    std::unique_ptr<impl::FrameTimeline> mFrameTimeline;
    impl::TokenManager* mTokenManager;
    FenceToFenceTimeMap fenceFactory;
    uint64_t maxDisplayFrames;
    uint32_t* maxDisplayFrames;
    nsecs_t maxTokenRetentionTime;
};

@@ -178,7 +183,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
    // Insert kMaxDisplayFrames' count of DisplayFrames to fill the deque
    int frameTimeFactor = 0;
    for (size_t i = 0; i < maxDisplayFrames; i++) {
    for (size_t i = 0; i < *maxDisplayFrames; i++) {
        auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
        int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions(
                {10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor});
@@ -233,4 +238,47 @@ TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) {
    EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
}

TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
    auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    presentFence->signalForTest(2);

    // Size shouldn't exceed maxDisplayFrames - 64
    for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
        auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
        int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
        mFrameTimeline->setSfWakeUp(sfToken, 22);
        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
                                        SurfaceFrame::PresentState::Presented);
        mFrameTimeline->setSfPresent(27, presentFence);
    }
    EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);

    // Increase the size to 256
    mFrameTimeline->setMaxDisplayFrames(256);
    EXPECT_EQ(*maxDisplayFrames, 256);

    for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
        auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
        int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
        mFrameTimeline->setSfWakeUp(sfToken, 22);
        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
                                        SurfaceFrame::PresentState::Presented);
        mFrameTimeline->setSfPresent(27, presentFence);
    }
    EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);

    // Shrink the size to 128
    mFrameTimeline->setMaxDisplayFrames(128);
    EXPECT_EQ(*maxDisplayFrames, 128);

    for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
        auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
        int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
        mFrameTimeline->setSfWakeUp(sfToken, 22);
        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
                                        SurfaceFrame::PresentState::Presented);
        mFrameTimeline->setSfPresent(27, presentFence);
    }
    EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);
}
} // namespace android::frametimeline