xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Tracing/TransactionTracing.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2021 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <android-base/thread_annotations.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <layerproto/TransactionProto.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <utils/Errors.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <utils/Singleton.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker #include <mutex>
26*38e8c45fSAndroid Build Coastguard Worker #include <optional>
27*38e8c45fSAndroid Build Coastguard Worker #include <set>
28*38e8c45fSAndroid Build Coastguard Worker #include <thread>
29*38e8c45fSAndroid Build Coastguard Worker 
30*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/DisplayInfo.h"
31*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/LayerCreationArgs.h"
32*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/Update.h"
33*38e8c45fSAndroid Build Coastguard Worker #include "LocklessStack.h"
34*38e8c45fSAndroid Build Coastguard Worker #include "TransactionProtoParser.h"
35*38e8c45fSAndroid Build Coastguard Worker #include "TransactionRingBuffer.h"
36*38e8c45fSAndroid Build Coastguard Worker 
37*38e8c45fSAndroid Build Coastguard Worker using namespace android::surfaceflinger;
38*38e8c45fSAndroid Build Coastguard Worker 
39*38e8c45fSAndroid Build Coastguard Worker namespace android {
40*38e8c45fSAndroid Build Coastguard Worker 
41*38e8c45fSAndroid Build Coastguard Worker class SurfaceFlinger;
42*38e8c45fSAndroid Build Coastguard Worker class TransactionTracingTest;
43*38e8c45fSAndroid Build Coastguard Worker 
44*38e8c45fSAndroid Build Coastguard Worker /*
45*38e8c45fSAndroid Build Coastguard Worker  * Records all committed transactions into a ring buffer.
46*38e8c45fSAndroid Build Coastguard Worker  *
47*38e8c45fSAndroid Build Coastguard Worker  * Transactions come in via the binder thread. They are serialized to proto
48*38e8c45fSAndroid Build Coastguard Worker  * and stored in a map using the transaction id as key. Main thread will
49*38e8c45fSAndroid Build Coastguard Worker  * pass the list of transaction ids that are committed every vsync and notify
50*38e8c45fSAndroid Build Coastguard Worker  * the tracing thread. The tracing thread will then wake up and add the
51*38e8c45fSAndroid Build Coastguard Worker  * committed transactions to the ring buffer.
52*38e8c45fSAndroid Build Coastguard Worker  *
53*38e8c45fSAndroid Build Coastguard Worker  * The traced data can then be collected via:
54*38e8c45fSAndroid Build Coastguard Worker  * - Perfetto (preferred).
55*38e8c45fSAndroid Build Coastguard Worker  * - File system, after triggering the disk write through SF backdoor. This is legacy and is going
56*38e8c45fSAndroid Build Coastguard Worker  *   to be phased out.
57*38e8c45fSAndroid Build Coastguard Worker  *
58*38e8c45fSAndroid Build Coastguard Worker  * The Perfetto custom data source TransactionDataSource is registered with perfetto and is used
59*38e8c45fSAndroid Build Coastguard Worker  * to listen to perfetto events (setup, start, stop, flush) and to write trace packets to perfetto.
60*38e8c45fSAndroid Build Coastguard Worker  *
61*38e8c45fSAndroid Build Coastguard Worker  * The user can configure/start/stop tracing via /system/bin/perfetto.
62*38e8c45fSAndroid Build Coastguard Worker  *
63*38e8c45fSAndroid Build Coastguard Worker  * Tracing can operate in the following modes.
64*38e8c45fSAndroid Build Coastguard Worker  *
65*38e8c45fSAndroid Build Coastguard Worker  * ACTIVE mode:
66*38e8c45fSAndroid Build Coastguard Worker  * The transactions ring buffer (starting state + following committed transactions) is written
67*38e8c45fSAndroid Build Coastguard Worker  * (only once) to perfetto when the 'start' event is received.
68*38e8c45fSAndroid Build Coastguard Worker  * Transactions are then written to perfetto each time they are committed.
69*38e8c45fSAndroid Build Coastguard Worker  * On the receiver side, the data source is to be configured to periodically
70*38e8c45fSAndroid Build Coastguard Worker  * flush data to disk providing virtually infinite storage.
71*38e8c45fSAndroid Build Coastguard Worker  *
72*38e8c45fSAndroid Build Coastguard Worker  * CONTINUOUS mode:
73*38e8c45fSAndroid Build Coastguard Worker  * Listens to the perfetto 'flush' event (e.g. when a bugreport is taken).
74*38e8c45fSAndroid Build Coastguard Worker  * When a 'flush' event is received, the ring buffer of transactions (starting state + following
75*38e8c45fSAndroid Build Coastguard Worker  * committed transactions) is written to perfetto. On the receiver side, the data source is to be
76*38e8c45fSAndroid Build Coastguard Worker  * configured with a dedicated buffer large enough to store all the flushed data.
77*38e8c45fSAndroid Build Coastguard Worker  *
78*38e8c45fSAndroid Build Coastguard Worker  *
79*38e8c45fSAndroid Build Coastguard Worker  * E.g. start active mode tracing:
80*38e8c45fSAndroid Build Coastguard Worker  *
81*38e8c45fSAndroid Build Coastguard Worker    adb shell perfetto \
82*38e8c45fSAndroid Build Coastguard Worker      -c - --txt \
83*38e8c45fSAndroid Build Coastguard Worker      -o /data/misc/perfetto-traces/trace \
84*38e8c45fSAndroid Build Coastguard Worker    <<EOF
85*38e8c45fSAndroid Build Coastguard Worker    unique_session_name: "surfaceflinger_transactions_active"
86*38e8c45fSAndroid Build Coastguard Worker    buffers: {
87*38e8c45fSAndroid Build Coastguard Worker        size_kb: 1024
88*38e8c45fSAndroid Build Coastguard Worker        fill_policy: RING_BUFFER
89*38e8c45fSAndroid Build Coastguard Worker    }
90*38e8c45fSAndroid Build Coastguard Worker    data_sources: {
91*38e8c45fSAndroid Build Coastguard Worker        config {
92*38e8c45fSAndroid Build Coastguard Worker            name: "android.surfaceflinger.transactions"
93*38e8c45fSAndroid Build Coastguard Worker            surfaceflinger_transactions_config: {
94*38e8c45fSAndroid Build Coastguard Worker                mode: MODE_ACTIVE
95*38e8c45fSAndroid Build Coastguard Worker            }
96*38e8c45fSAndroid Build Coastguard Worker        }
97*38e8c45fSAndroid Build Coastguard Worker    }
98*38e8c45fSAndroid Build Coastguard Worker    write_into_file: true
99*38e8c45fSAndroid Build Coastguard Worker    file_write_period_ms: 100
100*38e8c45fSAndroid Build Coastguard Worker    EOF
101*38e8c45fSAndroid Build Coastguard Worker  *
102*38e8c45fSAndroid Build Coastguard Worker  *
103*38e8c45fSAndroid Build Coastguard Worker  * E.g. start continuous mode tracing:
104*38e8c45fSAndroid Build Coastguard Worker  *
105*38e8c45fSAndroid Build Coastguard Worker    adb shell perfetto \
106*38e8c45fSAndroid Build Coastguard Worker      -c - --txt \
107*38e8c45fSAndroid Build Coastguard Worker      -o /data/misc/perfetto-traces/trace \
108*38e8c45fSAndroid Build Coastguard Worker    <<EOF
109*38e8c45fSAndroid Build Coastguard Worker    unique_session_name: "surfaceflinger_transactions_continuous"
110*38e8c45fSAndroid Build Coastguard Worker    buffers: {
111*38e8c45fSAndroid Build Coastguard Worker        size_kb: 1024
112*38e8c45fSAndroid Build Coastguard Worker        fill_policy: RING_BUFFER
113*38e8c45fSAndroid Build Coastguard Worker    }
114*38e8c45fSAndroid Build Coastguard Worker    data_sources: {
115*38e8c45fSAndroid Build Coastguard Worker        config {
116*38e8c45fSAndroid Build Coastguard Worker            name: "android.surfaceflinger.transactions"
117*38e8c45fSAndroid Build Coastguard Worker            surfaceflinger_transactions_config: {
118*38e8c45fSAndroid Build Coastguard Worker                mode: MODE_CONTINUOUS
119*38e8c45fSAndroid Build Coastguard Worker            }
120*38e8c45fSAndroid Build Coastguard Worker        }
121*38e8c45fSAndroid Build Coastguard Worker    }
122*38e8c45fSAndroid Build Coastguard Worker    EOF
123*38e8c45fSAndroid Build Coastguard Worker  *
124*38e8c45fSAndroid Build Coastguard Worker  */
125*38e8c45fSAndroid Build Coastguard Worker class TransactionTracing {
126*38e8c45fSAndroid Build Coastguard Worker public:
127*38e8c45fSAndroid Build Coastguard Worker     using Mode = perfetto::protos::pbzero::SurfaceFlingerTransactionsConfig::Mode;
128*38e8c45fSAndroid Build Coastguard Worker 
129*38e8c45fSAndroid Build Coastguard Worker     TransactionTracing();
130*38e8c45fSAndroid Build Coastguard Worker     ~TransactionTracing();
131*38e8c45fSAndroid Build Coastguard Worker 
132*38e8c45fSAndroid Build Coastguard Worker     // Start event from perfetto data source
133*38e8c45fSAndroid Build Coastguard Worker     void onStart(Mode mode);
134*38e8c45fSAndroid Build Coastguard Worker     // Flush event from perfetto data source
135*38e8c45fSAndroid Build Coastguard Worker     void onFlush(Mode mode);
136*38e8c45fSAndroid Build Coastguard Worker 
137*38e8c45fSAndroid Build Coastguard Worker     void addQueuedTransaction(const TransactionState&);
138*38e8c45fSAndroid Build Coastguard Worker     void addCommittedTransactions(int64_t vsyncId, nsecs_t commitTime, frontend::Update& update,
139*38e8c45fSAndroid Build Coastguard Worker                                   const frontend::DisplayInfos&, bool displayInfoChanged);
140*38e8c45fSAndroid Build Coastguard Worker     status_t writeToFile(const std::string& filename = FILE_PATH);
141*38e8c45fSAndroid Build Coastguard Worker     // Return buffer contents as trace file proto
142*38e8c45fSAndroid Build Coastguard Worker     perfetto::protos::TransactionTraceFile writeToProto() EXCLUDES(mMainThreadLock);
143*38e8c45fSAndroid Build Coastguard Worker     void setBufferSize(size_t bufferSizeInBytes);
144*38e8c45fSAndroid Build Coastguard Worker     void onLayerRemoved(int layerId);
145*38e8c45fSAndroid Build Coastguard Worker     void dump(std::string&) const;
146*38e8c45fSAndroid Build Coastguard Worker     // Wait until all the committed transactions for the specified vsync id are added to the buffer.
147*38e8c45fSAndroid Build Coastguard Worker     void flush() EXCLUDES(mMainThreadLock);
148*38e8c45fSAndroid Build Coastguard Worker 
149*38e8c45fSAndroid Build Coastguard Worker     static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024;
150*38e8c45fSAndroid Build Coastguard Worker     static constexpr auto LEGACY_ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024;
151*38e8c45fSAndroid Build Coastguard Worker     // version 1 - switching to support new frontend
152*38e8c45fSAndroid Build Coastguard Worker     static constexpr auto TRACING_VERSION = 1;
153*38e8c45fSAndroid Build Coastguard Worker 
154*38e8c45fSAndroid Build Coastguard Worker private:
155*38e8c45fSAndroid Build Coastguard Worker     friend class TransactionTraceWriter;
156*38e8c45fSAndroid Build Coastguard Worker     friend class TransactionTracingTest;
157*38e8c45fSAndroid Build Coastguard Worker     friend class SurfaceFlinger;
158*38e8c45fSAndroid Build Coastguard Worker 
159*38e8c45fSAndroid Build Coastguard Worker     static constexpr auto DIR_NAME = "/data/misc/wmtrace/";
160*38e8c45fSAndroid Build Coastguard Worker     static constexpr auto FILE_NAME = "transactions_trace.winscope";
161*38e8c45fSAndroid Build Coastguard Worker     static constexpr auto FILE_PATH = "/data/misc/wmtrace/transactions_trace.winscope";
getFilePath(const std::string & prefix)162*38e8c45fSAndroid Build Coastguard Worker     static std::string getFilePath(const std::string& prefix) {
163*38e8c45fSAndroid Build Coastguard Worker         return DIR_NAME + prefix + FILE_NAME;
164*38e8c45fSAndroid Build Coastguard Worker     }
165*38e8c45fSAndroid Build Coastguard Worker 
166*38e8c45fSAndroid Build Coastguard Worker     mutable std::mutex mTraceLock;
167*38e8c45fSAndroid Build Coastguard Worker     TransactionRingBuffer<perfetto::protos::TransactionTraceFile,
168*38e8c45fSAndroid Build Coastguard Worker                           perfetto::protos::TransactionTraceEntry>
169*38e8c45fSAndroid Build Coastguard Worker             mBuffer GUARDED_BY(mTraceLock);
170*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<uint64_t, perfetto::protos::TransactionState> mQueuedTransactions
171*38e8c45fSAndroid Build Coastguard Worker             GUARDED_BY(mTraceLock);
172*38e8c45fSAndroid Build Coastguard Worker     LocklessStack<perfetto::protos::TransactionState> mTransactionQueue;
173*38e8c45fSAndroid Build Coastguard Worker     nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
174*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<int, perfetto::protos::LayerCreationArgs> mCreatedLayers
175*38e8c45fSAndroid Build Coastguard Worker             GUARDED_BY(mTraceLock);
176*38e8c45fSAndroid Build Coastguard Worker     std::map<uint32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
177*38e8c45fSAndroid Build Coastguard Worker     frontend::DisplayInfos mStartingDisplayInfos GUARDED_BY(mTraceLock);
178*38e8c45fSAndroid Build Coastguard Worker 
179*38e8c45fSAndroid Build Coastguard Worker     std::set<uint32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock);
180*38e8c45fSAndroid Build Coastguard Worker     TransactionProtoParser mProtoParser;
181*38e8c45fSAndroid Build Coastguard Worker 
182*38e8c45fSAndroid Build Coastguard Worker     // We do not want main thread to block so main thread will try to acquire mMainThreadLock,
183*38e8c45fSAndroid Build Coastguard Worker     // otherwise will push data to temporary container.
184*38e8c45fSAndroid Build Coastguard Worker     std::mutex mMainThreadLock;
185*38e8c45fSAndroid Build Coastguard Worker     std::thread mThread GUARDED_BY(mMainThreadLock);
186*38e8c45fSAndroid Build Coastguard Worker     bool mDone GUARDED_BY(mMainThreadLock) = false;
187*38e8c45fSAndroid Build Coastguard Worker     std::condition_variable mTransactionsAvailableCv;
188*38e8c45fSAndroid Build Coastguard Worker     std::condition_variable mTransactionsAddedToBufferCv;
189*38e8c45fSAndroid Build Coastguard Worker     struct CommittedUpdates {
190*38e8c45fSAndroid Build Coastguard Worker         std::vector<uint64_t> transactionIds;
191*38e8c45fSAndroid Build Coastguard Worker         std::vector<LayerCreationArgs> createdLayers;
192*38e8c45fSAndroid Build Coastguard Worker         std::vector<uint32_t> destroyedLayerHandles;
193*38e8c45fSAndroid Build Coastguard Worker         bool displayInfoChanged;
194*38e8c45fSAndroid Build Coastguard Worker         frontend::DisplayInfos displayInfos;
195*38e8c45fSAndroid Build Coastguard Worker         int64_t vsyncId;
196*38e8c45fSAndroid Build Coastguard Worker         int64_t timestamp;
197*38e8c45fSAndroid Build Coastguard Worker     };
198*38e8c45fSAndroid Build Coastguard Worker     std::vector<CommittedUpdates> mUpdates GUARDED_BY(mMainThreadLock);
199*38e8c45fSAndroid Build Coastguard Worker     std::vector<CommittedUpdates> mPendingUpdates; // only accessed by main thread
200*38e8c45fSAndroid Build Coastguard Worker 
201*38e8c45fSAndroid Build Coastguard Worker     std::vector<uint32_t /* layerId */> mDestroyedLayers GUARDED_BY(mMainThreadLock);
202*38e8c45fSAndroid Build Coastguard Worker     std::vector<uint32_t /* layerId */> mPendingDestroyedLayers; // only accessed by main thread
203*38e8c45fSAndroid Build Coastguard Worker     int64_t mLastUpdatedVsyncId = -1;
204*38e8c45fSAndroid Build Coastguard Worker 
205*38e8c45fSAndroid Build Coastguard Worker     void writeRingBufferToPerfetto(TransactionTracing::Mode mode);
206*38e8c45fSAndroid Build Coastguard Worker     perfetto::protos::TransactionTraceFile createTraceFileProto() const;
207*38e8c45fSAndroid Build Coastguard Worker     void loop();
208*38e8c45fSAndroid Build Coastguard Worker     void addEntry(const std::vector<CommittedUpdates>& committedTransactions,
209*38e8c45fSAndroid Build Coastguard Worker                   const std::vector<uint32_t>& removedLayers) EXCLUDES(mTraceLock);
210*38e8c45fSAndroid Build Coastguard Worker     int32_t getLayerIdLocked(const sp<IBinder>& layerHandle) REQUIRES(mTraceLock);
211*38e8c45fSAndroid Build Coastguard Worker     void tryPushToTracingThread() EXCLUDES(mMainThreadLock);
212*38e8c45fSAndroid Build Coastguard Worker     std::optional<perfetto::protos::TransactionTraceEntry> createStartingStateProtoLocked()
213*38e8c45fSAndroid Build Coastguard Worker             REQUIRES(mTraceLock);
214*38e8c45fSAndroid Build Coastguard Worker     void updateStartingStateLocked(const perfetto::protos::TransactionTraceEntry& entry)
215*38e8c45fSAndroid Build Coastguard Worker             REQUIRES(mTraceLock);
216*38e8c45fSAndroid Build Coastguard Worker };
217*38e8c45fSAndroid Build Coastguard Worker 
218*38e8c45fSAndroid Build Coastguard Worker class TransactionTraceWriter : public Singleton<TransactionTraceWriter> {
219*38e8c45fSAndroid Build Coastguard Worker     friend class Singleton<TransactionTracing>;
220*38e8c45fSAndroid Build Coastguard Worker     std::function<void(const std::string& prefix, bool overwrite)> mWriterFunction =
221*38e8c45fSAndroid Build Coastguard Worker             [](const std::string&, bool) {};
222*38e8c45fSAndroid Build Coastguard Worker     std::atomic<bool> mEnabled{true};
223*38e8c45fSAndroid Build Coastguard Worker 
doInvoke(const std::string & filename,bool overwrite)224*38e8c45fSAndroid Build Coastguard Worker     void doInvoke(const std::string& filename, bool overwrite) {
225*38e8c45fSAndroid Build Coastguard Worker         if (mEnabled) {
226*38e8c45fSAndroid Build Coastguard Worker             mWriterFunction(filename, overwrite);
227*38e8c45fSAndroid Build Coastguard Worker         }
228*38e8c45fSAndroid Build Coastguard Worker     };
229*38e8c45fSAndroid Build Coastguard Worker 
230*38e8c45fSAndroid Build Coastguard Worker public:
setWriterFunction(std::function<void (const std::string & filename,bool overwrite)> function)231*38e8c45fSAndroid Build Coastguard Worker     void setWriterFunction(
232*38e8c45fSAndroid Build Coastguard Worker             std::function<void(const std::string& filename, bool overwrite)> function) {
233*38e8c45fSAndroid Build Coastguard Worker         mWriterFunction = std::move(function);
234*38e8c45fSAndroid Build Coastguard Worker     }
invoke(const std::string & prefix,bool overwrite)235*38e8c45fSAndroid Build Coastguard Worker     void invoke(const std::string& prefix, bool overwrite) {
236*38e8c45fSAndroid Build Coastguard Worker         doInvoke(TransactionTracing::getFilePath(prefix), overwrite);
237*38e8c45fSAndroid Build Coastguard Worker     }
238*38e8c45fSAndroid Build Coastguard Worker     /* pass in a complete file path for testing */
invokeForTest(const std::string & filename,bool overwrite)239*38e8c45fSAndroid Build Coastguard Worker     void invokeForTest(const std::string& filename, bool overwrite) {
240*38e8c45fSAndroid Build Coastguard Worker         doInvoke(filename, overwrite);
241*38e8c45fSAndroid Build Coastguard Worker     }
242*38e8c45fSAndroid Build Coastguard Worker     /* hacky way to avoid generating traces when converting transaction trace to layers trace. */
disable()243*38e8c45fSAndroid Build Coastguard Worker     void disable() { mEnabled.store(false); }
enable()244*38e8c45fSAndroid Build Coastguard Worker     void enable() { mEnabled.store(true); }
245*38e8c45fSAndroid Build Coastguard Worker };
246*38e8c45fSAndroid Build Coastguard Worker 
247*38e8c45fSAndroid Build Coastguard Worker } // namespace android
248