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(const char * where)71 void SurfaceTracing::notify(const char* where) {
72 std::scoped_lock lock(mSfLock);
73 mWhere = where;
74 mCanStartTrace.notify_one();
75 }
76
writeToFileAsync()77 void SurfaceTracing::writeToFileAsync() {
78 std::scoped_lock lock(mTraceLock);
79 mWriteToFile = true;
80 mCanStartTrace.notify_one();
81 }
82
reset(size_t newSize)83 void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
84 // use the swap trick to make sure memory is released
85 std::queue<LayersTraceProto>().swap(mStorage);
86 mSizeInBytes = newSize;
87 mUsedInBytes = 0U;
88 }
89
emplace(LayersTraceProto && proto)90 void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
91 auto protoSize = proto.ByteSize();
92 while (mUsedInBytes + protoSize > mSizeInBytes) {
93 if (mStorage.empty()) {
94 return;
95 }
96 mUsedInBytes -= mStorage.front().ByteSize();
97 mStorage.pop();
98 }
99 mUsedInBytes += protoSize;
100 mStorage.emplace();
101 mStorage.back().Swap(&proto);
102 }
103
flush(LayersTraceFileProto * fileProto)104 void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
105 fileProto->mutable_entry()->Reserve(mStorage.size());
106
107 while (!mStorage.empty()) {
108 auto entry = fileProto->add_entry();
109 entry->Swap(&mStorage.front());
110 mStorage.pop();
111 }
112 }
113
enable()114 void SurfaceTracing::enable() {
115 std::scoped_lock lock(mTraceLock);
116
117 if (mEnabled) {
118 return;
119 }
120 mBuffer.reset(mBufferSize);
121 mEnabled = true;
122 mThread = std::thread(&SurfaceTracing::mainLoop, this);
123 }
124
writeToFile()125 status_t SurfaceTracing::writeToFile() {
126 mThread.join();
127 return mLastErr;
128 }
129
disable()130 bool SurfaceTracing::disable() {
131 std::scoped_lock lock(mTraceLock);
132
133 if (!mEnabled) {
134 return false;
135 }
136
137 mEnabled = false;
138 mWriteToFile = true;
139 mCanStartTrace.notify_all();
140 return true;
141 }
142
isEnabled() const143 bool SurfaceTracing::isEnabled() const {
144 std::scoped_lock lock(mTraceLock);
145 return mEnabled;
146 }
147
setBufferSize(size_t bufferSizeInByte)148 void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
149 std::scoped_lock lock(mTraceLock);
150 mBufferSize = bufferSizeInByte;
151 mBuffer.setSize(bufferSizeInByte);
152 }
153
setTraceFlags(uint32_t flags)154 void SurfaceTracing::setTraceFlags(uint32_t flags) {
155 std::scoped_lock lock(mSfLock);
156 mTraceFlags = flags;
157 }
158
traceLayersLocked(const char * where)159 LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
160 ATRACE_CALL();
161
162 LayersTraceProto entry;
163 entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
164 entry.set_where(where);
165 LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags));
166 entry.mutable_layers()->Swap(&layers);
167
168 return entry;
169 }
170
writeProtoFileLocked()171 void SurfaceTracing::writeProtoFileLocked() {
172 ATRACE_CALL();
173
174 LayersTraceFileProto fileProto;
175 std::string output;
176
177 fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
178 LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
179 mBuffer.flush(&fileProto);
180 mBuffer.reset(mBufferSize);
181
182 if (!fileProto.SerializeToString(&output)) {
183 ALOGE("Could not save the proto file! Permission denied");
184 mLastErr = PERMISSION_DENIED;
185 }
186 if (!android::base::WriteStringToFile(output, kDefaultFileName, S_IRWXU | S_IRGRP, getuid(),
187 getgid(), true)) {
188 ALOGE("Could not save the proto file! There are missing fields");
189 mLastErr = PERMISSION_DENIED;
190 }
191
192 mLastErr = NO_ERROR;
193 }
194
dump(std::string & result) const195 void SurfaceTracing::dump(std::string& result) const {
196 std::scoped_lock lock(mTraceLock);
197 base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
198 base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n",
199 mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
200 float(mBuffer.size()) / float(1_MB));
201 }
202
203 } // namespace android
204