1 /*
2 * Copyright 2017 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 #undef LOG_TAG
17 #define LOG_TAG "SurfaceTracing"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19
20 #include "SurfaceTracing.h"
21 #include <SurfaceFlinger.h>
22
23 #include <android-base/file.h>
24 #include <android-base/stringprintf.h>
25 #include <log/log.h>
26 #include <utils/SystemClock.h>
27 #include <utils/Trace.h>
28
29 namespace android {
30
SurfaceTracing(SurfaceFlinger & flinger)31 SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger)
32 : mFlinger(flinger), mSfLock(flinger.mDrawingStateLock) {}
33
mainLoop()34 void SurfaceTracing::mainLoop() {
35 addFirstEntry();
36 bool enabled = true;
37 while (enabled) {
38 LayersTraceProto entry = traceWhenNotified();
39 enabled = addTraceToBuffer(entry);
40 }
41 }
42
addFirstEntry()43 void SurfaceTracing::addFirstEntry() {
44 LayersTraceProto entry;
45 {
46 std::scoped_lock lock(mSfLock);
47 entry = traceLayersLocked("tracing.enable");
48 }
49 addTraceToBuffer(entry);
50 }
51
traceWhenNotified()52 LayersTraceProto SurfaceTracing::traceWhenNotified() {
53 std::unique_lock<std::mutex> lock(mSfLock);
54 mCanStartTrace.wait(lock);
55 android::base::ScopedLockAssertion assumeLock(mSfLock);
56 LayersTraceProto entry = traceLayersLocked(mWhere);
57 lock.unlock();
58 return entry;
59 }
60
addTraceToBuffer(LayersTraceProto & entry)61 bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) {
62 std::scoped_lock lock(mTraceLock);
63 mBuffer.emplace(std::move(entry));
64 if (mWriteToFile) {
65 writeProtoFileLocked();
66 mWriteToFile = false;
67 }
68 return mEnabled;
69 }
70
notify(long compositionTime,const char * where)71 void SurfaceTracing::notify(long compositionTime, const char* where) {
72 std::scoped_lock lock(mSfLock);
73 mCompositionTime = compositionTime;
74 mWhere = where;
75 mCanStartTrace.notify_one();
76 }
77
writeToFileAsync()78 void SurfaceTracing::writeToFileAsync() {
79 std::scoped_lock lock(mTraceLock);
80 mWriteToFile = true;
81 mCanStartTrace.notify_one();
82 }
83
reset(size_t newSize)84 void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
85 // use the swap trick to make sure memory is released
86 std::queue<LayersTraceProto>().swap(mStorage);
87 mSizeInBytes = newSize;
88 mUsedInBytes = 0U;
89 }
90
emplace(LayersTraceProto && proto)91 void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
92 auto protoSize = proto.ByteSize();
93 while (mUsedInBytes + protoSize > mSizeInBytes) {
94 if (mStorage.empty()) {
95 return;
96 }
97 mUsedInBytes -= mStorage.front().ByteSize();
98 mStorage.pop();
99 }
100 mUsedInBytes += protoSize;
101 mStorage.emplace();
102 mStorage.back().Swap(&proto);
103 }
104
flush(LayersTraceFileProto * fileProto)105 void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
106 fileProto->mutable_entry()->Reserve(mStorage.size());
107
108 while (!mStorage.empty()) {
109 auto entry = fileProto->add_entry();
110 entry->Swap(&mStorage.front());
111 mStorage.pop();
112 }
113 }
114
enable()115 void SurfaceTracing::enable() {
116 std::scoped_lock lock(mTraceLock);
117
118 if (mEnabled) {
119 return;
120 }
121 mBuffer.reset(mBufferSize);
122 mEnabled = true;
123 mThread = std::thread(&SurfaceTracing::mainLoop, this);
124 }
125
writeToFile()126 status_t SurfaceTracing::writeToFile() {
127 mThread.join();
128 return mLastErr;
129 }
130
disable()131 bool SurfaceTracing::disable() {
132 std::scoped_lock lock(mTraceLock);
133
134 if (!mEnabled) {
135 return false;
136 }
137
138 mEnabled = false;
139 mWriteToFile = true;
140 mCanStartTrace.notify_all();
141 return true;
142 }
143
isEnabled() const144 bool SurfaceTracing::isEnabled() const {
145 std::scoped_lock lock(mTraceLock);
146 return mEnabled;
147 }
148
setBufferSize(size_t bufferSizeInByte)149 void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
150 std::scoped_lock lock(mTraceLock);
151 mBufferSize = bufferSizeInByte;
152 mBuffer.setSize(bufferSizeInByte);
153 }
154
setTraceFlags(uint32_t flags)155 void SurfaceTracing::setTraceFlags(uint32_t flags) {
156 std::scoped_lock lock(mSfLock);
157 mTraceFlags = flags;
158 }
159
traceLayersLocked(const char * where)160 LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
161 ATRACE_CALL();
162
163 LayersTraceProto entry;
164 entry.set_elapsed_realtime_nanos(mCompositionTime);
165 entry.set_where(where);
166 LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
167 entry.mutable_layers()->Swap(&layers);
168
169 return entry;
170 }
171
writeProtoFileLocked()172 void SurfaceTracing::writeProtoFileLocked() {
173 ATRACE_CALL();
174
175 LayersTraceFileProto fileProto;
176 std::string output;
177
178 fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
179 LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
180 mBuffer.flush(&fileProto);
181 mBuffer.reset(mBufferSize);
182
183 if (!fileProto.SerializeToString(&output)) {
184 ALOGE("Could not save the proto file! Permission denied");
185 mLastErr = PERMISSION_DENIED;
186 }
187 if (!android::base::WriteStringToFile(output, kDefaultFileName, S_IRWXU | S_IRGRP, getuid(),
188 getgid(), true)) {
189 ALOGE("Could not save the proto file! There are missing fields");
190 mLastErr = PERMISSION_DENIED;
191 }
192
193 mLastErr = NO_ERROR;
194 }
195
dump(std::string & result) const196 void SurfaceTracing::dump(std::string& result) const {
197 std::scoped_lock lock(mTraceLock);
198 base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
199 base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n",
200 mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
201 float(mBuffer.size()) / float(1_MB));
202 }
203
204 } // namespace android
205