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