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
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 22d9d10..43176a3 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -285,7 +285,9 @@
     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::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::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
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 1624c2b..7da0757 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -163,6 +163,12 @@
     //         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 @@
     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 @@
     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
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e9eb63f..619bc03 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4901,9 +4901,9 @@
         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 @@
 
                 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;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 738e056..d069f2b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -499,6 +499,8 @@
     }
 
     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;
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 617f95a..69efd7f 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -43,7 +43,7 @@
     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 @@
         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, 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 @@
     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