SF: Add continuous transaction tracing
Add the ability to capture all incoming transactions into a ring
buffer. Capture transactions as the come in through the binder
thread. On the main thread push committed transactions to the
tracing thread which will then add to the buffer and purge
older entries as the buffer gets filled.
Also introduce a new flag to enable transaction tracing (disabled
by default).
Test: presubmit
Bug: 200284593
Change-Id: I90dd0fa4f89f68cfc7b7922ecd0bba4adab8d7a4
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 93f8406..7a8968b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -357,10 +357,11 @@
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
+ mPid(getpid()),
mInterceptor(mFactory.createSurfaceInterceptor()),
mTimeStats(std::make_shared<impl::TimeStats>()),
mFrameTracer(mFactory.createFrameTracer()),
- mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())),
+ mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)),
mCompositionEngine(mFactory.createCompositionEngine()),
mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
@@ -489,6 +490,11 @@
enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false));
enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
+
+ mTransactionTracingEnabled = property_get_bool("debug.sf.enable_transaction_tracing", false);
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.enable();
+ }
}
LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -1946,7 +1952,7 @@
}
if (mTracingEnabledChanged) {
- mTracingEnabled = mLayerTracing.isEnabled();
+ mLayerTracingEnabled = mLayerTracing.isEnabled();
mTracingEnabledChanged = false;
}
@@ -1964,7 +1970,7 @@
bool needsTraversal = false;
if (clearTransactionFlags(eTransactionFlushNeeded)) {
- needsTraversal = flushTransactionQueues();
+ needsTraversal = flushTransactionQueues(vsyncId);
}
const bool shouldCommit =
@@ -2095,7 +2101,7 @@
modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
mLayersWithQueuedFrames.clear();
- if (mTracingEnabled) {
+ if (mLayerTracingEnabled) {
// This will block and should only be used for debugging.
if (mVisibleRegionsDirty) {
mLayerTracing.notify("visibleRegionsDirty");
@@ -3374,10 +3380,11 @@
client->attachLayer(handle, lbc);
}
+ int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++;
return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr,
InputWindowCommands{}, -1 /* desiredPresentTime */,
true /* isAutoTimestamp */, {}, false /* hasListenerCallbacks */, {},
- 0 /* Undefined transactionId */);
+ transactionId);
}
uint32_t SurfaceFlinger::getTransactionFlags() const {
@@ -3400,7 +3407,7 @@
return old;
}
-bool SurfaceFlinger::flushTransactionQueues() {
+bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
// states) around outside the scope of the lock
@@ -3486,12 +3493,13 @@
ATRACE_INT("TransactionQueue", mTransactionQueue.size());
}
- return applyTransactions(transactions);
+ return applyTransactions(transactions, vsyncId);
}
}
}
-bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) {
+bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
+ int64_t vsyncId) {
bool needsTraversal = false;
// Now apply all transactions.
for (const auto& transaction : transactions) {
@@ -3509,6 +3517,10 @@
std::move(transaction.transactionCommittedSignal));
}
}
+
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.addCommittedTransactions(transactions, vsyncId);
+ }
return needsTraversal;
}
@@ -3762,6 +3774,10 @@
state.traverseStatesWithBuffers([&](const layer_state_t& state) {
mBufferCountTracker.increment(state.surface->localBinder());
});
+
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.addQueuedTransaction(state);
+ }
queueTransaction(state);
// Check the pending state to make sure the transaction is synchronous.
@@ -4448,10 +4464,12 @@
displays.add(d);
nsecs_t now = systemTime();
+
+ int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++;
// It should be on the main thread, apply it directly.
applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands,
/* desiredPresentTime */ now, true, {}, /* postTime */ now, true, false,
- {}, getpid(), getuid(), 0 /* Undefined transactionId */);
+ {}, mPid, getuid(), transactionId);
setPowerModeInternal(display, hal::PowerMode::ON);
const nsecs_t vsyncPeriod =
@@ -4650,8 +4668,9 @@
}
status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
- if (asProto && mLayerTracing.isEnabled()) {
+ if (asProto) {
mLayerTracing.writeToFile();
+ mTransactionTracing.writeToFile();
}
return doDump(fd, DumpArgs(), asProto);
@@ -4848,7 +4867,6 @@
}
LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
- // If context is SurfaceTracing thread, mTracingLock blocks display transactions on main thread.
const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
LayersProto layersProto;
@@ -5049,6 +5067,8 @@
*/
mLayerTracing.dump(result);
result.append("\n");
+ mTransactionTracing.dump(result);
+ result.append("\n");
/*
* HWC layer minidump
@@ -5281,9 +5301,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1040 are currently used for backdoors. The code
+ // Numbers from 1000 to 1041 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 <= 1040) {
+ if (code >= 1000 && code <= 1041) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5724,6 +5744,20 @@
scheduleRepaint();
return NO_ERROR;
}
+ case 1041: { // Transaction tracing
+ if (data.readInt32()) {
+ // Transaction tracing is always running but allow the user to temporarily
+ // increase the buffer when actively debugging.
+ mTransactionTracing.setBufferSize(
+ TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
+ } else {
+ mTransactionTracing.setBufferSize(
+ TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
+ mTransactionTracing.writeToFile();
+ }
+ reply->writeInt32(NO_ERROR);
+ return NO_ERROR;
+ }
}
}
return err;