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