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