Add isBuffer to SurfaceFrame
Add a boolean that tells if the SurfaceFrame is representing a buffer or
not. This makes it easy to debug lost/stuck frames in the pending
classification list. Also add a miniDump for SurfaceFrame to enable
debugging the lost frame.
Bug: 182214639
Test: Build and flash
Change-Id: I6ceef46887a021c2f36e76f37fab8368802465a4
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3442706..b1dff8d 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -296,7 +296,7 @@
frametimeline::TimelineItem&& predictions,
std::shared_ptr<TimeStats> timeStats,
JankClassificationThresholds thresholds,
- TraceCookieCounter* traceCookieCounter)
+ TraceCookieCounter* traceCookieCounter, bool isBuffer)
: mToken(frameTimelineInfo.vsyncId),
mInputEventId(frameTimelineInfo.inputEventId),
mOwnerPid(ownerPid),
@@ -310,7 +310,8 @@
mActuals({0, 0, 0}),
mTimeStats(timeStats),
mJankClassificationThresholds(thresholds),
- mTraceCookieCounter(*traceCookieCounter) {}
+ mTraceCookieCounter(*traceCookieCounter),
+ mIsBuffer(isBuffer) {}
void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
std::scoped_lock lock(mMutex);
@@ -395,6 +396,20 @@
return mDropTime;
}
+void SurfaceFrame::promoteToBuffer() {
+ std::scoped_lock lock(mMutex);
+ LOG_ALWAYS_FATAL_IF(mIsBuffer == true,
+ "Trying to promote an already promoted BufferSurfaceFrame from layer %s "
+ "with token %" PRId64 "",
+ mDebugName.c_str(), mToken);
+ mIsBuffer = true;
+}
+
+bool SurfaceFrame::getIsBuffer() const {
+ std::scoped_lock lock(mMutex);
+ return mIsBuffer;
+}
+
void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const {
std::scoped_lock lock(mMutex);
StringAppendF(&result, "%s", indent.c_str());
@@ -407,6 +422,8 @@
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Token: %" PRId64 "\n", mToken);
StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Is Buffer?: %d\n", mIsBuffer);
+ StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Scheduled rendering rate: %d fps\n",
@@ -444,6 +461,21 @@
dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}
+std::string SurfaceFrame::miniDump() const {
+ std::scoped_lock lock(mMutex);
+ std::string result;
+ StringAppendF(&result, "Layer - %s\n", mDebugName.c_str());
+ StringAppendF(&result, "Token: %" PRId64 "\n", mToken);
+ StringAppendF(&result, "Is Buffer?: %d\n", mIsBuffer);
+ StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
+ StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
+ StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
+ StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
+ StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
+ StringAppendF(&result, "Present time: %" PRId64 "", mActuals.presentTime);
+ return result;
+}
+
void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
nsecs_t& deadlineDelta) {
if (mPredictionState == PredictionState::Expired ||
@@ -744,13 +776,14 @@
std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, int32_t layerId,
- std::string layerName, std::string debugName) {
+ std::string layerName, std::string debugName, bool isBuffer) {
ATRACE_CALL();
if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid, layerId,
std::move(layerName), std::move(debugName),
PredictionState::None, TimelineItem(), mTimeStats,
- mJankClassificationThresholds, &mTraceCookieCounter);
+ mJankClassificationThresholds, &mTraceCookieCounter,
+ isBuffer);
}
std::optional<TimelineItem> predictions =
mTokenManager.getPredictionsForToken(frameTimelineInfo.vsyncId);
@@ -759,12 +792,13 @@
std::move(layerName), std::move(debugName),
PredictionState::Valid, std::move(*predictions),
mTimeStats, mJankClassificationThresholds,
- &mTraceCookieCounter);
+ &mTraceCookieCounter, isBuffer);
}
return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid, layerId,
std::move(layerName), std::move(debugName),
PredictionState::Expired, TimelineItem(), mTimeStats,
- mJankClassificationThresholds, &mTraceCookieCounter);
+ mJankClassificationThresholds, &mTraceCookieCounter,
+ isBuffer);
}
FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index b66e02a..3cf35f0 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -159,7 +159,7 @@
int32_t layerId, std::string layerName, std::string debugName,
PredictionState predictionState, TimelineItem&& predictions,
std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds,
- TraceCookieCounter* traceCookieCounter);
+ TraceCookieCounter* traceCookieCounter, bool isBuffer);
~SurfaceFrame() = default;
// Returns std::nullopt if the frame hasn't been classified yet.
@@ -181,6 +181,10 @@
void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
void setRenderRate(Fps renderRate);
+ // When a bufferless SurfaceFrame is promoted to a buffer SurfaceFrame, we also have to update
+ // isBuffer.
+ void promoteToBuffer();
+
// Functions called by FrameTimeline
// BaseTime is the smallest timestamp in this SurfaceFrame.
// Used for dumping all timestamps relative to the oldest, making it easy to read.
@@ -192,6 +196,8 @@
nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta);
// All the timestamps are dumped relative to the baseTime
void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const;
+ // Dumps only the layer, token, is buffer, jank metadata, prediction and present states.
+ std::string miniDump() const;
// Emits a packet for perfetto tracing. The function body will be executed only if tracing is
// enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
// DisplayFrame at the trace processor side.
@@ -206,6 +212,7 @@
FrameReadyMetadata getFrameReadyMetadata() const;
FramePresentMetadata getFramePresentMetadata() const;
nsecs_t getDropTime() const;
+ bool getIsBuffer() const;
// For prediction expired frames, this delta is subtracted from the actual end time to get a
// start time decent enough to see in traces.
@@ -253,6 +260,9 @@
// TraceCookieCounter is used to obtain the cookie for sendig trace packets to perfetto. Using a
// reference here because the counter is owned by FrameTimeline, which outlives SurfaceFrame.
TraceCookieCounter& mTraceCookieCounter;
+ // Tells if the SurfaceFrame is representing a buffer or a transaction without a
+ // buffer(animations)
+ bool mIsBuffer;
};
/*
@@ -272,7 +282,7 @@
// Debug name is the human-readable debugging string for dumpsys.
virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
- int32_t layerId, std::string layerName, std::string debugName) = 0;
+ int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) = 0;
// Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be
// composited into one display frame.
@@ -431,7 +441,7 @@
frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
- int32_t layerId, std::string layerName, std::string debugName) override;
+ int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) override;
void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
void setSfPresent(nsecs_t sfPresentTime,